Skip to content
This repository has been archived by the owner on May 31, 2022. It is now read-only.

DefaultTokenServices refreshAccessToken doesn't store new refresh token when reuseRefreshToken is true #1818

Open
githubyong opened this issue Dec 3, 2019 · 0 comments

Comments

@githubyong
Copy link

Summary

DefaultTokenServices refreshAccessToken doesn't strore new refresh token when reuseRefreshToken is ture.

Actual Behavior

Response authServerResponse = obtainAccessToken();
String accessToken = authServerResponse.jsonPath().getString("access_token");
refreshToken = authServerResponse.jsonPath().getString("refresh_token");
Response refreshResponse = obtainRefreshToken("sampleclient", refreshToken);
String accessToken2 = refreshResponse.jsonPath().getString("access_token");
assertNotNull(accessToken2):

accessToken2 only not null the first time,and return null by second or more tests.

the reason is that when refresh token changed ,the DefaultTokenServices doesn't store it.

//org.springframework.security.oauth2.provider.token.DefaultTokenServices#refreshAccessToken

@Transactional(noRollbackFor={InvalidTokenException.class, InvalidGrantException.class})
	public OAuth2AccessToken refreshAccessToken(String refreshTokenValue, TokenRequest tokenRequest)
			throws AuthenticationException {

		if (!supportRefreshToken) {
			throw new InvalidGrantException("Invalid refresh token: " + refreshTokenValue);
		}

		OAuth2RefreshToken refreshToken = tokenStore.readRefreshToken(refreshTokenValue);
		if (refreshToken == null) {// note [2]
			throw new InvalidGrantException("Invalid refresh token: " + refreshTokenValue);
		}

		OAuth2Authentication authentication = tokenStore.readAuthenticationForRefreshToken(refreshToken);
		if (this.authenticationManager != null && !authentication.isClientOnly()) {
			// The client has already been authenticated, but the user authentication might be old now, so give it a
			// chance to re-authenticate.
			Authentication user = new PreAuthenticatedAuthenticationToken(authentication.getUserAuthentication(), "", authentication.getAuthorities());
			user = authenticationManager.authenticate(user);
			Object details = authentication.getDetails();
			authentication = new OAuth2Authentication(authentication.getOAuth2Request(), user);
			authentication.setDetails(details);
		}
		String clientId = authentication.getOAuth2Request().getClientId();
		if (clientId == null || !clientId.equals(tokenRequest.getClientId())) {
			throw new InvalidGrantException("Wrong client for this refresh token: " + refreshTokenValue);
		}

		// clear out any access tokens already associated with the refresh
		// token.
		tokenStore.removeAccessTokenUsingRefreshToken(refreshToken);

		if (isExpired(refreshToken)) {
			tokenStore.removeRefreshToken(refreshToken);
			throw new InvalidTokenException("Invalid refresh token (expired): " + refreshToken);
		}

		authentication = createRefreshedAuthentication(authentication, tokenRequest);

		if (!reuseRefreshToken) {
			tokenStore.removeRefreshToken(refreshToken);
			refreshToken = createRefreshToken(authentication);
		}

		OAuth2AccessToken accessToken = createAccessToken(authentication, refreshToken);
		tokenStore.storeAccessToken(accessToken, authentication);
		if (!reuseRefreshToken) {// note [1]
			tokenStore.storeRefreshToken(accessToken.getRefreshToken(), authentication);
		}
		return accessToken;
	}

note [1]: there doesn't sotre new refresh token
note [2]: there the new refresh token will aways return null.

Expected Behavior

Configuration

reuseRefreshTokens(true)

Version: 2.3.5.RELEASE - 2.4.0.RELEASE

Sample


import cn.yong.as.JwtUtil;
import io.jsonwebtoken.Claims;
import io.restassured.RestAssured;
import io.restassured.response.Response;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import static org.junit.Assert.*;

import java.util.HashMap;
import java.util.Map;


@Slf4j
public class ObtainToken_Test {

    static String ssaServer = "http://localhost:8120/ssol02as";

    private Response obtainAccessToken(String clientId, String username, String password, String... scopes) {
        final MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
        params.add("grant_type", "password");
        params.add("client_id", clientId);
        params.add("username", username);
        params.add("password", password);
        if (scopes != null) {
            for (String scope : scopes) {
                params.add("scope", scope);
            }
        }
        return RestAssured.given().auth().preemptive().basic(clientId, "secret").and().with().params(params).when().post(ssaServer + "/oauth/token");
    }

    private Response obtainRefreshToken(String clientId, final String refreshToken) {
        final MultiValueMap<String, String> params = new LinkedMultiValueMap<String, String>();
        params.add("grant_type", "refresh_token");
        params.add("client_id", clientId);
        params.add("refresh_token", refreshToken);

        return RestAssured.given().auth().preemptive().basic(clientId, "secret").and().with().params(params).when().post(ssaServer+"/oauth/token");
    }




    @Test
    public void testRefreshToken() throws Exception {
        Response authServerResponse = obtainAccessToken("sampleclient", "user1", "123", "foo");
        final String accessToken = authServerResponse.jsonPath().getString("access_token");
       String refreshToken = authServerResponse.jsonPath().getString("refresh_token");
        assertNotNull(accessToken);
     
    
        Response refreshResponse = obtainRefreshToken("sampleclient", refreshToken, "foo");
        final String accessToken2 = refreshResponse.jsonPath().getString("access_token");
        String refreshToken2 = refreshResponse.jsonPath().getString("refresh_token");
     
        assertNotNull(accessToken2);
    }

}

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Development

No branches or pull requests

2 participants