keycloak-admin 0.7.7 → 1.0.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -0
- data/Gemfile.lock +3 -3
- data/README.md +73 -28
- data/lib/keycloak-admin/client/identity_provider_client.rb +31 -0
- data/lib/keycloak-admin/client/realm_client.rb +4 -0
- data/lib/keycloak-admin/client/user_client.rb +36 -1
- data/lib/keycloak-admin/representation/identity_provider_representation.rb +67 -0
- data/lib/keycloak-admin/representation/user_representation.rb +5 -1
- data/lib/keycloak-admin/version.rb +1 -1
- data/lib/keycloak-admin.rb +3 -1
- data/spec/client/identity_provider_client_spec.rb +92 -0
- data/spec/client/user_client_spec.rb +16 -2
- data/spec/representation/identity_provider_representation_spec.rb +113 -0
- data/spec/representation/user_representation_spec.rb +1 -1
- metadata +10 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 832e114e10e83ff18cfb5eaad1c157248da889b5041137ebf28fd30e610ee07d
|
4
|
+
data.tar.gz: e1151d727d5d6d8320db86024e7f10ad81f35a23dc13312aac065757e8664be5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eae1ed6f49db46eec2b4463acbd7cf164948aeba4e672f30703f8724bb70d9d441ff469dfd0fa81645821d5d0bfb19ed0bd7376407026fa1467b66c20069c006
|
7
|
+
data.tar.gz: 26818a04afbc95c05e878881d1b7c38e336f5e18a926995390b5e629786c395807276e6ef18c466e61f1600e65cbdd6b4ea6f80ff6e3af5a3ea070c77f18c655
|
data/CHANGELOG.md
CHANGED
@@ -5,6 +5,27 @@ 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
|
+
|
9
|
+
## [1.0.1] - 2021-10-14
|
10
|
+
|
11
|
+
* List all `Identity Providers`
|
12
|
+
* Add Group on Users (thanks to @tomuench)
|
13
|
+
* Remove Group from Users (thanks to @tomuench)
|
14
|
+
|
15
|
+
## [1.0.0] - 2021-08-03
|
16
|
+
|
17
|
+
* Add `totp` on Users
|
18
|
+
* Add `required_actions` on Users
|
19
|
+
|
20
|
+
## [0.7.9] - 2020-10-22
|
21
|
+
|
22
|
+
* Extend `search` function to use complex queries (thanks to @hobbypunk90)
|
23
|
+
|
24
|
+
## [0.7.8] - 2020-10-15
|
25
|
+
|
26
|
+
* Bug: `rest_client_options` default value does not match the documentation (was `nil` by default, should be `{}`)
|
27
|
+
* Update documentation about client setup (based on Keycloak 11)
|
28
|
+
|
8
29
|
## [0.7.7] - 2020-07-10
|
9
30
|
|
10
31
|
* Fix: `Replace request method shorthand with .execute for proper RestClient option support` (thanks to @RomanHargrave)
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
keycloak-admin (0.
|
4
|
+
keycloak-admin (1.0.1)
|
5
5
|
http-cookie (~> 1.0, >= 1.0.3)
|
6
6
|
rest-client (~> 2.0)
|
7
7
|
|
@@ -13,11 +13,11 @@ GEM
|
|
13
13
|
domain_name (0.5.20190701)
|
14
14
|
unf (>= 0.0.5, < 1.0.0)
|
15
15
|
http-accept (1.7.0)
|
16
|
-
http-cookie (1.0.
|
16
|
+
http-cookie (1.0.4)
|
17
17
|
domain_name (~> 0.5)
|
18
18
|
mime-types (3.3.1)
|
19
19
|
mime-types-data (~> 3.2015)
|
20
|
-
mime-types-data (3.
|
20
|
+
mime-types-data (3.2021.0704)
|
21
21
|
netrc (0.11.0)
|
22
22
|
rest-client (2.1.0)
|
23
23
|
http-accept (>= 1.7.0, < 2.0)
|
data/README.md
CHANGED
@@ -12,37 +12,59 @@ 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.
|
15
|
+
gem "keycloak-admin", "1.0.1"
|
16
16
|
```
|
17
17
|
|
18
18
|
## Login
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
*
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
*
|
38
|
-
|
39
|
-
|
40
|
-
*
|
41
|
-
*
|
42
|
-
*
|
43
|
-
*
|
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`):
|
44
65
|
* Set `use_service_account` to `true`
|
45
|
-
* Setup `
|
66
|
+
* Setup `client_id` with your `Client ID` (_e.g. my-app-admin-client_)
|
67
|
+
* Copy its Client Secret to `client_secret`
|
46
68
|
|
47
69
|
## Configuration
|
48
70
|
|
@@ -69,7 +91,8 @@ All options have a default value. However, all of them can be changed in your in
|
|
69
91
|
|
70
92
|
| Option | Default Value | Type | Required? | Description | Example |
|
71
93
|
| ---- | ----- | ------ | ----- | ------ | ----- |
|
72
|
-
| `server_url` | `nil
|
94
|
+
| `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`
|
95
|
+
| `server_domain` | `nil`| String | Required | Public domain that identify your authentication cookies. | `auth.service.io` |
|
73
96
|
| `client_realm_name` | `""`| String | Required | Name of the realm that contains the admin client. | `master` |
|
74
97
|
| `client_id` | `admin-cli`| String | Required | Client that should be used to access admin capabilities. | `api-cli` |
|
75
98
|
| `client_secret` | `nil`| String | Optional | If your client is `confidential`, this parameter must be specified. | `4e3c481c-f823-4a6a-b8a7-bf8c86e3eac3` |
|
@@ -97,6 +120,9 @@ All options have a default value. However, all of them can be changed in your in
|
|
97
120
|
* Get list of client role mappings for a user/group
|
98
121
|
* Save client role mappings for a user/group
|
99
122
|
* Save realm-level role mappings for a user/group
|
123
|
+
* Add a Group on a User
|
124
|
+
* Remove a Group from a User
|
125
|
+
* Get list of Identity Providers
|
100
126
|
* Link/Unlink users to federated identity provider brokers
|
101
127
|
* Execute actions emails
|
102
128
|
* Send forgot passsword mail
|
@@ -122,10 +148,18 @@ KeycloakAdmin.realm("a_realm").users.get(user_id)
|
|
122
148
|
|
123
149
|
Returns an array of `KeycloakAdmin::UserRepresentation`.
|
124
150
|
|
151
|
+
According to [the documentation](https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_users_resource):
|
152
|
+
* When providing a `String` parameter, this produces an arbitrary search string
|
153
|
+
* When providing a `Hash`, you can search for specific field (_e.g_ an email)
|
154
|
+
|
125
155
|
```ruby
|
126
156
|
KeycloakAdmin.realm("a_realm").users.search("a_username_or_an_email")
|
127
157
|
```
|
128
158
|
|
159
|
+
```ruby
|
160
|
+
KeycloakAdmin.realm("a_realm").users.search({ email: "john@doe.com" })
|
161
|
+
```
|
162
|
+
|
129
163
|
### List all users in a realm
|
130
164
|
|
131
165
|
Returns an array of `KeycloakAdmin::UserRepresentation`.
|
@@ -336,6 +370,16 @@ group_id = "3a63b5c0-ef8a-47fd-86ed-b5fead18d9b8"
|
|
336
370
|
KeycloakAdmin.realm("a_realm").group(group_id).role_mapper.save_realm_level(role_list)
|
337
371
|
```
|
338
372
|
|
373
|
+
### Get list of identity providers
|
374
|
+
|
375
|
+
Note: This client requires the `realm-management.view-identity-providers` role.
|
376
|
+
|
377
|
+
Returns an array of `KeycloakAdmin::IdentityProviderRepresentation`.
|
378
|
+
|
379
|
+
```ruby
|
380
|
+
KeycloakAdmin.realm("a_realm").identity_providers.list
|
381
|
+
```
|
382
|
+
|
339
383
|
## How to execute library tests
|
340
384
|
|
341
385
|
From the `keycloak-admin-api` directory:
|
@@ -343,4 +387,5 @@ From the `keycloak-admin-api` directory:
|
|
343
387
|
```
|
344
388
|
$ docker build . -t keycloak-admin:test
|
345
389
|
$ docker run -v `pwd`:/usr/src/app/ keycloak-admin:test bundle exec rspec spec
|
346
|
-
```
|
390
|
+
```
|
391
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module KeycloakAdmin
|
2
|
+
class IdentityProviderClient < 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(identity_providers_url, @configuration.rest_client_options).get(headers)
|
12
|
+
end
|
13
|
+
JSON.parse(response).map { |provider_as_hash| IdentityProviderRepresentation.from_hash(provider_as_hash) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def get(internal_id_or_alias=nil)
|
17
|
+
response = execute_http do
|
18
|
+
RestClient::Resource.new(identity_providers_url, @configuration.rest_client_options).get(headers)
|
19
|
+
end
|
20
|
+
IdentityProviderRepresentation.from_hash(JSON.parse(response))
|
21
|
+
end
|
22
|
+
|
23
|
+
def identity_providers_url(internal_id_or_alias=nil)
|
24
|
+
if internal_id_or_alias
|
25
|
+
"#{@realm_client.realm_admin_url}/identity-provider/instances/#{internal_id_or_alias}"
|
26
|
+
else
|
27
|
+
"#{@realm_client.realm_admin_url}/identity-provider/instances"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -31,6 +31,27 @@ module KeycloakAdmin
|
|
31
31
|
)
|
32
32
|
end
|
33
33
|
|
34
|
+
def add_group(user_id, group_id)
|
35
|
+
RestClient::Request.execute(
|
36
|
+
@configuration.rest_client_options.merge(
|
37
|
+
method: :put,
|
38
|
+
url: "#{users_url(user_id)}/groups/#{group_id}",
|
39
|
+
payload: {},
|
40
|
+
headers: headers
|
41
|
+
)
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
def remove_group(user_id, group_id)
|
46
|
+
RestClient::Request.execute(
|
47
|
+
@configuration.rest_client_options.merge(
|
48
|
+
method: :delete,
|
49
|
+
url: "#{users_url(user_id)}/groups/#{group_id}",
|
50
|
+
headers: headers
|
51
|
+
)
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
34
55
|
def get(user_id)
|
35
56
|
response = execute_http do
|
36
57
|
RestClient::Resource.new(users_url(user_id), @configuration.rest_client_options).get(headers)
|
@@ -38,8 +59,22 @@ module KeycloakAdmin
|
|
38
59
|
UserRepresentation.from_hash(JSON.parse(response))
|
39
60
|
end
|
40
61
|
|
62
|
+
##
|
63
|
+
# Query can be a string or a hash.
|
64
|
+
# * String: It's used as search query
|
65
|
+
# * Hash: Used for complex search queries.
|
66
|
+
# For its documentation see: https://www.keycloak.org/docs-api/11.0/rest-api/index.html#_users_resource
|
67
|
+
##
|
41
68
|
def search(query)
|
42
|
-
derived_headers =
|
69
|
+
derived_headers = case query
|
70
|
+
when String
|
71
|
+
headers.merge({params: { search: query }})
|
72
|
+
when Hash
|
73
|
+
headers.merge({params: query })
|
74
|
+
else
|
75
|
+
headers
|
76
|
+
end
|
77
|
+
|
43
78
|
response = execute_http do
|
44
79
|
RestClient::Resource.new(users_url, @configuration.rest_client_options).get(derived_headers)
|
45
80
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module KeycloakAdmin
|
2
|
+
class IdentityProviderRepresentation < Representation
|
3
|
+
attr_accessor :alias,
|
4
|
+
:display_name,
|
5
|
+
:internal_id,
|
6
|
+
:provider_id,
|
7
|
+
:enabled,
|
8
|
+
:update_profile_first_login_mode,
|
9
|
+
:trust_email,
|
10
|
+
:store_token,
|
11
|
+
:add_read_token_role_on_create,
|
12
|
+
:authenticate_by_default,
|
13
|
+
:link_only,
|
14
|
+
:first_broker_login_flow_alias,
|
15
|
+
:configuration
|
16
|
+
|
17
|
+
def self.from_hash(hash)
|
18
|
+
if hash.nil?
|
19
|
+
nil
|
20
|
+
else
|
21
|
+
new(
|
22
|
+
hash["alias"],
|
23
|
+
hash["displayName"],
|
24
|
+
hash["internalId"],
|
25
|
+
hash["providerId"],
|
26
|
+
hash["enabled"],
|
27
|
+
hash["updateProfileFirstLoginMode"],
|
28
|
+
hash["trustEmail"],
|
29
|
+
hash["storeToken"],
|
30
|
+
hash["addReadTokenRoleOnCreate"],
|
31
|
+
hash["authenticateByDefault"],
|
32
|
+
hash["linkOnly"],
|
33
|
+
hash["firstBrokerLoginFlowAlias"],
|
34
|
+
hash["config"]
|
35
|
+
)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def initialize(alias_name,
|
40
|
+
display_name,
|
41
|
+
internal_id,
|
42
|
+
provider_id,
|
43
|
+
enabled,
|
44
|
+
update_profile_first_login_mode,
|
45
|
+
trust_email,
|
46
|
+
store_token,
|
47
|
+
add_read_token_role_on_create,
|
48
|
+
authenticate_by_default,
|
49
|
+
link_only,
|
50
|
+
first_broker_login_flow_alias,
|
51
|
+
configuration)
|
52
|
+
@alias = alias_name
|
53
|
+
@display_name = display_name
|
54
|
+
@internal_id = internal_id
|
55
|
+
@provider_id = provider_id
|
56
|
+
@enabled = enabled
|
57
|
+
@update_profile_first_login_mode = update_profile_first_login_mode
|
58
|
+
@trust_email = trust_email
|
59
|
+
@store_token = store_token
|
60
|
+
@add_read_token_role_on_create = add_read_token_role_on_create
|
61
|
+
@authenticate_by_default = authenticate_by_default
|
62
|
+
@link_only = link_only
|
63
|
+
@first_broker_login_flow_alias = first_broker_login_flow_alias
|
64
|
+
@configuration = configuration
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -10,8 +10,10 @@ module KeycloakAdmin
|
|
10
10
|
:email_verified,
|
11
11
|
:first_name,
|
12
12
|
:last_name,
|
13
|
+
:totp,
|
13
14
|
:credentials,
|
14
|
-
:federated_identities
|
15
|
+
:federated_identities,
|
16
|
+
:required_actions
|
15
17
|
|
16
18
|
def self.from_hash(hash)
|
17
19
|
user = new
|
@@ -25,6 +27,8 @@ module KeycloakAdmin
|
|
25
27
|
user.first_name = hash["firstName"]
|
26
28
|
user.last_name = hash["lastName"]
|
27
29
|
user.attributes = hash["attributes"]
|
30
|
+
user.required_actions = hash["requiredActions"] || []
|
31
|
+
user.totp = hash["totp"] || false
|
28
32
|
user.credentials = hash["credentials"]&.map{ |hash| CredentialRepresentation.from_hash(hash) } || []
|
29
33
|
user.federated_identities = hash["federatedIdentities"]&.map { |hash| FederatedIdentityRepresentation.from_hash(hash) } || []
|
30
34
|
user
|
data/lib/keycloak-admin.rb
CHANGED
@@ -10,6 +10,7 @@ require_relative "keycloak-admin/client/role_client"
|
|
10
10
|
require_relative "keycloak-admin/client/role_mapper_client"
|
11
11
|
require_relative "keycloak-admin/client/token_client"
|
12
12
|
require_relative "keycloak-admin/client/user_client"
|
13
|
+
require_relative "keycloak-admin/client/identity_provider_client"
|
13
14
|
require_relative "keycloak-admin/client/configurable_token_client"
|
14
15
|
require_relative "keycloak-admin/representation/camel_json"
|
15
16
|
require_relative "keycloak-admin/representation/representation"
|
@@ -23,6 +24,7 @@ require_relative "keycloak-admin/representation/realm_representation"
|
|
23
24
|
require_relative "keycloak-admin/representation/role_representation"
|
24
25
|
require_relative "keycloak-admin/representation/federated_identity_representation"
|
25
26
|
require_relative "keycloak-admin/representation/user_representation"
|
27
|
+
require_relative "keycloak-admin/representation/identity_provider_representation"
|
26
28
|
require_relative "keycloak-admin/resource/base_role_containing_resource"
|
27
29
|
require_relative "keycloak-admin/resource/group_resource"
|
28
30
|
require_relative "keycloak-admin/resource/user_resource"
|
@@ -55,7 +57,7 @@ module KeycloakAdmin
|
|
55
57
|
config.use_service_account = true
|
56
58
|
config.username = nil
|
57
59
|
config.password = nil
|
58
|
-
config.rest_client_options =
|
60
|
+
config.rest_client_options = {}
|
59
61
|
end
|
60
62
|
end
|
61
63
|
|
@@ -0,0 +1,92 @@
|
|
1
|
+
RSpec.describe KeycloakAdmin::IdentityProviderClient do
|
2
|
+
describe "#identity_providers_url" do
|
3
|
+
let(:realm_name) { "valid-realm" }
|
4
|
+
let(:provider_id) { nil }
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
@built_url = KeycloakAdmin.realm(realm_name).identity_providers.identity_providers_url(provider_id)
|
8
|
+
end
|
9
|
+
|
10
|
+
context "when provider_id is not defined" do
|
11
|
+
let(:provider_id) { nil }
|
12
|
+
it "returns a proper url without provider id" do
|
13
|
+
expect(@built_url).to eq "http://auth.service.io/auth/admin/realms/valid-realm/identity-provider/instances"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context "when provider_id is defined" do
|
18
|
+
let(:provider_id) { "95985b21-d884-4bbd-b852-cb8cd365afc2" }
|
19
|
+
it "returns a proper url with the provider id" do
|
20
|
+
expect(@built_url).to eq "http://auth.service.io/auth/admin/realms/valid-realm/identity-provider/instances/95985b21-d884-4bbd-b852-cb8cd365afc2"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "#list" do
|
26
|
+
let(:realm_name) { "valid-realm" }
|
27
|
+
let(:json_response) do
|
28
|
+
<<-JSON
|
29
|
+
[
|
30
|
+
{
|
31
|
+
"alias": "acme",
|
32
|
+
"displayName": "ACME",
|
33
|
+
"internalId": "20fea77e-ae3d-411e-9467-2b3a20cd3e6d",
|
34
|
+
"providerId": "saml",
|
35
|
+
"enabled": true,
|
36
|
+
"updateProfileFirstLoginMode": "on",
|
37
|
+
"trustEmail": true,
|
38
|
+
"storeToken": false,
|
39
|
+
"addReadTokenRoleOnCreate": false,
|
40
|
+
"authenticateByDefault": false,
|
41
|
+
"linkOnly": false,
|
42
|
+
"firstBrokerLoginFlowAlias": "first broker login",
|
43
|
+
"config": {
|
44
|
+
"hideOnLoginPage": "",
|
45
|
+
"validateSignature": "true",
|
46
|
+
"samlXmlKeyNameTranformer": "KEY_ID",
|
47
|
+
"signingCertificate": "",
|
48
|
+
"postBindingLogout": "false",
|
49
|
+
"nameIDPolicyFormat": "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent",
|
50
|
+
"postBindingResponse": "true",
|
51
|
+
"backchannelSupported": "",
|
52
|
+
"signatureAlgorithm": "RSA_SHA256",
|
53
|
+
"wantAssertionsEncrypted": "false",
|
54
|
+
"xmlSigKeyInfoKeyNameTransformer": "CERT_SUBJECT",
|
55
|
+
"useJwksUrl": "true",
|
56
|
+
"wantAssertionsSigned": "true",
|
57
|
+
"postBindingAuthnRequest": "true",
|
58
|
+
"forceAuthn": "",
|
59
|
+
"wantAuthnRequestsSigned": "true",
|
60
|
+
"singleSignOnServiceUrl": "https://login.microsoftonline.com/test/saml2",
|
61
|
+
"addExtensionsElementWithKeyInfo": "false"
|
62
|
+
}
|
63
|
+
}
|
64
|
+
]
|
65
|
+
JSON
|
66
|
+
end
|
67
|
+
before(:each) do
|
68
|
+
@identity_provider_client = KeycloakAdmin.realm(realm_name).identity_providers
|
69
|
+
|
70
|
+
stub_token_client
|
71
|
+
allow_any_instance_of(RestClient::Resource).to receive(:get).and_return json_response
|
72
|
+
end
|
73
|
+
|
74
|
+
it "lists identity providers" do
|
75
|
+
identity_providers = @identity_provider_client.list
|
76
|
+
expect(identity_providers.length).to eq 1
|
77
|
+
expect(identity_providers[0].alias).to eq "acme"
|
78
|
+
end
|
79
|
+
|
80
|
+
it "passes rest client options" do
|
81
|
+
rest_client_options = {verify_ssl: OpenSSL::SSL::VERIFY_NONE}
|
82
|
+
allow_any_instance_of(KeycloakAdmin::Configuration).to receive(:rest_client_options).and_return rest_client_options
|
83
|
+
|
84
|
+
expect(RestClient::Resource).to receive(:new).with(
|
85
|
+
"http://auth.service.io/auth/admin/realms/valid-realm/identity-provider/instances", rest_client_options).and_call_original
|
86
|
+
|
87
|
+
identity_providers = @identity_provider_client.list
|
88
|
+
expect(identity_providers.length).to eq 1
|
89
|
+
expect(identity_providers[0].alias).to eq "acme"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -158,7 +158,7 @@ RSpec.describe KeycloakAdmin::TokenClient do
|
|
158
158
|
@user_client = KeycloakAdmin.realm(realm_name).users
|
159
159
|
|
160
160
|
stub_token_client
|
161
|
-
allow_any_instance_of(RestClient::Resource).to receive(:get).and_return '{"username":"test_username","createdTimestamp":1559347200}'
|
161
|
+
allow_any_instance_of(RestClient::Resource).to receive(:get).and_return '{"username":"test_username","createdTimestamp":1559347200, "requiredActions":["CONFIGURE_TOTP"], "totp": true}'
|
162
162
|
end
|
163
163
|
|
164
164
|
it "parses the response" do
|
@@ -175,6 +175,8 @@ RSpec.describe KeycloakAdmin::TokenClient do
|
|
175
175
|
|
176
176
|
user = @user_client.get('test_user_id')
|
177
177
|
expect(user.username).to eq 'test_username'
|
178
|
+
expect(user.totp).to be true
|
179
|
+
expect(user.required_actions).to eq ["CONFIGURE_TOTP"]
|
178
180
|
end
|
179
181
|
end
|
180
182
|
|
@@ -192,12 +194,24 @@ RSpec.describe KeycloakAdmin::TokenClient do
|
|
192
194
|
allow_any_instance_of(RestClient::Resource).to receive(:get).and_return '[{"username":"test_username","createdTimestamp":1559347200}]'
|
193
195
|
end
|
194
196
|
|
195
|
-
it "finds a user" do
|
197
|
+
it "finds a user using a string" do
|
196
198
|
users = @user_client.search("test_username")
|
197
199
|
expect(users.length).to eq 1
|
198
200
|
expect(users[0].username).to eq "test_username"
|
199
201
|
end
|
200
202
|
|
203
|
+
it "finds a user using nil does not fail" do
|
204
|
+
users = @user_client.search(nil)
|
205
|
+
expect(users.length).to eq 1
|
206
|
+
expect(users[0].username).to eq "test_username"
|
207
|
+
end
|
208
|
+
|
209
|
+
it "finds a user using a hash" do
|
210
|
+
users = @user_client.search({ search: "test_username"})
|
211
|
+
expect(users.length).to eq 1
|
212
|
+
expect(users[0].username).to eq "test_username"
|
213
|
+
end
|
214
|
+
|
201
215
|
it "passes rest client options" do
|
202
216
|
rest_client_options = {verify_ssl: OpenSSL::SSL::VERIFY_NONE}
|
203
217
|
allow_any_instance_of(KeycloakAdmin::Configuration).to receive(:rest_client_options).and_return rest_client_options
|
@@ -0,0 +1,113 @@
|
|
1
|
+
RSpec.describe KeycloakAdmin::IdentityProviderRepresentation do
|
2
|
+
describe "#from_hash" do
|
3
|
+
before(:each) do
|
4
|
+
json = <<-JSON
|
5
|
+
{
|
6
|
+
"alias": "acme",
|
7
|
+
"displayName": "ACME",
|
8
|
+
"internalId": "20fea77e-ae3d-411e-9467-2b3a20cd3e6d",
|
9
|
+
"providerId": "saml",
|
10
|
+
"enabled": true,
|
11
|
+
"updateProfileFirstLoginMode": "on",
|
12
|
+
"trustEmail": true,
|
13
|
+
"storeToken": false,
|
14
|
+
"addReadTokenRoleOnCreate": false,
|
15
|
+
"authenticateByDefault": false,
|
16
|
+
"linkOnly": false,
|
17
|
+
"firstBrokerLoginFlowAlias": "first broker login",
|
18
|
+
"config": {
|
19
|
+
"hideOnLoginPage": "",
|
20
|
+
"validateSignature": "true",
|
21
|
+
"samlXmlKeyNameTranformer": "KEY_ID",
|
22
|
+
"signingCertificate": "",
|
23
|
+
"postBindingLogout": "false",
|
24
|
+
"nameIDPolicyFormat": "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent",
|
25
|
+
"postBindingResponse": "true",
|
26
|
+
"backchannelSupported": "",
|
27
|
+
"signatureAlgorithm": "RSA_SHA256",
|
28
|
+
"wantAssertionsEncrypted": "false",
|
29
|
+
"xmlSigKeyInfoKeyNameTransformer": "CERT_SUBJECT",
|
30
|
+
"useJwksUrl": "true",
|
31
|
+
"wantAssertionsSigned": "true",
|
32
|
+
"postBindingAuthnRequest": "true",
|
33
|
+
"forceAuthn": "",
|
34
|
+
"wantAuthnRequestsSigned": "true",
|
35
|
+
"singleSignOnServiceUrl": "https://login.microsoftonline.com/test/saml2",
|
36
|
+
"addExtensionsElementWithKeyInfo": "false"
|
37
|
+
}
|
38
|
+
}
|
39
|
+
JSON
|
40
|
+
payload = JSON.parse(json)
|
41
|
+
@identity_provider = KeycloakAdmin::IdentityProviderRepresentation.from_hash(payload)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "parses the alias" do
|
45
|
+
expect(@identity_provider.alias).to eq "acme"
|
46
|
+
end
|
47
|
+
|
48
|
+
it "parses the display name" do
|
49
|
+
expect(@identity_provider.display_name).to eq "ACME"
|
50
|
+
end
|
51
|
+
|
52
|
+
it "parses the internalId" do
|
53
|
+
expect(@identity_provider.internal_id).to eq "20fea77e-ae3d-411e-9467-2b3a20cd3e6d"
|
54
|
+
end
|
55
|
+
|
56
|
+
it "parses the provider id" do
|
57
|
+
expect(@identity_provider.provider_id).to eq "saml"
|
58
|
+
end
|
59
|
+
|
60
|
+
it "parses the enabled" do
|
61
|
+
expect(@identity_provider.enabled).to eq true
|
62
|
+
end
|
63
|
+
|
64
|
+
it "parses the update_profile_first_login_mode" do
|
65
|
+
expect(@identity_provider.update_profile_first_login_mode).to eq "on"
|
66
|
+
end
|
67
|
+
|
68
|
+
it "parses the trust_email" do
|
69
|
+
expect(@identity_provider.trust_email).to eq true
|
70
|
+
end
|
71
|
+
|
72
|
+
it "parses the store_token" do
|
73
|
+
expect(@identity_provider.store_token).to eq false
|
74
|
+
end
|
75
|
+
|
76
|
+
it "parses the add_read_token_role_on_create" do
|
77
|
+
expect(@identity_provider.add_read_token_role_on_create).to eq false
|
78
|
+
end
|
79
|
+
|
80
|
+
it "parses the authenticate_by_default" do
|
81
|
+
expect(@identity_provider.authenticate_by_default).to eq false
|
82
|
+
end
|
83
|
+
|
84
|
+
it "parses the link_only" do
|
85
|
+
expect(@identity_provider.link_only).to eq false
|
86
|
+
end
|
87
|
+
|
88
|
+
it "parses the first_broker_login_flow_alias" do
|
89
|
+
expect(@identity_provider.first_broker_login_flow_alias).to eq "first broker login"
|
90
|
+
end
|
91
|
+
|
92
|
+
it "parses the configuration as a hash with camel properties" do
|
93
|
+
expect(@identity_provider.configuration["hideOnLoginPage"]).to eq ""
|
94
|
+
expect(@identity_provider.configuration["validateSignature"]).to eq "true"
|
95
|
+
expect(@identity_provider.configuration["samlXmlKeyNameTranformer"]).to eq "KEY_ID"
|
96
|
+
expect(@identity_provider.configuration["signingCertificate"]).to eq ""
|
97
|
+
expect(@identity_provider.configuration["postBindingLogout"]).to eq "false"
|
98
|
+
expect(@identity_provider.configuration["nameIDPolicyFormat"]).to eq "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
|
99
|
+
expect(@identity_provider.configuration["postBindingResponse"]).to eq "true"
|
100
|
+
expect(@identity_provider.configuration["backchannelSupported"]).to eq ""
|
101
|
+
expect(@identity_provider.configuration["signatureAlgorithm"]).to eq "RSA_SHA256"
|
102
|
+
expect(@identity_provider.configuration["wantAssertionsEncrypted"]).to eq "false"
|
103
|
+
expect(@identity_provider.configuration["xmlSigKeyInfoKeyNameTransformer"]).to eq "CERT_SUBJECT"
|
104
|
+
expect(@identity_provider.configuration["useJwksUrl"]).to eq "true"
|
105
|
+
expect(@identity_provider.configuration["wantAssertionsSigned"]).to eq "true"
|
106
|
+
expect(@identity_provider.configuration["postBindingAuthnRequest"]).to eq "true"
|
107
|
+
expect(@identity_provider.configuration["forceAuthn"]).to eq ""
|
108
|
+
expect(@identity_provider.configuration["wantAuthnRequestsSigned"]).to eq "true"
|
109
|
+
expect(@identity_provider.configuration["singleSignOnServiceUrl"]).to eq "https://login.microsoftonline.com/test/saml2"
|
110
|
+
expect(@identity_provider.configuration["addExtensionsElementWithKeyInfo"]).to eq "false"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -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":[],"federatedIdentities":[]}'
|
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,"requiredActions":[],"totp":false,"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.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lorent Lempereur
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-10-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: http-cookie
|
@@ -94,6 +94,7 @@ files:
|
|
94
94
|
- lib/keycloak-admin/client/client_role_mappings_client.rb
|
95
95
|
- lib/keycloak-admin/client/configurable_token_client.rb
|
96
96
|
- lib/keycloak-admin/client/group_client.rb
|
97
|
+
- lib/keycloak-admin/client/identity_provider_client.rb
|
97
98
|
- lib/keycloak-admin/client/realm_client.rb
|
98
99
|
- lib/keycloak-admin/client/role_client.rb
|
99
100
|
- lib/keycloak-admin/client/role_mapper_client.rb
|
@@ -105,6 +106,7 @@ files:
|
|
105
106
|
- lib/keycloak-admin/representation/credential_representation.rb
|
106
107
|
- lib/keycloak-admin/representation/federated_identity_representation.rb
|
107
108
|
- lib/keycloak-admin/representation/group_representation.rb
|
109
|
+
- lib/keycloak-admin/representation/identity_provider_representation.rb
|
108
110
|
- lib/keycloak-admin/representation/impersonation_redirection_representation.rb
|
109
111
|
- lib/keycloak-admin/representation/impersonation_representation.rb
|
110
112
|
- lib/keycloak-admin/representation/realm_representation.rb
|
@@ -121,12 +123,14 @@ files:
|
|
121
123
|
- spec/client/client_spec.rb
|
122
124
|
- spec/client/configurable_token_client_spec.rb
|
123
125
|
- spec/client/group_client_spec.rb
|
126
|
+
- spec/client/identity_provider_client_spec.rb
|
124
127
|
- spec/client/realm_client_spec.rb
|
125
128
|
- spec/client/role_client_spec.rb
|
126
129
|
- spec/client/role_mapper_client_spec.rb
|
127
130
|
- spec/client/token_client_spec.rb
|
128
131
|
- spec/client/user_client_spec.rb
|
129
132
|
- spec/configuration_spec.rb
|
133
|
+
- spec/representation/identity_provider_representation_spec.rb
|
130
134
|
- spec/representation/impersonation_representation_spec.rb
|
131
135
|
- spec/representation/user_representation_spec.rb
|
132
136
|
- spec/resource/group_resource_spec.rb
|
@@ -136,7 +140,7 @@ homepage: https://github.com/looorent/keycloak-admin-ruby
|
|
136
140
|
licenses:
|
137
141
|
- MIT
|
138
142
|
metadata: {}
|
139
|
-
post_install_message:
|
143
|
+
post_install_message:
|
140
144
|
rdoc_options: []
|
141
145
|
require_paths:
|
142
146
|
- lib
|
@@ -151,8 +155,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
151
155
|
- !ruby/object:Gem::Version
|
152
156
|
version: '0'
|
153
157
|
requirements: []
|
154
|
-
rubygems_version: 3.
|
155
|
-
signing_key:
|
158
|
+
rubygems_version: 3.2.3
|
159
|
+
signing_key:
|
156
160
|
specification_version: 4
|
157
161
|
summary: Keycloak Admin REST API client written in Ruby
|
158
162
|
test_files: []
|