I have trouble resolving different encoding types from my LDAP server (which is in SSHA) and the authenticating value of just plain text.
I am using LDAP Repository to retrieve my LDAP server and used AuthenticationManager
and my own implementation of `UserDetailService.
The problem is always receive a Bad Credentials exception when i try to authenticate.
As seen on my codes below;
when i request to /auth
, i have a plain text username
and password
. However, i when try to authenticate it via AuthenticationManager
, it gives me a Bad Credentials. Now, i know that this has got to do with the UserDetailService.getPassword()
and the password
i provided in UsernamePasswordAuthenticationToken
. Its about the different encryption type. My LDAP has an {SSHA}, also translated to a binary (bytes) and the encoder is Bcrypt and String.
Now my question is how do you properly authenticate a password against the password return by LdapRespository ?
UPDATES
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
Above logs is during password matching in PasswordEncoder
. Based from it. it shows that the Raw Password (inputted by user) has a different hash from the Encoded Password (from ldap server).
I used LdapShaPasswordEncoder.encode
to hash user inputted password.
Also, i noticed that everytime i want to authenticate (call http://locahost:xxxx/auth ), the user inputted password's hash changes everytime. I think this is normal when hashing
Security Configuration NOTE: I am allowing all REST-API Endpoints for now, i gonna restrict it later
@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();
}
}
LoginController
@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 implementation
@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 implemenation
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
}
You are using BCryptPasswordEncoder but in LDAP is using the SSHA encryption.
You need to modify the method passwordEncoder
in class SantaRestApiSecurityConfiguration
@Bean
public PasswordEncoder passwordEncoder() {
return new LdapShaPasswordEncoder();
}
public Class UserLdap {
@Attribute(name = "userPassword", type = Type.BINARY)
private byte[] password;
}
and change the method 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()));
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.