mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-10 15:32:05 -03:30
Added a representation that includes an organization and user model
Closes #34013 Signed-off-by: Robert Rieser <Robert.Rieser@degoya.studio> Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com> Co-authored-by: Robert Rieser <Robert.Rieser@degoya.studio>
This commit is contained in:
parent
a3549f465e
commit
5c9f1837d7
@ -17,6 +17,8 @@
|
||||
|
||||
package org.keycloak.representations.idm;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
|
||||
*/
|
||||
@ -30,6 +32,7 @@ public class AdminEventRepresentation {
|
||||
private String resourcePath;
|
||||
private String representation;
|
||||
private String error;
|
||||
private Map<String, String> details;
|
||||
|
||||
public long getTime() {
|
||||
return time;
|
||||
@ -94,4 +97,12 @@ public class AdminEventRepresentation {
|
||||
public void setError(String error) {
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public Map<String, String> getDetails() {
|
||||
return details;
|
||||
}
|
||||
|
||||
public void setDetails(Map<String, String> details) {
|
||||
this.details = details;
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,6 +13,9 @@ include::topics/templates/document-attributes.adoc[]
|
||||
:release_header_latest_link: {releasenotes_link_latest}
|
||||
include::topics/templates/release-header.adoc[]
|
||||
|
||||
== {project_name_full} 26.0.6
|
||||
include::topics/26_0_6.adoc[leveloffset=2]
|
||||
|
||||
== {project_name_full} 26.0.5
|
||||
include::topics/26_0_5.adoc[leveloffset=2]
|
||||
|
||||
|
||||
4
docs/documentation/release_notes/topics/26_0_6.adoc
Normal file
4
docs/documentation/release_notes/topics/26_0_6.adoc
Normal file
@ -0,0 +1,4 @@
|
||||
= Admin events might include now additional details about the context when the event is fired
|
||||
|
||||
In this release, admin events might hold additional details about the context when the event is fired. When upgrading you should
|
||||
expect the database schema being updated to add a new column `DETAILS_JSON` to the `ADMIN_EVENT_ENTITY` table.
|
||||
@ -11,6 +11,10 @@ import {
|
||||
Chip,
|
||||
ChipGroup,
|
||||
DatePicker,
|
||||
DescriptionList,
|
||||
DescriptionListDescription,
|
||||
DescriptionListGroup,
|
||||
DescriptionListTerm,
|
||||
Flex,
|
||||
FlexItem,
|
||||
Form,
|
||||
@ -92,6 +96,24 @@ const DisplayDialog = ({
|
||||
);
|
||||
};
|
||||
|
||||
const DetailCell = (event: AdminEventRepresentation) => (
|
||||
<DescriptionList isHorizontal className="keycloak_eventsection_details">
|
||||
{event.details &&
|
||||
Object.entries(event.details).map(([key, value]) => (
|
||||
<DescriptionListGroup key={key}>
|
||||
<DescriptionListTerm>{key}</DescriptionListTerm>
|
||||
<DescriptionListDescription>{value}</DescriptionListDescription>
|
||||
</DescriptionListGroup>
|
||||
))}
|
||||
{event.error && (
|
||||
<DescriptionListGroup key="error">
|
||||
<DescriptionListTerm>error</DescriptionListTerm>
|
||||
<DescriptionListDescription>{event.error}</DescriptionListDescription>
|
||||
</DescriptionListGroup>
|
||||
)}
|
||||
</DescriptionList>
|
||||
);
|
||||
|
||||
export const AdminEvents = () => {
|
||||
const { adminClient } = useAdminClient();
|
||||
|
||||
@ -250,8 +272,16 @@ export const AdminEvents = () => {
|
||||
</DisplayDialog>
|
||||
)}
|
||||
<KeycloakDataTable
|
||||
className="keycloak__events_table"
|
||||
key={key}
|
||||
loader={loader}
|
||||
detailColumns={[
|
||||
{
|
||||
name: "details",
|
||||
enabled: (event) => event.details !== undefined,
|
||||
cellRenderer: DetailCell,
|
||||
},
|
||||
]}
|
||||
isPaginated
|
||||
ariaLabelKey="adminEvents"
|
||||
toolbarItem={
|
||||
|
||||
@ -9,4 +9,5 @@ export default interface AdminEventRepresentation {
|
||||
resourcePath?: string;
|
||||
resourceType?: string;
|
||||
time?: number;
|
||||
details?: Record<string, any>;
|
||||
}
|
||||
|
||||
@ -28,35 +28,35 @@ import jakarta.persistence.Table;
|
||||
@Entity
|
||||
@Table(name="ADMIN_EVENT_ENTITY")
|
||||
public class AdminEventEntity {
|
||||
|
||||
|
||||
@Id
|
||||
@Column(name="ID", length = 36)
|
||||
private String id;
|
||||
|
||||
|
||||
@Column(name="ADMIN_EVENT_TIME")
|
||||
private long time;
|
||||
|
||||
|
||||
@Column(name="REALM_ID")
|
||||
private String realmId;
|
||||
|
||||
|
||||
@Column(name="OPERATION_TYPE")
|
||||
private String operationType;
|
||||
|
||||
@Column(name="RESOURCE_TYPE", length = 64)
|
||||
private String resourceType;
|
||||
|
||||
|
||||
@Column(name="AUTH_REALM_ID")
|
||||
private String authRealmId;
|
||||
|
||||
|
||||
@Column(name="AUTH_CLIENT_ID")
|
||||
private String authClientId;
|
||||
|
||||
@Column(name="AUTH_USER_ID")
|
||||
private String authUserId;
|
||||
|
||||
|
||||
@Column(name="IP_ADDRESS")
|
||||
private String authIpAddress;
|
||||
|
||||
|
||||
@Column(name="RESOURCE_PATH")
|
||||
private String resourcePath;
|
||||
|
||||
@ -66,6 +66,9 @@ public class AdminEventEntity {
|
||||
@Column(name="ERROR")
|
||||
private String error;
|
||||
|
||||
@Column(name="DETAILS_JSON")
|
||||
private String detailsJson;
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
@ -161,4 +164,12 @@ public class AdminEventEntity {
|
||||
public void setResourceType(String resourceType) {
|
||||
this.resourceType = resourceType;
|
||||
}
|
||||
|
||||
public String getDetailsJson() {
|
||||
return detailsJson;
|
||||
}
|
||||
|
||||
public void setDetailsJson(String detailsJson) {
|
||||
this.detailsJson = detailsJson;
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,7 +174,7 @@ public class JpaEventStoreProvider implements EventStoreProvider {
|
||||
}
|
||||
return event;
|
||||
}
|
||||
|
||||
|
||||
private AdminEventEntity convertAdminEvent(AdminEvent adminEvent, boolean includeRepresentation) {
|
||||
AdminEventEntity adminEventEntity = new AdminEventEntity();
|
||||
adminEventEntity.setId(adminEvent.getId() == null ? UUID.randomUUID().toString() : adminEvent.getId());
|
||||
@ -189,10 +189,17 @@ public class JpaEventStoreProvider implements EventStoreProvider {
|
||||
|
||||
adminEventEntity.setResourcePath(adminEvent.getResourcePath());
|
||||
adminEventEntity.setError(adminEvent.getError());
|
||||
|
||||
|
||||
if (includeRepresentation) {
|
||||
adminEventEntity.setRepresentation(adminEvent.getRepresentation());
|
||||
}
|
||||
|
||||
try {
|
||||
adminEventEntity.setDetailsJson(mapper.writeValueAsString(adminEvent.getDetails()));
|
||||
} catch (IOException ex) {
|
||||
logger.error("Failed to write log details", ex);
|
||||
}
|
||||
|
||||
return adminEventEntity;
|
||||
}
|
||||
|
||||
@ -210,20 +217,28 @@ public class JpaEventStoreProvider implements EventStoreProvider {
|
||||
|
||||
adminEvent.setResourcePath(adminEventEntity.getResourcePath());
|
||||
adminEvent.setError(adminEventEntity.getError());
|
||||
|
||||
|
||||
if (adminEventEntity.getRepresentation() != null) {
|
||||
adminEvent.setRepresentation(adminEventEntity.getRepresentation());
|
||||
}
|
||||
|
||||
try {
|
||||
Map<String, String> details = mapper.readValue(adminEventEntity.getDetailsJson(), mapType);
|
||||
adminEvent.setDetails(details);
|
||||
} catch (IOException ex) {
|
||||
logger.error("Failed to read log details", ex);
|
||||
}
|
||||
|
||||
return adminEvent;
|
||||
}
|
||||
|
||||
|
||||
private static void setAuthDetails(AdminEventEntity adminEventEntity, AuthDetails authDetails) {
|
||||
adminEventEntity.setAuthRealmId(authDetails.getRealmId());
|
||||
adminEventEntity.setAuthClientId(authDetails.getClientId());
|
||||
adminEventEntity.setAuthUserId(authDetails.getUserId());
|
||||
adminEventEntity.setAuthIpAddress(authDetails.getIpAddress());
|
||||
}
|
||||
|
||||
|
||||
private static void setAuthDetails(AdminEvent adminEvent, AdminEventEntity adminEventEntity) {
|
||||
AuthDetails authDetails = new AuthDetails();
|
||||
authDetails.setRealmId(adminEventEntity.getAuthRealmId());
|
||||
|
||||
@ -191,6 +191,7 @@ public class JpaOrganizationProvider implements OrganizationProvider {
|
||||
}
|
||||
|
||||
user.joinGroup(group, metadata);
|
||||
OrganizationModel.OrganizationMemberJoinEvent.fire(organization, user, session);
|
||||
} finally {
|
||||
if (current == null) {
|
||||
session.getContext().setOrganization(null);
|
||||
@ -430,6 +431,8 @@ public class JpaOrganizationProvider implements OrganizationProvider {
|
||||
}
|
||||
}
|
||||
|
||||
OrganizationModel.OrganizationMemberLeaveEvent.fire(organization, member, session);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!--
|
||||
~ * Copyright 2024 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.
|
||||
-->
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
|
||||
|
||||
<changeSet author="keycloak" id="26.0.6-34013">
|
||||
<addColumn tableName="ADMIN_EVENT_ENTITY">
|
||||
<column name="DETAILS_JSON" type="NCLOB" />
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
@ -84,5 +84,6 @@
|
||||
<include file="META-INF/jpa-changelog-24.0.2.xml"/>
|
||||
<include file="META-INF/jpa-changelog-25.0.0.xml"/>
|
||||
<include file="META-INF/jpa-changelog-26.0.0.xml"/>
|
||||
<include file="META-INF/jpa-changelog-26.0.6.xml"/>
|
||||
|
||||
</databaseChangeLog>
|
||||
|
||||
@ -17,6 +17,9 @@
|
||||
|
||||
package org.keycloak.events.admin;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
@ -25,7 +28,7 @@ public class AdminEvent {
|
||||
private String id;
|
||||
|
||||
private long time;
|
||||
|
||||
|
||||
private String realmId;
|
||||
|
||||
private String realmName;
|
||||
@ -44,7 +47,9 @@ public class AdminEvent {
|
||||
private String representation;
|
||||
|
||||
private String error;
|
||||
|
||||
|
||||
private Map<String, String> details;
|
||||
|
||||
public AdminEvent() {}
|
||||
public AdminEvent(AdminEvent toCopy) {
|
||||
this.id = toCopy.getId();
|
||||
@ -57,6 +62,7 @@ public class AdminEvent {
|
||||
this.resourcePath = toCopy.getResourcePath();
|
||||
this.representation = toCopy.getRepresentation();
|
||||
this.error = toCopy.getError();
|
||||
this.details = toCopy.getDetails() == null ? null : new HashMap<>(toCopy.getDetails());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -84,7 +90,7 @@ public class AdminEvent {
|
||||
public void setTime(long time) {
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the id of the realm
|
||||
*
|
||||
@ -216,4 +222,12 @@ public class AdminEvent {
|
||||
public void setResourceTypeAsString(String resourceType) {
|
||||
this.resourceType = resourceType;
|
||||
}
|
||||
|
||||
public Map<String, String> getDetails() {
|
||||
return details;
|
||||
}
|
||||
|
||||
public void setDetails(Map<String, String> details) {
|
||||
this.details = details;
|
||||
}
|
||||
}
|
||||
|
||||
@ -308,6 +308,7 @@ public class ModelToRepresentation {
|
||||
rep.setResourcePath(adminEvent.getResourcePath());
|
||||
rep.setRepresentation(adminEvent.getRepresentation());
|
||||
rep.setError(adminEvent.getError());
|
||||
rep.setDetails(adminEvent.getDetails());
|
||||
|
||||
return rep;
|
||||
}
|
||||
|
||||
@ -22,6 +22,8 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.keycloak.provider.ProviderEvent;
|
||||
|
||||
public interface OrganizationModel {
|
||||
|
||||
String ORGANIZATION_ATTRIBUTE = "kc.org";
|
||||
@ -47,6 +49,54 @@ public interface OrganizationModel {
|
||||
}
|
||||
}
|
||||
|
||||
interface OrganizationMembershipEvent extends ProviderEvent {
|
||||
OrganizationModel getOrganization();
|
||||
UserModel getUser();
|
||||
KeycloakSession getSession();
|
||||
}
|
||||
|
||||
interface OrganizationMemberJoinEvent extends OrganizationMembershipEvent {
|
||||
static void fire(OrganizationModel organization, UserModel user, KeycloakSession session) {
|
||||
session.getKeycloakSessionFactory().publish(new OrganizationModel.OrganizationMemberJoinEvent() {
|
||||
@Override
|
||||
public UserModel getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrganizationModel getOrganization() {
|
||||
return organization;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeycloakSession getSession() {
|
||||
return session;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
interface OrganizationMemberLeaveEvent extends OrganizationMembershipEvent {
|
||||
static void fire(OrganizationModel organization, UserModel user, KeycloakSession session) {
|
||||
session.getKeycloakSessionFactory().publish(new OrganizationModel.OrganizationMemberLeaveEvent() {
|
||||
@Override
|
||||
public UserModel getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OrganizationModel getOrganization() {
|
||||
return organization;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeycloakSession getSession() {
|
||||
return session;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
String getId();
|
||||
|
||||
void setName(String name);
|
||||
|
||||
@ -165,6 +165,15 @@ public class JBossLoggingEventListenerProvider implements EventListenerProvider
|
||||
sanitize(sb, adminEvent.getError());
|
||||
}
|
||||
|
||||
if (adminEvent.getDetails() != null) {
|
||||
for (Map.Entry<String, String> e : adminEvent.getDetails().entrySet()) {
|
||||
sb.append(", ");
|
||||
sb.append(StringUtil.sanitizeSpacesAndQuotes(e.getKey(), null));
|
||||
sb.append("=");
|
||||
sanitize(sb, e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
if(logger.isTraceEnabled()) {
|
||||
setKeycloakContext(sb);
|
||||
}
|
||||
|
||||
@ -94,6 +94,8 @@ public class OrganizationMemberResource {
|
||||
adminEvent.operation(OperationType.CREATE).resource(ResourceType.ORGANIZATION_MEMBERSHIP)
|
||||
.representation(ModelToRepresentation.toRepresentation(organization))
|
||||
.resourcePath(session.getContext().getUri())
|
||||
.detail(UserModel.USERNAME, user.getUsername())
|
||||
.detail(UserModel.EMAIL, user.getEmail())
|
||||
.success();
|
||||
return Response.created(session.getContext().getUri().getAbsolutePathBuilder().path(user.getId()).build()).build();
|
||||
}
|
||||
@ -172,6 +174,8 @@ public class OrganizationMemberResource {
|
||||
adminEvent.operation(OperationType.DELETE).resource(ResourceType.ORGANIZATION_MEMBERSHIP)
|
||||
.representation(ModelToRepresentation.toRepresentation(organization))
|
||||
.resourcePath(session.getContext().getUri())
|
||||
.detail(UserModel.USERNAME, member.getUsername())
|
||||
.detail(UserModel.EMAIL, member.getEmail())
|
||||
.success();
|
||||
return Response.noContent().build();
|
||||
}
|
||||
|
||||
@ -37,6 +37,8 @@ import org.keycloak.services.ServicesLogger;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
import jakarta.ws.rs.core.UriInfo;
|
||||
import org.keycloak.utils.StringUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@ -264,6 +266,20 @@ public class AdminEventBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public AdminEventBuilder detail(String key, String value) {
|
||||
if (StringUtil.isBlank(value)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
if (adminEvent.getDetails() == null) {
|
||||
adminEvent.setDetails(new HashMap<>());
|
||||
}
|
||||
|
||||
adminEvent.getDetails().put(key, value);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public AdminEvent getEvent() {
|
||||
return adminEvent;
|
||||
}
|
||||
|
||||
@ -1030,7 +1030,13 @@ public class UserResource {
|
||||
try {
|
||||
if (user.isMemberOf(group)){
|
||||
user.leaveGroup(group);
|
||||
adminEvent.operation(OperationType.DELETE).resource(ResourceType.GROUP_MEMBERSHIP).representation(ModelToRepresentation.toRepresentation(group, true)).resourcePath(session.getContext().getUri()).success();
|
||||
adminEvent.operation(OperationType.DELETE)
|
||||
.resource(ResourceType.GROUP_MEMBERSHIP)
|
||||
.representation(ModelToRepresentation.toRepresentation(group, true))
|
||||
.resourcePath(session.getContext().getUri())
|
||||
.detail(UserModel.USERNAME, user.getUsername())
|
||||
.detail(UserModel.EMAIL, user.getEmail())
|
||||
.success();
|
||||
}
|
||||
} catch (ModelIllegalStateException e) {
|
||||
logger.error(e.getMessage(), e);
|
||||
@ -1057,7 +1063,13 @@ public class UserResource {
|
||||
|
||||
if (!RoleUtils.isDirectMember(user.getGroupsStream(),group)){
|
||||
user.joinGroup(group);
|
||||
adminEvent.operation(OperationType.CREATE).resource(ResourceType.GROUP_MEMBERSHIP).representation(ModelToRepresentation.toRepresentation(group, true)).resourcePath(session.getContext().getUri()).success();
|
||||
adminEvent.operation(OperationType.CREATE)
|
||||
.resource(ResourceType.GROUP_MEMBERSHIP)
|
||||
.representation(ModelToRepresentation.toRepresentation(group, true))
|
||||
.resourcePath(session.getContext().getUri())
|
||||
.detail(UserModel.USERNAME, user.getUsername())
|
||||
.detail(UserModel.EMAIL, user.getEmail())
|
||||
.success();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -23,8 +23,12 @@ import org.junit.Test;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.admin.client.resource.UserResource;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.events.admin.ResourceType;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.representations.idm.AdminEventRepresentation;
|
||||
import org.keycloak.representations.idm.AuthDetailsRepresentation;
|
||||
import org.keycloak.representations.idm.OrganizationDomainRepresentation;
|
||||
import org.keycloak.representations.idm.OrganizationRepresentation;
|
||||
import org.keycloak.representations.idm.RealmEventsConfigRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
@ -35,6 +39,7 @@ import org.keycloak.util.JsonSerialization;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hamcrest.Matchers.allOf;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
@ -112,6 +117,30 @@ public class AdminEventTest extends AbstractEventTest {
|
||||
assertThat(details.getIpAddress(), is(notNullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEventDetails() {
|
||||
String userId = createUser("user5");
|
||||
UserRepresentation userRep = testRealmResource().users().get(userId).toRepresentation();
|
||||
RealmRepresentation realmRep = testRealmResource().toRepresentation();
|
||||
realmRep.setOrganizationsEnabled(true);
|
||||
testRealmResource().update(realmRep);
|
||||
OrganizationRepresentation orgRep = new OrganizationRepresentation();
|
||||
orgRep.setName("test-org");
|
||||
orgRep.setAlias(orgRep.getName());
|
||||
orgRep.addDomain(new OrganizationDomainRepresentation(orgRep.getName()));
|
||||
testRealmResource().organizations().create(orgRep).close();
|
||||
orgRep = testRealmResource().organizations().getAll().get(0);
|
||||
testRealmResource().organizations().get(orgRep.getId()).members().addMember(userId).close();
|
||||
List<AdminEventRepresentation> events = events();
|
||||
assertThat(events().size(), is(equalTo(4)));
|
||||
|
||||
AdminEventRepresentation event = events.get(0);
|
||||
assertThat(event.getRealmId(), is(equalTo(realmName())));
|
||||
assertThat(event.getOperationType(), is(equalTo("CREATE")));
|
||||
assertThat(event.getResourceType(), is(equalTo(ResourceType.ORGANIZATION_MEMBERSHIP.name())));
|
||||
assertThat(event.getDetails(), is(equalTo(Map.of(UserModel.USERNAME, userRep.getUsername(), UserModel.EMAIL, userRep.getEmail()))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void retrieveAdminEventTest() {
|
||||
createUser("user1");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user