keycloak-aplcache

Details

diff --git a/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java b/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java
index ad294fd..5092ce2 100644
--- a/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java
+++ b/services/src/main/java/org/keycloak/authorization/authorization/AuthorizationTokenService.java
@@ -65,6 +65,7 @@ import org.keycloak.models.ClientSessionContext;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserSessionModel;
+import org.keycloak.models.UserSessionProvider;
 import org.keycloak.protocol.oidc.TokenManager;
 import org.keycloak.protocol.oidc.TokenManager.AccessTokenResponseBuilder;
 import org.keycloak.representations.AccessToken;
@@ -239,7 +240,13 @@ public class AuthorizationTokenService {
         KeycloakSession keycloakSession = request.getKeycloakSession();
         AccessToken accessToken = identity.getAccessToken();
         RealmModel realm = request.getRealm();
-        UserSessionModel userSessionModel = keycloakSession.sessions().getUserSession(realm, accessToken.getSessionState());
+        UserSessionProvider sessions = keycloakSession.sessions();
+        UserSessionModel userSessionModel = sessions.getUserSession(realm, accessToken.getSessionState());
+
+        if (userSessionModel == null) {
+            userSessionModel = sessions.getOfflineUserSession(realm, accessToken.getSessionState());
+        }
+
         ClientModel client = realm.getClientByClientId(accessToken.getIssuedFor());
         AuthenticatedClientSessionModel clientSession = userSessionModel.getAuthenticatedClientSessionByClient(client.getId());
         ClientSessionContext clientSessionCtx = DefaultClientSessionContext.fromClientSessionScopeParameter(clientSession);
diff --git a/services/src/main/java/org/keycloak/authorization/common/KeycloakIdentity.java b/services/src/main/java/org/keycloak/authorization/common/KeycloakIdentity.java
index 6393dc8..3eb4454 100644
--- a/services/src/main/java/org/keycloak/authorization/common/KeycloakIdentity.java
+++ b/services/src/main/java/org/keycloak/authorization/common/KeycloakIdentity.java
@@ -32,6 +32,7 @@ import org.keycloak.models.RealmModel;
 import org.keycloak.models.RoleModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.models.UserSessionModel;
+import org.keycloak.models.UserSessionProvider;
 import org.keycloak.protocol.oidc.TokenManager;
 import org.keycloak.representations.AccessToken;
 import org.keycloak.representations.IDToken;
@@ -116,7 +117,13 @@ public class KeycloakIdentity implements Identity {
             if (token instanceof AccessToken) {
                 this.accessToken = AccessToken.class.cast(token);
             } else {
-                UserSessionModel userSession = keycloakSession.sessions().getUserSession(realm, token.getSessionState());
+                UserSessionProvider sessions = keycloakSession.sessions();
+                UserSessionModel userSession = sessions.getUserSession(realm, token.getSessionState());
+
+                if (userSession == null) {
+                    userSession = sessions.getOfflineUserSession(realm, token.getSessionState());
+                }
+
                 ClientModel client = realm.getClientByClientId(token.getIssuedFor());
                 AuthenticatedClientSessionModel clientSessionModel = userSession.getAuthenticatedClientSessions().get(client.getId());
 
@@ -252,7 +259,13 @@ public class KeycloakIdentity implements Identity {
     }
 
     private UserModel getUserFromSessionState() {
-        UserSessionModel userSession = keycloakSession.sessions().getUserSession(realm, accessToken.getSessionState());
+        UserSessionProvider sessions = keycloakSession.sessions();
+        UserSessionModel userSession = sessions.getUserSession(realm, accessToken.getSessionState());
+
+        if (userSession == null) {
+            userSession = sessions.getOfflineUserSession(realm, accessToken.getSessionState());
+        }
+
         return userSession.getUser();
     }
 }
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/EntitlementAPITest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/EntitlementAPITest.java
index da2e3a8..d89748c 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/EntitlementAPITest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/EntitlementAPITest.java
@@ -36,6 +36,8 @@ import java.util.Set;
 import java.util.function.Supplier;
 
 import org.hamcrest.Matchers;
+import org.jboss.arquillian.container.test.api.ContainerController;
+import org.jboss.arquillian.test.api.ArquillianResource;
 import org.jetbrains.annotations.NotNull;
 import org.junit.After;
 import org.junit.Before;
@@ -48,11 +50,13 @@ import org.keycloak.admin.client.resource.RealmResource;
 import org.keycloak.authorization.client.AuthorizationDeniedException;
 import org.keycloak.authorization.client.AuthzClient;
 import org.keycloak.authorization.client.Configuration;
+import org.keycloak.authorization.client.representation.TokenIntrospectionResponse;
 import org.keycloak.authorization.client.util.HttpResponseException;
 import org.keycloak.common.util.Base64Url;
 import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.representations.AccessToken;
 import org.keycloak.representations.AccessToken.Authorization;
+import org.keycloak.representations.AccessTokenResponse;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.idm.authorization.AuthorizationRequest;
@@ -92,12 +96,16 @@ public class EntitlementAPITest extends AbstractAuthzTest {
 
     private AuthzClient authzClient;
 
+    @ArquillianResource
+    protected ContainerController controller;
+
     @Override
     public void addTestRealms(List<RealmRepresentation> testRealms) {
         testRealms.add(RealmBuilder.create().name("authz-test")
                 .roles(RolesBuilder.create().realmRole(RoleBuilder.create().name("uma_authorization").build()))
                 .user(UserBuilder.create().username("marta").password("password").addRoles("uma_authorization"))
                 .user(UserBuilder.create().username("kolo").password("password"))
+                .user(UserBuilder.create().username("offlineuser").password("password").addRoles("offline_access"))
                 .client(ClientBuilder.create().clientId(RESOURCE_SERVER_TEST)
                         .secret("secret")
                         .authorizationServicesEnabled(true)
@@ -1155,6 +1163,51 @@ public class EntitlementAPITest extends AbstractAuthzTest {
         }
     }
 
+    @Test
+    public void testOfflineRequestingPartyToken() throws Exception {
+        ClientResource client = getClient(getRealm(), RESOURCE_SERVER_TEST);
+        AuthorizationResource authorization = client.authorization();
+
+        JSPolicyRepresentation policy = new JSPolicyRepresentation();
+
+        policy.setName(KeycloakModelUtils.generateId());
+        policy.setCode("$evaluation.grant();");
+
+        authorization.policies().js().create(policy).close();
+
+        ResourceRepresentation resource = new ResourceRepresentation();
+
+        resource.setName("Sensors");
+        resource.addScope("sensors:view", "sensors:update", "sensors:delete");
+
+        resource = authorization.resources().create(resource).readEntity(ResourceRepresentation.class);
+
+        ScopePermissionRepresentation permission = new ScopePermissionRepresentation();
+
+        permission.setName("View Sensor");
+        permission.addScope("sensors:view");
+        permission.addPolicy(policy.getName());
+
+        authorization.permissions().scope().create(permission);
+
+        String accessToken = new OAuthClient().realm("authz-test").clientId(RESOURCE_SERVER_TEST).scope("offline_access").doGrantAccessTokenRequest("secret", "offlineuser", "password").getAccessToken();
+        AuthzClient authzClient = getAuthzClient(AUTHZ_CLIENT_CONFIG);
+        AccessTokenResponse response = authzClient.authorization(accessToken).authorize();
+        assertNotNull(response.getToken());
+
+        controller.stop(suiteContext.getAuthServerInfo().getQualifier());
+        controller.start(suiteContext.getAuthServerInfo().getQualifier());
+        reconnectAdminClient();
+
+        TokenIntrospectionResponse introspectionResponse = authzClient.protection().introspectRequestingPartyToken(response.getToken());
+
+        assertTrue(introspectionResponse.getActive());
+        assertFalse(introspectionResponse.getPermissions().isEmpty());
+
+        response = authzClient.authorization(accessToken).authorize();
+        assertNotNull(response.getToken());
+    }
+
     private void testRptRequestWithResourceName(String configFile) {
         Metadata metadata = new Metadata();