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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ac42aa0fb7d65030b403957a408d6d5b1f999614c957ec8176d814030ddb9381
4
- data.tar.gz: f67cf98dfdb162d1e015d3930b569756f2a25737a64e68ed36fcf31e2d672be2
3
+ metadata.gz: bf721a3632883e34bff44e33ca84c9a5aa2248748ccecf52c180edd25086abad
4
+ data.tar.gz: 59966edc773dbee470be46770532ee9159dfe370d346eca936a2ebc48a8fd224
5
5
  SHA512:
6
- metadata.gz: e86da1d43f30dfb18e1ae530dc5b1cc9cf69903d32a39bade2dc5881075140d79ef5644159ff40b1406b58dfb12197c79d13f683f20b431330d02d452b3cf87e
7
- data.tar.gz: ad35b6bc881f1e22f7cb7227115daee9556ebeada9e10b21e8ecfeb9dc0e7a51ddd606ef481f1125064e49d6ee39076bd8bc2043d58d0d103df6a27813a022db
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/httpx/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/httpx/2021/09/08/using-rodauth-oauth-in-rails-without-rodauth-based-auth.html)
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 if encryption_algorithm
199
- meth = encryption_method.to_sym if encryption_method
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
- auth_value_method :oauth_applications_request_uris_column, :request_uris
15
-
16
- auth_value_method :oauth_applications_request_object_signing_alg_column, :request_object_signing_alg
17
- auth_value_method :oauth_applications_request_object_encryption_alg_column, :request_object_encryption_alg
18
- auth_value_method :oauth_applications_request_object_encryption_enc_column, :request_object_encryption_enc
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
- return super unless (request_object || request_uri) && oauth_application
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 (request_object = param_or_nil("request")) && features.include?(:oauth_jwt_secured_authorization_request)
69
- claims = decode_request_object(request_object)
70
-
71
- # https://datatracker.ietf.org/doc/html/rfc9126#section-3-5.3
72
- # reject the request if the authenticated client_id does not match the client_id claim in the Request Object
73
- if (client_id = claims["client_id"]) && (client_id != oauth_application[oauth_applications_client_id_column])
74
- redirect_response_error("invalid_request_object")
75
- end
76
-
77
- # requiring the iss claim to match the client_id is at the discretion of the authorization server
78
- if oauth_require_pushed_authorization_request_iss_request_object &&
79
- (iss = claims.delete("iss")) &&
80
- iss != oauth_application[oauth_applications_client_id_column]
81
- redirect_response_error("invalid_request_object")
82
- end
83
-
84
- if (aud = claims.delete("aud")) && !verify_aud(aud, oauth_jwt_issuer)
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")
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Rodauth
4
4
  module OAuth
5
- VERSION = "1.3.1"
5
+ VERSION = "1.3.2"
6
6
  end
7
7
  end
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.1
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-06-27 00:00:00.000000000 Z
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