Merge pull request #2677 from stianst/KEYCLOAK-2850

KEYCLOAK-2850 Migrated ImpersonationTest and added builders
This commit is contained in:
Stian Thorgersen 2016-04-20 14:48:05 +02:00
commit b6ed681402
10 changed files with 578 additions and 221 deletions

View file

@ -129,7 +129,7 @@ public abstract class AbstractKeycloakTest {
private boolean resetTimeOffset; private boolean resetTimeOffset;
@Before @Before
public void beforeAbstractKeycloakTest() { public void beforeAbstractKeycloakTest() throws Exception {
adminClient = Keycloak.getInstance(AuthServerTestEnricher.getAuthServerContextRoot() + "/auth", adminClient = Keycloak.getInstance(AuthServerTestEnricher.getAuthServerContextRoot() + "/auth",
MASTER, ADMIN, ADMIN, Constants.ADMIN_CLI_CLIENT_ID); MASTER, ADMIN, ADMIN, Constants.ADMIN_CLI_CLIENT_ID);
deleteMeOAuthClient = new DeleteMeOAuthClient(AuthServerTestEnricher.getAuthServerContextRoot() + "/auth"); deleteMeOAuthClient = new DeleteMeOAuthClient(AuthServerTestEnricher.getAuthServerContextRoot() + "/auth");

View file

@ -64,7 +64,6 @@ public class AssertEvents {
private RealmRepresentation realmRep; private RealmRepresentation realmRep;
private AbstractKeycloakTest context; private AbstractKeycloakTest context;
private PublicKey realmPublicKey; private PublicKey realmPublicKey;
private UserRepresentation defaultUser;
public AssertEvents(AbstractKeycloakTest ctx) throws Exception { public AssertEvents(AbstractKeycloakTest ctx) throws Exception {
context = ctx; context = ctx;
@ -74,11 +73,6 @@ public class AssertEvents {
String pubKeyString = realmRep.getPublicKey(); String pubKeyString = realmRep.getPublicKey();
realmPublicKey = PemUtils.decodePublicKey(pubKeyString); realmPublicKey = PemUtils.decodePublicKey(pubKeyString);
defaultUser = getUser(DEFAULT_USERNAME);
if (defaultUser == null) {
throw new RuntimeException("Default user does not exist: " + DEFAULT_USERNAME + ". Make sure to add it to your test realm.");
}
defaultEventsQueueUri = getAuthServerEventsQueueUri(); defaultEventsQueueUri = getAuthServerEventsQueueUri();
} }
@ -192,7 +186,7 @@ public class AssertEvents {
return new ExpectedEvent() return new ExpectedEvent()
.realm(realmRep.getId()) .realm(realmRep.getId())
.client(DEFAULT_CLIENT_ID) .client(DEFAULT_CLIENT_ID)
.user(defaultUser.getId()) .user(defaultUserId())
.ipAddress(DEFAULT_IP_ADDRESS) .ipAddress(DEFAULT_IP_ADDRESS)
.session((String) null) .session((String) null)
.event(event); .event(event);
@ -357,6 +351,34 @@ public class AssertEvents {
}; };
} }
public Matcher<String> defaultUserId() {
return new TypeSafeMatcher<String>() {
private String userId;
@Override
protected boolean matchesSafely(String item) {
return item.equals(getUserId());
}
@Override
public void describeTo(Description description) {
description.appendText(getUserId());
}
private String getUserId() {
if (userId == null) {
UserRepresentation user = getUser(DEFAULT_USERNAME);
if (user == null) {
throw new RuntimeException("Default user does not exist: " + DEFAULT_USERNAME + ". Make sure to add it to your test realm.");
}
userId = user.getId();
}
return userId;
}
};
}
private EventRepresentation fetchNextEvent() { private EventRepresentation fetchNextEvent() {
CloseableHttpClient httpclient = HttpClients.createDefault(); CloseableHttpClient httpclient = HttpClients.createDefault();
try { try {

View file

@ -19,6 +19,7 @@ package org.keycloak.testsuite.admin;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.admin.client.resource.ClientResource; import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.admin.client.resource.RealmResource; import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.admin.client.resource.RoleResource;
import org.keycloak.admin.client.resource.UserResource; import org.keycloak.admin.client.resource.UserResource;
import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.CredentialRepresentation; import org.keycloak.representations.idm.CredentialRepresentation;
@ -85,6 +86,10 @@ public class ApiUtil {
return null; return null;
} }
public static RoleResource findClientRoleByName(ClientResource client, String role) {
return client.roles().get(role);
}
public static UserRepresentation findUserByUsername(RealmResource realm, String username) { public static UserRepresentation findUserByUsername(RealmResource realm, String username) {
UserRepresentation user = null; UserRepresentation user = null;
List<UserRepresentation> ur = realm.users().search(username, null, null); List<UserRepresentation> ur = realm.users().search(username, null, null);

View file

@ -0,0 +1,206 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.admin;
import org.junit.Assert;
import org.junit.Test;
import org.keycloak.Config;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.admin.client.resource.UserResource;
import org.keycloak.events.Details;
import org.keycloak.events.EventType;
import org.keycloak.models.AdminRoles;
import org.keycloak.models.Constants;
import org.keycloak.models.ImpersonationConstants;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.services.resources.admin.AdminRoot;
import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.AssertEvents;
import org.keycloak.testsuite.util.ClientBuilder;
import org.keycloak.testsuite.util.CredentialBuilder;
import org.keycloak.testsuite.util.OAuthClient.AccessTokenResponse;
import org.keycloak.testsuite.util.RealmBuilder;
import org.keycloak.testsuite.util.UserBuilder;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.client.ClientRequestFilter;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* Tests Undertow Adapter
*
* @author <a href="mailto:bburke@redhat.com">Bill Burke</a>
*/
public class ImpersonationTest extends AbstractKeycloakTest {
private AssertEvents events;
private String impersonatedUserId;
@Override
public void beforeAbstractKeycloakTest() throws Exception {
super.beforeAbstractKeycloakTest();
events = new AssertEvents(this);
}
@Override
public void addTestRealms(List<RealmRepresentation> testRealms) {
RealmBuilder realm = RealmBuilder.create().name("test").testEventListener();
realm.client(ClientBuilder.create().clientId("myclient").publicClient().directAccessGrants());
impersonatedUserId = KeycloakModelUtils.generateId();
realm.user(UserBuilder.create().id(impersonatedUserId).username("test-user@localhost"));
realm.user(UserBuilder.create().username("realm-admin").password("password").role(Constants.REALM_MANAGEMENT_CLIENT_ID, AdminRoles.REALM_ADMIN));
realm.user(UserBuilder.create().username("impersonator").password("password").role(Constants.REALM_MANAGEMENT_CLIENT_ID, ImpersonationConstants.IMPERSONATION_ROLE).role(Constants.REALM_MANAGEMENT_CLIENT_ID, AdminRoles.VIEW_USERS));
realm.user(UserBuilder.create().username("bad-impersonator").password("password").role(Constants.REALM_MANAGEMENT_CLIENT_ID, AdminRoles.MANAGE_USERS));
testRealms.add(realm.build());
}
private String createAdminToken(String username, String realm) {
try {
String password = username.equals("admin") ? "admin" : "password";
String clientId = realm.equals("master") ? Constants.ADMIN_CLI_CLIENT_ID : "myclient";
AccessTokenResponse tokenResponse = oauthClient.doGrantAccessTokenRequest(realm, username, password, null, clientId, null);
if (tokenResponse.getStatusCode() != 200) {
throw new RuntimeException("Failed to get token: " + tokenResponse.getErrorDescription());
}
events.clear();
return tokenResponse.getAccessToken();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Test
public void testImpersonateByMasterAdmin() {
// test that composite is set up right for impersonation role
testSuccessfulImpersonation("admin", Config.getAdminRealm());
}
@Test
public void testImpersonateByMasterImpersonator() {
Response response = adminClient.realm("master").users().create(UserBuilder.create().username("master-impersonator").build());
String userId = ApiUtil.getCreatedId(response);
response.close();
UserResource user = adminClient.realm("master").users().get(userId);
user.resetPassword(CredentialBuilder.create().password("password").build());
ClientResource testRealmClient = ApiUtil.findClientResourceByClientId(adminClient.realm("master"), "test-realm");
List<RoleRepresentation> roles = new LinkedList<>();
roles.add(ApiUtil.findClientRoleByName(testRealmClient, AdminRoles.VIEW_USERS).toRepresentation());
roles.add(ApiUtil.findClientRoleByName(testRealmClient, ImpersonationConstants.IMPERSONATION_ROLE).toRepresentation());
user.roles().clientLevel(testRealmClient.toRepresentation().getId()).add(roles);
testSuccessfulImpersonation("master-impersonator", Config.getAdminRealm());
adminClient.realm("master").users().get(userId).remove();
}
@Test
public void testImpersonateByTestImpersonator() {
testSuccessfulImpersonation("impersonator", "test");
}
@Test
public void testImpersonateByTestAdmin() {
// test that composite is set up right for impersonation role
testSuccessfulImpersonation("realm-admin", "test");
}
@Test
public void testImpersonateByTestBadImpersonator() {
testForbiddenImpersonation("bad-impersonator", "test");
}
@Test
public void testImpersonateByMastertBadImpersonator() {
Response response = adminClient.realm("master").users().create(UserBuilder.create().username("master-bad-impersonator").build());
String userId = ApiUtil.getCreatedId(response);
response.close();
adminClient.realm("master").users().get(userId).resetPassword(CredentialBuilder.create().password("password").build());
testForbiddenImpersonation("master-bad-impersonator", Config.getAdminRealm());
adminClient.realm("master").users().get(userId).remove();
}
protected void testSuccessfulImpersonation(String admin, String adminRealm) {
Client client = createClient(admin, adminRealm);
WebTarget impersonate = createImpersonateTarget(client);
Map data = impersonate.request().post(null, Map.class);
Assert.assertNotNull(data);
Assert.assertNotNull(data.get("redirect"));
// TODO Events not working
events.expect(EventType.IMPERSONATE)
.session(AssertEvents.isUUID())
.user(impersonatedUserId)
.detail(Details.IMPERSONATOR, admin)
.detail(Details.IMPERSONATOR_REALM, adminRealm)
.client((String) null).assertEvent();
client.close();
}
protected void testForbiddenImpersonation(String admin, String adminRealm) {
Client client = createClient(admin, adminRealm);
WebTarget impersonate = createImpersonateTarget(client);
Response response = impersonate.request().post(null);
response.close();
client.close();
}
protected WebTarget createImpersonateTarget(Client client) {
UriBuilder authBase = UriBuilder.fromUri(getAuthServerRoot());
WebTarget adminRealms = client.target(AdminRoot.realmsUrl(authBase));
WebTarget realmTarget = adminRealms.path("test");
return realmTarget.path("users").path(impersonatedUserId).path("impersonation");
}
protected Client createClient(String admin, String adminRealm) {
String token = createAdminToken(admin, adminRealm);
final String authHeader = "Bearer " + token;
ClientRequestFilter authFilter = new ClientRequestFilter() {
@Override
public void filter(ClientRequestContext requestContext) throws IOException {
requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader);
}
};
return javax.ws.rs.client.ClientBuilder.newBuilder().register(authFilter).build();
}
}

View file

@ -0,0 +1,66 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.util;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class ClientBuilder {
private ClientRepresentation rep = new ClientRepresentation();
public static ClientBuilder create() {
return new ClientBuilder();
}
private ClientBuilder() {
rep.setEnabled(true);
}
public ClientBuilder id(String id) {
rep.setId(id);
return this;
}
public ClientBuilder clientId(String clientId) {
rep.setClientId(clientId);
return this;
}
public ClientBuilder publicClient() {
rep.setPublicClient(true);
return this;
}
public ClientBuilder directAccessGrants() {
rep.setDirectAccessGrantsEnabled(true);
return this;
}
public ClientRepresentation build() {
return rep;
}
}

View file

@ -0,0 +1,51 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.util;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class CredentialBuilder {
private CredentialRepresentation rep = new CredentialRepresentation();
public static CredentialBuilder create() {
return new CredentialBuilder();
}
private CredentialBuilder() {
}
public CredentialBuilder password(String password) {
rep.setType(CredentialRepresentation.PASSWORD);
rep.setValue(password);
return this;
}
public CredentialRepresentation build() {
return rep;
}
}

View file

@ -0,0 +1,83 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.util;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import java.util.LinkedList;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class RealmBuilder {
private RealmRepresentation rep = new RealmRepresentation();
public static RealmBuilder create() {
return new RealmBuilder();
}
private RealmBuilder() {
rep.setEnabled(true);
}
public RealmBuilder name(String name) {
rep.setRealm(name);
return this;
}
public RealmBuilder testEventListener() {
if (rep.getEventsListeners() == null) {
rep.setEventsListeners(new LinkedList<String>());
}
rep.getEventsListeners().add("event-queue");
return this;
}
public RealmBuilder client(ClientBuilder client) {
return client(client.build());
}
public RealmBuilder client(ClientRepresentation client) {
if (rep.getClients() == null) {
rep.setClients(new LinkedList<ClientRepresentation>());
}
rep.getClients().add(client);
return this;
}
public RealmBuilder user(UserBuilder user) {
return user(user.build());
}
public RealmBuilder user(UserRepresentation user) {
if (rep.getUsers() == null) {
rep.setUsers(new LinkedList<UserRepresentation>());
}
rep.getUsers().add(user);
return this;
}
public RealmRepresentation build() {
return rep;
}
}

View file

@ -0,0 +1,50 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.util;
import org.keycloak.representations.idm.RoleRepresentation;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class RoleBuilder {
private RoleRepresentation rep = new RoleRepresentation();
public static RoleBuilder create() {
return new RoleBuilder();
}
private RoleBuilder() {
}
public RoleBuilder id(String id) {
rep.setId(id);
return this;
}
public RoleBuilder name(String name) {
rep.setName(name);
return this;
}
public RoleRepresentation build() {
return rep;
}
}

View file

@ -0,0 +1,87 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.util;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class UserBuilder {
private UserRepresentation rep = new UserRepresentation();
public static UserBuilder create() {
return new UserBuilder();
}
private UserBuilder() {
rep.setEnabled(true);
}
public UserBuilder id(String id) {
rep.setId(id);
return this;
}
public UserBuilder username(String username) {
rep.setUsername(username);
return this;
}
public UserBuilder password(String password) {
if (rep.getCredentials() == null) {
rep.setCredentials(new LinkedList<CredentialRepresentation>());
}
CredentialRepresentation credential = new CredentialRepresentation();
credential.setType(CredentialRepresentation.PASSWORD);
credential.setValue(password);
rep.getCredentials().add(credential);
return this;
}
public UserBuilder role(String role) {
if (rep.getRealmRoles() == null) {
rep.setRealmRoles(new LinkedList<String>());
}
return this;
}
public UserBuilder role(String client, String role) {
if (rep.getClientRoles() == null) {
rep.setClientRoles(new HashMap<String, List<String>>());
}
if (rep.getClientRoles().get(client) == null) {
rep.getClientRoles().put(client, new LinkedList<String>());
}
rep.getClientRoles().get(client).add(role);
return this;
}
public UserRepresentation build() {
return rep;
}
}

View file

@ -1,213 +0,0 @@
/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.admin;
import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.keycloak.Config;
import org.keycloak.events.Details;
import org.keycloak.events.EventType;
import org.keycloak.models.AdminRoles;
import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.Constants;
import org.keycloak.models.ImpersonationConstants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.protocol.oidc.TokenManager;
import org.keycloak.representations.AccessToken;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.resources.admin.AdminRoot;
import org.keycloak.testsuite.AssertEvents;
import org.keycloak.testsuite.rule.KeycloakRule;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.client.ClientRequestFilter;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import java.io.IOException;
import java.util.Map;
/**
* Tests Undertow Adapter
*
* @author <a href="mailto:bburke@redhat.com">Bill Burke</a>
*/
public class ImpersonationTest {
static String impersonatedUserId;
@ClassRule
public static KeycloakRule keycloakRule = new KeycloakRule( new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
impersonatedUserId = manager.getSession().users().getUserByUsername("test-user@localhost", appRealm).getId();
{
UserModel masterImpersonator = manager.getSession().users().addUser(adminstrationRealm, "master-impersonator");
masterImpersonator.setEnabled(true);
ClientModel adminRealmClient = adminstrationRealm.getClientByClientId(KeycloakModelUtils.getMasterRealmAdminApplicationClientId(appRealm.getName()));
RoleModel masterManageUsersRole = adminRealmClient.getRole(AdminRoles.MANAGE_USERS);
masterImpersonator.grantRole(masterManageUsersRole);
RoleModel masterImpersonatorRole = adminRealmClient.getRole(ImpersonationConstants.IMPERSONATION_ROLE);
masterImpersonator.grantRole(masterImpersonatorRole);
}
{
UserModel masterBadImpersonator = manager.getSession().users().addUser(adminstrationRealm, "master-bad-impersonator");
masterBadImpersonator.setEnabled(true);
}
{
UserModel impersonator = manager.getSession().users().addUser(appRealm, "impersonator");
impersonator.setEnabled(true);
ClientModel appRealmClient = appRealm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
RoleModel masterManageUsersRole = appRealmClient.getRole(AdminRoles.MANAGE_USERS);
impersonator.grantRole(masterManageUsersRole);
RoleModel realmImpersonatorRole = appRealmClient.getRole(ImpersonationConstants.IMPERSONATION_ROLE);
impersonator.grantRole(realmImpersonatorRole);
}
{
UserModel impersonator = manager.getSession().users().addUser(appRealm, "realm-admin");
impersonator.setEnabled(true);
ClientModel appRealmClient = appRealm.getClientByClientId(Constants.REALM_MANAGEMENT_CLIENT_ID);
RoleModel realmImpersonatorRole = appRealmClient.getRole(AdminRoles.REALM_ADMIN);
impersonator.grantRole(realmImpersonatorRole);
}
{
UserModel badimpersonator = manager.getSession().users().addUser(appRealm, "bad-impersonator");
badimpersonator.setEnabled(true);
}
}
});
@Rule
public AssertEvents events = new AssertEvents(keycloakRule);
private static String createAdminToken(String username, String realm) {
KeycloakSession session = keycloakRule.startSession();
try {
RealmManager manager = new RealmManager(session);
RealmModel adminRealm = manager.getRealm(realm);
ClientModel adminConsole = adminRealm.getClientByClientId(Constants.ADMIN_CLI_CLIENT_ID);
TokenManager tm = new TokenManager();
UserModel admin = session.users().getUserByUsername(username, adminRealm);
ClientSessionModel clientSession = session.sessions().createClientSession(adminRealm, adminConsole);
clientSession.setNote(OIDCLoginProtocol.ISSUER, "http://localhost:8081/auth/realms/" + realm);
UserSessionModel userSession = session.sessions().createUserSession(adminRealm, admin, "admin", null, "form", false, null, null);
AccessToken token = tm.createClientAccessToken(session, tm.getAccess(null, true, adminConsole, admin), adminRealm, adminConsole, admin, userSession, clientSession);
return tm.encodeToken(adminRealm, token);
} finally {
keycloakRule.stopSession(session, true);
}
}
@Test
public void testImpersonateByMasterAdmin() {
// test that composite is set up right for impersonation role
testSuccessfulImpersonation("admin", Config.getAdminRealm());
}
@Test
public void testImpersonateByMasterImpersonator() {
testSuccessfulImpersonation("master-impersonator", Config.getAdminRealm());
}
@Test
public void testImpersonateByTestImpersonator() {
testSuccessfulImpersonation("impersonator", "test");
}
@Test
public void testImpersonateByTestAdmin() {
// test that composite is set up right for impersonation role
testSuccessfulImpersonation("realm-admin", "test");
}
@Test
public void testImpersonateByTestBadImpersonator() {
testForbiddenImpersonation("bad-impersonator", "test");
}
@Test
public void testImpersonateByMastertBadImpersonator() {
testForbiddenImpersonation("master-bad-impersonator", Config.getAdminRealm());
}
protected void testSuccessfulImpersonation(String admin, String adminRealm) {
Client client = createClient(admin, adminRealm);
WebTarget impersonate = createImpersonateTarget(client);
Map data = impersonate.request().post(null, Map.class);
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();
client.close();
}
protected void testForbiddenImpersonation(String admin, String adminRealm) {
Client client = createClient(admin, adminRealm);
WebTarget impersonate = createImpersonateTarget(client);
Response response = impersonate.request().post(null);
response.close();
client.close();
}
protected WebTarget createImpersonateTarget(Client client) {
UriBuilder authBase = UriBuilder.fromUri("http://localhost:8081/auth");
WebTarget adminRealms = client.target(AdminRoot.realmsUrl(authBase));
WebTarget realmTarget = adminRealms.path("test");
return realmTarget.path("users").path(impersonatedUserId).path("impersonation");
}
protected Client createClient(String admin, String adminRealm) {
String token = createAdminToken(admin, adminRealm);
final String authHeader = "Bearer " + token;
ClientRequestFilter authFilter = new ClientRequestFilter() {
@Override
public void filter(ClientRequestContext requestContext) throws IOException {
requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader);
}
};
return ClientBuilder.newBuilder().register(authFilter).build();
}
}