keycloak-api-manager 3.2.0 → 3.2.1

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.
@@ -0,0 +1,197 @@
1
+ const { expect } = require('chai');
2
+ const { getAdminClient } = require('./config');
3
+
4
+ describe('Identity Providers Handler', function () {
5
+ this.timeout(15000);
6
+ let client;
7
+ let testIdpAlias;
8
+ let testMapperId;
9
+
10
+ before(function () {
11
+ client = getAdminClient();
12
+ testIdpAlias = `test-idp-${Date.now()}`;
13
+ });
14
+
15
+ // ==================== IDENTITY PROVIDER CRUD ====================
16
+ describe('CRUD Operations', function () {
17
+ describe('create', function () {
18
+ it('should create an identity provider with valid representation', async function () {
19
+ const idpRep = {
20
+ alias: testIdpAlias,
21
+ displayName: 'Test IDP',
22
+ providerId: 'oidc',
23
+ enabled: true,
24
+ config: {
25
+ clientId: 'test-client',
26
+ clientSecret: 'test-secret',
27
+ tokenUrl: 'https://example.com/token',
28
+ authorizationUrl: 'https://example.com/authorize',
29
+ userInfoUrl: 'https://example.com/userinfo',
30
+ },
31
+ };
32
+
33
+ const result = await client.identityProviders.create(
34
+ { realm: 'test-realm' },
35
+ idpRep
36
+ );
37
+
38
+ expect(result).to.have.property('alias');
39
+ expect(result.alias).to.equal(testIdpAlias);
40
+ });
41
+ });
42
+
43
+ describe('find', function () {
44
+ it('should list all identity providers', async function () {
45
+ const idps = await client.identityProviders.find({ realm: 'test-realm' });
46
+
47
+ expect(idps).to.be.an('array');
48
+ expect(idps.some((idp) => idp.alias === testIdpAlias)).to.be.true;
49
+ });
50
+ });
51
+
52
+ describe('findOne', function () {
53
+ it('should find a specific identity provider by alias', async function () {
54
+ const idp = await client.identityProviders.findOne({
55
+ realm: 'test-realm',
56
+ alias: testIdpAlias,
57
+ });
58
+
59
+ expect(idp).to.exist;
60
+ expect(idp.alias).to.equal(testIdpAlias);
61
+ });
62
+ });
63
+
64
+ describe('update', function () {
65
+ it('should update identity provider attributes', async function () {
66
+ const updateRep = {
67
+ displayName: 'Updated IDP Name',
68
+ enabled: false,
69
+ };
70
+
71
+ await client.identityProviders.update(
72
+ { realm: 'test-realm', alias: testIdpAlias },
73
+ updateRep
74
+ );
75
+
76
+ const updated = await client.identityProviders.findOne({
77
+ realm: 'test-realm',
78
+ alias: testIdpAlias,
79
+ });
80
+
81
+ expect(updated.displayName).to.equal('Updated IDP Name');
82
+ expect(updated.enabled).to.be.false;
83
+ });
84
+ });
85
+ });
86
+
87
+ // ==================== IDENTITY PROVIDER MAPPERS ====================
88
+ describe('Mappers', function () {
89
+ describe('createMapper', function () {
90
+ it('should create a mapper for identity provider', async function () {
91
+ const mapperRep = {
92
+ name: 'test-mapper',
93
+ identityProviderAlias: testIdpAlias,
94
+ identityProviderMapper: 'oidc-user-attribute-idp-mapper',
95
+ config: {
96
+ 'user.attribute': 'email',
97
+ 'claim': 'email',
98
+ },
99
+ };
100
+
101
+ const result = await client.identityProviders.createMapper(
102
+ { realm: 'test-realm' },
103
+ mapperRep
104
+ );
105
+
106
+ expect(result).to.exist;
107
+ testMapperId = result.id;
108
+ });
109
+ });
110
+
111
+ describe('findMappers', function () {
112
+ it('should find all mappers for identity provider', async function () {
113
+ const mappers = await client.identityProviders.findMappers({
114
+ realm: 'test-realm',
115
+ alias: testIdpAlias,
116
+ });
117
+
118
+ expect(mappers).to.be.an('array');
119
+ });
120
+ });
121
+
122
+ describe('findOneMapper', function () {
123
+ it('should find a specific mapper by id', async function () {
124
+ if (testMapperId) {
125
+ const mapper = await client.identityProviders.findOneMapper({
126
+ realm: 'test-realm',
127
+ alias: testIdpAlias,
128
+ id: testMapperId,
129
+ });
130
+
131
+ expect(mapper).to.exist;
132
+ }
133
+ });
134
+ });
135
+
136
+ describe('delMapper', function () {
137
+ it('should delete a mapper', async function () {
138
+ if (testMapperId) {
139
+ await client.identityProviders.delMapper({
140
+ realm: 'test-realm',
141
+ alias: testIdpAlias,
142
+ id: testMapperId,
143
+ });
144
+
145
+ // Verify deleted
146
+ }
147
+ });
148
+ });
149
+ });
150
+
151
+ // ==================== IDENTITY PROVIDER MANAGEMENT ====================
152
+ describe('Management Operations', function () {
153
+ describe('findFactory', function () {
154
+ it('should retrieve identity provider factory', async function () {
155
+ try {
156
+ const factory = await client.identityProviders.findFactory({
157
+ realm: 'test-realm',
158
+ providerId: 'oidc',
159
+ });
160
+
161
+ expect(factory).to.exist;
162
+ } catch (err) {
163
+ // Factory endpoint might not be available
164
+ }
165
+ });
166
+ });
167
+
168
+ describe('listPermissions', function () {
169
+ it('should list identity provider permissions', async function () {
170
+ try {
171
+ const perms = await client.identityProviders.listPermissions({
172
+ realm: 'test-realm',
173
+ alias: testIdpAlias,
174
+ });
175
+
176
+ expect(perms).to.be.an('object');
177
+ } catch (err) {
178
+ // Permissions might not be enabled
179
+ }
180
+ });
181
+ });
182
+ });
183
+
184
+ // ==================== CLEANUP ====================
185
+ after(async function () {
186
+ try {
187
+ if (testIdpAlias) {
188
+ await client.identityProviders.del({
189
+ realm: 'test-realm',
190
+ alias: testIdpAlias,
191
+ });
192
+ }
193
+ } catch (err) {
194
+ console.error('Cleanup error:', err.message);
195
+ }
196
+ });
197
+ });
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Mocha Root Setup Hook
3
+ * Orchestrates Docker container lifecycle and Keycloak initialization
4
+ */
5
+
6
+ const { startDocker, stopDocker, waitForHealthy } = require('./docker-helpers');
7
+ const { initializeAdminClient, setupTestRealm, cleanupTestRealm } = require('./config');
8
+
9
+ // Root hook plugin for Mocha
10
+ exports.mochaHooks = {
11
+ async beforeAll() {
12
+ this.timeout(120000); // 2 minutes max for setup
13
+
14
+ console.log('\n========== TEST SETUP ==========');
15
+ console.log('Starting Docker containers...');
16
+
17
+ try {
18
+ // Start Docker Compose
19
+ await startDocker();
20
+
21
+ // Wait for services to be healthy
22
+ await waitForHealthy();
23
+
24
+ // Initialize Keycloak admin client
25
+ await initializeAdminClient();
26
+
27
+ // Setup test realm
28
+ await setupTestRealm();
29
+
30
+ console.log('✓ Test environment ready\n');
31
+ } catch (err) {
32
+ console.error('✗ Test setup failed:', err.message);
33
+ throw err;
34
+ }
35
+ },
36
+
37
+ async afterAll() {
38
+ this.timeout(60000); // 1 minute max for teardown
39
+
40
+ console.log('\n========== TEST TEARDOWN ==========');
41
+
42
+ try {
43
+ // Cleanup Keycloak test realm
44
+ await cleanupTestRealm();
45
+
46
+ // Stop Docker Compose
47
+ await stopDocker();
48
+
49
+ console.log('✓ Test environment cleaned up\n');
50
+ } catch (err) {
51
+ console.error('✗ Test teardown failed:', err.message);
52
+ // Don't throw during cleanup to allow partial cleanup
53
+ }
54
+ },
55
+ };
@@ -0,0 +1,349 @@
1
+ const { expect } = require('chai');
2
+ const { getAdminClient } = require('./config');
3
+
4
+ describe('Realms Handler', function () {
5
+ this.timeout(15000);
6
+ let client;
7
+ let testRealmName;
8
+ let testGroupId;
9
+
10
+ before(function () {
11
+ client = getAdminClient();
12
+ testRealmName = `test-realm-${Date.now()}`;
13
+ });
14
+
15
+ // ==================== REALM CRUD ====================
16
+ describe('CRUD Operations', function () {
17
+ describe('create', function () {
18
+ it('should create a realm with minimal representation', async function () {
19
+ const result = await client.realms.create({
20
+ realm: testRealmName,
21
+ enabled: true,
22
+ });
23
+
24
+ expect(result).to.have.property('id');
25
+ expect(result.realm).to.equal(testRealmName);
26
+ });
27
+
28
+ it('should fail creating duplicate realm', async function () {
29
+ try {
30
+ await client.realms.create({
31
+ realm: testRealmName,
32
+ enabled: true,
33
+ });
34
+ expect.fail('Should have thrown an error for duplicate realm');
35
+ } catch (err) {
36
+ expect(err).to.exist;
37
+ }
38
+ });
39
+
40
+ it('should fail with missing realm name', async function () {
41
+ try {
42
+ await client.realms.create({
43
+ displayName: 'Invalid',
44
+ });
45
+ expect.fail('Should have thrown an error');
46
+ } catch (err) {
47
+ expect(err).to.exist;
48
+ }
49
+ });
50
+ });
51
+
52
+ describe('find', function () {
53
+ it('should list all realms', async function () {
54
+ const realms = await client.realms.find();
55
+
56
+ expect(realms).to.be.an('array');
57
+ expect(realms.length).to.be.greaterThan(0);
58
+ expect(realms.some((r) => r.realm === testRealmName)).to.be.true;
59
+ });
60
+ });
61
+
62
+ describe('findOne', function () {
63
+ it('should find a specific realm by name', async function () {
64
+ const realm = await client.realms.findOne({ realm: testRealmName });
65
+
66
+ expect(realm).to.exist;
67
+ expect(realm.realm).to.equal(testRealmName);
68
+ expect(realm.enabled).to.be.true;
69
+ });
70
+
71
+ it('should return null for non-existent realm', async function () {
72
+ try {
73
+ await client.realms.findOne({ realm: 'non-existent-realm-xyz' });
74
+ expect.fail('Should have thrown an error');
75
+ } catch (err) {
76
+ expect(err).to.exist;
77
+ }
78
+ });
79
+ });
80
+
81
+ describe('update', function () {
82
+ it('should update realm configuration', async function () {
83
+ const updateRep = {
84
+ displayName: 'Updated Display Name',
85
+ loginTheme: 'keycloak',
86
+ accessCodeLifespan: 60,
87
+ };
88
+
89
+ await client.realms.update({ realm: testRealmName }, updateRep);
90
+
91
+ const updated = await client.realms.findOne({ realm: testRealmName });
92
+ expect(updated.displayName).to.equal('Updated Display Name');
93
+ expect(updated.loginTheme).to.equal('keycloak');
94
+ });
95
+
96
+ it('should update realm enabled status', async function () {
97
+ await client.realms.update({ realm: testRealmName }, { enabled: false });
98
+
99
+ const updated = await client.realms.findOne({ realm: testRealmName });
100
+ expect(updated.enabled).to.be.false;
101
+ });
102
+ });
103
+ });
104
+
105
+ // ==================== REALM CONFIGURATION ====================
106
+ describe('Configuration Operations', function () {
107
+ describe('export', function () {
108
+ it('should export realm configuration', async function () {
109
+ const exported = await client.realms.export({
110
+ realm: testRealmName,
111
+ exportClients: true,
112
+ exportGroupsAndRoles: true,
113
+ });
114
+
115
+ expect(exported).to.be.an('object');
116
+ expect(exported.realm).to.equal(testRealmName);
117
+ });
118
+ });
119
+
120
+ describe('getKeys', function () {
121
+ it('should retrieve realm keys', async function () {
122
+ const keys = await client.realms.getKeys({ realm: testRealmName });
123
+
124
+ expect(keys).to.be.an('object');
125
+ expect(keys).to.have.property('keys');
126
+ expect(keys.keys).to.be.an('array');
127
+ });
128
+ });
129
+
130
+ describe('getClientSessionStats', function () {
131
+ it('should retrieve client session statistics', async function () {
132
+ const stats = await client.realms.getClientSessionStats({ realm: testRealmName });
133
+
134
+ expect(stats).to.be.an('array');
135
+ });
136
+ });
137
+ });
138
+
139
+ // ==================== EVENT CONFIGURATION ====================
140
+ describe('Event Management', function () {
141
+ describe('getConfigEvents', function () {
142
+ it('should retrieve event configuration', async function () {
143
+ const config = await client.realms.getConfigEvents({ realm: testRealmName });
144
+
145
+ expect(config).to.be.an('object');
146
+ });
147
+ });
148
+
149
+ describe('updateConfigEvents', function () {
150
+ it('should update event configuration', async function () {
151
+ const eventConfig = {
152
+ eventsEnabled: true,
153
+ eventsListeners: ['jboss-logging'],
154
+ enabledEventTypes: ['LOGIN', 'LOGOUT'],
155
+ };
156
+
157
+ await client.realms.updateConfigEvents({ realm: testRealmName }, eventConfig);
158
+
159
+ const updated = await client.realms.getConfigEvents({ realm: testRealmName });
160
+ expect(updated.eventsEnabled).to.be.true;
161
+ });
162
+ });
163
+
164
+ describe('findEvents', function () {
165
+ it('should retrieve realm events', async function () {
166
+ const events = await client.realms.findEvents({
167
+ realm: testRealmName,
168
+ max: 10,
169
+ });
170
+
171
+ expect(events).to.be.an('array');
172
+ });
173
+ });
174
+
175
+ describe('findAdminEvents', function () {
176
+ it('should retrieve admin events', async function () {
177
+ const events = await client.realms.findAdminEvents({
178
+ realm: testRealmName,
179
+ max: 10,
180
+ });
181
+
182
+ expect(events).to.be.an('array');
183
+ });
184
+ });
185
+
186
+ describe('clearEvents', function () {
187
+ it('should clear events for realm', async function () {
188
+ await client.realms.clearEvents({ realm: testRealmName });
189
+ // Verify no error thrown
190
+ });
191
+ });
192
+
193
+ describe('clearAdminEvents', function () {
194
+ it('should clear admin events for realm', async function () {
195
+ await client.realms.clearAdminEvents({ realm: testRealmName });
196
+ // Verify no error thrown
197
+ });
198
+ });
199
+ });
200
+
201
+ // ==================== DEFAULT GROUPS ====================
202
+ describe('Default Groups Management', function () {
203
+ before(async function () {
204
+ // Create a test group first
205
+ const group = await client.groups.create(
206
+ { realm: testRealmName },
207
+ { name: 'test-default-group' }
208
+ );
209
+ testGroupId = group.id;
210
+ });
211
+
212
+ describe('getDefaultGroups', function () {
213
+ it('should retrieve default groups for realm', async function () {
214
+ const groups = await client.realms.getDefaultGroups({
215
+ realm: testRealmName,
216
+ });
217
+
218
+ expect(groups).to.be.an('array');
219
+ });
220
+ });
221
+
222
+ describe('addDefaultGroup', function () {
223
+ it('should add a group to default groups', async function () {
224
+ await client.realms.addDefaultGroup({
225
+ realm: testRealmName,
226
+ id: testGroupId,
227
+ });
228
+
229
+ const defaultGroups = await client.realms.getDefaultGroups({
230
+ realm: testRealmName,
231
+ });
232
+
233
+ expect(defaultGroups.some((g) => g.id === testGroupId)).to.be.true;
234
+ });
235
+ });
236
+
237
+ describe('removeDefaultGroup', function () {
238
+ it('should remove a group from default groups', async function () {
239
+ await client.realms.removeDefaultGroup({
240
+ realm: testRealmName,
241
+ id: testGroupId,
242
+ });
243
+
244
+ const defaultGroups = await client.realms.getDefaultGroups({
245
+ realm: testRealmName,
246
+ });
247
+
248
+ expect(defaultGroups.some((g) => g.id === testGroupId)).to.be.false;
249
+ });
250
+ });
251
+
252
+ describe('getGroupByPath', function () {
253
+ it('should retrieve group by path', async function () {
254
+ const group = await client.realms.getGroupByPath({
255
+ realm: testRealmName,
256
+ path: '/test-default-group',
257
+ });
258
+
259
+ expect(group).to.exist;
260
+ expect(group.name).to.equal('test-default-group');
261
+ });
262
+ });
263
+ });
264
+
265
+ // ==================== CLIENT REGISTRATION ====================
266
+ describe('Client Registration', function () {
267
+ let initialAccessTokenId;
268
+
269
+ describe('createClientsInitialAccess', function () {
270
+ it('should create initial access token for client registration', async function () {
271
+ const result = await client.realms.createClientsInitialAccess(
272
+ { realm: testRealmName },
273
+ { count: 1, expiration: 3600 }
274
+ );
275
+
276
+ expect(result).to.have.property('token');
277
+ initialAccessTokenId = result.id;
278
+ });
279
+ });
280
+
281
+ describe('getClientsInitialAccess', function () {
282
+ it('should list all initial access tokens', async function () {
283
+ const tokens = await client.realms.getClientsInitialAccess({
284
+ realm: testRealmName,
285
+ });
286
+
287
+ expect(tokens).to.be.an('array');
288
+ expect(tokens.some((t) => t.id === initialAccessTokenId)).to.be.true;
289
+ });
290
+ });
291
+
292
+ describe('delClientsInitialAccess', function () {
293
+ it('should delete an initial access token', async function () {
294
+ await client.realms.delClientsInitialAccess({
295
+ realm: testRealmName,
296
+ id: initialAccessTokenId,
297
+ });
298
+
299
+ const tokens = await client.realms.getClientsInitialAccess({
300
+ realm: testRealmName,
301
+ });
302
+
303
+ expect(tokens.some((t) => t.id === initialAccessTokenId)).to.be.false;
304
+ });
305
+ });
306
+
307
+ describe('getClientRegistrationPolicyProviders', function () {
308
+ it('should retrieve client registration policy providers', async function () {
309
+ const providers = await client.realms.getClientRegistrationPolicyProviders({
310
+ realm: testRealmName,
311
+ });
312
+
313
+ expect(providers).to.be.an('array');
314
+ });
315
+ });
316
+ });
317
+
318
+ // ==================== REALM MANAGEMENT ====================
319
+ describe('Realm Management', function () {
320
+ describe('logoutAll', function () {
321
+ it('should logout all users in realm', async function () {
322
+ await client.realms.logoutAll({ realm: testRealmName });
323
+ // Verify no error thrown
324
+ });
325
+ });
326
+
327
+ describe('pushRevocation', function () {
328
+ it('should push revocation policy to realm', async function () {
329
+ await client.realms.pushRevocation({ realm: testRealmName });
330
+ // Verify no error thrown
331
+ });
332
+ });
333
+ });
334
+
335
+ // ==================== CLEANUP ====================
336
+ after(async function () {
337
+ try {
338
+ // Cleanup test group
339
+ if (testGroupId) {
340
+ await client.groups.del({ realm: testRealmName, id: testGroupId });
341
+ }
342
+ // Delete test realm
343
+ await client.realms.del({ realm: testRealmName });
344
+ } catch (err) {
345
+ // Ignore if not found
346
+ console.error('Cleanup error:', err.message);
347
+ }
348
+ });
349
+ });