keycloak-admin 1.1.3 → 1.1.4

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.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/Dockerfile +24 -24
  3. data/.github/workflows/ci.yml +80 -83
  4. data/.gitignore +9 -9
  5. data/.rspec +2 -2
  6. data/CHANGELOG.md +194 -188
  7. data/Dockerfile +12 -12
  8. data/Gemfile +3 -3
  9. data/Gemfile.lock +51 -49
  10. data/MIT-LICENSE +20 -20
  11. data/README.md +748 -748
  12. data/bin/console +9 -9
  13. data/keycloak-admin.gemspec +24 -24
  14. data/lib/keycloak-admin/client/attack_detection_client.rb +41 -41
  15. data/lib/keycloak-admin/client/client.rb +56 -56
  16. data/lib/keycloak-admin/client/client_authz_permission_client.rb +80 -80
  17. data/lib/keycloak-admin/client/client_authz_policy_client.rb +75 -75
  18. data/lib/keycloak-admin/client/client_authz_resource_client.rb +92 -92
  19. data/lib/keycloak-admin/client/client_authz_scope_client.rb +70 -70
  20. data/lib/keycloak-admin/client/client_client.rb +71 -71
  21. data/lib/keycloak-admin/client/client_role_client.rb +20 -20
  22. data/lib/keycloak-admin/client/client_role_mappings_client.rb +32 -32
  23. data/lib/keycloak-admin/client/configurable_token_client.rb +35 -35
  24. data/lib/keycloak-admin/client/group_client.rb +148 -131
  25. data/lib/keycloak-admin/client/identity_provider_client.rb +51 -51
  26. data/lib/keycloak-admin/client/realm_client.rb +122 -122
  27. data/lib/keycloak-admin/client/role_client.rb +59 -59
  28. data/lib/keycloak-admin/client/role_mapper_client.rb +47 -45
  29. data/lib/keycloak-admin/client/token_client.rb +29 -29
  30. data/lib/keycloak-admin/client/user_client.rb +266 -266
  31. data/lib/keycloak-admin/configuration.rb +52 -52
  32. data/lib/keycloak-admin/representation/attack_detection_representation.rb +17 -17
  33. data/lib/keycloak-admin/representation/camel_json.rb +12 -12
  34. data/lib/keycloak-admin/representation/client_authz_permission_representation.rb +33 -33
  35. data/lib/keycloak-admin/representation/client_authz_policy_config_representation.rb +14 -14
  36. data/lib/keycloak-admin/representation/client_authz_policy_representation.rb +26 -26
  37. data/lib/keycloak-admin/representation/client_authz_resource_representation.rb +25 -25
  38. data/lib/keycloak-admin/representation/client_authz_scope_representation.rb +16 -16
  39. data/lib/keycloak-admin/representation/client_representation.rb +71 -71
  40. data/lib/keycloak-admin/representation/credential_representation.rb +38 -38
  41. data/lib/keycloak-admin/representation/federated_identity_representation.rb +15 -15
  42. data/lib/keycloak-admin/representation/group_representation.rb +21 -21
  43. data/lib/keycloak-admin/representation/identity_provider_mapper_representation.rb +19 -19
  44. data/lib/keycloak-admin/representation/identity_provider_representation.rb +67 -67
  45. data/lib/keycloak-admin/representation/impersonation_redirection_representation.rb +16 -16
  46. data/lib/keycloak-admin/representation/impersonation_representation.rb +43 -43
  47. data/lib/keycloak-admin/representation/protocol_mapper_representation.rb +19 -19
  48. data/lib/keycloak-admin/representation/realm_representation.rb +14 -14
  49. data/lib/keycloak-admin/representation/representation.rb +23 -23
  50. data/lib/keycloak-admin/representation/role_representation.rb +19 -19
  51. data/lib/keycloak-admin/representation/session_representation.rb +22 -22
  52. data/lib/keycloak-admin/representation/token_representation.rb +39 -39
  53. data/lib/keycloak-admin/representation/user_representation.rb +47 -47
  54. data/lib/keycloak-admin/resource/base_role_containing_resource.rb +28 -28
  55. data/lib/keycloak-admin/resource/group_resource.rb +11 -11
  56. data/lib/keycloak-admin/resource/user_resource.rb +7 -7
  57. data/lib/keycloak-admin/version.rb +3 -3
  58. data/lib/keycloak-admin.rb +84 -84
  59. data/spec/client/attack_detection_client_spec.rb +102 -102
  60. data/spec/client/client_authz_permission_client_spec.rb +170 -170
  61. data/spec/client/client_authz_policy_client_spec.rb +169 -169
  62. data/spec/client/client_authz_resource_client_spec.rb +150 -150
  63. data/spec/client/client_authz_scope_client_spec.rb +133 -133
  64. data/spec/client/client_client_spec.rb +133 -133
  65. data/spec/client/client_role_mappings_client_spec.rb +82 -82
  66. data/spec/client/client_spec.rb +28 -28
  67. data/spec/client/configurable_token_client_spec.rb +34 -34
  68. data/spec/client/group_client_spec.rb +328 -258
  69. data/spec/client/identity_provider_client_spec.rb +92 -92
  70. data/spec/client/realm_client_spec.rb +155 -155
  71. data/spec/client/role_client_spec.rb +79 -79
  72. data/spec/client/role_mapper_client_spec.rb +113 -68
  73. data/spec/client/token_client_spec.rb +68 -68
  74. data/spec/client/user_client_spec.rb +373 -373
  75. data/spec/configuration_spec.rb +113 -113
  76. data/spec/integration/client_authorization_spec.rb +93 -95
  77. data/spec/representation/attack_detection_representation_spec.rb +15 -15
  78. data/spec/representation/client_authz_permission_representation_spec.rb +52 -52
  79. data/spec/representation/client_authz_policy_representation_spec.rb +46 -46
  80. data/spec/representation/client_authz_resource_representation_spec.rb +33 -33
  81. data/spec/representation/client_authz_scope_representation_spec.rb +18 -18
  82. data/spec/representation/client_representation_spec.rb +119 -119
  83. data/spec/representation/group_representation_spec.rb +22 -22
  84. data/spec/representation/identity_provider_mapper_representation_spec.rb +24 -24
  85. data/spec/representation/identity_provider_representation_spec.rb +113 -113
  86. data/spec/representation/impersonation_representation_spec.rb +163 -163
  87. data/spec/representation/protocol_mapper_representation_spec.rb +57 -57
  88. data/spec/representation/role_representation_spec.rb +37 -37
  89. data/spec/representation/session_representation_spec.rb +15 -15
  90. data/spec/representation/user_representation_spec.rb +15 -15
  91. data/spec/resource/group_resource_spec.rb +14 -14
  92. data/spec/resource/user_resource_spec.rb +14 -14
  93. data/spec/spec_helper.rb +37 -37
  94. metadata +10 -10
data/README.md CHANGED
@@ -1,748 +1,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.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.4"
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
+ ```