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.AccessControlContext;
021    import com.liferay.portal.kernel.security.auth.verifier.AuthVerifierResult;
022    import com.liferay.portal.kernel.servlet.ProtectedServletRequest;
023    import com.liferay.portal.kernel.util.GetterUtil;
024    import com.liferay.portal.kernel.util.Http;
025    import com.liferay.portal.kernel.util.HttpUtil;
026    import com.liferay.portal.kernel.util.MapUtil;
027    import com.liferay.portal.kernel.util.StringBundler;
028    import com.liferay.portal.kernel.util.StringPool;
029    import com.liferay.portal.kernel.util.StringUtil;
030    import com.liferay.portal.kernel.util.Validator;
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 (Map.Entry<Object, Object> entry : properties.entrySet()) {
081                                    _initParametersMap.put(
082                                            (String)entry.getKey(), entry.getValue());
083                            }
084                    }
085    
086                    if (_initParametersMap.containsKey("hosts.allowed")) {
087                            String hostsAllowedString = (String)_initParametersMap.get(
088                                    "hosts.allowed");
089    
090                            String[] hostsAllowed = StringUtil.split(hostsAllowedString);
091    
092                            for (String hostAllowed : hostsAllowed) {
093                                    _hostsAllowed.add(hostAllowed);
094                            }
095    
096                            _initParametersMap.remove("hosts.allowed");
097                    }
098    
099                    if (_initParametersMap.containsKey("https.required")) {
100                            _httpsRequired = GetterUtil.getBoolean(
101                                    _initParametersMap.get("https.required"));
102    
103                            _initParametersMap.remove("https.required");
104                    }
105    
106                    if (_initParametersMap.containsKey("use_permission_checker")) {
107                            _initParametersMap.remove("use_permission_checker");
108    
109                            if (_log.isWarnEnabled()) {
110                                    _log.warn("use_permission_checker is deprecated");
111                            }
112                    }
113            }
114    
115            @Override
116            protected void processFilter(
117                            HttpServletRequest request, HttpServletResponse response,
118                            FilterChain filterChain)
119                    throws Exception {
120    
121                    if (!_isAccessAllowed(request, response)) {
122                            return;
123                    }
124    
125                    if (_isApplySSL(request, response)) {
126                            return;
127                    }
128    
129                    AccessControlUtil.initAccessControlContext(
130                            request, response, _initParametersMap);
131    
132                    AuthVerifierResult.State state = AccessControlUtil.verifyRequest();
133    
134                    AccessControlContext accessControlContext =
135                            AccessControlUtil.getAccessControlContext();
136    
137                    AuthVerifierResult authVerifierResult =
138                            accessControlContext.getAuthVerifierResult();
139    
140                    if (_log.isDebugEnabled()) {
141                            _log.debug("Auth verifier result " + authVerifierResult);
142                    }
143    
144                    if (state == AuthVerifierResult.State.INVALID_CREDENTIALS) {
145                            if (_log.isDebugEnabled()) {
146                                    _log.debug("Result state doesn't allow us to continue.");
147                            }
148                    }
149                    else if (state == AuthVerifierResult.State.NOT_APPLICABLE) {
150                            _log.error("Invalid state " + state);
151                    }
152                    else if (state == AuthVerifierResult.State.SUCCESS) {
153                            long userId = authVerifierResult.getUserId();
154    
155                            AccessControlUtil.initContextUser(userId);
156    
157                            String authType = MapUtil.getString(
158                                    accessControlContext.getSettings(),
159                                    AuthVerifierPipeline.AUTH_TYPE);
160    
161                            ProtectedServletRequest protectedServletRequest =
162                                    new ProtectedServletRequest(
163                                            request, String.valueOf(userId), authType);
164    
165                            accessControlContext.setRequest(protectedServletRequest);
166    
167                            Class<?> clazz = getClass();
168    
169                            processFilter(
170                                    clazz.getName(), protectedServletRequest, response,
171                                    filterChain);
172                    }
173                    else {
174                            _log.error("Unimplemented state " + state);
175                    }
176            }
177    
178            private boolean _isAccessAllowed(
179                            HttpServletRequest request, HttpServletResponse response)
180                    throws IOException {
181    
182                    String remoteAddr = request.getRemoteAddr();
183    
184                    if (AccessControlUtil.isAccessAllowed(request, _hostsAllowed)) {
185                            if (_log.isDebugEnabled()) {
186                                    _log.debug("Access allowed for " + remoteAddr);
187                            }
188    
189                            return true;
190                    }
191    
192                    if (_log.isWarnEnabled()) {
193                            _log.warn("Access denied for " + remoteAddr);
194                    }
195    
196                    response.sendError(
197                            HttpServletResponse.SC_FORBIDDEN,
198                            "Access denied for " + remoteAddr);
199    
200                    return false;
201            }
202    
203            private boolean _isApplySSL(
204                            HttpServletRequest request, HttpServletResponse response)
205                    throws IOException {
206    
207                    if (!_httpsRequired || request.isSecure()) {
208                            return false;
209                    }
210    
211                    if (_log.isDebugEnabled()) {
212                            String completeURL = HttpUtil.getCompleteURL(request);
213    
214                            _log.debug("Securing " + completeURL);
215                    }
216    
217                    StringBundler redirectURL = new StringBundler(5);
218    
219                    redirectURL.append(Http.HTTPS_WITH_SLASH);
220                    redirectURL.append(request.getServerName());
221                    redirectURL.append(request.getServletPath());
222    
223                    String queryString = request.getQueryString();
224    
225                    if (Validator.isNotNull(queryString)) {
226                            redirectURL.append(StringPool.QUESTION);
227                            redirectURL.append(request.getQueryString());
228                    }
229    
230                    if (_log.isDebugEnabled()) {
231                            _log.debug("Redirect to " + redirectURL);
232                    }
233    
234                    response.sendRedirect(redirectURL.toString());
235    
236                    return true;
237            }
238    
239            private static final Log _log = LogFactoryUtil.getLog(
240                    AuthVerifierFilter.class.getName());
241    
242            private final Set<String> _hostsAllowed = new HashSet<>();
243            private boolean _httpsRequired;
244            private final Map<String, Object> _initParametersMap = new HashMap<>();
245    
246    }