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