Enterprise Security and Authentication Configuration

From alfrescowiki

Jump to: navigation, search


This page describes configuration methods prior to Alfresco Version 3.2. Refer to Alfresco Authentication Subsystems for Alfresco Versions 3.2 and up.

Entry Points to the Repository

There are a number of entry points to the repository that all carry out authentication. A number of these require matching and/or supported configurations.

The entry points are:

CIFS
alfresco - to be used with the Alfresco NTLMAuthenticationComponentImpl or an authentication component that supports MD4 password hashes. The NTLMAuthenticationComponentImpl supports NTLMv1 passthrough authentication. If the CIFS client supports single sign on using NTLMv1 then the NTLMAuthenticationComponentImpl can be used for SSO; NTLMv2 is not supported at all for this option. An authentication component that supports MD4 password hashes can be used to carry out an NTLMv1 authentication sequence with the client application but not single sign on. See also CIFS Server Authentication
passthru - which allows configuration of authentication direct against one or more AD servers. The repository must be configured so that it authenticates against the same AD server using something like LDAP or JAAS+Kerberos. This option does not support SSO. Pasthrough authentication is only supported for NTLMv1. . See also CIFS Server Authentication
enterprise - which supports using any authentication component that can provide the MD4 password hash (currently only the default Alfresco authentication component). The MD4 hash will be used for NTLMv1 or NTLMv2 authentication depending on the client/server negotiation. This does not support SSO.
enterprise - this option can also be configured to support Kerberos authentication. This supports SSO for CIFS clients that support Kerberos.
FTP
Uses the AuthenticationService to authenticate. Kerberos may be supported at some time in the future for suitable clients.
NFS
Uses the request UID to map to an alfresco user, as defined in the config. NFS requests then run as that user. Keberos and NTLM are not currently supported in the implementation but are possible in the NFS protocol. Support may be added in future releases.
The Web UI
Uses the authentication filter as defined in web.xml (this is not the same filter that is used for WebDAV)
Alfresco default filter - uses the AuthenticationService for user name and password authentication or to validate a ticket stored on the web session. The user names and password are sent in the post request. You may wish to use SSL.
NTLM filter - uses the authenticationComponent bean. If the authenticationComponent supports NTLMv1 passthru this will be used. If the web client supports NTLMv1 authentication then single sign on is supported. If the authenticationComponent bean supports MD4 password hashes then the filter will negotiate the NTLMv1 with the client - this is not single sign on.
HTTP Header filter - trusts a username set on a header request. You must set up a secure connection between Alfresco and the SSO provider (e.g. IChains, SiteMinder, ....) or use this filter after another (e.g. CAS authentication)
Kerberos filter - accepts a Kerberos ticket (2.2/3.0 onwards)
CAS - currently only has community support. A CAS filter is configured first and then typically the HTTP Header Filter.


WebDAV
Uses the authentication filter as defined in web.xml Note: this is not the same filter that used for the web UI.
Alfresco default filter - requires a different filter implementation but works as above
NTLM filter - requires a different filter implementation but works as above
HTTP Header filter - requires a different filter implementation but works as above (2.1/2.2 onwards)
Kerberos filter - requires a different filter implementation but works as above (2.2/3.0 onwards)
CAS - Not likely to work. See [1]
Web Services
Uses the AuthenticationService to authenticate.


The Java API
The public authentication API supported by Alfresco is defined by the AuthenticationService. The default implementation of this service delegates to an authentication component. There are a number of authentication components that can be wired up. An over view of each is given below.


Authentication components

The default set of services wired up to authentication components changes from time to time. The example configurations and Alfresco configuration will be updated to reflect this. 3.0 authentication components require the

  • tenant service;
  • person service;
  • node service;
  • transaction service: and
  • if guest log in is allowed.

The requirement for the tenant service is new in 3.0. In future these services will all be defined via an abstract base bean and wired up using:

 parent="authenticationComponentBase">

Currently, this base bean only contains the tenant service.


Alfresco
Stores user ids and passwords internally in Alfresco.
Uses the RepositoryAuthenticationDao which stores authentication details in a reserved Alfresco store
NTLM
Authentication is carried out against an external MS Domain Controller;
Should use the DefaultMutableAuthenticationDao
LDAP
Authentication is carried out against an external LDAP repository
OpenLDAP, AD, ...
Should use the DefaultMutableAuthenticationDao
JAAS+Kerberos
Authentication is carried out against a Kerberos server using the JAAS implementation for this. JAAS can be used to support other authentication implementations.
Should use the DefaultMutableAuthenticationDao
Deny or Allow All
This can be configured to accept any authentication, or deny any authentication. Allow is intended for test and disaster recovery. Deny is intended for SSO implementations where normal login should be disabled.
Should use the DefaultMutableAuthenticationDao
Chaining
This can be used to combine any of the authentication systems described above. The configured entries are tried in turn. If any implementation authenticates the user then authentication succeeds. It is not possible to do full chain NTLM authentication either based on passthrough authentication or the MD4 hash (the negotiation can only take place once so you should not be using chaining but configuring AD). So CIFS will support chaining using the user name and password. For MD4 and passthru based authentication it will use the first authentication component in the chain that supports MD4 or passthru. The default authentication filter will support chaining, including NTLM, as it uses the user name and password against each authentication component linked up in the chaining authentication component. For the NTLM filter it will only use the first authentication component in the chain that supports MD4 or NTLM passthru and should then default to asking for the user name and password, after which full chaining will take place.

If for instance you chain Alfresco and NTLM, by default only the first compatible authentication component in the chain will be used for CIFS, here alfresco. If you want to force the seond component (NTLM), you need to set the property ntlmMode to PASS_THROUGH for the ChainingAuthenticationComponentImpl bean.

<property name="ntlmMode">
<value>PASS_THROUGH</value>
</property>

Note: the reason why only one CIFS request can be made comes from the protocol. Alfresco may only get one logon request from the client before it fails and the password is hashed in the case of NTLM (for CIFS or HTTP).

Recommended combinations

Alfresco default authentication

CIFS alfresco or enterprise
FTP (authentication service)
NFS (user name mapping)
UI default authentication filter
WebDAV default authentication filter
WebServices (authentication service)
AuthenticationService default authentication component
LDAP Sync Does not apply

Notes:

  • Passwords are stored in Alfresco, by default as the MD4 hash to support CIFS authentication.
  • The authentication filters will send passwords and user ids in the request header. Tickets are part of the request context.
  • FTP will send the password in plain text.
  • WebSevices will send passwords, user ids and tickets as part of the SOAP message.
  • CIFS clients will not send plain text passwords. They may only be weakly encrypted (LM - DES, NTLMv1 - MD4, NTLMv2 - MD5)
  • To create a secure environment you would need to use SSL for all web access (UI, WebDAV, WebServices), the enterprise configuration for CIFS and clients that support NTLMv2 and do not fall back to weaker protocols, and disable FTP.

Active Directory - LDAP

CIFS passthru
FTP (authentication service)
NFS (user name mapping)
UI default authentication filter
WebDAV default authentication filter
WebServices (authentication service)
AuthenticationService LDAP authentication component
LDAP Sync Optional


Notes:

  • No password information is stored in alfresco. Authentication always takes place against the LDAP server.
  • The authentication filters will send passwords and user ids in the request header. Tickets are part of the request context.
  • FTP will send the password in plain text.
  • WebSevices will send passwords, user ids and tickets as part of the SOAP message.
  • CIFS clients will not send plain text passwords. They may only be weakly encrypted (LM - DES, NTLMv1 - MD4, NTLMv2 is not supported)
  • To create a secure environment you would need to use SSL for all web access (UI, WebDAV, WebServices) and disable FTP. If you do not consider NTLMv1 of sufficient strength then you should disable CIFS. You may want to use SSL for LDAP synchronisation.

Active Directory - Kerberos

CIFS enterprise with Kerberos
FTP (authentication service)
NFS (user name mapping)
UI Kerberos authentication filter
WebDAV Kerberos authentication filter
WebServices (authentication service)
AuthenticationService JAAS/Kerberos authentication component
LDAP Sync Optional

Notes:

  • LDAP sync should use MD5 digest (it may be configured to use Kerberos but this has not been tested). Simple authentication with SSL would also be possible.
  • No password information is stored in alfresco. Authentication always takes place against the Kerberos server.
  • The authentication filters will send Kerberos tickets in the request header. Alfresco tickets are part of the request context. Authentication may fall back to user name and password entry and you may need to consider SSL or disable non SSO access.
  • FTP will send the password in plain text, you may want to disable this.
  • Web Services will send passwords, user ids and tickets as part of the SOAP message. You may want to use SSL.
  • CIFS clients will use Kerberos.
  • You may want to use SSL for LDAP synchronisation.

LDAP Server

CIFS Not supported
FTP (authentication service)
NFS (user name mapping)
UI default authentication filter
WebDAV default authentication filter
WebServices (authentication service)
AuthenticationService LDAP authentication component
LDAP Sync Optional


Notes:

  • No password information is stored in alfresco. Authentication always takes place against the LDAP server.
  • The authentication filters will send passwords and user ids in the request header. Tickets are part of the request context.
  • FTP will send the password in plain text.
  • WebSevices will send passwords, user ids and tickets as part of the SOAP message.
  • CIFS is not generally supported (unless you can use the passthru configuration to AD or Samba). It could be possible to allow CIFS if the plain text password or MD4 hash were stored in the LDAP server - this is not currently supported and would require SSL to LDAP for password security.
  • To create a secure environment you would need to use SSL for all web access (UI, WebDAV, WebServices) and disable FTP. You would need to use SSL between alfresco and LDAP for simple authentication or an appropriate SASL authentication mechanism such as digest-md5.
  • You may want to use SSL for LDAP synchronisation.

SSO Configurations

Active Directory - SSO - NTLM

CIFS alfresco or passthru
FTP (authentication service)
NFS (user name mapping)
UI NTLM authentication filter
WebDAV NTLM authentication filter
WebServices (authentication service)
AuthenticationService NTLM authentication component
LDAP Sync Optional


Notes:

  • No password information is stored in alfresco. Authentication always takes place against the NTLM server.
  • The authentication filters will send NTLM security information in the request header. Alfresco tickets are part of the request context. If SSO fails authentication fail. (Check it does not fall back to the login prompt)
  • FTP will send the password in plain text.
  • WebSevices will send passwords, user ids and Alfresco tickets as part of the SOAP message.
  • CIFS will use NTLMv1 authentication
  • To create a secure environment you would need to decide if NTLMv1 is good enough and that clients can not fall back to weaker protocols. It may be that SSL is still what you need. Disable FTP. Add SSL for web services. Use SSL or digest authentication for LDAP synchronisation.

SSO - Kerberos

CIFS enterprise with Kerberos
FTP (authentication service)
NFS (user name mapping)
UI Kerberos authentication filter
WebDAV Kerberos authentication filter
WebServices (authentication service)
AuthenticationService JAAS/Kerberos authentication component
LDAP Sync Optional

SSO - SiteMinder, IChains, CAS and the like

CIFS May not be available - passthru and enterprise+kerberos are possible options
FTP (authentication service)
NFS (user name mapping)
UI HTTP Header Filter
WebDAV HTTP Header Filter
WebServices (authentication service)
AuthenticationService deny authentication component
LDAP Sync Possible - Depends on what the SSO layer is using

See Central Authentication Service Configuration for information about configuring Alfresco to work with CAS

Chaining

Introduction

The community and enterprise products both support enterprise authentication as described on this page.


JAAS - Java Authentication and Authorization Service

A Kerberos setup is detailed at Configuring_the_CIFS_and_web_servers_for_Kerberos/AD_integration and does not need JAAS.


The JAAS Authentication component is used most commonly within Alfresco to support Kerberos authentication of user names and passwords. You may choose to use Kerberos against an Active Directory server in preference to LDAP or NTLM as it provides strong encryption without using SSL. It is still possible to use LDAP synchronisation to extract user information.


The disadvantages of using LDAP authentication against Active Directory compared with JAAS/Kerberos are:

  • the simplest approach is to use the SIMPLE LDAP authentication protocol, which should be used with SSL;
  • AD requires special set up to use digest MD5 authentication (reversible encryption for passwords), which may be difficult retrospectively;
  • LDAP can use GSSAPI + Kerberos which would be equivalent but this is more difficult to configure and has not been tested.


IE exposes NTLMv1, NTLMv2 and Kerberos SSO support - but has to be configured correctly on the browser. The web authentication filters for the UI and WebDav support NTLMv1 and as of 3.0 support NTLMv2 for authentication components that can provide the MD4 password hash. From 2.2/3.0, Kerberos SSO is supported via the UI and WebDAV. A full kerberos authentication configuration is possible with the JAAS authentication component (except for how FTP transmits plain text passwords and how LDAP user synchronisation sends passwords)

Some of the configuration is common between CIFS Kerberos authentication and the UI and WebDAV Kerberos based authentication filters. If you have full SSO support it is likely that you do not want the JAAS authentication component configured in. Instead you probably want to reject all authentication that is not Kerberos ticket based - the users should already be authenticated.


Introduction

For some pointers and background information on JAAS, the Java Authentication and Authorization Service, please see:


To use JAAS authentication with Alfresco, you must:

  • replace the default implementation of the standard Alfresco authentication component bean with the JAASAuthenticationComponent; and
  • replace the default DAO bean that provides access to authentication information stored within Alfresco with the simple implementation that knows nothing about credentials and does not support any operations related to authorization. JAAS is an external authentication mechanism: there is no authentication information held within the repository, i.e. no password; there is no way to change a user's password, create a user or delete a user. These actions must be supported by some other mechanism, e.g. AD administration.


Note: Please read the page on how to override configuration settings in the repository. You should configure the security and authentication components without changing any of the files contained in the Alfresco distributions.


For JAAS authentication you can configure:

  • A default realm, required by some JAAS authentication mechanisms
  • The name of the configuration entry to use for the JAAS configuration, by default, this is "Alfresco".

The beans are defined by overriding the authenticationComponentImpl bean upto and including V1.4 and the authenticationComponent from V2.0 on. A sample config can be found in <configRoot>/alfresco/extension/jaas-authentication-context.xml.sample. This is always the best place to start.

Here is the 2.1 config.

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

<beans>
    <!-- The authentication component.                                      -->

    <!-- JAAS authentication - most of the config goes somewhere else       -->
       
    <bean id="authenticationComponent" 
                 class="org.alfresco.repo.security.authentication.jaas.JAASAuthenticationComponent">
        <property name="realm">
            <value>DEFAULT.REALM</value>
        </property>
        <property name="jaasConfigEntryName">
            <value>Alfresco</value>
        </property>
    </bean>

    <!-- DAO that rejects changes - JAAS is read only at the moment.      -->
    <!-- It does allow users to be deleted with out warnings from the UI. -->
    <!-- The user is still present in JAAS, only the personal information is removed from alfresco. --> 
    
    <bean name="authenticationDao" class="org.alfresco.repo.security.authentication.DefaultMutableAuthenticationDao" >
        <property name="allowDeleteUser">
            <value>true</value>
        </property>
    </bean>    

</beans>


The remainder of the example will describe how to configure a Kerberos 5 authentication mechanism that will support this definition. It was tested against Active Directory.


Defining the JAAS configuration for Kerberos

The location of the login config must be defined first. This can be done on the command line using system properties or it can be defined in the security configuration. The configuration defines which authentication mechanisms must be in place and succeed for authentication to take place.


By default, the location of the login configuration can be set in the JRE java.security file, found in somewhere like C:\Program Files\Java\jdk1.5.0_04\jre\lib\security for windows. If not, the location of the login configuration can be specified on the java command line using the -Djava.security.auth.login.config=c:\path\file.conf


To add the configuration to the java.security file, add a line:

login.config.url.1=file:${java.home}/lib/security/java.login.config

This will configure JAAS to look for the java.login.config file in the same directory as the java.security file.


The java.login.config file should contain something like:

Alfresco {
   com.sun.security.auth.module.Krb5LoginModule sufficient;
};

com.sun.net.ssl.client {
   com.sun.security.auth.module.Krb5LoginModule sufficient;
};

other {
   com.sun.security.auth.module.Krb5LoginModule sufficient;
};


This configures Alfresco to require kerberos. There are many more options for the Krb5LoginModule.


Making sure Kerberos is set up

Here it is assumed you have a simple configuration and are setting up a machine just to connect to existing Kerberos support, such as Active Directory.


MIT Docs

Kerberos: The Network Authentication Protocol http://web.mit.edu/kerberos


Microsoft docs

Kerberos Authentication in Windows Server 2003 http://technet2.microsoft.com/windowsserver/en/technologies/featured/kerberos/default.mspx

Kerberos Authentication in Windows 2000 Server http://www.microsoft.com/technet/prodtechnol/windows2000serv/technologies/security/kerberos/default.mspx

Troubleshooting Kerberos http://technet2.microsoft.com/WindowsServer/en/library/26ce2e7f-52d6-4425-88cc-1573bc5e646d1033.mspx


Setting the kerberos configuration can be done from the java command line, using system variables, or using a kerberos config file. This section describes using a config file.


The default locations for the config file are:

  • /etc/krb5/krb5.conf [Solaris]
  • c:\winnt\krb5.ini [Windows] or
  • c:\WINDOWS\krb5.ini [Windows]
  • /etc/krb5.conf [Linux]


At the minimum, the kerberos config file contains something like

[libdefaults]
	default_realm = COMPANY.COM

[realms]
	COMPANY.COM = {
		kdc = activeDirectoryHost.company.com
		admin_server = activeDirectoryHost.company.com
	}


[domain_realm]
	company.com = COMPANY.COM
	.company.com = COMPANY.COM

You can also set these parameters on the command line. See the GSS-API tutorials for mode details.


You can check the configuration files are correct and you can get a kerberos ticket using the commands kinit and klist. Note, at least on the windows xp version, kinit may echo your password to the screen - seems to fixed in XP somewhere along the line. kinit will get a kerberos ticket. klist will show you the tickets.

There are some problems according to usernames and case sensitivity.
If the loginname is User@COMPANY.COM authentication will fail if you use user@COMPANY.COM.
Take a look at this page Thread "Using Java client with Windows 2003 AD with mixed case PrincipalNames" --Mobang 10:03, 2 August 2006 (BST)

You should be able to login via the web client using kerberos.

LDAP

LDAP can be used for user authentication and to obtain user information. They do not have to be used together. LDAP authentication can be used without pulling in personal information using LDAP synchronisation - default entries would be created by the PersonService. LDAP synchronisation of personal information is most likely to be used in conjunction with LDAP authentication. LDAP personal information sychronisation can also be used with other authentication mechanisms: e.g. JAAS/Kerberos against Active Directory, NTLM against ActiveDirectory, and possibly other combinations such as NTLM using Samba on top of open LDAP.

There are three parts to LDAP configuration:

  • Authentication - the authentication component and DAO
  • scheduled jobs for loading people and groups; and
  • the authentication context (which configures LDAP authentication and how people and groups are extracted from LDAP).

Authentication and LDAP import are likely to use the same LDAP context to connect to the LDAP server.


A template configuration is provided in alfresco/extensions/extension/ldap-authentication-context.xml.sample.


It is best to get LDAP simple authentication up and running first and then set up the export and synchronisation of groups and people, followed by more complex authentication requirements.


Changes after 2.1

After 2.1 LDAP configuration is split into authentication and synchronisation. The configuration of both is simplified and less error prone with the use of properties files. There should be no reason to edit the xml for most use cases. It is also simpler to configure LDAP as part of chaining authentication.

User Authentication methods compatible with LDAP

Active Directory

Active Directory supports LDAP based authentication. It can also support authentication using JAAS+Kerberos (see above) and NTLM authentication. NTLM is the only solution that will give you single sign on. It is possible to use any of these authentication methods against an ActiveDirectory server and extract user and group information via LDAP.

Note that active directory allows two formats in the bind expressions:

  1. a full DN (Distinguished Name) format like: c=user1,ou=unit1,dc=example,dc=com
  2. the UPN (User Principal Name) like: user1@example.com

see for instance http://www.microsoft.com/technet/scriptcenter/resources/qanda/dec04/hey1206.mspx

OpenLDAP

Unless you have synchronized OpenLDAP with another authentication system you only have LDAP based authentication available.


Note that openlodap support only one format for the bind expression: the full DN (Distinguished Name).

How do I find out what Simple Authentication and Security Layer (SASL) authentication mechanisms my LDAP server supports

Using an LDAP browser, such as the one from Softerra, check the values of the supportedSASLMechanisms attributes on the root node of your LDAP server. Note: the "simple" authentication method will not be reported as it is not a SASL mechanism.

If you use openldap, you can also query using ldapsearch:

ldapsearch -h localhost -p 389 -x -b "" -s base -LLL supportedSASLMechanisms
dn:
supportedSASLMechanisms: DIGEST-MD5
supportedSASLMechanisms: NTLM
supportedSASLMechanisms: CRAM-MD5

LDAP Configuration before 2.1

The LDAP connection configuration is defined in the ldapInitialDirContextFactory bean.


This bean wraps the creation of an intial directory context for LDAP. You can set any LDAP related or SASL related property that you would be able to set using the Java API. For more configuration, see The full list of LDAP properties and more gory details for LDAP providers and Parameters for SASL.

The authentication credentials (principal and password) in this bean are only used for extracting user and group information from the LDAP server. The other options, including realm, are used if this bean is injected into LDAP authentication.

Note: LDAP servers may have a maximum request size (e.g. no more than 1000 entries). This could be an issue if you try to import a large amount of people or groups. This restriction should be removed on the LDAP server


This example illustrates the basic options:

    <bean id="authenticationComponentImpl" class="org.alfresco.repo.security.authentication.ldap.LDAPAuthenticationComponentImpl">
        <property name="LDAPInitialDirContextFactory">
            <ref bean="ldapInitialDirContextFactory" />
        </property>
        <property name="userNameFormat">
            <value>%s</value>
        </property>
    </bean>
    
    <bean id="ldapInitialDirContextFactory" class="org.alfresco.repo.security.authentication.ldap.LDAPInitialDirContextFactoryImpl">
        <property name="initialDirContextEnvironment">
             <map>
                <entry key="java.naming.factory.initial">
                    <value>com.sun.jndi.ldap.LdapCtxFactory</value>
                </entry> 
                <entry key="java.naming.provider.url">
                    <value>ldap://openldap.domain.com:389</value>
                </entry>
                <entry key="java.naming.security.authentication">
                    <value>DIGEST-MD5</value>
                </entry>
                <entry key="java.naming.security.principal">
                    <value>reader</value>
                </entry>
                <entry key="java.naming.security.credentials">
                    <value>secret</value>
                </entry>
             </map>
        </property>
    </bean>


java.naming.factory.initial
There is no need to change this unless you do not want to use the default Sun LDAP context factory. The other options should be standard for any provider.


java.naming.provider.url
This is the name and port of your ldap server. The standard ports for LDAP are 389 (and 636 for SSL)


java.naming.security.authentication
This is the authentication mechanism to use. "simple" may be used for testing, "DIGEST-MD5" is recommended and should be available for all LDAP servers, with the notable exception of Active Directory. See the tips below.


java.naming.security.principal
java.naming.security.credentials
These parameters are optional, they are only used to access LDAP for the extraction of user and group information. If they are omitted, then an anonymous authentication will be attempted. This may not be supported for all authentication mechanisms. For example, if you use DIGEST-MD5 authentication you must provide a login principal and credentials for a user that has read access to the group and people information to be extracted.
It MAY be possible to use Kerberos pass through authentication for extracting user and group information. It would be expected that users would normally be authenticated via JAAS+Kerberos, not LDAP authentication. A separate LDAP authentication for group and people extraction would specify a user id using the java.naming.security.principal, a ticket would be cached on the server machine for this user; using kinit, or some other means. This ticket would need to be valid while the server is running. If Kerberos is configured to read the external ticket cache, and has a JAAS entry for other in the login configuration, you should get pass through authentication. This would avoid having a password in the configuration. The CIFS Kerberos configuration could be used as a guide. THIS HAS NOT BEEN TESTED AND IS NOT A WAY TO GET SINGLE SIGN ON.


java.naming.security.principal
The identifier for a user who can read people and group information.


java.naming.security.credentials
The password of the user defined above.

LDAP Simple authentication

Note that this authentication mechanism sends user names and passwords in plain text. However, it is the most simple to set up. This is supported by both Active Directory and OpenLDAP. You may be able to add SSL for secure access, otherwise this should only be used for testing.


For simple LDAP Authentication the full distinguished name of the user is required, along with their password. This can take many forms depending on how the LDAP repository has been structured. The user is required to type in some kind of user identifier which is then translated into a distinguished name. This transformation is set on the authenticationComponent bean using the userNameFormat property. The %s is replaced with whatever the user types in as their userid on the login screen.


The most simple example is the when the user must enter their distinguished name.

    ...
    <property name="userNameFormat">
        <value>%s</value>
    </property>
    ....


If users are in a well known place in the LDAP repository tree structure then users only need to enter their common name (by convention the person's full name).

    ...
    <property name="userNameFormat">
        <value>cn=%s,dc=company,dc=com</value>
    </property>
    ....

MD5 Digest authentication

This is the default authentication mechanism that should be supported by all LDAP servers.

Active Directory does not support this, but it does support Kerberos authentication which you could use in combination with the synchronisation config.


The digest authentication mechanism (usually) requires users to enter their "uid" as stored in LDAP, but could be configured in other ways. In any case, the identity provided by the user in the login screen needs to be passed through unchanged to the LDAP authentication mechanism using the configuration snippet below for the authenticationComponentImpl bean.

    ...
    <property name="userNameFormat">
        <value>%s</value>
    </property>
    ....

LDAP Synchronization

Synchronization of people and groups between the Alfresco repository and LDAP is supported by scheduled jobs. These jobs extract the user or group information from the LDAP repository and create the appropriate information as an Alfresco import xml file. This file is then imported into the repository.


Information can be extracted from Active Directory. Because only Kerberos authentication is available for active directory and some of the oddities of LDAP/SASL/JAAS configuration it is simpler to configure Jaas direct for authentication against Active Directory and have a simple or simple + ssl read only user access. As mentioned below, it may be possible to configure Kerberos authentication for this use case.


The ldap configuration example includes all the new bean definitions to support this.


LDAP People synchronization

This uses:

  • the ldapPeopleExportSource bean to extract information from LDAP and build the import xml;
  • the ldapPeopleImport bean to generate and import this data;
  • the ldapPeopleTrigger bean to register and schedule this action with Spring/quartz.


The configuration assumes that people are stored in LDAP as inetOrgPerson objects but can be changed to match the "user" type in Active Directory. The details are in the sample configuration file.


The ldapPeopleExportSource bean is defined as:

<bean id="ldapPeopleExportSource" class="org.alfresco.repo.security.authentication.ldap.LDAPPersonExportSource">
        <property name="personQuery">
            <value>(objectclass=inetOrgPerson)</value>
        </property>
        <property name="searchBase">
            <value>dc=company,dc=com</value>
        </property>
        <property name="userIdAttributeName">
            <value>cn</value>
        </property>
        <property name="LDAPInitialDirContextFactory">
            <ref bean="ldapInitialDirContextFactory" />
        </property>
        <property name="personService">
            <ref bean="personService"></ref>
        </property>
        <property name="namespaceService">
            <ref bean="namespaceService" />
        </property>
        <property name="defaultHomeFolder">
            <value>/app:company_home</value>
        </property>
        <property name="attributeMapping">
            <map>
                <entry key="cm:userName">
                    <value>cn</value>
                </entry>
                <entry key="cm:firstName">
                    <value>givenName</value>
                </entry>
                <entry key="cm:lastName">
                    <value>sn</value>
                </entry>
                <entry key="cm:email">
                    <value>mail</value>
                </entry>
                <entry key="cm:organizationId">
                    <value>o</value>
                </entry>
            </map>    
        </property>
    </bean>

The configuration options are:

personQuery
searchBase
These two options combine to make the query to find people. In the example above, we find all objects of type inetOrgPerson anywhere in the directory.


userIdAttributeName
This property is the name of the attribute containing the user id on the entities found by the above query. For inetOrgPerson this is the uid attribute.


LDAPInitialDirContextFactory
A bean that configures access to an LDAP repository (the information will be accessed in the LDAP repository using the authentication credentials set on this bean).


personService
A link to the person service - this is used to sync LDAP people with alfresco internal people.


namespaceService
A common bean to translate between namespaces and namespace prefixes.


defaultHomeFolder - until 1.4
A simple path that defines the default home space used when creating new people. Existing people will not have their home space updated to this value.
//Comment by --Cludt 12:23, 20 October 2006 (BST)
Unfortunately, there is no easy way to set a user specific home folder (like Home/<username>). The only way up to now to do this is to adapt the export bean. But there is already a JIRA-entry for this issue: AR-633: Easy creation of users and home spaces as part of LDAP import.
This has been addressed ...Security_and_Authentication#Creating_home_spaces_-_from_1.4_onwards


attribute defaults - from 1.4
Default values for person attributes if they are not found via an attributeMapping.
See Security_and_Authentication#Creating_home_spaces_-_from_1.4_onwards for creating home folders.


attributeMapping
A mapping from LDAP attributes to the properties of the Alfresco Person type. The uid mapping is not required, it is set by the userIdAttributeName above.


The bean that imports this information is defined as

    <bean id="ldapPeopleImport" class="org.alfresco.repo.importer.ExportSourceImporter">
        <property name="importerService">
            <ref bean="importerComponent" />
        </property>
        <property name="transactionService">
            <ref bean="transactionComponent"/>
        </property>
        <property name="authenticationComponent">
            <ref bean="authenticationComponent" />
        </property>
        <property name="exportSource">
            <ref bean="ldapPeopleExportSource" />
        </property>
        <property name="storeRef">
            <value>${spaces.store}</value>
        </property>
        <property name="path">
            <value>/${system.system_container.childname}/${system.people_container.childname}</value>
        </property>
        <property name="clearAllChildren">
            <value>false</value>
        </property>
         <property name="nodeService">
            <ref bean="nodeService" />
        </property>
         <property name="searchService">
            <ref bean="searchService" />
        </property>
         <property name="namespacePrefixResolver">
            <ref bean="namespaceService" />
        </property>
    </bean>


The important configuration parameters are:

exportSource
the name of the bean that provides the import xml


storeRef
the store ref into which data is imported


path
the path to a node, into which the information will be imported


clearAllChildren
if true, all the children in the node wil be deleted before the import, if false the children will be left and updated.


The import will follow the "update existing" semantics of the import process.


The schedule for extraction and synchronisation is defined in

    <bean id="ldapPeopleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
        <property name="jobDetail">
            <bean id="ldapPeopleJobDetail" class="org.springframework.scheduling.quartz.JobDetailBean">
                <property name="jobClass">
                    <value>org.alfresco.repo.importer.ImporterJob</value>
                </property>
                <property name="jobDataAsMap">
                    <map>
                        <entry key="bean">
                            <ref bean="ldapPeopleImport" />
                        </entry>
                    </map>
                </property>
            </bean>
        </property>
        <property name="startDelay">
            <value>30000</value>
        </property>
        <property name="repeatInterval">
            <value>3600000</value>
        </property>
    </bean>


It is wired up to the scheduler in

    <!-- Scheduled tasks -->
    <bean id="schedulerFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers">
            <list>
                <ref bean="tempFileCleanerTrigger" />
                <!-- <ref local="fileContentStoreCleanerTrigger"/> -->
                <ref bean="ftsIndexerTrigger" />
                <ref bean="indexRecoveryTrigger" />
                <ref bean="indexBackupTrigger" />
                <!-- Uncomment to enable LDAP extraction ....
                <ref bean="ldapGroupTrigger" />
                <ref bean="ldapPeopleTrigger" />
                -->
                
            </list>
        </property>
        <property name="waitForJobsToCompleteOnShutdown">
            <value>true</value>
        </property>
        <property name="configLocation">
            <value>classpath:alfresco/domain/quartz.properties</value>
        </property>
    </bean>


Note: this will change at some point when the scheduler is injected into a trigger, as opposed to the reverse, as now.

LDAP Group synchronization

It has been assumed that groups are stored in LDAP as an object that has a repeating attribute which defines the distinguished names of other groups, or users. This is supported in the standard LDAP schema using the groupOfNames type. This is used in the example configuration. The sample xml file in the distribution has Active Directory settings.

Note: The import of groups will fail when you try to import an empty group (I only tested this in the Enterprise 1.2 release). This issue should be solved in the next release.

    <bean id="ldapGroupExportSource" class="org.alfresco.repo.security.authentication.ldap.LDAPGroupExportSource">
        <property name="groupQuery">
            <value>(objectclass=groupOfNames)</value>
        </property>
        <property name="searchBase">
            <value>dc=company,dc=com</value>
        </property>
        <property name="userIdAttributeName">
            <value>uid</value>
        </property>
        <property name="groupIdAttributeName">
            <value>cn</value>
        </property>
        <property name="groupType">
            <value>groupOfNames</value>
        </property>
        <property name="personType">
            <value>inetOrgPerson</value>
        </property>
        <property name="LDAPInitialDirContextFactory">
            <ref bean="ldapInitialDirContextFactory" />
        </property>
        <property name="namespaceService">
            <ref bean="namespaceService" />
        </property>
        <property name="memberAttribute">
            <value>member</value>
        </property>
    </bean>
searchBase
groupQuery
Combined, these produce the query to find all groups in the LDAP repository that should be in the Alfresco repository. The example is to find all obejcts of type groupOfNames anywhere in the LDAP store.


memberAttribute
On the groups found, this is the name of the repeating attribute that holds the distinguished names of other groups and people.


groupType
When the members of groups are found, if they are of this type, then they are treated as sub groups.


personType
When the members of groups are found, if they are of this type, then they are treated as people members of the group.


userIdAttributeName
For people/users the attribute that is the unique user id.


groupIdAttributeName
For groups, the attribute that is the unique group id


The remaining config is similar to that for people. The main differences are that groups are loaded into the user store and all existing groups are cleared at the start of the import. The trigger and its registration are very similar.


    <bean id="ldapGroupImport" class="org.alfresco.repo.importer.ExportSourceImporter">
        <property name="importerService">
            <ref bean="importerComponent" />
        </property>
        <property name="transactionService">
            <ref bean="transactionComponent"/>
        </property>
        <property name="authenticationComponent">
            <ref bean="authenticationComponent" />
        </property>
        <property name="exportSource">
            <ref bean="ldapGroupExportSource" />
        </property>
        <property name="storeRef">
            <value>${alfresco_user_store.store}</value>
        </property>
        <property name="path">
            <value>/${alfresco_user_store.system_container.childname}/${alfresco_user_store.authorities_container.childname}</value>
        </property>
        <property name="clearAllChildren">
            <value>true</value>
        </property>
         <property name="nodeService">
            <ref bean="nodeService" />
        </property>
         <property name="searchService">
            <ref bean="searchService" />
        </property>
         <property name="namespacePrefixResolver">
            <ref bean="namespaceService" />
        </property>
    </bean>

The schedule for extraction and synchronisation is defined in

   <bean id="ldapGroupTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
       <property name="jobDetail">
           <bean id="ldapGroupJobDetail" class="org.springframework.scheduling.quartz.JobDetailBean">
               <property name="jobClass">
                   <value>org.alfresco.repo.importer.ImporterJob</value>
               </property>
               <property name="jobDataAsMap">
                   <map>
                       <entry key="bean">
                           <ref bean="ldapGroupImport" />
                       </entry>
                   </map>
               </property>
           </bean>
       </property>
       <property name="startDelay">
           <value>60000</value>
       </property>
       <property name="repeatInterval">
           <value>3600000</value>
       </property>
   </bean>


It is wired up to the scheduler in

   <bean id="schedulerFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
       <property name="triggers">
           <list>
               <ref bean="tempFileCleanerTrigger" />
               <ref bean="ftsIndexerTrigger" />
               <ref bean="indexRecoveryTrigger" />
               <ref bean="indexBackupTrigger" />
               <ref bean="ldapGroupTrigger" />
           </list>
       </property>
       <property name="waitForJobsToCompleteOnShutdown">
           <value>true</value>
       </property>
       <property name="configLocation">
           <value>classpath:alfresco/domain/quartz.properties</value>
       </property>
   </bean>


LDAP Configuration after 2.1

For recent alfresco distributions, the above sections are still valid but there should be no need to modify the XML files. Instead there are two properties files


ldap-authentication.properties
ldap-synchronisation.properties


Open LDAP pointers

Here is a sample configuration file.

There are a number of things to note:

  • The maximum number of results returned has been increased from the default of 500. If you have more than 500 users or groups this would be an issue.
  • Digest authentication has been configured to map from a userid to the corresponding distinguished name. See the exmaple data.
  • Passwords are in clear text (so that any authentication mechanism can be used). It is possible they can be in the correct hashed form for the MD5 digest to work.
#
# See slapd.conf(5) for details on configuration options.
# This file should NOT be world readable.
#
include		/usr/local/etc/openldap/schema/core.schema
include		/usr/local/etc/openldap/schema/cosine.schema
include		/usr/local/etc/openldap/schema/inetorgperson.schema


# Define global ACLs to disable default read access.

# Do not enable referrals until AFTER you have a working directory
# service AND an understanding of referrals.
#referral	ldap://root.openldap.org

pidfile		/usr/local/var/run/slapd.pid
argsfile	/usr/local/var/run/slapd.args

# Load dynamic backend modules:
# modulepath	/usr/local/libexec/openldap
# moduleload	back_bdb.la
# moduleload	back_ldap.la
# moduleload	back_ldbm.la
# moduleload	back_passwd.la
# moduleload	back_shell.la

# Sample security restrictions
#	Require integrity protection (prevent hijacking)
#	Require 112-bit (3DES or better) encryption for updates
#	Require 63-bit encryption for simple bind
# security ssf=1 update_ssf=112 simple_bind=64

# Sample access control policy:
#	Root DSE: allow anyone to read it
#	Subschema (sub)entry DSE: allow anyone to read it
#	Other DSEs:
#		Allow self write access
#		Allow authenticated users read access
#		Allow anonymous users to authenticate
#	Directives needed to implement policy:
# access to dn.base="" by * read
# access to dn.base="cn=Subschema" by * read
# access to *
#	by self write
#	by users read
#	by anonymous auth
#
# if no access controls are present, the default policy
# allows anyone and everyone to read anything but restricts
# updates to rootdn.  (e.g., "access to * by * read")
#
# rootdn can always read and write EVERYTHING!

#######################################################################
# BDB database definitions
#######################################################################

database	bdb
suffix		"dc=company,dc=com"
rootdn		"cn=Manager,dc=company,dc=com"
# Cleartext passwords, especially for the rootdn, should
# be avoid.  See slappasswd(8) and slapd.conf(5) for details.
# Use of strong authentication encouraged.
# This is secret ....
rootpw          {SSHA}u9AUUYOSVX6idlXcwyYOAG6G84oHFpvG
# The database directory MUST exist prior to running slapd AND 
# should only be accessible by the slapd and slap tools.
# Mode 700 recommended.
directory	/usr/local/var/openldap-data
# Indices to maintain
index	objectClass	eq

# Clear text to allow hashing 
password-hash	{CLEARTEXT}


# SASL mappings for md5 digest authentication
# Extract the user id and use as the search key

authz-regexp
   uid=([^,]*),cn=digest-md5,cn=auth
   ldap:///dc=company,dc=com??one?(uid=$1)

authz-regexp
   uid=([^,]*),cn=company.com,cn=digest-md5,cn=auth
   ldap:///dc=company,dc=com??one?(uid=$1)

# Tweaks to increase the result set size and max query time

sizelimit 50000
timelimit 3600

Here is a very simple example data file that defines the ldap manager, admin user, an example user and an example group.


dn: dc=company,dc=com
changetype: add
objectclass: dcObject
objectclass: organization
o: Company Limited
dc: company

dn: cn=Manager,dc=company,dc=com
changetype: add
objectclass: organizationalRole
cn: Manager

dn: cn=admin,dc=company,dc=com
changetype: add
objectclass: inetOrgPerson
sn: Admin
cn: admin
userPassword: admin
telephoneNumber: 1234567890
uid: admin
givenName: Admin
mail: admin@company.org
o: Company Limited


dn: cn=Full Name,dc=company,dc=com
changetype: add
objectclass: inetOrgPerson
sn: Name
cn: Full Name
userPassword: inClearText
telephoneNumber: 1234567890
uid: fullname
givenName: Full
mail: full.name@company.com
o: Company Limited


dn: cn=Group One,dc=company,dc=com
changetype: add
objectclass: groupOfNames
cn: Group One
member: cn=Full Name,dc=company,dc=com 


Active Directory Tips for LDAP People and Group Synchronisation

  • You may need to give special permissions in the Active Directory to the account that you are using to do the LDAP bind (the java.naming.security.pricipal) in the authentication-services-context.xml file. To do this, open Active Directory Users and Computers, right click on the domain, and select "Delegate Control..." Click "Next", then select the user that you are using for the LDAP bind and click "Next". The permission that they will need is on the next screen "Read all inetOrgPerson information."
  • The syntax for the bean "ldapInitialDirContextFactory" looks like this for Active Directory. Note that this is NOT using SSL. SSL is recommended for production systems. You'll need to switch the port from 389 (below, non-SSL) to 636 for SSL.
<bean id="ldapInitialDirContextFactory" class="org.alfresco.repo.security.authentication.ldap.LDAPInitialDirContextFactoryImpl">
       <property name="initialDirContextEnvironment">
               <map>
                       <entry key="java.naming.factory.initial">
                               <value>com.sun.jndi.ldap.LdapCtxFactory</value>
                       </entry>
                       <entry key="java.naming.provider.url">
                               <value>ldap://domaincontroller.your.company.org:389</value>
                       </entry>
                       <entry key="java.naming.security.authentication">
                               <value>simple</value>
                       </entry>
                       <entry key="java.naming.security.principal">
                               <value>cn=Al Fresco,ou=SomeOU,dc=your,dc=company,dc=org</value>
                       </entry>
                       <entry key="java.naming.security.credentials">
                               <value>AlFrescoActiveDirectoryUserPassword</value>
                       </entry>
               </map>
       </property>
</bean>
  • It is often helpful to screen out non-user accounts and disabled accounts. One way to do this is to use a LDAP filter of userAccountControl=512. In combination with filtering for users who have all of the attributes needed for synchronisation, the filter would look like this.
<property name="personQuery">
 <value><![CDATA[(&(userAccountControl=512)(givenName=*)(sn=*)(mail=*)(company=*))]]></value>
</property>
  • Use the samAccountName for the userNameFormat as follows:
<bean id="authenticationComponentImpl" class="org.alfresco.repo.security.authentication.ldap.LDAPAuthenticationComponentImpl">
       <property name="LDAPInitialDirContextFactory">
               <ref bean="ldapInitialDirContextFactory" />
       </property>
       <property name="userNameFormat">
               <value>samaccountname=%s</value>
       </property>
</bean>
  • The attribute mapping should look like this:
<property name="attributeMapping">
               <map>
               <entry key="cm:userName">
                       <value>samaccountname</value>
               </entry>
               <entry key="cm:firstName">
                       <value>givenName</value>
               </entry>
               <entry key="cm:lastName">
                       <value>sn</value>
               </entry>
               <entry key="cm:email">
                       <value>mail</value>
               </entry>
               <entry key="cm:organizationId">
                       <value>company</value>
               </entry>
               </map>
</property>
  • The userIdAttributeName should be samAccountName as follows:
<property name="userIdAttributeName">
               <value>samaccountname</value>
</property>
  • For LDAP group synchronisation, the memberAttribute should be member as follows:
<property name="memberAttribute">
           <value>member</value>
</property>

RepositoryAuthenticationDao

Stores users in the Alfresco user store. The main configuration option determines if user names are case sensitive.


DefaultMutableAuthenticationDao

This DAO should be used with all external authentication components. There is some other way to make these changes to the information held in external authentication system. Alfresco never makes any changes to external authentication system. You would have to write your own DAO to do this.

By default all DAO operation will throw a runtime exception. It can be configured to allow the following actions which will then be a NO-OP or return the boolean values indicated.

Normally it is sufficient to allowDeleteUser which will allow people to be deleted via the Alfresco JSF client when using NTLM, JAAS/Kerberos, LDAP etc.

If you are using Alfresco Share then it is necessary to set allowGetEnabled to true to prevent site invites from breaking.

allowCreateUser
false - Exception
true - No-op
Allow users to be created. The backing authentication instance will not be updated. No user would be created in Active Directory, LDAP, etc.
allowUpdateUser
false - Exception
true - No-op
Allow user information to be updated without affecting the backing authentication instance.
allowDeleteUser
false - Exception
true - No-op
Allow users to be deleted without affecting the backing authentication instance.
allowSetEnabled
false - Exception
true - No-op
Allow users to be enabled/disabled without affecting the backing authentication instance.
allowGetEnabled
false - Exception
true - returns true.
allowSetAccountExpires
false - Exception
true - No-op


allowGetAccountHasExpired
false - Exception
true - returns false


allowSetCredentialsExpire
false - Exception
true - No-op
allowGetCredentialsExpire
false - Exception
true - returns false


allowGetCredentialsHaveExpired
false - Exception
true - returns false


allowSetAccountLocked
false - Exception
true - No-op


allowGetAccountLocked
false - Exception
true - returns false


allowSetAccountExpiryDate
false - Exception
true - No-op
allowGetAccountExpiryDate
false - Exception
true - returns null
allowSetCredentialsExpiryDate
false - Exception
true - No-op


allowGetCredentialsExpiryDate
false - Exception
true - No-op
false - returns null

External links

JAAS related:

LDAP related:

Examples

LDAP - known limitations

Most of these issues are fixed in Alfresco version 3.2. See Alfresco Authentication Subsystems.

  • No support for paging LDAP queries [2]
  • No support to look up a user by ID to get their DN and do a simple bind (unless doing this Alfresco JIRA)
  • No support to delete users
  • Does not skip existing info that would not be updated by a user/group import
  • No way to delete users automatically that are no longer in LDAP (would need to move away from the export based implementation)
  • poor support for queries based on various tree permissions (you would have to define another stack of beans to restrict import to two sub trees of users)
  • No way to partition the import and run a series of smaller jobs without lots of config
  • Config is error prone - there should be one bean holding all config (eg the user uid attribute)
Personal tools
© 2014 Alfresco Software, Inc. All Rights Reserved. Legal | Privacy | Accessibility