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.authverifier;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.kernel.security.access.control.AccessControlUtil;
020    import com.liferay.portal.kernel.security.auth.verifier.AuthVerifierResult;
021    import com.liferay.portal.kernel.servlet.ProtectedServletRequest;
022    import com.liferay.portal.kernel.util.GetterUtil;
023    import com.liferay.portal.kernel.util.Http;
024    import com.liferay.portal.kernel.util.HttpUtil;
025    import com.liferay.portal.kernel.util.MapUtil;
026    import com.liferay.portal.kernel.util.StringBundler;
027    import com.liferay.portal.kernel.util.StringPool;
028    import com.liferay.portal.kernel.util.StringUtil;
029    import com.liferay.portal.kernel.util.Validator;
030    import com.liferay.portal.security.auth.AccessControlContext;
031    import com.liferay.portal.security.auth.AuthVerifierPipeline;
032    import com.liferay.portal.servlet.filters.BasePortalFilter;
033    import com.liferay.portal.util.PropsUtil;
034    
035    import java.io.IOException;
036    
037    import java.util.Enumeration;
038    import java.util.HashMap;
039    import java.util.HashSet;
040    import java.util.Map;
041    import java.util.Properties;
042    import java.util.Set;
043    
044    import javax.servlet.FilterChain;
045    import javax.servlet.FilterConfig;
046    import javax.servlet.http.HttpServletRequest;
047    import javax.servlet.http.HttpServletResponse;
048    
049    /**
050     * <p>
051     * See https://issues.liferay.com/browse/LPS-27888.
052     * </p>
053     *
054     * @author Tomas Polesovsky
055     * @author Raymond Aug??
056     */
057    public class AuthVerifierFilter extends BasePortalFilter {
058    
059            @Override
060            public void init(FilterConfig filterConfig) {
061                    super.init(filterConfig);
062    
063                    Enumeration<String> enu = filterConfig.getInitParameterNames();
064    
065                    while (enu.hasMoreElements()) {
066                            String name = enu.nextElement();
067    
068                            String value = filterConfig.getInitParameter(name);
069    
070                            _initParametersMap.put(name, value);
071                    }
072    
073                    String portalPropertyPrefix = GetterUtil.getString(
074                            _initParametersMap.get("portal_property_prefix"));
075    
076                    if (Validator.isNotNull(portalPropertyPrefix)) {
077                            Properties properties = PropsUtil.getProperties(
078                                    portalPropertyPrefix, true);
079    
080                            for (Object name : properties.keySet()) {
081                                    Object value = properties.get(name);
082    
083                                    _initParametersMap.put((String)name, value);
084                            }
085                    }
086    
087                    if (_initParametersMap.containsKey("hosts.allowed")) {
088                            String hostsAllowedString = (String)_initParametersMap.get(
089                                    "hosts.allowed");
090    
091                            String[] hostsAllowed = StringUtil.split(hostsAllowedString);
092    
093                            for (String hostAllowed : hostsAllowed) {
094                                    _hostsAllowed.add(hostAllowed);
095                            }
096    
097                            _initParametersMap.remove("hosts.allowed");
098                    }
099    
100                    if (_initParametersMap.containsKey("https.required")) {
101                            _httpsRequired = GetterUtil.getBoolean(
102                                    _initParametersMap.get("https.required"));
103    
104                            _initParametersMap.remove("https.required");
105                    }
106    
107                    if (_initParametersMap.containsKey("use_permission_checker")) {
108                            _initParametersMap.remove("use_permission_checker");
109    
110                            if (_log.isWarnEnabled()) {
111                                    _log.warn("use_permission_checker is deprecated");
112                            }
113                    }
114            }
115    
116            @Override
117            protected void processFilter(
118                            HttpServletRequest request, HttpServletResponse response,
119                            FilterChain filterChain)
120                    throws Exception {
121    
122                    if (!_isAccessAllowed(request, response)) {
123                            return;
124                    }
125    
126                    if (_isApplySSL(request, response)) {
127                            return;
128                    }
129    
130                    AccessControlUtil.initAccessControlContext(
131                            request, response, _initParametersMap);
132    
133                    AuthVerifierResult.State state = AccessControlUtil.verifyRequest();
134    
135                    AccessControlContext accessControlContext =
136                            AccessControlUtil.getAccessControlContext();
137    
138                    AuthVerifierResult authVerifierResult =
139                            accessControlContext.getAuthVerifierResult();
140    
141                    if (_log.isDebugEnabled()) {
142                            _log.debug("Auth verifier result " + authVerifierResult);
143                    }
144    
145                    if (state == AuthVerifierResult.State.INVALID_CREDENTIALS) {
146                            if (_log.isDebugEnabled()) {
147                                    _log.debug("Result state doesn't allow us to continue.");
148                            }
149                    }
150                    else if (state == AuthVerifierResult.State.NOT_APPLICABLE) {
151                            _log.error("Invalid state " + state);
152                    }
153                    else if (state == AuthVerifierResult.State.SUCCESS) {
154                            long userId = authVerifierResult.getUserId();
155    
156                            AccessControlUtil.initContextUser(userId);
157    
158                            String authType = MapUtil.getString(
159                                    accessControlContext.getSettings(),
160                                    AuthVerifierPipeline.AUTH_TYPE);
161    
162                            ProtectedServletRequest protectedServletRequest =
163                                    new ProtectedServletRequest(
164                                            request, String.valueOf(userId), authType);
165    
166                            accessControlContext.setRequest(protectedServletRequest);
167    
168                            Class<?> clazz = getClass();
169    
170                            processFilter(
171                                    clazz.getName(), protectedServletRequest, response,
172                                    filterChain);
173                    }
174                    else {
175                            _log.error("Unimplemented state " + state);
176                    }
177            }
178    
179            private boolean _isAccessAllowed(
180                            HttpServletRequest request, HttpServletResponse response)
181                    throws IOException {
182    
183                    String remoteAddr = request.getRemoteAddr();
184    
185                    if (AccessControlUtil.isAccessAllowed(request, _hostsAllowed)) {
186                            if (_log.isDebugEnabled()) {
187                                    _log.debug("Access allowed for " + remoteAddr);
188                            }
189    
190                            return true;
191                    }
192    
193                    if (_log.isWarnEnabled()) {
194                            _log.warn("Access denied for " + remoteAddr);
195                    }
196    
197                    response.sendError(
198                            HttpServletResponse.SC_FORBIDDEN,
199                            "Access denied for " + remoteAddr);
200    
201                    return false;
202            }
203    
204            private boolean _isApplySSL(
205                            HttpServletRequest request, HttpServletResponse response)
206                    throws IOException {
207    
208                    if (!_httpsRequired || request.isSecure()) {
209                            return false;
210                    }
211    
212                    if (_log.isDebugEnabled()) {
213                            String completeURL = HttpUtil.getCompleteURL(request);
214    
215                            _log.debug("Securing " + completeURL);
216                    }
217    
218                    StringBundler redirectURL = new StringBundler(5);
219    
220                    redirectURL.append(Http.HTTPS_WITH_SLASH);
221                    redirectURL.append(request.getServerName());
222                    redirectURL.append(request.getServletPath());
223    
224                    String queryString = request.getQueryString();
225    
226                    if (Validator.isNotNull(queryString)) {
227                            redirectURL.append(StringPool.QUESTION);
228                            redirectURL.append(request.getQueryString());
229                    }
230    
231                    if (_log.isDebugEnabled()) {
232                            _log.debug("Redirect to " + redirectURL);
233                    }
234    
235                    response.sendRedirect(redirectURL.toString());
236    
237                    return true;
238            }
239    
240            private static final Log _log = LogFactoryUtil.getLog(
241                    AuthVerifierFilter.class.getName());
242    
243            private final Set<String> _hostsAllowed = new HashSet<>();
244            private boolean _httpsRequired;
245            private final Map<String, Object> _initParametersMap = new HashMap<>();
246    
247    }