PageRenderTime 1ms CodeModel.GetById 43ms app.highlight 9ms RepoModel.GetById 1ms app.codeStats 0ms

/modules/apps/archived/portal-security-sso-cas-impl/src/main/java/com/liferay/portal/security/sso/cas/internal/servlet/filter/CASFilter.java

https://github.com/danielreuther/liferay-portal
Java | 296 lines | 186 code | 64 blank | 46 comment | 14 complexity | 57444e129188913aa7824a38f3983e1f MD5 | raw file
  1/**
  2 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
  3 *
  4 * This library is free software; you can redistribute it and/or modify it under
  5 * the terms of the GNU Lesser General Public License as published by the Free
  6 * Software Foundation; either version 2.1 of the License, or (at your option)
  7 * any later version.
  8 *
  9 * This library is distributed in the hope that it will be useful, but WITHOUT
 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 11 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 12 * details.
 13 */
 14
 15package com.liferay.portal.security.sso.cas.internal.servlet.filter;
 16
 17import com.liferay.portal.kernel.exception.PortalException;
 18import com.liferay.portal.kernel.log.Log;
 19import com.liferay.portal.kernel.log.LogFactoryUtil;
 20import com.liferay.portal.kernel.module.configuration.ConfigurationProvider;
 21import com.liferay.portal.kernel.servlet.BaseFilter;
 22import com.liferay.portal.kernel.settings.CompanyServiceSettingsLocator;
 23import com.liferay.portal.kernel.util.HashMapBuilder;
 24import com.liferay.portal.kernel.util.HttpComponentsUtil;
 25import com.liferay.portal.kernel.util.ParamUtil;
 26import com.liferay.portal.kernel.util.Portal;
 27import com.liferay.portal.kernel.util.Validator;
 28import com.liferay.portal.security.sso.cas.configuration.CASConfiguration;
 29import com.liferay.portal.security.sso.cas.constants.CASConstants;
 30import com.liferay.portal.security.sso.cas.internal.constants.CASWebKeys;
 31
 32import java.util.Map;
 33import java.util.concurrent.ConcurrentHashMap;
 34
 35import javax.servlet.Filter;
 36import javax.servlet.FilterChain;
 37import javax.servlet.http.HttpServletRequest;
 38import javax.servlet.http.HttpServletResponse;
 39import javax.servlet.http.HttpSession;
 40
 41import org.jasig.cas.client.authentication.AttributePrincipal;
 42import org.jasig.cas.client.util.CommonUtils;
 43import org.jasig.cas.client.validation.Assertion;
 44import org.jasig.cas.client.validation.Cas20ProxyTicketValidator;
 45import org.jasig.cas.client.validation.TicketValidationException;
 46import org.jasig.cas.client.validation.TicketValidator;
 47
 48import org.osgi.service.component.annotations.Component;
 49import org.osgi.service.component.annotations.Reference;
 50
 51/**
 52 * Participates in every login and logout that triggers an HTTP request to
 53 * Liferay Portal.
 54 *
 55 * <p>
 56 * This class checks if the HTTP session attribute <code>CAS_FORCE_LOGOUT</code>
 57 * is set by CASAutoLogin and, if so, redirects the browser to the configured
 58 * CAS Logout URL.
 59 * </p>
 60 *
 61 * <p>
 62 * Next, if the session attribute <code>CAS_LOGIN</code> has not already been
 63 * set and no ticket parameter is received via the HTTP servlet request, the CAS
 64 * server login URL is constructed based on the configuration of the Login URL,
 65 * the Server name, and the Service URL and the browser is redirected to this
 66 * URL. If a ticket parameter was received, it will be validated.
 67 * </p>
 68 *
 69 * <p>
 70 * Validation includes sending a SAML request containing the ticket to the CAS
 71 * server, and in return receiving an assertion of user attributes. However,
 72 * only the principal attribute is used and it is set as the session attribute
 73 * <code>CAS_LOGIN</code> as mentioned earlier. It is important that the CAS
 74 * server issues a principal of the same type that the portal instance is
 75 * configured to use (e.g., screen name versus email address).
 76 * </p>
 77 *
 78 * @author Michael Young
 79 * @author Brian Wing Shun Chan
 80 * @author Raymond Augé
 81 * @author Tina Tian
 82 * @author Zsolt Balogh
 83 */
 84@Component(
 85	configurationPid = "com.liferay.portal.security.sso.cas.configuration.CASConfiguration",
 86	immediate = true,
 87	property = {
 88		"before-filter=Auto Login Filter", "dispatcher=FORWARD",
 89		"dispatcher=REQUEST", "servlet-context-name=",
 90		"servlet-filter-name=SSO CAS Filter", "url-pattern=/c/portal/login",
 91		"url-pattern=/c/portal/logout"
 92	},
 93	service = Filter.class
 94)
 95public class CASFilter extends BaseFilter {
 96
 97	public static void reload(long companyId) {
 98		_ticketValidators.remove(companyId);
 99	}
100
101	@Override
102	public boolean isFilterEnabled(
103		HttpServletRequest httpServletRequest,
104		HttpServletResponse httpServletResponse) {
105
106		try {
107			CASConfiguration casConfiguration =
108				_configurationProvider.getConfiguration(
109					CASConfiguration.class,
110					new CompanyServiceSettingsLocator(
111						_portal.getCompanyId(httpServletRequest),
112						CASConstants.SERVICE_NAME));
113
114			if (casConfiguration.enabled()) {
115				return true;
116			}
117		}
118		catch (Exception exception) {
119			_log.error(exception);
120		}
121
122		return false;
123	}
124
125	@Override
126	protected Log getLog() {
127		return _log;
128	}
129
130	@Override
131	protected void processFilter(
132			HttpServletRequest httpServletRequest,
133			HttpServletResponse httpServletResponse, FilterChain filterChain)
134		throws Exception {
135
136		HttpSession httpSession = httpServletRequest.getSession();
137
138		long companyId = _portal.getCompanyId(httpServletRequest);
139
140		CASConfiguration casConfiguration =
141			_configurationProvider.getConfiguration(
142				CASConfiguration.class,
143				new CompanyServiceSettingsLocator(
144					companyId, CASConstants.SERVICE_NAME));
145
146		Object forceLogout = httpSession.getAttribute(
147			CASWebKeys.CAS_FORCE_LOGOUT);
148
149		if (forceLogout != null) {
150			httpSession.removeAttribute(CASWebKeys.CAS_FORCE_LOGOUT);
151
152			String logoutUrl = casConfiguration.logoutURL();
153
154			httpServletResponse.sendRedirect(logoutUrl);
155
156			return;
157		}
158
159		String pathInfo = httpServletRequest.getPathInfo();
160
161		if (Validator.isNotNull(pathInfo) &&
162			pathInfo.contains("/portal/logout")) {
163
164			httpSession.invalidate();
165
166			String logoutUrl = casConfiguration.logoutURL();
167
168			httpServletResponse.sendRedirect(logoutUrl);
169
170			return;
171		}
172
173		String login = (String)httpSession.getAttribute(CASWebKeys.CAS_LOGIN);
174
175		if (Validator.isNotNull(login)) {
176			processFilter(
177				CASFilter.class.getName(), httpServletRequest,
178				httpServletResponse, filterChain);
179
180			return;
181		}
182
183		String serverName = casConfiguration.serverName();
184
185		String serviceURL = casConfiguration.serviceURL();
186
187		if (Validator.isNull(serviceURL)) {
188			serviceURL = CommonUtils.constructServiceUrl(
189				httpServletRequest, httpServletResponse, serviceURL, serverName,
190				"service", "ticket", true);
191		}
192
193		String ticket = ParamUtil.getString(httpServletRequest, "ticket");
194
195		if (Validator.isNull(ticket)) {
196			String loginUrl = casConfiguration.loginURL();
197
198			loginUrl = HttpComponentsUtil.addParameter(
199				loginUrl, "service", serviceURL);
200
201			httpServletResponse.sendRedirect(loginUrl);
202
203			return;
204		}
205
206		TicketValidator ticketValidator = _getTicketValidator(companyId);
207
208		Assertion assertion = null;
209
210		try {
211			assertion = ticketValidator.validate(ticket, serviceURL);
212		}
213		catch (TicketValidationException ticketValidationException) {
214			if (_log.isDebugEnabled()) {
215				_log.debug(ticketValidationException);
216			}
217			else if (_log.isInfoEnabled()) {
218				_log.info(ticketValidationException);
219			}
220
221			_portal.sendError(
222				new PortalException(
223					"Unable to validate CAS ticket: " + ticket,
224					ticketValidationException),
225				httpServletRequest, httpServletResponse);
226
227			return;
228		}
229
230		if (assertion != null) {
231			AttributePrincipal attributePrincipal = assertion.getPrincipal();
232
233			login = attributePrincipal.getName();
234
235			httpSession.setAttribute(CASWebKeys.CAS_LOGIN, login);
236		}
237
238		processFilter(
239			CASFilter.class.getName(), httpServletRequest, httpServletResponse,
240			filterChain);
241	}
242
243	@Reference(unbind = "-")
244	protected void setConfigurationProvider(
245		ConfigurationProvider configurationProvider) {
246
247		_configurationProvider = configurationProvider;
248	}
249
250	private TicketValidator _getTicketValidator(long companyId)
251		throws Exception {
252
253		TicketValidator ticketValidator = _ticketValidators.get(companyId);
254
255		if (ticketValidator != null) {
256			return ticketValidator;
257		}
258
259		CASConfiguration casConfiguration =
260			_configurationProvider.getConfiguration(
261				CASConfiguration.class,
262				new CompanyServiceSettingsLocator(
263					companyId, CASConstants.SERVICE_NAME));
264
265		String serverUrl = casConfiguration.serverURL();
266
267		Cas20ProxyTicketValidator cas20ProxyTicketValidator =
268			new Cas20ProxyTicketValidator(serverUrl);
269
270		cas20ProxyTicketValidator.setCustomParameters(
271			HashMapBuilder.put(
272				"casServerLoginUrl", casConfiguration.loginURL()
273			).put(
274				"casServerUrlPrefix", serverUrl
275			).put(
276				"redirectAfterValidation", "false"
277			).put(
278				"serverName", casConfiguration.serverName()
279			).build());
280
281		_ticketValidators.put(companyId, cas20ProxyTicketValidator);
282
283		return cas20ProxyTicketValidator;
284	}
285
286	private static final Log _log = LogFactoryUtil.getLog(CASFilter.class);
287
288	private static final Map<Long, TicketValidator> _ticketValidators =
289		new ConcurrentHashMap<>();
290
291	private ConfigurationProvider _configurationProvider;
292
293	@Reference
294	private Portal _portal;
295
296}