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