001    /**
002     * Copyright (c) 2000-present 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.CompanyThreadLocal;
030    import com.liferay.portal.security.auth.PrincipalThreadLocal;
031    import com.liferay.portal.security.permission.PermissionChecker;
032    import com.liferay.portal.security.permission.PermissionCheckerFactoryUtil;
033    import com.liferay.portal.security.permission.PermissionThreadLocal;
034    import com.liferay.portal.security.sso.SSOUtil;
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                    initThreadLocals(user);
196    
197                    PrincipalThreadLocal.setPassword(PortalUtil.getUserPassword(request));
198            }
199    
200            protected void initThreadLocals(User user) throws Exception {
201                    CompanyThreadLocal.setCompanyId(user.getCompanyId());
202    
203                    PrincipalThreadLocal.setName(user.getUserId());
204    
205                    if (!_usePermissionChecker) {
206                            return;
207                    }
208    
209                    PermissionChecker permissionChecker =
210                            PermissionThreadLocal.getPermissionChecker();
211    
212                    if (permissionChecker != null) {
213                            return;
214                    }
215    
216                    permissionChecker = PermissionCheckerFactoryUtil.create(user);
217    
218                    PermissionThreadLocal.setPermissionChecker(permissionChecker);
219            }
220    
221            @Override
222            protected void processFilter(
223                            HttpServletRequest request, HttpServletResponse response,
224                            FilterChain filterChain)
225                    throws Exception {
226    
227                    String remoteAddr = request.getRemoteAddr();
228    
229                    if (SSOUtil.isAccessAllowed(request, _hostsAllowed)) {
230                            if (_log.isDebugEnabled()) {
231                                    _log.debug("Access allowed for " + remoteAddr);
232                            }
233                    }
234                    else {
235                            if (_log.isWarnEnabled()) {
236                                    _log.warn("Access denied for " + remoteAddr);
237                            }
238    
239                            response.sendError(
240                                    HttpServletResponse.SC_FORBIDDEN,
241                                    "Access denied for " + remoteAddr);
242    
243                            return;
244                    }
245    
246                    if (_log.isDebugEnabled()) {
247                            if (_httpsRequired) {
248                                    _log.debug("https is required");
249                            }
250                            else {
251                                    _log.debug("https is not required");
252                            }
253                    }
254    
255                    if (_httpsRequired && !request.isSecure()) {
256                            if (_log.isDebugEnabled()) {
257                                    String completeURL = HttpUtil.getCompleteURL(request);
258    
259                                    _log.debug("Securing " + completeURL);
260                            }
261    
262                            StringBundler redirectURL = new StringBundler(5);
263    
264                            redirectURL.append(Http.HTTPS_WITH_SLASH);
265                            redirectURL.append(request.getServerName());
266                            redirectURL.append(request.getServletPath());
267    
268                            String queryString = request.getQueryString();
269    
270                            if (Validator.isNotNull(queryString)) {
271                                    redirectURL.append(StringPool.QUESTION);
272                                    redirectURL.append(request.getQueryString());
273                            }
274    
275                            if (_log.isDebugEnabled()) {
276                                    _log.debug("Redirect to " + redirectURL);
277                            }
278    
279                            response.sendRedirect(redirectURL.toString());
280                    }
281                    else {
282                            if (_log.isDebugEnabled()) {
283                                    String completeURL = HttpUtil.getCompleteURL(request);
284    
285                                    _log.debug("Not securing " + completeURL);
286                            }
287    
288                            User user = PortalUtil.getUser(request);
289    
290                            if (user == null) {
291                                    user = PortalUtil.initUser(request);
292                            }
293    
294                            initThreadLocals(user);
295    
296                            if (!user.isDefaultUser()) {
297                                    request = setCredentials(
298                                            request, request.getSession(), user.getUserId(), null);
299                            }
300                            else {
301                                    if (_digestAuthEnabled) {
302                                            request = digestAuth(request, response);
303                                    }
304                                    else if (_basicAuthEnabled) {
305                                            request = basicAuth(request, response);
306                                    }
307                            }
308    
309                            if (request != null) {
310                                    processFilter(getClass(), request, response, filterChain);
311                            }
312                    }
313            }
314    
315            protected HttpServletRequest setCredentials(
316                            HttpServletRequest request, HttpSession session, long userId,
317                            String authType)
318                    throws Exception {
319    
320                    User user = UserLocalServiceUtil.getUser(userId);
321    
322                    String userIdString = String.valueOf(userId);
323    
324                    request = new ProtectedServletRequest(request, userIdString, authType);
325    
326                    session.setAttribute(WebKeys.USER, user);
327                    session.setAttribute(_AUTHENTICATED_USER, userIdString);
328    
329                    initThreadLocals(request);
330    
331                    return request;
332            }
333    
334            protected void setUsePermissionChecker(boolean usePermissionChecker) {
335                    _usePermissionChecker = usePermissionChecker;
336            }
337    
338            private static final String _AUTHENTICATED_USER =
339                    SecureFilter.class + "_AUTHENTICATED_USER";
340    
341            private static final String _BASIC_REALM =
342                    "Basic realm=\"" + Portal.PORTAL_REALM + "\"";
343    
344            private static final String _DIGEST_REALM =
345                    "Digest realm=\"" + Portal.PORTAL_REALM + "\"";
346    
347            private static final Log _log = LogFactoryUtil.getLog(SecureFilter.class);
348    
349            private boolean _basicAuthEnabled;
350            private boolean _digestAuthEnabled;
351            private final Set<String> _hostsAllowed = new HashSet<>();
352            private boolean _httpsRequired;
353            private boolean _usePermissionChecker;
354    
355    }