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