rodauth-oauth 1.0.0.pre.beta1 → 1.0.0.pre.beta2
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 +6 -5
- data/doc/release_notes/1_0_0_beta2.md +34 -0
- data/lib/generators/rodauth/oauth/templates/app/views/rodauth/authorize.html.erb +19 -7
- 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 -6
- data/lib/rodauth/features/oauth_authorize_base.rb +16 -6
- data/lib/rodauth/features/oauth_base.rb +35 -16
- data/lib/rodauth/features/oauth_dynamic_client_registration.rb +7 -4
- data/lib/rodauth/features/oauth_implicit_grant.rb +6 -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 +231 -183
- data/lib/rodauth/features/oidc_dynamic_client_registration.rb +65 -25
- data/lib/rodauth/features/oidc_rp_initiated_logout.rb +115 -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 +3 -1
- data/locales/pt.yml +3 -1
- data/templates/authorize.str +17 -10
- metadata +5 -2
@@ -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,
|