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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1 -1
  3. data/MIGRATION-GUIDE-v1.md +12 -0
  4. data/README.md +30 -15
  5. data/doc/release_notes/0_1_0.md +2 -2
  6. data/doc/release_notes/0_2_0.md +1 -1
  7. data/doc/release_notes/0_3_0.md +1 -1
  8. data/doc/release_notes/0_5_0.md +2 -2
  9. data/doc/release_notes/0_8_0.md +2 -2
  10. data/doc/release_notes/1_0_0.md +79 -0
  11. data/lib/generators/rodauth/oauth/templates/app/views/rodauth/authorize.html.erb +19 -7
  12. data/lib/generators/rodauth/oauth/templates/app/views/rodauth/authorize_error.erb +10 -0
  13. data/lib/generators/rodauth/oauth/templates/db/migrate/create_rodauth_oauth.rb +54 -43
  14. data/lib/rodauth/features/oauth_application_management.rb +2 -2
  15. data/lib/rodauth/features/oauth_authorization_code_grant.rb +31 -7
  16. data/lib/rodauth/features/oauth_authorize_base.rb +32 -10
  17. data/lib/rodauth/features/oauth_base.rb +36 -16
  18. data/lib/rodauth/features/oauth_dynamic_client_registration.rb +7 -4
  19. data/lib/rodauth/features/oauth_implicit_grant.rb +16 -5
  20. data/lib/rodauth/features/oauth_jwt.rb +3 -3
  21. data/lib/rodauth/features/oauth_jwt_base.rb +29 -6
  22. data/lib/rodauth/features/oauth_jwt_bearer_grant.rb +7 -4
  23. data/lib/rodauth/features/oauth_jwt_secured_authorization_request.rb +64 -10
  24. data/lib/rodauth/features/oauth_resource_indicators.rb +0 -4
  25. data/lib/rodauth/features/oauth_resource_server.rb +3 -3
  26. data/lib/rodauth/features/oauth_saml_bearer_grant.rb +2 -0
  27. data/lib/rodauth/features/oidc.rb +263 -187
  28. data/lib/rodauth/features/oidc_dynamic_client_registration.rb +65 -25
  29. data/lib/rodauth/features/oidc_rp_initiated_logout.rb +118 -0
  30. data/lib/rodauth/oauth/http_extensions.rb +15 -2
  31. data/lib/rodauth/oauth/ttl_store.rb +2 -0
  32. data/lib/rodauth/oauth/version.rb +1 -1
  33. data/locales/en.yml +4 -1
  34. data/locales/pt.yml +4 -1
  35. data/templates/authorize.str +17 -10
  36. data/templates/authorize_error.str +12 -0
  37. metadata +15 -12
  38. 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", register_invalid_param_message("subject_type"))
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", register_invalid_param_message("id_token_signed_response_alg"))
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 (value = @oauth_application_params[oauth_applications_id_token_encrypted_response_alg_column]) &&
92
- !oauth_jwt_jwe_algorithms_supported.include?(value)
93
- register_throw_json_response_error("invalid_client_metadata", register_invalid_param_message("id_token_encrypted_response_alg"))
94
- end
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
- if (value = @oauth_application_params[oauth_applications_id_token_encrypted_response_enc_column]) &&
97
- !oauth_jwt_jwe_encryption_methods_supported.include?(value)
98
- register_throw_json_response_error("invalid_client_metadata", register_invalid_param_message("id_token_encrypted_response_enc"))
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 (value = @oauth_application_params[oauth_applications_userinfo_signed_response_alg_column]) &&
102
- !oauth_jwt_jws_algorithms_supported.include?(value)
103
- register_throw_json_response_error("invalid_client_metadata", register_invalid_param_message("userinfo_signed_response_alg"))
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[oauth_applications_userinfo_encrypted_response_alg_column]) &&
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", register_invalid_param_message("userinfo_encrypted_response_alg"))
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[oauth_applications_userinfo_encrypted_response_enc_column]) &&
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", register_invalid_param_message("userinfo_encrypted_response_enc"))
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 defined?(oauth_applications_request_object_signing_alg_column) &&
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", register_invalid_param_message("request_object_signing_alg"))
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 defined?(oauth_applications_request_object_encryption_alg_column) &&
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", register_invalid_param_message("request_object_encryption_alg"))
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 defined?(oauth_applications_request_object_encryption_enc_column) &&
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", register_invalid_param_message("request_object_encryption_enc"))
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[/max-age=(\d+)/, 1].to_i
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
- Time.parse(response["expires"]).to_i - Time.now.to_i
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.
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Rodauth
4
4
  module OAuth
5
- VERSION = "1.0.0-beta1"
5
+ VERSION = "1.0.0"
6
6
  end
7
7
  end
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"
@@ -9,12 +9,13 @@
9
9
  }
10
10
  <p class="lead">
11
11
  #{
12
- rodauth.authorize_page_lead(name: <<-LINK
13
- <a target="_blank" href="#{h(rodauth.oauth_application[rodauth.oauth_applications_homepage_url_column])}">
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
- <<-HTML
64
- <div class="form-check">
65
- <input id="#{scope}" class="form-check-input" type="checkbox" name="scope[]" value="#{h(scope)}">
66
- <label class="form-check-label" for="#{scope}">#{h(scope)}</label>
67
- </div>
68
- HTML
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=\"acr\" value=\"#{rodauth.param("acr_values")}\"/>" if rodauth.features.include?(:oidc) && rodauth.param_or_nil("acr_values")}
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|
@@ -0,0 +1,12 @@
1
+ <div class="container">
2
+ <div class="alert alert-danger">
3
+ <p>
4
+ #{@error}
5
+ </p>
6
+ </div>
7
+ <p class="text-center">
8
+ <a href="#{@back_url}" class="btn btn-outline-danger">
9
+ #{rodauth.oauth_cancel_button}
10
+ </a>
11
+ </p>
12
+ </div>
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.pre.beta1
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-10-21 00:00:00.000000000 Z
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/1_0_0_beta1.md
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/1_0_0_beta1.md
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/honeyryderchuck/rodauth-oauth
172
+ homepage: https://gitlab.com/os85/rodauth-oauth
170
173
  licenses:
171
174
  - Apache-2.0
172
175
  metadata:
173
- homepage_uri: https://honeyryderchuck.gitlab.io/rodauth-oauth/
174
- documentation_uri: https://honeyryderchuck.gitlab.io/rodauth-oauth/rdoc/
175
- bug_tracker_uri: https://gitlab.com/honeyryderchuck/rodauth-oauth/issues
176
- source_code_uri: https://gitlab.com/honeyryderchuck/rodauth-oauth
177
- changelog_uri: https://gitlab.com/honeyryderchuck/rodauth-oauth/-/blob/master/CHANGELOG.md
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: 1.3.1
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.