Search code examples
spring-securityspring-security-ldapldif

sample active directory ldif file with apacheds


Here there is a spring-security example, ldap-xml, which runs a ldap server and imports a LDIF file for testing:

https://github.com/spring-projects/spring-security/blob/master/samples/ldap-xml/src/main/webapp/WEB-INF/applicationContext-security.xml

[...]
    <s:ldap-server ldif="classpath:users.ldif" port="33389"/>

    <s:authentication-manager>
        <s:ldap-authentication-provider
            group-search-filter="member={0}"
            group-search-base="ou=groups"
            user-search-base="ou=people"
            user-search-filter="uid={0}"
        />
        <s:authentication-provider ref='secondLdapProvider' />
    </s:authentication-manager>
[...]

https://github.com/spring-projects/spring-security/blob/master/samples/ldap-xml/src/main/webapp/WEB-INF/classes/users.ldif

[...]
dn: uid=rod,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Rod Johnson
sn: Johnson
uid: rod
userPassword: koala
[...]

I need to modify this working example, in where the user-search-criteria is based on sAMAccountName instead of uid. I modify the users.ldif as follows:

[...]
dn: cn=rod,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Rod Johnson
sn: Johnson
sAMAccountName: rod
userPassword: koala
[...]

but apacheds shows a warning when importing users.ldif:

OID for name 'samaccountname' was not found within the OID registry

It seems that I need to add this new attribute, sAMAccountName, by modifing the LDAP schema. how to do that in the ldap-xml example?

In this gist example they modify the schema using "changetype: add". however adding this in users.ldif results in an error We cannot have entries when reading a file which already contains changes. In the gist example, they mention to update the schema running the ldifdecommand. How should I modify the ldap-xml project to do this?

How I need to modify the ldap-xml project, so that my users.ldif can contain a sAMAccountName attribute?


Solution

  • Add the following (it's the minimal fragment of Microsoft's schema that contains sAMAccountName) at the beginning of users.ldif file:

    dn: cn=microsoft, ou=schema
    objectclass: metaSchema
    objectclass: top
    cn: microsoft
    
    dn: ou=attributetypes, cn=microsoft, ou=schema
    objectclass: organizationalUnit
    objectclass: top
    ou: attributetypes
    
    dn: m-oid=1.2.840.113556.1.4.221, ou=attributetypes, cn=microsoft, ou=schema
    objectclass: metaAttributeType
    objectclass: metaTop
    objectclass: top
    m-oid: 1.2.840.113556.1.4.221
    m-name: sAMAccountName
    m-equality: caseIgnoreMatch
    m-syntax: 1.3.6.1.4.1.1466.115.121.1.15
    m-singleValue: TRUE
    
    dn: ou=objectclasses, cn=microsoft, ou=schema
    objectclass: organizationalUnit
    objectclass: top
    ou: objectClasses
    
    dn: m-oid=1.2.840.113556.1.5.6, ou=objectclasses, cn=microsoft, ou=schema
    objectclass: metaObjectClass
    objectclass: metaTop
    objectclass: top
    m-oid: 1.2.840.113556.1.5.6
    m-name: securityPrincipal
    m-supObjectClass: top
    m-typeObjectClass: AUXILIARY
    m-must: sAMAccountName
    
    [rest of users.ldif]
    

    Now add new objectClass to person entries:

    [...]
    dn: cn=rod,ou=people,dc=springframework,dc=org
    objectclass: top
    objectclass: person
    objectclass: organizationalPerson
    objectclass: inetOrgPerson
    objectclass: securityPrincipal   <--- new objectClass
    cn: Rod Johnson
    sn: Johnson
    sAMAccountName: rod
    userPassword: koala
    [...]
    

    It's not enough to have new entries. ApacheDS' configuration in Spring Security has disabled schema interceptor, so new schema entries are not created by default. We can turn it on by creating BeanPostProcessor that fixes this:

    package com.example.test.spring;
    
    import java.util.List;
    
    import org.apache.directory.server.core.interceptor.Interceptor;
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanPostProcessor;
    import org.springframework.security.ldap.server.ApacheDSContainer;
    
    import static org.springframework.util.CollectionUtils.isEmpty;
    
    public class ApacheDSContainerConfigurer implements BeanPostProcessor {
    
        private List<Interceptor> interceptors;
    
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            if (bean instanceof ApacheDSContainer){
                ApacheDSContainer dsContainer = ((ApacheDSContainer) bean);
                setInterceptorsIfPresent(dsContainer);
            }
            return bean;
        }
    
        private void setInterceptorsIfPresent(ApacheDSContainer container) {
            if (!isEmpty(interceptors)) {
                container.getService().setInterceptors(interceptors);
            }
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            return bean;
        }
    
        public void setInterceptors(List<Interceptor> interceptors) {
            this.interceptors = interceptors;
        }
    
    }
    

    We have to register and configure bean in application context:

    <bean class="com.example.test.spring.ApacheDSContainerConfigurer">
        <property name="interceptors">
            <list>
                <bean class="org.apache.directory.server.core.normalization.NormalizationInterceptor"/>
                <bean class="org.apache.directory.server.core.authn.AuthenticationInterceptor"/>
                <bean class="org.apache.directory.server.core.referral.ReferralInterceptor"/>
                <!--<bean class="org.apache.directory.server.core.authz.AciAuthorizationInterceptor"/>-->
                <!--<bean class="org.apache.directory.server.core.authz.DefaultAuthorizationInterceptor"/>-->
                <bean class="org.apache.directory.server.core.exception.ExceptionInterceptor"/>
                <!--<bean class="org.apache.directory.server.core.changelog.ChangeLogInterceptor"/>-->
                <bean class="org.apache.directory.server.core.operational.OperationalAttributeInterceptor"/>
                <bean class="org.apache.directory.server.core.schema.SchemaInterceptor"/>
                <bean class="org.apache.directory.server.core.subtree.SubentryInterceptor"/>
                <!--<bean class="org.apache.directory.server.core.collective.CollectiveAttributeInterceptor"/>-->
                <!--<bean class="org.apache.directory.server.core.event.EventInterceptor"/>-->
                <!--<bean class="org.apache.directory.server.core.trigger.TriggerInterceptor"/>-->
                <!--<bean class="org.apache.directory.server.core.journal.JournalInterceptor"/>-->
            </list>
        </property>
    </bean>
    

    It should be working now.