keycloak_rack 1.0.0 → 1.1.0
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/main.yml +2 -1
- data/gemfiles/rack_only.gemfile.lock +47 -52
- data/gemfiles/rails_6_0.gemfile +0 -1
- data/gemfiles/rails_6_0.gemfile.lock +113 -118
- data/gemfiles/rails_6_1.gemfile +0 -1
- data/gemfiles/rails_6_1.gemfile.lock +118 -123
- data/keycloak_rack.gemspec +1 -1
- data/lib/keycloak_rack/authenticate.rb +7 -43
- data/lib/keycloak_rack/container.rb +8 -0
- data/lib/keycloak_rack/decode_and_verify.rb +51 -0
- data/lib/keycloak_rack/decoded_token.rb +18 -8
- data/lib/keycloak_rack/middleware.rb +1 -1
- data/lib/keycloak_rack/version.rb +1 -1
- data/lib/keycloak_rack/wrap_token.rb +58 -0
- metadata +7 -5
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: ..
|
3
3
|
specs:
|
4
|
-
keycloak_rack (1.
|
4
|
+
keycloak_rack (1.1.0)
|
5
5
|
activesupport (>= 4.2)
|
6
6
|
anyway_config (>= 2.1.0, < 3)
|
7
7
|
dry-auto_inject
|
@@ -20,115 +20,112 @@ PATH
|
|
20
20
|
GEM
|
21
21
|
remote: https://rubygems.org/
|
22
22
|
specs:
|
23
|
-
actioncable (6.1.
|
24
|
-
actionpack (= 6.1.
|
25
|
-
activesupport (= 6.1.
|
23
|
+
actioncable (6.1.4.4)
|
24
|
+
actionpack (= 6.1.4.4)
|
25
|
+
activesupport (= 6.1.4.4)
|
26
26
|
nio4r (~> 2.0)
|
27
27
|
websocket-driver (>= 0.6.1)
|
28
|
-
actionmailbox (6.1.
|
29
|
-
actionpack (= 6.1.
|
30
|
-
activejob (= 6.1.
|
31
|
-
activerecord (= 6.1.
|
32
|
-
activestorage (= 6.1.
|
33
|
-
activesupport (= 6.1.
|
28
|
+
actionmailbox (6.1.4.4)
|
29
|
+
actionpack (= 6.1.4.4)
|
30
|
+
activejob (= 6.1.4.4)
|
31
|
+
activerecord (= 6.1.4.4)
|
32
|
+
activestorage (= 6.1.4.4)
|
33
|
+
activesupport (= 6.1.4.4)
|
34
34
|
mail (>= 2.7.1)
|
35
|
-
actionmailer (6.1.
|
36
|
-
actionpack (= 6.1.
|
37
|
-
actionview (= 6.1.
|
38
|
-
activejob (= 6.1.
|
39
|
-
activesupport (= 6.1.
|
35
|
+
actionmailer (6.1.4.4)
|
36
|
+
actionpack (= 6.1.4.4)
|
37
|
+
actionview (= 6.1.4.4)
|
38
|
+
activejob (= 6.1.4.4)
|
39
|
+
activesupport (= 6.1.4.4)
|
40
40
|
mail (~> 2.5, >= 2.5.4)
|
41
41
|
rails-dom-testing (~> 2.0)
|
42
|
-
actionpack (6.1.
|
43
|
-
actionview (= 6.1.
|
44
|
-
activesupport (= 6.1.
|
42
|
+
actionpack (6.1.4.4)
|
43
|
+
actionview (= 6.1.4.4)
|
44
|
+
activesupport (= 6.1.4.4)
|
45
45
|
rack (~> 2.0, >= 2.0.9)
|
46
46
|
rack-test (>= 0.6.3)
|
47
47
|
rails-dom-testing (~> 2.0)
|
48
48
|
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
49
|
-
actiontext (6.1.
|
50
|
-
actionpack (= 6.1.
|
51
|
-
activerecord (= 6.1.
|
52
|
-
activestorage (= 6.1.
|
53
|
-
activesupport (= 6.1.
|
49
|
+
actiontext (6.1.4.4)
|
50
|
+
actionpack (= 6.1.4.4)
|
51
|
+
activerecord (= 6.1.4.4)
|
52
|
+
activestorage (= 6.1.4.4)
|
53
|
+
activesupport (= 6.1.4.4)
|
54
54
|
nokogiri (>= 1.8.5)
|
55
|
-
actionview (6.1.
|
56
|
-
activesupport (= 6.1.
|
55
|
+
actionview (6.1.4.4)
|
56
|
+
activesupport (= 6.1.4.4)
|
57
57
|
builder (~> 3.1)
|
58
58
|
erubi (~> 1.4)
|
59
59
|
rails-dom-testing (~> 2.0)
|
60
60
|
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
61
|
-
activejob (6.1.
|
62
|
-
activesupport (= 6.1.
|
61
|
+
activejob (6.1.4.4)
|
62
|
+
activesupport (= 6.1.4.4)
|
63
63
|
globalid (>= 0.3.6)
|
64
|
-
activemodel (6.1.
|
65
|
-
activesupport (= 6.1.
|
66
|
-
activerecord (6.1.
|
67
|
-
activemodel (= 6.1.
|
68
|
-
activesupport (= 6.1.
|
69
|
-
activestorage (6.1.
|
70
|
-
actionpack (= 6.1.
|
71
|
-
activejob (= 6.1.
|
72
|
-
activerecord (= 6.1.
|
73
|
-
activesupport (= 6.1.
|
64
|
+
activemodel (6.1.4.4)
|
65
|
+
activesupport (= 6.1.4.4)
|
66
|
+
activerecord (6.1.4.4)
|
67
|
+
activemodel (= 6.1.4.4)
|
68
|
+
activesupport (= 6.1.4.4)
|
69
|
+
activestorage (6.1.4.4)
|
70
|
+
actionpack (= 6.1.4.4)
|
71
|
+
activejob (= 6.1.4.4)
|
72
|
+
activerecord (= 6.1.4.4)
|
73
|
+
activesupport (= 6.1.4.4)
|
74
74
|
marcel (~> 1.0.0)
|
75
|
-
mini_mime (
|
76
|
-
activesupport (6.1.
|
75
|
+
mini_mime (>= 1.1.0)
|
76
|
+
activesupport (6.1.4.4)
|
77
77
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
78
78
|
i18n (>= 1.6, < 2)
|
79
79
|
minitest (>= 5.1)
|
80
80
|
tzinfo (~> 2.0)
|
81
81
|
zeitwerk (~> 2.3)
|
82
|
-
addressable (2.
|
82
|
+
addressable (2.8.0)
|
83
83
|
public_suffix (>= 2.0.2, < 5.0)
|
84
|
-
anyway_config (2.
|
85
|
-
ruby-next-core (>= 0.
|
84
|
+
anyway_config (2.2.3)
|
85
|
+
ruby-next-core (>= 0.14.0)
|
86
86
|
appraisal (2.4.0)
|
87
87
|
bundler
|
88
88
|
rake
|
89
89
|
thor (>= 0.14.0)
|
90
90
|
ast (2.4.2)
|
91
|
-
backports (3.
|
91
|
+
backports (3.23.0)
|
92
92
|
builder (3.2.4)
|
93
93
|
coderay (1.1.3)
|
94
|
-
concurrent-ruby (1.1.
|
94
|
+
concurrent-ruby (1.1.9)
|
95
95
|
crack (0.4.5)
|
96
96
|
rexml
|
97
97
|
crass (1.0.6)
|
98
|
-
diff-lcs (1.
|
99
|
-
docile (1.
|
100
|
-
dry-auto_inject (0.
|
98
|
+
diff-lcs (1.5.0)
|
99
|
+
docile (1.4.0)
|
100
|
+
dry-auto_inject (0.9.0)
|
101
101
|
dry-container (>= 0.3.4)
|
102
|
-
dry-configurable (0.
|
102
|
+
dry-configurable (0.14.0)
|
103
103
|
concurrent-ruby (~> 1.0)
|
104
|
-
dry-core (~> 0.
|
105
|
-
dry-container (0.
|
104
|
+
dry-core (~> 0.6)
|
105
|
+
dry-container (0.9.0)
|
106
106
|
concurrent-ruby (~> 1.0)
|
107
|
-
dry-configurable (~> 0.
|
108
|
-
dry-core (0.
|
107
|
+
dry-configurable (~> 0.13, >= 0.13.0)
|
108
|
+
dry-core (0.7.1)
|
109
109
|
concurrent-ruby (~> 1.0)
|
110
|
-
dry-effects (0.
|
110
|
+
dry-effects (0.2.0)
|
111
111
|
concurrent-ruby (~> 1.0)
|
112
112
|
dry-container (~> 0.7, >= 0.7.2)
|
113
|
-
dry-core (~> 0.
|
114
|
-
dry-equalizer (~> 0.2, >= 0.2.2)
|
113
|
+
dry-core (~> 0.5, >= 0.5)
|
115
114
|
dry-inflector (~> 0.1, >= 0.1.2)
|
116
115
|
dry-initializer (~> 3.0)
|
117
|
-
dry-
|
118
|
-
dry-
|
119
|
-
dry-initializer (3.0.4)
|
116
|
+
dry-inflector (0.2.1)
|
117
|
+
dry-initializer (3.1.1)
|
120
118
|
dry-logic (1.2.0)
|
121
119
|
concurrent-ruby (~> 1.0)
|
122
120
|
dry-core (~> 0.5, >= 0.5)
|
123
121
|
dry-matcher (0.9.0)
|
124
122
|
dry-core (~> 0.4, >= 0.4.8)
|
125
|
-
dry-monads (1.
|
123
|
+
dry-monads (1.4.0)
|
126
124
|
concurrent-ruby (~> 1.0)
|
127
|
-
dry-core (~> 0.
|
128
|
-
|
129
|
-
dry-schema (1.6.2)
|
125
|
+
dry-core (~> 0.7)
|
126
|
+
dry-schema (1.8.0)
|
130
127
|
concurrent-ruby (~> 1.0)
|
131
|
-
dry-configurable (~> 0.
|
128
|
+
dry-configurable (~> 0.13, >= 0.13.0)
|
132
129
|
dry-core (~> 0.5, >= 0.5)
|
133
130
|
dry-initializer (~> 3.0)
|
134
131
|
dry-logic (~> 1.0)
|
@@ -143,96 +140,95 @@ GEM
|
|
143
140
|
dry-core (~> 0.5, >= 0.5)
|
144
141
|
dry-inflector (~> 0.1, >= 0.1.2)
|
145
142
|
dry-logic (~> 1.0, >= 1.0.2)
|
146
|
-
dry-validation (1.
|
143
|
+
dry-validation (1.7.0)
|
147
144
|
concurrent-ruby (~> 1.0)
|
148
145
|
dry-container (~> 0.7, >= 0.7.1)
|
149
|
-
dry-core (~> 0.
|
150
|
-
dry-equalizer (~> 0.2)
|
146
|
+
dry-core (~> 0.5, >= 0.5)
|
151
147
|
dry-initializer (~> 3.0)
|
152
|
-
dry-schema (~> 1.
|
148
|
+
dry-schema (~> 1.8, >= 1.8.0)
|
153
149
|
erubi (1.10.0)
|
154
150
|
factory_bot (6.1.0)
|
155
151
|
activesupport (>= 5.0.0)
|
156
|
-
faker (2.
|
152
|
+
faker (2.19.0)
|
157
153
|
i18n (>= 1.6, < 2)
|
158
|
-
globalid (0.
|
159
|
-
activesupport (>=
|
154
|
+
globalid (1.0.0)
|
155
|
+
activesupport (>= 5.0)
|
160
156
|
hashdiff (1.0.1)
|
161
|
-
i18n (1.
|
157
|
+
i18n (1.9.1)
|
162
158
|
concurrent-ruby (~> 1.0)
|
163
159
|
ice_nine (0.11.2)
|
164
|
-
jwt (2.
|
165
|
-
loofah (2.
|
160
|
+
jwt (2.3.0)
|
161
|
+
loofah (2.13.0)
|
166
162
|
crass (~> 1.0.2)
|
167
163
|
nokogiri (>= 1.5.9)
|
168
164
|
mail (2.7.1)
|
169
165
|
mini_mime (>= 0.1.1)
|
170
|
-
marcel (1.0.
|
166
|
+
marcel (1.0.2)
|
171
167
|
method_source (1.0.0)
|
172
|
-
mini_mime (1.
|
173
|
-
mini_portile2 (2.
|
174
|
-
minitest (5.
|
175
|
-
nio4r (2.5.
|
176
|
-
nokogiri (1.
|
177
|
-
mini_portile2 (~> 2.
|
168
|
+
mini_mime (1.1.2)
|
169
|
+
mini_portile2 (2.7.1)
|
170
|
+
minitest (5.15.0)
|
171
|
+
nio4r (2.5.8)
|
172
|
+
nokogiri (1.13.1)
|
173
|
+
mini_portile2 (~> 2.7.0)
|
178
174
|
racc (~> 1.4)
|
179
|
-
nokogiri (1.
|
175
|
+
nokogiri (1.13.1-x86_64-darwin)
|
180
176
|
racc (~> 1.4)
|
181
|
-
nokogiri (1.
|
177
|
+
nokogiri (1.13.1-x86_64-linux)
|
182
178
|
racc (~> 1.4)
|
183
|
-
parallel (1.
|
184
|
-
parser (3.0.
|
179
|
+
parallel (1.21.0)
|
180
|
+
parser (3.1.0.0)
|
185
181
|
ast (~> 2.4.1)
|
186
182
|
pry (0.14.1)
|
187
183
|
coderay (~> 1.1)
|
188
184
|
method_source (~> 1.0)
|
189
185
|
public_suffix (4.0.6)
|
190
|
-
racc (1.
|
186
|
+
racc (1.6.0)
|
191
187
|
rack (2.2.3)
|
192
188
|
rack-test (1.1.0)
|
193
189
|
rack (>= 1.0, < 3)
|
194
|
-
rails (6.1.
|
195
|
-
actioncable (= 6.1.
|
196
|
-
actionmailbox (= 6.1.
|
197
|
-
actionmailer (= 6.1.
|
198
|
-
actionpack (= 6.1.
|
199
|
-
actiontext (= 6.1.
|
200
|
-
actionview (= 6.1.
|
201
|
-
activejob (= 6.1.
|
202
|
-
activemodel (= 6.1.
|
203
|
-
activerecord (= 6.1.
|
204
|
-
activestorage (= 6.1.
|
205
|
-
activesupport (= 6.1.
|
190
|
+
rails (6.1.4.4)
|
191
|
+
actioncable (= 6.1.4.4)
|
192
|
+
actionmailbox (= 6.1.4.4)
|
193
|
+
actionmailer (= 6.1.4.4)
|
194
|
+
actionpack (= 6.1.4.4)
|
195
|
+
actiontext (= 6.1.4.4)
|
196
|
+
actionview (= 6.1.4.4)
|
197
|
+
activejob (= 6.1.4.4)
|
198
|
+
activemodel (= 6.1.4.4)
|
199
|
+
activerecord (= 6.1.4.4)
|
200
|
+
activestorage (= 6.1.4.4)
|
201
|
+
activesupport (= 6.1.4.4)
|
206
202
|
bundler (>= 1.15.0)
|
207
|
-
railties (= 6.1.
|
203
|
+
railties (= 6.1.4.4)
|
208
204
|
sprockets-rails (>= 2.0.0)
|
209
205
|
rails-dom-testing (2.0.3)
|
210
206
|
activesupport (>= 4.2.0)
|
211
207
|
nokogiri (>= 1.6)
|
212
|
-
rails-html-sanitizer (1.
|
208
|
+
rails-html-sanitizer (1.4.2)
|
213
209
|
loofah (~> 2.3)
|
214
|
-
railties (6.1.
|
215
|
-
actionpack (= 6.1.
|
216
|
-
activesupport (= 6.1.
|
210
|
+
railties (6.1.4.4)
|
211
|
+
actionpack (= 6.1.4.4)
|
212
|
+
activesupport (= 6.1.4.4)
|
217
213
|
method_source
|
218
|
-
rake (>= 0.
|
214
|
+
rake (>= 0.13)
|
219
215
|
thor (~> 1.0)
|
220
|
-
rainbow (3.
|
221
|
-
rake (13.0.
|
216
|
+
rainbow (3.1.1)
|
217
|
+
rake (13.0.6)
|
222
218
|
redcarpet (3.5.1)
|
223
|
-
regexp_parser (2.
|
219
|
+
regexp_parser (2.2.0)
|
224
220
|
rexml (3.2.5)
|
225
221
|
rspec (3.10.0)
|
226
222
|
rspec-core (~> 3.10.0)
|
227
223
|
rspec-expectations (~> 3.10.0)
|
228
224
|
rspec-mocks (~> 3.10.0)
|
229
|
-
rspec-core (3.10.
|
225
|
+
rspec-core (3.10.2)
|
230
226
|
rspec-support (~> 3.10.0)
|
231
|
-
rspec-expectations (3.10.
|
227
|
+
rspec-expectations (3.10.2)
|
232
228
|
diff-lcs (>= 1.2.0, < 2.0)
|
233
229
|
rspec-support (~> 3.10.0)
|
234
230
|
rspec-json_expectations (2.2.0)
|
235
|
-
rspec-mocks (3.10.
|
231
|
+
rspec-mocks (3.10.3)
|
236
232
|
diff-lcs (>= 1.2.0, < 2.0)
|
237
233
|
rspec-support (~> 3.10.0)
|
238
234
|
rspec-rails (5.0.1)
|
@@ -243,7 +239,7 @@ GEM
|
|
243
239
|
rspec-expectations (~> 3.10)
|
244
240
|
rspec-mocks (~> 3.10)
|
245
241
|
rspec-support (~> 3.10)
|
246
|
-
rspec-support (3.10.
|
242
|
+
rspec-support (3.10.3)
|
247
243
|
rubocop (1.13.0)
|
248
244
|
parallel (~> 1.10)
|
249
245
|
parser (>= 3.0.0.0)
|
@@ -253,38 +249,38 @@ GEM
|
|
253
249
|
rubocop-ast (>= 1.2.0, < 2.0)
|
254
250
|
ruby-progressbar (~> 1.7)
|
255
251
|
unicode-display_width (>= 1.4.0, < 3.0)
|
256
|
-
rubocop-ast (1.
|
252
|
+
rubocop-ast (1.15.1)
|
257
253
|
parser (>= 3.0.1.1)
|
258
254
|
rubocop-rake (0.5.1)
|
259
255
|
rubocop
|
260
256
|
rubocop-rspec (2.3.0)
|
261
257
|
rubocop (~> 1.0)
|
262
258
|
rubocop-ast (>= 1.1.0)
|
263
|
-
ruby-next-core (0.
|
259
|
+
ruby-next-core (0.14.1)
|
264
260
|
ruby-progressbar (1.11.0)
|
265
261
|
simplecov (0.21.2)
|
266
262
|
docile (~> 1.1)
|
267
263
|
simplecov-html (~> 0.11)
|
268
264
|
simplecov_json_formatter (~> 0.1)
|
269
265
|
simplecov-html (0.12.3)
|
270
|
-
simplecov_json_formatter (0.1.
|
266
|
+
simplecov_json_formatter (0.1.3)
|
271
267
|
sprockets (4.0.2)
|
272
268
|
concurrent-ruby (~> 1.0)
|
273
269
|
rack (> 1, < 3)
|
274
|
-
sprockets-rails (3.
|
275
|
-
actionpack (>=
|
276
|
-
activesupport (>=
|
270
|
+
sprockets-rails (3.4.2)
|
271
|
+
actionpack (>= 5.2)
|
272
|
+
activesupport (>= 5.2)
|
277
273
|
sprockets (>= 3.0.0)
|
278
|
-
thor (1.1
|
274
|
+
thor (1.2.1)
|
279
275
|
timecop (0.9.4)
|
280
276
|
tzinfo (2.0.4)
|
281
277
|
concurrent-ruby (~> 1.0)
|
282
|
-
unicode-display_width (2.
|
278
|
+
unicode-display_width (2.1.0)
|
283
279
|
webmock (3.12.2)
|
284
280
|
addressable (>= 2.3.6)
|
285
281
|
crack (>= 0.3.2)
|
286
282
|
hashdiff (>= 0.4.0, < 2.0.0)
|
287
|
-
websocket-driver (0.7.
|
283
|
+
websocket-driver (0.7.5)
|
288
284
|
websocket-extensions (>= 0.1.0)
|
289
285
|
websocket-extensions (0.1.5)
|
290
286
|
yard (0.9.26)
|
@@ -292,7 +288,7 @@ GEM
|
|
292
288
|
backports (>= 3.18)
|
293
289
|
rainbow
|
294
290
|
yard
|
295
|
-
zeitwerk (2.4
|
291
|
+
zeitwerk (2.5.4)
|
296
292
|
|
297
293
|
PLATFORMS
|
298
294
|
ruby
|
@@ -302,9 +298,8 @@ PLATFORMS
|
|
302
298
|
DEPENDENCIES
|
303
299
|
appraisal (= 2.4.0)
|
304
300
|
factory_bot (~> 6.1.0)
|
305
|
-
faker (= 2.
|
301
|
+
faker (= 2.19.0)
|
306
302
|
keycloak_rack!
|
307
|
-
nokogiri
|
308
303
|
pry (= 0.14.1)
|
309
304
|
rack-test (= 1.1.0)
|
310
305
|
rails (>= 6.1.0, < 6.2.0)
|
@@ -323,4 +318,4 @@ DEPENDENCIES
|
|
323
318
|
yard-junk
|
324
319
|
|
325
320
|
BUNDLED WITH
|
326
|
-
2.2.
|
321
|
+
2.2.19
|
data/keycloak_rack.gemspec
CHANGED
@@ -36,7 +36,7 @@ Gem::Specification.new do |spec|
|
|
36
36
|
|
37
37
|
spec.add_development_dependency "appraisal", "2.4.0"
|
38
38
|
spec.add_development_dependency "factory_bot", "~> 6.1.0"
|
39
|
-
spec.add_development_dependency "faker", "2.
|
39
|
+
spec.add_development_dependency "faker", "2.19.0"
|
40
40
|
spec.add_development_dependency "pry", "0.14.1"
|
41
41
|
spec.add_development_dependency "rack-test", "1.1.0"
|
42
42
|
spec.add_development_dependency "rake", ">= 13", "< 14"
|
@@ -50,20 +50,18 @@ module KeycloakRack
|
|
50
50
|
include Dry::Monads[:do, :result]
|
51
51
|
|
52
52
|
include Import[
|
53
|
-
|
54
|
-
key_resolver: "keycloak-rack.key_resolver",
|
53
|
+
decode_and_verify: "keycloak-rack.decode_and_verify",
|
55
54
|
read_token: "keycloak-rack.read_token",
|
56
|
-
skip_authentication: "keycloak-rack.skip_authentication"
|
55
|
+
skip_authentication: "keycloak-rack.skip_authentication",
|
56
|
+
wrap: "keycloak-rack.wrap_token",
|
57
57
|
]
|
58
58
|
|
59
|
-
delegate :token_leeway, to: :config
|
60
|
-
|
61
59
|
# @param [Hash] env the rack environment
|
62
60
|
# @return [Dry::Monads::Success(:authenticated, KeycloakRack::DecodedToken)]
|
63
61
|
# @return [Dry::Monads::Success(:skipped, String)]
|
64
62
|
# @return [Dry::Monads::Success(:unauthenticated)]
|
65
63
|
# @return [Dry::Monads::Failure(:expired, String, String, Exception)]
|
66
|
-
# @return [Dry::Monads::Failure(:decoding_failed, String,
|
64
|
+
# @return [Dry::Monads::Failure(:decoding_failed, String, Exception)]
|
67
65
|
def call(env)
|
68
66
|
return Success[:skipped] if yield skip_authentication.call(env)
|
69
67
|
|
@@ -71,45 +69,11 @@ module KeycloakRack
|
|
71
69
|
|
72
70
|
return Success[:unauthenticated] if token.blank?
|
73
71
|
|
74
|
-
|
75
|
-
|
76
|
-
Success[:authenticated, decoded_token]
|
77
|
-
end
|
78
|
-
|
79
|
-
private
|
72
|
+
payload, headers = yield decode_and_verify.call token
|
80
73
|
|
81
|
-
|
82
|
-
# @return [Dry::Monads::Success(KeycloakRack::DecodedToken)]
|
83
|
-
# @return [Dry::Monads::Failure(:expired, String, String, Exception)]
|
84
|
-
# @return [Dry::Monads::Failure(:decoding_failed, String, String, Exception)]
|
85
|
-
def decode_and_verify(token)
|
86
|
-
jwks = yield key_resolver.find_public_keys
|
74
|
+
decoded_token = yield wrap.call payload, headers
|
87
75
|
|
88
|
-
|
89
|
-
|
90
|
-
options = {
|
91
|
-
algorithms: algorithms,
|
92
|
-
leeway: token_leeway,
|
93
|
-
jwks: jwks
|
94
|
-
}
|
95
|
-
|
96
|
-
payload, headers = JWT.decode token, nil, true, options
|
97
|
-
rescue JWT::ExpiredSignature => e
|
98
|
-
Failure[:expired, "JWT is expired", token, e]
|
99
|
-
rescue JWT::DecodeError => e
|
100
|
-
Failure[:decoding_failed, "Failed to decode JWT", token, e]
|
101
|
-
else
|
102
|
-
Success DecodedToken.new payload.merge(original_payload: payload, headers: headers)
|
103
|
-
end
|
104
|
-
|
105
|
-
# @param [{ Symbol => <{ Symbol => String }> }] jwks
|
106
|
-
# @return [<String>]
|
107
|
-
def algorithms_for(jwks)
|
108
|
-
jwks.fetch(:keys, []).map do |k|
|
109
|
-
k[:alg]
|
110
|
-
end.uniq.compact.then do |algs|
|
111
|
-
algs.present? ? Success(algs) : Failure[:no_algorithms, "Could not derive algorithms from JWKS"]
|
112
|
-
end
|
76
|
+
Success[:authenticated, decoded_token]
|
113
77
|
end
|
114
78
|
end
|
115
79
|
end
|
@@ -19,6 +19,10 @@ module KeycloakRack
|
|
19
19
|
KeycloakRack::Authenticate.new
|
20
20
|
end
|
21
21
|
|
22
|
+
register :decode_and_verify do
|
23
|
+
KeycloakRack::DecodeAndVerify.new
|
24
|
+
end
|
25
|
+
|
22
26
|
register :http_client do
|
23
27
|
KeycloakRack::HTTPClient.new
|
24
28
|
end
|
@@ -48,6 +52,10 @@ module KeycloakRack
|
|
48
52
|
register :x509_store do
|
49
53
|
resolve(:config).build_x509_store
|
50
54
|
end
|
55
|
+
|
56
|
+
register :wrap_token do
|
57
|
+
KeycloakRack::WrapToken.new
|
58
|
+
end
|
51
59
|
end
|
52
60
|
end
|
53
61
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module KeycloakRack
|
4
|
+
# Accept an encoded JWT and return the raw token.
|
5
|
+
class DecodeAndVerify
|
6
|
+
include Dry::Monads[:do, :result]
|
7
|
+
|
8
|
+
include Import[
|
9
|
+
config: "keycloak-rack.config",
|
10
|
+
key_resolver: "keycloak-rack.key_resolver",
|
11
|
+
]
|
12
|
+
|
13
|
+
delegate :token_leeway, to: :config
|
14
|
+
|
15
|
+
# @param [String] token
|
16
|
+
# @return [Dry::Monads::Success(Hash, Hash)] a tuple of the JWT payload and its headers
|
17
|
+
# @return [Dry::Monads::Failure(:expired, String, String, Exception)]
|
18
|
+
# @return [Dry::Monads::Failure(:decoding_failed, String, Exception)]
|
19
|
+
def call(token)
|
20
|
+
jwks = yield key_resolver.find_public_keys
|
21
|
+
|
22
|
+
algorithms = yield algorithms_for jwks
|
23
|
+
|
24
|
+
options = {
|
25
|
+
algorithms: algorithms,
|
26
|
+
leeway: token_leeway,
|
27
|
+
jwks: jwks
|
28
|
+
}
|
29
|
+
|
30
|
+
payload, headers = JWT.decode token, nil, true, options
|
31
|
+
rescue JWT::ExpiredSignature => e
|
32
|
+
Failure[:expired, "JWT is expired", token, e]
|
33
|
+
rescue JWT::DecodeError => e
|
34
|
+
Failure[:decoding_failed, "Failed to decode JWT", e]
|
35
|
+
else
|
36
|
+
Success[payload, headers]
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# @param [{ Symbol => <{ Symbol => String }> }] jwks
|
42
|
+
# @return [<String>]
|
43
|
+
def algorithms_for(jwks)
|
44
|
+
jwks.fetch(:keys, []).map do |k|
|
45
|
+
k[:alg]
|
46
|
+
end.uniq.compact.then do |algs|
|
47
|
+
algs.present? ? Success(algs) : Failure[:no_algorithms, "Could not derive algorithms from JWKS"]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -18,6 +18,8 @@ module KeycloakRack
|
|
18
18
|
|
19
19
|
private_constant :KEY_MAP
|
20
20
|
|
21
|
+
ALIAS_MAP = KEY_MAP.invert.freeze
|
22
|
+
|
21
23
|
transform_keys do |k|
|
22
24
|
KEY_MAP[k] || k.to_sym
|
23
25
|
end
|
@@ -65,17 +67,17 @@ module KeycloakRack
|
|
65
67
|
# @!attribute [r] expires_at
|
66
68
|
# The `exp` claim
|
67
69
|
# @return [Time]
|
68
|
-
attribute :expires_at, Types::Timestamp
|
70
|
+
attribute? :expires_at, Types::Timestamp
|
69
71
|
|
70
72
|
# @!attribute [r] issued_at
|
71
73
|
# The `iat` claim
|
72
74
|
# @return [Time]
|
73
|
-
attribute :issued_at, Types::Timestamp
|
75
|
+
attribute? :issued_at, Types::Timestamp
|
74
76
|
|
75
77
|
# @!attribute [r] authorized_at
|
76
78
|
# The `auth_time` value from Keycloak.
|
77
79
|
# @return [Time]
|
78
|
-
attribute :authorized_at, Types::Timestamp
|
80
|
+
attribute? :authorized_at, Types::Timestamp
|
79
81
|
|
80
82
|
# @!attribute [r] jti
|
81
83
|
# @return [String]
|
@@ -93,20 +95,20 @@ module KeycloakRack
|
|
93
95
|
# @!attribute [r] authorized_party
|
94
96
|
# The `azp` claim
|
95
97
|
# @return [String]
|
96
|
-
attribute :authorized_party, Types::String
|
98
|
+
attribute? :authorized_party, Types::String
|
97
99
|
|
98
100
|
# @!attribute [r] nonce
|
99
101
|
# Cryptographic nonce for the token
|
100
102
|
# @return [String]
|
101
|
-
attribute :nonce, Types::String
|
103
|
+
attribute? :nonce, Types::String
|
102
104
|
|
103
105
|
# @!attribute [r] scope
|
104
106
|
# @return [String]
|
105
|
-
attribute :scope, Types::String
|
107
|
+
attribute? :scope, Types::String
|
106
108
|
|
107
109
|
# @!attribute [r] session_state
|
108
110
|
# @return [String]
|
109
|
-
attribute :session_state, Types::String
|
111
|
+
attribute? :session_state, Types::String
|
110
112
|
|
111
113
|
# @!attribute [r] locale
|
112
114
|
# @return [String, nil]
|
@@ -114,7 +116,7 @@ module KeycloakRack
|
|
114
116
|
|
115
117
|
# @!attribute [r] allowed_origins
|
116
118
|
# @return [<String>]
|
117
|
-
attribute :allowed_origins, Types::StringList
|
119
|
+
attribute? :allowed_origins, Types::StringList
|
118
120
|
|
119
121
|
# @!attribute [r] headers
|
120
122
|
# The JWT headers, provided for debugging
|
@@ -187,5 +189,13 @@ module KeycloakRack
|
|
187
189
|
# An error raised by {KeycloakRack::DecodedToken#fetch} when
|
188
190
|
# trying to fetch something the token doesn't know about
|
189
191
|
class UnknownAttribute < KeyError; end
|
192
|
+
|
193
|
+
class << self
|
194
|
+
# @param [Symbol] key
|
195
|
+
# @return [Symbol]
|
196
|
+
def maybe_unalias_key(key)
|
197
|
+
ALIAS_MAP.fetch(key, key).to_sym
|
198
|
+
end
|
199
|
+
end
|
190
200
|
end
|
191
201
|
end
|