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