rodauth-oauth 1.0.0.pre.beta1 → 1.0.0.pre.beta2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- return unless verify_aud(request.url, claims["aud"])
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
- return super unless request_object && oauth_application
31
+ request_uri = param_or_nil("request_uri")
27
32
 
28
- if (jwks = oauth_application_jwks(oauth_application))
29
- jwks = JSON.parse(jwks, symbolize_names: true) if jwks.is_a?(String)
30
- else
31
- redirect_response_error("invalid_request_object")
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
- claims = jwt_decode(request_object, jwks: jwks, verify_jti: false, verify_aud: false, **request_sig_enc_opts)
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
- bearer_token = fetch_access_token
19
+ access_token = fetch_access_token
20
20
 
21
- return unless bearer_token
21
+ return unless access_token
22
22
 
23
23
  # where in resource server, NOT the authorization server.
24
- payload = introspection_request("access_token", bearer_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,