【问题标题】:LDAP root query syntax to search more than one specific OU用于搜索多个特定 OU 的 LDAP 根查询语法
【发布时间】:2012-02-29 09:29:56
【问题描述】:

我需要运行一个 LDAP 查询,该查询将在根查询中搜索两个特定的组织单位 (OU),但是我很难做到这一点。我尝试了以下查询,但均未成功:

(|(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))

我的问题是;是否可以在单个查询中查询多个 OU?假设在根 LDAP 查询中这种类型的表达式的正确语法是什么。

【问题讨论】:

  • 如果包含 LDAP 客户端搜索的条目的 objectClasses 允许 ou 属性,则可以在搜索过滤器中使用 ou 属性。当然,这需要将ou 属性添加到相关条目中。这可能是一个有效的解决方案,因为 AD 不支持以下可扩展匹配过滤器的出色建议。
  • 如果您可以将我的答案标记为已接受的答案,那就太好了,因为当前接受的答案似乎显然不完全有效(不再有效?)并且对于 AD 而言是错误的,因此总的来说是错误的。它可能仅对某些 LDAP 实现有效。

标签: active-directory ldap ou


【解决方案1】:

你可以!!!简而言之,将其用作连接字符串:

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

连同您的搜索过滤器,例如

(&(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>))))

这将搜索所谓的Global Catalog,它在我们的环境中是开箱即用的。

而不是已知/常见的其他版本(或它们的组合)在我们的环境中不起作用具有多个 OU:

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)

(我是开发人员,而不是 AD/LDAP 专家:)该死的,我已经在各处寻找这个解决方案将近 2 天了,几乎放弃了,习惯了我可能不得不实现这个显然非常常见的场景的想法手动(使用 Jasperserver/Spring security(/Tomcat))。 (因此,如果其他人或我将来再次遇到此问题,这将是一个提醒:O))

以下是我在研究期间发现的其他一些相关主题,这些主题几乎没有什么帮助:

在这里,我将提供我们的匿名 Tomcat LDAP 配置以防万一 (/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 ############ -->

【讨论】:

【解决方案2】:

答案是否定的,你不能。为什么?

因为 LDAP 标准将 LDAP-SEARCH 描述为具有 4 个参数的函数:

  1. 应开始搜索的节点,即专有名称 (DN)
  2. 您想要恢复的属性
  3. 搜索深度(基础、一级、子树)
  4. 过滤器

您对过滤器感兴趣。您有一个摘要here(它是由 Microsoft 为 Active Directory 提供的,它来自一个标准)。过滤器由 Attribute Operator Value 类型的表达式以布尔方式组成。

所以你给的过滤器没有任何意义。

从理论上讲,ExtensibleMatch 允许在 DN 路径上构建过滤器,但 Active Directory 不支持它。

据我所知,您必须在 AD 中使用一个属性来区分两个 OU 中的用户。

它可以是任何现有的鉴别器属性,或者,例如继承自organizationalPerson 类的称为OU 的属性。您可以为某些用户设置它(它不是自动的,并且如果您移动用户也不会被维护)为某些用户设置“员工”,为其他用户设置“供应商”,他们使用过滤器:

(&(objectCategory=person)(|(ou=staff)(ou=vendors)))

【讨论】:

  • 我们能否使用 distinctName 属性进行过滤,例如 (distinguishedName=*OUPath) ?
  • 填充 OU 属性的最佳方式是什么?我打算编写一个每天运行的 PS 脚本,查看用户所在的 OU,然后将唯一的 OU 值写入 OU 属性。我认为 OU 只是一个名称,更改它不会影响其他任何事情?
  • @DevilWAH,如果您查看架构,它是一个目录字符串,它是组织人员或用户的兼性。
  • 好的,我真的在检查是否不可能“抛出”一个从 DN 填充的开关。照原样,我会将其添加到日常维护脚本中
【解决方案3】:

这很简单。换个端口就好了。使用 3268 而不是 389。如果您的域名 DOMAIN.LOCAL,请在搜索中输入 DC=DOMAIN,DC=LOCAL

端口 3268: 此端口用于专门针对全局编录的查询。发送到端口 3268 的 LDAP 请求可用于搜索整个林中的对象。但是,只能返回标记为复制到全局编录的属性。

端口 389: 此端口用于从域控制器请求信息。发送到端口 389 的 LDAP 请求只能用于搜索全局编录主域内的对象。但是,应用程序可以获取所有搜索到的对象的属性。

【讨论】:

  • 这个端口是否可以与 ldaps 一起使用,或者是否有另一个可以使用?
  • 3268 是 GC 纯文本。 3269 是 GC over SSL,默认加密。 389 是 AD 纯文本。 636 是基于 SSL 的 AD,默认加密。
【解决方案4】:

我认为这对于 AD 来说是不可能的。 distinctName 属性是我所知道的唯一包含您尝试搜索的 OU 片段的属性,因此您需要一个通配符来获取这些 OU 下对象的结果。不幸的是,DN 上的通配符 isn't supported

如果可能的话,我真的会考虑在 2 个查询中使用 OU=Staff... 和 OU=Vendors... 作为基本 DN。

【讨论】:

  • 不幸的是,SharePoint 将其用作解析成员的根查询,我无法更改 SharePoint。
  • 我们也遇到过类似的情况。我们能够通过组合其他属性来解决这个问题:邮件、用户帐户控制等,这些属性只识别了我们想要的用户。
  • 在 SharePoint 的情况下,为什么不添加另一个与 OU 的导入连接作为搜索库?以下是多个森林的方法:technet.microsoft.com/en-us/library/cc263247(office.12).aspx
  • 这不只是为了Profile导入吗?我的需要更多地与 SharePoint 中的名称解析有关(例如 People Picker 控件)
  • 没错 - 我没有意识到您希望限制人员选择器。我会编辑您的原始问题,以注意这是您要过滤的内容,否则您可能会看到另一个“无法完成”的答案。对于人员选择器,使用 Peoplepicker-serviceaccountdirectorypaths stsadm 属性看起来确实可行:technet.microsoft.com/en-us/library/cc263012(office.12).aspx。您只需提供一个以分号分隔的 OU 列表作为属性值。因此,“OU=Staff,DC=my,DC=super,DC=org;OU=Vendors,DC=my,DC=super,DC=org" 在您的情况下。
【解决方案5】:

在与 LDAP 专家交谈后,这是不可能的。一个查询不能搜索多个 DC 或 OU。

您的选择是:

  1. 运行超过 1 个查询并解析结果。
  2. 使用过滤器根据不同的属性(如 AD 组或名称)查找所需的用户/对象。

【讨论】:

    【解决方案6】:

    tl;dr -- 使用 ou:dn:=&lt;val&gt; 语法

    对于 OP 的问题,解决方法是:

    ldapsearch -b "DC=my,DC=super,DC=org" <other_options> "(|(ou:dc:=Staff)(ou:dc:=Vendors))"
    

    原则上,您的情况很棘手,因为 OU 值不会出现在用户的 ldapsearch 输出中——OU 值是 DN 的一部分。

    比如这里的搜索结果:

    [root@pg data]# ldapsearch -H "ldap://ldap-service" -D "cn=admin,dc=example,dc=org" -w admin -b"DC=example,DC=org" cn=testuser2 
    # extended LDIF
    #
    # LDAPv3
    # base <DC=example,DC=org> with scope subtree
    # filter: cn=testuser2
    # requesting: ALL
    #
    
    # testuser2, AU, IIQ, example.org
    dn: cn=testuser2,ou=AU,ou=IIQ,dc=example,dc=org
    cn: testuser2
    displayName: pgtest
    gidNumber: 500
    givenName: testuser2
    homeDirectory: /home/testuser2
    loginShell: /bin/sh
    objectClass: inetOrgPerson
    objectClass: posixAccount
    objectClass: top
    userPassword:: e01ENX1GMnFxVVpDTjh4VVJveGg5bkJBcGF3PT0=
    sn: testuser2
    uidNumber: 1012
    uid: testuser2
    
    # search result
    search: 2
    result: 0 Success
    
    # numResponses: 2
    # numEntries: 1
    
    

    没有ou: 行,因为OU 属于dn: 行。因此,如果您在搜索中添加ou,您会看到它是requesting: ou 而不是requesting: ALL,但没有列出任何属性:

    [root@pg data]# ldapsearch -H "ldap://ldap-service" -D "cn=admin,dc=example,dc=org" -w admin -b"DC=example,DC=org" cn=testuser2 ou
    # extended LDIF
    #
    # LDAPv3
    # base <DC=example,DC=org> with scope subtree
    # filter: cn=testuser2
    # requesting: ou 
    #
    
    # testuser2, AU, IIQ, example.org
    dn: cn=testuser2,ou=AU,ou=IIQ,dc=example,dc=org
    
    # search result
    search: 2
    result: 0 Success
    
    # numResponses: 2
    # numEntries: 1
    

    在 OU 上搜索会得到结果,但它们只是 OU 对象,而不是用户本身:

    [root@pg data]# ldapsearch -H "ldap://ldap-service" -D "cn=admin,dc=example,dc=org" -w admin -b"DC=example,DC=org" "(|(OU=IN)(OU=AU))"
    # extended LDIF
    #
    # LDAPv3
    # base <DC=example,DC=org> with scope subtree
    # filter: (|(OU=IN)(OU=AU))
    # requesting: ALL
    #
    
    # IN, example.org
    dn: ou=IN,dc=example,dc=org
    ou: IN
    objectClass: organizationalUnit
    objectClass: top
    
    # AU, example.org
    dn: ou=AU,dc=example,dc=org
    ou: AU
    objectClass: organizationalUnit
    objectClass: top
    
    # IN, IIQ, example.org
    dn: ou=IN,ou=IIQ,dc=example,dc=org
    objectClass: organizationalUnit
    objectClass: top
    ou: IN
    
    # AU, IIQ, example.org
    dn: ou=AU,ou=IIQ,dc=example,dc=org
    ou: AU
    objectClass: organizationalUnit
    objectClass: top
    
    # search result
    search: 2
    result: 0 Success
    
    # numResponses: 5
    # numEntries: 4
    

    但是,ldapsearch 允许您使用 ou:dn:=&lt;val&gt; 语法提取部分 DN:

    [root@pg data]# ldapsearch -H "ldap://ldap-service" -D "cn=admin,dc=example,dc=org" -w admin -b"DC=example,DC=org" "(&(displayname=pgtest)(|(ou:dn:=IN)(ou:dn:=AU)))" cn displayname
    # extended LDIF
    #
    # LDAPv3
    # base <DC=example,DC=org> with scope subtree
    # filter: (&(displayname=pgtest)(|(ou:dn:=IN)(ou:dn:=AU)))
    # requesting: cn displayname 
    #
    
    # testuser3, AU, example.org
    dn: cn=testuser3,ou=AU,dc=example,dc=org
    cn: testuser3
    displayName: pgtest
    
    # testuser4, IN, example.org
    dn: cn=testuser4,ou=IN,dc=example,dc=org
    cn: testuser4
    displayName: pgtest
    
    # testuser2, AU, IIQ, example.org
    dn: cn=testuser2,ou=AU,ou=IIQ,dc=example,dc=org
    cn: testuser2
    displayName: pgtest
    
    # testuser1, IN, IIQ, example.org
    dn: cn=testuser1,ou=IN,ou=IIQ,dc=example,dc=org
    cn: testuser1
    displayName: pgtest
    
    # testuser14, IN, example.org
    dn: cn=testuser14,ou=IN,dc=example,dc=org
    cn: testuser14
    displayName: pgtest
    
    # search result
    search: 2
    result: 0 Success
    
    # numResponses: 6
    # numEntries: 5
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-06-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多