通过 LDAP 存储库验证 LDAP

Posted

技术标签:

【中文标题】通过 LDAP 存储库验证 LDAP【英文标题】:Authenticating LDAP via LDAP Repository 【发布时间】:2020-07-24 19:48:06 【问题描述】:

我无法从我的 LDAP 服务器(在 SSHA 中)解析不同的编码类型以及纯文本的身份验证值。

我正在使用 LDAP 存储库来检索我的 LDAP 服务器,并使用了AuthenticationManager 和我自己的 `UserDetailService.

当我尝试进行身份验证时,问题总是会收到错误的凭据异常。

如下面的代码所示;

当我请求/auth 时,我有一个纯文本usernamepassword。但是,当我尝试通过AuthenticationManager 对其进行身份验证时,它给了我一个错误的凭据。现在,我知道这与我在UsernamePasswordAuthenticationToken 中提供的UserDetailService.getPassword()password 有关。它关于不同的加密类型。我的 LDAP 有一个 SSHA,也翻译成二进制(字节),编码器是 Bcrypt 和 String。

现在我的问题是,您如何针对 LdapRespository 返回的密码正确地验证密码

更新

2020-04-12 17:09:46.655  INFO 6672 --- [nio-8080-exec-1] s.w.s.SantaRestApiSecurityConfiguration  : Raw Password:  jdoe123 | Encoded Password: SSHAkMgk3gD4prAa/9m4wsPbuAoGhO7UvH2v6+W0Dg==
2020-04-12 17:09:58.110  INFO 6672 --- [nio-8080-exec-1] s.w.s.SantaRestApiSecurityConfiguration  : Raw Password: SSHAkMgk3gD4prAa/9m4wsPbuAoGhO7UvH2v6+W0Dg== matches Encoded Password: SSHAk1Pp3NICHbwuxFFdT7zno/iG/NTILZGL = false

以上日志是在PasswordEncoder 的密码匹配期间。以此为基础。它表明 原始密码(由用户输入)与 编码密码(来自 ldap 服务器)具有不同的哈希值。

我使用LdapShaPasswordEncoder.encode 对用户输入的密码进行哈希处理。

另外,我注意到每次我想进行身份验证(调用http://locahost:xxxx/auth)时,用户每次都输入密码的哈希更改。我认为哈希时这是正常的

安全配置 注意:我现在允许所有 REST-API 端点,稍后我会限制它

@Configuration
@EnableWebSecurity
public class SantaRestApiSecurityConfiguration extends WebSecurityConfigurerAdapter   

    @Autowired
    AuthService authService;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception 
        // configure AuthenticationManager so that it knows from where to load
        // user for matching credentials
        // Use BCryptPasswordEncoder
        auth.userDetailsService(authService).passwordEncoder(passwordEncoder());
    

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception 
        return super.authenticationManagerBean();
    

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        // TODO Auto-generated method stub
        http.csrf()
            .disable()
            .authorizeRequests().antMatchers("/*").permitAll();
    

    @Override
    public void configure(WebSecurity web) throws Exception 
        web.ignoring().antMatchers("/*");
    

    /*
     * i am not sure about this since my LDAP server has 
     * a SSHA password encrpytion
     * 
     * */
    @Bean
    public PasswordEncoder passwordEncoder() 
        return new BCryptPasswordEncoder();
    

登录控制器

@RestController
@RequestMapping("/auth")
public class LoginController 

    public static Logger logger = LoggerFactory.getLogger(LoginController.class);

    @Autowired
    private AuthenticationManager authManager;

    @PostMapping
    public ResponseEntity<String> login(@RequestBody Map<String, String> credentials) 
        String username = credentials.get("username");
        String password = credentials.get("password");

        authManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));

        return new ResponseEntity<String>("", HttpStatus.OK);
    

UserDetailService 实现

@Service
public class AuthService implements UserDetailsService 

    public static Logger logger = LoggerFactory.getLogger(AuthService.class);

    @Autowired
    UserLdapRepository ldapRepo;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException 

        UserLdap e = ldapRepo.findByUid(username);
        logger.info("",e.toString());

        return new AuthDetails(e.getCn(), 
                               e.getPassword(),
                               e.getUid(), 
                               e.getMail(), 
                               e.getSn(), 
                               Long.toString( e.getUidNumber()));
    

UserDetails 实现

public class AuthDetails implements UserDetails 

    public static Logger logger = LoggerFactory.getLogger(AuthDetails.class);

    private String username;
    private String password;
    private String email;
    private String uidNumber;
    private String sn;
    private String uid;

    public AuthDetails(String username, String password, String uid, String email,String sn, String uidNumber) 
        this.uid = uid;
        this.password = password;
        this.username = username;
        this.email = email;
        this.sn = sn;
        this.uidNumber = uidNumber;
    

    /*
     * Here i am not sure how to implement this one to satisfy AuthenticationManager
     *
     *
     **/
    @Override
    public String getPassword() 
        return this.password;
    

    @Override
    public String getUsername() 
        // TODO Auto-generated method stub
        return this.username;
    

    // some method to implement


【问题讨论】:

您是否将 LDAP 用户密码存储在 BCrypt 加密中? 不,我只是在读取现有的 LDAP 服务器。不写入或修改现有数据。现在,我正在阅读的 LDAP 服务器是 SSHA 加密的。 【参考方案1】:

您正在使用 BCryptPasswordEncoder,但在 LDAP 中使用的是 SSHA 加密。

需要修改SantaRestApiSecurityConfiguration类中的方法passwordEncoder

  @Bean
public PasswordEncoder passwordEncoder() 
   return  new LdapShaPasswordEncoder();





public Class UserLdap 

    @Attribute(name = "userPassword", type = Type.BINARY)
    private byte[] password;

并更改方法 loadUserByUsername

@Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException 

        UserLdap e = ldapRepo.findByUid(username);
        logger.info("",e.toString());
        String password = "SSHA" + new String(e.getPassword());
        return new AuthDetails(e.getCn(), 
                               password,
                               e.getUid(), 
                               e.getMail(), 
                               e.getSn(), 
                               Long.toString( e.getUidNumber()));
     

【讨论】:

我使用哪个LdapShaPasswordEncoder?,这里说它已被弃用,encodePassword 不存在,isPasswordValid。我分别使用encodematches 作为替代 如何从 ldaprepository 检索密码。我已经阅读了 ldap 服务器中用户密码的值,我存储了二进制文件。我应该如何转换它? 我做了类似的事情。我的问题是我从 ldap 服务器中的密码字段中检索的值类似于112,12,3,2,21 基本上是它的二进制文件,然后我用来验证的是一个可读字符串。 可能是 UserLdapRepository 的问题。它没有从 LDAP 服务器正确获取密码。 不,正确返回,它只是 LDAP 服务器以二进制格式存储密码。看这篇文章***.com/questions/25536341/…

以上是关于通过 LDAP 存储库验证 LDAP的主要内容,如果未能解决你的问题,请参考以下文章

使用 Acegi 和 Grails 通过 LDAP 进行身份验证时出现 PartialResultException

使用LDAP验证

通过 Active Directory 使用 LDAP 在 PHP 中进行身份验证

身份验证是如何建立在 LDAP 上的?

存储 LDAP 连接并在会话中绑定

LDAP 身份验证通过凭据