/** * Process a type 3 NTLM message * * @param type3Msg Type3NTLMMessage * @param req HttpServletRequest * @param res HttpServletResponse * @exception IOException * @exception ServletException */ protected boolean processType3( Type3NTLMMessage type3Msg, ServletContext context, HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { Log logger = getLogger(); if (logger.isDebugEnabled()) logger.debug("Received type3 " + type3Msg); // Get the existing NTLM details NTLMLogonDetails ntlmDetails = null; SessionUser user = null; user = getSessionUser(context, req, res, true); HttpSession session = req.getSession(); ntlmDetails = (NTLMLogonDetails) session.getAttribute(NTLM_AUTH_DETAILS); // Get the NTLM logon details String userName = type3Msg.getUserName(); String workstation = type3Msg.getWorkstation(); String domain = type3Msg.getDomain(); // ALF-10997 fix, normalize the userName // the system runAs is acceptable because we are resolving a username i.e. it's a system-wide // operation that does not need permission checks final String userName_f = userName; String normalized = transactionService .getRetryingTransactionHelper() .doInTransaction( new RetryingTransactionHelper.RetryingTransactionCallback<String>() { public String execute() throws Throwable { return AuthenticationUtil.runAs( new AuthenticationUtil.RunAsWork<String>() { public String doWork() throws Exception { String normalized = personService.getUserIdentifier(userName_f); return normalized; } }, AuthenticationUtil.SYSTEM_USER_NAME); } }, true); if (normalized != null) { userName = normalized; } boolean authenticated = false; // Check if we are using cached details for the authentication if (user != null && ntlmDetails != null && ntlmDetails.hasNTLMHashedPassword()) { // Check if the received NTLM hashed password matches the cached password byte[] ntlmPwd = type3Msg.getNTLMHash(); byte[] cachedPwd = ntlmDetails.getNTLMHashedPassword(); if (ntlmPwd != null) { authenticated = Arrays.equals(cachedPwd, ntlmPwd); } if (logger.isDebugEnabled()) logger.debug("Using cached NTLM hash, authenticated = " + authenticated); onValidate(context, req, res, new NTLMCredentials(userName, ntlmPwd)); // Allow the user to access the requested page return true; } else { WebCredentials credentials; // Check if we are using local MD4 password hashes or passthru authentication if (nltmAuthenticator.getNTLMMode() == NTLMMode.MD4_PROVIDER) { // Check if guest logons are allowed and this is a guest logon if (m_allowGuest && userName.equalsIgnoreCase(authenticationComponent.getGuestUserName())) { credentials = new GuestCredentials(); // Indicate that the user has been authenticated authenticated = true; if (getLogger().isDebugEnabled()) getLogger().debug("Guest logon"); } else { // Get the stored MD4 hashed password for the user, or null if the user does not exist String md4hash = getMD4Hash(userName); if (md4hash != null) { authenticated = validateLocalHashedPassword(type3Msg, ntlmDetails, authenticated, md4hash); credentials = new NTLMCredentials(ntlmDetails.getUserName(), ntlmDetails.getNTLMHashedPassword()); } else { // Check if unknown users should be logged on as guest if (m_mapUnknownUserToGuest) { // Reset the user name to be the guest user userName = authenticationComponent.getGuestUserName(); authenticated = true; credentials = new GuestCredentials(); if (logger.isDebugEnabled()) logger.debug("User " + userName + " logged on as guest, no Alfresco account"); } else { if (logger.isDebugEnabled()) logger.debug("User " + userName + " does not have Alfresco account"); // Bypass NTLM authentication and display the logon screen, // as user account does not exist in Alfresco credentials = new UnknownCredentials(); authenticated = false; } } } } else { credentials = new NTLMCredentials(type3Msg.getUserName(), type3Msg.getNTLMHash()); // Determine if the client sent us NTLMv1 or NTLMv2 if (type3Msg.hasFlag(NTLM.Flag128Bit) && type3Msg.hasFlag(NTLM.FlagNTLM2Key) || (type3Msg.getNTLMHash() != null && type3Msg.getNTLMHash().length > 24)) { // Cannot accept NTLMv2 if we are using passthru auth if (logger.isErrorEnabled()) logger.error( "Client " + workstation + " using NTLMv2 logon, not valid with passthru authentication"); } else { if (ntlmDetails == null) { if (logger.isWarnEnabled()) logger.warn( "Authentication failed: NTLM details can not be retrieved from session. Client must support cookies."); restartLoginChallenge(context, req, res); return false; } // Passthru mode, send the hashed password details to the passthru authentication server NTLMPassthruToken authToken = (NTLMPassthruToken) ntlmDetails.getAuthenticationToken(); authToken.setUserAndPassword( type3Msg.getUserName(), type3Msg.getNTLMHash(), PasswordEncryptor.NTLM1); try { // Run the second stage of the passthru authentication nltmAuthenticator.authenticate(authToken); authenticated = true; // Check if the user has been logged on as guest if (authToken.isGuestLogon()) { userName = authenticationComponent.getGuestUserName(); } // Set the authentication context authenticationComponent.setCurrentUser(userName); } catch (BadCredentialsException ex) { if (logger.isDebugEnabled()) logger.debug("Authentication failed, " + ex.getMessage()); } catch (AuthenticationException ex) { if (logger.isDebugEnabled()) logger.debug("Authentication failed, " + ex.getMessage()); } finally { // Clear the authentication token from the NTLM details ntlmDetails.setAuthenticationToken(null); } } } // Check if the user has been authenticated, if so then setup the user environment if (authenticated == true) { boolean userInit = false; if (user == null) { try { user = createUserEnvironment(session, userName); userInit = true; } catch (AuthenticationException ex) { if (logger.isDebugEnabled()) logger.debug("Failed to validate user " + userName, ex); onValidateFailed(context, req, res, session, credentials); return false; } } onValidate(context, req, res, credentials); // Update the NTLM logon details in the session String srvName = getServerName(); if (ntlmDetails == null) { // No cached NTLM details ntlmDetails = new NTLMLogonDetails(userName, workstation, domain, false, srvName); ntlmDetails.setNTLMHashedPassword(type3Msg.getNTLMHash()); session.setAttribute(NTLM_AUTH_DETAILS, ntlmDetails); if (logger.isDebugEnabled()) logger.debug("No cached NTLM details, created"); } else { // Update the cached NTLM details ntlmDetails.setDetails(userName, workstation, domain, false, srvName); ntlmDetails.setNTLMHashedPassword(type3Msg.getNTLMHash()); if (logger.isDebugEnabled()) logger.debug("Updated cached NTLM details"); } if (logger.isDebugEnabled()) logger.debug("User logged on via NTLM, " + ntlmDetails); if (onLoginComplete(context, req, res, userInit)) { // Allow the user to access the requested page return true; } } else { restartLoginChallenge(context, req, res); } } return false; }