keycloak-admin 0.7.2 → 0.7.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: ef2112e82d91e64a41f612eb13dd37bbd6e7b09b
4
- data.tar.gz: 66218b9a1051a9d592d236235ddb1ac6e22161cf
2
+ SHA256:
3
+ metadata.gz: 8be78b3854a7d3ac95ddb700599f49f8b108f2eda85de66df200aa5e362b7f5e
4
+ data.tar.gz: 81103f2021f10e78c92327d7beace0ea30bc23175e3605c408e70f01a172203b
5
5
  SHA512:
6
- metadata.gz: 8034f148b70ded3b877a486865eadec656bb6a551cc71630d326aa3f81c4bbf2ed87541e6aa7ec5528934cad3d1dab65cc9dbf8adf747e3bf9f5b61531b8a01c
7
- data.tar.gz: cd4abc841445b3e73b4ee385b2e0a762c27a927d02a6814752929650fe6ccc37e06c8ec8e1b73552ede40f1e1652571032ed0ede0fc107ca3eec49d69dcd1e36
6
+ metadata.gz: 83bda7a2b12cd6384710234618392aebfe0b29aa61378bf8350c8c8b3c70ad9725293f150c0074137351b21825cd3798d6ca180180a4b5d9c84909bef67a32b3
7
+ data.tar.gz: c052198198d30a8978229dfc71d2d5cb0d26db94e22291e6286dea7d8133b2060d5d658f26fc5e7e5f4b9b35fc11f3dce0eff13c1451aa48e85ee2678e90fde6
@@ -5,6 +5,30 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.7.7] - 2020-07-10
9
+
10
+ * Fix: `Replace request method shorthand with .execute for proper RestClient option support` (thanks to @RomanHargrave)
11
+ * When sending action emails, add lifespan as an optional parameter (thanks to @hobbypunk90)
12
+
13
+ ## [0.7.6] - 2020-06-22
14
+
15
+ Thanks to @hobbypunk90
16
+ * Support for action emails and send forgot passsword mail
17
+
18
+ ## [0.7.5] - 2020-03-28
19
+
20
+ Thanks to @RomanHargrave
21
+ * Support for working with federated identity provider (broker) links
22
+
23
+ ## [0.7.4] - 2019-10-17
24
+
25
+ * Support for Rails 6
26
+
27
+ ## [0.7.3] - 2019-07-11
28
+
29
+ Thanks to @cederigo:
30
+ * For a given user, get her list of groups
31
+
8
32
  ## [0.7.2] - 2019-06-17
9
33
 
10
34
  Thanks to @vlad-ro:
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.2)
4
+ keycloak-admin (0.7.7)
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.2020.0512)
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)
@@ -37,7 +39,7 @@ GEM
37
39
  rspec-support (3.7.0)
38
40
  unf (0.1.4)
39
41
  unf_ext
40
- unf_ext (0.0.7.6)
42
+ unf_ext (0.0.7.7)
41
43
 
42
44
  PLATFORMS
43
45
  ruby
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.2"
15
+ gem "keycloak-admin", "0.7.7"
16
16
  ```
17
17
 
18
18
  ## Login
@@ -97,6 +97,9 @@ All options have a default value. However, all of them can be changed in your in
97
97
  * Get list of client role mappings for a user/group
98
98
  * Save client role mappings for a user/group
99
99
  * Save realm-level role mappings for a user/group
100
+ * Link/Unlink users to federated identity provider brokers
101
+ * Execute actions emails
102
+ * Send forgot passsword mail
100
103
 
101
104
  ### Get an access token
102
105
 
@@ -340,8 +343,4 @@ From the `keycloak-admin-api` directory:
340
343
  ```
341
344
  $ docker build . -t keycloak-admin:test
342
345
  $ docker run -v `pwd`:/usr/src/app/ keycloak-admin:test bundle exec rspec spec
343
- ```
344
-
345
- ## Future work
346
-
347
- * Allow authentication using JWT assertions
346
+ ```
@@ -21,6 +21,7 @@ require_relative "keycloak-admin/representation/impersonation_representation"
21
21
  require_relative "keycloak-admin/representation/credential_representation"
22
22
  require_relative "keycloak-admin/representation/realm_representation"
23
23
  require_relative "keycloak-admin/representation/role_representation"
24
+ require_relative "keycloak-admin/representation/federated_identity_representation"
24
25
  require_relative "keycloak-admin/representation/user_representation"
25
26
  require_relative "keycloak-admin/resource/base_role_containing_resource"
26
27
  require_relative "keycloak-admin/resource/group_resource"
@@ -16,13 +16,18 @@ module KeycloakAdmin
16
16
 
17
17
  def exchange_with(user_access_token, token_lifespan_in_seconds)
18
18
  response = execute_http do
19
- RestClient.post(token_url, {
20
- tokenLifespanInSeconds: token_lifespan_in_seconds
21
- }.to_json, {
22
- Authorization: "Bearer #{user_access_token}",
23
- content_type: :json,
24
- accept: :json
25
- })
19
+ RestClient::Request.execute(
20
+ @configuration.rest_client_options.merge(
21
+ method: :post,
22
+ url: token_url,
23
+ payload: { tokenLifespanInSeconds: token_lifespan_in_seconds }.to_json,
24
+ headers: {
25
+ Authorization: "Bearer #{user_access_token}",
26
+ content_type: :json,
27
+ accept: :json
28
+ }
29
+ )
30
+ )
26
31
  end
27
32
  TokenRepresentation.from_json(response.body)
28
33
  end
@@ -21,7 +21,14 @@ module KeycloakAdmin
21
21
  end
22
22
 
23
23
  def update(user_id, user_representation_body)
24
- RestClient.put(users_url(user_id), user_representation_body.to_json, headers)
24
+ RestClient::Request.execute(
25
+ @configuration.rest_client_options.merge(
26
+ method: :put,
27
+ url: users_url(user_id),
28
+ payload: user_representation_body.to_json,
29
+ headers: headers
30
+ )
31
+ )
25
32
  end
26
33
 
27
34
  def get(user_id)
@@ -50,13 +57,35 @@ module KeycloakAdmin
50
57
  true
51
58
  end
52
59
 
60
+ def groups(user_id)
61
+ response = execute_http do
62
+ RestClient::Resource.new(groups_url(user_id), @configuration.rest_client_options).get(headers)
63
+ end
64
+ JSON.parse(response).map { |group_as_hash| GroupRepresentation.from_hash(group_as_hash) }
65
+ end
66
+
53
67
  def update_password(user_id, new_password)
54
68
  execute_http do
55
- RestClient.put(reset_password_url(user_id), {
56
- type: "password",
57
- value: new_password,
58
- temporary: false
59
- }.to_json, headers)
69
+ RestClient::Request.execute(
70
+ @configuration.rest_client_options.merge(
71
+ method: :put,
72
+ url: reset_password_url(user_id),
73
+ payload: { type: 'password', value: new_password, temporary: false }.to_json,
74
+ headers: headers
75
+ )
76
+ )
77
+ end
78
+ user_id
79
+ end
80
+
81
+ def forgot_password(user_id, lifespan=nil)
82
+ execute_actions_email(user_id, ["UPDATE_PASSWORD"], lifespan)
83
+ end
84
+
85
+ def execute_actions_email(user_id, actions=[], lifespan=nil)
86
+ execute_http do
87
+ lifespan_param = lifespan.nil? ? "" : "lifespan=#{lifespan.seconds}"
88
+ RestClient.put("#{execute_actions_email_url(user_id)}?#{lifespan_param}", actions.to_json, headers)
60
89
  end
61
90
  user_id
62
91
  end
@@ -64,7 +93,14 @@ module KeycloakAdmin
64
93
  def impersonate(user_id)
65
94
  impersonation = get_redirect_impersonation(user_id)
66
95
  response = execute_http do
67
- RestClient.post(impersonation.impersonation_url, impersonation.body.to_json, impersonation.headers)
96
+ RestClient::Request.execute(
97
+ @configuration.rest_client_options.merge(
98
+ method: :post,
99
+ url: impersonation.impersonation_url,
100
+ payload: impersonation.body.to_json,
101
+ headers: impersonation.headers
102
+ )
103
+ )
68
104
  end
69
105
  ImpersonationRepresentation.from_response(response, @configuration.server_domain)
70
106
  end
@@ -73,6 +109,30 @@ module KeycloakAdmin
73
109
  ImpersonationRedirectionRepresentation.from_url(impersonation_url(user_id), headers)
74
110
  end
75
111
 
112
+ def link_idp(user_id, idp_id, idp_user_id, idp_username)
113
+ fed_id_rep = FederatedIdentityRepresentation.new
114
+ fed_id_rep.user_id = idp_user_id
115
+ fed_id_rep.user_name = idp_username
116
+ fed_id_rep.identity_provider = idp_id
117
+
118
+ execute_http do
119
+ RestClient::Request.execute(
120
+ @configuration.rest_client_options.merge(
121
+ method: :post,
122
+ url: federated_identity_url(user_id, idp_id),
123
+ payload: fed_id_rep.to_json,
124
+ headers: headers
125
+ )
126
+ )
127
+ end
128
+ end
129
+
130
+ def unlink_idp(user_id, idp_id)
131
+ execute_http do
132
+ RestClient::Resource.new(federated_identity_url(user_id, idp_id), @configuration.rest_client_options).delete(headers)
133
+ end
134
+ end
135
+
76
136
  def users_url(id=nil)
77
137
  if id
78
138
  "#{@realm_client.realm_admin_url}/users/#{id}"
@@ -86,11 +146,27 @@ module KeycloakAdmin
86
146
  "#{users_url(user_id)}/reset-password"
87
147
  end
88
148
 
149
+ def execute_actions_email_url(user_id)
150
+ raise ArgumentError.new("user_id must be defined") if user_id.nil?
151
+ "#{users_url(user_id)}/execute-actions-email"
152
+ end
153
+
154
+ def groups_url(user_id)
155
+ raise ArgumentError.new("user_id must be defined") if user_id.nil?
156
+ "#{users_url(user_id)}/groups"
157
+ end
158
+
89
159
  def impersonation_url(user_id)
90
160
  raise ArgumentError.new("user_id must be defined") if user_id.nil?
91
161
  "#{users_url(user_id)}/impersonation"
92
162
  end
93
163
 
164
+ def federated_identity_url(user_id, identity_provider)
165
+ raise ArgumentError.new("user_id must be defined") if user_id.nil?
166
+ raise ArgumentError.new("identity_provider must be defined") if identity_provider.nil?
167
+ "#{users_url(user_id)}/federated-identity/#{identity_provider}"
168
+ end
169
+
94
170
  private
95
171
 
96
172
  def build(username, email, password, email_verified, locale)
@@ -0,0 +1,15 @@
1
+ module KeycloakAdmin
2
+ class FederatedIdentityRepresentation < Representation
3
+ attr_accessor :identity_provider,
4
+ :user_id,
5
+ :user_name
6
+
7
+ def self.from_hash(hash)
8
+ rep = new
9
+ rep.identity_provider = hash['identityProvider']
10
+ rep.user_id = hash['userId']
11
+ rep.user_name = hash['userName']
12
+ rep
13
+ end
14
+ end
15
+ end
@@ -4,12 +4,12 @@ require_relative "camel_json"
4
4
  class Representation
5
5
  include ::KeycloakAdmin::CamelJson
6
6
 
7
- def as_json
7
+ def as_json(options=nil)
8
8
  Hash[instance_variables.map { |ivar| [ivar.to_s[1..-1], instance_variable_get(ivar)] }]
9
9
  end
10
10
 
11
11
  def to_json(options=nil)
12
- snaked_hash = as_json
12
+ snaked_hash = as_json(options)
13
13
  snaked_hash.keys.reduce({}) do |camelized_hash, key|
14
14
  camelized_hash[camelize(key, false)] = snaked_hash[key]
15
15
  camelized_hash
@@ -10,21 +10,23 @@ module KeycloakAdmin
10
10
  :email_verified,
11
11
  :first_name,
12
12
  :last_name,
13
- :credentials
13
+ :credentials,
14
+ :federated_identities
14
15
 
15
16
  def self.from_hash(hash)
16
- user = new
17
- user.id = hash["id"]
18
- user.created_timestamp = hash["createdTimestamp"]
19
- user.origin = hash["origin"]
20
- user.username = hash["username"]
21
- user.email = hash["email"]
22
- user.enabled = hash["enabled"]
23
- user.email_verified = hash["emailVerified"]
24
- user.first_name = hash["firstName"]
25
- user.last_name = hash["lastName"]
26
- user.attributes = hash["attributes"]
27
- user.credentials = hash["credentials"]&.map{ |hash| CredentialRepresentation.from_hash(hash) } || []
17
+ user = new
18
+ user.id = hash["id"]
19
+ user.created_timestamp = hash["createdTimestamp"]
20
+ user.origin = hash["origin"]
21
+ user.username = hash["username"]
22
+ user.email = hash["email"]
23
+ user.enabled = hash["enabled"]
24
+ user.email_verified = hash["emailVerified"]
25
+ user.first_name = hash["firstName"]
26
+ user.last_name = hash["lastName"]
27
+ user.attributes = hash["attributes"]
28
+ user.credentials = hash["credentials"]&.map{ |hash| CredentialRepresentation.from_hash(hash) } || []
29
+ user.federated_identities = hash["federatedIdentities"]&.map { |hash| FederatedIdentityRepresentation.from_hash(hash) } || []
28
30
  user
29
31
  end
30
32
 
@@ -32,5 +34,10 @@ module KeycloakAdmin
32
34
  @credentials ||= []
33
35
  @credentials.push(credential_representation)
34
36
  end
37
+
38
+ def add_federated_identity(federated_identity_representation)
39
+ @federated_identities ||= []
40
+ @federated_identities.push(federated_identity_representation)
41
+ end
35
42
  end
36
43
  end
@@ -1,3 +1,3 @@
1
1
  module KeycloakAdmin
2
- VERSION = "0.7.2"
2
+ VERSION = "0.7.7"
3
3
  end
@@ -72,6 +72,31 @@ RSpec.describe KeycloakAdmin::TokenClient do
72
72
  end
73
73
  end
74
74
 
75
+ describe "#execute_actions_email_url" do
76
+ let(:realm_name) { "valid-realm" }
77
+ let(:user_id) { nil }
78
+
79
+ before(:each) do
80
+ @client = KeycloakAdmin.realm(realm_name).users
81
+ end
82
+
83
+ context "when user_id is not defined" do
84
+ let(:user_id) { nil }
85
+ it "raises an error" do
86
+ expect {
87
+ @client.execute_actions_email_url(user_id)
88
+ }.to raise_error(ArgumentError)
89
+ end
90
+ end
91
+
92
+ context "when user_id is defined" do
93
+ let(:user_id) { 42 }
94
+ it "return a proper url" do
95
+ expect(@client.execute_actions_email_url(user_id)).to eq "http://auth.service.io/auth/admin/realms/valid-realm/users/42/execute-actions-email"
96
+ end
97
+ end
98
+ end
99
+
75
100
  describe "#impersonation_url" do
76
101
  let(:realm_name) { "valid-realm" }
77
102
  let(:user_id) { nil }
@@ -9,7 +9,7 @@ RSpec.describe KeycloakAdmin::UserRepresentation do
9
9
  end
10
10
 
11
11
  it "can convert to json" do
12
- expect(@user.to_json).to eq '{"id":null,"createdTimestamp":1559836000,"origin":null,"username":"test_username","email":null,"enabled":true,"emailVerified":null,"firstName":null,"lastName":null,"attributes":null,"credentials":[]}'
12
+ expect(@user.to_json).to eq '{"id":null,"createdTimestamp":1559836000,"origin":null,"username":"test_username","email":null,"enabled":true,"emailVerified":null,"firstName":null,"lastName":null,"attributes":null,"credentials":[],"federatedIdentities":[]}'
13
13
  end
14
14
  end
15
15
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: keycloak-admin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.2
4
+ version: 0.7.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lorent Lempereur
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-06-17 00:00:00.000000000 Z
11
+ date: 2020-07-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: http-cookie
@@ -103,6 +103,7 @@ files:
103
103
  - lib/keycloak-admin/representation/camel_json.rb
104
104
  - lib/keycloak-admin/representation/client_representation.rb
105
105
  - lib/keycloak-admin/representation/credential_representation.rb
106
+ - lib/keycloak-admin/representation/federated_identity_representation.rb
106
107
  - lib/keycloak-admin/representation/group_representation.rb
107
108
  - lib/keycloak-admin/representation/impersonation_redirection_representation.rb
108
109
  - lib/keycloak-admin/representation/impersonation_representation.rb
@@ -150,8 +151,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
150
151
  - !ruby/object:Gem::Version
151
152
  version: '0'
152
153
  requirements: []
153
- rubyforge_project:
154
- rubygems_version: 2.6.4
154
+ rubygems_version: 3.0.3
155
155
  signing_key:
156
156
  specification_version: 4
157
157
  summary: Keycloak Admin REST API client written in Ruby