doorkeeper 5.1.0 → 5.5.0
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} +234 -25
- data/README.md +21 -11
- data/app/controllers/doorkeeper/application_controller.rb +2 -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 +5 -5
- 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 +291 -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 +32 -10
- 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 +2 -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 +1 -5
- 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 +43 -310
- 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
@@ -1,591 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "spec_helper"
|
4
|
-
|
5
|
-
module Doorkeeper
|
6
|
-
describe AccessToken do
|
7
|
-
let(:clazz) { Doorkeeper::AccessToken }
|
8
|
-
subject { FactoryBot.build(:access_token) }
|
9
|
-
|
10
|
-
it { expect(subject).to be_valid }
|
11
|
-
|
12
|
-
it_behaves_like "an accessible token"
|
13
|
-
it_behaves_like "a revocable token"
|
14
|
-
it_behaves_like "a unique token" do
|
15
|
-
let(:factory_name) { :access_token }
|
16
|
-
end
|
17
|
-
|
18
|
-
module CustomGeneratorArgs
|
19
|
-
def self.generate; end
|
20
|
-
end
|
21
|
-
|
22
|
-
describe :generate_token do
|
23
|
-
it "generates a token using the default method" do
|
24
|
-
FactoryBot.create :access_token
|
25
|
-
|
26
|
-
token = FactoryBot.create :access_token
|
27
|
-
expect(token.token).to be_a(String)
|
28
|
-
end
|
29
|
-
|
30
|
-
context "with hashing enabled" do
|
31
|
-
let(:token) { FactoryBot.create :access_token }
|
32
|
-
include_context "with token hashing enabled"
|
33
|
-
|
34
|
-
it "holds a volatile plaintext token when created" do
|
35
|
-
expect(token.plaintext_token).to be_a(String)
|
36
|
-
expect(token.token)
|
37
|
-
.to eq(hashed_or_plain_token_func.call(token.plaintext_token))
|
38
|
-
|
39
|
-
# Finder method only finds the hashed token
|
40
|
-
loaded = clazz.find_by(token: token.token)
|
41
|
-
expect(loaded).to eq(token)
|
42
|
-
expect(loaded.plaintext_token).to be_nil
|
43
|
-
expect(loaded.token).to eq(token.token)
|
44
|
-
end
|
45
|
-
|
46
|
-
it "does not find_by plain text tokens" do
|
47
|
-
expect(clazz.find_by(token: token.plaintext_token)).to be_nil
|
48
|
-
end
|
49
|
-
|
50
|
-
describe "with having a plain text token" do
|
51
|
-
let(:plain_text_token) { "plain text token" }
|
52
|
-
let(:access_token) { FactoryBot.create :access_token }
|
53
|
-
|
54
|
-
before do
|
55
|
-
# Assume we have a plain text token from before activating the option
|
56
|
-
access_token.update_column(:token, plain_text_token)
|
57
|
-
end
|
58
|
-
|
59
|
-
context "without fallback lookup" do
|
60
|
-
it "does not provide lookups with either through by_token" do
|
61
|
-
expect(clazz.by_token(plain_text_token)).to eq(nil)
|
62
|
-
expect(clazz.by_token(access_token.token)).to eq(nil)
|
63
|
-
|
64
|
-
# And it does not touch the token
|
65
|
-
access_token.reload
|
66
|
-
expect(access_token.token).to eq(plain_text_token)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
context "with fallback lookup" do
|
71
|
-
include_context "with token hashing and fallback lookup enabled"
|
72
|
-
|
73
|
-
it "upgrades a plain token when falling back to it" do
|
74
|
-
# Side-effect: This will automatically upgrade the token
|
75
|
-
expect(clazz).to receive(:upgrade_fallback_value).and_call_original
|
76
|
-
expect(clazz.by_token(plain_text_token)).to eq(access_token)
|
77
|
-
|
78
|
-
# Will find subsequently by hashing the token
|
79
|
-
expect(clazz.by_token(plain_text_token)).to eq(access_token)
|
80
|
-
|
81
|
-
# And it modifies the token value
|
82
|
-
access_token.reload
|
83
|
-
expect(access_token.token).not_to eq(plain_text_token)
|
84
|
-
expect(clazz.find_by(token: plain_text_token)).to eq(nil)
|
85
|
-
expect(clazz.find_by(token: access_token.token)).not_to be_nil
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
it "generates a token using a custom object" do
|
92
|
-
eigenclass = class << CustomGeneratorArgs; self; end
|
93
|
-
eigenclass.class_eval do
|
94
|
-
remove_method :generate
|
95
|
-
end
|
96
|
-
module CustomGeneratorArgs
|
97
|
-
def self.generate(opts = {})
|
98
|
-
"custom_generator_token_#{opts[:resource_owner_id]}"
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
Doorkeeper.configure do
|
103
|
-
orm DOORKEEPER_ORM
|
104
|
-
access_token_generator "Doorkeeper::CustomGeneratorArgs"
|
105
|
-
end
|
106
|
-
|
107
|
-
token = FactoryBot.create :access_token
|
108
|
-
expect(token.token).to match(/custom_generator_token_\d+/)
|
109
|
-
end
|
110
|
-
|
111
|
-
it "allows the custom generator to access the application details" do
|
112
|
-
eigenclass = class << CustomGeneratorArgs; self; end
|
113
|
-
eigenclass.class_eval do
|
114
|
-
remove_method :generate
|
115
|
-
end
|
116
|
-
module CustomGeneratorArgs
|
117
|
-
def self.generate(opts = {})
|
118
|
-
"custom_generator_token_#{opts[:application].name}"
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
Doorkeeper.configure do
|
123
|
-
orm DOORKEEPER_ORM
|
124
|
-
access_token_generator "Doorkeeper::CustomGeneratorArgs"
|
125
|
-
end
|
126
|
-
|
127
|
-
token = FactoryBot.create :access_token
|
128
|
-
expect(token.token).to match(/custom_generator_token_Application \d+/)
|
129
|
-
end
|
130
|
-
|
131
|
-
it "allows the custom generator to access the scopes" do
|
132
|
-
eigenclass = class << CustomGeneratorArgs; self; end
|
133
|
-
eigenclass.class_eval do
|
134
|
-
remove_method :generate
|
135
|
-
end
|
136
|
-
module CustomGeneratorArgs
|
137
|
-
def self.generate(opts = {})
|
138
|
-
"custom_generator_token_#{opts[:scopes].count}_#{opts[:scopes]}"
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
Doorkeeper.configure do
|
143
|
-
orm DOORKEEPER_ORM
|
144
|
-
access_token_generator "Doorkeeper::CustomGeneratorArgs"
|
145
|
-
end
|
146
|
-
|
147
|
-
token = FactoryBot.create :access_token, scopes: "public write"
|
148
|
-
|
149
|
-
expect(token.token).to eq "custom_generator_token_2_public write"
|
150
|
-
end
|
151
|
-
|
152
|
-
it "allows the custom generator to access the expiry length" do
|
153
|
-
eigenclass = class << CustomGeneratorArgs; self; end
|
154
|
-
eigenclass.class_eval do
|
155
|
-
remove_method :generate
|
156
|
-
end
|
157
|
-
module CustomGeneratorArgs
|
158
|
-
def self.generate(opts = {})
|
159
|
-
"custom_generator_token_#{opts[:expires_in]}"
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
Doorkeeper.configure do
|
164
|
-
orm DOORKEEPER_ORM
|
165
|
-
access_token_generator "Doorkeeper::CustomGeneratorArgs"
|
166
|
-
end
|
167
|
-
|
168
|
-
token = FactoryBot.create :access_token
|
169
|
-
expect(token.token).to eq "custom_generator_token_7200"
|
170
|
-
end
|
171
|
-
|
172
|
-
it "allows the custom generator to access the created time" do
|
173
|
-
module CustomGeneratorArgs
|
174
|
-
def self.generate(opts = {})
|
175
|
-
"custom_generator_token_#{opts[:created_at].to_i}"
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
Doorkeeper.configure do
|
180
|
-
orm DOORKEEPER_ORM
|
181
|
-
access_token_generator "Doorkeeper::CustomGeneratorArgs"
|
182
|
-
end
|
183
|
-
|
184
|
-
token = FactoryBot.create :access_token
|
185
|
-
created_at = token.created_at
|
186
|
-
expect(token.token).to eq "custom_generator_token_#{created_at.to_i}"
|
187
|
-
end
|
188
|
-
|
189
|
-
it "raises an error if the custom object does not support generate" do
|
190
|
-
module NoGenerate
|
191
|
-
end
|
192
|
-
|
193
|
-
Doorkeeper.configure do
|
194
|
-
orm DOORKEEPER_ORM
|
195
|
-
access_token_generator "Doorkeeper::NoGenerate"
|
196
|
-
end
|
197
|
-
|
198
|
-
expect { FactoryBot.create :access_token }.to(
|
199
|
-
raise_error(Doorkeeper::Errors::UnableToGenerateToken)
|
200
|
-
)
|
201
|
-
end
|
202
|
-
|
203
|
-
it "raises original error if something went wrong in custom generator" do
|
204
|
-
eigenclass = class << CustomGeneratorArgs; self; end
|
205
|
-
eigenclass.class_eval do
|
206
|
-
remove_method :generate
|
207
|
-
end
|
208
|
-
|
209
|
-
module CustomGeneratorArgs
|
210
|
-
def self.generate(_opts = {})
|
211
|
-
raise LoadError, "custom behaviour"
|
212
|
-
end
|
213
|
-
end
|
214
|
-
|
215
|
-
Doorkeeper.configure do
|
216
|
-
orm DOORKEEPER_ORM
|
217
|
-
access_token_generator "Doorkeeper::CustomGeneratorArgs"
|
218
|
-
end
|
219
|
-
|
220
|
-
expect { FactoryBot.create :access_token }.to(
|
221
|
-
raise_error(LoadError)
|
222
|
-
)
|
223
|
-
end
|
224
|
-
|
225
|
-
it "raises an error if the custom object does not exist" do
|
226
|
-
Doorkeeper.configure do
|
227
|
-
orm DOORKEEPER_ORM
|
228
|
-
access_token_generator "Doorkeeper::NotReal"
|
229
|
-
end
|
230
|
-
|
231
|
-
expect { FactoryBot.create :access_token }.to(
|
232
|
-
raise_error(Doorkeeper::Errors::TokenGeneratorNotFound, /NotReal/)
|
233
|
-
)
|
234
|
-
end
|
235
|
-
end
|
236
|
-
|
237
|
-
describe :refresh_token do
|
238
|
-
it "has empty refresh token if it was not required" do
|
239
|
-
token = FactoryBot.create :access_token
|
240
|
-
expect(token.refresh_token).to be_nil
|
241
|
-
end
|
242
|
-
|
243
|
-
it "generates a refresh token if it was requested" do
|
244
|
-
token = FactoryBot.create :access_token, use_refresh_token: true
|
245
|
-
expect(token.refresh_token).not_to be_nil
|
246
|
-
end
|
247
|
-
|
248
|
-
it "is not valid if token exists" do
|
249
|
-
token1 = FactoryBot.create :access_token, use_refresh_token: true
|
250
|
-
token2 = FactoryBot.create :access_token, use_refresh_token: true
|
251
|
-
token2.refresh_token = token1.refresh_token
|
252
|
-
expect(token2).not_to be_valid
|
253
|
-
end
|
254
|
-
|
255
|
-
it "expects database to raise an error if refresh tokens are the same" do
|
256
|
-
token1 = FactoryBot.create :access_token, use_refresh_token: true
|
257
|
-
token2 = FactoryBot.create :access_token, use_refresh_token: true
|
258
|
-
expect do
|
259
|
-
token2.refresh_token = token1.refresh_token
|
260
|
-
token2.save(validate: false)
|
261
|
-
end.to raise_error(uniqueness_error)
|
262
|
-
end
|
263
|
-
|
264
|
-
context "with hashing enabled" do
|
265
|
-
include_context "with token hashing enabled"
|
266
|
-
let(:token) { FactoryBot.create :access_token, use_refresh_token: true }
|
267
|
-
|
268
|
-
it "holds a volatile refresh token when created" do
|
269
|
-
expect(token.plaintext_refresh_token).to be_a(String)
|
270
|
-
expect(token.refresh_token)
|
271
|
-
.to eq(hashed_or_plain_token_func.call(token.plaintext_refresh_token))
|
272
|
-
|
273
|
-
# Finder method only finds the hashed token
|
274
|
-
loaded = clazz.find_by(refresh_token: token.refresh_token)
|
275
|
-
expect(loaded).to eq(token)
|
276
|
-
expect(loaded.plaintext_refresh_token).to be_nil
|
277
|
-
expect(loaded.refresh_token).to eq(token.refresh_token)
|
278
|
-
end
|
279
|
-
|
280
|
-
it "does not find_by plain text refresh tokens" do
|
281
|
-
expect(clazz.find_by(refresh_token: token.plaintext_refresh_token)).to be_nil
|
282
|
-
end
|
283
|
-
|
284
|
-
describe "with having a plain text token" do
|
285
|
-
let(:plain_refresh_token) { "plain refresh token" }
|
286
|
-
let(:access_token) { FactoryBot.create :access_token }
|
287
|
-
|
288
|
-
before do
|
289
|
-
# Assume we have a plain text token from before activating the option
|
290
|
-
access_token.update_column(:refresh_token, plain_refresh_token)
|
291
|
-
end
|
292
|
-
|
293
|
-
context "without fallback lookup" do
|
294
|
-
it "does not provide lookups with either through by_token" do
|
295
|
-
expect(clazz.by_refresh_token(plain_refresh_token)).to eq(nil)
|
296
|
-
expect(clazz.by_refresh_token(access_token.refresh_token)).to eq(nil)
|
297
|
-
|
298
|
-
# And it does not touch the token
|
299
|
-
access_token.reload
|
300
|
-
expect(access_token.refresh_token).to eq(plain_refresh_token)
|
301
|
-
end
|
302
|
-
end
|
303
|
-
|
304
|
-
context "with fallback lookup" do
|
305
|
-
include_context "with token hashing and fallback lookup enabled"
|
306
|
-
|
307
|
-
it "upgrades a plain token when falling back to it" do
|
308
|
-
# Side-effect: This will automatically upgrade the token
|
309
|
-
expect(clazz).to receive(:upgrade_fallback_value).and_call_original
|
310
|
-
expect(clazz.by_refresh_token(plain_refresh_token)).to eq(access_token)
|
311
|
-
|
312
|
-
# Will find subsequently by hashing the token
|
313
|
-
expect(clazz.by_refresh_token(plain_refresh_token)).to eq(access_token)
|
314
|
-
|
315
|
-
# And it modifies the token value
|
316
|
-
access_token.reload
|
317
|
-
expect(access_token.refresh_token).not_to eq(plain_refresh_token)
|
318
|
-
expect(clazz.find_by(refresh_token: plain_refresh_token)).to eq(nil)
|
319
|
-
expect(clazz.find_by(refresh_token: access_token.refresh_token)).not_to be_nil
|
320
|
-
end
|
321
|
-
end
|
322
|
-
end
|
323
|
-
end
|
324
|
-
end
|
325
|
-
|
326
|
-
describe "validations" do
|
327
|
-
it "is valid without resource_owner_id" do
|
328
|
-
# For client credentials flow
|
329
|
-
subject.resource_owner_id = nil
|
330
|
-
expect(subject).to be_valid
|
331
|
-
end
|
332
|
-
|
333
|
-
it "is valid without application_id" do
|
334
|
-
# For resource owner credentials flow
|
335
|
-
subject.application_id = nil
|
336
|
-
expect(subject).to be_valid
|
337
|
-
end
|
338
|
-
end
|
339
|
-
|
340
|
-
describe "#same_credential?" do
|
341
|
-
context "with default parameters" do
|
342
|
-
let(:resource_owner_id) { 100 }
|
343
|
-
let(:application) { FactoryBot.create :application }
|
344
|
-
let(:default_attributes) do
|
345
|
-
{ application: application, resource_owner_id: resource_owner_id }
|
346
|
-
end
|
347
|
-
let(:access_token1) { FactoryBot.create :access_token, default_attributes }
|
348
|
-
|
349
|
-
context "the second token has the same owner and same app" do
|
350
|
-
let(:access_token2) { FactoryBot.create :access_token, default_attributes }
|
351
|
-
it "success" do
|
352
|
-
expect(access_token1.same_credential?(access_token2)).to be_truthy
|
353
|
-
end
|
354
|
-
end
|
355
|
-
|
356
|
-
context "the second token has same owner and different app" do
|
357
|
-
let(:other_application) { FactoryBot.create :application }
|
358
|
-
let(:access_token2) do
|
359
|
-
FactoryBot.create :access_token,
|
360
|
-
application: other_application,
|
361
|
-
resource_owner_id: resource_owner_id
|
362
|
-
end
|
363
|
-
|
364
|
-
it "fail" do
|
365
|
-
expect(access_token1.same_credential?(access_token2)).to be_falsey
|
366
|
-
end
|
367
|
-
end
|
368
|
-
|
369
|
-
context "the second token has different owner and different app" do
|
370
|
-
let(:other_application) { FactoryBot.create :application }
|
371
|
-
let(:access_token2) do
|
372
|
-
FactoryBot.create :access_token, application: other_application, resource_owner_id: 42
|
373
|
-
end
|
374
|
-
|
375
|
-
it "fail" do
|
376
|
-
expect(access_token1.same_credential?(access_token2)).to be_falsey
|
377
|
-
end
|
378
|
-
end
|
379
|
-
|
380
|
-
context "the second token has different owner and same app" do
|
381
|
-
let(:access_token2) do
|
382
|
-
FactoryBot.create :access_token, application: application, resource_owner_id: 42
|
383
|
-
end
|
384
|
-
|
385
|
-
it "fail" do
|
386
|
-
expect(access_token1.same_credential?(access_token2)).to be_falsey
|
387
|
-
end
|
388
|
-
end
|
389
|
-
end
|
390
|
-
end
|
391
|
-
|
392
|
-
describe "#acceptable?" do
|
393
|
-
context "a token that is not accessible" do
|
394
|
-
let(:token) { FactoryBot.create(:access_token, created_at: 6.hours.ago) }
|
395
|
-
|
396
|
-
it "should return false" do
|
397
|
-
expect(token.acceptable?(nil)).to be false
|
398
|
-
end
|
399
|
-
end
|
400
|
-
|
401
|
-
context "a token that has the incorrect scopes" do
|
402
|
-
let(:token) { FactoryBot.create(:access_token) }
|
403
|
-
|
404
|
-
it "should return false" do
|
405
|
-
expect(token.acceptable?(["public"])).to be false
|
406
|
-
end
|
407
|
-
end
|
408
|
-
|
409
|
-
context "a token is acceptable with the correct scopes" do
|
410
|
-
let(:token) do
|
411
|
-
token = FactoryBot.create(:access_token)
|
412
|
-
token[:scopes] = "public"
|
413
|
-
token
|
414
|
-
end
|
415
|
-
|
416
|
-
it "should return true" do
|
417
|
-
expect(token.acceptable?(["public"])).to be true
|
418
|
-
end
|
419
|
-
end
|
420
|
-
end
|
421
|
-
|
422
|
-
describe ".revoke_all_for" do
|
423
|
-
let(:resource_owner) { double(id: 100) }
|
424
|
-
let(:application) { FactoryBot.create :application }
|
425
|
-
let(:default_attributes) do
|
426
|
-
{ application: application, resource_owner_id: resource_owner.id }
|
427
|
-
end
|
428
|
-
|
429
|
-
it "revokes all tokens for given application and resource owner" do
|
430
|
-
FactoryBot.create :access_token, default_attributes
|
431
|
-
AccessToken.revoke_all_for application.id, resource_owner
|
432
|
-
AccessToken.all.each do |token|
|
433
|
-
expect(token).to be_revoked
|
434
|
-
end
|
435
|
-
end
|
436
|
-
|
437
|
-
it "matches application" do
|
438
|
-
access_token_for_different_app = FactoryBot.create(
|
439
|
-
:access_token,
|
440
|
-
default_attributes.merge(application: FactoryBot.create(:application))
|
441
|
-
)
|
442
|
-
|
443
|
-
AccessToken.revoke_all_for application.id, resource_owner
|
444
|
-
|
445
|
-
expect(access_token_for_different_app.reload).not_to be_revoked
|
446
|
-
end
|
447
|
-
|
448
|
-
it "matches resource owner" do
|
449
|
-
access_token_for_different_owner = FactoryBot.create(
|
450
|
-
:access_token,
|
451
|
-
default_attributes.merge(resource_owner_id: 90)
|
452
|
-
)
|
453
|
-
|
454
|
-
AccessToken.revoke_all_for application.id, resource_owner
|
455
|
-
|
456
|
-
expect(access_token_for_different_owner.reload).not_to be_revoked
|
457
|
-
end
|
458
|
-
end
|
459
|
-
|
460
|
-
describe ".matching_token_for" do
|
461
|
-
let(:resource_owner_id) { 100 }
|
462
|
-
let(:application) { FactoryBot.create :application }
|
463
|
-
let(:scopes) { Doorkeeper::OAuth::Scopes.from_string("public write") }
|
464
|
-
let(:default_attributes) do
|
465
|
-
{
|
466
|
-
application: application,
|
467
|
-
resource_owner_id: resource_owner_id,
|
468
|
-
scopes: scopes.to_s,
|
469
|
-
}
|
470
|
-
end
|
471
|
-
|
472
|
-
before do
|
473
|
-
default_scopes_exist(*scopes.all)
|
474
|
-
end
|
475
|
-
|
476
|
-
it "returns only one token" do
|
477
|
-
token = FactoryBot.create :access_token, default_attributes
|
478
|
-
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
479
|
-
expect(last_token).to eq(token)
|
480
|
-
end
|
481
|
-
|
482
|
-
it "accepts resource owner as object" do
|
483
|
-
resource_owner = double(to_key: true, id: 100)
|
484
|
-
token = FactoryBot.create :access_token, default_attributes
|
485
|
-
last_token = AccessToken.matching_token_for(application, resource_owner, scopes)
|
486
|
-
expect(last_token).to eq(token)
|
487
|
-
end
|
488
|
-
|
489
|
-
it "accepts nil as resource owner" do
|
490
|
-
token = FactoryBot.create :access_token, default_attributes.merge(resource_owner_id: nil)
|
491
|
-
last_token = AccessToken.matching_token_for(application, nil, scopes)
|
492
|
-
expect(last_token).to eq(token)
|
493
|
-
end
|
494
|
-
|
495
|
-
it "excludes revoked tokens" do
|
496
|
-
FactoryBot.create :access_token, default_attributes.merge(revoked_at: 1.day.ago)
|
497
|
-
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
498
|
-
expect(last_token).to be_nil
|
499
|
-
end
|
500
|
-
|
501
|
-
it "excludes tokens with a different application" do
|
502
|
-
FactoryBot.create :access_token, default_attributes.merge(application: FactoryBot.create(:application))
|
503
|
-
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
504
|
-
expect(last_token).to be_nil
|
505
|
-
end
|
506
|
-
|
507
|
-
it "excludes tokens with a different resource owner" do
|
508
|
-
FactoryBot.create :access_token, default_attributes.merge(resource_owner_id: 2)
|
509
|
-
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
510
|
-
expect(last_token).to be_nil
|
511
|
-
end
|
512
|
-
|
513
|
-
it "excludes tokens with fewer scopes" do
|
514
|
-
FactoryBot.create :access_token, default_attributes.merge(scopes: "public")
|
515
|
-
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
516
|
-
expect(last_token).to be_nil
|
517
|
-
end
|
518
|
-
|
519
|
-
it "excludes tokens with different scopes" do
|
520
|
-
FactoryBot.create :access_token, default_attributes.merge(scopes: "public email")
|
521
|
-
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
522
|
-
expect(last_token).to be_nil
|
523
|
-
end
|
524
|
-
|
525
|
-
it "excludes tokens with additional scopes" do
|
526
|
-
FactoryBot.create :access_token, default_attributes.merge(scopes: "public write email")
|
527
|
-
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
528
|
-
expect(last_token).to be_nil
|
529
|
-
end
|
530
|
-
|
531
|
-
it "excludes tokens with scopes that are not present in server scopes" do
|
532
|
-
FactoryBot.create :access_token, default_attributes.merge(
|
533
|
-
application: application, scopes: "public read"
|
534
|
-
)
|
535
|
-
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
536
|
-
expect(last_token).to be_nil
|
537
|
-
end
|
538
|
-
|
539
|
-
it "excludes tokens with scopes that are not present in application scopes" do
|
540
|
-
application = FactoryBot.create :application, scopes: "private read"
|
541
|
-
FactoryBot.create :access_token, default_attributes.merge(
|
542
|
-
application: application
|
543
|
-
)
|
544
|
-
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
545
|
-
expect(last_token).to be_nil
|
546
|
-
end
|
547
|
-
|
548
|
-
it "does not match token if empty scope requested and token/app scopes present" do
|
549
|
-
application = FactoryBot.create :application, scopes: "sample:scope"
|
550
|
-
app_params = {
|
551
|
-
application_id: application.id, scopes: "sample:scope",
|
552
|
-
resource_owner_id: 100,
|
553
|
-
}
|
554
|
-
FactoryBot.create :access_token, app_params
|
555
|
-
empty_scopes = Doorkeeper::OAuth::Scopes.from_string("")
|
556
|
-
last_token = AccessToken.matching_token_for(application, 100, empty_scopes)
|
557
|
-
expect(last_token).to be_nil
|
558
|
-
end
|
559
|
-
|
560
|
-
it "matches token if empty scope requested and no token scopes present" do
|
561
|
-
empty_scopes = Doorkeeper::OAuth::Scopes.from_string("")
|
562
|
-
token = FactoryBot.create :access_token, default_attributes.merge(scopes: empty_scopes)
|
563
|
-
last_token = AccessToken.matching_token_for(application, 100, empty_scopes)
|
564
|
-
expect(last_token).to eq(token)
|
565
|
-
end
|
566
|
-
|
567
|
-
it "returns the last matching token" do
|
568
|
-
FactoryBot.create :access_token, default_attributes.merge(created_at: 1.day.ago)
|
569
|
-
matching_token = FactoryBot.create :access_token, default_attributes
|
570
|
-
FactoryBot.create :access_token, default_attributes.merge(scopes: "public")
|
571
|
-
|
572
|
-
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
573
|
-
expect(last_token).to eq(matching_token)
|
574
|
-
end
|
575
|
-
end
|
576
|
-
|
577
|
-
describe "#as_json" do
|
578
|
-
it "returns as_json hash" do
|
579
|
-
token = FactoryBot.create :access_token
|
580
|
-
token_hash = {
|
581
|
-
resource_owner_id: token.resource_owner_id,
|
582
|
-
scope: token.scopes,
|
583
|
-
expires_in: token.expires_in_seconds,
|
584
|
-
application: { uid: token.application.uid },
|
585
|
-
created_at: token.created_at.to_i,
|
586
|
-
}
|
587
|
-
expect(token.as_json).to eq token_hash
|
588
|
-
end
|
589
|
-
end
|
590
|
-
end
|
591
|
-
end
|