Search code examples
active-directoryldapou

LDAP root query syntax to search more than one specific OU


I need to run a single LDAP query that will search through two specific organization units (OU) in the root query however I'm having a tough go of it. I've tried the following queries below and neither were successful:

(|(OU=Staff,DC=my,DC=super,DC=org)(OU=Vendors,DC=my,DC=super,DC=org))

((OU=Staff,DC=my,DC=super,DC=org) | (OU=Vendors,DC=my,DC=super,DC=org))

My question is; is it possible to query more than one single OU in a single query? Assuming that it is what the proper syntax for this type of expression in the root LDAP query.


Solution

  • You can!!! In short use this as the connection string:

    ldap://<host>:3268/DC=<my>,DC=<domain>?cn
    

    together with your search filter, e.g.

    (&(sAMAccountName={0})(&((objectCategory=person)(objectclass=user)(mail=*)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(memberOf:1.2.840.113556.1.4.1941:=CN=<some-special-nested-group>,OU=<ou3>,OU=<ou2>,OU=<ou1>,DC=<dc3>,DC=<dc2>,DC=<dc1>))))
    

    That will search in the so called Global Catalog, that had been available out-of-the-box in our environment.

    Instead of the known/common other versions (or combinations thereof) that did NOT work in our environment with multiple OUs:

    ldap://<host>/DC=<my>,DC=<domain>
    ldap://<host>:389/DC=<my>,DC=<domain>  (standard port)
    ldap://<host>/OU=<someOU>,DC=<my>,DC=<domain>
    ldap://<host>/CN=<someCN>,DC=<my>,DC=<domain>
    ldap://<host>/(|(OU=<someOU1>)(OU=<someOU2>)),DC=<my>,DC=<domain> (search filters here shouldn't work at all by definition)
    

    (I am a developer, not an AD/LDAP guru:) Damn I had been searching for this solution everywhere for almost 2 days and almost gave up, getting used to the thought I might have to implement this obviously very common scenario by hand (with Jasperserver/Spring security(/Tomcat)). (So this shall be a reminder if somebody else or me should have this problem again in the future :O) )

    Here some other related threads I found during my research that had been mostly of little help:

    And here I will provide our anonymized Tomcat LDAP config in case it may be helpful (/var/lib/tomcat7/webapps/jasperserver/WEB-INF/applicationContext-externalAUTH-LDAP.xml):

    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
    
    <!-- ############ LDAP authentication ############ - Sample configuration 
        of external authentication via an external LDAP server. -->
    
    
    <bean id="proxyAuthenticationProcessingFilter"
        class="com.jaspersoft.jasperserver.api.security.externalAuth.BaseAuthenticationProcessingFilter">
        <property name="authenticationManager">
            <ref local="ldapAuthenticationManager" />
        </property>
        <property name="externalDataSynchronizer">
            <ref local="externalDataSynchronizer" />
        </property>
    
        <property name="sessionRegistry">
            <ref bean="sessionRegistry" />
        </property>
    
        <property name="internalAuthenticationFailureUrl" value="/login.html?error=1" />
        <property name="defaultTargetUrl" value="/loginsuccess.html" />
        <property name="invalidateSessionOnSuccessfulAuthentication"
            value="true" />
        <property name="migrateInvalidatedSessionAttributes" value="true" />
    </bean>
    
    <bean id="proxyAuthenticationSoapProcessingFilter"
        class="com.jaspersoft.jasperserver.api.security.externalAuth.DefaultAuthenticationSoapProcessingFilter">
        <property name="authenticationManager" ref="ldapAuthenticationManager" />
        <property name="externalDataSynchronizer" ref="externalDataSynchronizer" />
    
        <property name="invalidateSessionOnSuccessfulAuthentication"
            value="true" />
        <property name="migrateInvalidatedSessionAttributes" value="true" />
        <property name="filterProcessesUrl" value="/services" />
    </bean>
    
    <bean id="proxyRequestParameterAuthenticationFilter"
        class="com.jaspersoft.jasperserver.war.util.ExternalRequestParameterAuthenticationFilter">
        <property name="authenticationManager">
            <ref local="ldapAuthenticationManager" />
        </property>
        <property name="externalDataSynchronizer" ref="externalDataSynchronizer" />
    
        <property name="authenticationFailureUrl">
            <value>/login.html?error=1</value>
        </property>
        <property name="excludeUrls">
            <list>
                <value>/j_spring_switch_user</value>
            </list>
        </property>
    </bean>
    
    <bean id="proxyBasicProcessingFilter"
        class="com.jaspersoft.jasperserver.api.security.externalAuth.ExternalAuthBasicProcessingFilter">
        <property name="authenticationManager" ref="ldapAuthenticationManager" />
        <property name="externalDataSynchronizer" ref="externalDataSynchronizer" />
    
        <property name="authenticationEntryPoint">
            <ref local="basicProcessingFilterEntryPoint" />
        </property>
    </bean>
    
    <bean id="proxyAuthenticationRestProcessingFilter"
        class="com.jaspersoft.jasperserver.api.security.externalAuth.DefaultAuthenticationRestProcessingFilter">
        <property name="authenticationManager">
            <ref local="ldapAuthenticationManager" />
        </property>
        <property name="externalDataSynchronizer">
            <ref local="externalDataSynchronizer" />
        </property>
    
        <property name="filterProcessesUrl" value="/rest/login" />
        <property name="invalidateSessionOnSuccessfulAuthentication"
            value="true" />
        <property name="migrateInvalidatedSessionAttributes" value="true" />
    </bean>
    
    
    
    <bean id="ldapAuthenticationManager" class="org.springframework.security.providers.ProviderManager">
        <property name="providers">
            <list>
                <ref local="ldapAuthenticationProvider" />
                <ref bean="${bean.daoAuthenticationProvider}" />
                <!--anonymousAuthenticationProvider only needed if filterInvocationInterceptor.alwaysReauthenticate 
                    is set to true <ref bean="anonymousAuthenticationProvider"/> -->
            </list>
        </property>
    </bean>
    
    <bean id="ldapAuthenticationProvider"
        class="org.springframework.security.providers.ldap.LdapAuthenticationProvider">
        <constructor-arg>
            <bean
                class="org.springframework.security.providers.ldap.authenticator.BindAuthenticator">
                <constructor-arg>
                    <ref local="ldapContextSource" />
                </constructor-arg>
                <property name="userSearch" ref="userSearch" />
            </bean>
        </constructor-arg>
        <constructor-arg>
            <bean
                class="org.springframework.security.ldap.populator.DefaultLdapAuthoritiesPopulator">
                <constructor-arg index="0">
                    <ref local="ldapContextSource" />
                </constructor-arg>
                <constructor-arg index="1">
                    <value></value>
                </constructor-arg>
    
                <property name="groupRoleAttribute" value="cn" />
                <property name="convertToUpperCase" value="true" />
                <property name="rolePrefix" value="ROLE_" />
                <property name="groupSearchFilter"
                    value="(&amp;(member={0})(&amp;(objectCategory=Group)(objectclass=group)(cn=my-nested-group-name)))" />
                <property name="searchSubtree" value="true" />
                <!-- Can setup additional external default roles here <property name="defaultRole" 
                    value="LDAP"/> -->
            </bean>
        </constructor-arg>
    </bean>
    
    <bean id="userSearch"
        class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
        <constructor-arg index="0">
            <value></value>
        </constructor-arg>
        <constructor-arg index="1">
            <value>(&amp;(sAMAccountName={0})(&amp;((objectCategory=person)(objectclass=user)(mail=*)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(memberOf:1.2.840.113556.1.4.1941:=CN=my-nested-group-name,OU=ou3,OU=ou2,OU=ou1,DC=dc3,DC=dc2,DC=dc1))))
            </value>
        </constructor-arg>
        <constructor-arg index="2">
            <ref local="ldapContextSource" />
        </constructor-arg>
        <property name="searchSubtree">
            <value>true</value>
        </property>
    </bean>
    
    <bean id="ldapContextSource"
        class="com.jaspersoft.jasperserver.api.security.externalAuth.ldap.JSLdapContextSource">
        <constructor-arg value="ldap://myhost:3268/DC=dc3,DC=dc2,DC=dc1?cn" />
        <!-- manager user name and password (may not be needed) -->
        <property name="userDn" value="CN=someuser,OU=ou4,OU=1,DC=dc3,DC=dc2,DC=dc1" />
        <property name="password" value="somepass" />
        <!--End Changes -->
    </bean>
    <!-- ############ LDAP authentication ############ -->
    
    <!-- ############ JRS Synchronizer ############ -->
    <bean id="externalDataSynchronizer"
        class="com.jaspersoft.jasperserver.api.security.externalAuth.ExternalDataSynchronizerImpl">
        <property name="externalUserProcessors">
            <list>
                <ref local="externalUserSetupProcessor" />
                <!-- Example processor for creating user folder -->
                <!--<ref local="externalUserFolderProcessor"/> -->
            </list>
        </property>
    </bean>
    
    <bean id="abstractExternalProcessor"
        class="com.jaspersoft.jasperserver.api.security.externalAuth.processors.AbstractExternalUserProcessor"
        abstract="true">
        <property name="repositoryService" ref="${bean.repositoryService}" />
        <property name="userAuthorityService" ref="${bean.userAuthorityService}" />
        <property name="tenantService" ref="${bean.tenantService}" />
        <property name="profileAttributeService" ref="profileAttributeService" />
        <property name="objectPermissionService" ref="objectPermissionService" />
    </bean>
    
    <bean id="externalUserSetupProcessor"
        class="com.jaspersoft.jasperserver.api.security.externalAuth.processors.ExternalUserSetupProcessor"
        parent="abstractExternalProcessor">
        <property name="userAuthorityService">
            <ref bean="${bean.internalUserAuthorityService}" />
        </property>
        <property name="defaultInternalRoles">
            <list>
                <value>ROLE_USER</value>
            </list>
        </property>
    
        <property name="organizationRoleMap">
            <map>
                <!-- Example of mapping customer roles to JRS roles -->
                <entry>
                    <key>
                        <value>ROLE_MY-NESTED-GROUP-NAME</value>
                    </key>
                    <!-- JRS role that the <key> external role is mapped to -->
                    <value>ROLE_USER</value>
                </entry>
            </map>
        </property>
    </bean>
    
    <!--bean id="externalUserFolderProcessor" class="com.jaspersoft.jasperserver.api.security.externalAuth.processors.ExternalUserFolderProcessor" 
        parent="abstractExternalProcessor"> <property name="repositoryService" ref="${bean.unsecureRepositoryService}"/> 
        </bean -->
    
    <!-- ############ JRS Synchronizer ############ -->