用于搜索多个特定 OU 的 LDAP 根查询语法
Posted
技术标签:
【中文标题】用于搜索多个特定 OU 的 LDAP 根查询语法【英文标题】:LDAP root query syntax to search more than one specific OU 【发布时间】: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 实现有效。
【参考方案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))
以下是我在研究期间发现的其他一些相关主题,这些主题几乎没有什么帮助:
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)在这里,我将提供我们的匿名 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="(&(member=0)(&(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>(&(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=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 ############ -->
【讨论】:
嗨,我有同样的问题,但我使用不同的代码。您能否在这里阅读我的问题:***.com/questions/42971315/…【参考方案2】:答案是否定的,你不能。为什么?
因为 LDAP 标准将 LDAP-SEARCH 描述为具有 4 个参数的函数:
-
应开始搜索的节点,即专有名称 (DN)
您想要恢复的属性
搜索深度(基础、一级、子树)
过滤器
您对过滤器感兴趣。您有一个摘要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 个查询并解析结果。 使用过滤器根据不同的属性(如 AD 组或名称)查找所需的用户/对象。
【讨论】:
【参考方案6】:tl;dr -- 使用 ou:dn:=<val>
语法
对于 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:=<val>
语法提取部分 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
【讨论】:
以上是关于用于搜索多个特定 OU 的 LDAP 根查询语法的主要内容,如果未能解决你的问题,请参考以下文章