@logicpanel/keycloak-admin-client
Version:
commonjs wrapper for Keycloak Admin Client
1,556 lines (1,509 loc) • 86 kB
JavaScript
'use strict';
function normalize (strArray) {
var resultArray = [];
if (strArray.length === 0) { return ''; }
if (typeof strArray[0] !== 'string') {
throw new TypeError('Url must be a string. Received ' + strArray[0]);
}
// If the first part is a plain protocol, we combine it with the next part.
if (strArray[0].match(/^[^/:]+:\/*$/) && strArray.length > 1) {
var first = strArray.shift();
strArray[0] = first + strArray[0];
}
// There must be two or three slashes in the file protocol, two slashes in anything else.
if (strArray[0].match(/^file:\/\/\//)) {
strArray[0] = strArray[0].replace(/^([^/:]+):\/*/, '$1:///');
} else {
strArray[0] = strArray[0].replace(/^([^/:]+):\/*/, '$1://');
}
for (var i = 0; i < strArray.length; i++) {
var component = strArray[i];
if (typeof component !== 'string') {
throw new TypeError('Url must be a string. Received ' + component);
}
if (component === '') { continue; }
if (i > 0) {
// Removing the starting slashes for each component but the first.
component = component.replace(/^[\/]+/, '');
}
if (i < strArray.length - 1) {
// Removing the ending slashes for each component but the last.
component = component.replace(/[\/]+$/, '');
} else {
// For the last component we will combine multiple slashes to a single one.
component = component.replace(/[\/]+$/, '/');
}
resultArray.push(component);
}
var str = resultArray.join('/');
// Each input component is now separated by a single slash except the possible first plain protocol part.
// remove trailing slash before parameters or hash
str = str.replace(/\/(\?|&|#[^!])/g, '$1');
// replace ? in parameters with &
var parts = str.split('?');
str = parts.shift() + (parts.length > 0 ? '?': '') + parts.join('&');
return str;
}
function urlJoin() {
var input;
if (typeof arguments[0] === 'object') {
input = arguments[0];
} else {
input = [].slice.call(arguments);
}
return normalize(input);
}
function encodeReserved(str) {
return str.split(/(%[0-9A-Fa-f]{2})/g).map(function (part) {
if (!/%[0-9A-Fa-f]/.test(part)) {
part = encodeURI(part).replace(/%5B/g, '[').replace(/%5D/g, ']');
}
return part;
}).join('');
}
function encodeUnreserved(str) {
return encodeURIComponent(str).replace(/[!'()*]/g, function (c) {
return '%' + c.charCodeAt(0).toString(16).toUpperCase();
});
}
function encodeValue(operator, value, key) {
value = (operator === '+' || operator === '#') ? encodeReserved(value) : encodeUnreserved(value);
if (key) {
return encodeUnreserved(key) + '=' + value;
} else {
return value;
}
}
function isDefined(value) {
return value !== undefined && value !== null;
}
function isKeyOperator(operator) {
return operator === ';' || operator === '&' || operator === '?';
}
function getValues(context, operator, key, modifier) {
var value = context[key],
result = [];
if (isDefined(value) && value !== '') {
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
value = value.toString();
if (modifier && modifier !== '*') {
value = value.substring(0, parseInt(modifier, 10));
}
result.push(encodeValue(operator, value, isKeyOperator(operator) ? key : null));
} else {
if (modifier === '*') {
if (Array.isArray(value)) {
value.filter(isDefined).forEach(function (value) {
result.push(encodeValue(operator, value, isKeyOperator(operator) ? key : null));
});
} else {
Object.keys(value).forEach(function (k) {
if (isDefined(value[k])) {
result.push(encodeValue(operator, value[k], k));
}
});
}
} else {
var tmp = [];
if (Array.isArray(value)) {
value.filter(isDefined).forEach(function (value) {
tmp.push(encodeValue(operator, value));
});
} else {
Object.keys(value).forEach(function (k) {
if (isDefined(value[k])) {
tmp.push(encodeUnreserved(k));
tmp.push(encodeValue(operator, value[k].toString()));
}
});
}
if (isKeyOperator(operator)) {
result.push(encodeUnreserved(key) + '=' + tmp.join(','));
} else if (tmp.length !== 0) {
result.push(tmp.join(','));
}
}
}
} else {
if (operator === ';') {
if (isDefined(value)) {
result.push(encodeUnreserved(key));
}
} else if (value === '' && (operator === '&' || operator === '?')) {
result.push(encodeUnreserved(key) + '=');
} else if (value === '') {
result.push('');
}
}
return result;
}
function parseTemplate(template) {
var operators = ['+', '#', '.', '/', ';', '?', '&'];
return {
expand: function (context) {
return template.replace(/\{([^\{\}]+)\}|([^\{\}]+)/g, function (_, expression, literal) {
if (expression) {
var operator = null,
values = [];
if (operators.indexOf(expression.charAt(0)) !== -1) {
operator = expression.charAt(0);
expression = expression.substr(1);
}
expression.split(/,/g).forEach(function (variable) {
var tmp = /([^:\*]*)(?::(\d+)|(\*))?/.exec(variable);
values.push.apply(values, getValues(context, operator, tmp[1], tmp[2] || tmp[3]));
});
if (operator && operator !== '+') {
var separator = ',';
if (operator === '?') {
separator = '&';
} else if (operator !== '#') {
separator = operator;
}
return (values.length !== 0 ? operator : '') + values.join(separator);
} else {
return values.join(',');
}
} else {
return encodeReserved(literal);
}
});
}
};
}
class NetworkError extends Error {
response;
responseData;
constructor(message, options) {
super(message);
this.response = options.response;
this.responseData = options.responseData;
}
}
async function fetchWithError(input, init) {
const response = await fetch(input, init);
if (!response.ok) {
const responseData = await parseResponse(response);
throw new NetworkError("Network response was not OK.", {
response,
responseData,
});
}
return response;
}
async function parseResponse(response) {
if (!response.body) {
return "";
}
const data = await response.text();
try {
return JSON.parse(data);
// eslint-disable-next-line no-empty
}
catch (error) { }
return data;
}
function stringifyQueryParams(params) {
const searchParams = new URLSearchParams();
for (const [key, value] of Object.entries(params)) {
// Ignore undefined and null values.
if (value === undefined || value === null) {
continue;
}
// Ignore empty strings.
if (typeof value === "string" && value.length === 0) {
continue;
}
// Ignore empty arrays.
if (Array.isArray(value) && value.length === 0) {
continue;
}
// Append each entry of an array as a separate parameter, or the value itself otherwise.
if (Array.isArray(value)) {
value.forEach((item) => searchParams.append(key, item.toString()));
}
else {
searchParams.append(key, value.toString());
}
}
return searchParams.toString();
}
// constants
const SLASH = "/";
const pick = (value, keys) => Object.fromEntries(Object.entries(value).filter(([key]) => keys.includes(key)));
const omit = (value, keys) => Object.fromEntries(Object.entries(value).filter(([key]) => !keys.includes(key)));
class Agent {
#client;
#basePath;
#getBaseParams;
#getBaseUrl;
constructor({ client, path = "/", getUrlParams = () => ({}), getBaseUrl = () => client.baseUrl, }) {
this.#client = client;
this.#getBaseParams = getUrlParams;
this.#getBaseUrl = getBaseUrl;
this.#basePath = path;
}
request({ method, path = "", urlParamKeys = [], queryParamKeys = [], catchNotFound = false, keyTransform, payloadKey, returnResourceIdInLocationHeader, ignoredKeys, headers, }) {
return async (payload = {}, options) => {
const baseParams = this.#getBaseParams?.() ?? {};
// Filter query parameters by queryParamKeys
const queryParams = queryParamKeys.length > 0
? pick(payload, queryParamKeys)
: undefined;
// Add filtered payload parameters to base parameters
const allUrlParamKeys = [...Object.keys(baseParams), ...urlParamKeys];
const urlParams = { ...baseParams, ...pick(payload, allUrlParamKeys) };
if (!(payload instanceof FormData)) {
// Omit url parameters and query parameters from payload
const omittedKeys = ignoredKeys
? [...allUrlParamKeys, ...queryParamKeys].filter((key) => !ignoredKeys.includes(key))
: [...allUrlParamKeys, ...queryParamKeys];
payload = omit(payload, omittedKeys);
}
// Transform keys of both payload and queryParams
if (keyTransform) {
this.#transformKey(payload, keyTransform);
this.#transformKey(queryParams, keyTransform);
}
return this.#requestWithParams({
method,
path,
payload,
urlParams,
queryParams,
// catchNotFound precedence: global > local > default
catchNotFound,
...(this.#client.getGlobalRequestArgOptions() ?? options ?? {}),
payloadKey,
returnResourceIdInLocationHeader,
headers,
});
};
}
updateRequest({ method, path = "", urlParamKeys = [], queryParamKeys = [], catchNotFound = false, keyTransform, payloadKey, returnResourceIdInLocationHeader, headers, }) {
return async (query = {}, payload = {}) => {
const baseParams = this.#getBaseParams?.() ?? {};
// Filter query parameters by queryParamKeys
const queryParams = queryParamKeys
? pick(query, queryParamKeys)
: undefined;
// Add filtered query parameters to base parameters
const allUrlParamKeys = [...Object.keys(baseParams), ...urlParamKeys];
const urlParams = {
...baseParams,
...pick(query, allUrlParamKeys),
};
// Transform keys of queryParams
if (keyTransform) {
this.#transformKey(queryParams, keyTransform);
}
return this.#requestWithParams({
method,
path,
payload,
urlParams,
queryParams,
catchNotFound,
payloadKey,
returnResourceIdInLocationHeader,
headers,
});
};
}
async #requestWithParams({ method, path, payload, urlParams, queryParams, catchNotFound, payloadKey, returnResourceIdInLocationHeader, headers, }) {
const newPath = urlJoin(this.#basePath, path);
// Parse template and replace with values from urlParams
const pathTemplate = parseTemplate(newPath);
const parsedPath = pathTemplate.expand(urlParams);
const url = new URL(`${this.#getBaseUrl?.() ?? ""}${parsedPath}`);
const requestOptions = { ...this.#client.getRequestOptions() };
const requestHeaders = new Headers([
...new Headers(requestOptions.headers).entries(),
["authorization", `Bearer ${await this.#client.getAccessToken()}`],
["accept", "application/json, text/plain, */*"],
...new Headers(headers).entries(),
]);
const searchParams = {};
// Add payload parameters to search params if method is 'GET'.
if (method === "GET") {
Object.assign(searchParams, payload);
}
else if (requestHeaders.get("content-type") === "text/plain") {
// Pass the payload as a plain string if the content type is 'text/plain'.
requestOptions.body = payload;
}
else if (payload instanceof FormData) {
requestOptions.body = payload;
}
else {
// Otherwise assume it's JSON and stringify it.
requestOptions.body = JSON.stringify(payloadKey ? payload[payloadKey] : payload);
}
if (!requestHeaders.has("content-type") && !(payload instanceof FormData)) {
requestHeaders.set("content-type", "application/json");
}
if (queryParams) {
Object.assign(searchParams, queryParams);
}
url.search = stringifyQueryParams(searchParams);
try {
const res = await fetchWithError(url, {
...requestOptions,
headers: requestHeaders,
method,
});
// now we get the response of the http request
// if `resourceIdInLocationHeader` is true, we'll get the resourceId from the location header field
// todo: find a better way to find the id in path, maybe some kind of pattern matching
// for now, we simply split the last sub-path of the path returned in location header field
if (returnResourceIdInLocationHeader) {
const locationHeader = res.headers.get("location");
if (typeof locationHeader !== "string") {
throw new Error(`location header is not found in request: ${res.url}`);
}
const resourceId = locationHeader.split(SLASH).pop();
if (!resourceId) {
// throw an error to let users know the response is not expected
throw new Error(`resourceId is not found in Location header from request: ${res.url}`);
}
// return with format {[field]: string}
const { field } = returnResourceIdInLocationHeader;
return { [field]: resourceId };
}
if (Object.entries(headers || []).find(([key, value]) => key.toLowerCase() === "accept" &&
value === "application/octet-stream")) {
return res.arrayBuffer();
}
return parseResponse(res);
}
catch (err) {
if (err instanceof NetworkError &&
err.response.status === 404 &&
catchNotFound) {
return null;
}
throw err;
}
}
#transformKey(payload, keyMapping) {
if (!payload) {
return;
}
Object.keys(keyMapping).some((key) => {
if (typeof payload[key] === "undefined") {
return false;
}
const newKey = keyMapping[key];
payload[newKey] = payload[key];
delete payload[key];
});
}
}
class Resource {
#agent;
constructor(client, settings = {}) {
this.#agent = new Agent({
client,
...settings,
});
}
makeRequest = (args) => {
return this.#agent.request(args);
};
// update request will take three types: query, payload and response
makeUpdateRequest = (args) => {
return this.#agent.updateRequest(args);
};
}
class AttackDetection extends Resource {
findOne = this.makeRequest({
method: "GET",
path: "/users/{id}",
urlParamKeys: ["id"],
catchNotFound: true,
});
del = this.makeRequest({
method: "DELETE",
path: "/users/{id}",
urlParamKeys: ["id"],
});
delAll = this.makeRequest({
method: "DELETE",
path: "/users",
});
constructor(client) {
super(client, {
path: "/admin/realms/{realm}/attack-detection/brute-force",
getUrlParams: () => ({
realm: client.realmName,
}),
getBaseUrl: () => client.baseUrl,
});
}
}
class AuthenticationManagement extends Resource {
/**
* Authentication Management
* https://www.keycloak.org/docs-api/8.0/rest-api/index.html#_authentication_management_resource
*/
// Register a new required action
registerRequiredAction = this.makeRequest({
method: "POST",
path: "/register-required-action",
});
// Get required actions. Returns a list of required actions.
getRequiredActions = this.makeRequest({
method: "GET",
path: "/required-actions",
});
// Get required action for alias
getRequiredActionForAlias = this.makeRequest({
method: "GET",
path: "/required-actions/{alias}",
urlParamKeys: ["alias"],
catchNotFound: true,
});
getClientAuthenticatorProviders = this.makeRequest({
method: "GET",
path: "/client-authenticator-providers",
});
getAuthenticatorProviders = this.makeRequest({
method: "GET",
path: "/authenticator-providers",
});
getFormActionProviders = this.makeRequest({
method: "GET",
path: "/form-action-providers",
});
// Update required action
updateRequiredAction = this.makeUpdateRequest({
method: "PUT",
path: "/required-actions/{alias}",
urlParamKeys: ["alias"],
});
// Delete required action
deleteRequiredAction = this.makeRequest({
method: "DELETE",
path: "/required-actions/{alias}",
urlParamKeys: ["alias"],
});
// Lower required action’s priority
lowerRequiredActionPriority = this.makeRequest({
method: "POST",
path: "/required-actions/{alias}/lower-priority",
urlParamKeys: ["alias"],
});
// Raise required action’s priority
raiseRequiredActionPriority = this.makeRequest({
method: "POST",
path: "/required-actions/{alias}/raise-priority",
urlParamKeys: ["alias"],
});
// Get unregistered required actions Returns a list of unregistered required actions.
getUnregisteredRequiredActions = this.makeRequest({
method: "GET",
path: "/unregistered-required-actions",
});
getFlows = this.makeRequest({
method: "GET",
path: "/flows",
});
getFlow = this.makeRequest({
method: "GET",
path: "/flows/{flowId}",
urlParamKeys: ["flowId"],
});
getFormProviders = this.makeRequest({
method: "GET",
path: "/form-providers",
});
createFlow = this.makeRequest({
method: "POST",
path: "/flows",
returnResourceIdInLocationHeader: { field: "id" },
});
copyFlow = this.makeRequest({
method: "POST",
path: "/flows/{flow}/copy",
urlParamKeys: ["flow"],
});
deleteFlow = this.makeRequest({
method: "DELETE",
path: "/flows/{flowId}",
urlParamKeys: ["flowId"],
});
updateFlow = this.makeUpdateRequest({
method: "PUT",
path: "/flows/{flowId}",
urlParamKeys: ["flowId"],
});
getExecutions = this.makeRequest({
method: "GET",
path: "/flows/{flow}/executions",
urlParamKeys: ["flow"],
});
addExecution = this.makeUpdateRequest({
method: "POST",
path: "/flows/{flow}/executions",
urlParamKeys: ["flow"],
});
addExecutionToFlow = this.makeRequest({
method: "POST",
path: "/flows/{flow}/executions/execution",
urlParamKeys: ["flow"],
returnResourceIdInLocationHeader: { field: "id" },
});
addFlowToFlow = this.makeRequest({
method: "POST",
path: "/flows/{flow}/executions/flow",
urlParamKeys: ["flow"],
returnResourceIdInLocationHeader: { field: "id" },
});
updateExecution = this.makeUpdateRequest({
method: "PUT",
path: "/flows/{flow}/executions",
urlParamKeys: ["flow"],
});
delExecution = this.makeRequest({
method: "DELETE",
path: "/executions/{id}",
urlParamKeys: ["id"],
});
lowerPriorityExecution = this.makeRequest({
method: "POST",
path: "/executions/{id}/lower-priority",
urlParamKeys: ["id"],
});
raisePriorityExecution = this.makeRequest({
method: "POST",
path: "/executions/{id}/raise-priority",
urlParamKeys: ["id"],
});
getConfigDescription = this.makeRequest({
method: "GET",
path: "config-description/{providerId}",
urlParamKeys: ["providerId"],
});
createConfig = this.makeRequest({
method: "POST",
path: "/executions/{id}/config",
urlParamKeys: ["id"],
returnResourceIdInLocationHeader: { field: "id" },
});
updateConfig = this.makeRequest({
method: "PUT",
path: "/config/{id}",
urlParamKeys: ["id"],
});
getConfig = this.makeRequest({
method: "GET",
path: "/config/{id}",
urlParamKeys: ["id"],
});
delConfig = this.makeRequest({
method: "DELETE",
path: "/config/{id}",
urlParamKeys: ["id"],
});
constructor(client) {
super(client, {
path: "/admin/realms/{realm}/authentication",
getUrlParams: () => ({
realm: client.realmName,
}),
getBaseUrl: () => client.baseUrl,
});
}
}
class Cache extends Resource {
clearUserCache = this.makeRequest({
method: "POST",
path: "/clear-user-cache",
});
constructor(client) {
super(client, {
path: "/admin/realms/{realm}",
getUrlParams: () => ({
realm: client.realmName,
}),
getBaseUrl: () => client.baseUrl,
});
}
}
/**
* https://www.keycloak.org/docs-api/15.0/rest-api/#_client_registration_policy_resource
*/
class ClientPolicies extends Resource {
constructor(client) {
super(client, {
path: "/admin/realms/{realm}/client-policies",
getUrlParams: () => ({
realm: client.realmName,
}),
getBaseUrl: () => client.baseUrl,
});
}
/* Client Profiles */
listProfiles = this.makeRequest({
method: "GET",
path: "/profiles",
queryParamKeys: ["include-global-profiles"],
keyTransform: {
includeGlobalProfiles: "include-global-profiles",
},
});
createProfiles = this.makeRequest({
method: "PUT",
path: "/profiles",
});
/* Client Policies */
listPolicies = this.makeRequest({
method: "GET",
path: "/policies",
});
updatePolicy = this.makeRequest({
method: "PUT",
path: "/policies",
});
}
class Clients extends Resource {
find = this.makeRequest({
method: "GET",
});
create = this.makeRequest({
method: "POST",
returnResourceIdInLocationHeader: { field: "id" },
});
/**
* Single client
*/
findOne = this.makeRequest({
method: "GET",
path: "/{id}",
urlParamKeys: ["id"],
catchNotFound: true,
});
update = this.makeUpdateRequest({
method: "PUT",
path: "/{id}",
urlParamKeys: ["id"],
});
del = this.makeRequest({
method: "DELETE",
path: "/{id}",
urlParamKeys: ["id"],
});
/**
* Client roles
*/
createRole = this.makeRequest({
method: "POST",
path: "/{id}/roles",
urlParamKeys: ["id"],
returnResourceIdInLocationHeader: { field: "roleName" },
});
listRoles = this.makeRequest({
method: "GET",
path: "/{id}/roles",
urlParamKeys: ["id"],
});
findRole = this.makeRequest({
method: "GET",
path: "/{id}/roles/{roleName}",
urlParamKeys: ["id", "roleName"],
catchNotFound: true,
});
updateRole = this.makeUpdateRequest({
method: "PUT",
path: "/{id}/roles/{roleName}",
urlParamKeys: ["id", "roleName"],
});
delRole = this.makeRequest({
method: "DELETE",
path: "/{id}/roles/{roleName}",
urlParamKeys: ["id", "roleName"],
});
findUsersWithRole = this.makeRequest({
method: "GET",
path: "/{id}/roles/{roleName}/users",
urlParamKeys: ["id", "roleName"],
});
/**
* Service account user
*/
getServiceAccountUser = this.makeRequest({
method: "GET",
path: "/{id}/service-account-user",
urlParamKeys: ["id"],
});
/**
* Client secret
*/
generateNewClientSecret = this.makeRequest({
method: "POST",
path: "/{id}/client-secret",
urlParamKeys: ["id"],
});
invalidateSecret = this.makeRequest({
method: "DELETE",
path: "/{id}/client-secret/rotated",
urlParamKeys: ["id"],
});
generateRegistrationAccessToken = this.makeRequest({
method: "POST",
path: "/{id}/registration-access-token",
urlParamKeys: ["id"],
});
getClientSecret = this.makeRequest({
method: "GET",
path: "/{id}/client-secret",
urlParamKeys: ["id"],
});
/**
* Client Scopes
*/
listDefaultClientScopes = this.makeRequest({
method: "GET",
path: "/{id}/default-client-scopes",
urlParamKeys: ["id"],
});
addDefaultClientScope = this.makeRequest({
method: "PUT",
path: "/{id}/default-client-scopes/{clientScopeId}",
urlParamKeys: ["id", "clientScopeId"],
});
delDefaultClientScope = this.makeRequest({
method: "DELETE",
path: "/{id}/default-client-scopes/{clientScopeId}",
urlParamKeys: ["id", "clientScopeId"],
});
listOptionalClientScopes = this.makeRequest({
method: "GET",
path: "/{id}/optional-client-scopes",
urlParamKeys: ["id"],
});
addOptionalClientScope = this.makeRequest({
method: "PUT",
path: "/{id}/optional-client-scopes/{clientScopeId}",
urlParamKeys: ["id", "clientScopeId"],
});
delOptionalClientScope = this.makeRequest({
method: "DELETE",
path: "/{id}/optional-client-scopes/{clientScopeId}",
urlParamKeys: ["id", "clientScopeId"],
});
/**
* Protocol Mappers
*/
addMultipleProtocolMappers = this.makeUpdateRequest({
method: "POST",
path: "/{id}/protocol-mappers/add-models",
urlParamKeys: ["id"],
});
addProtocolMapper = this.makeUpdateRequest({
method: "POST",
path: "/{id}/protocol-mappers/models",
urlParamKeys: ["id"],
});
listProtocolMappers = this.makeRequest({
method: "GET",
path: "/{id}/protocol-mappers/models",
urlParamKeys: ["id"],
});
findProtocolMapperById = this.makeRequest({
method: "GET",
path: "/{id}/protocol-mappers/models/{mapperId}",
urlParamKeys: ["id", "mapperId"],
catchNotFound: true,
});
findProtocolMappersByProtocol = this.makeRequest({
method: "GET",
path: "/{id}/protocol-mappers/protocol/{protocol}",
urlParamKeys: ["id", "protocol"],
catchNotFound: true,
});
updateProtocolMapper = this.makeUpdateRequest({
method: "PUT",
path: "/{id}/protocol-mappers/models/{mapperId}",
urlParamKeys: ["id", "mapperId"],
});
delProtocolMapper = this.makeRequest({
method: "DELETE",
path: "/{id}/protocol-mappers/models/{mapperId}",
urlParamKeys: ["id", "mapperId"],
});
/**
* Scope Mappings
*/
listScopeMappings = this.makeRequest({
method: "GET",
path: "/{id}/scope-mappings",
urlParamKeys: ["id"],
});
addClientScopeMappings = this.makeUpdateRequest({
method: "POST",
path: "/{id}/scope-mappings/clients/{client}",
urlParamKeys: ["id", "client"],
});
listClientScopeMappings = this.makeRequest({
method: "GET",
path: "/{id}/scope-mappings/clients/{client}",
urlParamKeys: ["id", "client"],
});
listAvailableClientScopeMappings = this.makeRequest({
method: "GET",
path: "/{id}/scope-mappings/clients/{client}/available",
urlParamKeys: ["id", "client"],
});
listCompositeClientScopeMappings = this.makeRequest({
method: "GET",
path: "/{id}/scope-mappings/clients/{client}/composite",
urlParamKeys: ["id", "client"],
});
delClientScopeMappings = this.makeUpdateRequest({
method: "DELETE",
path: "/{id}/scope-mappings/clients/{client}",
urlParamKeys: ["id", "client"],
});
evaluatePermission = this.makeRequest({
method: "GET",
path: "/{id}/evaluate-scopes/scope-mappings/{roleContainer}/{type}",
urlParamKeys: ["id", "roleContainer", "type"],
queryParamKeys: ["scope"],
});
evaluateListProtocolMapper = this.makeRequest({
method: "GET",
path: "/{id}/evaluate-scopes/protocol-mappers",
urlParamKeys: ["id"],
queryParamKeys: ["scope"],
});
evaluateGenerateAccessToken = this.makeRequest({
method: "GET",
path: "/{id}/evaluate-scopes/generate-example-access-token",
urlParamKeys: ["id"],
queryParamKeys: ["scope", "userId"],
});
evaluateGenerateUserInfo = this.makeRequest({
method: "GET",
path: "/{id}/evaluate-scopes/generate-example-userinfo",
urlParamKeys: ["id"],
queryParamKeys: ["scope", "userId"],
});
evaluateGenerateIdToken = this.makeRequest({
method: "GET",
path: "/{id}/evaluate-scopes/generate-example-id-token",
urlParamKeys: ["id"],
queryParamKeys: ["scope", "userId"],
});
addRealmScopeMappings = this.makeUpdateRequest({
method: "POST",
path: "/{id}/scope-mappings/realm",
urlParamKeys: ["id", "client"],
});
listRealmScopeMappings = this.makeRequest({
method: "GET",
path: "/{id}/scope-mappings/realm",
urlParamKeys: ["id"],
});
listAvailableRealmScopeMappings = this.makeRequest({
method: "GET",
path: "/{id}/scope-mappings/realm/available",
urlParamKeys: ["id"],
});
listCompositeRealmScopeMappings = this.makeRequest({
method: "GET",
path: "/{id}/scope-mappings/realm/composite",
urlParamKeys: ["id"],
});
delRealmScopeMappings = this.makeUpdateRequest({
method: "DELETE",
path: "/{id}/scope-mappings/realm",
urlParamKeys: ["id"],
});
/**
* Sessions
*/
listSessions = this.makeRequest({
method: "GET",
path: "/{id}/user-sessions",
urlParamKeys: ["id"],
});
listOfflineSessions = this.makeRequest({
method: "GET",
path: "/{id}/offline-sessions",
urlParamKeys: ["id"],
});
getSessionCount = this.makeRequest({
method: "GET",
path: "/{id}/session-count",
urlParamKeys: ["id"],
});
/**
* Resource
*/
getResourceServer = this.makeRequest({
method: "GET",
path: "{id}/authz/resource-server",
urlParamKeys: ["id"],
});
updateResourceServer = this.makeUpdateRequest({
method: "PUT",
path: "{id}/authz/resource-server",
urlParamKeys: ["id"],
});
listResources = this.makeRequest({
method: "GET",
path: "{id}/authz/resource-server/resource",
urlParamKeys: ["id"],
});
createResource = this.makeUpdateRequest({
method: "POST",
path: "{id}/authz/resource-server/resource",
urlParamKeys: ["id"],
});
getResource = this.makeRequest({
method: "GET",
path: "{id}/authz/resource-server/resource/{resourceId}",
urlParamKeys: ["id", "resourceId"],
});
updateResource = this.makeUpdateRequest({
method: "PUT",
path: "/{id}/authz/resource-server/resource/{resourceId}",
urlParamKeys: ["id", "resourceId"],
});
delResource = this.makeRequest({
method: "DELETE",
path: "/{id}/authz/resource-server/resource/{resourceId}",
urlParamKeys: ["id", "resourceId"],
});
importResource = this.makeUpdateRequest({
method: "POST",
path: "/{id}/authz/resource-server/import",
urlParamKeys: ["id"],
});
exportResource = this.makeRequest({
method: "GET",
path: "/{id}/authz/resource-server/settings",
urlParamKeys: ["id"],
});
evaluateResource = this.makeUpdateRequest({
method: "POST",
path: "{id}/authz/resource-server/policy/evaluate",
urlParamKeys: ["id"],
});
/**
* Policy
*/
listPolicies = this.makeRequest({
method: "GET",
path: "{id}/authz/resource-server/policy",
urlParamKeys: ["id"],
});
findPolicyByName = this.makeRequest({
method: "GET",
path: "{id}/authz/resource-server/policy/search",
urlParamKeys: ["id"],
});
updatePolicy = this.makeUpdateRequest({
method: "PUT",
path: "/{id}/authz/resource-server/policy/{type}/{policyId}",
urlParamKeys: ["id", "type", "policyId"],
});
createPolicy = this.makeUpdateRequest({
method: "POST",
path: "/{id}/authz/resource-server/policy/{type}",
urlParamKeys: ["id", "type"],
});
findOnePolicy = this.makeRequest({
method: "GET",
path: "/{id}/authz/resource-server/policy/{type}/{policyId}",
urlParamKeys: ["id", "type", "policyId"],
catchNotFound: true,
});
listDependentPolicies = this.makeRequest({
method: "GET",
path: "/{id}/authz/resource-server/policy/{policyId}/dependentPolicies",
urlParamKeys: ["id", "policyId"],
});
delPolicy = this.makeRequest({
method: "DELETE",
path: "{id}/authz/resource-server/policy/{policyId}",
urlParamKeys: ["id", "policyId"],
});
listPolicyProviders = this.makeRequest({
method: "GET",
path: "/{id}/authz/resource-server/policy/providers",
urlParamKeys: ["id"],
});
async createOrUpdatePolicy(payload) {
const policyFound = await this.findPolicyByName({
id: payload.id,
name: payload.policyName,
});
if (policyFound) {
await this.updatePolicy({
id: payload.id,
policyId: policyFound.id,
type: payload.policy.type,
}, payload.policy);
return this.findPolicyByName({
id: payload.id,
name: payload.policyName,
});
}
else {
return this.createPolicy({ id: payload.id, type: payload.policy.type }, payload.policy);
}
}
/**
* Scopes
*/
listAllScopes = this.makeRequest({
method: "GET",
path: "/{id}/authz/resource-server/scope",
urlParamKeys: ["id"],
});
listAllResourcesByScope = this.makeRequest({
method: "GET",
path: "/{id}/authz/resource-server/scope/{scopeId}/resources",
urlParamKeys: ["id", "scopeId"],
});
listAllPermissionsByScope = this.makeRequest({
method: "GET",
path: "/{id}/authz/resource-server/scope/{scopeId}/permissions",
urlParamKeys: ["id", "scopeId"],
});
listPermissionsByResource = this.makeRequest({
method: "GET",
path: "/{id}/authz/resource-server/resource/{resourceId}/permissions",
urlParamKeys: ["id", "resourceId"],
});
listScopesByResource = this.makeRequest({
method: "GET",
path: "/{id}/authz/resource-server/resource/{resourceName}/scopes",
urlParamKeys: ["id", "resourceName"],
});
createAuthorizationScope = this.makeUpdateRequest({
method: "POST",
path: "{id}/authz/resource-server/scope",
urlParamKeys: ["id"],
});
updateAuthorizationScope = this.makeUpdateRequest({
method: "PUT",
path: "/{id}/authz/resource-server/scope/{scopeId}",
urlParamKeys: ["id", "scopeId"],
});
getAuthorizationScope = this.makeRequest({
method: "GET",
path: "/{id}/authz/resource-server/scope/{scopeId}",
urlParamKeys: ["id", "scopeId"],
});
delAuthorizationScope = this.makeRequest({
method: "DELETE",
path: "/{id}/authz/resource-server/scope/{scopeId}",
urlParamKeys: ["id", "scopeId"],
});
/**
* Permissions
*/
findPermissions = this.makeRequest({
method: "GET",
path: "{id}/authz/resource-server/permission",
urlParamKeys: ["id"],
});
createPermission = this.makeUpdateRequest({
method: "POST",
path: "/{id}/authz/resource-server/permission/{type}",
urlParamKeys: ["id", "type"],
});
updatePermission = this.makeUpdateRequest({
method: "PUT",
path: "/{id}/authz/resource-server/permission/{type}/{permissionId}",
urlParamKeys: ["id", "type", "permissionId"],
});
delPermission = this.makeRequest({
method: "DELETE",
path: "/{id}/authz/resource-server/permission/{type}/{permissionId}",
urlParamKeys: ["id", "type", "permissionId"],
});
findOnePermission = this.makeRequest({
method: "GET",
path: "/{id}/authz/resource-server/permission/{type}/{permissionId}",
urlParamKeys: ["id", "type", "permissionId"],
});
getAssociatedScopes = this.makeRequest({
method: "GET",
path: "/{id}/authz/resource-server/policy/{permissionId}/scopes",
urlParamKeys: ["id", "permissionId"],
});
getAssociatedResources = this.makeRequest({
method: "GET",
path: "/{id}/authz/resource-server/policy/{permissionId}/resources",
urlParamKeys: ["id", "permissionId"],
});
getAssociatedPolicies = this.makeRequest({
method: "GET",
path: "/{id}/authz/resource-server/policy/{permissionId}/associatedPolicies",
urlParamKeys: ["id", "permissionId"],
});
getOfflineSessionCount = this.makeRequest({
method: "GET",
path: "/{id}/offline-session-count",
urlParamKeys: ["id"],
});
getInstallationProviders = this.makeRequest({
method: "GET",
path: "/{id}/installation/providers/{providerId}",
urlParamKeys: ["id", "providerId"],
});
pushRevocation = this.makeRequest({
method: "POST",
path: "/{id}/push-revocation",
urlParamKeys: ["id"],
});
addClusterNode = this.makeRequest({
method: "POST",
path: "/{id}/nodes",
urlParamKeys: ["id"],
});
deleteClusterNode = this.makeRequest({
method: "DELETE",
path: "/{id}/nodes/{node}",
urlParamKeys: ["id", "node"],
});
testNodesAvailable = this.makeRequest({
method: "GET",
path: "/{id}/test-nodes-available",
urlParamKeys: ["id"],
});
getKeyInfo = this.makeRequest({
method: "GET",
path: "/{id}/certificates/{attr}",
urlParamKeys: ["id", "attr"],
});
generateKey = this.makeRequest({
method: "POST",
path: "/{id}/certificates/{attr}/generate",
urlParamKeys: ["id", "attr"],
});
downloadKey = this.makeUpdateRequest({
method: "POST",
path: "/{id}/certificates/{attr}/download",
urlParamKeys: ["id", "attr"],
headers: {
accept: "application/octet-stream",
},
});
generateAndDownloadKey = this.makeUpdateRequest({
method: "POST",
path: "/{id}/certificates/{attr}/generate-and-download",
urlParamKeys: ["id", "attr"],
headers: {
accept: "application/octet-stream",
},
});
uploadKey = this.makeUpdateRequest({
method: "POST",
path: "/{id}/certificates/{attr}/upload",
urlParamKeys: ["id", "attr"],
});
uploadCertificate = this.makeUpdateRequest({
method: "POST",
path: "/{id}/certificates/{attr}/upload-certificate",
urlParamKeys: ["id", "attr"],
});
updateFineGrainPermission = this.makeUpdateRequest({
method: "PUT",
path: "/{id}/management/permissions",
urlParamKeys: ["id"],
});
listFineGrainPermissions = this.makeRequest({
method: "GET",
path: "/{id}/management/permissions",
urlParamKeys: ["id"],
});
constructor(client) {
super(client, {
path: "/admin/realms/{realm}/clients",
getUrlParams: () => ({
realm: client.realmName,
}),
getBaseUrl: () => client.baseUrl,
});
}
/**
* Find single protocol mapper by name.
*/
async findProtocolMapperByName(payload) {
const allProtocolMappers = await this.listProtocolMappers({
id: payload.id,
...(payload.realm ? { realm: payload.realm } : {}),
});
return allProtocolMappers.find((mapper) => mapper.name === payload.name);
}
}
class ClientScopes extends Resource {
find = this.makeRequest({
method: "GET",
path: "/client-scopes",
});
create = this.makeRequest({
method: "POST",
path: "/client-scopes",
returnResourceIdInLocationHeader: { field: "id" },
});
/**
* Client-Scopes by id
*/
findOne = this.makeRequest({
method: "GET",
path: "/client-scopes/{id}",
urlParamKeys: ["id"],
catchNotFound: true,
});
update = this.makeUpdateRequest({
method: "PUT",
path: "/client-scopes/{id}",
urlParamKeys: ["id"],
});
del = this.makeRequest({
method: "DELETE",
path: "/client-scopes/{id}",
urlParamKeys: ["id"],
});
/**
* Default Client-Scopes
*/
listDefaultClientScopes = this.makeRequest({
method: "GET",
path: "/default-default-client-scopes",
});
addDefaultClientScope = this.makeRequest({
method: "PUT",
path: "/default-default-client-scopes/{id}",
urlParamKeys: ["id"],
});
delDefaultClientScope = this.makeRequest({
method: "DELETE",
path: "/default-default-client-scopes/{id}",
urlParamKeys: ["id"],
});
/**
* Default Optional Client-Scopes
*/
listDefaultOptionalClientScopes = this.makeRequest({
method: "GET",
path: "/default-optional-client-scopes",
});
addDefaultOptionalClientScope = this.makeRequest({
method: "PUT",
path: "/default-optional-client-scopes/{id}",
urlParamKeys: ["id"],
});
delDefaultOptionalClientScope = this.makeRequest({
method: "DELETE",
path: "/default-optional-client-scopes/{id}",
urlParamKeys: ["id"],
});
/**
* Protocol Mappers
*/
addMultipleProtocolMappers = this.makeUpdateRequest({
method: "POST",
path: "/client-scopes/{id}/protocol-mappers/add-models",
urlParamKeys: ["id"],
});
addProtocolMapper = this.makeUpdateRequest({
method: "POST",
path: "/client-scopes/{id}/protocol-mappers/models",
urlParamKeys: ["id"],
});
listProtocolMappers = this.makeRequest({
method: "GET",
path: "/client-scopes/{id}/protocol-mappers/models",
urlParamKeys: ["id"],
});
findProtocolMapper = this.makeRequest({
method: "GET",
path: "/client-scopes/{id}/protocol-mappers/models/{mapperId}",
urlParamKeys: ["id", "mapperId"],
catchNotFound: true,
});
findProtocolMappersByProtocol = this.makeRequest({
method: "GET",
path: "/client-scopes/{id}/protocol-mappers/protocol/{protocol}",
urlParamKeys: ["id", "protocol"],
catchNotFound: true,
});
updateProtocolMapper = this.makeUpdateRequest({
method: "PUT",
path: "/client-scopes/{id}/protocol-mappers/models/{mapperId}",
urlParamKeys: ["id", "mapperId"],
});
delProtocolMapper = this.makeRequest({
method: "DELETE",
path: "/client-scopes/{id}/protocol-mappers/models/{mapperId}",
urlParamKeys: ["id", "mapperId"],
});
/**
* Scope Mappings
*/
listScopeMappings = this.makeRequest({
method: "GET",
path: "/client-scopes/{id}/scope-mappings",
urlParamKeys: ["id"],
});
addClientScopeMappings = this.makeUpdateRequest({
method: "POST",
path: "/client-scopes/{id}/scope-mappings/clients/{client}",
urlParamKeys: ["id", "client"],
});
listClientScopeMappings = this.makeRequest({
method: "GET",
path: "/client-scopes/{id}/scope-mappings/clients/{client}",
urlParamKeys: ["id", "client"],
});
listAvailableClientScopeMappings = this.makeRequest({
method: "GET",
path: "/client-scopes/{id}/scope-mappings/clients/{client}/available",
urlParamKeys: ["id", "client"],
});
listCompositeClientScopeMappings = this.makeRequest({
method: "GET",
path: "/client-scopes/{id}/scope-mappings/clients/{client}/composite",
urlParamKeys: ["id", "client"],
});
delClientScopeMappings = this.makeUpdateRequest({
method: "DELETE",
path: "/client-scopes/{id}/scope-mappings/clients/{client}",
urlParamKeys: ["id", "client"],
});
addRealmScopeMappings = this.makeUpdateRequest({
method: "POST",
path: "/client-scopes/{id}/scope-mappings/realm",
urlParamKeys: ["id"],
});
listRealmScopeMappings = this.makeRequest({
method: "GET",
path: "/client-scopes/{id}/scope-mappings/realm",
urlParamKeys: ["id"],
});
listAvailableRealmScopeMappings = this.makeRequest({
method: "GET",
path: "/client-scopes/{id}/scope-mappings/realm/available",
urlParamKeys: ["id"],
});
listCompositeRealmScopeMappings = this.makeRequest({
method: "GET",
path: "/client-scopes/{id}/scope-mappings/realm/composite",
urlParamKeys: ["id"],
});
delRealmScopeMappings = this.makeUpdateRequest({
method: "DELETE",
path: "/client-scopes/{id}/scope-mappings/realm",
urlParamKeys: ["id"],
});
constructor(client) {
super(client, {
path: "/admin/realms/{realm}",
getUrlParams: () => ({
realm: client.realmName,
}),
getBaseUrl: () => client.baseUrl,
});
}
/**
* Find client scope by name.
*/
async findOneByName(payload) {
const allScopes = await this.find({
...(payload.realm ? { realm: payload.realm } : {}),
});
return allScopes.find((item) => item.name === payload.name);
}
/**
* Delete client scope by name.
*/
async delByName(payload) {
const scope = await this.findOneByName(payload);
if (!scope) {
throw new Error("Scope not found.");
}
await this.del({
...(payload.realm ? { realm: payload.realm } : {}),
id: scope.id,
});
}
/**
* Find single protocol mapper by name.
*/
async findProtocolMapperByName(payload) {
const allProtocolMappers = await this.listProtocolMappers({
id: payload.id,
...(payload.realm ? { realm: payload.realm } : {}),
});
return allProtocolMappers.find((mapper) => mapper.name === payload.name);
}
}
class Components extends Resource {
/**
* components
* https://www.keycloak.org/docs-api/11.0/rest-api/#_component_resource
*/
find = this.makeRequest({
method: "GET",
});
create = this.makeRequest({
method: "POST",
returnResourceIdInLocationHeader: { field: "id" },
});
findOne = this.makeRequest({
method: "GET",
path: "/{id}",
urlParamKeys: ["id"],
catchNotFound: true,
});
update = this.makeUpdateRequest({
method: "PUT",
path: "/{id}",
urlParamKeys: ["id"],
});
del = this.makeRequest({
method: "DELETE",
path: "/{id}",
urlParamKeys: ["id"],
});
listSubComponents = this.makeRequest({
method: "GET",
path: "/{id}/sub-component-types",
urlParamKeys: ["id"],
queryParamKeys: ["type"],
});
constructor(client) {
super(client, {
path: "/admin/realms/{realm}/components",
getUrlParams: () => ({
realm: client.realmName,
}),
getBaseUrl: () => client.baseUrl,
});
}
}
class Groups extends Resource {
find = this.makeRequest({
method: "GET",
queryParamKeys: [
"search",
"q",
"exact",
"briefRepresentation",
"first",
"max",
],
});
create = this.makeRequest({
method: "POST",
returnResourceIdInLocationHeader: { field: "id" },
});
updateRoot = this.makeRequest({
method: "P