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