From cd51ff34749289a5ee27b3b9af330431d756132d Mon Sep 17 00:00:00 2001 From: Thomas Darimont Date: Tue, 3 Mar 2020 13:21:36 +0100 Subject: [PATCH] KEYCLOAK-13186 Remove role information from RefreshTokens We now no longer expose role assignment information into the RefreshToken. Previously RefreshTokens contained information about the realm and client specific roles which are assigned to a user. Since the role information is usually either taken from the AccessToken, IDToken or the User-Info endpoint and the RefreshToken is an internal format which is opaque to the client, it would be a waste of space to keep that information in the RefreshToken. See: https://lists.jboss.org/pipermail/keycloak-dev/2019-April/011936.html --- .../representations/RefreshToken.java | 12 +------ .../testsuite/oauth/RefreshTokenTest.java | 36 ++++++++++++++++--- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/org/keycloak/representations/RefreshToken.java b/core/src/main/java/org/keycloak/representations/RefreshToken.java index d2749a7706..497e806ffc 100755 --- a/core/src/main/java/org/keycloak/representations/RefreshToken.java +++ b/core/src/main/java/org/keycloak/representations/RefreshToken.java @@ -34,8 +34,7 @@ public class RefreshToken extends AccessToken { } /** - * Deep copies issuer, subject, issuedFor, sessionState, realmAccess, and resourceAccess - * from AccessToken. + * Deep copies issuer, subject, issuedFor, sessionState from AccessToken. * * @param token */ @@ -48,15 +47,6 @@ public class RefreshToken extends AccessToken { this.nonce = token.nonce; this.audience = new String[] { token.issuer }; this.scope = token.scope; - if (token.realmAccess != null) { - realmAccess = token.realmAccess.clone(); - } - if (token.resourceAccess != null) { - resourceAccess = new HashMap<>(); - for (Map.Entry entry : token.resourceAccess.entrySet()) { - resourceAccess.put(entry.getKey(), entry.getValue().clone()); - } - } } @Override diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java index 22c47845e0..e0aa9ec8ee 100755 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/RefreshTokenTest.java @@ -76,6 +76,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson; import static org.keycloak.testsuite.admin.ApiUtil.findUserByUsername; import static org.keycloak.testsuite.arquillian.AuthServerTestEnricher.AUTH_SERVER_SSL_REQUIRED; @@ -149,8 +150,6 @@ public class RefreshTokenTest extends AbstractKeycloakTest { response.close(); } events.clear(); - - } @Test @@ -161,6 +160,35 @@ public class RefreshTokenTest extends AbstractKeycloakTest { events.clear(); } + @Test + public void refreshTokenStructure() { + + oauth.nonce("123456"); + oauth.doLogin("test-user@localhost", "password"); + + EventRepresentation loginEvent = events.expectLogin().assertEvent(); + + String sessionId = loginEvent.getSessionId(); + String codeId = loginEvent.getDetails().get(Details.CODE_ID); + + String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE); + + OAuthClient.AccessTokenResponse tokenResponse = oauth.doAccessTokenRequest(code, "password"); + AccessToken token = oauth.verifyToken(tokenResponse.getAccessToken()); + assertEquals("123456", token.getNonce()); + + String refreshTokenString = tokenResponse.getRefreshToken(); + RefreshToken refreshToken = oauth.parseRefreshToken(refreshTokenString); + + events.expectCodeToToken(codeId, sessionId).assertEvent(); + + assertNotNull(refreshTokenString); + + assertEquals("123456", refreshToken.getNonce()); + assertNull("RealmAccess should be null for RefreshTokens", refreshToken.getRealmAccess()); + assertTrue("ResourceAccess should be null for RefreshTokens", refreshToken.getResourceAccess().isEmpty()); + } + @Test public void refreshTokenRequest() throws Exception { oauth.nonce("123456"); @@ -221,10 +249,10 @@ public class RefreshTokenTest extends AbstractKeycloakTest { assertEquals(findUserByUsername(adminClient.realm("test"), "test-user@localhost").getId(), refreshedToken.getSubject()); Assert.assertNotEquals("test-user@localhost", refreshedToken.getSubject()); - Assert.assertTrue(refreshedToken.getRealmAccess().isUserInRole("user")); + assertTrue(refreshedToken.getRealmAccess().isUserInRole("user")); assertEquals(1, refreshedToken.getResourceAccess(oauth.getClientId()).getRoles().size()); - Assert.assertTrue(refreshedToken.getResourceAccess(oauth.getClientId()).isUserInRole("customer-user")); + assertTrue(refreshedToken.getResourceAccess(oauth.getClientId()).isUserInRole("customer-user")); EventRepresentation refreshEvent = events.expectRefresh(tokenEvent.getDetails().get(Details.REFRESH_TOKEN_ID), sessionId).assertEvent(); Assert.assertNotEquals(tokenEvent.getDetails().get(Details.TOKEN_ID), refreshEvent.getDetails().get(Details.TOKEN_ID));