keycloak-admin 0.7.2 → 0.7.7
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 +5 -5
- data/CHANGELOG.md +24 -0
- data/Dockerfile +1 -1
- data/Gemfile.lock +8 -6
- data/README.md +5 -6
- data/lib/keycloak-admin.rb +1 -0
- data/lib/keycloak-admin/client/configurable_token_client.rb +12 -7
- data/lib/keycloak-admin/client/user_client.rb +83 -7
- data/lib/keycloak-admin/representation/federated_identity_representation.rb +15 -0
- data/lib/keycloak-admin/representation/representation.rb +2 -2
- data/lib/keycloak-admin/representation/user_representation.rb +20 -13
- data/lib/keycloak-admin/version.rb +1 -1
- data/spec/client/user_client_spec.rb +25 -0
- data/spec/representation/user_representation_spec.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8be78b3854a7d3ac95ddb700599f49f8b108f2eda85de66df200aa5e362b7f5e
|
4
|
+
data.tar.gz: 81103f2021f10e78c92327d7beace0ea30bc23175e3605c408e70f01a172203b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 83bda7a2b12cd6384710234618392aebfe0b29aa61378bf8350c8c8b3c70ad9725293f150c0074137351b21825cd3798d6ca180180a4b5d9c84909bef67a32b3
|
7
|
+
data.tar.gz: c052198198d30a8978229dfc71d2d5cb0d26db94e22291e6286dea7d8133b2060d5d658f26fc5e7e5f4b9b35fc11f3dce0eff13c1451aa48e85ee2678e90fde6
|
data/CHANGELOG.md
CHANGED
@@ -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
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
keycloak-admin (0.7.
|
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.
|
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.
|
18
|
+
mime-types (3.3.1)
|
18
19
|
mime-types-data (~> 3.2015)
|
19
|
-
mime-types-data (3.
|
20
|
+
mime-types-data (3.2020.0512)
|
20
21
|
netrc (0.11.0)
|
21
|
-
rest-client (2.0
|
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.
|
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.
|
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
|
+
```
|
data/lib/keycloak-admin.rb
CHANGED
@@ -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.
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
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.
|
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.
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
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.
|
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
|
17
|
-
user.id
|
18
|
-
user.created_timestamp
|
19
|
-
user.origin
|
20
|
-
user.username
|
21
|
-
user.email
|
22
|
-
user.enabled
|
23
|
-
user.email_verified
|
24
|
-
user.first_name
|
25
|
-
user.last_name
|
26
|
-
user.attributes
|
27
|
-
user.credentials
|
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
|
@@ -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.
|
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:
|
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
|
-
|
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
|