001    /**
002     * Copyright (c) 2000-2012 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.PrincipalThreadLocal;
030    import com.liferay.portal.security.permission.PermissionChecker;
031    import com.liferay.portal.security.permission.PermissionCheckerFactoryUtil;
032    import com.liferay.portal.security.permission.PermissionThreadLocal;
033    import com.liferay.portal.service.UserLocalServiceUtil;
034    import com.liferay.portal.servlet.filters.BasePortalFilter;
035    import com.liferay.portal.util.Portal;
036    import com.liferay.portal.util.PortalInstances;
037    import com.liferay.portal.util.PortalUtil;
038    import com.liferay.portal.util.PropsUtil;
039    import com.liferay.portal.util.PropsValues;
040    import com.liferay.portal.util.WebKeys;
041    
042    import java.util.HashSet;
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    import javax.servlet.http.HttpSession;
050    
051    /**
052     * @author Brian Wing Shun Chan
053     * @author Raymond Augé
054     * @author Alexander Chow
055     */
056    public class SecureFilter extends BasePortalFilter {
057    
058            @Override
059            public void init(FilterConfig filterConfig) {
060                    super.init(filterConfig);
061    
062                    _basicAuthEnabled = GetterUtil.getBoolean(
063                            filterConfig.getInitParameter("basic_auth"));
064                    _digestAuthEnabled = GetterUtil.getBoolean(
065                            filterConfig.getInitParameter("digest_auth"));
066    
067                    String propertyPrefix =
068                            filterConfig.getInitParameter("portal_property_prefix");
069    
070                    String[] hostsAllowedArray = null;
071    
072                    if (Validator.isNull(propertyPrefix)) {
073                            hostsAllowedArray = StringUtil.split(
074                                    filterConfig.getInitParameter("hosts.allowed"));
075                            _httpsRequired = GetterUtil.getBoolean(
076                                    filterConfig.getInitParameter("https.required"));
077                    }
078                    else {
079                            hostsAllowedArray = PropsUtil.getArray(
080                                    propertyPrefix + "hosts.allowed");
081                            _httpsRequired = GetterUtil.getBoolean(
082                                    PropsUtil.get(propertyPrefix + "https.required"));
083                    }
084    
085                    for (int i = 0; i < hostsAllowedArray.length; i++) {
086                            _hostsAllowed.add(hostsAllowedArray[i]);
087                    }
088            }
089    
090            protected boolean isAccessAllowed(HttpServletRequest request) {
091                    if (_hostsAllowed.isEmpty()) {
092                            return true;
093                    }
094    
095                    String remoteAddr = request.getRemoteAddr();
096    
097                    if (_hostsAllowed.contains(remoteAddr)) {
098                            return true;
099                    }
100    
101                    String computerAddress = PortalUtil.getComputerAddress();
102    
103                    if (computerAddress.equals(remoteAddr) &&
104                            _hostsAllowed.contains(_SERVER_IP)) {
105    
106                            return true;
107                    }
108    
109                    return false;
110            }
111    
112            @Override
113            protected void processFilter(
114                            HttpServletRequest request, HttpServletResponse response,
115                            FilterChain filterChain)
116                    throws Exception {
117    
118                    String remoteAddr = request.getRemoteAddr();
119    
120                    if (isAccessAllowed(request)) {
121                            if (_log.isDebugEnabled()) {
122                                    _log.debug("Access allowed for " + remoteAddr);
123                            }
124                    }
125                    else {
126                            if (_log.isWarnEnabled()) {
127                                    _log.warn("Access denied for " + remoteAddr);
128                            }
129    
130                            response.sendError(
131                                    HttpServletResponse.SC_FORBIDDEN,
132                                    "Access denied for " + remoteAddr);
133    
134                            return;
135                    }
136    
137                    if (_log.isDebugEnabled()) {
138                            if (_httpsRequired) {
139                                    _log.debug("https is required");
140                            }
141                            else {
142                                    _log.debug("https is not required");
143                            }
144                    }
145    
146                    if (_httpsRequired && !request.isSecure()) {
147                            if (_log.isDebugEnabled()) {
148                                    String completeURL = HttpUtil.getCompleteURL(request);
149    
150                                    _log.debug("Securing " + completeURL);
151                            }
152    
153                            StringBundler redirectURL = new StringBundler(5);
154    
155                            redirectURL.append(Http.HTTPS_WITH_SLASH);
156                            redirectURL.append(request.getServerName());
157                            redirectURL.append(request.getServletPath());
158    
159                            String queryString = request.getQueryString();
160    
161                            if (Validator.isNotNull(queryString)) {
162                                    redirectURL.append(StringPool.QUESTION);
163                                    redirectURL.append(request.getQueryString());
164                            }
165    
166                            if (_log.isDebugEnabled()) {
167                                    _log.debug("Redirect to " + redirectURL);
168                            }
169    
170                            response.sendRedirect(redirectURL.toString());
171                    }
172                    else {
173                            if (_log.isDebugEnabled()) {
174                                    String completeURL = HttpUtil.getCompleteURL(request);
175    
176                                    _log.debug("Not securing " + completeURL);
177                            }
178    
179                            // This authentication should only be run if specified by web.xml
180                            // and JAAS is disabled. Make sure to run this once per session and
181                            // wrap the request if necessary.
182    
183                            if (!PropsValues.PORTAL_JAAS_ENABLE) {
184                                    User user = PortalUtil.getUser(request);
185    
186                                    if ((user != null) && !user.isDefaultUser()) {
187                                            request = setCredentials(
188                                                    request, request.getSession(), user.getUserId());
189                                    }
190                                    else {
191                                            if (_digestAuthEnabled) {
192                                                    request = digestAuth(request, response);
193                                            }
194                                            else if (_basicAuthEnabled) {
195                                                    request = basicAuth(request, response);
196                                            }
197                                    }
198                            }
199    
200                            if (request != null) {
201                                    processFilter(getClass(), request, response, filterChain);
202                            }
203                    }
204            }
205    
206            protected HttpServletRequest basicAuth(
207                            HttpServletRequest request, HttpServletResponse response)
208                    throws Exception {
209    
210                    HttpSession session = request.getSession();
211    
212                    session.setAttribute(WebKeys.BASIC_AUTH_ENABLED, Boolean.TRUE);
213    
214                    long userId = GetterUtil.getLong(
215                            (String)session.getAttribute(_AUTHENTICATED_USER));
216    
217                    if (userId > 0) {
218                            request = new ProtectedServletRequest(
219                                    request, String.valueOf(userId));
220                    }
221                    else {
222                            try {
223                                    userId = PortalUtil.getBasicAuthUserId(request);
224                            }
225                            catch (Exception e) {
226                                    _log.error(e, e);
227                            }
228    
229                            if (userId > 0) {
230                                    request = setCredentials(request, session, userId);
231                            }
232                            else {
233                                    response.setHeader(HttpHeaders.WWW_AUTHENTICATE, _BASIC_REALM);
234                                    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
235    
236                                    return null;
237                            }
238                    }
239    
240                    return request;
241            }
242    
243            protected HttpServletRequest digestAuth(
244                            HttpServletRequest request, HttpServletResponse response)
245                    throws Exception {
246    
247                    HttpSession session = request.getSession();
248    
249                    long userId = GetterUtil.getLong(
250                            (String)session.getAttribute(_AUTHENTICATED_USER));
251    
252                    if (userId > 0) {
253                            request = new ProtectedServletRequest(
254                                    request, String.valueOf(userId));
255                    }
256                    else {
257                            try {
258                                    userId = PortalUtil.getDigestAuthUserId(request);
259                            }
260                            catch (Exception e) {
261                                    _log.error(e, e);
262                            }
263    
264                            if (userId > 0) {
265                                    request = setCredentials(request, session, userId);
266                            }
267                            else {
268    
269                                    // Must generate a new nonce for each 401 (RFC2617, 3.2.1)
270    
271                                    long companyId = PortalInstances.getCompanyId(request);
272    
273                                    String remoteAddress = request.getRemoteAddr();
274    
275                                    String nonce = NonceUtil.generate(companyId, remoteAddress);
276    
277                                    StringBundler sb = new StringBundler(4);
278    
279                                    sb.append(_DIGEST_REALM);
280                                    sb.append(", nonce=\"");
281                                    sb.append(nonce);
282                                    sb.append("\"");
283    
284                                    response.setHeader(HttpHeaders.WWW_AUTHENTICATE, sb.toString());
285                                    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
286    
287                                    return null;
288                            }
289                    }
290    
291                    return request;
292            }
293    
294            protected HttpServletRequest setCredentials(
295                            HttpServletRequest request, HttpSession session, long userId)
296                    throws Exception {
297    
298                    User user = UserLocalServiceUtil.getUser(userId);
299    
300                    String userIdString = String.valueOf(userId);
301    
302                    request = new ProtectedServletRequest(request, userIdString);
303    
304                    session.setAttribute(WebKeys.USER, user);
305                    session.setAttribute(_AUTHENTICATED_USER, userIdString);
306    
307                    if (_usePermissionChecker) {
308                            PrincipalThreadLocal.setName(userId);
309                            PrincipalThreadLocal.setPassword(
310                                    PortalUtil.getUserPassword(request));
311    
312                            PermissionChecker permissionChecker =
313                                    PermissionCheckerFactoryUtil.create(user, false);
314    
315                            PermissionThreadLocal.setPermissionChecker(permissionChecker);
316                    }
317    
318                    return request;
319            }
320    
321            protected void setUsePermissionChecker(boolean usePermissionChecker) {
322                    _usePermissionChecker = usePermissionChecker;
323            }
324    
325            public static final String _AUTHENTICATED_USER =
326                    SecureFilter.class + "_AUTHENTICATED_USER";
327    
328            private static final String _BASIC_REALM =
329                    "Basic realm=\"" + Portal.PORTAL_REALM + "\"";
330    
331            private static final String _DIGEST_REALM =
332                    "Digest realm=\"" + Portal.PORTAL_REALM + "\"";
333    
334            private static final String _SERVER_IP = "SERVER_IP";
335    
336            private static Log _log = LogFactoryUtil.getLog(SecureFilter.class);
337    
338            private boolean _basicAuthEnabled;
339            private boolean _digestAuthEnabled;
340            private Set<String> _hostsAllowed = new HashSet<String>();
341            private boolean _httpsRequired;
342            private boolean _usePermissionChecker;
343    
344    }