简体   繁体   English

简单 Spring 引导 LDAP 身份验证示例不适用于 ActiveDirectory

[英]Simple Spring Boot LDAP authentication example does not work with ActiveDirectory

I found a very simple example for LDAP authentication, which works just fine using an embedded LDAP server: https://github.com/asbnotebook/spring-boot/tree/master/spring-security-embedded-ldap-example .我找到了一个非常简单的 LDAP 身份验证示例,它使用嵌入式 LDAP 服务器工作得很好: https://github.com/asbnotebook/spring-boot/tree/master/spring-security-embedded-ldap-example It is exactly what I need - one config class added and now all users are required to log in before accessing the application.这正是我所需要的——添加了一个配置 class,现在所有用户都需要在访问该应用程序之前登录。

Since our AD (local server, not the Azure AD) requires userDN and password for access, I added this to the example code, also modified url, base dn etc.由于我们的 AD(本地服务器,不是 Azure AD)需要 userDN 和密码才能访问,我将其添加到示例代码中,还修改了 url、base dn 等。

When I attempt to log in, I always get the "Bad credentials" error message.当我尝试登录时,总是收到“凭据错误”错误消息。 I then stepped through the code and found that the Spring LDAP code successfully retrieves some user data from AD (I found the user email address in the "userDetails" object which is known only in the AD), however the "password" field is set to null. This null value is then compared to the password entered by the user which fails and a BadCredentialsException is thrown in function org.springframework.security.authentication.dao.additionalAuthenticationChecks().然后我逐步查看代码,发现 Spring LDAP 代码成功地从 AD 中检索了一些用户数据(我在“userDetails”object 中找到了用户 email 地址,只有在 AD 中才知道),但是设置了“密码”字段到 null。然后将此 null 值与用户输入的密码进行比较,失败并在 function org.springframework.security.authentication.dao.additionalAuthenticationChecks() 中抛出 BadCredentialsException。

So now I have two questions:所以现在我有两个问题:

  1. why is the "password" attribute set to null?为什么“密码”属性设置为 null? My understanding is that it should contain the password hash. I checked the AD response with ldapsearch but I don't see anything looking like a password hash. However the userDN does work with other applications so it is probably not a problem with the userDN AD account.我的理解是它应该包含密码 hash。我用 ldapsearch 检查了 AD 响应,但我没有看到任何看起来像密码 hash 的东西。但是 userDN 确实可以与其他应用程序一起使用,所以它可能不是 userDN AD 的问题帐户。 Please advise how to properly retrieve the password information.请告知如何正确找回密码信息。

  2. I believe that the example does not handle password hashes.我相信该示例不处理密码哈希。 The LDIF file to preload the embedded LDAP server of the example application simply contains clear text passwords for the userPassword attribute.用于预加载示例应用程序的嵌入式 LDAP 服务器的 LDIF 文件只包含 userPassword 属性的明文密码。 Also the passwordEncoder in the example code looks like a No Op Encoder.此外,示例代码中的 passwordEncoder 看起来像一个无操作编码器。 How should I change this to make it work with the AD?我应该如何更改它以使其与 AD 一起使用?

Here is my code:这是我的代码:

package com.asbnotebook.example.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.ldap.DefaultLdapUsernameToDnMapper;
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
import org.springframework.security.ldap.userdetails.LdapUserDetailsManager;

@Configuration
public class LdapSecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public UserDetailsService userDetailsService() {
        
        var cs = new DefaultSpringSecurityContextSource("ldaps://ad.company.local/dc=company,dc=local");
        cs.setUserDn("cn=robot1,ou=robots");
        cs.setPassword("secret");
        cs.afterPropertiesSet();

        var manager = new LdapUserDetailsManager(cs);
        manager.setUsernameMapper(new DefaultLdapUsernameToDnMapper("ou=company_user", "cn"));
        manager.setGroupSearchBase("ou=company_groups");

        return manager;
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }
}

After considering Gabriel Luci's comment, I have now found a simple way to authenticate with our ActiveDirectory:在考虑了Gabriel Luci 的评论之后,我现在找到了一种使用 ActiveDirectory 进行身份验证的简单方法:

package com.asbnotebook.example.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider;

@Configuration
public class LdapSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception
    {
        ActiveDirectoryLdapAuthenticationProvider adProvider =
                new ActiveDirectoryLdapAuthenticationProvider(
                        "company.de","ldaps://ad.company.local","dc=company,dc=local");
        adProvider.setConvertSubErrorCodesToExceptions(true);
        adProvider.setUseAuthenticationRequestCredentials(true);
        auth.authenticationProvider(adProvider);
        auth.eraseCredentials(false);
    }
}

Login is possible using either the email address or sAMAccountName.可以使用 email 地址或 sAMAccountName 登录。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM