From a0a154d9c983158bf9155969bad1d88e4f9dcc45 Mon Sep 17 00:00:00 2001 From: Erik Jan de Wit Date: Wed, 24 Aug 2022 15:35:38 +0200 Subject: [PATCH] revert kotlin back to java (#3183) removing all extra dependencies --- keycloak-theme/pom.xml | 86 -------- .../ui/rest/AvailableRoleMappingProvider.java | 35 ++++ .../ui/rest/AvailableRoleMappingProvider.kt | 32 --- .../ui/rest/AvailableRoleMappingResource.java | 184 ++++++++++++++++++ .../ui/rest/AvailableRoleMappingResource.kt | 178 ----------------- .../ui/rest/EffectiveRoleMappingProvider.java | 35 ++++ .../ui/rest/EffectiveRoleMappingProvider.kt | 32 --- .../ui/rest/EffectiveRoleMappingResource.java | 171 ++++++++++++++++ .../ui/rest/EffectiveRoleMappingResource.kt | 156 --------------- .../admin/ui/rest/RoleMappingResource.java | 35 ++++ .../admin/ui/rest/RoleMappingResource.kt | 45 ----- .../admin/ui/rest/model/ClientRole.java | 79 ++++++++ .../admin/ui/rest/model/ClientRole.kt | 12 -- .../admin/ui/rest/model/RoleMapper.java | 17 ++ .../admin/ui/rest/model/RoleMapper.kt | 21 -- 15 files changed, 556 insertions(+), 562 deletions(-) create mode 100644 keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/AvailableRoleMappingProvider.java delete mode 100644 keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/AvailableRoleMappingProvider.kt create mode 100644 keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/AvailableRoleMappingResource.java delete mode 100644 keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/AvailableRoleMappingResource.kt create mode 100644 keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/EffectiveRoleMappingProvider.java delete mode 100644 keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/EffectiveRoleMappingProvider.kt create mode 100644 keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/EffectiveRoleMappingResource.java delete mode 100644 keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/EffectiveRoleMappingResource.kt create mode 100644 keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/RoleMappingResource.java delete mode 100644 keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/RoleMappingResource.kt create mode 100644 keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/model/ClientRole.java delete mode 100644 keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/model/ClientRole.kt create mode 100644 keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/model/RoleMapper.java delete mode 100644 keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/model/RoleMapper.kt diff --git a/keycloak-theme/pom.xml b/keycloak-theme/pom.xml index 3236615a46..d64f6d92b6 100644 --- a/keycloak-theme/pom.xml +++ b/keycloak-theme/pom.xml @@ -37,8 +37,6 @@ v18.7.0 19.0.1 - 1.7.10 - 1.5.2.Final @@ -93,27 +91,11 @@ keycloak-services ${keycloak.version} - - org.jetbrains.kotlin - kotlin-stdlib-jdk8 - ${kotlin.version} - - - org.mapstruct - mapstruct - ${mapstruct.version} - org.eclipse.microprofile.openapi microprofile-openapi-api 3.0 - - org.jetbrains.kotlin - kotlin-test - ${kotlin.version} - test - org.testng testng @@ -191,78 +173,10 @@ - - org.jetbrains.kotlin - kotlin-maven-plugin - ${kotlin.version} - - - compile - compile - - compile - - - - test-compile - test-compile - - test-compile - - - - kapt - - kapt - - - - src/main/java - - - - org.mapstruct - mapstruct-processor - ${mapstruct.version} - - - - - - - 1.8 - - org.apache.maven.plugins maven-compiler-plugin 3.10.1 - - - - default-compile - none - - - - default-testCompile - none - - - java-compile - compile - - compile - - - - java-test-compile - test-compile - - testCompile - - - 8 8 diff --git a/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/AvailableRoleMappingProvider.java b/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/AvailableRoleMappingProvider.java new file mode 100644 index 0000000000..2531384411 --- /dev/null +++ b/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/AvailableRoleMappingProvider.java @@ -0,0 +1,35 @@ +package org.keycloak.admin.ui.rest; + +import org.keycloak.Config; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.KeycloakSessionFactory; +import org.keycloak.models.RealmModel; +import org.keycloak.services.resources.admin.AdminEventBuilder; +import org.keycloak.services.resources.admin.ext.AdminRealmResourceProvider; +import org.keycloak.services.resources.admin.ext.AdminRealmResourceProviderFactory; +import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator; + +public final class AvailableRoleMappingProvider implements AdminRealmResourceProviderFactory, AdminRealmResourceProvider { + public AdminRealmResourceProvider create(KeycloakSession session) { + return this; + } + + public void init(Config.Scope config) { + + } + + public void postInit(KeycloakSessionFactory factory) { + + } + + public void close() { + } + + public String getId() { + return "admin-ui-available-roles"; + } + + public Object getResource(KeycloakSession session, RealmModel realm, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) { + return new AvailableRoleMappingResource(realm, auth); + } +} diff --git a/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/AvailableRoleMappingProvider.kt b/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/AvailableRoleMappingProvider.kt deleted file mode 100644 index a6577ed3f2..0000000000 --- a/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/AvailableRoleMappingProvider.kt +++ /dev/null @@ -1,32 +0,0 @@ -package org.keycloak.admin.ui.rest - -import org.keycloak.Config -import org.keycloak.models.KeycloakSession -import org.keycloak.models.KeycloakSessionFactory -import org.keycloak.models.RealmModel -import org.keycloak.services.resources.admin.AdminEventBuilder -import org.keycloak.services.resources.admin.ext.AdminRealmResourceProvider -import org.keycloak.services.resources.admin.ext.AdminRealmResourceProviderFactory -import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator - -class AvailableRoleMappingProvider : AdminRealmResourceProviderFactory, AdminRealmResourceProvider { - override fun create(session: KeycloakSession): AdminRealmResourceProvider { - return this - } - - override fun init(config: Config.Scope) {} - override fun postInit(factory: KeycloakSessionFactory) {} - override fun close() {} - override fun getId(): String { - return "admin-ui-available-roles" - } - - override fun getResource( - session: KeycloakSession, - realm: RealmModel, - auth: AdminPermissionEvaluator, - adminEvent: AdminEventBuilder - ): Any { - return AvailableRoleMappingResource(realm, auth) - } -} \ No newline at end of file diff --git a/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/AvailableRoleMappingResource.java b/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/AvailableRoleMappingResource.java new file mode 100644 index 0000000000..20c7b17300 --- /dev/null +++ b/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/AvailableRoleMappingResource.java @@ -0,0 +1,184 @@ +package org.keycloak.admin.ui.rest; + +import java.util.List; +import java.util.Objects; +import java.util.function.Predicate; +import javax.ws.rs.Consumes; +import javax.ws.rs.DefaultValue; +import javax.ws.rs.ForbiddenException; +import javax.ws.rs.GET; +import javax.ws.rs.NotFoundException; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import org.eclipse.microprofile.openapi.annotations.Operation; +import org.eclipse.microprofile.openapi.annotations.enums.SchemaType; +import org.eclipse.microprofile.openapi.annotations.media.Content; +import org.eclipse.microprofile.openapi.annotations.media.Schema; +import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; +import org.keycloak.admin.ui.rest.model.ClientRole; +import org.keycloak.models.ClientModel; +import org.keycloak.models.ClientScopeModel; +import org.keycloak.models.GroupModel; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.RealmModel; +import org.keycloak.models.RoleModel; +import org.keycloak.models.UserModel; +import org.keycloak.models.UserProvider; +import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator; + +public class AvailableRoleMappingResource extends RoleMappingResource { + @Context + private KeycloakSession session; + private final RealmModel realm; + private final AdminPermissionEvaluator auth; + + public AvailableRoleMappingResource(RealmModel realm, AdminPermissionEvaluator auth) { + super(realm, auth); + this.realm = realm; + this.auth = auth; + } + + @GET + @Path("/clientScopes/{id}") + @Consumes({"application/json"}) + @Produces({"application/json"}) + @Operation( + summary = "List all composite client roles for this client scope", + description = "This endpoint returns all the client role mapping for a specific client scope" + ) + @APIResponse( + responseCode = "200", + description = "", + content = {@Content( + schema = @Schema( + implementation = ClientRole.class, + type = SchemaType.ARRAY + ) + )} + ) + public final List listCompositeClientScopeRoleMappings(@PathParam("id") String id, @QueryParam("first") + @DefaultValue("0") long first, @QueryParam("max") @DefaultValue("10") long max, @QueryParam("search") @DefaultValue("") String search) { + ClientScopeModel scopeModel = this.realm.getClientScopeById(id); + if (scopeModel == null) { + throw new NotFoundException("Could not find client scope"); + } else { + this.auth.clients().requireView(scopeModel); + return this.mapping(((Predicate) scopeModel::hasDirectScope).negate(), first, max, search); + } + } + + @GET + @Path("/clients/{id}") + @Consumes({"application/json"}) + @Produces({"application/json"}) + @Operation( + summary = "List all composite client roles for this client", + description = "This endpoint returns all the client role mapping for a specific client" + ) + @APIResponse( + responseCode = "200", + description = "", + content = {@Content( + schema = @Schema( + implementation = ClientRole.class, + type = SchemaType.ARRAY + ) + )} + ) + public final List listCompositeClientRoleMappings(@PathParam("id") String id, @QueryParam("first") + @DefaultValue("0") long first, @QueryParam("max") @DefaultValue("10") long max, @QueryParam("search") @DefaultValue("") String search) { + ClientModel client = this.realm.getClientById(id); + if (client == null) { + throw new NotFoundException("Could not find client"); + } else { + this.auth.clients().requireView(client); + return this.mapping(((Predicate) client::hasDirectScope).negate(), first, max, search); + } + } + + @GET + @Path("/groups/{id}") + @Consumes({"application/json"}) + @Produces({"application/json"}) + @Operation( + summary = "List all composite client roles for this group", + description = "This endpoint returns all the client role mapping for a specific group" + ) + @APIResponse( + responseCode = "200", + description = "", + content = {@Content( + schema = @Schema( + implementation = ClientRole.class, + type = SchemaType.ARRAY + ) + )} + ) + public final List listCompositeGroupRoleMappings(@PathParam("id") String id, @QueryParam("first") + @DefaultValue("0") long first, @QueryParam("max") @DefaultValue("10") long max, @QueryParam("search") @DefaultValue("") String search) { + GroupModel group = this.realm.getGroupById(id); + if (group == null) { + throw new NotFoundException("Could not find group"); + } else { + this.auth.groups().requireView(group); + return this.mapping(((Predicate) group::hasDirectRole).negate(), first, max, search); + } + } + + @GET + @Path("/users/{id}") + @Consumes({"application/json"}) + @Produces({"application/json"}) + @Operation( + summary = "List all composite client roles for this user", + description = "This endpoint returns all the client role mapping for a specific user" + ) + @APIResponse( + responseCode = "200", + description = "", + content = {@Content( + schema = @Schema( + implementation = ClientRole.class, + type = SchemaType.ARRAY + ) + )} + ) + public final List listCompositeUserRoleMappings(@PathParam("id") String id, @QueryParam("first") @DefaultValue("0") long first, + @QueryParam("max") @DefaultValue("10") long max, @QueryParam("search") @DefaultValue("") String search) { + UserProvider users = Objects.requireNonNull(session).users(); + UserModel userModel = users.getUserById(this.realm, id); + if (userModel == null) { + if (auth.users().canQuery()) throw new NotFoundException("User not found"); + else throw new ForbiddenException(); + } + + this.auth.users().requireView(userModel); + return this.mapping(((Predicate) userModel::hasDirectRole).negate(), first, max, search); + } + + @GET + @Path("/roles/{id}") + @Consumes({"application/json"}) + @Produces({"application/json"}) + @Operation( + summary = "List all composite client roles", + description = "This endpoint returns all the client role" + ) + @APIResponse( + responseCode = "200", + description = "", + content = {@Content( + schema = @Schema( + implementation = ClientRole.class, + type = SchemaType.ARRAY + ) + )} + ) + public final List listCompositeRoleMappings(@QueryParam("first") @DefaultValue("0") long first, + @QueryParam("max") @DefaultValue("10") long max, @QueryParam("search") @DefaultValue("") String search) { + return this.mapping(o -> true, first, max, search); + } +} diff --git a/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/AvailableRoleMappingResource.kt b/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/AvailableRoleMappingResource.kt deleted file mode 100644 index b61d897f6e..0000000000 --- a/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/AvailableRoleMappingResource.kt +++ /dev/null @@ -1,178 +0,0 @@ -package org.keycloak.admin.ui.rest - -import org.eclipse.microprofile.openapi.annotations.Operation -import org.eclipse.microprofile.openapi.annotations.enums.SchemaType -import org.eclipse.microprofile.openapi.annotations.media.Content -import org.eclipse.microprofile.openapi.annotations.media.Schema -import org.eclipse.microprofile.openapi.annotations.responses.APIResponse -import org.keycloak.admin.ui.rest.model.ClientRole -import org.keycloak.admin.ui.rest.model.RoleMapper -import org.keycloak.models.KeycloakSession -import org.keycloak.models.RealmModel -import org.keycloak.models.RoleModel -import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator -import org.mapstruct.factory.Mappers -import java.util.* -import java.util.function.Predicate -import java.util.stream.Collectors -import javax.ws.rs.* -import javax.ws.rs.core.Context -import javax.ws.rs.core.MediaType - -@Path("/") -open class AvailableRoleMappingResource( - private var realm: RealmModel, - private var auth: AdminPermissionEvaluator, -) : RoleMappingResource(realm, auth) { - @Context - var session: KeycloakSession? = null - - @GET - @Path("/clientScopes/{id}") - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - @Operation( - summary = "List all composite client roles for this client scope", - description = "This endpoint returns all the client role mapping for a specific client scope" - ) - @APIResponse( - responseCode = "200", - description = "", - content = [Content( - schema = Schema( - type = SchemaType.ARRAY, - implementation = ClientRole::class - ) - )] - ) - fun listCompositeClientScopeRoleMappings( - @PathParam("id") id: String, - @QueryParam("first") @DefaultValue("0") first: Long, - @QueryParam("max") @DefaultValue("10") max: Long, - @QueryParam("search") @DefaultValue("") search: String - ): List { - val scopeContainer = realm.getClientScopeById(id) ?: throw NotFoundException("Could not find client scope") - auth.clients().requireView(scopeContainer) - - return mapping(Predicate { r -> scopeContainer.hasDirectScope(r) }.negate(), first, max, search) - } - - @GET - @Path("/clients/{id}") - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - @Operation( - summary = "List all composite client roles for this client", - description = "This endpoint returns all the client role mapping for a specific client" - ) - @APIResponse( - responseCode = "200", - description = "", - content = [Content( - schema = Schema( - type = SchemaType.ARRAY, - implementation = ClientRole::class - ) - )] - ) - fun listCompositeClientRoleMappings( - @PathParam("id") id: String, - @QueryParam("first") @DefaultValue("0") first: Long, - @QueryParam("max") @DefaultValue("10") max: Long, - @QueryParam("search") @DefaultValue("") search: String - ): List { - val scopeContainer = realm.getClientById(id) ?: throw NotFoundException("Could not find client") - auth.clients().requireView(scopeContainer) - - return mapping(Predicate { r -> scopeContainer.hasDirectScope(r) }.negate(), first, max, search) - } - - @GET - @Path("/groups/{id}") - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - @Operation( - summary = "List all composite client roles for this group", - description = "This endpoint returns all the client role mapping for a specific group" - ) - @APIResponse( - responseCode = "200", - description = "", - content = [Content( - schema = Schema( - type = SchemaType.ARRAY, - implementation = ClientRole::class - ) - )] - ) - fun listCompositeGroupRoleMappings( - @PathParam("id") id: String, - @QueryParam("first") @DefaultValue("0") first: Long, - @QueryParam("max") @DefaultValue("10") max: Long, - @QueryParam("search") @DefaultValue("") search: String - ): List { - val scopeContainer = realm.getGroupById(id) ?: throw NotFoundException("Could not find group") - auth.groups().requireView(scopeContainer) - - return mapping(Predicate { r -> scopeContainer.hasDirectRole(r) }.negate(), first, max, search) - - } - - @GET - @Path("/users/{id}") - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - @Operation( - summary = "List all composite client roles for this user", - description = "This endpoint returns all the client role mapping for a specific user" - ) - @APIResponse( - responseCode = "200", - description = "", - content = [Content( - schema = Schema( - type = SchemaType.ARRAY, - implementation = ClientRole::class - ) - )] - ) - fun listCompositeUserRoleMappings( - @PathParam("id") id: String, - @QueryParam("first") @DefaultValue("0") first: Long, - @QueryParam("max") @DefaultValue("10") max: Long, - @QueryParam("search") @DefaultValue("") search: String - ): List { - val user = session?.users()?.getUserById(realm, id) - ?: if (auth.users().canQuery()) throw NotFoundException("User not found") else throw ForbiddenException() - auth.users().requireView(user) - - return mapping(Predicate { r -> user.hasDirectRole(r) }.negate(), first, max, search) - - } - - @GET - @Path("/roles/{id}") - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - @Operation( - summary = "List all composite client roles", - description = "This endpoint returns all the client role" - ) - @APIResponse( - responseCode = "200", - description = "", - content = [Content( - schema = Schema( - type = SchemaType.ARRAY, - implementation = ClientRole::class - ) - )] - ) - fun listCompositeRoleMappings( - @QueryParam("first") @DefaultValue("0") first: Long, - @QueryParam("max") @DefaultValue("10") max: Long, - @QueryParam("search") @DefaultValue("") search: String - ): List { - return mapping({ true }, first, max, search) - } -} \ No newline at end of file diff --git a/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/EffectiveRoleMappingProvider.java b/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/EffectiveRoleMappingProvider.java new file mode 100644 index 0000000000..38c4d3a448 --- /dev/null +++ b/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/EffectiveRoleMappingProvider.java @@ -0,0 +1,35 @@ +package org.keycloak.admin.ui.rest; + +import org.keycloak.Config; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.KeycloakSessionFactory; +import org.keycloak.models.RealmModel; +import org.keycloak.services.resources.admin.AdminEventBuilder; +import org.keycloak.services.resources.admin.ext.AdminRealmResourceProvider; +import org.keycloak.services.resources.admin.ext.AdminRealmResourceProviderFactory; +import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator; + +public final class EffectiveRoleMappingProvider implements AdminRealmResourceProviderFactory, AdminRealmResourceProvider { + public AdminRealmResourceProvider create(KeycloakSession session) { + return this; + } + + public void init(Config.Scope config) { + + } + + public void postInit(KeycloakSessionFactory factory) { + + } + + public void close() { + } + + public String getId() { + return "admin-ui-effective-roles"; + } + + public Object getResource(KeycloakSession session, RealmModel realm, AdminPermissionEvaluator auth, AdminEventBuilder adminEvent) { + return new EffectiveRoleMappingResource(realm, auth); + } +} diff --git a/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/EffectiveRoleMappingProvider.kt b/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/EffectiveRoleMappingProvider.kt deleted file mode 100644 index ac3a3df1c0..0000000000 --- a/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/EffectiveRoleMappingProvider.kt +++ /dev/null @@ -1,32 +0,0 @@ -package org.keycloak.admin.ui.rest - -import org.keycloak.Config -import org.keycloak.models.KeycloakSession -import org.keycloak.models.KeycloakSessionFactory -import org.keycloak.models.RealmModel -import org.keycloak.services.resources.admin.AdminEventBuilder -import org.keycloak.services.resources.admin.ext.AdminRealmResourceProvider -import org.keycloak.services.resources.admin.ext.AdminRealmResourceProviderFactory -import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator - -class EffectiveRoleMappingProvider : AdminRealmResourceProviderFactory, AdminRealmResourceProvider { - override fun create(session: KeycloakSession): AdminRealmResourceProvider { - return this - } - - override fun init(config: Config.Scope) {} - override fun postInit(factory: KeycloakSessionFactory) {} - override fun close() {} - override fun getId(): String { - return "admin-ui-effective-roles" - } - - override fun getResource( - session: KeycloakSession, - realm: RealmModel, - auth: AdminPermissionEvaluator, - adminEvent: AdminEventBuilder - ): Any { - return EffectiveRoleMappingResource(realm, auth) - } -} \ No newline at end of file diff --git a/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/EffectiveRoleMappingResource.java b/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/EffectiveRoleMappingResource.java new file mode 100644 index 0000000000..72d52e6700 --- /dev/null +++ b/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/EffectiveRoleMappingResource.java @@ -0,0 +1,171 @@ +package org.keycloak.admin.ui.rest; + +import java.util.List; +import java.util.stream.Collectors; +import javax.ws.rs.Consumes; +import javax.ws.rs.ForbiddenException; +import javax.ws.rs.GET; +import javax.ws.rs.NotFoundException; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import org.eclipse.microprofile.openapi.annotations.Operation; +import org.eclipse.microprofile.openapi.annotations.enums.SchemaType; +import org.eclipse.microprofile.openapi.annotations.media.Content; +import org.eclipse.microprofile.openapi.annotations.media.Schema; +import org.eclipse.microprofile.openapi.annotations.responses.APIResponse; +import org.keycloak.admin.ui.rest.model.ClientRole; +import org.keycloak.models.ClientModel; +import org.keycloak.models.ClientScopeModel; +import org.keycloak.models.GroupModel; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.RealmModel; +import org.keycloak.models.UserModel; +import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator; + +public class EffectiveRoleMappingResource extends RoleMappingResource { + @Context + private KeycloakSession session; + private RealmModel realm; + private AdminPermissionEvaluator auth; + + public EffectiveRoleMappingResource(RealmModel realm, AdminPermissionEvaluator auth) { + super(realm, auth); + this.realm = realm; + this.auth = auth; + } + + @GET + @Path("/clientScopes/{id}") + @Consumes({"application/json"}) + @Produces({"application/json"}) + @Operation( + summary = "List all effective roles for this client scope", + description = "This endpoint returns all the client role mapping for a specific client scope" + ) + @APIResponse( + responseCode = "200", + description = "", + content = {@Content( + schema = @Schema( + implementation = ClientRole.class, + type = SchemaType.ARRAY + ) + )} + ) + public final List listCompositeClientScopeRoleMappings(@PathParam("id") String id) { + ClientScopeModel clientScope = this.realm.getClientScopeById(id); + if (clientScope == null) { + throw new NotFoundException("Could not find client scope"); + } + + this.auth.clients().requireView(clientScope); + return this.mapping(clientScope::hasScope).collect(Collectors.toList()); + } + + @GET + @Path("/clients/{id}") + @Consumes({"application/json"}) + @Produces({"application/json"}) + @Operation( + summary = "List all effective roles for this client", + description = "This endpoint returns all the client role mapping for a specific client" + ) + @APIResponse( + responseCode = "200", + description = "", + content = {@Content( + schema = @Schema( + implementation = ClientRole.class, + type = SchemaType.ARRAY + ) + )} + ) + public final List listCompositeClientsRoleMappings(@PathParam("id") String id) { + ClientModel client = this.realm.getClientById(id); + if (client == null) { + throw new NotFoundException("Could not find client"); + } + auth.clients().requireView(client); + return mapping(client::hasScope).collect(Collectors.toList()); + } + + @GET + @Path("/groups/{id}") + @Consumes({"application/json"}) + @Produces({"application/json"}) + @Operation( + summary = "List all effective roles for this group", + description = "This endpoint returns all the client role mapping for a specific group" + ) + @APIResponse( + responseCode = "200", + description = "", + content = {@Content( + schema = @Schema( + implementation = ClientRole.class, + type = SchemaType.ARRAY + ) + )} + ) + public final List listCompositeGroupsRoleMappings(@PathParam("id") String id) { + GroupModel group = this.realm.getGroupById(id); + if (group == null) { + throw new NotFoundException("Could not find group"); + } + + return mapping(group::hasDirectRole).collect(Collectors.toList()); + } + + @GET + @Path("/users/{id}") + @Consumes({"application/json"}) + @Produces({"application/json"}) + @Operation( + summary = "List all effective roles for this users", + description = "This endpoint returns all the client role mapping for a specific users" + ) + @APIResponse( + responseCode = "200", + description = "", + content = {@Content( + schema = @Schema( + implementation = ClientRole.class, + type = SchemaType.ARRAY + ) + )} + ) + public final List listCompositeUsersRoleMappings(@PathParam("id") String id) { + UserModel user = session.users().getUserById(this.realm, id); + if (user == null) { + if (auth.users().canQuery()) throw new NotFoundException("User not found"); + else throw new ForbiddenException(); + } + + return mapping(user::hasDirectRole).collect(Collectors.toList()); + } + + @GET + @Path("/roles/{id}") + @Consumes({"application/json"}) + @Produces({"application/json"}) + @Operation( + summary = "List all effective roles for this realm role", + description = "This endpoint returns all the client role mapping for a specific realm role" + ) + @APIResponse( + responseCode = "200", + description = "", + content = {@Content( + schema = @Schema( + implementation = ClientRole.class, + type = SchemaType.ARRAY + ) + )} + ) + public final List listCompositeRealmRoleMappings() { + return mapping (o -> true ).collect(Collectors.toList()); + } + +} diff --git a/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/EffectiveRoleMappingResource.kt b/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/EffectiveRoleMappingResource.kt deleted file mode 100644 index 54b29a711d..0000000000 --- a/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/EffectiveRoleMappingResource.kt +++ /dev/null @@ -1,156 +0,0 @@ -package org.keycloak.admin.ui.rest - -import org.eclipse.microprofile.openapi.annotations.Operation -import org.eclipse.microprofile.openapi.annotations.enums.SchemaType -import org.eclipse.microprofile.openapi.annotations.media.Content -import org.eclipse.microprofile.openapi.annotations.media.Schema -import org.eclipse.microprofile.openapi.annotations.responses.APIResponse -import org.keycloak.admin.ui.rest.model.ClientRole -import org.keycloak.models.KeycloakSession -import org.keycloak.models.RealmModel -import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator -import java.util.stream.Collectors -import javax.ws.rs.* -import javax.ws.rs.core.Context -import javax.ws.rs.core.MediaType - -@Path("/") -open class EffectiveRoleMappingResource( - private var realm: RealmModel, - private var auth: AdminPermissionEvaluator, -) : RoleMappingResource(realm, auth) { - @Context - var session: KeycloakSession? = null - - @GET - @Path("/clientScopes/{id}") - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - @Operation( - summary = "List all effective roles for this client scope", - description = "This endpoint returns all the client role mapping for a specific client scope" - ) - @APIResponse( - responseCode = "200", - description = "", - content = [Content( - schema = Schema( - type = SchemaType.ARRAY, - implementation = ClientRole::class - ) - )] - ) - fun listCompositeClientScopeRoleMappings( - @PathParam("id") id: String, - ): List { - val scopeContainer = realm.getClientScopeById(id) ?: throw NotFoundException("Could not find client scope") - auth.clients().requireView(scopeContainer) - - return mapping(scopeContainer::hasScope).collect(Collectors.toList()) - } - - @GET - @Path("/clients/{id}") - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - @Operation( - summary = "List all effective roles for this client", - description = "This endpoint returns all the client role mapping for a specific client" - ) - @APIResponse( - responseCode = "200", - description = "", - content = [Content( - schema = Schema( - type = SchemaType.ARRAY, - implementation = ClientRole::class - ) - )] - ) - fun listCompositeClientsRoleMappings( - @PathParam("id") id: String, - ): List { - val scopeContainer = realm.getClientById(id) ?: throw NotFoundException("Could not find client") - auth.clients().requireView(scopeContainer) - - return mapping(scopeContainer::hasScope).collect(Collectors.toList()) - } - - @GET - @Path("/groups/{id}") - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - @Operation( - summary = "List all effective roles for this group", - description = "This endpoint returns all the client role mapping for a specific group" - ) - @APIResponse( - responseCode = "200", - description = "", - content = [Content( - schema = Schema( - type = SchemaType.ARRAY, - implementation = ClientRole::class - ) - )] - ) - fun listCompositeGroupsRoleMappings( - @PathParam("id") id: String, - ): List { - val scopeContainer = realm.getGroupById(id) ?: throw NotFoundException("Could not find group") - - return mapping(scopeContainer::hasDirectRole).collect(Collectors.toList()) - } - - @GET - @Path("/users/{id}") - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - @Operation( - summary = "List all effective roles for this users", - description = "This endpoint returns all the client role mapping for a specific users" - ) - @APIResponse( - responseCode = "200", - description = "", - content = [Content( - schema = Schema( - type = SchemaType.ARRAY, - implementation = ClientRole::class - ) - )] - ) - fun listCompositeUsersRoleMappings( - @PathParam("id") id: String, - ): List { - val user = session?.users()?.getUserById(realm, id) - ?: if (auth.users().canQuery()) throw NotFoundException("User not found") else throw ForbiddenException() - auth.users().requireView(user) - - return mapping(user::hasDirectRole).collect(Collectors.toList()) - } - - @GET - @Path("/roles/{id}") - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - @Operation( - summary = "List all effective roles for this realm role", - description = "This endpoint returns all the client role mapping for a specific realm role" - ) - @APIResponse( - responseCode = "200", - description = "", - content = [Content( - schema = Schema( - type = SchemaType.ARRAY, - implementation = ClientRole::class - ) - )] - ) - fun listCompositeRealmRoleMappings( - ): List { - return mapping { true }.collect(Collectors.toList()) - } - -} \ No newline at end of file diff --git a/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/RoleMappingResource.java b/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/RoleMappingResource.java new file mode 100644 index 0000000000..faaaab30f9 --- /dev/null +++ b/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/RoleMappingResource.java @@ -0,0 +1,35 @@ +package org.keycloak.admin.ui.rest; + +import static org.keycloak.admin.ui.rest.model.RoleMapper.convertToRepresentation; + +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.keycloak.admin.ui.rest.model.ClientRole; +import org.keycloak.models.RealmModel; +import org.keycloak.models.RoleContainerModel; +import org.keycloak.models.RoleModel; +import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator; + +public abstract class RoleMappingResource { + private RealmModel realm; + private AdminPermissionEvaluator auth; + + public final Stream mapping(Predicate predicate) { + return realm.getClientsStream().flatMap(RoleContainerModel::getRolesStream).filter(predicate) + .filter(auth.roles()::canMapClientScope).map(roleModel -> convertToRepresentation(roleModel, realm.getClientsStream())); + } + + public final List mapping(Predicate predicate, long first, long max, final String search) { + + return mapping(predicate).filter(clientRole -> clientRole.getClient().contains(search) || clientRole.getRole().contains(search)) + + .skip("".equals(search) ? first : 0).limit(max).collect(Collectors.toList()); + } + + public RoleMappingResource(RealmModel realm, AdminPermissionEvaluator auth) { + this.realm = realm; + this.auth = auth; + } +} diff --git a/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/RoleMappingResource.kt b/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/RoleMappingResource.kt deleted file mode 100644 index c31bdadea8..0000000000 --- a/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/RoleMappingResource.kt +++ /dev/null @@ -1,45 +0,0 @@ -package org.keycloak.admin.ui.rest - -import org.keycloak.admin.ui.rest.model.ClientRole -import org.keycloak.admin.ui.rest.model.RoleMapper -import org.keycloak.models.RealmModel -import org.keycloak.models.RoleModel -import org.keycloak.services.resources.admin.permissions.AdminPermissionEvaluator -import org.mapstruct.factory.Mappers -import java.util.* -import java.util.function.Predicate -import java.util.stream.Collectors -import java.util.stream.Stream - -abstract class RoleMappingResource( - private var realm: RealmModel, - private var auth: AdminPermissionEvaluator, -) { - - fun mapping( - predicate: Predicate, - ): Stream { - val mapper = Mappers.getMapper(RoleMapper::class.java) - return realm.clientsStream - .flatMap { c -> c.rolesStream } - .filter(predicate) - .filter(auth.roles()::canMapClientScope) - - .map { r -> mapper.convertToRepresentation(r, realm.clientsStream) } - } - - fun mapping( - predicate: Predicate, - first: Long, - max: Long, - search: String - ): List { - return mapping(predicate) - .filter { r -> r.client!!.contains(search, true) || r.role.contains(search, true) } - - .skip(if (search.isBlank()) first else 0) - .limit(max) - .collect(Collectors.toList()) ?: Collections.emptyList() - } - -} \ No newline at end of file diff --git a/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/model/ClientRole.java b/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/model/ClientRole.java new file mode 100644 index 0000000000..ecb20c72cc --- /dev/null +++ b/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/model/ClientRole.java @@ -0,0 +1,79 @@ +package org.keycloak.admin.ui.rest.model; + +import java.util.Objects; +import org.eclipse.microprofile.openapi.annotations.media.Schema; + +public final class ClientRole { + @Schema(required = true) private final String id; + @Schema(required = true) private final String role; + @Schema(required = true) private String client; + @Schema(required = true) private String clientId; + private String description; + + public String getId() { + return this.id; + } + + public String getRole() { + return this.role; + } + + public String getClient() { + return this.client; + } + + public void setClient(String client) { + this.client = client; + } + + public String getClientId() { + return this.clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public String getDescription() { + return this.description; + } + + public void setDescription(String description) { + this.description = description; + } + + public ClientRole(String id, String role, String description) { + this.id = id; + this.role = role; + this.description = description; + } + + public ClientRole(String id, String role, String client, String clientId, String description) { + this.id = id; + this.role = role; + this.client = client; + this.clientId = clientId; + this.description = description; + } + + public ClientRole copy(String id, String role, String client, String clientId, String description) { + return new ClientRole(id, role, client, clientId, description); + } + + @Override public String toString() { + return "ClientRole{" + "id='" + id + '\'' + ", role='" + role + '\'' + ", client='" + client + '\'' + ", clientId='" + clientId + '\'' + ", description='" + description + '\'' + '}'; + } + + @Override public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + ClientRole that = (ClientRole) o; + return id.equals(that.id) && role.equals(that.role) && client.equals(that.client) && clientId.equals(that.clientId); + } + + @Override public int hashCode() { + return Objects.hash(id, role, client, clientId); + } +} diff --git a/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/model/ClientRole.kt b/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/model/ClientRole.kt deleted file mode 100644 index befe7693b1..0000000000 --- a/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/model/ClientRole.kt +++ /dev/null @@ -1,12 +0,0 @@ -package org.keycloak.admin.ui.rest.model - -import org.eclipse.microprofile.openapi.annotations.media.Schema - -data class ClientRole( - @field:Schema(required = true) var id: String, - @field:Schema(required = true) var role: String, - @field:Schema(required = true) var client: String?, - @field:Schema(required = true) var clientId: String?, - var description: String? -) { -} \ No newline at end of file diff --git a/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/model/RoleMapper.java b/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/model/RoleMapper.java new file mode 100644 index 0000000000..d24c4a58e8 --- /dev/null +++ b/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/model/RoleMapper.java @@ -0,0 +1,17 @@ +package org.keycloak.admin.ui.rest.model; + +import java.util.stream.Stream; +import org.keycloak.models.ClientModel; +import org.keycloak.models.RoleModel; + +public class RoleMapper { + + public static ClientRole convertToRepresentation(RoleModel roleModel, Stream clients) { + ClientRole clientRole = new ClientRole(roleModel.getId(), roleModel.getName(), roleModel.getDescription()); + ClientModel clientModel = clients.filter(c -> roleModel.getContainerId().equals(c.getId())).findFirst() + .orElseThrow(() -> new IllegalArgumentException("Could not find referenced client")); + clientRole.setClientId(clientModel.getId()); + clientRole.setClient(clientModel.getClientId()); + return clientRole; + } +} diff --git a/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/model/RoleMapper.kt b/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/model/RoleMapper.kt deleted file mode 100644 index 17b889bb48..0000000000 --- a/keycloak-theme/src/main/java/org/keycloak/admin/ui/rest/model/RoleMapper.kt +++ /dev/null @@ -1,21 +0,0 @@ -package org.keycloak.admin.ui.rest.model - -import org.keycloak.models.ClientModel -import org.keycloak.models.RoleModel -import org.mapstruct.* -import java.util.stream.Stream - -@Mapper -abstract class RoleMapper { - - @Mapping(source = "name", target = "role") - @Mapping(target = "client", ignore = true) - abstract fun convertToRepresentation(role: RoleModel, @Context clientModel: Stream): ClientRole - - @AfterMapping - fun convert(role: RoleModel, @MappingTarget clientRole: ClientRole, @Context list: Stream) { - val clientModel = list.filter { c -> role.containerId == c.id }.findFirst().get() - clientRole.clientId = clientModel.id - clientRole.client = clientModel.clientId - } -} \ No newline at end of file