keycloak-admin 1.2.0 → 2.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.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +4 -2
  3. data/.github/workflows/release.yml +112 -0
  4. data/CHANGELOG.md +14 -0
  5. data/Gemfile.lock +19 -20
  6. data/README.md +25 -5
  7. data/Rakefile +6 -0
  8. data/keycloak-admin.gemspec +5 -3
  9. data/lib/keycloak-admin/client/attack_detection_client.rb +3 -3
  10. data/lib/keycloak-admin/client/client.rb +18 -7
  11. data/lib/keycloak-admin/client/client_authz_permission_client.rb +7 -7
  12. data/lib/keycloak-admin/client/client_authz_policy_client.rb +5 -5
  13. data/lib/keycloak-admin/client/client_authz_resource_client.rb +6 -6
  14. data/lib/keycloak-admin/client/client_authz_scope_client.rb +5 -5
  15. data/lib/keycloak-admin/client/client_client.rb +6 -6
  16. data/lib/keycloak-admin/client/client_role_client.rb +1 -1
  17. data/lib/keycloak-admin/client/client_role_mappings_client.rb +2 -2
  18. data/lib/keycloak-admin/client/client_scope_client.rb +5 -5
  19. data/lib/keycloak-admin/client/client_scope_protocol_mapper_client.rb +5 -5
  20. data/lib/keycloak-admin/client/configurable_token_client.rb +4 -3
  21. data/lib/keycloak-admin/client/group_client.rb +15 -14
  22. data/lib/keycloak-admin/client/identity_provider_client.rb +4 -4
  23. data/lib/keycloak-admin/client/organization_client.rb +18 -18
  24. data/lib/keycloak-admin/client/realm_client.rb +4 -4
  25. data/lib/keycloak-admin/client/resource.rb +98 -0
  26. data/lib/keycloak-admin/client/response.rb +36 -0
  27. data/lib/keycloak-admin/client/role_client.rb +6 -6
  28. data/lib/keycloak-admin/client/role_mapper_client.rb +9 -8
  29. data/lib/keycloak-admin/client/token_client.rb +1 -3
  30. data/lib/keycloak-admin/client/user_client.rb +38 -31
  31. data/lib/keycloak-admin/configuration.rb +23 -1
  32. data/lib/keycloak-admin/version.rb +1 -1
  33. data/lib/keycloak-admin.rb +3 -1
  34. data/spec/client/attack_detection_client_spec.rb +3 -3
  35. data/spec/client/client_authz_permission_client_spec.rb +5 -5
  36. data/spec/client/client_authz_policy_client_spec.rb +5 -5
  37. data/spec/client/client_authz_resource_client_spec.rb +7 -7
  38. data/spec/client/client_authz_scope_client_spec.rb +5 -5
  39. data/spec/client/client_client_spec.rb +14 -14
  40. data/spec/client/client_role_mappings_client_spec.rb +11 -10
  41. data/spec/client/client_scope_client_spec.rb +7 -7
  42. data/spec/client/client_scope_protocol_mapper_client_spec.rb +7 -7
  43. data/spec/client/client_spec.rb +80 -7
  44. data/spec/client/group_client_spec.rb +47 -47
  45. data/spec/client/identity_provider_client_spec.rb +5 -5
  46. data/spec/client/organization_client_spec.rb +31 -31
  47. data/spec/client/realm_client_spec.rb +20 -20
  48. data/spec/client/resource_spec.rb +223 -0
  49. data/spec/client/response_spec.rb +68 -0
  50. data/spec/client/role_client_spec.rb +10 -10
  51. data/spec/client/role_mapper_client_spec.rb +10 -10
  52. data/spec/client/token_client_spec.rb +5 -5
  53. data/spec/client/user_client_spec.rb +29 -29
  54. data/spec/configuration_spec.rb +39 -2
  55. data/spec/gemspec_spec.rb +25 -0
  56. data/spec/integration/client_authorization_spec.rb +4 -4
  57. data/spec/representation/client_authz_policy_representation_spec.rb +1 -1
  58. data/spec/spec_helper.rb +8 -9
  59. metadata +42 -7
@@ -8,14 +8,14 @@ module KeycloakAdmin
8
8
 
9
9
  def list_available
10
10
  response = execute_http do
11
- RestClient::Resource.new(list_available_url, @configuration.rest_client_options).get(headers)
11
+ resource(list_available_url).get(headers)
12
12
  end
13
13
  JSON.parse(response).map { |role_as_hash| RoleRepresentation.from_hash(role_as_hash) }
14
14
  end
15
15
 
16
16
  def save(role_representation_list)
17
17
  execute_http do
18
- RestClient::Resource.new(base_url, @configuration.rest_client_options).post(
18
+ resource(base_url).post(
19
19
  create_payload(role_representation_list), headers
20
20
  )
21
21
  end
@@ -10,7 +10,7 @@ module KeycloakAdmin
10
10
 
11
11
  def list
12
12
  response = execute_http do
13
- RestClient::Resource.new(client_scopes_url, @configuration.rest_client_options).get(headers)
13
+ resource(client_scopes_url).get(headers)
14
14
  end
15
15
 
16
16
  JSON.parse(response).map { |h| ClientScopeRepresentation.from_hash(h) }
@@ -18,7 +18,7 @@ module KeycloakAdmin
18
18
 
19
19
  def get(client_scope_id)
20
20
  response = execute_http do
21
- RestClient::Resource.new(client_scopes_url(client_scope_id), @configuration.rest_client_options).get(headers)
21
+ resource(client_scopes_url(client_scope_id)).get(headers)
22
22
  end
23
23
 
24
24
  ClientScopeRepresentation.from_hash(JSON.parse(response))
@@ -26,7 +26,7 @@ module KeycloakAdmin
26
26
 
27
27
  def create!(client_scope_representation)
28
28
  execute_http do
29
- RestClient::Resource.new(client_scopes_url, @configuration.rest_client_options).post(
29
+ resource(client_scopes_url).post(
30
30
  create_payload(client_scope_representation), headers
31
31
  )
32
32
  end
@@ -36,7 +36,7 @@ module KeycloakAdmin
36
36
 
37
37
  def save(client_scope_representation)
38
38
  execute_http do
39
- RestClient::Resource.new(client_scopes_url(client_scope_representation.id), @configuration.rest_client_options).put(
39
+ resource(client_scopes_url(client_scope_representation.id)).put(
40
40
  create_payload(client_scope_representation), headers
41
41
  )
42
42
  end
@@ -50,7 +50,7 @@ module KeycloakAdmin
50
50
 
51
51
  def delete(client_scope_id)
52
52
  execute_http do
53
- RestClient::Resource.new(client_scopes_url(client_scope_id), @configuration.rest_client_options).delete(headers)
53
+ resource(client_scopes_url(client_scope_id)).delete(headers)
54
54
  end
55
55
 
56
56
  true
@@ -11,7 +11,7 @@ module KeycloakAdmin
11
11
 
12
12
  def list
13
13
  response = execute_http do
14
- RestClient::Resource.new(protocol_mappers_url, @configuration.rest_client_options).get(headers)
14
+ resource(protocol_mappers_url).get(headers)
15
15
  end
16
16
 
17
17
  JSON.parse(response).map { |h| ProtocolMapperRepresentation.from_hash(h) }
@@ -19,7 +19,7 @@ module KeycloakAdmin
19
19
 
20
20
  def get(mapper_id)
21
21
  response = execute_http do
22
- RestClient::Resource.new(protocol_mappers_url(mapper_id), @configuration.rest_client_options).get(headers)
22
+ resource(protocol_mappers_url(mapper_id)).get(headers)
23
23
  end
24
24
 
25
25
  ProtocolMapperRepresentation.from_hash(JSON.parse(response))
@@ -27,7 +27,7 @@ module KeycloakAdmin
27
27
 
28
28
  def create!(mapper_representation)
29
29
  execute_http do
30
- RestClient::Resource.new(protocol_mappers_url, @configuration.rest_client_options).post(
30
+ resource(protocol_mappers_url).post(
31
31
  create_payload(mapper_representation), headers
32
32
  )
33
33
  end
@@ -37,7 +37,7 @@ module KeycloakAdmin
37
37
 
38
38
  def save(mapper_representation)
39
39
  execute_http do
40
- RestClient::Resource.new(protocol_mappers_url(mapper_representation.id), @configuration.rest_client_options).put(
40
+ resource(protocol_mappers_url(mapper_representation.id)).put(
41
41
  create_payload(mapper_representation), headers
42
42
  )
43
43
  end
@@ -47,7 +47,7 @@ module KeycloakAdmin
47
47
 
48
48
  def delete(mapper_id)
49
49
  execute_http do
50
- RestClient::Resource.new(protocol_mappers_url(mapper_id), @configuration.rest_client_options).delete(headers)
50
+ resource(protocol_mappers_url(mapper_id)).delete(headers)
51
51
  end
52
52
 
53
53
  true
@@ -16,8 +16,8 @@ module KeycloakAdmin
16
16
 
17
17
  def exchange_with(user_access_token, token_lifespan_in_seconds)
18
18
  response = execute_http do
19
- RestClient::Request.execute(
20
- @configuration.rest_client_options.merge(
19
+ Resource.execute(
20
+ @configuration.faraday_options.merge(
21
21
  method: :post,
22
22
  url: token_url,
23
23
  payload: { tokenLifespanInSeconds: token_lifespan_in_seconds }.to_json,
@@ -25,7 +25,8 @@ module KeycloakAdmin
25
25
  Authorization: "Bearer #{user_access_token}",
26
26
  content_type: :json,
27
27
  accept: :json
28
- }
28
+ },
29
+ logger: @configuration.logger
29
30
  )
30
31
  )
31
32
  end
@@ -8,7 +8,7 @@ module KeycloakAdmin
8
8
 
9
9
  def get(group_id)
10
10
  response = execute_http do
11
- RestClient::Resource.new(groups_url(group_id), @configuration.rest_client_options).get(headers)
11
+ resource(groups_url(group_id)).get(headers)
12
12
  end
13
13
  GroupRepresentation.from_hash(JSON.parse(response))
14
14
  end
@@ -16,7 +16,7 @@ module KeycloakAdmin
16
16
  def children(parent_id)
17
17
  response = execute_http do
18
18
  url = "#{groups_url(parent_id)}/children"
19
- RestClient::Resource.new(url, @configuration.rest_client_options).get(headers)
19
+ resource(url).get(headers)
20
20
  end
21
21
  JSON.parse(response).map { |group_as_hash| GroupRepresentation.from_hash(group_as_hash) }
22
22
  end
@@ -35,7 +35,7 @@ module KeycloakAdmin
35
35
  headers
36
36
  end
37
37
  response = execute_http do
38
- RestClient::Resource.new(groups_url, @configuration.rest_client_options).get(derived_headers)
38
+ resource(groups_url).get(derived_headers)
39
39
  end
40
40
  JSON.parse(response).map { |group_as_hash| GroupRepresentation.from_hash(group_as_hash) }
41
41
  end
@@ -49,9 +49,9 @@ module KeycloakAdmin
49
49
  execute_http do
50
50
  payload = create_payload(group_representation)
51
51
  if group_representation.id
52
- RestClient::Resource.new(groups_url(group_representation.id), @configuration.rest_client_options).put(payload, headers)
52
+ resource(groups_url(group_representation.id)).put(payload, headers)
53
53
  else
54
- RestClient::Resource.new(groups_url, @configuration.rest_client_options).post(payload, headers)
54
+ resource(groups_url).post(payload, headers)
55
55
  end
56
56
  end
57
57
  end
@@ -59,7 +59,7 @@ module KeycloakAdmin
59
59
  def create_subgroup!(parent_id, name, attributes = {})
60
60
  url = "#{groups_url(parent_id)}/children"
61
61
  response = execute_http do
62
- RestClient::Resource.new(url, @configuration.rest_client_options).post(
62
+ resource(url).post(
63
63
  create_payload(build(name, nil, attributes)), headers
64
64
  )
65
65
  end
@@ -68,7 +68,7 @@ module KeycloakAdmin
68
68
 
69
69
  def delete(group_id)
70
70
  execute_http do
71
- RestClient::Resource.new(groups_url(group_id), @configuration.rest_client_options).delete(headers)
71
+ resource(groups_url(group_id)).delete(headers)
72
72
  end
73
73
  true
74
74
  end
@@ -81,7 +81,7 @@ module KeycloakAdmin
81
81
  url = "#{url}?#{query_string}"
82
82
  end
83
83
  response = execute_http do
84
- RestClient::Resource.new(url, @configuration.rest_client_options).get(headers)
84
+ resource(url).get(headers)
85
85
  end
86
86
  JSON.parse(response).map { |user_as_hash| UserRepresentation.from_hash(user_as_hash) }
87
87
  end
@@ -90,7 +90,7 @@ module KeycloakAdmin
90
90
  def get_realm_level_roles(group_id)
91
91
  url = "#{groups_url(group_id)}/role-mappings/realm"
92
92
  response = execute_http do
93
- RestClient::Resource.new(url, @configuration.rest_client_options).get(headers)
93
+ resource(url).get(headers)
94
94
  end
95
95
  JSON.parse(response).map { |role_as_hash| RoleRepresentation.from_hash(role_as_hash) }
96
96
  end
@@ -101,7 +101,7 @@ module KeycloakAdmin
101
101
  role_representation = RoleClient.new(@configuration, @realm_client).get(role_name)
102
102
  url = "#{groups_url(group_id)}/role-mappings/realm"
103
103
  response = execute_http do
104
- RestClient::Resource.new(url, @configuration.rest_client_options).post(
104
+ resource(url).post(
105
105
  create_payload([role_representation]), headers
106
106
  )
107
107
  end
@@ -113,12 +113,13 @@ module KeycloakAdmin
113
113
  role_representation = RoleClient.new(@configuration, @realm_client).get(role_name)
114
114
  url = "#{groups_url(group_id)}/role-mappings/realm"
115
115
  execute_http do
116
- RestClient::Request.execute(
117
- @configuration.rest_client_options.merge(
118
- url:,
116
+ Resource.execute(
117
+ @configuration.faraday_options.merge(
118
+ url: url,
119
119
  method: :delete,
120
120
  payload: create_payload([role_representation]),
121
- headers: headers
121
+ headers: headers,
122
+ logger: @configuration.logger
122
123
  )
123
124
  )
124
125
  end
@@ -8,7 +8,7 @@ module KeycloakAdmin
8
8
 
9
9
  def create(identity_provider_representation)
10
10
  execute_http do
11
- RestClient::Resource.new(identity_providers_url, @configuration.rest_client_options).post(
11
+ resource(identity_providers_url).post(
12
12
  create_payload(identity_provider_representation), headers
13
13
  )
14
14
  end
@@ -16,7 +16,7 @@ module KeycloakAdmin
16
16
 
17
17
  def add_mapping(identity_provider_alias, identity_provider_mapping_representation)
18
18
  execute_http do
19
- RestClient::Resource.new(identity_provider_mappers_url(identity_provider_alias), @configuration.rest_client_options).post(
19
+ resource(identity_provider_mappers_url(identity_provider_alias)).post(
20
20
  create_payload(identity_provider_mapping_representation), headers
21
21
  )
22
22
  end
@@ -24,14 +24,14 @@ module KeycloakAdmin
24
24
 
25
25
  def list
26
26
  response = execute_http do
27
- RestClient::Resource.new(identity_providers_url, @configuration.rest_client_options).get(headers)
27
+ resource(identity_providers_url).get(headers)
28
28
  end
29
29
  JSON.parse(response).map { |provider_as_hash| IdentityProviderRepresentation.from_hash(provider_as_hash) }
30
30
  end
31
31
 
32
32
  def get(internal_id_or_alias=nil)
33
33
  response = execute_http do
34
- RestClient::Resource.new(identity_providers_url(internal_id_or_alias), @configuration.rest_client_options).get(headers)
34
+ resource(identity_providers_url(internal_id_or_alias)).get(headers)
35
35
  end
36
36
  IdentityProviderRepresentation.from_hash(JSON.parse(response))
37
37
  end
@@ -9,28 +9,28 @@ module KeycloakAdmin
9
9
  # This endpoint does not return members
10
10
  def list(brief_representation=true, exact=nil, first=nil, max=nil, query=nil, search=nil)
11
11
  response = execute_http do
12
- RestClient::Resource.new(organizations_url_with_parameters(brief_representation, exact, first, max, query, search), @configuration.rest_client_options).get(headers)
12
+ resource(organizations_url_with_parameters(brief_representation, exact, first, max, query, search)).get(headers)
13
13
  end
14
14
  JSON.parse(response).map { |organization_as_hash| OrganizationRepresentation.from_hash(organization_as_hash) }
15
15
  end
16
16
 
17
17
  def count(exact=nil, query=nil, search=nil)
18
18
  response = execute_http do
19
- RestClient::Resource.new(count_url(exact, query, search), @configuration.rest_client_options).get(headers)
19
+ resource(count_url(exact, query, search)).get(headers)
20
20
  end
21
21
  response.to_i
22
22
  end
23
23
 
24
24
  def delete(organization_id)
25
25
  execute_http do
26
- RestClient::Resource.new(organization_url(organization_id), @configuration.rest_client_options).delete(headers)
26
+ resource(organization_url(organization_id)).delete(headers)
27
27
  end
28
28
  true
29
29
  end
30
30
 
31
31
  def update(organization_representation)
32
32
  execute_http do
33
- RestClient::Resource.new(organization_url(organization_representation.id), @configuration.rest_client_options).put(
33
+ resource(organization_url(organization_representation.id)).put(
34
34
  create_payload(organization_representation), headers
35
35
  )
36
36
  end
@@ -45,7 +45,7 @@ module KeycloakAdmin
45
45
  # This operation does not associate members and identity providers
46
46
  def save(organization_representation)
47
47
  execute_http do
48
- RestClient::Resource.new(organizations_url, @configuration.rest_client_options).post(
48
+ resource(organizations_url).post(
49
49
  create_payload(organization_representation), headers
50
50
  )
51
51
  end
@@ -54,14 +54,14 @@ module KeycloakAdmin
54
54
 
55
55
  def get(organization_id)
56
56
  response = execute_http do
57
- RestClient::Resource.new(organization_url(organization_id), @configuration.rest_client_options).get(headers)
57
+ resource(organization_url(organization_id)).get(headers)
58
58
  end
59
59
  OrganizationRepresentation.from_hash(JSON.parse(response))
60
60
  end
61
61
 
62
62
  def identity_providers(organization_id)
63
63
  response = execute_http do
64
- RestClient::Resource.new(identity_providers_url(organization_id), @configuration.rest_client_options).get(headers)
64
+ resource(identity_providers_url(organization_id)).get(headers)
65
65
  end
66
66
  JSON.parse(response).map { |idp_as_hash| IdentityProviderRepresentation.from_hash(idp_as_hash) }
67
67
  end
@@ -69,7 +69,7 @@ module KeycloakAdmin
69
69
  def get_identity_provider(organization_id, identity_provider_alias)
70
70
  raise ArgumentError.new("identity_provider_alias must be defined") if identity_provider_alias.nil?
71
71
  response = execute_http do
72
- RestClient::Resource.new("#{identity_providers_url(organization_id)}/#{identity_provider_alias}", @configuration.rest_client_options).get(headers)
72
+ resource("#{identity_providers_url(organization_id)}/#{identity_provider_alias}").get(headers)
73
73
  end
74
74
  IdentityProviderRepresentation.from_hash(JSON.parse(response))
75
75
  end
@@ -77,28 +77,28 @@ module KeycloakAdmin
77
77
  def add_identity_provider(organization_id, identity_provider_alias)
78
78
  raise ArgumentError.new("identity_provider_alias must be defined") if identity_provider_alias.nil?
79
79
  execute_http do
80
- RestClient::Resource.new(identity_providers_url(organization_id), @configuration.rest_client_options).post(identity_provider_alias, headers)
80
+ resource(identity_providers_url(organization_id)).post(identity_provider_alias, headers)
81
81
  end
82
82
  true
83
83
  end
84
84
 
85
85
  def delete_identity_provider(organization_id, identity_provider_alias)
86
86
  execute_http do
87
- RestClient::Resource.new(identity_provider_url(organization_id, identity_provider_alias), @configuration.rest_client_options).delete(headers)
87
+ resource(identity_provider_url(organization_id, identity_provider_alias)).delete(headers)
88
88
  end
89
89
  true
90
90
  end
91
91
 
92
92
  def members_count(organization_id)
93
93
  response = execute_http do
94
- RestClient::Resource.new(members_count_url(organization_id), @configuration.rest_client_options).get(headers)
94
+ resource(members_count_url(organization_id)).get(headers)
95
95
  end
96
96
  response.to_i
97
97
  end
98
98
 
99
99
  def members(organization_id, exact=nil, first=nil, max=nil, membership_type=nil, search=nil)
100
100
  response = execute_http do
101
- RestClient::Resource.new(members_url_with_query_parameters(organization_id, exact, first, max, membership_type, search), @configuration.rest_client_options).get(headers)
101
+ resource(members_url_with_query_parameters(organization_id, exact, first, max, membership_type, search)).get(headers)
102
102
  end
103
103
  JSON.parse(response).map { |member_as_hash| MemberRepresentation.from_hash(member_as_hash) }
104
104
  end
@@ -106,14 +106,14 @@ module KeycloakAdmin
106
106
  def invite_existing_user(organization_id, user_id)
107
107
  raise ArgumentError.new("user_id must be defined") if user_id.nil?
108
108
  execute_http do
109
- RestClient::Resource.new(invite_existing_user_url(organization_id), @configuration.rest_client_options).post({id: user_id}, headers.merge(content_type: "application/x-www-form-urlencoded"))
109
+ resource(invite_existing_user_url(organization_id)).post({id: user_id}, headers.merge(content_type: "application/x-www-form-urlencoded"))
110
110
  end
111
111
  true
112
112
  end
113
113
 
114
114
  def invite_user(organization_id, email, first_name, last_name)
115
115
  execute_http do
116
- RestClient::Resource.new(invite_user_url(organization_id), @configuration.rest_client_options).post({
116
+ resource(invite_user_url(organization_id)).post({
117
117
  email: email,
118
118
  firstName: first_name,
119
119
  lastName: last_name
@@ -125,28 +125,28 @@ module KeycloakAdmin
125
125
  def add_member(organization_id, user_id)
126
126
  raise ArgumentError.new("user_id must be defined") if user_id.nil?
127
127
  execute_http do
128
- RestClient::Resource.new(members_url(organization_id), @configuration.rest_client_options).post(user_id, headers)
128
+ resource(members_url(organization_id)).post(user_id, headers)
129
129
  end
130
130
  true
131
131
  end
132
132
 
133
133
  def delete_member(organization_id, member_id)
134
134
  execute_http do
135
- RestClient::Resource.new(member_url(organization_id, member_id), @configuration.rest_client_options).delete(headers)
135
+ resource(member_url(organization_id, member_id)).delete(headers)
136
136
  end
137
137
  true
138
138
  end
139
139
 
140
140
  def get_member(organization_id, member_id)
141
141
  response = execute_http do
142
- RestClient::Resource.new(member_url(organization_id, member_id), @configuration.rest_client_options).get(headers)
142
+ resource(member_url(organization_id, member_id)).get(headers)
143
143
  end
144
144
  MemberRepresentation.from_hash(JSON.parse(response))
145
145
  end
146
146
 
147
147
  def associated_with_member(member_id, brief_representation=true)
148
148
  response = execute_http do
149
- RestClient::Resource.new(associated_with_member_url(member_id, brief_representation), @configuration.rest_client_options).get(headers)
149
+ resource(associated_with_member_url(member_id, brief_representation)).get(headers)
150
150
  end
151
151
  JSON.parse(response).map { |organization_as_hash| OrganizationRepresentation.from_hash(organization_as_hash) }
152
152
  end
@@ -7,21 +7,21 @@ module KeycloakAdmin
7
7
 
8
8
  def list
9
9
  response = execute_http do
10
- RestClient::Resource.new(realm_list_url, @configuration.rest_client_options).get(headers)
10
+ resource(realm_list_url).get(headers)
11
11
  end
12
12
  JSON.parse(response).map { |realm_as_hash| RealmRepresentation.from_hash(realm_as_hash) }
13
13
  end
14
14
 
15
15
  def delete
16
16
  execute_http do
17
- RestClient::Resource.new(realm_admin_url, @configuration.rest_client_options).delete(headers)
17
+ resource(realm_admin_url).delete(headers)
18
18
  end
19
19
  true
20
20
  end
21
21
 
22
22
  def save(realm_representation)
23
23
  execute_http do
24
- RestClient::Resource.new(realm_list_url, @configuration.rest_client_options).post(
24
+ resource(realm_list_url).post(
25
25
  create_payload(realm_representation), headers
26
26
  )
27
27
  end
@@ -29,7 +29,7 @@ module KeycloakAdmin
29
29
 
30
30
  def update(realm_representation_body)
31
31
  execute_http do
32
- RestClient::Resource.new(realm_admin_url, @configuration.rest_client_options).put(
32
+ resource(realm_admin_url).put(
33
33
  create_payload(realm_representation_body), headers
34
34
  )
35
35
  end
@@ -0,0 +1,98 @@
1
+ require "faraday"
2
+ require "uri"
3
+
4
+ module KeycloakAdmin
5
+ # Thin facade over Faraday that mirrors RestClient::Resource/RestClient::Request's call
6
+ # shape, so every client class can build/send requests without depending on Faraday's API
7
+ # directly.
8
+ class Resource
9
+ MIME_TYPES = { json: "application/json" }.freeze
10
+
11
+ def self.execute(options)
12
+ options = options.dup
13
+ method = options.delete(:method)
14
+ url = options.delete(:url)
15
+ payload = options.delete(:payload)
16
+ headers = options.delete(:headers) || {}
17
+ logger = options.delete(:logger)
18
+ new(url, options, logger).send(:request, method, payload, headers)
19
+ end
20
+
21
+ def self.put(url, payload, headers = {}, logger = nil)
22
+ new(url, {}, logger).put(payload, headers)
23
+ end
24
+
25
+ def initialize(url, options = {}, logger = nil)
26
+ @url = url
27
+ @options = options || {}
28
+ @logger = logger
29
+ end
30
+
31
+ def get(headers = {})
32
+ request(:get, nil, headers)
33
+ end
34
+
35
+ def delete(headers = {})
36
+ request(:delete, nil, headers)
37
+ end
38
+
39
+ def post(payload, headers = {})
40
+ request(:post, payload, headers)
41
+ end
42
+
43
+ def put(payload, headers = {})
44
+ request(:put, payload, headers)
45
+ end
46
+
47
+ private
48
+
49
+ def request(method, payload, headers)
50
+ headers = headers || {}
51
+ query = headers[:params]
52
+ send_headers = build_headers(headers.reject { |key, _| key == :params })
53
+ body = encode_payload(payload)
54
+
55
+ # RestClient::Payload::UrlEncoded always stamped this Content-Type for Hash payloads,
56
+ # regardless of what the caller's headers said; token retrieval relies on it and never
57
+ # sets content_type itself.
58
+ if payload.is_a?(Hash) && !send_headers.key?("Content-Type")
59
+ send_headers["Content-Type"] = "application/x-www-form-urlencoded"
60
+ end
61
+
62
+ faraday_response = connection.public_send(method) do |req|
63
+ req.params.update(query) if query
64
+ send_headers.each { |name, value| req.headers[name] = value }
65
+ req.body = body unless body.nil?
66
+ end
67
+ Response.new(faraday_response)
68
+ end
69
+
70
+ def connection
71
+ Faraday.new(url: @url, **@options) do |f|
72
+ f.response :raise_error
73
+ # Added after :raise_error so it logs the raw response (status/duration) before
74
+ # :raise_error can raise, including on failures. Faraday's logger middleware logs
75
+ # headers by default, which would print the bearer token on every call; headers: false
76
+ # keeps this to method/url/status only. Bodies are already off by Faraday's own default.
77
+ f.response :logger, @logger, headers: false if @logger
78
+ f.adapter Faraday.default_adapter
79
+ end
80
+ end
81
+
82
+ def encode_payload(payload)
83
+ return nil if payload.nil?
84
+ payload.is_a?(Hash) ? URI.encode_www_form(payload) : payload.to_s
85
+ end
86
+
87
+ def build_headers(headers)
88
+ headers.each_with_object({}) do |(key, value), result|
89
+ name = key.is_a?(Symbol) ? humanize(key) : key.to_s
90
+ result[name] = value.is_a?(Symbol) ? MIME_TYPES.fetch(value, value.to_s) : value
91
+ end
92
+ end
93
+
94
+ def humanize(key)
95
+ key.to_s.split("_").map { |word| word.capitalize }.join("-")
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,36 @@
1
+ module KeycloakAdmin
2
+ # Wraps a Faraday::Response the way RestClient::Response used to: as the body string
3
+ # itself (RestClient::Response < String), so existing call sites that do JSON.parse(response)
4
+ # or response.to_i keep working, while .body/.headers/.status/.code/.reason_phrase stay
5
+ # available for call sites that need response metadata.
6
+ class Response < String
7
+ attr_reader :status, :reason_phrase, :headers
8
+
9
+ def initialize(faraday_response)
10
+ super(faraday_response.body.to_s)
11
+ @status = faraday_response.status
12
+ @reason_phrase = faraday_response.reason_phrase
13
+ @headers = symbolize_headers(faraday_response.headers)
14
+ end
15
+
16
+ alias_method :code, :status
17
+ alias_method :body, :to_s
18
+
19
+ private
20
+
21
+ def symbolize_headers(faraday_headers)
22
+ faraday_headers.each_with_object({}) do |(key, value), result|
23
+ symbol_key = key.downcase.tr("-", "_").to_sym
24
+ result[symbol_key] = symbol_key == :set_cookie ? split_set_cookie(value) : value
25
+ end
26
+ end
27
+
28
+ # Net::HTTP (used by Faraday's default adapter) joins repeated Set-Cookie header lines with
29
+ # ", " (see Net::HTTPHeader#each_header), losing the one-header-per-cookie structure RestClient
30
+ # exposed as an Array. Re-split on cookie boundaries rather than on every comma, since a comma
31
+ # can also appear inside a cookie's own "Expires=Wed, 09 Jun 2027 ..." attribute.
32
+ def split_set_cookie(value)
33
+ value.split(/,(?=\s*[^;\s]+=)/).map(&:strip)
34
+ end
35
+ end
36
+ end
@@ -8,17 +8,17 @@ module KeycloakAdmin
8
8
 
9
9
  def list
10
10
  response = execute_http do
11
- RestClient::Resource.new(roles_url, @configuration.rest_client_options).get(headers)
11
+ resource(roles_url).get(headers)
12
12
  end
13
13
  JSON.parse(response).map { |role_as_hash| RoleRepresentation.from_hash(role_as_hash) }
14
14
  end
15
-
15
+
16
16
  # Returns the role representation for the specified role name
17
17
  def get(name)
18
18
  # allows special characters in the name like space
19
19
  name = URI.encode_uri_component(name)
20
20
  response = execute_http do
21
- RestClient::Resource.new(role_name_url(name), @configuration.rest_client_options).get(headers)
21
+ resource(role_name_url(name)).get(headers)
22
22
  end
23
23
  RoleRepresentation.from_hash JSON.parse(response)
24
24
  end
@@ -28,7 +28,7 @@ module KeycloakAdmin
28
28
  # allows special characters in the name like space
29
29
  name = URI.encode_uri_component(name)
30
30
  response = execute_http do
31
- RestClient::Resource.new("#{role_name_url(name)}/groups", @configuration.rest_client_options).get(headers)
31
+ resource("#{role_name_url(name)}/groups").get(headers)
32
32
  end
33
33
  JSON.parse(response).map { |role_as_hash| GroupRepresentation.from_hash(role_as_hash) }
34
34
  end
@@ -37,9 +37,9 @@ module KeycloakAdmin
37
37
  execute_http do
38
38
  payload = create_payload(role_representation)
39
39
  if role_representation.id
40
- RestClient::Resource.new(role_id_url(role_representation.id), @configuration.rest_client_options).put(payload, headers)
40
+ resource(role_id_url(role_representation.id)).put(payload, headers)
41
41
  else
42
- RestClient::Resource.new(roles_url, @configuration.rest_client_options).post(payload, headers)
42
+ resource(roles_url).post(payload, headers)
43
43
  end
44
44
  end
45
45
  end
@@ -7,14 +7,14 @@ module KeycloakAdmin
7
7
 
8
8
  def list
9
9
  response = execute_http do
10
- RestClient::Resource.new(realm_level_url, @configuration.rest_client_options).get(headers)
10
+ resource(realm_level_url).get(headers)
11
11
  end
12
12
  JSON.parse(response).map { |role_as_hash| RoleRepresentation.from_hash(role_as_hash) }
13
13
  end
14
14
 
15
15
  def save_realm_level(role_representation_list)
16
16
  execute_http do
17
- RestClient::Resource.new(realm_level_url, @configuration.rest_client_options).post(
17
+ resource(realm_level_url).post(
18
18
  create_payload(role_representation_list), headers
19
19
  )
20
20
  end
@@ -22,20 +22,21 @@ module KeycloakAdmin
22
22
 
23
23
  def remove_realm_level(role_representation_list)
24
24
  execute_http do
25
- RestClient::Request.execute(
26
- @configuration.rest_client_options.merge(
25
+ Resource.execute(
26
+ @configuration.faraday_options.merge(
27
27
  method: :delete,
28
28
  url: realm_level_url,
29
- payload: create_payload(role_representation_list),
30
- headers: headers
29
+ payload: create_payload(role_representation_list),
30
+ headers: headers,
31
+ logger: @configuration.logger
31
32
  )
32
33
  )
33
34
  end
34
35
  end
35
-
36
+
36
37
  def remove_all_realm_roles
37
38
  execute_http do
38
- RestClient::Resource.new(realm_level_url, @configuration.rest_client_options).delete(headers)
39
+ resource(realm_level_url).delete(headers)
39
40
  end
40
41
  true
41
42
  end