0

In my system I use JWT tokens so that authorization of requests could be performed based on JWT only, with no need to call database to fetch roles etc. I use OAuth, and my services are Resource servers which works fine and I'm satisfied with that. The problem I have is with my uaa-service, which is both Authorization and Resource server.

I've noticed that when I send requests to uaa-service I can inject @AuthenticatedPrincipal into my controller method and I have access to all user fields, not only those which are present in JWT. It means that Spring somehow maintains session or maybe in the background fetches user data from database. Here are my settings:

@Configuration
@EnableResourceServer
@Slf4j
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {

@Override
public void configure(HttpSecurity http) throws Exception {
    log.info("Configuring resource server");
    http
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
            .authorizeRequests()
            .antMatchers("/register").permitAll().anyRequest().authenticated();
}

@Autowired
public void setJwtAccessTokenConverter(JwtAccessTokenConverter jwtAccessTokenConverter) {
    jwtAccessTokenConverter.setAccessTokenConverter(bitcoinTokenConverter());
}

@Bean
DefaultAccessTokenConverter bitcoinTokenConverter() {
    return new CustomTokenConverter();
}

And

@Configuration
@EnableAuthorizationServer
public class OAuth2AuthServerConfig extends AuthorizationServerConfigurerAdapter {

@Autowired
private CustomUserDetailsService customUserDetailsService;

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

@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
    JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
    KeyPair keyPair = new KeyStoreKeyFactory(new ClassPathResource(keystoreName), keystorePassword.toCharArray())
            .getKeyPair(keystoreAlias);
    converter.setKeyPair(keyPair);

    return converter;
}

@Bean
public TokenEnhancer tokenEnhancer() {
    return new CustomTokenEnhancer();
}

@Bean
public DefaultAccessTokenConverter accessTokenConverter() {
    return new DefaultAccessTokenConverter();
}

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
    tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer(), jwtAccessTokenConverter()));
    endpoints
            .authenticationManager(authenticationManager)
            .userDetailsService(customUserDetailsService)
            .tokenEnhancer(tokenEnhancerChain);
}

@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
    oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
}

and

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private CustomUserDetailsService customUserDetailsService;

@Autowired
private ApplicationEventPublisher applicationEventPublisher;

@Bean
FilterRegistrationBean forwardedHeaderFilter() {
    FilterRegistrationBean filterRegBean = new FilterRegistrationBean();
    filterRegBean.setFilter(new ForwardedHeaderFilter());
    filterRegBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
    return filterRegBean;
}

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

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
            .authorizeRequests().antMatchers("/register").permitAll().anyRequest().authenticated();
}

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(customUserDetailsService).passwordEncoder(new BCryptPasswordEncoder());
    auth.authenticationEventPublisher(new DefaultAuthenticationEventPublisher(applicationEventPublisher));
}

Where did I make a mistake? In my SecurityConfig.java I have

auth.userDetailsService(customUserDetailsService).passwordEncoder(new BCryptPasswordEncoder());

so that the login could be performed by fetchining user from database and validating password but it looks like it may also cause that incoming requests are not handled only based on JWT.

pzeszko
  • 1,989
  • 18
  • 29
  • 1
    Token saved into database in blob format where each piece of information stored (e.g token, validity etc). Did you create any table in database? where is your datasource information ? – Ataur Rahman Munna Sep 25 '17 at 11:29
  • I use default InMemoryTokenStore at the moment, so there's no need to create tables or anything. – pzeszko Sep 26 '17 at 10:44
  • Make a bean for `BCryptPasswordEncoder` and set it `auth.userDetailsService(customUserDetailsService).passwordEncoder(byCrypt());` assume that your bean method name `byCrypt()`. – Ataur Rahman Munna Sep 26 '17 at 11:00
  • Actually, it's not the point, but you pointed me in the right direction. I should have use JwtTokenStore instead of the default one. – pzeszko Sep 26 '17 at 12:14
  • What I am saying in the first comment ? – Ataur Rahman Munna Sep 26 '17 at 12:43
  • I wish I knew, sorry but your first comment was kind of messy :) The second one is even more obscure. My problem had nothing to do with bcrypt. As I mentioned earlier, I should have used JwtTokenStore so that my tokens wouldn't be persisted to InMemoryTokenStore (the default one which Spring uses) and this way the authorization is performed only based on incoming JWT. – pzeszko Sep 26 '17 at 17:59

0 Answers0