Search code examples
javaspringrestspring-security

Updated password not picked up after InMemoryUserDetailsManager updateUser call


Hi I have a Rest WS using WebSecurityConfigurerAdapter to implement HTTP Basic auth. The password is allowed to be updated and I need to let the WS to pick up updated password without restarting server Following are the codes:

SecurityConfig

// init a user with credentials admin/password
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                        //disable csrf
                        .csrf().disable()
                        //authentic all requests
                        .authorizeRequests().anyRequest().authenticated().and().httpBasic()
                        //disable session
                        .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(inMemoryUserDetailsManager());
    }

    @Bean
    public InMemoryUserDetailsManager inMemoryUserDetailsManager() {
        Properties users = new Properties();
        users.put("admin", "password,USER,enabled");
        return new InMemoryUserDetailsManager(users);
    }
}

The controller that will update password

@RestController
public class someController{
    @Autowired
    public InMemoryUserDetailsManager inMemoryUserDetailsManager;

    // update password from password -> pass
    @RequestMapping(...)
    public updatePass(){
        ArrayList<GrantedAuthority> grantedAuthoritiesList = new ArrayList<>();
        grantedAuthoritiesList.add(new SimpleGrantedAuthority("USER"));

        this.inMemoryUserDetailsManager.updateUser(new User("admin", "pass", grantedAuthoritiesList));
    }

    // another way that also doesn’t work
    @RequestMapping(...)
    public newUpdate(){
        ArrayList<GrantedAuthority> grantedAuthoritiesList = new ArrayList<>();
        grantedAuthoritiesList.add(new SimpleGrantedAuthority("USER"));    
        UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("admin", "pass",
                        grantedAuthoritiesList);

        SecurityContext context = SecurityContextHolder.getContext();
        context.setAuthentication(auth);
        SecurityContextHolder.setContext(context);
    }
}

After calling updatePass() with credential admin/password for the first time, I can see that the password has been updated to "pass" in debugger

enter image description here

I assume that if I'm to call updatePass() again, I should use admin/pass. However it turned out to be still using the old admin/password.

Sources I referred to when writing this code source1 source2

*I'm using Advance Rest Client to make the calls


Solution

  • instead of using SecurityContext, I overwrote function loadUserByUsername of interface UserDetailsService to let spring security always pick up the latest pwd from DB.