1

I had Oauth implemented in Spring Boot 1.5.7 but when I switched to 2 it showed me error "java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null".

From some research, I found that this may be an issue about password storage and password encoding.

What I've tried - I tried encoding the client secret in the authorization server file but that doesn't do anything and the error remains.

I've also tried saving the password with {bcrypt} as a prefix as spring security 5 looks for ann {id} during the password search.

I'm not able to fetch the access token and the above error doesn't go. Can someone help me figure this out? I've read and implemented almost everything and it doesn't seem to work.

Update: I was able to solve the above error by saving the password with {bcrypt} format. Similarly applying passwordEncoder in other required places.

Issue: I'm now facing an error with bad credentials. I've debugged and figured that its not getting the username we're trying to pass in the api and receiving null parameter. The flow reaches the userDetailservice but with an epmty parameter. I've attached my UserDetailsService along with this.

SecurityConfig.java

@Configuration
@EnableWebSecurity
public class OAuth2SecurityConfiguration extends WebSecurityConfigurerAdapter {

  @Autowired
  private ClientDetailsService clientDetailsService;

  @Autowired
  private UserDetailsService userDetailsService;

  @Autowired
  private CustomPasswordEncoder customPasswordEncoder;

  @Autowired
  public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService).passwordEncoder(customPasswordEncoder);
  }

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable()
        .anonymous().disable()
        .authorizeRequests()
        .antMatchers("/oauth/token").permitAll();
  }

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

  @Bean
  @Autowired
  public TokenStoreUserApprovalHandler userApprovalHandler(TokenStore tokenStore) {
    TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
    handler.setTokenStore(tokenStore);
    handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
    handler.setClientDetailsService(clientDetailsService);
    return handler;
  }

  @Bean
  @Autowired
  public ApprovalStore approvalStore(TokenStore tokenStore) throws Exception {
    TokenApprovalStore store = new TokenApprovalStore();
    store.setTokenStore(tokenStore);
    return store;
  }

  @Bean
  public BCryptPasswordEncoder passwordEncoder(){ 
      return new BCryptPasswordEncoder(); 
  }
}

AuthorizationServerConfig.java

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

    private static String REALM = "api-security";

    @Value("${app.oauth.client-id}")
    private String CLIENT_ID;

    @Value("${app.oauth.client-secret}")
    private String CLIENT_SECRET;

    @Value("${app.oauth.access-token-validity}")
    private int accessTokenValidity;

    @Value("${app.oauth.refresh-token-validity}")
    private int refreshTokenValidity;

    @Autowired
    @Qualifier("tokenStore")
    private TokenStoreService tokenStore;

    @Autowired
    private UserApprovalHandler userApprovalHandler;

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    @Autowired
    @Qualifier("authenticationManagerBean")
    private AuthenticationManager authenticationManager;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory().withClient(CLIENT_ID)
                .authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")
                .authorities("ROLE_ADMIN").scopes("read", "write", "trust").secret(passwordEncoder.encode(CLIENT_SECRET))
                .accessTokenValiditySeconds(accessTokenValidity).refreshTokenValiditySeconds(refreshTokenValidity);
        System.out.println(passwordEncoder.encode(CLIENT_SECRET));
        System.out.println(CLIENT_SECRET);
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(tokenStore).userApprovalHandler(userApprovalHandler)
                .authenticationManager(authenticationManager);
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer.realm(REALM + "/client");
    }
}

UserDetailsService.java

@Configuration
@EnableWebSecurity
public class OAuth2SecurityConfiguration extends WebSecurityConfigurerAdapter {

  @Autowired
  private ClientDetailsService clientDetailsService;

  @Autowired
  @Qualifier("userDetailsService")
  private UserDetailsService userDetailsService;


  @Autowired
  public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
  }

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable()
        .anonymous().disable()
        .authorizeRequests()
        .antMatchers("/oauth/token").permitAll();
  }

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

  @Bean
  @Autowired
  public TokenStoreUserApprovalHandler userApprovalHandler(TokenStore tokenStore) {
    TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
    handler.setTokenStore(tokenStore);
    handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
    handler.setClientDetailsService(clientDetailsService);
    return handler;
  }

  @Bean
  @Autowired
  public ApprovalStore approvalStore(TokenStore tokenStore) throws Exception {
    TokenApprovalStore store = new TokenApprovalStore();
    store.setTokenStore(tokenStore);
    return store;
  }

  @Bean
  public PasswordEncoder passwordEncoder() {
      return PasswordEncoderFactories.createDelegatingPasswordEncoder();
  }

//  @Bean
//  @Override
//  public UserDetailsService userDetailsServiceBean() throws Exception {
//      return super.userDetailsServiceBean();
//  }

//  @Bean
//  public UserDetailsService userDetailsService() {
//    return super.userDetailsService();
//  }
}
okaycharm
  • 41
  • 1
  • 8

1 Answers1

0

For whoever finds this useful, I was able to solve this by the following points:

  1. If you clear your access token collection or table, you'll be able to get the access toke once but that's it. Every request you do after that will go with "500 error - Internal server error".

  2. This happens because spring boot wasn't able to understand the access token from the DB when making other requests, for which you can use "org.springframework.util.SerializationUtils" package. You can search about this, it serializes and deserializes the access tokens and refresh token when requests are made.

okaycharm
  • 41
  • 1
  • 8