keycloak-admin 0.7.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/CHANGELOG.md +48 -0
  4. data/Gemfile.lock +1 -1
  5. data/README.md +109 -2
  6. data/lib/keycloak-admin.rb +9 -0
  7. data/lib/keycloak-admin/client/client.rb +11 -3
  8. data/lib/keycloak-admin/client/client_client.rb +24 -0
  9. data/lib/keycloak-admin/client/client_role_mappings_client.rb +20 -0
  10. data/lib/keycloak-admin/client/group_client.rb +46 -0
  11. data/lib/keycloak-admin/client/realm_client.rb +50 -0
  12. data/lib/keycloak-admin/client/role_client.rb +32 -0
  13. data/lib/keycloak-admin/client/user_client.rb +9 -2
  14. data/lib/keycloak-admin/representation/camel_json.rb +1 -1
  15. data/lib/keycloak-admin/representation/client_representation.rb +16 -0
  16. data/lib/keycloak-admin/representation/group_representation.rb +15 -0
  17. data/lib/keycloak-admin/representation/realm_representation.rb +14 -0
  18. data/lib/keycloak-admin/representation/representation.rb +4 -0
  19. data/lib/keycloak-admin/representation/role_representation.rb +17 -0
  20. data/lib/keycloak-admin/representation/user_representation.rb +13 -13
  21. data/lib/keycloak-admin/resource/user_resource.rb +18 -0
  22. data/lib/keycloak-admin/version.rb +1 -1
  23. data/spec/client/client_client_spec.rb +53 -0
  24. data/spec/client/client_role_mappings_client_spec.rb +48 -0
  25. data/spec/client/group_client_spec.rb +125 -0
  26. data/spec/client/realm_client_spec.rb +108 -0
  27. data/spec/client/role_client_spec.rb +83 -0
  28. data/spec/client/user_client_spec.rb +105 -14
  29. data/spec/representation/user_representation_spec.rb +15 -0
  30. data/spec/resource/user_resource_spec.rb +14 -0
  31. data/spec/spec_helper.rb +7 -0
  32. metadata +18 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 970da832a135573c026406dd6e24bebad0faadde
4
- data.tar.gz: 0116019f2c32443bbd8c9567b8243cb84e75da7a
3
+ metadata.gz: 39322dd0c0035b30a67644fa401bbe55c835dbf1
4
+ data.tar.gz: 268b16b6d6e20aac7a44ba993a76114f8d86e1b8
5
5
  SHA512:
6
- metadata.gz: 65fab8de261bdb5bbef86e05961e4c49858143d6b0eb3e1282ed13b67aa3d4b2e2a7bf6a54788cf02ebaee78eea9c2658644d54e70b45777e6348ac4867c199e
7
- data.tar.gz: b8ab004c2772051d424f277572b42c57ef523d04fc1f43274c97964bd4dc1291b54d24bb70b8785b0fe404c30a23f2bba2636efb244ac6a4eb663bc40e58708f
6
+ metadata.gz: 8f57fe6316a4378bfc8e3c90e6732b5977fc2f14a7871f0b69fb2790bcf60ec047a4a3841e8075eabfdd83d3961d3f1c4bdc38ac2a13a630e8a236e098d877bd
7
+ data.tar.gz: bb2384c3c9c16d498baade9a2ef02766396ca370724114da3b0136976bca61f6a9a6912d106ef5420f3bbdba65f06c88daa476088e77f28c2eaa73546857e1f6
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,48 @@
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.1] - Next version
9
+
10
+ Thanks to @vlad-ro:
11
+
12
+ * List users
13
+ * List clients
14
+ * List groups, create/save a group
15
+ * List roles, save a role
16
+ * List realms, save/update/delete a realm
17
+ * Get list of client role mappings for a user
18
+ * Support passing rest client options for user save and search
19
+ * Support using gem without ActiveSupport
20
+
21
+ ## [0.7.0] - 2019-06-11
22
+
23
+ Thanks to @vlad-ro:
24
+
25
+ * Support passing rest client options
26
+ * More documentation
27
+ * More tests
28
+ * Better handling of timeouts
29
+
30
+ ## [0.6.5] - 2019-05-14
31
+
32
+ * Get user
33
+
34
+ ## [0.6.2] - 2019-05-14
35
+
36
+ * Update users
37
+
38
+ ## [0.6] - 2019-03-06
39
+
40
+ * Save a locale when creating a new user
41
+
42
+ ## [0.5] - 2018-01-26
43
+
44
+ * Client to access Custom REST API configurable-token
45
+
46
+ ## [0.3] - 2018-01-19
47
+
48
+ * Support of impersonation
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- keycloak-admin (0.7.0)
4
+ keycloak-admin (0.7.1)
5
5
  http-cookie (~> 1.0, >= 1.0.3)
6
6
  rest-client (~> 2.0)
7
7
 
data/README.md CHANGED
@@ -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,16 @@ 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
91
98
 
92
99
  ### Get an access token
93
100
 
@@ -114,6 +121,14 @@ Returns an array of `KeycloakAdmin::UserRepresentation`.
114
121
  KeycloakAdmin.realm("a_realm").users.search("a_username_or_an_email")
115
122
  ```
116
123
 
124
+ ### List all users in a realm
125
+
126
+ Returns an array of `KeycloakAdmin::UserRepresentation`.
127
+
128
+ ```ruby
129
+ KeycloakAdmin.realm("a_realm").users.list
130
+ ```
131
+
117
132
  ### Save a user
118
133
 
119
134
  Returns the provided `user`, which must be of type `KeycloakAdmin::UserRepresentation`.
@@ -188,6 +203,98 @@ token_lifespan_in_seconds = 20
188
203
  KeycloakAdmin.realm("a_realm").configurable_token.exchange_with(user_access_token, token_lifespan_in_seconds)
189
204
  ```
190
205
 
206
+ ### Get list of realms
207
+
208
+ Returns an array of `KeycloakAdmin::RealmRepresentation`.
209
+
210
+ ```ruby
211
+ KeycloakAdmin.realm("master").list
212
+ ```
213
+
214
+ ### Save a realm
215
+
216
+ Takes `realm` of type `KeycloakAdmin::RealmRepresentation`, or an object implementing `to_json`, such as a `Hash`.
217
+
218
+ ```ruby
219
+ KeycloakAdmin.realm(nil).save(realm)
220
+ ```
221
+
222
+ ### Update a realm
223
+
224
+ If you want to update its entire entity. To update some specific attributes, provide an object implementing `to_json`, such as a `Hash`.
225
+
226
+ ```ruby
227
+ KeycloakAdmin.realm("a_realm").update({
228
+ smtpServer: { host: 'test_host' }
229
+ })
230
+ ```
231
+
232
+ ### Delete a realm
233
+
234
+ ```ruby
235
+ KeycloakAdmin.realm("a_realm").delete
236
+ ```
237
+
238
+ ### Get list of clients in a realm
239
+
240
+ Returns an array of `KeycloakAdmin::ClientRepresentation`.
241
+
242
+ ```ruby
243
+ KeycloakAdmin.realm("a_realm").clients.list
244
+ ```
245
+
246
+ ### Get list of groups in a realm
247
+
248
+ Returns an array of `KeycloakAdmin::GroupRepresentation`.
249
+
250
+ ```ruby
251
+ KeycloakAdmin.realm("a_realm").groups.list
252
+ ```
253
+
254
+ ### Save a group
255
+
256
+ Returns the id of saved `group` provided, which must be of type `KeycloakAdmin::GroupRepresentation`.
257
+
258
+ ```ruby
259
+ KeycloakAdmin.realm("a_realm").groups.save(group)
260
+ ```
261
+
262
+ ### Create and save a group with a name and path
263
+
264
+ Returns the id of created group.
265
+
266
+ ```ruby
267
+ group_name = "test"
268
+ group_path = "/top"
269
+ group_id = KeycloakAdmin.realm("a_realm").groups.create!(group_name, group_path)
270
+ ```
271
+
272
+ ### Get list of roles in a realm
273
+
274
+ Returns an array of `KeycloakAdmin::RoleRepresentation`.
275
+
276
+ ```ruby
277
+ KeycloakAdmin.realm("a_realm").roles.list
278
+ ```
279
+
280
+ ### Save a role
281
+
282
+ Takes `role`, which must be of type `KeycloakAdmin::RoleRepresentation`.
283
+
284
+ ```ruby
285
+ KeycloakAdmin.realm("a_realm").roles.save(role)
286
+ ```
287
+
288
+ ### Get list of client role mappings for a user
289
+
290
+ Returns an array of `KeycloakAdmin::RoleRepresentation`.
291
+
292
+ ```ruby
293
+ user_id = "95985b21-d884-4bbd-b852-cb8cd365afc2"
294
+ client_id = "1869e876-71b4-4de2-849e-66540db3a098"
295
+ KeycloakAdmin.realm("a_realm").user(user_id).client_role_mappings(client_id).list_available
296
+ ```
297
+
191
298
  ## How to execute library tests
192
299
 
193
300
  From the `keycloak-admin-api` directory:
@@ -2,17 +2,26 @@ 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"
6
10
  require_relative "keycloak-admin/client/token_client"
7
11
  require_relative "keycloak-admin/client/user_client"
8
12
  require_relative "keycloak-admin/client/configurable_token_client"
9
13
  require_relative "keycloak-admin/representation/camel_json"
10
14
  require_relative "keycloak-admin/representation/representation"
15
+ require_relative "keycloak-admin/representation/client_representation"
16
+ require_relative "keycloak-admin/representation/group_representation"
11
17
  require_relative "keycloak-admin/representation/token_representation"
12
18
  require_relative "keycloak-admin/representation/impersonation_redirection_representation"
13
19
  require_relative "keycloak-admin/representation/impersonation_representation"
14
20
  require_relative "keycloak-admin/representation/credential_representation"
21
+ require_relative "keycloak-admin/representation/realm_representation"
22
+ require_relative "keycloak-admin/representation/role_representation"
15
23
  require_relative "keycloak-admin/representation/user_representation"
24
+ require_relative "keycloak-admin/resource/user_resource"
16
25
 
17
26
  module KeycloakAdmin
18
27
 
@@ -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,20 @@
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 list_available_url
17
+ "#{@user_resource.resource_url}/role-mappings/clients/#{@client_id}/available"
18
+ end
19
+ end
20
+ 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
@@ -5,6 +5,36 @@ module KeycloakAdmin
5
5
  @realm_name = realm_name
6
6
  end
7
7
 
8
+ def list
9
+ response = execute_http do
10
+ RestClient::Resource.new(realm_list_url, @configuration.rest_client_options).get(headers)
11
+ end
12
+ JSON.parse(response).map { |realm_as_hash| RealmRepresentation.from_hash(realm_as_hash) }
13
+ end
14
+
15
+ def delete
16
+ execute_http do
17
+ RestClient::Resource.new(realm_admin_url, @configuration.rest_client_options).delete(headers)
18
+ end
19
+ true
20
+ end
21
+
22
+ def save(realm_representation)
23
+ execute_http do
24
+ RestClient::Resource.new(realm_list_url, @configuration.rest_client_options).post(
25
+ realm_representation.to_json, headers
26
+ )
27
+ end
28
+ end
29
+
30
+ def update(realm_representation_body)
31
+ execute_http do
32
+ RestClient::Resource.new(realm_admin_url, @configuration.rest_client_options).put(
33
+ realm_representation_body.to_json, headers
34
+ )
35
+ end
36
+ end
37
+
8
38
  def realm_url
9
39
  if @realm_name
10
40
  "#{server_url}/realms/#{@realm_name}"
@@ -21,6 +51,10 @@ module KeycloakAdmin
21
51
  end
22
52
  end
23
53
 
54
+ def realm_list_url
55
+ "#{server_url}/admin/realms"
56
+ end
57
+
24
58
  def token
25
59
  TokenClient.new(@configuration, self)
26
60
  end
@@ -29,10 +63,26 @@ module KeycloakAdmin
29
63
  ConfigurableTokenClient.new(@configuration, self)
30
64
  end
31
65
 
66
+ def clients
67
+ ClientClient.new(@configuration, self)
68
+ end
69
+
70
+ def groups
71
+ GroupClient.new(@configuration, self)
72
+ end
73
+
74
+ def roles
75
+ RoleClient.new(@configuration, self)
76
+ end
77
+
32
78
  def users
33
79
  UserClient.new(@configuration, self)
34
80
  end
35
81
 
82
+ def user(user_id)
83
+ UserResource.new(@configuration, self, user_id)
84
+ end
85
+
36
86
  def name_defined?
37
87
  !@realm_name.nil?
38
88
  end