1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portal.servlet.filters.sso.ntlm;
16  
17  import com.liferay.portal.kernel.exception.SystemException;
18  import com.liferay.portal.kernel.log.Log;
19  import com.liferay.portal.kernel.log.LogFactoryUtil;
20  import com.liferay.portal.kernel.servlet.HttpHeaders;
21  import com.liferay.portal.kernel.util.GetterUtil;
22  import com.liferay.portal.kernel.util.PropsKeys;
23  import com.liferay.portal.kernel.util.Validator;
24  import com.liferay.portal.security.ldap.LDAPSettingsUtil;
25  import com.liferay.portal.security.ntlm.NtlmManager;
26  import com.liferay.portal.security.ntlm.NtlmUserAccount;
27  import com.liferay.portal.servlet.filters.BasePortalFilter;
28  import com.liferay.portal.util.PortalInstances;
29  import com.liferay.portal.util.PrefsPropsUtil;
30  import com.liferay.portal.util.PropsUtil;
31  import com.liferay.portal.util.PropsValues;
32  import com.liferay.portal.util.WebKeys;
33  
34  import java.security.SecureRandom;
35  
36  import java.util.Iterator;
37  import java.util.Map;
38  import java.util.Properties;
39  import java.util.concurrent.ConcurrentHashMap;
40  
41  import javax.servlet.FilterChain;
42  import javax.servlet.FilterConfig;
43  import javax.servlet.http.HttpServletRequest;
44  import javax.servlet.http.HttpServletResponse;
45  import javax.servlet.http.HttpSession;
46  
47  import jcifs.Config;
48  
49  import jcifs.http.NtlmHttpFilter;
50  
51  import jcifs.util.Base64;
52  
53  /**
54   * <a href="NtlmFilter.java.html"><b><i>View Source</i></b></a>
55   *
56   * @author Bruno Farache
57   * @author Marcus Schmidke
58   * @author Brian Wing Shun Chan
59   * @author Wesley Gong
60   * @author Marcellus Tavares
61   */
62  public class NtlmFilter extends BasePortalFilter {
63  
64      public void init(FilterConfig filterConfig) {
65          try {
66              NtlmHttpFilter ntlmFilter = new NtlmHttpFilter();
67  
68              ntlmFilter.init(filterConfig);
69  
70              Properties properties = PropsUtil.getProperties("jcifs.", false);
71  
72              Iterator<Map.Entry<Object, Object>> itr =
73                  properties.entrySet().iterator();
74  
75              while (itr.hasNext()) {
76                  Map.Entry<Object, Object> entry = itr.next();
77  
78                  String key = (String)entry.getKey();
79                  String value = (String)entry.getValue();
80  
81                  Config.setProperty(key, value);
82              }
83          }
84          catch (Exception e) {
85              _log.error(e, e);
86          }
87      }
88  
89      protected Log getLog() {
90          return _log;
91      }
92  
93      protected NtlmManager getNtlmManager(long companyId)
94          throws SystemException {
95  
96          String domain = PrefsPropsUtil.getString(
97              companyId, PropsKeys.NTLM_DOMAIN, PropsValues.NTLM_DOMAIN);
98          String domainController =  PrefsPropsUtil.getString(
99              companyId, PropsKeys.NTLM_DOMAIN_CONTROLLER,
100             PropsValues.NTLM_DOMAIN_CONTROLLER);
101         String domainControllerName =  PrefsPropsUtil.getString(
102             companyId, PropsKeys.NTLM_DOMAIN_CONTROLLER_NAME,
103             PropsValues.NTLM_DOMAIN_CONTROLLER_NAME);
104         String serviceAccount =  PrefsPropsUtil.getString(
105             companyId, PropsKeys.NTLM_SERVICE_ACCOUNT,
106             PropsValues.NTLM_SERVICE_ACCOUNT);
107         String servicePassword =  PrefsPropsUtil.getString(
108             companyId, PropsKeys.NTLM_SERVICE_PASSWORD,
109             PropsValues.NTLM_SERVICE_PASSWORD);
110 
111         NtlmManager ntlmManager = _ntlmManagers.get(companyId);
112 
113         if (ntlmManager == null) {
114             ntlmManager = new NtlmManager(
115                 domain, domainController, domainControllerName, serviceAccount,
116                 servicePassword);
117 
118             _ntlmManagers.put(companyId, ntlmManager);
119         }
120         else {
121             if (!Validator.equals(ntlmManager.getDomain(), domain) ||
122                 !Validator.equals(
123                     ntlmManager.getDomainController(), domainController) ||
124                 !Validator.equals(
125                     ntlmManager.getDomainControllerName(),
126                     domainControllerName) ||
127                 !Validator.equals(
128                     ntlmManager.getServiceAccount(), serviceAccount) ||
129                 !Validator.equals(
130                      ntlmManager.getServicePassword(), servicePassword)) {
131 
132                 ntlmManager.setConfiguration(
133                     domain, domainController, domainControllerName,
134                     serviceAccount, servicePassword);
135             }
136         }
137 
138         return ntlmManager;
139     }
140 
141     protected void processFilter(
142             HttpServletRequest request, HttpServletResponse response,
143             FilterChain filterChain)
144         throws Exception {
145 
146         long companyId = PortalInstances.getCompanyId(request);
147 
148         if (LDAPSettingsUtil.isNtlmEnabled(companyId)) {
149 
150             // Type 1 NTLM requests from browser can (and should) always
151             // immediately be replied to with an Type 2 NTLM response, no
152             // matter whether we're yet logging in or whether it is much
153             // later in the session.
154 
155             HttpSession session = request.getSession(false);
156 
157             String authorization = GetterUtil.getString(
158                 request.getHeader(HttpHeaders.AUTHORIZATION));
159 
160             if (authorization.startsWith("NTLM")) {
161                 NtlmManager ntlmManager = getNtlmManager(companyId);
162 
163                 byte[] src = Base64.decode(authorization.substring(5));
164 
165                 if (src[8] == 1) {
166                     byte[] serverChallenge = new byte[8];
167 
168                     _secureRandom.nextBytes(serverChallenge);
169 
170                     byte[] challengeMessage = ntlmManager.negotiate(
171                         src, serverChallenge);
172 
173                     authorization = Base64.encode(challengeMessage);
174 
175                     response.setHeader(
176                         HttpHeaders.WWW_AUTHENTICATE, "NTLM " + authorization);
177                     response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
178                     response.setContentLength(0);
179 
180                     response.flushBuffer();
181 
182                     _serverChallenges.put(
183                         request.getRemoteAddr(), serverChallenge);
184 
185                     // Interrupt filter chain, send response. Browser will
186                     // immediately post a new request.
187 
188                     return;
189                 }
190                 else {
191                     byte[] serverChallenge = _serverChallenges.get(
192                         request.getRemoteAddr());
193 
194                     NtlmUserAccount ntlmUserAccount = ntlmManager.authenticate(
195                         src, serverChallenge);
196 
197                     if (ntlmUserAccount == null) {
198                         return;
199                     }
200 
201                     if (_log.isDebugEnabled()) {
202                         _log.debug(
203                             "NTLM remote user " +
204                                 ntlmUserAccount.getUserName());
205                     }
206 
207                     _serverChallenges.remove(request.getRemoteAddr());
208 
209                     request.setAttribute(
210                         WebKeys.NTLM_REMOTE_USER,
211                         ntlmUserAccount.getUserName());
212 
213                     if (session != null) {
214                         session.setAttribute(
215                             WebKeys.NTLM_USER_ACCOUNT, ntlmUserAccount);
216                     }
217                 }
218             }
219 
220             String path = request.getPathInfo();
221 
222             if ((path != null) && path.endsWith("/login")) {
223                 NtlmUserAccount ntlmUserAccount = null;
224 
225                 if (session != null) {
226                     ntlmUserAccount = (NtlmUserAccount)session.getAttribute(
227                         WebKeys.NTLM_USER_ACCOUNT);
228                 }
229 
230                 if (ntlmUserAccount == null) {
231                     response.setHeader(HttpHeaders.WWW_AUTHENTICATE, "NTLM");
232                     response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
233                     response.setContentLength(0);
234 
235                     response.flushBuffer();
236 
237                     return;
238                 }
239             }
240         }
241 
242         processFilter(NtlmPostFilter.class, request, response, filterChain);
243     }
244 
245     private static Log _log = LogFactoryUtil.getLog(NtlmFilter.class);
246 
247     private Map<Long, NtlmManager> _ntlmManagers =
248         new ConcurrentHashMap<Long, NtlmManager>();
249     private SecureRandom _secureRandom = new SecureRandom();
250     private Map<String, byte[]> _serverChallenges =
251         new ConcurrentHashMap<String, byte[]>();
252 
253 }