mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-14 17:58:59 +00:00
ETHREEOH-2242: New ldap-ad Authentication subsystem with defaults for Active Directory
- Fixed parsing of timestamps - Fixed resolution of group members - Shared Spring configuration with ldap subsystem - Authentication still only supported with DIGEST-MD5 binding enabled - chain with passthru authentication otherwise git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@14934 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -0,0 +1,354 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
|
||||
<!--
|
||||
Bean definitions shared by the ldap and ldap-ad subsystems
|
||||
-->
|
||||
|
||||
<beans>
|
||||
<!--
|
||||
DAO that rejects changes - LDAP is read only at the moment. It does allow users to be deleted with out warnings
|
||||
from the UI.
|
||||
-->
|
||||
|
||||
<bean id="authenticationDao" class="org.alfresco.repo.security.authentication.DefaultMutableAuthenticationDao">
|
||||
<property name="allowSetEnabled" value="true" />
|
||||
<property name="allowGetEnabled" value="true" />
|
||||
<property name="allowDeleteUser" value="true" />
|
||||
<property name="allowCreateUser" value="true" />
|
||||
</bean>
|
||||
|
||||
<!-- LDAP authentication configuration -->
|
||||
|
||||
<!--
|
||||
|
||||
You can also use JAAS authentication for Kerberos against Active Directory or NTLM if you also require single sign
|
||||
on from the web browser. You do not have to use LDAP authentication to synchronise groups and users from an LDAP
|
||||
store if it supports other authentication routes, like Active Directory.
|
||||
-->
|
||||
|
||||
<bean id="authenticationComponent" class="org.alfresco.repo.security.authentication.ldap.LDAPAuthenticationComponentImpl"
|
||||
parent="authenticationComponentBase">
|
||||
<property name="active">
|
||||
<value>${ldap.authentication.active}</value>
|
||||
</property>
|
||||
<property name="LDAPInitialDirContextFactory">
|
||||
<ref bean="ldapInitialDirContextFactory" />
|
||||
</property>
|
||||
<property name="userNameFormat">
|
||||
<!--
|
||||
|
||||
This maps between what the user types in and what is passed through to the underlying LDAP authentication.
|
||||
|
||||
"%s" - the user id is passed through without modification. Used for LDAP authentication such as DIGEST-MD5,
|
||||
anything that is not "simple". "cn=%s,ou=London,dc=company,dc=com" - If the user types in "Joe Bloggs" the
|
||||
authenticate as "cn=Joe Bloggs,ou=London,dc=company,dc=com" Usually for simple authentication. Simple
|
||||
authentication always uses the DN for the user.
|
||||
-->
|
||||
<value>${ldap.authentication.userNameFormat}</value>
|
||||
</property>
|
||||
<property name="nodeService">
|
||||
<ref bean="nodeService" />
|
||||
</property>
|
||||
<property name="personService">
|
||||
<ref bean="personService" />
|
||||
</property>
|
||||
<property name="transactionService">
|
||||
<ref bean="transactionService" />
|
||||
</property>
|
||||
<property name="escapeCommasInBind">
|
||||
<value>${ldap.authentication.escapeCommasInBind}</value>
|
||||
</property>
|
||||
<property name="escapeCommasInUid">
|
||||
<value>${ldap.authentication.escapeCommasInUid}</value>
|
||||
</property>
|
||||
<property name="allowGuestLogin">
|
||||
<value>${ldap.authentication.allowGuestLogin}</value>
|
||||
</property>
|
||||
<property name="defaultAdministratorUserNameList">
|
||||
<value>${ldap.authentication.defaultAdministratorUserNames}</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Wrapped version to be used within subsystem -->
|
||||
<bean id="AuthenticationComponent" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
|
||||
<property name="proxyInterfaces">
|
||||
<value>org.alfresco.repo.security.authentication.AuthenticationComponent</value>
|
||||
</property>
|
||||
<property name="transactionManager">
|
||||
<ref bean="transactionManager" />
|
||||
</property>
|
||||
<property name="target">
|
||||
<ref bean="authenticationComponent" />
|
||||
</property>
|
||||
<property name="transactionAttributes">
|
||||
<props>
|
||||
<prop key="*">${server.transaction.mode.default}</prop>
|
||||
</props>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Authenticaton service for chaining -->
|
||||
<bean id="localAuthenticationService" class="org.alfresco.repo.security.authentication.AuthenticationServiceImpl">
|
||||
<property name="authenticationDao">
|
||||
<ref bean="authenticationDao" />
|
||||
</property>
|
||||
<property name="ticketComponent">
|
||||
<ref bean="ticketComponent" />
|
||||
</property>
|
||||
<property name="authenticationComponent">
|
||||
<ref bean="authenticationComponent" />
|
||||
</property>
|
||||
<property name="sysAdminCache">
|
||||
<ref bean="sysAdminCache" />
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!--
|
||||
|
||||
This bean is used to support general LDAP authentication. It is also used to provide read only access to users and
|
||||
groups to pull them out of the LDAP reopsitory
|
||||
-->
|
||||
|
||||
<bean id="ldapInitialDirContextFactory" class="org.alfresco.repo.security.authentication.ldap.LDAPInitialDirContextFactoryImpl">
|
||||
<property name="initialDirContextEnvironment">
|
||||
<map>
|
||||
<!-- The LDAP provider -->
|
||||
<entry key="java.naming.factory.initial">
|
||||
<value>${ldap.authentication.java.naming.factory.initial}</value>
|
||||
</entry>
|
||||
|
||||
<!-- The url to the LDAP server -->
|
||||
<!-- Note you can use space separated urls - they will be tried in turn until one works -->
|
||||
<!-- This could be used to authenticate against one or more ldap servers (you will not know which one ....) -->
|
||||
<entry key="java.naming.provider.url">
|
||||
<value>${ldap.authentication.java.naming.provider.url}</value>
|
||||
</entry>
|
||||
|
||||
<!-- The authentication mechanism to use -->
|
||||
<!-- Some sasl authentication mechanisms may require a realm to be set -->
|
||||
<!-- java.naming.security.sasl.realm -->
|
||||
<!-- The available options will depend on your LDAP provider -->
|
||||
<entry key="java.naming.security.authentication">
|
||||
<value>${ldap.authentication.java.naming.security.authentication}</value>
|
||||
</entry>
|
||||
|
||||
<!-- The id of a user who can read group and user information -->
|
||||
<!-- This does not go through the pattern substitution defined above and is used "as is" -->
|
||||
<entry key="java.naming.security.principal">
|
||||
<value>${ldap.synchronization.java.naming.security.principal}</value>
|
||||
</entry>
|
||||
|
||||
<!-- The password for the user defined above -->
|
||||
<entry key="java.naming.security.credentials">
|
||||
<value>${ldap.synchronization.java.naming.security.credentials}</value>
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Regularly exports user and group information from LDAP -->
|
||||
|
||||
<bean id="userRegistry" class="org.alfresco.repo.security.sync.ldap.LDAPUserRegistry">
|
||||
<property name="active">
|
||||
<value>${ldap.synchronization.active}</value>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
If positive, this property indicates that RFC 2696 paged results should be
|
||||
used to split query results into batches of the specified size. This
|
||||
overcomes any size limits imposed by the LDAP server.
|
||||
-->
|
||||
<property name="queryBatchSize">
|
||||
<value>${ldap.synchronization.queryBatchSize}</value>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
The query to select all objects that represent the groups to import.
|
||||
|
||||
For Open LDAP, using a basic schema, the following is probably what you want:
|
||||
(objectclass=groupOfNames)
|
||||
|
||||
For Active Directory:
|
||||
(objectclass=group)
|
||||
-->
|
||||
<property name="groupQuery">
|
||||
<value>${ldap.synchronization.groupQuery}</value>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
The query to select objects that represent the groups to import that have changed since a certain time.
|
||||
|
||||
For Open LDAP, using a basic schema, the following is probably what you want:
|
||||
(&(objectclass=groupOfNames)(!(modifyTimestamp<={0})))
|
||||
|
||||
For Active Directory:
|
||||
(&(objectclass=group)(!(modifyTimestamp<={0})))
|
||||
-->
|
||||
<property name="groupDifferentialQuery">
|
||||
<value>${ldap.synchronization.groupDifferentialQuery}</value>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
The query to select all objects that represent the users to import.
|
||||
|
||||
For Open LDAP, using a basic schema, the following is probably what you want:
|
||||
(objectclass=inetOrgPerson)
|
||||
|
||||
For Active Directory:
|
||||
(objectclass=user)
|
||||
-->
|
||||
<property name="personQuery">
|
||||
<value>${ldap.synchronization.personQuery}</value>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
The query to select objects that represent the users to import that have changed since a certain time.
|
||||
|
||||
For Open LDAP, using a basic schema, the following is probably what you want:
|
||||
(&(objectclass=inetOrgPerson)(!(modifyTimestamp<={0})))
|
||||
|
||||
For Active Directory:
|
||||
(&(objectclass=user)(!(modifyTimestamp<={0})))
|
||||
-->
|
||||
<property name="personDifferentialQuery">
|
||||
<value>${ldap.synchronization.personDifferentialQuery}</value>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
The group search base restricts the LDAP group query to a sub section of tree on the LDAP server.
|
||||
-->
|
||||
<property name="groupSearchBase">
|
||||
<value>${ldap.synchronization.groupSearchBase}</value>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
The user search base restricts the LDAP user query to a sub section of tree on the LDAP server.
|
||||
-->
|
||||
<property name="userSearchBase">
|
||||
<value>${ldap.synchronization.userSearchBase}</value>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
The unique identifier for the user.
|
||||
-->
|
||||
<property name="userIdAttributeName">
|
||||
<value>${ldap.synchronization.userIdAttributeName}</value>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
The name of the operational attribute recording the last update time for a group or user.
|
||||
-->
|
||||
<property name="modifyTimestampAttributeName">
|
||||
<value>${ldap.synchronization.modifyTimestampAttributeName}</value>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
The timestamp format. Unfortunately, this varies between directory servers.
|
||||
-->
|
||||
<property name="timestampFormat">
|
||||
<value>${ldap.synchronization.timestampFormat}</value>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
An attribute that is a unique identifier for each group found.
|
||||
This is also the name of the group with the current group implementation.
|
||||
This is mandatory for any groups found.
|
||||
|
||||
OpenLDAP: "cn" as it is mandatory on groupOfNames
|
||||
Active Directory: "cn"
|
||||
|
||||
-->
|
||||
<property name="groupIdAttributeName">
|
||||
<value>${ldap.synchronization.groupIdAttributeName}</value>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
The objectClass attribute for group members.
|
||||
For each member of a group, the distinguished name is given.
|
||||
The object is looked up by its DN. If the object is of this class it is treated as a group.
|
||||
-->
|
||||
<property name="groupType">
|
||||
<value>${ldap.synchronization.groupType}</value>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
The objectClass attribute for person members.
|
||||
For each member of a group, the distinguished name is given.
|
||||
The object is looked up by its DN. If the object is of this class it is treated as a person.
|
||||
-->
|
||||
<property name="personType">
|
||||
<value>${ldap.synchronization.personType}</value>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
The repeating attribute on group objects (found by query or as sub groups)
|
||||
used to define membership of the group. This is assumed to hold distinguished names of
|
||||
other groups or users/people; the above types are used to determine this.
|
||||
|
||||
OpenLDAP: "member" as it is mandatory on groupOfNames
|
||||
Active Directory: "member"
|
||||
|
||||
-->
|
||||
<property name="memberAttribute">
|
||||
<value>${ldap.synchronization.groupMemberAttributeName}</value>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
This property defines a mapping between attributes held on LDAP user objects and
|
||||
the properties of user objects held in the repository. The key is the QName of an attribute in
|
||||
the repository, the value is the attribute name from the user/inetOrgPerson/.. object in the
|
||||
LDAP repository.
|
||||
-->
|
||||
<property name="attributeMapping">
|
||||
<map>
|
||||
<entry key="cm:userName">
|
||||
<!-- Must match the same attribute as userIdAttributeName -->
|
||||
<value>${ldap.synchronization.userIdAttributeName}</value>
|
||||
</entry>
|
||||
<entry key="cm:firstName">
|
||||
<!-- OpenLDAP: "givenName" -->
|
||||
<!-- Active Directory: "givenName" -->
|
||||
<value>${ldap.synchronization.userFirstNameAttributeName}</value>
|
||||
</entry>
|
||||
<entry key="cm:lastName">
|
||||
<!-- OpenLDAP: "sn" -->
|
||||
<!-- Active Directory: "sn" -->
|
||||
<value>${ldap.synchronization.userLastNameAttributeName}</value>
|
||||
</entry>
|
||||
<entry key="cm:email">
|
||||
<!-- OpenLDAP: "mail" -->
|
||||
<!-- Active Directory: "???" -->
|
||||
<value>${ldap.synchronization.userEmailAttributeName}</value>
|
||||
</entry>
|
||||
<entry key="cm:organizationId">
|
||||
<!-- OpenLDAP: "o" -->
|
||||
<!-- Active Directory: "???" -->
|
||||
<value>${ldap.synchronization.userOrganizationalIdAttributeName}</value>
|
||||
</entry>
|
||||
<!-- Always use the default -->
|
||||
<entry key="cm:homeFolderProvider">
|
||||
<null/>
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
<!-- Set a default home folder provider -->
|
||||
<!-- Defaults only apply for values above -->
|
||||
<property name="attributeDefaults">
|
||||
<map>
|
||||
<entry key="cm:homeFolderProvider">
|
||||
<value>${ldap.synchronization.defaultHomeFolderProvider}</value>
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
|
||||
<!-- Services -->
|
||||
<property name="LDAPInitialDirContextFactory">
|
||||
<ref bean="ldapInitialDirContextFactory"/>
|
||||
</property>
|
||||
<property name="namespaceService">
|
||||
<ref bean="namespaceService"/>
|
||||
</property>
|
||||
|
||||
</bean>
|
||||
|
||||
</beans>
|
@@ -0,0 +1,10 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
|
||||
|
||||
<beans>
|
||||
<!--
|
||||
The bean definitions for this subsystem are shared by the ldap and ldap-ad subsystems with different property
|
||||
defaults
|
||||
-->
|
||||
<import resource="../common-ldap-context.xml" />
|
||||
</beans>
|
@@ -0,0 +1,109 @@
|
||||
# This flag enables use of this LDAP subsystem for authentication. It may be
|
||||
# that this subsytem should only be used for synchronization, in which case
|
||||
# this flag should be set to false.
|
||||
ldap.authentication.active=true
|
||||
|
||||
#
|
||||
# This properties file brings together the common options for LDAP authentication rather than editing the bean definitions
|
||||
#
|
||||
ldap.authentication.allowGuestLogin=true
|
||||
# How to map the user id entered by the user to taht passed through to LDAP
|
||||
# - simple
|
||||
# - this must be a DN and would be something like
|
||||
# uid=%s,ou=People,dc=company,dc=com
|
||||
# - digest
|
||||
# - usually pass through what is entered
|
||||
# %s
|
||||
ldap.authentication.userNameFormat=%s
|
||||
|
||||
# The LDAP context factory to use
|
||||
ldap.authentication.java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory
|
||||
|
||||
# The URL to connect to the LDAP server
|
||||
ldap.authentication.java.naming.provider.url=ldap://domaincontroller.company.com:389
|
||||
|
||||
# The authentication mechanism to use
|
||||
ldap.authentication.java.naming.security.authentication=DIGEST-MD5
|
||||
|
||||
# Escape commas entered by the user at bind time
|
||||
# Useful when using simple authentication and the CN is part of the DN and contains commas
|
||||
ldap.authentication.escapeCommasInBind=false
|
||||
|
||||
# Escape commas entered by the user when setting the authenticated user
|
||||
# Useful when using simple authentication and the CN is part of the DN and contains commas, and the escaped \, is
|
||||
# pulled in as part of an LDAP sync
|
||||
# If this option is set to true it will break the default home folder provider as space names can not contain \
|
||||
ldap.authentication.escapeCommasInUid=false
|
||||
|
||||
# Comma separated list of user names who should be considered administrators by default
|
||||
ldap.authentication.defaultAdministratorUserNames=Administrator
|
||||
|
||||
# This flag enables use of this LDAP subsystem for user and group
|
||||
# synchronization. It may be that this subsytem should only be used for
|
||||
# authentication, in which case this flag should be set to false.
|
||||
ldap.synchronization.active=true
|
||||
|
||||
# The default principal to use (only used for LDAP sync)
|
||||
ldap.synchronization.java.naming.security.principal=alfresco
|
||||
|
||||
# The password for the default principal (only used for LDAP sync)
|
||||
ldap.synchronization.java.naming.security.credentials=secret
|
||||
|
||||
# If positive, this property indicates that RFC 2696 paged results should be
|
||||
# used to split query results into batches of the specified size. This
|
||||
# overcomes any size limits imposed by the LDAP server.
|
||||
ldap.synchronization.queryBatchSize=1000
|
||||
|
||||
# The query to select all objects that represent the groups to import.
|
||||
ldap.synchronization.groupQuery=(objectclass\=group)
|
||||
|
||||
# The query to select objects that represent the groups to import that have changed since a certain time.
|
||||
ldap.synchronization.groupDifferentialQuery=(&(objectclass\=group)(!(modifyTimestamp<\={0})))
|
||||
|
||||
# The query to select all objects that represent the users to import.
|
||||
ldap.synchronization.personQuery=(&(objectclass\=user)(userAccountControl\:1.2.840.113556.1.4.803\:\=512))
|
||||
|
||||
# The query to select objects that represent the users to import that have changed since a certain time.
|
||||
ldap.synchronization.personDifferentialQuery=(&(objectclass\=user)(userAccountControl\:1.2.840.113556.1.4.803\:\=512)(!(modifyTimestamp<\={0})))
|
||||
|
||||
# The group search base restricts the LDAP group query to a sub section of tree on the LDAP server.
|
||||
ldap.synchronization.groupSearchBase=ou\=Security Groups,ou\=Alfresco,dc=domain
|
||||
|
||||
# The user search base restricts the LDAP user query to a sub section of tree on the LDAP server.
|
||||
ldap.synchronization.userSearchBase=ou\=User Accounts,ou=\Alfresco,dc=domain
|
||||
|
||||
# The name of the operational attribute recording the last update time for a group or user.
|
||||
ldap.synchronization.modifyTimestampAttributeName=modifyTimestamp
|
||||
|
||||
# The timestamp format. Unfortunately, this varies between directory servers.
|
||||
ldap.synchronization.timestampFormat=yyyyMMddHHmmss'.0Z'
|
||||
|
||||
# The attribute name on people objects found in LDAP to use as the uid in Alfresco
|
||||
ldap.synchronization.userIdAttributeName=sAMAccountName
|
||||
|
||||
# The attribute on person objects in LDAP to map to the first name property in Alfresco
|
||||
ldap.synchronization.userFirstNameAttributeName=givenName
|
||||
|
||||
# The attribute on person objects in LDAP to map to the last name property in Alfresco
|
||||
ldap.synchronization.userLastNameAttributeName=sn
|
||||
|
||||
# The attribute on person objects in LDAP to map to the email property in Alfresco
|
||||
ldap.synchronization.userEmailAttributeName=mail
|
||||
|
||||
# The attribute on person objects in LDAP to map to the organizational id property in Alfresco
|
||||
ldap.synchronization.userOrganizationalIdAttributeName=company
|
||||
|
||||
# The default home folder provider to use for people created via LDAP import
|
||||
ldap.synchronization.defaultHomeFolderProvider=personalHomeFolderProvider
|
||||
|
||||
# The attribute on LDAP group objects to map to the gid property in Alfrecso
|
||||
ldap.synchronization.groupIdAttributeName=cn
|
||||
|
||||
# The group type in LDAP
|
||||
ldap.synchronization.groupType=group
|
||||
|
||||
# The person type in LDAP
|
||||
ldap.synchronization.personType=user
|
||||
|
||||
# The attribute in LDAP on group objects that defines the DN for its members
|
||||
ldap.synchronization.groupMemberAttributeName=member
|
@@ -3,342 +3,8 @@
|
||||
|
||||
<beans>
|
||||
<!--
|
||||
DAO that rejects changes - LDAP is read only at the moment. It does allow users to be deleted with out warnings
|
||||
from the UI.
|
||||
The bean definitions for this subsystem are shared by the ldap and ldap-ad subsystems with different property
|
||||
defaults
|
||||
-->
|
||||
|
||||
<bean id="authenticationDao" class="org.alfresco.repo.security.authentication.DefaultMutableAuthenticationDao">
|
||||
<property name="allowSetEnabled" value="true" />
|
||||
<property name="allowGetEnabled" value="true" />
|
||||
<property name="allowDeleteUser" value="true" />
|
||||
<property name="allowCreateUser" value="true" />
|
||||
</bean>
|
||||
|
||||
<!-- LDAP authentication configuration -->
|
||||
|
||||
<!--
|
||||
|
||||
You can also use JAAS authentication for Kerberos against Active Directory or NTLM if you also require single sign
|
||||
on from the web browser. You do not have to use LDAP authentication to synchronise groups and users from an LDAP
|
||||
store if it supports other authentication routes, like Active Directory.
|
||||
-->
|
||||
|
||||
<bean id="authenticationComponent" class="org.alfresco.repo.security.authentication.ldap.LDAPAuthenticationComponentImpl"
|
||||
parent="authenticationComponentBase">
|
||||
<property name="active">
|
||||
<value>${ldap.authentication.active}</value>
|
||||
</property>
|
||||
<property name="LDAPInitialDirContextFactory">
|
||||
<ref bean="ldapInitialDirContextFactory" />
|
||||
</property>
|
||||
<property name="userNameFormat">
|
||||
<!--
|
||||
|
||||
This maps between what the user types in and what is passed through to the underlying LDAP authentication.
|
||||
|
||||
"%s" - the user id is passed through without modification. Used for LDAP authentication such as DIGEST-MD5,
|
||||
anything that is not "simple". "cn=%s,ou=London,dc=company,dc=com" - If the user types in "Joe Bloggs" the
|
||||
authenticate as "cn=Joe Bloggs,ou=London,dc=company,dc=com" Usually for simple authentication. Simple
|
||||
authentication always uses the DN for the user.
|
||||
-->
|
||||
<value>${ldap.authentication.userNameFormat}</value>
|
||||
</property>
|
||||
<property name="nodeService">
|
||||
<ref bean="nodeService" />
|
||||
</property>
|
||||
<property name="personService">
|
||||
<ref bean="personService" />
|
||||
</property>
|
||||
<property name="transactionService">
|
||||
<ref bean="transactionService" />
|
||||
</property>
|
||||
<property name="escapeCommasInBind">
|
||||
<value>${ldap.authentication.escapeCommasInBind}</value>
|
||||
</property>
|
||||
<property name="escapeCommasInUid">
|
||||
<value>${ldap.authentication.escapeCommasInUid}</value>
|
||||
</property>
|
||||
<property name="allowGuestLogin">
|
||||
<value>${ldap.authentication.allowGuestLogin}</value>
|
||||
</property>
|
||||
<property name="defaultAdministratorUserNameList">
|
||||
<value>${ldap.authentication.defaultAdministratorUserNames}</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Wrapped version to be used within subsystem -->
|
||||
<bean id="AuthenticationComponent" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
|
||||
<property name="proxyInterfaces">
|
||||
<value>org.alfresco.repo.security.authentication.AuthenticationComponent</value>
|
||||
</property>
|
||||
<property name="transactionManager">
|
||||
<ref bean="transactionManager" />
|
||||
</property>
|
||||
<property name="target">
|
||||
<ref bean="authenticationComponent" />
|
||||
</property>
|
||||
<property name="transactionAttributes">
|
||||
<props>
|
||||
<prop key="*">${server.transaction.mode.default}</prop>
|
||||
</props>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Authenticaton service for chaining -->
|
||||
<bean id="localAuthenticationService" class="org.alfresco.repo.security.authentication.AuthenticationServiceImpl">
|
||||
<property name="authenticationDao">
|
||||
<ref bean="authenticationDao" />
|
||||
</property>
|
||||
<property name="ticketComponent">
|
||||
<ref bean="ticketComponent" />
|
||||
</property>
|
||||
<property name="authenticationComponent">
|
||||
<ref bean="authenticationComponent" />
|
||||
</property>
|
||||
<property name="sysAdminCache">
|
||||
<ref bean="sysAdminCache" />
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!--
|
||||
|
||||
This bean is used to support general LDAP authentication. It is also used to provide read only access to users and
|
||||
groups to pull them out of the LDAP reopsitory
|
||||
-->
|
||||
|
||||
<bean id="ldapInitialDirContextFactory" class="org.alfresco.repo.security.authentication.ldap.LDAPInitialDirContextFactoryImpl">
|
||||
<property name="initialDirContextEnvironment">
|
||||
<map>
|
||||
<!-- The LDAP provider -->
|
||||
<entry key="java.naming.factory.initial">
|
||||
<value>${ldap.authentication.java.naming.factory.initial}</value>
|
||||
</entry>
|
||||
|
||||
<!-- The url to the LDAP server -->
|
||||
<!-- Note you can use space separated urls - they will be tried in turn until one works -->
|
||||
<!-- This could be used to authenticate against one or more ldap servers (you will not know which one ....) -->
|
||||
<entry key="java.naming.provider.url">
|
||||
<value>${ldap.authentication.java.naming.provider.url}</value>
|
||||
</entry>
|
||||
|
||||
<!-- The authentication mechanism to use -->
|
||||
<!-- Some sasl authentication mechanisms may require a realm to be set -->
|
||||
<!-- java.naming.security.sasl.realm -->
|
||||
<!-- The available options will depend on your LDAP provider -->
|
||||
<entry key="java.naming.security.authentication">
|
||||
<value>${ldap.authentication.java.naming.security.authentication}</value>
|
||||
</entry>
|
||||
|
||||
<!-- The id of a user who can read group and user information -->
|
||||
<!-- This does not go through the pattern substitution defined above and is used "as is" -->
|
||||
<entry key="java.naming.security.principal">
|
||||
<value>${ldap.authentication.java.naming.security.principal}</value>
|
||||
</entry>
|
||||
|
||||
<!-- The password for the user defined above -->
|
||||
<entry key="java.naming.security.credentials">
|
||||
<value>${ldap.authentication.java.naming.security.credentials}</value>
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Regularly exports user and group information from LDAP -->
|
||||
|
||||
<bean id="userRegistry" class="org.alfresco.repo.security.sync.ldap.LDAPUserRegistry">
|
||||
<property name="active">
|
||||
<value>${ldap.synchronization.active}</value>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
If positive, this property indicates that RFC 2696 paged results should be
|
||||
used to split query results into batches of the specified size. This
|
||||
overcomes any size limits imposed by the LDAP server.
|
||||
-->
|
||||
<property name="queryBatchSize">
|
||||
<value>${ldap.synchronization.queryBatchSize}</value>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
The query to select all objects that represent the groups to import.
|
||||
|
||||
For Open LDAP, using a basic schema, the following is probably what you want:
|
||||
(objectclass=groupOfNames)
|
||||
|
||||
For Active Directory:
|
||||
(objectclass=group)
|
||||
-->
|
||||
<property name="groupQuery">
|
||||
<value>${ldap.synchronization.groupQuery}</value>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
The query to select objects that represent the groups to import that have changed since a certain time.
|
||||
|
||||
For Open LDAP, using a basic schema, the following is probably what you want:
|
||||
(&(objectclass=groupOfNames)(!(modifyTimestamp<={0})))
|
||||
|
||||
For Active Directory:
|
||||
(&(objectclass=group)(!(modifyTimestamp<={0})))
|
||||
-->
|
||||
<property name="groupDifferentialQuery">
|
||||
<value>${ldap.synchronization.groupDifferentialQuery}</value>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
The query to select all objects that represent the users to import.
|
||||
|
||||
For Open LDAP, using a basic schema, the following is probably what you want:
|
||||
(objectclass=inetOrgPerson)
|
||||
|
||||
For Active Directory:
|
||||
(objectclass=user)
|
||||
-->
|
||||
<property name="personQuery">
|
||||
<value>${ldap.synchronization.personQuery}</value>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
The query to select objects that represent the users to import that have changed since a certain time.
|
||||
|
||||
For Open LDAP, using a basic schema, the following is probably what you want:
|
||||
(&(objectclass=inetOrgPerson)(!(modifyTimestamp<={0})))
|
||||
|
||||
For Active Directory:
|
||||
(&(objectclass=user)(!(modifyTimestamp<={0})))
|
||||
-->
|
||||
<property name="personDifferentialQuery">
|
||||
<value>${ldap.synchronization.personDifferentialQuery}</value>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
The group search base restricts the LDAP group query to a sub section of tree on the LDAP server.
|
||||
-->
|
||||
<property name="groupSearchBase">
|
||||
<value>${ldap.synchronization.groupSearchBase}</value>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
The user search base restricts the LDAP user query to a sub section of tree on the LDAP server.
|
||||
-->
|
||||
<property name="userSearchBase">
|
||||
<value>${ldap.synchronization.userSearchBase}</value>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
The unique identifier for the user.
|
||||
-->
|
||||
<property name="userIdAttributeName">
|
||||
<value>${ldap.synchronization.userIdAttributeName}</value>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
The name of the operational attribute recording the last update time for a group or user.
|
||||
-->
|
||||
<property name="modifyTimestampAttributeName">
|
||||
<value>${ldap.synchronization.modifyTimestampAttributeName}</value>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
An attribute that is a unique identifier for each group found.
|
||||
This is also the name of the group with the current group implementation.
|
||||
This is mandatory for any groups found.
|
||||
|
||||
OpenLDAP: "cn" as it is mandatory on groupOfNames
|
||||
Active Directory: "cn"
|
||||
|
||||
-->
|
||||
<property name="groupIdAttributeName">
|
||||
<value>${ldap.synchronization.groupIdAttributeName}</value>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
The objectClass attribute for group members.
|
||||
For each member of a group, the distinguished name is given.
|
||||
The object is looked up by its DN. If the object is of this class it is treated as a group.
|
||||
-->
|
||||
<property name="groupType">
|
||||
<value>${ldap.synchronization.groupType}</value>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
The objectClass attribute for person members.
|
||||
For each member of a group, the distinguished name is given.
|
||||
The object is looked up by its DN. If the object is of this class it is treated as a person.
|
||||
-->
|
||||
<property name="personType">
|
||||
<value>${ldap.synchronization.personType}</value>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
The repeating attribute on group objects (found by query or as sub groups)
|
||||
used to define membership of the group. This is assumed to hold distinguished names of
|
||||
other groups or users/people; the above types are used to determine this.
|
||||
|
||||
OpenLDAP: "member" as it is mandatory on groupOfNames
|
||||
Active Directory: "member"
|
||||
|
||||
-->
|
||||
<property name="memberAttribute">
|
||||
<value>${ldap.synchronization.groupMemberAttributeName}</value>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
This property defines a mapping between attributes held on LDAP user objects and
|
||||
the properties of user objects held in the repository. The key is the QName of an attribute in
|
||||
the repository, the value is the attribute name from the user/inetOrgPerson/.. object in the
|
||||
LDAP repository.
|
||||
-->
|
||||
<property name="attributeMapping">
|
||||
<map>
|
||||
<entry key="cm:userName">
|
||||
<!-- Must match the same attribute as userIdAttributeName -->
|
||||
<value>${ldap.synchronization.userIdAttributeName}</value>
|
||||
</entry>
|
||||
<entry key="cm:firstName">
|
||||
<!-- OpenLDAP: "givenName" -->
|
||||
<!-- Active Directory: "givenName" -->
|
||||
<value>${ldap.synchronization.userFirstNameAttributeName}</value>
|
||||
</entry>
|
||||
<entry key="cm:lastName">
|
||||
<!-- OpenLDAP: "sn" -->
|
||||
<!-- Active Directory: "sn" -->
|
||||
<value>${ldap.synchronization.userLastNameAttributeName}</value>
|
||||
</entry>
|
||||
<entry key="cm:email">
|
||||
<!-- OpenLDAP: "mail" -->
|
||||
<!-- Active Directory: "???" -->
|
||||
<value>${ldap.synchronization.userEmailAttributeName}</value>
|
||||
</entry>
|
||||
<entry key="cm:organizationId">
|
||||
<!-- OpenLDAP: "o" -->
|
||||
<!-- Active Directory: "???" -->
|
||||
<value>${ldap.synchronization.userOrganizationalIdAttributeName}</value>
|
||||
</entry>
|
||||
<!-- Always use the default -->
|
||||
<entry key="cm:homeFolderProvider">
|
||||
<null/>
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
<!-- Set a default home folder provider -->
|
||||
<!-- Defaults only apply for values above -->
|
||||
<property name="attributeDefaults">
|
||||
<map>
|
||||
<entry key="cm:homeFolderProvider">
|
||||
<value>${ldap.synchronization.defaultHomeFolderProvider}</value>
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
|
||||
<!-- Services -->
|
||||
<property name="LDAPInitialDirContextFactory">
|
||||
<ref bean="ldapInitialDirContextFactory"/>
|
||||
</property>
|
||||
<property name="namespaceService">
|
||||
<ref bean="namespaceService"/>
|
||||
</property>
|
||||
|
||||
</bean>
|
||||
|
||||
<import resource="../common-ldap-context.xml" />
|
||||
</beans>
|
@@ -25,12 +25,6 @@ ldap.authentication.java.naming.provider.url=ldap://openldap.domain.com:389
|
||||
# The authentication mechanism to use
|
||||
ldap.authentication.java.naming.security.authentication=simple
|
||||
|
||||
# The default principal to use (only used for LDAP sync)
|
||||
ldap.authentication.java.naming.security.principal=cn\=Manager,dc\=company,dc\=com
|
||||
|
||||
# The password for the default principal (only used for LDAP sync)
|
||||
ldap.authentication.java.naming.security.credentials=secret
|
||||
|
||||
# Escape commas entered by the user at bind time
|
||||
# Useful when using simple authentication and the CN is part of the DN and contains commas
|
||||
ldap.authentication.escapeCommasInBind=false
|
||||
@@ -49,6 +43,12 @@ ldap.authentication.defaultAdministratorUserNames=
|
||||
# authentication, in which case this flag should be set to false.
|
||||
ldap.synchronization.active=true
|
||||
|
||||
# The default principal to use (only used for LDAP sync)
|
||||
ldap.synchronization.java.naming.security.principal=cn\=Manager,dc\=company,dc\=com
|
||||
|
||||
# The password for the default principal (only used for LDAP sync)
|
||||
ldap.synchronization.java.naming.security.credentials=secret
|
||||
|
||||
# If positive, this property indicates that RFC 2696 paged results should be
|
||||
# used to split query results into batches of the specified size. This
|
||||
# overcomes any size limits imposed by the LDAP server.
|
||||
@@ -75,6 +75,9 @@ ldap.synchronization.userSearchBase=ou\=People,dc\=company,dc\=com
|
||||
# The name of the operational attribute recording the last update time for a group or user.
|
||||
ldap.synchronization.modifyTimestampAttributeName=modifyTimestamp
|
||||
|
||||
# The timestamp format. Unfortunately, this varies between directory servers.
|
||||
ldap.synchronization.timestampFormat=yyyyMMddHHmmss'Z'
|
||||
|
||||
# The attribute name on people objects found in LDAP to use as the uid in Alfresco
|
||||
ldap.synchronization.userIdAttributeName=uid
|
||||
|
||||
|
@@ -145,11 +145,12 @@ public class LDAPUserRegistry implements UserRegistry, InitializingBean, Activat
|
||||
private String[] groupAttributeNames;
|
||||
|
||||
/** The LDAP generalized time format. */
|
||||
private static DateFormat LDAP_GENERALIZED_TIME_FORMAT;
|
||||
static
|
||||
private DateFormat timestampFormat;
|
||||
|
||||
public LDAPUserRegistry()
|
||||
{
|
||||
LDAPUserRegistry.LDAP_GENERALIZED_TIME_FORMAT = new SimpleDateFormat("yyyyMMddHHmmss'Z'");
|
||||
LDAPUserRegistry.LDAP_GENERALIZED_TIME_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
// Default to official LDAP generalized time format (unfortunately not used by Active Directory)
|
||||
setTimestampFormat("yyyyMMddHHmmss'Z'");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -295,6 +296,22 @@ public class LDAPUserRegistry implements UserRegistry, InitializingBean, Activat
|
||||
this.modifyTimestampAttributeName = modifyTimestampAttributeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the timestamp format. Unfortunately, this varies between directory servers.
|
||||
*
|
||||
* @param timestampFormat
|
||||
* the timestamp format
|
||||
* <ul>
|
||||
* <li>OpenLDAP: "yyyyMMddHHmmss'Z'"
|
||||
* <li>Active Directory: "yyyyMMddHHmmss'.0Z'"
|
||||
* </ul>
|
||||
*/
|
||||
public void setTimestampFormat(String timestampFormat)
|
||||
{
|
||||
this.timestampFormat = new SimpleDateFormat(timestampFormat);
|
||||
this.timestampFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Decides whether to error on missing group members.
|
||||
*
|
||||
@@ -464,13 +481,18 @@ public class LDAPUserRegistry implements UserRegistry, InitializingBean, Activat
|
||||
{
|
||||
searchResults = ctx.search(this.groupSearchBase, this.groupDifferentialQuery, new Object[]
|
||||
{
|
||||
LDAPUserRegistry.LDAP_GENERALIZED_TIME_FORMAT.format(modifiedSince)
|
||||
this.timestampFormat.format(modifiedSince)
|
||||
}, userSearchCtls);
|
||||
}
|
||||
|
||||
LdapName groupDistinguishedNamePrefix = new LdapName(this.groupSearchBase);
|
||||
LdapName userDistinguishedNamePrefix = new LdapName(this.userSearchBase);
|
||||
|
||||
// Work out whether the user and group trees are disjoint. This may allow us to optimize reverse DN
|
||||
// resolution.
|
||||
boolean disjoint = !groupDistinguishedNamePrefix.startsWith(userDistinguishedNamePrefix)
|
||||
&& !userDistinguishedNamePrefix.startsWith(groupDistinguishedNamePrefix);
|
||||
|
||||
while (searchResults.hasMoreElements())
|
||||
{
|
||||
SearchResult result = searchResults.next();
|
||||
@@ -511,8 +533,7 @@ public class LDAPUserRegistry implements UserRegistry, InitializingBean, Activat
|
||||
Attribute modifyTimestamp = attributes.get(this.modifyTimestampAttributeName);
|
||||
if (modifyTimestamp != null)
|
||||
{
|
||||
group.setLastModified(LDAPUserRegistry.LDAP_GENERALIZED_TIME_FORMAT.parse(modifyTimestamp.get()
|
||||
.toString()));
|
||||
group.setLastModified(this.timestampFormat.parse(modifyTimestamp.get().toString()));
|
||||
}
|
||||
Set<String> childAssocs = group.getChildAssociations();
|
||||
|
||||
@@ -530,7 +551,7 @@ public class LDAPUserRegistry implements UserRegistry, InitializingBean, Activat
|
||||
|
||||
// If the user and group search bases are different we may be able to recognise user and
|
||||
// group DNs without a secondary lookup
|
||||
if (!this.userSearchBase.equalsIgnoreCase(this.groupSearchBase))
|
||||
if (disjoint)
|
||||
{
|
||||
Attributes nameAttributes = distinguishedName.getRdn(distinguishedName.size() - 1)
|
||||
.toAttributes();
|
||||
@@ -563,8 +584,8 @@ public class LDAPUserRegistry implements UserRegistry, InitializingBean, Activat
|
||||
{
|
||||
"objectclass", this.groupIdAttributeName, this.userIdAttributeName
|
||||
});
|
||||
String objectclass = (String) childAttributes.get("objectclass").get();
|
||||
if (objectclass.equalsIgnoreCase(this.personType))
|
||||
Attribute objectClass = childAttributes.get("objectclass");
|
||||
if (hasAttributeValue(objectClass, this.personType))
|
||||
{
|
||||
nameAttribute = childAttributes.get(this.userIdAttributeName);
|
||||
if (nameAttribute == null)
|
||||
@@ -586,9 +607,8 @@ public class LDAPUserRegistry implements UserRegistry, InitializingBean, Activat
|
||||
childAssocs.add((String) nameAttribute.get());
|
||||
continue;
|
||||
}
|
||||
else if (objectclass.equalsIgnoreCase(this.groupType))
|
||||
else if (hasAttributeValue(objectClass, this.groupType))
|
||||
{
|
||||
|
||||
nameAttribute = childAttributes.get(this.groupIdAttributeName);
|
||||
if (nameAttribute == null)
|
||||
{
|
||||
@@ -656,6 +676,37 @@ public class LDAPUserRegistry implements UserRegistry, InitializingBean, Activat
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does a case-insensitive search for the given value in an attribute
|
||||
*
|
||||
* @param attribute
|
||||
* the attribute
|
||||
* @param value
|
||||
* the value to search for
|
||||
* @return <code>true</code>, if the value was found
|
||||
* @throws NamingException
|
||||
* if there is a problem accessing the attribute values
|
||||
*/
|
||||
private boolean hasAttributeValue(Attribute attribute, String value) throws NamingException
|
||||
{
|
||||
NamingEnumeration<?> values = attribute.getAll();
|
||||
while (values.hasMore())
|
||||
{
|
||||
try
|
||||
{
|
||||
if (value.equalsIgnoreCase((String) values.next()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (ClassCastException e)
|
||||
{
|
||||
// Not a string value. ignore and continue
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the LDAP user query as an {@link Iterator}.
|
||||
*/
|
||||
@@ -811,8 +862,8 @@ public class LDAPUserRegistry implements UserRegistry, InitializingBean, Activat
|
||||
{
|
||||
try
|
||||
{
|
||||
person.setLastModified(LDAPUserRegistry.LDAP_GENERALIZED_TIME_FORMAT.parse(modifyTimestamp
|
||||
.get().toString()));
|
||||
person.setLastModified(LDAPUserRegistry.this.timestampFormat.parse(modifyTimestamp.get()
|
||||
.toString()));
|
||||
}
|
||||
catch (ParseException e)
|
||||
{
|
||||
@@ -879,7 +930,7 @@ public class LDAPUserRegistry implements UserRegistry, InitializingBean, Activat
|
||||
this.searchResults = this.ctx.search(LDAPUserRegistry.this.userSearchBase,
|
||||
LDAPUserRegistry.this.personDifferentialQuery, new Object[]
|
||||
{
|
||||
LDAPUserRegistry.LDAP_GENERALIZED_TIME_FORMAT.format(this.modifiedSince)
|
||||
LDAPUserRegistry.this.timestampFormat.format(this.modifiedSince)
|
||||
}, this.userSearchCtls);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user