@@ -12,7 +12,8 @@ def initialize(
12
12
jwt : JWT ,
13
13
http : Net ::HTTP , # check that this is needed
14
14
json : JSON ,
15
- cache : Rails . cache
15
+ cache : Rails . cache ,
16
+ oidc_discovery_configuration : ::OpenIDConnect ::Discovery ::Provider ::Config
16
17
)
17
18
@authenticator = authenticator
18
19
@logger = logger
@@ -21,6 +22,7 @@ def initialize(
21
22
@json = json
22
23
@http = http
23
24
@cache = cache
25
+ @oidc_discovery_configuration = oidc_discovery_configuration
24
26
end
25
27
26
28
def callback ( parameters :, request_body :)
@@ -53,14 +55,32 @@ def callback(parameters:, request_body:)
53
55
hash [ :aud ] = @authenticator . audience
54
56
hash [ :verify_aud ] = true
55
57
end
56
- hash [ :jwks ] = jwk_loader
58
+ hash [ :jwks ] = jwk_loader ( @authenticator . jwks_uri )
57
59
elsif @authenticator . public_keys . present?
58
60
hash [ :iss ] = @authenticator . issuer
59
61
hash [ :verify_iss ] = true
60
62
# Looks like loading from the public key is really just injesting
61
63
# a JWKS endpoint from a local source.
62
64
keys = @json . parse ( @authenticator . public_keys ) &.deep_symbolize_keys
63
65
hash [ :jwks ] = keys [ :value ]
66
+ elsif @authenticator . provider_uri . present?
67
+ begin
68
+ if @authenticator . issuer . present?
69
+ hash [ :iss ] = @authenticator . issuer
70
+ hash [ :verify_iss ] = true
71
+ end
72
+ if @authenticator . audience . present?
73
+ hash [ :aud ] = @authenticator . audience
74
+ hash [ :verify_aud ] = true
75
+ end
76
+ hash [ :jwks ] = jwk_loader (
77
+ @oidc_discovery_configuration . discover! (
78
+ @authenticator . provider_uri
79
+ ) &.jwks_uri
80
+ )
81
+ rescue Exception => e
82
+ raise Errors ::Authentication ::OAuth ::ProviderDiscoveryFailed . new ( @authenticator . provider_uri , e . inspect )
83
+ end
64
84
else
65
85
raise Errors ::Authentication ::AuthnJwt ::InvalidSigningKeySettings ,
66
86
'Failed to find a JWT decode option. Either `jwks-uri` or `public-keys` variable must be set.'
@@ -92,9 +112,9 @@ def callback(parameters:, request_body:)
92
112
# Looks like only the "malformed JWT" decode error has a unique custom exception
93
113
if e . message == 'Not enough or too many segments'
94
114
raise Errors ::Authentication ::Jwt ::RequestBodyMissingJWTToken
95
- else
96
- raise Errors ::Authentication ::Jwt ::TokenDecodeFailed , e . inspect
97
115
end
116
+
117
+ raise Errors ::Authentication ::Jwt ::TokenDecodeFailed , e . inspect
98
118
rescue => e
99
119
raise Errors ::Authentication ::Jwt ::TokenVerificationFailed , e . inspect
100
120
end
@@ -115,14 +135,14 @@ def callback(parameters:, request_body:)
115
135
116
136
private
117
137
118
- def jwk_loader
138
+ def jwk_loader ( jwks_url )
119
139
-> ( options ) do
120
- jwks ( force : options [ :invalidate ] ) || { }
140
+ jwks ( jwks_url : jwks_url , force : options [ :invalidate ] ) || { }
121
141
end
122
142
end
123
143
124
- def fetch_jwks
125
- uri = URI ( @authenticator . jwks_uri )
144
+ def fetch_jwks ( url )
145
+ uri = URI ( url )
126
146
http = @http . new ( uri . host , uri . port )
127
147
if uri . instance_of? ( URI ::HTTPS )
128
148
# Enable SSL support
@@ -140,11 +160,13 @@ def fetch_jwks
140
160
http . cert_store = store
141
161
end
142
162
163
+ # If path is an empty string, the get request will fail. We set it default to a slash.
164
+ path = uri . path . empty? ? '/' : uri . path
143
165
begin
144
- response = http . request ( @http ::Get . new ( uri . path ) )
166
+ response = http . request ( @http ::Get . new ( path ) )
145
167
rescue Exception => e
146
168
raise Errors ::Authentication ::AuthnJwt ::FetchJwksKeysFailed . new (
147
- @authenticator . jwks_uri ,
169
+ url ,
148
170
e . inspect
149
171
)
150
172
end
@@ -154,14 +176,14 @@ def fetch_jwks
154
176
@json . parse ( response . body )
155
177
end
156
178
157
- def jwks ( force : false )
179
+ def jwks ( jwks_url : , force : false )
158
180
# TODO: Need a mechanism to allow us to expire cache from Cucumber tests
159
181
# so that we can include tests with different JWKS certificates.
160
182
#
161
183
# @cache.fetch(@cache_key, force: force, skip_nil: true) do
162
- # fetch_jwks
184
+ # fetch_jwks(jwks_url)
163
185
# end&.deep_symbolize_keys
164
- fetch_jwks &.deep_symbolize_keys
186
+ fetch_jwks ( jwks_url ) &.deep_symbolize_keys
165
187
end
166
188
end
167
189
end
0 commit comments