KEYCLOAK-2881 Admin events testing

This commit is contained in:
mposolda 2016-05-10 12:07:11 +02:00
parent 7193b54419
commit fc9dbcf6cb
35 changed files with 1646 additions and 313 deletions

View file

@ -30,6 +30,7 @@ import java.util.concurrent.LinkedBlockingQueue;
public class EventsListenerProvider implements EventListenerProvider {
private static final BlockingQueue<Event> events = new LinkedBlockingQueue<Event>();
private static final BlockingQueue<AdminEvent> adminEvents = new LinkedBlockingQueue<>();
@Override
public void onEvent(Event event) {
@ -38,7 +39,8 @@ public class EventsListenerProvider implements EventListenerProvider {
@Override
public void onEvent(AdminEvent event, boolean includeRepresentation) {
// TODO: implement if needed
// Save the copy for case when same AdminEventBuilder is used more times during same transaction to avoid overwriting previously referenced event
adminEvents.add(copy(event));
}
@Override
@ -46,7 +48,31 @@ public class EventsListenerProvider implements EventListenerProvider {
}
public static BlockingQueue<Event> getInstance() {
return events;
public static Event poll() {
return events.poll();
}
public static AdminEvent pollAdminEvent() {
return adminEvents.poll();
}
public static void clear() {
events.clear();
}
public static void clearAdminEvents() {
adminEvents.clear();
}
private AdminEvent copy(AdminEvent adminEvent) {
AdminEvent newEvent = new AdminEvent();
newEvent.setAuthDetails(adminEvent.getAuthDetails());
newEvent.setError(adminEvent.getError());
newEvent.setOperationType(adminEvent.getOperationType());
newEvent.setRealmId(adminEvent.getRealmId());
newEvent.setRepresentation(adminEvent.getRepresentation());
newEvent.setResourcePath(adminEvent.getResourcePath());
newEvent.setTime(adminEvent.getTime());
return newEvent;
}
}

View file

@ -28,6 +28,8 @@ import org.keycloak.models.KeycloakSessionFactory;
*/
public class EventsListenerProviderFactory implements EventListenerProviderFactory {
public static final String PROVIDER_ID = "event-queue";
private static final EventsListenerProvider INSTANCE = new EventsListenerProvider();
@Override
@ -49,6 +51,6 @@ public class EventsListenerProviderFactory implements EventListenerProviderFacto
@Override
public String getId() {
return "event-queue";
return PROVIDER_ID;
}
}

View file

@ -21,10 +21,12 @@ import org.infinispan.Cache;
import org.keycloak.common.util.Time;
import org.keycloak.connections.infinispan.InfinispanConnectionProvider;
import org.keycloak.events.Event;
import org.keycloak.events.admin.AdminEvent;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.representations.idm.AdminEventRepresentation;
import org.keycloak.representations.idm.EventRepresentation;
import org.keycloak.services.managers.ClientSessionCode;
import org.keycloak.services.managers.RealmManager;
@ -139,7 +141,7 @@ public class TestingResourceProvider implements RealmResourceProvider {
@Path("/poll-event-queue")
@Produces(MediaType.APPLICATION_JSON)
public EventRepresentation getEvent() {
Event event = EventsListenerProvider.getInstance().poll();
Event event = EventsListenerProvider.poll();
if (event != null) {
return ModelToRepresentation.toRepresentation(event);
} else {
@ -147,11 +149,31 @@ public class TestingResourceProvider implements RealmResourceProvider {
}
}
@POST
@Path("/poll-admin-event-queue")
@Produces(MediaType.APPLICATION_JSON)
public AdminEventRepresentation getAdminEvent() {
AdminEvent adminEvent = EventsListenerProvider.pollAdminEvent();
if (adminEvent != null) {
return ModelToRepresentation.toRepresentation(adminEvent);
} else {
return null;
}
}
@POST
@Path("/clear-event-queue")
@Produces(MediaType.APPLICATION_JSON)
public Response clearQueue() {
EventsListenerProvider.getInstance().clear();
public Response clearEventQueue() {
EventsListenerProvider.clear();
return Response.ok().build();
}
@POST
@Path("/clear-admin-event-queue")
@Produces(MediaType.APPLICATION_JSON)
public Response clearAdminEventQueue() {
EventsListenerProvider.clearAdminEvents();
return Response.ok().build();
}

View file

@ -17,6 +17,7 @@
package org.keycloak.testsuite.client.resources;
import org.keycloak.representations.idm.AdminEventRepresentation;
import org.keycloak.representations.idm.EventRepresentation;
import org.keycloak.testsuite.rest.representation.AuthenticatorState;
@ -56,10 +57,20 @@ public interface TestingResource {
@Produces(MediaType.APPLICATION_JSON)
EventRepresentation pollEvent();
@POST
@Path("/poll-admin-event-queue")
@Produces(MediaType.APPLICATION_JSON)
AdminEventRepresentation pollAdminEvent();
@POST
@Path("/clear-event-queue")
@Produces(MediaType.APPLICATION_JSON)
Response clearQueue();
Response clearEventQueue();
@POST
@Path("/clear-admin-event-queue")
@Produces(MediaType.APPLICATION_JSON)
Response clearAdminEventQueue();
@POST
@Path("/remove-user-session")

View file

@ -184,13 +184,17 @@ public abstract class AbstractKeycloakTest {
loginPage.setAuthRealm(MASTER);
}
protected KeycloakTestingClient getTestingClient() {
public KeycloakTestingClient getTestingClient() {
if (testingClient == null) {
testingClient = KeycloakTestingClient.getInstance(AuthServerTestEnricher.getAuthServerContextRoot() + "/auth");
}
return testingClient;
}
public Keycloak getAdminClient() {
return adminClient;
}
public abstract void addTestRealms(List<RealmRepresentation> testRealms);
private void addTestRealms() {

View file

@ -63,7 +63,8 @@ public class AssertEvents implements TestRule {
return new Statement() {
@Override
public void evaluate() throws Throwable {
context.getTestingClient().testing().clearQueue();
// TODO: Ideally clear the queue just before testClass rather then before each method
context.getTestingClient().testing().clearEventQueue();
base.evaluate();
// TODO Test should fail if there are leftover events
}
@ -83,7 +84,7 @@ public class AssertEvents implements TestRule {
}
public void clear() {
Response res = context.testingClient.testing().clearQueue();
Response res = context.testingClient.testing().clearEventQueue();
try {
Assert.assertEquals("clear-event-queue success", res.getStatus(), 200);
} finally {

View file

@ -19,6 +19,7 @@ package org.keycloak.testsuite.admin;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
@ -27,11 +28,15 @@ import java.util.List;
import java.util.Map;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.events.log.JBossLoggingEventListenerProviderFactory;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.testsuite.TestRealmKeycloakTest;
import org.keycloak.testsuite.events.EventsListenerProviderFactory;
import org.keycloak.testsuite.util.AssertAdminEvents;
import org.keycloak.util.JsonSerialization;
import static org.junit.Assert.assertArrayEquals;
@ -46,6 +51,10 @@ public abstract class AbstractAdminTest extends TestRealmKeycloakTest {
protected static final String REALM_NAME = "admin-client-test";
protected RealmResource realm;
protected String realmId;
@Rule
public AssertAdminEvents assertAdminEvents = new AssertAdminEvents(this);
@Override
public void configureTestRealm(RealmRepresentation testRealm) {
@ -64,12 +73,19 @@ public abstract class AbstractAdminTest extends TestRealmKeycloakTest {
config.put("host", "localhost");
config.put("port", "3025");
adminRealmRep.setSmtpServer(config);
List<String> eventListeners = new ArrayList<>();
eventListeners.add(JBossLoggingEventListenerProviderFactory.ID);
eventListeners.add(EventsListenerProviderFactory.PROVIDER_ID);
adminRealmRep.setEventsListeners(eventListeners);
testRealms.add(adminRealmRep);
}
@Before
public void setRealm() {
realm = adminClient.realm(REALM_NAME);
realmId = realm.toRepresentation().getId();
}
// old testsuite expects this realm to be removed at the end of the test

View file

@ -162,7 +162,7 @@ public class ApiUtil {
+ clientName + "\" in realm: \"" + realmName + "\"");
userResource.roles().clientLevel(clientId).add(roleRepresentations);
} else {
log.warn("client with name " + clientName + "doesn't exist in realm " + realmName);
log.warn("client with name " + clientName + " doesn't exist in realm " + realmName);
}
}

View file

@ -33,6 +33,8 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* TODO adminEvents: Add adminEvents once resourcePath is added in AttackDetectionResource (server-side) events
*
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class AttackDetectionResourceTest extends AbstractAdminTest {

View file

@ -17,12 +17,14 @@
package org.keycloak.testsuite.admin;
import org.hamcrest.Matchers;
import org.junit.Test;
import org.keycloak.OAuth2Constants;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.admin.client.resource.ProtocolMappersResource;
import org.keycloak.admin.client.resource.RoleMappingResource;
import org.keycloak.common.util.Time;
import org.keycloak.events.admin.OperationType;
import org.keycloak.models.AccountRoles;
import org.keycloak.models.Constants;
import org.keycloak.protocol.oidc.OIDCLoginProtocolFactory;
@ -43,6 +45,8 @@ import java.util.Set;
import org.keycloak.services.resources.admin.ScopeMappedResource;
import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.util.AdminEventPaths;
import org.keycloak.testsuite.util.AssertAdminEvents;
import org.keycloak.testsuite.util.ClientBuilder;
import org.keycloak.testsuite.util.CredentialBuilder;
import org.keycloak.testsuite.util.OAuthClient;
@ -75,7 +79,11 @@ public class ClientTest extends AbstractAdminTest {
Response response = realm.clients().create(rep);
response.close();
String id = ApiUtil.getCreatedId(response);
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientResourcePath(id), rep);
rep.setId(id);
return rep;
}
@ -92,6 +100,8 @@ public class ClientTest extends AbstractAdminTest {
String id = createClient().getId();
realm.clients().get(id).remove();
assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.clientResourcePath(id));
}
@Test
@ -138,33 +148,35 @@ public class ClientTest extends AbstractAdminTest {
@Test
// KEYCLOAK-1110
public void deleteDefaultRole() {
ClientRepresentation rep = new ClientRepresentation();
rep.setClientId("my-app");
rep.setEnabled(true);
Response response = realm.clients().create(rep);
response.close();
String id = ApiUtil.getCreatedId(response);
ClientRepresentation rep = createClient();
String id = rep.getId();
RoleRepresentation role = new RoleRepresentation("test", "test", false);
realm.clients().get(id).roles().create(role);
rep = realm.clients().get(id).toRepresentation();
rep.setDefaultRoles(new String[] { "test" });
realm.clients().get(id).update(rep);
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, Matchers.startsWith(AdminEventPaths.clientRolesResourcePath(id)), role);
assertArrayEquals(new String[] { "test" }, realm.clients().get(id).toRepresentation().getDefaultRoles());
ClientRepresentation foundClientRep = realm.clients().get(id).toRepresentation();
foundClientRep.setDefaultRoles(new String[]{"test"});
realm.clients().get(id).update(foundClientRep);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.clientResourcePath(id), rep);
assertArrayEquals(new String[]{"test"}, realm.clients().get(id).toRepresentation().getDefaultRoles());
realm.clients().get(id).roles().deleteRole("test");
assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.clientRoleResourcePath(id, "test"));
assertNull(realm.clients().get(id).toRepresentation().getDefaultRoles());
}
@Test
public void testProtocolMappers() {
createClient();
String clientDbId = createClient().getId();
ProtocolMappersResource mappersResource = ApiUtil.findClientByClientId(realm, "my-app").getProtocolMappers();
protocolMappersTest(mappersResource);
protocolMappersTest(clientDbId, mappersResource);
}
@Test
@ -178,6 +190,8 @@ public class ClientTest extends AbstractAdminTest {
realm.clients().get(client.getId()).update(newClient);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.clientResourcePath(client.getId()), newClient);
ClientRepresentation storedClient = realm.clients().get(client.getId()).toRepresentation();
assertClient(client, storedClient);
@ -186,6 +200,8 @@ public class ClientTest extends AbstractAdminTest {
realm.clients().get(client.getId()).update(newClient);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.clientResourcePath(client.getId()), newClient);
storedClient = realm.clients().get(client.getId()).toRepresentation();
assertClient(client, storedClient);
}
@ -202,6 +218,18 @@ public class ClientTest extends AbstractAdminTest {
public void pushRevocation() {
testingClient.testApp().clearAdminActions();
ClientRepresentation client = createAppClient();
String id = client.getId();
realm.clients().get(id).pushRevocation();
PushNotBeforeAction pushNotBefore = testingClient.testApp().getAdminPushNotBefore();
assertEquals(client.getNotBefore().intValue(), pushNotBefore.getNotBefore());
assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.clientPushRevocationPath(id));
}
private ClientRepresentation createAppClient() {
String redirectUri = oauth.getRedirectUri().replace("/master/", "/" + REALM_NAME + "/");
ClientRepresentation client = new ClientRepresentation();
@ -211,41 +239,38 @@ public class ClientTest extends AbstractAdminTest {
client.setSecret("secret");
int notBefore = Time.currentTime() - 60;
client.setNotBefore(notBefore);
Response response = realm.clients().create(client);
String id = ApiUtil.getCreatedId(response);
response.close();
realm.clients().get(id).pushRevocation();
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientResourcePath(id), client);
PushNotBeforeAction pushNotBefore = testingClient.testApp().getAdminPushNotBefore();
assertEquals(notBefore, pushNotBefore.getNotBefore());
client.setId(id);
return client;
}
@Test
public void nodes() {
testingClient.testApp().clearAdminActions();
String redirectUri = oauth.getRedirectUri().replace("/master/", "/" + REALM_NAME + "/");
ClientRepresentation client = new ClientRepresentation();
client.setClientId("test-app");
client.setAdminUrl(suiteContext.getAuthServerInfo().getContextRoot() + "/auth/realms/master/app/admin");
client.setRedirectUris(Collections.singletonList(redirectUri));
client.setSecret("secret");
Response response = realm.clients().create(client);
String id = ApiUtil.getCreatedId(response);
response.close();
ClientRepresentation client = createAppClient();
String id = client.getId();
realm.clients().get(id).registerNode(Collections.singletonMap("node", suiteContext.getAuthServerInfo().getContextRoot().getHost()));
realm.clients().get(id).registerNode(Collections.singletonMap("node", "invalid"));
// TODO adminEvents: should be rather CREATE and include nodePath like in DELETE event
assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.clientNodesPath(id));
assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.clientNodesPath(id));
GlobalRequestResult result = realm.clients().get(id).testNodesAvailable();
assertEquals(1, result.getSuccessRequests().size());
assertEquals(1, result.getFailedRequests().size());
assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.clientTestNodesAvailablePath(id));
TestAvailabilityAction testAvailable = testingClient.testApp().getTestAvailable();
assertEquals("test-app", testAvailable.getResource());
@ -253,24 +278,17 @@ public class ClientTest extends AbstractAdminTest {
realm.clients().get(id).unregisterNode("invalid");
assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.clientNodePath(id, "invalid"));
assertEquals(1, realm.clients().get(id).toRepresentation().getRegisteredNodes().size());
}
@Test
public void offlineUserSessions() throws IOException {
String redirectUri = oauth.getRedirectUri().replace("/master/", "/" + REALM_NAME + "/");
ClientRepresentation client = createAppClient();
String id = client.getId();
ClientRepresentation client = new ClientRepresentation();
client.setClientId("test-app");
client.setAdminUrl(suiteContext.getAuthServerInfo().getContextRoot() + "/auth/realms/master/app/admin");
client.setRedirectUris(Collections.singletonList(redirectUri));
client.setSecret("secret");
Response response = realm.clients().create(client);
String id = ApiUtil.getCreatedId(response);
response.close();
response = realm.users().create(UserBuilder.create().username("testuser").build());
Response response = realm.users().create(UserBuilder.create().username("testuser").build());
String userId = ApiUtil.getCreatedId(response);
response.close();
@ -280,7 +298,7 @@ public class ClientTest extends AbstractAdminTest {
assertEquals(new Long(0), offlineSessionCount.get("count"));
oauth.realm(REALM_NAME);
oauth.redirectUri(redirectUri);
oauth.redirectUri(client.getRedirectUris().get(0));
oauth.scope(OAuth2Constants.OFFLINE_ACCESS);
oauth.doLogin("testuser", "password");
AccessTokenResponse accessTokenResponse = oauth.doAccessTokenRequest(oauth.getCurrentQuery().get("code"), "secret");
@ -300,21 +318,37 @@ public class ClientTest extends AbstractAdminTest {
String id = ApiUtil.getCreatedId(response);
response.close();
assertAdminEvents.poll();
RoleMappingResource scopesResource = realm.clients().get(id).getScopeMappings();
realm.roles().create(RoleBuilder.create().name("role1").build());
realm.roles().create(RoleBuilder.create().name("role2").build());
RoleRepresentation roleRep1 = RoleBuilder.create().name("role1").build();
RoleRepresentation roleRep2 = RoleBuilder.create().name("role2").build();
realm.roles().create(roleRep1);
realm.roles().create(roleRep2);
RoleRepresentation roleRep1 = realm.roles().get("role1").toRepresentation();
RoleRepresentation roleRep2 = realm.roles().get("role2").toRepresentation();
AssertAdminEvents.ExpectedAdminEvent adminEvent = assertAdminEvents.expect()
.realmId(realmId)
.operationType(OperationType.CREATE)
.resourcePath(Matchers.startsWith(AdminEventPaths.rolesResourcePath()));
adminEvent.representation(roleRep1).assertEvent();
adminEvent.representation(roleRep2).assertEvent();
roleRep1 = realm.roles().get("role1").toRepresentation();
roleRep2 = realm.roles().get("role2").toRepresentation();
realm.roles().get("role1").addComposites(Collections.singletonList(roleRep2));
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, Matchers.startsWith(AdminEventPaths.roleResourceCompositesPath("role1")));
String accountMgmtId = realm.clients().findByClientId(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID).get(0).getId();
RoleRepresentation viewAccountRoleRep = realm.clients().get(accountMgmtId).roles().get(AccountRoles.VIEW_PROFILE).toRepresentation();
scopesResource.realmLevel().add(Collections.singletonList(roleRep1));
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientScopeMappingsRealmLevelPath(id) + "/" + roleRep1.getId());
scopesResource.clientLevel(accountMgmtId).add(Collections.singletonList(viewAccountRoleRep));
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientScopeMappingsClientLevelPath(id, accountMgmtId) + "/" + viewAccountRoleRep.getId());
Assert.assertNames(scopesResource.realmLevel().listAll(), "role1");
Assert.assertNames(scopesResource.realmLevel().listEffective(), "role1", "role2");
@ -328,7 +362,10 @@ public class ClientTest extends AbstractAdminTest {
Assert.assertNames(scopesResource.getAll().getClientMappings().get(Constants.ACCOUNT_MANAGEMENT_CLIENT_ID).getMappings(), AccountRoles.VIEW_PROFILE);
scopesResource.realmLevel().remove(Collections.singletonList(roleRep1));
assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.clientScopeMappingsRealmLevelPath(id) + "/" + roleRep1.getId());
scopesResource.clientLevel(accountMgmtId).remove(Collections.singletonList(viewAccountRoleRep));
assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.clientScopeMappingsClientLevelPath(id, accountMgmtId) + "/" + viewAccountRoleRep.getId());
Assert.assertNames(scopesResource.realmLevel().listAll());
Assert.assertNames(scopesResource.realmLevel().listEffective());
@ -338,7 +375,7 @@ public class ClientTest extends AbstractAdminTest {
Assert.assertNames(scopesResource.clientLevel(accountMgmtId).listEffective());
}
public static void protocolMappersTest(ProtocolMappersResource mappersResource) {
public void protocolMappersTest(String clientDbId, ProtocolMappersResource mappersResource) {
// assert default mappers found
List<ProtocolMapperRepresentation> protocolMappers = mappersResource.getMappers();
@ -370,6 +407,8 @@ public class ClientTest extends AbstractAdminTest {
fooMapperId = location.substring(location.lastIndexOf("/") + 1);
response.close();
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientProtocolMapperPath(clientDbId, fooMapperId), fooMapper);
fooMapper = mappersResource.getMapperById(fooMapperId);
assertEquals(fooMapper.getName(), "foo");
@ -377,11 +416,14 @@ public class ClientTest extends AbstractAdminTest {
fooMapper.setProtocolMapper("foo-mapper-updated");
mappersResource.update(fooMapperId, fooMapper);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.clientProtocolMapperPath(clientDbId, fooMapperId), fooMapper);
fooMapper = mappersResource.getMapperById(fooMapperId);
assertEquals(fooMapper.getProtocolMapper(), "foo-mapper-updated");
// Remove foo mapper
mappersResource.delete(fooMapperId);
assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.clientProtocolMapperPath(clientDbId, fooMapperId));
try {
mappersResource.getMapperById(fooMapperId);
fail("Not expected to find deleted mapper");

View file

@ -17,6 +17,7 @@
package org.keycloak.testsuite.admin;
import org.hamcrest.Matchers;
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput;
import org.junit.Test;
import org.keycloak.admin.client.resource.IdentityProviderResource;
@ -25,6 +26,7 @@ import org.keycloak.dom.saml.v2.metadata.EntityDescriptorType;
import org.keycloak.dom.saml.v2.metadata.IndexedEndpointType;
import org.keycloak.dom.saml.v2.metadata.KeyTypes;
import org.keycloak.dom.saml.v2.metadata.SPSSODescriptorType;
import org.keycloak.events.admin.OperationType;
import org.keycloak.representations.idm.IdentityProviderMapperRepresentation;
import org.keycloak.representations.idm.IdentityProviderMapperTypeRepresentation;
import org.keycloak.representations.idm.IdentityProviderRepresentation;
@ -32,6 +34,7 @@ import org.keycloak.saml.common.exceptions.ParsingException;
import org.keycloak.saml.common.util.StaxParserUtil;
import org.keycloak.saml.processing.core.parsers.saml.metadata.SAMLEntityDescriptorParser;
import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.util.AdminEventPaths;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.core.MediaType;
@ -61,27 +64,21 @@ public class IdentityProviderTest extends AbstractAdminTest {
@Test
public void testFindAll() {
Response response = realm.identityProviders().create(create("google", "google"));
Assert.assertNotNull(ApiUtil.getCreatedId(response));
response.close();
create(createRep("google", "google"));
response = realm.identityProviders().create(create("facebook", "facebook"));
Assert.assertNotNull(ApiUtil.getCreatedId(response));
response.close();
create(createRep("facebook", "facebook"));
Assert.assertNames(realm.identityProviders().findAll(), "google", "facebook");
}
@Test
public void testCreate() {
IdentityProviderRepresentation newIdentityProvider = create("new-identity-provider", "oidc");
IdentityProviderRepresentation newIdentityProvider = createRep("new-identity-provider", "oidc");
newIdentityProvider.getConfig().put("clientId", "clientId");
newIdentityProvider.getConfig().put("clientSecret", "clientSecret");
Response response = realm.identityProviders().create(newIdentityProvider);
Assert.assertNotNull(ApiUtil.getCreatedId(response));
response.close();
create(newIdentityProvider);
IdentityProviderResource identityProviderResource = realm.identityProviders().get("new-identity-provider");
@ -103,14 +100,12 @@ public class IdentityProviderTest extends AbstractAdminTest {
@Test
public void testUpdate() {
IdentityProviderRepresentation newIdentityProvider = create("update-identity-provider", "oidc");
IdentityProviderRepresentation newIdentityProvider = createRep("update-identity-provider", "oidc");
newIdentityProvider.getConfig().put("clientId", "clientId");
newIdentityProvider.getConfig().put("clientSecret", "clientSecret");
Response response = realm.identityProviders().create(newIdentityProvider);
Assert.assertNotNull(ApiUtil.getCreatedId(response));
response.close();
create(newIdentityProvider);
IdentityProviderResource identityProviderResource = realm.identityProviders().get("update-identity-provider");
@ -128,6 +123,7 @@ public class IdentityProviderTest extends AbstractAdminTest {
representation.getConfig().put("clientId", "changedClientId");
identityProviderResource.update(representation);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.identityProviderPath("update-identity-provider"), representation);
identityProviderResource = realm.identityProviders().get(representation.getInternalId());
@ -140,15 +136,13 @@ public class IdentityProviderTest extends AbstractAdminTest {
assertEquals("changedClientId", representation.getConfig().get("clientId"));
}
@Test(expected = NotFoundException.class)
@Test
public void testRemove() {
IdentityProviderRepresentation newIdentityProvider = create("remove-identity-provider", "saml");
IdentityProviderRepresentation newIdentityProvider = createRep("remove-identity-provider", "saml");
Response response = realm.identityProviders().create(newIdentityProvider);
Assert.assertNotNull(ApiUtil.getCreatedId(response));
response.close();
create(newIdentityProvider);
IdentityProviderResource identityProviderResource = realm.identityProviders().get("update-identity-provider");
IdentityProviderResource identityProviderResource = realm.identityProviders().get("remove-identity-provider");
assertNotNull(identityProviderResource);
@ -157,16 +151,30 @@ public class IdentityProviderTest extends AbstractAdminTest {
assertNotNull(representation);
identityProviderResource.remove();
assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.identityProviderPath("remove-identity-provider"));
realm.identityProviders().get("update-identity-provider");
try {
realm.identityProviders().get("remove-identity-provider").toRepresentation();
Assert.fail("Not expected to found");
} catch (NotFoundException nfe) {
// Expected
}
}
private void create(IdentityProviderRepresentation idpRep) {
Response response = realm.identityProviders().create(idpRep);
Assert.assertNotNull(ApiUtil.getCreatedId(response));
response.close();
private IdentityProviderRepresentation create(String id, String providerId) {
return create(id, providerId, null);
// TODO adminEvents: should rather use alias instead of internalId (same issue like for roles)
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, Matchers.startsWith(AdminEventPaths.identityProviderCreatePath()), idpRep);
}
private IdentityProviderRepresentation create(String id, String providerId, Map<String, String> config) {
private IdentityProviderRepresentation createRep(String id, String providerId) {
return createRep(id, providerId, null);
}
private IdentityProviderRepresentation createRep(String id, String providerId, Map<String, String> config) {
IdentityProviderRepresentation idp = new IdentityProviderRepresentation();
idp.setAlias(id);
@ -184,82 +192,52 @@ public class IdentityProviderTest extends AbstractAdminTest {
IdentityProviderResource provider;
Map<String, IdentityProviderMapperTypeRepresentation> mapperTypes;
Response response = realm.identityProviders().create(create("google", "google"));
Assert.assertNotNull(ApiUtil.getCreatedId(response));
response.close();
create(createRep("google", "google"));
provider = realm.identityProviders().get("google");
mapperTypes = provider.getMapperTypes();
assertMapperTypes(mapperTypes, "google-user-attribute-mapper");
response = realm.identityProviders().create(create("facebook", "facebook"));
Assert.assertNotNull(ApiUtil.getCreatedId(response));
response.close();
create(createRep("facebook", "facebook"));
provider = realm.identityProviders().get("facebook");
mapperTypes = provider.getMapperTypes();
assertMapperTypes(mapperTypes, "facebook-user-attribute-mapper");
response = realm.identityProviders().create(create("github", "github"));
Assert.assertNotNull(ApiUtil.getCreatedId(response));
response.close();
create(createRep("github", "github"));
provider = realm.identityProviders().get("github");
mapperTypes = provider.getMapperTypes();
assertMapperTypes(mapperTypes, "github-user-attribute-mapper");
response = realm.identityProviders().create(create("twitter", "twitter"));
Assert.assertNotNull(ApiUtil.getCreatedId(response));
response.close();
create(createRep("twitter", "twitter"));
provider = realm.identityProviders().get("twitter");
mapperTypes = provider.getMapperTypes();
assertMapperTypes(mapperTypes);
response = realm.identityProviders().create(create("linkedin", "linkedin"));
Assert.assertNotNull(ApiUtil.getCreatedId(response));
response.close();
create(createRep("linkedin", "linkedin"));
provider = realm.identityProviders().get("linkedin");
mapperTypes = provider.getMapperTypes();
assertMapperTypes(mapperTypes, "linkedin-user-attribute-mapper");
response = realm.identityProviders().create(create("microsoft", "microsoft"));
Assert.assertNotNull(ApiUtil.getCreatedId(response));
response.close();
create(createRep("microsoft", "microsoft"));
provider = realm.identityProviders().get("microsoft");
mapperTypes = provider.getMapperTypes();
assertMapperTypes(mapperTypes, "microsoft-user-attribute-mapper");
response = realm.identityProviders().create(create("stackoverflow", "stackoverflow"));
Assert.assertNotNull(ApiUtil.getCreatedId(response));
response.close();
create(createRep("stackoverflow", "stackoverflow"));
provider = realm.identityProviders().get("stackoverflow");
mapperTypes = provider.getMapperTypes();
assertMapperTypes(mapperTypes, "stackoverflow-user-attribute-mapper");
response = realm.identityProviders().create(create("keycloak-oidc", "keycloak-oidc"));
Assert.assertNotNull(ApiUtil.getCreatedId(response));
response.close();
create(createRep("keycloak-oidc", "keycloak-oidc"));
provider = realm.identityProviders().get("keycloak-oidc");
mapperTypes = provider.getMapperTypes();
assertMapperTypes(mapperTypes, "keycloak-oidc-role-to-role-idp-mapper", "oidc-user-attribute-idp-mapper", "oidc-role-idp-mapper", "oidc-username-idp-mapper");
response = realm.identityProviders().create(create("oidc", "oidc"));
Assert.assertNotNull(ApiUtil.getCreatedId(response));
response.close();
create(createRep("oidc", "oidc"));
provider = realm.identityProviders().get("oidc");
mapperTypes = provider.getMapperTypes();
assertMapperTypes(mapperTypes, "oidc-user-attribute-idp-mapper", "oidc-role-idp-mapper", "oidc-username-idp-mapper");
response = realm.identityProviders().create(create("saml", "saml"));
Assert.assertNotNull(ApiUtil.getCreatedId(response));
response.close();
create(createRep("saml", "saml"));
provider = realm.identityProviders().get("saml");
mapperTypes = provider.getMapperTypes();
assertMapperTypes(mapperTypes, "saml-user-attribute-idp-mapper", "saml-role-idp-mapper", "saml-username-idp-mapper");
@ -278,11 +256,9 @@ public class IdentityProviderTest extends AbstractAdminTest {
@Test
public void testNoExport() {
Response response = realm.identityProviders().create(create("keycloak-oidc", "keycloak-oidc"));
Assert.assertNotNull(ApiUtil.getCreatedId(response));
response.close();
create(createRep("keycloak-oidc", "keycloak-oidc"));
response = realm.identityProviders().get("keycloak-oidc").export("json");
Response response = realm.identityProviders().get("keycloak-oidc").export("json");
Assert.assertEquals("status", 204, response.getStatus());
String body = response.readEntity(String.class);
Assert.assertNull("body", body);
@ -306,9 +282,7 @@ public class IdentityProviderTest extends AbstractAdminTest {
assertSamlImport(result);
// Create new SAML identity provider using configuration retrieved from import-config
Response response = realm.identityProviders().create(create("saml", "saml", result));
Assert.assertNotNull(ApiUtil.getCreatedId(response));
response.close();
create(createRep("saml", "saml", result));
IdentityProviderResource provider = realm.identityProviders().get("saml");
IdentityProviderRepresentation rep = provider.toRepresentation();
@ -321,7 +295,7 @@ public class IdentityProviderTest extends AbstractAdminTest {
assertEqual(rep, providers.get(0));
// Perform export, and make sure some of the values are like they're supposed to be
response = realm.identityProviders().get("saml").export("xml");
Response response = realm.identityProviders().get("saml").export("xml");
Assert.assertEquals(200, response.getStatus());
body = response.readEntity(String.class);
response.close();
@ -331,9 +305,7 @@ public class IdentityProviderTest extends AbstractAdminTest {
@Test
public void testMappers() {
Response response = realm.identityProviders().create(create("google", "google"));
Assert.assertNotNull(ApiUtil.getCreatedId(response));
response.close();
create(createRep("google", "google"));
IdentityProviderResource provider = realm.identityProviders().get("google");
@ -345,11 +317,12 @@ public class IdentityProviderTest extends AbstractAdminTest {
config.put("role", "offline_access");
mapper.setConfig(config);
// create and add mapper
response = provider.addMapper(mapper);
// createRep and add mapper
Response response = provider.addMapper(mapper);
String id = ApiUtil.getCreatedId(response);
Assert.assertNotNull(id);
response.close();
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.identityProviderMapperPath("google", id), mapper);
// list mappers
List<IdentityProviderMapperRepresentation> mappers = provider.getMappers();
@ -366,16 +339,20 @@ public class IdentityProviderTest extends AbstractAdminTest {
// update mapper
mapper.getConfig().put("role", "master-realm.manage-realm");
provider.update(id, mapper);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.identityProviderMapperPath("google", id), mapper);
mapper = provider.getMapperById(id);
Assert.assertNotNull("mapperById not null", mapper);
Assert.assertEquals("config changed", "master-realm.manage-realm", mapper.getConfig().get("role"));
// delete mapper
provider.delete(id);
assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.identityProviderMapperPath("google", id));
try {
provider.getMapperById(id);
Assert.fail("Should fail with NotFoundException");
} catch (NotFoundException e) {
// Expected
}
}

View file

@ -21,8 +21,10 @@ import org.junit.Before;
import org.junit.Test;
import org.keycloak.admin.client.resource.ClientInitialAccessResource;
import org.keycloak.common.util.Time;
import org.keycloak.events.admin.OperationType;
import org.keycloak.representations.idm.ClientInitialAccessCreatePresentation;
import org.keycloak.representations.idm.ClientInitialAccessPresentation;
import org.keycloak.testsuite.util.AdminEventPaths;
import java.util.List;
@ -52,6 +54,7 @@ public class InitialAccessTokenResourceTest extends AbstractAdminTest {
int time = Time.currentTime();
ClientInitialAccessPresentation response = resource.create(rep);
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientInitialAccessPath(response.getId()), rep);
assertNotNull(response.getId());
assertEquals(new Integer(2), response.getCount());
@ -61,10 +64,12 @@ public class InitialAccessTokenResourceTest extends AbstractAdminTest {
assertNotNull(response.getToken());
rep.setCount(3);
resource.create(rep);
response = resource.create(rep);
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientInitialAccessPath(response.getId()), rep);
rep.setCount(4);
resource.create(rep);
response = resource.create(rep);
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientInitialAccessPath(response.getId()), rep);
List<ClientInitialAccessPresentation> list = resource.list();
assertEquals(3, list.size());

View file

@ -17,11 +17,14 @@
package org.keycloak.testsuite.admin;
import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
import org.keycloak.admin.client.resource.RoleByIdResource;
import org.keycloak.events.admin.OperationType;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.util.AdminEventPaths;
import org.keycloak.testsuite.util.ClientBuilder;
import org.keycloak.testsuite.util.RoleBuilder;
@ -63,6 +66,8 @@ public class RoleByIdResourceTest extends AbstractAdminTest {
}
resource = adminClient.realm(REALM_NAME).rolesById();
assertAdminEvents.clear(); // Tested in RealmRolesTest already
}
@Test
@ -82,6 +87,7 @@ public class RoleByIdResourceTest extends AbstractAdminTest {
role.setDescription("Role A New");
resource.updateRole(ids.get("role-a"), role);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.roleByIdResourcePath(ids.get("role-a")), role);
role = resource.getRole(ids.get("role-a"));
@ -95,6 +101,8 @@ public class RoleByIdResourceTest extends AbstractAdminTest {
public void deleteRole() {
assertNotNull(resource.getRole(ids.get("role-a")));
resource.deleteRole(ids.get("role-a"));
assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.roleByIdResourcePath(ids.get("role-a")));
try {
resource.getRole(ids.get("role-a"));
fail("Expected 404");
@ -112,6 +120,10 @@ public class RoleByIdResourceTest extends AbstractAdminTest {
l.add(RoleBuilder.create().id(ids.get("role-c")).build());
resource.addComposites(ids.get("role-a"), l);
// TODO adminEvents: Fix once composite roles events will be fixed...
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, Matchers.startsWith(AdminEventPaths.roleByIdResourceCompositesPath(ids.get("role-a"))));
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, Matchers.startsWith(AdminEventPaths.roleByIdResourceCompositesPath(ids.get("role-a"))));
Set<RoleRepresentation> composites = resource.getRoleComposites(ids.get("role-a"));
assertTrue(resource.getRole(ids.get("role-a")).isComposite());
@ -124,6 +136,7 @@ public class RoleByIdResourceTest extends AbstractAdminTest {
Assert.assertNames(clientComposites, "role-c");
resource.deleteComposites(ids.get("role-a"), l);
assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.roleByIdResourceCompositesPath(ids.get("role-a")));
assertFalse(resource.getRole(ids.get("role-a")).isComposite());
assertEquals(0, resource.getRoleComposites(ids.get("role-a")).size());

View file

@ -32,6 +32,7 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.keycloak.admin.client.resource.UserFederationProviderResource;
import org.keycloak.events.admin.OperationType;
import org.keycloak.federation.ldap.mappers.UserAttributeLDAPFederationMapper;
import org.keycloak.federation.ldap.mappers.UserAttributeLDAPFederationMapperFactory;
import org.keycloak.federation.ldap.mappers.membership.role.RoleLDAPFederationMapperFactory;
@ -43,6 +44,7 @@ import org.keycloak.representations.idm.UserFederationProviderRepresentation;
import org.keycloak.representations.idm.UserFederationSyncResultRepresentation;
import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.federation.DummyUserFederationMapper;
import org.keycloak.testsuite.util.AdminEventPaths;
import org.keycloak.testsuite.util.UserFederationProviderBuilder;
/**
@ -63,6 +65,7 @@ public class UserFederationMapperTest extends AbstractAdminTest {
Response resp = realm.userFederation().create(ldapRep);
this.ldapProviderId = ApiUtil.getCreatedId(resp);
resp.close();
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.userFederationCreateResourcePath(), ldapRep);
UserFederationProviderRepresentation dummyRep = UserFederationProviderBuilder.create()
.displayName("dummy-1")
@ -72,12 +75,16 @@ public class UserFederationMapperTest extends AbstractAdminTest {
resp = realm.userFederation().create(dummyRep);
this.dummyProviderId = ApiUtil.getCreatedId(resp);
resp.close();
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.userFederationCreateResourcePath(), dummyRep);
}
@After
public void cleanFederationProviders() {
realm.userFederation().get(ldapProviderId).remove();
assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.userFederationResourcePath(ldapProviderId));
realm.userFederation().get(dummyProviderId).remove();
assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.userFederationResourcePath(dummyProviderId));
}
@ -138,7 +145,7 @@ public class UserFederationMapperTest extends AbstractAdminTest {
// Test create success when all mandatory attributes available
attrMapper.getConfig().put(UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, "mail");
String mapperId = createMapper(attrMapper);
String mapperId = createMapper(ldapProviderId, attrMapper);
// Test get
UserFederationMapperRepresentation mapperRep = ldapProviderResource().getMapperById(mapperId);
@ -162,12 +169,15 @@ public class UserFederationMapperTest extends AbstractAdminTest {
mapperRep.getConfig().put(UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, "email-updated");
mapperRep.getConfig().put(UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, "mail-updated");
ldapProviderResource().updateMapper(mapperId, mapperRep);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.userFederationMapperResourcePath(ldapProviderId, mapperId), mapperRep);
mapperRep = ldapProviderResource().getMapperById(mapperId);
assertMapper(mapperRep, mapperId, "email-mapper", UserAttributeLDAPFederationMapperFactory.PROVIDER_ID, UserAttributeLDAPFederationMapper.USER_MODEL_ATTRIBUTE, "email-updated", UserAttributeLDAPFederationMapper.LDAP_ATTRIBUTE, "mail-updated");
// Test removed successfully
ldapProviderResource().removeMapper(mapperId);
assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.userFederationMapperResourcePath(ldapProviderId, mapperId));
try {
ldapProviderResource().getMapperById(mapperId);
Assert.fail("Not expected find to success as mapper was removed");
@ -176,11 +186,15 @@ public class UserFederationMapperTest extends AbstractAdminTest {
}
}
private String createMapper(UserFederationMapperRepresentation mapper) {
Response response = ldapProviderResource().addMapper(mapper);
private String createMapper(String userFederationProviderId, UserFederationMapperRepresentation mapper) {
Response response = realm.userFederation().get(userFederationProviderId).addMapper(mapper);
Assert.assertEquals(201, response.getStatus());
response.close();
return ApiUtil.getCreatedId(response);
String mapperId = ApiUtil.getCreatedId(response);
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.userFederationMapperResourcePath(userFederationProviderId , mapperId), mapper);
return mapperId;
}
@ -196,7 +210,7 @@ public class UserFederationMapperTest extends AbstractAdminTest {
// Fix config and create successfully
roleMapper.getConfig().put(RoleMapperConfig.USE_REALM_ROLES_MAPPING, "true");
String roleMapperId = createMapper(roleMapper);
String roleMapperId = createMapper(ldapProviderId, roleMapper);
// Assert builtin mappers
List<UserFederationMapperRepresentation> mappers = ldapProviderResource().getMappers();
@ -213,6 +227,8 @@ public class UserFederationMapperTest extends AbstractAdminTest {
// Remove role mapper and assert not found anymore
ldapProviderResource().removeMapper(roleMapperId);
assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.userFederationMapperResourcePath(ldapProviderId, roleMapperId));
mappers = ldapProviderResource().getMappers();
Assert.assertNull(findMapperByName(mappers, "role-mapper"));
}
@ -225,23 +241,25 @@ public class UserFederationMapperTest extends AbstractAdminTest {
dummyMapperRep.setName("some-dummy");
dummyMapperRep.setFederationMapperType(DummyUserFederationMapper.PROVIDER_NAME);
dummyMapperRep.setFederationProviderDisplayName("dummy-1");
String mapperId = createMapper(dummyMapperRep);
String mapperId = createMapper(dummyProviderId, dummyMapperRep);
// Try to sync with unknown action - fail
try {
realm.userFederation().get(dummyProviderId).syncMapperData(mapperId, "unknown");
ldapProviderResource().syncMapperData(mapperId, "unknown");
Assert.fail("Not expected to pass");
} catch (NotFoundException nfe) {
// Expected
}
// Try fed To Keycloak sync
UserFederationSyncResultRepresentation result = realm.userFederation().get(dummyProviderId).syncMapperData(mapperId, "fedToKeycloak");
UserFederationSyncResultRepresentation result = ldapProviderResource().syncMapperData(mapperId, "fedToKeycloak");
Assert.assertEquals("dummyFedToKeycloakSuccess mapper=some-dummy", result.getStatus());
assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userFederationMapperResourcePath(ldapProviderId, mapperId) + "/sync");
// Try keycloak to fed
result = realm.userFederation().get(dummyProviderId).syncMapperData(mapperId, "keycloakToFed");
result = ldapProviderResource().syncMapperData(mapperId, "keycloakToFed");
Assert.assertEquals("dummyKeycloakToFedSuccess mapper=some-dummy", result.getStatus());
assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userFederationMapperResourcePath(ldapProviderId, mapperId) + "/sync");
}

View file

@ -27,6 +27,7 @@ import javax.ws.rs.core.Response;
import org.junit.Test;
import org.keycloak.admin.client.resource.UserFederationProvidersResource;
import org.keycloak.common.constants.KerberosConstants;
import org.keycloak.events.admin.OperationType;
import org.keycloak.models.AuthenticationExecutionModel;
import org.keycloak.models.LDAPConstants;
import org.keycloak.provider.ProviderConfigProperty;
@ -36,6 +37,7 @@ import org.keycloak.representations.idm.UserFederationProviderRepresentation;
import org.keycloak.representations.idm.UserFederationSyncResultRepresentation;
import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.admin.authentication.AbstractAuthenticationTest;
import org.keycloak.testsuite.util.AdminEventPaths;
import org.keycloak.testsuite.util.UserFederationProviderBuilder;
/**
@ -115,8 +117,8 @@ public class UserFederationTest extends AbstractAdminTest {
assertFederationProvider(providerInstances.get(1), id1, id1, "dummy", 2, 1000, 500, 123);
// Remove providers
userFederation().get(id1).remove();
userFederation().get(id2).remove();
removeUserFederationProvider(id1);
removeUserFederationProvider(id2);
}
@ -147,6 +149,7 @@ public class UserFederationTest extends AbstractAdminTest {
// Assert nothing created so far
Assert.assertTrue(userFederation().getProviderInstances().isEmpty());
assertAdminEvents.assertEmpty();
// Valid filter. Creation success
@ -170,8 +173,8 @@ public class UserFederationTest extends AbstractAdminTest {
assertFederationProvider(providerInstances.get(1), id2, "ldap2", "ldap", 2, -1, -1, -1, LDAPConstants.BIND_DN, "cn=manager", LDAPConstants.BIND_CREDENTIAL, "password");
// Cleanup
userFederation().get(id1).remove();
userFederation().get(id2).remove();
removeUserFederationProvider(id1);
removeUserFederationProvider(id2);
}
@ -204,6 +207,7 @@ public class UserFederationTest extends AbstractAdminTest {
// Change filter to be valid
ldapRep.getConfig().put(LDAPConstants.CUSTOM_USER_SEARCH_FILTER, "(dc=something2)");
userFederation().get(id).update(ldapRep);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.userFederationResourcePath(id), ldapRep);
// Assert updated successfully
ldapRep = userFederation().get(id).toRepresentation();
@ -213,13 +217,15 @@ public class UserFederationTest extends AbstractAdminTest {
// Assert update displayName
ldapRep.setDisplayName("ldap2");
userFederation().get(id).update(ldapRep);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.userFederationResourcePath(id), ldapRep);
assertFederationProvider(userFederation().get(id).toRepresentation(), id, "ldap2", "ldap", 2, -1, -1, -1, LDAPConstants.BIND_DN, "cn=manager-updated", LDAPConstants.BIND_CREDENTIAL, "password",
LDAPConstants.CUSTOM_USER_SEARCH_FILTER, "(dc=something2)");
// Cleanup
userFederation().get(id).remove();
removeUserFederationProvider(id);
}
@ -249,6 +255,7 @@ public class UserFederationTest extends AbstractAdminTest {
// update LDAP provider with kerberos
ldapRep = userFederation().get(id).toRepresentation();
userFederation().get(id).update(ldapRep);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.userFederationResourcePath(id), ldapRep);
// Assert kerberos authenticator ALTERNATIVE
kerberosExecution = findKerberosExecution();
@ -257,7 +264,7 @@ public class UserFederationTest extends AbstractAdminTest {
// Cleanup
kerberosExecution.setRequirement(AuthenticationExecutionModel.Requirement.DISABLED.toString());
realm.flows().updateExecutions("browser", kerberosExecution);
userFederation().get(id).remove();
removeUserFederationProvider(id);
}
@ -290,19 +297,23 @@ public class UserFederationTest extends AbstractAdminTest {
// Sync and assert it happened
UserFederationSyncResultRepresentation syncResult = userFederation().get(id1).syncUsers("triggerFullSync");
Assert.assertEquals("0 imported users, 0 updated users", syncResult.getStatus());
assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userFederationResourcePath(id1) + "/sync");
int fullSyncTime = userFederation().get(id1).toRepresentation().getLastSync();
Assert.assertTrue(fullSyncTime > 0);
// Changed sync
setTimeOffset(50);
syncResult = userFederation().get(id1).syncUsers("triggerChangedUsersSync");
assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userFederationResourcePath(id1) + "/sync");
Assert.assertEquals("0 imported users, 0 updated users", syncResult.getStatus());
int changedSyncTime = userFederation().get(id1).toRepresentation().getLastSync();
Assert.assertTrue(fullSyncTime + 50 <= changedSyncTime);
// Cleanup
resetTimeOffset();
userFederation().get(id1).remove();
removeUserFederationProvider(id1);
}
@ -310,7 +321,16 @@ public class UserFederationTest extends AbstractAdminTest {
Response resp = userFederation().create(rep);
Assert.assertEquals(201, resp.getStatus());
resp.close();
return ApiUtil.getCreatedId(resp);
String federationProviderId = ApiUtil.getCreatedId(resp);
// TODO adminEvents: should be rather whole path include ID (consistency with UPDATE and DELETE)
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.userFederationCreateResourcePath(), rep);
return federationProviderId;
}
private void removeUserFederationProvider(String id) {
userFederation().get(id).remove();
assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.userFederationResourcePath(id));
}
private void assertFederationProvider(UserFederationProviderRepresentation rep, String id, String displayName, String providerName,

View file

@ -17,6 +17,7 @@
package org.keycloak.testsuite.admin;
import org.hamcrest.Matchers;
import org.jboss.arquillian.drone.api.annotation.Drone;
import org.jboss.arquillian.graphene.page.Page;
import org.jboss.arquillian.test.api.ArquillianResource;
@ -27,11 +28,11 @@ import org.keycloak.admin.client.resource.IdentityProviderResource;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.admin.client.resource.RoleMappingResource;
import org.keycloak.admin.client.resource.UserResource;
import org.keycloak.events.admin.OperationType;
import org.keycloak.models.UserModel;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.ErrorRepresentation;
import org.keycloak.representations.idm.FederatedIdentityRepresentation;
import org.keycloak.representations.idm.GroupRepresentation;
import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.representations.idm.MappingsRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
@ -42,10 +43,12 @@ import org.keycloak.services.resources.RealmsResource;
import org.keycloak.testsuite.page.LoginPasswordUpdatePage;
import org.keycloak.testsuite.pages.InfoPage;
import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.util.AdminEventPaths;
import org.keycloak.testsuite.util.ClientBuilder;
import org.keycloak.testsuite.util.GreenMailRule;
import org.keycloak.testsuite.util.MailUtils;
import org.keycloak.testsuite.util.OAuthClient;
import org.keycloak.testsuite.util.RealmBuilder;
import org.keycloak.testsuite.util.RoleBuilder;
import org.keycloak.testsuite.util.UserBuilder;
import org.openqa.selenium.WebDriver;
@ -56,7 +59,6 @@ import javax.ws.rs.ClientErrorException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import java.io.IOException;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
@ -100,12 +102,23 @@ public class UserTest extends AbstractAdminTest {
user.setRequiredActions(Collections.<String>emptyList());
user.setEnabled(true);
Response response = realm.users().create(user);
return createUser(user);
}
private String createUser(UserRepresentation userRep) {
Response response = realm.users().create(userRep);
String createdId = ApiUtil.getCreatedId(response);
response.close();
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.userResourcePath(createdId), userRep);
return createdId;
}
private void updateUser(UserResource user, UserRepresentation userRep) {
user.update(userRep);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.userResourcePath(userRep.getId()), userRep);
}
@Test
public void verifyCreateUser() {
createUser();
@ -119,6 +132,7 @@ public class UserTest extends AbstractAdminTest {
user.setUsername("user1");
Response response = realm.users().create(user);
assertEquals(409, response.getStatus());
assertAdminEvents.assertEmpty();
// Just to show how to retrieve underlying error message
ErrorRepresentation error = response.readEntity(ErrorRepresentation.class);
@ -196,6 +210,8 @@ public class UserTest extends AbstractAdminTest {
assertEquals(409, response.getStatus());
response.close();
assertAdminEvents.assertEmpty();
}
private void createUsers() {
@ -206,7 +222,7 @@ public class UserTest extends AbstractAdminTest {
user.setFirstName("First" + i);
user.setLastName("Last" + i);
realm.users().create(user).close();
createUser(user);
}
}
@ -256,9 +272,11 @@ public class UserTest extends AbstractAdminTest {
@Test
public void delete() {
Response response = realm.users().delete( createUser() );
String userId = createUser();
Response response = realm.users().delete( userId );
assertEquals(204, response.getStatus());
response.close();
assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.userResourcePath(userId));
}
@Test
@ -266,6 +284,7 @@ public class UserTest extends AbstractAdminTest {
Response response = realm.users().delete( "does-not-exist" );
assertEquals(404, response.getStatus());
response.close();
assertAdminEvents.assertEmpty();
}
@Test
@ -306,6 +325,7 @@ public class UserTest extends AbstractAdminTest {
link.setUserName("social-username");
Response response = user.addFederatedIdentity("social-provider-id", link);
assertEquals(204, response.getStatus());
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.userFederatedIdentityLink(id, "social-provider-id"), link);
// Verify social link is here
user = realm.users().get(id);
@ -318,6 +338,7 @@ public class UserTest extends AbstractAdminTest {
// Remove social link now
user.removeFederatedIdentity("social-provider-id");
assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.userFederatedIdentityLink(id, "social-provider-id"));
assertEquals(0, user.getFederatedIdentity().size());
removeSampleIdentityProvider();
@ -330,13 +351,16 @@ public class UserTest extends AbstractAdminTest {
IdentityProviderRepresentation rep = new IdentityProviderRepresentation();
rep.setAlias("social-provider-id");
rep.setProviderId("social-provider-type");
realm.identityProviders().create(rep);
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, Matchers.startsWith(AdminEventPaths.identityProviderCreatePath()), rep);
}
private void removeSampleIdentityProvider() {
IdentityProviderResource resource = realm.identityProviders().get("social-provider-id");
Assert.assertNotNull(resource);
resource.remove();
assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.identityProviderPath("social-provider-id"));
}
@Test
@ -348,7 +372,7 @@ public class UserTest extends AbstractAdminTest {
UserRepresentation userRep = user.toRepresentation();
userRep.getRequiredActions().add("UPDATE_PASSWORD");
user.update(userRep);
updateUser(user, userRep);
assertEquals(1, user.toRepresentation().getRequiredActions().size());
assertEquals("UPDATE_PASSWORD", user.toRepresentation().getRequiredActions().get(0));
@ -363,12 +387,12 @@ public class UserTest extends AbstractAdminTest {
UserRepresentation userRep = user.toRepresentation();
userRep.getRequiredActions().add("UPDATE_PASSWORD");
user.update(userRep);
updateUser(user, userRep);
user = realm.users().get(id);
userRep = user.toRepresentation();
userRep.getRequiredActions().clear();
user.update(userRep);
updateUser(user, userRep);
assertTrue(user.toRepresentation().getRequiredActions().isEmpty());
}
@ -380,9 +404,7 @@ public class UserTest extends AbstractAdminTest {
user1.singleAttribute("attr1", "value1user1");
user1.singleAttribute("attr2", "value2user1");
Response response = realm.users().create(user1);
String user1Id = ApiUtil.getCreatedId(response);
response.close();
String user1Id = createUser(user1);
UserRepresentation user2 = new UserRepresentation();
user2.setUsername("user2");
@ -392,9 +414,8 @@ public class UserTest extends AbstractAdminTest {
vals.add("value2user2_2");
user2.getAttributesAsListValues().put("attr2", vals);
response = realm.users().create(user2);
String user2Id = ApiUtil.getCreatedId(response);
response.close();
String user2Id = createUser(user2);
user1 = realm.users().get(user1Id).toRepresentation();
assertEquals(2, user1.getAttributesAsListValues().size());
assertAttributeValue("value1user1", user1.getAttributesAsListValues().get("attr1"));
@ -410,7 +431,7 @@ public class UserTest extends AbstractAdminTest {
user1.singleAttribute("attr1", "value3user1");
user1.singleAttribute("attr3", "value4user1");
realm.users().get(user1Id).update(user1);
updateUser(realm.users().get(user1Id), user1);
user1 = realm.users().get(user1Id).toRepresentation();
assertEquals(3, user1.getAttributesAsListValues().size());
@ -419,7 +440,7 @@ public class UserTest extends AbstractAdminTest {
assertAttributeValue("value4user1", user1.getAttributesAsListValues().get("attr3"));
user1.getAttributes().remove("attr1");
realm.users().get(user1Id).update(user1);
updateUser(realm.users().get(user1Id), user1);
user1 = realm.users().get(user1Id).toRepresentation();
assertEquals(2, user1.getAttributesAsListValues().size());
@ -427,7 +448,7 @@ public class UserTest extends AbstractAdminTest {
assertAttributeValue("value4user1", user1.getAttributesAsListValues().get("attr3"));
user1.getAttributes().clear();
realm.users().get(user1Id).update(user1);
updateUser(realm.users().get(user1Id), user1);
user1 = realm.users().get(user1Id).toRepresentation();
assertNull(user1.getAttributes());
@ -442,9 +463,9 @@ public class UserTest extends AbstractAdminTest {
public void sendResetPasswordEmail() {
UserRepresentation userRep = new UserRepresentation();
userRep.setUsername("user1");
Response response = realm.users().create(userRep);
String id = ApiUtil.getCreatedId(response);
response.close();
String id = createUser(userRep);
UserResource user = realm.users().get(id);
List<String> actions = new LinkedList<>();
try {
@ -460,7 +481,8 @@ public class UserTest extends AbstractAdminTest {
userRep = user.toRepresentation();
userRep.setEmail("user1@localhost");
userRep.setEnabled(false);
user.update(userRep);
updateUser(user, userRep);
user.executeActionsEmail(actions);
fail("Expected failure");
} catch (ClientErrorException e) {
@ -471,7 +493,8 @@ public class UserTest extends AbstractAdminTest {
}
try {
userRep.setEnabled(true);
user.update(userRep);
updateUser(user, userRep);
user.executeActionsEmail("invalidClientId", actions);
fail("Expected failure");
} catch (ClientErrorException e) {
@ -488,13 +511,14 @@ public class UserTest extends AbstractAdminTest {
userRep.setEnabled(true);
userRep.setUsername("user1");
userRep.setEmail("user1@test.com");
Response response = realm.users().create(userRep);
String id = ApiUtil.getCreatedId(response);
response.close();
String id = createUser(userRep);
UserResource user = realm.users().get(id);
List<String> actions = new LinkedList<>();
actions.add(UserModel.RequiredAction.UPDATE_PASSWORD.name());
user.executeActionsEmail("account", actions);
assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userResourcePath(id) + "/execute-actions-email");
Assert.assertEquals(1, greenMail.getReceivedMessages().length);
@ -520,9 +544,8 @@ public class UserTest extends AbstractAdminTest {
public void sendVerifyEmail() throws IOException, MessagingException {
UserRepresentation userRep = new UserRepresentation();
userRep.setUsername("user1");
Response response = realm.users().create(userRep);
String id = ApiUtil.getCreatedId(response);
response.close();
String id = createUser(userRep);
UserResource user = realm.users().get(id);
@ -539,7 +562,8 @@ public class UserTest extends AbstractAdminTest {
userRep = user.toRepresentation();
userRep.setEmail("user1@localhost");
userRep.setEnabled(false);
user.update(userRep);
updateUser(user, userRep);
user.sendVerifyEmail();
fail("Expected failure");
} catch (ClientErrorException e) {
@ -550,7 +574,8 @@ public class UserTest extends AbstractAdminTest {
}
try {
userRep.setEnabled(true);
user.update(userRep);
updateUser(user, userRep);
user.sendVerifyEmail("invalidClientId");
fail("Expected failure");
} catch (ClientErrorException e) {
@ -561,6 +586,8 @@ public class UserTest extends AbstractAdminTest {
}
user.sendVerifyEmail();
assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userResourcePath(id) + "/send-verify-email");
Assert.assertEquals(1, greenMail.getReceivedMessages().length);
String link = MailUtils.getPasswordResetEmailLink(greenMail.getReceivedMessages()[0]);
@ -578,7 +605,7 @@ public class UserTest extends AbstractAdminTest {
UserResource user = realm.users().get(id);
UserRepresentation userRep = user.toRepresentation();
userRep.setUsername("user11");
user.update(userRep);
updateUser(user, userRep);
userRep = realm.users().get(id).toRepresentation();
assertEquals("user11", userRep.getUsername());
@ -596,11 +623,13 @@ public class UserTest extends AbstractAdminTest {
rep.setFirstName("Firstname");
user.update(rep);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.userResourcePath(id), rep);
rep = new UserRepresentation();
rep.setLastName("Lastname");
user.update(rep);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.userResourcePath(id), rep);
rep = realm.users().get(id).toRepresentation();
@ -617,7 +646,7 @@ public class UserTest extends AbstractAdminTest {
UserResource user = realm.users().get(id);
UserRepresentation userRep = user.toRepresentation();
userRep.setUsername("user11");
user.update(userRep);
updateUser(user, userRep);
userRep = realm.users().get(id).toRepresentation();
assertEquals("user1", userRep.getUsername());
@ -632,7 +661,7 @@ public class UserTest extends AbstractAdminTest {
UserResource user = realm.users().get("user1");
UserRepresentation userRep = user.toRepresentation();
userRep.setUsername("user1");
user.update(userRep);
updateUser(user, userRep);
realm.users().get("user11").toRepresentation();
fail("Expected failure");
@ -648,9 +677,8 @@ public class UserTest extends AbstractAdminTest {
UserRepresentation userRep = new UserRepresentation();
userRep.setUsername("user2");
Response response = realm.users().create(userRep);
String createdId = ApiUtil.getCreatedId(response);
response.close();
String createdId = createUser(userRep);
try {
UserResource user = realm.users().get(createdId);
@ -660,6 +688,10 @@ public class UserTest extends AbstractAdminTest {
fail("Expected failure");
} catch (ClientErrorException e) {
assertEquals(409, e.getResponse().getStatus());
// TODO adminEvents: Event queue should be empty, but it's not because of bug in UsersResource.updateUser, which sends event earlier than transaction commit.
// assertAdminEvents.assertEmpty();
assertAdminEvents.poll();
}
}
@ -673,6 +705,7 @@ public class UserTest extends AbstractAdminTest {
cred.setTemporary(false);
realm.users().get(userId).resetPassword(cred);
assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userResetPasswordPath(userId));
String accountUrl = RealmsResource.accountUrl(UriBuilder.fromUri(getAuthServerRoot())).build(REALM_NAME).toString();
@ -699,6 +732,7 @@ public class UserTest extends AbstractAdminTest {
} catch (ClientErrorException e) {
assertEquals(400, e.getResponse().getStatus());
e.getResponse().close();
assertAdminEvents.assertEmpty();
}
}
@ -725,25 +759,33 @@ public class UserTest extends AbstractAdminTest {
@Test
public void roleMappings() {
RealmResource realm = adminClient.realms().realm("test");
// Enable events
RealmRepresentation realmRep = RealmBuilder.edit(realm.toRepresentation()).testEventListener().build();
realm.update(realmRep);
realm.roles().create(RoleBuilder.create().name("realm-role").build());
realm.roles().create(RoleBuilder.create().name("realm-composite").build());
realm.roles().create(RoleBuilder.create().name("realm-child").build());
realm.roles().get("realm-composite").addComposites(Collections.singletonList(realm.roles().get("realm-child").toRepresentation()));
Response response = realm.clients().create(ClientBuilder.create().clientId("myclient").build());
String clientId = ApiUtil.getCreatedId(response);
String clientUuid = ApiUtil.getCreatedId(response);
response.close();
realm.clients().get(clientId).roles().create(RoleBuilder.create().name("client-role").build());
realm.clients().get(clientId).roles().create(RoleBuilder.create().name("client-role2").build());
realm.clients().get(clientId).roles().create(RoleBuilder.create().name("client-composite").build());
realm.clients().get(clientId).roles().create(RoleBuilder.create().name("client-child").build());
realm.clients().get(clientId).roles().get("client-composite").addComposites(Collections.singletonList(realm.clients().get(clientId).roles().get("client-child").toRepresentation()));
realm.clients().get(clientUuid).roles().create(RoleBuilder.create().name("client-role").build());
realm.clients().get(clientUuid).roles().create(RoleBuilder.create().name("client-role2").build());
realm.clients().get(clientUuid).roles().create(RoleBuilder.create().name("client-composite").build());
realm.clients().get(clientUuid).roles().create(RoleBuilder.create().name("client-child").build());
realm.clients().get(clientUuid).roles().get("client-composite").addComposites(Collections.singletonList(realm.clients().get(clientUuid).roles().get("client-child").toRepresentation()));
response = realm.users().create(UserBuilder.create().username("myuser").build());
String userId = ApiUtil.getCreatedId(response);
response.close();
// Admin events for creating role, client or user tested already in other places
assertAdminEvents.clear();
RoleMappingResource roles = realm.users().get(userId).roles();
assertNames(roles.realmLevel().listAll(), "user", "offline_access");
@ -752,10 +794,14 @@ public class UserTest extends AbstractAdminTest {
l.add(realm.roles().get("realm-role").toRepresentation());
l.add(realm.roles().get("realm-composite").toRepresentation());
roles.realmLevel().add(l);
assertAdminEvents.assertEvent("test", OperationType.CREATE, Matchers.startsWith(AdminEventPaths.userRealmRoleMappingsPath(userId)));
assertAdminEvents.assertEvent("test", OperationType.CREATE, Matchers.startsWith(AdminEventPaths.userRealmRoleMappingsPath(userId)));
// Add client roles
roles.clientLevel(clientId).add(Collections.singletonList(realm.clients().get(clientId).roles().get("client-role").toRepresentation()));
roles.clientLevel(clientId).add(Collections.singletonList(realm.clients().get(clientId).roles().get("client-composite").toRepresentation()));
roles.clientLevel(clientUuid).add(Collections.singletonList(realm.clients().get(clientUuid).roles().get("client-role").toRepresentation()));
roles.clientLevel(clientUuid).add(Collections.singletonList(realm.clients().get(clientUuid).roles().get("client-composite").toRepresentation()));
assertAdminEvents.assertEvent("test", OperationType.CREATE, Matchers.startsWith(AdminEventPaths.userClientRoleMappingsPath(userId, clientUuid)));
assertAdminEvents.assertEvent("test", OperationType.CREATE, Matchers.startsWith(AdminEventPaths.userClientRoleMappingsPath(userId, clientUuid)));
// List realm roles
assertNames(roles.realmLevel().listAll(), "realm-role", "realm-composite", "user", "offline_access");
@ -763,9 +809,9 @@ public class UserTest extends AbstractAdminTest {
assertNames(roles.realmLevel().listEffective(), "realm-role", "realm-composite", "realm-child", "user", "offline_access");
// List client roles
assertNames(roles.clientLevel(clientId).listAll(), "client-role", "client-composite");
assertNames(roles.clientLevel(clientId).listAvailable(), "client-role2");
assertNames(roles.clientLevel(clientId).listEffective(), "client-role", "client-composite", "client-child");
assertNames(roles.clientLevel(clientUuid).listAll(), "client-role", "client-composite");
assertNames(roles.clientLevel(clientUuid).listAvailable(), "client-role2");
assertNames(roles.clientLevel(clientUuid).listEffective(), "client-role", "client-composite", "client-child");
// Get mapping representation
MappingsRepresentation all = roles.getAll();
@ -775,18 +821,27 @@ public class UserTest extends AbstractAdminTest {
assertNames(all.getClientMappings().get("account").getMappings(), "manage-account", "view-profile");
// Remove realm role
roles.realmLevel().remove(Collections.singletonList(realm.roles().get("realm-role").toRepresentation()));
RoleRepresentation realmRoleRep = realm.roles().get("realm-role").toRepresentation();
roles.realmLevel().remove(Collections.singletonList(realmRoleRep));
assertAdminEvents.assertEvent("test", OperationType.DELETE, AdminEventPaths.userRealmRoleMappingsPath(userId) + "/" + realmRoleRep.getId());
assertNames(roles.realmLevel().listAll(), "realm-composite", "user", "offline_access");
// Remove client role
roles.clientLevel(clientId).remove(Collections.singletonList(realm.clients().get(clientId).roles().get("client-role").toRepresentation()));
assertNames(roles.clientLevel(clientId).listAll(), "client-composite");
RoleRepresentation clientRoleRep = realm.clients().get(clientUuid).roles().get("client-role").toRepresentation();
roles.clientLevel(clientUuid).remove(Collections.singletonList(clientRoleRep));
// TODO: Inconsistency between event for delete realm role mapping and client role mapping (the latter doesn't have roleRep.getId() in the path)
assertAdminEvents.assertEvent("test", OperationType.DELETE, AdminEventPaths.userClientRoleMappingsPath(userId, clientUuid));
assertNames(roles.clientLevel(clientUuid).listAll(), "client-composite");
}
private void switchEditUsernameAllowedOn() {
RealmRepresentation rep = realm.toRepresentation();
rep.setEditUsernameAllowed(true);
realm.update(rep);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep);
}
}

View file

@ -19,12 +19,21 @@ package org.keycloak.testsuite.admin.client;
import java.util.List;
import javax.ws.rs.core.Response;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.events.admin.OperationType;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.AbstractAuthTest;
import org.keycloak.testsuite.admin.ApiUtil;
import org.keycloak.testsuite.events.EventsListenerProviderFactory;
import org.keycloak.testsuite.util.AdminEventPaths;
import org.keycloak.testsuite.util.AssertAdminEvents;
import org.keycloak.testsuite.util.RealmBuilder;
/**
*
@ -32,10 +41,32 @@ import org.keycloak.testsuite.admin.ApiUtil;
*/
public abstract class AbstractClientTest extends AbstractAuthTest {
@Rule
public AssertAdminEvents assertAdminEvents = new AssertAdminEvents(this);
@Before
public void setupAdminEvents() {
RealmRepresentation realm = testRealmResource().toRepresentation();
if (realm.getEventsListeners() == null || !realm.getEventsListeners().contains(EventsListenerProviderFactory.PROVIDER_ID)) {
realm = RealmBuilder.edit(testRealmResource().toRepresentation()).testEventListener().build();
testRealmResource().update(realm);
}
}
@After
public void tearDownAdminEvents() {
RealmRepresentation realm = RealmBuilder.edit(testRealmResource().toRepresentation()).removeTestEventListener().build();
testRealmResource().update(realm);
}
protected RealmRepresentation realmRep() {
return testRealmResource().toRepresentation();
}
protected String getRealmId() {
return "master";
}
// returns UserRepresentation retrieved from server, with all fields, including id
protected UserRepresentation getFullUserRep(String userName) {
List<UserRepresentation> results = testRealmResource().users().search(userName, null, null, null, null, null);
@ -64,7 +95,17 @@ public abstract class AbstractClientTest extends AbstractAuthTest {
protected String createClient(ClientRepresentation clientRep) {
Response resp = testRealmResource().clients().create(clientRep);
resp.close();
return ApiUtil.getCreatedId(resp);
String id = ApiUtil.getCreatedId(resp);
assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientResourcePath(id), clientRep);
return id;
}
protected void removeClient(String clientDbId) {
testRealmResource().clients().get(clientDbId).remove();
assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientResourcePath(clientDbId));
}
protected ClientRepresentation findClientRepresentation(String name) {

View file

@ -17,13 +17,20 @@
package org.keycloak.testsuite.admin.client;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.core.type.TypeReference;
import org.keycloak.admin.client.resource.ProtocolMappersResource;
import org.keycloak.events.admin.OperationType;
import org.keycloak.representations.idm.AdminEventRepresentation;
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
import org.keycloak.testsuite.Assert;
import org.keycloak.util.JsonSerialization;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@ -93,16 +100,31 @@ public abstract class AbstractProtocolMapperTest extends AbstractClientTest {
return mappersToAdd;
}
protected void testAddAllBuiltinMappers(ProtocolMappersResource resource, String resourceName) {
List<ProtocolMapperRepresentation> oldMappers = resource.getMappersPerProtocol(resourceName);
List<ProtocolMapperRepresentation> builtins = builtinMappers.get(resourceName);
protected void testAddAllBuiltinMappers(ProtocolMappersResource resource, String protocolName, String adminEventPath) {
List<ProtocolMapperRepresentation> oldMappers = resource.getMappersPerProtocol(protocolName);
List<ProtocolMapperRepresentation> builtins = builtinMappers.get(protocolName);
List<ProtocolMapperRepresentation> mappersToAdd = mappersToAdd(oldMappers, builtins);
// This is used by admin console to add builtin mappers
resource.createMapper(mappersToAdd);
List<ProtocolMapperRepresentation> newMappers = resource.getMappersPerProtocol(resourceName);
AdminEventRepresentation adminEvent = assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, adminEventPath + "/add-models");
try {
List<ProtocolMapperRepresentation> eventMappers = JsonSerialization.readValue(new ByteArrayInputStream(adminEvent.getRepresentation().getBytes()), new TypeReference<List<ProtocolMapperRepresentation>>() {
});
Assert.assertEquals(eventMappers.size(), mappersToAdd.size());
for (int i=0 ; i< mappersToAdd.size() ; i++) {
ProtocolMapperRepresentation repExpected = mappersToAdd.get(i);
ProtocolMapperRepresentation repActual = eventMappers.get(i);
assertEqualMappers(repExpected, repActual);
}
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
List<ProtocolMapperRepresentation> newMappers = resource.getMappersPerProtocol(protocolName);
assertEquals(oldMappers.size() + mappersToAdd.size(), newMappers.size());
for (ProtocolMapperRepresentation rep : mappersToAdd) {

View file

@ -24,8 +24,11 @@ import org.junit.Before;
import org.junit.Test;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.admin.client.resource.ProtocolMappersResource;
import org.keycloak.events.admin.OperationType;
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.admin.ApiUtil;
import org.keycloak.testsuite.util.AdminEventPaths;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@ -37,17 +40,19 @@ import static org.junit.Assert.assertFalse;
public class ClientProtocolMapperTest extends AbstractProtocolMapperTest {
private ClientResource oidcClientRsc;
private String oidcClientId;
private ProtocolMappersResource oidcMappersRsc;
private ClientResource samlClientRsc;
private String samlClientId;
private ProtocolMappersResource samlMappersRsc;
@Before
public void init() {
createOidcClient("oidcMapperClient");
oidcClientId = createOidcClient("oidcMapperClient");
oidcClientRsc = findClientResource("oidcMapperClient");
oidcMappersRsc = oidcClientRsc.getProtocolMappers();
createSamlClient("samlMapperClient");
samlClientId = createSamlClient("samlMapperClient");
samlClientRsc = findClientResource("samlMapperClient");
samlMappersRsc = samlClientRsc.getProtocolMappers();
@ -56,8 +61,8 @@ public class ClientProtocolMapperTest extends AbstractProtocolMapperTest {
@After
public void tearDown() {
oidcClientRsc.remove();
samlClientRsc.remove();
removeClient(oidcClientId);
removeClient(samlClientId);
}
@Test
@ -68,12 +73,12 @@ public class ClientProtocolMapperTest extends AbstractProtocolMapperTest {
@Test
public void testCreateOidcMappersFromList() {
testAddAllBuiltinMappers(oidcMappersRsc, "openid-connect");
testAddAllBuiltinMappers(oidcMappersRsc, "openid-connect", AdminEventPaths.clientProtocolMappersPath(oidcClientId));
}
@Test
public void testCreateSamlMappersFromList() {
testAddAllBuiltinMappers(samlMappersRsc, "saml");
testAddAllBuiltinMappers(samlMappersRsc, "saml", AdminEventPaths.clientProtocolMappersPath(samlClientId));
}
@Test
@ -91,10 +96,12 @@ public class ClientProtocolMapperTest extends AbstractProtocolMapperTest {
int totalSamlMappers = samlMappersRsc.getMappersPerProtocol("saml").size();
Response resp = samlMappersRsc.createMapper(rep);
resp.close();
String createdId = ApiUtil.getCreatedId(resp);
assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientProtocolMapperPath(samlClientId, createdId), rep);
assertEquals(totalMappers + 1, samlMappersRsc.getMappers().size());
assertEquals(totalSamlMappers + 1, samlMappersRsc.getMappersPerProtocol("saml").size());
String createdId = ApiUtil.getCreatedId(resp);
ProtocolMapperRepresentation created = samlMappersRsc.getMapperById(createdId);
assertEqualMappers(rep, created);
}
@ -113,12 +120,15 @@ public class ClientProtocolMapperTest extends AbstractProtocolMapperTest {
int totalOidcMappers = oidcMappersRsc.getMappersPerProtocol("openid-connect").size();
Response resp = oidcMappersRsc.createMapper(rep);
resp.close();
String createdId = ApiUtil.getCreatedId(resp);
assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientProtocolMapperPath(oidcClientId, createdId), rep);
assertEquals(totalMappers + 1, oidcMappersRsc.getMappers().size());
assertEquals(totalOidcMappers + 1, oidcMappersRsc.getMappersPerProtocol("openid-connect").size());
String createdId = ApiUtil.getCreatedId(resp);
ProtocolMapperRepresentation created = oidcMappersRsc.getMapperById(createdId);//findByName(samlMappersRsc, "saml-role-name-mapper");
assertEqualMappers(rep, created);
}
@Test
@ -127,13 +137,14 @@ public class ClientProtocolMapperTest extends AbstractProtocolMapperTest {
Response resp = samlMappersRsc.createMapper(rep);
resp.close();
String createdId = ApiUtil.getCreatedId(resp);
assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientProtocolMapperPath(samlClientId, createdId), rep);
rep.getConfig().put("role", "account.manage-account");
rep.setId(createdId);
rep.setConsentRequired(false);
samlMappersRsc.update(createdId, rep);
assertAdminEvents.assertEvent(getRealmId(), OperationType.UPDATE, AdminEventPaths.clientProtocolMapperPath(samlClientId, createdId), rep);
ProtocolMapperRepresentation updated = samlMappersRsc.getMapperById(createdId);
assertEqualMappers(rep, updated);
@ -145,44 +156,57 @@ public class ClientProtocolMapperTest extends AbstractProtocolMapperTest {
Response resp = oidcMappersRsc.createMapper(rep);
resp.close();
String createdId = ApiUtil.getCreatedId(resp);
assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientProtocolMapperPath(oidcClientId, createdId), rep);
rep.getConfig().put("role", "myotherrole");
rep.setId(createdId);
rep.setConsentRequired(false);
oidcMappersRsc.update(createdId, rep);
assertAdminEvents.assertEvent(getRealmId(), OperationType.UPDATE, AdminEventPaths.clientProtocolMapperPath(oidcClientId, createdId), rep);
ProtocolMapperRepresentation updated = oidcMappersRsc.getMapperById(createdId);
assertEqualMappers(rep, updated);
}
@Test (expected = NotFoundException.class)
@Test
public void testDeleteSamlMapper() {
ProtocolMapperRepresentation rep = makeSamlMapper("saml-role-name-mapper3");
Response resp = samlMappersRsc.createMapper(rep);
resp.close();
String createdId = ApiUtil.getCreatedId(resp);
assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientProtocolMapperPath(samlClientId, createdId), rep);
samlMappersRsc.delete(createdId);
assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientProtocolMapperPath(samlClientId, createdId));
try {
samlMappersRsc.getMapperById(createdId);
Assert.fail("Not expected to find mapper");
} catch (NotFoundException nfe) {
// Expected
}
}
@Test (expected = NotFoundException.class)
@Test
public void testDeleteOidcMapper() {
ProtocolMapperRepresentation rep = makeOidcMapper("oidc-hardcoded-role-mapper3");
Response resp = oidcMappersRsc.createMapper(rep);
resp.close();
String createdId = ApiUtil.getCreatedId(resp);
assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientProtocolMapperPath(oidcClientId, createdId), rep);
oidcMappersRsc.delete(createdId);
assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientProtocolMapperPath(oidcClientId, createdId));
try {
oidcMappersRsc.getMapperById(createdId);
Assert.fail("Not expected to find mapper");
} catch (NotFoundException nfe) {
// Expected
}
}
}

View file

@ -17,13 +17,16 @@
package org.keycloak.testsuite.admin.client;
import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.admin.client.resource.RolesResource;
import org.keycloak.events.admin.OperationType;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.util.AdminEventPaths;
import org.keycloak.testsuite.util.RoleBuilder;
import java.util.LinkedList;
@ -41,11 +44,12 @@ import static org.junit.Assert.assertTrue;
public class ClientRolesTest extends AbstractClientTest {
private ClientResource clientRsc;
private String clientDbId;
private RolesResource rolesRsc;
@Before
public void init() {
createOidcClient("roleClient");
clientDbId = createOidcClient("roleClient");
clientRsc = findClientResource("roleClient");
rolesRsc = clientRsc.roles();
}
@ -72,30 +76,42 @@ public class ClientRolesTest extends AbstractClientTest {
@Test
public void testAddRole() {
rolesRsc.create(makeRole("role1"));
assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, Matchers.startsWith(AdminEventPaths.clientRolesResourcePath(clientDbId)));
assertTrue(hasRole(rolesRsc, "role1"));
}
@Test
public void testRemoveRole() {
rolesRsc.create(makeRole("role2"));
assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, Matchers.startsWith(AdminEventPaths.clientRolesResourcePath(clientDbId)));
rolesRsc.deleteRole("role2");
assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientRoleResourcePath(clientDbId, "role2"));
assertFalse(hasRole(rolesRsc, "role2"));
}
@Test
public void testComposites() {
rolesRsc.create(makeRole("role-a"));
assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, Matchers.startsWith(AdminEventPaths.clientRolesResourcePath(clientDbId)));
assertFalse(rolesRsc.get("role-a").toRepresentation().isComposite());
assertEquals(0, rolesRsc.get("role-a").getRoleComposites().size());
rolesRsc.create(makeRole("role-b"));
assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, Matchers.startsWith(AdminEventPaths.clientRolesResourcePath(clientDbId)));
testRealmResource().roles().create(makeRole("role-c"));
assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, Matchers.startsWith(AdminEventPaths.rolesResourcePath()));
List<RoleRepresentation> l = new LinkedList<>();
l.add(rolesRsc.get("role-b").toRepresentation());
l.add(testRealmResource().roles().get("role-c").toRepresentation());
rolesRsc.get("role-a").addComposites(l);
// TODO adminEvents: Fix once composite roles events will be fixed...
assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, Matchers.startsWith(AdminEventPaths.clientRoleResourceCompositesPath(clientDbId, "role-a")));
assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, Matchers.startsWith(AdminEventPaths.clientRoleResourceCompositesPath(clientDbId, "role-a")));
Set<RoleRepresentation> composites = rolesRsc.get("role-a").getRoleComposites();
@ -109,6 +125,7 @@ public class ClientRolesTest extends AbstractClientTest {
Assert.assertNames(clientComposites, "role-b");
rolesRsc.get("role-a").deleteComposites(l);
assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientRoleResourceCompositesPath(clientDbId, "role-a"));
assertFalse(rolesRsc.get("role-a").toRepresentation().isComposite());
assertEquals(0, rolesRsc.get("role-a").getRoleComposites().size());

View file

@ -29,11 +29,13 @@ import org.junit.runners.MethodSorters;
import org.keycloak.admin.client.resource.ClientTemplateResource;
import org.keycloak.admin.client.resource.ClientTemplatesResource;
import org.keycloak.admin.client.resource.ProtocolMappersResource;
import org.keycloak.events.admin.OperationType;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.protocol.saml.SamlProtocol;
import org.keycloak.representations.idm.ClientTemplateRepresentation;
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
import org.keycloak.testsuite.admin.ApiUtil;
import org.keycloak.testsuite.util.AdminEventPaths;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@ -44,26 +46,26 @@ import static org.junit.Assert.assertTrue;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ClientTemplateProtocolMapperTest extends AbstractProtocolMapperTest {
private ClientTemplateResource oidcClientTemplateRsc;
private String oidcClientTemplateId;
private ProtocolMappersResource oidcMappersRsc;
private ClientTemplateResource samlClientTemplateRsc;
private String samlClientTemplateId;
private ProtocolMappersResource samlMappersRsc;
@Before
public void init() {
oidcClientTemplateRsc = createTemplate("oidcMapperClient-template", OIDCLoginProtocol.LOGIN_PROTOCOL);
oidcMappersRsc = oidcClientTemplateRsc.getProtocolMappers();
oidcClientTemplateId = createTemplate("oidcMapperClient-template", OIDCLoginProtocol.LOGIN_PROTOCOL);
oidcMappersRsc = clientTemplates().get(oidcClientTemplateId).getProtocolMappers();
samlClientTemplateRsc = createTemplate("samlMapperClient-template", SamlProtocol.LOGIN_PROTOCOL);
samlMappersRsc = samlClientTemplateRsc.getProtocolMappers();
samlClientTemplateId = createTemplate("samlMapperClient-template", SamlProtocol.LOGIN_PROTOCOL);
samlMappersRsc = clientTemplates().get(samlClientTemplateId).getProtocolMappers();
super.initBuiltinMappers();
}
@After
public void tearDown() {
oidcClientTemplateRsc.remove();
samlClientTemplateRsc.remove();
removeTemplate(oidcClientTemplateId);
removeTemplate(samlClientTemplateId);
}
@Test
@ -74,12 +76,12 @@ public class ClientTemplateProtocolMapperTest extends AbstractProtocolMapperTest
@Test
public void test02CreateOidcMappersFromList() {
testAddAllBuiltinMappers(oidcMappersRsc, "openid-connect");
testAddAllBuiltinMappers(oidcMappersRsc, "openid-connect", AdminEventPaths.clientTemplateProtocolMappersPath(oidcClientTemplateId));
}
@Test
public void test03CreateSamlMappersFromList() {
testAddAllBuiltinMappers(samlMappersRsc, "saml");
testAddAllBuiltinMappers(samlMappersRsc, "saml", AdminEventPaths.clientTemplateProtocolMappersPath(samlClientTemplateId));
}
@Test
@ -97,10 +99,13 @@ public class ClientTemplateProtocolMapperTest extends AbstractProtocolMapperTest
int totalSamlMappers = samlMappersRsc.getMappersPerProtocol("saml").size();
Response resp = samlMappersRsc.createMapper(rep);
resp.close();
String createdId = ApiUtil.getCreatedId(resp);
assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateProtocolMapperPath(samlClientTemplateId, createdId), rep);
assertEquals(totalMappers + 1, samlMappersRsc.getMappers().size());
assertEquals(totalSamlMappers + 1, samlMappersRsc.getMappersPerProtocol("saml").size());
String createdId = ApiUtil.getCreatedId(resp);
ProtocolMapperRepresentation created = samlMappersRsc.getMapperById(createdId);
assertEqualMappers(rep, created);
}
@ -119,10 +124,13 @@ public class ClientTemplateProtocolMapperTest extends AbstractProtocolMapperTest
int totalOidcMappers = oidcMappersRsc.getMappersPerProtocol("openid-connect").size();
Response resp = oidcMappersRsc.createMapper(rep);
resp.close();
String createdId = ApiUtil.getCreatedId(resp);
assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateProtocolMapperPath(oidcClientTemplateId, createdId), rep);
assertEquals(totalMappers + 1, oidcMappersRsc.getMappers().size());
assertEquals(totalOidcMappers + 1, oidcMappersRsc.getMappersPerProtocol("openid-connect").size());
String createdId = ApiUtil.getCreatedId(resp);
ProtocolMapperRepresentation created = oidcMappersRsc.getMapperById(createdId);//findByName(samlMappersRsc, "saml-role-name-mapper");
assertEqualMappers(rep, created);
}
@ -133,13 +141,14 @@ public class ClientTemplateProtocolMapperTest extends AbstractProtocolMapperTest
Response resp = samlMappersRsc.createMapper(rep);
resp.close();
String createdId = ApiUtil.getCreatedId(resp);
assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateProtocolMapperPath(samlClientTemplateId, createdId), rep);
rep.getConfig().put("role", "account.manage-account");
rep.setId(createdId);
rep.setConsentRequired(false);
samlMappersRsc.update(createdId, rep);
assertAdminEvents.assertEvent(getRealmId(), OperationType.UPDATE, AdminEventPaths.clientTemplateProtocolMapperPath(samlClientTemplateId, createdId), rep);
ProtocolMapperRepresentation updated = samlMappersRsc.getMapperById(createdId);
assertEqualMappers(rep, updated);
@ -151,44 +160,57 @@ public class ClientTemplateProtocolMapperTest extends AbstractProtocolMapperTest
Response resp = oidcMappersRsc.createMapper(rep);
resp.close();
String createdId = ApiUtil.getCreatedId(resp);
assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateProtocolMapperPath(oidcClientTemplateId, createdId), rep);
rep.getConfig().put("role", "myotherrole");
rep.setId(createdId);
rep.setConsentRequired(false);
oidcMappersRsc.update(createdId, rep);
assertAdminEvents.assertEvent(getRealmId(), OperationType.UPDATE, AdminEventPaths.clientTemplateProtocolMapperPath(oidcClientTemplateId, createdId), rep);
ProtocolMapperRepresentation updated = oidcMappersRsc.getMapperById(createdId);
assertEqualMappers(rep, updated);
}
@Test (expected = NotFoundException.class)
@Test
public void testDeleteSamlMapper() {
ProtocolMapperRepresentation rep = makeSamlMapper("saml-role-name-mapper3");
Response resp = samlMappersRsc.createMapper(rep);
resp.close();
String createdId = ApiUtil.getCreatedId(resp);
assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateProtocolMapperPath(samlClientTemplateId, createdId), rep);
samlMappersRsc.delete(createdId);
assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientTemplateProtocolMapperPath(samlClientTemplateId, createdId));
try {
samlMappersRsc.getMapperById(createdId);
Assert.fail("Not expected to find mapper");
} catch (NotFoundException nfe) {
// Expected
}
}
@Test (expected = NotFoundException.class)
@Test
public void testDeleteOidcMapper() {
ProtocolMapperRepresentation rep = makeOidcMapper("oidc-hardcoded-role-mapper3");
Response resp = oidcMappersRsc.createMapper(rep);
resp.close();
String createdId = ApiUtil.getCreatedId(resp);
assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateProtocolMapperPath(oidcClientTemplateId, createdId), rep);
oidcMappersRsc.delete(createdId);
assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientTemplateProtocolMapperPath(oidcClientTemplateId, createdId));
try {
oidcMappersRsc.getMapperById(createdId);
Assert.fail("Not expected to find mapper");
} catch (NotFoundException nfe) {
// Expected
}
}
@ -196,7 +218,7 @@ public class ClientTemplateProtocolMapperTest extends AbstractProtocolMapperTest
return testRealmResource().clientTemplates();
}
private ClientTemplateResource createTemplate(String templateName, String protocol) {
private String createTemplate(String templateName, String protocol) {
ClientTemplateRepresentation rep = new ClientTemplateRepresentation();
rep.setName(templateName);
rep.setFullScopeAllowed(false);
@ -204,7 +226,15 @@ public class ClientTemplateProtocolMapperTest extends AbstractProtocolMapperTest
Response resp = clientTemplates().create(rep);
Assert.assertEquals(201, resp.getStatus());
resp.close();
String clientTemplateId = ApiUtil.getCreatedId(resp);
return clientTemplates().get(clientTemplateId);
String templateId = ApiUtil.getCreatedId(resp);
assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateResourcePath(templateId), rep);
return templateId;
}
private void removeTemplate(String templateId) {
clientTemplates().get(templateId).remove();
assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientTemplateResourcePath(templateId));
}
}

View file

@ -27,10 +27,12 @@ import javax.ws.rs.BadRequestException;
import javax.ws.rs.NotFoundException;
import javax.ws.rs.core.Response;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Test;
import org.keycloak.admin.client.resource.ClientTemplatesResource;
import org.keycloak.admin.client.resource.RoleMappingResource;
import org.keycloak.events.admin.OperationType;
import org.keycloak.models.AccountRoles;
import org.keycloak.models.Constants;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
@ -41,6 +43,7 @@ import org.keycloak.representations.idm.ErrorRepresentation;
import org.keycloak.representations.idm.MappingsRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.testsuite.admin.ApiUtil;
import org.keycloak.testsuite.util.AdminEventPaths;
import static org.junit.Assert.assertEquals;
@ -64,7 +67,7 @@ public class ClientTemplateTest extends AbstractClientTest {
Assert.assertEquals("Client Template template1 already exists", error.getErrorMessage());
// Cleanup
clientTemplates().get(templateId).remove();
removeTemplate(templateId);
}
@ -94,7 +97,7 @@ public class ClientTemplateTest extends AbstractClientTest {
Assert.assertEquals(2, clientTemplates.size());
// Remove template1
clientTemplates().get(template1Id).remove();
removeTemplate(template1Id);
clientTemplates = clientTemplates().findAll();
Assert.assertEquals(1, clientTemplates.size());
@ -102,7 +105,7 @@ public class ClientTemplateTest extends AbstractClientTest {
// Remove template2
clientTemplates().get(template2Id).remove();
removeTemplate(template2Id);
clientTemplates = clientTemplates().findAll();
Assert.assertEquals(0, clientTemplates.size());
@ -135,6 +138,8 @@ public class ClientTemplateTest extends AbstractClientTest {
clientTemplates().get(template1Id).update(templateRep);
assertAdminEvents.assertEvent(getRealmId(), OperationType.UPDATE, AdminEventPaths.clientTemplateResourcePath(template1Id), templateRep);
// Assert updated attributes
templateRep = clientTemplates().get(template1Id).toRepresentation();
Assert.assertEquals("template1-updated", templateRep.getName());
@ -150,20 +155,14 @@ public class ClientTemplateTest extends AbstractClientTest {
@Test
public void testScopes() {
// Add realm role1
RoleRepresentation roleRep1 = new RoleRepresentation();
roleRep1.setName("role1");
testRealmResource().roles().create(roleRep1);
roleRep1 = testRealmResource().roles().get("role1").toRepresentation();
RoleRepresentation roleRep1 = createRealmRole("role1");
// Add realm role2
RoleRepresentation roleRep2 = roleRep2 = new RoleRepresentation();
roleRep2.setName("role2");
testRealmResource().roles().create(roleRep2);
roleRep2 = testRealmResource().roles().get("role2").toRepresentation();
RoleRepresentation roleRep2 = createRealmRole("role2");
// Add role2 as composite to role1
testRealmResource().roles().get("role1").addComposites(Collections.singletonList(roleRep2));
assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, Matchers.startsWith(AdminEventPaths.roleResourceCompositesPath("role1")));
// create client template
ClientTemplateRepresentation templateRep = new ClientTemplateRepresentation();
@ -177,7 +176,10 @@ public class ClientTemplateTest extends AbstractClientTest {
RoleMappingResource scopesResource = clientTemplates().get(templateId).getScopeMappings();
scopesResource.realmLevel().add(Collections.singletonList(roleRep1));
assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateScopeMappingsRealmLevelPath(templateId) + "/" + roleRep1.getId());
scopesResource.clientLevel(accountMgmtId).add(Collections.singletonList(viewAccountRoleRep));
assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateScopeMappingsClientLevelPath(templateId, accountMgmtId) + "/" + viewAccountRoleRep.getId());
// test that scopes are available (also through composite role)
List<RoleRepresentation> allRealm = scopesResource.realmLevel().listAll();
@ -196,7 +198,10 @@ public class ClientTemplateTest extends AbstractClientTest {
// remove scopes
scopesResource.realmLevel().remove(Collections.singletonList(roleRep1));
assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientTemplateScopeMappingsRealmLevelPath(templateId) + "/" + roleRep1.getId());
scopesResource.clientLevel(accountMgmtId).remove(Collections.singletonList(viewAccountRoleRep));
assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientTemplateScopeMappingsClientLevelPath(templateId, accountMgmtId) + "/" + viewAccountRoleRep.getId());
// assert scopes are removed
allRealm = scopesResource.realmLevel().listAll();
@ -209,7 +214,7 @@ public class ClientTemplateTest extends AbstractClientTest {
assertRolesNotPresent(accountRoles, AccountRoles.VIEW_PROFILE);
// remove template
clientTemplates().get(templateId).remove();
removeTemplate(templateId);
}
private void assertRolesPresent(List<RoleRepresentation> roles, String... expectedRoleNames) {
@ -241,10 +246,7 @@ public class ClientTemplateTest extends AbstractClientTest {
@Test
public void testRemoveScopedRole() {
// Add realm role
RoleRepresentation roleRep = new RoleRepresentation();
roleRep.setName("foo-role");
testRealmResource().roles().create(roleRep);
roleRep = testRealmResource().roles().get("foo-role").toRepresentation();
RoleRepresentation roleRep = createRealmRole("foo-role");
// Add client template
ClientTemplateRepresentation templateRep = new ClientTemplateRepresentation();
@ -254,6 +256,7 @@ public class ClientTemplateTest extends AbstractClientTest {
// Add realm role to scopes of clientTemplate
clientTemplates().get(templateId).getScopeMappings().realmLevel().add(Collections.singletonList(roleRep));
assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateScopeMappingsRealmLevelPath(templateId) + "/" + roleRep.getId());
List<RoleRepresentation> roleReps = clientTemplates().get(templateId).getScopeMappings().realmLevel().listAll();
Assert.assertEquals(1, roleReps.size());
@ -261,13 +264,24 @@ public class ClientTemplateTest extends AbstractClientTest {
// Remove realm role
testRealmResource().roles().deleteRole("foo-role");
assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.roleResourcePath("foo-role"));
// Get scope mappings
roleReps = clientTemplates().get(templateId).getScopeMappings().realmLevel().listAll();
Assert.assertEquals(0, roleReps.size());
// Cleanup
clientTemplates().get(templateId).remove();
removeTemplate(templateId);
}
private RoleRepresentation createRealmRole(String roleName) {
RoleRepresentation roleRep = new RoleRepresentation();
roleRep.setName(roleName);
testRealmResource().roles().create(roleRep);
assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, Matchers.startsWith(AdminEventPaths.rolesResourcePath()));
return testRealmResource().roles().get(roleName).toRepresentation();
}
@ -295,13 +309,14 @@ public class ClientTemplateTest extends AbstractClientTest {
} catch (BadRequestException bre) {
ErrorRepresentation error = bre.getResponse().readEntity(ErrorRepresentation.class);
Assert.assertEquals("Cannot remove client template, it is currently in use", error.getErrorMessage());
assertAdminEvents.assertEmpty();
}
// Remove client
testRealmResource().clients().get(clientDbId).remove();
removeClient(clientDbId);
// Can remove clientTemplate now
clientTemplates().get(templateId).remove();
removeTemplate(templateId);
}
@ -313,7 +328,16 @@ public class ClientTemplateTest extends AbstractClientTest {
Response resp = clientTemplates().create(templateRep);
Assert.assertEquals(201, resp.getStatus());
resp.close();
return ApiUtil.getCreatedId(resp);
String templateId = ApiUtil.getCreatedId(resp);
assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.clientTemplateResourcePath(templateId), templateRep);
return templateId;
}
private void removeTemplate(String templateId) {
clientTemplates().get(templateId).remove();
assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientTemplateResourcePath(templateId));
}
}

View file

@ -18,9 +18,14 @@
package org.keycloak.testsuite.admin.client;
import java.util.List;
import org.junit.Rule;
import org.junit.Test;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.events.admin.OperationType;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.testsuite.util.AdminEventPaths;
import org.keycloak.testsuite.util.AssertAdminEvents;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@ -34,7 +39,6 @@ import static org.junit.Assert.assertTrue;
*/
public class ClientTest extends AbstractClientTest {
public static void assertEqualClients(ClientRepresentation expected, ClientRepresentation actual) {
assertEquals(expected.getClientId(), actual.getClientId());
assertEquals(expected.getName(), actual.getName());
@ -49,16 +53,20 @@ public class ClientTest extends AbstractClientTest {
@Test
public void testCreateClient() {
createOidcClient("foo");
assertEquals("foo", findClientRepresentation("foo").getName());
ClientRepresentation found = findClientRepresentation("foo");
assertEquals("foo", found.getName());
}
@Test
public void testDeleteClient() {
createOidcClient("deleteMe");
String clientDbId = createOidcClient("deleteMe");
ClientResource clientRsc = findClientResource("deleteMe");
assertNotNull(clientRsc);
clientRsc.remove();
assertNull(findClientResource("deleteMe"));
assertAdminEvents.assertEvent(getRealmId(), OperationType.DELETE, AdminEventPaths.clientResourcePath(clientDbId));
}
@Test
@ -74,6 +82,12 @@ public class ClientTest extends AbstractClientTest {
assertNotNull(updatedClient);
assertEquals("updateMe", updatedClient.getClientId());
assertEquals("iWasUpdated", updatedClient.getName());
// Assert admin event
ClientRepresentation expectedClientRep = new ClientRepresentation();
expectedClientRep.setClientId("updateMe");
expectedClientRep.setName("iWasUpdated");
assertAdminEvents.assertEvent(getRealmId(), OperationType.UPDATE, AdminEventPaths.clientResourcePath(clientRep.getId()), expectedClientRep);
}
@Test

View file

@ -24,9 +24,11 @@ import org.keycloak.admin.client.resource.ClientAttributeCertificateResource;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.representations.KeyStoreConfig;
import org.keycloak.events.admin.OperationType;
import org.keycloak.representations.idm.CertificateRepresentation;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.testsuite.util.AdminEventPaths;
import javax.ws.rs.core.MediaType;
@ -53,16 +55,23 @@ import static org.junit.Assert.assertTrue;
public class CredentialsTest extends AbstractClientTest {
private ClientResource accountClient;
private String accountClientDbId;
@Before
public void init() {
accountClient = findClientResourceById("account");
accountClientDbId = accountClient.toRepresentation().getId();
}
@Test
public void testGetAndRegenerateSecret() {
CredentialRepresentation oldCredential = accountClient.getSecret();
CredentialRepresentation newCredential = accountClient.generateNewSecret();
CredentialRepresentation secretRep = new CredentialRepresentation();
secretRep.setType(CredentialRepresentation.SECRET);
assertAdminEvents.assertEvent(getRealmId(), OperationType.ACTION, AdminEventPaths.clientGenerateSecretPath(accountClientDbId), secretRep);
assertNotNull(oldCredential);
assertNotNull(newCredential);
assertNotEquals(newCredential.getValue(), oldCredential.getValue());
@ -77,6 +86,12 @@ public class CredentialsTest extends AbstractClientTest {
assertNull(oldToken); // registration access token not saved in ClientRep
assertNotNull(newToken); // it's only available via regenerateRegistrationAccessToken()
assertNull(accountClient.toRepresentation().getRegistrationAccessToken());
// Test event
ClientRepresentation testedRep = new ClientRepresentation();
testedRep.setClientId(rep.getClientId());
testedRep.setRegistrationAccessToken(newToken);
assertAdminEvents.assertEvent(getRealmId(), OperationType.ACTION, AdminEventPaths.clientRegenerateRegistrationAccessTokenPath(accountClientDbId), testedRep);
}
@Test
@ -86,6 +101,8 @@ public class CredentialsTest extends AbstractClientTest {
CertificateRepresentation certFromGet = certRsc.getKeyInfo();
assertEquals(cert.getCertificate(), certFromGet.getCertificate());
assertEquals(cert.getPrivateKey(), certFromGet.getPrivateKey());
assertAdminEvents.assertEvent(getRealmId(), OperationType.ACTION, AdminEventPaths.clientCertificateGenerateSecretPath(accountClientDbId, "jwt.credential"), cert);
}
@Test

View file

@ -21,6 +21,7 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.events.admin.OperationType;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.testsuite.arquillian.AuthServerTestEnricher;
@ -37,21 +38,23 @@ public class InstallationTest extends AbstractClientTest {
private static final String SAML_NAME = "samlInstallationClient";
private ClientResource oidcClient;
private String oidcClientId;
private ClientResource samlClient;
private String samlClientId;
@Before
public void createClients() {
createOidcClient(OIDC_NAME);
oidcClientId = createOidcClient(OIDC_NAME);
oidcClient = findClientResource(OIDC_NAME);
createSamlClient(SAML_NAME);
samlClientId = createSamlClient(SAML_NAME);
samlClient = findClientResource(SAML_NAME);
}
@After
public void tearDown() {
oidcClient.remove();
samlClient.remove();
removeClient(oidcClientId);
removeClient(samlClientId);
}
private String authServerUrl() {

View file

@ -22,9 +22,11 @@ import org.jboss.arquillian.graphene.page.Page;
import org.junit.Before;
import org.junit.Test;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.events.admin.OperationType;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.representations.idm.UserSessionRepresentation;
import org.keycloak.testsuite.auth.page.account.AccountManagement;
import org.keycloak.testsuite.util.AdminEventPaths;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@ -42,7 +44,12 @@ public class SessionTest extends AbstractClientTest {
@Before
public void init() {
// make user test user exists in test realm
if (!testUserCreated) createTestUserWithAdminClient();
if (!testUserCreated) {
createTestUserWithAdminClient();
assertAdminEvents.assertEvent(getRealmId(), OperationType.CREATE, AdminEventPaths.userResourcePath(testUser.getId()));
assertAdminEvents.assertEvent(getRealmId(), OperationType.ACTION, AdminEventPaths.userResetPasswordPath(testUser.getId()));
}
testUserCreated = true;
}

View file

@ -0,0 +1,146 @@
/*
* 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.event;
import java.util.Collections;
import java.util.List;
import org.junit.Before;
import org.junit.ComparisonFailure;
import org.junit.Rule;
import org.junit.Test;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.events.admin.OperationType;
import org.keycloak.models.AdminRoles;
import org.keycloak.models.Constants;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.AbstractAuthTest;
import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.admin.ApiUtil;
import org.keycloak.testsuite.arquillian.AuthServerTestEnricher;
import org.keycloak.testsuite.util.AdminEventPaths;
import org.keycloak.testsuite.util.AssertAdminEvents;
import org.keycloak.testsuite.util.ClientBuilder;
import org.keycloak.testsuite.util.RealmBuilder;
import org.keycloak.testsuite.util.UserBuilder;
import static org.keycloak.testsuite.auth.page.AuthRealm.ADMIN;
import static org.keycloak.testsuite.auth.page.AuthRealm.MASTER;
/**
* Test authDetails in admin events
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class AdminEventAuthDetailsTest extends AbstractAuthTest {
@Rule
public AssertAdminEvents assertAdminEvents = new AssertAdminEvents(this);
private String masterAdminCliUuid;
private String masterAdminUserId;
private String masterAdminUser2Id;
private String realmUuid;
private String client1Uuid;
private String adminCliUuid;
private String admin1Id;
private String admin2Id;
private String appUserId;
@Override
public void addTestRealms(List<RealmRepresentation> testRealms) {
RealmBuilder realm = RealmBuilder.create().name("test").testEventListener();
client1Uuid = KeycloakModelUtils.generateId();
realm.client(ClientBuilder.create().id(client1Uuid).clientId("client1").publicClient().directAccessGrants());
admin1Id = KeycloakModelUtils.generateId();
realm.user(UserBuilder.create().id(admin1Id).username("admin1").password("password").role(Constants.REALM_MANAGEMENT_CLIENT_ID, AdminRoles.REALM_ADMIN));
admin2Id = KeycloakModelUtils.generateId();
realm.user(UserBuilder.create().id(admin2Id).username("admin2").password("password").role(Constants.REALM_MANAGEMENT_CLIENT_ID, AdminRoles.REALM_ADMIN));
appUserId = KeycloakModelUtils.generateId();
realm.user(UserBuilder.create().id(appUserId).username("app-user").password("password"));
testRealms.add(realm.build());
}
@Before
public void initConfig() {
RealmResource masterRealm = adminClient.realm(MASTER);
masterAdminCliUuid = ApiUtil.findClientByClientId(masterRealm, Constants.ADMIN_CLI_CLIENT_ID).toRepresentation().getId();
masterAdminUserId = ApiUtil.findUserByUsername(masterRealm, "admin").getId();
masterAdminUser2Id = ApiUtil.createUserAndResetPasswordWithAdminClient(masterRealm, UserBuilder.create().username("admin2").build(), "password");
masterRealm.users().get(masterAdminUser2Id).roles().realmLevel().add(Collections.singletonList(masterRealm.roles().get("admin").toRepresentation()));
RealmResource testRealm = adminClient.realm("test");
realmUuid = testRealm.toRepresentation().getId();
adminCliUuid = ApiUtil.findClientByClientId(testRealm, Constants.ADMIN_CLI_CLIENT_ID).toRepresentation().getId();
}
@Test
public void testAuth() {
testClient(MASTER, ADMIN, ADMIN, Constants.ADMIN_CLI_CLIENT_ID, MASTER, masterAdminCliUuid, masterAdminUserId);
testClient(MASTER, "admin2", "password", Constants.ADMIN_CLI_CLIENT_ID, MASTER, masterAdminCliUuid, masterAdminUser2Id);
testClient("test", "admin1", "password", Constants.ADMIN_CLI_CLIENT_ID, realmUuid, adminCliUuid, admin1Id);
testClient("test", "admin2", "password", Constants.ADMIN_CLI_CLIENT_ID, realmUuid, adminCliUuid, admin2Id);
testClient("test", "admin1", "password", "client1", realmUuid, client1Uuid, admin1Id);
testClient("test", "admin2", "password", "client1", realmUuid, client1Uuid, admin2Id);
// Should fail due to different client UUID
try {
testClient("test", "admin1", "password", "client1", realmUuid, adminCliUuid, admin1Id);
Assert.fail("Not expected to pass");
} catch (ComparisonFailure expected) {
// expected
}
// Should fail due to different user ID
try {
testClient("test", "admin1", "password", "client1", realmUuid, client1Uuid, admin2Id);
Assert.fail("Not expected to pass");
} catch (ComparisonFailure expected) {
// expected
}
}
private void testClient(String realmName, String username, String password, String clientId, String expectedRealmId, String expectedClientUuid, String expectedUserId) {
Keycloak keycloak = Keycloak.getInstance(AuthServerTestEnricher.getAuthServerContextRoot() + "/auth",
realmName, username, password, clientId);
try {
UserRepresentation rep = UserBuilder.create().id(appUserId).username("app-user").email("foo@email.org").build();
keycloak.realm("test").users().get(appUserId).update(rep);
assertAdminEvents.expect()
.realmId(realmUuid)
.operationType(OperationType.UPDATE)
.resourcePath(AdminEventPaths.userResourcePath(appUserId))
.representation(rep)
.authDetails(expectedRealmId, expectedClientUuid, expectedUserId)
.assertEvent();
} finally {
keycloak.close();
}
}
}

View file

@ -31,6 +31,7 @@ import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.AssertEvents;
import org.keycloak.testsuite.arquillian.AuthServerTestEnricher;
import org.keycloak.testsuite.util.AssertAdminEvents;
import org.keycloak.testsuite.util.OAuthClient.AccessTokenResponse;
import java.security.PublicKey;
@ -46,6 +47,9 @@ public abstract class AbstractGroupTest extends AbstractKeycloakTest {
@Rule
public AssertEvents events = new AssertEvents(this);
@Rule
public AssertAdminEvents assertAdminEvents = new AssertAdminEvents(this);
AccessToken login(String login, String clientId, String clientSecret, String userId) throws Exception {
AccessTokenResponse tokenResponse = oauth.doGrantAccessTokenRequest("test", login, "password", null, clientId, clientSecret);

View file

@ -17,10 +17,12 @@
package org.keycloak.testsuite.admin.group;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Test;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.admin.client.resource.RoleMappingResource;
import org.keycloak.events.admin.OperationType;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.CredentialRepresentation;
@ -30,6 +32,7 @@ import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.admin.ApiUtil;
import org.keycloak.testsuite.util.AdminEventPaths;
import org.keycloak.testsuite.util.ClientBuilder;
import org.keycloak.testsuite.util.RoleBuilder;
import org.keycloak.testsuite.util.URLAssert;
@ -92,26 +95,47 @@ public class GroupTest extends AbstractGroupTest {
@Test
public void testClientRemoveWithClientRoleGroupMapping() throws Exception {
RealmResource realm = adminClient.realms().realm("test");
ClientRepresentation client = new ClientRepresentation();
client.setClientId("foo");
client.setRootUrl("http://foo");
client.setProtocol("openid-connect");
Response response = realm.clients().create(client);
response.close();
String clientUuid = ApiUtil.getCreatedId(response);
assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.clientResourcePath(clientUuid), client);
client = realm.clients().findByClientId("foo").get(0);
RoleRepresentation role = new RoleRepresentation();
role.setName("foo-role");
realm.clients().get(client.getId()).roles().create(role);
assertAdminEvents.assertEvent("test", OperationType.CREATE, Matchers.startsWith(AdminEventPaths.clientRolesResourcePath(clientUuid)), role);
role = realm.clients().get(client.getId()).roles().get("foo-role").toRepresentation();
GroupRepresentation group = new GroupRepresentation();
group.setName("2716");
realm.groups().add(group).close();
group = realm.getGroupByPath("/2716");
group = createGroup(realm, group);
List<RoleRepresentation> list = new LinkedList<>();
list.add(role);
realm.groups().group(group.getId()).roles().clientLevel(client.getId()).add(list);
realm.clients().get(client.getId()).remove();
assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.groupRolesClientRolesPath(group.getId(), clientUuid));
realm.clients().get(client.getId()).remove();
assertAdminEvents.assertEvent("test", OperationType.DELETE, AdminEventPaths.clientResourcePath(clientUuid));
}
private GroupRepresentation createGroup(RealmResource realm, GroupRepresentation group) {
Response response = realm.groups().add(group);
String groupId = ApiUtil.getCreatedId(response);
response.close();
// TODO adminEvents: ID of group is missing in create event
assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.groupsPath(), group);
// Set ID to the original rep
group.setId(groupId);
return group;
}
@Test
@ -136,21 +160,24 @@ public class GroupTest extends AbstractGroupTest {
}
RoleRepresentation level3Role = realm.roles().get("level3Role").toRepresentation();
// Role events tested elsewhere
assertAdminEvents.clear();
GroupRepresentation topGroup = new GroupRepresentation();
topGroup.setName("top");
Response response = realm.groups().add(topGroup);
response.close();
topGroup = realm.getGroupByPath("/top");
Assert.assertNotNull(topGroup);
topGroup = createGroup(realm, topGroup);
List<RoleRepresentation> roles = new LinkedList<>();
roles.add(topRole);
realm.groups().group(topGroup.getId()).roles().realmLevel().add(roles);
assertAdminEvents.assertEvent("test", OperationType.CREATE, Matchers.startsWith(AdminEventPaths.groupRolesRealmRolesPath(topGroup.getId())));
GroupRepresentation level2Group = new GroupRepresentation();
level2Group.setName("level2");
response = realm.groups().group(topGroup.getId()).subGroup(level2Group);
Response response = realm.groups().group(topGroup.getId()).subGroup(level2Group);
response.close();
// TODO adminEvents: Should be CREATE
assertAdminEvents.assertEvent("test", OperationType.UPDATE, AdminEventPaths.groupSubgroupsPath(topGroup.getId()), level2Group);
URI location = response.getLocation();
final String level2Id = ApiUtil.getCreatedId(response);
@ -171,16 +198,21 @@ public class GroupTest extends AbstractGroupTest {
roles.clear();
roles.add(level2Role);
realm.groups().group(level2Group.getId()).roles().realmLevel().add(roles);
assertAdminEvents.assertEvent("test", OperationType.CREATE, Matchers.startsWith(AdminEventPaths.groupRolesRealmRolesPath(level2Group.getId())));
GroupRepresentation level3Group = new GroupRepresentation();
level3Group.setName("level3");
response = realm.groups().group(level2Group.getId()).subGroup(level3Group);
response.close();
// TODO adminEvents: Should be CREATE
assertAdminEvents.assertEvent("test", OperationType.UPDATE, AdminEventPaths.groupSubgroupsPath(level2Group.getId()), level3Group);
level3Group = realm.getGroupByPath("/top/level2/level3");
Assert.assertNotNull(level3Group);
roles.clear();
roles.add(level3Role);
realm.groups().group(level3Group.getId()).roles().realmLevel().add(roles);
assertAdminEvents.assertEvent("test", OperationType.CREATE, Matchers.startsWith(AdminEventPaths.groupRolesRealmRolesPath(level3Group.getId())));
topGroup = realm.getGroupByPath("/top");
assertEquals(1, topGroup.getRealmRoles().size());
@ -200,6 +232,8 @@ public class GroupTest extends AbstractGroupTest {
UserRepresentation user = realm.users().search("direct-login", -1, -1).get(0);
realm.users().get(user.getId()).joinGroup(level3Group.getId());
assertAdminEvents.assertEvent("test", OperationType.CREATE, Matchers.startsWith(AdminEventPaths.userGroupPath(user.getId(), level3Group.getId())));
List<GroupRepresentation> membership = realm.users().get(user.getId()).groups();
assertEquals(1, membership.size());
assertEquals("level3", membership.get(0).getName());
@ -219,9 +253,11 @@ public class GroupTest extends AbstractGroupTest {
newUser.setUsername("groupUser");
newUser.setEmail("group@group.com");
response = realm.users().create(newUser);
String userId = ApiUtil.getCreatedId(response);
response.close();
newUser = realm.users().search("groupUser", -1, -1).get(0);
membership = realm.users().get(newUser.getId()).groups();
assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.userResourcePath(userId), newUser);
membership = realm.users().get(userId).groups();
assertEquals(1, membership.size());
assertEquals("level3", membership.get(0).getName());
@ -230,6 +266,7 @@ public class GroupTest extends AbstractGroupTest {
assertEquals(0, defaultGroups.size());
realm.groups().group(topGroup.getId()).remove();
assertAdminEvents.assertEvent("test", OperationType.DELETE, AdminEventPaths.groupPath(topGroup.getId()));
try {
realm.getGroupByPath("/top/level2/level3");
@ -263,10 +300,9 @@ public class GroupTest extends AbstractGroupTest {
attrs.put("attr1", Collections.singletonList("attrval1"));
attrs.put("attr2", Collections.singletonList("attrval2"));
group.setAttributes(attrs);
Response response = realm.groups().add(group);
response.close();
createGroup(realm, group);
group = realm.getGroupByPath("/group");
Assert.assertNotNull(group);
assertEquals("group", group.getName());
assertEquals(2, group.getAttributes().size());
@ -282,6 +318,7 @@ public class GroupTest extends AbstractGroupTest {
group.getAttributes().put("attr3", Collections.singletonList("attrval2"));
realm.groups().group(group.getId()).update(group);
assertAdminEvents.assertEvent("test", OperationType.UPDATE, AdminEventPaths.groupPath(group.getId()), group);
group = realm.getGroupByPath("/group-new");
@ -297,29 +334,32 @@ public class GroupTest extends AbstractGroupTest {
GroupRepresentation group = new GroupRepresentation();
group.setName("group");
Response response = realm.groups().add(group);
String groupId = ApiUtil.getCreatedId(response);
response.close();
String groupId = createGroup(realm, group).getId();
response = realm.users().create(UserBuilder.create().username("user-a").build());
Response response = realm.users().create(UserBuilder.create().username("user-a").build());
String userAId = ApiUtil.getCreatedId(response);
response.close();
assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.userResourcePath(userAId));
response = realm.users().create(UserBuilder.create().username("user-b").build());
String userBId = ApiUtil.getCreatedId(response);
response.close();
assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.userResourcePath(userBId));
realm.users().get(userAId).joinGroup(groupId);
assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.userGroupPath(userAId, groupId));
List<UserRepresentation> members = realm.groups().group(groupId).members(0, 10);
assertNames(members, "user-a");
realm.users().get(userBId).joinGroup(groupId);
assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.userGroupPath(userBId, groupId));
members = realm.groups().group(groupId).members(0, 10);
assertNames(members, "user-a", "user-b");
realm.users().get(userAId).leaveGroup(groupId);
assertAdminEvents.assertEvent("test", OperationType.DELETE, AdminEventPaths.userGroupPath(userAId, groupId));
members = realm.groups().group(groupId).members(0, 10);
assertNames(members, "user-b");
@ -361,11 +401,13 @@ public class GroupTest extends AbstractGroupTest {
realm.clients().get(clientId).roles().create(RoleBuilder.create().name("client-child").build());
realm.clients().get(clientId).roles().get("client-composite").addComposites(Collections.singletonList(realm.clients().get(clientId).roles().get("client-child").toRepresentation()));
// Roles+clients tested elsewhere
assertAdminEvents.clear();
GroupRepresentation group = new GroupRepresentation();
group.setName("group");
response = realm.groups().add(group);
String groupId = ApiUtil.getCreatedId(response);
response.close();
String groupId = createGroup(realm, group).getId();
RoleMappingResource roles = realm.groups().group(groupId).roles();
assertEquals(0, roles.realmLevel().listAll().size());
@ -375,10 +417,14 @@ public class GroupTest extends AbstractGroupTest {
l.add(realm.roles().get("realm-role").toRepresentation());
l.add(realm.roles().get("realm-composite").toRepresentation());
roles.realmLevel().add(l);
assertAdminEvents.assertEvent("test", OperationType.CREATE, Matchers.startsWith(AdminEventPaths.groupRolesRealmRolesPath(group.getId())));
assertAdminEvents.assertEvent("test", OperationType.CREATE, Matchers.startsWith(AdminEventPaths.groupRolesRealmRolesPath(group.getId())));
// Add client roles
roles.clientLevel(clientId).add(Collections.singletonList(realm.clients().get(clientId).roles().get("client-role").toRepresentation()));
roles.clientLevel(clientId).add(Collections.singletonList(realm.clients().get(clientId).roles().get("client-composite").toRepresentation()));
assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.groupRolesClientRolesPath(group.getId(), clientId));
assertAdminEvents.assertEvent("test", OperationType.CREATE, AdminEventPaths.groupRolesClientRolesPath(group.getId(), clientId));
// List realm roles
assertNames(roles.realmLevel().listAll(), "realm-role", "realm-composite");
@ -397,11 +443,16 @@ public class GroupTest extends AbstractGroupTest {
assertNames(all.getClientMappings().get("myclient").getMappings(), "client-role", "client-composite");
// Remove realm role
roles.realmLevel().remove(Collections.singletonList(realm.roles().get("realm-role").toRepresentation()));
// TODO adminEvents: DEleting group realmRole mapping has ID in the end. For deleting clientRole not.
RoleRepresentation realmRoleRep = realm.roles().get("realm-role").toRepresentation();
roles.realmLevel().remove(Collections.singletonList(realmRoleRep));
assertAdminEvents.assertEvent("test", OperationType.DELETE, AdminEventPaths.groupRolesRealmRolesPath(group.getId()) + "/" + realmRoleRep.getId());
assertNames(roles.realmLevel().listAll(), "realm-composite");
// Remove client role
roles.clientLevel(clientId).remove(Collections.singletonList(realm.clients().get(clientId).roles().get("client-role").toRepresentation()));
RoleRepresentation clientRoleRep = realm.clients().get(clientId).roles().get("client-role").toRepresentation();
roles.clientLevel(clientId).remove(Collections.singletonList(clientRoleRep));
assertAdminEvents.assertEvent("test", OperationType.DELETE, AdminEventPaths.groupRolesClientRolesPath(group.getId(), clientId));
assertNames(roles.clientLevel(clientId).listAll(), "client-composite");
}

View file

@ -19,21 +19,30 @@ package org.keycloak.testsuite.admin.partialimport;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.ws.rs.core.Response;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.admin.client.resource.IdentityProviderResource;
import org.keycloak.admin.client.resource.RoleResource;
import org.keycloak.admin.client.resource.UserResource;
import org.keycloak.events.admin.OperationType;
import org.keycloak.partialimport.PartialImportResult;
import org.keycloak.partialimport.PartialImportResults;
import org.keycloak.representations.idm.AdminEventRepresentation;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.GroupRepresentation;
import org.keycloak.representations.idm.IdentityProviderRepresentation;
import org.keycloak.representations.idm.PartialImportRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.AbstractAuthTest;
@ -45,7 +54,11 @@ import static org.junit.Assert.assertTrue;
import org.keycloak.representations.idm.PartialImportRepresentation.Policy;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.representations.idm.RolesRepresentation;
import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.admin.ApiUtil;
import org.keycloak.testsuite.util.AdminEventPaths;
import org.keycloak.testsuite.util.AssertAdminEvents;
import org.keycloak.testsuite.util.RealmBuilder;
/**
* Tests for the partial import endpoint in admin client. Also tests the
@ -56,6 +69,9 @@ import org.keycloak.testsuite.admin.ApiUtil;
*/
public class PartialImportTest extends AbstractAuthTest {
@Rule
public AssertAdminEvents assertAdminEvents = new AssertAdminEvents(this);
private static final int NUM_RESOURCE_TYPES = 6;
private static final String CLIENT_ROLES_CLIENT = "clientRolesClient";
private static final String USER_PREFIX = "user";
@ -67,12 +83,23 @@ public class PartialImportTest extends AbstractAuthTest {
private static final int NUM_ENTITIES = IDP_ALIASES.length;
private PartialImportRepresentation piRep;
private String realmId;
@Before
public void init() {
public void initAdminEvents() {
RealmRepresentation realmRep = RealmBuilder.edit(testRealmResource().toRepresentation()).testEventListener().build();
realmId = realmRep.getId();
adminClient.realm(realmRep.getRealm()).update(realmRep);
piRep = new PartialImportRepresentation();
}
@After
public void tearDownAdminEvents() {
RealmRepresentation realmRep = RealmBuilder.edit(testRealmResource().toRepresentation()).removeTestEventListener().build();
adminClient.realm(realmRep.getRealm()).update(realmRep);
}
@Before
public void createClientForClientRoles() {
ClientRepresentation client = new ClientRepresentation();
@ -251,17 +278,34 @@ public class PartialImportTest extends AbstractAuthTest {
@Test
public void testAddUsers() {
assertAdminEvents.clear();
setFail();
addUsers();
PartialImportResults results = doImport();
assertEquals(NUM_ENTITIES, results.getAdded());
// Need to do this way as admin events from partial import are unsorted
Set<String> userIds = new HashSet<>();
for (int i=0 ; i<NUM_ENTITIES ; i++) {
AdminEventRepresentation adminEvent = assertAdminEvents.poll();
Assert.assertEquals(realmId, adminEvent.getRealmId());
Assert.assertEquals(OperationType.CREATE.name(), adminEvent.getOperationType());
Assert.assertTrue(adminEvent.getResourcePath().startsWith("users/"));
String userId = adminEvent.getResourcePath().substring(6);
userIds.add(userId);
}
assertAdminEvents.assertEmpty();
for (PartialImportResult result : results.getResults()) {
String id = result.getId();
UserResource userRsc = testRealmResource().users().get(id);
UserRepresentation user = userRsc.toRepresentation();
assertTrue(user.getUsername().startsWith(USER_PREFIX));
Assert.assertTrue(userIds.contains(id));
}
}

View file

@ -17,14 +17,18 @@
package org.keycloak.testsuite.admin.realm;
import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
import org.keycloak.admin.client.resource.RoleByIdResource;
import org.keycloak.admin.client.resource.RolesResource;
import org.keycloak.events.admin.OperationType;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.admin.AbstractAdminTest;
import org.keycloak.testsuite.admin.ApiUtil;
import org.keycloak.testsuite.util.AdminEventPaths;
import org.keycloak.testsuite.util.ClientBuilder;
import org.keycloak.testsuite.util.RoleBuilder;
@ -54,12 +58,17 @@ public class RealmRolesTest extends AbstractAdminTest {
@Before
public void before() {
adminClient.realm(REALM_NAME).roles().create(RoleBuilder.create().name("role-a").description("Role A").build());
adminClient.realm(REALM_NAME).roles().create(RoleBuilder.create().name("role-b").description("Role B").build());
RoleRepresentation roleA = RoleBuilder.create().name("role-a").description("Role A").build();
RoleRepresentation roleB = RoleBuilder.create().name("role-b").description("Role B").build();
adminClient.realm(REALM_NAME).roles().create(roleA);
adminClient.realm(REALM_NAME).roles().create(roleB);
Response response = adminClient.realm(REALM_NAME).clients().create(ClientBuilder.create().clientId("client-a").build());
ClientRepresentation clientRep = ClientBuilder.create().clientId("client-a").build();
Response response = adminClient.realm(REALM_NAME).clients().create(clientRep);
clientUuid = ApiUtil.getCreatedId(response);
adminClient.realm(REALM_NAME).clients().get(clientUuid).roles().create(RoleBuilder.create().name("role-c").description("Role C").build());
RoleRepresentation roleC = RoleBuilder.create().name("role-c").description("Role C").build();
adminClient.realm(REALM_NAME).clients().get(clientUuid).roles().create(roleC);
for (RoleRepresentation r : adminClient.realm(REALM_NAME).roles().list()) {
ids.put(r.getName(), r.getId());
@ -70,6 +79,13 @@ public class RealmRolesTest extends AbstractAdminTest {
}
resource = adminClient.realm(REALM_NAME).roles();
// ResourcePath for event for creating role contains roleID instead of roleName (looks like a bug...)
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.roleResourcePath(ids.get("role-a")), roleA);
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.roleResourcePath(ids.get("role-b")), roleB);
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientResourcePath(clientUuid), clientRep);
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientRoleResourcePath(clientUuid, ids.get("role-c")), roleC);
}
@Test
@ -89,6 +105,7 @@ public class RealmRolesTest extends AbstractAdminTest {
role.setDescription("Role A New");
resource.get("role-a").update(role);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, AdminEventPaths.roleResourcePath("role-a"), role);
role = resource.get("role-a-new").toRepresentation();
@ -102,10 +119,13 @@ public class RealmRolesTest extends AbstractAdminTest {
public void deleteRole() {
assertNotNull(resource.get("role-a"));
resource.deleteRole("role-a");
assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.roleResourcePath("role-a"));
try {
resource.get("role-a").toRepresentation();
fail("Expected 404");
} catch (NotFoundException e) {
// expected
}
}
@ -118,6 +138,9 @@ public class RealmRolesTest extends AbstractAdminTest {
l.add(RoleBuilder.create().id(ids.get("role-b")).build());
l.add(RoleBuilder.create().id(ids.get("role-c")).build());
resource.get("role-a").addComposites(l);
// TODO adminEvents: Fix once composite roles events will be fixed...
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, Matchers.startsWith(AdminEventPaths.roleResourceCompositesPath("role-a")));
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, Matchers.startsWith(AdminEventPaths.roleResourceCompositesPath("role-a")));
Set<RoleRepresentation> composites = resource.get("role-a").getRoleComposites();
@ -131,6 +154,7 @@ public class RealmRolesTest extends AbstractAdminTest {
Assert.assertNames(clientComposites, "role-c");
resource.get("role-a").deleteComposites(l);
assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.roleResourceCompositesPath("role-a"));
assertFalse(resource.get("role-a").toRepresentation().isComposite());
assertEquals(0, resource.get("role-a").getRoleComposites().size());

View file

@ -18,6 +18,7 @@
package org.keycloak.testsuite.admin.realm;
import org.apache.commons.io.IOUtils;
import org.hamcrest.Matchers;
import org.junit.Rule;
import org.junit.Test;
import org.keycloak.OAuth2Constants;
@ -25,6 +26,7 @@ import org.keycloak.admin.client.Keycloak;
import org.keycloak.admin.client.resource.ServerInfoResource;
import org.keycloak.common.util.StreamUtil;
import org.keycloak.common.util.Time;
import org.keycloak.events.admin.OperationType;
import org.keycloak.models.Constants;
import org.keycloak.representations.adapters.action.GlobalRequestResult;
import org.keycloak.representations.adapters.action.PushNotBeforeAction;
@ -39,9 +41,9 @@ import org.keycloak.testsuite.admin.AbstractAdminTest;
import org.keycloak.testsuite.admin.ApiUtil;
import org.keycloak.testsuite.arquillian.AuthServerTestEnricher;
import org.keycloak.testsuite.auth.page.AuthRealm;
import org.keycloak.testsuite.util.AdminEventPaths;
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 org.keycloak.util.JsonSerialization;
@ -191,6 +193,7 @@ public class RealmTest extends AbstractAdminTest {
rep.setEditUsernameAllowed(true);
realm.update(rep);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep);
rep = realm.toRepresentation();
@ -207,6 +210,7 @@ public class RealmTest extends AbstractAdminTest {
rep.setEditUsernameAllowed(false);
realm.update(rep);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep);
rep = realm.toRepresentation();
assertEquals(Boolean.FALSE, rep.isRegistrationAllowed());
@ -222,6 +226,7 @@ public class RealmTest extends AbstractAdminTest {
rep.setSupportedLocales(new HashSet<>(Arrays.asList("en", "de")));
realm.update(rep);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep);
rep = realm.toRepresentation();
@ -233,6 +238,7 @@ public class RealmTest extends AbstractAdminTest {
rep.setEditUsernameAllowed(false);
realm.update(rep);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep);
rep = realm.toRepresentation();
assertEquals(Boolean.FALSE, rep.isEditUsernameAllowed());
@ -252,10 +258,11 @@ public class RealmTest extends AbstractAdminTest {
}
@Test
// KEYCLOAK-1110 TODO: Functionality more related to roles. So maybe rather move to RolesTest once we have it
// KEYCLOAK-1110
public void deleteDefaultRole() {
RoleRepresentation role = new RoleRepresentation("test", "test", false);
realm.roles().create(role);
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, Matchers.startsWith(AdminEventPaths.rolesResourcePath()));
assertNotNull(realm.roles().get("test").toRepresentation());
@ -264,8 +271,10 @@ public class RealmTest extends AbstractAdminTest {
rep.getDefaultRoles().add("test");
realm.update(rep);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep);
realm.roles().deleteRole("test");
assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.roleResourcePath("test"));
try {
realm.roles().get("testsadfsadf").toRepresentation();
@ -378,6 +387,7 @@ public class RealmTest extends AbstractAdminTest {
fail("Expected BadRequestException");
} catch (BadRequestException e) {
// Expected
assertAdminEvents.assertEmpty();
}
rep.setPrivateKey(PRIVATE_KEY);
@ -388,12 +398,14 @@ public class RealmTest extends AbstractAdminTest {
fail("Expected BadRequestException");
} catch (BadRequestException e) {
// Expected
assertAdminEvents.assertEmpty();
}
Assert.assertEquals(originalPublicKey, realm.toRepresentation().getPublicKey());
rep.setPublicKey(PUBLIC_KEY);
realm.update(rep);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep);
assertEquals(PUBLIC_KEY, rep.getPublicKey());
@ -407,6 +419,7 @@ public class RealmTest extends AbstractAdminTest {
fail("Expected BadRequestException");
} catch (BadRequestException e) {
// Expected
assertAdminEvents.assertEmpty();
}
Assert.assertEquals(PUBLIC_KEY, realm.toRepresentation().getPublicKey());
@ -414,6 +427,7 @@ public class RealmTest extends AbstractAdminTest {
rep.setPublicKey(publicKey2048);
realm.update(rep);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep);
Assert.assertEquals(publicKey2048, realm.toRepresentation().getPublicKey());
@ -423,6 +437,7 @@ public class RealmTest extends AbstractAdminTest {
rep.setPublicKey(publicKey4096);
realm.update(rep);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep);
Assert.assertEquals(publicKey4096, realm.toRepresentation().getPublicKey());
}
@ -433,6 +448,7 @@ public class RealmTest extends AbstractAdminTest {
rep.setCertificate(CERTIFICATE);
realm.update(rep);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep);
assertEquals(CERTIFICATE, rep.getCertificate());
@ -440,6 +456,7 @@ public class RealmTest extends AbstractAdminTest {
rep.setCertificate(certificate);
realm.update(rep);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep);
assertEquals(certificate, rep.getCertificate());
}
@ -448,7 +465,10 @@ public class RealmTest extends AbstractAdminTest {
public void clearRealmCache() {
RealmRepresentation realmRep = realm.toRepresentation();
assertTrue(testingClient.testing().isCached("realms", realmRep.getId()));
adminClient.realm("master").clearRealmCache();
realm.clearRealmCache();
assertAdminEvents.assertEvent(realmId, OperationType.ACTION, "clear-realm-cache");
assertFalse(testingClient.testing().isCached("realms", realmRep.getId()));
}
@ -459,11 +479,15 @@ public class RealmTest extends AbstractAdminTest {
Response response = realm.users().create(user);
String userId = ApiUtil.getCreatedId(response);
response.close();
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.userResourcePath(userId), user);
realm.users().get(userId).toRepresentation();
assertTrue(testingClient.testing().isCached("users", userId));
adminClient.realm("master").clearUserCache();
realm.clearUserCache();
assertAdminEvents.assertEvent(realmId, OperationType.ACTION, "clear-user-cache");
assertFalse(testingClient.testing().isCached("users", userId));
}
@ -476,8 +500,11 @@ public class RealmTest extends AbstractAdminTest {
RealmRepresentation rep = realm.toRepresentation();
rep.setNotBefore(time);
realm.update(rep);
assertAdminEvents.assertEvent(realmId, OperationType.UPDATE, Matchers.nullValue(String.class), rep);
GlobalRequestResult globalRequestResult = realm.pushRevocation();
assertAdminEvents.assertEvent(realmId, OperationType.ACTION, "push-revocation");
assertEquals(1, globalRequestResult.getSuccessRequests().size());
assertEquals("http://localhost:8180/auth/realms/master/app/admin", globalRequestResult.getSuccessRequests().get(0));
assertNull(globalRequestResult.getFailedRequests());
@ -493,12 +520,16 @@ public class RealmTest extends AbstractAdminTest {
Response response = realm.users().create(UserBuilder.create().username("user").build());
String userId = ApiUtil.getCreatedId(response);
response.close();
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.userResourcePath(userId));
realm.users().get(userId).resetPassword(CredentialBuilder.create().password("password").build());
assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userResetPasswordPath(userId));
oauth.doLogin("user", "password");
GlobalRequestResult globalRequestResult = realm.logoutAll();
assertAdminEvents.assertEvent(realmId, OperationType.ACTION, "logout-all");
assertEquals(1, globalRequestResult.getSuccessRequests().size());
assertEquals("http://localhost:8180/auth/realms/master/app/admin", globalRequestResult.getSuccessRequests().get(0));
assertNull(globalRequestResult.getFailedRequests());
@ -518,10 +549,13 @@ public class RealmTest extends AbstractAdminTest {
assertNotNull(event);
realm.deleteSession(event.getSessionId());
assertAdminEvents.assertEvent(realmId, OperationType.DELETE, AdminEventPaths.deleteSessionPath(event.getSessionId()));
try {
realm.deleteSession(event.getSessionId());
fail("Expected 404");
} catch (NotFoundException e) {
// Expected
assertAdminEvents.assertEmpty();
}
tokenResponse = oauth.doRefreshTokenRequest(tokenResponse.getRefreshToken(), "secret");
@ -550,8 +584,6 @@ public class RealmTest extends AbstractAdminTest {
}
private void setupTestAppAndUser() {
realm.update(RealmBuilder.edit(realm.toRepresentation()).testEventListener().build());
testingClient.testApp().clearAdminActions();
String redirectUri = oauth.getRedirectUri().replace("/master/", "/" + REALM_NAME + "/");
@ -561,16 +593,22 @@ public class RealmTest extends AbstractAdminTest {
client.setAdminUrl(suiteContext.getAuthServerInfo().getContextRoot() + "/auth/realms/master/app/admin");
client.setRedirectUris(Collections.singletonList(redirectUri));
client.setSecret("secret");
realm.clients().create(client);
Response resp = realm.clients().create(client);
String clientDbId = ApiUtil.getCreatedId(resp);
resp.close();
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.clientResourcePath(clientDbId), client);
oauth.realm(REALM_NAME);
oauth.redirectUri(redirectUri);
Response response = realm.users().create(UserBuilder.create().username("testuser").build());
UserRepresentation userRep = UserBuilder.create().username("testuser").build();
Response response = realm.users().create(userRep);
String userId = ApiUtil.getCreatedId(response);
response.close();
assertAdminEvents.assertEvent(realmId, OperationType.CREATE, AdminEventPaths.userResourcePath(userId), userRep);
realm.users().get(userId).resetPassword(CredentialBuilder.create().password("password").build());
assertAdminEvents.assertEvent(realmId, OperationType.ACTION, AdminEventPaths.userResetPasswordPath(userId));
testingClient.testApp().clearAdminActions();
}

View file

@ -0,0 +1,356 @@
/*
* 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 java.net.URI;
import javax.ws.rs.core.UriBuilder;
import org.keycloak.admin.client.resource.ClientAttributeCertificateResource;
import org.keycloak.admin.client.resource.ClientInitialAccessResource;
import org.keycloak.admin.client.resource.ClientResource;
import org.keycloak.admin.client.resource.ClientTemplateResource;
import org.keycloak.admin.client.resource.ClientTemplatesResource;
import org.keycloak.admin.client.resource.ClientsResource;
import org.keycloak.admin.client.resource.GroupResource;
import org.keycloak.admin.client.resource.GroupsResource;
import org.keycloak.admin.client.resource.IdentityProviderResource;
import org.keycloak.admin.client.resource.IdentityProvidersResource;
import org.keycloak.admin.client.resource.ProtocolMappersResource;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.admin.client.resource.RoleByIdResource;
import org.keycloak.admin.client.resource.RoleMappingResource;
import org.keycloak.admin.client.resource.RoleResource;
import org.keycloak.admin.client.resource.RolesResource;
import org.keycloak.admin.client.resource.UserFederationProviderResource;
import org.keycloak.admin.client.resource.UserFederationProvidersResource;
import org.keycloak.admin.client.resource.UserResource;
import org.keycloak.admin.client.resource.UsersResource;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class AdminEventPaths {
// REALM
public static String deleteSessionPath(String userSessionId) {
URI uri = UriBuilder.fromUri("").path(RealmResource.class, "deleteSession").build(userSessionId);
return uri.toString();
}
// CLIENT RESOURCE
public static String clientResourcePath(String clientDbId) {
URI uri = UriBuilder.fromUri("").path(RealmResource.class, "clients").path(ClientsResource.class, "get").build(clientDbId);
return uri.toString();
}
public static String clientRolesResourcePath(String clientDbId) {
URI uri = UriBuilder.fromUri(clientResourcePath(clientDbId)).path(ClientResource.class, "roles").build();
return uri.toString();
}
public static String clientRoleResourcePath(String clientDbId, String roleName) {
URI uri = UriBuilder.fromUri(clientRolesResourcePath(clientDbId)).path(RolesResource.class, "get").build(roleName);
return uri.toString();
}
public static String clientRoleResourceCompositesPath(String clientDbId, String roleName) {
URI uri = UriBuilder.fromUri(clientRoleResourcePath(clientDbId, roleName))
.path(RoleResource.class, "getRoleComposites").build();
return uri.toString();
}
public static String clientProtocolMappersPath(String clientDbId) {
URI uri = UriBuilder.fromUri(clientResourcePath(clientDbId))
.path(ClientResource.class, "getProtocolMappers")
.build();
return uri.toString();
}
public static String clientProtocolMapperPath(String clientDbId, String protocolMapperId) {
URI uri = UriBuilder.fromUri(clientProtocolMappersPath(clientDbId))
.path(ProtocolMappersResource.class, "getMapperById")
.build(protocolMapperId);
return uri.toString();
}
public static String clientPushRevocationPath(String clientDbId) {
URI uri = UriBuilder.fromUri(clientResourcePath(clientDbId)).path(ClientResource.class, "pushRevocation").build();
return uri.toString();
}
public static String clientNodesPath(String clientDbId) {
URI uri = UriBuilder.fromUri(clientResourcePath(clientDbId)).path(ClientResource.class, "registerNode").build();
return uri.toString();
}
public static String clientNodePath(String clientDbId, String node) {
URI uri = UriBuilder.fromUri(clientResourcePath(clientDbId)).path(ClientResource.class, "unregisterNode").build(node);
return uri.toString();
}
public static String clientTestNodesAvailablePath(String clientDbId) {
URI uri = UriBuilder.fromUri(clientResourcePath(clientDbId)).path(ClientResource.class, "testNodesAvailable").build();
return uri.toString();
}
public static String clientGenerateSecretPath(String clientDbId) {
URI uri = UriBuilder.fromUri(clientResourcePath(clientDbId)).path(ClientResource.class, "generateNewSecret").build();
return uri.toString();
}
public static String clientRegenerateRegistrationAccessTokenPath(String clientDbId) {
URI uri = UriBuilder.fromUri(clientResourcePath(clientDbId)).path(ClientResource.class, "regenerateRegistrationAccessToken").build();
return uri.toString();
}
public static String clientCertificateGenerateSecretPath(String clientDbId, String certificateAttribute) {
URI uri = UriBuilder.fromUri(clientResourcePath(clientDbId))
.path(ClientResource.class, "getCertficateResource")
.path(ClientAttributeCertificateResource.class, "generate")
.build(certificateAttribute);
return uri.toString();
}
public static String clientScopeMappingsRealmLevelPath(String clientDbId) {
URI uri = UriBuilder.fromUri(clientResourcePath(clientDbId)).path(ClientResource.class, "getScopeMappings")
.path(RoleMappingResource.class, "realmLevel")
.build();
return uri.toString();
}
public static String clientScopeMappingsClientLevelPath(String clientDbId, String clientOwningRoleId) {
URI uri = UriBuilder.fromUri(clientResourcePath(clientDbId)).path(ClientResource.class, "getScopeMappings")
.path(RoleMappingResource.class, "clientLevel")
.build(clientOwningRoleId);
return uri.toString();
}
// CLIENT TEMPLATES
public static String clientTemplateResourcePath(String clientTemplateId) {
URI uri = UriBuilder.fromUri("").path(RealmResource.class, "clientTemplates").path(ClientTemplatesResource.class, "get").build(clientTemplateId);
return uri.toString();
}
public static String clientTemplateScopeMappingsRealmLevelPath(String clientTemplateDbId) {
URI uri = UriBuilder.fromUri(clientTemplateResourcePath(clientTemplateDbId)).path(ClientTemplateResource.class, "getScopeMappings")
.path(RoleMappingResource.class, "realmLevel")
.build();
return uri.toString();
}
public static String clientTemplateScopeMappingsClientLevelPath(String clientTemplateDbId, String clientOwningRoleId) {
URI uri = UriBuilder.fromUri(clientTemplateResourcePath(clientTemplateDbId)).path(ClientTemplateResource.class, "getScopeMappings")
.path(RoleMappingResource.class, "clientLevel")
.build(clientOwningRoleId);
return uri.toString();
}
public static String clientTemplateProtocolMappersPath(String clientTemplateDbId) {
URI uri = UriBuilder.fromUri(clientTemplateResourcePath(clientTemplateDbId))
.path(ClientTemplateResource.class, "getProtocolMappers")
.build();
return uri.toString();
}
public static String clientTemplateProtocolMapperPath(String clientTemplateDbId, String protocolMapperId) {
URI uri = UriBuilder.fromUri(clientTemplateProtocolMappersPath(clientTemplateDbId))
.path(ProtocolMappersResource.class, "getMapperById")
.build(protocolMapperId);
return uri.toString();
}
// ROLES
public static String rolesResourcePath() {
URI uri = UriBuilder.fromUri("").path(RealmResource.class, "roles").build();
return uri.toString();
}
public static String roleResourcePath(String roleName) {
URI uri = UriBuilder.fromUri(rolesResourcePath()).path(RolesResource.class, "get").build(roleName);
return uri.toString();
}
public static String roleResourceCompositesPath(String roleName) {
URI uri = UriBuilder.fromUri(roleResourcePath(roleName)).path(RoleResource.class, "getRoleComposites").build();
return uri.toString();
}
public static String rolesByIdResourcePath() {
URI uri = UriBuilder.fromUri("").path(RealmResource.class, "rolesById").build();
return uri.toString();
}
public static String roleByIdResourcePath(String roleId) {
URI uri = UriBuilder.fromUri(rolesByIdResourcePath()).path(RoleByIdResource.class, "getRole").build(roleId);
return uri.toString();
}
public static String roleByIdResourceCompositesPath(String roleId) {
URI uri = UriBuilder.fromUri(rolesByIdResourcePath()).path(RoleByIdResource.class, "getRoleComposites").build(roleId);
return uri.toString();
}
// USERS
public static String userResourcePath(String userId) {
URI uri = UriBuilder.fromUri("").path(RealmResource.class, "users").path(UsersResource.class, "get").build(userId);
return uri.toString();
}
public static String userResetPasswordPath(String userId) {
URI uri = UriBuilder.fromUri(userResourcePath(userId)).path(UserResource.class, "resetPassword").build(userId);
return uri.toString();
}
public static String userRealmRoleMappingsPath(String userId) {
URI uri = UriBuilder.fromUri(userResourcePath(userId))
.path(UserResource.class, "roles")
.path(RoleMappingResource.class, "realmLevel").build();
return uri.toString();
}
public static String userClientRoleMappingsPath(String userId, String clientDbId) {
URI uri = UriBuilder.fromUri(userResourcePath(userId))
.path(UserResource.class, "roles")
.path(RoleMappingResource.class, "clientLevel").build(clientDbId);
return uri.toString();
}
public static String userFederatedIdentityLink(String userId, String idpAlias) {
URI uri = UriBuilder.fromUri(userResourcePath(userId))
.path(UserResource.class, "addFederatedIdentity")
.build(idpAlias);
return uri.toString();
}
public static String userGroupPath(String userId, String groupId) {
URI uri = UriBuilder.fromUri(userResourcePath(userId))
.path(UserResource.class, "joinGroup")
.build(groupId);
return uri.toString();
}
// IDENTITY PROVIDERS
public static String identityProvidersPath() {
URI uri = UriBuilder.fromUri("").path(RealmResource.class, "identityProviders").build();
return uri.toString();
}
public static String identityProviderCreatePath() {
URI uri = UriBuilder.fromUri(identityProvidersPath()).path(IdentityProvidersResource.class, "create").build();
return uri.toString();
}
public static String identityProviderPath(String idpAlias) {
URI uri = UriBuilder.fromUri(identityProvidersPath()).path(IdentityProvidersResource.class, "get").build(idpAlias);
return uri.toString();
}
public static String identityProviderMapperPath(String idpAlias, String idpMapperId) {
URI uri = UriBuilder.fromUri(identityProviderPath(idpAlias)).path(IdentityProviderResource.class, "getMapperById").build(idpMapperId);
return uri.toString();
}
// USER FEDERATION PROVIDERS AND MAPPERS
public static String userFederationsResourcePath() {
URI uri = UriBuilder.fromUri("").path(RealmResource.class, "userFederation").build();
return uri.toString();
}
public static String userFederationCreateResourcePath() {
URI uri = UriBuilder.fromUri(userFederationsResourcePath()).path(UserFederationProvidersResource.class, "create").build();
return uri.toString();
}
public static String userFederationResourcePath(String userFederationId) {
URI uri = UriBuilder.fromUri(userFederationsResourcePath()).path(UserFederationProvidersResource.class, "get").build(userFederationId);
return uri.toString();
}
public static String userFederationMapperResourcePath(String userFederationId, String userFederationMapperId) {
URI uri = UriBuilder.fromUri(userFederationResourcePath(userFederationId))
.path(UserFederationProviderResource.class, "getMapperById").build(userFederationMapperId);
return uri.toString();
}
// CLIENT INITIAL ACCESS
public static String clientInitialAccessPath(String clientInitialAccessId) {
URI uri = UriBuilder.fromUri("").path(RealmResource.class, "clientInitialAccess")
.path(ClientInitialAccessResource.class, "delete")
.build(clientInitialAccessId);
return uri.toString();
}
// GROUPS
public static String groupsPath() {
URI uri = UriBuilder.fromUri("").path(RealmResource.class, "groups")
.build();
return uri.toString();
}
public static String groupPath(String groupId) {
URI uri = UriBuilder.fromUri(groupsPath()).path(GroupsResource.class, "group")
.build(groupId);
return uri.toString();
}
public static String groupRolesPath(String groupId) {
URI uri = UriBuilder.fromUri(groupPath(groupId))
.path(GroupResource.class, "roles")
.build();
return uri.toString();
}
public static String groupRolesRealmRolesPath(String groupId) {
URI uri = UriBuilder.fromUri(groupRolesPath(groupId))
.path(RoleMappingResource.class, "realmLevel")
.build();
return uri.toString();
}
public static String groupRolesClientRolesPath(String groupId, String clientDbId) {
URI uri = UriBuilder.fromUri(groupRolesPath(groupId))
.path(RoleMappingResource.class, "clientLevel")
.build(clientDbId);
return uri.toString();
}
public static String groupSubgroupsPath(String groupId) {
URI uri = UriBuilder.fromUri(groupPath(groupId))
.path(GroupResource.class, "subGroup")
.build();
return uri.toString();
}
}

View file

@ -0,0 +1,245 @@
/*
* 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 java.io.IOException;
import java.lang.reflect.Method;
import javax.ws.rs.core.Response;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers;
import org.junit.rules.TestRule;
import org.junit.runners.model.Statement;
import org.keycloak.common.util.ObjectUtil;
import org.keycloak.common.util.reflections.Reflections;
import org.keycloak.events.admin.OperationType;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.jose.jws.JWSInputException;
import org.keycloak.representations.AccessToken;
import org.keycloak.representations.idm.AdminEventRepresentation;
import org.keycloak.representations.idm.AuthDetailsRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.testsuite.AbstractKeycloakTest;
import org.keycloak.testsuite.Assert;
import org.keycloak.util.JsonSerialization;
/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public class AssertAdminEvents implements TestRule {
private AbstractKeycloakTest context;
public AssertAdminEvents(AbstractKeycloakTest ctx) {
context = ctx;
}
@Override
public Statement apply(final Statement base, org.junit.runner.Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
// TODO: Ideally clear the queue just before testClass rather then before each method
context.getTestingClient().testing().clearAdminEventQueue();
base.evaluate();
// TODO Test should fail if there are leftover events
}
};
}
public AdminEventRepresentation poll() {
AdminEventRepresentation event = fetchNextEvent();
Assert.assertNotNull("Admin event expected", event);
return event;
}
public void assertEmpty() {
AdminEventRepresentation event = fetchNextEvent();
Assert.assertNull("Empty admin event queue expected, but there is " + event, event);
}
// Clears both "classic" and admin events for now
public void clear() {
Response res = context.getTestingClient().testing().clearAdminEventQueue();
try {
Assert.assertEquals("clear-admin-event-queue success", res.getStatus(), 200);
} finally {
res.close();
}
}
private AdminEventRepresentation fetchNextEvent() {
return context.getTestingClient().testing().pollAdminEvent();
}
public ExpectedAdminEvent expect() {
return new ExpectedAdminEvent();
}
public AdminEventRepresentation assertEvent(String realmId, OperationType operationType, String resourcePath) {
return assertEvent(realmId, operationType, resourcePath, null);
}
public AdminEventRepresentation assertEvent(String realmId, OperationType operationType, Matcher<String> resourcePath) {
return assertEvent(realmId, operationType, resourcePath, null);
}
public AdminEventRepresentation assertEvent(String realmId, OperationType operationType, String resourcePath, Object representation) {
return assertEvent(realmId, operationType, Matchers.equalTo(resourcePath), representation);
}
public AdminEventRepresentation assertEvent(String realmId, OperationType operationType, Matcher<String> resourcePath, Object representation) {
return expect().realmId(realmId)
.operationType(operationType)
.resourcePath(resourcePath)
.representation(representation)
.assertEvent();
}
public class ExpectedAdminEvent {
private AdminEventRepresentation expected = new AdminEventRepresentation();
private Matcher<String> resourcePath;
private Object expectedRep;
public ExpectedAdminEvent realmId(String realmId) {
expected.setRealmId(realmId);
return this;
}
public ExpectedAdminEvent realm(RealmRepresentation realm) {
return realmId(realm.getId());
}
public ExpectedAdminEvent operationType(OperationType operationType) {
expected.setOperationType(operationType.toString());
updateOperationTypeIfError();
return this;
}
public ExpectedAdminEvent resourcePath(String resourcePath) {
return resourcePath(Matchers.equalTo(resourcePath));
}
public ExpectedAdminEvent resourcePath(Matcher<String> resourcePath) {
this.resourcePath = resourcePath;
return this;
}
public ExpectedAdminEvent error(String error) {
expected.setError(error);
updateOperationTypeIfError();
return this;
}
private void updateOperationTypeIfError() {
if (expected.getError() != null && expected.getOperationType() != null) {
expected.setOperationType(expected.getOperationType() + "_ERROR");
}
}
public ExpectedAdminEvent authDetails(String realmId, String clientId, String userId) {
AuthDetailsRepresentation authDetails = new AuthDetailsRepresentation();
authDetails.setRealmId(realmId);
authDetails.setClientId(clientId);
authDetails.setUserId(userId);
expected.setAuthDetails(authDetails);
return this;
}
public ExpectedAdminEvent representation(Object representation) {
this.expectedRep = representation;
return this;
}
public AdminEventRepresentation assertEvent() {
return assertEvent(poll());
}
public AdminEventRepresentation assertEvent(AdminEventRepresentation actual) {
Assert.assertEquals(expected.getRealmId(), actual.getRealmId());
Assert.assertEquals(expected.getOperationType(), actual.getOperationType());
Assert.assertThat(actual.getResourcePath(), resourcePath);
Assert.assertTrue(ObjectUtil.isEqualOrBothNull(expected.getError(), actual.getError()));
// AuthDetails
AuthDetailsRepresentation expectedAuth = expected.getAuthDetails();
if (expectedAuth == null) {
expectedAuth = defaultAuthDetails();
}
AuthDetailsRepresentation actualAuth = actual.getAuthDetails();
Assert.assertEquals(expectedAuth.getRealmId(), actualAuth.getRealmId());
Assert.assertEquals(expectedAuth.getUserId(), actualAuth.getUserId());
if (expectedAuth.getClientId() != null) {
Assert.assertEquals(expectedAuth.getClientId(), actualAuth.getClientId());
}
// Representation - compare the non-null fields of "expected" representation with the actual representation
if (expectedRep != null) {
if (actual.getRepresentation() == null) {
Assert.fail("Expected representation " + expectedRep + " but no representation was available on actual event");
} else {
try {
Object actualRep = JsonSerialization.readValue(actual.getRepresentation(), expectedRep.getClass());
for (Method method : Reflections.getAllDeclaredMethods(expectedRep.getClass())) {
if (method.getName().startsWith("get") || method.getName().startsWith("is")) {
Object expectedValue = Reflections.invokeMethod(method, expectedRep);
if (expectedValue != null) {
Object actualValue = Reflections.invokeMethod(method, actualRep);
Assert.assertEquals("Property " + method.getName() + " of representation not equal.", expectedValue, actualValue);
}
}
}
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
}
return actual;
}
}
private AuthDetailsRepresentation defaultAuthDetails() {
String accessTokenString = context.getAdminClient().tokenManager().getAccessTokenString();
try {
JWSInput input = new JWSInput(accessTokenString);
AccessToken token = input.readJsonContent(AccessToken.class);
AuthDetailsRepresentation authDetails = new AuthDetailsRepresentation();
String realmId = token.getIssuer().substring(token.getIssuer().lastIndexOf('/') + 1);
authDetails.setRealmId(realmId);
authDetails.setUserId(token.getSubject());
return authDetails;
} catch (JWSInputException jwe) {
throw new RuntimeException(jwe);
}
}
}

View file

@ -20,6 +20,7 @@ package org.keycloak.testsuite.util;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.events.EventsListenerProviderFactory;
import sun.security.krb5.Realm;
import java.util.HashMap;
@ -80,7 +81,18 @@ public class RealmBuilder {
rep.setEventsListeners(new LinkedList<String>());
}
rep.getEventsListeners().add("event-queue");
if (!rep.getEventsListeners().contains(EventsListenerProviderFactory.PROVIDER_ID)) {
rep.getEventsListeners().add(EventsListenerProviderFactory.PROVIDER_ID);
}
return this;
}
public RealmBuilder removeTestEventListener() {
if (rep.getEventsListeners() != null && rep.getEventsListeners().contains(EventsListenerProviderFactory.PROVIDER_ID)) {
rep.getEventsListeners().remove(EventsListenerProviderFactory.PROVIDER_ID);
}
return this;
}