001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
014    
015    package com.liferay.portal.servlet.filters.sso.ntlm;
016    
017    import com.liferay.portal.kernel.cache.PortalCache;
018    import com.liferay.portal.kernel.cache.SingleVMPoolUtil;
019    import com.liferay.portal.kernel.exception.SystemException;
020    import com.liferay.portal.kernel.log.Log;
021    import com.liferay.portal.kernel.log.LogFactoryUtil;
022    import com.liferay.portal.kernel.servlet.BrowserSnifferUtil;
023    import com.liferay.portal.kernel.servlet.HttpHeaders;
024    import com.liferay.portal.kernel.util.GetterUtil;
025    import com.liferay.portal.kernel.util.PropsKeys;
026    import com.liferay.portal.kernel.util.Validator;
027    import com.liferay.portal.security.auth.AuthSettingsUtil;
028    import com.liferay.portal.security.ntlm.NtlmManager;
029    import com.liferay.portal.security.ntlm.NtlmUserAccount;
030    import com.liferay.portal.servlet.filters.BasePortalFilter;
031    import com.liferay.portal.util.PortalInstances;
032    import com.liferay.portal.util.PrefsPropsUtil;
033    import com.liferay.portal.util.PropsUtil;
034    import com.liferay.portal.util.PropsValues;
035    import com.liferay.portal.util.WebKeys;
036    
037    import java.security.SecureRandom;
038    
039    import java.util.Iterator;
040    import java.util.Map;
041    import java.util.Properties;
042    import java.util.concurrent.ConcurrentHashMap;
043    
044    import javax.servlet.FilterChain;
045    import javax.servlet.FilterConfig;
046    import javax.servlet.http.HttpServletRequest;
047    import javax.servlet.http.HttpServletResponse;
048    import javax.servlet.http.HttpSession;
049    
050    import jcifs.Config;
051    
052    import jcifs.http.NtlmHttpFilter;
053    
054    import jcifs.util.Base64;
055    
056    /**
057     * @author Bruno Farache
058     * @author Marcus Schmidke
059     * @author Brian Wing Shun Chan
060     * @author Wesley Gong
061     * @author Marcellus Tavares
062     * @author Michael C. Han
063     */
064    public class NtlmFilter extends BasePortalFilter {
065    
066            @Override
067            public void init(FilterConfig filterConfig) {
068                    super.init(filterConfig);
069    
070                    try {
071                            NtlmHttpFilter ntlmFilter = new NtlmHttpFilter();
072    
073                            ntlmFilter.init(filterConfig);
074    
075                            Properties properties = PropsUtil.getProperties("jcifs.", false);
076    
077                            Iterator<Map.Entry<Object, Object>> itr =
078                                    properties.entrySet().iterator();
079    
080                            while (itr.hasNext()) {
081                                    Map.Entry<Object, Object> entry = itr.next();
082    
083                                    String key = (String)entry.getKey();
084                                    String value = (String)entry.getValue();
085    
086                                    Config.setProperty(key, value);
087                            }
088                    }
089                    catch (Exception e) {
090                            _log.error(e, e);
091                    }
092            }
093    
094            @Override
095            public boolean isFilterEnabled(
096                    HttpServletRequest request, HttpServletResponse response) {
097    
098                    try {
099                            long companyId = PortalInstances.getCompanyId(request);
100    
101                            if (BrowserSnifferUtil.isIe(request) &&
102                                    AuthSettingsUtil.isNtlmEnabled(companyId)) {
103    
104                                    return true;
105                            }
106                    }
107                    catch (Exception e) {
108                            _log.error(e, e);
109                    }
110    
111                    return false;
112            }
113    
114            @Override
115            protected Log getLog() {
116                    return _log;
117            }
118    
119            protected NtlmManager getNtlmManager(long companyId)
120                    throws SystemException {
121    
122                    String domain = PrefsPropsUtil.getString(
123                            companyId, PropsKeys.NTLM_DOMAIN, PropsValues.NTLM_DOMAIN);
124                    String domainController = PrefsPropsUtil.getString(
125                            companyId, PropsKeys.NTLM_DOMAIN_CONTROLLER,
126                            PropsValues.NTLM_DOMAIN_CONTROLLER);
127                    String domainControllerName = PrefsPropsUtil.getString(
128                            companyId, PropsKeys.NTLM_DOMAIN_CONTROLLER_NAME,
129                            PropsValues.NTLM_DOMAIN_CONTROLLER_NAME);
130                    String serviceAccount = PrefsPropsUtil.getString(
131                            companyId, PropsKeys.NTLM_SERVICE_ACCOUNT,
132                            PropsValues.NTLM_SERVICE_ACCOUNT);
133                    String servicePassword = PrefsPropsUtil.getString(
134                            companyId, PropsKeys.NTLM_SERVICE_PASSWORD,
135                            PropsValues.NTLM_SERVICE_PASSWORD);
136    
137                    NtlmManager ntlmManager = _ntlmManagers.get(companyId);
138    
139                    if (ntlmManager == null) {
140                            ntlmManager = new NtlmManager(
141                                    domain, domainController, domainControllerName, serviceAccount,
142                                    servicePassword);
143    
144                            _ntlmManagers.put(companyId, ntlmManager);
145                    }
146                    else {
147                            if (!Validator.equals(ntlmManager.getDomain(), domain) ||
148                                    !Validator.equals(
149                                            ntlmManager.getDomainController(), domainController) ||
150                                    !Validator.equals(
151                                            ntlmManager.getDomainControllerName(),
152                                            domainControllerName) ||
153                                    !Validator.equals(
154                                            ntlmManager.getServiceAccount(), serviceAccount) ||
155                                    !Validator.equals(
156                                            ntlmManager.getServicePassword(), servicePassword)) {
157    
158                                    ntlmManager.setConfiguration(
159                                            domain, domainController, domainControllerName,
160                                            serviceAccount, servicePassword);
161                            }
162                    }
163    
164                    return ntlmManager;
165            }
166    
167            @Override
168            protected void processFilter(
169                            HttpServletRequest request, HttpServletResponse response,
170                            FilterChain filterChain)
171                    throws Exception {
172    
173                    // Type 1 NTLM requests from browser can (and should) always immediately
174                    // be replied to with an Type 2 NTLM response, no matter whether we're
175                    // yet logging in or whether it is much later in the session.
176    
177                    HttpSession session = request.getSession(false);
178    
179                    long companyId = PortalInstances.getCompanyId(request);
180    
181                    String authorization = GetterUtil.getString(
182                            request.getHeader(HttpHeaders.AUTHORIZATION));
183    
184                    if (authorization.startsWith("NTLM")) {
185                            NtlmManager ntlmManager = getNtlmManager(companyId);
186    
187                            byte[] src = Base64.decode(authorization.substring(5));
188    
189                            if (src[8] == 1) {
190                                    byte[] serverChallenge = new byte[8];
191    
192                                    _secureRandom.nextBytes(serverChallenge);
193    
194                                    byte[] challengeMessage = ntlmManager.negotiate(
195                                            src, serverChallenge);
196    
197                                    authorization = Base64.encode(challengeMessage);
198    
199                                    response.setContentLength(0);
200                                    response.setHeader(
201                                            HttpHeaders.WWW_AUTHENTICATE, "NTLM " + authorization);
202                                    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
203    
204                                    response.flushBuffer();
205    
206                                    _portalCache.put(request.getRemoteAddr(), serverChallenge);
207    
208                                    // Interrupt filter chain, send response. Browser will
209                                    // immediately post a new request.
210    
211                                    return;
212                            }
213    
214                            byte[] serverChallenge = (byte[])_portalCache.get(
215                                    request.getRemoteAddr());
216    
217                            if (serverChallenge == null) {
218                                    response.setContentLength(0);
219                                    response.setHeader(HttpHeaders.WWW_AUTHENTICATE, "NTLM");
220                                    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
221    
222                                    response.flushBuffer();
223    
224                                    return;
225                            }
226    
227                            NtlmUserAccount ntlmUserAccount = null;
228    
229                            try {
230                                    ntlmUserAccount = ntlmManager.authenticate(
231                                            src, serverChallenge);
232                            }
233                            catch (Exception e) {
234                                    if (_log.isErrorEnabled()) {
235                                            _log.error("Unable to perform NTLM authentication", e);
236                                    }
237                            }
238                            finally {
239                                    _portalCache.remove(request.getRemoteAddr());
240                            }
241    
242                            if (ntlmUserAccount == null) {
243                                    response.setContentLength(0);
244                                    response.setHeader(HttpHeaders.WWW_AUTHENTICATE, "NTLM");
245                                    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
246    
247                                    response.flushBuffer();
248    
249                                    return;
250                            }
251    
252                            if (_log.isDebugEnabled()) {
253                                    _log.debug("NTLM remote user " + ntlmUserAccount.getUserName());
254                            }
255    
256                            request.setAttribute(
257                                    WebKeys.NTLM_REMOTE_USER, ntlmUserAccount.getUserName());
258    
259                            if (session != null) {
260                                    session.setAttribute(
261                                            WebKeys.NTLM_USER_ACCOUNT, ntlmUserAccount);
262                            }
263                    }
264    
265                    String path = request.getPathInfo();
266    
267                    if ((path != null) && path.endsWith("/login")) {
268                            NtlmUserAccount ntlmUserAccount = null;
269    
270                            if (session != null) {
271                                    ntlmUserAccount = (NtlmUserAccount)session.getAttribute(
272                                            WebKeys.NTLM_USER_ACCOUNT);
273                            }
274    
275                            if (ntlmUserAccount == null) {
276                                    response.setContentLength(0);
277                                    response.setHeader(HttpHeaders.WWW_AUTHENTICATE, "NTLM");
278                                    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
279    
280                                    response.flushBuffer();
281    
282                                    return;
283                            }
284                    }
285    
286                    processFilter(NtlmPostFilter.class, request, response, filterChain);
287            }
288    
289            private static Log _log = LogFactoryUtil.getLog(NtlmFilter.class);
290    
291            private Map<Long, NtlmManager> _ntlmManagers =
292                    new ConcurrentHashMap<Long, NtlmManager>();
293            private PortalCache _portalCache = SingleVMPoolUtil.getCache(
294                    NtlmFilter.class.getName());
295            private SecureRandom _secureRandom = new SecureRandom();
296    
297    }