You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by co...@apache.org on 2019/11/05 17:34:54 UTC
[cxf] branch 3.3.x-fixes updated: Make sure that only the client
associated with a token can revoke it
This is an automated email from the ASF dual-hosted git repository.
coheigea pushed a commit to branch 3.3.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git
The following commit(s) were added to refs/heads/3.3.x-fixes by this push:
new 3aa9f80 Make sure that only the client associated with a token can revoke it
3aa9f80 is described below
commit 3aa9f8011b54b9a1540a61abc24dac75c0b68381
Author: Colm O hEigeartaigh <co...@apache.org>
AuthorDate: Tue Nov 5 16:20:07 2019 +0000
Make sure that only the client associated with a token can revoke it
(cherry picked from commit a9a7302896c4d52bace3af0ac2e252bf6e4d6ba1)
---
.../oauth2/provider/AbstractOAuthDataProvider.java | 37 +++++++------
.../oauth2/grants/RevocationServiceTest.java | 60 ++++++++++++++++++++++
2 files changed, 82 insertions(+), 15 deletions(-)
diff --git a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/AbstractOAuthDataProvider.java b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/AbstractOAuthDataProvider.java
index 3413976..3681b86 100644
--- a/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/AbstractOAuthDataProvider.java
+++ b/rt/rs/security/oauth-parent/oauth2/src/main/java/org/apache/cxf/rs/security/oauth2/provider/AbstractOAuthDataProvider.java
@@ -199,18 +199,18 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
public ServerAccessToken refreshAccessToken(Client client, String refreshTokenKey,
List<String> restrictedScopes) throws OAuthServiceException {
RefreshToken currentRefreshToken = recycleRefreshTokens
- ? revokeRefreshToken(refreshTokenKey) : getRefreshToken(refreshTokenKey);
+ ? revokeRefreshToken(client, refreshTokenKey) : getRefreshToken(refreshTokenKey);
if (currentRefreshToken == null) {
throw new OAuthServiceException(OAuthConstants.ACCESS_DENIED);
}
if (OAuthUtils.isExpired(currentRefreshToken.getIssuedAt(), currentRefreshToken.getExpiresIn())) {
if (!recycleRefreshTokens) {
- revokeRefreshToken(refreshTokenKey);
+ revokeRefreshToken(client, refreshTokenKey);
}
throw new OAuthServiceException(OAuthConstants.ACCESS_DENIED);
}
if (recycleRefreshTokens) {
- revokeAccessTokens(currentRefreshToken);
+ revokeAccessTokens(client, currentRefreshToken);
}
ServerAccessToken at = doRefreshAccessToken(client, currentRefreshToken, restrictedScopes);
@@ -227,16 +227,17 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
public void revokeToken(Client client, String tokenKey, String tokenTypeHint) throws OAuthServiceException {
ServerAccessToken accessToken = null;
if (!OAuthConstants.REFRESH_TOKEN.equals(tokenTypeHint)) {
- accessToken = revokeAccessToken(tokenKey);
+ accessToken = revokeAccessToken(client, tokenKey);
}
if (accessToken != null) {
- handleLinkedRefreshToken(accessToken);
+ handleLinkedRefreshToken(client, accessToken);
} else if (!OAuthConstants.ACCESS_TOKEN.equals(tokenTypeHint)) {
- RefreshToken currentRefreshToken = revokeRefreshToken(tokenKey);
- revokeAccessTokens(currentRefreshToken);
+ RefreshToken currentRefreshToken = revokeRefreshToken(client, tokenKey);
+ revokeAccessTokens(client, currentRefreshToken);
}
}
- protected void handleLinkedRefreshToken(ServerAccessToken accessToken) {
+
+ protected void handleLinkedRefreshToken(Client client, ServerAccessToken accessToken) {
if (accessToken != null && accessToken.getRefreshToken() != null) {
RefreshToken rt = getRefreshToken(accessToken.getRefreshToken());
if (rt == null) {
@@ -245,7 +246,7 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
unlinkRefreshAccessToken(rt, accessToken.getTokenKey());
if (rt.getAccessTokens().isEmpty()) {
- revokeRefreshToken(rt.getTokenKey());
+ revokeRefreshToken(client, rt.getTokenKey());
} else {
saveRefreshToken(rt);
}
@@ -253,10 +254,10 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
}
- protected void revokeAccessTokens(RefreshToken currentRefreshToken) {
+ protected void revokeAccessTokens(Client client, RefreshToken currentRefreshToken) {
if (currentRefreshToken != null) {
for (String accessTokenKey : currentRefreshToken.getAccessTokens()) {
- revokeAccessToken(accessTokenKey);
+ revokeAccessToken(client, accessTokenKey);
}
}
}
@@ -495,13 +496,13 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
List<RefreshToken> refreshTokens = getRefreshTokens(c, null);
if (refreshTokens != null) {
for (RefreshToken rt : refreshTokens) {
- revokeRefreshToken(rt.getTokenKey());
+ revokeRefreshToken(c, rt.getTokenKey());
}
}
List<ServerAccessToken> accessTokens = getAccessTokens(c, null);
if (accessTokens != null) {
for (ServerAccessToken at : accessTokens) {
- revokeAccessToken(at.getTokenKey());
+ revokeAccessToken(c, at.getTokenKey());
}
}
}
@@ -549,16 +550,22 @@ public abstract class AbstractOAuthDataProvider implements OAuthDataProvider, Cl
return null;
}
- protected ServerAccessToken revokeAccessToken(String accessTokenKey) {
+ protected ServerAccessToken revokeAccessToken(Client client, String accessTokenKey) {
ServerAccessToken at = getAccessToken(accessTokenKey);
if (at != null) {
+ if (!at.getClient().getClientId().equals(client.getClientId())) {
+ throw new OAuthServiceException(OAuthConstants.INVALID_GRANT);
+ }
doRevokeAccessToken(at);
}
return at;
}
- protected RefreshToken revokeRefreshToken(String refreshTokenKey) {
+ protected RefreshToken revokeRefreshToken(Client client, String refreshTokenKey) {
RefreshToken refreshToken = getRefreshToken(refreshTokenKey);
if (refreshToken != null) {
+ if (!refreshToken.getClient().getClientId().equals(client.getClientId())) {
+ throw new OAuthServiceException(OAuthConstants.INVALID_GRANT);
+ }
doRevokeRefreshToken(refreshToken);
}
return refreshToken;
diff --git a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/grants/RevocationServiceTest.java b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/grants/RevocationServiceTest.java
index 057eda6..7847f7a 100644
--- a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/grants/RevocationServiceTest.java
+++ b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/grants/RevocationServiceTest.java
@@ -201,6 +201,66 @@ public class RevocationServiceTest extends AbstractBusClientServerTestBase {
assertEquals(400, response.getStatus());
}
+ @org.junit.Test
+ public void testAccessTokenRevocationWrongClient() throws Exception {
+ URL busFile = RevocationServiceTest.class.getResource("client.xml");
+
+ String address = "https://localhost:" + port + "/services/";
+ WebClient client = WebClient.create(address, OAuth2TestUtils.setupProviders(),
+ "alice", "security", busFile.toString());
+ // Save the Cookie for the second request...
+ WebClient.getConfig(client).getRequestContext().put(
+ org.apache.cxf.message.Message.MAINTAIN_SESSION, Boolean.TRUE);
+
+ // Get Authorization Code
+ String code = OAuth2TestUtils.getAuthorizationCode(client);
+ assertNotNull(code);
+
+ // Now get the access token
+ client = WebClient.create(address, OAuth2TestUtils.setupProviders(),
+ "consumer-id", "this-is-a-secret", busFile.toString());
+ // Save the Cookie for the second request...
+ WebClient.getConfig(client).getRequestContext().put(
+ org.apache.cxf.message.Message.MAINTAIN_SESSION, Boolean.TRUE);
+
+ ClientAccessToken accessToken = OAuth2TestUtils.getAccessTokenWithAuthorizationCode(client, code);
+ assertNotNull(accessToken.getTokenKey());
+
+ // Now query the token introspection service to make sure the token is valid
+ client = WebClient.create(address, OAuth2TestUtils.setupProviders(),
+ "consumer-id", "this-is-a-secret", busFile.toString());
+ client.accept("application/json").type("application/x-www-form-urlencoded");
+ Form form = new Form();
+ form.param("token", accessToken.getTokenKey());
+ client.path("introspect/");
+ Response response = client.post(form);
+
+ TokenIntrospection tokenIntrospection = response.readEntity(TokenIntrospection.class);
+ assertTrue(tokenIntrospection.isActive());
+
+ // Now try to revoke the token as a different client (this should fail, but no exception is thrown)
+ client = WebClient.create(address, OAuth2TestUtils.setupProviders(),
+ "consumer-id-aud", "this-is-a-secret", busFile.toString());
+ client.accept("application/json").type("application/x-www-form-urlencoded");
+ form = new Form();
+ form.param("token", accessToken.getTokenKey());
+ client.path("revoke/");
+ response = client.post(form);
+
+ // Now check the token introspection service again to make sure the token is still valid
+ // (the token revocation call failed)
+ client = WebClient.create(address, OAuth2TestUtils.setupProviders(),
+ "consumer-id", "this-is-a-secret", busFile.toString());
+ client.accept("application/json").type("application/x-www-form-urlencoded");
+ form = new Form();
+ form.param("token", accessToken.getTokenKey());
+ client.path("introspect/");
+ response = client.post(form);
+
+ tokenIntrospection = response.readEntity(TokenIntrospection.class);
+ assertTrue(tokenIntrospection.isActive());
+ }
+
//
// Server implementations
//