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.
- checksums.yaml +4 -4
- data/.github/workflows/Dockerfile +24 -24
- data/.github/workflows/ci.yml +80 -83
- data/.gitignore +9 -9
- data/.rspec +2 -2
- data/CHANGELOG.md +194 -188
- data/Dockerfile +12 -12
- data/Gemfile +3 -3
- data/Gemfile.lock +51 -49
- data/MIT-LICENSE +20 -20
- data/README.md +748 -748
- data/bin/console +9 -9
- data/keycloak-admin.gemspec +24 -24
- data/lib/keycloak-admin/client/attack_detection_client.rb +41 -41
- data/lib/keycloak-admin/client/client.rb +56 -56
- data/lib/keycloak-admin/client/client_authz_permission_client.rb +80 -80
- data/lib/keycloak-admin/client/client_authz_policy_client.rb +75 -75
- data/lib/keycloak-admin/client/client_authz_resource_client.rb +92 -92
- data/lib/keycloak-admin/client/client_authz_scope_client.rb +70 -70
- data/lib/keycloak-admin/client/client_client.rb +71 -71
- data/lib/keycloak-admin/client/client_role_client.rb +20 -20
- data/lib/keycloak-admin/client/client_role_mappings_client.rb +32 -32
- data/lib/keycloak-admin/client/configurable_token_client.rb +35 -35
- data/lib/keycloak-admin/client/group_client.rb +148 -131
- data/lib/keycloak-admin/client/identity_provider_client.rb +51 -51
- data/lib/keycloak-admin/client/realm_client.rb +122 -122
- data/lib/keycloak-admin/client/role_client.rb +59 -59
- data/lib/keycloak-admin/client/role_mapper_client.rb +47 -45
- data/lib/keycloak-admin/client/token_client.rb +29 -29
- data/lib/keycloak-admin/client/user_client.rb +266 -266
- data/lib/keycloak-admin/configuration.rb +52 -52
- data/lib/keycloak-admin/representation/attack_detection_representation.rb +17 -17
- data/lib/keycloak-admin/representation/camel_json.rb +12 -12
- data/lib/keycloak-admin/representation/client_authz_permission_representation.rb +33 -33
- data/lib/keycloak-admin/representation/client_authz_policy_config_representation.rb +14 -14
- data/lib/keycloak-admin/representation/client_authz_policy_representation.rb +26 -26
- data/lib/keycloak-admin/representation/client_authz_resource_representation.rb +25 -25
- data/lib/keycloak-admin/representation/client_authz_scope_representation.rb +16 -16
- data/lib/keycloak-admin/representation/client_representation.rb +71 -71
- data/lib/keycloak-admin/representation/credential_representation.rb +38 -38
- data/lib/keycloak-admin/representation/federated_identity_representation.rb +15 -15
- data/lib/keycloak-admin/representation/group_representation.rb +21 -21
- data/lib/keycloak-admin/representation/identity_provider_mapper_representation.rb +19 -19
- data/lib/keycloak-admin/representation/identity_provider_representation.rb +67 -67
- data/lib/keycloak-admin/representation/impersonation_redirection_representation.rb +16 -16
- data/lib/keycloak-admin/representation/impersonation_representation.rb +43 -43
- data/lib/keycloak-admin/representation/protocol_mapper_representation.rb +19 -19
- data/lib/keycloak-admin/representation/realm_representation.rb +14 -14
- data/lib/keycloak-admin/representation/representation.rb +23 -23
- data/lib/keycloak-admin/representation/role_representation.rb +19 -19
- data/lib/keycloak-admin/representation/session_representation.rb +22 -22
- data/lib/keycloak-admin/representation/token_representation.rb +39 -39
- data/lib/keycloak-admin/representation/user_representation.rb +47 -47
- data/lib/keycloak-admin/resource/base_role_containing_resource.rb +28 -28
- data/lib/keycloak-admin/resource/group_resource.rb +11 -11
- data/lib/keycloak-admin/resource/user_resource.rb +7 -7
- data/lib/keycloak-admin/version.rb +3 -3
- data/lib/keycloak-admin.rb +84 -84
- data/spec/client/attack_detection_client_spec.rb +102 -102
- data/spec/client/client_authz_permission_client_spec.rb +170 -170
- data/spec/client/client_authz_policy_client_spec.rb +169 -169
- data/spec/client/client_authz_resource_client_spec.rb +150 -150
- data/spec/client/client_authz_scope_client_spec.rb +133 -133
- data/spec/client/client_client_spec.rb +133 -133
- data/spec/client/client_role_mappings_client_spec.rb +82 -82
- data/spec/client/client_spec.rb +28 -28
- data/spec/client/configurable_token_client_spec.rb +34 -34
- data/spec/client/group_client_spec.rb +328 -258
- data/spec/client/identity_provider_client_spec.rb +92 -92
- data/spec/client/realm_client_spec.rb +155 -155
- data/spec/client/role_client_spec.rb +79 -79
- data/spec/client/role_mapper_client_spec.rb +113 -68
- data/spec/client/token_client_spec.rb +68 -68
- data/spec/client/user_client_spec.rb +373 -373
- data/spec/configuration_spec.rb +113 -113
- data/spec/integration/client_authorization_spec.rb +93 -95
- data/spec/representation/attack_detection_representation_spec.rb +15 -15
- data/spec/representation/client_authz_permission_representation_spec.rb +52 -52
- data/spec/representation/client_authz_policy_representation_spec.rb +46 -46
- data/spec/representation/client_authz_resource_representation_spec.rb +33 -33
- data/spec/representation/client_authz_scope_representation_spec.rb +18 -18
- data/spec/representation/client_representation_spec.rb +119 -119
- data/spec/representation/group_representation_spec.rb +22 -22
- data/spec/representation/identity_provider_mapper_representation_spec.rb +24 -24
- data/spec/representation/identity_provider_representation_spec.rb +113 -113
- data/spec/representation/impersonation_representation_spec.rb +163 -163
- data/spec/representation/protocol_mapper_representation_spec.rb +57 -57
- data/spec/representation/role_representation_spec.rb +37 -37
- data/spec/representation/session_representation_spec.rb +15 -15
- data/spec/representation/user_representation_spec.rb +15 -15
- data/spec/resource/group_resource_spec.rb +14 -14
- data/spec/resource/user_resource_spec.rb +14 -14
- data/spec/spec_helper.rb +37 -37
- 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.
|
|
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
|
+
```
|