1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17   * SOFTWARE.
18   */
19  
20  package com.liferay.portal.servlet.filters.secure;
21  
22  import com.liferay.portal.kernel.log.Log;
23  import com.liferay.portal.kernel.log.LogFactoryUtil;
24  import com.liferay.portal.kernel.servlet.HttpHeaders;
25  import com.liferay.portal.kernel.servlet.ProtectedServletRequest;
26  import com.liferay.portal.kernel.util.Base64;
27  import com.liferay.portal.kernel.util.GetterUtil;
28  import com.liferay.portal.kernel.util.Http;
29  import com.liferay.portal.kernel.util.HttpUtil;
30  import com.liferay.portal.kernel.util.StringPool;
31  import com.liferay.portal.kernel.util.StringUtil;
32  import com.liferay.portal.kernel.util.Validator;
33  import com.liferay.portal.model.CompanyConstants;
34  import com.liferay.portal.service.UserLocalServiceUtil;
35  import com.liferay.portal.servlet.filters.BasePortalFilter;
36  import com.liferay.portal.util.PortalInstances;
37  import com.liferay.portal.util.PropsUtil;
38  import com.liferay.portal.util.PropsValues;
39  
40  import java.io.IOException;
41  
42  import java.util.HashSet;
43  import java.util.Set;
44  
45  import javax.servlet.FilterChain;
46  import javax.servlet.FilterConfig;
47  import javax.servlet.ServletException;
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) throws ServletException {
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         String password = loginAndPassword[1].trim();
119 
120         // Strip @uid and @sn for backwards compatibility
121 
122         if (login.endsWith("@uid")) {
123             int pos = login.indexOf("@uid");
124 
125             login = login.substring(0, pos);
126         }
127         else if (login.endsWith("@sn")) {
128             int pos = login.indexOf("@sn");
129 
130             login = login.substring(0, pos);
131         }
132 
133         // Try every authentication type
134 
135         userId = UserLocalServiceUtil.authenticateForBasic(
136             companyId, CompanyConstants.AUTH_TYPE_EA, login, password);
137 
138         if (userId > 0) {
139             return userId;
140         }
141 
142         userId = UserLocalServiceUtil.authenticateForBasic(
143             companyId, CompanyConstants.AUTH_TYPE_SN, login, password);
144 
145         if (userId > 0) {
146             return userId;
147         }
148 
149         userId = UserLocalServiceUtil.authenticateForBasic(
150             companyId, CompanyConstants.AUTH_TYPE_ID, login, password);
151 
152         return userId;
153     }
154 
155     protected boolean isAccessAllowed(HttpServletRequest request) {
156         String remoteAddr = request.getRemoteAddr();
157         String serverIp = request.getServerName();
158 
159         if ((_hostsAllowed.size() > 0) &&
160             (!_hostsAllowed.contains(remoteAddr))) {
161 
162             if ((serverIp.equals(remoteAddr)) &&
163                 (_hostsAllowed.contains(_SERVER_IP))) {
164 
165                 return true;
166             }
167 
168             return false;
169         }
170         else {
171             return true;
172         }
173     }
174 
175     protected void processFilter(
176             HttpServletRequest request, HttpServletResponse response,
177             FilterChain filterChain)
178         throws IOException, ServletException {
179 
180         String remoteAddr = request.getRemoteAddr();
181 
182         if (isAccessAllowed(request)) {
183             if (_log.isDebugEnabled()) {
184                 _log.debug("Access allowed for " + remoteAddr);
185             }
186         }
187         else {
188             if (_log.isErrorEnabled()) {
189                 _log.error("Access denied for " + remoteAddr);
190             }
191 
192             response.sendError(
193                 HttpServletResponse.SC_FORBIDDEN,
194                 "Access denied for " + remoteAddr);
195 
196             return;
197         }
198 
199         if (_log.isDebugEnabled()) {
200             if (_httpsRequired) {
201                 _log.debug("https is required");
202             }
203             else {
204                 _log.debug("https is not required");
205             }
206         }
207 
208         String completeURL = HttpUtil.getCompleteURL(request);
209 
210         if (_httpsRequired && !request.isSecure()) {
211             if (_log.isDebugEnabled()) {
212                 _log.debug("Securing " + completeURL);
213             }
214 
215             StringBuilder redirectURL = new StringBuilder();
216 
217             redirectURL.append(Http.HTTPS_WITH_SLASH);
218             redirectURL.append(request.getServerName());
219             redirectURL.append(request.getServletPath());
220 
221             String queryString = request.getQueryString();
222 
223             if (Validator.isNotNull(queryString)) {
224                 redirectURL.append(StringPool.QUESTION);
225                 redirectURL.append(request.getQueryString());
226             }
227 
228             if (_log.isDebugEnabled()) {
229                 _log.debug("Redirect to " + redirectURL);
230             }
231 
232             response.sendRedirect(redirectURL.toString());
233         }
234         else {
235             if (_log.isDebugEnabled()) {
236                 _log.debug("Not securing " + completeURL);
237             }
238 
239             // This basic authentication should only be run if specified by
240             // web.xml and JAAS is disabled. Make sure to run this once per
241             // session and wrap the request if necessary.
242 
243             HttpSession session = request.getSession();
244 
245             long userId = GetterUtil.getLong(
246                 (String)session.getAttribute(_AUTHENTICATED_USER));
247 
248             if (_basicAuthEnabled && !PropsValues.PORTAL_JAAS_ENABLE) {
249                 if (userId > 0) {
250                     request = new ProtectedServletRequest(
251                         request, String.valueOf(userId));
252                 }
253                 else {
254                     try {
255                         userId = getBasicAuthUserId(request);
256                     }
257                     catch (Exception e) {
258                         _log.error(e);
259                     }
260 
261                     if (userId > 0) {
262                         String userIdString = String.valueOf(userId);
263 
264                         request = new ProtectedServletRequest(
265                             request, userIdString);
266 
267                         session.setAttribute(_AUTHENTICATED_USER, userIdString);
268                     }
269                     else {
270                         response.setHeader(
271                             HttpHeaders.WWW_AUTHENTICATE, _PORTAL_REALM);
272                         response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
273 
274                         return;
275                     }
276                 }
277             }
278 
279             processFilter(SecureFilter.class, request, response, filterChain);
280         }
281     }
282 
283     private static final String _SERVER_IP = "SERVER_IP";
284 
285     private static final String _PORTAL_REALM = "Basic realm=\"PortalRealm\"";
286 
287     private static final String _AUTHENTICATED_USER =
288         SecureFilter.class + "_AUTHENTICATED_USER";
289 
290     private static Log _log = LogFactoryUtil.getLog(SecureFilter.class);
291 
292     private boolean _basicAuthEnabled;
293     private Set<String> _hostsAllowed = new HashSet<String>();
294     private boolean _httpsRequired;
295 
296 }