'How to update the password in Spring SecurityContext?
Using Spring Boot 2.6.4. Here is my SecurityConfig class:
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
@Autowired
SecurityService securityService;
@Override
protected void configure(HttpSecurity http) throws Exception
{
http.csrf().disable()
.authorizeRequests().anyRequest().authenticated()
.and()
.httpBasic();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception
{
auth.inMemoryAuthentication()
.withUser("admin")
.password("{noop}"+securityService.getApiKey())
.roles("ADMIN");
}
}
I'm entering here only when starting application. How to get to the configureGlobal
method after changing the password?
Here is how I change my password in the @RestController class (just store it in DB):
@PostMapping
public void update(@Valid @RequestBody SecurityDto dto) {
securityService.save(dto.getApiKey());
SecurityContextHolder.clearContext();
}
So my old password remains valid until restarting the application. Thats because I get to the SecurityConfig.configureGlobal method only when application starts. So how to change the password properly?
UPDATE: Resolved by implementing own UserDetailsService and using it instead of inMemoryAuthentication
auth.userDetailsService(userDetailsService);
Solution 1:[1]
InMemoryUserDetailsManager implements UserDetailsPasswordService and UserDetailsManager. You can use either to change the password:
For UserDetailsPasswordService
you can do:
private final UserDetailsPasswordService passwordService;
private final PasswordEncoder passwordEncoder;
@Autowired
public MyController(UserDetailsPasswordService passwordService, PasswordEncoder passwordEncoder) {
this.passwordService = passwordService;
this.passwordEncoder = passwordEncoder;
}
@PostMapping
public void update(@Valid @RequestBody SecurityDto dto) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Object principal = authentication.getPrincipal();
UserDetails userDetails;
if (principal instanceof UserDetails) {
userDetails = (UserDetails) principal;
} else {
userDetails = new User(authentication.getName(), "", authentication.getAuthorities());
}
String newPass = dto.getApiKey();
String pass = this.passwordEncoder.encode(newPass);
this.passwordService.updatePassword(userDetails, pass);
securityService.save(dto.getApiKey());
SecurityContextHolder.clearContext();
}
If you don't use password encoder, just remove it, and manually prepend the {noop}
prefix to the password. The important method is updatePassword()
.
You can refer to this question for how to do it with UserDetailsManager
. The method is changePassword?()
.
Edit: You can declare , and populate the bean with users manually in any @Configuration
class:
@Bean
public InMemoryUserDetailsManager inMemoryUserDetailsManager() {
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
String password = "{noop}" + this.securityService.getApiKey();
manager.createUser(new User("admin", password, Collections.singletonList(new SimpleGrantedAuthority("ADMIN"))));
return manager;
}
Solution 2:[2]
You can create an interceptor for your http calls and then get the UserContext from there; usually the principal object will have all the headers in a map available which you can use to get the key which you are looking for authentication
//Create a USER object where your updating the specific attributes
Optional<User> user = Optional.ofNullable(SecurityContextHolder.getContext())
.map(SecurityContext::getAuthentication) // can override to update the authentication ideally change your password here
.filter(Authentication::isAuthenticated)
.map(Authentication::getPrincipal)
.filter(DefaultOAuth2AuthenticatedPrincipal.class::isInstance)
.map(DefaultOAuth2AuthenticatedPrincipal.class::cast)
.map(principal -> getUser(principal.getAttributes()));
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Deb Das |