keycloak-api-manager 4.0.0 → 5.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/Handlers/attackDetectionHandler.js +64 -0
- package/Handlers/clientPoliciesHandler.js +120 -0
- package/Handlers/groupsHandler.js +32 -0
- package/Handlers/organizationsHandler.js +243 -0
- package/Handlers/serverInfoHandler.js +36 -0
- package/Handlers/userProfileHandler.js +121 -0
- package/README.md +83 -7157
- package/docs/architecture.md +47 -0
- package/docs/deployment.md +32 -0
- package/docs/keycloak-setup.md +47 -0
- package/docs/test-configuration.md +43 -0
- package/docs/testing.md +60 -0
- package/index.js +156 -240
- package/package.json +28 -15
- package/test/.mocharc.json +2 -2
- package/test/config/secrets.json +12 -0
- package/test/docker-keycloak/certs/keycloak.crt +58 -0
- package/test/docker-keycloak/certs/keycloak.key +28 -0
- package/test/docker-keycloak/docker-compose-https.yml +2 -0
- package/test/docker-keycloak/docker-compose.yml +4 -4
- package/test/helpers/matrix.js +16 -0
- package/test/matrix/auth.json +27 -0
- package/test/matrix/clients.json +45 -0
- package/test/matrix/realms-components-idp.json +37 -0
- package/test/matrix/users-roles-groups.json +26 -0
- package/test/package-lock.json +3032 -0
- package/test/specs/attackDetection.test.js +102 -0
- package/test/specs/clientCredentials.test.js +79 -0
- package/test/specs/clientPolicies.test.js +162 -0
- package/test/specs/{debugClientLibrary.test.js → diagnostics/debugClientLibrary.test.js} +2 -2
- package/test/specs/groupPermissions.test.js +87 -0
- package/test/specs/matrix/matrix-auth.test.js +112 -0
- package/test/specs/matrix/matrix-clients.test.js +59 -0
- package/test/specs/matrix/matrix-realms-components-idp.test.js +111 -0
- package/test/specs/matrix/matrix-users-roles-groups.test.js +68 -0
- package/test/specs/organizations.test.js +183 -0
- package/test/specs/serverInfo.test.js +140 -0
- package/test/specs/userProfile.test.js +135 -0
- package/test/{enableServerFeatures.js → support/enableServerFeatures.js} +43 -26
- package/test/{setup.js → support/setup.js} +3 -3
- package/test/support/testConfig.js +69 -0
- package/test/testConfig.js +1 -69
- package/test-output.log +72 -0
- package/test/TESTING.md +0 -327
- package/test/config/CONFIGURATION.md +0 -170
- package/test/diagnostic-protocol-mappers.js +0 -189
- package/test/docker-keycloak/DEPLOYMENT_GUIDE.md +0 -262
- package/test/helpers/setup.js +0 -186
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **************************************************************************************************
|
|
3
|
+
* **************************************************************************************************
|
|
4
|
+
* The Attack Detection entity provides functionality for managing brute force attack detection
|
|
5
|
+
* in Keycloak. This allows you to detect and prevent brute force login attempts, lock users,
|
|
6
|
+
* and clear login failures.
|
|
7
|
+
* **************************************************************************************************
|
|
8
|
+
* **************************************************************************************************
|
|
9
|
+
*/
|
|
10
|
+
let kcAdminClientHandler = null;
|
|
11
|
+
|
|
12
|
+
exports.setKcAdminClient = function(kcAdminClient) {
|
|
13
|
+
kcAdminClientHandler = kcAdminClient;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* ***************************** - getBruteForceStatus - *******************************
|
|
18
|
+
* Get brute force detection status for all users in a realm
|
|
19
|
+
*
|
|
20
|
+
* @parameters:
|
|
21
|
+
* - realm: (string, required) - The realm name
|
|
22
|
+
* @returns: Array of user brute force status objects
|
|
23
|
+
*/
|
|
24
|
+
exports.getBruteForceStatus = function(filter) {
|
|
25
|
+
return kcAdminClientHandler.attackDetection.findAll(filter);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* ***************************** - getUserBruteForceStatus - *******************************
|
|
30
|
+
* Get brute force detection status for a specific user
|
|
31
|
+
*
|
|
32
|
+
* @parameters:
|
|
33
|
+
* - realm: (string, required) - The realm name
|
|
34
|
+
* - id: (string, required) - The user ID
|
|
35
|
+
* @returns: User brute force status object
|
|
36
|
+
*/
|
|
37
|
+
exports.getUserBruteForceStatus = function(filter) {
|
|
38
|
+
return kcAdminClientHandler.attackDetection.findOne(filter);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* ***************************** - clearUserLoginFailures - *******************************
|
|
43
|
+
* Clear all login failures for a specific user
|
|
44
|
+
*
|
|
45
|
+
* @parameters:
|
|
46
|
+
* - realm: (string, required) - The realm name
|
|
47
|
+
* - id: (string, required) - The user ID
|
|
48
|
+
* @returns: Promise
|
|
49
|
+
*/
|
|
50
|
+
exports.clearUserLoginFailures = function(filter) {
|
|
51
|
+
return kcAdminClientHandler.attackDetection.del(filter);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* ***************************** - clearAllLoginFailures - *******************************
|
|
56
|
+
* Clear all login failures for all users in a realm
|
|
57
|
+
*
|
|
58
|
+
* @parameters:
|
|
59
|
+
* - realm: (string, required) - The realm name
|
|
60
|
+
* @returns: Promise
|
|
61
|
+
*/
|
|
62
|
+
exports.clearAllLoginFailures = function(filter) {
|
|
63
|
+
return kcAdminClientHandler.attackDetection.delAll(filter);
|
|
64
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **************************************************************************************************
|
|
3
|
+
* **************************************************************************************************
|
|
4
|
+
* The Client Policies entity (Keycloak 12+) provides governance and security policies
|
|
5
|
+
* for client applications. Client policies allow administrators to enforce security
|
|
6
|
+
* requirements, configure client behavior, and ensure compliance across all clients.
|
|
7
|
+
* **************************************************************************************************
|
|
8
|
+
* **************************************************************************************************
|
|
9
|
+
*/
|
|
10
|
+
let kcAdminClientHandler = null;
|
|
11
|
+
|
|
12
|
+
exports.setKcAdminClient = function(kcAdminClient) {
|
|
13
|
+
kcAdminClientHandler = kcAdminClient;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* ***************************** - getPolicies - *******************************
|
|
18
|
+
* Get all client policies for a realm
|
|
19
|
+
*
|
|
20
|
+
* @parameters:
|
|
21
|
+
* - filter: [optional] parameter
|
|
22
|
+
* - realm: (string, optional) - The realm name
|
|
23
|
+
* @returns: Object containing policies array
|
|
24
|
+
*/
|
|
25
|
+
exports.getPolicies = function(filter) {
|
|
26
|
+
return kcAdminClientHandler.clientPolicies.listPolicies(filter);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* ***************************** - updatePolicies - *******************************
|
|
31
|
+
* Update client policies configuration
|
|
32
|
+
*
|
|
33
|
+
* @parameters:
|
|
34
|
+
* - filter: [optional] parameter
|
|
35
|
+
* - realm: (string, optional) - The realm name
|
|
36
|
+
* - policiesRepresentation: Object with policies array
|
|
37
|
+
* - policies: (array) - Array of policy objects
|
|
38
|
+
* - name: (string) - Policy name
|
|
39
|
+
* - description: (string) - Policy description
|
|
40
|
+
* - enabled: (boolean) - Whether policy is enabled
|
|
41
|
+
* - conditions: (array) - Conditions that trigger the policy
|
|
42
|
+
* - profiles: (array) - Profiles to apply when policy matches
|
|
43
|
+
*/
|
|
44
|
+
exports.updatePolicies = async function(filter, policiesRepresentation) {
|
|
45
|
+
// Direct API call since @keycloak/keycloak-admin-client doesn't support this
|
|
46
|
+
const realm = filter?.realm || kcAdminClientHandler.realmName;
|
|
47
|
+
const baseUrl = kcAdminClientHandler.baseUrl;
|
|
48
|
+
const token = kcAdminClientHandler.accessToken;
|
|
49
|
+
|
|
50
|
+
const url = `${baseUrl}/admin/realms/${realm}/client-policies/policies`;
|
|
51
|
+
|
|
52
|
+
const response = await fetch(url, {
|
|
53
|
+
method: 'PUT',
|
|
54
|
+
headers: {
|
|
55
|
+
'Content-Type': 'application/json',
|
|
56
|
+
'Authorization': `Bearer ${token}`
|
|
57
|
+
},
|
|
58
|
+
body: JSON.stringify(policiesRepresentation)
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
if (!response.ok) {
|
|
62
|
+
const error = await response.text();
|
|
63
|
+
throw new Error(`Failed to update client policies: ${error}`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return response.status === 204 ? undefined : response.json();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* ***************************** - getProfiles - *******************************
|
|
71
|
+
* Get all client profiles for a realm
|
|
72
|
+
*
|
|
73
|
+
* @parameters:
|
|
74
|
+
* - filter: [optional] parameter
|
|
75
|
+
* - realm: (string, optional) - The realm name
|
|
76
|
+
* @returns: Object containing profiles array
|
|
77
|
+
*/
|
|
78
|
+
exports.getProfiles = function(filter) {
|
|
79
|
+
return kcAdminClientHandler.clientPolicies.listProfiles(filter);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* ***************************** - updateProfiles - *******************************
|
|
84
|
+
* Update client profiles configuration
|
|
85
|
+
*
|
|
86
|
+
* @parameters:
|
|
87
|
+
* - filter: [optional] parameter
|
|
88
|
+
* - realm: (string, optional) - The realm name
|
|
89
|
+
* - profilesRepresentation: Object with profiles array
|
|
90
|
+
* - profiles: (array) - Array of profile objects
|
|
91
|
+
* - name: (string) - Profile name
|
|
92
|
+
* - description: (string) - Profile description
|
|
93
|
+
* - executors: (array) - Executors that enforce security requirements
|
|
94
|
+
* - executor: (string) - Executor type
|
|
95
|
+
* - configuration: (object) - Executor-specific configuration
|
|
96
|
+
*/
|
|
97
|
+
exports.updateProfiles = async function(filter, profilesRepresentation) {
|
|
98
|
+
// Direct API call since @keycloak/keycloak-admin-client doesn't support this
|
|
99
|
+
const realm = filter?.realm || kcAdminClientHandler.realmName;
|
|
100
|
+
const baseUrl = kcAdminClientHandler.baseUrl;
|
|
101
|
+
const token = kcAdminClientHandler.accessToken;
|
|
102
|
+
|
|
103
|
+
const url = `${baseUrl}/admin/realms/${realm}/client-policies/profiles`;
|
|
104
|
+
|
|
105
|
+
const response = await fetch(url, {
|
|
106
|
+
method: 'PUT',
|
|
107
|
+
headers: {
|
|
108
|
+
'Content-Type': 'application/json',
|
|
109
|
+
'Authorization': `Bearer ${token}`
|
|
110
|
+
},
|
|
111
|
+
body: JSON.stringify(profilesRepresentation)
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
if (!response.ok) {
|
|
115
|
+
const error = await response.text();
|
|
116
|
+
throw new Error(`Failed to update client profiles: ${error}`);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return response.status === 204 ? undefined : response.json();
|
|
120
|
+
}
|
|
@@ -306,3 +306,35 @@ exports.delClientRoleMappings=function(filters){
|
|
|
306
306
|
return (kcAdminClientHandler.groups.delClientRoleMappings(filters));
|
|
307
307
|
}
|
|
308
308
|
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* ***************************** - setPermissions - *******************************
|
|
312
|
+
* Enable or update permission settings for a group.
|
|
313
|
+
* This allows fine-grained control over who can manage group membership and permissions.
|
|
314
|
+
* @parameters:
|
|
315
|
+
* - filters: parameter provided as a JSON object that accepts the following parameters:
|
|
316
|
+
* - id: [required] The ID of the group
|
|
317
|
+
* - permissionRepresentation: Object with permission settings
|
|
318
|
+
* - enabled: [required] (boolean) Whether permissions are enabled
|
|
319
|
+
*/
|
|
320
|
+
exports.setPermissions=function(filters, permissionRepresentation){
|
|
321
|
+
return (kcAdminClientHandler.groups.updatePermission(filters, permissionRepresentation));
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* ***************************** - listPermissions - *******************************
|
|
327
|
+
* Get the current permission settings for a group.
|
|
328
|
+
* Returns information about who can manage the group, view members, etc.
|
|
329
|
+
* @parameters:
|
|
330
|
+
* - filters: parameter provided as a JSON object that accepts the following parameters:
|
|
331
|
+
* - id: [required] The ID of the group
|
|
332
|
+
* @returns: Object with permission configuration including:
|
|
333
|
+
* - enabled: (boolean) Whether permissions are enabled
|
|
334
|
+
* - resource: (string) Associated authorization resource ID
|
|
335
|
+
* - scopePermissions: (object) Map of scope permissions
|
|
336
|
+
*/
|
|
337
|
+
exports.listPermissions=function(filters){
|
|
338
|
+
return (kcAdminClientHandler.groups.listPermissions(filters));
|
|
339
|
+
}
|
|
340
|
+
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **************************************************************************************************
|
|
3
|
+
* **************************************************************************************************
|
|
4
|
+
* The Organizations entity (Keycloak 25+) allows managing organizations for multi-tenancy.
|
|
5
|
+
* Organizations provide a way to group users, identity providers, and domains together,
|
|
6
|
+
* enabling better isolation and management of different organizational units.
|
|
7
|
+
*
|
|
8
|
+
* NOTE: Some Organizations APIs are not fully supported by @keycloak/keycloak-admin-client
|
|
9
|
+
* so this handler uses direct REST API calls for those endpoints.
|
|
10
|
+
* **************************************************************************************************
|
|
11
|
+
* **************************************************************************************************
|
|
12
|
+
*/
|
|
13
|
+
let kcAdminClientHandler = null;
|
|
14
|
+
|
|
15
|
+
exports.setKcAdminClient = function(kcAdminClient) {
|
|
16
|
+
kcAdminClientHandler = kcAdminClient;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Helper function to make direct API calls to Keycloak
|
|
21
|
+
*/
|
|
22
|
+
async function makeDirectApiCall(method, endpoint, body = null) {
|
|
23
|
+
const baseUrl = kcAdminClientHandler.baseUrl;
|
|
24
|
+
const realmName = kcAdminClientHandler.realmName;
|
|
25
|
+
const accessToken = kcAdminClientHandler.accessToken;
|
|
26
|
+
|
|
27
|
+
const url = `${baseUrl}/admin/realms/${realmName}${endpoint}`;
|
|
28
|
+
|
|
29
|
+
const options = {
|
|
30
|
+
method,
|
|
31
|
+
headers: {
|
|
32
|
+
'Authorization': `Bearer ${accessToken}`,
|
|
33
|
+
'Content-Type': 'application/json'
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
if (body) {
|
|
38
|
+
options.body = JSON.stringify(body);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const response = await fetch(url, options);
|
|
42
|
+
|
|
43
|
+
if (!response.ok) {
|
|
44
|
+
const errorText = await response.text();
|
|
45
|
+
let errorMessage;
|
|
46
|
+
try {
|
|
47
|
+
const errorJson = JSON.parse(errorText);
|
|
48
|
+
errorMessage = errorJson.errorMessage || errorJson.error || errorText;
|
|
49
|
+
} catch (e) {
|
|
50
|
+
errorMessage = errorText;
|
|
51
|
+
}
|
|
52
|
+
throw new Error(errorMessage || `HTTP ${response.status}: ${response.statusText}`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Handle empty responses (DELETE, PUT requests may return 204 No Content)
|
|
56
|
+
if (response.status === 204 || response.headers.get('content-length') === '0') {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const responseText = await response.text();
|
|
61
|
+
if (!responseText) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return JSON.parse(responseText);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* ***************************** - create - *******************************
|
|
70
|
+
* Create a new organization
|
|
71
|
+
*
|
|
72
|
+
* @parameters:
|
|
73
|
+
* - organizationRepresentation: An object representing the organization
|
|
74
|
+
* - name: [required] (string) - Organization name
|
|
75
|
+
* - displayName: [optional] (string) - Display name
|
|
76
|
+
* - url: [optional] (string) - Organization URL
|
|
77
|
+
* - domains: [optional] (array) - List of domains
|
|
78
|
+
* - attributes: [optional] (object) - Custom attributes
|
|
79
|
+
*/
|
|
80
|
+
exports.create = function(organizationRepresentation) {
|
|
81
|
+
return kcAdminClientHandler.organizations.create(organizationRepresentation);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* ***************************** - find - *******************************
|
|
86
|
+
* Get all organizations in a realm
|
|
87
|
+
*
|
|
88
|
+
* @parameters:
|
|
89
|
+
* - filter: [optional] parameter for filtering
|
|
90
|
+
* - realm: (string, optional) - The realm name
|
|
91
|
+
* - search: (string, optional) - Search string
|
|
92
|
+
* - first: (number, optional) - First result index
|
|
93
|
+
* - max: (number, optional) - Maximum results
|
|
94
|
+
*/
|
|
95
|
+
exports.find = function(filter) {
|
|
96
|
+
return kcAdminClientHandler.organizations.find(filter);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* ***************************** - findOne - *******************************
|
|
101
|
+
* Get a specific organization by ID
|
|
102
|
+
*
|
|
103
|
+
* @parameters:
|
|
104
|
+
* - filter: parameter with organization ID
|
|
105
|
+
* - id: (string, required) - Organization ID
|
|
106
|
+
* - realm: (string, optional) - The realm name
|
|
107
|
+
*/
|
|
108
|
+
exports.findOne = function(filter) {
|
|
109
|
+
return kcAdminClientHandler.organizations.findOne(filter);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* ***************************** - update - *******************************
|
|
114
|
+
* Update an organization
|
|
115
|
+
*
|
|
116
|
+
* @parameters:
|
|
117
|
+
* - filter: parameter with organization ID
|
|
118
|
+
* - id: (string, required) - Organization ID
|
|
119
|
+
* - organizationRepresentation: Updated organization data
|
|
120
|
+
*/
|
|
121
|
+
exports.update = async function(filter, organizationRepresentation) {
|
|
122
|
+
const { id } = filter;
|
|
123
|
+
const current = await exports.findOne({ id });
|
|
124
|
+
const merged = {
|
|
125
|
+
...current,
|
|
126
|
+
...organizationRepresentation,
|
|
127
|
+
id,
|
|
128
|
+
name: organizationRepresentation?.name || current?.name
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
return await makeDirectApiCall('PUT', `/organizations/${id}`, merged);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* ***************************** - del - *******************************
|
|
136
|
+
* Delete an organization
|
|
137
|
+
*
|
|
138
|
+
* @parameters:
|
|
139
|
+
* - filter: parameter with organization ID
|
|
140
|
+
* - id: (string, required) - Organization ID
|
|
141
|
+
*/
|
|
142
|
+
exports.del = async function(filter) {
|
|
143
|
+
return kcAdminClientHandler.organizations.delById(filter);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* ***************************** - addMember - *******************************
|
|
148
|
+
* Add a user as member to an organization
|
|
149
|
+
*
|
|
150
|
+
* @parameters:
|
|
151
|
+
* - filter: parameter with organization ID and user ID
|
|
152
|
+
* - id: (string, required) - Organization ID
|
|
153
|
+
* - userId: (string, required) - User ID
|
|
154
|
+
*/
|
|
155
|
+
exports.addMember = async function(filter) {
|
|
156
|
+
const { id, userId } = filter;
|
|
157
|
+
return kcAdminClientHandler.organizations.addMember({
|
|
158
|
+
orgId: id,
|
|
159
|
+
userId
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* ***************************** - listMembers - *******************************
|
|
165
|
+
* List all members of an organization
|
|
166
|
+
*
|
|
167
|
+
* @parameters:
|
|
168
|
+
* - filter: parameter with organization ID
|
|
169
|
+
* - id: (string, required) - Organization ID
|
|
170
|
+
* - first: (number, optional) - First result
|
|
171
|
+
* - max: (number, optional) - Max results
|
|
172
|
+
*/
|
|
173
|
+
exports.listMembers = async function(filter) {
|
|
174
|
+
const { id, ...rest } = filter;
|
|
175
|
+
return kcAdminClientHandler.organizations.listMembers({
|
|
176
|
+
orgId: id,
|
|
177
|
+
...rest
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* ***************************** - delMember - *******************************
|
|
183
|
+
* Remove a member from an organization
|
|
184
|
+
*
|
|
185
|
+
* @parameters:
|
|
186
|
+
* - filter: parameter with organization ID and user ID
|
|
187
|
+
* - id: (string, required) - Organization ID
|
|
188
|
+
* - userId: (string, required) - User ID
|
|
189
|
+
*/
|
|
190
|
+
exports.delMember = async function(filter) {
|
|
191
|
+
const { id, userId } = filter;
|
|
192
|
+
return kcAdminClientHandler.organizations.delMember({
|
|
193
|
+
orgId: id,
|
|
194
|
+
userId
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* ***************************** - addIdentityProvider - *******************************
|
|
200
|
+
* Link an identity provider to an organization
|
|
201
|
+
*
|
|
202
|
+
* @parameters:
|
|
203
|
+
* - filter: parameter with organization ID and IDP alias
|
|
204
|
+
* - id: (string, required) - Organization ID
|
|
205
|
+
* - alias: (string, required) - Identity provider alias
|
|
206
|
+
*/
|
|
207
|
+
exports.addIdentityProvider = async function(filter) {
|
|
208
|
+
const { id, alias } = filter;
|
|
209
|
+
return kcAdminClientHandler.organizations.linkIdp({
|
|
210
|
+
orgId: id,
|
|
211
|
+
alias
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* ***************************** - listIdentityProviders - *******************************
|
|
217
|
+
* List identity providers linked to an organization
|
|
218
|
+
*
|
|
219
|
+
* @parameters:
|
|
220
|
+
* - filter: parameter with organization ID
|
|
221
|
+
* - id: (string, required) - Organization ID
|
|
222
|
+
*/
|
|
223
|
+
exports.listIdentityProviders = async function(filter) {
|
|
224
|
+
const { id } = filter;
|
|
225
|
+
return kcAdminClientHandler.organizations.listIdentityProviders({ orgId: id });
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* ***************************** - delIdentityProvider - *******************************
|
|
230
|
+
* Unlink an identity provider from an organization
|
|
231
|
+
*
|
|
232
|
+
* @parameters:
|
|
233
|
+
* - filter: parameter with organization ID and IDP alias
|
|
234
|
+
* - id: (string, required) - Organization ID
|
|
235
|
+
* - alias: (string, required) - Identity provider alias
|
|
236
|
+
*/
|
|
237
|
+
exports.delIdentityProvider = async function(filter) {
|
|
238
|
+
const { id, alias } = filter;
|
|
239
|
+
return kcAdminClientHandler.organizations.unLinkIdp({
|
|
240
|
+
orgId: id,
|
|
241
|
+
alias
|
|
242
|
+
});
|
|
243
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **************************************************************************************************
|
|
3
|
+
* **************************************************************************************************
|
|
4
|
+
* The Server Info entity provides information about the Keycloak server instance,
|
|
5
|
+
* including available providers, themes, system info, memory usage, and enabled features.
|
|
6
|
+
* This is useful for monitoring, diagnostics, and understanding server capabilities.
|
|
7
|
+
* **************************************************************************************************
|
|
8
|
+
* **************************************************************************************************
|
|
9
|
+
*/
|
|
10
|
+
let kcAdminClientHandler = null;
|
|
11
|
+
|
|
12
|
+
exports.setKcAdminClient = function(kcAdminClient) {
|
|
13
|
+
kcAdminClientHandler = kcAdminClient;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* ***************************** - getInfo - *******************************
|
|
18
|
+
* Get comprehensive server information
|
|
19
|
+
*
|
|
20
|
+
* @returns: Object containing:
|
|
21
|
+
* - systemInfo: System and environment information
|
|
22
|
+
* - memoryInfo: Memory usage statistics
|
|
23
|
+
* - profileInfo: Active profile information
|
|
24
|
+
* - themes: Available themes
|
|
25
|
+
* - providers: Available SPI providers
|
|
26
|
+
* - protocolMapperTypes: Available protocol mapper types
|
|
27
|
+
* - builtinProtocolMappers: Built-in protocol mappers
|
|
28
|
+
* - clientInstallations: Available client installation formats
|
|
29
|
+
* - componentTypes: Available component types
|
|
30
|
+
* - passwordPolicies: Available password policy types
|
|
31
|
+
* - enums: Various enum values used in Keycloak
|
|
32
|
+
* - cryptoInfo: Cryptographic information
|
|
33
|
+
*/
|
|
34
|
+
exports.getInfo = function() {
|
|
35
|
+
return kcAdminClientHandler.serverInfo.find();
|
|
36
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **************************************************************************************************
|
|
3
|
+
* **************************************************************************************************
|
|
4
|
+
* The User Profile entity (Keycloak 15+) allows managing declarative user profile configuration.
|
|
5
|
+
* This modern approach replaces the legacy attribute-based user management with a more
|
|
6
|
+
* structured and type-safe configuration model.
|
|
7
|
+
* **************************************************************************************************
|
|
8
|
+
* **************************************************************************************************
|
|
9
|
+
*/
|
|
10
|
+
let kcAdminClientHandler = null;
|
|
11
|
+
|
|
12
|
+
exports.setKcAdminClient = function(kcAdminClient) {
|
|
13
|
+
kcAdminClientHandler = kcAdminClient;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* ***************************** - getConfiguration - *******************************
|
|
18
|
+
* Get the user profile configuration for a realm
|
|
19
|
+
*
|
|
20
|
+
* @parameters:
|
|
21
|
+
* - filter: [optional] parameter
|
|
22
|
+
* - realm: (string, optional) - The realm name
|
|
23
|
+
* @returns: User profile configuration object with attributes, groups, etc.
|
|
24
|
+
*/
|
|
25
|
+
exports.getConfiguration = async function(filter) {
|
|
26
|
+
// Direct API call for better compatibility
|
|
27
|
+
const realm = filter?.realm || kcAdminClientHandler.realmName;
|
|
28
|
+
const baseUrl = kcAdminClientHandler.baseUrl;
|
|
29
|
+
const token = kcAdminClientHandler.accessToken;
|
|
30
|
+
|
|
31
|
+
const url = `${baseUrl}/admin/realms/${realm}/users/profile`;
|
|
32
|
+
|
|
33
|
+
const response = await fetch(url, {
|
|
34
|
+
method: 'GET',
|
|
35
|
+
headers: {
|
|
36
|
+
'Authorization': `Bearer ${token}`
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
if (!response.ok) {
|
|
41
|
+
const error = await response.text();
|
|
42
|
+
throw new Error(`Failed to get user profile: ${error}`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return response.json();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* ***************************** - updateConfiguration - *******************************
|
|
50
|
+
* Update the user profile configuration
|
|
51
|
+
*
|
|
52
|
+
* @parameters:
|
|
53
|
+
* - filter: [optional] parameter
|
|
54
|
+
* - realm: (string, optional) - The realm name
|
|
55
|
+
* - userProfileConfig: User profile configuration object
|
|
56
|
+
* - attributes: (array) - List of attribute configurations
|
|
57
|
+
* - name: (string) - Attribute name
|
|
58
|
+
* - displayName: (string) - Display name
|
|
59
|
+
* - validations: (object) - Validation rules
|
|
60
|
+
* - permissions: (object) - View/edit permissions
|
|
61
|
+
* - required: (object) - Required scopes
|
|
62
|
+
* - groups: (array) - Attribute groups
|
|
63
|
+
* - unmanagedAttributePolicy: (string) - Policy for unmanaged attributes
|
|
64
|
+
*/
|
|
65
|
+
exports.updateConfiguration = async function(filter, userProfileConfig) {
|
|
66
|
+
// Direct API call for better compatibility
|
|
67
|
+
const realm = filter?.realm || kcAdminClientHandler.realmName;
|
|
68
|
+
const baseUrl = kcAdminClientHandler.baseUrl;
|
|
69
|
+
const token = kcAdminClientHandler.accessToken;
|
|
70
|
+
|
|
71
|
+
const url = `${baseUrl}/admin/realms/${realm}/users/profile`;
|
|
72
|
+
|
|
73
|
+
const response = await fetch(url, {
|
|
74
|
+
method: 'PUT',
|
|
75
|
+
headers: {
|
|
76
|
+
'Content-Type': 'application/json',
|
|
77
|
+
'Authorization': `Bearer ${token}`
|
|
78
|
+
},
|
|
79
|
+
body: JSON.stringify(userProfileConfig)
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
if (!response.ok) {
|
|
83
|
+
const error = await response.text();
|
|
84
|
+
throw new Error(`Failed to update user profile: ${error}`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return response.status === 204 ? undefined : response.json();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* ***************************** - getMetadata - *******************************
|
|
92
|
+
* Get metadata about the user profile
|
|
93
|
+
* Returns information about available validators, attribute types, etc.
|
|
94
|
+
*
|
|
95
|
+
* @parameters:
|
|
96
|
+
* - filter: [optional] parameter
|
|
97
|
+
* - realm: (string, optional) - The realm name
|
|
98
|
+
* @returns: Metadata object with validators, attribute config, etc.
|
|
99
|
+
*/
|
|
100
|
+
exports.getMetadata = async function(filter) {
|
|
101
|
+
// Direct API call for better compatibility
|
|
102
|
+
const realm = filter?.realm || kcAdminClientHandler.realmName;
|
|
103
|
+
const baseUrl = kcAdminClientHandler.baseUrl;
|
|
104
|
+
const token = kcAdminClientHandler.accessToken;
|
|
105
|
+
|
|
106
|
+
const url = `${baseUrl}/admin/realms/${realm}/users/profile/metadata`;
|
|
107
|
+
|
|
108
|
+
const response = await fetch(url, {
|
|
109
|
+
method: 'GET',
|
|
110
|
+
headers: {
|
|
111
|
+
'Authorization': `Bearer ${token}`
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
if (!response.ok) {
|
|
116
|
+
const error = await response.text();
|
|
117
|
+
throw new Error(`Failed to get user profile metadata: ${error}`);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return response.json();
|
|
121
|
+
}
|