Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 803
James Avatar asked Feb 07 '12 22:02

James


People also ask

What is LDAP search filter?

1. Search Filter is a basic LDAP Query for searching users based on mapping of username to a particular LDAP attribute. 2. The following are some commonly used Search Filters. You will need to use a search filter which uses the attributes specific to your LDAP environment.

What is base search in LDAP?

Search Base denotes the location in the directory where the search for a particular directory object begins. 2. It is denoted as the distinguished name of the search base directory object. e.g. CN=Users,DC=domain,DC=com.


2 Answers

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:

  • the solution hidden in a comment of LarreDo from 2006
  • some Microsoft answered question of best practices how to design your organization in the directory, stating using multiple top-level OUs in bigger companies is not unusual or even suitable
  • Tim Wong (2011) added that this may be a problem of unresolvable DNS names in the ForestDNSZones (part of the AD top-level domain used)
  • example code for implementing it by hand when using Spring security (e.g. also used in Jasper)
  • John Morrissey (2012) suggested it could be related to some security settings and it may work if you use TLS (I guess if the LDAP server wants to restrict such global searches for non-secure connections - which would not seem a good (its kind of half-baked) security approach to me)
  • awatkins (2012) used some hacking approach in some mod_ldap.c code (of whatever software)

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 ############ --> 

like image 64
Andreas Covidiot Avatar answered Sep 22 '22 10:09

Andreas Covidiot


The answer is NO you can't. Why?

Because the LDAP standard describes a LDAP-SEARCH as kind of function with 4 parameters:

  1. The node where the search should begin, which is a Distinguish Name (DN)
  2. The attributes you want to be brought back
  3. The depth of the search (base, one-level, subtree)
  4. The filter

You are interested in the filter. You've got a summary here (it's provided by Microsoft for Active Directory, it's from a standard). The filter is composed, in a boolean way, by expression of the type Attribute Operator Value.

So the filter you give does not mean anything.

On the theoretical point of view there is ExtensibleMatch that allows buildind filters on the DN path, but it's not supported by Active Directory.

As far as I know, you have to use an attribute in AD to make the distinction for users in the two OUs.

It can be any existing discriminator attribute, or, for example the attribute called OU which is inherited from organizationalPerson class. you can set it (it's not automatic, and will not be maintained if you move the users) with "staff" for some users and "vendors" for others and them use the filter:

(&(objectCategory=person)(|(ou=staff)(ou=vendors))) 
like image 34
JPBlanc Avatar answered Sep 24 '22 10:09

JPBlanc