standard_id 0.49.0 → 0.49.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
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8b5e02f9651266077753a98125e3772a99bd2cf935da68d17f98df4bfd59505e
|
|
4
|
+
data.tar.gz: e703964c3b6c2c0ffd10a5475f370c9dea0f6f4873fd6827606ee9869a12726d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4091588b0c3b2cc3f06c25682e840cb2a1293a94d67abaf25eb81cce6331fe7a8325aea577fd69ceb5405c09dd0aa39fc0e70ed17df493a92da566fd8da10343
|
|
7
|
+
data.tar.gz: a10b76363a599b3c5fc29681665f8a20d564476cb6682a32c8555f4e2464945f41e0ccfcc7897db8c65df57483f8be3b927294282121d47bbc3226564e3dc0b2
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.49.1] - 2026-10-20
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **Dynamic registration refuses non-https redirect URIs** (`invalid_redirect_uri`): https, or http only on a loopback host (RFC 8252 §7.3), and at most 10 entries — the rules every consumer's own registration operation enforced and the gem's model (which also serves operator-registered clients) does not. Applies to RFC 7592 updates too.
|
|
15
|
+
- **A refused registration no longer leaves an owner row behind**: the `dynamic_registration_owner` callable now runs inside the registration transaction, so a host creating a per-registration owner record gets it rolled back when the client is invalid.
|
|
16
|
+
- **`StandardId::ResourceServer`'s scope check defers to the auth layer**: with no session (the action skipped `verify_access_token!`, e.g. a 405 responder) it no longer raises `NotAuthenticatedError` itself, matching `AudienceVerification`.
|
|
17
|
+
|
|
10
18
|
## [0.49.0] - 2026-10-20
|
|
11
19
|
|
|
12
20
|
### Added
|
|
@@ -81,8 +81,12 @@ module StandardId
|
|
|
81
81
|
raise(StandardId::ConfigurationError, "#{self.class.name} includes StandardId::ResourceServer but never called protected_resource")
|
|
82
82
|
end
|
|
83
83
|
|
|
84
|
+
# Like verify_audience!: without a session there is nothing to check, and
|
|
85
|
+
# either the auth layer is answering the 401 or the action skipped
|
|
86
|
+
# verify_access_token! on purpose (a 405 responder, say).
|
|
84
87
|
def verify_protected_resource_scopes!
|
|
85
88
|
return if _protected_resource_scopes.empty?
|
|
89
|
+
return unless current_session
|
|
86
90
|
|
|
87
91
|
require_scopes!(*_protected_resource_scopes)
|
|
88
92
|
end
|
|
@@ -37,6 +37,8 @@ module StandardId
|
|
|
37
37
|
# Keys `config.oauth.dynamic_registration_attributes` may pin.
|
|
38
38
|
PINNABLE_ATTRIBUTES = %w[scopes metadata access_token_lifetime authorization_code_lifetime require_consent description].freeze
|
|
39
39
|
REGISTRATION_ACCESS_TOKEN_BYTES = 32
|
|
40
|
+
# A self-registered client gets a handful of callbacks, not a list.
|
|
41
|
+
MAX_REDIRECT_URIS = 10
|
|
40
42
|
|
|
41
43
|
# Minimal result object mirroring the gem's `result.success?` /
|
|
42
44
|
# `result.value` convention. `client_secret` is the one-time plaintext for
|
|
@@ -88,18 +90,23 @@ module StandardId
|
|
|
88
90
|
client
|
|
89
91
|
end
|
|
90
92
|
|
|
93
|
+
# Everything, the owner resolver included, runs inside one transaction:
|
|
94
|
+
# a host whose resolver creates a per-registration owner row must not be
|
|
95
|
+
# left with that row when the client itself is refused.
|
|
91
96
|
def call
|
|
92
|
-
|
|
97
|
+
validate_redirect_uris!
|
|
93
98
|
registration_access_token = nil
|
|
94
|
-
if StandardId::ClientApplication.registration_management_column?
|
|
95
|
-
registration_access_token = SecureRandom.urlsafe_base64(REGISTRATION_ACCESS_TOKEN_BYTES)
|
|
96
|
-
attrs[:registration_access_token_digest] =
|
|
97
|
-
StandardId::ClientApplication.digest_registration_access_token(registration_access_token)
|
|
98
|
-
end
|
|
99
|
-
client = StandardId::ClientApplication.new(attrs)
|
|
100
|
-
|
|
101
99
|
secret_plaintext = nil
|
|
100
|
+
client = nil
|
|
101
|
+
|
|
102
102
|
StandardId::ClientApplication.transaction do
|
|
103
|
+
attrs = mapped_attributes
|
|
104
|
+
if StandardId::ClientApplication.registration_management_column?
|
|
105
|
+
registration_access_token = SecureRandom.urlsafe_base64(REGISTRATION_ACCESS_TOKEN_BYTES)
|
|
106
|
+
attrs[:registration_access_token_digest] =
|
|
107
|
+
StandardId::ClientApplication.digest_registration_access_token(registration_access_token)
|
|
108
|
+
end
|
|
109
|
+
client = StandardId::ClientApplication.new(attrs)
|
|
103
110
|
client.save!
|
|
104
111
|
if client.confidential?
|
|
105
112
|
secret_plaintext = SecureRandom.hex(32)
|
|
@@ -117,6 +124,7 @@ module StandardId
|
|
|
117
124
|
end
|
|
118
125
|
|
|
119
126
|
def update(client)
|
|
127
|
+
validate_redirect_uris!
|
|
120
128
|
if metadata[:client_id].present? && metadata[:client_id].to_s != client.client_id
|
|
121
129
|
raise StandardId::InvalidClientMetadataError, "client_id does not match the client being updated"
|
|
122
130
|
end
|
|
@@ -191,7 +199,34 @@ module StandardId
|
|
|
191
199
|
# the model and let its redirect-uri validation surface an invalid_redirect_uri
|
|
192
200
|
# error — keeping a single source of truth for URI rules.
|
|
193
201
|
def redirect_uris
|
|
194
|
-
|
|
202
|
+
redirect_uri_list.join(" ")
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def redirect_uri_list
|
|
206
|
+
value = metadata[:redirect_uris]
|
|
207
|
+
list = value.is_a?(Array) ? value : value.to_s.split(/\s+/)
|
|
208
|
+
list.map { |u| u.to_s.strip }.reject(&:blank?)
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# What the model does not enforce for a client an operator registers by
|
|
212
|
+
# hand, but a self-registering client must meet: https, or http only on a
|
|
213
|
+
# loopback host (RFC 8252 §7.3, for native apps on an ephemeral port), and
|
|
214
|
+
# a bounded list. Absent or empty is left to the model's presence check.
|
|
215
|
+
def validate_redirect_uris!
|
|
216
|
+
list = redirect_uri_list
|
|
217
|
+
return if list.empty?
|
|
218
|
+
|
|
219
|
+
if list.size > MAX_REDIRECT_URIS
|
|
220
|
+
raise StandardId::InvalidRedirectUriError, "redirect_uris must not contain more than #{MAX_REDIRECT_URIS} entries"
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
list.each do |uri|
|
|
224
|
+
parsed = StandardId::ClientApplication.parse_redirect_uri(uri)
|
|
225
|
+
next if parsed && (parsed.scheme == "https" || StandardId::ClientApplication.loopback_redirect_uri?(parsed))
|
|
226
|
+
|
|
227
|
+
raise StandardId::InvalidRedirectUriError,
|
|
228
|
+
"redirect_uri #{uri.inspect} must use https (http is allowed only for loopback hosts)"
|
|
229
|
+
end
|
|
195
230
|
end
|
|
196
231
|
|
|
197
232
|
def client_name
|
data/lib/standard_id/version.rb
CHANGED