rodauth-oauth 0.10.4 → 1.0.0.pre.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/MIGRATION-GUIDE-v1.md +286 -0
- data/README.md +22 -30
- data/doc/release_notes/1_0_0_beta1.md +38 -0
- data/lib/generators/rodauth/oauth/install_generator.rb +0 -1
- data/lib/generators/rodauth/oauth/templates/app/views/rodauth/authorize.html.erb +4 -6
- data/lib/generators/rodauth/oauth/templates/app/views/rodauth/device_search.html.erb +1 -1
- data/lib/generators/rodauth/oauth/templates/app/views/rodauth/device_verification.html.erb +2 -2
- data/lib/generators/rodauth/oauth/templates/app/views/rodauth/new_oauth_application.html.erb +1 -6
- data/lib/generators/rodauth/oauth/templates/app/views/rodauth/oauth_application.html.erb +0 -2
- data/lib/generators/rodauth/oauth/templates/app/views/rodauth/oauth_application_oauth_grants.html.erb +41 -0
- data/lib/generators/rodauth/oauth/templates/app/views/rodauth/oauth_applications.html.erb +2 -2
- data/lib/generators/rodauth/oauth/templates/app/views/rodauth/oauth_grants.html.erb +37 -0
- data/lib/generators/rodauth/oauth/templates/db/migrate/create_rodauth_oauth.rb +18 -29
- data/lib/rodauth/features/oauth_application_management.rb +59 -72
- data/lib/rodauth/features/oauth_assertion_base.rb +19 -23
- data/lib/rodauth/features/oauth_authorization_code_grant.rb +35 -88
- data/lib/rodauth/features/oauth_authorize_base.rb +103 -20
- data/lib/rodauth/features/oauth_base.rb +365 -302
- data/lib/rodauth/features/oauth_client_credentials_grant.rb +20 -18
- data/lib/rodauth/features/{oauth_device_grant.rb → oauth_device_code_grant.rb} +62 -73
- data/lib/rodauth/features/oauth_dynamic_client_registration.rb +46 -28
- data/lib/rodauth/features/oauth_grant_management.rb +70 -0
- data/lib/rodauth/features/oauth_implicit_grant.rb +25 -24
- data/lib/rodauth/features/oauth_jwt.rb +52 -688
- data/lib/rodauth/features/oauth_jwt_base.rb +435 -0
- data/lib/rodauth/features/oauth_jwt_bearer_grant.rb +45 -17
- data/lib/rodauth/features/oauth_jwt_jwks.rb +47 -0
- data/lib/rodauth/features/oauth_jwt_secured_authorization_request.rb +62 -0
- data/lib/rodauth/features/oauth_management_base.rb +2 -0
- data/lib/rodauth/features/oauth_pkce.rb +22 -26
- data/lib/rodauth/features/oauth_resource_indicators.rb +33 -21
- data/lib/rodauth/features/oauth_resource_server.rb +59 -0
- data/lib/rodauth/features/oauth_saml_bearer_grant.rb +5 -1
- data/lib/rodauth/features/oauth_token_introspection.rb +76 -46
- data/lib/rodauth/features/oauth_token_revocation.rb +46 -33
- data/lib/rodauth/features/oidc.rb +188 -95
- data/lib/rodauth/features/oidc_dynamic_client_registration.rb +89 -53
- data/lib/rodauth/oauth/database_extensions.rb +8 -6
- data/lib/rodauth/oauth/http_extensions.rb +61 -0
- data/lib/rodauth/oauth/railtie.rb +20 -0
- data/lib/rodauth/oauth/version.rb +1 -1
- data/lib/rodauth/oauth.rb +29 -1
- data/locales/en.yml +32 -22
- data/locales/pt.yml +32 -22
- data/templates/authorize.str +19 -24
- data/templates/device_search.str +1 -1
- data/templates/device_verification.str +2 -2
- data/templates/jwks_field.str +1 -0
- data/templates/new_oauth_application.str +1 -2
- data/templates/oauth_application.str +2 -2
- data/templates/oauth_application_oauth_grants.str +54 -0
- data/templates/oauth_applications.str +2 -2
- data/templates/oauth_grants.str +52 -0
- metadata +20 -16
- data/lib/generators/rodauth/oauth/templates/app/models/oauth_token.rb +0 -4
- data/lib/generators/rodauth/oauth/templates/app/views/rodauth/oauth_application_oauth_tokens.html.erb +0 -39
- data/lib/generators/rodauth/oauth/templates/app/views/rodauth/oauth_tokens.html.erb +0 -35
- data/lib/rodauth/features/oauth.rb +0 -9
- data/lib/rodauth/features/oauth_http_mac.rb +0 -86
- data/lib/rodauth/features/oauth_token_management.rb +0 -81
- data/lib/rodauth/oauth/refinements.rb +0 -48
- data/templates/jwt_public_key_field.str +0 -4
- data/templates/oauth_application_oauth_tokens.str +0 -52
- data/templates/oauth_tokens.str +0 -50
@@ -24,6 +24,19 @@ class CreateRodauthOauth < ActiveRecord::Migration<%= migration_version %>
|
|
24
24
|
# t.string :contacts, null: true
|
25
25
|
# t.string :software_id, null: true
|
26
26
|
# t.string :software_version, null: true
|
27
|
+
# oidc extra params
|
28
|
+
# t.string :sector_identifier_uri, null: true
|
29
|
+
# t.string :application_type, null: true
|
30
|
+
# t.string :subject_type, null: true
|
31
|
+
# t.string :id_token_signed_response_alg, null: true
|
32
|
+
# t.string :id_token_encrypted_response_alg, null: true
|
33
|
+
# t.string :id_token_encrypted_response_enc, null: true
|
34
|
+
# t.string :userinfo_signed_response_alg, null: true
|
35
|
+
# t.string :userinfo_encrypted_response_alg, null: true
|
36
|
+
# t.string :userinfo_encrypted_response_enc, null: true
|
37
|
+
# t.string :request_object_signing_alg, null: true
|
38
|
+
# t.string :request_object_encryption_alg, null: true
|
39
|
+
# t.string :request_object_encryption_enc, null: true
|
27
40
|
# JWT/OIDC per application signing verification
|
28
41
|
# t.text :jwt_public_key, null: true
|
29
42
|
# RP-initiated logout
|
@@ -35,8 +48,11 @@ class CreateRodauthOauth < ActiveRecord::Migration<%= migration_version %>
|
|
35
48
|
t.foreign_key :accounts, column: :account_id
|
36
49
|
t.integer :oauth_application_id
|
37
50
|
t.foreign_key :oauth_applications, column: :oauth_application_id
|
38
|
-
t.string :
|
51
|
+
t.string :type, null: true
|
52
|
+
t.string :code, null: true
|
39
53
|
t.index(%i[oauth_application_id code], unique: true)
|
54
|
+
t.string :token, unique: true
|
55
|
+
t.string :refresh_token, unique: true
|
40
56
|
t.datetime :expires_in, null: false
|
41
57
|
t.string :redirect_uri
|
42
58
|
t.datetime :revoked_at
|
@@ -47,41 +63,14 @@ class CreateRodauthOauth < ActiveRecord::Migration<%= migration_version %>
|
|
47
63
|
# uncomment to enable PKCE
|
48
64
|
# t.string :code_challenge
|
49
65
|
# t.string :code_challenge_method
|
50
|
-
# uncomment to use OIDC nonce
|
51
|
-
# t.string :nonce
|
52
66
|
# device code grant
|
53
67
|
# t.string :user_code, null: true, unique: true
|
54
68
|
# t.datetime :last_polled_at, null: true
|
55
69
|
# when using :oauth_resource_indicators feature
|
56
70
|
# t.string :resource
|
57
|
-
end
|
58
|
-
|
59
|
-
create_table :oauth_tokens do |t|
|
60
|
-
t.integer :account_id
|
61
|
-
t.foreign_key :accounts, column: :account_id
|
62
|
-
t.integer :oauth_grant_id
|
63
|
-
t.foreign_key :oauth_grants, column: :oauth_grant_id
|
64
|
-
t.integer :oauth_token_id
|
65
|
-
t.foreign_key :oauth_tokens, column: :oauth_token_id
|
66
|
-
t.integer :oauth_application_id
|
67
|
-
t.foreign_key :oauth_applications, column: :oauth_application_id
|
68
|
-
t.string :token, null: false, token: true, unique: true
|
69
|
-
# uncomment if setting oauth_tokens_token_hash_column
|
70
|
-
# and delete the token column
|
71
|
-
# t.string :token_hash, token: true, unique: true
|
72
|
-
t.string :refresh_token, unique: true
|
73
|
-
# uncomment if setting oauth_tokens_refresh_token_hash_column
|
74
|
-
# and delete the refresh_token column
|
75
|
-
# t.string :refresh_token_hash, token: true, unique: true
|
76
|
-
t.datetime :expires_in, null: false
|
77
|
-
t.datetime :revoked_at
|
78
|
-
t.string :scopes, null: false
|
79
|
-
t.datetime :created_at, null: false, default: -> { "CURRENT_TIMESTAMP" }
|
80
71
|
# uncomment to use OIDC nonce
|
81
72
|
# t.string :nonce
|
82
|
-
# t.
|
83
|
-
# when using :oauth_resource_indicators feature
|
84
|
-
# t.string :resource
|
73
|
+
# t.string :acr
|
85
74
|
end
|
86
75
|
end
|
87
76
|
end
|
@@ -1,8 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "rodauth/oauth"
|
4
|
+
|
3
5
|
module Rodauth
|
4
6
|
Feature.define(:oauth_application_management, :OauthApplicationManagement) do
|
5
|
-
depends :oauth_management_base
|
7
|
+
depends :oauth_management_base, :oauth_token_revocation
|
6
8
|
|
7
9
|
before "create_oauth_application"
|
8
10
|
after "create_oauth_application"
|
@@ -13,7 +15,7 @@ module Rodauth
|
|
13
15
|
view "oauth_applications", "Oauth Applications", "oauth_applications"
|
14
16
|
view "oauth_application", "Oauth Application", "oauth_application"
|
15
17
|
view "new_oauth_application", "New Oauth Application", "new_oauth_application"
|
16
|
-
view "
|
18
|
+
view "oauth_application_oauth_grants", "Oauth Application Grants", "oauth_application_oauth_grants"
|
17
19
|
|
18
20
|
# Application
|
19
21
|
APPLICATION_REQUIRED_PARAMS = %w[name scopes homepage_url redirect_uri client_secret].freeze
|
@@ -21,12 +23,6 @@ module Rodauth
|
|
21
23
|
|
22
24
|
(APPLICATION_REQUIRED_PARAMS + %w[description client_id]).each do |param|
|
23
25
|
auth_value_method :"oauth_application_#{param}_param", param
|
24
|
-
configuration_module_eval do
|
25
|
-
define_method :"#{param}_label" do
|
26
|
-
warn "#{__method__} is deprecated, switch to oauth_applications_#{__method__}_label"
|
27
|
-
__send__(:"oauth_applications_#{param}_label")
|
28
|
-
end
|
29
|
-
end
|
30
26
|
end
|
31
27
|
|
32
28
|
translatable_method :oauth_applications_name_label, "Name"
|
@@ -41,36 +37,42 @@ module Rodauth
|
|
41
37
|
translatable_method :oauth_applications_redirect_uri_label, "Redirect URI"
|
42
38
|
translatable_method :oauth_applications_client_secret_label, "Client Secret"
|
43
39
|
translatable_method :oauth_applications_client_id_label, "Client ID"
|
40
|
+
|
41
|
+
%w[type token refresh_token expires_in revoked_at].each do |param|
|
42
|
+
translatable_method :"oauth_grants_#{param}_label", param.gsub("_", " ").capitalize
|
43
|
+
end
|
44
|
+
|
44
45
|
button "Register", "oauth_application"
|
45
|
-
button "Revoke", "
|
46
|
+
button "Revoke", "oauth_grant_revoke"
|
46
47
|
|
47
|
-
auth_value_method :
|
48
|
+
auth_value_method :oauth_applications_oauth_grants_path, "oauth-grants"
|
48
49
|
auth_value_method :oauth_applications_route, "oauth-applications"
|
49
50
|
auth_value_method :oauth_applications_per_page, 20
|
50
51
|
auth_value_method :oauth_applications_id_pattern, Integer
|
51
|
-
auth_value_method :
|
52
|
+
auth_value_method :oauth_grants_per_page, 20
|
52
53
|
|
53
54
|
translatable_method :invalid_url_message, "Invalid URL"
|
54
55
|
translatable_method :null_error_message, "is not filled"
|
55
56
|
|
56
|
-
|
57
|
-
|
58
|
-
end
|
57
|
+
translatable_method :oauth_no_applications_text, "No oauth applications yet!"
|
58
|
+
translatable_method :oauth_no_grants_text, "No oauth grants yet!"
|
59
59
|
|
60
|
-
def oauth_applications_url(opts = {})
|
61
|
-
route_url(oauth_applications_route, opts)
|
62
|
-
end
|
63
60
|
auth_value_methods(
|
64
61
|
:oauth_application_path
|
65
62
|
)
|
66
63
|
|
64
|
+
def oauth_applications_path(opts = {})
|
65
|
+
route_path(oauth_applications_route, opts)
|
66
|
+
end
|
67
|
+
|
67
68
|
def oauth_application_path(id)
|
68
69
|
"#{oauth_applications_path}/#{id}"
|
69
70
|
end
|
70
71
|
|
71
72
|
# /oauth-applications routes
|
72
|
-
def
|
73
|
+
def load_oauth_application_management_routes
|
73
74
|
request.on(oauth_applications_route) do
|
75
|
+
check_csrf if check_csrf?
|
74
76
|
require_account
|
75
77
|
|
76
78
|
request.get "new" do
|
@@ -92,57 +94,52 @@ module Rodauth
|
|
92
94
|
end
|
93
95
|
end
|
94
96
|
|
95
|
-
request.on(
|
97
|
+
request.on(oauth_applications_oauth_grants_path) do
|
96
98
|
page = Integer(param_or_nil("page") || 1)
|
97
|
-
per_page = per_page_param(
|
98
|
-
|
99
|
-
.where(
|
100
|
-
.order(Sequel.desc(
|
101
|
-
scope.instance_variable_set(:@
|
102
|
-
request.
|
103
|
-
|
99
|
+
per_page = per_page_param(oauth_grants_per_page)
|
100
|
+
oauth_grants = db[oauth_grants_table]
|
101
|
+
.where(oauth_grants_oauth_application_id_column => id)
|
102
|
+
.order(Sequel.desc(oauth_grants_id_column))
|
103
|
+
scope.instance_variable_set(:@oauth_grants, oauth_grants.paginate(page, per_page))
|
104
|
+
request.is do
|
105
|
+
request.get do
|
106
|
+
oauth_application_oauth_grants_view
|
107
|
+
end
|
104
108
|
end
|
105
109
|
end
|
106
110
|
end
|
107
111
|
|
108
|
-
request.
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
.
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
oauth_applications_view
|
117
|
-
end
|
112
|
+
request.is do
|
113
|
+
request.get do
|
114
|
+
page = Integer(param_or_nil("page") || 1)
|
115
|
+
per_page = per_page_param(oauth_applications_per_page)
|
116
|
+
scope.instance_variable_set(:@oauth_applications, db[oauth_applications_table]
|
117
|
+
.where(oauth_applications_account_id_column => account_id)
|
118
|
+
.order(Sequel.desc(oauth_applications_id_column))
|
119
|
+
.paginate(page, per_page))
|
118
120
|
|
119
|
-
|
120
|
-
|
121
|
-
validate_oauth_application_params
|
121
|
+
oauth_applications_view
|
122
|
+
end
|
122
123
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
124
|
+
request.post do
|
125
|
+
catch_error do
|
126
|
+
validate_oauth_application_params
|
127
|
+
|
128
|
+
transaction do
|
129
|
+
before_create_oauth_application
|
130
|
+
id = create_oauth_application
|
131
|
+
after_create_oauth_application
|
132
|
+
set_notice_flash create_oauth_application_notice_flash
|
133
|
+
redirect "#{request.path}/#{id}"
|
134
|
+
end
|
129
135
|
end
|
136
|
+
set_error_flash create_oauth_application_error_flash
|
137
|
+
new_oauth_application_view
|
130
138
|
end
|
131
|
-
set_error_flash create_oauth_application_error_flash
|
132
|
-
new_oauth_application_view
|
133
139
|
end
|
134
140
|
end
|
135
141
|
end
|
136
142
|
|
137
|
-
def check_csrf?
|
138
|
-
case request.path
|
139
|
-
when oauth_applications_path
|
140
|
-
only_json? ? false : super
|
141
|
-
else
|
142
|
-
super
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
143
|
private
|
147
144
|
|
148
145
|
def oauth_application_params
|
@@ -176,7 +173,7 @@ module Rodauth
|
|
176
173
|
elsif key == oauth_application_scopes_param
|
177
174
|
|
178
175
|
value.each do |scope|
|
179
|
-
set_field_error(key,
|
176
|
+
set_field_error(key, oauth_invalid_scope_message) unless oauth_application_scopes.include?(scope)
|
180
177
|
end
|
181
178
|
end
|
182
179
|
end
|
@@ -196,28 +193,18 @@ module Rodauth
|
|
196
193
|
redirect_uris = oauth_application_params[oauth_application_redirect_uri_param]
|
197
194
|
redirect_uris = redirect_uris.to_a.reject(&:empty?).join(" ") if redirect_uris.respond_to?(:each)
|
198
195
|
create_params[oauth_applications_redirect_uri_column] = redirect_uris unless redirect_uris.empty?
|
199
|
-
# set client ID/secret pairs
|
200
196
|
|
201
|
-
|
202
|
-
|
203
|
-
secret_hash(oauth_application_params[oauth_application_client_secret_param])
|
197
|
+
# set client ID/secret pairs
|
198
|
+
set_client_secret(create_params, oauth_application_params[oauth_application_client_secret_param])
|
204
199
|
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
oauth_application_default_scope
|
209
|
-
end
|
200
|
+
if create_params[oauth_applications_scopes_column]
|
201
|
+
create_params[oauth_applications_scopes_column] = create_params[oauth_applications_scopes_column].join(oauth_scope_separator)
|
202
|
+
end
|
210
203
|
|
211
204
|
rescue_from_uniqueness_error do
|
212
205
|
create_params[oauth_applications_client_id_column] = oauth_unique_id_generator
|
213
206
|
db[oauth_applications_table].insert(create_params)
|
214
207
|
end
|
215
208
|
end
|
216
|
-
|
217
|
-
def oauth_server_metadata_body(*)
|
218
|
-
super.tap do |data|
|
219
|
-
data[:registration_endpoint] = oauth_applications_url
|
220
|
-
end
|
221
|
-
end
|
222
209
|
end
|
223
210
|
end
|
@@ -1,11 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "rodauth/oauth
|
3
|
+
require "rodauth/oauth"
|
4
4
|
|
5
5
|
module Rodauth
|
6
6
|
Feature.define(:oauth_assertion_base, :OauthAssertionBase) do
|
7
|
-
using PrefixExtensions
|
8
|
-
|
9
7
|
depends :oauth_base
|
10
8
|
|
11
9
|
auth_value_methods(
|
@@ -17,7 +15,7 @@ module Rodauth
|
|
17
15
|
|
18
16
|
private
|
19
17
|
|
20
|
-
def
|
18
|
+
def validate_token_params
|
21
19
|
return super unless assertion_grant_type?
|
22
20
|
|
23
21
|
redirect_response_error("invalid_grant") unless param_or_nil("assertion")
|
@@ -29,19 +27,16 @@ module Rodauth
|
|
29
27
|
elsif client_assertion_type?
|
30
28
|
@oauth_application = __send__(:"require_oauth_application_from_#{client_assertion_type}_assertion_subject",
|
31
29
|
param("client_assertion"))
|
32
|
-
else
|
33
|
-
return super
|
34
|
-
end
|
35
30
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
31
|
+
if (client_id = param_or_nil("client_id")) &&
|
32
|
+
client_id != @oauth_application[oauth_applications_client_id_column]
|
33
|
+
# If present, the value of the
|
34
|
+
# "client_id" parameter MUST identify the same client as is
|
35
|
+
# identified by the client assertion.
|
36
|
+
redirect_response_error("invalid_grant")
|
37
|
+
end
|
38
|
+
else
|
39
|
+
super
|
45
40
|
end
|
46
41
|
end
|
47
42
|
|
@@ -54,7 +49,7 @@ module Rodauth
|
|
54
49
|
)
|
55
50
|
end
|
56
51
|
|
57
|
-
def
|
52
|
+
def create_token(grant_type)
|
58
53
|
return super unless assertion_grant_type?(grant_type) && supported_grant_type?(grant_type)
|
59
54
|
|
60
55
|
account = __send__(:"account_from_#{assertion_grant_type}_assertion", param("assertion"))
|
@@ -62,19 +57,20 @@ module Rodauth
|
|
62
57
|
redirect_response_error("invalid_grant") unless account
|
63
58
|
|
64
59
|
grant_scopes = if param_or_nil("scope")
|
65
|
-
redirect_response_error("
|
60
|
+
redirect_response_error("invalid_scope") unless check_valid_scopes?
|
66
61
|
scopes
|
67
62
|
else
|
68
63
|
@oauth_application[oauth_applications_scopes_column]
|
69
64
|
end
|
70
65
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
66
|
+
grant_params = {
|
67
|
+
oauth_grants_type_column => grant_type,
|
68
|
+
oauth_grants_account_id_column => account[account_id_column],
|
69
|
+
oauth_grants_oauth_application_id_column => @oauth_application[oauth_applications_id_column],
|
70
|
+
oauth_grants_scopes_column => grant_scopes
|
75
71
|
}
|
76
72
|
|
77
|
-
|
73
|
+
generate_token(grant_params, false)
|
78
74
|
end
|
79
75
|
|
80
76
|
def assertion_grant_type?(grant_type = param("grant_type"))
|
@@ -1,67 +1,53 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "rodauth/oauth"
|
4
|
+
|
3
5
|
module Rodauth
|
4
6
|
Feature.define(:oauth_authorization_code_grant, :OauthAuthorizationCodeGrant) do
|
5
7
|
depends :oauth_authorize_base
|
6
8
|
|
7
|
-
auth_value_method :
|
9
|
+
auth_value_method :oauth_response_mode, "form_post"
|
10
|
+
|
11
|
+
def oauth_grant_types_supported
|
12
|
+
super | %w[authorization_code]
|
13
|
+
end
|
14
|
+
|
15
|
+
def oauth_response_types_supported
|
16
|
+
super | %w[code]
|
17
|
+
end
|
18
|
+
|
19
|
+
def oauth_response_modes_supported
|
20
|
+
super | %w[query form_post]
|
21
|
+
end
|
8
22
|
|
9
23
|
private
|
10
24
|
|
11
25
|
def validate_authorize_params
|
12
26
|
super
|
13
27
|
|
14
|
-
|
28
|
+
return unless (response_mode = param_or_nil("response_mode")) && !oauth_response_modes_supported.include?(response_mode)
|
15
29
|
|
16
|
-
redirect_response_error("invalid_request")
|
17
|
-
|
18
|
-
try_approval_prompt if use_oauth_access_type? && request.get?
|
30
|
+
redirect_response_error("invalid_request")
|
19
31
|
end
|
20
32
|
|
21
|
-
def
|
33
|
+
def validate_token_params
|
22
34
|
redirect_response_error("invalid_request") if param_or_nil("grant_type") == "authorization_code" && !param_or_nil("code")
|
23
35
|
super
|
24
36
|
end
|
25
37
|
|
26
|
-
def
|
27
|
-
|
28
|
-
|
29
|
-
return unless approval_prompt && approval_prompt == "auto"
|
30
|
-
|
31
|
-
return if db[oauth_grants_table].where(
|
32
|
-
oauth_grants_account_id_column => account_id,
|
33
|
-
oauth_grants_oauth_application_id_column => oauth_application[oauth_applications_id_column],
|
34
|
-
oauth_grants_redirect_uri_column => redirect_uri,
|
35
|
-
oauth_grants_scopes_column => scopes.join(oauth_scope_separator),
|
36
|
-
oauth_grants_access_type_column => "online"
|
37
|
-
).count.zero?
|
38
|
-
|
39
|
-
# if there's a previous oauth grant for the params combo, it means that this user has approved before.
|
40
|
-
request.env["REQUEST_METHOD"] = "POST"
|
41
|
-
end
|
38
|
+
def do_authorize(response_params = {}, response_mode = param_or_nil("response_mode"))
|
39
|
+
response_mode ||= oauth_response_mode
|
42
40
|
|
43
|
-
|
44
|
-
# Access Type flow
|
45
|
-
if use_oauth_access_type? && (access_type = param_or_nil("access_type"))
|
46
|
-
create_params[oauth_grants_access_type_column] = access_type
|
47
|
-
end
|
41
|
+
redirect_response_error("invalid_request") unless response_mode.nil? || supported_response_mode?(response_mode)
|
48
42
|
|
49
|
-
|
50
|
-
end
|
43
|
+
response_type = param_or_nil("response_type")
|
51
44
|
|
52
|
-
|
53
|
-
case param("response_type")
|
45
|
+
redirect_response_error("invalid_request") unless response_type.nil? || supported_response_type?(response_type)
|
54
46
|
|
55
|
-
|
56
|
-
|
57
|
-
response_params.replace(_do_authorize_code)
|
58
|
-
when "none"
|
59
|
-
response_mode ||= "none"
|
60
|
-
when "", nil
|
47
|
+
case response_type
|
48
|
+
when "code", nil
|
61
49
|
response_mode ||= oauth_response_mode
|
62
50
|
response_params.replace(_do_authorize_code)
|
63
|
-
else
|
64
|
-
return super if response_params.empty?
|
65
51
|
end
|
66
52
|
|
67
53
|
response_params["state"] = param("state") if param_or_nil("state")
|
@@ -70,11 +56,11 @@ module Rodauth
|
|
70
56
|
end
|
71
57
|
|
72
58
|
def _do_authorize_code
|
73
|
-
create_params = {
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
59
|
+
create_params = {
|
60
|
+
oauth_grants_type_column => "authorization_code",
|
61
|
+
oauth_grants_account_id_column => account_id
|
62
|
+
}
|
63
|
+
|
78
64
|
{ "code" => create_oauth_grant(create_params) }
|
79
65
|
end
|
80
66
|
|
@@ -102,53 +88,20 @@ module Rodauth
|
|
102
88
|
</body>
|
103
89
|
</html>
|
104
90
|
FORM
|
105
|
-
when "none"
|
106
|
-
redirect(redirect_url.to_s)
|
107
|
-
else
|
108
|
-
super
|
109
91
|
end
|
110
92
|
end
|
111
93
|
|
112
|
-
def
|
94
|
+
def create_token(grant_type)
|
113
95
|
return super unless supported_grant_type?(grant_type, "authorization_code")
|
114
96
|
|
115
|
-
|
116
|
-
|
97
|
+
grant_params = {
|
98
|
+
oauth_grants_type_column => grant_type,
|
117
99
|
oauth_grants_code_column => param("code"),
|
118
100
|
oauth_grants_redirect_uri_column => param("redirect_uri"),
|
119
|
-
oauth_grants_oauth_application_id_column => oauth_application[oauth_applications_id_column]
|
120
|
-
oauth_grants_revoked_at_column => nil
|
121
|
-
).where(Sequel[oauth_grants_expires_in_column] >= Sequel::CURRENT_TIMESTAMP)
|
122
|
-
.for_update
|
123
|
-
.first
|
124
|
-
|
125
|
-
redirect_response_error("invalid_grant") unless oauth_grant
|
126
|
-
|
127
|
-
create_params = {
|
128
|
-
oauth_tokens_account_id_column => oauth_grant[oauth_grants_account_id_column],
|
129
|
-
oauth_tokens_oauth_application_id_column => oauth_grant[oauth_grants_oauth_application_id_column],
|
130
|
-
oauth_tokens_oauth_grant_id_column => oauth_grant[oauth_grants_id_column],
|
131
|
-
oauth_tokens_scopes_column => oauth_grant[oauth_grants_scopes_column]
|
101
|
+
oauth_grants_oauth_application_id_column => oauth_application[oauth_applications_id_column]
|
132
102
|
}
|
133
|
-
create_oauth_token_from_authorization_code(oauth_grant, create_params, !use_oauth_access_type?)
|
134
|
-
end
|
135
|
-
|
136
|
-
ACCESS_TYPES = %w[offline online].freeze
|
137
|
-
|
138
|
-
def check_valid_access_type?
|
139
|
-
return true unless use_oauth_access_type?
|
140
103
|
|
141
|
-
|
142
|
-
!access_type || ACCESS_TYPES.include?(access_type)
|
143
|
-
end
|
144
|
-
|
145
|
-
APPROVAL_PROMPTS = %w[force auto].freeze
|
146
|
-
|
147
|
-
def check_valid_approval_prompt?
|
148
|
-
return true unless use_oauth_access_type?
|
149
|
-
|
150
|
-
approval_prompt = param_or_nil("approval_prompt")
|
151
|
-
!approval_prompt || APPROVAL_PROMPTS.include?(approval_prompt)
|
104
|
+
create_token_from_authorization_code(grant_params)
|
152
105
|
end
|
153
106
|
|
154
107
|
def check_valid_response_type?
|
@@ -160,12 +113,6 @@ module Rodauth
|
|
160
113
|
def oauth_server_metadata_body(*)
|
161
114
|
super.tap do |data|
|
162
115
|
data[:authorization_endpoint] = authorize_url
|
163
|
-
data[:response_types_supported] << "code"
|
164
|
-
|
165
|
-
data[:response_modes_supported] << "query"
|
166
|
-
data[:response_modes_supported] << "form_post"
|
167
|
-
|
168
|
-
data[:grant_types_supported] << "authorization_code"
|
169
116
|
end
|
170
117
|
end
|
171
118
|
end
|