cancel
Showing results for 
Search instead for 
Did you mean: 

Alfresco 1.3 (fresh from svn) + NTLM authentication

d_baijot
Champ in-the-making
Champ in-the-making
Hi,

I'm trying to setup alfresco so that authentication is done through NTLM.
My alfresco-tomcat-server is running on a linux box outside the windows domain and my configuration follows the one described in the wiki (http://wiki.alfresco.com/wiki/Configuring_NTLM)… in web.xml and in alfresco/extension/ntlm-authentication-context.xml.

When i strictly follows the tutorial, i get a "spring circular reference" thrown at startup.
When i remove the ioc for "personService" and "nodeService" attributes, the application starts, but NullPointers occurs at runtime.

does the personService and nodeService beans need to be changed in order to work with alfresco 1.3 and NTLM ?

Best Regards
Dany.
13 REPLIES 13

d_baijot
Champ in-the-making
Champ in-the-making
when accessing the personService and nodeService through an "ApplicationContextAware' bean, the NTLM login works great…

Does somebody from alfresco can help ?

Here is the code is used…

Best regards
Dany.


ntlm-authentication-context.xml:

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>

<beans>

    <bean id="authenticationDao" class="org.alfresco.repo.security.authentication.ntlm.NullMutableAuthenticationDao" />

    <!– The authentication component.                                      –>

    <!– Use the passthru authentication component to authenticate using    –>
    <!– user accounts on one or more Windows servers.                      –>
   
    <!– Properties that specify the server(s) to use for passthru          –>
    <!– authentication :-                                                  –>
    <!–   useLocalServer   use the local server for authentication         –>
    <!–   domain           use domain controllers from the specified domain–>
    <!–   servers          comma delimted list of server addresses or      –>
    <!–                    names                                           –>
      
      
    <bean id="beanService" class="org.alfresco.repo.security.authentication.ntlm.MyApplicationContextAware" />
    
      
    <bean id="authenticationComponentImpl" class="org.alfresco.repo.security.authentication.ntlm.NTLMAuthenticationComponentImpl">
        <property name="useLocalServer">
            <value>false</value>
        </property>

        <property name="servers">
            <value>192.168.97.1</value>
        </property>

<!–       
        <property name="personService">
            <ref bean="personService" />
        </property>
        <property name="nodeService">
            <ref bean="nodeService" />
        </property>
–>

        <property name="guestAccess">
            <value>false</value>
        </property>
    </bean>
</beans>

MyApplicationContextAware.java:

package org.alfresco.repo.security.authentication.ntlm;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
* This "spring" bean has acces to the spring's application context and is able
* to find other bean's using their name.
*
* @author baijoda
*/
public final class MyApplicationContextAware implements ApplicationContextAware {

   private static final Log LOG = LogFactory.getLog(MyApplicationContextAware.class);

   private static ApplicationContext context;

   /**
    * setter for spring framework. called when spring initialize its
    * application context aware beans.
    *
    * @param aContext
    *            spring application context
    */
   public void setApplicationContext(ApplicationContext aContext) {
      if (LOG.isDebugEnabled()) {
         LOG.debug("setting context to MyApplicationContextAware…");
      }
      MyApplicationContextAware.context = aContext;
   }

   /**
    * Retrieve beans declared with a non 'interface' name from
    * applicationContext (only).<br/> Use getNamedBean(String bean, Class
    * clazz) to retrieve a named bean from a 'package' config.xml file.
    *
    * @param beanName
    *            bean's name
    * @return a bean impl
    */
   public static Object getNamedBean(String beanName) {
      return context.getBean(beanName);
   }
}

NTLMAuthenticationComponentImpl.java:

/*

* Copyright (C) 2005-2006 Alfresco, Inc.

*

* Licensed under the Mozilla Public License version 1.1

* with a permitted attribution clause. You may obtain a

* copy of the License at

*

*   http://www.alfresco.org/legal/license.txt

*

* Unless required by applicable law or agreed to in writing,

* software distributed under the License is distributed on an

* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,

* either express or implied. See the License for the specific

* language governing permissions and limitations under the

* License.

*/

package org.alfresco.repo.security.authentication.ntlm;



import java.io.IOException;

import java.net.InetAddress;

import java.net.UnknownHostException;

import java.security.InvalidKeyException;

import java.security.NoSuchAlgorithmException;

import java.security.Provider;

import java.security.Security;

import java.util.Enumeration;

import java.util.Hashtable;



import net.sf.acegisecurity.Authentication;

import net.sf.acegisecurity.AuthenticationServiceException;

import net.sf.acegisecurity.BadCredentialsException;

import net.sf.acegisecurity.CredentialsExpiredException;

import net.sf.acegisecurity.GrantedAuthority;

import net.sf.acegisecurity.GrantedAuthorityImpl;



import org.alfresco.error.AlfrescoRuntimeException;

import org.alfresco.filesys.server.auth.PasswordEncryptor;

import org.alfresco.filesys.server.auth.passthru.AuthenticateSession;

import org.alfresco.filesys.server.auth.passthru.PassthruServers;

import org.alfresco.filesys.smb.SMBException;

import org.alfresco.filesys.smb.SMBStatus;

import org.alfresco.model.ContentModel;

import org.alfresco.repo.security.authentication.AbstractAuthenticationComponent;

import org.alfresco.repo.security.authentication.AuthenticationException;

import org.alfresco.repo.security.authentication.NTLMMode;

import org.alfresco.service.cmr.repository.NodeRef;

import org.alfresco.service.cmr.repository.NodeService;

import org.alfresco.service.cmr.security.PersonService;

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;



/**

* NTLM Authentication Component Class

*

* <p>Provides authentication using passthru to a Windows server(s)/domain controller(s) using the accounts

* defined on the passthru server to validate users.

*

* @author GKSpencer

*/

public class NTLMAuthenticationComponentImpl extends AbstractAuthenticationComponent

{

    // Logging

   

    private static final Log logger = LogFactory.getLog("org.alfresco.passthru.auth");



    // Constants

    //

    // Standard authorities

   

    public static final String NTLMAuthorityGuest         = "Guest";

    public static final String NTLMAuthorityAdministrator = "Administrator";

   

    // Active session timeout

   

    private static final long DefaultSessionTimeout = 60000L;   // 1 minute

    private static final long MinimumSessionTimeout = 5000L;    // 5 seconds

   

    // Passthru authentication servers

   

    private PassthruServers m_passthruServers;

   

    // Password encryptor for generating password hash for local authentication

   

    private PasswordEncryptor m_encryptor;

   

    // Allow guest access

   

    private boolean m_allowGuest;

   

    // Table of currently active passthru authentications and the associated authentication session

    //

    // If the two authentication stages are not completed within a reasonable time the authentication

    // session will be closed by the reaper thread.

   

    private Hashtable<NTLMPassthruToken,AuthenticateSession> m_passthruSessions;

   

    // Active authentication session timeout, in milliseconds

   

    private long m_passthruSessTmo = DefaultSessionTimeout;

   

    // Authentication session reaper thread

   

    private PassthruReaperThread m_reaperThread;

   

    /**

     * Passthru Session Reaper Thread

     */

    class PassthruReaperThread extends Thread

    {

        // Thread shutdown request flag

       

        private boolean m_ishutdown;



        // Reaper wakeup interval, in milliseconds

       

        private long m_wakeupInterval = m_passthruSessTmo / 2;

       

        /**

         * Default constructor

         */

        PassthruReaperThread()

        {

            setDaemon(true);

            setName("PassthruReaper");

            start();

        }

       

        /**

         * Set the wakeup interval

         *

         * @param wakeup long

         */

        public final void setWakeup(long wakeup)

        {

            m_wakeupInterval = wakeup;

        }

       

        /**

         * Main thread code

         */

        public void run()

        {

            // Loop until shutdown

           

            m_ishutdown = false;

           

            while ( m_ishutdown == false)

            {

                // Sleep for a while

               

                try

                {

                    sleep( m_wakeupInterval);

                }

                catch ( InterruptedException ex)

                {

                }

               

                // Check if there are any active sessions to check

               

                if ( m_passthruSessions.size() > 0)

                {

                    // Enumerate the active sessions

                   

                    Enumeration<NTLMPassthruToken> tokenEnum = m_passthruSessions.keys();

                    long timeNow = System.currentTimeMillis();

                   

                    while (tokenEnum.hasMoreElements())

                    {

                        // Get the current NTLM token and check if it has expired

                       

                        NTLMPassthruToken ntlmToken = tokenEnum.nextElement();

                       

                        if ( ntlmToken != null && ntlmToken.getAuthenticationExpireTime() < timeNow)

                        {

                            // Authentication token has expired, close the associated authentication session

                           

                            AuthenticateSession authSess = m_passthruSessions.get(ntlmToken);

                            if ( authSess != null)

                            {

                                try

                                {

                                    // Close the authentication session

                                   

                                    authSess.CloseSession();

                                }

                                catch ( Exception ex)

                                {

                                    // Debug

                                   

                                    if(logger.isDebugEnabled())

                                        logger.debug("Error closing expired authentication session", ex);

                                }

                            }

                           

                            // Remove the expired token from the active list

                           

                            m_passthruSessions.remove(ntlmToken);

                           

                            // Debug

                           

                            if(logger.isDebugEnabled())

                                logger.debug("Removed expired NTLM token " + ntlmToken);

                        }

                    }

                }

            }

           

            // Debug

           

            if(logger.isDebugEnabled())

                logger.debug("Passthru reaper thread shutdown");

        }

       

        /**

         * Shutdown the reaper thread

         */

        public final void shutdownRequest()

        {

            m_ishutdown = true;

            this.interrupt();

        }

    }



    /**

     * Class constructor

     */

    public NTLMAuthenticationComponentImpl() {

       

        // Create the passthru authentication server list

       

        m_passthruServers = new PassthruServers();

       

        // Create the password encryptor for local password hashing

       

        m_encryptor = new PasswordEncryptor();

       

        // Create the active session list and reaper thread

       

        m_passthruSessions = new Hashtable<NTLMPassthruToken,AuthenticateSession>();

        m_reaperThread = new PassthruReaperThread();

    }



    /**

     * Determine if guest logons are allowed

     *

     * @return boolean

     */

    public final boolean allowsGuest()

    {

        return m_allowGuest;

    }

   

    /**

     * Set the domain to authenticate against

     *

     * @param domain String

     */

    public void setDomain(String domain) {

       

        // Check if the passthru server list is already configured

       

        if ( m_passthruServers.getTotalServerCount() > 0)

            throw new AlfrescoRuntimeException("Passthru server list already configured");

       

        // Configure the passthru authentication server list using the domain controllers

       

        m_passthruServers.setDomain(domain);

    }

   

    /**

     * Set the server(s) to authenticate against

     *

     * @param servers String

     */

    public void setServers(String servers) {

       

        // Check if the passthru server list is already configured

       

        if ( m_passthruServers.getTotalServerCount() > 0)

            throw new AlfrescoRuntimeException("Passthru server list already configured");

       

        // Configure the passthru authenticaiton list using a list of server names/addresses

       

        m_passthruServers.setServerList(servers);

    }

   

    /**

     * Use the local server as the authentication server

     *

     * @param useLocal String

     */

    public void setUseLocalServer(String useLocal)

    {

        // Check if the local server should be used for authentication

       

        if ( Boolean.parseBoolean(useLocal) == true)

        {

            // Check if the passthru server list is already configured

           

            if ( m_passthruServers.getTotalServerCount() > 0)

                throw new AlfrescoRuntimeException("Passthru server list already configured");



            try

            {

                // Get the list of local network addresses

               

                InetAddress[] localAddrs = InetAddress.getAllByName(InetAddress.getLocalHost().getHostName());

               

                // Build the list of local addresses

               

                if ( localAddrs != null && localAddrs.length > 0)

                {

                    StringBuilder addrStr = new StringBuilder();

               

                    for ( InetAddress curAddr  : localAddrs)

                    {

                        if ( curAddr.isLoopbackAddress() == false)

                        {

                            addrStr.append(curAddr.getHostAddress());

                            addrStr.append(",");

                        }

                    }

                   

                    if ( addrStr.length() > 0)

                        addrStr.setLength(addrStr.length() - 1);

                   

                    // Set the server list using the local address list

                   

                    m_passthruServers.setServerList(addrStr.toString());

                }

                else

                    throw new AlfrescoRuntimeException("No local server address(es)");

            }

            catch ( UnknownHostException ex)

            {

                throw new AlfrescoRuntimeException("Failed to get local address list");

            }

        }

    }

   

    /**

     * Allow guest access

     *

     * @param guest String

     */

    public void setGuestAccess(String guest)

    {

        m_allowGuest = Boolean.parseBoolean(guest);

    }

   

    /**

     * Set the JCE provider

     *

     * @param providerClass String

     */

    public void setJCEProvider(String providerClass)

    {

        // Set the JCE provider, required to provide various encryption/hashing algorithms not available

        // in the standard Sun JDK/JRE

       

        try

        {



            // Load the JCE provider class and validate



            Object jceObj = Class.forName(providerClass).newInstance();

            if (jceObj instanceof java.security.Provider)

            {



                // Inform listeners, validate the configuration change



                Provider jceProvider = (Provider) jceObj;



                // Add the JCE provider



                Security.addProvider(jceProvider);

               

                // Debug

               

                if ( logger.isDebugEnabled())

                    logger.debug("Using JCE provider " + providerClass);

            }

            else

            {

                throw new AlfrescoRuntimeException("JCE provider class is not a valid Provider class");

            }

        }

        catch (ClassNotFoundException ex)

        {

            throw new AlfrescoRuntimeException("JCE provider class " + providerClass + " not found");

        }

        catch (Exception ex)

        {

            throw new AlfrescoRuntimeException("JCE provider class error", ex);

        }

    }

   

    /**

     * Set the authentication session timeout, in seconds

     *

     * @param sessTmo String

     */

    public void setSessionTimeout(String sessTmo)

    {

        // Convert to an integer value and range check the timeout value

       

        try

        {

            // Convert to an integer value

           

            long sessTmoMilli = Long.parseLong(sessTmo) * 1000L;

           

            if ( sessTmoMilli < MinimumSessionTimeout)

                throw new AlfrescoRuntimeException("Authentication session timeout too low, " + sessTmo);

           

            // Set the authentication session timeout value

           

            m_passthruSessTmo = sessTmoMilli;

           

            // Set the reaper thread wakeup interval

           

            m_reaperThread.setWakeup( sessTmoMilli / 2);

        }

        catch(NumberFormatException ex)

        {

            throw new AlfrescoRuntimeException("Invalid authenication session timeout value");

        }

    }

   

    /**

     * Return the authentication session timeout, in milliseconds

     *

     * @return long

     */

    private final long getSessionTimeout()

    {

        return m_passthruSessTmo;

    }

   

    /**

     * Authenticate

     *

     * @param userName String

     * @param password char[]

     * @throws AuthenticationException

     */    

    public void authenticate(String userName, char[] password) throws AuthenticationException

    {

        // Debug

       

        if ( logger.isDebugEnabled())

            logger.debug("Authenticate user=" + userName + " via local credentials");

       

        // Create a local authentication token

       

        NTLMLocalToken authToken = new NTLMLocalToken(userName, new String(password));

       

        // Authenticate using the token

       

        authenticate( authToken);

        setCurrentUser( userName.toLowerCase());

    }



    /**

     * Authenticate using a token

     *

     * @param token Authentication

     * @return Authentication

     * @throws AuthenticationException

     */

    public Authentication authenticate(Authentication auth) throws AuthenticationException

    {

        // DEBUG

       

        if ( logger.isDebugEnabled())

            logger.debug("Authenticate " + auth + " via token");

       

        // Check if the token is for passthru authentication

       

        if( auth instanceof NTLMPassthruToken)

        {

            // Access the NTLM passthru token

           

            NTLMPassthruToken ntlmToken = (NTLMPassthruToken) auth;

           

            // Authenticate using passthru

           

            authenticatePassthru(ntlmToken);

        }



        // Check for a local authentication token

       

        else if( auth instanceof NTLMLocalToken)

        {

            AuthenticateSession authSess = null;

           

            try

            {



                // Access the NTLM token

               

                NTLMLocalToken ntlmToken = (NTLMLocalToken) auth;

   

                // Open a session to an authentication server

               

                authSess = m_passthruServers.openSession();

               

                // Authenticate using the credentials supplied

                   

                authenticateLocal(ntlmToken, authSess);

            }

            finally

            {

                // Make sure the authentication session is closed

               

                if ( authSess != null)

                {

                    try

                    {

                        authSess.CloseSession();

                    }

                    catch ( Exception ex)

                    {

                    }

                }

            }

        }

        else

        {

            // Unsupported authentication token

           

            throw new AuthenticationException("Unsupported authentication token type");

        }



        // Return the updated authentication token

       

        return getCurrentAuthentication();

    }

   

    /**

     * Get the enum that describes NTLM integration

     *

     * @return NTLMMode

     */

    public NTLMMode getNTLMMode()

    {

        return NTLMMode.PASS_THROUGH;

    }



    /**

     * Get the MD4 password hash, as required by NTLM based authentication methods.

     *

     * @param userName String

     * @return String

     */

    public String getMD4HashedPassword(String userName)

    {

        // Do not support MD4 hashed password

       

        throw new AlfrescoRuntimeException("MD4 passwords not supported");

    }

   

    /**

     * Authenticate a user using local credentials

     *

     * @param ntlmToken NTLMLocalToken

     * @param authSess AuthenticateSession

     */

    private void authenticateLocal(NTLMLocalToken ntlmToken, AuthenticateSession authSess)

    {

        try

        {

            // Get the plaintext password and generate an NTLM1 password hash

           

            String username = (String) ntlmToken.getPrincipal();

            String plainPwd = (String) ntlmToken.getCredentials();

            byte[] ntlm1Pwd = m_encryptor.generateEncryptedPassword( plainPwd, authSess.getEncryptionKey(), PasswordEncryptor.NTLM1, null, null);

           

            // Send the logon request to the authentication server

            //

            // Note: Only use the stronger NTLM hash, we do not send the LM hash

           

            authSess.doSessionSetup(username, null, ntlm1Pwd);

           

            // Check if the session has logged on as a guest

           

            if ( authSess.isGuest() || username.equalsIgnoreCase("GUEST"))

            {

                // If guest access is enabled add a guest authority to the token

               

                if ( allowsGuest())

                {

                    // Set the guest authority

                   

                    GrantedAuthority[] authorities = new GrantedAuthority[2];

                    authorities[0] = new GrantedAuthorityImpl(NTLMAuthorityGuest);

                    authorities[1] = new GrantedAuthorityImpl("ROLE_AUTHENTICATED");

                   

                    ntlmToken.setAuthorities(authorities);

                }

                else

                {

                    // Guest access not allowed

                   

                    throw new AuthenticationException("Guest logons disabled");

                }

            }

            else

            {

                // Set authorities

               

                GrantedAuthority[] authorities = new GrantedAuthority[1];

                authorities[0] = new GrantedAuthorityImpl("ROLE_AUTHENTICATED");

               

                ntlmToken.setAuthorities(authorities);

            }

           

            // Indicate that the token is authenticated

           

            ntlmToken.setAuthenticated(true);

           

            // Map the passthru username to an Alfresco person

           

            //HACK dany

            PersonService m_personService = (PersonService) MyApplicationContextAware.getNamedBean("personService");

            NodeService m_nodeService = (NodeService) MyApplicationContextAware.getNamedBean("nodeService");

            //HACK dany

           

            NodeRef userNode = m_personService.getPerson(username);

            if ( userNode != null)

            {

                // Get the person name and use that as the current user to line up with permission checks

               

                String personName = (String) m_nodeService.getProperty(userNode, ContentModel.PROP_USERNAME);

                setCurrentUser(personName);

               

                // DEBUG

               

                if ( logger.isDebugEnabled())

                    logger.debug("Setting current user using person " + personName + " (username " + username + ")");

            }

            else

            {

                // Set using the user name, lowercase the name if hte person service is case insensitive

               

                if ( m_personService.getUserNamesAreCaseSensitive() == false)

                    username = username.toLowerCase();

                setCurrentUser( username);

               

                // DEBUG

               

                if ( logger.isDebugEnabled())

                    logger.debug("Setting current user using username " + username);

            }

           

            // Debug

           

            if ( logger.isDebugEnabled())

                logger.debug("Authenticated token=" + ntlmToken);

        }

        catch (NoSuchAlgorithmException ex)

        {

            // JCE provider does not have the required encryption/hashing algorithms

           

            throw new AuthenticationServiceException("JCE provider error", ex);

        }

        catch (InvalidKeyException ex)

        {

            // Problem creating key during encryption

           

            throw new AuthenticationServiceException("Invalid key error", ex);

        }

        catch (IOException ex)

        {

            // Error connecting to the authentication server

           

            throw new AuthenticationServiceException("I/O error", ex);

        }

        catch (SMBException ex)

        {

            // Check the returned status code to determine why the logon failed and throw an appropriate exception

           

            if ( ex.getErrorClass() == SMBStatus.NTErr)

            {

                AuthenticationException authEx = null;

               

                switch( ex.getErrorCode())

                {

                case SMBStatus.NTLogonFailure:

                    authEx = new AuthenticationException("Logon failure");

                    break;

                case SMBStatus.NTAccountDisabled:

                    authEx = new AuthenticationException("Account disabled");

                    break;

                default:

                    authEx = new AuthenticationException("Logon failure");

                break;

                }

               

                throw authEx;

            }

            else

                throw new AuthenticationException("Logon failure");

        }

    }

   

    /**

     * Authenticate using passthru authentication with a client

     *

     * @param ntlmToken NTLMPassthruToken

     */

    private void authenticatePassthru(NTLMPassthruToken ntlmToken)

    {

        // Check if the token has an authentication session, if not then it is either a new token

        // or the session has been timed out

       

        AuthenticateSession authSess = m_passthruSessions.get(ntlmToken);

       

        if ( authSess == null)

        {

            // Check if the token has a challenge, if it does then the associated session has been

            // timed out

           

            if ( ntlmToken.getChallenge() != null)

                throw new CredentialsExpiredException("Authentication session expired");

           

            // Open an authentication session for the new token and add to the active session list

           

            authSess = m_passthruServers.openSession();

           

            ntlmToken.setAuthenticationExpireTime(System.currentTimeMillis() + getSessionTimeout());

           

            // Get the challenge from the initial session negotiate stage

           

            ntlmToken.setChallenge(new NTLMChallenge(authSess.getEncryptionKey()));



            StringBuilder details = new StringBuilder();



            // Build a details string with the authentication session details

           

            details.append(authSess.getDomain());

            details.append("\\");

            details.append(authSess.getPCShare().getNodeName());

            details.append(",");

            details.append(authSess.getSession().getProtocolName());

           

            ntlmToken.setDetails(details.toString());



            // Put the token/session into the active session list

           

            m_passthruSessions.put(ntlmToken, authSess);

           

            // Debug

           

            if ( logger.isDebugEnabled())

                logger.debug("Passthru stage 1 token " + ntlmToken);

        }

        else

        {

            try

            {

                // Stage two of the authentication, send the hashed password to the authentication server

           

                byte[] lmPwd = null;

                byte[] ntlmPwd = null;

               

                if ( ntlmToken.getPasswordType() == PasswordEncryptor.LANMAN)

                    lmPwd = ntlmToken.getHashedPassword();

                else if ( ntlmToken.getPasswordType() == PasswordEncryptor.NTLM1)

                    ntlmPwd = ntlmToken.getHashedPassword();

               

                String username = (String) ntlmToken.getPrincipal();

               

                authSess.doSessionSetup(username, lmPwd, ntlmPwd);

               

                // Check if the session has logged on as a guest

               

                if ( authSess.isGuest() || username.equalsIgnoreCase("GUEST"))

                {

                    // If guest access is enabled add a guest authority to the token

                   

                    if ( allowsGuest())

                    {

                        // Set the guest authority

                       

                        GrantedAuthority[] authorities = new GrantedAuthority[1];

                        authorities[0] = new GrantedAuthorityImpl(NTLMAuthorityGuest);

                       

                        ntlmToken.setAuthorities(authorities);

                    }

                    else

                    {

                        // Guest access not allowed

                       

                        throw new BadCredentialsException("Guest logons disabled");

                    }

                }

               

                // Indicate that the token is authenticated

               

                ntlmToken.setAuthenticated(true);

               

                //HACK dany

               PersonService m_personService = (PersonService) MyApplicationContextAware.getNamedBean("personService");

               NodeService m_nodeService = (NodeService) MyApplicationContextAware.getNamedBean("nodeService");

               //HACK dany





                // Map the passthru username to an Alfresco person

               

                NodeRef userNode = m_personService.getPerson(username);

                if ( userNode != null)

                {

                    // Get the person name and use that as the current user to line up with permission checks

                   

                    String personName = (String) m_nodeService.getProperty(userNode, ContentModel.PROP_USERNAME);

                    setCurrentUser(personName);

                   

                    // DEBUG

                   

                    if ( logger.isDebugEnabled())

                        logger.debug("Setting current user using person " + personName + " (username " + username + ")");

                }

                else

                {

                    // Set using the user name, lowercase the name if the person service is case insensitive

                   

                    if ( m_personService.getUserNamesAreCaseSensitive() == false)

                        username = username.toLowerCase();

                    setCurrentUser( username);

                   

                    // DEBUG

                   

                    if ( logger.isDebugEnabled())

                        logger.debug("Setting current user using username " + username);

                }

            }               

            catch (IOException ex)

            {

                // Error connecting to the authentication server

               

                throw new AuthenticationServiceException("I/O error", ex);

            }

            catch (SMBException ex)

            {

                // Debug

               

                if ( logger.isDebugEnabled())

                    logger.debug("Passthru exception, " + ex);

               

                // Check the returned status code to determine why the logon failed and throw an appropriate exception

               

                if ( ex.getErrorClass() == SMBStatus.NTErr)

                {

                    AuthenticationException authEx = null;

                   

                    switch( ex.getErrorCode())

                    {

                    case SMBStatus.NTLogonFailure:

                        authEx = new AuthenticationException("Logon failure");

                        break;

                    case SMBStatus.NTAccountDisabled:

                        authEx = new AuthenticationException("Account disabled");

                        break;

                    default:

                        authEx = new AuthenticationException("Logon failure");

                    break;

                    }

                   

                    throw authEx;

                }

                else

                    throw new BadCredentialsException("Logon failure");

            }

            finally

            {

                // Make sure the authentication session is closed

               

                if ( authSess != null)

                {

                    try

                    {

                        // Remove the session from the active list

                       

                        m_passthruSessions.remove(ntlmToken);

                       

                        // Close the session to the authentication server

                       

                        authSess.CloseSession();

                    }

                    catch (Exception ex)

                    {

                    }

                }

            }

        }

    }



    /**

     * Check if the user exists

     *

     * @param userName String

     * @return boolean

     */

    public boolean exists(String userName)

    {

       throw new UnsupportedOperationException();

    }



    @Override

    protected boolean implementationAllowsGuestLogin()

    {

       return allowsGuest();

    }
   

}

lgr
Champ in-the-making
Champ in-the-making
Hi,

Just for your information, same 1.3.0dev on linux => same ntlm configuration from the wiki procedure => same behaviour, this does not work because FactoryBean was not able to create authenticationComponent bean.

Laurent.

steve
Champ in-the-making
Champ in-the-making
Hi,

The NTLM Configuration steps in the wiki are correct, but we've found a small problem in another place that is causing the problem.

However, you can resolve it by doing the following:

In 'tomcat\webapps\alfresco\WEB-INF\classes\alfresco\authority-services-context.xml'

Find
<bean id="authorityService" class="org.alfresco.repo.security.authority.AuthorityServiceImpl">
        <property name="authenticationComponent">
        <ref bean="authenticationComponent" />
</property>

And change it to:
<bean id="authorityService" class="org.alfresco.repo.security.authority.AuthorityServiceImpl">
        <property name="authenticationComponent">
        <ref bean="authenticationComponentImpl" />
</property>

We'll get this fixed up in the next drop.

Steve

tcordova
Champ in-the-making
Champ in-the-making
I've managed to get this done and alfresco starts up just fine…  now what?  Nothing seems to have changed…  How do I set up users from the domain?

tcordova
Champ in-the-making
Champ in-the-making
Ok… after resolving stupid typo errors, I've got ntlm up and running.  I can log in and authenticate against the enterprise domain…  Now, however, I no longer have Admin access…  how do I get admin access?

steve
Champ in-the-making
Champ in-the-making
Hi,

You can find how to assign Administrators in the wiki here:
http://wiki.alfresco.com/wiki/Security_and_Authentication#Configuration

Steve

tcordova
Champ in-the-making
Champ in-the-making
Great!  That works.

Now, I'm trying to get Single Sign-On to work through NTLM.  According to the Alfresco web-site…

"Alfresco now offers the same functionality across the Enterprise, Small Business and Community product lines. The customer has the option to purchase additional support, consulting, integration and training services."

But web.xml contains comments that say NTLM is only available for enterprise users…  not sure which is true, but I know that I still have to login manually.  It is authenticating properly to my domain.


I've changed web.xml as documented here:  http://wiki.alfresco.com/wiki/Configuring_NTLM to look like this:


<?xml version='1.0' encoding='UTF-8'?>

<!DOCTYPE web-app PUBLIC
  "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
  "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
   <display-name>Alfresco Web Client</display-name>
   
   <description>Alfresco Web Client</description>
  
   <context-param>
      <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
      <param-value>server</param-value>
   </context-param>

   <context-param>
      <param-name>javax.faces.CONFIG_FILES</param-name>
      <param-value>/WEB-INF/faces-config-app.xml,/WEB-INF/faces-config-beans.xml,/WEB-INF/faces-config-navigation.xml,/WEB-INF/faces-config-common.xml,/WEB-INF/faces-config-repo.xml</param-value>
   </context-param>

   <context-param>
      <param-name>org.apache.myfaces.ALLOW_JAVASCRIPT</param-name>
      <param-value>true</param-value>
   </context-param>
   
   <context-param>
      <param-name>org.apache.myfaces.DETECT_JAVASCRIPT</param-name>
      <param-value>false</param-value>
      <description>This is an EXPERIMENTAL feature, so leave it off for now!</description>
    </context-param>

    <!– TODO: Change this to false for production –>
    <context-param>
        <param-name>org.apache.myfaces.PRETTY_HTML</param-name>
        <param-value>true</param-value>
        <description>
            If true, rendered HTML code will be formatted, so that it is "human readable".
            i.e. additional line separators and whitespace will be written, that do not
            influence the HTML code.
            Default: "true"
        </description>
    </context-param>

    <context-param>
        <param-name>org.apache.myfaces.AUTO_SCROLL</param-name>
        <param-value>false</param-value>
        <description>
            If true, a javascript function will be rendered that is able to restore the
            former vertical scroll on every request. Convenient feature if you have pages
            with long lists and you do not want the browser page to always jump to the top
            if you trigger a link or button action that stays on the same page.
            Default: "false"
        </description>
    </context-param>

   <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>
         classpath:alfresco/web-client-application-context.xml
         classpath:web-services-application-context.xml
         classpath:alfresco/application-context.xml
      </param-value>
      <description>Spring config file locations</description>
   </context-param>

   <filter>
      <filter-name>Authentication Filter</filter-name>
      <!– Default Setting –>
      <!–
      <filter-class>org.alfresco.web.app.servlet.AuthenticationFilter</filter-class>
      –>
     
      <!– For Novell IChain support use the following filter –>
      <!– (Enterprise version only)                          –>
      <!–
        <filter-class>org.alfresco.web.app.servlet.NovellIChainsHTTPRequestAuthenticationFilter</filter-class>
      –>
     
      <!– For NTLM authentication support use the following filter –>
      <!– (Enterprise version only)                                –>
        <filter-class>org.alfresco.web.app.servlet.NTLMAuthenticationFilter</filter-class>
   </filter>

   <filter>
      <filter-name>WebDAV Authentication Filter</filter-name>
      <!– Default Setting –>
      <!–
      <filter-class>org.alfresco.repo.webdav.auth.AuthenticationFilter</filter-class>
   –>
            
      <!– For NTLM authentication support use the following filter –>
      <!– (Enterprise version only)                                –>
        <filter-class>org.alfresco.repo.webdav.auth.NTLMAuthenticationFilter</filter-class>
   </filter>

  <filter-mapping>
    <filter-name>Authentication Filter</filter-name>
    <url-pattern>/faces/*</url-pattern>
  </filter-mapping>

   <!– For NTLM authentication support enable the following mapping –>
   <!– (Enterprise version only)                                    –>
   <filter-mapping>
      <filter-name>Authentication Filter</filter-name>
      <url-pattern>/navigate/*</url-pattern>
   </filter-mapping>

   <filter-mapping>
      <filter-name>WebDAV Authentication Filter</filter-name>
      <url-pattern>/webdav/*</url-pattern>
   </filter-mapping>
  
   <listener>
      <listener-class>org.apache.myfaces.webapp.StartupServletContextListener</listener-class>
   </listener>
  
   <listener>
      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
   </listener>
  
   <listener>
      <listener-class>org.alfresco.web.app.ContextListener</listener-class>
   </listener>
  
   <!– Faces Servlet –>
   <servlet>
      <servlet-name>Faces Servlet</servlet-name>
      <servlet-class>org.alfresco.web.app.servlet.AlfrescoFacesServlet</servlet-class>
      <load-on-startup>1</load-on-startup>
   </servlet>
  
   <servlet>
      <servlet-name>uploadFile</servlet-name>
      <servlet-class>org.alfresco.web.app.servlet.UploadFileServlet</servlet-class>
   </servlet>
  
   <servlet>
      <servlet-name>downloadContent</servlet-name>
      <servlet-class>org.alfresco.web.app.servlet.DownloadContentServlet</servlet-class>
   </servlet>
  
   <servlet>
      <servlet-name>externalAccess</servlet-name>
      <servlet-class>org.alfresco.web.app.servlet.ExternalAccessServlet</servlet-class>
   </servlet>
  
   <servlet>
      <servlet-name>templateContent</servlet-name>
      <servlet-class>org.alfresco.web.app.servlet.TemplateContentServlet</servlet-class>
   </servlet>
  
   <servlet>
      <servlet-name>commandServlet</servlet-name>
      <servlet-class>org.alfresco.web.app.servlet.CommandServlet</servlet-class>
   </servlet>
  
   <servlet>
      <servlet-name>axis</servlet-name>
      <servlet-class>org.apache.axis.transport.http.AxisServlet</servlet-class>
      <load-on-startup>5</load-on-startup>
   </servlet>
  
   <servlet>
      <servlet-name>WebDAV</servlet-name>
      <servlet-class>org.alfresco.repo.webdav.WebDAVServlet</servlet-class>
      <init-param>
         <param-name>store</param-name>
         <param-value>workspace://SpacesStore</param-value>
      </init-param>
      <init-param>
         <param-name>rootPath</param-name>
         <param-value>/app:company_home</param-value>
      </init-param>
      <load-on-startup>5</load-on-startup>
   </servlet>
  
   <servlet-mapping>
      <servlet-name>Faces Servlet</servlet-name>
      <url-pattern>/faces/*</url-pattern>
   </servlet-mapping>
  
   <servlet-mapping>
      <servlet-name>uploadFile</servlet-name>
      <url-pattern>/uploadFileServlet</url-pattern>
   </servlet-mapping>
  
   <servlet-mapping>
      <servlet-name>downloadContent</servlet-name>
      <url-pattern>/download/*</url-pattern>
   </servlet-mapping>
  
   <servlet-mapping>
      <servlet-name>externalAccess</servlet-name>
      <url-pattern>/navigate/*</url-pattern>
   </servlet-mapping>
  
   <servlet-mapping>
      <servlet-name>templateContent</servlet-name>
      <url-pattern>/template/*</url-pattern>
   </servlet-mapping>
  
   <servlet-mapping>
      <servlet-name>commandServlet</servlet-name>
      <url-pattern>/command/*</url-pattern>
   </servlet-mapping>
  
   <servlet-mapping>
      <servlet-name>axis</servlet-name>
      <url-pattern>/api/*</url-pattern>
   </servlet-mapping>
  
   <servlet-mapping>
      <servlet-name>WebDAV</servlet-name>
      <url-pattern>/webdav/*</url-pattern>
   </servlet-mapping>
  
   <session-config>
      <session-timeout>60</session-timeout>
   </session-config>
  
   <welcome-file-list>
      <welcome-file>index.jsp</welcome-file>
   </welcome-file-list>

</web-app>

My authority-services-context.xml looks like this:

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>

<!– ========================================================= –>
<!– The configuration of the Authority Service Implementation –>
<!– ========================================================= –>

<!–                                                                          –>
<!– This implementation supports the identification of users as admin users. –>
<!– It also supports groups and allows groups and users to be arranged into  –>
<!– hierarchies.                                                             –>
<!–                                                                          –>
<beans>
   
    <bean id="authorityService" class="org.alfresco.repo.security.authority.AuthorityServiceImpl">
        <property name="authenticationComponent">
            <ref bean="authenticationComponentImpl" />
        </property>
        <property name="personService">
            <ref bean="personService" />
        </property>
        <property name="nodeService">
            <ref bean="nodeService" />
        </property>
        <property name="authorityDAO">
            <ref bean="authorityDAO" />
        </property>
        <property name="permissionServiceSPI">
            <ref bean="permissionServiceImpl" />
        </property>
        <!–                                                                  –>
        <!– A list of users with admin rights.                               –>
        <!–                                                                  –>
        <!– If the security framework is case sensitive these values should  –>
        <!– be case sensitive user names. If the security framework is not   –>
        <!– case sensitive these values should be the lower-case user names. –>
        <!–                                                                  –>
        <!– By default this includes:                                        –>
        <!–    admin (the user name of default alfresco admin user)          –>
        <!–    administrator (the windows default admin user)                –>
        <!–                                                                  –>
        <!– This assumes that user names are not case sensitive.             –>
        <!–                                                                  –>
        <property name="adminUsers">
            <set>
             <value>admin</value>
             <value>administrator</value>
             <value>tcordova</value>
          </set>
        </property>
    </bean>
   
    <!– Authority DAO that stores group information along with user information, –>
    <!– in the repository.                                                       –>
    <!–                                                                          –>
    <!– This bean uses the userToAuthorityCache configured in cache-context.xml  –>
    <!–                                                                          –>
    <bean id="authorityDAO" class="org.alfresco.repo.security.authority.AuthorityDAOImpl">  
        <property name="nodeService">
            <ref bean="nodeService" />
        </property>
        <property name="namespacePrefixResolver">
            <ref bean="namespaceService" />
        </property>
        <property name="searchService">
            <ref bean="searchService" />
        </property>
        <property name="dictionaryService">
            <ref bean="dictionaryService" />
        </property>
        <property name="userToAuthorityCache">
            <ref bean="userToAuthorityCache" />
        </property>
    </bean>
   
</beans>

And my ntlm-authentication-context.xml extension file looks like this:

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>

<beans>

    <bean id="authenticationDao" class="org.alfresco.repo.security.authentication.ntlm.NullMutableAuthenticationDao">
       <property name="nodeService">
           <ref bean="nodeService" />
       </property>
    </bean>

    <!– The authentication component.                                      –>

    <!– Use the passthru authentication component to authenticate using    –>
    <!– user accounts on one or more Windows servers.                      –>
   
    <!– Properties that specify the server(s) to use for passthru          –>
    <!– authentication :-                                                  –>
    <!–   useLocalServer   use the local server for authentication         –>
    <!–   domain           use domain controllers from the specified domain–>
    <!–   servers          comma delimted list of server addresses or      –>
    <!–                    names                                           –>
      
    <bean id="authenticationComponentImpl" class="org.alfresco.repo.security.authentication.ntlm.NTLMAuthenticationComponentImpl">
        <property name="useLocalServer">
            <value>true</value>
        </property>
        <property name="personService">
            <ref bean="personService" />
        </property>
        <property name="nodeService">
            <ref bean="nodeService" />
        </property>
        <property name="guestAccess">
            <value>true</value>
        </property>
    </bean>
   
</beans>

Any help you can give would be greatly appreciated.

tcordova
Champ in-the-making
Champ in-the-making
I still need help getting Single Sign-On to work.

d_baijot
Champ in-the-making
Champ in-the-making
can't see any mis-configuration compared to the one i used…

i saw that NTLM "no-login" only works with Internet Explorer and that Netscape still ask for a login/password…

hope this helps…
Dany.