keycloak-api-rails 1.0.0 → 1.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -1
- data/Dockerfile +1 -1
- data/Gemfile.lock +100 -95
- data/README.md +8 -8
- data/keycloak-api-rails.gemspec +1 -1
- data/lib/keycloak-api-rails/authentication.rb +3 -5
- data/lib/keycloak-api-rails/configuration.rb +9 -10
- data/lib/keycloak-api-rails/helper.rb +2 -2
- data/lib/keycloak-api-rails/public_key_cached_resolver.rb +1 -1
- data/lib/keycloak-api-rails/service.rb +2 -2
- data/lib/keycloak-api-rails/version.rb +1 -1
- data/spec/keycloak-api-rails/activesupport_free_spec.rb +18 -0
- data/spec/keycloak-api-rails/authentication_spec.rb +38 -0
- data/spec/keycloak-api-rails/configuration_spec.rb +101 -0
- data/spec/keycloak-api-rails/helper_spec.rb +61 -0
- data/spec/keycloak-api-rails/service_spec.rb +23 -1
- data/spec/support/activesupport_free_probe.rb +131 -0
- metadata +7 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 72a9cf5907ae0256e7acfbf9bd9e453dcbcaeae5fd4c5ce146780e3ef5ec2644
|
|
4
|
+
data.tar.gz: ac22d1edfbf8d1701ac82a213f3052ca32976dd766841111066600910497d58d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e73d57fcaf904c534048ff6d6e611913298b173be1e47b01b31c7c6cb351f2e8d74b00a57027ce03063b63391f2200c9c8d866a18a7cb632856acb77bdb5d494
|
|
7
|
+
data.tar.gz: be4136364d974a0ebcba62a31f526341cdef89f0f87f991dde409cb40a36303f0ae4a781599929caf830cf89a58ce01b20e2c7209ef7613c9e0d465b831bbb17
|
data/CHANGELOG.md
CHANGED
|
@@ -5,7 +5,13 @@ 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.0.
|
|
8
|
+
## [1.0.1] - 2026-07-30
|
|
9
|
+
|
|
10
|
+
* Dependencies: Upgrade test dependency `timecop` to `0.9.11`
|
|
11
|
+
* Upgrade Docker image to Ruby 3.4
|
|
12
|
+
* Remove all usages of `ActiveSupport` from the library, replaced by plain Ruby
|
|
13
|
+
|
|
14
|
+
## [1.0.0] - 2025-12-10
|
|
9
15
|
|
|
10
16
|
* *[BREAKING CHANGE!]* Rename top-level module from `Keycloak` to `KeycloakApiRails` to avoid conflicts with other gems. (thanks to @eilers)
|
|
11
17
|
* *Migration: Please do a global find and replace of `Keycloak.` to `KeycloakApiRails.` in your application.*
|
data/Dockerfile
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -8,31 +8,31 @@ PATH
|
|
|
8
8
|
GEM
|
|
9
9
|
remote: https://rubygems.org/
|
|
10
10
|
specs:
|
|
11
|
-
action_text-trix (2.1.
|
|
11
|
+
action_text-trix (2.1.19)
|
|
12
12
|
railties
|
|
13
|
-
actioncable (8.1.1)
|
|
14
|
-
actionpack (= 8.1.1)
|
|
15
|
-
activesupport (= 8.1.1)
|
|
13
|
+
actioncable (8.1.3.1)
|
|
14
|
+
actionpack (= 8.1.3.1)
|
|
15
|
+
activesupport (= 8.1.3.1)
|
|
16
16
|
nio4r (~> 2.0)
|
|
17
17
|
websocket-driver (>= 0.6.1)
|
|
18
18
|
zeitwerk (~> 2.6)
|
|
19
|
-
actionmailbox (8.1.1)
|
|
20
|
-
actionpack (= 8.1.1)
|
|
21
|
-
activejob (= 8.1.1)
|
|
22
|
-
activerecord (= 8.1.1)
|
|
23
|
-
activestorage (= 8.1.1)
|
|
24
|
-
activesupport (= 8.1.1)
|
|
19
|
+
actionmailbox (8.1.3.1)
|
|
20
|
+
actionpack (= 8.1.3.1)
|
|
21
|
+
activejob (= 8.1.3.1)
|
|
22
|
+
activerecord (= 8.1.3.1)
|
|
23
|
+
activestorage (= 8.1.3.1)
|
|
24
|
+
activesupport (= 8.1.3.1)
|
|
25
25
|
mail (>= 2.8.0)
|
|
26
|
-
actionmailer (8.1.1)
|
|
27
|
-
actionpack (= 8.1.1)
|
|
28
|
-
actionview (= 8.1.1)
|
|
29
|
-
activejob (= 8.1.1)
|
|
30
|
-
activesupport (= 8.1.1)
|
|
26
|
+
actionmailer (8.1.3.1)
|
|
27
|
+
actionpack (= 8.1.3.1)
|
|
28
|
+
actionview (= 8.1.3.1)
|
|
29
|
+
activejob (= 8.1.3.1)
|
|
30
|
+
activesupport (= 8.1.3.1)
|
|
31
31
|
mail (>= 2.8.0)
|
|
32
32
|
rails-dom-testing (~> 2.2)
|
|
33
|
-
actionpack (8.1.1)
|
|
34
|
-
actionview (= 8.1.1)
|
|
35
|
-
activesupport (= 8.1.1)
|
|
33
|
+
actionpack (8.1.3.1)
|
|
34
|
+
actionview (= 8.1.3.1)
|
|
35
|
+
activesupport (= 8.1.3.1)
|
|
36
36
|
nokogiri (>= 1.8.5)
|
|
37
37
|
rack (>= 2.2.4)
|
|
38
38
|
rack-session (>= 1.0.1)
|
|
@@ -40,36 +40,36 @@ GEM
|
|
|
40
40
|
rails-dom-testing (~> 2.2)
|
|
41
41
|
rails-html-sanitizer (~> 1.6)
|
|
42
42
|
useragent (~> 0.16)
|
|
43
|
-
actiontext (8.1.1)
|
|
43
|
+
actiontext (8.1.3.1)
|
|
44
44
|
action_text-trix (~> 2.1.15)
|
|
45
|
-
actionpack (= 8.1.1)
|
|
46
|
-
activerecord (= 8.1.1)
|
|
47
|
-
activestorage (= 8.1.1)
|
|
48
|
-
activesupport (= 8.1.1)
|
|
45
|
+
actionpack (= 8.1.3.1)
|
|
46
|
+
activerecord (= 8.1.3.1)
|
|
47
|
+
activestorage (= 8.1.3.1)
|
|
48
|
+
activesupport (= 8.1.3.1)
|
|
49
49
|
globalid (>= 0.6.0)
|
|
50
50
|
nokogiri (>= 1.8.5)
|
|
51
|
-
actionview (8.1.1)
|
|
52
|
-
activesupport (= 8.1.1)
|
|
51
|
+
actionview (8.1.3.1)
|
|
52
|
+
activesupport (= 8.1.3.1)
|
|
53
53
|
builder (~> 3.1)
|
|
54
54
|
erubi (~> 1.11)
|
|
55
55
|
rails-dom-testing (~> 2.2)
|
|
56
56
|
rails-html-sanitizer (~> 1.6)
|
|
57
|
-
activejob (8.1.1)
|
|
58
|
-
activesupport (= 8.1.1)
|
|
57
|
+
activejob (8.1.3.1)
|
|
58
|
+
activesupport (= 8.1.3.1)
|
|
59
59
|
globalid (>= 0.3.6)
|
|
60
|
-
activemodel (8.1.1)
|
|
61
|
-
activesupport (= 8.1.1)
|
|
62
|
-
activerecord (8.1.1)
|
|
63
|
-
activemodel (= 8.1.1)
|
|
64
|
-
activesupport (= 8.1.1)
|
|
60
|
+
activemodel (8.1.3.1)
|
|
61
|
+
activesupport (= 8.1.3.1)
|
|
62
|
+
activerecord (8.1.3.1)
|
|
63
|
+
activemodel (= 8.1.3.1)
|
|
64
|
+
activesupport (= 8.1.3.1)
|
|
65
65
|
timeout (>= 0.4.0)
|
|
66
|
-
activestorage (8.1.1)
|
|
67
|
-
actionpack (= 8.1.1)
|
|
68
|
-
activejob (= 8.1.1)
|
|
69
|
-
activerecord (= 8.1.1)
|
|
70
|
-
activesupport (= 8.1.1)
|
|
66
|
+
activestorage (8.1.3.1)
|
|
67
|
+
actionpack (= 8.1.3.1)
|
|
68
|
+
activejob (= 8.1.3.1)
|
|
69
|
+
activerecord (= 8.1.3.1)
|
|
70
|
+
activesupport (= 8.1.3.1)
|
|
71
71
|
marcel (~> 1.0)
|
|
72
|
-
activesupport (8.1.1)
|
|
72
|
+
activesupport (8.1.3.1)
|
|
73
73
|
base64
|
|
74
74
|
bigdecimal
|
|
75
75
|
concurrent-ruby (~> 1.0, >= 1.3.1)
|
|
@@ -84,37 +84,38 @@ GEM
|
|
|
84
84
|
uri (>= 0.13.1)
|
|
85
85
|
aes_key_wrap (1.1.0)
|
|
86
86
|
base64 (0.3.0)
|
|
87
|
-
bigdecimal (
|
|
88
|
-
bindata (
|
|
87
|
+
bigdecimal (4.1.2)
|
|
88
|
+
bindata (3.0.0)
|
|
89
89
|
builder (3.3.0)
|
|
90
90
|
byebug (12.0.0)
|
|
91
|
-
concurrent-ruby (1.3.
|
|
91
|
+
concurrent-ruby (1.3.8)
|
|
92
92
|
connection_pool (3.0.2)
|
|
93
|
-
crass (1.0.
|
|
93
|
+
crass (1.0.7)
|
|
94
94
|
date (3.5.1)
|
|
95
95
|
diff-lcs (1.6.2)
|
|
96
96
|
drb (2.2.3)
|
|
97
|
-
erb (6.0.
|
|
97
|
+
erb (6.0.6)
|
|
98
98
|
erubi (1.13.1)
|
|
99
|
-
faraday (2.14.
|
|
99
|
+
faraday (2.14.3)
|
|
100
100
|
faraday-net_http (>= 2.0, < 3.5)
|
|
101
101
|
json
|
|
102
102
|
logger
|
|
103
|
-
faraday-follow_redirects (0.
|
|
103
|
+
faraday-follow_redirects (0.5.0)
|
|
104
104
|
faraday (>= 1, < 3)
|
|
105
|
-
faraday-net_http (3.4.
|
|
105
|
+
faraday-net_http (3.4.4)
|
|
106
106
|
net-http (~> 0.5)
|
|
107
|
-
globalid (1.
|
|
107
|
+
globalid (1.4.0)
|
|
108
108
|
activesupport (>= 6.1)
|
|
109
|
-
i18n (1.
|
|
109
|
+
i18n (1.15.2)
|
|
110
110
|
concurrent-ruby (~> 1.0)
|
|
111
|
-
io-console (0.8.
|
|
112
|
-
irb (1.
|
|
111
|
+
io-console (0.8.2)
|
|
112
|
+
irb (1.18.0)
|
|
113
113
|
pp (>= 0.6.0)
|
|
114
|
+
prism (>= 1.3.0)
|
|
114
115
|
rdoc (>= 4.0.0)
|
|
115
116
|
reline (>= 0.4.2)
|
|
116
|
-
json (2.
|
|
117
|
-
json-jwt (1.17.
|
|
117
|
+
json (2.21.1)
|
|
118
|
+
json-jwt (1.17.1)
|
|
118
119
|
activesupport (>= 4.2)
|
|
119
120
|
aes_key_wrap
|
|
120
121
|
base64
|
|
@@ -122,22 +123,24 @@ GEM
|
|
|
122
123
|
faraday (~> 2.0)
|
|
123
124
|
faraday-follow_redirects
|
|
124
125
|
logger (1.7.0)
|
|
125
|
-
loofah (2.
|
|
126
|
+
loofah (2.25.2)
|
|
126
127
|
crass (~> 1.0.2)
|
|
127
128
|
nokogiri (>= 1.12.0)
|
|
128
|
-
mail (2.9.
|
|
129
|
+
mail (2.9.1)
|
|
129
130
|
logger
|
|
130
131
|
mini_mime (>= 0.1.1)
|
|
131
132
|
net-imap
|
|
132
133
|
net-pop
|
|
133
134
|
net-smtp
|
|
134
|
-
marcel (1.1
|
|
135
|
+
marcel (1.2.1)
|
|
135
136
|
mini_mime (1.1.5)
|
|
136
137
|
mini_portile2 (2.8.9)
|
|
137
|
-
minitest (
|
|
138
|
-
|
|
138
|
+
minitest (6.0.6)
|
|
139
|
+
drb (~> 2.0)
|
|
140
|
+
prism (~> 1.5)
|
|
141
|
+
net-http (0.9.1)
|
|
139
142
|
uri (>= 0.11.1)
|
|
140
|
-
net-imap (0.
|
|
143
|
+
net-imap (0.6.6)
|
|
141
144
|
date
|
|
142
145
|
net-protocol
|
|
143
146
|
net-pop (0.1.2)
|
|
@@ -147,58 +150,61 @@ GEM
|
|
|
147
150
|
net-smtp (0.5.1)
|
|
148
151
|
net-protocol
|
|
149
152
|
nio4r (2.7.5)
|
|
150
|
-
nokogiri (1.
|
|
153
|
+
nokogiri (1.19.4)
|
|
151
154
|
mini_portile2 (~> 2.8.2)
|
|
152
155
|
racc (~> 1.4)
|
|
153
|
-
pp (0.6.
|
|
156
|
+
pp (0.6.4)
|
|
154
157
|
prettyprint
|
|
155
158
|
prettyprint (0.2.0)
|
|
156
|
-
|
|
157
|
-
date
|
|
158
|
-
stringio
|
|
159
|
+
prism (1.9.0)
|
|
159
160
|
racc (1.8.1)
|
|
160
|
-
rack (3.2.
|
|
161
|
-
rack-session (2.1.
|
|
161
|
+
rack (3.2.6)
|
|
162
|
+
rack-session (2.1.2)
|
|
162
163
|
base64 (>= 0.1.0)
|
|
163
164
|
rack (>= 3.0.0)
|
|
164
165
|
rack-test (2.2.0)
|
|
165
166
|
rack (>= 1.3)
|
|
166
167
|
rackup (2.3.1)
|
|
167
168
|
rack (>= 3)
|
|
168
|
-
rails (8.1.1)
|
|
169
|
-
actioncable (= 8.1.1)
|
|
170
|
-
actionmailbox (= 8.1.1)
|
|
171
|
-
actionmailer (= 8.1.1)
|
|
172
|
-
actionpack (= 8.1.1)
|
|
173
|
-
actiontext (= 8.1.1)
|
|
174
|
-
actionview (= 8.1.1)
|
|
175
|
-
activejob (= 8.1.1)
|
|
176
|
-
activemodel (= 8.1.1)
|
|
177
|
-
activerecord (= 8.1.1)
|
|
178
|
-
activestorage (= 8.1.1)
|
|
179
|
-
activesupport (= 8.1.1)
|
|
169
|
+
rails (8.1.3.1)
|
|
170
|
+
actioncable (= 8.1.3.1)
|
|
171
|
+
actionmailbox (= 8.1.3.1)
|
|
172
|
+
actionmailer (= 8.1.3.1)
|
|
173
|
+
actionpack (= 8.1.3.1)
|
|
174
|
+
actiontext (= 8.1.3.1)
|
|
175
|
+
actionview (= 8.1.3.1)
|
|
176
|
+
activejob (= 8.1.3.1)
|
|
177
|
+
activemodel (= 8.1.3.1)
|
|
178
|
+
activerecord (= 8.1.3.1)
|
|
179
|
+
activestorage (= 8.1.3.1)
|
|
180
|
+
activesupport (= 8.1.3.1)
|
|
180
181
|
bundler (>= 1.15.0)
|
|
181
|
-
railties (= 8.1.1)
|
|
182
|
+
railties (= 8.1.3.1)
|
|
182
183
|
rails-dom-testing (2.3.0)
|
|
183
184
|
activesupport (>= 5.0.0)
|
|
184
185
|
minitest
|
|
185
186
|
nokogiri (>= 1.6)
|
|
186
|
-
rails-html-sanitizer (1.
|
|
187
|
-
loofah (~> 2.
|
|
187
|
+
rails-html-sanitizer (1.7.1)
|
|
188
|
+
loofah (~> 2.25, >= 2.25.2)
|
|
188
189
|
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
|
|
189
|
-
railties (8.1.1)
|
|
190
|
-
actionpack (= 8.1.1)
|
|
191
|
-
activesupport (= 8.1.1)
|
|
190
|
+
railties (8.1.3.1)
|
|
191
|
+
actionpack (= 8.1.3.1)
|
|
192
|
+
activesupport (= 8.1.3.1)
|
|
192
193
|
irb (~> 1.13)
|
|
193
194
|
rackup (>= 1.0.0)
|
|
194
195
|
rake (>= 12.2)
|
|
195
196
|
thor (~> 1.0, >= 1.2.2)
|
|
196
197
|
tsort (>= 0.2)
|
|
197
198
|
zeitwerk (~> 2.6)
|
|
198
|
-
rake (13.
|
|
199
|
-
|
|
199
|
+
rake (13.4.2)
|
|
200
|
+
rbs (4.1.1)
|
|
201
|
+
logger
|
|
202
|
+
prism (>= 1.6.0)
|
|
203
|
+
tsort
|
|
204
|
+
rdoc (8.0.0)
|
|
200
205
|
erb
|
|
201
|
-
|
|
206
|
+
prism (>= 1.6.0)
|
|
207
|
+
rbs (>= 4.0.0)
|
|
202
208
|
tsort
|
|
203
209
|
reline (0.6.3)
|
|
204
210
|
io-console (~> 0.5)
|
|
@@ -211,25 +217,24 @@ GEM
|
|
|
211
217
|
rspec-expectations (3.13.5)
|
|
212
218
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
213
219
|
rspec-support (~> 3.13.0)
|
|
214
|
-
rspec-mocks (3.13.
|
|
220
|
+
rspec-mocks (3.13.8)
|
|
215
221
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
216
222
|
rspec-support (~> 3.13.0)
|
|
217
|
-
rspec-support (3.13.
|
|
223
|
+
rspec-support (3.13.7)
|
|
218
224
|
securerandom (0.4.1)
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
timeout (0.5.0)
|
|
225
|
+
thor (1.5.0)
|
|
226
|
+
timecop (0.9.11)
|
|
227
|
+
timeout (0.6.1)
|
|
223
228
|
tsort (0.2.0)
|
|
224
229
|
tzinfo (2.0.6)
|
|
225
230
|
concurrent-ruby (~> 1.0)
|
|
226
231
|
uri (1.1.1)
|
|
227
232
|
useragent (0.16.11)
|
|
228
|
-
websocket-driver (0.8.
|
|
233
|
+
websocket-driver (0.8.2)
|
|
229
234
|
base64
|
|
230
235
|
websocket-extensions (>= 0.1.0)
|
|
231
236
|
websocket-extensions (0.1.5)
|
|
232
|
-
zeitwerk (2.
|
|
237
|
+
zeitwerk (2.8.2)
|
|
233
238
|
|
|
234
239
|
PLATFORMS
|
|
235
240
|
ruby
|
|
@@ -238,7 +243,7 @@ DEPENDENCIES
|
|
|
238
243
|
byebug (= 12.0.0)
|
|
239
244
|
keycloak-api-rails!
|
|
240
245
|
rspec (= 3.13.2)
|
|
241
|
-
timecop (= 0.9.
|
|
246
|
+
timecop (= 0.9.11)
|
|
242
247
|
|
|
243
248
|
BUNDLED WITH
|
|
244
249
|
2.4.13
|
data/README.md
CHANGED
|
@@ -5,7 +5,7 @@ This gem validates Keycloak JWT token for Ruby On Rails APIs.
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
7
7
|
```ruby
|
|
8
|
-
gem "keycloak-api-rails", "1.0.
|
|
8
|
+
gem "keycloak-api-rails", "1.0.1"
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
## Token validation
|
|
@@ -63,7 +63,7 @@ All options have a default value. However, all of them can be changed in your in
|
|
|
63
63
|
Create a `keycloak.rb` file in your Rails `config/initializers` folder. For instance:
|
|
64
64
|
|
|
65
65
|
```
|
|
66
|
-
|
|
66
|
+
KeycloakApiRails.configure do |config|
|
|
67
67
|
config.server_url = ENV["KEYCLOAK_SERVER_URL"]
|
|
68
68
|
config.realm_id = ENV["KEYCLOAK_REALM_ID"]
|
|
69
69
|
config.logger = Rails.logger
|
|
@@ -77,7 +77,7 @@ end
|
|
|
77
77
|
Or using opt-in configuration:
|
|
78
78
|
|
|
79
79
|
```ruby
|
|
80
|
-
|
|
80
|
+
KeycloakApiRails.configure do |config|
|
|
81
81
|
config.server_url = ENV["KEYCLOAK_SERVER_URL"]
|
|
82
82
|
config.realm_id = ENV["KEYCLOAK_REALM_ID"]
|
|
83
83
|
config.logger = Rails.logger
|
|
@@ -163,14 +163,14 @@ This should output `https://api.pouet.io/api/more-pouets?authorizationToken=myTo
|
|
|
163
163
|
|
|
164
164
|
### Accessing Keycloak Service
|
|
165
165
|
|
|
166
|
-
A lazy-loaded service KeycloakApiRails::Service can be accessed using `
|
|
166
|
+
A lazy-loaded service KeycloakApiRails::Service can be accessed using `KeycloakApiRails.service`.
|
|
167
167
|
For instance, to read a provided token:
|
|
168
168
|
```ruby
|
|
169
169
|
class RenderTokenController < ApplicationController
|
|
170
170
|
def show
|
|
171
171
|
uri = request.env["REQUEST_URI"]
|
|
172
172
|
headers = request.env
|
|
173
|
-
token =
|
|
173
|
+
token = KeycloakApiRails.service.read_token(uri, headers)
|
|
174
174
|
render json: { token: token }, status: :ok
|
|
175
175
|
end
|
|
176
176
|
end
|
|
@@ -200,10 +200,10 @@ let(:jwt) do
|
|
|
200
200
|
token.sign($private_key, :RS256).to_s
|
|
201
201
|
end
|
|
202
202
|
```
|
|
203
|
-
* Finally, in the same `shared_context`, stub `
|
|
203
|
+
* Finally, in the same `shared_context`, stub `KeycloakApiRails.public_key_resolver` to use a valid public key that is able to validate `jwt`:
|
|
204
204
|
```ruby
|
|
205
205
|
before(:each) do
|
|
206
|
-
public_key_resolver =
|
|
206
|
+
public_key_resolver = KeycloakApiRails.public_key_resolver
|
|
207
207
|
allow(public_key_resolver).to receive(:find_public_keys) { JSON::JWK::Set.new(JSON::JWK.new($private_key, kid: "default")) }
|
|
208
208
|
end
|
|
209
209
|
```
|
|
@@ -216,7 +216,7 @@ From the `keycloak-rails-api` directory:
|
|
|
216
216
|
$ docker build . -t keycloak-rails-api:test
|
|
217
217
|
$ docker run -v `pwd`:/usr/src/app/ keycloak-rails-api:test bundle exec rspec spec
|
|
218
218
|
```
|
|
219
|
-
|
|
219
|
+
|
|
220
220
|
## Next developments
|
|
221
221
|
|
|
222
222
|
* Manage multiple realms
|
data/keycloak-api-rails.gemspec
CHANGED
|
@@ -19,6 +19,6 @@ Gem::Specification.new do |spec|
|
|
|
19
19
|
spec.add_dependency "json-jwt", ">= 1.11.0"
|
|
20
20
|
|
|
21
21
|
spec.add_development_dependency "rspec", "3.13.2"
|
|
22
|
-
spec.add_development_dependency "timecop", "0.9.
|
|
22
|
+
spec.add_development_dependency "timecop", "0.9.11"
|
|
23
23
|
spec.add_development_dependency "byebug", "12.0.0"
|
|
24
24
|
end
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
module KeycloakApiRails
|
|
2
2
|
module Authentication
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
if respond_to?(:helper_method)
|
|
7
|
-
helper_method :keycloak_authenticate
|
|
3
|
+
def self.included(base)
|
|
4
|
+
if base.respond_to?(:helper_method)
|
|
5
|
+
base.helper_method :keycloak_authenticate
|
|
8
6
|
end
|
|
9
7
|
end
|
|
10
8
|
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
module KeycloakApiRails
|
|
2
2
|
class Configuration
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
config_accessor :ca_certificate_file
|
|
3
|
+
attr_accessor :server_url
|
|
4
|
+
attr_accessor :realm_id
|
|
5
|
+
attr_accessor :skip_paths
|
|
6
|
+
attr_accessor :opt_in
|
|
7
|
+
attr_accessor :token_expiration_tolerance_in_seconds
|
|
8
|
+
attr_accessor :public_key_cache_ttl
|
|
9
|
+
attr_accessor :custom_attributes
|
|
10
|
+
attr_accessor :logger
|
|
11
|
+
attr_accessor :ca_certificate_file
|
|
13
12
|
end
|
|
14
13
|
end
|
|
@@ -83,11 +83,11 @@ module KeycloakApiRails
|
|
|
83
83
|
end
|
|
84
84
|
|
|
85
85
|
def self.read_token_from_query_string(uri)
|
|
86
|
-
if uri.
|
|
86
|
+
if uri && !uri.strip.empty?
|
|
87
87
|
parsed_uri = URI.parse(uri)
|
|
88
88
|
query = URI.decode_www_form(parsed_uri.query || "")
|
|
89
89
|
query_string_token = query.detect { |param| param.first == QUERY_STRING_TOKEN_KEY }
|
|
90
|
-
query_string_token&.
|
|
90
|
+
query_string_token&.at(1)
|
|
91
91
|
else
|
|
92
92
|
""
|
|
93
93
|
end
|
|
@@ -24,7 +24,7 @@ module KeycloakApiRails
|
|
|
24
24
|
private
|
|
25
25
|
|
|
26
26
|
def public_keys_are_outdated?
|
|
27
|
-
@cached_public_keys.nil? || @cached_public_key_retrieved_at.nil? || Time.now > (@cached_public_key_retrieved_at + @public_key_cache_ttl
|
|
27
|
+
@cached_public_keys.nil? || @cached_public_key_retrieved_at.nil? || Time.now > (@cached_public_key_retrieved_at + @public_key_cache_ttl)
|
|
28
28
|
end
|
|
29
29
|
end
|
|
30
30
|
end
|
|
@@ -53,8 +53,8 @@ module KeycloakApiRails
|
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
def expired?(token)
|
|
56
|
-
token_expiration = Time.at(token["exp"])
|
|
57
|
-
token_expiration < Time.now + @token_expiration_tolerance_in_seconds
|
|
56
|
+
token_expiration = Time.at(token["exp"])
|
|
57
|
+
token_expiration < Time.now + @token_expiration_tolerance_in_seconds
|
|
58
58
|
end
|
|
59
59
|
end
|
|
60
60
|
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require "rbconfig"
|
|
2
|
+
|
|
3
|
+
RSpec.describe "The library without ActiveSupport" do
|
|
4
|
+
|
|
5
|
+
let(:probe) { File.expand_path("../../support/activesupport_free_probe.rb", __FILE__) }
|
|
6
|
+
|
|
7
|
+
# RUBYOPT is cleared so that nothing set up by bundler is preloaded in the probe process.
|
|
8
|
+
def run_probe
|
|
9
|
+
output = IO.popen({ "RUBYOPT" => nil }, [RbConfig.ruby, probe], err: [:child, :out], &:read)
|
|
10
|
+
[$?.exitstatus, output]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "loads and behaves the same way when ActiveSupport is not available" do
|
|
14
|
+
status, output = run_probe
|
|
15
|
+
|
|
16
|
+
expect(status).to eq(0), "The library relies on ActiveSupport:\n#{output}"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -17,6 +17,44 @@ describe KeycloakApiRails::Authentication do
|
|
|
17
17
|
}
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
+
describe "when included" do
|
|
21
|
+
it "declares keycloak_authenticate as a helper method when the base class supports helpers" do
|
|
22
|
+
declared_helper_methods = []
|
|
23
|
+
base = Class.new do
|
|
24
|
+
define_singleton_method(:helper_method) { |*names| declared_helper_methods.concat(names) }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
base.include(KeycloakApiRails::Authentication)
|
|
28
|
+
|
|
29
|
+
expect(declared_helper_methods).to eq [:keycloak_authenticate]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "declares the helper method on a real controller" do
|
|
33
|
+
expect(ExampleController._helper_methods).to include :keycloak_authenticate
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "does not fail when the base class does not support helpers" do
|
|
37
|
+
expect {
|
|
38
|
+
Class.new.include(KeycloakApiRails::Authentication)
|
|
39
|
+
}.to_not raise_error
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "exposes its methods as protected instance methods" do
|
|
43
|
+
expect(KeycloakApiRails::Authentication.protected_instance_methods).to match_array %i[
|
|
44
|
+
keycloak_authenticate
|
|
45
|
+
authentication_failed
|
|
46
|
+
authentication_succeeded
|
|
47
|
+
]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "does not add any public method to the including class" do
|
|
51
|
+
base = Class.new.include(KeycloakApiRails::Authentication)
|
|
52
|
+
|
|
53
|
+
expect(base.public_instance_methods).to_not include :keycloak_authenticate
|
|
54
|
+
expect(base.protected_instance_methods).to include :keycloak_authenticate
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
20
58
|
describe "#keycloak_authenticate" do
|
|
21
59
|
before do
|
|
22
60
|
# Mock request object because we aren't using real request spec
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
RSpec.describe KeycloakApiRails::Configuration do
|
|
2
|
+
|
|
3
|
+
# Every attribute that used to be declared through ActiveSupport's `config_accessor`.
|
|
4
|
+
let(:attribute_names) do
|
|
5
|
+
%i[
|
|
6
|
+
server_url
|
|
7
|
+
realm_id
|
|
8
|
+
skip_paths
|
|
9
|
+
opt_in
|
|
10
|
+
token_expiration_tolerance_in_seconds
|
|
11
|
+
public_key_cache_ttl
|
|
12
|
+
custom_attributes
|
|
13
|
+
logger
|
|
14
|
+
ca_certificate_file
|
|
15
|
+
]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe "attributes" do
|
|
19
|
+
let(:configuration) { KeycloakApiRails::Configuration.new }
|
|
20
|
+
|
|
21
|
+
it "exposes a reader and a writer for each attribute" do
|
|
22
|
+
attribute_names.each do |name|
|
|
23
|
+
expect(configuration).to respond_to name
|
|
24
|
+
expect(configuration).to respond_to "#{name}="
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "returns nil for each attribute that has not been assigned" do
|
|
29
|
+
attribute_names.each do |name|
|
|
30
|
+
expect(configuration.public_send(name)).to be_nil
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "returns the value that has been assigned" do
|
|
35
|
+
attribute_names.each do |name|
|
|
36
|
+
configuration.public_send("#{name}=", "a value for #{name}")
|
|
37
|
+
expect(configuration.public_send(name)).to eq "a value for #{name}"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "does not respond to an unknown attribute" do
|
|
42
|
+
expect(configuration).to_not respond_to :not_a_configuration_attribute
|
|
43
|
+
expect {
|
|
44
|
+
configuration.not_a_configuration_attribute
|
|
45
|
+
}.to raise_error NoMethodError
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
describe "#configure" do
|
|
50
|
+
after(:each) do
|
|
51
|
+
KeycloakApiRails.load_configuration
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "yields the configuration" do
|
|
55
|
+
expect { |block| KeycloakApiRails.configure(&block) }.to yield_with_args KeycloakApiRails::Configuration
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "keeps the values assigned within the block" do
|
|
59
|
+
KeycloakApiRails.configure do |config|
|
|
60
|
+
config.server_url = "http://keycloak:8080"
|
|
61
|
+
config.realm_id = "a-realm"
|
|
62
|
+
config.ca_certificate_file = "/etc/ssl/a-certificate.pem"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
expect(KeycloakApiRails.config.server_url).to eq "http://keycloak:8080"
|
|
66
|
+
expect(KeycloakApiRails.config.realm_id).to eq "a-realm"
|
|
67
|
+
expect(KeycloakApiRails.config.ca_certificate_file).to eq "/etc/ssl/a-certificate.pem"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "always returns the same configuration instance" do
|
|
71
|
+
expect(KeycloakApiRails.config).to be KeycloakApiRails.config
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
describe "#load_configuration" do
|
|
76
|
+
before(:each) do
|
|
77
|
+
KeycloakApiRails.load_configuration
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
after(:each) do
|
|
81
|
+
KeycloakApiRails.load_configuration
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it "applies the documented default values" do
|
|
85
|
+
config = KeycloakApiRails.config
|
|
86
|
+
|
|
87
|
+
expect(config.server_url).to be_nil
|
|
88
|
+
expect(config.realm_id).to be_nil
|
|
89
|
+
expect(config.logger).to be_a ::Logger
|
|
90
|
+
expect(config.skip_paths).to eq({})
|
|
91
|
+
expect(config.opt_in).to be false
|
|
92
|
+
expect(config.token_expiration_tolerance_in_seconds).to eq 10
|
|
93
|
+
expect(config.public_key_cache_ttl).to eq 86400
|
|
94
|
+
expect(config.custom_attributes).to eq []
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
it "exposes the logger through KeycloakApiRails.logger" do
|
|
98
|
+
expect(KeycloakApiRails.logger).to be KeycloakApiRails.config.logger
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -1,4 +1,65 @@
|
|
|
1
1
|
RSpec.describe KeycloakApiRails::Helper do
|
|
2
|
+
describe "#read_token_from_query_string" do
|
|
3
|
+
|
|
4
|
+
subject { KeycloakApiRails::Helper.read_token_from_query_string(uri) }
|
|
5
|
+
|
|
6
|
+
context "when the uri is nil" do
|
|
7
|
+
let(:uri) { nil }
|
|
8
|
+
it "returns an empty token" do
|
|
9
|
+
expect(subject).to eq ""
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
context "when the uri is empty" do
|
|
14
|
+
let(:uri) { "" }
|
|
15
|
+
it "returns an empty token" do
|
|
16
|
+
expect(subject).to eq ""
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
context "when the uri only contains whitespaces" do
|
|
21
|
+
let(:uri) { " " }
|
|
22
|
+
it "returns an empty token" do
|
|
23
|
+
expect(subject).to eq ""
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
context "when the uri has no query string" do
|
|
28
|
+
let(:uri) { "http://www.an-url.io/health" }
|
|
29
|
+
it "returns no token" do
|
|
30
|
+
expect(subject).to be_nil
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
context "when the uri has a query string but no token" do
|
|
35
|
+
let(:uri) { "http://www.an-url.io/health?firstName=ouioui" }
|
|
36
|
+
it "returns no token" do
|
|
37
|
+
expect(subject).to be_nil
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
context "when the uri has a token in the query string" do
|
|
42
|
+
let(:uri) { "http://www.an-url.io/health?authorizationToken=aToken" }
|
|
43
|
+
it "returns the token" do
|
|
44
|
+
expect(subject).to eq "aToken"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
context "when the uri has a token among other query string parameters" do
|
|
49
|
+
let(:uri) { "http://www.an-url.io/health?firstName=ouioui&authorizationToken=aToken&lastName=nonnon" }
|
|
50
|
+
it "returns the token" do
|
|
51
|
+
expect(subject).to eq "aToken"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
context "when the uri has an empty token in the query string" do
|
|
56
|
+
let(:uri) { "http://www.an-url.io/health?authorizationToken=" }
|
|
57
|
+
it "returns an empty token" do
|
|
58
|
+
expect(subject).to eq ""
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
2
63
|
describe "#create_url_with_token" do
|
|
3
64
|
|
|
4
65
|
let(:uri) { "http://www.an-url.io" }
|
|
@@ -80,9 +80,31 @@ RSpec.describe KeycloakApiRails::Service do
|
|
|
80
80
|
end
|
|
81
81
|
end
|
|
82
82
|
|
|
83
|
+
# The service reads `token_expiration_tolerance_in_seconds` when it is instantiated:
|
|
84
|
+
# a token expiring within that tolerance is already considered as expired.
|
|
85
|
+
context "and token expires within the expiration tolerance" do
|
|
86
|
+
let(:expiration_date) { Time.now + 5 }
|
|
87
|
+
|
|
88
|
+
it "should raise an error :expiration_date" do
|
|
89
|
+
expect(KeycloakApiRails.config.token_expiration_tolerance_in_seconds).to eq 10
|
|
90
|
+
expect {
|
|
91
|
+
service.decode_and_verify(token)
|
|
92
|
+
}.to raise_error(TokenError, "JWT token is expired")
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
context "and token expires just after the expiration tolerance" do
|
|
97
|
+
let(:expiration_date) { Time.now + 30 }
|
|
98
|
+
|
|
99
|
+
it "should return a not-nil decoded token" do
|
|
100
|
+
expect(KeycloakApiRails.config.token_expiration_tolerance_in_seconds).to eq 10
|
|
101
|
+
expect(service.decode_and_verify(token)).to_not be_nil
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
83
105
|
context "and token is not expired" do
|
|
84
106
|
let(:expiration_date) { Time.now + 2.days }
|
|
85
|
-
|
|
107
|
+
|
|
86
108
|
context "and token is encrypted using RS256" do
|
|
87
109
|
let(:algorithm) { :RS256 }
|
|
88
110
|
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Loads the library and exercises every code path that used to rely on ActiveSupport,
|
|
2
|
+
# in a process where ActiveSupport is *not* loaded.
|
|
3
|
+
#
|
|
4
|
+
# The regular test suite loads `rails/all`, which makes ActiveSupport available everywhere and
|
|
5
|
+
# therefore cannot detect that the library depends on it again. This probe is executed in a
|
|
6
|
+
# separate process by spec/keycloak-api-rails/activesupport_free_spec.rb.
|
|
7
|
+
#
|
|
8
|
+
# The library files are required one by one on purpose: `lib/keycloak-api-rails.rb` pulls in
|
|
9
|
+
# `json/jwt`, which depends on ActiveSupport. The point of this probe is that *our* code does not
|
|
10
|
+
# use ActiveSupport, not that it never gets loaded by a third party.
|
|
11
|
+
|
|
12
|
+
require "uri"
|
|
13
|
+
require "date"
|
|
14
|
+
require "logger"
|
|
15
|
+
|
|
16
|
+
LIB = File.expand_path("../../../lib/keycloak-api-rails", __FILE__)
|
|
17
|
+
|
|
18
|
+
# Minimal stand-in for the parts of lib/keycloak-api-rails.rb the required files call at runtime.
|
|
19
|
+
module KeycloakApiRails
|
|
20
|
+
class << self
|
|
21
|
+
attr_accessor :config
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
require "#{LIB}/configuration"
|
|
26
|
+
require "#{LIB}/helper"
|
|
27
|
+
require "#{LIB}/authentication"
|
|
28
|
+
require "#{LIB}/public_key_resolver"
|
|
29
|
+
require "#{LIB}/public_key_cached_resolver"
|
|
30
|
+
require "#{LIB}/service"
|
|
31
|
+
|
|
32
|
+
$failures = []
|
|
33
|
+
|
|
34
|
+
def assert(description)
|
|
35
|
+
$failures << description unless yield
|
|
36
|
+
rescue => e
|
|
37
|
+
$failures << "#{description} (raised #{e.class}: #{e.message})"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
assert("ActiveSupport is not loaded by the library") { !defined?(ActiveSupport) }
|
|
41
|
+
|
|
42
|
+
### Configuration -- used to be ActiveSupport::Configurable
|
|
43
|
+
configuration = KeycloakApiRails::Configuration.new
|
|
44
|
+
KeycloakApiRails.config = configuration
|
|
45
|
+
|
|
46
|
+
%i[
|
|
47
|
+
server_url realm_id skip_paths opt_in token_expiration_tolerance_in_seconds
|
|
48
|
+
public_key_cache_ttl custom_attributes logger ca_certificate_file
|
|
49
|
+
].each do |name|
|
|
50
|
+
assert("Configuration##{name} is nil until it is assigned") { configuration.public_send(name).nil? }
|
|
51
|
+
configuration.public_send("#{name}=", "a value for #{name}")
|
|
52
|
+
assert("Configuration##{name} returns what was assigned") { configuration.public_send(name) == "a value for #{name}" }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
### Authentication -- used to be ActiveSupport::Concern
|
|
56
|
+
declared_helper_methods = []
|
|
57
|
+
controller_with_helpers = Class.new do
|
|
58
|
+
define_singleton_method(:helper_method) { |*names| declared_helper_methods.concat(names) }
|
|
59
|
+
end
|
|
60
|
+
controller_with_helpers.include(KeycloakApiRails::Authentication)
|
|
61
|
+
assert("Authentication declares keycloak_authenticate as a helper method") do
|
|
62
|
+
declared_helper_methods == [:keycloak_authenticate]
|
|
63
|
+
end
|
|
64
|
+
assert("Authentication can be included in a class without helper_method") do
|
|
65
|
+
Class.new.include(KeycloakApiRails::Authentication)
|
|
66
|
+
true
|
|
67
|
+
end
|
|
68
|
+
assert("Authentication keeps its methods protected") do
|
|
69
|
+
KeycloakApiRails::Authentication.protected_instance_methods.sort ==
|
|
70
|
+
%i[authentication_failed authentication_succeeded keycloak_authenticate]
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
### Helper#read_token_from_query_string -- used to be `present?` and `second`
|
|
74
|
+
{
|
|
75
|
+
nil => "",
|
|
76
|
+
"" => "",
|
|
77
|
+
" " => "",
|
|
78
|
+
"http://www.an-url.io/health" => nil,
|
|
79
|
+
"http://www.an-url.io/health?firstName=ouioui" => nil,
|
|
80
|
+
"http://www.an-url.io/health?authorizationToken=aToken" => "aToken",
|
|
81
|
+
"http://www.an-url.io/health?a=1&authorizationToken=aToken&b=2" => "aToken",
|
|
82
|
+
}.each do |uri, expected|
|
|
83
|
+
assert("Helper.read_token_from_query_string(#{uri.inspect}) returns #{expected.inspect}") do
|
|
84
|
+
KeycloakApiRails::Helper.read_token_from_query_string(uri) == expected
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
### Service#expired? -- used to be `to_datetime` and `seconds`
|
|
89
|
+
configuration.token_expiration_tolerance_in_seconds = 10
|
|
90
|
+
configuration.skip_paths = {}
|
|
91
|
+
configuration.opt_in = false
|
|
92
|
+
configuration.logger = ::Logger.new(File::NULL)
|
|
93
|
+
service = KeycloakApiRails::Service.new(nil)
|
|
94
|
+
now = Time.now
|
|
95
|
+
|
|
96
|
+
{
|
|
97
|
+
"expiring in one hour" => [(now + 3600).to_i, false],
|
|
98
|
+
"expired two days ago" => [(now - 172800).to_i, true],
|
|
99
|
+
"expiring within the tolerance (5s < 10s)" => [(now + 5).to_i, true],
|
|
100
|
+
"expiring after the tolerance (30s > 10s)" => [(now + 30).to_i, false],
|
|
101
|
+
}.each do |description, (exp, expected)|
|
|
102
|
+
assert("Service#expired? returns #{expected} for a token #{description}") do
|
|
103
|
+
service.send(:expired?, { "exp" => exp }) == expected
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
### PublicKeyCachedResolver -- used to be `seconds`
|
|
108
|
+
ttl = 86400
|
|
109
|
+
resolver = KeycloakApiRails::PublicKeyCachedResolver.new(nil, "a-realm", ttl)
|
|
110
|
+
assert("PublicKeyCachedResolver considers an empty cache as outdated") do
|
|
111
|
+
resolver.send(:public_keys_are_outdated?) == true
|
|
112
|
+
end
|
|
113
|
+
resolver.instance_variable_set(:@cached_public_keys, "a-public-key")
|
|
114
|
+
resolver.instance_variable_set(:@cached_public_key_retrieved_at, Time.now - (ttl - 10))
|
|
115
|
+
assert("PublicKeyCachedResolver keeps a cache that is within its TTL") do
|
|
116
|
+
resolver.send(:public_keys_are_outdated?) == false
|
|
117
|
+
end
|
|
118
|
+
resolver.instance_variable_set(:@cached_public_key_retrieved_at, Time.now - (ttl + 10))
|
|
119
|
+
assert("PublicKeyCachedResolver invalidates a cache that outlived its TTL") do
|
|
120
|
+
resolver.send(:public_keys_are_outdated?) == true
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
assert("ActiveSupport has not been loaded while exercising the library") { !defined?(ActiveSupport) }
|
|
124
|
+
|
|
125
|
+
if $failures.empty?
|
|
126
|
+
puts "The library behaves correctly without ActiveSupport"
|
|
127
|
+
exit 0
|
|
128
|
+
else
|
|
129
|
+
$failures.each { |failure| puts "FAILED: #{failure}" }
|
|
130
|
+
exit 1
|
|
131
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: keycloak-api-rails
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Lorent Lempereur
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-07-30 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
@@ -58,14 +58,14 @@ dependencies:
|
|
|
58
58
|
requirements:
|
|
59
59
|
- - '='
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: 0.9.
|
|
61
|
+
version: 0.9.11
|
|
62
62
|
type: :development
|
|
63
63
|
prerelease: false
|
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
65
|
requirements:
|
|
66
66
|
- - '='
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: 0.9.
|
|
68
|
+
version: 0.9.11
|
|
69
69
|
- !ruby/object:Gem::Dependency
|
|
70
70
|
name: byebug
|
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -109,11 +109,14 @@ files:
|
|
|
109
109
|
- lib/keycloak-api-rails/service.rb
|
|
110
110
|
- lib/keycloak-api-rails/token_error.rb
|
|
111
111
|
- lib/keycloak-api-rails/version.rb
|
|
112
|
+
- spec/keycloak-api-rails/activesupport_free_spec.rb
|
|
112
113
|
- spec/keycloak-api-rails/authentication_spec.rb
|
|
114
|
+
- spec/keycloak-api-rails/configuration_spec.rb
|
|
113
115
|
- spec/keycloak-api-rails/helper_spec.rb
|
|
114
116
|
- spec/keycloak-api-rails/public_key_cached_resolver_spec.rb
|
|
115
117
|
- spec/keycloak-api-rails/service_spec.rb
|
|
116
118
|
- spec/spec_helper.rb
|
|
119
|
+
- spec/support/activesupport_free_probe.rb
|
|
117
120
|
- spec/support/public_key_cached_resolver_stub.rb
|
|
118
121
|
- spec/support/public_key_resolver_stub.rb
|
|
119
122
|
- spec/support/rails_helper.rb
|