cancel
Showing results for 
Search instead for 
Did you mean: 

Authentication Chains

clynham
Champ in-the-making
Champ in-the-making
Hi,

I'm trying to setup an authentication chain in Alfreso 3.2.

I successfully managed to get LDAP working using:

authentication.chain=alfrescoNtlm1:alfrescoNtlm,ldap1:ldap 

and confiduring the LDAP properties file.  I now need to move this a step further by enabling CIFS authentication using Passthru.  I've amended the chain to read:

authentication.chain=alfrescoNtlm1:alfrescoNtlm,ldap1:ldap,passthru1:passthru

and configured the passthru properties file as follows:

passthru.authentication.useLocalServer=false
passthru.authentication.domain=DOMAINNAME
passthru.authentication.servers=NAMEOFDOMAINCONTROLLER
passthru.authentication.guestAccess=false
passthru.authentication.defaultAdministratorUserNames=administrator,admin
#Timeout value when opening a session to an authentication server, in milliseconds
passthru.authentication.connectTimeout=5000
#Offline server check interval in seconds
passthru.authentication.offlineCheckInterval=300
passthru.authentication.protocolOrder=NetBIOS,TCPIP
passthru.authentication.authenticateCIFS=true
passthru.authentication.authenticateFTP=false

However when calling up the Alfresco login page I get the following error:

net.sf.acegisecurity.AuthenticationServiceException: Failed to open passthru auth session 
at org.alfresco.repo.security.authentication.ntlm.NTLMAuthenticationComponentImpl.authenticatePassthru(NTLMAuthenticationComponentImpl.java:789)
at org.alfresco.repo.security.authentication.ntlm.NTLMAuthenticationComponentImpl.authenticate(NTLMAuthenticationComponentImpl.java:560)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:304)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at $Proxy190.authenticate(Unknown Source)
at org.alfresco.repo.webdav.auth.BaseNTLMAuthenticationFilter.processType1(BaseNTLMAuthenticationFilter.java:423)
at org.alfresco.repo.webdav.auth.BaseNTLMAuthenticationFilter.doFilter(BaseNTLMAuthenticationFilter.java:332)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.alfresco.repo.management.subsystems.ChainingSubsystemProxyFactory$1.invoke(ChainingSubsystemProxyFactory.java:109)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at $Proxy194.doFilter(Unknown Source)
at org.alfresco.repo.web.filter.beans.BeanProxyFilter.doFilter(BeanProxyFilter.java:88)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:845)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
at java.lang.Thread.run(Thread.java:619)

Can anyone help?

Many thanks!
23 REPLIES 23

nuttinjeff
Champ in-the-making
Champ in-the-making
nuttinjef

NTLM v2 just can't be proxied like NTLM v1 as it is designed to prevent 'man-in-the-middle' attacks.

So your options are:

1. Enable NTLM v1 on the Vista machines
http://www.technologyquestions.com/technology/windows-vista/50823-force-ntlm-vista-home-premium.html
2. Use the alfrescoNtlm subsystem instead. This supports NTLM v2 but will require alfresco to store its own copy of the user password. You can switch on NTLM v2 SSO with
authentication.chain=alfrescoNtlm1:alfrescoNtlm
ntlm.authentication.sso.enabled=true
3. Switch off SSO with the passthru subsystem
ntlm.authentication.sso.enabled=false

Thanks again dward, it did the trick, now both CIFS and Vista/IE clients are working (no SSO, but working).

paulweb
Champ in-the-making
Champ in-the-making
Server: os centos 5.2
Alfresco: latest version (upload 6 septemper 2009)

Client: os win xp
For authentication using NTLMv2 and for test NTLMv1

1. Enable NTLM v1 on the Vista machines
http://www.technologyquestions.com/tech … emium.html

For the organization it is not correct because of safety

2. Use the alfrescoNtlm subsystem instead. This supports NTLM v2 but will require alfresco to store its own copy of the user password. You can switch on NTLM v2 SSO with
authentication.chain=alfrescoNtlm1:alfrescoNtlm
ntlm.authentication.sso.enabled=true
3. Switch off SSO with the passthru subsystem
ntlm.authentication.sso.enabled=false

Ok. I have set following chain (for test) alfrescoNtlm1:alfrescoNtlm,passthru1Smiley Tongueassthru, ldap1:ldap-ad with dward recommendations

Then steps:
I am
1. I start up alfresco
Alfresco
2. add people from ad to alfresco without password
I am
3. in browser I enter address http://localhost:8080/alfresco
Alfresco
4. get ntlm query (pass and username)
5. Tries to find for itself username with pass
View code

protected void processType3(Type3NTLMMessage type3Msg, ServletContext context, HttpServletRequest req, HttpServletResponse res,
            HttpSession session, FilterChain chain) 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;
       
        if (session != null)
        {
            ntlmDetails = (NTLMLogonDetails)session.getAttribute(NTLM_AUTH_DETAILS);
            user = getSessionUser(session);
        }
       
        // Get the NTLM logon details
        String userName = type3Msg.getUserName();
        String workstation = type3Msg.getWorkstation();
        String domain = type3Msg.getDomain();
       
        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);
           
            try
            {
                if (logger.isDebugEnabled())
                    logger.debug("User " + user.getUserName() + " validate ticket");
               
                // Validate the user ticket
                authenticationService.validate(user.getTicket());
               
                onValidate(context, req, res);
            }
            catch (AuthenticationException ex)
            {
                if (logger.isErrorEnabled())
                    logger.error("Failed to validate user " + user.getUserName(), ex);
               
                removeSessionUser(session);
               
                onValidateFailed(req, res, session);
                return;
            }
           
            // Allow the user to access the requested page
            chain.doFilter(req, res);
            return;
        }
        else
        {
            // 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()))
                {
                    // 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);
                    }
                    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;
                           
                            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
                            authenticated = false;
                        }
                    }
                }
            }
            else
            {
                //  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
                {
                    // 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)
            {
                if (user == null)
                {
                    user = createUserEnvironment(session, userName);
                }
                else
                {
                    // user already exists - revalidate ticket to authenticate the current user thread
                    try
                    {
                        authenticationService.validate(user.getTicket());
                    }
                    catch (AuthenticationException ex)
                    {
                        if (logger.isErrorEnabled())
                            logger.error("Failed to validate user " + user.getUserName(), ex);
                       
                        removeSessionUser(session);
                       
                        onValidateFailed(req, res, session);
                        return;
                    }
                }
               
                onValidate(context, req, res);
               
                // 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(req, res))
                {
                    // Allow the user to access the requested page
                    chain.doFilter(req, res);
                }
            }
            else
            {
                restartLoginChallenge(res, session);
            }
        }
    }
6. As there is only a user, and the password, to which it is necessary to compare, there is not, that is received the following

View log

11:43:51,317 DEBUG [org.alfresco.web.app.servlet.NTLMAuthenticationFilter] New NTLM auth request from 127.0.0.1 (127.0.0.1:3990) SID:62AD906989E08668F737B80C4458B865
11:43:51,333 DEBUG [org.alfresco.web.app.servlet.NTLMAuthenticationFilter] Received type1 [Type1:0xa208b207,Domain:MY-DOMAIN,Wks:ITPROGVENG2]
11:43:51,348 DEBUG [org.alfresco.web.app.servlet.NTLMAuthenticationFilter] Sending NTLM type2 to client - [Type2:0xa0080201,Target:ITPROGVENG2A,Ch:23a24d4bb9e6d775]
11:43:51,348 DEBUG [org.alfresco.web.app.servlet.NTLMAuthenticationFilter] Received type3 [Type3:,LM:40a9dce061ef41d200000000000000000000000000000000,NTLM:5d67d431322f129dd8d35e17f9af1a22faf0242775fdaa55,Dom:MY-DOMAIN,User:p.web,Wks:ITPROGVENG2]
11:43:51,379 DEBUG [org.alfresco.web.app.servlet.NTLMAuthenticationFilter] User p.web does not have Alfresco account
7. Access to the user is denied

I do not know there can be it and should transfer further on a chain, but for me with the given version does not work

P.S: dward sync work normal. Thanks.

dward
Champ on-the-rise
Champ on-the-rise
Just to point out - if you use alfrescoNtlm, you can't use LDAP sync. The users created by LDAP sync do not have their password information stored in alfresco.

paulweb
Champ in-the-making
Champ in-the-making
use kerberos

paulweb
Champ in-the-making
Champ in-the-making
If to use a chain alfrescoNtlm1:alfrescoNtlm,passthru1Smiley Tongueassthru then NTLMv2 will work?

dward
Champ on-the-rise
Champ on-the-rise
The chain you just mentioned would only work if you switched off SSO with

ntlm.authentication.sso.enabled=false

Then you could have password-based login for Alfresco internal users and Windows domain users.

But NTLM wouldn't work for all users, because NTLM SSO cannot be chained.

And you'd have to decide whether you wanted Alfresco or Windows to authenticate CIFS. Not all users would be able to use CIFS.

jc09
Champ in-the-making
Champ in-the-making
Hello,

An other problem for me.
I shall want that all the users who want to reach Alfresco by the WEB interface are identified by a LDAP authentification and that only the Windows domain users (included in AD) can use the access in CIFS like this :

[img]http://easycaptures.com/fs/uploaded/354/3205637094.jpg[/img]

If I use this : authentication-chain = ldap1:ldap,passthru1Smiley Tongueassthru

Do you think that it will work? Which keys I have to define in the file alfresco-global.properties ?

dward
Champ on-the-rise
Champ on-the-rise
Nice picture.

Yes I think it will work. Assuming that you have 2 non-AD LDAP servers, plus 1 AD server you will need the following in alfresco-global.properties

authentication.chain=ldap1:ldap,ldap2:ldap,passthru1Smiley Tongueassthru

ntlm.authentication.sso.enabled=false # Chained authentication, so we can't use NTLM
passthru.authentication.domain=# Leave blank
passthru.authentication.servers=YOURDOMAIN\adserver.com,adserver.com
passthru.authentication.authenticateFTP=false # If you want chained FTP authentication

The properties for the individual LDAP servers will have to be set as per

http://wiki.alfresco.com/wiki/Alfresco_Authentication_Subsystems#Example_2:_Advanced_LDAP_Chain

But please note that you will need a v3.2 nighly build in order for this to work.

nuttinjeff
Champ in-the-making
Champ in-the-making
Yes, It will work like dward said.

I'm using Alfresco configured like this.

jc09
Champ in-the-making
Champ in-the-making
Nice picture.

Yes I think it will work. Assuming that you have 2 non-AD LDAP servers, plus 1 AD server you will need the following in alfresco-global.properties

authentication.chain=ldap1:ldap,ldap2:ldap,passthru1Smiley Tongueassthru

ntlm.authentication.sso.enabled=false # Chained authentication, so we can't use NTLM
passthru.authentication.domain=# Leave blank
passthru.authentication.servers=YOURDOMAIN\adserver.com,adserver.com
passthru.authentication.authenticateFTP=false # If you want chained FTP authentication

The properties for the individual LDAP servers will have to be set as per

http://wiki.alfresco.com/wiki/Alfresco_Authentication_Subsystems#Example_2:_Advanced_LDAP_Chain

But please note that you will need a v3.2 nighly build in order for this to work.

Thank you very much for this answer.

What I forgot to specify, it is that OVD corresponds to the LDAP server allowing the authentification for the Web access.
Its relation with the other LDAP server (included AD) is already organized.

Does this precision change anything in your answer? the ldap2 is still necessary ?
How Alfresco knows which subsystem to use to authenticate either by Web or by CIFS with this configuration ?

Thank you one more time