0

I use mongo custom tokenStore and codeService:

this is my custom mongoTokenStore:

public class MongoTokenStore implements TokenStore {

    private final MongoAccessTokenRepository mongoAccessTokenRepository;
    private final MongoRefreshTokenRepository mongoRefreshTokenRepository;
    private AuthenticationKeyGenerator authenticationKeyGenerator =
            new DefaultAuthenticationKeyGenerator();

    public MongoTokenStore(MongoAccessTokenRepository mongoAccessTokenRepository, MongoRefreshTokenRepository mongoRefreshTokenRepository) {
        this.mongoAccessTokenRepository = mongoAccessTokenRepository;
        this.mongoRefreshTokenRepository = mongoRefreshTokenRepository;
    }


    @Override
    public OAuth2Authentication readAuthentication(OAuth2AccessToken oAuth2AccessToken) {
        return readAuthentication(oAuth2AccessToken.getValue());
    }

    @Override
    public OAuth2Authentication readAuthentication(String tokenId) {
        return mongoAccessTokenRepository.findByTokenId(tokenId)
                .map(MongoAccessToken::getAuthentication)
                .orElse(null);
    }

    @Override
    public void storeAccessToken(OAuth2AccessToken oAuth2AccessToken, OAuth2Authentication oAuth2Authentication) {

        MongoAccessToken mongoAccessToken = new MongoAccessToken(oAuth2AccessToken, oAuth2Authentication,
                authenticationKeyGenerator.extractKey(oAuth2Authentication));
        mongoAccessTokenRepository.save(mongoAccessToken);
    }

    @Override
    public OAuth2AccessToken readAccessToken(String tokenValue) {
        return mongoAccessTokenRepository.findByTokenId(tokenValue)
                .map(MongoAccessToken::getOAuth2AccessToken)
                .orElse(null);
    }

    @Override
    public void removeAccessToken(OAuth2AccessToken oAuth2AccessToken) {
        mongoAccessTokenRepository.findByTokenId(oAuth2AccessToken.getValue())
                .ifPresent(mongoAccessTokenRepository::delete);
    }

    @Override
    public void storeRefreshToken(OAuth2RefreshToken oAuth2RefreshToken, OAuth2Authentication oAuth2Authentication) {
        MongoRefreshToken token=new MongoRefreshToken(oAuth2RefreshToken,oAuth2Authentication);
        mongoRefreshTokenRepository.save(token);

    }

    @Override
    public OAuth2RefreshToken readRefreshToken(String tokenValue) {
        return mongoRefreshTokenRepository.findByTokenId(tokenValue)
                .map(MongoRefreshToken::getOAuth2RefreshToken)
                .orElse(null);
    }

    @Override
    public OAuth2Authentication readAuthenticationForRefreshToken(OAuth2RefreshToken oAuth2RefreshToken) {

        return mongoRefreshTokenRepository.findByTokenId(oAuth2RefreshToken.getValue())
                .map(MongoRefreshToken::getAuthentication)
                .orElse(null);
    }

    @Override
    public void removeRefreshToken(OAuth2RefreshToken oAuth2RefreshToken) {
        mongoRefreshTokenRepository.findByTokenId(oAuth2RefreshToken.getValue())
                .ifPresent(mongoRefreshTokenRepository::delete);
    }

    @Override
    public void removeAccessTokenUsingRefreshToken(OAuth2RefreshToken oAuth2RefreshToken) {

        mongoAccessTokenRepository.findByRefreshToken(oAuth2RefreshToken.getValue())
                .ifPresent(mongoAccessTokenRepository::delete);
    }

    @Override
    public OAuth2AccessToken getAccessToken(OAuth2Authentication oAuth2Authentication) {

        return mongoAccessTokenRepository.findByAuthenticationId(authenticationKeyGenerator
                .extractKey(oAuth2Authentication))
                .map(MongoAccessToken::getOAuth2AccessToken)
                .orElse(null);
    }

    @Override
    public Collection<OAuth2AccessToken> findTokensByClientIdAndUserName(String s, String s1) {

        return mongoAccessTokenRepository.findByClientIdAndUserName(s,s1)
                .stream()
                .map(MongoAccessToken::getOAuth2AccessToken)
                .collect(Collectors.toList());
    }

    @Override
    public Collection<OAuth2AccessToken> findTokensByClientId(String s) {
        return mongoAccessTokenRepository.findByClientId(s)
                .stream()
                .map(MongoAccessToken::getOAuth2AccessToken)
                .collect(Collectors.toList());
    }
}

and this is my custom mongoCodeService:

@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class MongoAuthenticationCodeService extends RandomValueAuthorizationCodeServices{

    private final MongoAuthenticationCodeRepository repository;

    @Override
    protected void store(String code, OAuth2Authentication oAuth2Authentication) {

        repository.save(new MongoAuthenticationCode(code,oAuth2Authentication));
    }

    @Override
    protected OAuth2Authentication remove(String code) {

        return repository.findOneByCode(code)
                .map(MongoAuthenticationCode::getAuthentication)
                .orElse(null);
    }
}

and my OAuth2Config:

@Configuration
public class OAuth2ServerConfiguration {

    @Configuration
    @EnableResourceServer
    protected static class ResourceServerConfiguration extends
            ResourceServerConfigurerAdapter {

        @Override
        public void configure(ResourceServerSecurityConfigurer resources) {
            resources.resourceId(READ_AND_WRITE_RESOURCE_ID);
        }

        @Override
        public void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                    .antMatchers("/webjars/**", "/oauth/authorize/**", "/", "/customLogout",
                            "/oauth/check_token/**", "/login").permitAll()
                    .mvcMatchers(HttpMethod.GET, "/loginAttemptUsers").hasRole("ADMIN")
                    .anyRequest().authenticated();
        }

    }

    @Configuration
    @EnableAuthorizationServer
    protected static class AuthorizationServerConfiguration extends
            AuthorizationServerConfigurerAdapter {

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


        @Autowired
        private CustomUserDetailService customUserDetailService;

        @Autowired
        private MongoAuthenticationCodeService mongoAuthenticationCodeService;

        @Autowired
        private MongoTokenStore mongoTokenStore;

        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints)
                throws Exception {

            endpoints
                    .authorizationCodeServices(mongoAuthenticationCodeService)
                    .tokenStore(mongoTokenStore)
                    .authenticationManager(authenticationManager)
                    .userDetailsService(customUserDetailService)
                    .approvalStoreDisabled();

        }

        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

            clients
                    .inMemory()
                    .withClient("kksdi2388wmkwe")
                    .authorizedGrantTypes("authorization_code", "password", "refresh_token")
                    .scopes("read", "write")
                    .resourceIds("ReadAndWriteResource")
                    .secret("kksd23isdmsisdi2")
                    .autoApprove(true)
                    .accessTokenValiditySeconds(120)
                    .refreshTokenValiditySeconds(1200);

        }

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

        @Bean
        @Primary
        public DefaultTokenServices tokenServices() {
            DefaultTokenServices tokenServices = new DefaultTokenServices();
            tokenServices.setSupportRefreshToken(true);
            tokenServices.setTokenStore(tokenStore);
            return tokenServices;
        }

    }
}

the problem is:

I can login from spring zuul ui-server by "authorization_code",and can access ResourceServer data .

But when the access_token expired(120s), while re-getting ResourceServer data, I see mongoTokenStore removed the existed access_token , but why not refresh new access_token automatically?

How to resolve it?

Kery Hu
  • 5,626
  • 11
  • 34
  • 51

1 Answers1

0

The whole point of refresh token is to add one more security dimension to OAuth2.

When the end user has acquired access token, he now can access any resource within the authorization rules that the token awards him.

If his access token is stolen somehow, the attacker can now access to any resource that the access token authorizes him, but if we set an expiry time for the access token the attacker will have limited access time.

With that being said, if spring oauth2 would have refresh that token automatically that one more security aspect would not be applied, and the whole idea of refreshing the token would be wasted.

So, to conclude it's your responsibility to make sure that your end user is re-authorize via OAuth2 again.

You can also read this:

Why Does OAuth v2 Have Both Access and Refresh Tokens?

Community
  • 1
  • 1
Moshe Arad
  • 3,587
  • 4
  • 18
  • 33
  • thanks your answer, I know the rule, Can you give me some advice of how to implements with custom **MongoTokenStore (authorization_code grant type)** – Kery Hu Nov 28 '16 at 00:30