keycloak-admin 1.1.3 → 1.1.5

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.
data/README.md CHANGED
@@ -1,748 +1,756 @@
1
-
2
- # Keycloak Admin Ruby
3
-
4
- Ruby client that acts as a client for the Keycloak REST API.
5
- This gem basically acts as an url builder using `http-client` to get responses and serialize them into _representation_ objects.
6
-
7
- _Warning: This beta gem is currently used for personal use. Most Keycloak Admin features are not implemented yet._
8
-
9
- ## Install
10
-
11
- This gem *does not* require Rails.
12
- For example, using `bundle`, add this line to your Gemfile.
13
-
14
- ```ruby
15
- gem "keycloak-admin", "1.1.3"
16
- ```
17
-
18
- ## Login
19
-
20
- To login on Keycloak's Admin API, you first need to setup a client.
21
-
22
- Go to your realm administration page and open `Clients`. Then, click on the `Create` button.
23
- On the first screen, enter:
24
- * `Client ID`: _e.g. my-app-admin-client_
25
- * `Client Protocol`: select `openid-connect`
26
- * `Root URL`: let it blank
27
-
28
- The next screen must be configured depending on how you want to authenticate:
29
- * `username/password` with a user of the realm
30
- * `Direct Access Grants` with a service account
31
-
32
- ### Login with username/password (realm user)
33
-
34
- * In Keycloak, during the client setup:
35
- * `Access Type`: `public` or `confidential`
36
- * `Service Accounts Enabled` (when `confidential`): `false`
37
- * After saving your client, if you have chosen a `confidential` client, go to `Credentials` tab and copy the `Client Secret`
38
-
39
- * In Keycloak, create a dedicated user (and her credentials):
40
- * Go to `Users`
41
- * Click on the `Add user` button
42
- * Setup her mandatory information, depending on your realm's configuration
43
- * On the `Credentials` tab, create her a password (toggle off `Temporary`)
44
-
45
- * In this gem's configuration (see Section `Configuration`):
46
- * Setup `username` and `password` according to your user's configuration
47
- * Setup `client_id` with your `Client ID` (_e.g. my-app-admin-client_)
48
- * If your client is `confidential`, copy its Client Secret to `client_secret`
49
-
50
- ### Login with `Direct Access Grants` (Service account)
51
-
52
- Using a service account to use the REST Admin API does not require to create a dedicated user (https://www.keycloak.org/docs/latest/server_admin/#_service_accounts).
53
-
54
- * In Keycloak, during the client setup:
55
- * `Access Type`: `confidential`
56
- * `Service Accounts Enabled` (when `confidential`): `true`
57
- * `Standard Flow Enabled`: `false`
58
- * `Implicit Flow Enabled`: `false`
59
- * `Direct Access Grants Enabled`: `true`
60
- * After saving this client
61
- * open the `Service Account Roles` and add relevant `realm-management.` client's roles. For instance: `view-users` if you want to search for users using this gem.
62
- * open the `Credentials` tab and copy the `Client Secret`
63
-
64
- * In this gem's configuration (see Section `Configuration`):
65
- * Set `use_service_account` to `true`
66
- * Setup `client_id` with your `Client ID` (_e.g. my-app-admin-client_)
67
- * Copy its Client Secret to `client_secret`
68
-
69
- ## Configuration
70
-
71
- To configure this gem, call `KeycloakAdmin.configure`.
72
- For instance, to configure this gem based on environment variables, write (and load if required) a `keycloak_admin.rb`:
73
- ```ruby
74
- KeycloakAdmin.configure do |config|
75
- config.use_service_account = false
76
- config.server_url = ENV["KEYCLOAK_SERVER_URL"]
77
- config.server_domain = ENV["KEYCLOAK_SERVER_DOMAIN"]
78
- config.client_id = ENV["KEYCLOAK_ADMIN_CLIENT_ID"]
79
- config.client_realm_name = ENV["KEYCLOAK_REALM_ID"]
80
- config.username = ENV["KEYCLOAK_ADMIN_USER"]
81
- config.password = ENV["KEYCLOAK_ADMIN_PASSWORD"]
82
- config.logger = Rails.logger
83
-
84
- # You configure RestClient to your liking – see https://github.com/rest-client/rest-client/blob/master/lib/restclient/request.rb for available options.
85
- config.rest_client_options = { timeout: 5 }
86
- end
87
- ```
88
- This example is autoloaded in a Rails environment.
89
-
90
- ### Overall configuration options
91
-
92
- All options have a default value. However, all of them can be changed in your initializer file.
93
-
94
- | Option | Default Value | Type | Required? | Description | Example |
95
- | ---- | ----- | ------ | ----- | ------ | ----- |
96
- | `server_url` | `nil` | String | Required | The base url where your Keycloak server is located (a URL that starts with `http` and that ends with `/auth`). This value can be retrieved in your Keycloak client configuration. | `http://auth:8080/auth`
97
- | `server_domain` | `nil`| String | Required | Public domain that identify your authentication cookies. | `auth.service.io` |
98
- | `client_realm_name` | `""`| String | Required | Name of the realm that contains the admin client. | `master` |
99
- | `client_id` | `admin-cli`| String | Required | Client that should be used to access admin capabilities. | `api-cli` |
100
- | `client_secret` | `nil`| String | Optional | If your client is `confidential`, this parameter must be specified. | `4e3c481c-f823-4a6a-b8a7-bf8c86e3eac3` |
101
- | `use_service_account` | `true` | Boolean | Required | `true` if the connection to the client uses a Service Account. `false` if the connection to the client uses a username/password credential. | `false` |
102
- | `username` | `nil`| String | Optional | Username to access the Admin REST API. Recommended if `user_service_account` is set to `false`. | `mummy` |
103
- | `password` | `nil`| String | Optional | Clear password to access the Admin REST API. Recommended if `user_service_account` is set to `false`. | `bobby` |
104
- | `logger` | `Logger.new(STDOUT)`| Logger | Optional | The logger used by `keycloak-admin` | `Rails.logger` | 
105
- | `rest_client_options` | `{}`| Hash | Optional | Options to pass to `RestClient` | `{ timeout: 5 }` | 
106
-
107
-
108
- ## Use Cases
109
-
110
- ### Supported features
111
-
112
- * Get an access token
113
- * Create/update/get/delete a user
114
- * Get list of users, search for user(s)
115
- * Reset credentials
116
- * Impersonate a user
117
- * Exchange a configurable token
118
- * Get list of clients, or find a client by its id or client_id
119
- * Create, update, and delete clients
120
- * Get list of groups, create/save a group
121
- * Get list of roles, save a role
122
- * Get list of realms, save/update/delete a realm
123
- * Get list of client role mappings for a user/group
124
- * Get list of members of a group
125
- * Get list of groups that have a specific role assigned
126
- * Get list of realm-roles assigned to a group, add a realm-role to a group
127
- * Save client role mappings for a user/group
128
- * Save realm-level role mappings for a user/group
129
- * Add a Group on a User
130
- * Remove a Group from a User
131
- * Get list of Identity Providers
132
- * Create Identity Providers
133
- * Link/Unlink users to federated identity provider brokers
134
- * Execute actions emails
135
- * Send forgot passsword mail
136
- * Client Authorization, create, update, get, delete Resource, Scope, Policy, Permission, Policy Enforcer
137
-
138
- ### Get an access token
139
-
140
- Returns an instance of `KeycloakAdmin::TokenRepresentation`.
141
-
142
- ```ruby
143
- KeycloakAdmin.realm("a_realm").token.get
144
- ```
145
-
146
- ### Get a user from its identifier
147
-
148
- Returns an instance of `KeycloakAdmin::UserRepresentation` or `nil` when this user does not exist.
149
-
150
- ```ruby
151
- user_id = "95985b21-d884-4bbd-b852-cb8cd365afc2"
152
- KeycloakAdmin.realm("a_realm").users.get(user_id)
153
- ```
154
-
155
- ### Search for users
156
-
157
- Returns an array of `KeycloakAdmin::UserRepresentation`.
158
-
159
- According to [the documentation](https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_users_resource):
160
- * When providing a `String` parameter, this produces an arbitrary search string
161
- * When providing a `Hash`, you can search for specific field (_e.g_ an email)
162
-
163
- ```ruby
164
- KeycloakAdmin.realm("a_realm").users.search("a_username_or_an_email")
165
- ```
166
-
167
- ```ruby
168
- KeycloakAdmin.realm("a_realm").users.search({ email: "john@doe.com" })
169
- ```
170
-
171
- ### List all users in a realm
172
-
173
- Returns an array of `KeycloakAdmin::UserRepresentation`.
174
-
175
- ```ruby
176
- KeycloakAdmin.realm("a_realm").users.list
177
- ```
178
-
179
- ### Save a user
180
-
181
- Returns the provided `user`, which must be of type `KeycloakAdmin::UserRepresentation`.
182
-
183
- ```ruby
184
- KeycloakAdmin.realm("a_realm").users.save(user)
185
- ```
186
-
187
- ### Update a user
188
-
189
- If you want to update its entire entity. To update some specific attributes, provide an object implementing `to_json`, such as a `Hash`.
190
-
191
- ```ruby
192
- KeycloakAdmin.realm("a_realm").users.update("05c135c6-5ad8-4e17-b1fa-635fc089fd71", {
193
- email: "hello@gmail.com",
194
- username: "hello",
195
- first_name: "Jean",
196
- last_name: "Dupond"
197
- })
198
- ```
199
-
200
- Attention point: Since Keycloak 24.0.4, when updating a user, all the writable profile attributes must be passed, otherwise they will be removed. (https://www.keycloak.org/docs/24.0.4/upgrading/)
201
-
202
- ### Delete a user
203
-
204
- ```ruby
205
- KeycloakAdmin.realm("a_realm").users.delete(user_id)
206
- ```
207
-
208
- ### Create and save a user with password and a locale
209
-
210
- Returns the created user of type `KeycloakAdmin::UserRepresentation`.
211
-
212
- ```ruby
213
- username = "pioupioux"
214
- email = "pioupioux@email.com"
215
- password = "acme0"
216
- email_verified = true
217
- locale = "en"
218
- KeycloakAdmin.realm("a_realm").users.create!(username, email, password, email_verified, locale)
219
- ```
220
-
221
- ### Reset a password
222
-
223
- ```ruby
224
- user_id = "95985b21-d884-4bbd-b852-cb8cd365afc2"
225
- new_password = "coco"
226
- KeycloakAdmin.realm("a_realm").users.update_password(user_id, new_password)
227
- ```
228
-
229
- ### Impersonate a password directly
230
-
231
- Returns an instance of `KeycloakAdmin::ImpersonationRepresentation`.
232
-
233
- ```ruby
234
- user_id = "95985b21-d884-4bbd-b852-cb8cd365afc2"
235
- KeycloakAdmin.realm("a_realm").users.impersonate(user_id)
236
- ```
237
-
238
- ### Impersonate a password indirectly
239
-
240
- To have enough information to execute an impersonation by yourself, `get_redirect_impersonation` returns an instance of `KeycloakAdmin::ImpersonationRedirectionRepresentation`.
241
-
242
- ```ruby
243
- user_id = "95985b21-d884-4bbd-b852-cb8cd365afc2"
244
- KeycloakAdmin.realm("a_realm").users.get_redirect_impersonation(user_id)
245
- ```
246
-
247
- ### Exchange a configurable token
248
-
249
- *Requires your Keycloak server to have deployed the Custom REST API `configurable-token`* (https://github.com/looorent/keycloak-configurable-token-api)
250
- Returns an instance of `KeycloakAdmin::TokenRepresentation`.
251
-
252
- ```ruby
253
- user_access_token = "abqsdofnqdsogn"
254
- token_lifespan_in_seconds = 20
255
- KeycloakAdmin.realm("a_realm").configurable_token.exchange_with(user_access_token, token_lifespan_in_seconds)
256
- ```
257
-
258
- ### Get list of realms
259
-
260
- Returns an array of `KeycloakAdmin::RealmRepresentation`.
261
-
262
- ```ruby
263
- KeycloakAdmin.realm("master").list
264
- ```
265
-
266
- ### Save a realm
267
-
268
- Takes `realm` of type `KeycloakAdmin::RealmRepresentation`, or an object implementing `to_json`, such as a `Hash`.
269
-
270
- ```ruby
271
- KeycloakAdmin.realm(nil).save(realm)
272
- ```
273
-
274
- ### Update a realm
275
-
276
- If you want to update its entire entity. To update some specific attributes, provide an object implementing `to_json`, such as a `Hash`.
277
-
278
- ```ruby
279
- KeycloakAdmin.realm("a_realm").update({
280
- smtpServer: { host: 'test_host' }
281
- })
282
- ```
283
-
284
- ### Delete a realm
285
-
286
- ```ruby
287
- KeycloakAdmin.realm("a_realm").delete
288
- ```
289
-
290
- ### Get list of clients in a realm
291
-
292
- Returns an array of `KeycloakAdmin::ClientRepresentation` or a single `KeycloakAdmin::ClientRepresentation`
293
-
294
- Finding a client by its `client_id` is a somewhat slow operation, as it requires fetching all clients and then filtering. Keycloak's API does not support fetching a client by its `client_id` directly.
295
-
296
- ```ruby
297
- KeycloakAdmin.realm("a_realm").clients.list
298
- KeycloakAdmin.realm("a_realm").clients.get(id) # id is Keycloak's database id, not the client_id
299
- KeycloakAdmin.realm("a_realm").clients.find_by_client_id(client_id)
300
- ```
301
-
302
- ### Updating a client
303
-
304
- ```ruby
305
- my_client = KeycloakAdmin.realm("a_realm").clients.get(id)
306
-
307
- my_client.name = "My new client name"
308
- my_client.description = "This is a new description"
309
- my_client.redirect_uris << "https://www.example.com/auth/callback"
310
-
311
- KeycloakAdmin.realm("a_realm").clients.update(client) # Returns the updated client
312
- ```
313
-
314
- ### Get list of groups in a realm
315
-
316
- Returns an array of `KeycloakAdmin::GroupRepresentation`.
317
-
318
- ```ruby
319
- KeycloakAdmin.realm("a_realm").groups.list
320
- ```
321
-
322
- ### Search for a group
323
-
324
- Returns an array of `KeycloakAdmin::GroupRepresentation`.
325
-
326
- According to [the documentation](https://www.keycloak.org/docs-api/22.0.1/rest-api/index.html#_groups):
327
- * When providing a `String` parameter, this produces an arbitrary search string
328
- * When providing a `Hash`, you can specify other fields (_e.g_ q, max, first)
329
-
330
- ```ruby
331
- KeycloakAdmin.realm("a_realm").groups.search("MyGroup")
332
- ```
333
-
334
- ```ruby
335
- KeycloakAdmin.realm("a_realm").groups.search({query: "MyGroup", exact: true, max: 1})
336
- ```
337
-
338
- ### Save a group
339
-
340
- Returns the id of saved `group` provided, which must be of type `KeycloakAdmin::GroupRepresentation`.
341
-
342
- ```ruby
343
- KeycloakAdmin.realm("a_realm").groups.save(group)
344
- ```
345
-
346
- ### Create and save a group with a name and path
347
-
348
- Returns the id of created group.
349
-
350
- ```ruby
351
- group_name = "test"
352
- group_path = "/top"
353
- group_id = KeycloakAdmin.realm("a_realm").groups.create!(group_name, group_path)
354
- ```
355
-
356
- ### Create a new subgroup of an existing group
357
-
358
- Create a new group as the child of an existing group.
359
-
360
- ```ruby
361
- parent_id = "7686af34-204c-4515-8122-78d19febbf6e"
362
- group_name = "test"
363
- sub_group_id = KeycloakAdmin.realm("a_realm").groups.create_subgroup!(parent_id, group_name)
364
- ```
365
-
366
- ### Get list of members of a group
367
-
368
- Returns an array of `KeycloakAdmin::UserRepresentation`.
369
-
370
- ```ruby
371
- KeycloakAdmin.realm("a_realm").group("group_id").members
372
- ```
373
-
374
- You can specify paging with `first` and `max`:
375
-
376
- ```ruby
377
- KeycloakAdmin.realm("a_realm").group("group_id").members(first:0, max:100)
378
- ```
379
-
380
- ### Get list of groups that have a specific role assigned
381
-
382
- Returns an array of `KeycloakAdmin::GroupRepresentation`
383
-
384
- ```ruby
385
- KeycloakAdmin.realm("a_realm").roles.list_groups("role_name")
386
- ```
387
-
388
- ### Get list of realm-roles assigned to a group
389
-
390
- Returns an array of `KeycloakAdmin::RoleRepresentation`
391
-
392
- ```ruby
393
- KeycloakAdmin.realm("a_realm").groups.get_realm_level_roles("group_id")
394
- ```
395
-
396
- ### Add a realm-role to a group
397
-
398
- Returns added `KeycloakAdmin::RoleRepresentation`
399
-
400
- ```ruby
401
- KeycloakAdmin.realm("a_realm").groups.add_realm_level_role_name!("group_id", "role_name")
402
- ```
403
-
404
- ### Get list of roles in a realm
405
-
406
- Returns an array of `KeycloakAdmin::RoleRepresentation`.
407
-
408
- ```ruby
409
- KeycloakAdmin.realm("a_realm").roles.list
410
- ```
411
-
412
- ### Save a role
413
-
414
- Takes `role`, which must be of type `KeycloakAdmin::RoleRepresentation`.
415
-
416
- ```ruby
417
- KeycloakAdmin.realm("a_realm").roles.save(role)
418
- ```
419
-
420
- ### Get list of client role mappings for a user/group
421
-
422
- Returns an array of `KeycloakAdmin::RoleRepresentation`.
423
-
424
- ```ruby
425
- user_id = "95985b21-d884-4bbd-b852-cb8cd365afc2"
426
- client_id = "1869e876-71b4-4de2-849e-66540db3a098"
427
- KeycloakAdmin.realm("a_realm").user(user_id).client_role_mappings(client_id).list_available
428
- ```
429
- or
430
- ```ruby
431
- group_id = "3a63b5c0-ef8a-47fd-86ed-b5fead18d9b8"
432
- client_id = "1869e876-71b4-4de2-849e-66540db3a098"
433
- KeycloakAdmin.realm("a_realm").group(group_id).client_role_mappings(client_id).list_available
434
- ```
435
-
436
- ### Save list of client role mappings for a user/group
437
-
438
- Takes `role_list`, which must be an array of type `KeycloakAdmin::RoleRepresentation`.
439
-
440
- ```ruby
441
- user_id = "95985b21-d884-4bbd-b852-cb8cd365afc2"
442
- client_id = "1869e876-71b4-4de2-849e-66540db3a098"
443
- KeycloakAdmin.realm("a_realm").user(user_id).client_role_mappings(client_id).save(role_list)
444
- ```
445
- or
446
- ```ruby
447
- group_id = "3a63b5c0-ef8a-47fd-86ed-b5fead18d9b8"
448
- client_id = "1869e876-71b4-4de2-849e-66540db3a098"
449
- KeycloakAdmin.realm("a_realm").group(group_id).client_role_mappings(client_id).save(role_list)
450
- ```
451
-
452
- ### Save list of realm-level role mappings for a user/group
453
-
454
- Takes `role_list`, which must be an array of type `KeycloakAdmin::RoleRepresentation`.
455
-
456
- ```ruby
457
- user_id = "95985b21-d884-4bbd-b852-cb8cd365afc2"
458
- KeycloakAdmin.realm("a_realm").user(user_id).role_mapper.save_realm_level(role_list)
459
- ```
460
- or
461
- ```ruby
462
- group_id = "3a63b5c0-ef8a-47fd-86ed-b5fead18d9b8"
463
- KeycloakAdmin.realm("a_realm").group(group_id).role_mapper.save_realm_level(role_list)
464
- ```
465
-
466
- ### Get list of identity providers
467
-
468
- Note: This client requires the `realm-management.view-identity-providers` role.
469
-
470
- Returns an array of `KeycloakAdmin::IdentityProviderRepresentation`.
471
-
472
- ```ruby
473
- KeycloakAdmin.realm("a_realm").identity_providers.list
474
- ```
475
-
476
- ### Manage [Client Authorization Resources & Scopes](https://www.keycloak.org/docs/latest/authorization_services/index.html#_resource_overview)
477
-
478
- In order to use authorization, you need to enable the client's `authorization_services_enabled` attribute.
479
-
480
- ```ruby
481
- client_id = "dummy-client"
482
- client = KeycloakAdmin.realm("realm_a").clients.find_by_client_id(client_id)
483
- client.authorization_services_enabled = true
484
- KeycloakAdmin.realm("a_realm").clients.update(client)
485
- ```
486
-
487
- ### Create a scope
488
-
489
- Returns added `KeycloakAdmin::ClientAuthzScopeRepresentation`
490
-
491
- ```ruby
492
- KeycloakAdmin.realm("a_realm").authz_scopes(client_id).create!("POST_1", "POST 1 scope description", "http://icon.url")
493
- ````
494
-
495
- ### Search for scope
496
-
497
- Returns array of `KeycloakAdmin::ClientAuthzScopeRepresentation`
498
-
499
- ```ruby
500
- KeycloakAdmin.realm("a_realm").authz_scopes(client.id).search("POST")
501
- ```
502
-
503
- ### Get one scope by its id
504
-
505
- Returns `KeycloakAdmin::ClientAuthzScopeRepresentation`
506
-
507
- ```ruby
508
- KeycloakAdmin.realm("a_realm").authz_scopes(client.id).get(scope_id)
509
- ```
510
-
511
- ### Delete one scope
512
-
513
- ```ruby
514
- KeycloakAdmin.realm("a_realm").authz_scopes(client.id).delete(scope.id)
515
- ```
516
-
517
- ### Create a client authorization resource
518
-
519
- note: for scopes, use {name: scope.name} to reference the scope object
520
-
521
- Returns added `KeycloakAdmin::ClientAuthzResourceRepresentation`
522
-
523
- ```ruby
524
- KeycloakAdmin.realm("realm_id")
525
- .authz_resources(client.id)
526
- .create!(
527
- "Dummy Resource",
528
- "type",
529
- ["/resource_1/*", "/resource_1/"],
530
- true,
531
- "display_name",
532
- [ {name: scope_1.name} ],
533
- {"attribute": ["value_1", "value_2"]}
534
- )
535
- ```
536
-
537
- ### Update a client authorization resource
538
-
539
- Returns updated `KeycloakAdmin::ClientAuthzResourceRepresentation`
540
-
541
- note: for scopes, use {name: scope.name} to reference the scope object
542
-
543
- ```ruby
544
- KeycloakAdmin.realm("realm_a")
545
- .authz_resources(client.id)
546
- .update(resource.id,
547
- {
548
- "name": "Dummy Resource",
549
- "type": "type",
550
- "owner_managed_access": true,
551
- "display_name": "display_name",
552
- "attributes": {"a":["b","c"]},
553
- "uris": [ "/resource_1/*" , "/resource_1/" ],
554
- "scopes":[
555
- {name: scope_1.name},
556
- {name: scope_2.name}
557
- ],
558
- "icon_uri": "https://icon.url"
559
- })
560
- ```
561
-
562
- ### Find client authorization resources by (name, type, uri, owner, scope)
563
-
564
- Returns array of `KeycloakAdmin::ClientAuthzResourceRepresentation`
565
-
566
- ```ruby
567
- KeycloakAdmin.realm("realm_a").authz_resources(client.id).find_by("Dummy Resource", "", "", "", "")
568
- ```
569
- or
570
- ```ruby
571
- KeycloakAdmin.realm("realm_a").authz_resources(client.id).find_by("", "type", "", "", "")
572
- ```
573
-
574
- ### Get client authorization resource by its id
575
-
576
- Returns `KeycloakAdmin::ClientAuthzResourceRepresentation`
577
-
578
- ```ruby
579
- KeycloakAdmin.realm("realm_a").authz_resources(client.id).get(resource.id)
580
- ```
581
-
582
- ### delete a client authorization resource
583
-
584
- ```ruby
585
- KeycloakAdmin.realm("realm_a").authz_resources(client.id).delete(resource.id)
586
- ```
587
-
588
- ### Create a client authorization policy
589
-
590
- Note: for the moment only `role` policies are supported.
591
-
592
- Returns added `KeycloakAdmin::ClientAuthzPolicyRepresentation`
593
-
594
- ```ruby
595
- KeycloakAdmin.realm("realm_a")
596
- .authz_policies(client.id, 'role')
597
- .create!("Policy 1",
598
- "description",
599
- "role",
600
- "POSITIVE",
601
- "UNANIMOUS",
602
- true,
603
- [{id: realm_role.id, required: true}]
604
- )
605
- ```
606
-
607
- ### Find client authorization policies by (name, type)
608
-
609
- Returns array of `KeycloakAdmin::ClientAuthzPolicyRepresentation`
610
-
611
- ```ruby
612
- KeycloakAdmin.realm("realm_a").authz_policies(client.id, 'role').find_by("Policy 1", "role")
613
- ```
614
-
615
- ### Get client authorization policy by its id
616
-
617
- Returns `KeycloakAdmin::ClientAuthzPolicyRepresentation`
618
-
619
- ```ruby
620
- KeycloakAdmin.realm("realm_a").authz_policies(client.id, 'role').get(policy.id)
621
- ```
622
-
623
- ### Delete a client authorization policy
624
-
625
- ```ruby
626
- KeycloakAdmin.realm("realm_a").authz_policies(client.id, 'role').delete(policy.id)
627
- ```
628
-
629
- ### Create a client authorization permission (Resource type)
630
-
631
- Returns added `KeycloakAdmin::ClientAuthzPermissionRepresentation`
632
-
633
- ```ruby
634
- KeycloakAdmin.realm("realm_a")
635
- .authz_permissions(client.id, :resource)
636
- .create!("Dummy Resource Permission",
637
- "resource description",
638
- "UNANIMOUS",
639
- "POSITIVE",
640
- [resource.id],
641
- [policy.id],
642
- nil,
643
- ""
644
- )
645
- ```
646
-
647
- ### Create a client authorization permission (Scope type)
648
-
649
- Returns added `KeycloakAdmin::ClientAuthzPermissionRepresentation`
650
-
651
- ```ruby
652
- KeycloakAdmin.realm("realm_a")
653
- .authz_permissions(client.id, :scope)
654
- .create!("Dummy Scope Permission",
655
- "scope description",
656
- "UNANIMOUS",
657
- "POSITIVE",
658
- [resource.id],
659
- [policy.id],
660
- [scope_1.id, scope_2.id],
661
- ""
662
- )
663
- ```
664
-
665
- ### List a resource authorization permissions (all: scope or resource)
666
-
667
- Return array of `KeycloakAdmin::ClientAuthzPermissionRepresentation`
668
-
669
- ```ruby
670
- KeycloakAdmin.realm("realm_a").authz_permissions(client.id, "", resource.id).list
671
- ```
672
-
673
- ### List a resource authorization permissions (by type: resource)
674
-
675
- Return array of `KeycloakAdmin::ClientAuthzPermissionRepresentation`
676
-
677
- ```ruby
678
- KeycloakAdmin.realm("realm_a").authz_permissions(client.id, 'resource').list
679
- ```
680
- ### List a resource authorization permissions (by type: scope)
681
-
682
- Return array of `KeycloakAdmin::ClientAuthzPermissionRepresentation`
683
-
684
- ```ruby
685
- authz_permissions(client.id, 'scope').list.size
686
- ```
687
-
688
- ### Find client authorization permissions by (name, type, scope)
689
-
690
- Return array of `KeycloakAdmin::ClientAuthzPermissionRepresentation`
691
-
692
- ```ruby
693
- KeycloakAdmin.realm("realm_a").authz_permissions(client.id, "resource").find_by(resource_permission.name, nil)
694
- ```
695
- or
696
- ```ruby
697
- KeycloakAdmin.realm("realm_a").authz_permissions(client.id, "resource").find_by(resource_permission.name, nil)
698
- ```
699
- or
700
- ```ruby
701
- KeycloakAdmin.realm("realm_a").authz_permissions(client.id, "resource").find_by(resource_permission.name, resource.id)
702
-
703
- ```
704
- or
705
- ```ruby
706
- KeycloakAdmin.realm("realm_a").authz_permissions(client.id, "scope").find_by(scope_permission.name, resource.id)
707
- ```
708
- or
709
- ```ruby
710
- KeycloakAdmin.realm("realm_a").authz_permissions(client.id, "scope").find_by(scope_permission.name, resource.id, "POST_1")
711
- ```
712
- or
713
- ```ruby
714
- KeycloakAdmin.realm("realm_a").authz_permissions(client.id, "resource").find_by(nil, resource.id)
715
- ```
716
- or
717
- ```ruby
718
- KeycloakAdmin.realm("realm_a").authz_permissions(client.id, "scope").find_by(nil, resource.id)
719
- ```
720
- or
721
- ```ruby
722
- KeycloakAdmin.realm("realm_a").authz_permissions(client.id, "scope").find_by(nil, resource.id, "POST_1")
723
- ```
724
- or
725
- ```ruby
726
- KeycloakAdmin.realm("realm_a").authz_permissions(client.id, "scope").find_by(scope_permission.name, nil)
727
- ```
728
-
729
- ### Delete a client authorization permission, scope type
730
-
731
- ```ruby
732
- KeycloakAdmin.realm("realm_a").authz_permissions(client.id, 'scope').delete(scope.id)
733
- ```
734
-
735
- ### Delete a client authorization permission, resource type
736
-
737
- ```ruby
738
- KeycloakAdmin.realm("realm_a").authz_permissions(client.id, 'resource').delete(resource_permission.id)
739
- ```
740
-
741
- ## How to execute library tests
742
-
743
- From the `keycloak-admin-api` directory:
744
-
745
- ```
746
- $ docker build . -t keycloak-admin:test
747
- $ docker run -v `pwd`:/usr/src/app/ keycloak-admin:test rspec spec
748
- ```
1
+
2
+ # Keycloak Admin Ruby
3
+
4
+ Ruby client that acts as a client for the Keycloak REST API.
5
+ This gem basically acts as an url builder using `http-client` to get responses and serialize them into _representation_ objects.
6
+
7
+ _Warning: This beta gem is currently used for personal use. Most Keycloak Admin features are not implemented yet._
8
+
9
+ ## Install
10
+
11
+ This gem *does not* require Rails.
12
+ For example, using `bundle`, add this line to your Gemfile.
13
+
14
+ ```ruby
15
+ gem "keycloak-admin", "1.1.5"
16
+ ```
17
+
18
+ ## Login
19
+
20
+ To login on Keycloak's Admin API, you first need to setup a client.
21
+
22
+ Go to your realm administration page and open `Clients`. Then, click on the `Create` button.
23
+ On the first screen, enter:
24
+ * `Client ID`: _e.g. my-app-admin-client_
25
+ * `Client Protocol`: select `openid-connect`
26
+ * `Root URL`: let it blank
27
+
28
+ The next screen must be configured depending on how you want to authenticate:
29
+ * `username/password` with a user of the realm
30
+ * `Direct Access Grants` with a service account
31
+
32
+ ### Login with username/password (realm user)
33
+
34
+ * In Keycloak, during the client setup:
35
+ * `Access Type`: `public` or `confidential`
36
+ * `Service Accounts Enabled` (when `confidential`): `false`
37
+ * After saving your client, if you have chosen a `confidential` client, go to `Credentials` tab and copy the `Client Secret`
38
+
39
+ * In Keycloak, create a dedicated user (and her credentials):
40
+ * Go to `Users`
41
+ * Click on the `Add user` button
42
+ * Setup her mandatory information, depending on your realm's configuration
43
+ * On the `Credentials` tab, create her a password (toggle off `Temporary`)
44
+
45
+ * In this gem's configuration (see Section `Configuration`):
46
+ * Setup `username` and `password` according to your user's configuration
47
+ * Setup `client_id` with your `Client ID` (_e.g. my-app-admin-client_)
48
+ * If your client is `confidential`, copy its Client Secret to `client_secret`
49
+
50
+ ### Login with `Direct Access Grants` (Service account)
51
+
52
+ Using a service account to use the REST Admin API does not require to create a dedicated user (https://www.keycloak.org/docs/latest/server_admin/#_service_accounts).
53
+
54
+ * In Keycloak, during the client setup:
55
+ * `Access Type`: `confidential`
56
+ * `Service Accounts Enabled` (when `confidential`): `true`
57
+ * `Standard Flow Enabled`: `false`
58
+ * `Implicit Flow Enabled`: `false`
59
+ * `Direct Access Grants Enabled`: `true`
60
+ * After saving this client
61
+ * open the `Service Account Roles` and add relevant `realm-management.` client's roles. For instance: `view-users` if you want to search for users using this gem.
62
+ * open the `Credentials` tab and copy the `Client Secret`
63
+
64
+ * In this gem's configuration (see Section `Configuration`):
65
+ * Set `use_service_account` to `true`
66
+ * Setup `client_id` with your `Client ID` (_e.g. my-app-admin-client_)
67
+ * Copy its Client Secret to `client_secret`
68
+
69
+ ## Configuration
70
+
71
+ To configure this gem, call `KeycloakAdmin.configure`.
72
+ For instance, to configure this gem based on environment variables, write (and load if required) a `keycloak_admin.rb`:
73
+ ```ruby
74
+ KeycloakAdmin.configure do |config|
75
+ config.use_service_account = false
76
+ config.server_url = ENV["KEYCLOAK_SERVER_URL"]
77
+ config.server_domain = ENV["KEYCLOAK_SERVER_DOMAIN"]
78
+ config.client_id = ENV["KEYCLOAK_ADMIN_CLIENT_ID"]
79
+ config.client_realm_name = ENV["KEYCLOAK_REALM_ID"]
80
+ config.username = ENV["KEYCLOAK_ADMIN_USER"]
81
+ config.password = ENV["KEYCLOAK_ADMIN_PASSWORD"]
82
+ config.logger = Rails.logger
83
+
84
+ # You configure RestClient to your liking – see https://github.com/rest-client/rest-client/blob/master/lib/restclient/request.rb for available options.
85
+ config.rest_client_options = { timeout: 5 }
86
+ end
87
+ ```
88
+ This example is autoloaded in a Rails environment.
89
+
90
+ ### Overall configuration options
91
+
92
+ All options have a default value. However, all of them can be changed in your initializer file.
93
+
94
+ | Option | Default Value | Type | Required? | Description | Example |
95
+ | ---- | ----- | ------ | ----- | ------ | ----- |
96
+ | `server_url` | `nil` | String | Required | The base url where your Keycloak server is located (a URL that starts with `http` and that ends with `/auth`). This value can be retrieved in your Keycloak client configuration. | `http://auth:8080/auth`
97
+ | `server_domain` | `nil`| String | Required | Public domain that identify your authentication cookies. | `auth.service.io` |
98
+ | `client_realm_name` | `""`| String | Required | Name of the realm that contains the admin client. | `master` |
99
+ | `client_id` | `admin-cli`| String | Required | Client that should be used to access admin capabilities. | `api-cli` |
100
+ | `client_secret` | `nil`| String | Optional | If your client is `confidential`, this parameter must be specified. | `4e3c481c-f823-4a6a-b8a7-bf8c86e3eac3` |
101
+ | `use_service_account` | `true` | Boolean | Required | `true` if the connection to the client uses a Service Account. `false` if the connection to the client uses a username/password credential. | `false` |
102
+ | `username` | `nil`| String | Optional | Username to access the Admin REST API. Recommended if `user_service_account` is set to `false`. | `mummy` |
103
+ | `password` | `nil`| String | Optional | Clear password to access the Admin REST API. Recommended if `user_service_account` is set to `false`. | `bobby` |
104
+ | `logger` | `Logger.new(STDOUT)`| Logger | Optional | The logger used by `keycloak-admin` | `Rails.logger` | 
105
+ | `rest_client_options` | `{}`| Hash | Optional | Options to pass to `RestClient` | `{ timeout: 5 }` | 
106
+
107
+
108
+ ## Use Cases
109
+
110
+ ### Supported features
111
+
112
+ * Get an access token
113
+ * Create/update/get/delete a user
114
+ * Get list of users, search for user(s)
115
+ * List credentials of a user
116
+ * Reset credentials
117
+ * Impersonate a user
118
+ * Exchange a configurable token
119
+ * Get list of clients, or find a client by its id or client_id
120
+ * Create, update, and delete clients
121
+ * Get list of groups, create/save a group
122
+ * Get list of roles, save a role
123
+ * Get list of realms, save/update/delete a realm
124
+ * Get list of client role mappings for a user/group
125
+ * Get list of members of a group
126
+ * Get list of groups that have a specific role assigned
127
+ * Get list of realm-roles assigned to a group, add a realm-role to a group
128
+ * Save client role mappings for a user/group
129
+ * Save realm-level role mappings for a user/group
130
+ * Add a Group on a User
131
+ * Remove a Group from a User
132
+ * Get list of Identity Providers
133
+ * Create Identity Providers
134
+ * Link/Unlink users to federated identity provider brokers
135
+ * Execute actions emails
136
+ * Send forgot passsword mail
137
+ * Client Authorization, create, update, get, delete Resource, Scope, Policy, Permission, Policy Enforcer
138
+
139
+ ### Get an access token
140
+
141
+ Returns an instance of `KeycloakAdmin::TokenRepresentation`.
142
+
143
+ ```ruby
144
+ KeycloakAdmin.realm("a_realm").token.get
145
+ ```
146
+
147
+ ### Get a user from its identifier
148
+
149
+ Returns an instance of `KeycloakAdmin::UserRepresentation` or `nil` when this user does not exist.
150
+
151
+ ```ruby
152
+ user_id = "95985b21-d884-4bbd-b852-cb8cd365afc2"
153
+ KeycloakAdmin.realm("a_realm").users.get(user_id)
154
+ ```
155
+
156
+ ### Search for users
157
+
158
+ Returns an array of `KeycloakAdmin::UserRepresentation`.
159
+
160
+ According to [the documentation](https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_users_resource):
161
+ * When providing a `String` parameter, this produces an arbitrary search string
162
+ * When providing a `Hash`, you can search for specific field (_e.g_ an email)
163
+
164
+ ```ruby
165
+ KeycloakAdmin.realm("a_realm").users.search("a_username_or_an_email")
166
+ ```
167
+
168
+ ```ruby
169
+ KeycloakAdmin.realm("a_realm").users.search({ email: "john@doe.com" })
170
+ ```
171
+
172
+ ### List all users in a realm
173
+
174
+ Returns an array of `KeycloakAdmin::UserRepresentation`.
175
+
176
+ ```ruby
177
+ KeycloakAdmin.realm("a_realm").users.list
178
+ ```
179
+
180
+ ### Save a user
181
+
182
+ Returns the provided `user`, which must be of type `KeycloakAdmin::UserRepresentation`.
183
+
184
+ ```ruby
185
+ KeycloakAdmin.realm("a_realm").users.save(user)
186
+ ```
187
+
188
+ ### Update a user
189
+
190
+ If you want to update its entire entity. To update some specific attributes, provide an object implementing `to_json`, such as a `Hash`.
191
+
192
+ ```ruby
193
+ KeycloakAdmin.realm("a_realm").users.update("05c135c6-5ad8-4e17-b1fa-635fc089fd71", {
194
+ email: "hello@gmail.com",
195
+ username: "hello",
196
+ first_name: "Jean",
197
+ last_name: "Dupond"
198
+ })
199
+ ```
200
+
201
+ Attention point: Since Keycloak 24.0.4, when updating a user, all the writable profile attributes must be passed, otherwise they will be removed. (https://www.keycloak.org/docs/24.0.4/upgrading/)
202
+
203
+ ### Delete a user
204
+
205
+ ```ruby
206
+ KeycloakAdmin.realm("a_realm").users.delete(user_id)
207
+ ```
208
+
209
+ ### Create and save a user with password and a locale
210
+
211
+ Returns the created user of type `KeycloakAdmin::UserRepresentation`.
212
+
213
+ ```ruby
214
+ username = "pioupioux"
215
+ email = "pioupioux@email.com"
216
+ password = "acme0"
217
+ email_verified = true
218
+ locale = "en"
219
+ KeycloakAdmin.realm("a_realm").users.create!(username, email, password, email_verified, locale)
220
+ ```
221
+
222
+ ### Reset a password
223
+
224
+ ```ruby
225
+ user_id = "95985b21-d884-4bbd-b852-cb8cd365afc2"
226
+ new_password = "coco"
227
+ KeycloakAdmin.realm("a_realm").users.update_password(user_id, new_password)
228
+ ```
229
+
230
+ ### List credentials
231
+
232
+ ```ruby
233
+ user_id = "95985b21-d884-4bbd-b852-cb8cd365afc2"
234
+ KeycloakAdmin.realm("a_realm").users.credentials(user_id)
235
+ ```
236
+
237
+ ### Impersonate a password directly
238
+
239
+ Returns an instance of `KeycloakAdmin::ImpersonationRepresentation`.
240
+
241
+ ```ruby
242
+ user_id = "95985b21-d884-4bbd-b852-cb8cd365afc2"
243
+ KeycloakAdmin.realm("a_realm").users.impersonate(user_id)
244
+ ```
245
+
246
+ ### Impersonate a password indirectly
247
+
248
+ To have enough information to execute an impersonation by yourself, `get_redirect_impersonation` returns an instance of `KeycloakAdmin::ImpersonationRedirectionRepresentation`.
249
+
250
+ ```ruby
251
+ user_id = "95985b21-d884-4bbd-b852-cb8cd365afc2"
252
+ KeycloakAdmin.realm("a_realm").users.get_redirect_impersonation(user_id)
253
+ ```
254
+
255
+ ### Exchange a configurable token
256
+
257
+ *Requires your Keycloak server to have deployed the Custom REST API `configurable-token`* (https://github.com/looorent/keycloak-configurable-token-api)
258
+ Returns an instance of `KeycloakAdmin::TokenRepresentation`.
259
+
260
+ ```ruby
261
+ user_access_token = "abqsdofnqdsogn"
262
+ token_lifespan_in_seconds = 20
263
+ KeycloakAdmin.realm("a_realm").configurable_token.exchange_with(user_access_token, token_lifespan_in_seconds)
264
+ ```
265
+
266
+ ### Get list of realms
267
+
268
+ Returns an array of `KeycloakAdmin::RealmRepresentation`.
269
+
270
+ ```ruby
271
+ KeycloakAdmin.realm("master").list
272
+ ```
273
+
274
+ ### Save a realm
275
+
276
+ Takes `realm` of type `KeycloakAdmin::RealmRepresentation`, or an object implementing `to_json`, such as a `Hash`.
277
+
278
+ ```ruby
279
+ KeycloakAdmin.realm(nil).save(realm)
280
+ ```
281
+
282
+ ### Update a realm
283
+
284
+ If you want to update its entire entity. To update some specific attributes, provide an object implementing `to_json`, such as a `Hash`.
285
+
286
+ ```ruby
287
+ KeycloakAdmin.realm("a_realm").update({
288
+ smtpServer: { host: 'test_host' }
289
+ })
290
+ ```
291
+
292
+ ### Delete a realm
293
+
294
+ ```ruby
295
+ KeycloakAdmin.realm("a_realm").delete
296
+ ```
297
+
298
+ ### Get list of clients in a realm
299
+
300
+ Returns an array of `KeycloakAdmin::ClientRepresentation` or a single `KeycloakAdmin::ClientRepresentation`
301
+
302
+ Finding a client by its `client_id` is a somewhat slow operation, as it requires fetching all clients and then filtering. Keycloak's API does not support fetching a client by its `client_id` directly.
303
+
304
+ ```ruby
305
+ KeycloakAdmin.realm("a_realm").clients.list
306
+ KeycloakAdmin.realm("a_realm").clients.get(id) # id is Keycloak's database id, not the client_id
307
+ KeycloakAdmin.realm("a_realm").clients.find_by_client_id(client_id)
308
+ ```
309
+
310
+ ### Updating a client
311
+
312
+ ```ruby
313
+ my_client = KeycloakAdmin.realm("a_realm").clients.get(id)
314
+
315
+ my_client.name = "My new client name"
316
+ my_client.description = "This is a new description"
317
+ my_client.redirect_uris << "https://www.example.com/auth/callback"
318
+
319
+ KeycloakAdmin.realm("a_realm").clients.update(client) # Returns the updated client
320
+ ```
321
+
322
+ ### Get list of groups in a realm
323
+
324
+ Returns an array of `KeycloakAdmin::GroupRepresentation`.
325
+
326
+ ```ruby
327
+ KeycloakAdmin.realm("a_realm").groups.list
328
+ ```
329
+
330
+ ### Search for a group
331
+
332
+ Returns an array of `KeycloakAdmin::GroupRepresentation`.
333
+
334
+ According to [the documentation](https://www.keycloak.org/docs-api/22.0.1/rest-api/index.html#_groups):
335
+ * When providing a `String` parameter, this produces an arbitrary search string
336
+ * When providing a `Hash`, you can specify other fields (_e.g_ q, max, first)
337
+
338
+ ```ruby
339
+ KeycloakAdmin.realm("a_realm").groups.search("MyGroup")
340
+ ```
341
+
342
+ ```ruby
343
+ KeycloakAdmin.realm("a_realm").groups.search({query: "MyGroup", exact: true, max: 1})
344
+ ```
345
+
346
+ ### Save a group
347
+
348
+ Returns the id of saved `group` provided, which must be of type `KeycloakAdmin::GroupRepresentation`.
349
+
350
+ ```ruby
351
+ KeycloakAdmin.realm("a_realm").groups.save(group)
352
+ ```
353
+
354
+ ### Create and save a group with a name and path
355
+
356
+ Returns the id of created group.
357
+
358
+ ```ruby
359
+ group_name = "test"
360
+ group_path = "/top"
361
+ group_id = KeycloakAdmin.realm("a_realm").groups.create!(group_name, group_path)
362
+ ```
363
+
364
+ ### Create a new subgroup of an existing group
365
+
366
+ Create a new group as the child of an existing group.
367
+
368
+ ```ruby
369
+ parent_id = "7686af34-204c-4515-8122-78d19febbf6e"
370
+ group_name = "test"
371
+ sub_group_id = KeycloakAdmin.realm("a_realm").groups.create_subgroup!(parent_id, group_name)
372
+ ```
373
+
374
+ ### Get list of members of a group
375
+
376
+ Returns an array of `KeycloakAdmin::UserRepresentation`.
377
+
378
+ ```ruby
379
+ KeycloakAdmin.realm("a_realm").group("group_id").members
380
+ ```
381
+
382
+ You can specify paging with `first` and `max`:
383
+
384
+ ```ruby
385
+ KeycloakAdmin.realm("a_realm").group("group_id").members(first:0, max:100)
386
+ ```
387
+
388
+ ### Get list of groups that have a specific role assigned
389
+
390
+ Returns an array of `KeycloakAdmin::GroupRepresentation`
391
+
392
+ ```ruby
393
+ KeycloakAdmin.realm("a_realm").roles.list_groups("role_name")
394
+ ```
395
+
396
+ ### Get list of realm-roles assigned to a group
397
+
398
+ Returns an array of `KeycloakAdmin::RoleRepresentation`
399
+
400
+ ```ruby
401
+ KeycloakAdmin.realm("a_realm").groups.get_realm_level_roles("group_id")
402
+ ```
403
+
404
+ ### Add a realm-role to a group
405
+
406
+ Returns added `KeycloakAdmin::RoleRepresentation`
407
+
408
+ ```ruby
409
+ KeycloakAdmin.realm("a_realm").groups.add_realm_level_role_name!("group_id", "role_name")
410
+ ```
411
+
412
+ ### Get list of roles in a realm
413
+
414
+ Returns an array of `KeycloakAdmin::RoleRepresentation`.
415
+
416
+ ```ruby
417
+ KeycloakAdmin.realm("a_realm").roles.list
418
+ ```
419
+
420
+ ### Save a role
421
+
422
+ Takes `role`, which must be of type `KeycloakAdmin::RoleRepresentation`.
423
+
424
+ ```ruby
425
+ KeycloakAdmin.realm("a_realm").roles.save(role)
426
+ ```
427
+
428
+ ### Get list of client role mappings for a user/group
429
+
430
+ Returns an array of `KeycloakAdmin::RoleRepresentation`.
431
+
432
+ ```ruby
433
+ user_id = "95985b21-d884-4bbd-b852-cb8cd365afc2"
434
+ client_id = "1869e876-71b4-4de2-849e-66540db3a098"
435
+ KeycloakAdmin.realm("a_realm").user(user_id).client_role_mappings(client_id).list_available
436
+ ```
437
+ or
438
+ ```ruby
439
+ group_id = "3a63b5c0-ef8a-47fd-86ed-b5fead18d9b8"
440
+ client_id = "1869e876-71b4-4de2-849e-66540db3a098"
441
+ KeycloakAdmin.realm("a_realm").group(group_id).client_role_mappings(client_id).list_available
442
+ ```
443
+
444
+ ### Save list of client role mappings for a user/group
445
+
446
+ Takes `role_list`, which must be an array of type `KeycloakAdmin::RoleRepresentation`.
447
+
448
+ ```ruby
449
+ user_id = "95985b21-d884-4bbd-b852-cb8cd365afc2"
450
+ client_id = "1869e876-71b4-4de2-849e-66540db3a098"
451
+ KeycloakAdmin.realm("a_realm").user(user_id).client_role_mappings(client_id).save(role_list)
452
+ ```
453
+ or
454
+ ```ruby
455
+ group_id = "3a63b5c0-ef8a-47fd-86ed-b5fead18d9b8"
456
+ client_id = "1869e876-71b4-4de2-849e-66540db3a098"
457
+ KeycloakAdmin.realm("a_realm").group(group_id).client_role_mappings(client_id).save(role_list)
458
+ ```
459
+
460
+ ### Save list of realm-level role mappings for a user/group
461
+
462
+ Takes `role_list`, which must be an array of type `KeycloakAdmin::RoleRepresentation`.
463
+
464
+ ```ruby
465
+ user_id = "95985b21-d884-4bbd-b852-cb8cd365afc2"
466
+ KeycloakAdmin.realm("a_realm").user(user_id).role_mapper.save_realm_level(role_list)
467
+ ```
468
+ or
469
+ ```ruby
470
+ group_id = "3a63b5c0-ef8a-47fd-86ed-b5fead18d9b8"
471
+ KeycloakAdmin.realm("a_realm").group(group_id).role_mapper.save_realm_level(role_list)
472
+ ```
473
+
474
+ ### Get list of identity providers
475
+
476
+ Note: This client requires the `realm-management.view-identity-providers` role.
477
+
478
+ Returns an array of `KeycloakAdmin::IdentityProviderRepresentation`.
479
+
480
+ ```ruby
481
+ KeycloakAdmin.realm("a_realm").identity_providers.list
482
+ ```
483
+
484
+ ### Manage [Client Authorization Resources & Scopes](https://www.keycloak.org/docs/latest/authorization_services/index.html#_resource_overview)
485
+
486
+ In order to use authorization, you need to enable the client's `authorization_services_enabled` attribute.
487
+
488
+ ```ruby
489
+ client_id = "dummy-client"
490
+ client = KeycloakAdmin.realm("realm_a").clients.find_by_client_id(client_id)
491
+ client.authorization_services_enabled = true
492
+ KeycloakAdmin.realm("a_realm").clients.update(client)
493
+ ```
494
+
495
+ ### Create a scope
496
+
497
+ Returns added `KeycloakAdmin::ClientAuthzScopeRepresentation`
498
+
499
+ ```ruby
500
+ KeycloakAdmin.realm("a_realm").authz_scopes(client_id).create!("POST_1", "POST 1 scope description", "http://icon.url")
501
+ ````
502
+
503
+ ### Search for scope
504
+
505
+ Returns array of `KeycloakAdmin::ClientAuthzScopeRepresentation`
506
+
507
+ ```ruby
508
+ KeycloakAdmin.realm("a_realm").authz_scopes(client.id).search("POST")
509
+ ```
510
+
511
+ ### Get one scope by its id
512
+
513
+ Returns `KeycloakAdmin::ClientAuthzScopeRepresentation`
514
+
515
+ ```ruby
516
+ KeycloakAdmin.realm("a_realm").authz_scopes(client.id).get(scope_id)
517
+ ```
518
+
519
+ ### Delete one scope
520
+
521
+ ```ruby
522
+ KeycloakAdmin.realm("a_realm").authz_scopes(client.id).delete(scope.id)
523
+ ```
524
+
525
+ ### Create a client authorization resource
526
+
527
+ note: for scopes, use {name: scope.name} to reference the scope object
528
+
529
+ Returns added `KeycloakAdmin::ClientAuthzResourceRepresentation`
530
+
531
+ ```ruby
532
+ KeycloakAdmin.realm("realm_id")
533
+ .authz_resources(client.id)
534
+ .create!(
535
+ "Dummy Resource",
536
+ "type",
537
+ ["/resource_1/*", "/resource_1/"],
538
+ true,
539
+ "display_name",
540
+ [ {name: scope_1.name} ],
541
+ {"attribute": ["value_1", "value_2"]}
542
+ )
543
+ ```
544
+
545
+ ### Update a client authorization resource
546
+
547
+ Returns updated `KeycloakAdmin::ClientAuthzResourceRepresentation`
548
+
549
+ note: for scopes, use {name: scope.name} to reference the scope object
550
+
551
+ ```ruby
552
+ KeycloakAdmin.realm("realm_a")
553
+ .authz_resources(client.id)
554
+ .update(resource.id,
555
+ {
556
+ "name": "Dummy Resource",
557
+ "type": "type",
558
+ "owner_managed_access": true,
559
+ "display_name": "display_name",
560
+ "attributes": {"a":["b","c"]},
561
+ "uris": [ "/resource_1/*" , "/resource_1/" ],
562
+ "scopes":[
563
+ {name: scope_1.name},
564
+ {name: scope_2.name}
565
+ ],
566
+ "icon_uri": "https://icon.url"
567
+ })
568
+ ```
569
+
570
+ ### Find client authorization resources by (name, type, uri, owner, scope)
571
+
572
+ Returns array of `KeycloakAdmin::ClientAuthzResourceRepresentation`
573
+
574
+ ```ruby
575
+ KeycloakAdmin.realm("realm_a").authz_resources(client.id).find_by("Dummy Resource", "", "", "", "")
576
+ ```
577
+ or
578
+ ```ruby
579
+ KeycloakAdmin.realm("realm_a").authz_resources(client.id).find_by("", "type", "", "", "")
580
+ ```
581
+
582
+ ### Get client authorization resource by its id
583
+
584
+ Returns `KeycloakAdmin::ClientAuthzResourceRepresentation`
585
+
586
+ ```ruby
587
+ KeycloakAdmin.realm("realm_a").authz_resources(client.id).get(resource.id)
588
+ ```
589
+
590
+ ### delete a client authorization resource
591
+
592
+ ```ruby
593
+ KeycloakAdmin.realm("realm_a").authz_resources(client.id).delete(resource.id)
594
+ ```
595
+
596
+ ### Create a client authorization policy
597
+
598
+ Note: for the moment only `role` policies are supported.
599
+
600
+ Returns added `KeycloakAdmin::ClientAuthzPolicyRepresentation`
601
+
602
+ ```ruby
603
+ KeycloakAdmin.realm("realm_a")
604
+ .authz_policies(client.id, 'role')
605
+ .create!("Policy 1",
606
+ "description",
607
+ "role",
608
+ "POSITIVE",
609
+ "UNANIMOUS",
610
+ true,
611
+ [{id: realm_role.id, required: true}]
612
+ )
613
+ ```
614
+
615
+ ### Find client authorization policies by (name, type)
616
+
617
+ Returns array of `KeycloakAdmin::ClientAuthzPolicyRepresentation`
618
+
619
+ ```ruby
620
+ KeycloakAdmin.realm("realm_a").authz_policies(client.id, 'role').find_by("Policy 1", "role")
621
+ ```
622
+
623
+ ### Get client authorization policy by its id
624
+
625
+ Returns `KeycloakAdmin::ClientAuthzPolicyRepresentation`
626
+
627
+ ```ruby
628
+ KeycloakAdmin.realm("realm_a").authz_policies(client.id, 'role').get(policy.id)
629
+ ```
630
+
631
+ ### Delete a client authorization policy
632
+
633
+ ```ruby
634
+ KeycloakAdmin.realm("realm_a").authz_policies(client.id, 'role').delete(policy.id)
635
+ ```
636
+
637
+ ### Create a client authorization permission (Resource type)
638
+
639
+ Returns added `KeycloakAdmin::ClientAuthzPermissionRepresentation`
640
+
641
+ ```ruby
642
+ KeycloakAdmin.realm("realm_a")
643
+ .authz_permissions(client.id, :resource)
644
+ .create!("Dummy Resource Permission",
645
+ "resource description",
646
+ "UNANIMOUS",
647
+ "POSITIVE",
648
+ [resource.id],
649
+ [policy.id],
650
+ nil,
651
+ ""
652
+ )
653
+ ```
654
+
655
+ ### Create a client authorization permission (Scope type)
656
+
657
+ Returns added `KeycloakAdmin::ClientAuthzPermissionRepresentation`
658
+
659
+ ```ruby
660
+ KeycloakAdmin.realm("realm_a")
661
+ .authz_permissions(client.id, :scope)
662
+ .create!("Dummy Scope Permission",
663
+ "scope description",
664
+ "UNANIMOUS",
665
+ "POSITIVE",
666
+ [resource.id],
667
+ [policy.id],
668
+ [scope_1.id, scope_2.id],
669
+ ""
670
+ )
671
+ ```
672
+
673
+ ### List a resource authorization permissions (all: scope or resource)
674
+
675
+ Return array of `KeycloakAdmin::ClientAuthzPermissionRepresentation`
676
+
677
+ ```ruby
678
+ KeycloakAdmin.realm("realm_a").authz_permissions(client.id, "", resource.id).list
679
+ ```
680
+
681
+ ### List a resource authorization permissions (by type: resource)
682
+
683
+ Return array of `KeycloakAdmin::ClientAuthzPermissionRepresentation`
684
+
685
+ ```ruby
686
+ KeycloakAdmin.realm("realm_a").authz_permissions(client.id, 'resource').list
687
+ ```
688
+ ### List a resource authorization permissions (by type: scope)
689
+
690
+ Return array of `KeycloakAdmin::ClientAuthzPermissionRepresentation`
691
+
692
+ ```ruby
693
+ authz_permissions(client.id, 'scope').list.size
694
+ ```
695
+
696
+ ### Find client authorization permissions by (name, type, scope)
697
+
698
+ Return array of `KeycloakAdmin::ClientAuthzPermissionRepresentation`
699
+
700
+ ```ruby
701
+ KeycloakAdmin.realm("realm_a").authz_permissions(client.id, "resource").find_by(resource_permission.name, nil)
702
+ ```
703
+ or
704
+ ```ruby
705
+ KeycloakAdmin.realm("realm_a").authz_permissions(client.id, "resource").find_by(resource_permission.name, nil)
706
+ ```
707
+ or
708
+ ```ruby
709
+ KeycloakAdmin.realm("realm_a").authz_permissions(client.id, "resource").find_by(resource_permission.name, resource.id)
710
+
711
+ ```
712
+ or
713
+ ```ruby
714
+ KeycloakAdmin.realm("realm_a").authz_permissions(client.id, "scope").find_by(scope_permission.name, resource.id)
715
+ ```
716
+ or
717
+ ```ruby
718
+ KeycloakAdmin.realm("realm_a").authz_permissions(client.id, "scope").find_by(scope_permission.name, resource.id, "POST_1")
719
+ ```
720
+ or
721
+ ```ruby
722
+ KeycloakAdmin.realm("realm_a").authz_permissions(client.id, "resource").find_by(nil, resource.id)
723
+ ```
724
+ or
725
+ ```ruby
726
+ KeycloakAdmin.realm("realm_a").authz_permissions(client.id, "scope").find_by(nil, resource.id)
727
+ ```
728
+ or
729
+ ```ruby
730
+ KeycloakAdmin.realm("realm_a").authz_permissions(client.id, "scope").find_by(nil, resource.id, "POST_1")
731
+ ```
732
+ or
733
+ ```ruby
734
+ KeycloakAdmin.realm("realm_a").authz_permissions(client.id, "scope").find_by(scope_permission.name, nil)
735
+ ```
736
+
737
+ ### Delete a client authorization permission, scope type
738
+
739
+ ```ruby
740
+ KeycloakAdmin.realm("realm_a").authz_permissions(client.id, 'scope').delete(scope.id)
741
+ ```
742
+
743
+ ### Delete a client authorization permission, resource type
744
+
745
+ ```ruby
746
+ KeycloakAdmin.realm("realm_a").authz_permissions(client.id, 'resource').delete(resource_permission.id)
747
+ ```
748
+
749
+ ## How to execute library tests
750
+
751
+ From the `keycloak-admin-api` directory:
752
+
753
+ ```
754
+ $ docker build . -t keycloak-admin:test
755
+ $ docker run -v `pwd`:/usr/src/app/ keycloak-admin:test rspec spec
756
+ ```