Skip to content

Commit

Permalink
New public methods in OAuth2Request identify a refresh token request
Browse files Browse the repository at this point in the history
Provided you use a DefaultTokenServices then the TokenEnhancer can now
be certain that it is enhancing a token that was refreshed. There's a
boolean method isRefresh() and full access to the TokenRequest in case
there's anything useful in there as well (e.g. the requested scopes).

Fixes spring-atticgh-405
  • Loading branch information
dsyer committed Feb 16, 2015
1 parent befb023 commit 27a2b25
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ public class OAuth2Request extends BaseRequest implements Serializable {
*/
private boolean approved = false;

/**
* Will be non-null if the request is for a token to be refreshed (the original grant type might still be available
* via {@link #getGrantType()}).
*/
private TokenRequest refresh = null;

/**
* The resolved redirect URI of this request. A URI may be present in the original request, in the
* authorizationParameters, or it may not be provided, in which case it will be defaulted (by processing classes) to
Expand Down Expand Up @@ -138,8 +144,34 @@ public OAuth2Request createOAuth2Request(Map<String, String> parameters) {
* @return a new request with the narrowed scope
*/
public OAuth2Request narrowScope(Set<String> scope) {
return new OAuth2Request(getRequestParameters(), getClientId(), authorities, approved, scope, resourceIds,
redirectUri, responseTypes, extensions);
OAuth2Request request = new OAuth2Request(getRequestParameters(), getClientId(), authorities, approved, scope,
resourceIds, redirectUri, responseTypes, extensions);
request.refresh = this.refresh;
return request;
}

public OAuth2Request refresh(TokenRequest tokenRequest) {
OAuth2Request request = new OAuth2Request(getRequestParameters(), getClientId(), authorities, approved,
getScope(), resourceIds, redirectUri, responseTypes, extensions);
request.refresh = tokenRequest;
return request;
}

/**
* @return true if this request is known to be for a token to be refreshed
*/
public boolean isRefresh() {
return refresh != null;
}

/**
* If this request was for an access token to be refreshed, then the {@link TokenRequest} that led to the refresh
* <i>may</i> be available here if it is known.
*
* @return the refresh token request (may be null)
*/
public TokenRequest getRefreshTokenRequest() {
return refresh;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ public OAuth2AccessToken refreshAccessToken(String refreshTokenValue, TokenReque
throw new InvalidTokenException("Invalid refresh token (expired): " + refreshToken);
}

authentication = createRefreshedAuthentication(authentication, tokenRequest.getScope());
authentication = createRefreshedAuthentication(authentication, tokenRequest);

if (!reuseRefreshToken) {
tokenStore.removeRefreshToken(refreshToken);
Expand All @@ -178,20 +178,21 @@ public OAuth2AccessToken getAccessToken(OAuth2Authentication authentication) {
* @return The refreshed authentication.
* @throws InvalidScopeException If the scope requested is invalid or wider than the original scope.
*/
private OAuth2Authentication createRefreshedAuthentication(OAuth2Authentication authentication, Set<String> scope) {
private OAuth2Authentication createRefreshedAuthentication(OAuth2Authentication authentication, TokenRequest request) {
OAuth2Authentication narrowed = authentication;
Set<String> scope = request.getScope();
OAuth2Request clientAuth = authentication.getOAuth2Request().refresh(request);
if (scope != null && !scope.isEmpty()) {
OAuth2Request clientAuth = authentication.getOAuth2Request();
Set<String> originalScope = clientAuth.getScope();
if (originalScope == null || !originalScope.containsAll(scope)) {
throw new InvalidScopeException("Unable to narrow the scope of the client authentication to " + scope
+ ".", originalScope);
}
else {
narrowed = new OAuth2Authentication(clientAuth.narrowScope(scope),
authentication.getUserAuthentication());
clientAuth = clientAuth.narrowScope(scope);
}
}
narrowed = new OAuth2Authentication(clientAuth, authentication.getUserAuthentication());
return narrowed;
}

Expand Down Expand Up @@ -340,7 +341,8 @@ public void setTokenEnhancer(TokenEnhancer accessTokenEnhancer) {
}

/**
* The validity (in seconds) of the refresh token. If less than or equal to zero then the tokens will be non-expiring.
* The validity (in seconds) of the refresh token. If less than or equal to zero then the tokens will be
* non-expiring.
*
* @param refreshTokenValiditySeconds The validity (in seconds) of the refresh token.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,7 @@ public ClientDetails loadClientByClientId(String clientId) throws OAuth2Exceptio
return client;
}
});
OAuth2AccessToken token = getTokenServices()
.createAccessToken(createAuthentication());
OAuth2AccessToken token = getTokenServices().createAccessToken(createAuthentication());
deleted.set(true);
OAuth2Authentication authentication = getTokenServices().loadAuthentication(token.getValue());
assertNotNull(authentication.getOAuth2Request());
Expand Down Expand Up @@ -120,6 +119,25 @@ public void testRefreshedTokenHasNarrowedScopes() throws Exception {
assertEquals("[read]", refreshedAccessToken.getScope().toString());
}

@Test
public void testRefreshTokenRequestHasRefreshFlag() throws Exception {
ExpiringOAuth2RefreshToken expectedExpiringRefreshToken = (ExpiringOAuth2RefreshToken) getTokenServices()
.createAccessToken(createAuthentication()).getRefreshToken();
TokenRequest tokenRequest = new TokenRequest(Collections.singletonMap("client_id", "id"), "id",
Collections.singleton("read"), null);
final AtomicBoolean called = new AtomicBoolean(false);
getTokenServices().setTokenEnhancer(new TokenEnhancer() {
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
assertTrue(authentication.getOAuth2Request().isRefresh());
called.set(true);
return accessToken;
}
});
getTokenServices().refreshAccessToken(expectedExpiringRefreshToken.getValue(), tokenRequest);
assertTrue(called.get());
}

@Test
public void testTokenRevoked() throws Exception {
OAuth2Authentication authentication = createAuthentication();
Expand Down Expand Up @@ -170,8 +188,8 @@ public void testRefreshedTokenHasScopes() throws Exception {
@Test
public void testRefreshedTokenNotExpiring() throws Exception {
getTokenServices().setRefreshTokenValiditySeconds(0);
OAuth2RefreshToken expectedExpiringRefreshToken = getTokenServices()
.createAccessToken(createAuthentication()).getRefreshToken();
OAuth2RefreshToken expectedExpiringRefreshToken = getTokenServices().createAccessToken(createAuthentication())
.getRefreshToken();
assertFalse(expectedExpiringRefreshToken instanceof DefaultExpiringOAuth2RefreshToken);
}

Expand Down

0 comments on commit 27a2b25

Please sign in to comment.