Spring-security-oauth: Better JWT Support with a UserAuthenticationConverter Supporting UserDetailsService

Created on 12 Jan 2015  路  2Comments  路  Source: spring-projects/spring-security-oauth

I was having a lot of problems trying to switch from the InMemoryTokenStore to the JWTTokenStore while using the @AuthenticationPrincipal annotation for injecting the principal. The in-memory would inject the UserDetails, as expected, while the JWT store only injected the username.

I finally figured out how to fix this. It involved implementing a UserAuthenticationConverter that uses the UserDetailsService in the UserAuthenticationConverter#extractAuthentication method. It seems like this should be an option included in Spring OAuth to me. In addition to the existing DefaultUserAuthenticationConverter.

Also, to make it work like the DefaultUserAuthenticationConverter I had to replicate the DefaultUserAuthenticationConverter#getAuthorities() method. It is currently marked as private. Can I also suggest changing the visibility to protected and expose the defaultAuthorities. That makes it much easier to subclass DefaultUserAuthenticationConverter if necessary.

enhancement

Most helpful comment

So I'm trying to figure out how this is used in practice. Since this setUserDetailsService() helper was added to DefaultUserAuthenticationConverter, I need to explicitly cast the AccessTokenConverter I get from jwtAccessTokenConverter.getAccessTokenConverter()? This implementation works for me, but I just wanted to check if this was "good practice":

@Configuration
@EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
    // ...
    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        final JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
        jwtAccessTokenConverter.setSigningKey("some_key");
        ((DefaultAccessTokenConverter) jwtAccessTokenConverter.getAccessTokenConverter())
                .setUserTokenConverter(userAuthenticationConverter());
        return jwtAccessTokenConverter;
    }

    @Bean
    public UserAuthenticationConverter userAuthenticationConverter() {
        DefaultUserAuthenticationConverter defaultUserAuthenticationConverter = new DefaultUserAuthenticationConverter();
        defaultUserAuthenticationConverter.setUserDetailsService(userDetailsService);
        return defaultUserAuthenticationConverter;
    }
    // ...
}

All 2 comments

I don't like making private methods public, so you still have to write your own if you want to change it (but it's only a few lines to copy).

So I'm trying to figure out how this is used in practice. Since this setUserDetailsService() helper was added to DefaultUserAuthenticationConverter, I need to explicitly cast the AccessTokenConverter I get from jwtAccessTokenConverter.getAccessTokenConverter()? This implementation works for me, but I just wanted to check if this was "good practice":

@Configuration
@EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
    // ...
    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        final JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
        jwtAccessTokenConverter.setSigningKey("some_key");
        ((DefaultAccessTokenConverter) jwtAccessTokenConverter.getAccessTokenConverter())
                .setUserTokenConverter(userAuthenticationConverter());
        return jwtAccessTokenConverter;
    }

    @Bean
    public UserAuthenticationConverter userAuthenticationConverter() {
        DefaultUserAuthenticationConverter defaultUserAuthenticationConverter = new DefaultUserAuthenticationConverter();
        defaultUserAuthenticationConverter.setUserDetailsService(userDetailsService);
        return defaultUserAuthenticationConverter;
    }
    // ...
}
Was this page helpful?
0 / 5 - 0 ratings