hydra-keycloak-client 0.1.16 → 0.1.18
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/.gitignore +3 -0
- data/Gemfile.lock +1 -1
- data/lib/hydra/keycloak/client.rb +31 -17
- data/lib/hydra/keycloak/store/memcached_client.rb +6 -6
- data/lib/hydra/keycloak/store/redis_client.rb +6 -6
- data/lib/hydra/keycloak/tokens/gateway.rb +35 -9
- data/lib/hydra/keycloak/tokens/repo.rb +6 -12
- data/lib/hydra/keycloak/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0a2e948b3a20ed2ba3bbbfa11c0d8095d1d2668ab7b84ab9c84ee141b4ffd858
|
4
|
+
data.tar.gz: 470d447468b40bb7f22ba97126702a7c99952cf9038005097b44651ce900a0c3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce821ea5c0d68d23c1e57c5696013b4a3cdec84e4bd70e1ad484c2c394e1fa5699f7b685311732c4ed8d176406faeece9b78e722cb53fae7666c69e77cb9dfa5
|
7
|
+
data.tar.gz: fdb9094dd2861753b689f2a83b367116460b49f0a3817d2ba01b1c2fcf5ea705d2e4c7f903b6131c6d137c2785a8e5572ed9c80f74959447a37e9238a2eadecb
|
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
@@ -127,7 +127,12 @@ module Hydra
|
|
127
127
|
class Client
|
128
128
|
extend ::Hydra::Keycloak::Mixin
|
129
129
|
include ::Dry::Monads[:result, :do]
|
130
|
-
inject[
|
130
|
+
inject[
|
131
|
+
'urls',
|
132
|
+
'tokens_repo',
|
133
|
+
'store',
|
134
|
+
'code_verifier'
|
135
|
+
]
|
131
136
|
|
132
137
|
def auth_url
|
133
138
|
code_verifier.generate
|
@@ -171,17 +176,17 @@ module Hydra
|
|
171
176
|
end
|
172
177
|
|
173
178
|
def access_token(session_state)
|
174
|
-
return Failure(status: 400, code: :not_authenticated) unless authenticated?(session_state)
|
175
|
-
|
176
179
|
fetch_token(session_state, 'access_token')
|
180
|
+
.or(Failure(code: :not_authenticated,
|
181
|
+
context: { args: { session_state: session_state } }))
|
177
182
|
end
|
178
183
|
|
179
184
|
def authorize!(session_state)
|
180
|
-
return Failure(status: 400, code: :not_authenticated) unless authenticated?(session_state)
|
181
|
-
|
182
185
|
access_token = yield fetch_token(session_state, 'access_token')
|
186
|
+
.or(Failure(code: :not_authenticated,
|
187
|
+
context: { args: { session_state: session_state } }))
|
183
188
|
if token_expired?(access_token)
|
184
|
-
refresh_tokens(session_state)
|
189
|
+
yield refresh_tokens(session_state)
|
185
190
|
|
186
191
|
access_token = yield fetch_token(session_state, 'access_token')
|
187
192
|
end
|
@@ -190,17 +195,17 @@ module Hydra
|
|
190
195
|
end
|
191
196
|
|
192
197
|
def access_token_jti(session_state)
|
193
|
-
|
194
|
-
|
195
|
-
|
198
|
+
fetch_token(session_state, 'access_token')
|
199
|
+
.either(->(token) { Success(token[:jti]) },
|
200
|
+
->(_) { Failure(code: :not_authenticated, context: { args: { session_state: session_state } }) })
|
196
201
|
end
|
197
202
|
|
198
203
|
def logout!(session_state)
|
199
|
-
fetch_token(session_state, 'id_token')
|
200
|
-
clear_tokens(session_state)
|
204
|
+
id_token = yield fetch_token(session_state, 'id_token')
|
201
205
|
|
202
|
-
|
203
|
-
|
206
|
+
yield clear_tokens(session_state)
|
207
|
+
|
208
|
+
Success(urls.end_session_url(id_token.source))
|
204
209
|
end
|
205
210
|
|
206
211
|
def introspect_token(token)
|
@@ -218,15 +223,22 @@ module Hydra
|
|
218
223
|
if value
|
219
224
|
Success(::Hydra::Keycloak::Token.new(value))
|
220
225
|
else
|
221
|
-
Failure(
|
226
|
+
Failure(code: :token_not_found,
|
227
|
+
context: { args: { session_state: session_state,
|
228
|
+
token_name: token_name } })
|
222
229
|
end
|
223
230
|
end
|
224
231
|
end
|
225
232
|
|
226
233
|
def clear_tokens(session_state)
|
227
|
-
|
228
|
-
|
229
|
-
|
234
|
+
Dry::Monads::List[
|
235
|
+
"#{session_state}_access_token",
|
236
|
+
"#{session_state}_id_token",
|
237
|
+
"#{session_state}_refresh_token"
|
238
|
+
]
|
239
|
+
.fmap { |x| store.delete(x) }
|
240
|
+
.typed(Dry::Monads::Result)
|
241
|
+
.traverse
|
230
242
|
end
|
231
243
|
|
232
244
|
def token_expired?(token)
|
@@ -240,6 +252,8 @@ module Hydra
|
|
240
252
|
yield save_token(session_state, 'access_token', new_tokens[:access_token])
|
241
253
|
yield save_token(session_state, 'id_token', new_tokens[:id_token])
|
242
254
|
yield save_token(session_state, 'refresh_token', new_tokens[:refresh_token])
|
255
|
+
|
256
|
+
Success()
|
243
257
|
end
|
244
258
|
end
|
245
259
|
end
|
@@ -15,22 +15,22 @@ module Hydra
|
|
15
15
|
dalli.set(key, value)
|
16
16
|
|
17
17
|
Success(:ok)
|
18
|
-
rescue Dalli::DalliError
|
19
|
-
Failure(
|
18
|
+
rescue Dalli::DalliError => e
|
19
|
+
Failure(code: :memcached_unavailable, context: { args: { key: key }, action: :set, error: e.message })
|
20
20
|
end
|
21
21
|
|
22
22
|
def get(key)
|
23
23
|
Success(dalli.get(key))
|
24
|
-
rescue Dalli::DalliError
|
25
|
-
Failure(
|
24
|
+
rescue Dalli::DalliError => e
|
25
|
+
Failure(code: :memcached_unavailable, context: { args: { key: key }, action: :get, error: e.message })
|
26
26
|
end
|
27
27
|
|
28
28
|
def delete(key)
|
29
29
|
dalli.delete(key)
|
30
30
|
|
31
31
|
Success(:ok)
|
32
|
-
rescue Dalli::DalliError
|
33
|
-
Failure(
|
32
|
+
rescue Dalli::DalliError => e
|
33
|
+
Failure(code: :memcached_unavailable, context: { args: { key: key }, action: :delete, error: e.message })
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
@@ -15,22 +15,22 @@ module Hydra
|
|
15
15
|
redis.set(key, value)
|
16
16
|
|
17
17
|
Success(:ok)
|
18
|
-
rescue Redis::BaseError
|
19
|
-
Failure(
|
18
|
+
rescue Redis::BaseError => e
|
19
|
+
Failure(code: :redis_unavailable, context: { args: { key: key }, action: :set, error: e.message })
|
20
20
|
end
|
21
21
|
|
22
22
|
def get(key)
|
23
23
|
Success(redis.get(key))
|
24
|
-
rescue Redis::BaseError
|
25
|
-
Failure(
|
24
|
+
rescue Redis::BaseError => e
|
25
|
+
Failure(code: :redis_unavailable, context: { args: { key: key }, action: :get, error: e.message })
|
26
26
|
end
|
27
27
|
|
28
28
|
def delete(key)
|
29
29
|
redis.del(key)
|
30
30
|
|
31
31
|
Success(:ok)
|
32
|
-
rescue Redis::BaseError
|
33
|
-
Failure(
|
32
|
+
rescue Redis::BaseError => e
|
33
|
+
Failure(code: :redis_unavailable, context: { args: { key: key }, action: :delete, error: e.message })
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
@@ -25,19 +25,45 @@ module Hydra
|
|
25
25
|
Net::ProtocolError].freeze
|
26
26
|
|
27
27
|
def post(path, body)
|
28
|
-
|
28
|
+
_post(URI(path), body)
|
29
|
+
.bind { |resp| parse_response(resp.body) }
|
30
|
+
end
|
29
31
|
|
30
|
-
|
31
|
-
json = JSON.parse(response.body)
|
32
|
+
private
|
32
33
|
|
33
|
-
|
34
|
+
def _post(path, body)
|
35
|
+
response = http.post_form(URI(path), body)
|
36
|
+
|
37
|
+
if %w[200 201].include?(response.code)
|
38
|
+
Success(response)
|
34
39
|
else
|
35
|
-
Failure(
|
40
|
+
Failure(code: :bad_keycloak_response,
|
41
|
+
context: { args: { path: path,
|
42
|
+
body: hide_secrets(body) },
|
43
|
+
method: :post,
|
44
|
+
response: { code: response.code,
|
45
|
+
body: response.body } })
|
36
46
|
end
|
37
|
-
rescue *NETWORK_ERRORS
|
38
|
-
Failure(
|
39
|
-
|
40
|
-
|
47
|
+
rescue *NETWORK_ERRORS => e
|
48
|
+
Failure(code: :keycloak_unavailable, context: { error: e.message })
|
49
|
+
end
|
50
|
+
|
51
|
+
def parse_response(body)
|
52
|
+
Success(JSON.parse(body))
|
53
|
+
rescue JSON::ParserError => e
|
54
|
+
Failure(code: :json_parser_error, context: { args: { body: body }, error: e.message })
|
55
|
+
end
|
56
|
+
|
57
|
+
def hide_secrets(body)
|
58
|
+
secret_fields = %i[client_secret]
|
59
|
+
|
60
|
+
body.map do |k, v|
|
61
|
+
if secret_fields.include?(k)
|
62
|
+
[k, '**hidden**']
|
63
|
+
else
|
64
|
+
[k, v]
|
65
|
+
end
|
66
|
+
end.to_h
|
41
67
|
end
|
42
68
|
end
|
43
69
|
end
|
@@ -14,7 +14,7 @@ module Hydra
|
|
14
14
|
inject['tokens_gateway', 'urls']
|
15
15
|
|
16
16
|
def get_tokens(auth_code, code_verifier)
|
17
|
-
return Failure(
|
17
|
+
return Failure(code: :auth_code_was_not_received) unless auth_code
|
18
18
|
|
19
19
|
result = tokens_gateway.post(
|
20
20
|
urls.token_endpoint,
|
@@ -31,7 +31,7 @@ module Hydra
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def get_tokens_by_password(username, password)
|
34
|
-
return Failure(
|
34
|
+
return Failure(code: :username_or_password_is_empty) if username.nil? || password.nil?
|
35
35
|
|
36
36
|
result = tokens_gateway.post(
|
37
37
|
urls.token_endpoint,
|
@@ -55,7 +55,7 @@ module Hydra
|
|
55
55
|
if result['active']
|
56
56
|
Success(result)
|
57
57
|
else
|
58
|
-
Failure(
|
58
|
+
Failure(code: :token_not_active)
|
59
59
|
end
|
60
60
|
end
|
61
61
|
end
|
@@ -65,15 +65,9 @@ module Hydra
|
|
65
65
|
urls.token_endpoint,
|
66
66
|
urls.refresh_request_body(refresh_token)
|
67
67
|
).bind do |result|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
Success({
|
72
|
-
access_token: ::Hydra::Keycloak::Token.new(result['access_token']),
|
73
|
-
id_token: ::Hydra::Keycloak::Token.new(result['id_token']),
|
74
|
-
refresh_token: ::Hydra::Keycloak::Token.new(result['refresh_token'])
|
75
|
-
})
|
76
|
-
end
|
68
|
+
Success({ access_token: ::Hydra::Keycloak::Token.new(result['access_token']),
|
69
|
+
id_token: ::Hydra::Keycloak::Token.new(result['id_token']),
|
70
|
+
refresh_token: ::Hydra::Keycloak::Token.new(result['refresh_token']) })
|
77
71
|
end
|
78
72
|
end
|
79
73
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hydra-keycloak-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.18
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Fedor Kosolapov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-02-
|
11
|
+
date: 2023-02-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: jwt
|