@keycloak/keycloak-admin-client 21.1.2 → 22.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/lib/defs/policyRepresentation.js +3 -3
- package/lib/defs/requiredActionProviderRepresentation.js +1 -1
- package/lib/defs/serverInfoRepesentation.d.ts +2 -0
- package/lib/resources/agent.js +8 -8
- package/lib/resources/groups.d.ts +23 -0
- package/lib/resources/groups.js +22 -0
- package/lib/resources/identityProviders.d.ts +2 -2
- package/lib/resources/realms.js +2 -2
- package/lib/utils/auth.js +13 -1
- package/package.json +12 -13
package/README.md
CHANGED
|
@@ -107,20 +107,20 @@ setInterval(() => kcAdminClient.auth(credentials), 58 * 1000); // 58 seconds
|
|
|
107
107
|
To build the source do a build:
|
|
108
108
|
|
|
109
109
|
```bash
|
|
110
|
-
|
|
110
|
+
pnpm run build
|
|
111
111
|
```
|
|
112
112
|
|
|
113
113
|
Start the Keycloak server:
|
|
114
114
|
|
|
115
115
|
```bash
|
|
116
|
-
|
|
116
|
+
pnpm run server:start
|
|
117
117
|
```
|
|
118
118
|
|
|
119
119
|
If you started your container manually make sure there is an admin user named 'admin' with password 'admin'.
|
|
120
120
|
Then start the tests with:
|
|
121
121
|
|
|
122
122
|
```bash
|
|
123
|
-
|
|
123
|
+
pnpm test
|
|
124
124
|
```
|
|
125
125
|
|
|
126
126
|
## Supported APIs
|
|
@@ -6,14 +6,14 @@ export var DecisionStrategy;
|
|
|
6
6
|
DecisionStrategy["AFFIRMATIVE"] = "AFFIRMATIVE";
|
|
7
7
|
DecisionStrategy["UNANIMOUS"] = "UNANIMOUS";
|
|
8
8
|
DecisionStrategy["CONSENSUS"] = "CONSENSUS";
|
|
9
|
-
})(DecisionStrategy
|
|
9
|
+
})(DecisionStrategy || (DecisionStrategy = {}));
|
|
10
10
|
export var DecisionEffect;
|
|
11
11
|
(function (DecisionEffect) {
|
|
12
12
|
DecisionEffect["Permit"] = "PERMIT";
|
|
13
13
|
DecisionEffect["Deny"] = "DENY";
|
|
14
|
-
})(DecisionEffect
|
|
14
|
+
})(DecisionEffect || (DecisionEffect = {}));
|
|
15
15
|
export var Logic;
|
|
16
16
|
(function (Logic) {
|
|
17
17
|
Logic["POSITIVE"] = "POSITIVE";
|
|
18
18
|
Logic["NEGATIVE"] = "NEGATIVE";
|
|
19
|
-
})(Logic
|
|
19
|
+
})(Logic || (Logic = {}));
|
|
@@ -8,4 +8,4 @@ export var RequiredActionAlias;
|
|
|
8
8
|
RequiredActionAlias["CONFIGURE_TOTP"] = "CONFIGURE_TOTP";
|
|
9
9
|
RequiredActionAlias["UPDATE_PASSWORD"] = "UPDATE_PASSWORD";
|
|
10
10
|
RequiredActionAlias["TERMS_AND_CONDITIONS"] = "TERMS_AND_CONDITIONS";
|
|
11
|
-
})(RequiredActionAlias
|
|
11
|
+
})(RequiredActionAlias || (RequiredActionAlias = {}));
|
|
@@ -87,4 +87,6 @@ export interface ProtocolMapperTypeRepresentation {
|
|
|
87
87
|
export interface CryptoInfoRepresentation {
|
|
88
88
|
cryptoProvider: string;
|
|
89
89
|
supportedKeystoreTypes: string[];
|
|
90
|
+
clientSignatureSymmetricAlgorithms: string[];
|
|
91
|
+
clientSignatureAsymmetricAlgorithms: string[];
|
|
90
92
|
}
|
package/lib/resources/agent.js
CHANGED
|
@@ -20,17 +20,17 @@ export class Agent {
|
|
|
20
20
|
return async (payload = {}, options) => {
|
|
21
21
|
const baseParams = this.getBaseParams?.() ?? {};
|
|
22
22
|
// Filter query parameters by queryParamKeys
|
|
23
|
-
const queryParams = queryParamKeys
|
|
24
|
-
? pick(payload, queryParamKeys)
|
|
25
|
-
: undefined;
|
|
23
|
+
const queryParams = queryParamKeys.length > 0 ? pick(payload, queryParamKeys) : undefined;
|
|
26
24
|
// Add filtered payload parameters to base parameters
|
|
27
25
|
const allUrlParamKeys = [...Object.keys(baseParams), ...urlParamKeys];
|
|
28
26
|
const urlParams = { ...baseParams, ...pick(payload, allUrlParamKeys) };
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
if (!(payload instanceof FormData)) {
|
|
28
|
+
// Omit url parameters and query parameters from payload
|
|
29
|
+
const omittedKeys = ignoredKeys
|
|
30
|
+
? [...allUrlParamKeys, ...queryParamKeys].filter((key) => !ignoredKeys.includes(key))
|
|
31
|
+
: [...allUrlParamKeys, ...queryParamKeys];
|
|
32
|
+
payload = omit(payload, omittedKeys);
|
|
33
|
+
}
|
|
34
34
|
// Transform keys of both payload and queryParams
|
|
35
35
|
if (keyTransform) {
|
|
36
36
|
this.transformKey(payload, keyTransform);
|
|
@@ -27,6 +27,9 @@ export declare class Groups extends Resource<{
|
|
|
27
27
|
}) | undefined, options?: Pick<import("./agent.js").RequestArgs, "catchNotFound"> | undefined) => Promise<{
|
|
28
28
|
id: string;
|
|
29
29
|
}>;
|
|
30
|
+
updateRoot: (payload?: (GroupRepresentation & {
|
|
31
|
+
realm?: string | undefined;
|
|
32
|
+
}) | undefined, options?: Pick<import("./agent.js").RequestArgs, "catchNotFound"> | undefined) => Promise<void>;
|
|
30
33
|
/**
|
|
31
34
|
* Single user
|
|
32
35
|
*/
|
|
@@ -53,6 +56,7 @@ export declare class Groups extends Resource<{
|
|
|
53
56
|
/**
|
|
54
57
|
* Set or create child.
|
|
55
58
|
* This will just set the parent if it exists. Create it and set the parent if the group doesn’t exist.
|
|
59
|
+
* @deprecated Use `createChildGroup` or `updateChildGroup` instead.
|
|
56
60
|
*/
|
|
57
61
|
setOrCreateChild: (query: {
|
|
58
62
|
id: string;
|
|
@@ -61,6 +65,25 @@ export declare class Groups extends Resource<{
|
|
|
61
65
|
}, payload: GroupRepresentation) => Promise<{
|
|
62
66
|
id: string;
|
|
63
67
|
}>;
|
|
68
|
+
/**
|
|
69
|
+
* Creates a child group on the specified parent group. If the group already exists, then an error is returned.
|
|
70
|
+
*/
|
|
71
|
+
createChildGroup: (query: {
|
|
72
|
+
id: string;
|
|
73
|
+
} & {
|
|
74
|
+
realm?: string | undefined;
|
|
75
|
+
}, payload: Omit<GroupRepresentation, "id">) => Promise<{
|
|
76
|
+
id: string;
|
|
77
|
+
}>;
|
|
78
|
+
/**
|
|
79
|
+
* Updates a child group on the specified parent group. If the group doesn’t exist, then an error is returned.
|
|
80
|
+
* Can be used to move a group from one parent to another.
|
|
81
|
+
*/
|
|
82
|
+
updateChildGroup: (query: {
|
|
83
|
+
id: string;
|
|
84
|
+
} & {
|
|
85
|
+
realm?: string | undefined;
|
|
86
|
+
}, payload: GroupRepresentation) => Promise<void>;
|
|
64
87
|
/**
|
|
65
88
|
* Members
|
|
66
89
|
*/
|
package/lib/resources/groups.js
CHANGED
|
@@ -7,6 +7,9 @@ export class Groups extends Resource {
|
|
|
7
7
|
method: "POST",
|
|
8
8
|
returnResourceIdInLocationHeader: { field: "id" },
|
|
9
9
|
});
|
|
10
|
+
updateRoot = this.makeRequest({
|
|
11
|
+
method: "POST",
|
|
12
|
+
});
|
|
10
13
|
/**
|
|
11
14
|
* Single user
|
|
12
15
|
*/
|
|
@@ -33,6 +36,7 @@ export class Groups extends Resource {
|
|
|
33
36
|
/**
|
|
34
37
|
* Set or create child.
|
|
35
38
|
* This will just set the parent if it exists. Create it and set the parent if the group doesn’t exist.
|
|
39
|
+
* @deprecated Use `createChildGroup` or `updateChildGroup` instead.
|
|
36
40
|
*/
|
|
37
41
|
setOrCreateChild = this.makeUpdateRequest({
|
|
38
42
|
method: "POST",
|
|
@@ -40,6 +44,24 @@ export class Groups extends Resource {
|
|
|
40
44
|
urlParamKeys: ["id"],
|
|
41
45
|
returnResourceIdInLocationHeader: { field: "id" },
|
|
42
46
|
});
|
|
47
|
+
/**
|
|
48
|
+
* Creates a child group on the specified parent group. If the group already exists, then an error is returned.
|
|
49
|
+
*/
|
|
50
|
+
createChildGroup = this.makeUpdateRequest({
|
|
51
|
+
method: "POST",
|
|
52
|
+
path: "/{id}/children",
|
|
53
|
+
urlParamKeys: ["id"],
|
|
54
|
+
returnResourceIdInLocationHeader: { field: "id" },
|
|
55
|
+
});
|
|
56
|
+
/**
|
|
57
|
+
* Updates a child group on the specified parent group. If the group doesn’t exist, then an error is returned.
|
|
58
|
+
* Can be used to move a group from one parent to another.
|
|
59
|
+
*/
|
|
60
|
+
updateChildGroup = this.makeUpdateRequest({
|
|
61
|
+
method: "POST",
|
|
62
|
+
path: "/{id}/children",
|
|
63
|
+
urlParamKeys: ["id"],
|
|
64
|
+
});
|
|
43
65
|
/**
|
|
44
66
|
* Members
|
|
45
67
|
*/
|
|
@@ -75,10 +75,10 @@ export declare class IdentityProviders extends Resource<{
|
|
|
75
75
|
} & {
|
|
76
76
|
realm?: string | undefined;
|
|
77
77
|
}) | undefined, options?: Pick<import("./agent.js").RequestArgs, "catchNotFound"> | undefined) => Promise<Record<string, IdentityProviderMapperTypeRepresentation>>;
|
|
78
|
-
importFromUrl: (payload?: ({
|
|
78
|
+
importFromUrl: (payload?: ((FormData | {
|
|
79
79
|
fromUrl: string;
|
|
80
80
|
providerId: string;
|
|
81
|
-
} & {
|
|
81
|
+
}) & {
|
|
82
82
|
realm?: string | undefined;
|
|
83
83
|
}) | undefined, options?: Pick<import("./agent.js").RequestArgs, "catchNotFound"> | undefined) => Promise<Record<string, string>>;
|
|
84
84
|
updatePermission: (query: {
|
package/lib/resources/realms.js
CHANGED
|
@@ -122,8 +122,8 @@ export class Realms extends Resource {
|
|
|
122
122
|
*/
|
|
123
123
|
removeSession = this.makeRequest({
|
|
124
124
|
method: "DELETE",
|
|
125
|
-
path: "/{realm}/sessions/{
|
|
126
|
-
urlParamKeys: ["realm", "
|
|
125
|
+
path: "/{realm}/sessions/{sessionId}",
|
|
126
|
+
urlParamKeys: ["realm", "sessionId"],
|
|
127
127
|
catchNotFound: true,
|
|
128
128
|
});
|
|
129
129
|
/**
|
package/lib/utils/auth.js
CHANGED
|
@@ -2,6 +2,14 @@ import camelize from "camelize-ts";
|
|
|
2
2
|
import { defaultBaseUrl, defaultRealm } from "./constants.js";
|
|
3
3
|
import { fetchWithError } from "./fetchWithError.js";
|
|
4
4
|
import { stringifyQueryParams } from "./stringifyQueryParams.js";
|
|
5
|
+
// See: https://developer.mozilla.org/en-US/docs/Glossary/Base64
|
|
6
|
+
const bytesToBase64 = (bytes) => btoa(Array.from(bytes, (byte) => String.fromCodePoint(byte)).join(""));
|
|
7
|
+
const toBase64 = (input) => bytesToBase64(new TextEncoder().encode(input));
|
|
8
|
+
// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent#encoding_for_rfc3986
|
|
9
|
+
const encodeRFC3986URIComponent = (input) => encodeURIComponent(input).replace(/[!'()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);
|
|
10
|
+
// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
|
|
11
|
+
// Specifically, the section on encoding `application/x-www-form-urlencoded`.
|
|
12
|
+
const encodeFormURIComponent = (data) => encodeRFC3986URIComponent(data).replaceAll("%20", "+");
|
|
5
13
|
export const getToken = async (settings) => {
|
|
6
14
|
// Construct URL
|
|
7
15
|
const baseUrl = settings.baseUrl || defaultBaseUrl;
|
|
@@ -28,7 +36,11 @@ export const getToken = async (settings) => {
|
|
|
28
36
|
const options = settings.requestOptions ?? {};
|
|
29
37
|
const headers = new Headers(options.headers);
|
|
30
38
|
if (credentials.clientSecret) {
|
|
31
|
-
|
|
39
|
+
// See: https://datatracker.ietf.org/doc/html/rfc6749#section-2.3.1
|
|
40
|
+
const username = encodeFormURIComponent(credentials.clientId);
|
|
41
|
+
const password = encodeFormURIComponent(credentials.clientSecret);
|
|
42
|
+
// See: https://datatracker.ietf.org/doc/html/rfc2617#section-2
|
|
43
|
+
headers.set("authorization", `Basic ${toBase64(`${username}:${password}`)}`);
|
|
32
44
|
}
|
|
33
45
|
headers.set("content-type", "application/x-www-form-urlencoded");
|
|
34
46
|
const response = await fetchWithError(url, {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keycloak/keycloak-admin-client",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "22.0.0",
|
|
4
4
|
"description": "A client to interact with Keycloak's Administration API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -11,12 +11,6 @@
|
|
|
11
11
|
"engines": {
|
|
12
12
|
"node": ">=18"
|
|
13
13
|
},
|
|
14
|
-
"scripts": {
|
|
15
|
-
"build": "wireit",
|
|
16
|
-
"lint": "wireit",
|
|
17
|
-
"test": "wireit",
|
|
18
|
-
"prepublishOnly": "npm run build"
|
|
19
|
-
},
|
|
20
14
|
"wireit": {
|
|
21
15
|
"build": {
|
|
22
16
|
"command": "tsc --pretty",
|
|
@@ -37,17 +31,17 @@
|
|
|
37
31
|
}
|
|
38
32
|
},
|
|
39
33
|
"dependencies": {
|
|
40
|
-
"camelize-ts": "^
|
|
34
|
+
"camelize-ts": "^3.0.0",
|
|
41
35
|
"lodash-es": "^4.17.21",
|
|
42
36
|
"url-join": "^5.0.0",
|
|
43
37
|
"url-template": "^3.1.0"
|
|
44
38
|
},
|
|
45
39
|
"devDependencies": {
|
|
46
|
-
"@faker-js/faker": "^
|
|
47
|
-
"@types/chai": "^4.3.
|
|
40
|
+
"@faker-js/faker": "^8.0.2",
|
|
41
|
+
"@types/chai": "^4.3.5",
|
|
48
42
|
"@types/lodash-es": "^4.17.7",
|
|
49
43
|
"@types/mocha": "^10.0.1",
|
|
50
|
-
"@types/node": "^
|
|
44
|
+
"@types/node": "^20.4.1",
|
|
51
45
|
"chai": "^4.3.7",
|
|
52
46
|
"mocha": "^10.2.0",
|
|
53
47
|
"ts-node": "^10.9.1"
|
|
@@ -61,5 +55,10 @@
|
|
|
61
55
|
"type": "git",
|
|
62
56
|
"url": "https://github.com/keycloak/keycloak.git"
|
|
63
57
|
},
|
|
64
|
-
"homepage": "https://www.keycloak.org/"
|
|
65
|
-
|
|
58
|
+
"homepage": "https://www.keycloak.org/",
|
|
59
|
+
"scripts": {
|
|
60
|
+
"build": "wireit",
|
|
61
|
+
"lint": "wireit",
|
|
62
|
+
"test": "wireit"
|
|
63
|
+
}
|
|
64
|
+
}
|