2 * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
\r
4 * This library is free software; you can redistribute it and/or modify it under
\r
5 * the terms of the GNU Lesser General Public License as published by the Free
\r
6 * Software Foundation; either version 2.1 of the License, or (at your option)
\r
9 * This library is distributed in the hope that it will be useful, but WITHOUT
\r
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
11 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
\r
15 package com.liferay.portal.servlet.filters.secure;
\r
17 import java.util.HashSet;
\r
18 import java.util.Set;
\r
20 import javax.servlet.FilterChain;
\r
21 import javax.servlet.FilterConfig;
\r
22 import javax.servlet.http.HttpServletRequest;
\r
23 import javax.servlet.http.HttpServletResponse;
\r
24 import javax.servlet.http.HttpSession;
\r
26 import com.liferay.portal.kernel.log.Log;
\r
27 import com.liferay.portal.kernel.log.LogFactoryUtil;
\r
28 import com.liferay.portal.kernel.servlet.HttpHeaders;
\r
29 import com.liferay.portal.kernel.servlet.ProtectedServletRequest;
\r
30 import com.liferay.portal.kernel.util.GetterUtil;
\r
31 import com.liferay.portal.kernel.util.Http;
\r
32 import com.liferay.portal.kernel.util.HttpUtil;
\r
33 import com.liferay.portal.kernel.util.StringBundler;
\r
34 import com.liferay.portal.kernel.util.StringPool;
\r
35 import com.liferay.portal.kernel.util.StringUtil;
\r
36 import com.liferay.portal.kernel.util.Validator;
\r
37 import com.liferay.portal.model.Group;
\r
38 import com.liferay.portal.model.User;
\r
39 import com.liferay.portal.security.auth.PrincipalThreadLocal;
\r
40 import com.liferay.portal.security.permission.PermissionChecker;
\r
41 import com.liferay.portal.security.permission.PermissionCheckerFactoryUtil;
\r
42 import com.liferay.portal.security.permission.PermissionThreadLocal;
\r
43 import com.liferay.portal.service.GroupLocalServiceUtil;
\r
44 import com.liferay.portal.service.UserLocalServiceUtil;
\r
45 import com.liferay.portal.servlet.filters.BasePortalFilter;
\r
46 import com.liferay.portal.util.Portal;
\r
47 import com.liferay.portal.util.PortalInstances;
\r
48 import com.liferay.portal.util.PortalUtil;
\r
49 import com.liferay.portal.util.PropsUtil;
\r
50 import com.liferay.portal.util.PropsValues;
\r
51 import com.liferay.portal.util.WebKeys;
\r
54 * @author Brian Wing Shun Chan
\r
55 * @author Raymond Augé
\r
56 * @author Alexander Chow
\r
58 public class SecureFilter extends BasePortalFilter {
\r
61 public void init(FilterConfig filterConfig) {
\r
62 super.init(filterConfig);
\r
64 _basicAuthEnabled = GetterUtil.getBoolean(
\r
65 filterConfig.getInitParameter("basic_auth"));
\r
66 _digestAuthEnabled = GetterUtil.getBoolean(
\r
67 filterConfig.getInitParameter("digest_auth"));
\r
68 _usePermissionChecker = GetterUtil.getBoolean(
\r
69 filterConfig.getInitParameter("use_permission_checker"));
\r
71 String propertyPrefix = filterConfig.getInitParameter(
\r
72 "portal_property_prefix");
\r
74 String[] hostsAllowedArray = null;
\r
76 if (Validator.isNull(propertyPrefix)) {
\r
77 hostsAllowedArray = StringUtil.split(
\r
78 filterConfig.getInitParameter("hosts.allowed"));
\r
79 _httpsRequired = GetterUtil.getBoolean(
\r
80 filterConfig.getInitParameter("https.required"));
\r
83 hostsAllowedArray = PropsUtil.getArray(
\r
84 propertyPrefix + "hosts.allowed");
\r
85 _httpsRequired = GetterUtil.getBoolean(
\r
86 PropsUtil.get(propertyPrefix + "https.required"));
\r
89 for (int i = 0; i < hostsAllowedArray.length; i++) {
\r
90 _hostsAllowed.add(hostsAllowedArray[i]);
\r
94 protected HttpServletRequest basicAuth(
\r
95 HttpServletRequest request, HttpServletResponse response)
\r
98 HttpSession session = request.getSession();
\r
100 session.setAttribute(WebKeys.BASIC_AUTH_ENABLED, Boolean.TRUE);
\r
102 long userId = GetterUtil.getLong(
\r
103 (String)session.getAttribute(_AUTHENTICATED_USER));
\r
106 request = new ProtectedServletRequest(request, String.valueOf(userId), HttpServletRequest.BASIC_AUTH);
\r
110 userId = PortalUtil.getBasicAuthUserId(request);
\r
112 catch (Exception e) {
\r
117 request = setCredentials(
\r
118 request, session, userId, HttpServletRequest.BASIC_AUTH);
\r
119 request = checkWebdavAccessPermission(request, response, userId);
\r
122 response.setHeader(HttpHeaders.WWW_AUTHENTICATE, _BASIC_REALM);
\r
123 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
\r
132 protected HttpServletRequest digestAuth(
\r
133 HttpServletRequest request, HttpServletResponse response)
\r
136 HttpSession session = request.getSession();
\r
138 long userId = GetterUtil.getLong(
\r
139 (String)session.getAttribute(_AUTHENTICATED_USER));
\r
142 request = new ProtectedServletRequest(
\r
143 request, String.valueOf(userId),
\r
144 HttpServletRequest.DIGEST_AUTH);
\r
148 userId = PortalUtil.getDigestAuthUserId(request);
\r
150 catch (Exception e) {
\r
155 request = setCredentials(
\r
156 request, session, userId, HttpServletRequest.DIGEST_AUTH);
\r
157 request = checkWebdavAccessPermission(request, response, userId);
\r
161 // Must generate a new nonce for each 401 (RFC2617, 3.2.1)
\r
163 long companyId = PortalInstances.getCompanyId(request);
\r
165 String remoteAddress = request.getRemoteAddr();
\r
167 String nonce = NonceUtil.generate(companyId, remoteAddress);
\r
169 StringBundler sb = new StringBundler(4);
\r
171 sb.append(_DIGEST_REALM);
\r
172 sb.append(", nonce=\"");
\r
176 response.setHeader(HttpHeaders.WWW_AUTHENTICATE, sb.toString());
\r
177 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
\r
186 protected boolean isAccessAllowed(HttpServletRequest request) {
\r
187 if (_hostsAllowed.isEmpty()) {
\r
191 String remoteAddr = request.getRemoteAddr();
\r
193 if (_hostsAllowed.contains(remoteAddr)) {
\r
197 String computerAddress = PortalUtil.getComputerAddress();
\r
199 if (computerAddress.equals(remoteAddr) &&
\r
200 _hostsAllowed.contains(_SERVER_IP)) {
\r
209 protected void processFilter(
\r
210 HttpServletRequest request, HttpServletResponse response,
\r
211 FilterChain filterChain)
\r
214 String remoteAddr = request.getRemoteAddr();
\r
216 if (isAccessAllowed(request)) {
\r
217 if (_log.isDebugEnabled()) {
\r
218 _log.debug("Access allowed for " + remoteAddr);
\r
222 if (_log.isWarnEnabled()) {
\r
223 _log.warn("Access denied for " + remoteAddr);
\r
226 response.sendError(
\r
227 HttpServletResponse.SC_FORBIDDEN,
\r
228 "Access denied for " + remoteAddr);
\r
233 if (_log.isDebugEnabled()) {
\r
234 if (_httpsRequired) {
\r
235 _log.debug("https is required");
\r
238 _log.debug("https is not required");
\r
242 if (_httpsRequired && !request.isSecure()) {
\r
243 if (_log.isDebugEnabled()) {
\r
244 String completeURL = HttpUtil.getCompleteURL(request);
\r
246 _log.debug("Securing " + completeURL);
\r
249 StringBundler redirectURL = new StringBundler(5);
\r
251 redirectURL.append(Http.HTTPS_WITH_SLASH);
\r
252 redirectURL.append(request.getServerName());
\r
253 redirectURL.append(request.getServletPath());
\r
255 String queryString = request.getQueryString();
\r
257 if (Validator.isNotNull(queryString)) {
\r
258 redirectURL.append(StringPool.QUESTION);
\r
259 redirectURL.append(request.getQueryString());
\r
262 if (_log.isDebugEnabled()) {
\r
263 _log.debug("Redirect to " + redirectURL);
\r
266 response.sendRedirect(redirectURL.toString());
\r
269 if (_log.isDebugEnabled()) {
\r
270 String completeURL = HttpUtil.getCompleteURL(request);
\r
272 _log.debug("Not securing " + completeURL);
\r
275 // This authentication should only be run if specified by web.xml
\r
276 // and JAAS is disabled. Make sure to run this once per session and
\r
277 // wrap the request if necessary.
\r
279 if (!PropsValues.PORTAL_JAAS_ENABLE) {
\r
280 User user = PortalUtil.getUser(request);
\r
282 if ((user != null) && !user.isDefaultUser()) {
\r
283 request = setCredentials(
\r
284 request, request.getSession(), user.getUserId(), null);
\r
287 if (_digestAuthEnabled) {
\r
288 request = digestAuth(request, response);
\r
290 else if (_basicAuthEnabled) {
\r
291 request = basicAuth(request, response);
\r
296 if (request != null) {
\r
297 processFilter(getClass(), request, response, filterChain);
\r
303 * Check that the authenticated user is the one contained in the WebDAV URL in case of personnal storage access
\r
309 protected HttpServletRequest checkWebdavAccessPermission(HttpServletRequest request, HttpServletResponse response, long userId) {
\r
311 String completeURL = HttpUtil.getCompleteURL(request);
\r
313 if (completeURL.contains("api/secure/webdav")) {
\r
318 user = UserLocalServiceUtil.getUser(userId);
\r
320 } catch (Exception e) {
\r
321 _log.error("Could not find user attached to webdav request", e);
\r
322 response.setHeader(HttpHeaders.WWW_AUTHENTICATE, _BASIC_REALM);
\r
323 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
\r
327 // The WebDAV URL has the following format:
\r
328 // <host>/api/secure/webdav/<user screenName or group friendly URL>/document_library/...
\r
330 String[] urlTab = completeURL.split("/");
\r
332 if (urlTab != null && urlTab.length > 0) {
\r
334 // Extract the user screen name or group friendlyUrl from the webdav URL
\r
335 String urlPart = "";
\r
337 while (!urlPart.equals("webdav")) {
\r
339 urlPart = urlTab[idx];
\r
341 String userOrGroupName = urlTab[idx + 1];
\r
343 // Determine if the userOrGroupName is either a screenName or a group friendlyURL
\r
344 User urlUser = null;
\r
346 urlUser = UserLocalServiceUtil.getUserByScreenName(user.getCompanyId(), userOrGroupName);
\r
348 // This is a personal storage area
\r
349 // We must ensure that the screenname contained in the webdav URL is the screenname of the authenticated user
\r
350 if (urlUser != null && urlUser.getUserId() != user.getUserId()) {
\r
351 _log.info("Do not authorize webdav connection to url "+completeURL+" for user with screen name "+urlUser.getScreenName());
\r
352 response.setHeader(HttpHeaders.WWW_AUTHENTICATE, _BASIC_REALM);
\r
353 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
\r
357 } catch (Exception e) {
\r
358 // This is not a user but a group
\r
368 protected HttpServletRequest setCredentials(
\r
369 HttpServletRequest request, HttpSession session, long userId,
\r
373 User user = UserLocalServiceUtil.getUser(userId);
\r
375 String userIdString = String.valueOf(userId);
\r
377 request = new ProtectedServletRequest(request, userIdString, authType);
\r
379 session.setAttribute(WebKeys.USER, user);
\r
380 session.setAttribute(_AUTHENTICATED_USER, userIdString);
\r
382 if (_usePermissionChecker) {
\r
383 PrincipalThreadLocal.setName(userId);
\r
384 PrincipalThreadLocal.setPassword(
\r
385 PortalUtil.getUserPassword(request));
\r
387 PermissionChecker permissionChecker =
\r
388 PermissionCheckerFactoryUtil.create(user);
\r
390 PermissionThreadLocal.setPermissionChecker(permissionChecker);
\r
396 protected void setUsePermissionChecker(boolean usePermissionChecker) {
\r
397 _usePermissionChecker = usePermissionChecker;
\r
400 private static final String _AUTHENTICATED_USER =
\r
401 SecureFilter.class + "_AUTHENTICATED_USER";
\r
403 private static final String _BASIC_REALM =
\r
404 "Basic realm=\"" + Portal.PORTAL_REALM + "\"";
\r
406 private static final String _DIGEST_REALM =
\r
407 "Digest realm=\"" + Portal.PORTAL_REALM + "\"";
\r
409 private static final String _SERVER_IP = "SERVER_IP";
\r
411 private static Log _log = LogFactoryUtil.getLog(SecureFilter.class);
\r
413 private boolean _basicAuthEnabled;
\r
414 private boolean _digestAuthEnabled;
\r
415 private Set<String> _hostsAllowed = new HashSet<String>();
\r
416 private boolean _httpsRequired;
\r
417 private boolean _usePermissionChecker;
\r