doorkeeper-openid_connect 1.10.0 → 1.10.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 +13 -0
- data/README.md +86 -0
- data/app/controllers/doorkeeper/openid_connect/discovery_controller.rb +4 -4
- data/app/controllers/doorkeeper/openid_connect/dynamic_client_registration_controller.rb +1 -1
- data/config/locales/en.yml +1 -0
- data/lib/doorkeeper/oauth/id_token_response.rb +1 -1
- data/lib/doorkeeper/oauth/id_token_token_response.rb +1 -1
- data/lib/doorkeeper/openid_connect/claims_builder.rb +1 -1
- data/lib/doorkeeper/openid_connect/config.rb +1 -1
- data/lib/doorkeeper/openid_connect/helpers/controller.rb +5 -1
- data/lib/doorkeeper/openid_connect/id_token.rb +9 -7
- data/lib/doorkeeper/openid_connect/oauth/authorization/code.rb +1 -1
- data/lib/doorkeeper/openid_connect/orm/active_record/access_grant.rb +4 -4
- data/lib/doorkeeper/openid_connect/orm/active_record.rb +3 -3
- data/lib/doorkeeper/openid_connect/rails/routes/mapping.rb +3 -3
- data/lib/doorkeeper/openid_connect/user_info.rb +1 -1
- data/lib/doorkeeper/openid_connect/version.rb +1 -1
- data/lib/doorkeeper/openid_connect.rb +24 -13
- data/lib/generators/doorkeeper/openid_connect/install_generator.rb +1 -1
- data/lib/generators/doorkeeper/openid_connect/migration_generator.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: f6e40af64a066cdb6b80a91eb5ecb97016c6c4a0695c4a362f72942577b7a1bd
|
|
4
|
+
data.tar.gz: 57999fcd4eba595ca726f41767c301dbd652b76ea039787d9f00fa5177b7aefa
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7a722b6a8cf208f7c9ba6af64c8b4518a20d206d991f81f45d0a5fa21fffead56f6c134c0bb65f1de9e8d0addba5b3db408df02ed10d9a70f55b4d343ee3fb6c
|
|
7
|
+
data.tar.gz: afd99576ba3f10b38b55cd9cb2ed721ebed97a33aba778939c6aabae07ca91a07a2f4531a178716dda14adb2b4641a627c2bf9d38a8fe8b89d65a1e971ecd5c4
|
data/CHANGELOG.md
CHANGED
|
@@ -2,8 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
- Please add here
|
|
4
4
|
|
|
5
|
+
## v1.10.1 (2026-06-03)
|
|
6
|
+
|
|
7
|
+
- [#294] Drop stale `Metrics/ClassLength` and `Metrics/BlockLength` overrides from `.rubocop_todo.yml`
|
|
8
|
+
- [#293] Drop `Naming/VariableNumber` from `.rubocop_todo.yml` and normalise test variable names
|
|
9
|
+
- [#291] Document multi-namespace mount pattern for multiple resource owner models ([#192](https://github.com/doorkeeper-gem/doorkeeper-openid_connect/issues/192))
|
|
10
|
+
- [#292] Drop formatting cops from `.rubocop_todo.yml` and align trailing-comma style with upstream doorkeeper
|
|
11
|
+
- [#296] Fix the `prompt` parameter being rejected with `invalid_request` when it contains leading or duplicate spaces (e.g. `prompt=%20none`) — blank entries in the space-delimited value are now ignored
|
|
12
|
+
- [#299] Raise `InvalidConfiguration` when the `issuer` config resolves to a blank value instead of silently advertising an empty `issuer` in the discovery document. Since v1.10.0 an arity-2 `issuer` block receives `(resource_owner, application)` — both `nil` in the discovery context — so a block relying on the old v1.9.0 request argument could return `nil` and produce a discovery `issuer` that mismatched the ID token `iss` ([#298](https://github.com/doorkeeper-gem/doorkeeper-openid_connect/issues/298))
|
|
13
|
+
|
|
5
14
|
## v1.10.0 (2026-06-01)
|
|
6
15
|
|
|
16
|
+
>[!IMPORTANT]
|
|
17
|
+
>
|
|
18
|
+
>- **Breaking (arity-2 issuer blocks):** `resolve_issuer` now dispatches arity-2 blocks with `(resource_owner, application)` in all contexts, including discovery. In v1.9.0 `DiscoveryController` passed `request` as the first argument; existing arity-2 blocks that relied on this receive `(nil, nil)` in v1.10.0 and should migrate to arity-3 — see [#298](https://github.com/doorkeeper-gem/doorkeeper-openid_connect/issues/298) for details and migration examples
|
|
19
|
+
|
|
7
20
|
- [#241] Fix NameError on doorkeeper master by deferring AR model loading in run_hooks (see [Doorkeeper PR](https://github.com/doorkeeper-gem/doorkeeper/pull/1804))
|
|
8
21
|
- [#242] Fix `NoMethodError` for openid_request in testing environments.
|
|
9
22
|
- [#246] Fix `at_hash` to use correct hash algorithm based on `signing_algorithm`
|
data/README.md
CHANGED
|
@@ -414,6 +414,92 @@ After this, `.well-known/openid-configuration` returns `"jwks_uri": "https://exa
|
|
|
414
414
|
> [!Note]
|
|
415
415
|
> A naive `match "/-/jwks", ..., as: :oauth_discovery_keys` won't work — Rails has refused to reuse a route name [since 4.0](https://github.com/rails/rails/commit/a2b7c0e69d) and raises `ArgumentError: Invalid route name, already in use: 'oauth_discovery_keys'`. The `direct` helper sidesteps this by overriding the URL helper itself rather than re-declaring the route name.
|
|
416
416
|
|
|
417
|
+
#### Mounting under multiple namespaces (multiple resource owner models)
|
|
418
|
+
|
|
419
|
+
If your app authenticates more than one kind of resource owner (e.g. a `User`
|
|
420
|
+
and a `Customer` Devise model) you may want to mount Doorkeeper — and this engine
|
|
421
|
+
— more than once, each under its own namespace:
|
|
422
|
+
|
|
423
|
+
```ruby
|
|
424
|
+
# config/routes.rb
|
|
425
|
+
Rails.application.routes.draw do
|
|
426
|
+
scope :users, as: :users do
|
|
427
|
+
use_doorkeeper { controllers authorizations: "users/authorizations" }
|
|
428
|
+
use_doorkeeper_openid_connect
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
scope :customers, as: :customers do
|
|
432
|
+
use_doorkeeper { controllers authorizations: "customers/authorizations" }
|
|
433
|
+
use_doorkeeper_openid_connect
|
|
434
|
+
end
|
|
435
|
+
end
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
Most of the request flow is model-agnostic: the `resource_owner_authenticator`
|
|
439
|
+
block can dispatch on whichever owner is signed in (`current_user ||
|
|
440
|
+
current_customer`), and claims / userinfo / ID token generation follow from
|
|
441
|
+
whatever it returns.
|
|
442
|
+
|
|
443
|
+
The one piece that needs attention is the **discovery document**.
|
|
444
|
+
[`DiscoveryController#provider_response`](app/controllers/doorkeeper/openid_connect/discovery_controller.rb)
|
|
445
|
+
builds the published endpoints by calling named route helpers
|
|
446
|
+
(`oauth_authorization_url`, `oauth_token_url`, …) directly. The
|
|
447
|
+
[`discovery_url_options`](#configuration) setting (added in #126) lets you
|
|
448
|
+
override the `host` / `protocol` / `port` of those URLs, but not *which* named
|
|
449
|
+
helper is resolved — so under multiple mounts every namespace's discovery
|
|
450
|
+
document would point at the same set of endpoints.
|
|
451
|
+
|
|
452
|
+
The idiomatic fix is to subclass the discovery controller per namespace and
|
|
453
|
+
re-point the helper calls at that namespace's routes:
|
|
454
|
+
|
|
455
|
+
```ruby
|
|
456
|
+
# app/controllers/users/discovery_controller.rb
|
|
457
|
+
module Users
|
|
458
|
+
class DiscoveryController < Doorkeeper::OpenidConnect::DiscoveryController
|
|
459
|
+
private
|
|
460
|
+
|
|
461
|
+
# Re-point each helper used by `provider_response` at the namespaced route.
|
|
462
|
+
def oauth_authorization_url(opts = {})
|
|
463
|
+
users_oauth_authorization_url(opts)
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
def oauth_token_url(opts = {})
|
|
467
|
+
users_oauth_token_url(opts)
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
def oauth_revoke_url(opts = {})
|
|
471
|
+
users_oauth_revoke_url(opts)
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
def oauth_userinfo_url(opts = {})
|
|
475
|
+
users_oauth_userinfo_url(opts)
|
|
476
|
+
end
|
|
477
|
+
|
|
478
|
+
def oauth_discovery_keys_url(opts = {})
|
|
479
|
+
users_oauth_discovery_keys_url(opts)
|
|
480
|
+
end
|
|
481
|
+
|
|
482
|
+
# ...and `oauth_introspect_url` / `oauth_dynamic_client_registration_url`
|
|
483
|
+
# if you advertise those.
|
|
484
|
+
end
|
|
485
|
+
end
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
```ruby
|
|
489
|
+
# config/routes.rb (inside the `:users` scope)
|
|
490
|
+
get "/.well-known/openid-configuration",
|
|
491
|
+
to: "users/discovery#provider", as: :users_openid_connect_config
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
Repeat for the `customers` namespace. Each `.well-known/openid-configuration`
|
|
495
|
+
then advertises the endpoints for its own namespace.
|
|
496
|
+
|
|
497
|
+
> [!Note]
|
|
498
|
+
> See [#192](https://github.com/doorkeeper-gem/doorkeeper-openid_connect/issues/192)
|
|
499
|
+
> for the original discussion. First-class multi-mount support is not provided
|
|
500
|
+
> out of the box; the per-namespace controller override above is the supported
|
|
501
|
+
> extension pattern for now.
|
|
502
|
+
|
|
417
503
|
### Nonces
|
|
418
504
|
|
|
419
505
|
To support clients who send nonces you have to tweak Doorkeeper's authorization view so the parameter is passed on.
|
|
@@ -53,7 +53,7 @@ module Doorkeeper
|
|
|
53
53
|
subject_types_supported: openid_connect.subject_types_supported,
|
|
54
54
|
|
|
55
55
|
id_token_signing_alg_values_supported: [
|
|
56
|
-
::Doorkeeper::OpenidConnect.signing_algorithm
|
|
56
|
+
::Doorkeeper::OpenidConnect.signing_algorithm,
|
|
57
57
|
],
|
|
58
58
|
|
|
59
59
|
claim_types_supported: [
|
|
@@ -93,8 +93,8 @@ module Doorkeeper
|
|
|
93
93
|
{
|
|
94
94
|
rel: WEBFINGER_RELATION,
|
|
95
95
|
href: issuer,
|
|
96
|
-
}
|
|
97
|
-
]
|
|
96
|
+
},
|
|
97
|
+
],
|
|
98
98
|
}
|
|
99
99
|
end
|
|
100
100
|
|
|
@@ -113,7 +113,7 @@ module Doorkeeper
|
|
|
113
113
|
|
|
114
114
|
def discovery_url_default_options
|
|
115
115
|
{
|
|
116
|
-
protocol: protocol
|
|
116
|
+
protocol: protocol,
|
|
117
117
|
}
|
|
118
118
|
end
|
|
119
119
|
|
|
@@ -17,7 +17,7 @@ module Doorkeeper
|
|
|
17
17
|
render json: registration_response(client, registration), status: :created
|
|
18
18
|
rescue ActiveRecord::RecordInvalid => e
|
|
19
19
|
render json: { error: "invalid_client_params", error_description: e.record.errors.full_messages.join(", ") },
|
|
20
|
-
|
|
20
|
+
status: :bad_request
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
private
|
data/config/locales/en.yml
CHANGED
|
@@ -22,4 +22,5 @@ en:
|
|
|
22
22
|
select_account_for_resource_owner_not_configured: 'Failure due to Doorkeeper::OpenidConnect.configure.select_account_for_resource_owner missing configuration.'
|
|
23
23
|
subject_not_configured: 'ID Token generation failed due to Doorkeeper::OpenidConnect.configure.subject missing configuration.'
|
|
24
24
|
signing_key_not_configured: 'Doorkeeper::OpenidConnect.configure.signing_key must resolve to at least one key.'
|
|
25
|
+
issuer_not_configured: 'Doorkeeper::OpenidConnect.configure.issuer must resolve to a non-blank value.'
|
|
25
26
|
dynamic_client_registration_unauthorized: 'Authorization required for client registration'
|
|
@@ -5,7 +5,7 @@ module Doorkeeper
|
|
|
5
5
|
def self.configure(&block)
|
|
6
6
|
if Doorkeeper.configuration.orm != :active_record
|
|
7
7
|
raise Errors::InvalidConfiguration,
|
|
8
|
-
"Doorkeeper OpenID Connect currently only supports the ActiveRecord ORM adapter"
|
|
8
|
+
"Doorkeeper OpenID Connect currently only supports the ActiveRecord ORM adapter"
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
@config = Config::Builder.new(&block).build
|
|
@@ -176,7 +176,11 @@ module Doorkeeper
|
|
|
176
176
|
end
|
|
177
177
|
|
|
178
178
|
def oidc_prompt_values
|
|
179
|
-
|
|
179
|
+
# Reject blank entries so leading/duplicate spaces in the
|
|
180
|
+
# space-delimited `prompt` parameter don't surface as an empty
|
|
181
|
+
# value (which would otherwise be treated as an unknown prompt and
|
|
182
|
+
# rejected with `invalid_request`).
|
|
183
|
+
@oidc_prompt_values ||= params[:prompt].to_s.split(/ +/).reject(&:blank?).uniq
|
|
180
184
|
end
|
|
181
185
|
|
|
182
186
|
# Resolve auth_time for max_age enforcement.
|
|
@@ -26,7 +26,7 @@ module Doorkeeper
|
|
|
26
26
|
exp: expiration,
|
|
27
27
|
iat: issued_at,
|
|
28
28
|
nonce: nonce,
|
|
29
|
-
auth_time: auth_time
|
|
29
|
+
auth_time: auth_time,
|
|
30
30
|
)
|
|
31
31
|
end
|
|
32
32
|
|
|
@@ -36,9 +36,9 @@ module Doorkeeper
|
|
|
36
36
|
|
|
37
37
|
def as_jws_token
|
|
38
38
|
::JWT.encode(as_json,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
Doorkeeper::OpenidConnect.signing_key.keypair,
|
|
40
|
+
Doorkeeper::OpenidConnect.signing_algorithm.to_s,
|
|
41
|
+
{ typ: "JWT", kid: Doorkeeper::OpenidConnect.signing_key.kid }).to_s
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
private
|
|
@@ -46,13 +46,15 @@ module Doorkeeper
|
|
|
46
46
|
def issuer
|
|
47
47
|
Doorkeeper::OpenidConnect.resolve_issuer(
|
|
48
48
|
resource_owner: @resource_owner,
|
|
49
|
-
application: @access_token.application
|
|
49
|
+
application: @access_token.application,
|
|
50
50
|
)
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
def subject
|
|
54
|
-
Doorkeeper::OpenidConnect.configuration.subject.call(
|
|
55
|
-
@
|
|
54
|
+
Doorkeeper::OpenidConnect.configuration.subject.call(
|
|
55
|
+
@resource_owner,
|
|
56
|
+
@access_token.application,
|
|
57
|
+
).to_s
|
|
56
58
|
end
|
|
57
59
|
|
|
58
60
|
def audience
|
|
@@ -6,10 +6,10 @@ module Doorkeeper
|
|
|
6
6
|
def self.prepended(base)
|
|
7
7
|
base.class_eval do
|
|
8
8
|
has_one :openid_request,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
class_name: Doorkeeper::OpenidConnect.configuration.open_id_request_class,
|
|
10
|
+
foreign_key: "access_grant_id",
|
|
11
|
+
inverse_of: :access_grant,
|
|
12
|
+
dependent: :delete
|
|
13
13
|
end
|
|
14
14
|
end
|
|
15
15
|
end
|
|
@@ -11,7 +11,7 @@ module Doorkeeper
|
|
|
11
11
|
module ActiveRecord
|
|
12
12
|
module Mixins
|
|
13
13
|
autoload :OpenidRequest,
|
|
14
|
-
"doorkeeper/openid_connect/orm/active_record/mixins/openid_request"
|
|
14
|
+
"doorkeeper/openid_connect/orm/active_record/mixins/openid_request"
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def run_hooks
|
|
@@ -30,7 +30,7 @@ module Doorkeeper
|
|
|
30
30
|
if Doorkeeper.configuration.respond_to?(:active_record_options) && Doorkeeper.configuration.active_record_options[:establish_connection]
|
|
31
31
|
[Doorkeeper::OpenidConnect.configuration.open_id_request_model].each do |c|
|
|
32
32
|
c.send :establish_connection,
|
|
33
|
-
Doorkeeper.configuration.active_record_options[:establish_connection]
|
|
33
|
+
Doorkeeper.configuration.active_record_options[:establish_connection]
|
|
34
34
|
end
|
|
35
35
|
end
|
|
36
36
|
end
|
|
@@ -51,7 +51,7 @@ Doorkeeper.configuration.active_record_options[:establish_connection]
|
|
|
51
51
|
if Doorkeeper.configuration.active_record_options[:establish_connection]
|
|
52
52
|
[Doorkeeper::OpenidConnect.configuration.open_id_request_model].each do |c|
|
|
53
53
|
c.send :establish_connection,
|
|
54
|
-
Doorkeeper.configuration.active_record_options[:establish_connection]
|
|
54
|
+
Doorkeeper.configuration.active_record_options[:establish_connection]
|
|
55
55
|
end
|
|
56
56
|
end
|
|
57
57
|
end
|
|
@@ -11,13 +11,13 @@ module Doorkeeper
|
|
|
11
11
|
@controllers = {
|
|
12
12
|
userinfo: "doorkeeper/openid_connect/userinfo",
|
|
13
13
|
discovery: "doorkeeper/openid_connect/discovery",
|
|
14
|
-
dynamic_client_registration: "doorkeeper/openid_connect/dynamic_client_registration"
|
|
14
|
+
dynamic_client_registration: "doorkeeper/openid_connect/dynamic_client_registration",
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
@as = {
|
|
18
18
|
userinfo: :userinfo,
|
|
19
19
|
discovery: :discovery,
|
|
20
|
-
dynamic_client_registration: :dynamic_client_registration
|
|
20
|
+
dynamic_client_registration: :dynamic_client_registration,
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
@skips = []
|
|
@@ -26,7 +26,7 @@ module Doorkeeper
|
|
|
26
26
|
def [](routes)
|
|
27
27
|
{
|
|
28
28
|
controllers: @controllers[routes],
|
|
29
|
-
as: @as[routes]
|
|
29
|
+
as: @as[routes],
|
|
30
30
|
}
|
|
31
31
|
end
|
|
32
32
|
|
|
@@ -132,18 +132,29 @@ module Doorkeeper
|
|
|
132
132
|
# @return [String] the issuer string
|
|
133
133
|
def self.resolve_issuer(resource_owner: nil, application: nil, request: nil)
|
|
134
134
|
issuer = configuration.issuer
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
135
|
+
|
|
136
|
+
value =
|
|
137
|
+
if issuer.respond_to?(:call)
|
|
138
|
+
case issuer.arity
|
|
139
|
+
when 0
|
|
140
|
+
issuer.call
|
|
141
|
+
when 1
|
|
142
|
+
issuer.call(request || resource_owner)
|
|
143
|
+
when 2
|
|
144
|
+
issuer.call(resource_owner, application)
|
|
145
|
+
else
|
|
146
|
+
issuer.call(resource_owner, application, request)
|
|
147
|
+
end
|
|
148
|
+
else
|
|
149
|
+
issuer
|
|
150
|
+
end.to_s
|
|
151
|
+
|
|
152
|
+
if value.blank?
|
|
153
|
+
raise Errors::InvalidConfiguration,
|
|
154
|
+
I18n.translate("doorkeeper.openid_connect.errors.messages.issuer_not_configured")
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
value
|
|
147
158
|
end
|
|
148
159
|
|
|
149
160
|
Doorkeeper::GrantFlow.register(
|
|
@@ -161,7 +172,7 @@ module Doorkeeper
|
|
|
161
172
|
)
|
|
162
173
|
|
|
163
174
|
Doorkeeper::GrantFlow.register_alias(
|
|
164
|
-
"implicit_oidc", as: ["implicit", "id_token", "id_token token"]
|
|
175
|
+
"implicit_oidc", as: ["implicit", "id_token", "id_token token"],
|
|
165
176
|
)
|
|
166
177
|
end
|
|
167
178
|
end
|
|
@@ -10,7 +10,7 @@ module Doorkeeper
|
|
|
10
10
|
def install
|
|
11
11
|
template "initializer.rb", "config/initializers/doorkeeper_openid_connect.rb"
|
|
12
12
|
copy_file File.expand_path("../../../../config/locales/en.yml", __dir__),
|
|
13
|
-
"config/locales/doorkeeper_openid_connect.en.yml"
|
|
13
|
+
"config/locales/doorkeeper_openid_connect.en.yml"
|
|
14
14
|
route "use_doorkeeper_openid_connect"
|
|
15
15
|
end
|
|
16
16
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: doorkeeper-openid_connect
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.10.
|
|
4
|
+
version: 1.10.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sam Dengler
|
|
@@ -10,7 +10,7 @@ authors:
|
|
|
10
10
|
autorequire:
|
|
11
11
|
bindir: bin
|
|
12
12
|
cert_chain: []
|
|
13
|
-
date: 2026-06-
|
|
13
|
+
date: 2026-06-03 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: doorkeeper
|