Merge pull request #2677 from stianst/KEYCLOAK-2850
KEYCLOAK-2850 Migrated ImpersonationTest and added builders
This commit is contained in:
commit
b6ed681402
10 changed files with 578 additions and 221 deletions
|
@ -129,7 +129,7 @@ public abstract class AbstractKeycloakTest {
|
|||
private boolean resetTimeOffset;
|
||||
|
||||
@Before
|
||||
public void beforeAbstractKeycloakTest() {
|
||||
public void beforeAbstractKeycloakTest() throws Exception {
|
||||
adminClient = Keycloak.getInstance(AuthServerTestEnricher.getAuthServerContextRoot() + "/auth",
|
||||
MASTER, ADMIN, ADMIN, Constants.ADMIN_CLI_CLIENT_ID);
|
||||
deleteMeOAuthClient = new DeleteMeOAuthClient(AuthServerTestEnricher.getAuthServerContextRoot() + "/auth");
|
||||
|
|
|
@ -64,7 +64,6 @@ public class AssertEvents {
|
|||
private RealmRepresentation realmRep;
|
||||
private AbstractKeycloakTest context;
|
||||
private PublicKey realmPublicKey;
|
||||
private UserRepresentation defaultUser;
|
||||
|
||||
public AssertEvents(AbstractKeycloakTest ctx) throws Exception {
|
||||
context = ctx;
|
||||
|
@ -74,11 +73,6 @@ public class AssertEvents {
|
|||
String pubKeyString = realmRep.getPublicKey();
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -192,7 +186,7 @@ public class AssertEvents {
|
|||
return new ExpectedEvent()
|
||||
.realm(realmRep.getId())
|
||||
.client(DEFAULT_CLIENT_ID)
|
||||
.user(defaultUser.getId())
|
||||
.user(defaultUserId())
|
||||
.ipAddress(DEFAULT_IP_ADDRESS)
|
||||
.session((String) null)
|
||||
.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() {
|
||||
CloseableHttpClient httpclient = HttpClients.createDefault();
|
||||
try {
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.keycloak.testsuite.admin;
|
|||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.admin.client.resource.ClientResource;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.admin.client.resource.RoleResource;
|
||||
import org.keycloak.admin.client.resource.UserResource;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.CredentialRepresentation;
|
||||
|
@ -85,6 +86,10 @@ public class ApiUtil {
|
|||
return null;
|
||||
}
|
||||
|
||||
public static RoleResource findClientRoleByName(ClientResource client, String role) {
|
||||
return client.roles().get(role);
|
||||
}
|
||||
|
||||
public static UserRepresentation findUserByUsername(RealmResource realm, String username) {
|
||||
UserRepresentation user = null;
|
||||
List<UserRepresentation> ur = realm.users().search(username, null, null);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue