Add admin events for realm create/delete. (#10831)

Closes #10733
This commit is contained in:
Tero Saarni 2023-03-07 16:57:06 +02:00 committed by GitHub
parent 96c1cf3c49
commit 9052ec2b02
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 63 additions and 6 deletions

View file

@ -450,6 +450,12 @@ public class RealmAdminResource {
if (!new RealmManager(session).removeRealm(realm)) { if (!new RealmManager(session).removeRealm(realm)) {
throw new NotFoundException("Realm doesn't exist"); throw new NotFoundException("Realm doesn't exist");
} }
// The delete event is associated with the realm of the user executing the operation,
// instead of the realm being deleted.
AdminEventBuilder deleteAdminEvent = new AdminEventBuilder(auth.adminAuth().getRealm(), auth.adminAuth(), session, connection);
deleteAdminEvent.operation(OperationType.DELETE).resource(ResourceType.REALM)
.realm(auth.adminAuth().getRealm().getId()).resourcePath(realm.getName()).success();
} }
/** /**

View file

@ -19,12 +19,15 @@ package org.keycloak.services.resources.admin;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.jboss.resteasy.annotations.cache.NoCache; import org.jboss.resteasy.annotations.cache.NoCache;
import org.keycloak.common.ClientConnection; import org.keycloak.common.ClientConnection;
import org.keycloak.events.admin.OperationType;
import org.keycloak.events.admin.ResourceType;
import org.keycloak.models.AdminRoles; import org.keycloak.models.AdminRoles;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ModelDuplicateException; import org.keycloak.models.ModelDuplicateException;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.utils.ModelToRepresentation; import org.keycloak.models.utils.ModelToRepresentation;
import org.keycloak.models.utils.StripSecretsUtils;
import org.keycloak.policy.PasswordPolicyNotMetException; import org.keycloak.policy.PasswordPolicyNotMetException;
import org.keycloak.protocol.oidc.TokenManager; import org.keycloak.protocol.oidc.TokenManager;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
@ -134,6 +137,15 @@ public class RealmsAdminResource {
URI location = AdminRoot.realmsUrl(session.getContext().getUri()).path(realm.getName()).build(); URI location = AdminRoot.realmsUrl(session.getContext().getUri()).path(realm.getName()).build();
logger.debugv("imported realm success, sending back: {0}", location.toString()); logger.debugv("imported realm success, sending back: {0}", location.toString());
// The create event is associated with the realm of the user executing the operation,
// instead of the realm being created.
AdminEventBuilder adminEvent = new AdminEventBuilder(auth.getRealm(), auth, session, clientConnection);
adminEvent.resource(ResourceType.REALM).realm(auth.getRealm().getId()).operation(OperationType.CREATE)
.resourcePath(realm.getName())
.representation(
StripSecretsUtils.strip(ModelToRepresentation.toRepresentation(session, realm, false)))
.success();
return Response.created(location).build(); return Response.created(location).build();
} catch (ModelDuplicateException e) { } catch (ModelDuplicateException e) {
logger.error("Conflict detected", e); logger.error("Conflict detected", e);

View file

@ -23,6 +23,7 @@ import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.events.admin.OperationType; import org.keycloak.events.admin.OperationType;
import org.keycloak.representations.idm.AdminEventRepresentation; import org.keycloak.representations.idm.AdminEventRepresentation;
import org.keycloak.representations.idm.AuthDetailsRepresentation; import org.keycloak.representations.idm.AuthDetailsRepresentation;
import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.testsuite.admin.ApiUtil; import org.keycloak.testsuite.admin.ApiUtil;
@ -39,7 +40,7 @@ import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.keycloak.testsuite.auth.page.AuthRealm.MASTER; import static org.keycloak.testsuite.auth.page.AuthRealm.MASTER;
/** /**
@ -220,4 +221,42 @@ public class AdminEventTest extends AbstractEventTest {
saveConfig(); saveConfig();
assertThat(events().size(), is(equalTo(3))); assertThat(events().size(), is(equalTo(3)));
} }
@Test
public void createAndDeleteRealm() {
// Enable admin events on "master" realm, since realm create/delete events will be stored in realm of
// the authenticated user who executes the operations (admin in master realm),
RealmResource master = adminClient.realm(MASTER);
RealmEventsConfigRepresentation masterConfig = master.getRealmEventsConfig();
masterConfig.setAdminEventsDetailsEnabled(true);
masterConfig.setAdminEventsEnabled(true);
master.updateRealmEventsConfig(masterConfig);
master.clearAdminEvents();
// Create realm.
RealmRepresentation realm = new RealmRepresentation();
realm.setId("test-realm");
realm.setRealm("test-realm");
importRealm(realm);
// Delete realm.
removeRealm("test-realm");
// Check that events were logged.
List<AdminEventRepresentation> events = master.getAdminEvents();
assertThat(events.size(), is(equalTo(2)));
AdminEventRepresentation createEvent = events.get(1);
assertThat(createEvent.getOperationType(), is(equalTo("CREATE")));
assertThat(createEvent.getRealmId(), is(equalTo(masterRealmId)));
assertThat(createEvent.getResourceType(), is(equalTo("REALM")));
assertThat(createEvent.getResourcePath(), is(equalTo("test-realm")));
assertThat(createEvent.getRepresentation(), is(notNullValue()));
AdminEventRepresentation deleteEvent = events.get(0);
assertThat(deleteEvent.getOperationType(), is(equalTo("DELETE")));
assertThat(deleteEvent.getRealmId(), is(equalTo(masterRealmId)));
assertThat(deleteEvent.getResourceType(), is(equalTo("REALM")));
assertThat(deleteEvent.getResourcePath(), is(equalTo("test-realm")));
}
} }