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 = filterConfig.getInitParameter(
068                            "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 HttpServletRequest basicAuth(
091                            HttpServletRequest request, HttpServletResponse response)
092                    throws Exception {
093    
094                    HttpSession session = request.getSession();
095    
096                    session.setAttribute(WebKeys.BASIC_AUTH_ENABLED, Boolean.TRUE);
097    
098                    long userId = GetterUtil.getLong(
099                            (String)session.getAttribute(_AUTHENTICATED_USER));
100    
101                    if (userId > 0) {
102                            request = new ProtectedServletRequest(
103                                    request, String.valueOf(userId));
104                    }
105                    else {
106                            try {
107                                    userId = PortalUtil.getBasicAuthUserId(request);
108                            }
109                            catch (Exception e) {
110                                    _log.error(e, e);
111                            }
112    
113                            if (userId > 0) {
114                                    request = setCredentials(request, session, userId);
115                            }
116                            else {
117                                    response.setHeader(HttpHeaders.WWW_AUTHENTICATE, _BASIC_REALM);
118                                    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
119    
120                                    return null;
121                            }
122                    }
123    
124                    return request;
125            }
126    
127            protected HttpServletRequest digestAuth(
128                            HttpServletRequest request, HttpServletResponse response)
129                    throws Exception {
130    
131                    HttpSession session = request.getSession();
132    
133                    long userId = GetterUtil.getLong(
134                            (String)session.getAttribute(_AUTHENTICATED_USER));
135    
136                    if (userId > 0) {
137                            request = new ProtectedServletRequest(
138                                    request, String.valueOf(userId));
139                    }
140                    else {
141                            try {
142                                    userId = PortalUtil.getDigestAuthUserId(request);
143                            }
144                            catch (Exception e) {
145                                    _log.error(e, e);
146                            }
147    
148                            if (userId > 0) {
149                                    request = setCredentials(request, session, userId);
150                            }
151                            else {
152    
153                                    // Must generate a new nonce for each 401 (RFC2617, 3.2.1)
154    
155                                    long companyId = PortalInstances.getCompanyId(request);
156    
157                                    String remoteAddress = request.getRemoteAddr();
158    
159                                    String nonce = NonceUtil.generate(companyId, remoteAddress);
160    
161                                    StringBundler sb = new StringBundler(4);
162    
163                                    sb.append(_DIGEST_REALM);
164                                    sb.append(", nonce=\"");
165                                    sb.append(nonce);
166                                    sb.append("\"");
167    
168                                    response.setHeader(HttpHeaders.WWW_AUTHENTICATE, sb.toString());
169                                    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
170    
171                                    return null;
172                            }
173                    }
174    
175                    return request;
176            }
177    
178            protected boolean isAccessAllowed(HttpServletRequest request) {
179                    if (_hostsAllowed.isEmpty()) {
180                            return true;
181                    }
182    
183                    String remoteAddr = request.getRemoteAddr();
184    
185                    if (_hostsAllowed.contains(remoteAddr)) {
186                            return true;
187                    }
188    
189                    String computerAddress = PortalUtil.getComputerAddress();
190    
191                    if (computerAddress.equals(remoteAddr) &&
192                            _hostsAllowed.contains(_SERVER_IP)) {
193    
194                            return true;
195                    }
196    
197                    return false;
198            }
199    
200            @Override
201            protected void processFilter(
202                            HttpServletRequest request, HttpServletResponse response,
203                            FilterChain filterChain)
204                    throws Exception {
205    
206                    String remoteAddr = request.getRemoteAddr();
207    
208                    if (isAccessAllowed(request)) {
209                            if (_log.isDebugEnabled()) {
210                                    _log.debug("Access allowed for " + remoteAddr);
211                            }
212                    }
213                    else {
214                            if (_log.isWarnEnabled()) {
215                                    _log.warn("Access denied for " + remoteAddr);
216                            }
217    
218                            response.sendError(
219                                    HttpServletResponse.SC_FORBIDDEN,
220                                    "Access denied for " + remoteAddr);
221    
222                            return;
223                    }
224    
225                    if (_log.isDebugEnabled()) {
226                            if (_httpsRequired) {
227                                    _log.debug("https is required");
228                            }
229                            else {
230                                    _log.debug("https is not required");
231                            }
232                    }
233    
234                    if (_httpsRequired && !request.isSecure()) {
235                            if (_log.isDebugEnabled()) {
236                                    String completeURL = HttpUtil.getCompleteURL(request);
237    
238                                    _log.debug("Securing " + completeURL);
239                            }
240    
241                            StringBundler redirectURL = new StringBundler(5);
242    
243                            redirectURL.append(Http.HTTPS_WITH_SLASH);
244                            redirectURL.append(request.getServerName());
245                            redirectURL.append(request.getServletPath());
246    
247                            String queryString = request.getQueryString();
248    
249                            if (Validator.isNotNull(queryString)) {
250                                    redirectURL.append(StringPool.QUESTION);
251                                    redirectURL.append(request.getQueryString());
252                            }
253    
254                            if (_log.isDebugEnabled()) {
255                                    _log.debug("Redirect to " + redirectURL);
256                            }
257    
258                            response.sendRedirect(redirectURL.toString());
259                    }
260                    else {
261                            if (_log.isDebugEnabled()) {
262                                    String completeURL = HttpUtil.getCompleteURL(request);
263    
264                                    _log.debug("Not securing " + completeURL);
265                            }
266    
267                            // This authentication should only be run if specified by web.xml
268                            // and JAAS is disabled. Make sure to run this once per session and
269                            // wrap the request if necessary.
270    
271                            if (!PropsValues.PORTAL_JAAS_ENABLE) {
272                                    User user = PortalUtil.getUser(request);
273    
274                                    if ((user != null) && !user.isDefaultUser()) {
275                                            request = setCredentials(
276                                                    request, request.getSession(), user.getUserId());
277                                    }
278                                    else {
279                                            if (_digestAuthEnabled) {
280                                                    request = digestAuth(request, response);
281                                            }
282                                            else if (_basicAuthEnabled) {
283                                                    request = basicAuth(request, response);
284                                            }
285                                    }
286                            }
287    
288                            if (request != null) {
289                                    processFilter(getClass(), request, response, filterChain);
290                            }
291                    }
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);
314    
315                            PermissionThreadLocal.setPermissionChecker(permissionChecker);
316                    }
317    
318                    return request;
319            }
320    
321            protected void setUsePermissionChecker(boolean usePermissionChecker) {
322                    _usePermissionChecker = usePermissionChecker;
323            }
324    
325            private 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    }