rodauth-oauth 1.0.0.pre.beta1 → 1.0.0
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 +1 -1
- data/MIGRATION-GUIDE-v1.md +12 -0
- data/README.md +30 -15
- data/doc/release_notes/0_1_0.md +2 -2
- data/doc/release_notes/0_2_0.md +1 -1
- data/doc/release_notes/0_3_0.md +1 -1
- data/doc/release_notes/0_5_0.md +2 -2
- data/doc/release_notes/0_8_0.md +2 -2
- data/doc/release_notes/1_0_0.md +79 -0
- data/lib/generators/rodauth/oauth/templates/app/views/rodauth/authorize.html.erb +19 -7
- data/lib/generators/rodauth/oauth/templates/app/views/rodauth/authorize_error.erb +10 -0
- data/lib/generators/rodauth/oauth/templates/db/migrate/create_rodauth_oauth.rb +54 -43
- data/lib/rodauth/features/oauth_application_management.rb +2 -2
- data/lib/rodauth/features/oauth_authorization_code_grant.rb +31 -7
- data/lib/rodauth/features/oauth_authorize_base.rb +32 -10
- data/lib/rodauth/features/oauth_base.rb +36 -16
- data/lib/rodauth/features/oauth_dynamic_client_registration.rb +7 -4
- data/lib/rodauth/features/oauth_implicit_grant.rb +16 -5
- data/lib/rodauth/features/oauth_jwt.rb +3 -3
- data/lib/rodauth/features/oauth_jwt_base.rb +29 -6
- data/lib/rodauth/features/oauth_jwt_bearer_grant.rb +7 -4
- data/lib/rodauth/features/oauth_jwt_secured_authorization_request.rb +64 -10
- data/lib/rodauth/features/oauth_resource_indicators.rb +0 -4
- data/lib/rodauth/features/oauth_resource_server.rb +3 -3
- data/lib/rodauth/features/oauth_saml_bearer_grant.rb +2 -0
- data/lib/rodauth/features/oidc.rb +263 -187
- data/lib/rodauth/features/oidc_dynamic_client_registration.rb +65 -25
- data/lib/rodauth/features/oidc_rp_initiated_logout.rb +118 -0
- data/lib/rodauth/oauth/http_extensions.rb +15 -2
- data/lib/rodauth/oauth/ttl_store.rb +2 -0
- data/lib/rodauth/oauth/version.rb +1 -1
- data/locales/en.yml +4 -1
- data/locales/pt.yml +4 -1
- data/templates/authorize.str +17 -10
- data/templates/authorize_error.str +12 -0
- metadata +15 -12
- data/doc/release_notes/1_0_0_beta1.md +0 -38
@@ -10,6 +10,7 @@ module Rodauth
|
|
10
10
|
after "authorize"
|
11
11
|
|
12
12
|
view "authorize", "Authorize", "authorize"
|
13
|
+
view "authorize_error", "Authorize Error", "authorize_error"
|
13
14
|
|
14
15
|
button "Authorize", "oauth_authorize"
|
15
16
|
button "Back to Client Application", "oauth_authorize_post"
|
@@ -23,6 +24,8 @@ module Rodauth
|
|
23
24
|
translatable_method :oauth_applications_contacts_label, "Contacts"
|
24
25
|
translatable_method :oauth_applications_tos_uri_label, "Terms of service URL"
|
25
26
|
translatable_method :oauth_applications_policy_uri_label, "Policy URL"
|
27
|
+
translatable_method :oauth_unsupported_response_type_message, "Unsupported response type"
|
28
|
+
translatable_method :oauth_authorize_parameter_required, "Invalid or missing '%<parameter>s'"
|
26
29
|
|
27
30
|
# /authorize
|
28
31
|
auth_server_route(:authorize) do |r|
|
@@ -63,9 +66,17 @@ module Rodauth
|
|
63
66
|
private
|
64
67
|
|
65
68
|
def validate_authorize_params
|
66
|
-
|
69
|
+
redirect_authorize_error("client_id") unless oauth_application
|
67
70
|
|
68
|
-
|
71
|
+
redirect_uris = oauth_application[oauth_applications_redirect_uri_column].split(" ")
|
72
|
+
|
73
|
+
if (redirect_uri = param_or_nil("redirect_uri"))
|
74
|
+
redirect_authorize_error("redirect_uri") unless redirect_uris.include?(redirect_uri)
|
75
|
+
elsif redirect_uris.size > 1
|
76
|
+
redirect_authorize_error("redirect_uri")
|
77
|
+
end
|
78
|
+
|
79
|
+
redirect_response_error("unsupported_response_type") unless check_valid_response_type?
|
69
80
|
|
70
81
|
redirect_response_error("invalid_request") unless check_valid_access_type? && check_valid_approval_prompt?
|
71
82
|
|
@@ -78,10 +89,6 @@ module Rodauth
|
|
78
89
|
false
|
79
90
|
end
|
80
91
|
|
81
|
-
def check_valid_redirect_uri?
|
82
|
-
oauth_application[oauth_applications_redirect_uri_column].split(" ").include?(redirect_uri)
|
83
|
-
end
|
84
|
-
|
85
92
|
ACCESS_TYPES = %w[offline online].freeze
|
86
93
|
|
87
94
|
def check_valid_access_type?
|
@@ -117,6 +124,21 @@ module Rodauth
|
|
117
124
|
request.env["REQUEST_METHOD"] = "POST"
|
118
125
|
end
|
119
126
|
|
127
|
+
def redirect_authorize_error(parameter, referer = request.referer || default_redirect)
|
128
|
+
error_message = oauth_authorize_parameter_required(parameter: parameter)
|
129
|
+
|
130
|
+
if accepts_json?
|
131
|
+
status_code = oauth_invalid_response_status
|
132
|
+
|
133
|
+
throw_json_response_error(status_code, "invalid_request", error_message)
|
134
|
+
else
|
135
|
+
scope.instance_variable_set(:@error, error_message)
|
136
|
+
scope.instance_variable_set(:@back_url, referer)
|
137
|
+
|
138
|
+
return_response(authorize_error_view)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
120
142
|
def authorization_required
|
121
143
|
if accepts_json?
|
122
144
|
throw_json_response_error(oauth_authorization_required_error_status, "invalid_client")
|
@@ -140,10 +162,10 @@ module Rodauth
|
|
140
162
|
end
|
141
163
|
|
142
164
|
def create_oauth_grant(create_params = {})
|
143
|
-
create_params[oauth_grants_oauth_application_id_column]
|
144
|
-
create_params[oauth_grants_redirect_uri_column]
|
145
|
-
create_params[oauth_grants_expires_in_column]
|
146
|
-
create_params[oauth_grants_scopes_column]
|
165
|
+
create_params[oauth_grants_oauth_application_id_column] ||= oauth_application[oauth_applications_id_column]
|
166
|
+
create_params[oauth_grants_redirect_uri_column] ||= redirect_uri
|
167
|
+
create_params[oauth_grants_expires_in_column] ||= Sequel.date_add(Sequel::CURRENT_TIMESTAMP, seconds: oauth_grant_expires_in)
|
168
|
+
create_params[oauth_grants_scopes_column] ||= scopes.join(oauth_scope_separator)
|
147
169
|
|
148
170
|
if use_oauth_access_type? && (access_type = param_or_nil("access_type"))
|
149
171
|
create_params[oauth_grants_access_type_column] = access_type
|
@@ -3,6 +3,8 @@
|
|
3
3
|
require "time"
|
4
4
|
require "base64"
|
5
5
|
require "securerandom"
|
6
|
+
require "cgi"
|
7
|
+
require "digest/sha2"
|
6
8
|
require "rodauth/version"
|
7
9
|
require "rodauth/oauth"
|
8
10
|
require "rodauth/oauth/database_extensions"
|
@@ -17,8 +19,6 @@ module Rodauth
|
|
17
19
|
auth_value_methods(:http_request)
|
18
20
|
auth_value_methods(:http_request_cache)
|
19
21
|
|
20
|
-
SCOPES = %w[profile.read].freeze
|
21
|
-
|
22
22
|
before "token"
|
23
23
|
|
24
24
|
error_flash "Please authorize to continue", "require_authorization"
|
@@ -82,7 +82,7 @@ module Rodauth
|
|
82
82
|
auth_value_method :oauth_already_in_use_response_status, 409
|
83
83
|
|
84
84
|
# Feature options
|
85
|
-
auth_value_method :oauth_application_scopes,
|
85
|
+
auth_value_method :oauth_application_scopes, []
|
86
86
|
auth_value_method :oauth_token_type, "bearer"
|
87
87
|
auth_value_method :oauth_refresh_token_protection_policy, "rotation" # can be: none, sender_constrained, rotation
|
88
88
|
|
@@ -228,13 +228,20 @@ module Rodauth
|
|
228
228
|
end
|
229
229
|
|
230
230
|
def fetch_access_token
|
231
|
-
|
231
|
+
if (token = request.params["access_token"])
|
232
|
+
if request.post? && !(request.content_type.start_with?("application/x-www-form-urlencoded") &&
|
233
|
+
request.params.size == 1)
|
234
|
+
return
|
235
|
+
end
|
236
|
+
else
|
237
|
+
value = request.env["HTTP_AUTHORIZATION"]
|
232
238
|
|
233
|
-
|
239
|
+
return unless value && !value.empty?
|
234
240
|
|
235
|
-
|
241
|
+
scheme, token = value.split(" ", 2)
|
236
242
|
|
237
|
-
|
243
|
+
return unless scheme.downcase == oauth_token_type
|
244
|
+
end
|
238
245
|
|
239
246
|
return if token.nil? || token.empty?
|
240
247
|
|
@@ -245,11 +252,11 @@ module Rodauth
|
|
245
252
|
return @authorization_token if defined?(@authorization_token)
|
246
253
|
|
247
254
|
# check if there is a token
|
248
|
-
|
255
|
+
access_token = fetch_access_token
|
249
256
|
|
250
|
-
return unless
|
257
|
+
return unless access_token
|
251
258
|
|
252
|
-
@authorization_token = oauth_grant_by_token(
|
259
|
+
@authorization_token = oauth_grant_by_token(access_token)
|
253
260
|
end
|
254
261
|
|
255
262
|
def require_oauth_authorization(*scopes)
|
@@ -758,22 +765,31 @@ module Rodauth
|
|
758
765
|
query_params = []
|
759
766
|
|
760
767
|
query_params << if respond_to?(:"oauth_#{error_code}_error_code")
|
761
|
-
"error
|
768
|
+
["error", send(:"oauth_#{error_code}_error_code")]
|
762
769
|
else
|
763
|
-
"error
|
770
|
+
["error", error_code]
|
764
771
|
end
|
765
772
|
|
766
773
|
if respond_to?(:"oauth_#{error_code}_message")
|
767
774
|
message = send(:"oauth_#{error_code}_message")
|
768
|
-
query_params << ["error_description
|
775
|
+
query_params << ["error_description", CGI.escape(message)]
|
769
776
|
end
|
770
777
|
|
771
|
-
|
772
|
-
|
773
|
-
|
778
|
+
state = param_or_nil("state")
|
779
|
+
|
780
|
+
query_params << ["state", state] if state
|
781
|
+
|
782
|
+
_redirect_response_error(redirect_url, query_params)
|
774
783
|
end
|
775
784
|
end
|
776
785
|
|
786
|
+
def _redirect_response_error(redirect_url, query_params)
|
787
|
+
query_params = query_params.map { |k, v| "#{k}=#{v}" }
|
788
|
+
query_params << redirect_url.query if redirect_url.query
|
789
|
+
redirect_url.query = query_params.join("&")
|
790
|
+
redirect(redirect_url.to_s)
|
791
|
+
end
|
792
|
+
|
777
793
|
def json_response_success(body, cache = false)
|
778
794
|
response.status = 200
|
779
795
|
response["Content-Type"] ||= json_response_content_type
|
@@ -835,6 +851,10 @@ module Rodauth
|
|
835
851
|
URI::DEFAULT_PARSER.make_regexp(oauth_valid_uri_schemes).match?(uri)
|
836
852
|
end
|
837
853
|
|
854
|
+
def check_valid_no_fragment_uri?(uri)
|
855
|
+
check_valid_uri?(uri) && URI.parse(uri).fragment.nil?
|
856
|
+
end
|
857
|
+
|
838
858
|
# Resource server mode
|
839
859
|
|
840
860
|
def authorization_server_metadata
|
@@ -8,7 +8,7 @@ module Rodauth
|
|
8
8
|
|
9
9
|
before "register"
|
10
10
|
|
11
|
-
auth_value_method :oauth_client_registration_required_params, %w[redirect_uris client_name
|
11
|
+
auth_value_method :oauth_client_registration_required_params, %w[redirect_uris client_name]
|
12
12
|
|
13
13
|
PROTECTED_APPLICATION_ATTRIBUTES = %w[account_id client_id].freeze
|
14
14
|
|
@@ -68,7 +68,10 @@ module Rodauth
|
|
68
68
|
when "redirect_uris"
|
69
69
|
if value.is_a?(Array)
|
70
70
|
value = value.each do |uri|
|
71
|
-
|
71
|
+
unless check_valid_no_fragment_uri?(uri)
|
72
|
+
register_throw_json_response_error("invalid_redirect_uri",
|
73
|
+
register_invalid_uri_message(uri))
|
74
|
+
end
|
72
75
|
end.join(" ")
|
73
76
|
else
|
74
77
|
register_throw_json_response_error("invalid_redirect_uri", register_invalid_uri_message(value))
|
@@ -76,7 +79,7 @@ module Rodauth
|
|
76
79
|
key = oauth_applications_redirect_uri_column
|
77
80
|
when "token_endpoint_auth_method"
|
78
81
|
unless oauth_token_endpoint_auth_methods_supported.include?(value)
|
79
|
-
register_throw_json_response_error("invalid_client_metadata",
|
82
|
+
register_throw_json_response_error("invalid_client_metadata", register_invalid_client_metadata_message(key, value))
|
80
83
|
end
|
81
84
|
# verify if in range
|
82
85
|
key = oauth_applications_token_endpoint_auth_method_column
|
@@ -84,7 +87,7 @@ module Rodauth
|
|
84
87
|
if value.is_a?(Array)
|
85
88
|
value = value.each do |grant_type|
|
86
89
|
unless oauth_grant_types_supported.include?(grant_type)
|
87
|
-
register_throw_json_response_error("invalid_client_metadata",
|
90
|
+
register_throw_json_response_error("invalid_client_metadata", register_invalid_client_metadata_message(grant_type, value))
|
88
91
|
end
|
89
92
|
end.join(" ")
|
90
93
|
else
|
@@ -28,23 +28,34 @@ module Rodauth
|
|
28
28
|
|
29
29
|
redirect_response_error("invalid_request") unless supported_response_mode?(response_mode)
|
30
30
|
|
31
|
-
|
31
|
+
oauth_grant = _do_authorize_token
|
32
|
+
|
33
|
+
response_params.replace(json_access_token_payload(oauth_grant))
|
32
34
|
|
33
35
|
response_params["state"] = param("state") if param_or_nil("state")
|
34
36
|
|
35
37
|
[response_params, response_mode]
|
36
38
|
end
|
37
39
|
|
38
|
-
def _do_authorize_token
|
40
|
+
def _do_authorize_token(grant_params = {})
|
39
41
|
grant_params = {
|
40
42
|
oauth_grants_type_column => "implicit",
|
41
43
|
oauth_grants_oauth_application_id_column => oauth_application[oauth_applications_id_column],
|
42
44
|
oauth_grants_scopes_column => scopes,
|
43
45
|
oauth_grants_account_id_column => account_id
|
44
|
-
}
|
45
|
-
|
46
|
+
}.merge(grant_params)
|
47
|
+
|
48
|
+
generate_token(grant_params, false)
|
49
|
+
end
|
46
50
|
|
47
|
-
|
51
|
+
def _redirect_response_error(redirect_url, query_params)
|
52
|
+
response_types = param("response_type").split(/ +/)
|
53
|
+
|
54
|
+
return super if response_types.empty? || response_types == %w[code]
|
55
|
+
|
56
|
+
query_params = query_params.map { |k, v| "#{k}=#{v}" }
|
57
|
+
redirect_url.fragment = query_params.join("&")
|
58
|
+
redirect(redirect_url.to_s)
|
48
59
|
end
|
49
60
|
|
50
61
|
def authorize_response(params, mode)
|
@@ -49,11 +49,11 @@ module Rodauth
|
|
49
49
|
return @authorization_token if defined?(@authorization_token)
|
50
50
|
|
51
51
|
@authorization_token = begin
|
52
|
-
|
52
|
+
access_token = fetch_access_token
|
53
53
|
|
54
|
-
return unless
|
54
|
+
return unless access_token
|
55
55
|
|
56
|
-
jwt_claims = jwt_decode(
|
56
|
+
jwt_claims = jwt_decode(access_token)
|
57
57
|
|
58
58
|
return unless jwt_claims
|
59
59
|
|
@@ -63,7 +63,11 @@ module Rodauth
|
|
63
63
|
end
|
64
64
|
|
65
65
|
def jwt_subject(oauth_grant, client_application = oauth_application)
|
66
|
-
oauth_grant[oauth_grants_account_id_column]
|
66
|
+
account_id = oauth_grant[oauth_grants_account_id_column]
|
67
|
+
|
68
|
+
return account_id.to_s if account_id
|
69
|
+
|
70
|
+
client_application[oauth_applications_client_id_column]
|
67
71
|
end
|
68
72
|
|
69
73
|
def oauth_server_metadata_body(path = nil)
|
@@ -207,14 +211,23 @@ module Rodauth
|
|
207
211
|
|
208
212
|
claims = if is_authorization_server?
|
209
213
|
if jwks
|
214
|
+
jwks = jwks[:keys] if jwks.is_a?(Hash)
|
215
|
+
|
210
216
|
enc_algs = [jws_encryption_algorithm].compact
|
211
217
|
enc_meths = [jws_encryption_method].compact
|
212
218
|
|
213
219
|
sig_algs = jws_algorithm ? [jws_algorithm] : jwks.select { |k| k[:use] == "sig" }.map { |k| k[:alg] }
|
214
220
|
sig_algs = sig_algs.compact.map(&:to_sym)
|
215
221
|
|
216
|
-
|
217
|
-
|
222
|
+
# JWKs may be set up without a KID, when there's a single one
|
223
|
+
if jwks.size == 1 && !jwks[0][:kid]
|
224
|
+
key = jwks[0]
|
225
|
+
jwk_key = JSON::JWK.new(key)
|
226
|
+
jws = JSON::JWT.decode(token, jwk_key)
|
227
|
+
else
|
228
|
+
jws = JSON::JWT.decode(token, JSON::JWK::Set.new({ keys: jwks }), enc_algs + sig_algs, enc_meths)
|
229
|
+
jws = JSON::JWT.decode(jws.plain_text, JSON::JWK::Set.new({ keys: jwks }), sig_algs) if jws.is_a?(JSON::JWE)
|
230
|
+
end
|
218
231
|
jws
|
219
232
|
elsif jws_key
|
220
233
|
JSON::JWT.decode(token, jws_key)
|
@@ -279,7 +292,7 @@ module Rodauth
|
|
279
292
|
end
|
280
293
|
|
281
294
|
def jwt_encode(payload,
|
282
|
-
signing_algorithm: oauth_jwt_keys.keys.first)
|
295
|
+
signing_algorithm: oauth_jwt_keys.keys.first, **)
|
283
296
|
headers = {}
|
284
297
|
|
285
298
|
key = oauth_jwt_keys[signing_algorithm] || _jwt_key
|
@@ -368,8 +381,18 @@ module Rodauth
|
|
368
381
|
# decode jwt
|
369
382
|
claims = if is_authorization_server?
|
370
383
|
if jwks
|
371
|
-
|
372
|
-
|
384
|
+
jwks = jwks[:keys] if jwks.is_a?(Hash)
|
385
|
+
|
386
|
+
# JWKs may be set up without a KID, when there's a single one
|
387
|
+
if jwks.size == 1 && !jwks[0][:kid]
|
388
|
+
key = jwks[0]
|
389
|
+
algo = key[:alg]
|
390
|
+
key = JWT::JWK.import(key).keypair
|
391
|
+
JWT.decode(token, key, true, algorithms: [algo], **verify_claims_params).first
|
392
|
+
else
|
393
|
+
algorithms = jws_algorithm ? [jws_algorithm] : jwks.select { |k| k[:use] == "sig" }.map { |k| k[:alg] }
|
394
|
+
JWT.decode(token, nil, true, algorithms: algorithms, jwks: { keys: jwks }, **verify_claims_params).first
|
395
|
+
end
|
373
396
|
elsif jws_key
|
374
397
|
JWT.decode(token, jws_key, true, algorithms: [jws_algorithm], **verify_claims_params).first
|
375
398
|
end
|
@@ -6,6 +6,8 @@ module Rodauth
|
|
6
6
|
Feature.define(:oauth_jwt_bearer_grant, :OauthJwtBearerGrant) do
|
7
7
|
depends :oauth_assertion_base, :oauth_jwt
|
8
8
|
|
9
|
+
auth_value_method :max_param_bytesize, nil if Rodauth::VERSION >= "2.26.0"
|
10
|
+
|
9
11
|
auth_value_methods(
|
10
12
|
:require_oauth_application_from_jwt_bearer_assertion_issuer,
|
11
13
|
:require_oauth_application_from_jwt_bearer_assertion_subject,
|
@@ -54,7 +56,7 @@ module Rodauth
|
|
54
56
|
|
55
57
|
def require_oauth_application_from_client_secret_jwt(client_id, assertion, alg)
|
56
58
|
oauth_application = db[oauth_applications_table].where(oauth_applications_client_id_column => client_id).first
|
57
|
-
authorization_required unless supports_auth_method?(oauth_application, "client_secret_jwt")
|
59
|
+
authorization_required unless oauth_application && supports_auth_method?(oauth_application, "client_secret_jwt")
|
58
60
|
client_secret = oauth_application[oauth_applications_client_secret_column]
|
59
61
|
claims = jwt_assertion(assertion, jws_key: client_secret, jws_algorithm: alg)
|
60
62
|
authorization_required unless claims && claims["iss"] == client_id
|
@@ -63,7 +65,7 @@ module Rodauth
|
|
63
65
|
|
64
66
|
def require_oauth_application_from_private_key_jwt(client_id, assertion)
|
65
67
|
oauth_application = db[oauth_applications_table].where(oauth_applications_client_id_column => client_id).first
|
66
|
-
authorization_required unless supports_auth_method?(oauth_application, "private_key_jwt")
|
68
|
+
authorization_required unless oauth_application && supports_auth_method?(oauth_application, "private_key_jwt")
|
67
69
|
jwks = oauth_application_jwks(oauth_application)
|
68
70
|
claims = jwt_assertion(assertion, jwks: jwks)
|
69
71
|
authorization_required unless claims
|
@@ -79,8 +81,9 @@ module Rodauth
|
|
79
81
|
end
|
80
82
|
|
81
83
|
def jwt_assertion(assertion, **kwargs)
|
82
|
-
claims = jwt_decode(assertion, verify_iss: false, verify_aud: false, **kwargs)
|
83
|
-
|
84
|
+
claims = jwt_decode(assertion, verify_iss: false, verify_aud: false, verify_jti: false, **kwargs)
|
85
|
+
|
86
|
+
return unless claims && verify_aud(request.url, claims["aud"])
|
84
87
|
|
85
88
|
claims
|
86
89
|
end
|
@@ -4,31 +4,46 @@ require "rodauth/oauth"
|
|
4
4
|
|
5
5
|
module Rodauth
|
6
6
|
Feature.define(:oauth_jwt_secured_authorization_request, :OauthJwtSecuredAuthorizationRequest) do
|
7
|
+
ALLOWED_REQUEST_URI_CONTENT_TYPES = %w[application/jose application/oauth-authz-req+jwt].freeze
|
8
|
+
|
7
9
|
depends :oauth_authorize_base, :oauth_jwt_base
|
8
10
|
|
11
|
+
auth_value_method :oauth_require_request_uri_registration, false
|
12
|
+
auth_value_method :oauth_request_object_signing_alg_allow_none, false
|
13
|
+
|
14
|
+
auth_value_method :oauth_applications_request_uris_column, :request_uris
|
15
|
+
|
9
16
|
auth_value_method :oauth_applications_request_object_signing_alg_column, :request_object_signing_alg
|
10
17
|
auth_value_method :oauth_applications_request_object_encryption_alg_column, :request_object_encryption_alg
|
11
18
|
auth_value_method :oauth_applications_request_object_encryption_enc_column, :request_object_encryption_enc
|
12
19
|
|
13
|
-
translatable_method :oauth_request_uri_not_supported_message, "request uri is unsupported"
|
14
20
|
translatable_method :oauth_invalid_request_object_message, "request object is invalid"
|
15
21
|
|
22
|
+
auth_value_method :max_param_bytesize, nil if Rodauth::VERSION >= "2.26.0"
|
23
|
+
|
16
24
|
private
|
17
25
|
|
18
26
|
# /authorize
|
19
27
|
|
20
28
|
def validate_authorize_params
|
21
|
-
# TODO: add support for requst_uri
|
22
|
-
redirect_response_error("request_uri_not_supported") if param_or_nil("request_uri")
|
23
|
-
|
24
29
|
request_object = param_or_nil("request")
|
25
30
|
|
26
|
-
|
31
|
+
request_uri = param_or_nil("request_uri")
|
27
32
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
33
|
+
return super unless (request_object || request_uri) && oauth_application
|
34
|
+
|
35
|
+
if request_uri
|
36
|
+
request_uri = CGI.unescape(request_uri)
|
37
|
+
|
38
|
+
redirect_response_error("invalid_request_uri") unless supported_request_uri?(request_uri, oauth_application)
|
39
|
+
|
40
|
+
response = http_request(request_uri)
|
41
|
+
|
42
|
+
unless response.code.to_i == 200 && ALLOWED_REQUEST_URI_CONTENT_TYPES.include?(response["content-type"])
|
43
|
+
redirect_response_error("invalid_request_uri")
|
44
|
+
end
|
45
|
+
|
46
|
+
request_object = response.body
|
32
47
|
end
|
33
48
|
|
34
49
|
request_sig_enc_opts = {
|
@@ -37,10 +52,33 @@ module Rodauth
|
|
37
52
|
jws_encryption_method: oauth_application[oauth_applications_request_object_encryption_enc_column]
|
38
53
|
}.compact
|
39
54
|
|
40
|
-
|
55
|
+
request_sig_enc_opts[:jws_algorithm] ||= "none" if oauth_request_object_signing_alg_allow_none
|
56
|
+
|
57
|
+
if request_sig_enc_opts[:jws_algorithm] == "none"
|
58
|
+
jwks = nil
|
59
|
+
elsif (jwks = oauth_application_jwks(oauth_application))
|
60
|
+
jwks = JSON.parse(jwks, symbolize_names: true) if jwks.is_a?(String)
|
61
|
+
else
|
62
|
+
redirect_response_error("invalid_request_object")
|
63
|
+
end
|
64
|
+
|
65
|
+
claims = jwt_decode(request_object,
|
66
|
+
jwks: jwks,
|
67
|
+
verify_jti: false,
|
68
|
+
verify_iss: false,
|
69
|
+
verify_aud: false,
|
70
|
+
**request_sig_enc_opts)
|
41
71
|
|
42
72
|
redirect_response_error("invalid_request_object") unless claims
|
43
73
|
|
74
|
+
if (iss = claims["iss"]) && (iss != oauth_application[oauth_applications_client_id_column])
|
75
|
+
redirect_response_error("invalid_request_object")
|
76
|
+
end
|
77
|
+
|
78
|
+
if (aud = claims["aud"]) && !verify_aud(aud, oauth_jwt_issuer)
|
79
|
+
redirect_response_error("invalid_request_object")
|
80
|
+
end
|
81
|
+
|
44
82
|
# If signed, the Authorization Request
|
45
83
|
# Object SHOULD contain the Claims "iss" (issuer) and "aud" (audience)
|
46
84
|
# as members, with their semantics being the same as defined in the JWT
|
@@ -58,5 +96,21 @@ module Rodauth
|
|
58
96
|
|
59
97
|
super
|
60
98
|
end
|
99
|
+
|
100
|
+
def supported_request_uri?(request_uri, oauth_application)
|
101
|
+
return false unless check_valid_uri?(request_uri)
|
102
|
+
|
103
|
+
request_uris = oauth_application[oauth_applications_request_uris_column]
|
104
|
+
|
105
|
+
request_uris.nil? || request_uris.split(oauth_scope_separator).one? { |uri| request_uri.start_with?(uri) }
|
106
|
+
end
|
107
|
+
|
108
|
+
def oauth_server_metadata_body(*)
|
109
|
+
super.tap do |data|
|
110
|
+
data[:request_parameter_supported] = true
|
111
|
+
data[:request_uri_parameter_supported] = true
|
112
|
+
data[:require_request_uri_registration] = oauth_require_request_uri_registration
|
113
|
+
end
|
114
|
+
end
|
61
115
|
end
|
62
116
|
end
|
@@ -70,10 +70,6 @@ module Rodauth
|
|
70
70
|
super(oauth_grant, update_params.merge(oauth_grants_resource_column => resource_indicators))
|
71
71
|
end
|
72
72
|
|
73
|
-
def check_valid_no_fragment_uri?(uri)
|
74
|
-
check_valid_uri?(uri) && URI.parse(uri).fragment.nil?
|
75
|
-
end
|
76
|
-
|
77
73
|
module IndicatorAuthorizationCodeGrant
|
78
74
|
private
|
79
75
|
|
@@ -16,12 +16,12 @@ module Rodauth
|
|
16
16
|
return @authorization_token if defined?(@authorization_token)
|
17
17
|
|
18
18
|
# check if there is a token
|
19
|
-
|
19
|
+
access_token = fetch_access_token
|
20
20
|
|
21
|
-
return unless
|
21
|
+
return unless access_token
|
22
22
|
|
23
23
|
# where in resource server, NOT the authorization server.
|
24
|
-
payload = introspection_request("access_token",
|
24
|
+
payload = introspection_request("access_token", access_token)
|
25
25
|
|
26
26
|
return unless payload["active"]
|
27
27
|
|
@@ -17,6 +17,8 @@ module Rodauth
|
|
17
17
|
auth_value_method :oauth_saml_security_digest_method, XMLSecurity::Document::SHA1
|
18
18
|
auth_value_method :oauth_saml_security_signature_method, XMLSecurity::Document::RSA_SHA1
|
19
19
|
|
20
|
+
auth_value_method :max_param_bytesize, nil if Rodauth::VERSION >= "2.26.0"
|
21
|
+
|
20
22
|
auth_value_methods(
|
21
23
|
:require_oauth_application_from_saml2_bearer_assertion_issuer,
|
22
24
|
:require_oauth_application_from_saml2_bearer_assertion_subject,
|