keycloak-aplcache

add ofline token test

1/29/2018 8:08:13 PM

Details

diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/federation/HardcodedClientStorageProvider.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/federation/HardcodedClientStorageProvider.java
index acf0db8..e56c864 100644
--- a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/federation/HardcodedClientStorageProvider.java
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/federation/HardcodedClientStorageProvider.java
@@ -259,7 +259,10 @@ public class HardcodedClientStorageProvider implements ClientStorageProvider, Cl
 
         @Override
         public Set<RoleModel> getScopeMappings() {
-            return Collections.EMPTY_SET;
+            RoleModel offlineAccess = realm.getRole("offline_access");
+            Set<RoleModel> set = new HashSet<>();
+            set.add(offlineAccess);
+            return set;
         }
 
         @Override
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/ClientStorageTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/ClientStorageTest.java
index eb231db..5656e6e 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/ClientStorageTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/storage/ClientStorageTest.java
@@ -36,10 +36,14 @@ import org.keycloak.models.AuthenticationExecutionModel;
 import org.keycloak.models.AuthenticationFlowBindings;
 import org.keycloak.models.AuthenticationFlowModel;
 import org.keycloak.models.ClientModel;
+import org.keycloak.models.Constants;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.cache.infinispan.ClientAdapter;
+import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.RefreshToken;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.ComponentRepresentation;
+import org.keycloak.representations.idm.EventRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.storage.CacheableStorageProviderModel;
 import org.keycloak.storage.UserStorageProvider;
@@ -59,8 +63,10 @@ import org.keycloak.testsuite.pages.LoginPage;
 import org.keycloak.testsuite.runonserver.RunOnServerDeployment;
 import org.keycloak.testsuite.util.OAuthClient;
 import org.keycloak.util.BasicAuthHelper;
+import org.keycloak.util.TokenUtil;
 import org.openqa.selenium.By;
 
+import javax.ws.rs.NotFoundException;
 import javax.ws.rs.client.Client;
 import javax.ws.rs.client.Entity;
 import javax.ws.rs.client.WebTarget;
@@ -82,6 +88,7 @@ import static org.keycloak.storage.CacheableStorageProviderModel.EVICTION_DAY;
 import static org.keycloak.storage.CacheableStorageProviderModel.EVICTION_HOUR;
 import static org.keycloak.storage.CacheableStorageProviderModel.EVICTION_MINUTE;
 import static org.keycloak.storage.CacheableStorageProviderModel.MAX_LIFESPAN;
+import static org.keycloak.testsuite.admin.ApiUtil.findUserByUsername;
 
 /**
  * Test that clients can override auth flows
@@ -134,6 +141,15 @@ public class ClientStorageTest extends AbstractTestRealmKeycloakTest {
         providerId = addComponent(provider);
     }
 
+    protected String userId;
+
+    @Before
+    public void clientConfiguration() {
+        userId = findUserByUsername(adminClient.realm("test"), "test-user@localhost").getId();
+        oauth.clientId("hardcoded-client");
+    }
+
+
 
 
 
@@ -356,4 +372,81 @@ public class ClientStorageTest extends AbstractTestRealmKeycloakTest {
             realm.updateComponent(model);
         });
     }
+
+    @Test
+    public void offlineTokenDirectGrantFlow() throws Exception {
+        oauth.scope(OAuth2Constants.OFFLINE_ACCESS);
+        oauth.clientId("hardcoded-client");
+        OAuthClient.AccessTokenResponse tokenResponse = oauth.doGrantAccessTokenRequest("password", "test-user@localhost", "password");
+        Assert.assertNull(tokenResponse.getErrorDescription());
+        AccessToken token = oauth.verifyToken(tokenResponse.getAccessToken());
+        String offlineTokenString = tokenResponse.getRefreshToken();
+        RefreshToken offlineToken = oauth.verifyRefreshToken(offlineTokenString);
+
+        events.expectLogin()
+                .client("hardcoded-client")
+                .user(userId)
+                .session(token.getSessionState())
+                .detail(Details.GRANT_TYPE, OAuth2Constants.PASSWORD)
+                .detail(Details.TOKEN_ID, token.getId())
+                .detail(Details.REFRESH_TOKEN_ID, offlineToken.getId())
+                .detail(Details.REFRESH_TOKEN_TYPE, TokenUtil.TOKEN_TYPE_OFFLINE)
+                .detail(Details.USERNAME, "test-user@localhost")
+                .removeDetail(Details.CODE_ID)
+                .removeDetail(Details.REDIRECT_URI)
+                .removeDetail(Details.CONSENT)
+                .assertEvent();
+
+        Assert.assertEquals(TokenUtil.TOKEN_TYPE_OFFLINE, offlineToken.getType());
+        Assert.assertEquals(0, offlineToken.getExpiration());
+
+        testRefreshWithOfflineToken(token, offlineToken, offlineTokenString, token.getSessionState(), userId);
+
+        // Assert same token can be refreshed again
+        testRefreshWithOfflineToken(token, offlineToken, offlineTokenString, token.getSessionState(), userId);
+    }
+
+    private String testRefreshWithOfflineToken(AccessToken oldToken, RefreshToken offlineToken, String offlineTokenString,
+                                               final String sessionId, String userId) {
+        // Change offset to big value to ensure userSession expired
+        setTimeOffset(99999);
+        Assert.assertFalse(oldToken.isActive());
+        Assert.assertTrue(offlineToken.isActive());
+
+        // Assert userSession expired
+        testingClient.testing().removeExpired("test");
+        try {
+            testingClient.testing().removeUserSession("test", sessionId);
+        } catch (NotFoundException nfe) {
+            // Ignore
+        }
+
+        OAuthClient.AccessTokenResponse response = oauth.doRefreshTokenRequest(offlineTokenString, "password");
+        AccessToken refreshedToken = oauth.verifyToken(response.getAccessToken());
+        Assert.assertEquals(200, response.getStatusCode());
+        Assert.assertEquals(sessionId, refreshedToken.getSessionState());
+
+        // Assert new refreshToken in the response
+        String newRefreshToken = response.getRefreshToken();
+        Assert.assertNotNull(newRefreshToken);
+        Assert.assertNotEquals(oldToken.getId(), refreshedToken.getId());
+
+        Assert.assertEquals(userId, refreshedToken.getSubject());
+
+        Assert.assertTrue(refreshedToken.getRealmAccess().isUserInRole(Constants.OFFLINE_ACCESS_ROLE));
+
+
+        EventRepresentation refreshEvent = events.expectRefresh(offlineToken.getId(), sessionId)
+                .client("hardcoded-client")
+                .user(userId)
+                .removeDetail(Details.UPDATED_REFRESH_TOKEN_ID)
+                .detail(Details.REFRESH_TOKEN_TYPE, TokenUtil.TOKEN_TYPE_OFFLINE)
+                .assertEvent();
+        Assert.assertNotEquals(oldToken.getId(), refreshEvent.getDetails().get(Details.TOKEN_ID));
+
+        setTimeOffset(0);
+        return newRefreshToken;
+    }
+
+
 }