keycloak-admin 0.7.0 → 0.7.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +2 -1
  3. data/CHANGELOG.md +70 -0
  4. data/Dockerfile +1 -1
  5. data/Gemfile.lock +7 -5
  6. data/README.md +149 -3
  7. data/lib/keycloak-admin.rb +13 -0
  8. data/lib/keycloak-admin/client/client.rb +11 -3
  9. data/lib/keycloak-admin/client/client_client.rb +24 -0
  10. data/lib/keycloak-admin/client/client_role_mappings_client.rb +32 -0
  11. data/lib/keycloak-admin/client/group_client.rb +46 -0
  12. data/lib/keycloak-admin/client/realm_client.rb +54 -0
  13. data/lib/keycloak-admin/client/role_client.rb +32 -0
  14. data/lib/keycloak-admin/client/role_mapper_client.rb +20 -0
  15. data/lib/keycloak-admin/client/user_client.rb +44 -2
  16. data/lib/keycloak-admin/representation/camel_json.rb +1 -1
  17. data/lib/keycloak-admin/representation/client_representation.rb +16 -0
  18. data/lib/keycloak-admin/representation/federated_identity_representation.rb +15 -0
  19. data/lib/keycloak-admin/representation/group_representation.rb +15 -0
  20. data/lib/keycloak-admin/representation/realm_representation.rb +14 -0
  21. data/lib/keycloak-admin/representation/representation.rb +5 -1
  22. data/lib/keycloak-admin/representation/role_representation.rb +17 -0
  23. data/lib/keycloak-admin/representation/user_representation.rb +21 -14
  24. data/lib/keycloak-admin/resource/base_role_containing_resource.rb +26 -0
  25. data/lib/keycloak-admin/resource/group_resource.rb +7 -0
  26. data/lib/keycloak-admin/resource/user_resource.rb +7 -0
  27. data/lib/keycloak-admin/version.rb +1 -1
  28. data/spec/client/client_client_spec.rb +53 -0
  29. data/spec/client/client_role_mappings_client_spec.rb +82 -0
  30. data/spec/client/group_client_spec.rb +125 -0
  31. data/spec/client/realm_client_spec.rb +108 -0
  32. data/spec/client/role_client_spec.rb +83 -0
  33. data/spec/client/role_mapper_client_spec.rb +47 -0
  34. data/spec/client/user_client_spec.rb +105 -14
  35. data/spec/representation/user_representation_spec.rb +15 -0
  36. data/spec/resource/group_resource_spec.rb +14 -0
  37. data/spec/resource/user_resource_spec.rb +14 -0
  38. data/spec/spec_helper.rb +7 -0
  39. metadata +25 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 970da832a135573c026406dd6e24bebad0faadde
4
- data.tar.gz: 0116019f2c32443bbd8c9567b8243cb84e75da7a
2
+ SHA256:
3
+ metadata.gz: 4c3087f9b9079163b0648bd1a3ae30d3526fef7f8f5d7afc59f251b9f23e7507
4
+ data.tar.gz: 99eeb84049b48e7410e271f4633d0a79b765d9dd5bb4d185469eebe247c98b19
5
5
  SHA512:
6
- metadata.gz: 65fab8de261bdb5bbef86e05961e4c49858143d6b0eb3e1282ed13b67aa3d4b2e2a7bf6a54788cf02ebaee78eea9c2658644d54e70b45777e6348ac4867c199e
7
- data.tar.gz: b8ab004c2772051d424f277572b42c57ef523d04fc1f43274c97964bd4dc1291b54d24bb70b8785b0fe404c30a23f2bba2636efb244ac6a4eb663bc40e58708f
6
+ metadata.gz: 28d689fe25884746e02f3f1dba166a2c78472f7e897680b39efe2c10e782fe52a1f661265e59ee676f65a4ee8cd3cc3b99e77dcb9fc3e8a44b2a92ca976db038
7
+ data.tar.gz: d065e64a554f1991e1ec4be2c77cfb81d5e811a6db64d452bdafb7e1cf1e0ce4449444446374e9f09472fa07fee6f8a7468311ff44a86bfd7c5e1ff2cd573656
data/.gitignore CHANGED
@@ -5,4 +5,5 @@ test/dummy/db/*.sqlite3
5
5
  test/dummy/db/*.sqlite3-journal
6
6
  test/dummy/log/*.log
7
7
  test/dummy/tmp/
8
- *.gem
8
+ *.gem
9
+ .idea/
@@ -0,0 +1,70 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.7.5] - 2020-03-28
9
+
10
+ Thanks to @RomanHargrave
11
+ * Support for working with federated identity provider (broker) links
12
+
13
+ ## [0.7.4] - 2019-10-17
14
+
15
+ * Support for Rails 6
16
+
17
+ ## [0.7.3] - 2019-07-11
18
+
19
+ Thanks to @cederigo=
20
+ * For a given user, get her list of groups
21
+
22
+ ## [0.7.2] - 2019-06-17
23
+
24
+ Thanks to @vlad-ro:
25
+
26
+ * Get list of client role mappings for a group
27
+ * Save client role mappings for a user/group
28
+ * Save realm-level role mappings for a user/group
29
+
30
+ ## [0.7.1] - 2019-06-11
31
+
32
+ Thanks to @vlad-ro:
33
+
34
+ * List users
35
+ * List clients
36
+ * List groups, create/save a group
37
+ * List roles, save a role
38
+ * List realms, save/update/delete a realm
39
+ * Get list of client role mappings for a user
40
+ * Support passing rest client options for user save and search
41
+ * Support using gem without ActiveSupport
42
+
43
+ ## [0.7.0] - 2019-06-06
44
+
45
+ Thanks to @vlad-ro:
46
+
47
+ * Support passing rest client options
48
+ * More documentation
49
+ * More tests
50
+ * Better handling of timeouts
51
+
52
+ ## [0.6.5] - 2019-05-14
53
+
54
+ * Get user
55
+
56
+ ## [0.6.2] - 2019-05-14
57
+
58
+ * Update users
59
+
60
+ ## [0.6] - 2019-03-06
61
+
62
+ * Save a locale when creating a new user
63
+
64
+ ## [0.5] - 2018-01-26
65
+
66
+ * Client to access Custom REST API configurable-token
67
+
68
+ ## [0.3] - 2018-01-19
69
+
70
+ * Support of impersonation
data/Dockerfile CHANGED
@@ -1,4 +1,4 @@
1
- FROM ruby:2.3
1
+ FROM ruby:2.6.5
2
2
  RUN mkdir -p /usr/src/app/lib/keycloak-admin
3
3
  WORKDIR /usr/src/app
4
4
 
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- keycloak-admin (0.7.0)
4
+ keycloak-admin (0.7.5)
5
5
  http-cookie (~> 1.0, >= 1.0.3)
6
6
  rest-client (~> 2.0)
7
7
 
@@ -10,15 +10,17 @@ GEM
10
10
  specs:
11
11
  byebug (9.1.0)
12
12
  diff-lcs (1.3)
13
- domain_name (0.5.20180417)
13
+ domain_name (0.5.20190701)
14
14
  unf (>= 0.0.5, < 1.0.0)
15
+ http-accept (1.7.0)
15
16
  http-cookie (1.0.3)
16
17
  domain_name (~> 0.5)
17
- mime-types (3.2.2)
18
+ mime-types (3.3.1)
18
19
  mime-types-data (~> 3.2015)
19
- mime-types-data (3.2019.0331)
20
+ mime-types-data (3.2019.1009)
20
21
  netrc (0.11.0)
21
- rest-client (2.0.2)
22
+ rest-client (2.1.0)
23
+ http-accept (>= 1.7.0, < 2.0)
22
24
  http-cookie (>= 1.0.2, < 2.0)
23
25
  mime-types (>= 1.16, < 4.0)
24
26
  netrc (~> 0.8)
data/README.md CHANGED
@@ -12,7 +12,7 @@ This gem *does not* require Rails.
12
12
  For example, using `bundle`, add this line to your Gemfile.
13
13
 
14
14
  ```ruby
15
- gem "keycloak-admin", "0.7.0"
15
+ gem "keycloak-admin", "0.7.5"
16
16
  ```
17
17
 
18
18
  ## Login
@@ -58,6 +58,7 @@ KeycloakAdmin.configure do |config|
58
58
  config.username = ENV["KEYCLOAK_ADMIN_USER"]
59
59
  config.password = ENV["KEYCLOAK_ADMIN_PASSWORD"]
60
60
  config.logger = Rails.logger
61
+ config.rest_client_options = { verify_ssl: OpenSSL::SSL::VERIFY_NONE }
61
62
  end
62
63
  ```
63
64
  This example is autoloaded in a Rails environment.
@@ -76,6 +77,7 @@ All options have a default value. However, all of them can be changed in your in
76
77
  | `username` | `nil`| String | Optional | Username to access the Admin REST API. Recommended if `user_service_account` is set to `false`. | `mummy` |
77
78
  | `password` | `nil`| String | Optional | Clear password to access the Admin REST API. Recommended if `user_service_account` is set to `false`. | `bobby` |
78
79
  | `logger` | `Logger.new(STDOUT)`| Logger | Optional | The logger used by `keycloak-admin` | `Rails.logger` | 
80
+ | `rest_client_options` | `{}`| Hash | Optional | Options to pass to `RestClient` | `{ verify_ssl: OpenSSL::SSL::VERIFY_NONE }` | 
79
81
 
80
82
 
81
83
  ## Use Case
@@ -83,11 +85,19 @@ All options have a default value. However, all of them can be changed in your in
83
85
  ### Supported features
84
86
 
85
87
  * Get an access token
86
- * Create/update/get a user
88
+ * Create/update/get/delete a user
89
+ * Get list of users, search for user(s)
87
90
  * Reset credentials
88
- * Delete a user
89
91
  * Impersonate a user
90
92
  * Exchange a configurable token
93
+ * Get list of clients
94
+ * Get list of groups, create/save a group
95
+ * Get list of roles, save a role
96
+ * Get list of realms, save/update/delete a realm
97
+ * Get list of client role mappings for a user/group
98
+ * Save client role mappings for a user/group
99
+ * Save realm-level role mappings for a user/group
100
+ * Link/Unlink users to federated identity provider brokers
91
101
 
92
102
  ### Get an access token
93
103
 
@@ -114,6 +124,14 @@ Returns an array of `KeycloakAdmin::UserRepresentation`.
114
124
  KeycloakAdmin.realm("a_realm").users.search("a_username_or_an_email")
115
125
  ```
116
126
 
127
+ ### List all users in a realm
128
+
129
+ Returns an array of `KeycloakAdmin::UserRepresentation`.
130
+
131
+ ```ruby
132
+ KeycloakAdmin.realm("a_realm").users.list
133
+ ```
134
+
117
135
  ### Save a user
118
136
 
119
137
  Returns the provided `user`, which must be of type `KeycloakAdmin::UserRepresentation`.
@@ -188,6 +206,134 @@ token_lifespan_in_seconds = 20
188
206
  KeycloakAdmin.realm("a_realm").configurable_token.exchange_with(user_access_token, token_lifespan_in_seconds)
189
207
  ```
190
208
 
209
+ ### Get list of realms
210
+
211
+ Returns an array of `KeycloakAdmin::RealmRepresentation`.
212
+
213
+ ```ruby
214
+ KeycloakAdmin.realm("master").list
215
+ ```
216
+
217
+ ### Save a realm
218
+
219
+ Takes `realm` of type `KeycloakAdmin::RealmRepresentation`, or an object implementing `to_json`, such as a `Hash`.
220
+
221
+ ```ruby
222
+ KeycloakAdmin.realm(nil).save(realm)
223
+ ```
224
+
225
+ ### Update a realm
226
+
227
+ If you want to update its entire entity. To update some specific attributes, provide an object implementing `to_json`, such as a `Hash`.
228
+
229
+ ```ruby
230
+ KeycloakAdmin.realm("a_realm").update({
231
+ smtpServer: { host: 'test_host' }
232
+ })
233
+ ```
234
+
235
+ ### Delete a realm
236
+
237
+ ```ruby
238
+ KeycloakAdmin.realm("a_realm").delete
239
+ ```
240
+
241
+ ### Get list of clients in a realm
242
+
243
+ Returns an array of `KeycloakAdmin::ClientRepresentation`.
244
+
245
+ ```ruby
246
+ KeycloakAdmin.realm("a_realm").clients.list
247
+ ```
248
+
249
+ ### Get list of groups in a realm
250
+
251
+ Returns an array of `KeycloakAdmin::GroupRepresentation`.
252
+
253
+ ```ruby
254
+ KeycloakAdmin.realm("a_realm").groups.list
255
+ ```
256
+
257
+ ### Save a group
258
+
259
+ Returns the id of saved `group` provided, which must be of type `KeycloakAdmin::GroupRepresentation`.
260
+
261
+ ```ruby
262
+ KeycloakAdmin.realm("a_realm").groups.save(group)
263
+ ```
264
+
265
+ ### Create and save a group with a name and path
266
+
267
+ Returns the id of created group.
268
+
269
+ ```ruby
270
+ group_name = "test"
271
+ group_path = "/top"
272
+ group_id = KeycloakAdmin.realm("a_realm").groups.create!(group_name, group_path)
273
+ ```
274
+
275
+ ### Get list of roles in a realm
276
+
277
+ Returns an array of `KeycloakAdmin::RoleRepresentation`.
278
+
279
+ ```ruby
280
+ KeycloakAdmin.realm("a_realm").roles.list
281
+ ```
282
+
283
+ ### Save a role
284
+
285
+ Takes `role`, which must be of type `KeycloakAdmin::RoleRepresentation`.
286
+
287
+ ```ruby
288
+ KeycloakAdmin.realm("a_realm").roles.save(role)
289
+ ```
290
+
291
+ ### Get list of client role mappings for a user/group
292
+
293
+ Returns an array of `KeycloakAdmin::RoleRepresentation`.
294
+
295
+ ```ruby
296
+ user_id = "95985b21-d884-4bbd-b852-cb8cd365afc2"
297
+ client_id = "1869e876-71b4-4de2-849e-66540db3a098"
298
+ KeycloakAdmin.realm("a_realm").user(user_id).client_role_mappings(client_id).list_available
299
+ ```
300
+ or
301
+ ```ruby
302
+ group_id = "3a63b5c0-ef8a-47fd-86ed-b5fead18d9b8"
303
+ client_id = "1869e876-71b4-4de2-849e-66540db3a098"
304
+ KeycloakAdmin.realm("a_realm").group(group_id).client_role_mappings(client_id).list_available
305
+ ```
306
+
307
+ ### Save list of client role mappings for a user/group
308
+
309
+ Takes `role_list`, which must be an array of type `KeycloakAdmin::RoleRepresentation`.
310
+
311
+ ```ruby
312
+ user_id = "95985b21-d884-4bbd-b852-cb8cd365afc2"
313
+ client_id = "1869e876-71b4-4de2-849e-66540db3a098"
314
+ KeycloakAdmin.realm("a_realm").user(user_id).client_role_mappings(client_id).save(role_list)
315
+ ```
316
+ or
317
+ ```ruby
318
+ group_id = "3a63b5c0-ef8a-47fd-86ed-b5fead18d9b8"
319
+ client_id = "1869e876-71b4-4de2-849e-66540db3a098"
320
+ KeycloakAdmin.realm("a_realm").group(group_id).client_role_mappings(client_id).save(role_list)
321
+ ```
322
+
323
+ ### Save list of realm-level role mappings for a user/group
324
+
325
+ Takes `role_list`, which must be an array of type `KeycloakAdmin::RoleRepresentation`.
326
+
327
+ ```ruby
328
+ user_id = "95985b21-d884-4bbd-b852-cb8cd365afc2"
329
+ KeycloakAdmin.realm("a_realm").user(user_id).role_mapper.save_realm_level(role_list)
330
+ ```
331
+ or
332
+ ```ruby
333
+ group_id = "3a63b5c0-ef8a-47fd-86ed-b5fead18d9b8"
334
+ KeycloakAdmin.realm("a_realm").group(group_id).role_mapper.save_realm_level(role_list)
335
+ ```
336
+
191
337
  ## How to execute library tests
192
338
 
193
339
  From the `keycloak-admin-api` directory:
@@ -2,17 +2,30 @@ require "logger"
2
2
 
3
3
  require_relative "keycloak-admin/configuration"
4
4
  require_relative "keycloak-admin/client/client"
5
+ require_relative "keycloak-admin/client/client_client"
6
+ require_relative "keycloak-admin/client/client_role_mappings_client"
7
+ require_relative "keycloak-admin/client/group_client"
5
8
  require_relative "keycloak-admin/client/realm_client"
9
+ require_relative "keycloak-admin/client/role_client"
10
+ require_relative "keycloak-admin/client/role_mapper_client"
6
11
  require_relative "keycloak-admin/client/token_client"
7
12
  require_relative "keycloak-admin/client/user_client"
8
13
  require_relative "keycloak-admin/client/configurable_token_client"
9
14
  require_relative "keycloak-admin/representation/camel_json"
10
15
  require_relative "keycloak-admin/representation/representation"
16
+ require_relative "keycloak-admin/representation/client_representation"
17
+ require_relative "keycloak-admin/representation/group_representation"
11
18
  require_relative "keycloak-admin/representation/token_representation"
12
19
  require_relative "keycloak-admin/representation/impersonation_redirection_representation"
13
20
  require_relative "keycloak-admin/representation/impersonation_representation"
14
21
  require_relative "keycloak-admin/representation/credential_representation"
22
+ require_relative "keycloak-admin/representation/realm_representation"
23
+ require_relative "keycloak-admin/representation/role_representation"
24
+ require_relative "keycloak-admin/representation/federated_identity_representation"
15
25
  require_relative "keycloak-admin/representation/user_representation"
26
+ require_relative "keycloak-admin/resource/base_role_containing_resource"
27
+ require_relative "keycloak-admin/resource/group_resource"
28
+ require_relative "keycloak-admin/resource/user_resource"
16
29
 
17
30
  module KeycloakAdmin
18
31
 
@@ -9,13 +9,13 @@ module KeycloakAdmin
9
9
  @configuration.server_url
10
10
  end
11
11
 
12
- def token
13
- @token ||= KeycloakAdmin.realm(@configuration.client_realm_name).token.get
12
+ def current_token
13
+ @current_token ||= KeycloakAdmin.realm(@configuration.client_realm_name).token.get
14
14
  end
15
15
 
16
16
  def headers
17
17
  {
18
- Authorization: "Bearer #{token.access_token}",
18
+ Authorization: "Bearer #{current_token.access_token}",
19
19
  content_type: :json,
20
20
  accept: :json
21
21
  }
@@ -29,6 +29,14 @@ module KeycloakAdmin
29
29
  http_error(e.response)
30
30
  end
31
31
 
32
+ def created_id(response)
33
+ unless response.net_http_res.is_a? Net::HTTPCreated
34
+ raise "Create method returned status #{response.net_http_res.message} (Code: #{response.net_http_res.code}); expected status: Created (201)"
35
+ end
36
+ (_head, _separator, id) = response.headers[:location].rpartition('/')
37
+ id
38
+ end
39
+
32
40
  private
33
41
 
34
42
  def http_error(response)
@@ -0,0 +1,24 @@
1
+ module KeycloakAdmin
2
+ class ClientClient < Client
3
+ def initialize(configuration, realm_client)
4
+ super(configuration)
5
+ raise ArgumentError.new("realm must be defined") unless realm_client.name_defined?
6
+ @realm_client = realm_client
7
+ end
8
+
9
+ def list
10
+ response = execute_http do
11
+ RestClient::Resource.new(clients_url, @configuration.rest_client_options).get(headers)
12
+ end
13
+ JSON.parse(response).map { |client_as_hash| ClientRepresentation.from_hash(client_as_hash) }
14
+ end
15
+
16
+ def clients_url(id=nil)
17
+ if id
18
+ "#{@realm_client.realm_admin_url}/clients/#{id}"
19
+ else
20
+ "#{@realm_client.realm_admin_url}/clients"
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,32 @@
1
+ module KeycloakAdmin
2
+ class ClientRoleMappingsClient < Client
3
+ def initialize(configuration, user_resource, client_id)
4
+ super(configuration)
5
+ @user_resource = user_resource
6
+ @client_id = client_id
7
+ end
8
+
9
+ def list_available
10
+ response = execute_http do
11
+ RestClient::Resource.new(list_available_url, @configuration.rest_client_options).get(headers)
12
+ end
13
+ JSON.parse(response).map { |role_as_hash| RoleRepresentation.from_hash(role_as_hash) }
14
+ end
15
+
16
+ def save(role_representation_list)
17
+ execute_http do
18
+ RestClient::Resource.new(base_url, @configuration.rest_client_options).post(
19
+ role_representation_list.to_json, headers
20
+ )
21
+ end
22
+ end
23
+
24
+ def list_available_url
25
+ "#{@user_resource.resource_url}/role-mappings/clients/#{@client_id}/available"
26
+ end
27
+
28
+ def base_url
29
+ "#{@user_resource.resource_url}/role-mappings/clients/#{@client_id}"
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,46 @@
1
+ module KeycloakAdmin
2
+ class GroupClient < Client
3
+ def initialize(configuration, realm_client)
4
+ super(configuration)
5
+ raise ArgumentError.new("realm must be defined") unless realm_client.name_defined?
6
+ @realm_client = realm_client
7
+ end
8
+
9
+ def list
10
+ response = execute_http do
11
+ RestClient::Resource.new(groups_url, @configuration.rest_client_options).get(headers)
12
+ end
13
+ JSON.parse(response).map { |group_as_hash| GroupRepresentation.from_hash(group_as_hash) }
14
+ end
15
+
16
+ def create!(name, path = nil)
17
+ response = save(build(name, path))
18
+ created_id(response)
19
+ end
20
+
21
+ def save(group_representation)
22
+ execute_http do
23
+ RestClient::Resource.new(groups_url, @configuration.rest_client_options).post(
24
+ group_representation.to_json, headers
25
+ )
26
+ end
27
+ end
28
+
29
+ def groups_url(id=nil)
30
+ if id
31
+ "#{@realm_client.realm_admin_url}/groups/#{id}"
32
+ else
33
+ "#{@realm_client.realm_admin_url}/groups"
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def build(name, path)
40
+ group = GroupRepresentation.new
41
+ group.name = name
42
+ group.path = path
43
+ group
44
+ end
45
+ end
46
+ end