super-smart-kit 0.0.1
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 +7 -0
- data/doorkeeper-5.9.3/CHANGELOG.md +1208 -0
- data/doorkeeper-5.9.3/MIT-LICENSE +20 -0
- data/doorkeeper-5.9.3/README.md +186 -0
- data/doorkeeper-5.9.3/app/assets/stylesheets/doorkeeper/admin/application.css +10 -0
- data/doorkeeper-5.9.3/app/assets/stylesheets/doorkeeper/application.css +64 -0
- data/doorkeeper-5.9.3/app/controllers/doorkeeper/application_controller.rb +14 -0
- data/doorkeeper-5.9.3/app/controllers/doorkeeper/application_metal_controller.rb +13 -0
- data/doorkeeper-5.9.3/app/controllers/doorkeeper/applications_controller.rb +99 -0
- data/doorkeeper-5.9.3/app/controllers/doorkeeper/authorizations_controller.rb +164 -0
- data/doorkeeper-5.9.3/app/controllers/doorkeeper/authorized_applications_controller.rb +33 -0
- data/doorkeeper-5.9.3/app/controllers/doorkeeper/token_info_controller.rb +25 -0
- data/doorkeeper-5.9.3/app/controllers/doorkeeper/tokens_controller.rb +180 -0
- data/doorkeeper-5.9.3/app/helpers/doorkeeper/dashboard_helper.rb +21 -0
- data/doorkeeper-5.9.3/app/views/doorkeeper/applications/_delete_form.html.erb +6 -0
- data/doorkeeper-5.9.3/app/views/doorkeeper/applications/_form.html.erb +59 -0
- data/doorkeeper-5.9.3/app/views/doorkeeper/applications/edit.html.erb +5 -0
- data/doorkeeper-5.9.3/app/views/doorkeeper/applications/index.html.erb +38 -0
- data/doorkeeper-5.9.3/app/views/doorkeeper/applications/new.html.erb +5 -0
- data/doorkeeper-5.9.3/app/views/doorkeeper/applications/show.html.erb +63 -0
- data/doorkeeper-5.9.3/app/views/doorkeeper/authorizations/error.html.erb +9 -0
- data/doorkeeper-5.9.3/app/views/doorkeeper/authorizations/form_post.html.erb +15 -0
- data/doorkeeper-5.9.3/app/views/doorkeeper/authorizations/new.html.erb +46 -0
- data/doorkeeper-5.9.3/app/views/doorkeeper/authorizations/show.html.erb +7 -0
- data/doorkeeper-5.9.3/app/views/doorkeeper/authorized_applications/_delete_form.html.erb +4 -0
- data/doorkeeper-5.9.3/app/views/doorkeeper/authorized_applications/index.html.erb +24 -0
- data/doorkeeper-5.9.3/app/views/layouts/doorkeeper/admin.html.erb +39 -0
- data/doorkeeper-5.9.3/app/views/layouts/doorkeeper/application.html.erb +23 -0
- data/doorkeeper-5.9.3/config/locales/en.yml +155 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/config/abstract_builder.rb +28 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/config/option.rb +82 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/config/validations.rb +65 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/config.rb +721 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/engine.rb +38 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/errors.rb +85 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/grant_flow/fallback_flow.rb +15 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/grant_flow/flow.rb +44 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/grant_flow/registry.rb +50 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/grant_flow.rb +45 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/grape/authorization_decorator.rb +19 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/grape/helpers.rb +58 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/helpers/controller.rb +91 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/models/access_grant_mixin.rb +124 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/models/access_token_mixin.rb +526 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/models/application_mixin.rb +96 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/accessible.rb +15 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/expirable.rb +36 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/expiration_time_sql_math.rb +96 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/orderable.rb +15 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/ownership.rb +18 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/polymorphic_resource_owner.rb +29 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/reusable.rb +19 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/revocable.rb +31 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/scopes.rb +27 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/secret_storable.rb +106 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/models/concerns/write_to_primary.rb +57 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/authorization/code.rb +76 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/authorization/context.rb +17 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/authorization/token.rb +100 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/authorization/uri_builder.rb +33 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/authorization_code_request.rb +125 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/base_request.rb +68 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/base_response.rb +31 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/client/credentials.rb +34 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/client.rb +28 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/client_credentials/creator.rb +57 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/client_credentials/issuer.rb +48 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/client_credentials/validator.rb +55 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/client_credentials_request.rb +46 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/code_request.rb +25 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/code_response.rb +51 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/error.rb +16 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/error_response.rb +121 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/forbidden_token_response.rb +31 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/helpers/scope_checker.rb +50 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/helpers/unique_token.rb +30 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/helpers/uri_checker.rb +83 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/hooks/context.rb +21 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/invalid_request_response.rb +47 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/invalid_token_response.rb +54 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/nonstandard.rb +39 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/password_access_token_request.rb +75 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/pre_authorization.rb +187 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/refresh_token_request.rb +144 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/scopes.rb +134 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/token.rb +66 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/token_introspection.rb +220 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/token_request.rb +25 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth/token_response.rb +38 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/oauth.rb +13 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/orm/active_record/access_grant.rb +9 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/orm/active_record/access_token.rb +9 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/orm/active_record/application.rb +10 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +64 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/orm/active_record/mixins/access_token.rb +95 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/orm/active_record/mixins/application.rb +223 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +66 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +44 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/orm/active_record.rb +41 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/rails/helpers.rb +82 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/rails/routes/mapper.rb +30 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/rails/routes/mapping.rb +40 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/rails/routes/registry.rb +45 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/rails/routes.rb +110 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/rake/db.rake +40 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/rake/setup.rake +6 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/rake.rb +14 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/request/authorization_code.rb +26 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/request/client_credentials.rb +17 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/request/code.rb +17 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/request/password.rb +19 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/request/refresh_token.rb +22 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/request/strategy.rb +19 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/request/token.rb +17 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/request.rb +73 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/revocable_tokens/revocable_access_token.rb +21 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/revocable_tokens/revocable_refresh_token.rb +21 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/secret_storing/base.rb +64 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/secret_storing/bcrypt.rb +60 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/secret_storing/plain.rb +33 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/secret_storing/sha256_hash.rb +26 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/server.rb +44 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/stale_records_cleaner.rb +24 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/validations.rb +33 -0
- data/doorkeeper-5.9.3/lib/doorkeeper/version.rb +14 -0
- data/doorkeeper-5.9.3/lib/doorkeeper.rb +209 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/application_owner_generator.rb +33 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/confidential_applications_generator.rb +33 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/install_generator.rb +22 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/migration_generator.rb +32 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/pkce_generator.rb +33 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/previous_refresh_token_generator.rb +41 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/remove_applications_secret_not_null_constraint_generator.rb +33 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/templates/README +24 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +9 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb +13 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +8 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/templates/initializer.rb +544 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/templates/migration.rb.erb +99 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/templates/remove_applications_secret_not_null_constraint.rb.erb +7 -0
- data/doorkeeper-5.9.3/lib/generators/doorkeeper/views_generator.rb +18 -0
- data/doorkeeper-5.9.3/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +6 -0
- data/super-smart-kit.gemspec +12 -0
- metadata +188 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Doorkeeper
|
|
4
|
+
module OAuth
|
|
5
|
+
class PreAuthorization
|
|
6
|
+
include Validations
|
|
7
|
+
|
|
8
|
+
validate :client_id, error: Errors::InvalidRequest
|
|
9
|
+
validate :client, error: Errors::InvalidClient
|
|
10
|
+
validate :client_supports_grant_flow, error: Errors::UnauthorizedClient
|
|
11
|
+
validate :resource_owner_authorize_for_client, error: Errors::InvalidClient
|
|
12
|
+
validate :redirect_uri, error: Errors::InvalidRedirectUri
|
|
13
|
+
validate :params, error: Errors::InvalidRequest
|
|
14
|
+
validate :response_type, error: Errors::UnsupportedResponseType
|
|
15
|
+
validate :response_mode, error: Errors::UnsupportedResponseMode
|
|
16
|
+
validate :scopes, error: Errors::InvalidScope
|
|
17
|
+
validate :code_challenge, error: Errors::InvalidRequest
|
|
18
|
+
validate :code_challenge_method, error: Errors::InvalidCodeChallengeMethod
|
|
19
|
+
|
|
20
|
+
attr_reader :client, :code_challenge, :code_challenge_method, :missing_param,
|
|
21
|
+
:redirect_uri, :resource_owner, :response_type, :state,
|
|
22
|
+
:authorization_response_flow, :response_mode, :custom_access_token_attributes,
|
|
23
|
+
:invalid_request_reason
|
|
24
|
+
|
|
25
|
+
def initialize(server, parameters = {}, resource_owner = nil)
|
|
26
|
+
@server = server
|
|
27
|
+
@client_id = parameters[:client_id]
|
|
28
|
+
@response_type = parameters[:response_type]
|
|
29
|
+
@response_mode = parameters[:response_mode]
|
|
30
|
+
@redirect_uri = parameters[:redirect_uri]
|
|
31
|
+
@scope = parameters[:scope]
|
|
32
|
+
@state = parameters[:state]
|
|
33
|
+
@code_challenge = parameters[:code_challenge]
|
|
34
|
+
@code_challenge_method = parameters[:code_challenge_method]
|
|
35
|
+
@resource_owner = resource_owner
|
|
36
|
+
@custom_access_token_attributes = parameters.slice(*Doorkeeper.config.custom_access_token_attributes).to_h
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def authorizable?
|
|
40
|
+
valid?
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def scopes
|
|
44
|
+
Scopes.from_string(scope)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def scope
|
|
48
|
+
@scope.presence || (server.default_scopes.presence && build_scopes)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def error_response
|
|
52
|
+
if error == Errors::InvalidRequest
|
|
53
|
+
OAuth::InvalidRequestResponse.from_request(
|
|
54
|
+
self,
|
|
55
|
+
response_on_fragment: response_on_fragment?,
|
|
56
|
+
)
|
|
57
|
+
else
|
|
58
|
+
OAuth::ErrorResponse.from_request(self, response_on_fragment: response_on_fragment?)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def as_json(_options = nil)
|
|
63
|
+
pre_auth_hash
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def form_post_response?
|
|
67
|
+
response_mode == "form_post"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
attr_reader :client_id, :server
|
|
73
|
+
|
|
74
|
+
def build_scopes
|
|
75
|
+
client_scopes = client.scopes
|
|
76
|
+
if client_scopes.blank?
|
|
77
|
+
server.default_scopes.to_s
|
|
78
|
+
else
|
|
79
|
+
server.default_scopes.allowed(client_scopes).to_s
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def validate_client_id
|
|
84
|
+
@missing_param = :client_id if client_id.blank?
|
|
85
|
+
@missing_param.nil?
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def validate_client
|
|
89
|
+
@client = OAuth::Client.find(client_id)
|
|
90
|
+
@client.present?
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def validate_client_supports_grant_flow
|
|
94
|
+
Doorkeeper.config.allow_grant_flow_for_client?(grant_type, client.application)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def validate_resource_owner_authorize_for_client
|
|
98
|
+
# The `authorize_resource_owner_for_client` config option is used for this validation
|
|
99
|
+
client.application.authorized_for_resource_owner?(@resource_owner)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def validate_redirect_uri
|
|
103
|
+
return false if redirect_uri.blank?
|
|
104
|
+
|
|
105
|
+
Helpers::URIChecker.valid_for_authorization?(
|
|
106
|
+
redirect_uri,
|
|
107
|
+
client.redirect_uri,
|
|
108
|
+
)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def validate_params
|
|
112
|
+
@missing_param = if response_type.blank?
|
|
113
|
+
:response_type
|
|
114
|
+
elsif @scope.blank? && server.default_scopes.blank?
|
|
115
|
+
:scope
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
@missing_param.nil?
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def validate_response_type
|
|
122
|
+
server.authorization_response_flows.any? do |flow|
|
|
123
|
+
if flow.matches_response_type?(response_type)
|
|
124
|
+
@authorization_response_flow = flow
|
|
125
|
+
true
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def validate_response_mode
|
|
131
|
+
if response_mode.blank?
|
|
132
|
+
@response_mode = authorization_response_flow.default_response_mode
|
|
133
|
+
return true
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
authorization_response_flow.matches_response_mode?(response_mode)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def validate_scopes
|
|
140
|
+
Helpers::ScopeChecker.valid?(
|
|
141
|
+
scope_str: scope,
|
|
142
|
+
server_scopes: server.scopes,
|
|
143
|
+
app_scopes: client.scopes,
|
|
144
|
+
grant_type: grant_type,
|
|
145
|
+
)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def validate_code_challenge
|
|
149
|
+
return true unless Doorkeeper.config.force_pkce?
|
|
150
|
+
return true if client.confidential
|
|
151
|
+
return true if code_challenge.present?
|
|
152
|
+
|
|
153
|
+
@invalid_request_reason = :invalid_code_challenge
|
|
154
|
+
false
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def validate_code_challenge_method
|
|
158
|
+
return true unless Doorkeeper.config.access_grant_model.pkce_supported?
|
|
159
|
+
|
|
160
|
+
code_challenge.blank? ||
|
|
161
|
+
(code_challenge_method.present? && Doorkeeper.config.pkce_code_challenge_methods_supported.include?(code_challenge_method))
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def response_on_fragment?
|
|
165
|
+
return response_type == "token" if response_mode.nil?
|
|
166
|
+
|
|
167
|
+
response_mode == "fragment"
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def grant_type
|
|
171
|
+
response_type == "code" ? AUTHORIZATION_CODE : IMPLICIT
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def pre_auth_hash
|
|
175
|
+
{
|
|
176
|
+
client_id: client.uid,
|
|
177
|
+
redirect_uri: redirect_uri,
|
|
178
|
+
state: state,
|
|
179
|
+
response_type: response_type,
|
|
180
|
+
scope: scope,
|
|
181
|
+
client_name: client.name,
|
|
182
|
+
status: I18n.t("doorkeeper.pre_authorization.status"),
|
|
183
|
+
}
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Doorkeeper
|
|
4
|
+
module OAuth
|
|
5
|
+
class RefreshTokenRequest < BaseRequest
|
|
6
|
+
include OAuth::Helpers
|
|
7
|
+
|
|
8
|
+
validate :token_presence, error: Errors::InvalidRequest
|
|
9
|
+
validate :token, error: Errors::InvalidGrant
|
|
10
|
+
validate :client, error: Errors::InvalidClient
|
|
11
|
+
validate :client_match, error: Errors::InvalidGrant
|
|
12
|
+
validate :scope, error: Errors::InvalidScope
|
|
13
|
+
|
|
14
|
+
attr_reader :access_token, :client, :credentials, :refresh_token
|
|
15
|
+
attr_reader :missing_param
|
|
16
|
+
|
|
17
|
+
def initialize(server, refresh_token, credentials, parameters = {})
|
|
18
|
+
@server = server
|
|
19
|
+
@refresh_token = refresh_token
|
|
20
|
+
@credentials = credentials
|
|
21
|
+
@grant_type = Doorkeeper::OAuth::REFRESH_TOKEN
|
|
22
|
+
@original_scopes = parameters[:scope] || parameters[:scopes]
|
|
23
|
+
@refresh_token_parameter = parameters[:refresh_token]
|
|
24
|
+
@client = load_client(credentials) if credentials
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def load_client(credentials)
|
|
30
|
+
Doorkeeper.config.application_model.by_uid_and_secret(credentials.uid, credentials.secret)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def before_successful_response
|
|
34
|
+
if refresh_token_revoked_on_use?
|
|
35
|
+
# No locking needed when refresh tokens are revoked on use
|
|
36
|
+
# because the old token is revoked later when the new token is used.
|
|
37
|
+
# This allows multiple concurrent refresh requests to succeed during the
|
|
38
|
+
# transition period, after which the old refresh token will be revoked.
|
|
39
|
+
raise Errors::InvalidGrantReuse if refresh_token.revoked?
|
|
40
|
+
|
|
41
|
+
create_access_token
|
|
42
|
+
else
|
|
43
|
+
# Use locking when refresh tokens are revoked immediately
|
|
44
|
+
# to prevent race conditions where multiple tokens could be created
|
|
45
|
+
refresh_token.with_lock do
|
|
46
|
+
raise Errors::InvalidGrantReuse if refresh_token.revoked?
|
|
47
|
+
|
|
48
|
+
refresh_token.revoke
|
|
49
|
+
create_access_token
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
super
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def refresh_token_revoked_on_use?
|
|
56
|
+
Doorkeeper.config.access_token_model.refresh_token_revoked_on_use?
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def default_scopes
|
|
60
|
+
refresh_token.scopes
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def create_access_token
|
|
64
|
+
attributes = {}.merge(custom_token_attributes_with_data)
|
|
65
|
+
|
|
66
|
+
resource_owner =
|
|
67
|
+
if Doorkeeper.config.polymorphic_resource_owner?
|
|
68
|
+
refresh_token.resource_owner
|
|
69
|
+
else
|
|
70
|
+
refresh_token.resource_owner_id
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
if refresh_token_revoked_on_use?
|
|
74
|
+
attributes[:previous_refresh_token] = refresh_token.refresh_token
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# RFC6749
|
|
78
|
+
# 1.5. Refresh Token
|
|
79
|
+
#
|
|
80
|
+
# Refresh tokens are issued to the client by the authorization server and are
|
|
81
|
+
# used to obtain a new access token when the current access token
|
|
82
|
+
# becomes invalid or expires, or to obtain additional access tokens
|
|
83
|
+
# with identical or narrower scope (access tokens may have a shorter
|
|
84
|
+
# lifetime and fewer permissions than authorized by the resource
|
|
85
|
+
# owner).
|
|
86
|
+
#
|
|
87
|
+
# Here we assume that TTL of the token received after refreshing should be
|
|
88
|
+
# the same as that of the original token.
|
|
89
|
+
#
|
|
90
|
+
@access_token = Doorkeeper.config.access_token_model.create_for(
|
|
91
|
+
application: refresh_token.application,
|
|
92
|
+
resource_owner: resource_owner,
|
|
93
|
+
scopes: scopes,
|
|
94
|
+
expires_in: refresh_token.expires_in,
|
|
95
|
+
use_refresh_token: true,
|
|
96
|
+
**attributes,
|
|
97
|
+
)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def validate_token_presence
|
|
101
|
+
@missing_param = :refresh_token if refresh_token.blank? && @refresh_token_parameter.blank?
|
|
102
|
+
|
|
103
|
+
@missing_param.nil?
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def validate_token
|
|
107
|
+
refresh_token.present? && !refresh_token.revoked?
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def validate_client
|
|
111
|
+
return true if credentials.blank?
|
|
112
|
+
|
|
113
|
+
client.present?
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# @see https://datatracker.ietf.org/doc/html/rfc6749#section-1.5
|
|
117
|
+
#
|
|
118
|
+
def validate_client_match
|
|
119
|
+
return true if refresh_token.application_id.blank?
|
|
120
|
+
|
|
121
|
+
client && refresh_token.application_id == client.id
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def validate_scope
|
|
125
|
+
if @original_scopes.present?
|
|
126
|
+
ScopeChecker.valid?(
|
|
127
|
+
scope_str: @original_scopes,
|
|
128
|
+
server_scopes: refresh_token.scopes,
|
|
129
|
+
)
|
|
130
|
+
else
|
|
131
|
+
true
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def custom_token_attributes_with_data
|
|
136
|
+
refresh_token
|
|
137
|
+
.attributes
|
|
138
|
+
.with_indifferent_access
|
|
139
|
+
.slice(*Doorkeeper.config.custom_access_token_attributes)
|
|
140
|
+
.symbolize_keys
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Doorkeeper
|
|
4
|
+
module OAuth
|
|
5
|
+
class Scopes
|
|
6
|
+
include Enumerable
|
|
7
|
+
include Comparable
|
|
8
|
+
|
|
9
|
+
DYNAMIC_SCOPE_WILDCARD = "*"
|
|
10
|
+
|
|
11
|
+
def self.from_string(string)
|
|
12
|
+
string ||= ""
|
|
13
|
+
new.tap do |scope|
|
|
14
|
+
scope.add(*string.split)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.from_array(array)
|
|
19
|
+
new.tap do |scope|
|
|
20
|
+
scope.add(*array)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
delegate :each, :empty?, to: :@scopes
|
|
25
|
+
|
|
26
|
+
def initialize
|
|
27
|
+
@scopes = []
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def exists?(scope)
|
|
31
|
+
scope = scope.to_s
|
|
32
|
+
|
|
33
|
+
@scopes.any? do |allowed_scope|
|
|
34
|
+
if dynamic_scopes_enabled? && dynamic_scopes_present?(allowed_scope, scope)
|
|
35
|
+
dynamic_scope_match?(allowed_scope, scope)
|
|
36
|
+
else
|
|
37
|
+
allowed_scope == scope
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def add(*scopes)
|
|
43
|
+
@scopes.push(*scopes.map(&:to_s))
|
|
44
|
+
@scopes.uniq!
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def all
|
|
48
|
+
@scopes
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def to_s
|
|
52
|
+
@scopes.join(" ")
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def scopes?(scopes)
|
|
56
|
+
scopes.all? { |scope| exists?(scope) }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
alias has_scopes? scopes?
|
|
60
|
+
|
|
61
|
+
def +(other)
|
|
62
|
+
self.class.from_array(all + to_array(other))
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def <=>(other)
|
|
66
|
+
if other.respond_to?(:map)
|
|
67
|
+
map(&:to_s).sort <=> other.map(&:to_s).sort
|
|
68
|
+
else
|
|
69
|
+
super
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# DEPRECATED: With dynamic scopes, #allowed should be called because
|
|
74
|
+
# A & B doesn't really make sense with dynamic scopes.
|
|
75
|
+
#
|
|
76
|
+
# For example, if A = user:* and B is user:1, A & B = [].
|
|
77
|
+
# If we modified this method to take dynamic scopes into an account, then order
|
|
78
|
+
# becomes important, and this would violate the principle that A & B = B & A.
|
|
79
|
+
def &(other)
|
|
80
|
+
return allowed(other) if dynamic_scopes_enabled?
|
|
81
|
+
|
|
82
|
+
self.class.from_array(all & to_array(other))
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Returns a set of scopes that are allowed, taking dynamic
|
|
86
|
+
# scopes into account. This instance's scopes is taken as the allowed set,
|
|
87
|
+
# and the passed value is the set to filter.
|
|
88
|
+
#
|
|
89
|
+
# @param other The set of scopes to filter
|
|
90
|
+
def allowed(other)
|
|
91
|
+
filtered_scopes = other.select { |scope| exists?(scope) }
|
|
92
|
+
self.class.from_array(filtered_scopes)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
private
|
|
96
|
+
|
|
97
|
+
def dynamic_scopes_enabled?
|
|
98
|
+
Doorkeeper.config.enable_dynamic_scopes?
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def dynamic_scope_delimiter
|
|
102
|
+
return unless dynamic_scopes_enabled?
|
|
103
|
+
|
|
104
|
+
@dynamic_scope_delimiter ||= Doorkeeper.config.dynamic_scopes_delimiter
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def dynamic_scopes_present?(allowed, requested)
|
|
108
|
+
allowed.include?(dynamic_scope_delimiter) && requested.include?(dynamic_scope_delimiter)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def dynamic_scope_match?(allowed, requested)
|
|
112
|
+
allowed_pattern = allowed.split(dynamic_scope_delimiter, 2)
|
|
113
|
+
request_pattern = requested.split(dynamic_scope_delimiter, 2)
|
|
114
|
+
|
|
115
|
+
return false if allowed_pattern[0] != request_pattern[0]
|
|
116
|
+
return false if allowed_pattern[1].blank?
|
|
117
|
+
return false if request_pattern[1].blank?
|
|
118
|
+
|
|
119
|
+
return true if allowed_pattern[1] == DYNAMIC_SCOPE_WILDCARD
|
|
120
|
+
|
|
121
|
+
allowed_pattern[1] == request_pattern[1]
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def to_array(other)
|
|
125
|
+
case other
|
|
126
|
+
when Scopes
|
|
127
|
+
other.all
|
|
128
|
+
else
|
|
129
|
+
other.to_a
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Doorkeeper
|
|
4
|
+
module OAuth
|
|
5
|
+
class Token
|
|
6
|
+
class << self
|
|
7
|
+
def from_request(request, *methods)
|
|
8
|
+
methods.inject(nil) do |_, method|
|
|
9
|
+
method = self.method(method) if method.is_a?(Symbol)
|
|
10
|
+
credentials = method.call(request)
|
|
11
|
+
break credentials if credentials.present?
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def authenticate(request, *methods)
|
|
16
|
+
if (token = from_request(request, *methods))
|
|
17
|
+
access_token = Doorkeeper.config.access_token_model.by_token(token)
|
|
18
|
+
if access_token.present? && Doorkeeper.config.refresh_token_enabled?
|
|
19
|
+
access_token.revoke_previous_refresh_token!
|
|
20
|
+
end
|
|
21
|
+
access_token
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def from_access_token_param(request)
|
|
26
|
+
request.parameters[:access_token]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def from_bearer_param(request)
|
|
30
|
+
request.parameters[:bearer_token]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def from_bearer_authorization(request)
|
|
34
|
+
pattern = /^Bearer /i
|
|
35
|
+
header = request.authorization
|
|
36
|
+
token_from_header(header, pattern) if match?(header, pattern)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def from_basic_authorization(request)
|
|
40
|
+
pattern = /^Basic /i
|
|
41
|
+
header = request.authorization
|
|
42
|
+
token_from_basic_header(header, pattern) if match?(header, pattern)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def token_from_basic_header(header, pattern)
|
|
48
|
+
encoded_header = token_from_header(header, pattern)
|
|
49
|
+
decode_basic_credentials_token(encoded_header)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def decode_basic_credentials_token(encoded_header)
|
|
53
|
+
Base64.decode64(encoded_header).split(/:/, 2).first
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def token_from_header(header, pattern)
|
|
57
|
+
header.gsub(pattern, "")
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def match?(header, pattern)
|
|
61
|
+
header&.match(pattern)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|