1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    *
5    *
6    *
7    * The contents of this file are subject to the terms of the Liferay Enterprise
8    * Subscription License ("License"). You may not use this file except in
9    * compliance with the License. You can obtain a copy of the License by
10   * contacting Liferay, Inc. See the License for the specific language governing
11   * permissions and limitations under the License, including but not limited to
12   * distribution rights 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.servlet.HttpHeaders;
28  import com.liferay.portal.kernel.util.GetterUtil;
29  import com.liferay.portal.kernel.util.PropsKeys;
30  import com.liferay.portal.kernel.util.StringPool;
31  import com.liferay.portal.kernel.util.Validator;
32  import com.liferay.portal.security.ldap.PortalLDAPUtil;
33  import com.liferay.portal.servlet.filters.BasePortalFilter;
34  import com.liferay.portal.util.PortalInstances;
35  import com.liferay.portal.util.PrefsPropsUtil;
36  import com.liferay.portal.util.PropsUtil;
37  import com.liferay.portal.util.PropsValues;
38  import com.liferay.portal.util.WebKeys;
39  import com.liferay.util.servlet.filters.DynamicFilterConfig;
40  
41  import java.util.Iterator;
42  import java.util.Map;
43  import java.util.Properties;
44  
45  import javax.servlet.FilterChain;
46  import javax.servlet.FilterConfig;
47  import javax.servlet.http.HttpServletRequest;
48  import javax.servlet.http.HttpServletResponse;
49  import javax.servlet.http.HttpSession;
50  
51  import jcifs.Config;
52  import jcifs.UniAddress;
53  
54  import jcifs.http.NtlmHttpFilter;
55  import jcifs.http.NtlmSsp;
56  
57  import jcifs.ntlmssp.Type1Message;
58  import jcifs.ntlmssp.Type2Message;
59  
60  import jcifs.smb.NtlmPasswordAuthentication;
61  import jcifs.smb.SmbSession;
62  
63  import jcifs.util.Base64;
64  
65  /**
66   * <a href="NtlmFilter.java.html"><b><i>View Source</i></b></a>
67   *
68   * @author Bruno Farache
69   * @author Marcus Schmidke
70   * @author Brian Wing Shun Chan
71   * @author Wesley Gong
72   */
73  public class NtlmFilter extends BasePortalFilter {
74  
75      public void init(FilterConfig filterConfig) {
76          try {
77              NtlmHttpFilter ntlmFilter = new NtlmHttpFilter();
78  
79              ntlmFilter.init(filterConfig);
80  
81              Properties properties = PropsUtil.getProperties("jcifs.", false);
82  
83              Iterator<Map.Entry<Object, Object>> itr =
84                  properties.entrySet().iterator();
85  
86              while (itr.hasNext()) {
87                  Map.Entry<Object, Object> entry = itr.next();
88  
89                  String key = (String)entry.getKey();
90                  String value = (String)entry.getValue();
91  
92                  Config.setProperty(key, value);
93              }
94          }
95          catch (Exception e) {
96              _log.error(e, e);
97          }
98  
99          _filterConfig = new DynamicFilterConfig(filterConfig);
100     }
101 
102     protected Log getLog() {
103         return _log;
104     }
105 
106     protected void processFilter(
107             HttpServletRequest request, HttpServletResponse response,
108             FilterChain filterChain)
109         throws Exception {
110 
111         long companyId = PortalInstances.getCompanyId(request);
112 
113         if (PortalLDAPUtil.isNtlmEnabled(companyId)) {
114             String domainController = _filterConfig.getInitParameter(
115                 "jcifs.http.domainController");
116             String domain = _filterConfig.getInitParameter(
117                 "jcifs.smb.client.domain");
118 
119             String preferencesDomainController = PrefsPropsUtil.getString(
120                 companyId, PropsKeys.NTLM_DOMAIN_CONTROLLER,
121                 PropsValues.NTLM_DOMAIN_CONTROLLER);
122             String preferencesDomain = PrefsPropsUtil.getString(
123                 companyId, PropsKeys.NTLM_DOMAIN, PropsValues.NTLM_DOMAIN);
124 
125             if (!Validator.equals(
126                     domainController, preferencesDomainController) ||
127                 !Validator.equals(domain, preferencesDomain)) {
128 
129                 domainController = preferencesDomainController;
130                 domain = preferencesDomain;
131 
132                 _filterConfig.addInitParameter(
133                     "jcifs.http.domainController", domainController);
134                 _filterConfig.addInitParameter(
135                     "jcifs.smb.client.domain", domain);
136 
137                 super.init(_filterConfig);
138             }
139 
140             if (_log.isDebugEnabled()) {
141                 _log.debug("Host " + domainController);
142                 _log.debug("Domain " + domain);
143             }
144 
145             // Type 1 NTLM requests from browser can (and should) always
146             // immediately be replied to with an Type 2 NTLM response, no
147             // matter whether we're yet logging in or whether it is much
148             // later in the session.
149 
150             String authorization = GetterUtil.getString(
151                 request.getHeader(HttpHeaders.AUTHORIZATION));
152 
153             if (authorization.startsWith("NTLM")) {
154                 byte[] src = Base64.decode(authorization.substring(5));
155 
156                 if (src[8] == 1) {
157                     UniAddress dc = UniAddress.getByName(
158                         domainController, true);
159 
160                     byte[] challenge = SmbSession.getChallenge(dc);
161 
162                     Type1Message type1 = new Type1Message(src);
163                     Type2Message type2 = new Type2Message(
164                         type1, challenge, null);
165 
166                     authorization = Base64.encode(type2.toByteArray());
167 
168                     response.setHeader(
169                         HttpHeaders.WWW_AUTHENTICATE, "NTLM " + authorization);
170                     response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
171                     response.setContentLength(0);
172 
173                     response.flushBuffer();
174 
175                     // Interrupt filter chain, send response. Browser will
176                     // immediately post a new request.
177 
178                     return;
179                 }
180             }
181 
182             String path = request.getPathInfo();
183 
184             if ((path != null) && path.endsWith("/login")) {
185                 NtlmPasswordAuthentication ntlm = negotiate(
186                     request, response, false);
187 
188                 if (ntlm == null) {
189                     return;
190                 }
191 
192                 String remoteUser = ntlm.getName();
193 
194                 int pos = remoteUser.indexOf(StringPool.BACK_SLASH);
195 
196                 if (pos != -1) {
197                     remoteUser = remoteUser.substring(pos + 1);
198                 }
199 
200                 if (_log.isDebugEnabled()) {
201                     _log.debug("NTLM remote user " + remoteUser);
202                 }
203 
204                 request.setAttribute(WebKeys.NTLM_REMOTE_USER, remoteUser);
205             }
206         }
207 
208         processFilter(NtlmPostFilter.class, request, response, filterChain);
209     }
210 
211     protected NtlmPasswordAuthentication negotiate(
212             HttpServletRequest request, HttpServletResponse response,
213             boolean skipAuthentication)
214         throws Exception {
215 
216         NtlmPasswordAuthentication ntlm = null;
217 
218         HttpSession session = request.getSession(false);
219 
220         String authorization = GetterUtil.getString(
221             request.getHeader(HttpHeaders.AUTHORIZATION));
222 
223         if (_log.isDebugEnabled()) {
224             _log.debug("Authorization header " + authorization);
225         }
226 
227         if (authorization.startsWith("NTLM ")) {
228             String domainController = _filterConfig.getInitParameter(
229                 "jcifs.http.domainController");
230 
231             UniAddress uniAddress = UniAddress.getByName(
232                 domainController, true);
233 
234             if (_log.isDebugEnabled()) {
235                 _log.debug("Address " + uniAddress);
236             }
237 
238             byte[] challenge = SmbSession.getChallenge(uniAddress);
239 
240             ntlm = NtlmSsp.authenticate(request, response, challenge);
241 
242             try {
243                 SmbSession.logon(uniAddress, ntlm);
244             }
245             catch (Exception e) {
246                 response.setHeader(HttpHeaders.WWW_AUTHENTICATE, "NTLM");
247                 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
248                 response.setContentLength(0);
249 
250                 response.flushBuffer();
251 
252                 return null;
253             }
254 
255             session.setAttribute("NtlmHttpAuth", ntlm);
256         }
257         else {
258             if (session != null) {
259                 ntlm = (NtlmPasswordAuthentication)session.getAttribute(
260                     "NtlmHttpAuth");
261             }
262 
263             if (ntlm == null) {
264                 response.setHeader(HttpHeaders.WWW_AUTHENTICATE, "NTLM");
265                 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
266                 response.setContentLength(0);
267 
268                 response.flushBuffer();
269 
270                 return null;
271             }
272         }
273 
274         if (_log.isDebugEnabled()) {
275             _log.debug("Password authentication " + ntlm);
276         }
277 
278         return ntlm;
279     }
280 
281     private static Log _log = LogFactoryUtil.getLog(NtlmFilter.class);
282 
283     private DynamicFilterConfig _filterConfig;
284 
285 }