diff --git a/source/java/org/alfresco/web/app/servlet/AbstractAuthenticationFilter.java b/source/java/org/alfresco/web/app/servlet/AbstractAuthenticationFilter.java index 9e4d419cfb..919b83411e 100644 --- a/source/java/org/alfresco/web/app/servlet/AbstractAuthenticationFilter.java +++ b/source/java/org/alfresco/web/app/servlet/AbstractAuthenticationFilter.java @@ -29,29 +29,28 @@ import java.util.List; import java.util.Locale; import java.util.StringTokenizer; +import javax.servlet.Filter; import javax.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -public class AbstractAuthenticationFilter -{ +/** + * Base class for all externally based authentication mechanism filters + */ +public abstract class AbstractAuthenticationFilter implements Filter +{ private static Log logger = LogFactory.getLog(AbstractAuthenticationFilter.class); - public AbstractAuthenticationFilter() - { - super(); - } - - + /** * Parse the Accept-Lanaguage HTTP header value * * @param req HttpServletRequest * @return Locale */ - protected static final Locale parseAcceptLanguageHeader(HttpServletRequest req, List m_languages) + public static final Locale parseAcceptLanguageHeader(HttpServletRequest req, List m_languages) { // Default the locale @@ -176,5 +175,4 @@ public class AbstractAuthenticationFilter return locale; } - } diff --git a/source/java/org/alfresco/web/app/servlet/NTLMAuthenticationFilter.java b/source/java/org/alfresco/web/app/servlet/NTLMAuthenticationFilter.java index 1a1f865b58..660b853f47 100644 --- a/source/java/org/alfresco/web/app/servlet/NTLMAuthenticationFilter.java +++ b/source/java/org/alfresco/web/app/servlet/NTLMAuthenticationFilter.java @@ -25,18 +25,11 @@ package org.alfresco.web.app.servlet; import java.io.IOException; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; import java.util.List; import java.util.Locale; -import java.util.Random; -import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; -import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; @@ -45,36 +38,18 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import javax.transaction.UserTransaction; -import net.sf.acegisecurity.BadCredentialsException; - import org.alfresco.config.ConfigService; -import org.alfresco.filesys.ServerConfigurationBean; +import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.i18n.I18NUtil; -import org.alfresco.jlan.server.auth.PasswordEncryptor; import org.alfresco.jlan.server.auth.ntlm.NTLM; -import org.alfresco.jlan.server.auth.ntlm.NTLMLogonDetails; import org.alfresco.jlan.server.auth.ntlm.NTLMMessage; -import org.alfresco.jlan.server.auth.ntlm.TargetInfo; import org.alfresco.jlan.server.auth.ntlm.Type1NTLMMessage; -import org.alfresco.jlan.server.auth.ntlm.Type2NTLMMessage; import org.alfresco.jlan.server.auth.ntlm.Type3NTLMMessage; -import org.alfresco.jlan.server.auth.passthru.DomainMapping; -import org.alfresco.jlan.server.config.SecurityConfigSection; -import org.alfresco.jlan.util.DataPacker; -import org.alfresco.jlan.util.IPAddress; import org.alfresco.model.ContentModel; -import org.alfresco.repo.security.authentication.AuthenticationComponent; +import org.alfresco.repo.SessionUser; import org.alfresco.repo.security.authentication.AuthenticationException; -import org.alfresco.repo.security.authentication.MD4PasswordEncoder; -import org.alfresco.repo.security.authentication.MD4PasswordEncoderImpl; -import org.alfresco.repo.security.authentication.NTLMMode; -import org.alfresco.repo.security.authentication.ntlm.NTLMPassthruToken; -import org.alfresco.service.ServiceRegistry; +import org.alfresco.repo.webdav.auth.BaseNTLMAuthenticationFilter; import org.alfresco.service.cmr.repository.NodeRef; -import org.alfresco.service.cmr.repository.NodeService; -import org.alfresco.service.cmr.security.AuthenticationService; -import org.alfresco.service.cmr.security.PersonService; -import org.alfresco.service.transaction.TransactionService; import org.alfresco.web.app.Application; import org.alfresco.web.bean.LoginBean; import org.alfresco.web.bean.repository.User; @@ -90,77 +65,25 @@ import org.springframework.web.context.support.WebApplicationContextUtils; * * @author GKSpencer */ -public class NTLMAuthenticationFilter extends AbstractAuthenticationFilter implements Filter +public class NTLMAuthenticationFilter extends BaseNTLMAuthenticationFilter { - // NTLM authentication session object names - - public static final String NTLM_AUTH_SESSION = "_alfNTLMAuthSess"; - public static final String NTLM_AUTH_DETAILS = "_alfNTLMDetails"; - // Locale object stored in the session - private static final String LOCALE = "locale"; - public static final String MESSAGE_BUNDLE = "alfresco.messages.webclient"; - - // NTLM flags mask, used to mask out features that are not supported - - private static final int NTLM_FLAGS = NTLM.Flag56Bit + NTLM.FlagLanManKey + NTLM.FlagNegotiateNTLM + - NTLM.FlagNegotiateOEM + NTLM.FlagNegotiateUnicode; + private static final String MESSAGE_BUNDLE = "alfresco.messages.webclient"; // Debug logging - private static Log logger = LogFactory.getLog(NTLMAuthenticationFilter.class); - // Servlet context, required to get authentication service - - private ServletContext m_context; - - // File server configuration - - private ServerConfigurationBean m_srvConfig; - // Various services required by NTLM authenticator - - private AuthenticationService m_authService; - private AuthenticationComponent m_authComponent; - private PersonService m_personService; - private NodeService m_nodeService; - private TransactionService m_transactionService; private ConfigService m_configService; - // Security configuration section, for domain mappings - - private SecurityConfigSection m_secConfig; - - // Password encryptor - - private PasswordEncryptor m_encryptor = new PasswordEncryptor(); - - // Allow guest access, map unknown users to the guest account - - private boolean m_allowGuest; - public boolean m_mapUnknownUserToGuest; - // Login page address - private String m_loginPage; - // Random number generator used to generate challenge keys - - private Random m_random = new Random(System.currentTimeMillis()); - - // MD4 hash decoder - - private MD4PasswordEncoder m_md4Encoder = new MD4PasswordEncoderImpl(); - - // Local server name, from either the file servers config or DNS host name - - private String m_srvName; - // List of available locales (from the web-client configuration) - private List m_languages; + /** * Initialize the filter * @@ -169,113 +92,16 @@ public class NTLMAuthenticationFilter extends AbstractAuthenticationFilter imple */ public void init(FilterConfig args) throws ServletException { - // Save the servlet context, needed to get hold of the authentication service + super.init(args); - m_context = args.getServletContext(); - // Setup the authentication context - WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(m_context); + m_configService = (ConfigService)ctx.getBean("webClientConfigService"); - ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY); - m_nodeService = serviceRegistry.getNodeService(); - m_transactionService = serviceRegistry.getTransactionService(); - - m_authService = (AuthenticationService) ctx.getBean("AuthenticationService"); - m_authComponent = (AuthenticationComponent) ctx.getBean("AuthenticationComponent"); - m_personService = (PersonService) ctx.getBean("personService"); - m_configService = (ConfigService) ctx.getBean("webClientConfigService"); - - m_srvConfig = (ServerConfigurationBean) ctx.getBean(ServerConfigurationBean.SERVER_CONFIGURATION); - - // Check that the authentication component supports the required mode - - if ( m_authComponent.getNTLMMode() != NTLMMode.MD4_PROVIDER && - m_authComponent.getNTLMMode() != NTLMMode.PASS_THROUGH) - { - throw new ServletException("Required authentication mode not available"); - } - - // Get the local server name, try the file server config first - - if ( m_srvConfig != null) - { - m_srvName = m_srvConfig.getServerName(); - - if ( m_srvName == null) - { - // CIFS server may not be running so the local server name has not been set, generate - // a server name - - m_srvName = m_srvConfig.getLocalServerName(true) + "_A"; - } - - // Find the security configuration section - - m_secConfig = (SecurityConfigSection) m_srvConfig.getConfigSection( SecurityConfigSection.SectionName); - } - else - { - // Get the host name - - try - { - // Get the local host name - - m_srvName = InetAddress.getLocalHost().getHostName(); - - // Strip any domain name - - int pos = m_srvName.indexOf("."); - if ( pos != -1) - m_srvName = m_srvName.substring(0, pos - 1); - } - catch (UnknownHostException ex) - { - // Log the error - - if ( logger.isErrorEnabled()) - logger.error("NTLM filter, error getting local host name", ex); - } - - } - - // Check if the server name is valid - - if ( m_srvName == null || m_srvName.length() == 0) - throw new ServletException("Failed to get local server name"); - - // Check if guest access is to be allowed - - String guestAccess = args.getInitParameter("AllowGuest"); - if ( guestAccess != null) - { - m_allowGuest = Boolean.parseBoolean(guestAccess); - - // Debug - - if ( logger.isDebugEnabled() && m_allowGuest) - logger.debug("NTLM filter guest access allowed"); - } - - // Check if unknown users should be mapped to guest access - - String mapUnknownToGuest = args.getInitParameter("MapUnknownUserToGuest"); - if ( mapUnknownToGuest != null) - { - m_mapUnknownUserToGuest = Boolean.parseBoolean(mapUnknownToGuest); - - // Debug - - if ( logger.isDebugEnabled() && m_mapUnknownUserToGuest) - logger.debug("NTLM filter map unknown users to guest"); - } - // Get a list of the available locales - LanguagesConfigElement config = (LanguagesConfigElement) m_configService. getConfig("Languages").getConfigElement(LanguagesConfigElement.CONFIG_ELEMENT_ID); - + m_languages = config.getLanguages(); } @@ -292,45 +118,33 @@ public class NTLMAuthenticationFilter extends AbstractAuthenticationFilter imple ServletException { // Get the HTTP request/response/session - HttpServletRequest req = (HttpServletRequest) sreq; HttpServletResponse resp = (HttpServletResponse) sresp; - HttpSession httpSess = req.getSession(true); - + // Check if there is an authorization header with an NTLM security blob - - String authHdr = req.getHeader("Authorization"); - boolean reqAuth = false; - - if ( authHdr != null && authHdr.startsWith("NTLM")) - reqAuth = true; + String authHdr = req.getHeader(AUTHORIZATION); + boolean reqAuth = (authHdr != null && authHdr.startsWith(AUTH_NTLM)); // Check if the user is already authenticated - User user = (User) httpSess.getAttribute(AuthenticationHelper.AUTHENTICATION_USER); - - if ( user != null && reqAuth == false) + if (user != null && reqAuth == false) { try { - // Debug - - if ( logger.isDebugEnabled()) + if (logger.isDebugEnabled()) logger.debug("User " + user.getUserName() + " validate ticket"); // Validate the user ticket - - m_authService.validate( user.getTicket()); + m_authService.validate(user.getTicket()); reqAuth = false; // Set the current locale - I18NUtil.setLocale(Application.getLanguage(httpSess)); } catch (AuthenticationException ex) { - if ( logger.isErrorEnabled()) + if (logger.isErrorEnabled()) logger.error("Failed to validate user " + user.getUserName(), ex); reqAuth = true; @@ -339,104 +153,210 @@ public class NTLMAuthenticationFilter extends AbstractAuthenticationFilter imple // If the user has been validated and we do not require re-authentication then continue to // the next filter - - if ( reqAuth == false && user != null) + if (reqAuth == false && user != null) { - // Debug - - if ( logger.isDebugEnabled()) + if (logger.isDebugEnabled()) logger.debug("Authentication not required, chaining ..."); // Chain to the next filter - chain.doFilter(sreq, sresp); return; } // Check if the login page is being accessed, do not intercept the login page - - if ( req.getRequestURI().endsWith(getLoginPage()) == true) + if (req.getRequestURI().endsWith(getLoginPage()) == true) { - // Debug - - if ( logger.isDebugEnabled()) + if (logger.isDebugEnabled()) logger.debug("Login page requested, chaining ..."); // Chain to the next filter - chain.doFilter( sreq, sresp); return; } // Check if the browser is Opera, if so then display the login page as Opera does not // support NTLM and displays an error page if a request to use NTLM is sent to it - String userAgent = req.getHeader("user-agent"); - - if ( userAgent != null && userAgent.indexOf("Opera ") != -1) + if (userAgent != null && userAgent.indexOf("Opera ") != -1) { - // Debug - - if ( logger.isDebugEnabled()) + if (logger.isDebugEnabled()) logger.debug("Opera detected, redirecting to login page"); // Redirect to the login page - resp.sendRedirect(req.getContextPath() + "/faces" + getLoginPage()); return; } // Check the authorization header - - if ( authHdr == null) { - - // Debug - - if ( logger.isDebugEnabled()) + if (authHdr == null) + { + if (logger.isDebugEnabled()) logger.debug("New NTLM auth request from " + req.getRemoteHost() + " (" + req.getRemoteAddr() + ":" + req.getRemotePort() + ")"); // Send back a request for NTLM authentication - - resp.setHeader("WWW-Authenticate", "NTLM"); - resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED); - - resp.flushBuffer(); + restartLoginChallenge(resp, httpSess); } else { // Decode the received NTLM blob and validate - - final byte[] ntlmByts = Base64.decodeBase64( authHdr.substring(5).getBytes()); + final byte[] ntlmByts = Base64.decodeBase64(authHdr.substring(5).getBytes()); int ntlmTyp = NTLMMessage.isNTLMType(ntlmByts); - - if ( ntlmTyp == NTLM.Type1) + if (ntlmTyp == NTLM.Type1) { // Process the type 1 NTLM message - Type1NTLMMessage type1Msg = new Type1NTLMMessage(ntlmByts); processType1(type1Msg, req, resp, httpSess); } - else if ( ntlmTyp == NTLM.Type3) + else if (ntlmTyp == NTLM.Type3) { // Process the type 3 NTLM message - Type3NTLMMessage type3Msg = new Type3NTLMMessage(ntlmByts); processType3(type3Msg, req, resp, httpSess, chain); } else { - // Debug - - if ( logger.isDebugEnabled()) - logger.debug("NTLM not handled, redirecting to login page"); + if (logger.isDebugEnabled()) + logger.debug("NTLM blob not handled, redirecting to login page."); // Redirect to the login page - resp.sendRedirect(req.getContextPath() + "/faces" + getLoginPage()); } } } + + /* (non-Javadoc) + * @see org.alfresco.repo.webdav.auth.BaseNTLMAuthenticationFilter#getSessionUser(javax.servlet.http.HttpSession) + */ + @Override + protected SessionUser getSessionUser(HttpSession session) + { + return (SessionUser)session.getAttribute(AuthenticationHelper.AUTHENTICATION_USER); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.webdav.auth.BaseNTLMAuthenticationFilter#onValidate(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpSession) + */ + @Override + protected void onValidate(HttpServletRequest req, HttpSession session) + { + // Set the current locale from the Accept-Lanaguage header if available + Locale userLocale = AbstractAuthenticationFilter.parseAcceptLanguageHeader(req, m_languages); + if (userLocale != null) + { + session.setAttribute(LOCALE, userLocale); + session.removeAttribute(MESSAGE_BUNDLE); + } + + // Set the locale using the session + I18NUtil.setLocale(Application.getLanguage(session)); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.webdav.auth.BaseNTLMAuthenticationFilter#onValidateFailed(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.http.HttpSession) + */ + @Override + protected void onValidateFailed(HttpServletRequest req, HttpServletResponse res, HttpSession session) + throws IOException + { + // Redirect to the login page if user validation fails + res.sendRedirect(req.getContextPath() + "/faces" + getLoginPage()); + } + + /* (non-Javadoc) + * @see org.alfresco.repo.webdav.auth.BaseNTLMAuthenticationFilter#createUserEnvironment(javax.servlet.http.HttpSession, java.lang.String) + */ + @Override + protected SessionUser createUserEnvironment(HttpSession session, String userName) + throws IOException, ServletException + { + Log logger = getLogger(); + + SessionUser user = null; + + UserTransaction tx = m_transactionService.getUserTransaction(); + NodeRef homeSpaceRef = null; + + try + { + tx.begin(); + + // Setup User object and Home space ID etc. + NodeRef personNodeRef = m_personService.getPerson(userName); + + // Use the system user context to do the user lookup + m_authComponent.setCurrentUser(m_authComponent.getSystemUserName()); + + // User name should match the uid in the person entry found + m_authComponent.setSystemUserAsCurrentUser(); + userName = (String) m_nodeService.getProperty(personNodeRef, ContentModel.PROP_USERNAME); + + m_authComponent.setCurrentUser(userName); + String currentTicket = m_authService.getCurrentTicket(); + user = new User(userName, currentTicket, personNodeRef); + + homeSpaceRef = (NodeRef) m_nodeService.getProperty(personNodeRef, ContentModel.PROP_HOMEFOLDER); + ((User)user).setHomeSpaceId(homeSpaceRef.getId()); + + tx.commit(); + } + catch (Throwable ex) + { + try + { + tx.rollback(); + } + catch (Exception err) + { + logger.error("Failed to rollback transaction", err); + } + if (ex instanceof RuntimeException) + { + throw (RuntimeException)ex; + } + else if (ex instanceof IOException) + { + throw (IOException)ex; + } + else if (ex instanceof ServletException) + { + throw (ServletException)ex; + } + else + { + throw new RuntimeException("Authentication setup failed", ex); + } + } + + // Store the user on the session + session.setAttribute(AuthenticationHelper.AUTHENTICATION_USER, user); + session.setAttribute(LoginBean.LOGIN_EXTERNAL_AUTH, Boolean.TRUE); + + return user; + } + + /* (non-Javadoc) + * @see org.alfresco.repo.webdav.auth.BaseNTLMAuthenticationFilter#onLoginComplete(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + */ + @Override + protected boolean onLoginComplete(HttpServletRequest req, HttpServletResponse res) + throws IOException + { + // If the original URL requested was the login page then redirect to the browse view + if (req.getRequestURI().endsWith(getLoginPage()) == true) + { + if (logger.isDebugEnabled()) + logger.debug("Login page requested, redirecting to browse page"); + + // Redirect to the browse view + res.sendRedirect(req.getContextPath() + "/faces/jsp/browse/browse.jsp"); + return false; + } + else + { + return true; + } + } /** * Return the login page address @@ -453,587 +373,12 @@ public class NTLMAuthenticationFilter extends AbstractAuthenticationFilter imple return m_loginPage; } - /** - * Delete the servlet filter + /* (non-Javadoc) + * @see org.alfresco.repo.webdav.auth.BaseNTLMAuthenticationFilter#getLogger() */ - public void destroy() + @Override + final protected Log getLogger() { - } - - /** - * Process a type 1 NTLM message - * - * @param type1Msg Type1NTLMMessage - * @param req HttpServletRequest - * @param resp HttpServletResponse - * @param httpSess HttpSession - * @exception IOException - */ - private void processType1(Type1NTLMMessage type1Msg, HttpServletRequest req, HttpServletResponse resp, - HttpSession httpSess) throws IOException - { - // Debug - - if ( logger.isDebugEnabled()) - logger.debug("Received type1 " + type1Msg); - - // Get the existing NTLM details - - NTLMLogonDetails ntlmDetails = null; - - if ( httpSess != null) - { - ntlmDetails = (NTLMLogonDetails) httpSess.getAttribute(NTLM_AUTH_DETAILS); - } - - // Check if cached logon details are available - - if ( ntlmDetails != null && ntlmDetails.hasType2Message() && ntlmDetails.hasNTLMHashedPassword() && - ntlmDetails.hasAuthenticationToken()) - { - // Get the authentication server type2 response - - Type2NTLMMessage cachedType2 = ntlmDetails.getType2Message(); - - byte[] type2Bytes = cachedType2.getBytes(); - String ntlmBlob = "NTLM " + new String(Base64.encodeBase64(type2Bytes)); - - // Debug - - if ( logger.isDebugEnabled()) - logger.debug("Sending cached NTLM type2 to client - " + cachedType2); - - // Send back a request for NTLM authentication - - resp.setHeader("WWW-Authenticate", ntlmBlob); - resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED); - - resp.flushBuffer(); - return; - } - else - { - // Clear any cached logon details - - httpSess.removeAttribute(NTLM_AUTH_DETAILS); - - // Set the 8 byte challenge for the new logon request - - byte[] challenge = null; - NTLMPassthruToken authToken = null; - - if ( m_authComponent.getNTLMMode() == NTLMMode.MD4_PROVIDER) - { - // Generate a random 8 byte challenge - - challenge = new byte[8]; - DataPacker.putIntelLong(m_random.nextLong(), challenge, 0); - } - else - { - // Get the client domain - - String domain = type1Msg.getDomain(); - if ( domain == null || domain.length() == 0) - domain = mapClientAddressToDomain( req.getRemoteAddr()); - else if ( logger.isDebugEnabled()) - logger.debug("Client domain " + domain); - - // Create an authentication token for the new logon - - authToken = new NTLMPassthruToken( domain); - - // Run the first stage of the passthru authentication to get the challenge - - m_authComponent.authenticate( authToken); - - // Get the challenge from the token - - if ( authToken.getChallenge() != null) - challenge = authToken.getChallenge().getBytes(); - } - - // Get the flags from the client request and mask out unsupported features - - int ntlmFlags = type1Msg.getFlags() & NTLM_FLAGS; - - // Build a type2 message to send back to the client, containing the challenge - - List tList = new ArrayList(); - tList.add(new TargetInfo(NTLM.TargetServer, m_srvName)); - - Type2NTLMMessage type2Msg = new Type2NTLMMessage(); - type2Msg.buildType2(ntlmFlags, m_srvName, challenge, null, tList); - - // Store the NTLM logon details, cache the type2 message, and token if using passthru - - ntlmDetails = new NTLMLogonDetails(); - ntlmDetails.setType2Message( type2Msg); - ntlmDetails.setAuthenticationToken(authToken); - - httpSess.setAttribute(NTLM_AUTH_DETAILS, ntlmDetails); - - // Debug - - if ( logger.isDebugEnabled()) - logger.debug("Sending NTLM type2 to client - " + type2Msg); - - // Send back a request for NTLM authentication - - byte[] type2Bytes = type2Msg.getBytes(); - String ntlmBlob = "NTLM " + new String(Base64.encodeBase64(type2Bytes)); - - resp.setHeader("WWW-Authenticate", ntlmBlob); - resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED); - - resp.flushBuffer(); - return; - } - } - - /** - * Process a type 3 NTLM message - * - * @param type3Msg Type3NTLMMessage - * @param req HttpServletRequest - * @param resp HttpServletResponse - * @param httpSess HttpSession - * @param chain FilterChain - * @exception IOException - * @exception ServletException - */ - private void processType3(Type3NTLMMessage type3Msg, HttpServletRequest req, HttpServletResponse resp, - HttpSession httpSess, FilterChain chain) throws IOException, ServletException - { - // Debug - - if ( logger.isDebugEnabled()) - logger.debug("Received type3 " + type3Msg); - - // Get the existing NTLM details - - NTLMLogonDetails ntlmDetails = null; - User user = null; - - if ( httpSess != null) - { - ntlmDetails = (NTLMLogonDetails) httpSess.getAttribute(NTLM_AUTH_DETAILS); - user = (User) httpSess.getAttribute(AuthenticationHelper.AUTHENTICATION_USER); - } - - // Get the NTLM logon details - - String userName = type3Msg.getUserName(); - String workstation = type3Msg.getWorkstation(); - String domain = type3Msg.getDomain(); - - boolean authenticated = false; - boolean useNTLM = true; - - // 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) - { - if ( ntlmPwd.length == cachedPwd.length) - { - authenticated = true; - for ( int i = 0; i < ntlmPwd.length; i++) - { - if ( ntlmPwd[i] != cachedPwd[i]) - authenticated = false; - } - } - } - - // Debug - - if ( logger.isDebugEnabled()) - logger.debug("Using cached NTLM hash, authenticated = " + authenticated); - - try - { - // Debug - - if ( logger.isDebugEnabled()) - logger.debug("User " + user.getUserName() + " validate ticket"); - - // Validate the user ticket - - m_authService.validate( user.getTicket()); - - // Set the current locale - - I18NUtil.setLocale(Application.getLanguage(httpSess)); - } - catch (AuthenticationException ex) - { - if ( logger.isErrorEnabled()) - logger.error("Failed to validate user " + user.getUserName(), ex); - - // Redirect to the login page - - resp.sendRedirect(req.getContextPath() + "/faces" + getLoginPage()); - return; - } - - // Allow the user to access the requested page - - chain.doFilter( req, resp); - return; - } - else - { - // Check if we are using local MD4 password hashes or passthru authentication - - if ( m_authComponent.getNTLMMode() == NTLMMode.MD4_PROVIDER) - { - // Check if guest logons are allowed and this is a guest logon - - if ( m_allowGuest == true && userName.equalsIgnoreCase( m_authComponent.getGuestUserName())) - { - // Indicate that the user has been authenticated - - authenticated = true; - - // Debug - - if ( logger.isDebugEnabled()) - logger.debug("Guest logon"); - } - else - { - // Get the stored MD4 hashed password for the user, or null if the user does not exist - - String md4hash = m_authComponent.getMD4HashedPassword(userName); - - if ( md4hash != null) - { - // Generate the local encrypted password using the challenge that was sent to the client - - byte[] p21 = new byte[21]; - byte[] md4byts = m_md4Encoder.decodeHash(md4hash); - System.arraycopy(md4byts, 0, p21, 0, 16); - - // Generate the local hash of the password using the same challenge - - byte[] localHash = null; - - try - { - localHash = m_encryptor.doNTLM1Encryption(p21, ntlmDetails.getChallengeKey()); - } - catch (NoSuchAlgorithmException ex) - { - } - - // Validate the password - - byte[] clientHash = type3Msg.getNTLMHash(); - - if ( clientHash != null && localHash != null && clientHash.length == localHash.length) - { - int i = 0; - - while ( i < clientHash.length && clientHash[i] == localHash[i]) - i++; - - if ( i == clientHash.length) - authenticated = true; - } - } - else - { - // Check if unknown users should be logged on as guest - - if ( m_mapUnknownUserToGuest == true) - { - // Reset the user name to be the guest user - - userName = m_authComponent.getGuestUserName(); - authenticated = true; - - // Debug - - if ( logger.isDebugEnabled()) - logger.debug("User " + userName + " logged on as guest, no Alfresco account"); - } - else - { - // Debug - - if ( logger.isDebugEnabled()) - logger.debug("User " + userName + " does not have Alfresco account"); - - // Bypass NTLM authentication and display the logon screen, user account does not - // exist in Alfresco - - authenticated = false; - } - } - } - } - else - { - // 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 - - m_authComponent.authenticate(authToken); - authenticated = true; - - // Check if the user has been logged on as guest - - if ( authToken.isGuestLogon()) - userName = m_authComponent.getGuestUserName(); - - // Set the authentication context - - m_authComponent.setCurrentUser( userName); - } - catch (BadCredentialsException ex) - { - // Debug - - if ( logger.isDebugEnabled()) - logger.debug("Authentication failed, " + ex.getMessage()); - } - catch (AuthenticationException ex) - { - // Debug - - 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) - { - UserTransaction tx = m_transactionService.getUserTransaction(); - NodeRef homeSpaceRef = null; - - try - { - tx.begin(); - - // Setup User object and Home space ID etc. - - NodeRef personNodeRef = m_personService.getPerson(userName); - - // Use the system user context to do the user lookup - - m_authComponent.setCurrentUser( m_authComponent.getSystemUserName()); - - // User name should match the uid in the person entry found - - m_authComponent.setSystemUserAsCurrentUser(); - userName = (String) m_nodeService.getProperty(personNodeRef, ContentModel.PROP_USERNAME); - - m_authComponent.setCurrentUser(userName); - String currentTicket = m_authService.getCurrentTicket(); - user = new User(userName, currentTicket, personNodeRef); - - homeSpaceRef = (NodeRef) m_nodeService.getProperty( personNodeRef, ContentModel.PROP_HOMEFOLDER); - user.setHomeSpaceId(homeSpaceRef.getId()); - - // Commit - - tx.commit(); - } - catch (Throwable ex) - { - try - { - tx.rollback(); - } - catch (Exception ex2) - { - logger.error("Failed to rollback transaction", ex2); - } - if(ex instanceof RuntimeException) - { - throw (RuntimeException)ex; - } - else if(ex instanceof IOException) - { - throw (IOException)ex; - } - else if(ex instanceof ServletException) - { - throw (ServletException)ex; - } - else - { - throw new RuntimeException("Authentication setup failed", ex); - } - } - - // Store the user - - httpSess.setAttribute(AuthenticationHelper.AUTHENTICATION_USER, user); - httpSess.setAttribute(LoginBean.LOGIN_EXTERNAL_AUTH, Boolean.TRUE); - - // Set the current locale from the Accept-Lanaguage header if available - - Locale userLocale = parseAcceptLanguageHeader(req, m_languages); - - if ( userLocale != null) - { - httpSess.setAttribute(LOCALE, userLocale); - httpSess.removeAttribute(MESSAGE_BUNDLE); - } - - // Set the locale using the session - - I18NUtil.setLocale(Application.getLanguage(httpSess)); - - // Update the NTLM logon details in the session - - if ( ntlmDetails == null) - { - // No cached NTLM details - - ntlmDetails = new NTLMLogonDetails( userName, workstation, domain, false, m_srvName); - - httpSess.setAttribute(NTLM_AUTH_DETAILS, ntlmDetails); - - // Debug - - if ( logger.isDebugEnabled()) - logger.debug("No cached NTLM details, created"); - - } - else - { - // Update the cached NTLM details - - ntlmDetails.setDetails(userName, workstation, domain, false, m_srvName); - ntlmDetails.setNTLMHashedPassword(type3Msg.getNTLMHash()); - - // Debug - - if ( logger.isDebugEnabled()) - logger.debug("Updated cached NTLM details"); - } - - // Debug - - if ( logger.isDebugEnabled()) - logger.debug("User logged on via NTLM, " + ntlmDetails); - - // If the original URL requested was the login page then redirect to the browse view - - if (req.getRequestURI().endsWith(getLoginPage()) == true) - { - // Debug - - if ( logger.isDebugEnabled()) - logger.debug("Login page requested, redirecting to browse page"); - - // Redirect to the browse view - - resp.sendRedirect(req.getContextPath() + "/faces/jsp/browse/browse.jsp"); - return; - } - else - { - // Allow the user to access the requested page - - chain.doFilter( req, resp); - return; - } - } - else - { - // Check if NTLM should be used, switched off if the user does not exist in the Alfresco - // user database - - if (useNTLM == true) - { - // Remove any existing session and NTLM details from the session - - httpSess.removeAttribute(NTLM_AUTH_SESSION); - httpSess.removeAttribute(NTLM_AUTH_DETAILS); - - // Force the logon to start again - - resp.setHeader("WWW-Authenticate", "NTLM"); - resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED); - - resp.flushBuffer(); - return; - } - else - { - // Debug - - if ( logger.isDebugEnabled()) - logger.debug("Redirecting to login page"); - - // Redirect to the login page - - resp.sendRedirect(req.getContextPath() + "/faces" + getLoginPage()); - return; - } - } - } - } - - /** - * Map a client IP address to a domain - * - * @param clientIP String - * @return String - */ - protected final String mapClientAddressToDomain( String clientIP) - { - // Check if there are any domain mappings - - if ( m_secConfig != null && m_secConfig.hasDomainMappings() == false) - return null; - - // convert the client IP address to an integer value - - int clientAddr = IPAddress.parseNumericAddress( clientIP); - for ( DomainMapping domainMap : m_secConfig.getDomainMappings()) - { - if ( domainMap.isMemberOfDomain( clientAddr)) - { - // DEBUG - - if ( logger.isDebugEnabled()) - logger.debug( "Mapped client IP " + clientIP + " to domain " + domainMap.getDomain()); - - return domainMap.getDomain(); - } - } - - // DEBUG - - if ( logger.isDebugEnabled()) - logger.debug( "Failed to map client IP " + clientIP + " to a domain"); - - // No domain mapping for the client address - - return null; + return logger; } } diff --git a/source/java/org/alfresco/web/bean/repository/User.java b/source/java/org/alfresco/web/bean/repository/User.java index cc52c35247..a3f088a516 100644 --- a/source/java/org/alfresco/web/bean/repository/User.java +++ b/source/java/org/alfresco/web/bean/repository/User.java @@ -35,6 +35,7 @@ import javax.transaction.UserTransaction; import org.alfresco.error.AlfrescoRuntimeException; import org.alfresco.model.ApplicationModel; import org.alfresco.model.ContentModel; +import org.alfresco.repo.SessionUser; import org.alfresco.repo.configuration.ConfigurableService; import org.alfresco.service.ServiceRegistry; import org.alfresco.service.cmr.repository.ChildAssociationRef; @@ -52,7 +53,7 @@ import org.springframework.web.jsf.FacesContextUtils; * * @author gavinc */ -public final class User implements Serializable +public final class User implements SessionUser { private static final long serialVersionUID = -90577901805847829L;