rodauth-oauth 1.0.0.pre.beta1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -51,9 +51,25 @@ module Rodauth
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
+
if features.include?(:oauth_jwt_secured_authorization_request)
|
55
|
+
if (value = @oauth_application_params[oauth_applications_request_uris_column])
|
56
|
+
if value.is_a?(Array)
|
57
|
+
@oauth_application_params[oauth_applications_request_uris_column] = value.each do |req_uri|
|
58
|
+
unless check_valid_uri?(req_uri)
|
59
|
+
register_throw_json_response_error("invalid_redirect_uri", register_invalid_uri_message(req_uri))
|
60
|
+
end
|
61
|
+
end.join(" ")
|
62
|
+
else
|
63
|
+
register_throw_json_response_error("invalid_redirect_uri", register_invalid_uri_message(value))
|
64
|
+
end
|
65
|
+
elsif oauth_require_request_uri_registration
|
66
|
+
register_throw_json_response_error("invalid_client_metadata", register_required_param_message("request_uris"))
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
54
70
|
if (value = @oauth_application_params[oauth_applications_subject_type_column])
|
55
71
|
unless %w[pairwise public].include?(value)
|
56
|
-
register_throw_json_response_error("invalid_client_metadata",
|
72
|
+
register_throw_json_response_error("invalid_client_metadata", register_invalid_client_metadata_message("subject_type", value))
|
57
73
|
end
|
58
74
|
|
59
75
|
if value == "pairwise"
|
@@ -84,51 +100,75 @@ module Rodauth
|
|
84
100
|
register_throw_json_response_error("invalid_client_metadata", register_invalid_param_message("id_token_signed_response_alg"))
|
85
101
|
end
|
86
102
|
elsif !oauth_jwt_jws_algorithms_supported.include?(value)
|
87
|
-
register_throw_json_response_error("invalid_client_metadata",
|
103
|
+
register_throw_json_response_error("invalid_client_metadata",
|
104
|
+
register_invalid_client_metadata_message("id_token_signed_response_alg", value))
|
88
105
|
end
|
89
106
|
end
|
90
107
|
|
91
|
-
if (
|
92
|
-
|
93
|
-
|
94
|
-
|
108
|
+
if features.include?(:oauth_jwt_secured_authorization_request)
|
109
|
+
if defined?(oauth_applications_request_object_signing_alg_column) &&
|
110
|
+
(value = @oauth_application_params[oauth_applications_request_object_signing_alg_column]) &&
|
111
|
+
!oauth_jwt_jws_algorithms_supported.include?(value) && !(value == "none" && oauth_request_object_signing_alg_allow_none)
|
112
|
+
register_throw_json_response_error("invalid_client_metadata",
|
113
|
+
register_invalid_client_metadata_message("request_object_signing_alg", value))
|
114
|
+
end
|
95
115
|
|
96
|
-
|
97
|
-
|
98
|
-
|
116
|
+
if defined?(oauth_applications_request_object_encryption_alg_column) &&
|
117
|
+
(value = @oauth_application_params[oauth_applications_request_object_encryption_alg_column]) &&
|
118
|
+
!oauth_jwt_jwe_algorithms_supported.include?(value)
|
119
|
+
register_throw_json_response_error("invalid_client_metadata",
|
120
|
+
register_invalid_client_metadata_message("request_object_encryption_alg", value))
|
121
|
+
end
|
122
|
+
|
123
|
+
if defined?(oauth_applications_request_object_encryption_enc_column) &&
|
124
|
+
(value = @oauth_application_params[oauth_applications_request_object_encryption_enc_column]) &&
|
125
|
+
!oauth_jwt_jwe_encryption_methods_supported.include?(value)
|
126
|
+
register_throw_json_response_error("invalid_client_metadata",
|
127
|
+
register_invalid_client_metadata_message("request_object_encryption_enc", value))
|
128
|
+
end
|
99
129
|
end
|
100
130
|
|
101
|
-
if (
|
102
|
-
|
103
|
-
|
131
|
+
if features.include?(:oidc_rp_initiated_logout) && (defined?(oauth_applications_post_logout_redirect_uris_column) &&
|
132
|
+
(value = @oauth_application_params[oauth_applications_post_logout_redirect_uris_column]))
|
133
|
+
if value.is_a?(Array)
|
134
|
+
@oauth_application_params[oauth_applications_post_logout_redirect_uris_column] = value.each do |redirect_uri|
|
135
|
+
unless check_valid_uri?(redirect_uri)
|
136
|
+
register_throw_json_response_error("invalid_client_metadata", register_invalid_uri_message(redirect_uri))
|
137
|
+
end
|
138
|
+
end.join(" ")
|
139
|
+
else
|
140
|
+
register_throw_json_response_error("invalid_client_metadata", register_invalid_uri_message(value))
|
141
|
+
end
|
104
142
|
end
|
105
143
|
|
106
|
-
if (value = @oauth_application_params[
|
144
|
+
if (value = @oauth_application_params[oauth_applications_id_token_encrypted_response_alg_column]) &&
|
107
145
|
!oauth_jwt_jwe_algorithms_supported.include?(value)
|
108
|
-
register_throw_json_response_error("invalid_client_metadata",
|
146
|
+
register_throw_json_response_error("invalid_client_metadata",
|
147
|
+
register_invalid_client_metadata_message("id_token_encrypted_response_alg", value))
|
109
148
|
end
|
110
149
|
|
111
|
-
if (value = @oauth_application_params[
|
150
|
+
if (value = @oauth_application_params[oauth_applications_id_token_encrypted_response_enc_column]) &&
|
112
151
|
!oauth_jwt_jwe_encryption_methods_supported.include?(value)
|
113
|
-
register_throw_json_response_error("invalid_client_metadata",
|
152
|
+
register_throw_json_response_error("invalid_client_metadata",
|
153
|
+
register_invalid_client_metadata_message("id_token_encrypted_response_enc", value))
|
114
154
|
end
|
115
155
|
|
116
|
-
if
|
117
|
-
(value = @oauth_application_params[oauth_applications_request_object_signing_alg_column]) &&
|
156
|
+
if (value = @oauth_application_params[oauth_applications_userinfo_signed_response_alg_column]) &&
|
118
157
|
!oauth_jwt_jws_algorithms_supported.include?(value)
|
119
|
-
register_throw_json_response_error("invalid_client_metadata",
|
158
|
+
register_throw_json_response_error("invalid_client_metadata",
|
159
|
+
register_invalid_client_metadata_message("userinfo_signed_response_alg", value))
|
120
160
|
end
|
121
161
|
|
122
|
-
if
|
123
|
-
(value = @oauth_application_params[oauth_applications_request_object_encryption_alg_column]) &&
|
162
|
+
if (value = @oauth_application_params[oauth_applications_userinfo_encrypted_response_alg_column]) &&
|
124
163
|
!oauth_jwt_jwe_algorithms_supported.include?(value)
|
125
|
-
register_throw_json_response_error("invalid_client_metadata",
|
164
|
+
register_throw_json_response_error("invalid_client_metadata",
|
165
|
+
register_invalid_client_metadata_message("userinfo_encrypted_response_alg", value))
|
126
166
|
end
|
127
167
|
|
128
|
-
if
|
129
|
-
(value = @oauth_application_params[oauth_applications_request_object_encryption_enc_column]) &&
|
168
|
+
if (value = @oauth_application_params[oauth_applications_userinfo_encrypted_response_enc_column]) &&
|
130
169
|
!oauth_jwt_jwe_encryption_methods_supported.include?(value)
|
131
|
-
register_throw_json_response_error("invalid_client_metadata",
|
170
|
+
register_throw_json_response_error("invalid_client_metadata",
|
171
|
+
register_invalid_client_metadata_message("userinfo_encrypted_response_enc", value))
|
132
172
|
end
|
133
173
|
end
|
134
174
|
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rodauth/oauth"
|
4
|
+
|
5
|
+
module Rodauth
|
6
|
+
Feature.define(:oidc_rp_initiated_logout, :OidcRpInitiatedLogout) do
|
7
|
+
depends :oidc
|
8
|
+
|
9
|
+
auth_value_method :oauth_applications_post_logout_redirect_uris_column, :post_logout_redirect_uris
|
10
|
+
translatable_method :oauth_invalid_post_logout_redirect_uri_message, "Invalid post logout redirect URI"
|
11
|
+
|
12
|
+
# /oidc-logout
|
13
|
+
auth_server_route(:oidc_logout) do |r|
|
14
|
+
require_authorizable_account
|
15
|
+
before_oidc_logout_route
|
16
|
+
|
17
|
+
# OpenID Providers MUST support the use of the HTTP GET and POST methods
|
18
|
+
r.on method: %i[get post] do
|
19
|
+
catch_error do
|
20
|
+
validate_oidc_logout_params
|
21
|
+
|
22
|
+
oauth_application = nil
|
23
|
+
|
24
|
+
if (id_token_hint = param_or_nil("id_token_hint"))
|
25
|
+
#
|
26
|
+
# why this is done:
|
27
|
+
#
|
28
|
+
# we need to decode the id token in order to get the application, because, if the
|
29
|
+
# signing key is application-specific, we don't know how to verify the signature
|
30
|
+
# beforehand. Hence, we have to do it twice: decode-and-do-not-verify, initialize
|
31
|
+
# the @oauth_application, and then decode-and-verify.
|
32
|
+
#
|
33
|
+
claims = jwt_decode(id_token_hint, verify_claims: false)
|
34
|
+
|
35
|
+
redirect_logout_with_error(oauth_invalid_client_message) unless claims
|
36
|
+
|
37
|
+
oauth_application = db[oauth_applications_table].where(oauth_applications_client_id_column => claims["aud"]).first
|
38
|
+
oauth_grant = db[oauth_grants_table]
|
39
|
+
.where(
|
40
|
+
oauth_grants_oauth_application_id_column => oauth_application[oauth_applications_id_column],
|
41
|
+
oauth_grants_account_id_column => account_id
|
42
|
+
).first
|
43
|
+
|
44
|
+
# check whether ID token belongs to currently logged-in user
|
45
|
+
redirect_logout_with_error(oauth_invalid_client_message) unless oauth_grant && claims["sub"] == jwt_subject(oauth_grant,
|
46
|
+
oauth_application)
|
47
|
+
|
48
|
+
# When an id_token_hint parameter is present, the OP MUST validate that it was the issuer of the ID Token.
|
49
|
+
redirect_logout_with_error(oauth_invalid_client_message) unless claims && claims["iss"] == oauth_jwt_issuer
|
50
|
+
end
|
51
|
+
|
52
|
+
# now let's logout from IdP
|
53
|
+
transaction do
|
54
|
+
before_logout
|
55
|
+
logout
|
56
|
+
after_logout
|
57
|
+
end
|
58
|
+
|
59
|
+
error_message = logout_notice_flash
|
60
|
+
|
61
|
+
if (post_logout_redirect_uri = param_or_nil("post_logout_redirect_uri"))
|
62
|
+
error_message = catch(:default_logout_redirect) do
|
63
|
+
oauth_application = db[oauth_applications_table].where(oauth_applications_client_id_column => claims["client_id"]).first
|
64
|
+
|
65
|
+
throw(:default_logout_redirect, oauth_invalid_client_message) unless oauth_application
|
66
|
+
|
67
|
+
post_logout_redirect_uris = oauth_application[oauth_applications_post_logout_redirect_uris_column].split(" ")
|
68
|
+
|
69
|
+
unless post_logout_redirect_uris.include?(post_logout_redirect_uri)
|
70
|
+
throw(:default_logout_redirect,
|
71
|
+
oauth_invalid_post_logout_redirect_uri_message)
|
72
|
+
end
|
73
|
+
|
74
|
+
if (state = param_or_nil("state"))
|
75
|
+
post_logout_redirect_uri = URI(post_logout_redirect_uri)
|
76
|
+
params = ["state=#{CGI.escape(state)}"]
|
77
|
+
params << post_logout_redirect_uri.query if post_logout_redirect_uri.query
|
78
|
+
post_logout_redirect_uri.query = params.join("&")
|
79
|
+
post_logout_redirect_uri = post_logout_redirect_uri.to_s
|
80
|
+
end
|
81
|
+
|
82
|
+
redirect(post_logout_redirect_uri)
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
redirect_logout_with_error(error_message)
|
88
|
+
end
|
89
|
+
|
90
|
+
redirect_response_error("invalid_request")
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
# Logout
|
97
|
+
|
98
|
+
def validate_oidc_logout_params
|
99
|
+
# check if valid token hint type
|
100
|
+
return unless (redirect_uri = param_or_nil("post_logout_redirect_uri"))
|
101
|
+
|
102
|
+
return if check_valid_no_fragment_uri?(redirect_uri)
|
103
|
+
|
104
|
+
redirect_logout_with_error(oauth_invalid_client_message)
|
105
|
+
end
|
106
|
+
|
107
|
+
def redirect_logout_with_error(error_message = oauth_invalid_client_message)
|
108
|
+
set_notice_flash(error_message)
|
109
|
+
redirect(logout_redirect)
|
110
|
+
end
|
111
|
+
|
112
|
+
def oauth_server_metadata_body(*)
|
113
|
+
super.tap do |data|
|
114
|
+
data[:end_session_endpoint] = oidc_logout_url
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -16,6 +16,9 @@ module Rodauth
|
|
16
16
|
|
17
17
|
http = Net::HTTP.new(uri.host, uri.port)
|
18
18
|
http.use_ssl = uri.scheme == "https"
|
19
|
+
http.open_timeout = 15
|
20
|
+
http.read_timeout = 15
|
21
|
+
http.write_timeout = 15 if http.respond_to?(:write_timeout)
|
19
22
|
|
20
23
|
if form_data
|
21
24
|
request = Net::HTTP::Post.new(uri.request_uri)
|
@@ -44,9 +47,19 @@ module Rodauth
|
|
44
47
|
response = http_request(uri, *args)
|
45
48
|
ttl = if response.key?("cache-control")
|
46
49
|
cache_control = response["cache-control"]
|
47
|
-
cache_control
|
50
|
+
if cache_control.include?("no-cache")
|
51
|
+
nil
|
52
|
+
else
|
53
|
+
max_age = cache_control[/max-age=(\d+)/, 1].to_i
|
54
|
+
max_age.zero? ? nil : max_age
|
55
|
+
end
|
48
56
|
elsif response.key?("expires")
|
49
|
-
|
57
|
+
expires = response["expires"]
|
58
|
+
begin
|
59
|
+
Time.parse(expires).to_i - Time.now.to_i
|
60
|
+
rescue ArgumentError
|
61
|
+
nil
|
62
|
+
end
|
50
63
|
end
|
51
64
|
|
52
65
|
[JSON.parse(response.body, symbolize_names: true), ttl]
|
@@ -28,6 +28,8 @@ class Rodauth::OAuth::TtlStore
|
|
28
28
|
|
29
29
|
payload, ttl = block.call
|
30
30
|
|
31
|
+
return payload unless ttl
|
32
|
+
|
31
33
|
@store_mutex.synchronize do
|
32
34
|
# given that the block call triggers network, and two requests for the same key be processed
|
33
35
|
# at the same time, this ensures the first one wins.
|
data/locales/en.yml
CHANGED
@@ -9,6 +9,7 @@ en:
|
|
9
9
|
user_code_not_found_error_flash: "No device to authorize with the given user code"
|
10
10
|
authorize_page_title: "Authorize"
|
11
11
|
authorize_page_lead: "The application %{name} would like to access your data."
|
12
|
+
authorize_error_page_title: "Authorize Error"
|
12
13
|
oauth_cancel_button: "Cancel"
|
13
14
|
oauth_applications_page_title: "Oauth Applications"
|
14
15
|
oauth_application_page_title: "Oauth Application"
|
@@ -55,6 +56,7 @@ en:
|
|
55
56
|
invalid_url_message: "Invalid URL"
|
56
57
|
oauth_unsupported_token_type_message: "Invalid token type hint"
|
57
58
|
null_error_message: "is not filled"
|
59
|
+
oauth_unsupported_response_type_message: "Unsupported response type"
|
58
60
|
oauth_already_in_use_message: "error generating unique token"
|
59
61
|
oauth_expired_token_message: "the device code has expired"
|
60
62
|
oauth_access_denied_message: "the authorization request has been denied"
|
@@ -62,6 +64,7 @@ en:
|
|
62
64
|
oauth_slow_down_message: "authorization request is still pending but poll interval should be increased"
|
63
65
|
oauth_code_challenge_required_message: "code challenge required"
|
64
66
|
oauth_unsupported_transform_algorithm_message: "transform algorithm not supported"
|
65
|
-
oauth_request_uri_not_supported_message: "request uri is unsupported"
|
66
67
|
oauth_invalid_request_object_message: "request object is invalid"
|
67
68
|
oauth_invalid_scope_message: "The Access Token expired"
|
69
|
+
oauth_authorize_parameter_required: "Invalid or missing '%{parameter}'"
|
70
|
+
oauth_invalid_post_logout_redirect_uri_message: "Invalid post logout redirect URI"
|
data/locales/pt.yml
CHANGED
@@ -9,6 +9,7 @@ pt:
|
|
9
9
|
user_code_not_found_error_flash: "Não existe nenhum dispositivo a ser autorizado com o código de usuário inserido"
|
10
10
|
authorize_page_title: "Autorizar"
|
11
11
|
authorize_page_lead: "O aplicativo %{name} gostaria de aceder aos seus dados."
|
12
|
+
authorize_error_page_title: Erro de autorização
|
12
13
|
oauth_cancel_button: "Cancelar"
|
13
14
|
oauth_applications_page_title: "Aplicativos OAuth"
|
14
15
|
oauth_application_page_title: "Aplicativo Oauth"
|
@@ -55,6 +56,7 @@ pt:
|
|
55
56
|
invalid_url_message: "URL inválido"
|
56
57
|
oauth_unsupported_token_type_message: "Sugestão de tipo de token inválida"
|
57
58
|
null_error_message: "não está preenchido"
|
59
|
+
oauth_unsupported_response_type_message: "Tipo de resposta inválido"
|
58
60
|
oauth_already_in_use_message: "erro ao gerar token único"
|
59
61
|
oauth_expired_token_message: "o código de dispositivo expirou"
|
60
62
|
oauth_access_denied_message: "o pedido de autorização foi negado"
|
@@ -62,6 +64,7 @@ pt:
|
|
62
64
|
oauth_slow_down_message: "o pedido de autorização ainda está pendente mas o intervalo de actualização deve ser aumentado"
|
63
65
|
oauth_code_challenge_required_message: "código de negociação necessário"
|
64
66
|
oauth_unsupported_transform_algorithm_message: "algoritmo de transformação não suportado"
|
65
|
-
oauth_request_uri_not_supported_message: "request_uri não é suportado"
|
66
67
|
oauth_invalid_request_object_message: "request_object é inválido"
|
67
68
|
oauth_invalid_scope_message: "O Token de acesso expirou"
|
69
|
+
oauth_authorize_parameter_required: "'%{parameter}' inválido ou em falta"
|
70
|
+
oauth_invalid_post_logout_redirect_uri_message: "URI de redireccionamento pós-logout inválido"
|
data/templates/authorize.str
CHANGED
@@ -9,12 +9,13 @@
|
|
9
9
|
}
|
10
10
|
<p class="lead">
|
11
11
|
#{
|
12
|
-
rodauth.
|
13
|
-
|
12
|
+
application_uri = rodauth.oauth_application[rodauth.oauth_applications_homepage_url_column]
|
13
|
+
application_name = application_uri ? (<<-LINK) : rodauth.oauth_application[rodauth.oauth_applications_name_column]
|
14
|
+
<a target="_blank" href="#{h(application_uri)}">
|
14
15
|
#{h(rodauth.oauth_application[rodauth.oauth_applications_name_column])}
|
15
16
|
</a>
|
16
17
|
LINK
|
17
|
-
)
|
18
|
+
rodauth.authorize_page_lead(name: application_name)
|
18
19
|
}
|
19
20
|
</p>
|
20
21
|
<div class="list-group">
|
@@ -60,12 +61,16 @@
|
|
60
61
|
|
61
62
|
#{
|
62
63
|
rodauth.authorize_scopes.map do |scope|
|
63
|
-
|
64
|
-
<
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
64
|
+
if rodauth.features.include?(:oidc) && scope == "offline_access"
|
65
|
+
"<input type=\"hidden\" name=\"scope[]\" value=\"#{scope}\" />"
|
66
|
+
else
|
67
|
+
<<-HTML
|
68
|
+
<div class="form-check">
|
69
|
+
<input id="#{scope}" class="form-check-input" type="checkbox" name="scope[]" value="#{h(scope)}">
|
70
|
+
<label class="form-check-label" for="#{scope}">#{h(scope)}</label>
|
71
|
+
</div>
|
72
|
+
HTML
|
73
|
+
end
|
69
74
|
end.join
|
70
75
|
}
|
71
76
|
|
@@ -77,10 +82,12 @@
|
|
77
82
|
#{"<input type=\"hidden\" name=\"redirect_uri\" value=\"#{rodauth.redirect_uri}\"/>" if rodauth.param_or_nil("redirect_uri")}
|
78
83
|
#{"<input type=\"hidden\" name=\"code_challenge\" value=\"#{rodauth.param("code_challenge")}\"/>" if rodauth.features.include?(:oauth_pkce) && rodauth.param_or_nil("code_challenge")}
|
79
84
|
#{"<input type=\"hidden\" name=\"code_challenge_method\" value=\"#{rodauth.param("code_challenge_method")}\"/>" if rodauth.features.include?(:oauth_pkce) && rodauth.param_or_nil("code_challenge_method")}
|
85
|
+
#{"<input type=\"hidden\" name=\"prompt\" value=\"#{rodauth.param("prompt")}\"/>" if rodauth.features.include?(:oidc) && rodauth.param_or_nil("prompt")}
|
80
86
|
#{"<input type=\"hidden\" name=\"nonce\" value=\"#{rodauth.param("nonce")}\"/>" if rodauth.features.include?(:oidc) && rodauth.param_or_nil("nonce")}
|
81
87
|
#{"<input type=\"hidden\" name=\"ui_locales\" value=\"#{rodauth.param("ui_locales")}\"/>" if rodauth.features.include?(:oidc) && rodauth.param_or_nil("ui_locales")}
|
82
88
|
#{"<input type=\"hidden\" name=\"claims_locales\" value=\"#{rodauth.param("claims_locales")}\"/>" if rodauth.features.include?(:oidc) && rodauth.param_or_nil("claims_locales")}
|
83
|
-
#{"<input type=\"hidden\" name=\"
|
89
|
+
#{"<input type=\"hidden\" name=\"claims\" value=\"#{h(rodauth.param("claims"))}\"/>" if rodauth.features.include?(:oidc) && rodauth.param_or_nil("claims")}
|
90
|
+
#{"<input type=\"hidden\" name=\"acr_values\" value=\"#{rodauth.param("acr_values")}\"/>" if rodauth.features.include?(:oidc) && rodauth.param_or_nil("acr_values")}
|
84
91
|
#{
|
85
92
|
if rodauth.features.include?(:oauth_resource_indicators) && rodauth.resource_indicators
|
86
93
|
rodauth.resource_indicators.map do |resource|
|
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.0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tiago Cardoso
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-12-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rodauth
|
@@ -66,7 +66,7 @@ extra_rdoc_files:
|
|
66
66
|
- doc/release_notes/0_9_1.md
|
67
67
|
- doc/release_notes/0_9_2.md
|
68
68
|
- doc/release_notes/0_9_3.md
|
69
|
-
- doc/release_notes/
|
69
|
+
- doc/release_notes/1_0_0.md
|
70
70
|
files:
|
71
71
|
- CHANGELOG.md
|
72
72
|
- LICENSE.txt
|
@@ -104,11 +104,12 @@ files:
|
|
104
104
|
- doc/release_notes/0_9_1.md
|
105
105
|
- doc/release_notes/0_9_2.md
|
106
106
|
- doc/release_notes/0_9_3.md
|
107
|
-
- doc/release_notes/
|
107
|
+
- doc/release_notes/1_0_0.md
|
108
108
|
- lib/generators/rodauth/oauth/install_generator.rb
|
109
109
|
- lib/generators/rodauth/oauth/templates/app/models/oauth_application.rb
|
110
110
|
- lib/generators/rodauth/oauth/templates/app/models/oauth_grant.rb
|
111
111
|
- lib/generators/rodauth/oauth/templates/app/views/rodauth/authorize.html.erb
|
112
|
+
- lib/generators/rodauth/oauth/templates/app/views/rodauth/authorize_error.erb
|
112
113
|
- lib/generators/rodauth/oauth/templates/app/views/rodauth/device_search.html.erb
|
113
114
|
- lib/generators/rodauth/oauth/templates/app/views/rodauth/device_verification.html.erb
|
114
115
|
- lib/generators/rodauth/oauth/templates/app/views/rodauth/new_oauth_application.html.erb
|
@@ -142,6 +143,7 @@ files:
|
|
142
143
|
- lib/rodauth/features/oauth_token_revocation.rb
|
143
144
|
- lib/rodauth/features/oidc.rb
|
144
145
|
- lib/rodauth/features/oidc_dynamic_client_registration.rb
|
146
|
+
- lib/rodauth/features/oidc_rp_initiated_logout.rb
|
145
147
|
- lib/rodauth/oauth.rb
|
146
148
|
- lib/rodauth/oauth/database_extensions.rb
|
147
149
|
- lib/rodauth/oauth/http_extensions.rb
|
@@ -152,6 +154,7 @@ files:
|
|
152
154
|
- locales/en.yml
|
153
155
|
- locales/pt.yml
|
154
156
|
- templates/authorize.str
|
157
|
+
- templates/authorize_error.str
|
155
158
|
- templates/client_secret_field.str
|
156
159
|
- templates/description_field.str
|
157
160
|
- templates/device_search.str
|
@@ -166,15 +169,15 @@ files:
|
|
166
169
|
- templates/oauth_grants.str
|
167
170
|
- templates/redirect_uri_field.str
|
168
171
|
- templates/scope_field.str
|
169
|
-
homepage: https://gitlab.com/
|
172
|
+
homepage: https://gitlab.com/os85/rodauth-oauth
|
170
173
|
licenses:
|
171
174
|
- Apache-2.0
|
172
175
|
metadata:
|
173
|
-
homepage_uri: https://
|
174
|
-
documentation_uri: https://
|
175
|
-
bug_tracker_uri: https://gitlab.com/
|
176
|
-
source_code_uri: https://gitlab.com/
|
177
|
-
changelog_uri: https://gitlab.com/
|
176
|
+
homepage_uri: https://os85.gitlab.io/rodauth-oauth/
|
177
|
+
documentation_uri: https://os85.gitlab.io/rodauth-oauth/rdoc/
|
178
|
+
bug_tracker_uri: https://gitlab.com/os85/rodauth-oauth/issues
|
179
|
+
source_code_uri: https://gitlab.com/os85/rodauth-oauth
|
180
|
+
changelog_uri: https://gitlab.com/os85/rodauth-oauth/-/blob/master/CHANGELOG.md
|
178
181
|
rubygems_mfa_required: 'true'
|
179
182
|
post_install_message:
|
180
183
|
rdoc_options: []
|
@@ -187,9 +190,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
187
190
|
version: 2.5.0
|
188
191
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
189
192
|
requirements:
|
190
|
-
- - "
|
193
|
+
- - ">="
|
191
194
|
- !ruby/object:Gem::Version
|
192
|
-
version:
|
195
|
+
version: '0'
|
193
196
|
requirements: []
|
194
197
|
rubygems_version: 3.2.32
|
195
198
|
signing_key:
|
@@ -1,38 +0,0 @@
|
|
1
|
-
## 1.0.0-beta1 (21/10/2022)
|
2
|
-
|
3
|
-
### Breaking changes
|
4
|
-
|
5
|
-
The full description of breaking changes, and suggestions on how to make the migration smoother, can be found in the [migration guide](https://gitlab.com/honeyryderchuck/rodauth-oauth/-/blob/6465b8522a78cf0037a55d3d4b81f68f7811be68/MIGRATION-GUIDE-v1.md).
|
6
|
-
|
7
|
-
A short list of the main highlights:
|
8
|
-
|
9
|
-
|
10
|
-
* Ruby 2.5 or higher is required.
|
11
|
-
* `oauth_http_mac` feature removed.
|
12
|
-
* `oauth_tokens` table (and resource) were removed (only `oauth_applications` and `oauth_grants`, access and refresh tokens are now properties of the latter).
|
13
|
-
* access and refresh tokens hashed by default when stored in the database.
|
14
|
-
* default oauth response mode is `"form_post"`.
|
15
|
-
* oauth specific features require explicit enablement of respective features (no more `enable :oauth`)
|
16
|
-
* refresh token policy is "rotation" by default
|
17
|
-
|
18
|
-
### Features
|
19
|
-
|
20
|
-
The following helpers are exposed in the `rodauth` object:
|
21
|
-
|
22
|
-
* `current_oauth_account` - returns the dataset row for the `rodauth` account associated to an oauth access token in the "authorization" header.
|
23
|
-
* `current_oauth_application` - returns the dataset row for the oauth application associated to an oauth access token in the "authorization" header.
|
24
|
-
|
25
|
-
When used in `rails` via `rodauth-rails`, both are exposed directly as controller helpers.
|
26
|
-
|
27
|
-
#### `oauth_resource_server` plugin
|
28
|
-
|
29
|
-
This plugin can be used as a convenience when configuring resource servers.
|
30
|
-
|
31
|
-
### Improvements
|
32
|
-
|
33
|
-
* `:oauth_introspect` plugin: OAuth introspection endpoint exposes the token's `"username"` claim.
|
34
|
-
* endpoint client authentication supports "client credentials grant" access tokens.
|
35
|
-
|
36
|
-
### Bugfixes
|
37
|
-
|
38
|
-
* fixed `oidc` calculation of `"auth_time"` claim.
|