Add organization admin crud events
Closes #31421 Signed-off-by: Maksim Zvankovich <m.zvankovich@rheagroup.com> Co-authored-by: Stefan Guilhen <sguilhen@redhat.com>
This commit is contained in:
parent
e2810b788e
commit
90dc7c168c
7 changed files with 55 additions and 8 deletions
|
@ -10,6 +10,7 @@ import { toClientScope } from "../client-scopes/routes/ClientScope";
|
||||||
import { toUser } from "../user/routes/User";
|
import { toUser } from "../user/routes/User";
|
||||||
import { toRealmRole } from "../realm-roles/routes/RealmRole";
|
import { toRealmRole } from "../realm-roles/routes/RealmRole";
|
||||||
import { toFlow } from "../authentication/routes/Flow";
|
import { toFlow } from "../authentication/routes/Flow";
|
||||||
|
import { toEditOrganization } from "../organizations/routes/EditOrganization";
|
||||||
|
|
||||||
type ResourceLinkProps = {
|
type ResourceLinkProps = {
|
||||||
event: AdminEventRepresentation;
|
event: AdminEventRepresentation;
|
||||||
|
@ -42,6 +43,8 @@ const isLinkable = (event: AdminEventRepresentation) => {
|
||||||
event.resourceType === "GROUP_MEMBERSHIP" ||
|
event.resourceType === "GROUP_MEMBERSHIP" ||
|
||||||
event.resourceType === "GROUP" ||
|
event.resourceType === "GROUP" ||
|
||||||
event.resourceType === "CLIENT" ||
|
event.resourceType === "CLIENT" ||
|
||||||
|
event.resourceType === "ORGANIZATION" ||
|
||||||
|
event.resourceType === "ORGANIZATION_MEMBERSHIP" ||
|
||||||
event.resourceType?.startsWith("AUTHORIZATION_RESOURCE") ||
|
event.resourceType?.startsWith("AUTHORIZATION_RESOURCE") ||
|
||||||
event.resourceType === "CLIENT_SCOPE" ||
|
event.resourceType === "CLIENT_SCOPE" ||
|
||||||
event.resourceType === "AUTH_FLOW" ||
|
event.resourceType === "AUTH_FLOW" ||
|
||||||
|
@ -95,6 +98,14 @@ const createLink = (realm: string, event: AdminEventRepresentation) => {
|
||||||
return toRealmRole({ realm, id, tab: "details" });
|
return toRealmRole({ realm, id, tab: "details" });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event.resourceType === "ORGANIZATION") {
|
||||||
|
return toEditOrganization({ realm, id, tab: "settings" });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.resourceType === "ORGANIZATION_MEMBERSHIP") {
|
||||||
|
return toEditOrganization({ realm, id, tab: "members" });
|
||||||
|
}
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,6 @@ export class Organizations extends Resource<{ realm?: string }> {
|
||||||
|
|
||||||
public create = this.makeRequest<OrganizationRepresentation, { id: string }>({
|
public create = this.makeRequest<OrganizationRepresentation, { id: string }>({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
path: "/",
|
|
||||||
returnResourceIdInLocationHeader: { field: "id" },
|
returnResourceIdInLocationHeader: { field: "id" },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -196,5 +196,15 @@ public enum ResourceType {
|
||||||
/**
|
/**
|
||||||
* The user profile configuration
|
* The user profile configuration
|
||||||
*/
|
*/
|
||||||
, USER_PROFILE;
|
, USER_PROFILE
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
, ORGANIZATION
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
, ORGANIZATION_MEMBERSHIP;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.keycloak.common.util.Time;
|
||||||
import org.keycloak.email.EmailException;
|
import org.keycloak.email.EmailException;
|
||||||
import org.keycloak.email.EmailTemplateProvider;
|
import org.keycloak.email.EmailTemplateProvider;
|
||||||
import org.keycloak.events.admin.OperationType;
|
import org.keycloak.events.admin.OperationType;
|
||||||
|
import org.keycloak.events.admin.ResourceType;
|
||||||
import org.keycloak.models.Constants;
|
import org.keycloak.models.Constants;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.OrganizationModel;
|
import org.keycloak.models.OrganizationModel;
|
||||||
|
@ -59,7 +60,7 @@ public class OrganizationInvitationResource {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
this.realm = session.getContext().getRealm();
|
this.realm = session.getContext().getRealm();
|
||||||
this.organization = organization;
|
this.organization = organization;
|
||||||
this.adminEvent = adminEvent;
|
this.adminEvent = adminEvent.resource(ResourceType.ORGANIZATION_MEMBERSHIP);
|
||||||
this.tokenExpiration = getTokenExpiration();
|
this.tokenExpiration = getTokenExpiration();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,8 @@ import org.eclipse.microprofile.openapi.annotations.extensions.Extension;
|
||||||
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
|
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
|
||||||
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
|
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
|
||||||
import org.jboss.resteasy.reactive.NoCache;
|
import org.jboss.resteasy.reactive.NoCache;
|
||||||
|
import org.keycloak.events.admin.OperationType;
|
||||||
|
import org.keycloak.events.admin.ResourceType;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.ModelException;
|
import org.keycloak.models.ModelException;
|
||||||
import org.keycloak.models.OrganizationModel;
|
import org.keycloak.models.OrganizationModel;
|
||||||
|
@ -79,7 +81,7 @@ public class OrganizationMemberResource {
|
||||||
this.realm = session.getContext().getRealm();
|
this.realm = session.getContext().getRealm();
|
||||||
this.provider = session.getProvider(OrganizationProvider.class);
|
this.provider = session.getProvider(OrganizationProvider.class);
|
||||||
this.organization = organization;
|
this.organization = organization;
|
||||||
this.adminEvent = adminEvent;
|
this.adminEvent = adminEvent.resource(ResourceType.ORGANIZATION_MEMBERSHIP);
|
||||||
}
|
}
|
||||||
|
|
||||||
@POST
|
@POST
|
||||||
|
@ -97,6 +99,10 @@ public class OrganizationMemberResource {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (provider.addMember(organization, user)) {
|
if (provider.addMember(organization, user)) {
|
||||||
|
adminEvent.operation(OperationType.CREATE).resource(ResourceType.ORGANIZATION_MEMBERSHIP)
|
||||||
|
.representation(ModelToRepresentation.toRepresentation(organization))
|
||||||
|
.resourcePath(session.getContext().getUri())
|
||||||
|
.success();
|
||||||
return Response.created(session.getContext().getUri().getAbsolutePathBuilder().path(user.getId()).build()).build();
|
return Response.created(session.getContext().getUri().getAbsolutePathBuilder().path(user.getId()).build()).build();
|
||||||
}
|
}
|
||||||
} catch (ModelException me) {
|
} catch (ModelException me) {
|
||||||
|
@ -171,6 +177,10 @@ public class OrganizationMemberResource {
|
||||||
UserModel member = getMember(id);
|
UserModel member = getMember(id);
|
||||||
|
|
||||||
if (provider.removeMember(organization, member)) {
|
if (provider.removeMember(organization, member)) {
|
||||||
|
adminEvent.operation(OperationType.DELETE).resource(ResourceType.ORGANIZATION_MEMBERSHIP)
|
||||||
|
.representation(ModelToRepresentation.toRepresentation(organization))
|
||||||
|
.resourcePath(session.getContext().getUri())
|
||||||
|
.success();
|
||||||
return Response.noContent().build();
|
return Response.noContent().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,11 +25,14 @@ import jakarta.ws.rs.Path;
|
||||||
import jakarta.ws.rs.Produces;
|
import jakarta.ws.rs.Produces;
|
||||||
import jakarta.ws.rs.core.MediaType;
|
import jakarta.ws.rs.core.MediaType;
|
||||||
import jakarta.ws.rs.core.Response;
|
import jakarta.ws.rs.core.Response;
|
||||||
|
import jakarta.ws.rs.core.Response.Status;
|
||||||
import jakarta.ws.rs.ext.Provider;
|
import jakarta.ws.rs.ext.Provider;
|
||||||
import org.eclipse.microprofile.openapi.annotations.Operation;
|
import org.eclipse.microprofile.openapi.annotations.Operation;
|
||||||
import org.eclipse.microprofile.openapi.annotations.extensions.Extension;
|
import org.eclipse.microprofile.openapi.annotations.extensions.Extension;
|
||||||
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
|
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
|
||||||
import org.jboss.resteasy.reactive.NoCache;
|
import org.jboss.resteasy.reactive.NoCache;
|
||||||
|
import org.keycloak.events.admin.OperationType;
|
||||||
|
import org.keycloak.events.admin.ResourceType;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.ModelValidationException;
|
import org.keycloak.models.ModelValidationException;
|
||||||
import org.keycloak.models.OrganizationModel;
|
import org.keycloak.models.OrganizationModel;
|
||||||
|
@ -59,7 +62,7 @@ public class OrganizationResource {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
this.provider = session == null ? null : session.getProvider(OrganizationProvider.class);
|
this.provider = session == null ? null : session.getProvider(OrganizationProvider.class);
|
||||||
this.organization = organization;
|
this.organization = organization;
|
||||||
this.adminEvent = adminEvent;
|
this.adminEvent = adminEvent.resource(ResourceType.ORGANIZATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
|
@ -75,8 +78,13 @@ public class OrganizationResource {
|
||||||
@Tag(name = KeycloakOpenAPI.Admin.Tags.ORGANIZATIONS)
|
@Tag(name = KeycloakOpenAPI.Admin.Tags.ORGANIZATIONS)
|
||||||
@Operation(summary = "Deletes the organization")
|
@Operation(summary = "Deletes the organization")
|
||||||
public Response delete() {
|
public Response delete() {
|
||||||
provider.remove(organization);
|
boolean removed = provider.remove(organization);
|
||||||
return Response.noContent().build();
|
if (removed) {
|
||||||
|
adminEvent.operation(OperationType.DELETE).resourcePath(session.getContext().getUri()).success();
|
||||||
|
return Response.noContent().build();
|
||||||
|
} else {
|
||||||
|
throw ErrorResponse.error("organization couldn't be deleted", Status.BAD_REQUEST);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@PUT
|
@PUT
|
||||||
|
@ -86,6 +94,7 @@ public class OrganizationResource {
|
||||||
public Response update(OrganizationRepresentation organizationRep) {
|
public Response update(OrganizationRepresentation organizationRep) {
|
||||||
try {
|
try {
|
||||||
RepresentationToModel.toModel(organizationRep, organization);
|
RepresentationToModel.toModel(organizationRep, organization);
|
||||||
|
adminEvent.operation(OperationType.UPDATE).resourcePath(session.getContext().getUri()).representation(organizationRep).success();
|
||||||
return Response.noContent().build();
|
return Response.noContent().build();
|
||||||
} catch (ModelValidationException mve) {
|
} catch (ModelValidationException mve) {
|
||||||
throw ErrorResponse.error(mve.getMessage(), Response.Status.BAD_REQUEST);
|
throw ErrorResponse.error(mve.getMessage(), Response.Status.BAD_REQUEST);
|
||||||
|
|
|
@ -37,7 +37,10 @@ import org.eclipse.microprofile.openapi.annotations.Operation;
|
||||||
import org.eclipse.microprofile.openapi.annotations.extensions.Extension;
|
import org.eclipse.microprofile.openapi.annotations.extensions.Extension;
|
||||||
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
|
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
|
||||||
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
|
import org.eclipse.microprofile.openapi.annotations.tags.Tag;
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
import org.jboss.resteasy.reactive.NoCache;
|
import org.jboss.resteasy.reactive.NoCache;
|
||||||
|
import org.keycloak.events.admin.OperationType;
|
||||||
|
import org.keycloak.events.admin.ResourceType;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.ModelDuplicateException;
|
import org.keycloak.models.ModelDuplicateException;
|
||||||
import org.keycloak.models.ModelValidationException;
|
import org.keycloak.models.ModelValidationException;
|
||||||
|
@ -64,6 +67,8 @@ public class OrganizationsResource {
|
||||||
private final AdminPermissionEvaluator auth;
|
private final AdminPermissionEvaluator auth;
|
||||||
private final AdminEventBuilder adminEvent;
|
private final AdminEventBuilder adminEvent;
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(OrganizationsResource.class);
|
||||||
|
|
||||||
public OrganizationsResource() {
|
public OrganizationsResource() {
|
||||||
// needed for registering to the JAX-RS stack
|
// needed for registering to the JAX-RS stack
|
||||||
this(null, null, null);
|
this(null, null, null);
|
||||||
|
@ -73,7 +78,7 @@ public class OrganizationsResource {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
this.provider = session == null ? null : session.getProvider(OrganizationProvider.class);
|
this.provider = session == null ? null : session.getProvider(OrganizationProvider.class);
|
||||||
this.auth = auth;
|
this.auth = auth;
|
||||||
this.adminEvent = adminEvent;
|
this.adminEvent = adminEvent.resource(ResourceType.ORGANIZATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -99,6 +104,8 @@ public class OrganizationsResource {
|
||||||
try {
|
try {
|
||||||
OrganizationModel model = provider.create(organization.getName(), organization.getAlias());
|
OrganizationModel model = provider.create(organization.getName(), organization.getAlias());
|
||||||
RepresentationToModel.toModel(organization, model);
|
RepresentationToModel.toModel(organization, model);
|
||||||
|
organization.setId(model.getId());
|
||||||
|
adminEvent.operation(OperationType.CREATE).resourcePath(session.getContext().getUri(), model.getId()).representation(organization).success();
|
||||||
return Response.created(session.getContext().getUri().getAbsolutePathBuilder().path(model.getId()).build()).build();
|
return Response.created(session.getContext().getUri().getAbsolutePathBuilder().path(model.getId()).build()).build();
|
||||||
} catch (ModelValidationException mve) {
|
} catch (ModelValidationException mve) {
|
||||||
throw ErrorResponse.error(mve.getMessage(), Response.Status.BAD_REQUEST);
|
throw ErrorResponse.error(mve.getMessage(), Response.Status.BAD_REQUEST);
|
||||||
|
|
Loading…
Reference in a new issue