keycloak-admin 1.1.6 → 1.1.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 +4 -4
- data/.github/workflows/ci.yml +1 -1
- data/CHANGELOG.md +5 -0
- data/Gemfile.lock +10 -6
- data/README.md +116 -0
- data/keycloak-admin.gemspec +1 -1
- data/lib/keycloak-admin/client/client_scope_client.rb +65 -0
- data/lib/keycloak-admin/client/client_scope_protocol_mapper_client.rb +62 -0
- data/lib/keycloak-admin/client/realm_client.rb +8 -0
- data/lib/keycloak-admin/representation/client_scope_representation.rb +21 -0
- data/lib/keycloak-admin/version.rb +1 -1
- data/lib/keycloak-admin.rb +3 -0
- data/spec/client/client_scope_client_spec.rb +220 -0
- data/spec/client/client_scope_protocol_mapper_client_spec.rb +230 -0
- data/spec/representation/client_scope_representation_spec.rb +125 -0
- metadata +14 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0e12885f5810b15fdc63cc227cb48c1e5a730b6328d3021e4de319d1859fb996
|
|
4
|
+
data.tar.gz: 5b691cf6498c9754c8778ed043501c94620ef0ca3a7649ae1e2d8ebf310047c8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 552d1b3896305cbe8799ca2627631f049fe8a526b3450fec6c4a360dd9ac2139185b91e642973acf2ee9c1af2bdf49073e5cf66c2eafbc3d5a72c8749331cb53
|
|
7
|
+
data.tar.gz: 2fbd6f1e6034c0654ac56b856d67fc975fab74a6642071e0bb6f5e8fcdd0b2989042ee2a6aef735e767ca6a9ba53d471870e58b97d1cd71df68b62036677eea4
|
data/.github/workflows/ci.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,11 @@ 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
|
+
## [1.1.7] - 2026-03-27
|
|
9
|
+
|
|
10
|
+
* [Feature] Client scopes - supported operations: `create!`, `get`, `delete`, `list`, and `search`.
|
|
11
|
+
* [Feature] Client scopes protocol mappers - supported operations: `create!`, `get`, `delete`, `list`, and `search`.
|
|
12
|
+
|
|
8
13
|
## [1.1.6] - 2026-01-05
|
|
9
14
|
|
|
10
15
|
* [Feature] Support for Organizations (Multi-tenancy):
|
data/Gemfile.lock
CHANGED
|
@@ -1,25 +1,29 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
keycloak-admin (1.1.
|
|
4
|
+
keycloak-admin (1.1.7)
|
|
5
5
|
http-cookie (~> 1.0, >= 1.0.3)
|
|
6
6
|
rest-client (~> 2.0)
|
|
7
7
|
|
|
8
8
|
GEM
|
|
9
9
|
remote: https://rubygems.org/
|
|
10
10
|
specs:
|
|
11
|
-
byebug (
|
|
11
|
+
byebug (13.0.0)
|
|
12
|
+
reline (>= 0.6.0)
|
|
12
13
|
diff-lcs (1.6.2)
|
|
13
14
|
domain_name (0.6.20240107)
|
|
14
15
|
http-accept (1.7.0)
|
|
15
16
|
http-cookie (1.1.0)
|
|
16
17
|
domain_name (~> 0.5)
|
|
18
|
+
io-console (0.8.2)
|
|
17
19
|
logger (1.7.0)
|
|
18
20
|
mime-types (3.7.0)
|
|
19
21
|
logger
|
|
20
22
|
mime-types-data (~> 3.2025, >= 3.2025.0507)
|
|
21
|
-
mime-types-data (3.
|
|
23
|
+
mime-types-data (3.2026.0317)
|
|
22
24
|
netrc (0.11.0)
|
|
25
|
+
reline (0.6.3)
|
|
26
|
+
io-console (~> 0.5)
|
|
23
27
|
rest-client (2.1.0)
|
|
24
28
|
http-accept (>= 1.7.0, < 2.0)
|
|
25
29
|
http-cookie (>= 1.0.2, < 2.0)
|
|
@@ -34,16 +38,16 @@ GEM
|
|
|
34
38
|
rspec-expectations (3.13.5)
|
|
35
39
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
36
40
|
rspec-support (~> 3.13.0)
|
|
37
|
-
rspec-mocks (3.13.
|
|
41
|
+
rspec-mocks (3.13.8)
|
|
38
42
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
39
43
|
rspec-support (~> 3.13.0)
|
|
40
|
-
rspec-support (3.13.
|
|
44
|
+
rspec-support (3.13.7)
|
|
41
45
|
|
|
42
46
|
PLATFORMS
|
|
43
47
|
ruby
|
|
44
48
|
|
|
45
49
|
DEPENDENCIES
|
|
46
|
-
byebug (=
|
|
50
|
+
byebug (= 13.0.0)
|
|
47
51
|
keycloak-admin!
|
|
48
52
|
rspec (= 3.13.2)
|
|
49
53
|
|
data/README.md
CHANGED
|
@@ -135,6 +135,8 @@ All options have a default value. However, all of them can be changed in your in
|
|
|
135
135
|
* Execute actions emails
|
|
136
136
|
* Send forgot passsword mail
|
|
137
137
|
* Client Authorization, create, update, get, delete Resource, Scope, Policy, Permission, Policy Enforcer
|
|
138
|
+
* Get list of client scopes, create/save/get/delete/search a client scope
|
|
139
|
+
* Get list of protocol mappers for a client scope, create/save/get/delete a protocol mapper
|
|
138
140
|
* Get list of organizations, create/update/get/delete an organization
|
|
139
141
|
* Get list of members of an organization, add/remove members
|
|
140
142
|
* Invite new or existing users to an organization
|
|
@@ -757,6 +759,120 @@ KeycloakAdmin.realm("realm_a").authz_permissions(client.id, 'scope').delete(scop
|
|
|
757
759
|
KeycloakAdmin.realm("realm_a").authz_permissions(client.id, 'resource').delete(resource_permission.id)
|
|
758
760
|
```
|
|
759
761
|
|
|
762
|
+
### Manage Client Scopes
|
|
763
|
+
|
|
764
|
+
### List all client scopes in a realm
|
|
765
|
+
|
|
766
|
+
Returns an array of `KeycloakAdmin::ClientScopeRepresentation`.
|
|
767
|
+
|
|
768
|
+
```ruby
|
|
769
|
+
KeycloakAdmin.realm("a_realm").client_scopes.list
|
|
770
|
+
```
|
|
771
|
+
|
|
772
|
+
### Get a client scope by its id
|
|
773
|
+
|
|
774
|
+
Returns an instance of `KeycloakAdmin::ClientScopeRepresentation`.
|
|
775
|
+
|
|
776
|
+
```ruby
|
|
777
|
+
client_scope_id = "7686af34-204c-4515-8122-78d19febbf6e"
|
|
778
|
+
KeycloakAdmin.realm("a_realm").client_scopes.get(client_scope_id)
|
|
779
|
+
```
|
|
780
|
+
|
|
781
|
+
### Search for client scopes by name
|
|
782
|
+
|
|
783
|
+
Returns an array of `KeycloakAdmin::ClientScopeRepresentation` whose names contain the given substring.
|
|
784
|
+
|
|
785
|
+
```ruby
|
|
786
|
+
KeycloakAdmin.realm("a_realm").client_scopes.search("my-scope")
|
|
787
|
+
```
|
|
788
|
+
|
|
789
|
+
### Create a client scope
|
|
790
|
+
|
|
791
|
+
Takes `scope_representation` of type `KeycloakAdmin::ClientScopeRepresentation`. Returns `true` on success.
|
|
792
|
+
|
|
793
|
+
```ruby
|
|
794
|
+
scope = KeycloakAdmin::ClientScopeRepresentation.new
|
|
795
|
+
scope.name = "my-scope"
|
|
796
|
+
scope.description = "My custom scope"
|
|
797
|
+
scope.protocol = "openid-connect"
|
|
798
|
+
scope.attributes = { "display.on.consent.screen" => "true", "include.in.token.scope" => "true" }
|
|
799
|
+
KeycloakAdmin.realm("a_realm").client_scopes.create!(scope)
|
|
800
|
+
```
|
|
801
|
+
|
|
802
|
+
### Save (update) a client scope
|
|
803
|
+
|
|
804
|
+
Takes `scope_representation` of type `KeycloakAdmin::ClientScopeRepresentation` (must include its `id`). Returns `true` on success.
|
|
805
|
+
|
|
806
|
+
```ruby
|
|
807
|
+
client_scope_id = "7686af34-204c-4515-8122-78d19febbf6e"
|
|
808
|
+
scope = KeycloakAdmin.realm("a_realm").client_scopes.get(client_scope_id)
|
|
809
|
+
scope.description = "Updated description"
|
|
810
|
+
KeycloakAdmin.realm("a_realm").client_scopes.save(scope)
|
|
811
|
+
```
|
|
812
|
+
|
|
813
|
+
### Delete a client scope
|
|
814
|
+
|
|
815
|
+
```ruby
|
|
816
|
+
client_scope_id = "7686af34-204c-4515-8122-78d19febbf6e"
|
|
817
|
+
KeycloakAdmin.realm("a_realm").client_scopes.delete(client_scope_id)
|
|
818
|
+
```
|
|
819
|
+
|
|
820
|
+
### Manage Protocol Mappers for a Client Scope
|
|
821
|
+
|
|
822
|
+
Protocol mappers allow you to transform tokens and assertions. The following operations are available on the protocol mappers of a given client scope.
|
|
823
|
+
|
|
824
|
+
### List protocol mappers for a client scope
|
|
825
|
+
|
|
826
|
+
Returns an array of `KeycloakAdmin::ProtocolMapperRepresentation`.
|
|
827
|
+
|
|
828
|
+
```ruby
|
|
829
|
+
client_scope_id = "7686af34-204c-4515-8122-78d19febbf6e"
|
|
830
|
+
KeycloakAdmin.realm("a_realm").client_scope_protocol_mappers(client_scope_id).list
|
|
831
|
+
```
|
|
832
|
+
|
|
833
|
+
### Get a protocol mapper by its id
|
|
834
|
+
|
|
835
|
+
Returns an instance of `KeycloakAdmin::ProtocolMapperRepresentation`.
|
|
836
|
+
|
|
837
|
+
```ruby
|
|
838
|
+
client_scope_id = "7686af34-204c-4515-8122-78d19febbf6e"
|
|
839
|
+
mapper_id = "95985b21-d884-4bbd-b852-cb8cd365afc2"
|
|
840
|
+
KeycloakAdmin.realm("a_realm").client_scope_protocol_mappers(client_scope_id).get(mapper_id)
|
|
841
|
+
```
|
|
842
|
+
|
|
843
|
+
### Create a protocol mapper for a client scope
|
|
844
|
+
|
|
845
|
+
Takes `mapper_representation` of type `KeycloakAdmin::ProtocolMapperRepresentation`. Returns `true` on success.
|
|
846
|
+
|
|
847
|
+
```ruby
|
|
848
|
+
client_scope_id = "7686af34-204c-4515-8122-78d19febbf6e"
|
|
849
|
+
mapper = KeycloakAdmin::ProtocolMapperRepresentation.new
|
|
850
|
+
mapper.name = "my-mapper"
|
|
851
|
+
mapper.protocol = "openid-connect"
|
|
852
|
+
mapper.protocolMapper = "oidc-usermodel-attribute-mapper"
|
|
853
|
+
mapper.config = { "user.attribute" => "locale", "claim.name" => "locale", "jsonType.label" => "String", "id.token.claim" => "true", "access.token.claim" => "true", "userinfo.token.claim" => "true" }
|
|
854
|
+
KeycloakAdmin.realm("a_realm").client_scope_protocol_mappers(client_scope_id).create!(mapper)
|
|
855
|
+
```
|
|
856
|
+
|
|
857
|
+
### Save (update) a protocol mapper for a client scope
|
|
858
|
+
|
|
859
|
+
Takes `mapper_representation` of type `KeycloakAdmin::ProtocolMapperRepresentation` (must include its `id`). Returns `true` on success.
|
|
860
|
+
|
|
861
|
+
```ruby
|
|
862
|
+
client_scope_id = "7686af34-204c-4515-8122-78d19febbf6e"
|
|
863
|
+
mapper = KeycloakAdmin.realm("a_realm").client_scope_protocol_mappers(client_scope_id).get(mapper_id)
|
|
864
|
+
mapper.config["claim.name"] = "updated_claim"
|
|
865
|
+
KeycloakAdmin.realm("a_realm").client_scope_protocol_mappers(client_scope_id).save(mapper)
|
|
866
|
+
```
|
|
867
|
+
|
|
868
|
+
### Delete a protocol mapper from a client scope
|
|
869
|
+
|
|
870
|
+
```ruby
|
|
871
|
+
client_scope_id = "7686af34-204c-4515-8122-78d19febbf6e"
|
|
872
|
+
mapper_id = "95985b21-d884-4bbd-b852-cb8cd365afc2"
|
|
873
|
+
KeycloakAdmin.realm("a_realm").client_scope_protocol_mappers(client_scope_id).delete(mapper_id)
|
|
874
|
+
```
|
|
875
|
+
|
|
760
876
|
## How to execute library tests
|
|
761
877
|
|
|
762
878
|
From the `keycloak-admin-api` directory:
|
data/keycloak-admin.gemspec
CHANGED
|
@@ -20,5 +20,5 @@ Gem::Specification.new do |spec|
|
|
|
20
20
|
spec.add_dependency "http-cookie", "~> 1.0", ">= 1.0.3"
|
|
21
21
|
spec.add_dependency "rest-client", "~> 2.0"
|
|
22
22
|
spec.add_development_dependency "rspec", "3.13.2"
|
|
23
|
-
spec.add_development_dependency "byebug", "
|
|
23
|
+
spec.add_development_dependency "byebug", "13.0.0"
|
|
24
24
|
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
module KeycloakAdmin
|
|
2
|
+
class ClientScopeClient < Client
|
|
3
|
+
def initialize(configuration, realm_client)
|
|
4
|
+
super(configuration)
|
|
5
|
+
|
|
6
|
+
raise ArgumentError.new("realm must be defined") unless realm_client.name_defined?
|
|
7
|
+
|
|
8
|
+
@realm_client = realm_client
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def list
|
|
12
|
+
response = execute_http do
|
|
13
|
+
RestClient::Resource.new(client_scopes_url, @configuration.rest_client_options).get(headers)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
JSON.parse(response).map { |h| ClientScopeRepresentation.from_hash(h) }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def get(client_scope_id)
|
|
20
|
+
response = execute_http do
|
|
21
|
+
RestClient::Resource.new(client_scopes_url(client_scope_id), @configuration.rest_client_options).get(headers)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
ClientScopeRepresentation.from_hash(JSON.parse(response))
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def create!(client_scope_representation)
|
|
28
|
+
execute_http do
|
|
29
|
+
RestClient::Resource.new(client_scopes_url, @configuration.rest_client_options).post(
|
|
30
|
+
create_payload(client_scope_representation), headers
|
|
31
|
+
)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
true
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def save(client_scope_representation)
|
|
38
|
+
execute_http do
|
|
39
|
+
RestClient::Resource.new(client_scopes_url(client_scope_representation.id), @configuration.rest_client_options).put(
|
|
40
|
+
create_payload(client_scope_representation), headers
|
|
41
|
+
)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
true
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def search(name)
|
|
48
|
+
list.select { |scope| scope&.name&.include?(name) }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def delete(client_scope_id)
|
|
52
|
+
execute_http do
|
|
53
|
+
RestClient::Resource.new(client_scopes_url(client_scope_id), @configuration.rest_client_options).delete(headers)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
true
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def client_scopes_url(client_scope_id = nil)
|
|
60
|
+
base = "#{@realm_client.realm_admin_url}/client-scopes"
|
|
61
|
+
|
|
62
|
+
client_scope_id ? "#{base}/#{client_scope_id}" : base
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
module KeycloakAdmin
|
|
2
|
+
class ClientScopeProtocolMapperClient < Client
|
|
3
|
+
def initialize(configuration, realm_client, client_scope_id)
|
|
4
|
+
super(configuration)
|
|
5
|
+
|
|
6
|
+
raise ArgumentError.new("realm must be defined") unless realm_client.name_defined?
|
|
7
|
+
|
|
8
|
+
@realm_client = realm_client
|
|
9
|
+
@client_scope_id = client_scope_id
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def list
|
|
13
|
+
response = execute_http do
|
|
14
|
+
RestClient::Resource.new(protocol_mappers_url, @configuration.rest_client_options).get(headers)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
JSON.parse(response).map { |h| ProtocolMapperRepresentation.from_hash(h) }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def get(mapper_id)
|
|
21
|
+
response = execute_http do
|
|
22
|
+
RestClient::Resource.new(protocol_mappers_url(mapper_id), @configuration.rest_client_options).get(headers)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
ProtocolMapperRepresentation.from_hash(JSON.parse(response))
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def create!(mapper_representation)
|
|
29
|
+
execute_http do
|
|
30
|
+
RestClient::Resource.new(protocol_mappers_url, @configuration.rest_client_options).post(
|
|
31
|
+
create_payload(mapper_representation), headers
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
true
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def save(mapper_representation)
|
|
39
|
+
execute_http do
|
|
40
|
+
RestClient::Resource.new(protocol_mappers_url(mapper_representation.id), @configuration.rest_client_options).put(
|
|
41
|
+
create_payload(mapper_representation), headers
|
|
42
|
+
)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
true
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def delete(mapper_id)
|
|
49
|
+
execute_http do
|
|
50
|
+
RestClient::Resource.new(protocol_mappers_url(mapper_id), @configuration.rest_client_options).delete(headers)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
true
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def protocol_mappers_url(mapper_id = nil)
|
|
57
|
+
base = "#{@realm_client.realm_admin_url}/client-scopes/#{@client_scope_id}/protocol-mappers/models"
|
|
58
|
+
|
|
59
|
+
mapper_id ? "#{base}/#{mapper_id}" : base
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -103,6 +103,14 @@ module KeycloakAdmin
|
|
|
103
103
|
UserResource.new(@configuration, self, user_id)
|
|
104
104
|
end
|
|
105
105
|
|
|
106
|
+
def client_scopes
|
|
107
|
+
ClientScopeClient.new(@configuration, self)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def client_scope_protocol_mappers(client_scope_id)
|
|
111
|
+
ClientScopeProtocolMapperClient.new(@configuration, self, client_scope_id)
|
|
112
|
+
end
|
|
113
|
+
|
|
106
114
|
def authz_scopes(client_id, resource_id = nil)
|
|
107
115
|
ClientAuthzScopeClient.new(@configuration, self, client_id, resource_id)
|
|
108
116
|
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module KeycloakAdmin
|
|
2
|
+
class ClientScopeRepresentation < Representation
|
|
3
|
+
attr_accessor :id,
|
|
4
|
+
:name,
|
|
5
|
+
:description,
|
|
6
|
+
:protocol,
|
|
7
|
+
:attributes,
|
|
8
|
+
:protocol_mappers
|
|
9
|
+
|
|
10
|
+
def self.from_hash(hash)
|
|
11
|
+
rep = new
|
|
12
|
+
rep.id = hash["id"]
|
|
13
|
+
rep.name = hash["name"]
|
|
14
|
+
rep.description = hash["description"]
|
|
15
|
+
rep.protocol = hash["protocol"]
|
|
16
|
+
rep.attributes = hash["attributes"]
|
|
17
|
+
rep.protocol_mappers = (hash["protocolMappers"] || []).map { |m| ProtocolMapperRepresentation.from_hash(m) }
|
|
18
|
+
rep
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
data/lib/keycloak-admin.rb
CHANGED
|
@@ -16,6 +16,8 @@ require_relative "keycloak-admin/client/identity_provider_client"
|
|
|
16
16
|
require_relative "keycloak-admin/client/configurable_token_client"
|
|
17
17
|
require_relative "keycloak-admin/client/attack_detection_client"
|
|
18
18
|
require_relative "keycloak-admin/client/client_authz_scope_client"
|
|
19
|
+
require_relative "keycloak-admin/client/client_scope_client"
|
|
20
|
+
require_relative "keycloak-admin/client/client_scope_protocol_mapper_client"
|
|
19
21
|
require_relative "keycloak-admin/client/client_authz_resource_client"
|
|
20
22
|
require_relative "keycloak-admin/client/client_authz_policy_client"
|
|
21
23
|
require_relative "keycloak-admin/client/client_authz_permission_client"
|
|
@@ -39,6 +41,7 @@ require_relative "keycloak-admin/representation/identity_provider_mapper_represe
|
|
|
39
41
|
require_relative "keycloak-admin/representation/identity_provider_representation"
|
|
40
42
|
require_relative "keycloak-admin/representation/attack_detection_representation"
|
|
41
43
|
require_relative "keycloak-admin/representation/session_representation"
|
|
44
|
+
require_relative "keycloak-admin/representation/client_scope_representation"
|
|
42
45
|
require_relative "keycloak-admin/representation/client_authz_scope_representation"
|
|
43
46
|
require_relative "keycloak-admin/representation/client_authz_resource_representation"
|
|
44
47
|
require_relative "keycloak-admin/representation/client_authz_policy_representation"
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
RSpec.describe KeycloakAdmin::ClientScopeClient do
|
|
2
|
+
let(:realm_name) { "valid-realm" }
|
|
3
|
+
let(:client_scope_id) { "valid-scope-id" }
|
|
4
|
+
|
|
5
|
+
let(:scope_json) do
|
|
6
|
+
<<~JSON
|
|
7
|
+
{"id":"valid-scope-id","name":"my-scope","description":"A test scope","protocol":"openid-connect","attributes":{"display.on.consent.screen":"true","include.in.token.scope":"true"}}
|
|
8
|
+
JSON
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
let(:scope_with_mappers_json) do
|
|
12
|
+
<<~JSON
|
|
13
|
+
{"id":"valid-scope-id","name":"my-scope","description":"A test scope","protocol":"openid-connect","attributes":{},"protocolMappers":[{"id":"mapper-id","name":"my-claim","protocol":"openid-connect","protocolMapper":"oidc-hardcoded-claim-mapper","config":{"claim.name":"my_claim","claim.value":"bar","access.token.claim":"true"}}]}
|
|
14
|
+
JSON
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe "#initialize" do
|
|
18
|
+
context "when realm_name is defined" do
|
|
19
|
+
it "does not raise any error" do
|
|
20
|
+
expect { KeycloakAdmin.realm(realm_name).client_scopes }.to_not raise_error
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
context "when realm_name is not defined" do
|
|
25
|
+
it "raises an argument error" do
|
|
26
|
+
expect { KeycloakAdmin.realm(nil).client_scopes }.to raise_error(ArgumentError)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
describe "#list" do
|
|
32
|
+
before(:each) do
|
|
33
|
+
@client = KeycloakAdmin.realm(realm_name).client_scopes
|
|
34
|
+
stub_token_client
|
|
35
|
+
allow_any_instance_of(RestClient::Resource).to receive(:get).and_return stub_response
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
context "with one scope" do
|
|
39
|
+
let(:stub_response) { "[#{scope_json}]" }
|
|
40
|
+
|
|
41
|
+
it "returns one scope" do
|
|
42
|
+
expect(@client.list.size).to eq 1
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "returns the correct scope attributes" do
|
|
46
|
+
expect(@client.list.first).to have_attributes(
|
|
47
|
+
id: "valid-scope-id",
|
|
48
|
+
name: "my-scope",
|
|
49
|
+
description: "A test scope",
|
|
50
|
+
protocol: "openid-connect"
|
|
51
|
+
)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "returns attributes map" do
|
|
55
|
+
expect(@client.list.first.attributes).to include(
|
|
56
|
+
"display.on.consent.screen" => "true",
|
|
57
|
+
"include.in.token.scope" => "true"
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
context "with multiple scopes" do
|
|
63
|
+
let(:second_scope_json) { '{"id":"other-scope-id","name":"other-scope","protocol":"openid-connect"}' }
|
|
64
|
+
let(:stub_response) { "[#{scope_json},#{second_scope_json}]" }
|
|
65
|
+
|
|
66
|
+
it "returns two scopes" do
|
|
67
|
+
expect(@client.list.size).to eq 2
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "includes both scope names" do
|
|
71
|
+
expect(@client.list.map(&:name)).to include("my-scope", "other-scope")
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
describe "#get" do
|
|
77
|
+
before(:each) do
|
|
78
|
+
@client = KeycloakAdmin.realm(realm_name).client_scopes
|
|
79
|
+
stub_token_client
|
|
80
|
+
allow_any_instance_of(RestClient::Resource).to receive(:get).and_return stub_response
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
context "without protocol mappers" do
|
|
84
|
+
let(:stub_response) { scope_json }
|
|
85
|
+
|
|
86
|
+
it "returns the correct id" do
|
|
87
|
+
expect(@client.get(client_scope_id).id).to eq "valid-scope-id"
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it "returns the correct name" do
|
|
91
|
+
expect(@client.get(client_scope_id).name).to eq "my-scope"
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it "returns the correct description" do
|
|
95
|
+
expect(@client.get(client_scope_id).description).to eq "A test scope"
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it "returns the correct protocol" do
|
|
99
|
+
expect(@client.get(client_scope_id).protocol).to eq "openid-connect"
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it "returns an empty protocolMappers list" do
|
|
103
|
+
expect(@client.get(client_scope_id).protocol_mappers).to eq []
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
context "with protocol mappers" do
|
|
108
|
+
let(:stub_response) { scope_with_mappers_json }
|
|
109
|
+
|
|
110
|
+
it "returns protocol mappers" do
|
|
111
|
+
expect(@client.get(client_scope_id).protocol_mappers.size).to eq 1
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
it "returns the correct mapper name" do
|
|
115
|
+
expect(@client.get(client_scope_id).protocol_mappers.first.name).to eq "my-claim"
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
describe "#create!" do
|
|
121
|
+
before(:each) do
|
|
122
|
+
@client = KeycloakAdmin.realm(realm_name).client_scopes
|
|
123
|
+
stub_token_client
|
|
124
|
+
allow_any_instance_of(RestClient::Resource).to receive(:post).and_return ""
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
let(:scope_representation) do
|
|
128
|
+
scope = KeycloakAdmin::ClientScopeRepresentation.new
|
|
129
|
+
scope.name = "my-scope"
|
|
130
|
+
scope.description = "A test scope"
|
|
131
|
+
scope.protocol = "openid-connect"
|
|
132
|
+
scope.attributes = { "display.on.consent.screen" => "true", "include.in.token.scope" => "true" }
|
|
133
|
+
scope
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it "creates successfully" do
|
|
137
|
+
expect(@client.create!(scope_representation)).to be true
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
describe "#save" do
|
|
142
|
+
before(:each) do
|
|
143
|
+
@client = KeycloakAdmin.realm(realm_name).client_scopes
|
|
144
|
+
stub_token_client
|
|
145
|
+
allow_any_instance_of(RestClient::Resource).to receive(:put).and_return ""
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
let(:scope_representation) { KeycloakAdmin::ClientScopeRepresentation.from_hash(JSON.parse(scope_json)) }
|
|
149
|
+
|
|
150
|
+
it "calls put on the scope url" do
|
|
151
|
+
expect_any_instance_of(RestClient::Resource).to receive(:put).with(anything, anything)
|
|
152
|
+
@client.save(scope_representation)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
it "returns true" do
|
|
156
|
+
expect(@client.save(scope_representation)).to be true
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
describe "#search" do
|
|
161
|
+
let(:second_scope_json) { '{"id":"other-scope-id","name":"other-scope","protocol":"openid-connect"}' }
|
|
162
|
+
|
|
163
|
+
before(:each) do
|
|
164
|
+
@client = KeycloakAdmin.realm(realm_name).client_scopes
|
|
165
|
+
stub_token_client
|
|
166
|
+
allow_any_instance_of(RestClient::Resource).to receive(:get).and_return "[#{scope_json},#{second_scope_json}]"
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
context "when the name matches one scope" do
|
|
170
|
+
it "returns only the matching scope" do
|
|
171
|
+
expect(@client.search("my-scope").size).to eq 1
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
it "returns the correct scope" do
|
|
175
|
+
expect(@client.search("my-scope").first).to have_attributes(id: "valid-scope-id", name: "my-scope")
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
context "when the name is a partial match" do
|
|
180
|
+
it "returns all scopes containing the substring" do
|
|
181
|
+
expect(@client.search("scope").size).to eq 2
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
context "when no scope matches" do
|
|
186
|
+
it "returns an empty array" do
|
|
187
|
+
expect(@client.search("unknown")).to eq []
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
describe "#delete" do
|
|
193
|
+
before(:each) do
|
|
194
|
+
@client = KeycloakAdmin.realm(realm_name).client_scopes
|
|
195
|
+
stub_token_client
|
|
196
|
+
allow_any_instance_of(RestClient::Resource).to receive(:delete).and_return ""
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
it "returns true" do
|
|
200
|
+
expect(@client.delete(client_scope_id)).to eq true
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
describe "#client_scopes_url" do
|
|
205
|
+
let(:client) { KeycloakAdmin.realm(realm_name).client_scopes }
|
|
206
|
+
let(:base_url) { "http://auth.service.io/auth/admin/realms/valid-realm/client-scopes" }
|
|
207
|
+
|
|
208
|
+
context "without a client_scope_id" do
|
|
209
|
+
it "returns the base url" do
|
|
210
|
+
expect(client.client_scopes_url).to eq base_url
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
context "with a client_scope_id" do
|
|
215
|
+
it "returns the url with client_scope_id appended" do
|
|
216
|
+
expect(client.client_scopes_url(client_scope_id)).to eq "#{base_url}/valid-scope-id"
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
end
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
RSpec.describe KeycloakAdmin::ClientScopeProtocolMapperClient do
|
|
2
|
+
let(:realm_name) { "valid-realm" }
|
|
3
|
+
let(:client_scope_id) { "valid-scope-id" }
|
|
4
|
+
let(:mapper_id) { "valid-mapper-id" }
|
|
5
|
+
|
|
6
|
+
let(:mapper_json) do
|
|
7
|
+
<<~JSON
|
|
8
|
+
{"id":"valid-mapper-id","name":"my-claim","protocol":"openid-connect","protocolMapper":"oidc-hardcoded-claim-mapper","config":{"claim.name":"my_claim","claim.value":"bar","access.token.claim":"true"}}
|
|
9
|
+
JSON
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
let(:audience_mapper_json) do
|
|
13
|
+
<<~JSON
|
|
14
|
+
{"protocol":"openid-connect","protocolMapper":"oidc-audience-mapper","name":"audience-config-rvw-123","config":{"included.client.audience":"","included.custom.audience":"https://api.example.com","id.token.claim":"false","access.token.claim":"true","lightweight.claim":"false","introspection.token.claim":"true"}}
|
|
15
|
+
JSON
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe "#initialize" do
|
|
19
|
+
context "when realm_name is defined" do
|
|
20
|
+
it "does not raise any error" do
|
|
21
|
+
expect { KeycloakAdmin.realm(realm_name).client_scope_protocol_mappers(client_scope_id) }.to_not raise_error
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
context "when realm_name is not defined" do
|
|
26
|
+
it "raises an argument error" do
|
|
27
|
+
expect { KeycloakAdmin.realm(nil).client_scope_protocol_mappers(client_scope_id) }.to raise_error(ArgumentError)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
describe "#list" do
|
|
33
|
+
before(:each) do
|
|
34
|
+
@client = KeycloakAdmin.realm(realm_name).client_scope_protocol_mappers(client_scope_id)
|
|
35
|
+
stub_token_client
|
|
36
|
+
allow_any_instance_of(RestClient::Resource).to receive(:get).and_return stub_response
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
context "with a hardcoded claim mapper" do
|
|
40
|
+
let(:stub_response) { "[#{mapper_json}]" }
|
|
41
|
+
|
|
42
|
+
it "returns one mapper" do
|
|
43
|
+
expect(@client.list.size).to eq 1
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "returns the correct mapper attributes" do
|
|
47
|
+
expect(@client.list.first).to have_attributes(id: "valid-mapper-id", name: "my-claim", protocol: "openid-connect", protocolMapper: "oidc-hardcoded-claim-mapper")
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
context "with an audience mapper" do
|
|
52
|
+
let(:stub_response) { "[#{audience_mapper_json}]" }
|
|
53
|
+
|
|
54
|
+
it "returns one mapper" do
|
|
55
|
+
expect(@client.list.size).to eq 1
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "returns the correct mapper attributes" do
|
|
59
|
+
expect(@client.list.first).to have_attributes(name: "audience-config-rvw-123", protocol: "openid-connect", protocolMapper: "oidc-audience-mapper")
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
context "with multiple mappers" do
|
|
64
|
+
let(:stub_response) { "[#{mapper_json},#{audience_mapper_json}]" }
|
|
65
|
+
|
|
66
|
+
it "returns two mappers" do
|
|
67
|
+
expect(@client.list.size).to eq 2
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "includes both mapper names" do
|
|
71
|
+
expect(@client.list.map(&:name)).to include("my-claim", "audience-config-rvw-123")
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
describe "#get" do
|
|
77
|
+
before(:each) do
|
|
78
|
+
@client = KeycloakAdmin.realm(realm_name).client_scope_protocol_mappers(client_scope_id)
|
|
79
|
+
stub_token_client
|
|
80
|
+
allow_any_instance_of(RestClient::Resource).to receive(:get).and_return stub_response
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
context "with a hardcoded claim mapper" do
|
|
84
|
+
let(:stub_response) { mapper_json }
|
|
85
|
+
|
|
86
|
+
it "returns the correct id" do
|
|
87
|
+
expect(@client.get(mapper_id).id).to eq "valid-mapper-id"
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it "returns the correct name" do
|
|
91
|
+
expect(@client.get(mapper_id).name).to eq "my-claim"
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it "returns the correct protocol" do
|
|
95
|
+
expect(@client.get(mapper_id).protocol).to eq "openid-connect"
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it "returns the correct protocolMapper" do
|
|
99
|
+
expect(@client.get(mapper_id).protocolMapper).to eq "oidc-hardcoded-claim-mapper"
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
context "with an audience mapper" do
|
|
104
|
+
let(:stub_response) { audience_mapper_json }
|
|
105
|
+
|
|
106
|
+
it "returns the correct name" do
|
|
107
|
+
expect(@client.get(mapper_id).name).to eq "audience-config-rvw-123"
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it "returns the correct protocol" do
|
|
111
|
+
expect(@client.get(mapper_id).protocol).to eq "openid-connect"
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
it "returns the correct protocolMapper" do
|
|
115
|
+
expect(@client.get(mapper_id).protocolMapper).to eq "oidc-audience-mapper"
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
it "returns the correct config" do
|
|
119
|
+
expect(@client.get(mapper_id).config).to include(
|
|
120
|
+
"included.custom.audience" => "https://api.example.com",
|
|
121
|
+
"access.token.claim" => "true",
|
|
122
|
+
"introspection.token.claim" => "true",
|
|
123
|
+
"id.token.claim" => "false"
|
|
124
|
+
)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
describe "#create!" do
|
|
130
|
+
before(:each) do
|
|
131
|
+
@client = KeycloakAdmin.realm(realm_name).client_scope_protocol_mappers(client_scope_id)
|
|
132
|
+
stub_token_client
|
|
133
|
+
allow_any_instance_of(RestClient::Resource).to receive(:post).and_return stub_response
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
context "with a hardcoded claim mapper" do
|
|
137
|
+
let(:stub_response) { mapper_json }
|
|
138
|
+
let(:mapper_representation) do
|
|
139
|
+
mapper = KeycloakAdmin::ProtocolMapperRepresentation.new
|
|
140
|
+
mapper.name = "my-claim"
|
|
141
|
+
mapper.protocol = "openid-connect"
|
|
142
|
+
mapper.protocolMapper = "oidc-hardcoded-claim-mapper"
|
|
143
|
+
mapper.config = { "claim.name" => "my_claim", "claim.value" => "bar", "access.token.claim" => "true" }
|
|
144
|
+
mapper
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it "creates successfully" do
|
|
148
|
+
expect(@client.create!(mapper_representation)).to be true
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
context "with an audience mapper" do
|
|
153
|
+
let(:stub_response) { audience_mapper_json }
|
|
154
|
+
let(:mapper_representation) do
|
|
155
|
+
mapper = KeycloakAdmin::ProtocolMapperRepresentation.new
|
|
156
|
+
mapper.name = "audience-config-rvw-123"
|
|
157
|
+
mapper.protocol = "openid-connect"
|
|
158
|
+
mapper.protocolMapper = "oidc-audience-mapper"
|
|
159
|
+
mapper.config = {
|
|
160
|
+
"included.client.audience" => "",
|
|
161
|
+
"included.custom.audience" => "https://api.example.com",
|
|
162
|
+
"id.token.claim" => "false",
|
|
163
|
+
"access.token.claim" => "true",
|
|
164
|
+
"lightweight.claim" => "false",
|
|
165
|
+
"introspection.token.claim" => "true"
|
|
166
|
+
}
|
|
167
|
+
mapper
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
it "creates successfully" do
|
|
171
|
+
expect(@client.create!(mapper_representation)).to be true
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
describe "#save" do
|
|
177
|
+
before(:each) do
|
|
178
|
+
@client = KeycloakAdmin.realm(realm_name).client_scope_protocol_mappers(client_scope_id)
|
|
179
|
+
stub_token_client
|
|
180
|
+
allow_any_instance_of(RestClient::Resource).to receive(:put).and_return ""
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
context "with a hardcoded claim mapper" do
|
|
184
|
+
let(:mapper_representation) { KeycloakAdmin::ProtocolMapperRepresentation.from_hash(JSON.parse(mapper_json)) }
|
|
185
|
+
|
|
186
|
+
it "calls put on the mapper url" do
|
|
187
|
+
expect_any_instance_of(RestClient::Resource).to receive(:put).with(anything, anything)
|
|
188
|
+
@client.save(mapper_representation)
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
context "with an audience mapper" do
|
|
193
|
+
let(:mapper_representation) { KeycloakAdmin::ProtocolMapperRepresentation.from_hash(JSON.parse(audience_mapper_json)) }
|
|
194
|
+
|
|
195
|
+
it "calls put on the mapper url" do
|
|
196
|
+
expect_any_instance_of(RestClient::Resource).to receive(:put).with(anything, anything)
|
|
197
|
+
@client.save(mapper_representation)
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
describe "#delete" do
|
|
203
|
+
before(:each) do
|
|
204
|
+
@client = KeycloakAdmin.realm(realm_name).client_scope_protocol_mappers(client_scope_id)
|
|
205
|
+
stub_token_client
|
|
206
|
+
allow_any_instance_of(RestClient::Resource).to receive(:delete).and_return ""
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
it "returns true" do
|
|
210
|
+
expect(@client.delete(mapper_id)).to eq true
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
describe "#protocol_mappers_url" do
|
|
215
|
+
let(:client) { KeycloakAdmin.realm(realm_name).client_scope_protocol_mappers(client_scope_id) }
|
|
216
|
+
let(:base_url) { "http://auth.service.io/auth/admin/realms/valid-realm/client-scopes/valid-scope-id/protocol-mappers/models" }
|
|
217
|
+
|
|
218
|
+
context "without a mapper_id" do
|
|
219
|
+
it "returns the base url" do
|
|
220
|
+
expect(client.protocol_mappers_url).to eq base_url
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
context "with a mapper_id" do
|
|
225
|
+
it "returns the url with mapper_id appended" do
|
|
226
|
+
expect(client.protocol_mappers_url(mapper_id)).to eq "#{base_url}/valid-mapper-id"
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
end
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe KeycloakAdmin::ClientScopeRepresentation do
|
|
4
|
+
describe ".from_hash" do
|
|
5
|
+
context "with all fields" do
|
|
6
|
+
let(:hash) do
|
|
7
|
+
{
|
|
8
|
+
"id" => "valid-scope-id",
|
|
9
|
+
"name" => "my-scope",
|
|
10
|
+
"description" => "A test scope",
|
|
11
|
+
"protocol" => "openid-connect",
|
|
12
|
+
"attributes" => {
|
|
13
|
+
"display.on.consent.screen" => "true",
|
|
14
|
+
"include.in.token.scope" => "true"
|
|
15
|
+
},
|
|
16
|
+
"protocolMappers" => [
|
|
17
|
+
{
|
|
18
|
+
"id" => "mapper-id",
|
|
19
|
+
"name" => "my-claim",
|
|
20
|
+
"protocol" => "openid-connect",
|
|
21
|
+
"protocolMapper" => "oidc-hardcoded-claim-mapper",
|
|
22
|
+
"config" => { "claim.name" => "my_claim", "claim.value" => "bar" }
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
subject { described_class.from_hash(hash) }
|
|
29
|
+
|
|
30
|
+
it "returns an instance of the class" do
|
|
31
|
+
expect(subject).to be_a described_class
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "sets id" do
|
|
35
|
+
expect(subject.id).to eq "valid-scope-id"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "sets name" do
|
|
39
|
+
expect(subject.name).to eq "my-scope"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "sets description" do
|
|
43
|
+
expect(subject.description).to eq "A test scope"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "sets protocol" do
|
|
47
|
+
expect(subject.protocol).to eq "openid-connect"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "sets attributes" do
|
|
51
|
+
expect(subject.attributes).to eq(
|
|
52
|
+
"display.on.consent.screen" => "true",
|
|
53
|
+
"include.in.token.scope" => "true"
|
|
54
|
+
)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "deserializes protocolMappers as ProtocolMapperRepresentation objects" do
|
|
58
|
+
expect(subject.protocol_mappers.size).to eq 1
|
|
59
|
+
expect(subject.protocol_mappers.first).to be_a KeycloakAdmin::ProtocolMapperRepresentation
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "sets the correct mapper attributes" do
|
|
63
|
+
expect(subject.protocol_mappers.first).to have_attributes(
|
|
64
|
+
id: "mapper-id",
|
|
65
|
+
name: "my-claim",
|
|
66
|
+
protocol: "openid-connect",
|
|
67
|
+
protocolMapper: "oidc-hardcoded-claim-mapper"
|
|
68
|
+
)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
context "without protocolMappers" do
|
|
73
|
+
subject { described_class.from_hash({ "id" => "valid-scope-id", "name" => "my-scope" }) }
|
|
74
|
+
|
|
75
|
+
it "defaults protocolMappers to an empty array" do
|
|
76
|
+
expect(subject.protocol_mappers).to eq []
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
context "with minimal fields" do
|
|
81
|
+
subject { described_class.from_hash({ "name" => "my-scope", "protocol" => "saml" }) }
|
|
82
|
+
|
|
83
|
+
it "sets name" do
|
|
84
|
+
expect(subject.name).to eq "my-scope"
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it "sets protocol" do
|
|
88
|
+
expect(subject.protocol).to eq "saml"
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it "leaves id nil" do
|
|
92
|
+
expect(subject.id).to be_nil
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
it "leaves description nil" do
|
|
96
|
+
expect(subject.description).to be_nil
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it "leaves attributes nil" do
|
|
100
|
+
expect(subject.attributes).to be_nil
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
describe "#to_json" do
|
|
106
|
+
subject do
|
|
107
|
+
described_class.from_hash(
|
|
108
|
+
"id" => "valid-scope-id",
|
|
109
|
+
"name" => "my-scope",
|
|
110
|
+
"description" => "A test scope",
|
|
111
|
+
"protocol" => "openid-connect",
|
|
112
|
+
"attributes" => { "include.in.token.scope" => "true" }
|
|
113
|
+
)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
it "serializes to JSON" do
|
|
117
|
+
parsed = JSON.parse(subject.to_json)
|
|
118
|
+
expect(parsed["id"]).to eq "valid-scope-id"
|
|
119
|
+
expect(parsed["name"]).to eq "my-scope"
|
|
120
|
+
expect(parsed["description"]).to eq "A test scope"
|
|
121
|
+
expect(parsed["protocol"]).to eq "openid-connect"
|
|
122
|
+
expect(parsed["attributes"]).to eq("include.in.token.scope" => "true")
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
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: 1.1.
|
|
4
|
+
version: 1.1.7
|
|
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: 2026-
|
|
11
|
+
date: 2026-03-27 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: http-cookie
|
|
@@ -64,14 +64,14 @@ dependencies:
|
|
|
64
64
|
requirements:
|
|
65
65
|
- - '='
|
|
66
66
|
- !ruby/object:Gem::Version
|
|
67
|
-
version:
|
|
67
|
+
version: 13.0.0
|
|
68
68
|
type: :development
|
|
69
69
|
prerelease: false
|
|
70
70
|
version_requirements: !ruby/object:Gem::Requirement
|
|
71
71
|
requirements:
|
|
72
72
|
- - '='
|
|
73
73
|
- !ruby/object:Gem::Version
|
|
74
|
-
version:
|
|
74
|
+
version: 13.0.0
|
|
75
75
|
description: Keycloak Admin REST API client written in Ruby
|
|
76
76
|
email:
|
|
77
77
|
- lorent.lempereur.dev@gmail.com
|
|
@@ -101,6 +101,8 @@ files:
|
|
|
101
101
|
- lib/keycloak-admin/client/client_client.rb
|
|
102
102
|
- lib/keycloak-admin/client/client_role_client.rb
|
|
103
103
|
- lib/keycloak-admin/client/client_role_mappings_client.rb
|
|
104
|
+
- lib/keycloak-admin/client/client_scope_client.rb
|
|
105
|
+
- lib/keycloak-admin/client/client_scope_protocol_mapper_client.rb
|
|
104
106
|
- lib/keycloak-admin/client/configurable_token_client.rb
|
|
105
107
|
- lib/keycloak-admin/client/group_client.rb
|
|
106
108
|
- lib/keycloak-admin/client/identity_provider_client.rb
|
|
@@ -119,6 +121,7 @@ files:
|
|
|
119
121
|
- lib/keycloak-admin/representation/client_authz_resource_representation.rb
|
|
120
122
|
- lib/keycloak-admin/representation/client_authz_scope_representation.rb
|
|
121
123
|
- lib/keycloak-admin/representation/client_representation.rb
|
|
124
|
+
- lib/keycloak-admin/representation/client_scope_representation.rb
|
|
122
125
|
- lib/keycloak-admin/representation/credential_representation.rb
|
|
123
126
|
- lib/keycloak-admin/representation/federated_identity_representation.rb
|
|
124
127
|
- lib/keycloak-admin/representation/group_representation.rb
|
|
@@ -147,6 +150,8 @@ files:
|
|
|
147
150
|
- spec/client/client_authz_scope_client_spec.rb
|
|
148
151
|
- spec/client/client_client_spec.rb
|
|
149
152
|
- spec/client/client_role_mappings_client_spec.rb
|
|
153
|
+
- spec/client/client_scope_client_spec.rb
|
|
154
|
+
- spec/client/client_scope_protocol_mapper_client_spec.rb
|
|
150
155
|
- spec/client/client_spec.rb
|
|
151
156
|
- spec/client/configurable_token_client_spec.rb
|
|
152
157
|
- spec/client/group_client_spec.rb
|
|
@@ -165,6 +170,7 @@ files:
|
|
|
165
170
|
- spec/representation/client_authz_resource_representation_spec.rb
|
|
166
171
|
- spec/representation/client_authz_scope_representation_spec.rb
|
|
167
172
|
- spec/representation/client_representation_spec.rb
|
|
173
|
+
- spec/representation/client_scope_representation_spec.rb
|
|
168
174
|
- spec/representation/credential_representation_spec.rb
|
|
169
175
|
- spec/representation/group_representation_spec.rb
|
|
170
176
|
- spec/representation/identity_provider_mapper_representation_spec.rb
|
|
@@ -182,7 +188,7 @@ homepage: https://github.com/looorent/keycloak-admin-ruby
|
|
|
182
188
|
licenses:
|
|
183
189
|
- MIT
|
|
184
190
|
metadata: {}
|
|
185
|
-
post_install_message:
|
|
191
|
+
post_install_message:
|
|
186
192
|
rdoc_options: []
|
|
187
193
|
require_paths:
|
|
188
194
|
- lib
|
|
@@ -197,8 +203,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
197
203
|
- !ruby/object:Gem::Version
|
|
198
204
|
version: '0'
|
|
199
205
|
requirements: []
|
|
200
|
-
rubygems_version: 3.3.
|
|
201
|
-
signing_key:
|
|
206
|
+
rubygems_version: 3.0.3.1
|
|
207
|
+
signing_key:
|
|
202
208
|
specification_version: 4
|
|
203
209
|
summary: Keycloak Admin REST API client written in Ruby
|
|
204
210
|
test_files: []
|