doorkeeper 5.1.0 → 5.5.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of doorkeeper might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/{NEWS.md → CHANGELOG.md} +242 -25
- data/README.md +21 -11
- data/app/controllers/doorkeeper/application_controller.rb +3 -2
- data/app/controllers/doorkeeper/application_metal_controller.rb +3 -2
- data/app/controllers/doorkeeper/applications_controller.rb +8 -7
- data/app/controllers/doorkeeper/authorizations_controller.rb +56 -19
- data/app/controllers/doorkeeper/authorized_applications_controller.rb +6 -6
- data/app/controllers/doorkeeper/token_info_controller.rb +12 -2
- data/app/controllers/doorkeeper/tokens_controller.rb +93 -25
- data/app/views/doorkeeper/applications/_form.html.erb +1 -7
- data/app/views/doorkeeper/applications/show.html.erb +35 -14
- data/app/views/doorkeeper/authorizations/form_post.html.erb +11 -0
- data/config/locales/en.yml +13 -3
- data/lib/doorkeeper/config/abstract_builder.rb +28 -0
- data/lib/doorkeeper/config/option.rb +20 -2
- data/lib/doorkeeper/config/validations.rb +53 -0
- data/lib/doorkeeper/config.rb +295 -121
- data/lib/doorkeeper/engine.rb +1 -1
- data/lib/doorkeeper/errors.rb +13 -18
- data/lib/doorkeeper/grant_flow/fallback_flow.rb +15 -0
- data/lib/doorkeeper/grant_flow/flow.rb +44 -0
- data/lib/doorkeeper/grant_flow/registry.rb +50 -0
- data/lib/doorkeeper/grant_flow.rb +45 -0
- data/lib/doorkeeper/grape/helpers.rb +7 -3
- data/lib/doorkeeper/helpers/controller.rb +36 -11
- data/lib/doorkeeper/models/access_grant_mixin.rb +22 -18
- data/lib/doorkeeper/models/access_token_mixin.rb +194 -51
- data/lib/doorkeeper/models/application_mixin.rb +8 -7
- data/lib/doorkeeper/models/concerns/ownership.rb +1 -1
- data/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
- data/lib/doorkeeper/models/concerns/reusable.rb +1 -1
- data/lib/doorkeeper/models/concerns/revocable.rb +1 -28
- data/lib/doorkeeper/models/concerns/scopes.rb +5 -1
- data/lib/doorkeeper/models/concerns/secret_storable.rb +1 -3
- data/lib/doorkeeper/oauth/authorization/code.rb +25 -14
- data/lib/doorkeeper/oauth/authorization/context.rb +5 -5
- data/lib/doorkeeper/oauth/authorization/token.rb +24 -19
- data/lib/doorkeeper/oauth/authorization/uri_builder.rb +4 -4
- data/lib/doorkeeper/oauth/authorization_code_request.rb +40 -21
- data/lib/doorkeeper/oauth/base_request.rb +21 -23
- data/lib/doorkeeper/oauth/client/credentials.rb +2 -4
- data/lib/doorkeeper/oauth/client.rb +8 -9
- data/lib/doorkeeper/oauth/client_credentials/creator.rb +45 -5
- data/lib/doorkeeper/oauth/client_credentials/issuer.rb +10 -8
- data/lib/doorkeeper/oauth/client_credentials/{validation.rb → validator.rb} +13 -3
- data/lib/doorkeeper/oauth/client_credentials_request.rb +8 -7
- data/lib/doorkeeper/oauth/code_request.rb +6 -12
- data/lib/doorkeeper/oauth/code_response.rb +24 -14
- data/lib/doorkeeper/oauth/error.rb +1 -1
- data/lib/doorkeeper/oauth/error_response.rb +10 -11
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +8 -12
- data/lib/doorkeeper/oauth/helpers/unique_token.rb +8 -5
- data/lib/doorkeeper/oauth/helpers/uri_checker.rb +19 -5
- data/lib/doorkeeper/oauth/hooks/context.rb +21 -0
- data/lib/doorkeeper/oauth/invalid_request_response.rb +43 -0
- data/lib/doorkeeper/oauth/invalid_token_response.rb +7 -4
- data/lib/doorkeeper/oauth/nonstandard.rb +39 -0
- data/lib/doorkeeper/oauth/password_access_token_request.rb +34 -11
- data/lib/doorkeeper/oauth/pre_authorization.rb +111 -42
- data/lib/doorkeeper/oauth/refresh_token_request.rb +45 -33
- data/lib/doorkeeper/oauth/token.rb +6 -7
- data/lib/doorkeeper/oauth/token_introspection.rb +24 -18
- data/lib/doorkeeper/oauth/token_request.rb +6 -20
- data/lib/doorkeeper/oauth/token_response.rb +1 -1
- data/lib/doorkeeper/orm/active_record/access_grant.rb +4 -43
- data/lib/doorkeeper/orm/active_record/access_token.rb +4 -35
- data/lib/doorkeeper/orm/active_record/application.rb +5 -83
- data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +68 -0
- data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +59 -0
- data/lib/doorkeeper/orm/active_record/mixins/application.rb +198 -0
- data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +66 -0
- data/lib/doorkeeper/orm/active_record.rb +20 -6
- data/lib/doorkeeper/rails/helpers.rb +4 -4
- data/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
- data/lib/doorkeeper/rails/routes/mapper.rb +2 -2
- data/lib/doorkeeper/rails/routes/registry.rb +45 -0
- data/lib/doorkeeper/rails/routes.rb +17 -25
- data/lib/doorkeeper/rake/db.rake +6 -6
- data/lib/doorkeeper/rake/setup.rake +5 -0
- data/lib/doorkeeper/request/authorization_code.rb +5 -3
- data/lib/doorkeeper/request/client_credentials.rb +2 -2
- data/lib/doorkeeper/request/password.rb +3 -2
- data/lib/doorkeeper/request/refresh_token.rb +5 -4
- data/lib/doorkeeper/request/strategy.rb +2 -2
- data/lib/doorkeeper/request.rb +49 -17
- data/lib/doorkeeper/server.rb +7 -11
- data/lib/doorkeeper/stale_records_cleaner.rb +6 -2
- data/lib/doorkeeper/version.rb +2 -6
- data/lib/doorkeeper.rb +114 -79
- data/lib/generators/doorkeeper/application_owner_generator.rb +1 -1
- data/lib/generators/doorkeeper/confidential_applications_generator.rb +2 -2
- data/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
- data/lib/generators/doorkeeper/migration_generator.rb +1 -1
- data/lib/generators/doorkeeper/pkce_generator.rb +1 -1
- data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +7 -7
- data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +3 -1
- data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb +2 -0
- data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +2 -0
- data/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
- data/lib/generators/doorkeeper/templates/initializer.rb +205 -43
- data/lib/generators/doorkeeper/templates/migration.rb.erb +18 -6
- metadata +45 -312
- data/.coveralls.yml +0 -1
- data/.github/ISSUE_TEMPLATE.md +0 -25
- data/.github/PULL_REQUEST_TEMPLATE.md +0 -17
- data/.gitignore +0 -20
- data/.gitlab-ci.yml +0 -16
- data/.hound.yml +0 -3
- data/.rspec +0 -1
- data/.rubocop.yml +0 -50
- data/.travis.yml +0 -35
- data/Appraisals +0 -40
- data/CODE_OF_CONDUCT.md +0 -46
- data/CONTRIBUTING.md +0 -47
- data/Dangerfile +0 -67
- data/Gemfile +0 -24
- data/RELEASING.md +0 -10
- data/Rakefile +0 -28
- data/SECURITY.md +0 -15
- data/UPGRADE.md +0 -2
- data/app/validators/redirect_uri_validator.rb +0 -50
- data/bin/console +0 -16
- data/doorkeeper.gemspec +0 -34
- data/gemfiles/rails_5_0.gemfile +0 -17
- data/gemfiles/rails_5_1.gemfile +0 -17
- data/gemfiles/rails_5_2.gemfile +0 -17
- data/gemfiles/rails_6_0.gemfile +0 -17
- data/gemfiles/rails_master.gemfile +0 -17
- data/spec/controllers/application_metal_controller_spec.rb +0 -64
- data/spec/controllers/applications_controller_spec.rb +0 -180
- data/spec/controllers/authorizations_controller_spec.rb +0 -527
- data/spec/controllers/protected_resources_controller_spec.rb +0 -353
- data/spec/controllers/token_info_controller_spec.rb +0 -50
- data/spec/controllers/tokens_controller_spec.rb +0 -330
- data/spec/dummy/Rakefile +0 -9
- data/spec/dummy/app/assets/config/manifest.js +0 -2
- data/spec/dummy/app/controllers/application_controller.rb +0 -5
- data/spec/dummy/app/controllers/custom_authorizations_controller.rb +0 -9
- data/spec/dummy/app/controllers/full_protected_resources_controller.rb +0 -14
- data/spec/dummy/app/controllers/home_controller.rb +0 -18
- data/spec/dummy/app/controllers/metal_controller.rb +0 -13
- data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +0 -13
- data/spec/dummy/app/helpers/application_helper.rb +0 -7
- data/spec/dummy/app/models/user.rb +0 -7
- data/spec/dummy/app/views/home/index.html.erb +0 -0
- data/spec/dummy/app/views/layouts/application.html.erb +0 -14
- data/spec/dummy/config/application.rb +0 -47
- data/spec/dummy/config/boot.rb +0 -7
- data/spec/dummy/config/database.yml +0 -15
- data/spec/dummy/config/environment.rb +0 -5
- data/spec/dummy/config/environments/development.rb +0 -31
- data/spec/dummy/config/environments/production.rb +0 -64
- data/spec/dummy/config/environments/test.rb +0 -45
- data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -9
- data/spec/dummy/config/initializers/doorkeeper.rb +0 -121
- data/spec/dummy/config/initializers/secret_token.rb +0 -10
- data/spec/dummy/config/initializers/session_store.rb +0 -10
- data/spec/dummy/config/initializers/wrap_parameters.rb +0 -16
- data/spec/dummy/config/locales/doorkeeper.en.yml +0 -5
- data/spec/dummy/config/routes.rb +0 -13
- data/spec/dummy/config.ru +0 -6
- data/spec/dummy/db/migrate/20111122132257_create_users.rb +0 -11
- data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +0 -7
- data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +0 -69
- data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +0 -9
- data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +0 -13
- data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +0 -8
- data/spec/dummy/db/migrate/20180210183654_add_confidential_to_applications.rb +0 -13
- data/spec/dummy/db/schema.rb +0 -68
- data/spec/dummy/public/404.html +0 -26
- data/spec/dummy/public/422.html +0 -26
- data/spec/dummy/public/500.html +0 -26
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +0 -9
- data/spec/factories.rb +0 -30
- data/spec/generators/application_owner_generator_spec.rb +0 -28
- data/spec/generators/confidential_applications_generator_spec.rb +0 -29
- data/spec/generators/install_generator_spec.rb +0 -36
- data/spec/generators/migration_generator_spec.rb +0 -28
- data/spec/generators/pkce_generator_spec.rb +0 -28
- data/spec/generators/previous_refresh_token_generator_spec.rb +0 -44
- data/spec/generators/templates/routes.rb +0 -4
- data/spec/generators/views_generator_spec.rb +0 -29
- data/spec/grape/grape_integration_spec.rb +0 -137
- data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +0 -26
- data/spec/lib/config_spec.rb +0 -697
- data/spec/lib/doorkeeper_spec.rb +0 -27
- data/spec/lib/models/expirable_spec.rb +0 -61
- data/spec/lib/models/reusable_spec.rb +0 -40
- data/spec/lib/models/revocable_spec.rb +0 -59
- data/spec/lib/models/scopes_spec.rb +0 -53
- data/spec/lib/models/secret_storable_spec.rb +0 -135
- data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -39
- data/spec/lib/oauth/authorization_code_request_spec.rb +0 -156
- data/spec/lib/oauth/base_request_spec.rb +0 -205
- data/spec/lib/oauth/base_response_spec.rb +0 -47
- data/spec/lib/oauth/client/credentials_spec.rb +0 -90
- data/spec/lib/oauth/client_credentials/creator_spec.rb +0 -94
- data/spec/lib/oauth/client_credentials/issuer_spec.rb +0 -112
- data/spec/lib/oauth/client_credentials/validation_spec.rb +0 -59
- data/spec/lib/oauth/client_credentials_integration_spec.rb +0 -29
- data/spec/lib/oauth/client_credentials_request_spec.rb +0 -109
- data/spec/lib/oauth/client_spec.rb +0 -38
- data/spec/lib/oauth/code_request_spec.rb +0 -47
- data/spec/lib/oauth/code_response_spec.rb +0 -36
- data/spec/lib/oauth/error_response_spec.rb +0 -66
- data/spec/lib/oauth/error_spec.rb +0 -23
- data/spec/lib/oauth/forbidden_token_response_spec.rb +0 -22
- data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -98
- data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -21
- data/spec/lib/oauth/helpers/uri_checker_spec.rb +0 -247
- data/spec/lib/oauth/invalid_token_response_spec.rb +0 -55
- data/spec/lib/oauth/password_access_token_request_spec.rb +0 -192
- data/spec/lib/oauth/pre_authorization_spec.rb +0 -215
- data/spec/lib/oauth/refresh_token_request_spec.rb +0 -177
- data/spec/lib/oauth/scopes_spec.rb +0 -148
- data/spec/lib/oauth/token_request_spec.rb +0 -150
- data/spec/lib/oauth/token_response_spec.rb +0 -86
- data/spec/lib/oauth/token_spec.rb +0 -158
- data/spec/lib/request/strategy_spec.rb +0 -54
- data/spec/lib/secret_storing/base_spec.rb +0 -60
- data/spec/lib/secret_storing/bcrypt_spec.rb +0 -49
- data/spec/lib/secret_storing/plain_spec.rb +0 -44
- data/spec/lib/secret_storing/sha256_hash_spec.rb +0 -48
- data/spec/lib/server_spec.rb +0 -61
- data/spec/lib/stale_records_cleaner_spec.rb +0 -89
- data/spec/models/doorkeeper/access_grant_spec.rb +0 -144
- data/spec/models/doorkeeper/access_token_spec.rb +0 -591
- data/spec/models/doorkeeper/application_spec.rb +0 -367
- data/spec/requests/applications/applications_request_spec.rb +0 -259
- data/spec/requests/applications/authorized_applications_spec.rb +0 -32
- data/spec/requests/endpoints/authorization_spec.rb +0 -73
- data/spec/requests/endpoints/token_spec.rb +0 -75
- data/spec/requests/flows/authorization_code_errors_spec.rb +0 -78
- data/spec/requests/flows/authorization_code_spec.rb +0 -447
- data/spec/requests/flows/client_credentials_spec.rb +0 -128
- data/spec/requests/flows/implicit_grant_errors_spec.rb +0 -34
- data/spec/requests/flows/implicit_grant_spec.rb +0 -90
- data/spec/requests/flows/password_spec.rb +0 -259
- data/spec/requests/flows/refresh_token_spec.rb +0 -233
- data/spec/requests/flows/revoke_token_spec.rb +0 -143
- data/spec/requests/flows/skip_authorization_spec.rb +0 -66
- data/spec/requests/protected_resources/metal_spec.rb +0 -16
- data/spec/requests/protected_resources/private_api_spec.rb +0 -83
- data/spec/routing/custom_controller_routes_spec.rb +0 -133
- data/spec/routing/default_routes_spec.rb +0 -41
- data/spec/routing/scoped_routes_spec.rb +0 -47
- data/spec/spec_helper.rb +0 -57
- data/spec/spec_helper_integration.rb +0 -4
- data/spec/support/dependencies/factory_bot.rb +0 -4
- data/spec/support/doorkeeper_rspec.rb +0 -22
- data/spec/support/helpers/access_token_request_helper.rb +0 -13
- data/spec/support/helpers/authorization_request_helper.rb +0 -43
- data/spec/support/helpers/config_helper.rb +0 -11
- data/spec/support/helpers/model_helper.rb +0 -78
- data/spec/support/helpers/request_spec_helper.rb +0 -98
- data/spec/support/helpers/url_helper.rb +0 -62
- data/spec/support/http_method_shim.rb +0 -29
- data/spec/support/orm/active_record.rb +0 -5
- data/spec/support/shared/controllers_shared_context.rb +0 -123
- data/spec/support/shared/hashing_shared_context.rb +0 -36
- data/spec/support/shared/models_shared_examples.rb +0 -54
- data/spec/validators/redirect_uri_validator_spec.rb +0 -158
- data/spec/version/version_spec.rb +0 -17
@@ -12,6 +12,7 @@ module Doorkeeper
|
|
12
12
|
include Models::Orderable
|
13
13
|
include Models::SecretStorable
|
14
14
|
include Models::Scopes
|
15
|
+
include Models::ResourceOwnerable
|
15
16
|
|
16
17
|
module ClassMethods
|
17
18
|
# Returns an instance of the Doorkeeper::AccessToken with
|
@@ -40,18 +41,35 @@ module Doorkeeper
|
|
40
41
|
find_by_plaintext_token(:refresh_token, refresh_token)
|
41
42
|
end
|
42
43
|
|
44
|
+
# Returns an instance of the Doorkeeper::AccessToken
|
45
|
+
# found by previous refresh token. Keep in mind that value
|
46
|
+
# of the previous_refresh_token isn't encrypted using
|
47
|
+
# secrets strategy.
|
48
|
+
#
|
49
|
+
# @param previous_refresh_token [#to_s]
|
50
|
+
# previous refresh token value (any object that responds to `#to_s`)
|
51
|
+
#
|
52
|
+
# @return [Doorkeeper::AccessToken, nil] AccessToken object or nil
|
53
|
+
# if there is no record with such refresh token
|
54
|
+
#
|
55
|
+
def by_previous_refresh_token(previous_refresh_token)
|
56
|
+
find_by(refresh_token: previous_refresh_token)
|
57
|
+
end
|
58
|
+
|
43
59
|
# Revokes AccessToken records that have not been revoked and associated
|
44
60
|
# with the specific Application and Resource Owner.
|
45
61
|
#
|
46
62
|
# @param application_id [Integer]
|
47
63
|
# ID of the Application
|
48
|
-
# @param resource_owner [ActiveRecord::Base]
|
49
|
-
# instance of the Resource Owner model
|
64
|
+
# @param resource_owner [ActiveRecord::Base, Integer]
|
65
|
+
# instance of the Resource Owner model or it's ID
|
50
66
|
#
|
51
67
|
def revoke_all_for(application_id, resource_owner, clock = Time)
|
52
|
-
|
53
|
-
|
54
|
-
|
68
|
+
by_resource_owner(resource_owner)
|
69
|
+
.where(
|
70
|
+
application_id: application_id,
|
71
|
+
revoked_at: nil,
|
72
|
+
)
|
55
73
|
.update_all(revoked_at: clock.now.utc)
|
56
74
|
end
|
57
75
|
|
@@ -60,7 +78,7 @@ module Doorkeeper
|
|
60
78
|
#
|
61
79
|
# @param application [Doorkeeper::Application]
|
62
80
|
# Application instance
|
63
|
-
# @param
|
81
|
+
# @param resource_owner [ActiveRecord::Base, Integer]
|
64
82
|
# Resource Owner model instance or it's ID
|
65
83
|
# @param scopes [String, Doorkeeper::OAuth::Scopes]
|
66
84
|
# set of scopes
|
@@ -68,17 +86,53 @@ module Doorkeeper
|
|
68
86
|
# @return [Doorkeeper::AccessToken, nil] Access Token instance or
|
69
87
|
# nil if matching record was not found
|
70
88
|
#
|
71
|
-
def matching_token_for(application,
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
resource_owner_or_id
|
76
|
-
end
|
89
|
+
def matching_token_for(application, resource_owner, scopes)
|
90
|
+
tokens = authorized_tokens_for(application&.id, resource_owner)
|
91
|
+
find_matching_token(tokens, application, scopes)
|
92
|
+
end
|
77
93
|
|
78
|
-
|
79
|
-
|
80
|
-
|
94
|
+
# Interface to enumerate access token records in batches in order not
|
95
|
+
# to bloat the memory. Could be overloaded in any ORM extension.
|
96
|
+
#
|
97
|
+
def find_access_token_in_batches(relation, **args, &block)
|
98
|
+
relation.find_in_batches(**args, &block)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Enumerates AccessToken records in batches to find a matching token.
|
102
|
+
# Batching is required in order not to pollute the memory if Application
|
103
|
+
# has huge amount of associated records.
|
104
|
+
#
|
105
|
+
# ActiveRecord 5.x - 6.x ignores custom ordering so we can't perform a
|
106
|
+
# database sort by created_at, so we need to load all the matching records,
|
107
|
+
# sort them and find latest one. Probably it would be better to rewrite this
|
108
|
+
# query using Time math if possible, but we n eed to consider ORM and
|
109
|
+
# different databases support.
|
110
|
+
#
|
111
|
+
# @param relation [ActiveRecord::Relation]
|
112
|
+
# Access tokens relation
|
113
|
+
# @param application [Doorkeeper::Application]
|
114
|
+
# Application instance
|
115
|
+
# @param scopes [String, Doorkeeper::OAuth::Scopes]
|
116
|
+
# set of scopes
|
117
|
+
#
|
118
|
+
# @return [Doorkeeper::AccessToken, nil] Access Token instance or
|
119
|
+
# nil if matching record was not found
|
120
|
+
#
|
121
|
+
def find_matching_token(relation, application, scopes)
|
122
|
+
return nil unless relation
|
123
|
+
|
124
|
+
matching_tokens = []
|
125
|
+
batch_size = Doorkeeper.configuration.token_lookup_batch_size
|
126
|
+
|
127
|
+
find_access_token_in_batches(relation, batch_size: batch_size) do |batch|
|
128
|
+
tokens = batch.select do |token|
|
129
|
+
scopes_match?(token.scopes, scopes, application&.scopes)
|
130
|
+
end
|
131
|
+
|
132
|
+
matching_tokens.concat(tokens)
|
81
133
|
end
|
134
|
+
|
135
|
+
matching_tokens.max_by(&:created_at)
|
82
136
|
end
|
83
137
|
|
84
138
|
# Checks whether the token scopes match the scopes from the parameters
|
@@ -101,8 +155,8 @@ module Doorkeeper
|
|
101
155
|
(token_scopes.sort == param_scopes.sort) &&
|
102
156
|
Doorkeeper::OAuth::Helpers::ScopeChecker.valid?(
|
103
157
|
scope_str: param_scopes.to_s,
|
104
|
-
server_scopes: Doorkeeper.
|
105
|
-
app_scopes: app_scopes
|
158
|
+
server_scopes: Doorkeeper.config.scopes,
|
159
|
+
app_scopes: app_scopes,
|
106
160
|
)
|
107
161
|
end
|
108
162
|
|
@@ -112,48 +166,81 @@ module Doorkeeper
|
|
112
166
|
#
|
113
167
|
# @param application [Doorkeeper::Application]
|
114
168
|
# Application instance
|
115
|
-
# @param
|
169
|
+
# @param resource_owner [ActiveRecord::Base, Integer]
|
116
170
|
# Resource Owner model instance or it's ID
|
117
171
|
# @param scopes [#to_s]
|
118
172
|
# set of scopes (any object that responds to `#to_s`)
|
119
|
-
# @param
|
173
|
+
# @param token_attributes [Hash]
|
174
|
+
# Additional attributes to use when creating a token
|
175
|
+
# @option token_attributes [Integer] :expires_in
|
120
176
|
# token lifetime in seconds
|
121
|
-
# @
|
177
|
+
# @option token_attributes [Boolean] :use_refresh_token
|
122
178
|
# whether to use the refresh token
|
123
179
|
#
|
124
180
|
# @return [Doorkeeper::AccessToken] existing record or a new one
|
125
181
|
#
|
126
|
-
def find_or_create_for(application
|
127
|
-
if Doorkeeper.
|
128
|
-
access_token = matching_token_for(application,
|
182
|
+
def find_or_create_for(application:, resource_owner:, scopes:, **token_attributes)
|
183
|
+
if Doorkeeper.config.reuse_access_token
|
184
|
+
access_token = matching_token_for(application, resource_owner, scopes)
|
129
185
|
|
130
186
|
return access_token if access_token&.reusable?
|
131
187
|
end
|
132
188
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
scopes: scopes
|
137
|
-
|
138
|
-
use_refresh_token: use_refresh_token
|
189
|
+
create_for(
|
190
|
+
application: application,
|
191
|
+
resource_owner: resource_owner,
|
192
|
+
scopes: scopes,
|
193
|
+
**token_attributes,
|
139
194
|
)
|
140
195
|
end
|
141
196
|
|
197
|
+
# Creates a not expired AccessToken record with a matching set of
|
198
|
+
# scopes that belongs to specific Application and Resource Owner.
|
199
|
+
#
|
200
|
+
# @param application [Doorkeeper::Application]
|
201
|
+
# Application instance
|
202
|
+
# @param resource_owner [ActiveRecord::Base, Integer]
|
203
|
+
# Resource Owner model instance or it's ID
|
204
|
+
# @param scopes [#to_s]
|
205
|
+
# set of scopes (any object that responds to `#to_s`)
|
206
|
+
# @param token_attributes [Hash]
|
207
|
+
# Additional attributes to use when creating a token
|
208
|
+
# @option token_attributes [Integer] :expires_in
|
209
|
+
# token lifetime in seconds
|
210
|
+
# @option token_attributes [Boolean] :use_refresh_token
|
211
|
+
# whether to use the refresh token
|
212
|
+
#
|
213
|
+
# @return [Doorkeeper::AccessToken] new access token
|
214
|
+
#
|
215
|
+
def create_for(application:, resource_owner:, scopes:, **token_attributes)
|
216
|
+
token_attributes[:application_id] = application&.id
|
217
|
+
token_attributes[:scopes] = scopes.to_s
|
218
|
+
|
219
|
+
if Doorkeeper.config.polymorphic_resource_owner?
|
220
|
+
token_attributes[:resource_owner] = resource_owner
|
221
|
+
else
|
222
|
+
token_attributes[:resource_owner_id] = resource_owner_id_for(resource_owner)
|
223
|
+
end
|
224
|
+
|
225
|
+
create!(token_attributes)
|
226
|
+
end
|
227
|
+
|
142
228
|
# Looking for not revoked Access Token records that belongs to specific
|
143
229
|
# Application and Resource Owner.
|
144
230
|
#
|
145
231
|
# @param application_id [Integer]
|
146
232
|
# ID of the Application model instance
|
147
|
-
# @param
|
148
|
-
#
|
233
|
+
# @param resource_owner [ActiveRecord::Base, Integer]
|
234
|
+
# Resource Owner model instance or it's ID
|
149
235
|
#
|
150
|
-
# @return [
|
236
|
+
# @return [ActiveRecord::Relation]
|
237
|
+
# collection of matching AccessToken objects
|
151
238
|
#
|
152
|
-
def authorized_tokens_for(application_id,
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
239
|
+
def authorized_tokens_for(application_id, resource_owner)
|
240
|
+
by_resource_owner(resource_owner).where(
|
241
|
+
application_id: application_id,
|
242
|
+
revoked_at: nil,
|
243
|
+
)
|
157
244
|
end
|
158
245
|
|
159
246
|
# Convenience method for backwards-compatibility, return the last
|
@@ -161,28 +248,33 @@ module Doorkeeper
|
|
161
248
|
#
|
162
249
|
# @param application_id [Integer]
|
163
250
|
# ID of the Application model instance
|
164
|
-
# @param
|
251
|
+
# @param resource_owner [ActiveRecord::Base, Integer]
|
165
252
|
# ID of the Resource Owner model instance
|
166
253
|
#
|
167
254
|
# @return [Doorkeeper::AccessToken, nil] matching AccessToken object or
|
168
255
|
# nil if nothing was found
|
169
256
|
#
|
170
|
-
def last_authorized_token_for(application_id,
|
171
|
-
authorized_tokens_for(application_id,
|
257
|
+
def last_authorized_token_for(application_id, resource_owner)
|
258
|
+
authorized_tokens_for(application_id, resource_owner)
|
259
|
+
.ordered_by(:created_at, :desc)
|
260
|
+
.first
|
172
261
|
end
|
173
262
|
|
174
263
|
##
|
175
264
|
# Determines the secret storing transformer
|
176
265
|
# Unless configured otherwise, uses the plain secret strategy
|
266
|
+
#
|
267
|
+
# @return [Doorkeeper::SecretStoring::Base]
|
268
|
+
#
|
177
269
|
def secret_strategy
|
178
|
-
::Doorkeeper.
|
270
|
+
::Doorkeeper.config.token_secret_strategy
|
179
271
|
end
|
180
272
|
|
181
273
|
##
|
182
274
|
# Determine the fallback storing strategy
|
183
275
|
# Unless configured, there will be no fallback
|
184
276
|
def fallback_secret_strategy
|
185
|
-
::Doorkeeper.
|
277
|
+
::Doorkeeper.config.token_secret_fallback_strategy
|
186
278
|
end
|
187
279
|
end
|
188
280
|
|
@@ -209,7 +301,11 @@ module Doorkeeper
|
|
209
301
|
expires_in: expires_in_seconds,
|
210
302
|
application: { uid: application.try(:uid) },
|
211
303
|
created_at: created_at.to_i,
|
212
|
-
}
|
304
|
+
}.tap do |json|
|
305
|
+
if Doorkeeper.configuration.polymorphic_resource_owner?
|
306
|
+
json[:resource_owner_type] = resource_owner_type
|
307
|
+
end
|
308
|
+
end
|
213
309
|
end
|
214
310
|
|
215
311
|
# Indicates whether the token instance have the same credential
|
@@ -221,7 +317,22 @@ module Doorkeeper
|
|
221
317
|
#
|
222
318
|
def same_credential?(access_token)
|
223
319
|
application_id == access_token.application_id &&
|
320
|
+
same_resource_owner?(access_token)
|
321
|
+
end
|
322
|
+
|
323
|
+
# Indicates whether the token instance have the same credential
|
324
|
+
# as the other Access Token.
|
325
|
+
#
|
326
|
+
# @param access_token [Doorkeeper::AccessToken] other token
|
327
|
+
#
|
328
|
+
# @return [Boolean] true if credentials are same of false in other cases
|
329
|
+
#
|
330
|
+
def same_resource_owner?(access_token)
|
331
|
+
if Doorkeeper.configuration.polymorphic_resource_owner?
|
332
|
+
resource_owner == access_token.resource_owner
|
333
|
+
else
|
224
334
|
resource_owner_id == access_token.resource_owner_id
|
335
|
+
end
|
225
336
|
end
|
226
337
|
|
227
338
|
# Indicates if token is acceptable for specific scopes.
|
@@ -259,8 +370,28 @@ module Doorkeeper
|
|
259
370
|
end
|
260
371
|
end
|
261
372
|
|
373
|
+
# Revokes token with `:refresh_token` equal to `:previous_refresh_token`
|
374
|
+
# and clears `:previous_refresh_token` attribute.
|
375
|
+
#
|
376
|
+
def revoke_previous_refresh_token!
|
377
|
+
return if !self.class.refresh_token_revoked_on_use? || previous_refresh_token.blank?
|
378
|
+
|
379
|
+
old_refresh_token&.revoke
|
380
|
+
update_attribute(:previous_refresh_token, "")
|
381
|
+
end
|
382
|
+
|
262
383
|
private
|
263
384
|
|
385
|
+
# Searches for Access Token record with `:refresh_token` equal to
|
386
|
+
# `:previous_refresh_token` value.
|
387
|
+
#
|
388
|
+
# @return [Doorkeeper::AccessToken, nil]
|
389
|
+
# Access Token record or nil if nothing found
|
390
|
+
#
|
391
|
+
def old_refresh_token
|
392
|
+
@old_refresh_token ||= self.class.by_previous_refresh_token(previous_refresh_token)
|
393
|
+
end
|
394
|
+
|
264
395
|
# Generates refresh token with UniqueToken generator.
|
265
396
|
#
|
266
397
|
# @return [String] refresh token value
|
@@ -271,7 +402,7 @@ module Doorkeeper
|
|
271
402
|
end
|
272
403
|
|
273
404
|
# Generates and sets the token value with the
|
274
|
-
# configured Generator class (see Doorkeeper.
|
405
|
+
# configured Generator class (see Doorkeeper.config).
|
275
406
|
#
|
276
407
|
# @return [String] generated token value
|
277
408
|
#
|
@@ -283,20 +414,32 @@ module Doorkeeper
|
|
283
414
|
def generate_token
|
284
415
|
self.created_at ||= Time.now.utc
|
285
416
|
|
286
|
-
@raw_token = token_generator.generate(
|
417
|
+
@raw_token = token_generator.generate(attributes_for_token_generator)
|
418
|
+
secret_strategy.store_secret(self, :token, @raw_token)
|
419
|
+
@raw_token
|
420
|
+
end
|
421
|
+
|
422
|
+
# Set of attributes that would be passed to token generator to
|
423
|
+
# generate unique token based on them.
|
424
|
+
#
|
425
|
+
# @return [Hash] set of attributes
|
426
|
+
#
|
427
|
+
def attributes_for_token_generator
|
428
|
+
{
|
287
429
|
resource_owner_id: resource_owner_id,
|
288
430
|
scopes: scopes,
|
289
431
|
application: application,
|
290
432
|
expires_in: expires_in,
|
291
|
-
created_at: created_at
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
433
|
+
created_at: created_at,
|
434
|
+
}.tap do |attributes|
|
435
|
+
if Doorkeeper.config.polymorphic_resource_owner?
|
436
|
+
attributes[:resource_owner] = resource_owner
|
437
|
+
end
|
438
|
+
end
|
296
439
|
end
|
297
440
|
|
298
441
|
def token_generator
|
299
|
-
generator_name = Doorkeeper.
|
442
|
+
generator_name = Doorkeeper.config.access_token_generator
|
300
443
|
generator = generator_name.constantize
|
301
444
|
|
302
445
|
return generator if generator.respond_to?(:generate)
|
@@ -20,8 +20,8 @@ module Doorkeeper
|
|
20
20
|
# @param uid [#to_s] UID (any object that responds to `#to_s`)
|
21
21
|
# @param secret [#to_s] secret (any object that responds to `#to_s`)
|
22
22
|
#
|
23
|
-
# @return [Doorkeeper::Application, nil]
|
24
|
-
# if there is no record with such credentials
|
23
|
+
# @return [Doorkeeper::Application, nil]
|
24
|
+
# Application instance or nil if there is no record with such credentials
|
25
25
|
#
|
26
26
|
def by_uid_and_secret(uid, secret)
|
27
27
|
app = by_uid(uid)
|
@@ -47,22 +47,23 @@ module Doorkeeper
|
|
47
47
|
# Determines the secret storing transformer
|
48
48
|
# Unless configured otherwise, uses the plain secret strategy
|
49
49
|
def secret_strategy
|
50
|
-
::Doorkeeper.
|
50
|
+
::Doorkeeper.config.application_secret_strategy
|
51
51
|
end
|
52
52
|
|
53
53
|
##
|
54
54
|
# Determine the fallback storing strategy
|
55
55
|
# Unless configured, there will be no fallback
|
56
56
|
def fallback_secret_strategy
|
57
|
-
::Doorkeeper.
|
57
|
+
::Doorkeeper.config.application_secret_fallback_strategy
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
61
|
# Set an application's valid redirect URIs.
|
62
62
|
#
|
63
|
-
# @param uris [String, Array] Newline-separated string or array the URI(s)
|
63
|
+
# @param uris [String, Array<String>] Newline-separated string or array the URI(s)
|
64
|
+
#
|
65
|
+
# @return [String] The redirect URI(s) separated by newlines.
|
64
66
|
#
|
65
|
-
# @return [String] The redirect URI(s) seperated by newlines.
|
66
67
|
def redirect_uri=(uris)
|
67
68
|
super(uris.is_a?(Array) ? uris.join("\n") : uris)
|
68
69
|
end
|
@@ -72,7 +73,7 @@ module Doorkeeper
|
|
72
73
|
# @param input [#to_s] Plain secret provided by user
|
73
74
|
# (any object that responds to `#to_s`)
|
74
75
|
#
|
75
|
-
# @return [
|
76
|
+
# @return [Boolean] Whether the given secret matches the stored secret
|
76
77
|
# of this application.
|
77
78
|
#
|
78
79
|
def secret_matches?(input)
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Doorkeeper
|
4
|
+
module Models
|
5
|
+
module ResourceOwnerable
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
# Searches for record by Resource Owner considering Doorkeeper
|
10
|
+
# configuration for resource owner association.
|
11
|
+
#
|
12
|
+
# @param resource_owner [ActiveRecord::Base, Integer]
|
13
|
+
# resource owner
|
14
|
+
#
|
15
|
+
# @return [Doorkeeper::AccessGrant, Doorkeeper::AccessToken]
|
16
|
+
# collection of records
|
17
|
+
#
|
18
|
+
def by_resource_owner(resource_owner)
|
19
|
+
if Doorkeeper.configuration.polymorphic_resource_owner?
|
20
|
+
where(resource_owner: resource_owner)
|
21
|
+
else
|
22
|
+
where(resource_owner_id: resource_owner_id_for(resource_owner))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
27
|
+
|
28
|
+
# Backward compatible way to retrieve resource owner itself (if
|
29
|
+
# polymorphic association enabled) or just it's ID.
|
30
|
+
#
|
31
|
+
# @param resource_owner [ActiveRecord::Base, Integer]
|
32
|
+
# resource owner
|
33
|
+
#
|
34
|
+
# @return [ActiveRecord::Base, Integer]
|
35
|
+
# instance of Resource Owner or it's ID
|
36
|
+
#
|
37
|
+
def resource_owner_id_for(resource_owner)
|
38
|
+
if resource_owner.respond_to?(:to_key)
|
39
|
+
resource_owner.id
|
40
|
+
else
|
41
|
+
resource_owner
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -11,7 +11,7 @@ module Doorkeeper
|
|
11
11
|
return false if expired?
|
12
12
|
return true unless expires_in
|
13
13
|
|
14
|
-
threshold_limit = 100 - Doorkeeper.
|
14
|
+
threshold_limit = 100 - Doorkeeper.config.token_reuse_limit
|
15
15
|
expires_in_seconds >= threshold_limit * expires_in / 100
|
16
16
|
end
|
17
17
|
end
|
@@ -9,7 +9,7 @@ module Doorkeeper
|
|
9
9
|
# @param clock [Time] time object
|
10
10
|
#
|
11
11
|
def revoke(clock = Time)
|
12
|
-
update_attribute
|
12
|
+
update_attribute(:revoked_at, clock.now.utc)
|
13
13
|
end
|
14
14
|
|
15
15
|
# Indicates whether the object has been revoked.
|
@@ -19,33 +19,6 @@ module Doorkeeper
|
|
19
19
|
def revoked?
|
20
20
|
!!(revoked_at && revoked_at <= Time.now.utc)
|
21
21
|
end
|
22
|
-
|
23
|
-
# Revokes token with `:refresh_token` equal to `:previous_refresh_token`
|
24
|
-
# and clears `:previous_refresh_token` attribute.
|
25
|
-
#
|
26
|
-
def revoke_previous_refresh_token!
|
27
|
-
return unless refresh_token_revoked_on_use?
|
28
|
-
|
29
|
-
old_refresh_token&.revoke
|
30
|
-
update_attribute :previous_refresh_token, ""
|
31
|
-
end
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
# Searches for Access Token record with `:refresh_token` equal to
|
36
|
-
# `:previous_refresh_token` value.
|
37
|
-
#
|
38
|
-
# @return [Doorkeeper::AccessToken, nil]
|
39
|
-
# Access Token record or nil if nothing found
|
40
|
-
#
|
41
|
-
def old_refresh_token
|
42
|
-
@old_refresh_token ||=
|
43
|
-
AccessToken.by_refresh_token(previous_refresh_token)
|
44
|
-
end
|
45
|
-
|
46
|
-
def refresh_token_revoked_on_use?
|
47
|
-
AccessToken.refresh_token_revoked_on_use?
|
48
|
-
end
|
49
22
|
end
|
50
23
|
end
|
51
24
|
end
|
@@ -8,7 +8,11 @@ module Doorkeeper
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def scopes=(value)
|
11
|
-
|
11
|
+
if value.is_a?(Array)
|
12
|
+
super(Doorkeeper::OAuth::Scopes.from_array(value).to_s)
|
13
|
+
else
|
14
|
+
super(Doorkeeper::OAuth::Scopes.from_string(value.to_s).to_s)
|
15
|
+
end
|
12
16
|
end
|
13
17
|
|
14
18
|
def scopes_string
|
@@ -25,9 +25,7 @@ module Doorkeeper
|
|
25
25
|
# @return [Boolean]
|
26
26
|
# Whether input matches secret as per the secret strategy
|
27
27
|
#
|
28
|
-
|
29
|
-
secret_strategy.secret_matches?(input, secret)
|
30
|
-
end
|
28
|
+
delegate :secret_matches?, to: :secret_strategy
|
31
29
|
|
32
30
|
# Returns an instance of the Doorkeeper::AccessToken with
|
33
31
|
# specific token value.
|
@@ -4,37 +4,48 @@ module Doorkeeper
|
|
4
4
|
module OAuth
|
5
5
|
module Authorization
|
6
6
|
class Code
|
7
|
-
|
7
|
+
attr_reader :pre_auth, :resource_owner, :token
|
8
8
|
|
9
9
|
def initialize(pre_auth, resource_owner)
|
10
10
|
@pre_auth = pre_auth
|
11
11
|
@resource_owner = resource_owner
|
12
12
|
end
|
13
13
|
|
14
|
-
def issue_token
|
15
|
-
@token
|
14
|
+
def issue_token!
|
15
|
+
return @token if defined?(@token)
|
16
|
+
|
17
|
+
@token = Doorkeeper.config.access_grant_model.create!(access_grant_attributes)
|
16
18
|
end
|
17
19
|
|
18
|
-
def
|
20
|
+
def oob_redirect
|
19
21
|
{ action: :show, code: token.plaintext_token }
|
20
22
|
end
|
21
23
|
|
22
|
-
def
|
23
|
-
|
24
|
+
def access_grant?
|
25
|
+
true
|
24
26
|
end
|
25
27
|
|
26
28
|
private
|
27
29
|
|
28
30
|
def authorization_code_expires_in
|
29
|
-
|
31
|
+
Doorkeeper.config.authorization_code_expires_in
|
30
32
|
end
|
31
33
|
|
32
34
|
def access_grant_attributes
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
35
|
+
attributes = {
|
36
|
+
application_id: pre_auth.client.id,
|
37
|
+
expires_in: authorization_code_expires_in,
|
38
|
+
redirect_uri: pre_auth.redirect_uri,
|
39
|
+
scopes: pre_auth.scopes.to_s,
|
40
|
+
}
|
41
|
+
|
42
|
+
if Doorkeeper.config.polymorphic_resource_owner?
|
43
|
+
attributes[:resource_owner] = resource_owner
|
44
|
+
else
|
45
|
+
attributes[:resource_owner_id] = resource_owner.id
|
46
|
+
end
|
47
|
+
|
48
|
+
pkce_attributes.merge(attributes)
|
38
49
|
end
|
39
50
|
|
40
51
|
def pkce_attributes
|
@@ -46,10 +57,10 @@ module Doorkeeper
|
|
46
57
|
}
|
47
58
|
end
|
48
59
|
|
49
|
-
#
|
60
|
+
# Ensures firstly, if migration with additional PKCE columns was
|
50
61
|
# generated and migrated
|
51
62
|
def pkce_supported?
|
52
|
-
Doorkeeper
|
63
|
+
Doorkeeper.config.access_grant_model.pkce_supported?
|
53
64
|
end
|
54
65
|
end
|
55
66
|
end
|
@@ -4,12 +4,12 @@ module Doorkeeper
|
|
4
4
|
module OAuth
|
5
5
|
module Authorization
|
6
6
|
class Context
|
7
|
-
attr_reader :client, :grant_type, :scopes
|
7
|
+
attr_reader :client, :grant_type, :resource_owner, :scopes
|
8
8
|
|
9
|
-
def initialize(
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
def initialize(**attributes)
|
10
|
+
attributes.each do |name, value|
|
11
|
+
instance_variable_set(:"@#{name}", value) if respond_to?(name)
|
12
|
+
end
|
13
13
|
end
|
14
14
|
end
|
15
15
|
end
|