doorkeeper 5.0.2 → 5.1.0
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 +5 -5
- data/.hound.yml +2 -1
- data/.rubocop.yml +37 -4
- data/.travis.yml +11 -21
- data/Appraisals +29 -7
- data/Dangerfile +5 -2
- data/Gemfile +19 -5
- data/NEWS.md +80 -19
- data/README.md +75 -485
- data/Rakefile +10 -8
- data/app/controllers/doorkeeper/application_controller.rb +1 -2
- data/app/controllers/doorkeeper/application_metal_controller.rb +2 -13
- data/app/controllers/doorkeeper/applications_controller.rb +17 -5
- data/app/controllers/doorkeeper/token_info_controller.rb +2 -2
- data/app/controllers/doorkeeper/tokens_controller.rb +11 -11
- data/app/helpers/doorkeeper/dashboard_helper.rb +1 -1
- data/app/validators/redirect_uri_validator.rb +5 -2
- data/app/views/doorkeeper/applications/_form.html.erb +6 -0
- data/app/views/doorkeeper/applications/show.html.erb +1 -1
- data/app/views/layouts/doorkeeper/admin.html.erb +5 -3
- data/bin/console +16 -0
- data/config/locales/en.yml +1 -0
- data/doorkeeper.gemspec +24 -21
- data/gemfiles/rails_5_0.gemfile +9 -4
- data/gemfiles/rails_5_1.gemfile +9 -4
- data/gemfiles/rails_5_2.gemfile +10 -5
- data/gemfiles/rails_6_0.gemfile +17 -0
- data/gemfiles/rails_master.gemfile +9 -9
- data/lib/doorkeeper/config/option.rb +64 -0
- data/lib/doorkeeper/config.rb +191 -75
- data/lib/doorkeeper/engine.rb +1 -1
- data/lib/doorkeeper/grape/authorization_decorator.rb +4 -4
- data/lib/doorkeeper/grape/helpers.rb +3 -3
- data/lib/doorkeeper/helpers/controller.rb +3 -2
- data/lib/doorkeeper/models/access_grant_mixin.rb +20 -3
- data/lib/doorkeeper/models/access_token_mixin.rb +63 -19
- data/lib/doorkeeper/models/application_mixin.rb +43 -1
- data/lib/doorkeeper/models/concerns/expirable.rb +4 -2
- data/lib/doorkeeper/models/concerns/ownership.rb +1 -6
- data/lib/doorkeeper/models/concerns/reusable.rb +19 -0
- data/lib/doorkeeper/models/concerns/revocable.rb +2 -1
- data/lib/doorkeeper/models/concerns/scopes.rb +5 -1
- data/lib/doorkeeper/models/concerns/secret_storable.rb +108 -0
- data/lib/doorkeeper/oauth/authorization/code.rb +2 -2
- data/lib/doorkeeper/oauth/authorization/token.rb +12 -7
- data/lib/doorkeeper/oauth/authorization/uri_builder.rb +1 -1
- data/lib/doorkeeper/oauth/authorization_code_request.rb +6 -4
- data/lib/doorkeeper/oauth/client.rb +1 -1
- data/lib/doorkeeper/oauth/client_credentials/validation.rb +5 -4
- data/lib/doorkeeper/oauth/client_credentials_request.rb +1 -1
- data/lib/doorkeeper/oauth/code_response.rb +2 -2
- data/lib/doorkeeper/oauth/error_response.rb +10 -6
- data/lib/doorkeeper/oauth/forbidden_token_response.rb +1 -1
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +23 -8
- data/lib/doorkeeper/oauth/helpers/unique_token.rb +13 -1
- data/lib/doorkeeper/oauth/helpers/uri_checker.rb +37 -1
- data/lib/doorkeeper/oauth/invalid_token_response.rb +5 -1
- data/lib/doorkeeper/oauth/password_access_token_request.rb +7 -2
- data/lib/doorkeeper/oauth/pre_authorization.rb +11 -5
- data/lib/doorkeeper/oauth/refresh_token_request.rb +5 -2
- data/lib/doorkeeper/oauth/scopes.rb +5 -3
- data/lib/doorkeeper/oauth/token.rb +2 -2
- data/lib/doorkeeper/oauth/token_introspection.rb +74 -8
- data/lib/doorkeeper/oauth/token_response.rb +9 -9
- data/lib/doorkeeper/oauth.rb +5 -5
- data/lib/doorkeeper/orm/active_record/access_grant.rb +27 -13
- data/lib/doorkeeper/orm/active_record/access_token.rb +6 -13
- data/lib/doorkeeper/orm/active_record/application.rb +26 -7
- data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +10 -3
- data/lib/doorkeeper/orm/active_record.rb +6 -6
- data/lib/doorkeeper/rails/helpers.rb +1 -1
- data/lib/doorkeeper/rails/routes/mapping.rb +7 -7
- data/lib/doorkeeper/rails/routes.rb +11 -11
- data/lib/doorkeeper/rake/db.rake +13 -13
- data/lib/doorkeeper/rake.rb +1 -1
- data/lib/doorkeeper/request.rb +1 -1
- data/lib/doorkeeper/secret_storing/base.rb +64 -0
- data/lib/doorkeeper/secret_storing/bcrypt.rb +60 -0
- data/lib/doorkeeper/secret_storing/plain.rb +33 -0
- data/lib/doorkeeper/secret_storing/sha256_hash.rb +26 -0
- data/lib/doorkeeper/stale_records_cleaner.rb +1 -1
- data/lib/doorkeeper/version.rb +3 -3
- data/lib/doorkeeper.rb +69 -60
- data/lib/generators/doorkeeper/application_owner_generator.rb +10 -9
- data/lib/generators/doorkeeper/confidential_applications_generator.rb +10 -9
- data/lib/generators/doorkeeper/install_generator.rb +11 -9
- data/lib/generators/doorkeeper/migration_generator.rb +9 -9
- data/lib/generators/doorkeeper/pkce_generator.rb +10 -9
- data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +10 -9
- data/lib/generators/doorkeeper/templates/initializer.rb +120 -13
- data/lib/generators/doorkeeper/templates/migration.rb.erb +15 -7
- data/lib/generators/doorkeeper/views_generator.rb +6 -4
- data/spec/controllers/application_metal_controller_spec.rb +24 -10
- data/spec/controllers/applications_controller_spec.rb +54 -52
- data/spec/controllers/authorizations_controller_spec.rb +139 -145
- data/spec/controllers/protected_resources_controller_spec.rb +78 -76
- data/spec/controllers/token_info_controller_spec.rb +14 -12
- data/spec/controllers/tokens_controller_spec.rb +167 -108
- data/spec/dummy/Rakefile +3 -1
- data/spec/dummy/app/controllers/application_controller.rb +3 -1
- data/spec/dummy/app/controllers/custom_authorizations_controller.rb +2 -0
- data/spec/dummy/app/controllers/full_protected_resources_controller.rb +4 -2
- data/spec/dummy/app/controllers/home_controller.rb +5 -3
- data/spec/dummy/app/controllers/metal_controller.rb +2 -0
- data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +4 -2
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/models/user.rb +2 -0
- data/spec/dummy/config/application.rb +25 -1
- data/spec/dummy/config/environments/development.rb +2 -0
- data/spec/dummy/config/environments/production.rb +2 -0
- data/spec/dummy/config/environments/test.rb +3 -1
- data/spec/dummy/config/initializers/backtrace_silencers.rb +2 -0
- data/spec/dummy/config/initializers/doorkeeper.rb +5 -2
- data/spec/dummy/config/initializers/secret_token.rb +3 -1
- data/spec/dummy/config/initializers/session_store.rb +3 -1
- data/spec/dummy/config/initializers/wrap_parameters.rb +2 -0
- data/spec/dummy/config.ru +3 -1
- data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +17 -10
- data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +2 -0
- data/spec/dummy/db/schema.rb +1 -1
- data/spec/dummy/script/rails +5 -3
- data/spec/factories.rb +8 -6
- data/spec/generators/application_owner_generator_spec.rb +13 -26
- data/spec/generators/confidential_applications_generator_spec.rb +12 -28
- data/spec/generators/install_generator_spec.rb +17 -15
- data/spec/generators/migration_generator_spec.rb +13 -26
- data/spec/generators/pkce_generator_spec.rb +11 -26
- data/spec/generators/previous_refresh_token_generator_spec.rb +16 -29
- data/spec/generators/templates/routes.rb +2 -0
- data/spec/generators/views_generator_spec.rb +14 -12
- data/spec/grape/grape_integration_spec.rb +34 -32
- data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +9 -7
- data/spec/lib/config_spec.rb +268 -99
- data/spec/lib/doorkeeper_spec.rb +3 -1
- data/spec/lib/models/expirable_spec.rb +22 -8
- data/spec/lib/models/reusable_spec.rb +40 -0
- data/spec/lib/models/revocable_spec.rb +8 -6
- data/spec/lib/models/scopes_spec.rb +27 -13
- data/spec/lib/models/secret_storable_spec.rb +135 -0
- data/spec/lib/oauth/authorization/uri_builder_spec.rb +17 -15
- data/spec/lib/oauth/authorization_code_request_spec.rb +34 -11
- data/spec/lib/oauth/base_request_spec.rb +20 -8
- data/spec/lib/oauth/base_response_spec.rb +3 -1
- data/spec/lib/oauth/client/credentials_spec.rb +24 -22
- data/spec/lib/oauth/client_credentials/creator_spec.rb +56 -10
- data/spec/lib/oauth/client_credentials/issuer_spec.rb +27 -18
- data/spec/lib/oauth/client_credentials/validation_spec.rb +20 -15
- data/spec/lib/oauth/client_credentials_integration_spec.rb +7 -5
- data/spec/lib/oauth/client_credentials_request_spec.rb +27 -21
- data/spec/lib/oauth/client_spec.rb +15 -13
- data/spec/lib/oauth/code_request_spec.rb +8 -6
- data/spec/lib/oauth/code_response_spec.rb +9 -7
- data/spec/lib/oauth/error_response_spec.rb +19 -11
- data/spec/lib/oauth/error_spec.rb +4 -2
- data/spec/lib/oauth/forbidden_token_response_spec.rb +7 -5
- data/spec/lib/oauth/helpers/scope_checker_spec.rb +68 -31
- data/spec/lib/oauth/helpers/unique_token_spec.rb +8 -6
- data/spec/lib/oauth/helpers/uri_checker_spec.rb +115 -95
- data/spec/lib/oauth/invalid_token_response_spec.rb +3 -1
- data/spec/lib/oauth/password_access_token_request_spec.rb +79 -30
- data/spec/lib/oauth/pre_authorization_spec.rb +80 -54
- data/spec/lib/oauth/refresh_token_request_spec.rb +36 -33
- data/spec/lib/oauth/scopes_spec.rb +63 -61
- data/spec/lib/oauth/token_request_spec.rb +79 -24
- data/spec/lib/oauth/token_response_spec.rb +40 -38
- data/spec/lib/oauth/token_spec.rb +60 -44
- data/spec/lib/request/strategy_spec.rb +3 -1
- data/spec/lib/secret_storing/base_spec.rb +60 -0
- data/spec/lib/secret_storing/bcrypt_spec.rb +49 -0
- data/spec/lib/secret_storing/plain_spec.rb +44 -0
- data/spec/lib/secret_storing/sha256_hash_spec.rb +48 -0
- data/spec/lib/server_spec.rb +16 -14
- data/spec/lib/stale_records_cleaner_spec.rb +17 -17
- data/spec/models/doorkeeper/access_grant_spec.rb +80 -15
- data/spec/models/doorkeeper/access_token_spec.rb +198 -73
- data/spec/models/doorkeeper/application_spec.rb +142 -45
- data/spec/requests/applications/applications_request_spec.rb +98 -66
- data/spec/requests/applications/authorized_applications_spec.rb +20 -18
- data/spec/requests/endpoints/authorization_spec.rb +25 -23
- data/spec/requests/endpoints/token_spec.rb +38 -36
- data/spec/requests/flows/authorization_code_errors_spec.rb +26 -24
- data/spec/requests/flows/authorization_code_spec.rb +193 -151
- data/spec/requests/flows/client_credentials_spec.rb +54 -52
- data/spec/requests/flows/implicit_grant_errors_spec.rb +10 -8
- data/spec/requests/flows/implicit_grant_spec.rb +27 -25
- data/spec/requests/flows/password_spec.rb +59 -55
- data/spec/requests/flows/refresh_token_spec.rb +45 -43
- data/spec/requests/flows/revoke_token_spec.rb +40 -54
- data/spec/requests/flows/skip_authorization_spec.rb +23 -21
- data/spec/requests/protected_resources/metal_spec.rb +7 -5
- data/spec/requests/protected_resources/private_api_spec.rb +35 -33
- data/spec/routing/custom_controller_routes_spec.rb +71 -65
- data/spec/routing/default_routes_spec.rb +22 -20
- data/spec/routing/scoped_routes_spec.rb +20 -18
- data/spec/spec_helper.rb +15 -13
- data/spec/spec_helper_integration.rb +3 -1
- data/spec/support/dependencies/factory_bot.rb +3 -1
- data/spec/support/doorkeeper_rspec.rb +3 -1
- data/spec/support/helpers/access_token_request_helper.rb +3 -1
- data/spec/support/helpers/authorization_request_helper.rb +4 -2
- data/spec/support/helpers/config_helper.rb +2 -0
- data/spec/support/helpers/model_helper.rb +3 -1
- data/spec/support/helpers/request_spec_helper.rb +5 -3
- data/spec/support/helpers/url_helper.rb +9 -7
- data/spec/support/http_method_shim.rb +4 -9
- data/spec/support/orm/active_record.rb +3 -1
- data/spec/support/shared/controllers_shared_context.rb +18 -16
- data/spec/support/shared/hashing_shared_context.rb +36 -0
- data/spec/support/shared/models_shared_examples.rb +12 -10
- data/spec/validators/redirect_uri_validator_spec.rb +74 -45
- data/spec/version/version_spec.rb +7 -5
- metadata +61 -28
- data/gemfiles/rails_4_2.gemfile +0 -13
- data/spec/dummy/config/initializers/new_framework_defaults.rb +0 -8
|
@@ -1,15 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
require "bcrypt"
|
|
2
5
|
|
|
3
6
|
module Doorkeeper
|
|
4
7
|
describe Application do
|
|
5
|
-
let(:
|
|
6
|
-
let(:
|
|
8
|
+
let(:clazz) { Doorkeeper::Application }
|
|
9
|
+
let(:require_owner) { Doorkeeper.configuration.instance_variable_set("@confirm_application_owner", true) }
|
|
10
|
+
let(:unset_require_owner) { Doorkeeper.configuration.instance_variable_set("@confirm_application_owner", false) }
|
|
7
11
|
let(:new_application) { FactoryBot.build(:application) }
|
|
8
12
|
|
|
9
13
|
let(:uid) { SecureRandom.hex(8) }
|
|
10
14
|
let(:secret) { SecureRandom.hex(8) }
|
|
11
15
|
|
|
12
|
-
context
|
|
16
|
+
context "application_owner is enabled" do
|
|
13
17
|
before do
|
|
14
18
|
Doorkeeper.configure do
|
|
15
19
|
orm DOORKEEPER_ORM
|
|
@@ -17,122 +21,215 @@ module Doorkeeper
|
|
|
17
21
|
end
|
|
18
22
|
end
|
|
19
23
|
|
|
20
|
-
context
|
|
24
|
+
context "application owner is not required" do
|
|
21
25
|
before(:each) do
|
|
22
26
|
unset_require_owner
|
|
23
27
|
end
|
|
24
28
|
|
|
25
|
-
it
|
|
29
|
+
it "is valid given valid attributes" do
|
|
26
30
|
expect(new_application).to be_valid
|
|
27
31
|
end
|
|
28
32
|
end
|
|
29
33
|
|
|
30
|
-
context
|
|
34
|
+
context "application owner is required" do
|
|
31
35
|
before(:each) do
|
|
32
36
|
require_owner
|
|
33
37
|
@owner = FactoryBot.build_stubbed(:doorkeeper_testing_user)
|
|
34
38
|
end
|
|
35
39
|
|
|
36
|
-
it
|
|
40
|
+
it "is invalid without an owner" do
|
|
37
41
|
expect(new_application).not_to be_valid
|
|
38
42
|
end
|
|
39
43
|
|
|
40
|
-
it
|
|
44
|
+
it "is valid with an owner" do
|
|
41
45
|
new_application.owner = @owner
|
|
42
46
|
expect(new_application).to be_valid
|
|
43
47
|
end
|
|
44
48
|
end
|
|
45
49
|
end
|
|
46
50
|
|
|
47
|
-
it
|
|
51
|
+
it "is invalid without a name" do
|
|
48
52
|
new_application.name = nil
|
|
49
53
|
expect(new_application).not_to be_valid
|
|
50
54
|
end
|
|
51
55
|
|
|
52
|
-
it
|
|
56
|
+
it "is invalid without determining confidentiality" do
|
|
53
57
|
new_application.confidential = nil
|
|
54
58
|
expect(new_application).not_to be_valid
|
|
55
59
|
end
|
|
56
60
|
|
|
57
|
-
it
|
|
61
|
+
it "generates uid on create" do
|
|
58
62
|
expect(new_application.uid).to be_nil
|
|
59
63
|
new_application.save
|
|
60
64
|
expect(new_application.uid).not_to be_nil
|
|
61
65
|
end
|
|
62
66
|
|
|
63
|
-
it
|
|
64
|
-
new_application.uid =
|
|
67
|
+
it "generates uid on create if an empty string" do
|
|
68
|
+
new_application.uid = ""
|
|
65
69
|
new_application.save
|
|
66
70
|
expect(new_application.uid).not_to be_blank
|
|
67
71
|
end
|
|
68
72
|
|
|
69
|
-
it
|
|
73
|
+
it "generates uid on create unless one is set" do
|
|
70
74
|
new_application.uid = uid
|
|
71
75
|
new_application.save
|
|
72
76
|
expect(new_application.uid).to eq(uid)
|
|
73
77
|
end
|
|
74
78
|
|
|
75
|
-
it
|
|
79
|
+
it "is invalid without uid" do
|
|
76
80
|
new_application.save
|
|
77
81
|
new_application.uid = nil
|
|
78
82
|
expect(new_application).not_to be_valid
|
|
79
83
|
end
|
|
80
84
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
+
context "redirect URI" do
|
|
86
|
+
context "when grant flows allow blank redirect URI" do
|
|
87
|
+
before do
|
|
88
|
+
Doorkeeper.configure do
|
|
89
|
+
grant_flows %w[password client_credentials]
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it "is valid without redirect_uri" do
|
|
94
|
+
new_application.save
|
|
95
|
+
new_application.redirect_uri = nil
|
|
96
|
+
expect(new_application).to be_valid
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
context "when grant flows require redirect URI" do
|
|
101
|
+
before do
|
|
102
|
+
Doorkeeper.configure do
|
|
103
|
+
grant_flows %w[password client_credentials authorization_code]
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
it "is invalid without redirect_uri" do
|
|
108
|
+
new_application.save
|
|
109
|
+
new_application.redirect_uri = nil
|
|
110
|
+
expect(new_application).not_to be_valid
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
context "when blank URI option disabled" do
|
|
115
|
+
before do
|
|
116
|
+
Doorkeeper.configure do
|
|
117
|
+
grant_flows %w[password client_credentials]
|
|
118
|
+
allow_blank_redirect_uri false
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it "is invalid without redirect_uri" do
|
|
123
|
+
new_application.save
|
|
124
|
+
new_application.redirect_uri = nil
|
|
125
|
+
expect(new_application).not_to be_valid
|
|
126
|
+
end
|
|
127
|
+
end
|
|
85
128
|
end
|
|
86
129
|
|
|
87
|
-
it
|
|
130
|
+
it "checks uniqueness of uid" do
|
|
88
131
|
app1 = FactoryBot.create(:application)
|
|
89
132
|
app2 = FactoryBot.create(:application)
|
|
90
133
|
app2.uid = app1.uid
|
|
91
134
|
expect(app2).not_to be_valid
|
|
92
135
|
end
|
|
93
136
|
|
|
94
|
-
it
|
|
137
|
+
it "expects database to throw an error when uids are the same" do
|
|
95
138
|
app1 = FactoryBot.create(:application)
|
|
96
139
|
app2 = FactoryBot.create(:application)
|
|
97
140
|
app2.uid = app1.uid
|
|
98
141
|
expect { app2.save!(validate: false) }.to raise_error(uniqueness_error)
|
|
99
142
|
end
|
|
100
143
|
|
|
101
|
-
it
|
|
144
|
+
it "generate secret on create" do
|
|
102
145
|
expect(new_application.secret).to be_nil
|
|
103
146
|
new_application.save
|
|
104
147
|
expect(new_application.secret).not_to be_nil
|
|
105
148
|
end
|
|
106
149
|
|
|
107
|
-
it
|
|
108
|
-
new_application.secret =
|
|
150
|
+
it "generate secret on create if is blank string" do
|
|
151
|
+
new_application.secret = ""
|
|
109
152
|
new_application.save
|
|
110
153
|
expect(new_application.secret).not_to be_blank
|
|
111
154
|
end
|
|
112
155
|
|
|
113
|
-
it
|
|
156
|
+
it "generate secret on create unless one is set" do
|
|
114
157
|
new_application.secret = secret
|
|
115
158
|
new_application.save
|
|
116
159
|
expect(new_application.secret).to eq(secret)
|
|
117
160
|
end
|
|
118
161
|
|
|
119
|
-
it
|
|
162
|
+
it "is invalid without secret" do
|
|
120
163
|
new_application.save
|
|
121
164
|
new_application.secret = nil
|
|
122
165
|
expect(new_application).not_to be_valid
|
|
123
166
|
end
|
|
124
167
|
|
|
125
|
-
|
|
168
|
+
context "with hashing enabled" do
|
|
169
|
+
include_context "with application hashing enabled"
|
|
170
|
+
let(:app) { FactoryBot.create :application }
|
|
171
|
+
let(:default_strategy) { Doorkeeper::SecretStoring::Sha256Hash }
|
|
172
|
+
|
|
173
|
+
it "uses SHA256 to avoid additional dependencies" do
|
|
174
|
+
# Ensure token was generated
|
|
175
|
+
app.validate
|
|
176
|
+
expect(app.secret).to eq(default_strategy.transform_secret(app.plaintext_secret))
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
context "when bcrypt strategy is configured" do
|
|
180
|
+
# In this text context, we have bcrypt loaded so `bcrypt_present?`
|
|
181
|
+
# will always be true
|
|
182
|
+
before do
|
|
183
|
+
Doorkeeper.configure do
|
|
184
|
+
hash_application_secrets using: "Doorkeeper::SecretStoring::BCrypt"
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
it "holds a volatile plaintext and BCrypt secret" do
|
|
189
|
+
expect(app.secret_strategy).to eq Doorkeeper::SecretStoring::BCrypt
|
|
190
|
+
expect(app.plaintext_secret).to be_a(String)
|
|
191
|
+
expect(app.secret).not_to eq(app.plaintext_secret)
|
|
192
|
+
expect { ::BCrypt::Password.create(app.secret) }.not_to raise_error
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
it "does not fallback to plain lookup by default" do
|
|
197
|
+
lookup = clazz.by_uid_and_secret(app.uid, app.secret)
|
|
198
|
+
expect(lookup).to eq(nil)
|
|
199
|
+
|
|
200
|
+
lookup = clazz.by_uid_and_secret(app.uid, app.plaintext_secret)
|
|
201
|
+
expect(lookup).to eq(app)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
context "with fallback enabled" do
|
|
205
|
+
include_context "with token hashing and fallback lookup enabled"
|
|
206
|
+
|
|
207
|
+
it "provides plain and hashed lookup" do
|
|
208
|
+
lookup = clazz.by_uid_and_secret(app.uid, app.secret)
|
|
209
|
+
expect(lookup).to eq(app)
|
|
210
|
+
|
|
211
|
+
lookup = clazz.by_uid_and_secret(app.uid, app.plaintext_secret)
|
|
212
|
+
expect(lookup).to eq(app)
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
it "does not provide access to secret after loading" do
|
|
217
|
+
lookup = clazz.by_uid_and_secret(app.uid, app.plaintext_secret)
|
|
218
|
+
expect(lookup.plaintext_secret).to be_nil
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
describe "destroy related models on cascade" do
|
|
126
223
|
before(:each) do
|
|
127
224
|
new_application.save
|
|
128
225
|
end
|
|
129
226
|
|
|
130
|
-
it
|
|
227
|
+
it "should destroy its access grants" do
|
|
131
228
|
FactoryBot.create(:access_grant, application: new_application)
|
|
132
229
|
expect { new_application.destroy }.to change { Doorkeeper::AccessGrant.count }.by(-1)
|
|
133
230
|
end
|
|
134
231
|
|
|
135
|
-
it
|
|
232
|
+
it "should destroy its access tokens" do
|
|
136
233
|
FactoryBot.create(:access_token, application: new_application)
|
|
137
234
|
FactoryBot.create(:access_token, application: new_application, revoked_at: Time.now.utc)
|
|
138
235
|
expect do
|
|
@@ -144,15 +241,15 @@ module Doorkeeper
|
|
|
144
241
|
describe :ordered_by do
|
|
145
242
|
let(:applications) { FactoryBot.create_list(:application, 5) }
|
|
146
243
|
|
|
147
|
-
context
|
|
148
|
-
it
|
|
244
|
+
context "when a direction is not specified" do
|
|
245
|
+
it "calls order with a default order of asc" do
|
|
149
246
|
names = applications.map(&:name).sort
|
|
150
247
|
expect(Application.ordered_by(:name).map(&:name)).to eq(names)
|
|
151
248
|
end
|
|
152
249
|
end
|
|
153
250
|
|
|
154
|
-
context
|
|
155
|
-
it
|
|
251
|
+
context "when a direction is specified" do
|
|
252
|
+
it "calls order with specified direction" do
|
|
156
253
|
names = applications.map(&:name).sort.reverse
|
|
157
254
|
expect(Application.ordered_by(:name, :desc).map(&:name)).to eq(names)
|
|
158
255
|
end
|
|
@@ -162,7 +259,7 @@ module Doorkeeper
|
|
|
162
259
|
describe "#redirect_uri=" do
|
|
163
260
|
context "when array of valid redirect_uris" do
|
|
164
261
|
it "should join by newline" do
|
|
165
|
-
new_application.redirect_uri = [
|
|
262
|
+
new_application.redirect_uri = ["http://localhost/callback1", "http://localhost/callback2"]
|
|
166
263
|
expect(new_application.redirect_uri).to eq("http://localhost/callback1\nhttp://localhost/callback2")
|
|
167
264
|
end
|
|
168
265
|
end
|
|
@@ -177,28 +274,28 @@ module Doorkeeper
|
|
|
177
274
|
describe :authorized_for do
|
|
178
275
|
let(:resource_owner) { double(:resource_owner, id: 10) }
|
|
179
276
|
|
|
180
|
-
it
|
|
277
|
+
it "is empty if the application is not authorized for anyone" do
|
|
181
278
|
expect(Application.authorized_for(resource_owner)).to be_empty
|
|
182
279
|
end
|
|
183
280
|
|
|
184
|
-
it
|
|
281
|
+
it "returns only application for a specific resource owner" do
|
|
185
282
|
FactoryBot.create(:access_token, resource_owner_id: resource_owner.id + 1)
|
|
186
283
|
token = FactoryBot.create(:access_token, resource_owner_id: resource_owner.id)
|
|
187
284
|
expect(Application.authorized_for(resource_owner)).to eq([token.application])
|
|
188
285
|
end
|
|
189
286
|
|
|
190
|
-
it
|
|
287
|
+
it "excludes revoked tokens" do
|
|
191
288
|
FactoryBot.create(:access_token, resource_owner_id: resource_owner.id, revoked_at: 2.days.ago)
|
|
192
289
|
expect(Application.authorized_for(resource_owner)).to be_empty
|
|
193
290
|
end
|
|
194
291
|
|
|
195
|
-
it
|
|
292
|
+
it "returns all applications that have been authorized" do
|
|
196
293
|
token1 = FactoryBot.create(:access_token, resource_owner_id: resource_owner.id)
|
|
197
294
|
token2 = FactoryBot.create(:access_token, resource_owner_id: resource_owner.id)
|
|
198
295
|
expect(Application.authorized_for(resource_owner)).to eq([token1.application, token2.application])
|
|
199
296
|
end
|
|
200
297
|
|
|
201
|
-
it
|
|
298
|
+
it "returns only one application even if it has been authorized twice" do
|
|
202
299
|
application = FactoryBot.create(:application)
|
|
203
300
|
FactoryBot.create(:access_token, resource_owner_id: resource_owner.id, application: application)
|
|
204
301
|
FactoryBot.create(:access_token, resource_owner_id: resource_owner.id, application: application)
|
|
@@ -207,7 +304,7 @@ module Doorkeeper
|
|
|
207
304
|
end
|
|
208
305
|
|
|
209
306
|
describe :revoke_tokens_and_grants_for do
|
|
210
|
-
it
|
|
307
|
+
it "revokes all access tokens and access grants" do
|
|
211
308
|
application_id = 42
|
|
212
309
|
resource_owner = double
|
|
213
310
|
expect(Doorkeeper::AccessToken)
|
|
@@ -229,7 +326,7 @@ module Doorkeeper
|
|
|
229
326
|
context "when secret is wrong" do
|
|
230
327
|
it "should not find the application" do
|
|
231
328
|
app = FactoryBot.create :application
|
|
232
|
-
authenticated = Application.by_uid_and_secret(app.uid,
|
|
329
|
+
authenticated = Application.by_uid_and_secret(app.uid, "bad")
|
|
233
330
|
expect(authenticated).to eq(nil)
|
|
234
331
|
end
|
|
235
332
|
end
|
|
@@ -246,7 +343,7 @@ module Doorkeeper
|
|
|
246
343
|
context "when secret is wrong" do
|
|
247
344
|
it "should not find the application" do
|
|
248
345
|
app = FactoryBot.create :application, confidential: false
|
|
249
|
-
authenticated = Application.by_uid_and_secret(app.uid,
|
|
346
|
+
authenticated = Application.by_uid_and_secret(app.uid, "bad")
|
|
250
347
|
expect(authenticated).to eq(nil)
|
|
251
348
|
end
|
|
252
349
|
end
|
|
@@ -256,12 +353,12 @@ module Doorkeeper
|
|
|
256
353
|
describe :confidential? do
|
|
257
354
|
subject { FactoryBot.create(:application, confidential: confidential).confidential? }
|
|
258
355
|
|
|
259
|
-
context
|
|
356
|
+
context "when application is private/confidential" do
|
|
260
357
|
let(:confidential) { true }
|
|
261
358
|
it { expect(subject).to eq(true) }
|
|
262
359
|
end
|
|
263
360
|
|
|
264
|
-
context
|
|
361
|
+
context "when application is public/non-confidential" do
|
|
265
362
|
let(:confidential) { false }
|
|
266
363
|
it { expect(subject).to eq(false) }
|
|
267
364
|
end
|
|
@@ -1,25 +1,27 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
feature "Adding applications" do
|
|
6
|
+
context "in application form" do
|
|
5
7
|
background do
|
|
6
8
|
i_am_logged_in
|
|
7
|
-
visit
|
|
9
|
+
visit "/oauth/applications/new"
|
|
8
10
|
end
|
|
9
11
|
|
|
10
|
-
scenario
|
|
11
|
-
fill_in
|
|
12
|
-
fill_in
|
|
13
|
-
with:
|
|
12
|
+
scenario "adding a valid app" do
|
|
13
|
+
fill_in "doorkeeper_application[name]", with: "My Application"
|
|
14
|
+
fill_in "doorkeeper_application[redirect_uri]",
|
|
15
|
+
with: "https://example.com"
|
|
14
16
|
|
|
15
|
-
click_button
|
|
16
|
-
i_should_see
|
|
17
|
-
i_should_see
|
|
17
|
+
click_button "Submit"
|
|
18
|
+
i_should_see "Application created"
|
|
19
|
+
i_should_see "My Application"
|
|
18
20
|
end
|
|
19
21
|
|
|
20
|
-
scenario
|
|
21
|
-
click_button
|
|
22
|
-
i_should_see
|
|
22
|
+
scenario "adding invalid app" do
|
|
23
|
+
click_button "Submit"
|
|
24
|
+
i_should_see "Whoops! Check your form for possible errors"
|
|
23
25
|
end
|
|
24
26
|
|
|
25
27
|
scenario "adding app ignoring bad scope" do
|
|
@@ -88,63 +90,93 @@ feature 'Adding applications' do
|
|
|
88
90
|
click_button "Submit"
|
|
89
91
|
i_should_see "Whoops! Check your form for possible errors"
|
|
90
92
|
i_should_see Regexp.new(
|
|
91
|
-
I18n.t(
|
|
93
|
+
I18n.t("activerecord.errors.models.doorkeeper/application.attributes.scopes.not_match_configured"),
|
|
92
94
|
true
|
|
93
95
|
)
|
|
94
96
|
end
|
|
97
|
+
|
|
98
|
+
context "redirect URI" do
|
|
99
|
+
scenario "adding app with blank redirect URI when configured flows requires redirect uri" do
|
|
100
|
+
config_is_set("grant_flows", %w[authorization_code implicit client_credentials])
|
|
101
|
+
|
|
102
|
+
fill_in "doorkeeper_application[name]", with: "My Application"
|
|
103
|
+
fill_in "doorkeeper_application[redirect_uri]",
|
|
104
|
+
with: ""
|
|
105
|
+
|
|
106
|
+
click_button "Submit"
|
|
107
|
+
i_should_see "Whoops! Check your form for possible errors"
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
scenario "adding app with blank redirect URI when configured flows without redirect uri" do
|
|
111
|
+
config_is_set("grant_flows", %w[client_credentials password])
|
|
112
|
+
|
|
113
|
+
# Visit it once again to consider grant flows
|
|
114
|
+
visit "/oauth/applications/new"
|
|
115
|
+
|
|
116
|
+
i_should_see I18n.t("doorkeeper.applications.help.blank_redirect_uri")
|
|
117
|
+
|
|
118
|
+
fill_in "doorkeeper_application[name]", with: "My Application"
|
|
119
|
+
fill_in "doorkeeper_application[redirect_uri]",
|
|
120
|
+
with: ""
|
|
121
|
+
|
|
122
|
+
click_button "Submit"
|
|
123
|
+
i_should_see "Application created"
|
|
124
|
+
i_should_see "My Application"
|
|
125
|
+
end
|
|
126
|
+
end
|
|
95
127
|
end
|
|
96
128
|
end
|
|
97
129
|
|
|
98
|
-
feature
|
|
130
|
+
feature "Listing applications" do
|
|
99
131
|
background do
|
|
100
132
|
i_am_logged_in
|
|
101
133
|
|
|
102
|
-
FactoryBot.create :application, name:
|
|
103
|
-
FactoryBot.create :application, name:
|
|
134
|
+
FactoryBot.create :application, name: "Oauth Dude"
|
|
135
|
+
FactoryBot.create :application, name: "Awesome App"
|
|
104
136
|
end
|
|
105
137
|
|
|
106
|
-
scenario
|
|
107
|
-
visit
|
|
138
|
+
scenario "application list" do
|
|
139
|
+
visit "/oauth/applications"
|
|
108
140
|
|
|
109
|
-
i_should_see
|
|
110
|
-
i_should_see
|
|
141
|
+
i_should_see "Awesome App"
|
|
142
|
+
i_should_see "Oauth Dude"
|
|
111
143
|
end
|
|
112
144
|
end
|
|
113
145
|
|
|
114
|
-
feature
|
|
115
|
-
scenario
|
|
116
|
-
visit
|
|
146
|
+
feature "Renders assets" do
|
|
147
|
+
scenario "admin stylesheets" do
|
|
148
|
+
visit "/assets/doorkeeper/admin/application.css"
|
|
117
149
|
|
|
118
|
-
i_should_see
|
|
119
|
-
i_should_see
|
|
150
|
+
i_should_see "Bootstrap"
|
|
151
|
+
i_should_see ".doorkeeper-admin"
|
|
120
152
|
end
|
|
121
153
|
|
|
122
|
-
scenario
|
|
123
|
-
visit
|
|
154
|
+
scenario "application stylesheets" do
|
|
155
|
+
visit "/assets/doorkeeper/application.css"
|
|
124
156
|
|
|
125
|
-
i_should_see
|
|
126
|
-
i_should_see
|
|
127
|
-
i_should_see
|
|
157
|
+
i_should_see "Bootstrap"
|
|
158
|
+
i_should_see "#oauth-permissions"
|
|
159
|
+
i_should_see "#container"
|
|
128
160
|
end
|
|
129
161
|
end
|
|
130
162
|
|
|
131
|
-
feature
|
|
163
|
+
feature "Show application" do
|
|
132
164
|
given :app do
|
|
133
165
|
i_am_logged_in
|
|
134
166
|
|
|
135
|
-
FactoryBot.create :application, name:
|
|
167
|
+
FactoryBot.create :application, name: "Just another oauth app"
|
|
136
168
|
end
|
|
137
169
|
|
|
138
|
-
scenario
|
|
170
|
+
scenario "visiting application page" do
|
|
139
171
|
visit "/oauth/applications/#{app.id}"
|
|
140
172
|
|
|
141
|
-
i_should_see
|
|
173
|
+
i_should_see "Just another oauth app"
|
|
142
174
|
end
|
|
143
175
|
end
|
|
144
176
|
|
|
145
|
-
feature
|
|
177
|
+
feature "Edit application" do
|
|
146
178
|
let :app do
|
|
147
|
-
FactoryBot.create :application, name:
|
|
179
|
+
FactoryBot.create :application, name: "OMG my app"
|
|
148
180
|
end
|
|
149
181
|
|
|
150
182
|
background do
|
|
@@ -153,72 +185,72 @@ feature 'Edit application' do
|
|
|
153
185
|
visit "/oauth/applications/#{app.id}/edit"
|
|
154
186
|
end
|
|
155
187
|
|
|
156
|
-
scenario
|
|
157
|
-
fill_in
|
|
158
|
-
click_button
|
|
188
|
+
scenario "updating a valid app" do
|
|
189
|
+
fill_in "doorkeeper_application[name]", with: "Serious app"
|
|
190
|
+
click_button "Submit"
|
|
159
191
|
|
|
160
|
-
i_should_see
|
|
161
|
-
i_should_see
|
|
162
|
-
i_should_not_see
|
|
192
|
+
i_should_see "Application updated"
|
|
193
|
+
i_should_see "Serious app"
|
|
194
|
+
i_should_not_see "OMG my app"
|
|
163
195
|
end
|
|
164
196
|
|
|
165
|
-
scenario
|
|
166
|
-
fill_in
|
|
167
|
-
click_button
|
|
197
|
+
scenario "updating an invalid app" do
|
|
198
|
+
fill_in "doorkeeper_application[name]", with: ""
|
|
199
|
+
click_button "Submit"
|
|
168
200
|
|
|
169
|
-
i_should_see
|
|
201
|
+
i_should_see "Whoops! Check your form for possible errors"
|
|
170
202
|
end
|
|
171
203
|
end
|
|
172
204
|
|
|
173
|
-
feature
|
|
205
|
+
feature "Remove application" do
|
|
174
206
|
background do
|
|
175
207
|
i_am_logged_in
|
|
176
208
|
|
|
177
209
|
@app = FactoryBot.create :application
|
|
178
210
|
end
|
|
179
211
|
|
|
180
|
-
scenario
|
|
181
|
-
visit
|
|
212
|
+
scenario "deleting an application from list" do
|
|
213
|
+
visit "/oauth/applications"
|
|
182
214
|
|
|
183
215
|
i_should_see @app.name
|
|
184
216
|
|
|
185
217
|
within(:css, "tr#application_#{@app.id}") do
|
|
186
|
-
click_button
|
|
218
|
+
click_button "Destroy"
|
|
187
219
|
end
|
|
188
220
|
|
|
189
|
-
i_should_see
|
|
221
|
+
i_should_see "Application deleted"
|
|
190
222
|
i_should_not_see @app.name
|
|
191
223
|
end
|
|
192
224
|
|
|
193
|
-
scenario
|
|
225
|
+
scenario "deleting an application from show" do
|
|
194
226
|
visit "/oauth/applications/#{@app.id}"
|
|
195
|
-
click_button
|
|
227
|
+
click_button "Destroy"
|
|
196
228
|
|
|
197
|
-
i_should_see
|
|
229
|
+
i_should_see "Application deleted"
|
|
198
230
|
end
|
|
199
231
|
end
|
|
200
232
|
|
|
201
|
-
context
|
|
202
|
-
let(:app) { FactoryBot.create :application, name:
|
|
233
|
+
context "when admin authenticator block is default" do
|
|
234
|
+
let(:app) { FactoryBot.create :application, name: "app" }
|
|
203
235
|
|
|
204
|
-
feature
|
|
205
|
-
scenario
|
|
206
|
-
visit
|
|
236
|
+
feature "application list" do
|
|
237
|
+
scenario "fails with forbidden" do
|
|
238
|
+
visit "/oauth/applications"
|
|
207
239
|
|
|
208
240
|
should_have_status 403
|
|
209
241
|
end
|
|
210
242
|
end
|
|
211
243
|
|
|
212
|
-
feature
|
|
213
|
-
scenario
|
|
214
|
-
visit
|
|
244
|
+
feature "adding an app" do
|
|
245
|
+
scenario "fails with forbidden" do
|
|
246
|
+
visit "/oauth/applications/new"
|
|
215
247
|
|
|
216
248
|
should_have_status 403
|
|
217
249
|
end
|
|
218
250
|
end
|
|
219
251
|
|
|
220
|
-
feature
|
|
221
|
-
scenario
|
|
252
|
+
feature "editing an app" do
|
|
253
|
+
scenario "fails with forbidden" do
|
|
222
254
|
visit "/oauth/applications/#{app.id}/edit"
|
|
223
255
|
|
|
224
256
|
should_have_status 403
|