0

I am migrating from Spring Boot 1.5.12 to Spring Boot 2.0 and also to Spring Security 5 and I am trying to do authenticate via OAuth 2. But I am getting this error even after using delegate {noop}:

java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null

Here is my code :

SecurityConfig

public class SecurityConfig extends WebSecurityConfigurerAdapter {

    
    @Autowired
    private CustomUserDetailsService userDetailsService;
    
    @Bean
    public PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }

    public SecurityConfig() {
        super();
        SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
    }

    @Override
    protected void configure(final HttpSecurity http) throws Exception {
            http.cors().and().csrf().disable().exceptionHandling().and().authorizeRequests()
                .antMatchers("/api/v1/**")
                .authenticated().and().httpBasic();
    }

    @Override
    public void configure(final WebSecurity web) throws Exception {
            web.ignoring().antMatchers(
                "/v2/api-docs","/configuration/ui","/swagger-resources", "/configuration/security", "/webjars/**",
                "/swagger-resources/configuration/ui","/swagger-resources/configuration/security",
                "/swagger-ui.html", "/admin11/*", "/*.html", "/*.jsp", "/favicon.ico", "//*.html", "//*.css", "//*.js",
                "/admin11/monitoring","/proxy.jsp");
    }

    @Override
    protected void configure(final AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

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

Oauth2AuthorizationServerConfig

public class Oauth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    @Autowired
    @Qualifier("authenticationManagerBean")
    private AuthenticationManager authenticationManager;

    @Autowired
    private CustomUserDetailsService userDetailsService;
    
    @Autowired
    private JdbcTokenStore jdbcTokenStore;
    
    @Bean
    public TokenStore tokenStore() {
        return jdbcTokenStore;
    }

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        CustomTokenEnhancer converter = new CustomTokenEnhancer();
        converter.setSigningKey("secret_api");
        return converter;
    }

    @Override
    public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
                
        endpoints.tokenStore(tokenStore())
                .accessTokenConverter(accessTokenConverter())
                .authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService)
                .pathMapping("/oauth/token", "/api/v1/oauth/token");
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory().withClient("app").secret("{noop}secret")
                .authorizedGrantTypes("password", "authorization_code").scopes("read", "write")
                .autoApprove(true).accessTokenValiditySeconds(0);
    }

    @Override
    public void configure(final AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
    }
    
    @Bean
    public DefaultTokenServices defaultTokenServices() {
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        return defaultTokenServices;
    }
}

CustomUserDetailsService

public interface CustomUserDetailsService extends UserDetailsService {

    UserDetails getByMsisdn(String msisdn);

    void initDummyUsers();
}

To solve this issue I tried the below questions from Stackoverflow:

Spring Boot PasswordEncoder Error

kobaltoloy
  • 149
  • 1
  • 12
  • public interface CustomUserDetailsService extends UserDetailsService { UserDetails getByMsisdn(String msisdn); void initDummyUsers(); } – kobaltoloy Jul 07 '20 at 07:50

1 Answers1

0

The Spring Security documentation is addressing your exact problem.

The following error occurs when one of the passwords that are stored has no id as described in Password Storage Format.

java.lang.IllegalArgumentException: There is no PasswordEncoder mapped
for the id "null"
     at org.springframework.security.crypto.password.DelegatingPasswordEncoder$UnmappedIdPasswordEncoder.matches(DelegatingPasswordEncoder.java:233)
     at org.springframework.security.crypto.password.DelegatingPasswordEncoder.matches(DelegatingPasswordEncoder.java:196)

The easiest way to resolve the error is to switch to explicitly provide the PasswordEncoder that you passwords are encoded with. The easiest way to resolve it is to figure out how your passwords are currently being stored and explicitly provide the correct PasswordEncoder.

If you are migrating from Spring Security 4.2.x you can revert to the previous behavior by exposing a NoOpPasswordEncoder bean.

So you should be able to fix this by explicitly providing the PasswordEncoder

// remember, its bad practice
@Bean
public PasswordEncoder passwordEncoder() {
    return NoOpPasswordEncoder.getInstance();
}

Or even better supply a custom defined password encoder delegator:

String idForEncode = "bcrypt";
Map encoders = new HashMap<>();
encoders.put(idForEncode, new BCryptPasswordEncoder());
encoders.put("noop", NoOpPasswordEncoder.getInstance());
encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
encoders.put("scrypt", new SCryptPasswordEncoder());
encoders.put("sha256", new StandardPasswordEncoder());

PasswordEncoder passwordEncoder =
    new DelegatingPasswordEncoder(idForEncode, encoders);

All taken from the official spring security docs on password encoding.

Toerktumlare
  • 12,548
  • 3
  • 35
  • 54