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