1   /**
2    * Copyright (c) 2000-2009 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.sso.ntlm;
24  
25  import com.liferay.portal.kernel.log.Log;
26  import com.liferay.portal.kernel.log.LogFactoryUtil;
27  import com.liferay.portal.kernel.util.StringPool;
28  import com.liferay.portal.security.ldap.PortalLDAPUtil;
29  import com.liferay.portal.util.PortalInstances;
30  import com.liferay.portal.util.PrefsPropsUtil;
31  import com.liferay.portal.util.PropsKeys;
32  import com.liferay.portal.util.PropsValues;
33  import com.liferay.portal.util.WebKeys;
34  import com.liferay.util.servlet.filters.DynamicFilterConfig;
35  
36  import java.io.IOException;
37  
38  import javax.servlet.FilterChain;
39  import javax.servlet.FilterConfig;
40  import javax.servlet.ServletException;
41  import javax.servlet.ServletRequest;
42  import javax.servlet.ServletResponse;
43  import javax.servlet.http.HttpServletRequest;
44  import javax.servlet.http.HttpServletResponse;
45  import javax.servlet.http.HttpSession;
46  
47  import jcifs.Config;
48  import jcifs.UniAddress;
49  
50  import jcifs.http.NtlmHttpFilter;
51  import jcifs.http.NtlmSsp;
52  
53  import jcifs.ntlmssp.Type1Message;
54  import jcifs.ntlmssp.Type2Message;
55  
56  import jcifs.smb.NtlmPasswordAuthentication;
57  import jcifs.smb.SmbSession;
58  
59  import jcifs.util.Base64;
60  
61  /**
62   * <a href="NtlmFilter.java.html"><b><i>View Source</i></b></a>
63   *
64   * @author Bruno Farache
65   * @author Marcus Schmidke
66   *
67   */
68  public class NtlmFilter extends NtlmHttpFilter {
69  
70      public void init(FilterConfig filterConfig) throws ServletException {
71          super.init(filterConfig);
72  
73          _filterConfig = new DynamicFilterConfig(filterConfig);
74      }
75  
76      public void doFilter(
77              ServletRequest servletRequest, ServletResponse servletResponse,
78              FilterChain filterChain)
79          throws IOException, ServletException {
80  
81          try {
82              HttpServletRequest request = (HttpServletRequest)servletRequest;
83              HttpServletResponse response = (HttpServletResponse)servletResponse;
84  
85              long companyId = PortalInstances.getCompanyId(request);
86  
87              if (PortalLDAPUtil.isNtlmEnabled(companyId)) {
88                  String domainController = _filterConfig.getInitParameter(
89                      "jcifs.http.domainController");
90                  String domain = _filterConfig.getInitParameter(
91                      "jcifs.smb.client.domain");
92  
93                  if ((domainController == null) && (domain == null)) {
94                      domainController = PrefsPropsUtil.getString(
95                          companyId, PropsKeys.NTLM_DOMAIN_CONTROLLER,
96                          PropsValues.NTLM_DOMAIN_CONTROLLER);
97                      domain = PrefsPropsUtil.getString(
98                          companyId, PropsKeys.NTLM_DOMAIN,
99                          PropsValues.NTLM_DOMAIN);
100 
101                     _filterConfig.addInitParameter(
102                         "jcifs.http.domainController", domainController);
103                     _filterConfig.addInitParameter(
104                         "jcifs.smb.client.domain", domain);
105 
106                     super.init(_filterConfig);
107 
108                     if (_log.isDebugEnabled()) {
109                         _log.debug("Host " + domainController);
110                         _log.debug("Domain " + domain);
111                     }
112                 }
113 
114                 // Type 1 NTLM requests from browser can (and should) always
115                 // immediately be replied to with an Type 2 NTLM response, no
116                 // matter whether we're yet logging in or whether it is much
117                 // later in the session.
118 
119                 String msg = request.getHeader("Authorization");
120 
121                 if (msg != null && msg.startsWith("NTLM")) {
122                     byte[] src = Base64.decode(msg.substring(5));
123 
124                     if (src[8] == 1) {
125                         UniAddress dc = UniAddress.getByName(
126                             Config.getProperty("jcifs.http.domainController"),
127                             true);
128 
129                         byte[] challenge = SmbSession.getChallenge(dc);
130 
131                         Type1Message type1 = new Type1Message(src);
132                         Type2Message type2 = new Type2Message(
133                             type1, challenge, null);
134 
135                         msg = Base64.encode(type2.toByteArray());
136 
137                         response.setHeader("WWW-Authenticate", "NTLM " + msg);
138                         response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
139                         response.setContentLength(0);
140 
141                         response.flushBuffer();
142 
143                         // Interrupt filter chain, send response. Browser will
144                         // immediately post a new request.
145 
146                         return;
147                     }
148                 }
149 
150                 String path = request.getPathInfo();
151 
152                 if (path != null && path.endsWith("/login")) {
153                     NtlmPasswordAuthentication ntlm = negotiate(
154                         request, response, false);
155 
156                     if (ntlm == null) {
157                         return;
158                     }
159 
160                     String remoteUser = ntlm.getName();
161 
162                     int pos = remoteUser.indexOf(StringPool.BACK_SLASH);
163 
164                     if (pos != -1) {
165                         remoteUser = remoteUser.substring(pos + 1);
166                     }
167 
168                     if (_log.isDebugEnabled()) {
169                         _log.debug("NTLM remote user " + remoteUser);
170                     }
171 
172                     servletRequest.setAttribute(
173                         WebKeys.NTLM_REMOTE_USER, remoteUser);
174                 }
175             }
176         }
177         catch (Exception e) {
178             _log.error(e);
179         }
180 
181         filterChain.doFilter(servletRequest, servletResponse);
182     }
183 
184     public NtlmPasswordAuthentication negotiate(
185             HttpServletRequest request, HttpServletResponse response,
186             boolean skipAuthentication)
187         throws IOException, ServletException {
188 
189         NtlmPasswordAuthentication ntlm = null;
190 
191         HttpSession session = request.getSession(false);
192 
193         String authorizationHeader = request.getHeader("Authorization");
194 
195         if (_log.isDebugEnabled()) {
196             _log.debug("Authorization header " + authorizationHeader);
197         }
198 
199         if ((authorizationHeader != null) && (
200             (authorizationHeader.startsWith("NTLM ")))) {
201 
202             String domainController = Config.getProperty(
203                 "jcifs.http.domainController");
204 
205             UniAddress uniAddress = UniAddress.getByName(
206                 domainController, true);
207 
208             if (_log.isDebugEnabled()) {
209                 _log.debug("Address " + uniAddress);
210             }
211 
212             byte[] challenge = SmbSession.getChallenge(uniAddress);
213 
214             ntlm = NtlmSsp.authenticate(request, response, challenge);
215 
216             session.setAttribute("NtlmHttpAuth", ntlm);
217         }
218         else {
219             if (session != null) {
220                 ntlm = (NtlmPasswordAuthentication)session.getAttribute(
221                     "NtlmHttpAuth");
222             }
223 
224             if (ntlm == null) {
225                 response.setHeader("WWW-Authenticate", "NTLM");
226                 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
227                 response.setContentLength(0);
228 
229                 response.flushBuffer();
230 
231                 return null;
232             }
233         }
234 
235         if (_log.isDebugEnabled()) {
236             _log.debug("Password authentication " + ntlm);
237         }
238 
239         return ntlm;
240     }
241 
242     private static Log _log = LogFactoryUtil.getLog(NtlmFilter.class);
243 
244     private DynamicFilterConfig _filterConfig;
245 
246 }