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.
- 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,
|