keycloak-aplcache

Details

diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java
index d20d09f..7b76083 100644
--- a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java
@@ -19,6 +19,7 @@ package org.keycloak.testsuite.rest;
 
 import org.jboss.resteasy.annotations.cache.NoCache;
 import org.jboss.resteasy.spi.BadRequestException;
+import org.jboss.resteasy.spi.HttpRequest;
 import org.keycloak.common.util.Time;
 import org.keycloak.component.ComponentModel;
 import org.keycloak.events.Event;
@@ -48,6 +49,7 @@ import org.keycloak.representations.idm.AuthDetailsRepresentation;
 import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
 import org.keycloak.representations.idm.EventRepresentation;
 import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.services.managers.AuthenticationManager;
 import org.keycloak.services.managers.RealmManager;
 import org.keycloak.services.resource.RealmResourceProvider;
 import org.keycloak.services.scheduled.ClearExpiredUserSessions;
@@ -78,6 +80,8 @@ import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Cookie;
 import javax.ws.rs.core.Response;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
@@ -96,6 +100,9 @@ public class TestingResourceProvider implements RealmResourceProvider {
     private final KeycloakSession session;
     private final Map<String, TimerProvider.TimerTaskContext> suspendedTimerTasks;
 
+    @Context
+    private HttpRequest request;
+
     @Override
     public Object getResource() {
         return this;
@@ -549,6 +556,15 @@ public class TestingResourceProvider implements RealmResourceProvider {
         return details;
     }
 
+    @GET
+    @Path("/get-sso-cookie")
+    @Produces(MediaType.APPLICATION_JSON)
+    public String getSSOCookieValue() {
+        Map<String, Cookie> cookies = request.getHttpHeaders().getCookies();
+        return cookies.get(AuthenticationManager.KEYCLOAK_IDENTITY_COOKIE).getValue();
+    }
+
+
     @Path("/cache/{cache}")
     public TestCacheResource getCacheResource(@PathParam("cache") String cacheName) {
         return new TestCacheResource(session, cacheName);
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProviderFactory.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProviderFactory.java
index d796c2f..e1a1f30 100644
--- a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProviderFactory.java
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProviderFactory.java
@@ -20,6 +20,7 @@ package org.keycloak.testsuite.rest;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
+import org.jboss.resteasy.spi.ResteasyProviderFactory;
 import org.keycloak.Config.Scope;
 import org.keycloak.models.KeycloakSession;
 import org.keycloak.models.KeycloakSessionFactory;
@@ -36,7 +37,9 @@ public class TestingResourceProviderFactory implements RealmResourceProviderFact
 
     @Override
     public RealmResourceProvider create(KeycloakSession session) {
-        return new TestingResourceProvider(session, suspendedTimerTasks);
+        TestingResourceProvider testProvider = new TestingResourceProvider(session, suspendedTimerTasks);
+        ResteasyProviderFactory.getInstance().injectProperties(testProvider);
+        return testProvider;
     }
 
     @Override
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/KeycloakTestingClient.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/KeycloakTestingClient.java
index 7c61206..57b9afc 100755
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/KeycloakTestingClient.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/KeycloakTestingClient.java
@@ -56,6 +56,10 @@ public class KeycloakTestingClient {
         return new KeycloakTestingClient(serverUrl, null);
     }
 
+    public static KeycloakTestingClient getInstance(String serverUrl, ResteasyClient resteasyClient) {
+        return new KeycloakTestingClient(serverUrl, resteasyClient);
+    }
+
     public TestingResource testing() {
         return target.path("/realms/master").proxy(TestingResource.class);
     }
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingResource.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingResource.java
index 8b551f0..dc6bfaf 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingResource.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingResource.java
@@ -171,6 +171,11 @@ public interface TestingResource {
     @Consumes(MediaType.APPLICATION_JSON)
     void onAdminEvent(final AdminEventRepresentation rep, @QueryParam("includeRepresentation") boolean includeRepresentation);
 
+    @GET
+    @Path("/get-sso-cookie")
+    @Produces(MediaType.APPLICATION_JSON)
+    String getSSOCookieValue();
+
     @POST
     @Path("/remove-user-session")
     @Produces(MediaType.APPLICATION_JSON)
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ImpersonationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ImpersonationTest.java
index 72421cc..c1e0f49 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ImpersonationTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/ImpersonationTest.java
@@ -17,13 +17,18 @@
 
 package org.keycloak.testsuite.admin;
 
+import org.jboss.arquillian.graphene.page.Page;
+import org.jboss.resteasy.client.jaxrs.ResteasyClient;
+import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.keycloak.Config;
 import org.keycloak.admin.client.Keycloak;
+import org.keycloak.admin.client.KeycloakBuilder;
 import org.keycloak.admin.client.resource.ClientResource;
+import org.keycloak.admin.client.resource.RealmResource;
 import org.keycloak.admin.client.resource.UserResource;
 import org.keycloak.events.Details;
 import org.keycloak.events.EventType;
@@ -34,12 +39,17 @@ import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.representations.idm.EventRepresentation;
 import org.keycloak.representations.idm.RealmRepresentation;
 import org.keycloak.representations.idm.RoleRepresentation;
+import org.keycloak.services.managers.AuthenticationManager;
 import org.keycloak.testsuite.AbstractKeycloakTest;
 import org.keycloak.testsuite.AssertEvents;
 import org.keycloak.testsuite.arquillian.AuthServerTestEnricher;
 import org.keycloak.testsuite.auth.page.AuthRealm;
+import org.keycloak.testsuite.client.KeycloakTestingClient;
+import org.keycloak.testsuite.pages.AppPage;
+import org.keycloak.testsuite.pages.LoginPage;
 import org.keycloak.testsuite.util.ClientBuilder;
 import org.keycloak.testsuite.util.CredentialBuilder;
+import org.keycloak.testsuite.util.OAuthClient;
 import org.keycloak.testsuite.util.RealmBuilder;
 import org.keycloak.testsuite.util.UserBuilder;
 
@@ -50,6 +60,7 @@ import java.util.List;
 import java.util.Map;
 import org.junit.Assume;
 import org.junit.BeforeClass;
+import org.openqa.selenium.Cookie;
 
 /**
  * Tests Undertow Adapter
@@ -61,6 +72,12 @@ public class ImpersonationTest extends AbstractKeycloakTest {
     @Rule
     public AssertEvents events = new AssertEvents(this);
 
+    @Page
+    protected AppPage appPage;
+
+    @Page
+    protected LoginPage loginPage;
+
     private String impersonatedUserId;
 
     @Override
@@ -147,25 +164,66 @@ public class ImpersonationTest extends AbstractKeycloakTest {
     }
 
 
-    protected void testSuccessfulImpersonation(String admin, String adminRealm) {
+    // KEYCLOAK-5981
+    @Test
+    public void testImpersonationWorksWhenAuthenticationSessionExists() throws Exception {
+        // Create test client
+        RealmResource realm = adminClient.realms().realm("test");
+        Response resp = realm.clients().create(ClientBuilder.create().clientId("test-app").addRedirectUri(OAuthClient.APP_ROOT + "/*").build());
+        resp.close();
+
+        // Open the URL for the client (will redirect to Keycloak server AuthorizationEndpoint and create authenticationSession)
+        String loginFormUrl = oauth.getLoginFormUrl();
+        driver.navigate().to(loginFormUrl);
+        loginPage.assertCurrent();
+
+        // Impersonate and get SSO cookie. Setup that cookie for webDriver
+        String ssoCookie = testSuccessfulImpersonation("realm-admin", "test");
+        driver.manage().addCookie(new Cookie(AuthenticationManager.KEYCLOAK_IDENTITY_COOKIE, ssoCookie));
+
+        // Open the URL again - should be directly redirected to the app due the SSO login
+        driver.navigate().to(loginFormUrl);
+        appPage.assertCurrent();
+
+        // Remove test client
+        ApiUtil.findClientByClientId(realm, "test-app").remove();
+    }
+
+
+    // Return the SSO cookie from the impersonated session
+    protected String testSuccessfulImpersonation(String admin, String adminRealm) {
+        ResteasyClient resteasyClient = new ResteasyClientBuilder().connectionPoolSize(10).build();
 
-        Keycloak client = login(admin, adminRealm);
+        // Login adminClient
+        Keycloak client = login(admin, adminRealm, resteasyClient);
         try {
-            Map data = client.realms().realm("test").users().get(impersonatedUserId).impersonate();
-            Assert.assertNotNull(data);
-            Assert.assertNotNull(data.get("redirect"));
-
-            events.expect(EventType.IMPERSONATE)
-                    .session(AssertEvents.isUUID())
-                    .user(impersonatedUserId)
-                    .detail(Details.IMPERSONATOR, admin)
-                    .detail(Details.IMPERSONATOR_REALM, adminRealm)
-                    .client((String) null).assertEvent();
+            // Impersonate
+            impersonate(client, admin, adminRealm);
+
+            // Get the SSO cookie. Needs to use same RestEasyClient used by adminClient to be able to see the cookies
+            KeycloakTestingClient testingClient = KeycloakTestingClient.getInstance(AuthServerTestEnricher.getAuthServerContextRoot() + "/auth", resteasyClient);
+            String kcIdentity = testingClient.testing("test").getSSOCookieValue();
+            Assert.assertNotNull(kcIdentity);
+
+            return kcIdentity;
         } finally {
-            client.close();
+            resteasyClient.close();
         }
     }
 
+    private void impersonate(Keycloak adminClient, String admin, String adminRealm) {
+        Map data = adminClient.realms().realm("test").users().get(impersonatedUserId).impersonate();
+        Assert.assertNotNull(data);
+        Assert.assertNotNull(data.get("redirect"));
+
+        events.expect(EventType.IMPERSONATE)
+                .session(AssertEvents.isUUID())
+                .user(impersonatedUserId)
+                .detail(Details.IMPERSONATOR, admin)
+                .detail(Details.IMPERSONATOR_REALM, adminRealm)
+                .client((String) null).assertEvent();
+    }
+
     protected void testForbiddenImpersonation(String admin, String adminRealm) {
         Keycloak client = createAdminClient(adminRealm, establishClientId(adminRealm), admin);
         try {
@@ -178,24 +236,30 @@ public class ImpersonationTest extends AbstractKeycloakTest {
     }
 
     Keycloak createAdminClient(String realm, String clientId, String username) {
-        return createAdminClient(realm, clientId, username, null);
+        return createAdminClient(realm, clientId, username, null, null);
     }
 
     String establishClientId(String realm) {
         return realm.equals("master") ? Constants.ADMIN_CLI_CLIENT_ID : "myclient";
     }
 
-    Keycloak createAdminClient(String realm, String clientId, String username, String password) {
+    Keycloak createAdminClient(String realm, String clientId, String username, String password, ResteasyClient resteasyClient) {
         if (password == null) {
             password = username.equals("admin") ? "admin" : "password";
         }
-        return Keycloak.getInstance(AuthServerTestEnricher.getAuthServerContextRoot() + "/auth",
-                realm, username, password, clientId);
+
+        return KeycloakBuilder.builder().serverUrl(AuthServerTestEnricher.getAuthServerContextRoot() + "/auth")
+                .realm(realm)
+                .username(username)
+                .password(password)
+                .clientId(clientId)
+                .resteasyClient(resteasyClient)
+                .build();
     }
 
-    private Keycloak login(String username, String realm) {
+    private Keycloak login(String username, String realm, ResteasyClient resteasyClient) {
         String clientId = establishClientId(realm);
-        Keycloak client = createAdminClient(realm, clientId, username);
+        Keycloak client = createAdminClient(realm, clientId, username, null, resteasyClient);
 
         client.tokenManager().grantToken();
         // only poll for LOGIN event if realm is not master