001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.servlet.filters.secure;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.servlet.HttpHeaders;
020    import com.liferay.portal.kernel.servlet.ProtectedServletRequest;
021    import com.liferay.portal.kernel.util.GetterUtil;
022    import com.liferay.portal.kernel.util.Http;
023    import com.liferay.portal.kernel.util.HttpUtil;
024    import com.liferay.portal.kernel.util.StringBundler;
025    import com.liferay.portal.kernel.util.StringPool;
026    import com.liferay.portal.kernel.util.StringUtil;
027    import com.liferay.portal.kernel.util.Validator;
028    import com.liferay.portal.model.User;
029    import com.liferay.portal.security.auth.AuthSettingsUtil;
030    import com.liferay.portal.security.auth.CompanyThreadLocal;
031    import com.liferay.portal.security.auth.PrincipalThreadLocal;
032    import com.liferay.portal.security.permission.PermissionChecker;
033    import com.liferay.portal.security.permission.PermissionCheckerFactoryUtil;
034    import com.liferay.portal.security.permission.PermissionThreadLocal;
035    import com.liferay.portal.service.UserLocalServiceUtil;
036    import com.liferay.portal.servlet.filters.BasePortalFilter;
037    import com.liferay.portal.util.Portal;
038    import com.liferay.portal.util.PortalInstances;
039    import com.liferay.portal.util.PortalUtil;
040    import com.liferay.portal.util.PropsUtil;
041    import com.liferay.portal.util.WebKeys;
042    
043    import java.util.HashSet;
044    import java.util.Set;
045    
046    import javax.servlet.FilterChain;
047    import javax.servlet.FilterConfig;
048    import javax.servlet.http.HttpServletRequest;
049    import javax.servlet.http.HttpServletResponse;
050    import javax.servlet.http.HttpSession;
051    
052    /**
053     * @author Brian Wing Shun Chan
054     * @author Raymond Aug??
055     * @author Alexander Chow
056     */
057    public class SecureFilter extends BasePortalFilter {
058    
059            @Override
060            public void init(FilterConfig filterConfig) {
061                    super.init(filterConfig);
062    
063                    _basicAuthEnabled = GetterUtil.getBoolean(
064                            filterConfig.getInitParameter("basic_auth"));
065                    _digestAuthEnabled = GetterUtil.getBoolean(
066                            filterConfig.getInitParameter("digest_auth"));
067    
068                    String propertyPrefix = filterConfig.getInitParameter(
069                            "portal_property_prefix");
070    
071                    String[] hostsAllowed = null;
072    
073                    if (Validator.isNull(propertyPrefix)) {
074                            hostsAllowed = StringUtil.split(
075                                    filterConfig.getInitParameter("hosts.allowed"));
076                            _httpsRequired = GetterUtil.getBoolean(
077                                    filterConfig.getInitParameter("https.required"));
078                    }
079                    else {
080                            hostsAllowed = PropsUtil.getArray(propertyPrefix + "hosts.allowed");
081                            _httpsRequired = GetterUtil.getBoolean(
082                                    PropsUtil.get(propertyPrefix + "https.required"));
083                    }
084    
085                    for (String hostAllowed : hostsAllowed) {
086                            _hostsAllowed.add(hostAllowed);
087                    }
088    
089                    _usePermissionChecker = GetterUtil.getBoolean(
090                            filterConfig.getInitParameter("use_permission_checker"));
091            }
092    
093            protected HttpServletRequest basicAuth(
094                            HttpServletRequest request, HttpServletResponse response)
095                    throws Exception {
096    
097                    HttpSession session = request.getSession();
098    
099                    session.setAttribute(WebKeys.BASIC_AUTH_ENABLED, Boolean.TRUE);
100    
101                    long userId = GetterUtil.getLong(
102                            (String)session.getAttribute(_AUTHENTICATED_USER));
103    
104                    if (userId > 0) {
105                            request = new ProtectedServletRequest(
106                                    request, String.valueOf(userId), HttpServletRequest.BASIC_AUTH);
107    
108                            initThreadLocals(request);
109                    }
110                    else {
111                            try {
112                                    userId = PortalUtil.getBasicAuthUserId(request);
113                            }
114                            catch (Exception e) {
115                                    _log.error(e, e);
116                            }
117    
118                            if (userId > 0) {
119                                    request = setCredentials(
120                                            request, session, userId, HttpServletRequest.BASIC_AUTH);
121                            }
122                            else {
123                                    response.setHeader(HttpHeaders.WWW_AUTHENTICATE, _BASIC_REALM);
124                                    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
125    
126                                    return null;
127                            }
128                    }
129    
130                    return request;
131            }
132    
133            protected HttpServletRequest digestAuth(
134                            HttpServletRequest request, HttpServletResponse response)
135                    throws Exception {
136    
137                    HttpSession session = request.getSession();
138    
139                    long userId = GetterUtil.getLong(
140                            (String)session.getAttribute(_AUTHENTICATED_USER));
141    
142                    if (userId > 0) {
143                            request = new ProtectedServletRequest(
144                                    request, String.valueOf(userId),
145                                    HttpServletRequest.DIGEST_AUTH);
146    
147                            initThreadLocals(request);
148                    }
149                    else {
150                            try {
151                                    userId = PortalUtil.getDigestAuthUserId(request);
152                            }
153                            catch (Exception e) {
154                                    _log.error(e, e);
155                            }
156    
157                            if (userId > 0) {
158                                    request = setCredentials(
159                                            request, session, userId, HttpServletRequest.DIGEST_AUTH);
160                            }
161                            else {
162    
163                                    // Must generate a new nonce for each 401 (RFC2617, 3.2.1)
164    
165                                    long companyId = PortalInstances.getCompanyId(request);
166    
167                                    String remoteAddress = request.getRemoteAddr();
168    
169                                    String nonce = NonceUtil.generate(companyId, remoteAddress);
170    
171                                    StringBundler sb = new StringBundler(4);
172    
173                                    sb.append(_DIGEST_REALM);
174                                    sb.append(", nonce=\"");
175                                    sb.append(nonce);
176                                    sb.append("\"");
177    
178                                    response.setHeader(HttpHeaders.WWW_AUTHENTICATE, sb.toString());
179                                    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
180    
181                                    return null;
182                            }
183                    }
184    
185                    return request;
186            }
187    
188            protected void initThreadLocals(HttpServletRequest request)
189                    throws Exception {
190    
191                    HttpSession session = request.getSession();
192    
193                    User user = (User)session.getAttribute(WebKeys.USER);
194    
195                    CompanyThreadLocal.setCompanyId(user.getCompanyId());
196    
197                    PrincipalThreadLocal.setName(user.getUserId());
198                    PrincipalThreadLocal.setPassword(PortalUtil.getUserPassword(request));
199    
200                    if (!_usePermissionChecker) {
201                            return;
202                    }
203    
204                    PermissionChecker permissionChecker =
205                            PermissionCheckerFactoryUtil.create(user);
206    
207                    PermissionThreadLocal.setPermissionChecker(permissionChecker);
208            }
209    
210            @Override
211            protected void processFilter(
212                            HttpServletRequest request, HttpServletResponse response,
213                            FilterChain filterChain)
214                    throws Exception {
215    
216                    String remoteAddr = request.getRemoteAddr();
217    
218                    if (AuthSettingsUtil.isAccessAllowed(request, _hostsAllowed)) {
219                            if (_log.isDebugEnabled()) {
220                                    _log.debug("Access allowed for " + remoteAddr);
221                            }
222                    }
223                    else {
224                            if (_log.isWarnEnabled()) {
225                                    _log.warn("Access denied for " + remoteAddr);
226                            }
227    
228                            response.sendError(
229                                    HttpServletResponse.SC_FORBIDDEN,
230                                    "Access denied for " + remoteAddr);
231    
232                            return;
233                    }
234    
235                    if (_log.isDebugEnabled()) {
236                            if (_httpsRequired) {
237                                    _log.debug("https is required");
238                            }
239                            else {
240                                    _log.debug("https is not required");
241                            }
242                    }
243    
244                    if (_httpsRequired && !request.isSecure()) {
245                            if (_log.isDebugEnabled()) {
246                                    String completeURL = HttpUtil.getCompleteURL(request);
247    
248                                    _log.debug("Securing " + completeURL);
249                            }
250    
251                            StringBundler redirectURL = new StringBundler(5);
252    
253                            redirectURL.append(Http.HTTPS_WITH_SLASH);
254                            redirectURL.append(request.getServerName());
255                            redirectURL.append(request.getServletPath());
256    
257                            String queryString = request.getQueryString();
258    
259                            if (Validator.isNotNull(queryString)) {
260                                    redirectURL.append(StringPool.QUESTION);
261                                    redirectURL.append(request.getQueryString());
262                            }
263    
264                            if (_log.isDebugEnabled()) {
265                                    _log.debug("Redirect to " + redirectURL);
266                            }
267    
268                            response.sendRedirect(redirectURL.toString());
269                    }
270                    else {
271                            if (_log.isDebugEnabled()) {
272                                    String completeURL = HttpUtil.getCompleteURL(request);
273    
274                                    _log.debug("Not securing " + completeURL);
275                            }
276    
277                            User user = PortalUtil.getUser(request);
278    
279                            if ((user != null) && !user.isDefaultUser()) {
280                                    request = setCredentials(
281                                            request, request.getSession(), user.getUserId(), null);
282                            }
283                            else {
284                                    if (_digestAuthEnabled) {
285                                            request = digestAuth(request, response);
286                                    }
287                                    else if (_basicAuthEnabled) {
288                                            request = basicAuth(request, response);
289                                    }
290                            }
291    
292                            if (request != null) {
293                                    processFilter(getClass(), request, response, filterChain);
294                            }
295                    }
296            }
297    
298            protected HttpServletRequest setCredentials(
299                            HttpServletRequest request, HttpSession session, long userId,
300                            String authType)
301                    throws Exception {
302    
303                    User user = UserLocalServiceUtil.getUser(userId);
304    
305                    String userIdString = String.valueOf(userId);
306    
307                    request = new ProtectedServletRequest(request, userIdString, authType);
308    
309                    session.setAttribute(WebKeys.USER, user);
310                    session.setAttribute(_AUTHENTICATED_USER, userIdString);
311    
312                    initThreadLocals(request);
313    
314                    return request;
315            }
316    
317            protected void setUsePermissionChecker(boolean usePermissionChecker) {
318                    _usePermissionChecker = usePermissionChecker;
319            }
320    
321            private static final String _AUTHENTICATED_USER =
322                    SecureFilter.class + "_AUTHENTICATED_USER";
323    
324            private static final String _BASIC_REALM =
325                    "Basic realm=\"" + Portal.PORTAL_REALM + "\"";
326    
327            private static final String _DIGEST_REALM =
328                    "Digest realm=\"" + Portal.PORTAL_REALM + "\"";
329    
330            private static Log _log = LogFactoryUtil.getLog(SecureFilter.class);
331    
332            private boolean _basicAuthEnabled;
333            private boolean _digestAuthEnabled;
334            private Set<String> _hostsAllowed = new HashSet<String>();
335            private boolean _httpsRequired;
336            private boolean _usePermissionChecker;
337    
338    }