rodauth-oauth 0.10.4 → 1.0.0.pre.beta1
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/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
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "rodauth/oauth"
|
4
|
+
|
3
5
|
module Rodauth
|
4
6
|
Feature.define(:oauth_authorize_base, :OauthAuthorizeBase) do
|
5
7
|
depends :oauth_base
|
@@ -12,17 +14,20 @@ module Rodauth
|
|
12
14
|
button "Authorize", "oauth_authorize"
|
13
15
|
button "Back to Client Application", "oauth_authorize_post"
|
14
16
|
|
15
|
-
|
17
|
+
auth_value_method :use_oauth_access_type?, false
|
18
|
+
|
19
|
+
auth_value_method :oauth_grants_access_type_column, :access_type
|
20
|
+
|
21
|
+
translatable_method :authorize_page_lead, "The application %<name>s would like to access your data"
|
22
|
+
translatable_method :oauth_grants_scopes_label, "Scopes"
|
16
23
|
translatable_method :oauth_applications_contacts_label, "Contacts"
|
17
24
|
translatable_method :oauth_applications_tos_uri_label, "Terms of service URL"
|
18
25
|
translatable_method :oauth_applications_policy_uri_label, "Policy URL"
|
19
26
|
|
20
27
|
# /authorize
|
21
|
-
|
22
|
-
next unless is_authorization_server?
|
23
|
-
|
24
|
-
before_authorize_route
|
28
|
+
auth_server_route(:authorize) do |r|
|
25
29
|
require_authorizable_account
|
30
|
+
before_authorize_route
|
26
31
|
|
27
32
|
validate_authorize_params
|
28
33
|
|
@@ -49,6 +54,12 @@ module Rodauth
|
|
49
54
|
end
|
50
55
|
end
|
51
56
|
|
57
|
+
def authorize_scopes
|
58
|
+
scopes || begin
|
59
|
+
oauth_application[oauth_applications_scopes_column].split(oauth_scope_separator)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
52
63
|
private
|
53
64
|
|
54
65
|
def validate_authorize_params
|
@@ -56,7 +67,11 @@ module Rodauth
|
|
56
67
|
|
57
68
|
redirect_response_error("invalid_request") unless check_valid_response_type?
|
58
69
|
|
59
|
-
redirect_response_error("
|
70
|
+
redirect_response_error("invalid_request") unless check_valid_access_type? && check_valid_approval_prompt?
|
71
|
+
|
72
|
+
try_approval_prompt if use_oauth_access_type? && request.get?
|
73
|
+
|
74
|
+
redirect_response_error("invalid_scope") if (request.post? || param_or_nil("scope")) && !check_valid_scopes?
|
60
75
|
end
|
61
76
|
|
62
77
|
def check_valid_response_type?
|
@@ -67,9 +82,44 @@ module Rodauth
|
|
67
82
|
oauth_application[oauth_applications_redirect_uri_column].split(" ").include?(redirect_uri)
|
68
83
|
end
|
69
84
|
|
85
|
+
ACCESS_TYPES = %w[offline online].freeze
|
86
|
+
|
87
|
+
def check_valid_access_type?
|
88
|
+
return true unless use_oauth_access_type?
|
89
|
+
|
90
|
+
access_type = param_or_nil("access_type")
|
91
|
+
!access_type || ACCESS_TYPES.include?(access_type)
|
92
|
+
end
|
93
|
+
|
94
|
+
APPROVAL_PROMPTS = %w[force auto].freeze
|
95
|
+
|
96
|
+
def check_valid_approval_prompt?
|
97
|
+
return true unless use_oauth_access_type?
|
98
|
+
|
99
|
+
approval_prompt = param_or_nil("approval_prompt")
|
100
|
+
!approval_prompt || APPROVAL_PROMPTS.include?(approval_prompt)
|
101
|
+
end
|
102
|
+
|
103
|
+
def try_approval_prompt
|
104
|
+
approval_prompt = param_or_nil("approval_prompt")
|
105
|
+
|
106
|
+
return unless approval_prompt && approval_prompt == "auto"
|
107
|
+
|
108
|
+
return if db[oauth_grants_table].where(
|
109
|
+
oauth_grants_account_id_column => account_id,
|
110
|
+
oauth_grants_oauth_application_id_column => oauth_application[oauth_applications_id_column],
|
111
|
+
oauth_grants_redirect_uri_column => redirect_uri,
|
112
|
+
oauth_grants_scopes_column => scopes.join(oauth_scope_separator),
|
113
|
+
oauth_grants_access_type_column => "online"
|
114
|
+
).count.zero?
|
115
|
+
|
116
|
+
# if there's a previous oauth grant for the params combo, it means that this user has approved before.
|
117
|
+
request.env["REQUEST_METHOD"] = "POST"
|
118
|
+
end
|
119
|
+
|
70
120
|
def authorization_required
|
71
121
|
if accepts_json?
|
72
|
-
throw_json_response_error(
|
122
|
+
throw_json_response_error(oauth_authorization_required_error_status, "invalid_client")
|
73
123
|
else
|
74
124
|
set_redirect_error_flash(require_authorization_error_flash)
|
75
125
|
redirect(authorize_path)
|
@@ -80,29 +130,62 @@ module Rodauth
|
|
80
130
|
|
81
131
|
def authorize_response(params, mode); end
|
82
132
|
|
83
|
-
def
|
84
|
-
#
|
85
|
-
|
86
|
-
.update(oauth_grants_revoked_at_column => Sequel::CURRENT_TIMESTAMP)
|
133
|
+
def create_token_from_authorization_code(grant_params, should_generate_refresh_token = !use_oauth_access_type?, oauth_grant: nil)
|
134
|
+
# fetch oauth grant
|
135
|
+
oauth_grant ||= valid_locked_oauth_grant(grant_params)
|
87
136
|
|
88
137
|
should_generate_refresh_token ||= oauth_grant[oauth_grants_access_type_column] == "offline"
|
89
138
|
|
90
|
-
|
139
|
+
generate_token(oauth_grant, should_generate_refresh_token)
|
91
140
|
end
|
92
141
|
|
93
142
|
def create_oauth_grant(create_params = {})
|
94
|
-
create_params
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
)
|
143
|
+
create_params[oauth_grants_oauth_application_id_column] = oauth_application[oauth_applications_id_column]
|
144
|
+
create_params[oauth_grants_redirect_uri_column] = redirect_uri
|
145
|
+
create_params[oauth_grants_expires_in_column] = Sequel.date_add(Sequel::CURRENT_TIMESTAMP, seconds: oauth_grant_expires_in)
|
146
|
+
create_params[oauth_grants_scopes_column] = scopes.join(oauth_scope_separator)
|
147
|
+
|
148
|
+
if use_oauth_access_type? && (access_type = param_or_nil("access_type"))
|
149
|
+
create_params[oauth_grants_access_type_column] = access_type
|
150
|
+
end
|
100
151
|
|
101
152
|
ds = db[oauth_grants_table]
|
102
153
|
|
154
|
+
create_params[oauth_grants_code_column] = oauth_unique_id_generator
|
155
|
+
|
156
|
+
if oauth_reuse_access_token
|
157
|
+
unique_conds = Hash[oauth_grants_unique_columns.map { |column| [column, create_params[column]] }]
|
158
|
+
valid_grant = valid_oauth_grant_ds(unique_conds).select(oauth_grants_id_column).first
|
159
|
+
if valid_grant
|
160
|
+
create_params[oauth_grants_id_column] = valid_grant[oauth_grants_id_column]
|
161
|
+
rescue_from_uniqueness_error do
|
162
|
+
__insert_or_update_and_return__(
|
163
|
+
ds,
|
164
|
+
oauth_grants_id_column,
|
165
|
+
[oauth_grants_id_column],
|
166
|
+
create_params
|
167
|
+
)
|
168
|
+
end
|
169
|
+
return create_params[oauth_grants_code_column]
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
103
173
|
rescue_from_uniqueness_error do
|
104
|
-
|
105
|
-
|
174
|
+
if __one_oauth_token_per_account
|
175
|
+
__insert_or_update_and_return__(
|
176
|
+
ds,
|
177
|
+
oauth_grants_id_column,
|
178
|
+
oauth_grants_unique_columns,
|
179
|
+
create_params,
|
180
|
+
nil,
|
181
|
+
{
|
182
|
+
oauth_grants_expires_in_column => Sequel.date_add(Sequel::CURRENT_TIMESTAMP, seconds: oauth_grant_expires_in),
|
183
|
+
oauth_grants_revoked_at_column => nil
|
184
|
+
}
|
185
|
+
)
|
186
|
+
else
|
187
|
+
__insert_and_return__(ds, oauth_grants_id_column, create_params)
|
188
|
+
end
|
106
189
|
end
|
107
190
|
create_params[oauth_grants_code_column]
|
108
191
|
end
|