1   /**
2    * Copyright (c) 2000-2008 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.servlet.filters.secure;
24  
25  import com.liferay.portal.kernel.log.Log;
26  import com.liferay.portal.kernel.log.LogFactoryUtil;
27  import com.liferay.portal.kernel.servlet.BaseFilter;
28  import com.liferay.portal.kernel.servlet.HttpHeaders;
29  import com.liferay.portal.kernel.servlet.ProtectedServletRequest;
30  import com.liferay.portal.kernel.util.Base64;
31  import com.liferay.portal.kernel.util.GetterUtil;
32  import com.liferay.portal.kernel.util.Http;
33  import com.liferay.portal.kernel.util.HttpUtil;
34  import com.liferay.portal.kernel.util.StringMaker;
35  import com.liferay.portal.kernel.util.StringPool;
36  import com.liferay.portal.kernel.util.StringUtil;
37  import com.liferay.portal.kernel.util.Validator;
38  import com.liferay.portal.model.Company;
39  import com.liferay.portal.model.CompanyConstants;
40  import com.liferay.portal.service.CompanyLocalServiceUtil;
41  import com.liferay.portal.service.UserLocalServiceUtil;
42  import com.liferay.portal.util.PortalInstances;
43  import com.liferay.portal.util.PropsUtil;
44  import com.liferay.portal.util.PropsValues;
45  
46  import java.io.IOException;
47  
48  import java.util.HashSet;
49  import java.util.Set;
50  
51  import javax.servlet.FilterChain;
52  import javax.servlet.FilterConfig;
53  import javax.servlet.ServletException;
54  import javax.servlet.ServletRequest;
55  import javax.servlet.ServletResponse;
56  import javax.servlet.http.HttpServletRequest;
57  import javax.servlet.http.HttpServletResponse;
58  import javax.servlet.http.HttpSession;
59  
60  /**
61   * <a href="SecureFilter.java.html"><b><i>View Source</i></b></a>
62   *
63   * @author Brian Wing Shun Chan
64   * @author Raymond Aug�
65   * @author Alexander Chow
66   *
67   */
68  public class SecureFilter extends BaseFilter {
69  
70      public void init(FilterConfig config) throws ServletException {
71          super.init(config);
72  
73          _basicAuthEnabled = GetterUtil.getBoolean(
74              config.getInitParameter("basic_auth"));
75  
76          String propertyPrefix =
77              config.getInitParameter("portal_property_prefix");
78  
79          String[] hostsAllowedArray = null;
80  
81          if (Validator.isNull(propertyPrefix)) {
82              hostsAllowedArray = StringUtil.split(
83                  config.getInitParameter("hosts.allowed"));
84              _httpsRequired = GetterUtil.getBoolean(
85                  config.getInitParameter("https.required"));
86          }
87          else {
88              hostsAllowedArray = PropsUtil.getArray(
89                  propertyPrefix + "hosts.allowed");
90              _httpsRequired = GetterUtil.getBoolean(
91                  PropsUtil.get(propertyPrefix + "https.required"));
92          }
93  
94          for (int i = 0; i < hostsAllowedArray.length; i++) {
95              _hostsAllowed.add(hostsAllowedArray[i]);
96          }
97      }
98  
99      public void doFilter(
100             ServletRequest req, ServletResponse res, FilterChain chain)
101         throws IOException, ServletException {
102 
103         HttpServletRequest httpReq = (HttpServletRequest)req;
104         HttpServletResponse httpRes = (HttpServletResponse)res;
105 
106         String remoteAddr = httpReq.getRemoteAddr();
107 
108         if (isAccessAllowed(httpReq)) {
109             if (_log.isDebugEnabled()) {
110                 _log.debug("Access allowed for " + remoteAddr);
111             }
112         }
113         else {
114             if (_log.isErrorEnabled()) {
115                 _log.error("Access denied for " + remoteAddr);
116             }
117 
118             httpRes.sendError(
119                 HttpServletResponse.SC_FORBIDDEN,
120                 "Access denied for " + remoteAddr);
121 
122             return;
123         }
124 
125         if (_log.isDebugEnabled()) {
126             if (_httpsRequired) {
127                 _log.debug("https is required");
128             }
129             else {
130                 _log.debug("https is not required");
131             }
132         }
133 
134         String completeURL = HttpUtil.getCompleteURL(httpReq);
135 
136         if (_httpsRequired && !httpReq.isSecure()) {
137             if (_log.isDebugEnabled()) {
138                 _log.debug("Securing " + completeURL);
139             }
140 
141             StringMaker redirectURL = new StringMaker();
142 
143             redirectURL.append(Http.HTTPS_WITH_SLASH);
144             redirectURL.append(httpReq.getServerName());
145             redirectURL.append(httpReq.getServletPath());
146 
147             String queryString = httpReq.getQueryString();
148 
149             if (Validator.isNotNull(queryString)) {
150                 redirectURL.append(StringPool.QUESTION);
151                 redirectURL.append(httpReq.getQueryString());
152             }
153 
154             if (_log.isDebugEnabled()) {
155                 _log.debug("Redirect to " + redirectURL);
156             }
157 
158             httpRes.sendRedirect(redirectURL.toString());
159         }
160         else {
161             if (_log.isDebugEnabled()) {
162                 _log.debug("Not securing " + completeURL);
163             }
164 
165             // This basic authentication should only be run if specified by
166             // web.xml and JAAS is disabled. Make sure to run this once per
167             // session and wrap the request if necessary.
168 
169             HttpSession ses = httpReq.getSession();
170 
171             long userId = GetterUtil.getLong(
172                 (String)ses.getAttribute(_AUTHENTICATED_USER));
173 
174             if (_basicAuthEnabled && !PropsValues.PORTAL_JAAS_ENABLE) {
175                 if (userId > 0) {
176                     req = new ProtectedServletRequest(
177                         httpReq, String.valueOf(userId));
178                 }
179                 else {
180                     try {
181                         userId = getBasicAuthUserId(httpReq);
182                     }
183                     catch (Exception e) {
184                         _log.error(e);
185                     }
186 
187                     if (userId > 0) {
188                         String userIdString = String.valueOf(userId);
189 
190                         req = new ProtectedServletRequest(
191                             httpReq, userIdString);
192 
193                         ses.setAttribute(_AUTHENTICATED_USER, userIdString);
194                     }
195                     else {
196                         httpRes.setHeader(
197                             HttpHeaders.WWW_AUTHENTICATE, _PORTAL_REALM);
198                         httpRes.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
199 
200                         return;
201                     }
202                 }
203             }
204 
205             doFilter(SecureFilter.class, req, res, chain);
206         }
207     }
208 
209     protected long getBasicAuthUserId(HttpServletRequest req) throws Exception {
210         long userId = 0;
211 
212         String authorizationHeader = req.getHeader(HttpHeaders.AUTHORIZATION);
213 
214         if (Validator.isNull(authorizationHeader)) {
215             return userId;
216         }
217 
218         String[] authorizationArray = authorizationHeader.split("\\s+");
219 
220         String authorization = authorizationArray[0];
221         String credentials = new String(Base64.decode(authorizationArray[1]));
222 
223         if (!authorization.equalsIgnoreCase(HttpServletRequest.BASIC_AUTH)) {
224             return userId;
225         }
226 
227         long companyId = PortalInstances.getCompanyId(req);
228 
229         Company company = CompanyLocalServiceUtil.getCompanyById(companyId);
230 
231         String authType = company.getAuthType();
232 
233         String[] loginAndPassword = StringUtil.split(
234             credentials, StringPool.COLON);
235 
236         String login = loginAndPassword[0].trim();
237         String password = loginAndPassword[1].trim();
238 
239         if (login.endsWith("@uid")) {
240             authType = CompanyConstants.AUTH_TYPE_ID;
241 
242             int pos = login.indexOf("@uid");
243 
244             login = login.substring(0, pos);
245         }
246         else if (login.endsWith("@sn")) {
247             authType = CompanyConstants.AUTH_TYPE_SN;
248 
249             int pos = login.indexOf("@sn");
250 
251             login = login.substring(0, pos);
252         }
253 
254         userId = UserLocalServiceUtil.authenticateForBasic(
255             companyId, authType, login, password);
256 
257         return userId;
258     }
259 
260     protected boolean isAccessAllowed(HttpServletRequest req) {
261         String remoteAddr = req.getRemoteAddr();
262         String serverIp = req.getServerName();
263 
264         if ((_hostsAllowed.size() > 0) &&
265             (!_hostsAllowed.contains(remoteAddr))) {
266 
267             if ((serverIp.equals(remoteAddr)) &&
268                 (_hostsAllowed.contains(_SERVER_IP))) {
269 
270                 return true;
271             }
272 
273             return false;
274         }
275         else {
276             return true;
277         }
278     }
279 
280     private static final String _SERVER_IP = "SERVER_IP";
281 
282     private static final String _PORTAL_REALM = "Basic realm=\"PortalRealm\"";
283 
284     private static final String _AUTHENTICATED_USER =
285         SecureFilter.class + "_AUTHENTICATED_USER";
286 
287     private static Log _log = LogFactoryUtil.getLog(SecureFilter.class);
288 
289     private boolean _basicAuthEnabled;
290     private Set<String> _hostsAllowed = new HashSet<String>();
291     private boolean _httpsRequired;
292 
293 }