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