Java 通过LDAP存储库验证LDAP

Java 通过LDAP存储库验证LDAP,java,spring-boot,spring-security,spring-data,spring-security-ldap,Java,Spring Boot,Spring Security,Spring Data,Spring Security Ldap,我在解析LDAP服务器(位于SSHA中)的不同编码类型和纯文本的身份验证值时遇到问题 我正在使用LDAP存储库检索我的LDAP服务器,并使用了AuthenticationManager和我自己的“UserDetailService”实现 问题是,当我尝试进行身份验证时,总是会收到错误的凭据异常 如下面我的代码所示 当我请求/auth时,我有一个纯文本用户名和密码。但是,当我尝试通过AuthenticationManager对其进行身份验证时,它会给我错误的凭据。现在,我知道这与我在Usernam

我在解析LDAP服务器(位于SSHA中)的不同编码类型和纯文本的身份验证值时遇到问题

我正在使用LDAP存储库检索我的LDAP服务器,并使用了
AuthenticationManager
和我自己的“UserDetailService”实现

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

如下面我的代码所示

当我请求
/auth
时,我有一个纯文本
用户名
密码
。但是,当我尝试通过
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: {SSHA}kMgk3gD4prAa/9m4wsPbuAoGhO7UvH2v6+W0Dg==
2020-04-12 17:09:58.110  INFO 6672 --- [nio-8080-exec-1] s.w.s.SantaRestApiSecurityConfiguration  : Raw Password: {SSHA}kMgk3gD4prAa/9m4wsPbuAoGhO7UvH2v6+W0Dg== matches Encoded Password: {SSHA}k1Pp3NICHbwuxFFdT7zno/iG/NTILZGL = false
以上日志是在
PasswordEncoder
中进行密码匹配时记录的。基于此。它显示原始密码(由用户输入)与编码密码(来自ldap服务器)具有不同的哈希值

我使用
LdapShaPasswordEncoder.encode
散列用户输入的密码

另外,我注意到,每次我想要验证(调用)时,用户输入的密码的散列值都会发生变化。我认为这在散列时是正常的

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

@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);
    }
}
登录控制器

@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);
    }
}
用户详细信息实施

@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()));
    }
}
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

}

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

您需要在类
santarestapisesecurityConfiguration

  @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()));
    } 

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

您需要在类
santarestapisesecurityConfiguration

  @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()));
    } 

是否将LDAP用户密码存储在BCrypt endcoin中?否,我仅读取现有LDAP服务器。不写入或修改现有数据。现在,我正在读取的LDAP服务器处于SSHA加密中。是否将LDAP用户密码存储在BCrypt endcoin中?否,我只读取现有的LDAP服务器。不写入或修改现有数据。现在,我正在阅读的LDAP服务器使用的是SSHA加密。我使用的是哪个
LdapShaPasswordEncoder
,它在这里说它已被弃用
encodePassword
不存在,并且
isPasswordValid
。我分别使用
encode
matches
作为从ldaprepository检索密码的替代方法。我在ldap服务器中读取了我存储的二进制用户密码的值。我应该如何转换它?我做了类似的事情。我的问题是,我从ldap服务器的密码字段中检索到的值类似于
112,12,3,2,21
基本上是它的二进制,那么我用来进行身份验证的是一个可读的字符串。可能是UserLdapRepository中的问题。它没有从LDAP服务器正确获取密码。不,返回正确的jsut,LDAP服务器以二进制格式存储密码。请参阅这篇文章,其中
LdapShaPasswordEncoder
doi use?,它在这里说它已被弃用,
encodePassword
不存在,并且
isPasswordValid
。我分别使用
encode
matches
作为从ldaprepository检索密码的替代方法。我在ldap服务器中读取了我存储的二进制用户密码的值。我应该如何转换它?我做了类似的事情。我的问题是,我从ldap服务器的密码字段中检索到的值类似于
112,12,3,2,21
基本上是它的二进制,那么我用来进行身份验证的是一个可读的字符串。可能是UserLdapRepository中的问题。它没有从LDAP服务器正确获取密码。不,返回正确的jsut,LDAP服务器以二进制格式存储密码。参见本文