created endpoint for effective client roles (#3165)
This commit is contained in:
parent
711a780be6
commit
b5ea27c194
12 changed files with 306 additions and 83 deletions
|
@ -9,7 +9,7 @@ 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 AdminUIRestEndpointProvider : AdminRealmResourceProviderFactory, AdminRealmResourceProvider {
|
||||
class AvailableRoleMappingProvider : AdminRealmResourceProviderFactory, AdminRealmResourceProvider {
|
||||
override fun create(session: KeycloakSession): AdminRealmResourceProvider {
|
||||
return this
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ class AdminUIRestEndpointProvider : AdminRealmResourceProviderFactory, AdminReal
|
|||
override fun postInit(factory: KeycloakSessionFactory) {}
|
||||
override fun close() {}
|
||||
override fun getId(): String {
|
||||
return "admin-ui"
|
||||
return "admin-ui-available-roles"
|
||||
}
|
||||
|
||||
override fun getResource(
|
||||
|
@ -27,6 +27,6 @@ class AdminUIRestEndpointProvider : AdminRealmResourceProviderFactory, AdminReal
|
|||
auth: AdminPermissionEvaluator,
|
||||
adminEvent: AdminEventBuilder
|
||||
): Any {
|
||||
return AdminUIExtendedResource(realm, auth)
|
||||
return AvailableRoleMappingResource(realm, auth)
|
||||
}
|
||||
}
|
|
@ -20,10 +20,10 @@ import javax.ws.rs.core.Context
|
|||
import javax.ws.rs.core.MediaType
|
||||
|
||||
@Path("/")
|
||||
open class AdminUIExtendedResource(
|
||||
open class AvailableRoleMappingResource(
|
||||
private var realm: RealmModel,
|
||||
private var auth: AdminPermissionEvaluator,
|
||||
) {
|
||||
) : RoleMappingResource(realm, auth) {
|
||||
@Context
|
||||
var session: KeycloakSession? = null
|
||||
|
||||
|
@ -54,7 +54,7 @@ open class AdminUIExtendedResource(
|
|||
val scopeContainer = realm.getClientScopeById(id) ?: throw NotFoundException("Could not find client scope")
|
||||
auth.clients().requireView(scopeContainer)
|
||||
|
||||
return availableMapping(Predicate<RoleModel?> { r -> scopeContainer.hasDirectScope(r) }.negate(), first, max, search)
|
||||
return mapping(Predicate<RoleModel?> { r -> scopeContainer.hasDirectScope(r) }.negate(), first, max, search)
|
||||
}
|
||||
|
||||
@GET
|
||||
|
@ -84,7 +84,7 @@ open class AdminUIExtendedResource(
|
|||
val scopeContainer = realm.getClientById(id) ?: throw NotFoundException("Could not find client")
|
||||
auth.clients().requireView(scopeContainer)
|
||||
|
||||
return availableMapping(Predicate<RoleModel?> { r -> scopeContainer.hasDirectScope(r) }.negate(), first, max, search)
|
||||
return mapping(Predicate<RoleModel?> { r -> scopeContainer.hasDirectScope(r) }.negate(), first, max, search)
|
||||
}
|
||||
|
||||
@GET
|
||||
|
@ -114,7 +114,7 @@ open class AdminUIExtendedResource(
|
|||
val scopeContainer = realm.getGroupById(id) ?: throw NotFoundException("Could not find group")
|
||||
auth.groups().requireView(scopeContainer)
|
||||
|
||||
return availableMapping(Predicate<RoleModel?> { r -> scopeContainer.hasDirectRole(r) }.negate(), first, max, search)
|
||||
return mapping(Predicate<RoleModel?> { r -> scopeContainer.hasDirectRole(r) }.negate(), first, max, search)
|
||||
|
||||
}
|
||||
|
||||
|
@ -146,7 +146,7 @@ open class AdminUIExtendedResource(
|
|||
?: if (auth.users().canQuery()) throw NotFoundException("User not found") else throw ForbiddenException()
|
||||
auth.users().requireView(user)
|
||||
|
||||
return availableMapping(Predicate<RoleModel?> { r -> user.hasDirectRole(r) }.negate(), first, max, search)
|
||||
return mapping(Predicate<RoleModel?> { r -> user.hasDirectRole(r) }.negate(), first, max, search)
|
||||
|
||||
}
|
||||
|
||||
|
@ -173,33 +173,6 @@ open class AdminUIExtendedResource(
|
|||
@QueryParam("max") @DefaultValue("10") max: Long,
|
||||
@QueryParam("search") @DefaultValue("") search: String
|
||||
): List<ClientRole> {
|
||||
val clients = realm.clientsStream
|
||||
val mapper = Mappers.getMapper(RoleMapper::class.java)
|
||||
return clients
|
||||
.flatMap { c -> c.rolesStream }
|
||||
.map { r -> mapper.convertToRepresentation(r, realm.clientsStream) }
|
||||
.skip(first)
|
||||
.limit(max)
|
||||
.collect(Collectors.toList()) ?: Collections.emptyList()
|
||||
}
|
||||
|
||||
private fun availableMapping(
|
||||
predicate: Predicate<RoleModel?>,
|
||||
first: Long,
|
||||
max: Long,
|
||||
search: String
|
||||
): List<ClientRole> {
|
||||
val clients = realm.clientsStream
|
||||
val mapper = Mappers.getMapper(RoleMapper::class.java)
|
||||
return clients
|
||||
.flatMap { c -> c.rolesStream }
|
||||
.filter(predicate)
|
||||
.filter(auth.roles()::canMapClientScope)
|
||||
|
||||
.map { r -> mapper.convertToRepresentation(r, realm.clientsStream) }
|
||||
.filter { r -> r.client?.indexOf(search) != -1 || r.role.indexOf(search) != -1 }
|
||||
.skip(first)
|
||||
.limit(max)
|
||||
.collect(Collectors.toList()) ?: Collections.emptyList()
|
||||
return mapping({ true }, first, max, search)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
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)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
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<ClientRole> {
|
||||
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<ClientRole> {
|
||||
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<ClientRole> {
|
||||
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<ClientRole> {
|
||||
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<ClientRole> {
|
||||
return mapping { true }.collect(Collectors.toList())
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
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<RoleModel?>,
|
||||
): Stream<ClientRole> {
|
||||
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<RoleModel?>,
|
||||
first: Long,
|
||||
max: Long,
|
||||
search: String
|
||||
): List<ClientRole> {
|
||||
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()
|
||||
}
|
||||
|
||||
}
|
|
@ -6,6 +6,7 @@ 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?
|
||||
) {
|
||||
}
|
|
@ -14,6 +14,8 @@ abstract class RoleMapper {
|
|||
|
||||
@AfterMapping
|
||||
fun convert(role: RoleModel, @MappingTarget clientRole: ClientRole, @Context list: Stream<ClientModel>) {
|
||||
clientRole.client = list.filter { c -> role.containerId == c.id }.findFirst().get().clientId
|
||||
val clientModel = list.filter { c -> role.containerId == c.id }.findFirst().get()
|
||||
clientRole.clientId = clientModel.id
|
||||
clientRole.client = clientModel.clientId
|
||||
}
|
||||
}
|
|
@ -15,4 +15,5 @@
|
|||
# limitations under the License.
|
||||
#
|
||||
|
||||
org.keycloak.admin.ui.rest.AdminUIRestEndpointProvider
|
||||
org.keycloak.admin.ui.rest.AvailableRoleMappingProvider
|
||||
org.keycloak.admin.ui.rest.EffectiveRoleMappingProvider
|
|
@ -89,7 +89,7 @@ export const AddRoleMappingModal = ({
|
|||
|
||||
return localeSort(
|
||||
roles.map((e) => ({
|
||||
client: { clientId: e.client },
|
||||
client: { clientId: e.client, id: e.clientId },
|
||||
role: { id: e.id, name: e.role, description: e.description },
|
||||
})),
|
||||
compareRow
|
||||
|
|
|
@ -20,12 +20,9 @@ import { useAlerts } from "../alert/Alerts";
|
|||
import { useConfirmDialog } from "../confirm-dialog/ConfirmDialog";
|
||||
import { useAdminClient } from "../../context/auth/AdminClient";
|
||||
import { ListEmptyState } from "../list-empty-state/ListEmptyState";
|
||||
import {
|
||||
deleteMapping,
|
||||
getEffectiveClientRoles,
|
||||
getEffectiveRoles,
|
||||
getMapping,
|
||||
} from "./queries";
|
||||
import { deleteMapping, getEffectiveRoles, getMapping } from "./queries";
|
||||
import { getEffectiveClientRoles } from "./resource";
|
||||
import { useRealm } from "../../context/realm-context/RealmContext";
|
||||
|
||||
import "./role-mapping.css";
|
||||
|
||||
|
@ -92,6 +89,7 @@ export const RoleMapping = ({
|
|||
}: RoleMappingProps) => {
|
||||
const { t } = useTranslation(type);
|
||||
const { adminClient } = useAdminClient();
|
||||
const { realm } = useRealm();
|
||||
const { addAlert, addError } = useAlerts();
|
||||
|
||||
const [key, setKey] = useState(0);
|
||||
|
@ -107,23 +105,28 @@ export const RoleMapping = ({
|
|||
};
|
||||
|
||||
const loader = async () => {
|
||||
const effectiveRoles = await getEffectiveRoles(adminClient, type, id);
|
||||
|
||||
let effectiveRoles: Row[] = [];
|
||||
let effectiveClientRoles: Row[] = [];
|
||||
if (!hide) {
|
||||
const clients = await adminClient.clients.find();
|
||||
effectiveRoles = await getEffectiveRoles(adminClient, type, id);
|
||||
|
||||
effectiveClientRoles = (
|
||||
await Promise.all(
|
||||
clients.map(async (client) =>
|
||||
getEffectiveClientRoles(adminClient, type, id, client)
|
||||
)
|
||||
)
|
||||
).flat();
|
||||
await getEffectiveClientRoles({
|
||||
adminClient,
|
||||
realm,
|
||||
type,
|
||||
id,
|
||||
})
|
||||
).map((e) => ({
|
||||
client: { clientId: e.client, id: e.clientId },
|
||||
role: { id: e.id, name: e.role, description: e.description },
|
||||
}));
|
||||
}
|
||||
|
||||
const roles = await getMapping(adminClient, type, id);
|
||||
const realmRoles = roles.realmMappings?.map((role) => ({ role }));
|
||||
const client = Object.values(roles.clientMappings || {})
|
||||
const realmRolesMapping =
|
||||
roles.realmMappings?.map((role) => ({ role })) || [];
|
||||
const clientMapping = Object.values(roles.clientMappings || {})
|
||||
.map((client) =>
|
||||
client.mappings.map((role: RoleRepresentation) => ({
|
||||
client: { clientId: client.client, ...client },
|
||||
|
@ -133,8 +136,11 @@ export const RoleMapping = ({
|
|||
.flat();
|
||||
|
||||
return [
|
||||
...mapRoles(realmRoles || [], effectiveRoles, hide),
|
||||
...[...client, ...effectiveClientRoles],
|
||||
...mapRoles(
|
||||
[...realmRolesMapping, ...clientMapping],
|
||||
[...effectiveClientRoles, ...effectiveRoles],
|
||||
hide
|
||||
),
|
||||
];
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import type RoleRepresentation from "@keycloak/keycloak-admin-client/lib/defs/roleRepresentation";
|
||||
import type MappingsRepresentation from "@keycloak/keycloak-admin-client/lib/defs/mappingsRepresentation";
|
||||
import type ClientRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientRepresentation";
|
||||
import type { ClientScopes } from "@keycloak/keycloak-admin-client/lib/resources/clientScopes";
|
||||
import type { Groups } from "@keycloak/keycloak-admin-client/lib/resources/groups";
|
||||
import type { Roles } from "@keycloak/keycloak-admin-client/lib/resources/roles";
|
||||
|
@ -155,22 +154,6 @@ export const getEffectiveRoles = async (
|
|||
}));
|
||||
};
|
||||
|
||||
export const getEffectiveClientRoles = async (
|
||||
adminClient: KeycloakAdminClient,
|
||||
type: ResourcesKey,
|
||||
id: string,
|
||||
client: ClientRepresentation
|
||||
): Promise<Row[]> => {
|
||||
const query = mapping[type]!.listEffective[2];
|
||||
return (
|
||||
await applyQuery(adminClient, type, query, {
|
||||
id,
|
||||
client: client.id,
|
||||
clientUniqueId: client.id,
|
||||
})
|
||||
).map((role) => ({ role, client: { clientId: client.id, ...client } }));
|
||||
};
|
||||
|
||||
export const getAvailableRoles = async (
|
||||
adminClient: KeycloakAdminClient,
|
||||
type: ResourcesKey,
|
||||
|
|
|
@ -2,24 +2,35 @@ import KeycloakAdminClient from "@keycloak/keycloak-admin-client";
|
|||
import { addTrailingSlash } from "../../util";
|
||||
import { getAuthorizationHeaders } from "../../utils/getAuthorizationHeaders";
|
||||
|
||||
type AvailableClientRolesQuery = {
|
||||
type BaseClientRolesQuery = {
|
||||
adminClient: KeycloakAdminClient;
|
||||
id: string;
|
||||
realm: string;
|
||||
type: string;
|
||||
};
|
||||
|
||||
type AvailableClientRolesQuery = BaseClientRolesQuery & {
|
||||
first: number;
|
||||
max: number;
|
||||
search?: string;
|
||||
};
|
||||
|
||||
type EffectiveClientRolesQuery = BaseClientRolesQuery;
|
||||
|
||||
type Query = Partial<Omit<AvailableClientRolesQuery, "adminClient">> & {
|
||||
adminClient: KeycloakAdminClient;
|
||||
endpoint: string;
|
||||
};
|
||||
|
||||
type ClientRole = {
|
||||
id: string;
|
||||
role: string;
|
||||
description?: string;
|
||||
client?: string;
|
||||
client: string;
|
||||
clientId: string;
|
||||
};
|
||||
|
||||
export const getAvailableClientRoles = async ({
|
||||
const fetchRoles = async ({
|
||||
adminClient,
|
||||
id,
|
||||
realm,
|
||||
|
@ -27,16 +38,17 @@ export const getAvailableClientRoles = async ({
|
|||
first,
|
||||
max,
|
||||
search,
|
||||
}: AvailableClientRolesQuery): Promise<ClientRole[]> => {
|
||||
endpoint,
|
||||
}: Query): Promise<ClientRole[]> => {
|
||||
const accessToken = await adminClient.getAccessToken();
|
||||
const baseUrl = adminClient.baseUrl;
|
||||
|
||||
const response = await fetch(
|
||||
`${addTrailingSlash(
|
||||
baseUrl
|
||||
)}admin/realms/${realm}/admin-ui/${type}/${id}?first=${first}&max=${max}${
|
||||
search ? "&search=" + search : ""
|
||||
}`,
|
||||
)}admin/realms/${realm}/admin-ui-${endpoint}/${type}/${id}?first=${
|
||||
first || 0
|
||||
}&max=${max || 10}${search ? "&search=" + search : ""}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: getAuthorizationHeaders(accessToken),
|
||||
|
@ -45,3 +57,15 @@ export const getAvailableClientRoles = async ({
|
|||
|
||||
return await response.json();
|
||||
};
|
||||
|
||||
export const getAvailableClientRoles = async (
|
||||
query: AvailableClientRolesQuery
|
||||
): Promise<ClientRole[]> => {
|
||||
return fetchRoles({ ...query, endpoint: "available-roles" });
|
||||
};
|
||||
|
||||
export const getEffectiveClientRoles = async (
|
||||
query: EffectiveClientRolesQuery
|
||||
): Promise<ClientRole[]> => {
|
||||
return fetchRoles({ ...query, endpoint: "effective-roles" });
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue