keycloak-admin 0.7.7 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|