rodauth-oauth 1.3.1 → 1.3.2
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/README.md +2 -2
- data/doc/release_notes/1_3_2.md +14 -0
- data/lib/generators/rodauth/oauth/templates/db/migrate/create_rodauth_oauth.rb +1 -0
- data/lib/rodauth/features/oauth_dynamic_client_registration.rb +8 -0
- data/lib/rodauth/features/oauth_jwt_base.rb +8 -2
- data/lib/rodauth/features/oauth_jwt_secured_authorization_request.rb +25 -6
- data/lib/rodauth/features/oauth_pushed_authorization_request.rb +33 -24
- data/lib/rodauth/oauth/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bf721a3632883e34bff44e33ca84c9a5aa2248748ccecf52c180edd25086abad
|
4
|
+
data.tar.gz: 59966edc773dbee470be46770532ee9159dfe370d346eca936a2ebc48a8fd224
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6855059fe2d8225e4f3650dca01ad4ff3d82ad4e42623b43e5ea1d42ef3dbec317bf9488a2b1598556c135f9b9bf1d45ac41512d7347e3c5c55b7c5e8bd63305
|
7
|
+
data.tar.gz: 9a564b8ad6812841f4a2737ee263af188e5231c49b8b475f0c575a5b0496aa6f534709552845caaaacbb73dbe1afabb9079a17265683be5df73f62075a78896e
|
data/README.md
CHANGED
@@ -90,8 +90,8 @@ Or install it yourself as:
|
|
90
90
|
|
91
91
|
## Articles
|
92
92
|
|
93
|
-
* [How to use rodauth-oauth with rails and rodauth](https://honeyryderchuck.gitlab.io/
|
94
|
-
* [How to use rodauth-oauth with rails and without rodauth](https://honeyryderchuck.gitlab.io/
|
93
|
+
* [How to use rodauth-oauth with rails and rodauth](https://honeyryderchuck.gitlab.io/2021/03/15/oidc-provider-on-rails-using-rodauth-oauth.html)
|
94
|
+
* [How to use rodauth-oauth with rails and without rodauth](https://honeyryderchuck.gitlab.io/2021/09/08/using-rodauth-oauth-in-rails-without-rodauth-based-auth.html)
|
95
95
|
|
96
96
|
## Usage
|
97
97
|
|
@@ -0,0 +1,14 @@
|
|
1
|
+
### 1.3.2 (27/07/2023)
|
2
|
+
|
3
|
+
#### Improvements
|
4
|
+
|
5
|
+
* `require_signed_request_object` option for JAR (`oauth_jwt_secured_authorization_request` plugin) is now supported:
|
6
|
+
* in the oauth server metadata endpoint
|
7
|
+
* as a plugin config option (`oauth_require_signed_request_object`, defaults to `false`)
|
8
|
+
* as a oauth dynamic registration endpoint param (`require_signed_request_object`, requires corresponding columnn)
|
9
|
+
* enforces JAR-based authorization, andd does not allow unsigned JAR JWTs, when turned on.
|
10
|
+
|
11
|
+
#### Bugfixes
|
12
|
+
|
13
|
+
* JWT decoding failed in circumstances where a declared encryption algo didn't have key/method declared.
|
14
|
+
* fix for when PAR (`oauth_pushed_authorization_request` feature) is used with JAR (`oauth_jwt_secured_authorization_request` plugin), and PAR `request_uri` param wasn't being removed when validating authorize request parameters, thereby making JAR logic evaluate it as a JAR `requuest_uri` (it is now correctly not taken into account in such a case);
|
@@ -46,6 +46,7 @@ class CreateRodauthOauth < ActiveRecord::Migration<%= migration_version %>
|
|
46
46
|
t.string :request_object_encryption_alg, null: true
|
47
47
|
t.string :request_object_encryption_enc, null: true
|
48
48
|
t.string :request_uris, null: true
|
49
|
+
t.boolean :require_signed_request_object, null: true
|
49
50
|
t.boolean :require_pushed_authorization_requests, null: false, default: false
|
50
51
|
|
51
52
|
# :oauth_tls_client_auth
|
@@ -200,6 +200,14 @@ module Rodauth
|
|
200
200
|
when "client_name"
|
201
201
|
register_throw_json_response_error("invalid_client_metadata", register_invalid_param_message(value)) unless value.is_a?(String)
|
202
202
|
key = oauth_applications_name_column
|
203
|
+
when "require_signed_request_object"
|
204
|
+
unless respond_to?(:oauth_applications_require_signed_request_object_column)
|
205
|
+
register_throw_json_response_error("invalid_client_metadata",
|
206
|
+
register_invalid_param_message(key))
|
207
|
+
end
|
208
|
+
request_params[key] = value = convert_to_boolean(key, value)
|
209
|
+
|
210
|
+
key = oauth_applications_require_signed_request_object_column
|
203
211
|
when "require_pushed_authorization_requests"
|
204
212
|
unless respond_to?(:oauth_applications_require_pushed_authorization_requests_column)
|
205
213
|
register_throw_json_response_error("invalid_client_metadata",
|
@@ -189,14 +189,16 @@ module Rodauth
|
|
189
189
|
jwt = jwt.sign(jwk, signing_algorithm)
|
190
190
|
jwt.kid = jwk.thumbprint
|
191
191
|
|
192
|
+
return jwt.to_s unless encryption_algorithm && encryption_method
|
193
|
+
|
192
194
|
if jwks && (jwk = jwks.find { |k| k[:use] == "enc" && k[:alg] == encryption_algorithm && k[:enc] == encryption_method })
|
193
195
|
jwk = JSON::JWK.new(jwk)
|
194
196
|
jwe = jwt.encrypt(jwk, encryption_algorithm.to_sym, encryption_method.to_sym)
|
195
197
|
jwe.to_s
|
196
198
|
elsif jwe_key
|
197
199
|
jwe_key = jwe_key.first if jwe_key.is_a?(Array)
|
198
|
-
algorithm = encryption_algorithm.to_sym
|
199
|
-
meth = encryption_method.to_sym
|
200
|
+
algorithm = encryption_algorithm.to_sym
|
201
|
+
meth = encryption_method.to_sym
|
200
202
|
jwt.encrypt(jwe_key, algorithm, meth)
|
201
203
|
else
|
202
204
|
jwt.to_s
|
@@ -246,6 +248,8 @@ module Rodauth
|
|
246
248
|
jws
|
247
249
|
elsif jws_key
|
248
250
|
JSON::JWT.decode(token, jws_key)
|
251
|
+
else
|
252
|
+
JSON::JWT.decode(token, nil, jws_algorithm)
|
249
253
|
end
|
250
254
|
elsif (jwks = auth_server_jwks_set)
|
251
255
|
JSON::JWT.decode(token, JSON::JWK::Set.new(jwks))
|
@@ -428,6 +432,8 @@ module Rodauth
|
|
428
432
|
end
|
429
433
|
elsif jws_key
|
430
434
|
JWT.decode(token, jws_key, true, algorithms: [jws_algorithm], **verify_claims_params).first
|
435
|
+
else
|
436
|
+
JWT.decode(token, jws_key, false, **verify_claims_params).first
|
431
437
|
end
|
432
438
|
elsif (jwks = auth_server_jwks_set)
|
433
439
|
algorithms = jwks[:keys].select { |k| k[:use] == "sig" }.map { |k| k[:alg] }
|
@@ -9,13 +9,15 @@ module Rodauth
|
|
9
9
|
depends :oauth_authorize_base, :oauth_jwt_base
|
10
10
|
|
11
11
|
auth_value_method :oauth_require_request_uri_registration, false
|
12
|
+
auth_value_method :oauth_require_signed_request_object, false
|
12
13
|
auth_value_method :oauth_request_object_signing_alg_allow_none, false
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
%i[
|
16
|
+
request_uris require_signed_request_object request_object_signing_alg
|
17
|
+
request_object_encryption_alg request_object_encryption_enc
|
18
|
+
].each do |column|
|
19
|
+
auth_value_method :"oauth_applications_#{column}_column", column
|
20
|
+
end
|
19
21
|
|
20
22
|
translatable_method :oauth_invalid_request_object_message, "request object is invalid"
|
21
23
|
|
@@ -30,7 +32,13 @@ module Rodauth
|
|
30
32
|
|
31
33
|
request_uri = param_or_nil("request_uri")
|
32
34
|
|
33
|
-
|
35
|
+
unless (request_object || request_uri) && oauth_application
|
36
|
+
if request.path == authorize_path && request.get? && require_signed_request_object?
|
37
|
+
redirect_response_error("invalid_request_object")
|
38
|
+
end
|
39
|
+
|
40
|
+
return super
|
41
|
+
end
|
34
42
|
|
35
43
|
if request_uri
|
36
44
|
request_uri = CGI.unescape(request_uri)
|
@@ -84,6 +92,14 @@ module Rodauth
|
|
84
92
|
request_uris.nil? || request_uris.split(oauth_scope_separator).one? { |uri| request_uri.start_with?(uri) }
|
85
93
|
end
|
86
94
|
|
95
|
+
def require_signed_request_object?
|
96
|
+
return @require_signed_request_object if defined?(@require_signed_request_object)
|
97
|
+
|
98
|
+
@require_signed_request_object = (oauth_application[oauth_applications_require_signed_request_object_column] if oauth_application)
|
99
|
+
@require_signed_request_object = oauth_require_signed_request_object if @require_signed_request_object.nil?
|
100
|
+
@require_signed_request_object
|
101
|
+
end
|
102
|
+
|
87
103
|
def decode_request_object(request_object)
|
88
104
|
request_sig_enc_opts = {
|
89
105
|
jws_algorithm: oauth_application[oauth_applications_request_object_signing_alg_column],
|
@@ -94,6 +110,8 @@ module Rodauth
|
|
94
110
|
request_sig_enc_opts[:jws_algorithm] ||= "none" if oauth_request_object_signing_alg_allow_none
|
95
111
|
|
96
112
|
if request_sig_enc_opts[:jws_algorithm] == "none"
|
113
|
+
redirect_response_error("invalid_request_object") if require_signed_request_object?
|
114
|
+
|
97
115
|
jwks = nil
|
98
116
|
elsif (jwks = oauth_application_jwks(oauth_application))
|
99
117
|
jwks = JSON.parse(jwks, symbolize_names: true) if jwks.is_a?(String)
|
@@ -118,6 +136,7 @@ module Rodauth
|
|
118
136
|
data[:request_parameter_supported] = true
|
119
137
|
data[:request_uri_parameter_supported] = true
|
120
138
|
data[:require_request_uri_registration] = oauth_require_request_uri_registration
|
139
|
+
data[:require_signed_request_object] = oauth_require_signed_request_object
|
121
140
|
end
|
122
141
|
end
|
123
142
|
end
|
@@ -65,32 +65,37 @@ module Rodauth
|
|
65
65
|
# The request_uri authorization request parameter is one exception, and it MUST NOT be provided.
|
66
66
|
redirect_response_error("invalid_request") if param_or_nil("request_uri")
|
67
67
|
|
68
|
-
if
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
68
|
+
if features.include?(:oauth_jwt_secured_authorization_request)
|
69
|
+
|
70
|
+
if (request_object = param_or_nil("request"))
|
71
|
+
claims = decode_request_object(request_object)
|
72
|
+
|
73
|
+
# https://datatracker.ietf.org/doc/html/rfc9126#section-3-5.3
|
74
|
+
# reject the request if the authenticated client_id does not match the client_id claim in the Request Object
|
75
|
+
if (client_id = claims["client_id"]) && (client_id != oauth_application[oauth_applications_client_id_column])
|
76
|
+
redirect_response_error("invalid_request_object")
|
77
|
+
end
|
78
|
+
|
79
|
+
# requiring the iss claim to match the client_id is at the discretion of the authorization server
|
80
|
+
if oauth_require_pushed_authorization_request_iss_request_object &&
|
81
|
+
(iss = claims.delete("iss")) &&
|
82
|
+
iss != oauth_application[oauth_applications_client_id_column]
|
83
|
+
redirect_response_error("invalid_request_object")
|
84
|
+
end
|
85
|
+
|
86
|
+
if (aud = claims.delete("aud")) && !verify_aud(aud, oauth_jwt_issuer)
|
87
|
+
redirect_response_error("invalid_request_object")
|
88
|
+
end
|
89
|
+
|
90
|
+
claims.delete("exp")
|
91
|
+
request.params.delete("request")
|
92
|
+
|
93
|
+
claims.each do |k, v|
|
94
|
+
request.params[k.to_s] = v
|
95
|
+
end
|
96
|
+
elsif require_signed_request_object?
|
85
97
|
redirect_response_error("invalid_request_object")
|
86
98
|
end
|
87
|
-
|
88
|
-
claims.delete("exp")
|
89
|
-
request.params.delete("request")
|
90
|
-
|
91
|
-
claims.each do |k, v|
|
92
|
-
request.params[k.to_s] = v
|
93
|
-
end
|
94
99
|
end
|
95
100
|
|
96
101
|
validate_authorize_params
|
@@ -118,6 +123,10 @@ module Rodauth
|
|
118
123
|
request.params[k.to_s] = v
|
119
124
|
end
|
120
125
|
|
126
|
+
request.params.delete("request_uri")
|
127
|
+
|
128
|
+
# we're removing the request_uri here, so the checkup for signed reqest has to be invalidated.
|
129
|
+
@require_signed_request_object = false
|
121
130
|
elsif oauth_require_pushed_authorization_requests ||
|
122
131
|
(oauth_application && oauth_application[oauth_applications_require_pushed_authorization_requests_column])
|
123
132
|
redirect_authorize_error("request_uri")
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rodauth-oauth
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.3.
|
4
|
+
version: 1.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tiago Cardoso
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-07-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rodauth
|
@@ -71,6 +71,7 @@ extra_rdoc_files:
|
|
71
71
|
- doc/release_notes/1_2_0.md
|
72
72
|
- doc/release_notes/1_3_0.md
|
73
73
|
- doc/release_notes/1_3_1.md
|
74
|
+
- doc/release_notes/1_3_2.md
|
74
75
|
files:
|
75
76
|
- CHANGELOG.md
|
76
77
|
- LICENSE.txt
|
@@ -113,6 +114,7 @@ files:
|
|
113
114
|
- doc/release_notes/1_2_0.md
|
114
115
|
- doc/release_notes/1_3_0.md
|
115
116
|
- doc/release_notes/1_3_1.md
|
117
|
+
- doc/release_notes/1_3_2.md
|
116
118
|
- lib/generators/rodauth/oauth/install_generator.rb
|
117
119
|
- lib/generators/rodauth/oauth/templates/app/models/oauth_application.rb
|
118
120
|
- lib/generators/rodauth/oauth/templates/app/models/oauth_grant.rb
|