KEYCLOAK-5981 Test Impersonation works when authenticationSession exists
This commit is contained in:
parent
63efee6e15
commit
b8416dfa3e
5 changed files with 111 additions and 19 deletions
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
||||
Keycloak client = login(admin, adminRealm);
|
||||
// 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();
|
||||
|
||||
// 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"));
|
||||
// Impersonate
|
||||
impersonate(client, admin, adminRealm);
|
||||
|
||||
events.expect(EventType.IMPERSONATE)
|
||||
.session(AssertEvents.isUUID())
|
||||
.user(impersonatedUserId)
|
||||
.detail(Details.IMPERSONATOR, admin)
|
||||
.detail(Details.IMPERSONATOR_REALM, adminRealm)
|
||||
.client((String) null).assertEvent();
|
||||
// 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
|
||||
|
|
Loading…
Reference in a new issue