1   /**
2    * Copyright (c) 2000-2009 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.HttpHeaders;
28  import com.liferay.portal.kernel.servlet.ProtectedServletRequest;
29  import com.liferay.portal.kernel.util.Base64;
30  import com.liferay.portal.kernel.util.GetterUtil;
31  import com.liferay.portal.kernel.util.Http;
32  import com.liferay.portal.kernel.util.HttpUtil;
33  import com.liferay.portal.kernel.util.StringPool;
34  import com.liferay.portal.kernel.util.StringUtil;
35  import com.liferay.portal.kernel.util.Validator;
36  import com.liferay.portal.model.CompanyConstants;
37  import com.liferay.portal.service.UserLocalServiceUtil;
38  import com.liferay.portal.servlet.filters.BasePortalFilter;
39  import com.liferay.portal.util.PortalInstances;
40  import com.liferay.portal.util.PropsUtil;
41  import com.liferay.portal.util.PropsValues;
42  
43  import java.util.HashSet;
44  import java.util.Set;
45  
46  import javax.servlet.FilterChain;
47  import javax.servlet.FilterConfig;
48  import javax.servlet.http.HttpServletRequest;
49  import javax.servlet.http.HttpServletResponse;
50  import javax.servlet.http.HttpSession;
51  
52  /**
53   * <a href="SecureFilter.java.html"><b><i>View Source</i></b></a>
54   *
55   * @author Brian Wing Shun Chan
56   * @author Raymond Augé
57   * @author Alexander Chow
58   *
59   */
60  public class SecureFilter extends BasePortalFilter {
61  
62      public void init(FilterConfig filterConfig) {
63          super.init(filterConfig);
64  
65          _basicAuthEnabled = GetterUtil.getBoolean(
66              filterConfig.getInitParameter("basic_auth"));
67  
68          String propertyPrefix =
69              filterConfig.getInitParameter("portal_property_prefix");
70  
71          String[] hostsAllowedArray = null;
72  
73          if (Validator.isNull(propertyPrefix)) {
74              hostsAllowedArray = StringUtil.split(
75                  filterConfig.getInitParameter("hosts.allowed"));
76              _httpsRequired = GetterUtil.getBoolean(
77                  filterConfig.getInitParameter("https.required"));
78          }
79          else {
80              hostsAllowedArray = PropsUtil.getArray(
81                  propertyPrefix + "hosts.allowed");
82              _httpsRequired = GetterUtil.getBoolean(
83                  PropsUtil.get(propertyPrefix + "https.required"));
84          }
85  
86          for (int i = 0; i < hostsAllowedArray.length; i++) {
87              _hostsAllowed.add(hostsAllowedArray[i]);
88          }
89      }
90  
91      protected long getBasicAuthUserId(HttpServletRequest request)
92          throws Exception {
93  
94          long userId = 0;
95  
96          String authorizationHeader = request.getHeader(
97              HttpHeaders.AUTHORIZATION);
98  
99          if (Validator.isNull(authorizationHeader)) {
100             return userId;
101         }
102 
103         String[] authorizationArray = authorizationHeader.split("\\s+");
104 
105         String authorization = authorizationArray[0];
106         String credentials = new String(Base64.decode(authorizationArray[1]));
107 
108         if (!authorization.equalsIgnoreCase(HttpServletRequest.BASIC_AUTH)) {
109             return userId;
110         }
111 
112         long companyId = PortalInstances.getCompanyId(request);
113 
114         String[] loginAndPassword = StringUtil.split(
115             credentials, StringPool.COLON);
116 
117         String login = loginAndPassword[0].trim();
118 
119         String password = null;
120 
121         if (loginAndPassword.length > 1) {
122             password = loginAndPassword[1].trim();
123         }
124 
125         // Strip @uid and @sn for backwards compatibility
126 
127         if (login.endsWith("@uid")) {
128             int pos = login.indexOf("@uid");
129 
130             login = login.substring(0, pos);
131         }
132         else if (login.endsWith("@sn")) {
133             int pos = login.indexOf("@sn");
134 
135             login = login.substring(0, pos);
136         }
137 
138         // Try every authentication type
139 
140         userId = UserLocalServiceUtil.authenticateForBasic(
141             companyId, CompanyConstants.AUTH_TYPE_EA, login, password);
142 
143         if (userId > 0) {
144             return userId;
145         }
146 
147         userId = UserLocalServiceUtil.authenticateForBasic(
148             companyId, CompanyConstants.AUTH_TYPE_SN, login, password);
149 
150         if (userId > 0) {
151             return userId;
152         }
153 
154         userId = UserLocalServiceUtil.authenticateForBasic(
155             companyId, CompanyConstants.AUTH_TYPE_ID, login, password);
156 
157         return userId;
158     }
159 
160     protected boolean isAccessAllowed(HttpServletRequest request) {
161         String remoteAddr = request.getRemoteAddr();
162         String serverIp = request.getServerName();
163 
164         if ((_hostsAllowed.size() > 0) &&
165             (!_hostsAllowed.contains(remoteAddr))) {
166 
167             if ((serverIp.equals(remoteAddr)) &&
168                 (_hostsAllowed.contains(_SERVER_IP))) {
169 
170                 return true;
171             }
172 
173             return false;
174         }
175         else {
176             return true;
177         }
178     }
179 
180     protected void processFilter(
181             HttpServletRequest request, HttpServletResponse response,
182             FilterChain filterChain)
183         throws Exception {
184 
185         String remoteAddr = request.getRemoteAddr();
186 
187         if (isAccessAllowed(request)) {
188             if (_log.isDebugEnabled()) {
189                 _log.debug("Access allowed for " + remoteAddr);
190             }
191         }
192         else {
193             if (_log.isErrorEnabled()) {
194                 _log.error("Access denied for " + remoteAddr);
195             }
196 
197             response.sendError(
198                 HttpServletResponse.SC_FORBIDDEN,
199                 "Access denied for " + remoteAddr);
200 
201             return;
202         }
203 
204         if (_log.isDebugEnabled()) {
205             if (_httpsRequired) {
206                 _log.debug("https is required");
207             }
208             else {
209                 _log.debug("https is not required");
210             }
211         }
212 
213         if (_httpsRequired && !request.isSecure()) {
214             if (_log.isDebugEnabled()) {
215                 String completeURL = HttpUtil.getCompleteURL(request);
216 
217                 _log.debug("Securing " + completeURL);
218             }
219 
220             StringBuilder redirectURL = new StringBuilder();
221 
222             redirectURL.append(Http.HTTPS_WITH_SLASH);
223             redirectURL.append(request.getServerName());
224             redirectURL.append(request.getServletPath());
225 
226             String queryString = request.getQueryString();
227 
228             if (Validator.isNotNull(queryString)) {
229                 redirectURL.append(StringPool.QUESTION);
230                 redirectURL.append(request.getQueryString());
231             }
232 
233             if (_log.isDebugEnabled()) {
234                 _log.debug("Redirect to " + redirectURL);
235             }
236 
237             response.sendRedirect(redirectURL.toString());
238         }
239         else {
240             if (_log.isDebugEnabled()) {
241                 String completeURL = HttpUtil.getCompleteURL(request);
242 
243                 _log.debug("Not securing " + completeURL);
244             }
245 
246             // This basic authentication should only be run if specified by
247             // web.xml and JAAS is disabled. Make sure to run this once per
248             // session and wrap the request if necessary.
249 
250             HttpSession session = request.getSession();
251 
252             long userId = GetterUtil.getLong(
253                 (String)session.getAttribute(_AUTHENTICATED_USER));
254 
255             if (_basicAuthEnabled && !PropsValues.PORTAL_JAAS_ENABLE) {
256                 if (userId > 0) {
257                     request = new ProtectedServletRequest(
258                         request, String.valueOf(userId));
259                 }
260                 else {
261                     try {
262                         userId = getBasicAuthUserId(request);
263                     }
264                     catch (Exception e) {
265                         _log.error(e);
266                     }
267 
268                     if (userId > 0) {
269                         String userIdString = String.valueOf(userId);
270 
271                         request = new ProtectedServletRequest(
272                             request, userIdString);
273 
274                         session.setAttribute(_AUTHENTICATED_USER, userIdString);
275                     }
276                     else {
277                         response.setHeader(
278                             HttpHeaders.WWW_AUTHENTICATE, _PORTAL_REALM);
279                         response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
280 
281                         return;
282                     }
283                 }
284             }
285 
286             processFilter(SecureFilter.class, request, response, filterChain);
287         }
288     }
289 
290     private static final String _SERVER_IP = "SERVER_IP";
291 
292     private static final String _PORTAL_REALM = "Basic realm=\"PortalRealm\"";
293 
294     private static final String _AUTHENTICATED_USER =
295         SecureFilter.class + "_AUTHENTICATED_USER";
296 
297     private static Log _log = LogFactoryUtil.getLog(SecureFilter.class);
298 
299     private boolean _basicAuthEnabled;
300     private Set<String> _hostsAllowed = new HashSet<String>();
301     private boolean _httpsRequired;
302 
303 }