keycloak-api-rails 0.11.2 → 0.12.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/CHANGELOG.md +7 -3
- data/Dockerfile +2 -2
- data/Gemfile.lock +109 -105
- data/README.md +49 -3
- data/keycloak-api-rails.gemspec +3 -3
- data/lib/keycloak-api-rails/authentication.rb +57 -0
- data/lib/keycloak-api-rails/configuration.rb +1 -0
- data/lib/keycloak-api-rails/middleware.rb +1 -1
- data/lib/keycloak-api-rails/service.rb +3 -2
- data/lib/keycloak-api-rails/version.rb +1 -1
- data/lib/keycloak-api-rails.rb +2 -0
- data/spec/keycloak-api-rails/authentication_spec.rb +32 -0
- data/spec/keycloak-api-rails/service_spec.rb +14 -2
- metadata +14 -12
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d0e8e7c47df127347543955ffc2ed362dc9c2efb549bc970f0efdd519f8cfb1a
|
|
4
|
+
data.tar.gz: 5b77f9cf1171a36db3d80c6cd31e0df8f0acb00a58916e9b7a4fdcfdec331ecd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 38edbedbe88b629c6c6728eda1b60670cd9dd6b03f6246c4bfd79bcc6fd3832922c504b91c15f4f4c7e86128e4d143800f5562292cf0f38877e73f0f39f4a8ff
|
|
7
|
+
data.tar.gz: d6e9d6ca5a7d5a531e09e7e2fe63d026bd53f088ceabbb2484e59ab36ac1aee234d949ac30c342f67a2784442dacfb1d502762f35999d977d8175189c19193fa
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,10 @@ 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
|
+
## [0.12.0] - 2023-04-11
|
|
9
|
+
|
|
10
|
+
* Introduce Opt-in mode as an alternative configuration (thanks to @theSteveMitchell)
|
|
11
|
+
|
|
8
12
|
## [0.11.2] - 2022-03-30
|
|
9
13
|
|
|
10
14
|
* Update `Gemfile.lock` to avoid wrong CVE detections. The version of Rails should always be specified by the parent project. This change has no functional impact.
|
|
@@ -16,8 +20,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
16
20
|
|
|
17
21
|
## [0.11.0] - 2019-11-21
|
|
18
22
|
|
|
19
|
-
* Remove dependency to `rest-client` (thanks to
|
|
20
|
-
* Access Authorization Party from ENV (thanks to
|
|
21
|
-
* New configuration option: `ca_certificate_file` (thanks to
|
|
23
|
+
* Remove dependency to `rest-client` (thanks to @loicvigneron)
|
|
24
|
+
* Access Authorization Party from ENV (thanks to @loicvigneron)
|
|
25
|
+
* New configuration option: `ca_certificate_file` (thanks to @loicvigneron)
|
|
22
26
|
* Access the token from ENV
|
|
23
27
|
* Upgrade `json-jwt` to `1.11.0`
|
data/Dockerfile
CHANGED
|
@@ -9,6 +9,6 @@ COPY Gemfile /usr/src/app/
|
|
|
9
9
|
COPY Gemfile.lock /usr/src/app/
|
|
10
10
|
COPY keycloak-api-rails.gemspec /usr/src/app/
|
|
11
11
|
COPY lib/keycloak-api-rails/version.rb /usr/src/app/lib/keycloak-api-rails/
|
|
12
|
-
|
|
12
|
+
RUN bundle install
|
|
13
13
|
COPY . /usr/src/app
|
|
14
|
-
|
|
14
|
+
RUN bundle install
|
data/Gemfile.lock
CHANGED
|
@@ -1,188 +1,192 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
keycloak-api-rails (0.
|
|
4
|
+
keycloak-api-rails (0.12.0)
|
|
5
5
|
json-jwt (>= 1.11.0)
|
|
6
6
|
rails (>= 4.2)
|
|
7
7
|
|
|
8
8
|
GEM
|
|
9
9
|
remote: https://rubygems.org/
|
|
10
10
|
specs:
|
|
11
|
-
actioncable (7.0.
|
|
12
|
-
actionpack (= 7.0.
|
|
13
|
-
activesupport (= 7.0.
|
|
11
|
+
actioncable (7.0.4.3)
|
|
12
|
+
actionpack (= 7.0.4.3)
|
|
13
|
+
activesupport (= 7.0.4.3)
|
|
14
14
|
nio4r (~> 2.0)
|
|
15
15
|
websocket-driver (>= 0.6.1)
|
|
16
|
-
actionmailbox (7.0.
|
|
17
|
-
actionpack (= 7.0.
|
|
18
|
-
activejob (= 7.0.
|
|
19
|
-
activerecord (= 7.0.
|
|
20
|
-
activestorage (= 7.0.
|
|
21
|
-
activesupport (= 7.0.
|
|
16
|
+
actionmailbox (7.0.4.3)
|
|
17
|
+
actionpack (= 7.0.4.3)
|
|
18
|
+
activejob (= 7.0.4.3)
|
|
19
|
+
activerecord (= 7.0.4.3)
|
|
20
|
+
activestorage (= 7.0.4.3)
|
|
21
|
+
activesupport (= 7.0.4.3)
|
|
22
22
|
mail (>= 2.7.1)
|
|
23
23
|
net-imap
|
|
24
24
|
net-pop
|
|
25
25
|
net-smtp
|
|
26
|
-
actionmailer (7.0.
|
|
27
|
-
actionpack (= 7.0.
|
|
28
|
-
actionview (= 7.0.
|
|
29
|
-
activejob (= 7.0.
|
|
30
|
-
activesupport (= 7.0.
|
|
26
|
+
actionmailer (7.0.4.3)
|
|
27
|
+
actionpack (= 7.0.4.3)
|
|
28
|
+
actionview (= 7.0.4.3)
|
|
29
|
+
activejob (= 7.0.4.3)
|
|
30
|
+
activesupport (= 7.0.4.3)
|
|
31
31
|
mail (~> 2.5, >= 2.5.4)
|
|
32
32
|
net-imap
|
|
33
33
|
net-pop
|
|
34
34
|
net-smtp
|
|
35
35
|
rails-dom-testing (~> 2.0)
|
|
36
|
-
actionpack (7.0.
|
|
37
|
-
actionview (= 7.0.
|
|
38
|
-
activesupport (= 7.0.
|
|
36
|
+
actionpack (7.0.4.3)
|
|
37
|
+
actionview (= 7.0.4.3)
|
|
38
|
+
activesupport (= 7.0.4.3)
|
|
39
39
|
rack (~> 2.0, >= 2.2.0)
|
|
40
40
|
rack-test (>= 0.6.3)
|
|
41
41
|
rails-dom-testing (~> 2.0)
|
|
42
42
|
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
|
43
|
-
actiontext (7.0.
|
|
44
|
-
actionpack (= 7.0.
|
|
45
|
-
activerecord (= 7.0.
|
|
46
|
-
activestorage (= 7.0.
|
|
47
|
-
activesupport (= 7.0.
|
|
43
|
+
actiontext (7.0.4.3)
|
|
44
|
+
actionpack (= 7.0.4.3)
|
|
45
|
+
activerecord (= 7.0.4.3)
|
|
46
|
+
activestorage (= 7.0.4.3)
|
|
47
|
+
activesupport (= 7.0.4.3)
|
|
48
48
|
globalid (>= 0.6.0)
|
|
49
49
|
nokogiri (>= 1.8.5)
|
|
50
|
-
actionview (7.0.
|
|
51
|
-
activesupport (= 7.0.
|
|
50
|
+
actionview (7.0.4.3)
|
|
51
|
+
activesupport (= 7.0.4.3)
|
|
52
52
|
builder (~> 3.1)
|
|
53
53
|
erubi (~> 1.4)
|
|
54
54
|
rails-dom-testing (~> 2.0)
|
|
55
55
|
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
|
56
|
-
activejob (7.0.
|
|
57
|
-
activesupport (= 7.0.
|
|
56
|
+
activejob (7.0.4.3)
|
|
57
|
+
activesupport (= 7.0.4.3)
|
|
58
58
|
globalid (>= 0.3.6)
|
|
59
|
-
activemodel (7.0.
|
|
60
|
-
activesupport (= 7.0.
|
|
61
|
-
activerecord (7.0.
|
|
62
|
-
activemodel (= 7.0.
|
|
63
|
-
activesupport (= 7.0.
|
|
64
|
-
activestorage (7.0.
|
|
65
|
-
actionpack (= 7.0.
|
|
66
|
-
activejob (= 7.0.
|
|
67
|
-
activerecord (= 7.0.
|
|
68
|
-
activesupport (= 7.0.
|
|
59
|
+
activemodel (7.0.4.3)
|
|
60
|
+
activesupport (= 7.0.4.3)
|
|
61
|
+
activerecord (7.0.4.3)
|
|
62
|
+
activemodel (= 7.0.4.3)
|
|
63
|
+
activesupport (= 7.0.4.3)
|
|
64
|
+
activestorage (7.0.4.3)
|
|
65
|
+
actionpack (= 7.0.4.3)
|
|
66
|
+
activejob (= 7.0.4.3)
|
|
67
|
+
activerecord (= 7.0.4.3)
|
|
68
|
+
activesupport (= 7.0.4.3)
|
|
69
69
|
marcel (~> 1.0)
|
|
70
70
|
mini_mime (>= 1.1.0)
|
|
71
|
-
activesupport (7.0.
|
|
71
|
+
activesupport (7.0.4.3)
|
|
72
72
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
73
73
|
i18n (>= 1.6, < 2)
|
|
74
74
|
minitest (>= 5.1)
|
|
75
75
|
tzinfo (~> 2.0)
|
|
76
76
|
aes_key_wrap (1.1.0)
|
|
77
|
-
bindata (2.4.
|
|
77
|
+
bindata (2.4.15)
|
|
78
78
|
builder (3.2.4)
|
|
79
|
-
byebug (
|
|
80
|
-
concurrent-ruby (1.
|
|
79
|
+
byebug (11.1.3)
|
|
80
|
+
concurrent-ruby (1.2.2)
|
|
81
81
|
crass (1.0.6)
|
|
82
|
+
date (3.3.3)
|
|
82
83
|
diff-lcs (1.5.0)
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
erubi (1.12.0)
|
|
85
|
+
faraday (2.7.4)
|
|
86
|
+
faraday-net_http (>= 2.0, < 3.1)
|
|
87
|
+
ruby2_keywords (>= 0.0.4)
|
|
88
|
+
faraday-follow_redirects (0.3.0)
|
|
89
|
+
faraday (>= 1, < 3)
|
|
90
|
+
faraday-net_http (3.0.2)
|
|
91
|
+
globalid (1.1.0)
|
|
86
92
|
activesupport (>= 5.0)
|
|
87
|
-
i18n (1.
|
|
93
|
+
i18n (1.12.0)
|
|
88
94
|
concurrent-ruby (~> 1.0)
|
|
89
|
-
|
|
90
|
-
json-jwt (1.13.0)
|
|
95
|
+
json-jwt (1.16.3)
|
|
91
96
|
activesupport (>= 4.2)
|
|
92
97
|
aes_key_wrap
|
|
93
98
|
bindata
|
|
94
|
-
|
|
99
|
+
faraday (~> 2.0)
|
|
100
|
+
faraday-follow_redirects
|
|
101
|
+
loofah (2.20.0)
|
|
95
102
|
crass (~> 1.0.2)
|
|
96
103
|
nokogiri (>= 1.5.9)
|
|
97
|
-
mail (2.
|
|
104
|
+
mail (2.8.1)
|
|
98
105
|
mini_mime (>= 0.1.1)
|
|
106
|
+
net-imap
|
|
107
|
+
net-pop
|
|
108
|
+
net-smtp
|
|
99
109
|
marcel (1.0.2)
|
|
100
110
|
method_source (1.0.0)
|
|
101
111
|
mini_mime (1.1.2)
|
|
102
|
-
mini_portile2 (2.8.
|
|
103
|
-
minitest (5.
|
|
104
|
-
net-imap (0.
|
|
105
|
-
|
|
112
|
+
mini_portile2 (2.8.1)
|
|
113
|
+
minitest (5.18.0)
|
|
114
|
+
net-imap (0.3.4)
|
|
115
|
+
date
|
|
106
116
|
net-protocol
|
|
107
|
-
|
|
108
|
-
net-pop (0.1.1)
|
|
109
|
-
digest
|
|
117
|
+
net-pop (0.1.2)
|
|
110
118
|
net-protocol
|
|
119
|
+
net-protocol (0.2.1)
|
|
111
120
|
timeout
|
|
112
|
-
net-
|
|
113
|
-
io-wait
|
|
114
|
-
timeout
|
|
115
|
-
net-smtp (0.3.1)
|
|
116
|
-
digest
|
|
121
|
+
net-smtp (0.3.3)
|
|
117
122
|
net-protocol
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
nokogiri (1.13.3)
|
|
123
|
+
nio4r (2.5.9)
|
|
124
|
+
nokogiri (1.14.3)
|
|
121
125
|
mini_portile2 (~> 2.8.0)
|
|
122
126
|
racc (~> 1.4)
|
|
123
|
-
racc (1.6.
|
|
124
|
-
rack (2.2.
|
|
125
|
-
rack-test (
|
|
126
|
-
rack (>= 1.
|
|
127
|
-
rails (7.0.
|
|
128
|
-
actioncable (= 7.0.
|
|
129
|
-
actionmailbox (= 7.0.
|
|
130
|
-
actionmailer (= 7.0.
|
|
131
|
-
actionpack (= 7.0.
|
|
132
|
-
actiontext (= 7.0.
|
|
133
|
-
actionview (= 7.0.
|
|
134
|
-
activejob (= 7.0.
|
|
135
|
-
activemodel (= 7.0.
|
|
136
|
-
activerecord (= 7.0.
|
|
137
|
-
activestorage (= 7.0.
|
|
138
|
-
activesupport (= 7.0.
|
|
127
|
+
racc (1.6.2)
|
|
128
|
+
rack (2.2.6.4)
|
|
129
|
+
rack-test (2.1.0)
|
|
130
|
+
rack (>= 1.3)
|
|
131
|
+
rails (7.0.4.3)
|
|
132
|
+
actioncable (= 7.0.4.3)
|
|
133
|
+
actionmailbox (= 7.0.4.3)
|
|
134
|
+
actionmailer (= 7.0.4.3)
|
|
135
|
+
actionpack (= 7.0.4.3)
|
|
136
|
+
actiontext (= 7.0.4.3)
|
|
137
|
+
actionview (= 7.0.4.3)
|
|
138
|
+
activejob (= 7.0.4.3)
|
|
139
|
+
activemodel (= 7.0.4.3)
|
|
140
|
+
activerecord (= 7.0.4.3)
|
|
141
|
+
activestorage (= 7.0.4.3)
|
|
142
|
+
activesupport (= 7.0.4.3)
|
|
139
143
|
bundler (>= 1.15.0)
|
|
140
|
-
railties (= 7.0.
|
|
144
|
+
railties (= 7.0.4.3)
|
|
141
145
|
rails-dom-testing (2.0.3)
|
|
142
146
|
activesupport (>= 4.2.0)
|
|
143
147
|
nokogiri (>= 1.6)
|
|
144
|
-
rails-html-sanitizer (1.
|
|
145
|
-
loofah (~> 2.
|
|
146
|
-
railties (7.0.
|
|
147
|
-
actionpack (= 7.0.
|
|
148
|
-
activesupport (= 7.0.
|
|
148
|
+
rails-html-sanitizer (1.5.0)
|
|
149
|
+
loofah (~> 2.19, >= 2.19.1)
|
|
150
|
+
railties (7.0.4.3)
|
|
151
|
+
actionpack (= 7.0.4.3)
|
|
152
|
+
activesupport (= 7.0.4.3)
|
|
149
153
|
method_source
|
|
150
154
|
rake (>= 12.2)
|
|
151
155
|
thor (~> 1.0)
|
|
152
156
|
zeitwerk (~> 2.5)
|
|
153
157
|
rake (13.0.6)
|
|
154
|
-
rspec (3.
|
|
155
|
-
rspec-core (~> 3.
|
|
156
|
-
rspec-expectations (~> 3.
|
|
157
|
-
rspec-mocks (~> 3.
|
|
158
|
-
rspec-core (3.
|
|
159
|
-
rspec-support (~> 3.
|
|
160
|
-
rspec-expectations (3.
|
|
158
|
+
rspec (3.12.0)
|
|
159
|
+
rspec-core (~> 3.12.0)
|
|
160
|
+
rspec-expectations (~> 3.12.0)
|
|
161
|
+
rspec-mocks (~> 3.12.0)
|
|
162
|
+
rspec-core (3.12.1)
|
|
163
|
+
rspec-support (~> 3.12.0)
|
|
164
|
+
rspec-expectations (3.12.2)
|
|
161
165
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
162
|
-
rspec-support (~> 3.
|
|
163
|
-
rspec-mocks (3.
|
|
166
|
+
rspec-support (~> 3.12.0)
|
|
167
|
+
rspec-mocks (3.12.5)
|
|
164
168
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
165
|
-
rspec-support (~> 3.
|
|
166
|
-
rspec-support (3.
|
|
167
|
-
|
|
169
|
+
rspec-support (~> 3.12.0)
|
|
170
|
+
rspec-support (3.12.0)
|
|
171
|
+
ruby2_keywords (0.0.5)
|
|
168
172
|
thor (1.2.1)
|
|
169
|
-
timecop (0.9.
|
|
170
|
-
timeout (0.2
|
|
171
|
-
tzinfo (2.0.
|
|
173
|
+
timecop (0.9.6)
|
|
174
|
+
timeout (0.3.2)
|
|
175
|
+
tzinfo (2.0.6)
|
|
172
176
|
concurrent-ruby (~> 1.0)
|
|
173
177
|
websocket-driver (0.7.5)
|
|
174
178
|
websocket-extensions (>= 0.1.0)
|
|
175
179
|
websocket-extensions (0.1.5)
|
|
176
|
-
zeitwerk (2.
|
|
180
|
+
zeitwerk (2.6.7)
|
|
177
181
|
|
|
178
182
|
PLATFORMS
|
|
179
183
|
ruby
|
|
180
184
|
|
|
181
185
|
DEPENDENCIES
|
|
182
|
-
byebug (=
|
|
186
|
+
byebug (= 11.1.3)
|
|
183
187
|
keycloak-api-rails!
|
|
184
|
-
rspec (= 3.
|
|
185
|
-
timecop (= 0.9.
|
|
188
|
+
rspec (= 3.12.0)
|
|
189
|
+
timecop (= 0.9.6)
|
|
186
190
|
|
|
187
191
|
BUNDLED WITH
|
|
188
192
|
2.1.4
|
data/README.md
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
# Keycloak-Rails-Api
|
|
2
2
|
|
|
3
|
-
This gem
|
|
3
|
+
This gem validates Keycloak JWT token for Ruby On Rails APIs.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
7
7
|
```ruby
|
|
8
|
-
gem "keycloak-api-rails", "0.
|
|
8
|
+
gem "keycloak-api-rails", "0.12.0"
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
## Token validation
|
|
12
12
|
|
|
13
|
-
Tokens
|
|
13
|
+
Tokens sent (through query strings or Authorization headers) are validated against a Keycloak public key. This public key is downloaded every day by default (this interval can be changed through `public_key_cache_ttl`).
|
|
14
14
|
|
|
15
15
|
## Pass token to the API
|
|
16
16
|
|
|
@@ -21,6 +21,20 @@ Tokens send (through query strings or Authorization headers) to this Railtie Mid
|
|
|
21
21
|
|
|
22
22
|
_If both method are used at the same time, The query string as a higher priority when reading given tokens._
|
|
23
23
|
|
|
24
|
+
## Opt-in vs. Opt-out validation
|
|
25
|
+
|
|
26
|
+
By default, Keycloak-api-rails installs as a Rack Middleware. It processes all requests before any application logic. URIs/Paths can be excluded (opted-out) from this validation using the 'skip_paths' config option
|
|
27
|
+
|
|
28
|
+
Alternatively, it can be configured to `opt-in` to validation. In this case, no Rack middleware is used, and controllers can request (opt-in) by including the module `Keycloak::authentication` and calling `keycloak_authenticate`, for example in a `before_action`, like so:
|
|
29
|
+
|
|
30
|
+
```ruby
|
|
31
|
+
class MyApiController < ActionController::Base
|
|
32
|
+
include Keycloak::Authentication
|
|
33
|
+
|
|
34
|
+
before_action :keycloak_authenticate
|
|
35
|
+
end
|
|
36
|
+
```
|
|
37
|
+
|
|
24
38
|
## When a token is validated
|
|
25
39
|
|
|
26
40
|
In Rails controller, the request `env` variables has two more properties:
|
|
@@ -39,6 +53,7 @@ All options have a default value. However, all of them can be changed in your in
|
|
|
39
53
|
| `realm_id` | `nil`| String | Required | Realm's name (not id, actually) | `master` |
|
|
40
54
|
| `logger` | `Logger.new(STDOUT)`| Logger | Optional | The logger used by `keycloak-api-rails` | `Rails.logger` |
|
|
41
55
|
| `skip_paths` | `{}`| Hash of methods and paths regexp | Optional | Paths whose the token must not be validatefd | `{ get: [/^\/health\/.+/] }`|
|
|
56
|
+
| `opt_in` | `false` | Boolean | Optional | When true, All requests will be validated (excluding requests matching `skip_paths`). When false, validation must be explicitly requested | `true`
|
|
42
57
|
| `token_expiration_tolerance_in_seconds` | `10`| Logger | Optional | Number of seconds a token can expire before being rejected by the API. | `15` |
|
|
43
58
|
| `public_key_cache_ttl` | `86400`| Integer | Optional | Amount of time, in seconds, specifying maximum interval between two requests to {project_name} to retrieve new public keys. It is 86400 seconds (1 day) by default. At least once per this configured interval (1 day by default) will be new public key always downloaded. | `Rails.logger` |
|
|
44
59
|
| `custom_attributes` | `[]`| Array Of String | Optional | List of token attributes to read from each token and to add to their http request env | `["originalFirstName", "originalLastName"]` |
|
|
@@ -59,6 +74,19 @@ Keycloak.configure do |config|
|
|
|
59
74
|
end
|
|
60
75
|
```
|
|
61
76
|
|
|
77
|
+
Or using opt-in configuration:
|
|
78
|
+
|
|
79
|
+
```ruby
|
|
80
|
+
Keycloak.configure do |config|
|
|
81
|
+
config.server_url = ENV["KEYCLOAK_SERVER_URL"]
|
|
82
|
+
config.realm_id = ENV["KEYCLOAK_REALM_ID"]
|
|
83
|
+
config.logger = Rails.logger
|
|
84
|
+
config.opt_in = true
|
|
85
|
+
end
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
When using `opt-in` is true, `skip_paths` is not used.
|
|
89
|
+
|
|
62
90
|
## Use cases
|
|
63
91
|
|
|
64
92
|
Once this gem is configured in your Rails project, you can read, validate and use tokens in your controllers.
|
|
@@ -77,6 +105,24 @@ class AuthenticatedController < ApplicationController
|
|
|
77
105
|
end
|
|
78
106
|
```
|
|
79
107
|
|
|
108
|
+
Or if using opt-in mode, the controller can request validation conditionally:
|
|
109
|
+
```ruby
|
|
110
|
+
class MostlyAuthenticatedController < ApplicationController
|
|
111
|
+
include Keycloak::Authentication
|
|
112
|
+
|
|
113
|
+
before_action :keycloak_authenticate, only: show
|
|
114
|
+
|
|
115
|
+
def show
|
|
116
|
+
keycloak_id = Keycloak::Helper.current_user_id(request.env)
|
|
117
|
+
User.active.find_by(keycloak_id: keycloak_id)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def index
|
|
121
|
+
# unauthenticated
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
```
|
|
125
|
+
|
|
80
126
|
### Roles
|
|
81
127
|
|
|
82
128
|
`Keycloak::Helper.current_user_roles` can be use against a Rails request to read user's roles.
|
data/keycloak-api-rails.gemspec
CHANGED
|
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
|
|
|
18
18
|
spec.add_dependency "rails", ">= 4.2"
|
|
19
19
|
spec.add_dependency "json-jwt", ">= 1.11.0"
|
|
20
20
|
|
|
21
|
-
spec.add_development_dependency "rspec", "3.
|
|
22
|
-
spec.add_development_dependency "timecop", "0.9.
|
|
23
|
-
spec.add_development_dependency "byebug", "
|
|
21
|
+
spec.add_development_dependency "rspec", "3.12.0"
|
|
22
|
+
spec.add_development_dependency "timecop", "0.9.6"
|
|
23
|
+
spec.add_development_dependency "byebug", "11.1.3"
|
|
24
24
|
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
module Keycloak
|
|
2
|
+
module Authentication
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
included do
|
|
6
|
+
if respond_to?(:helper_method)
|
|
7
|
+
helper_method :keycloak_authenticate
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
protected
|
|
12
|
+
|
|
13
|
+
def keycloak_authenticate
|
|
14
|
+
|
|
15
|
+
env = request.env
|
|
16
|
+
method = env["REQUEST_METHOD"]
|
|
17
|
+
path = env["PATH_INFO"]
|
|
18
|
+
uri = env["REQUEST_URI"]
|
|
19
|
+
|
|
20
|
+
logger.debug("Start authentication for #{method} : #{path}")
|
|
21
|
+
token = service.read_token(uri, env)
|
|
22
|
+
decoded_token = service.decode_and_verify(token)
|
|
23
|
+
authentication_succeeded(env, decoded_token)
|
|
24
|
+
|
|
25
|
+
rescue TokenError => e
|
|
26
|
+
authentication_failed(e.message)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def authentication_failed(message)
|
|
30
|
+
logger.info(message)
|
|
31
|
+
[401, {"Content-Type" => "application/json"}, [ { error: message }.to_json]]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def authentication_succeeded(env, decoded_token)
|
|
35
|
+
Helper.assign_current_user_id(env, decoded_token)
|
|
36
|
+
Helper.assign_current_authorized_party(env, decoded_token)
|
|
37
|
+
Helper.assign_current_user_email(env, decoded_token)
|
|
38
|
+
Helper.assign_current_user_locale(env, decoded_token)
|
|
39
|
+
Helper.assign_current_user_custom_attributes(env, decoded_token, config.custom_attributes)
|
|
40
|
+
Helper.assign_realm_roles(env, decoded_token)
|
|
41
|
+
Helper.assign_resource_roles(env, decoded_token)
|
|
42
|
+
Helper.assign_keycloak_token(env, decoded_token)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def service
|
|
46
|
+
Keycloak.service
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def logger
|
|
50
|
+
Keycloak.logger
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def config
|
|
54
|
+
Keycloak.config
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -10,7 +10,7 @@ module Keycloak
|
|
|
10
10
|
path = env["PATH_INFO"]
|
|
11
11
|
uri = env["REQUEST_URI"]
|
|
12
12
|
|
|
13
|
-
if service.
|
|
13
|
+
if service.need_middleware_authentication?(method, path, env)
|
|
14
14
|
logger.debug("Start authentication for #{method} : #{path}")
|
|
15
15
|
token = service.read_token(uri, env)
|
|
16
16
|
decoded_token = service.decode_and_verify(token)
|
|
@@ -4,6 +4,7 @@ module Keycloak
|
|
|
4
4
|
def initialize(key_resolver)
|
|
5
5
|
@key_resolver = key_resolver
|
|
6
6
|
@skip_paths = Keycloak.config.skip_paths
|
|
7
|
+
@opt_in = Keycloak.config.opt_in
|
|
7
8
|
@logger = Keycloak.config.logger
|
|
8
9
|
@token_expiration_tolerance_in_seconds = Keycloak.config.token_expiration_tolerance_in_seconds
|
|
9
10
|
end
|
|
@@ -34,8 +35,8 @@ module Keycloak
|
|
|
34
35
|
Helper.read_token_from_query_string(uri) || Helper.read_token_from_headers(headers)
|
|
35
36
|
end
|
|
36
37
|
|
|
37
|
-
def
|
|
38
|
-
!
|
|
38
|
+
def need_middleware_authentication?(method, path, headers)
|
|
39
|
+
!is_preflight?(method, headers) && (!@opt_in && !should_skip?(method, path))
|
|
39
40
|
end
|
|
40
41
|
|
|
41
42
|
private
|
data/lib/keycloak-api-rails.rb
CHANGED
|
@@ -4,6 +4,7 @@ require "uri"
|
|
|
4
4
|
require "date"
|
|
5
5
|
require "net/http"
|
|
6
6
|
|
|
7
|
+
require_relative "keycloak-api-rails/authentication"
|
|
7
8
|
require_relative "keycloak-api-rails/configuration"
|
|
8
9
|
require_relative "keycloak-api-rails/http_client"
|
|
9
10
|
require_relative "keycloak-api-rails/token_error"
|
|
@@ -46,6 +47,7 @@ module Keycloak
|
|
|
46
47
|
config.realm_id = nil
|
|
47
48
|
config.logger = ::Logger.new(STDOUT)
|
|
48
49
|
config.skip_paths = {}
|
|
50
|
+
config.opt_in = false
|
|
49
51
|
config.token_expiration_tolerance_in_seconds = 10
|
|
50
52
|
config.public_key_cache_ttl = 86400
|
|
51
53
|
config.custom_attributes = []
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe Keycloak::Authentication do
|
|
4
|
+
class ExampleController < ActionController::Base
|
|
5
|
+
include Keycloak::Authentication
|
|
6
|
+
# Mark protected methods public so they may be called in tests
|
|
7
|
+
public(*Keycloak::Authentication.protected_instance_methods)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
let(:controller) { ExampleController.new }
|
|
11
|
+
let(:token) { 'keycloak_valid_token'}
|
|
12
|
+
let(:headers) do
|
|
13
|
+
{
|
|
14
|
+
'REQUEST_METHOD' => :get,
|
|
15
|
+
'REQUEST_URI' => 'http://www.an-url.io',
|
|
16
|
+
'HTTP_AUTHORIZATION' => "Bearer #{token}"
|
|
17
|
+
}
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe "#keycloak_authenticate" do
|
|
21
|
+
before do
|
|
22
|
+
# Mock request object because we aren't using real request spec
|
|
23
|
+
allow(controller).to receive(:request).and_return(double("request", env: headers ))
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "it authenticates with request header" do
|
|
27
|
+
expect_any_instance_of(Keycloak::Service).to receive(:decode_and_verify).with(token).and_return("A User")
|
|
28
|
+
expect(controller).to receive(:authentication_succeeded)
|
|
29
|
+
controller.keycloak_authenticate
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -103,7 +103,7 @@ RSpec.describe Keycloak::Service do
|
|
|
103
103
|
end
|
|
104
104
|
end
|
|
105
105
|
|
|
106
|
-
describe "#
|
|
106
|
+
describe "#need_middleware_authentication?" do
|
|
107
107
|
|
|
108
108
|
let(:method) { nil }
|
|
109
109
|
let(:path) { nil }
|
|
@@ -115,7 +115,7 @@ RSpec.describe Keycloak::Service do
|
|
|
115
115
|
post: [/^\/skip/],
|
|
116
116
|
get: [/^\/skip/]
|
|
117
117
|
}
|
|
118
|
-
@result = service.
|
|
118
|
+
@result = service.need_middleware_authentication?(method, path, headers)
|
|
119
119
|
end
|
|
120
120
|
|
|
121
121
|
context "when method is nil" do
|
|
@@ -175,6 +175,18 @@ RSpec.describe Keycloak::Service do
|
|
|
175
175
|
expect(@result).to be false
|
|
176
176
|
end
|
|
177
177
|
end
|
|
178
|
+
|
|
179
|
+
context "when configured as opt_in" do
|
|
180
|
+
before do
|
|
181
|
+
Keycloak.config.opt_in = true
|
|
182
|
+
service2 = Keycloak::Service.new(key_resolver)
|
|
183
|
+
@result = service2.need_middleware_authentication?(method, path, headers)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
it "should return false" do
|
|
187
|
+
expect(@result).to be false
|
|
188
|
+
end
|
|
189
|
+
end
|
|
178
190
|
end
|
|
179
191
|
|
|
180
192
|
describe "#read_token" do
|
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: 0.
|
|
4
|
+
version: 0.12.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Lorent Lempereur
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2023-04-11 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
@@ -44,42 +44,42 @@ dependencies:
|
|
|
44
44
|
requirements:
|
|
45
45
|
- - '='
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: 3.
|
|
47
|
+
version: 3.12.0
|
|
48
48
|
type: :development
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
52
|
- - '='
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: 3.
|
|
54
|
+
version: 3.12.0
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
56
|
name: timecop
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
58
58
|
requirements:
|
|
59
59
|
- - '='
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: 0.9.
|
|
61
|
+
version: 0.9.6
|
|
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.6
|
|
69
69
|
- !ruby/object:Gem::Dependency
|
|
70
70
|
name: byebug
|
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
|
72
72
|
requirements:
|
|
73
73
|
- - '='
|
|
74
74
|
- !ruby/object:Gem::Version
|
|
75
|
-
version:
|
|
75
|
+
version: 11.1.3
|
|
76
76
|
type: :development
|
|
77
77
|
prerelease: false
|
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
79
|
requirements:
|
|
80
80
|
- - '='
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
|
-
version:
|
|
82
|
+
version: 11.1.3
|
|
83
83
|
description: Rails middleware that validates Authorization token emitted by Keycloak
|
|
84
84
|
email:
|
|
85
85
|
- lorent.lempereur.dev@gmail.com
|
|
@@ -97,6 +97,7 @@ files:
|
|
|
97
97
|
- README.md
|
|
98
98
|
- keycloak-api-rails.gemspec
|
|
99
99
|
- lib/keycloak-api-rails.rb
|
|
100
|
+
- lib/keycloak-api-rails/authentication.rb
|
|
100
101
|
- lib/keycloak-api-rails/configuration.rb
|
|
101
102
|
- lib/keycloak-api-rails/helper.rb
|
|
102
103
|
- lib/keycloak-api-rails/http_client.rb
|
|
@@ -107,6 +108,7 @@ files:
|
|
|
107
108
|
- lib/keycloak-api-rails/service.rb
|
|
108
109
|
- lib/keycloak-api-rails/token_error.rb
|
|
109
110
|
- lib/keycloak-api-rails/version.rb
|
|
111
|
+
- spec/keycloak-api-rails/authentication_spec.rb
|
|
110
112
|
- spec/keycloak-api-rails/helper_spec.rb
|
|
111
113
|
- spec/keycloak-api-rails/public_key_cached_resolver_spec.rb
|
|
112
114
|
- spec/keycloak-api-rails/service_spec.rb
|
|
@@ -118,7 +120,7 @@ homepage: https://github.com/looorent/keycloak-api-rails
|
|
|
118
120
|
licenses:
|
|
119
121
|
- MIT
|
|
120
122
|
metadata: {}
|
|
121
|
-
post_install_message:
|
|
123
|
+
post_install_message:
|
|
122
124
|
rdoc_options: []
|
|
123
125
|
require_paths:
|
|
124
126
|
- lib
|
|
@@ -133,8 +135,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
133
135
|
- !ruby/object:Gem::Version
|
|
134
136
|
version: '0'
|
|
135
137
|
requirements: []
|
|
136
|
-
rubygems_version: 3.
|
|
137
|
-
signing_key:
|
|
138
|
+
rubygems_version: 3.0.3.1
|
|
139
|
+
signing_key:
|
|
138
140
|
specification_version: 4
|
|
139
141
|
summary: Rails middleware that validates Authorization token emitted by Keycloak
|
|
140
142
|
test_files: []
|