使用多个后缀值/域对 ldap 用户进行身份验证

Posted

技术标签:

【中文标题】使用多个后缀值/域对 ldap 用户进行身份验证【英文标题】:Authenticating ldap user with multiple suffix value/domain 【发布时间】:2017-11-04 10:03:50 【问题描述】:

我正在尝试使用 Spring Ldap Security 和 Spring Ldap 进行身份验证,然后查询 AD 树。

以下是我的配置文件——

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:ldap="http://www.springframework.org/schema/ldap"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="
        http://www.springframework.org/schema/security 
        http://www.springframework.org/schema/security/spring-security-3.2.xsd
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd 
        http://www.springframework.org/schema/ldap 
        http://www.springframework.org/schema/ldap/spring-ldap.xsd
        http://www.springframework.org/schema/util 
        http://www.springframework.org/schema/util/spring-util.xsd">

    <http use-expressions="true">
        <form-login login-page="/myApp/ldap" default-target-url="/myApp/ldap/config"
            authentication-failure-url="/myApp/ldap?error=true" />
        <logout />
    </http>

    <beans:bean
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <beans:property name="location">
            <beans:value>classpath:/ldap.properties</beans:value>
        </beans:property>
        <beans:property name="SystemPropertiesMode">
            <beans:value>2</beans:value>
        </beans:property>
    </beans:bean>

    <beans:bean id="adAuthenticationProvider" scope="prototype"
        class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider">
        <!-- the domain name (may be null or empty). If no domain name is configured, it is assumed that the username will always contain the domain name. -->
        <beans:constructor-arg index="0" value="$sample.ldap.domain" />
        <!-- an LDAP url (or multiple URLs) -->
        <beans:constructor-arg index="1" value="$sample.ldap.url" />
        <!-- Determines whether the supplied password will be used as the credentials in the successful authentication token. -->
        <beans:property name="useAuthenticationRequestCredentials"
            value="true" />
        <!-- by setting this property to true, when the authentication fails the error codes will also be used to control the exception raised. -->
        <beans:property name="convertSubErrorCodesToExceptions"
            value="true" />
    </beans:bean>

    <authentication-manager erase-credentials="false">
        <authentication-provider ref="adAuthenticationProvider" />
    </authentication-manager>

    <beans:bean
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <beans:property name="location">
            <beans:value>classpath:/ldap.properties</beans:value>
        </beans:property>
        <beans:property name="SystemPropertiesMode">
            <beans:value>2</beans:value> <!-- OVERRIDE is 2 -->
        </beans:property>
    </beans:bean>

    <ldap:context-source id="contextSource" 
                         url="$sample.ldap.url"
                         base="$sample.ldap.base" 
                         referral="follow"
                         authentication-source-ref="authenticationSource" 
                         base-env-props-ref="baseEnvironmentProperties"/>

    <util:map id="baseEnvironmentProperties">
        <beans:entry key="com.sun.jndi.ldap.connect.timeout" value="60000" />
        <beans:entry key="java.naming.ldap.attributes.binary" value="objectGUID objectSid"/>
    </util:map>

    <beans:bean id="authenticationSource"
        class="org.springframework.security.ldap.authentication.SpringSecurityAuthenticationSource" />

    <ldap:ldap-template id="ldapTemplate"
        context-source-ref="contextSource" />

</beans:beans>

而属性文件是 -

sample.ldap.url=ldap://xxx.xxx.xxx.xxx:3268
sample.ldap.base=dc=example,dc=com
sample.ldap.clean=true
sample.ldap.directory.type=AD
sample.ldap.domain=example.com

这些设置适用于以下登录 -

用户名 - example@example.com 或示例 密码 - 废话

但当我尝试时失败 - 用户名 - example2@example.net 或示例 密码 - blah2

这两个都是有效的登录,并且已经通过使用 AD Explorer 登录验证。

似乎我需要更新我的配置以支持 UPN 后缀/域,因为默认可以正常工作而其他不能。

有没有办法可以附加到这个配置文件来支持这个逻辑,支持验证/查询多个域?

【问题讨论】:

【参考方案1】:

不允许我使用配置的 UPN 后缀登录的原因是 ActiveDirectoryLdapAuthenticationProvider 似乎假设 UPN 后缀始终与域名相同。

请参考这篇文章-https://github.com/spring-projects/spring-security/issues/3204

我认为应该有更好的方法来处理这个问题,或者可能有更好的身份验证库。

【讨论】:

【参考方案2】:

解释@NewBee的解决方案:

1ActiveDirectoryLdapAuthenticationProvider:

使用 Active Directory 配置约定的专用 LDAP authentication provider。 它将使用username@domain 形式的Active Directory userPrincipalName 或sAMAccountName(或自定义searchFilter)进行身份验证。如果username 尚未以domain 名称结尾,则将通过将配置的域名附加到authentication request 中提供的用户名来构建userPrincipalName。如果未配置域名,则假定用户名始终包含域名。 用户权限从memberOf属性中包含的数据中获取。

2LDAP authentication in Spring Security:

从登录名中获取唯一的 LDAP Distinguished Name 或 DN。

这通常意味着在目录中执行search,除非事先知道用户名到 DN 的确切映射。因此,用户在登录时可能会输入他/她的姓名,但用于authenticate 到 LDAP 的实际名称将是完整的 DN,例如 uid=(username),ou=users,dc=springsource,dc=com

Authenticating the user,可以通过 binding 作为该用户,或者通过对 DN 目录条目中的密码属性执行用户密码的远程 compare 操作。

正在为用户加载权限列表。

参考How to configure multiple UPN Suffixes。另外,在ActiveDirectoryLdapAuthenticationProvider 中,您可以编写一个读取多个后缀的函数,因为库是adaptable。

【讨论】:

以上是关于使用多个后缀值/域对 ldap 用户进行身份验证的主要内容,如果未能解决你的问题,请参考以下文章

多个 OU 的 LDAP 身份验证配置

iOS Firebase 身份验证域对用户可见

LDAP:如何使用连接详细信息验证用户身份

Spring Security:针对多个 LDAP 服务器和基于 DAO 的身份验证进行身份验证

ldap spring security http基本身份验证

使用 LDAP 服务器对用户进行身份验证