doorkeeper 3.1.0 → 4.4.3
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/.coveralls.yml +1 -0
- data/.github/ISSUE_TEMPLATE.md +25 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +17 -0
- data/.gitignore +6 -1
- data/.hound.yml +2 -13
- data/.rubocop.yml +17 -0
- data/.travis.yml +26 -10
- data/Appraisals +18 -0
- data/CODE_OF_CONDUCT.md +46 -0
- data/CONTRIBUTING.md +2 -0
- data/Gemfile +5 -5
- data/NEWS.md +141 -2
- data/README.md +149 -66
- data/RELEASING.md +5 -12
- data/Rakefile +1 -1
- data/SECURITY.md +15 -0
- data/app/controllers/doorkeeper/application_controller.rb +4 -6
- data/app/controllers/doorkeeper/application_metal_controller.rb +3 -2
- data/app/controllers/doorkeeper/applications_controller.rb +18 -8
- data/app/controllers/doorkeeper/authorizations_controller.rb +1 -1
- data/app/controllers/doorkeeper/authorized_applications_controller.rb +1 -1
- data/app/controllers/doorkeeper/tokens_controller.rb +62 -15
- data/app/helpers/doorkeeper/dashboard_helper.rb +14 -10
- data/app/validators/redirect_uri_validator.rb +12 -2
- data/app/views/doorkeeper/applications/_delete_form.html.erb +1 -2
- data/app/views/doorkeeper/applications/_form.html.erb +13 -2
- data/app/views/doorkeeper/applications/index.html.erb +2 -0
- data/app/views/doorkeeper/applications/show.html.erb +4 -1
- data/app/views/doorkeeper/authorizations/new.html.erb +1 -1
- data/app/views/doorkeeper/authorized_applications/_delete_form.html.erb +1 -2
- data/app/views/doorkeeper/authorized_applications/index.html.erb +0 -1
- data/app/views/layouts/doorkeeper/admin.html.erb +1 -1
- data/config/locales/en.yml +12 -7
- data/doorkeeper.gemspec +16 -11
- data/gemfiles/rails_4_2.gemfile +13 -0
- data/gemfiles/rails_5_0.gemfile +12 -0
- data/gemfiles/rails_5_1.gemfile +12 -0
- data/gemfiles/rails_5_2.gemfile +12 -0
- data/gemfiles/rails_master.gemfile +14 -0
- data/lib/doorkeeper/config.rb +119 -46
- data/lib/doorkeeper/engine.rb +11 -7
- data/lib/doorkeeper/errors.rb +18 -0
- data/lib/doorkeeper/grape/helpers.rb +14 -8
- data/lib/doorkeeper/helpers/controller.rb +8 -19
- data/lib/doorkeeper/models/access_grant_mixin.rb +10 -21
- data/lib/doorkeeper/models/access_token_mixin.rb +147 -43
- data/lib/doorkeeper/models/application_mixin.rb +33 -35
- data/lib/doorkeeper/models/concerns/accessible.rb +4 -0
- data/lib/doorkeeper/models/concerns/expirable.rb +15 -5
- data/lib/doorkeeper/models/concerns/orderable.rb +13 -0
- data/lib/doorkeeper/models/concerns/ownership.rb +6 -1
- data/lib/doorkeeper/models/concerns/revocable.rb +37 -2
- data/lib/doorkeeper/oauth/authorization/token.rb +22 -18
- data/lib/doorkeeper/oauth/authorization/uri_builder.rb +20 -18
- data/lib/doorkeeper/oauth/authorization_code_request.rb +7 -5
- data/lib/doorkeeper/oauth/{request_concern.rb → base_request.rb} +9 -2
- data/lib/doorkeeper/oauth/base_response.rb +29 -0
- data/lib/doorkeeper/oauth/client/credentials.rb +21 -8
- data/lib/doorkeeper/oauth/client.rb +2 -3
- data/lib/doorkeeper/oauth/client_credentials/creator.rb +1 -1
- data/lib/doorkeeper/oauth/client_credentials/issuer.rb +3 -2
- data/lib/doorkeeper/oauth/client_credentials/validation.rb +1 -1
- data/lib/doorkeeper/oauth/client_credentials_request.rb +8 -8
- data/lib/doorkeeper/oauth/code_response.rb +16 -16
- data/lib/doorkeeper/oauth/error.rb +2 -2
- data/lib/doorkeeper/oauth/error_response.rb +10 -10
- data/lib/doorkeeper/oauth/forbidden_token_response.rb +1 -1
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +1 -1
- data/lib/doorkeeper/oauth/helpers/uri_checker.rb +17 -1
- data/lib/doorkeeper/oauth/invalid_token_response.rb +5 -4
- data/lib/doorkeeper/oauth/password_access_token_request.rb +8 -13
- data/lib/doorkeeper/oauth/pre_authorization.rb +5 -3
- data/lib/doorkeeper/oauth/refresh_token_request.rb +23 -14
- data/lib/doorkeeper/oauth/scopes.rb +18 -8
- data/lib/doorkeeper/oauth/token.rb +20 -21
- data/lib/doorkeeper/oauth/token_introspection.rb +128 -0
- data/lib/doorkeeper/oauth/token_request.rb +1 -2
- data/lib/doorkeeper/oauth/token_response.rb +1 -1
- data/lib/doorkeeper/orm/active_record/access_grant.rb +27 -0
- data/lib/doorkeeper/orm/active_record/access_token.rb +34 -8
- data/lib/doorkeeper/orm/active_record/application.rb +48 -11
- data/lib/doorkeeper/orm/active_record.rb +17 -22
- data/lib/doorkeeper/rails/helpers.rb +6 -9
- data/lib/doorkeeper/rails/routes/mapper.rb +4 -4
- data/lib/doorkeeper/rails/routes/mapping.rb +1 -1
- data/lib/doorkeeper/rails/routes.rb +17 -11
- data/lib/doorkeeper/request/authorization_code.rb +7 -1
- data/lib/doorkeeper/request/password.rb +2 -2
- data/lib/doorkeeper/request/refresh_token.rb +1 -1
- data/lib/doorkeeper/request.rb +7 -1
- data/lib/doorkeeper/server.rb +0 -8
- data/lib/doorkeeper/validations.rb +3 -2
- data/lib/doorkeeper/version.rb +34 -1
- data/lib/doorkeeper.rb +10 -2
- data/lib/generators/doorkeeper/add_client_confidentiality_generator.rb +31 -0
- data/lib/generators/doorkeeper/application_owner_generator.rb +11 -2
- data/lib/generators/doorkeeper/migration_generator.rb +13 -1
- data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +35 -0
- data/lib/generators/doorkeeper/templates/add_confidential_to_application_migration.rb.erb +11 -0
- data/{spec/dummy/db/migrate/20130902175349_add_owner_to_application.rb → lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb} +1 -1
- data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb +11 -0
- data/lib/generators/doorkeeper/templates/initializer.rb +38 -6
- data/lib/generators/doorkeeper/templates/migration.rb.erb +69 -0
- data/spec/controllers/application_metal_controller.rb +10 -0
- data/spec/controllers/applications_controller_spec.rb +15 -4
- data/spec/controllers/authorizations_controller_spec.rb +74 -27
- data/spec/controllers/protected_resources_controller_spec.rb +70 -32
- data/spec/controllers/token_info_controller_spec.rb +17 -13
- data/spec/controllers/tokens_controller_spec.rb +198 -12
- data/spec/dummy/app/controllers/full_protected_resources_controller.rb +4 -4
- data/spec/dummy/app/controllers/home_controller.rb +1 -1
- data/spec/dummy/app/controllers/metal_controller.rb +1 -1
- data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +3 -3
- data/spec/dummy/app/models/user.rb +0 -4
- data/spec/dummy/config/application.rb +2 -36
- data/spec/dummy/config/environment.rb +1 -1
- data/spec/dummy/config/environments/test.rb +4 -15
- data/spec/dummy/config/initializers/doorkeeper.rb +19 -3
- data/spec/dummy/config/initializers/new_framework_defaults.rb +6 -0
- data/spec/dummy/config/initializers/secret_token.rb +0 -1
- data/spec/dummy/db/migrate/20111122132257_create_users.rb +3 -1
- data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +3 -1
- data/{lib/generators/doorkeeper/templates/migration.rb → spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb} +16 -4
- data/{lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb → spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb} +4 -2
- data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +13 -0
- data/spec/dummy/db/migrate/20180210183654_add_confidential_to_application.rb +13 -0
- data/spec/dummy/db/schema.rb +24 -22
- data/spec/factories.rb +4 -2
- data/spec/generators/application_owner_generator_spec.rb +24 -5
- data/spec/generators/migration_generator_spec.rb +24 -3
- data/spec/generators/previous_refresh_token_generator_spec.rb +57 -0
- data/spec/grape/grape_integration_spec.rb +135 -0
- data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +1 -1
- data/spec/lib/config_spec.rb +159 -14
- data/spec/lib/doorkeeper_spec.rb +135 -13
- data/spec/lib/models/expirable_spec.rb +0 -1
- data/spec/lib/models/revocable_spec.rb +27 -4
- data/spec/lib/oauth/authorization/uri_builder_spec.rb +1 -2
- data/spec/lib/oauth/authorization_code_request_spec.rb +55 -12
- data/spec/lib/oauth/base_request_spec.rb +155 -0
- data/spec/lib/oauth/base_response_spec.rb +45 -0
- data/spec/lib/oauth/client/credentials_spec.rb +45 -2
- data/spec/lib/oauth/client_credentials/creator_spec.rb +1 -1
- data/spec/lib/oauth/client_credentials_integration_spec.rb +1 -1
- data/spec/lib/oauth/client_credentials_request_spec.rb +1 -0
- data/spec/lib/oauth/code_request_spec.rb +1 -3
- data/spec/lib/oauth/code_response_spec.rb +34 -0
- data/spec/lib/oauth/error_response_spec.rb +9 -9
- data/spec/lib/oauth/error_spec.rb +1 -1
- data/spec/lib/oauth/helpers/uri_checker_spec.rb +115 -1
- data/spec/lib/oauth/invalid_token_response_spec.rb +36 -8
- data/spec/lib/oauth/password_access_token_request_spec.rb +14 -8
- data/spec/lib/oauth/pre_authorization_spec.rb +12 -7
- data/spec/lib/oauth/refresh_token_request_spec.rb +52 -9
- data/spec/lib/oauth/scopes_spec.rb +28 -2
- data/spec/lib/oauth/token_request_spec.rb +6 -8
- data/spec/lib/oauth/token_spec.rb +12 -5
- data/spec/lib/server_spec.rb +10 -3
- data/spec/models/doorkeeper/access_grant_spec.rb +1 -1
- data/spec/models/doorkeeper/access_token_spec.rb +116 -48
- data/spec/models/doorkeeper/application_spec.rb +145 -29
- data/spec/requests/applications/applications_request_spec.rb +5 -5
- data/spec/requests/endpoints/authorization_spec.rb +5 -6
- data/spec/requests/endpoints/token_spec.rb +8 -1
- data/spec/requests/flows/authorization_code_errors_spec.rb +11 -1
- data/spec/requests/flows/authorization_code_spec.rb +6 -13
- data/spec/requests/flows/client_credentials_spec.rb +29 -1
- data/spec/requests/flows/implicit_grant_errors_spec.rb +2 -2
- data/spec/requests/flows/password_spec.rb +118 -15
- data/spec/requests/flows/refresh_token_spec.rb +89 -19
- data/spec/requests/flows/revoke_token_spec.rb +105 -91
- data/spec/requests/protected_resources/metal_spec.rb +1 -1
- data/spec/requests/protected_resources/private_api_spec.rb +1 -1
- data/spec/routing/custom_controller_routes_spec.rb +4 -0
- data/spec/routing/default_routes_spec.rb +5 -1
- data/spec/spec_helper.rb +2 -0
- data/spec/spec_helper_integration.rb +22 -4
- data/spec/support/dependencies/factory_girl.rb +2 -2
- data/spec/support/helpers/access_token_request_helper.rb +1 -1
- data/spec/support/helpers/model_helper.rb +34 -7
- data/spec/support/helpers/request_spec_helper.rb +17 -5
- data/spec/support/helpers/url_helper.rb +9 -8
- data/spec/support/http_method_shim.rb +38 -0
- data/spec/support/shared/controllers_shared_context.rb +15 -10
- data/spec/support/shared/models_shared_examples.rb +5 -5
- data/spec/validators/redirect_uri_validator_spec.rb +51 -6
- data/spec/version/version_spec.rb +15 -0
- metadata +128 -46
- data/lib/doorkeeper/oauth/client/methods.rb +0 -18
- data/lib/generators/doorkeeper/application_scopes_generator.rb +0 -34
- data/lib/generators/doorkeeper/templates/add_scopes_to_oauth_applications.rb +0 -5
- data/spec/dummy/db/migrate/20130902165751_create_doorkeeper_tables.rb +0 -41
- data/spec/dummy/db/migrate/20141209001746_add_scopes_to_oauth_applications.rb +0 -5
- data/spec/lib/oauth/client/methods_spec.rb +0 -54
@@ -2,7 +2,7 @@ require 'spec_helper_integration'
|
|
2
2
|
|
3
3
|
module Doorkeeper
|
4
4
|
describe AccessToken do
|
5
|
-
subject {
|
5
|
+
subject { FactoryBot.build(:access_token) }
|
6
6
|
|
7
7
|
it { expect(subject).to be_valid }
|
8
8
|
|
@@ -12,15 +12,24 @@ module Doorkeeper
|
|
12
12
|
let(:factory_name) { :access_token }
|
13
13
|
end
|
14
14
|
|
15
|
+
module CustomGeneratorArgs
|
16
|
+
def self.generate
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
15
20
|
describe :generate_token do
|
16
21
|
it 'generates a token using the default method' do
|
17
|
-
|
22
|
+
FactoryBot.create :access_token
|
18
23
|
|
19
|
-
token =
|
24
|
+
token = FactoryBot.create :access_token
|
20
25
|
expect(token.token).to be_a(String)
|
21
26
|
end
|
22
27
|
|
23
28
|
it 'generates a token using a custom object' do
|
29
|
+
eigenclass = class << CustomGeneratorArgs; self; end
|
30
|
+
eigenclass.class_eval do
|
31
|
+
remove_method :generate
|
32
|
+
end
|
24
33
|
module CustomGeneratorArgs
|
25
34
|
def self.generate(opts = {})
|
26
35
|
"custom_generator_token_#{opts[:resource_owner_id]}"
|
@@ -32,11 +41,15 @@ module Doorkeeper
|
|
32
41
|
access_token_generator "Doorkeeper::CustomGeneratorArgs"
|
33
42
|
end
|
34
43
|
|
35
|
-
token =
|
44
|
+
token = FactoryBot.create :access_token
|
36
45
|
expect(token.token).to match(%r{custom_generator_token_\d+})
|
37
46
|
end
|
38
47
|
|
39
48
|
it 'allows the custom generator to access the application details' do
|
49
|
+
eigenclass = class << CustomGeneratorArgs; self; end
|
50
|
+
eigenclass.class_eval do
|
51
|
+
remove_method :generate
|
52
|
+
end
|
40
53
|
module CustomGeneratorArgs
|
41
54
|
def self.generate(opts = {})
|
42
55
|
"custom_generator_token_#{opts[:application].name}"
|
@@ -48,11 +61,15 @@ module Doorkeeper
|
|
48
61
|
access_token_generator "Doorkeeper::CustomGeneratorArgs"
|
49
62
|
end
|
50
63
|
|
51
|
-
token =
|
64
|
+
token = FactoryBot.create :access_token
|
52
65
|
expect(token.token).to match(%r{custom_generator_token_Application \d+})
|
53
66
|
end
|
54
67
|
|
55
68
|
it 'allows the custom generator to access the scopes' do
|
69
|
+
eigenclass = class << CustomGeneratorArgs; self; end
|
70
|
+
eigenclass.class_eval do
|
71
|
+
remove_method :generate
|
72
|
+
end
|
56
73
|
module CustomGeneratorArgs
|
57
74
|
def self.generate(opts = {})
|
58
75
|
"custom_generator_token_#{opts[:scopes].count}_#{opts[:scopes]}"
|
@@ -64,12 +81,16 @@ module Doorkeeper
|
|
64
81
|
access_token_generator "Doorkeeper::CustomGeneratorArgs"
|
65
82
|
end
|
66
83
|
|
67
|
-
token =
|
84
|
+
token = FactoryBot.create :access_token, scopes: 'public write'
|
68
85
|
|
69
86
|
expect(token.token).to eq 'custom_generator_token_2_public write'
|
70
87
|
end
|
71
88
|
|
72
89
|
it 'allows the custom generator to access the expiry length' do
|
90
|
+
eigenclass = class << CustomGeneratorArgs; self; end
|
91
|
+
eigenclass.class_eval do
|
92
|
+
remove_method :generate
|
93
|
+
end
|
73
94
|
module CustomGeneratorArgs
|
74
95
|
def self.generate(opts = {})
|
75
96
|
"custom_generator_token_#{opts[:expires_in]}"
|
@@ -81,10 +102,27 @@ module Doorkeeper
|
|
81
102
|
access_token_generator "Doorkeeper::CustomGeneratorArgs"
|
82
103
|
end
|
83
104
|
|
84
|
-
token =
|
105
|
+
token = FactoryBot.create :access_token
|
85
106
|
expect(token.token).to eq 'custom_generator_token_7200'
|
86
107
|
end
|
87
108
|
|
109
|
+
it 'allows the custom generator to access the created time' do
|
110
|
+
module CustomGeneratorArgs
|
111
|
+
def self.generate(opts = {})
|
112
|
+
"custom_generator_token_#{opts[:created_at].to_i}"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
Doorkeeper.configure do
|
117
|
+
orm DOORKEEPER_ORM
|
118
|
+
access_token_generator "Doorkeeper::CustomGeneratorArgs"
|
119
|
+
end
|
120
|
+
|
121
|
+
token = FactoryBot.create :access_token
|
122
|
+
created_at = token.created_at
|
123
|
+
expect(token.token).to eq "custom_generator_token_#{created_at.to_i}"
|
124
|
+
end
|
125
|
+
|
88
126
|
it 'raises an error if the custom object does not support generate' do
|
89
127
|
module NoGenerate
|
90
128
|
end
|
@@ -94,8 +132,31 @@ module Doorkeeper
|
|
94
132
|
access_token_generator "Doorkeeper::NoGenerate"
|
95
133
|
end
|
96
134
|
|
97
|
-
expect {
|
98
|
-
raise_error(Doorkeeper::Errors::UnableToGenerateToken)
|
135
|
+
expect { FactoryBot.create :access_token }.to(
|
136
|
+
raise_error(Doorkeeper::Errors::UnableToGenerateToken)
|
137
|
+
)
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'raises original error if something went wrong in custom generator' do
|
141
|
+
eigenclass = class << CustomGeneratorArgs; self; end
|
142
|
+
eigenclass.class_eval do
|
143
|
+
remove_method :generate
|
144
|
+
end
|
145
|
+
|
146
|
+
module CustomGeneratorArgs
|
147
|
+
def self.generate(opts = {})
|
148
|
+
raise LoadError, 'custom behaviour'
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
Doorkeeper.configure do
|
153
|
+
orm DOORKEEPER_ORM
|
154
|
+
access_token_generator "Doorkeeper::CustomGeneratorArgs"
|
155
|
+
end
|
156
|
+
|
157
|
+
expect { FactoryBot.create :access_token }.to(
|
158
|
+
raise_error(LoadError)
|
159
|
+
)
|
99
160
|
end
|
100
161
|
|
101
162
|
it 'raises an error if the custom object does not exist' do
|
@@ -104,36 +165,37 @@ module Doorkeeper
|
|
104
165
|
access_token_generator "Doorkeeper::NotReal"
|
105
166
|
end
|
106
167
|
|
107
|
-
expect {
|
108
|
-
raise_error(Doorkeeper::Errors::TokenGeneratorNotFound)
|
168
|
+
expect { FactoryBot.create :access_token }.to(
|
169
|
+
raise_error(Doorkeeper::Errors::TokenGeneratorNotFound, /NotReal/)
|
170
|
+
)
|
109
171
|
end
|
110
172
|
end
|
111
173
|
|
112
174
|
describe :refresh_token do
|
113
175
|
it 'has empty refresh token if it was not required' do
|
114
|
-
token =
|
176
|
+
token = FactoryBot.create :access_token
|
115
177
|
expect(token.refresh_token).to be_nil
|
116
178
|
end
|
117
179
|
|
118
180
|
it 'generates a refresh token if it was requested' do
|
119
|
-
token =
|
181
|
+
token = FactoryBot.create :access_token, use_refresh_token: true
|
120
182
|
expect(token.refresh_token).not_to be_nil
|
121
183
|
end
|
122
184
|
|
123
185
|
it 'is not valid if token exists' do
|
124
|
-
token1 =
|
125
|
-
token2 =
|
186
|
+
token1 = FactoryBot.create :access_token, use_refresh_token: true
|
187
|
+
token2 = FactoryBot.create :access_token, use_refresh_token: true
|
126
188
|
token2.refresh_token = token1.refresh_token
|
127
189
|
expect(token2).not_to be_valid
|
128
190
|
end
|
129
191
|
|
130
192
|
it 'expects database to raise an error if refresh tokens are the same' do
|
131
|
-
token1 =
|
132
|
-
token2 =
|
193
|
+
token1 = FactoryBot.create :access_token, use_refresh_token: true
|
194
|
+
token2 = FactoryBot.create :access_token, use_refresh_token: true
|
133
195
|
expect do
|
134
196
|
token2.refresh_token = token1.refresh_token
|
135
197
|
token2.save(validate: false)
|
136
|
-
end.to raise_error(
|
198
|
+
end.to raise_error(uniqueness_error)
|
137
199
|
end
|
138
200
|
end
|
139
201
|
|
@@ -143,6 +205,12 @@ module Doorkeeper
|
|
143
205
|
subject.resource_owner_id = nil
|
144
206
|
expect(subject).to be_valid
|
145
207
|
end
|
208
|
+
|
209
|
+
it 'is valid without application_id' do
|
210
|
+
# For resource owner credentials flow
|
211
|
+
subject.application_id = nil
|
212
|
+
expect(subject).to be_valid
|
213
|
+
end
|
146
214
|
end
|
147
215
|
|
148
216
|
describe '#same_credential?' do
|
@@ -150,22 +218,22 @@ module Doorkeeper
|
|
150
218
|
context 'with default parameters' do
|
151
219
|
|
152
220
|
let(:resource_owner_id) { 100 }
|
153
|
-
let(:application) {
|
221
|
+
let(:application) { FactoryBot.create :application }
|
154
222
|
let(:default_attributes) do
|
155
223
|
{ application: application, resource_owner_id: resource_owner_id }
|
156
224
|
end
|
157
|
-
let(:access_token1) {
|
225
|
+
let(:access_token1) { FactoryBot.create :access_token, default_attributes }
|
158
226
|
|
159
227
|
context 'the second token has the same owner and same app' do
|
160
|
-
let(:access_token2) {
|
228
|
+
let(:access_token2) { FactoryBot.create :access_token, default_attributes }
|
161
229
|
it 'success' do
|
162
230
|
expect(access_token1.same_credential?(access_token2)).to be_truthy
|
163
231
|
end
|
164
232
|
end
|
165
233
|
|
166
234
|
context 'the second token has same owner and different app' do
|
167
|
-
let(:other_application) {
|
168
|
-
let(:access_token2) {
|
235
|
+
let(:other_application) { FactoryBot.create :application }
|
236
|
+
let(:access_token2) { FactoryBot.create :access_token, application: other_application, resource_owner_id: resource_owner_id }
|
169
237
|
|
170
238
|
it 'fail' do
|
171
239
|
expect(access_token1.same_credential?(access_token2)).to be_falsey
|
@@ -174,8 +242,8 @@ module Doorkeeper
|
|
174
242
|
|
175
243
|
context 'the second token has different owner and different app' do
|
176
244
|
|
177
|
-
let(:other_application) {
|
178
|
-
let(:access_token2) {
|
245
|
+
let(:other_application) { FactoryBot.create :application }
|
246
|
+
let(:access_token2) { FactoryBot.create :access_token, application: other_application, resource_owner_id: 42 }
|
179
247
|
|
180
248
|
it 'fail' do
|
181
249
|
expect(access_token1.same_credential?(access_token2)).to be_falsey
|
@@ -183,7 +251,7 @@ module Doorkeeper
|
|
183
251
|
end
|
184
252
|
|
185
253
|
context 'the second token has different owner and same app' do
|
186
|
-
let(:access_token2) {
|
254
|
+
let(:access_token2) { FactoryBot.create :access_token, application: application, resource_owner_id: 42 }
|
187
255
|
|
188
256
|
it 'fail' do
|
189
257
|
expect(access_token1.same_credential?(access_token2)).to be_falsey
|
@@ -194,7 +262,7 @@ module Doorkeeper
|
|
194
262
|
|
195
263
|
describe '#acceptable?' do
|
196
264
|
context 'a token that is not accessible' do
|
197
|
-
let(:token) {
|
265
|
+
let(:token) { FactoryBot.create(:access_token, created_at: 6.hours.ago) }
|
198
266
|
|
199
267
|
it 'should return false' do
|
200
268
|
expect(token.acceptable?(nil)).to be false
|
@@ -202,7 +270,7 @@ module Doorkeeper
|
|
202
270
|
end
|
203
271
|
|
204
272
|
context 'a token that has the incorrect scopes' do
|
205
|
-
let(:token) {
|
273
|
+
let(:token) { FactoryBot.create(:access_token) }
|
206
274
|
|
207
275
|
it 'should return false' do
|
208
276
|
expect(token.acceptable?(['public'])).to be false
|
@@ -211,7 +279,7 @@ module Doorkeeper
|
|
211
279
|
|
212
280
|
context 'a token is acceptable with the correct scopes' do
|
213
281
|
let(:token) do
|
214
|
-
token =
|
282
|
+
token = FactoryBot.create(:access_token)
|
215
283
|
token[:scopes] = 'public'
|
216
284
|
token
|
217
285
|
end
|
@@ -224,13 +292,13 @@ module Doorkeeper
|
|
224
292
|
|
225
293
|
describe '.revoke_all_for' do
|
226
294
|
let(:resource_owner) { double(id: 100) }
|
227
|
-
let(:application) {
|
295
|
+
let(:application) { FactoryBot.create :application }
|
228
296
|
let(:default_attributes) do
|
229
297
|
{ application: application, resource_owner_id: resource_owner.id }
|
230
298
|
end
|
231
299
|
|
232
300
|
it 'revokes all tokens for given application and resource owner' do
|
233
|
-
|
301
|
+
FactoryBot.create :access_token, default_attributes
|
234
302
|
AccessToken.revoke_all_for application.id, resource_owner
|
235
303
|
AccessToken.all.each do |token|
|
236
304
|
expect(token).to be_revoked
|
@@ -238,13 +306,13 @@ module Doorkeeper
|
|
238
306
|
end
|
239
307
|
|
240
308
|
it 'matches application' do
|
241
|
-
|
309
|
+
FactoryBot.create :access_token, default_attributes.merge(application: FactoryBot.create(:application))
|
242
310
|
AccessToken.revoke_all_for application.id, resource_owner
|
243
311
|
expect(AccessToken.all).not_to be_empty
|
244
312
|
end
|
245
313
|
|
246
314
|
it 'matches resource owner' do
|
247
|
-
|
315
|
+
FactoryBot.create :access_token, default_attributes.merge(resource_owner_id: 90)
|
248
316
|
AccessToken.revoke_all_for application.id, resource_owner
|
249
317
|
expect(AccessToken.all).not_to be_empty
|
250
318
|
end
|
@@ -252,7 +320,7 @@ module Doorkeeper
|
|
252
320
|
|
253
321
|
describe '.matching_token_for' do
|
254
322
|
let(:resource_owner_id) { 100 }
|
255
|
-
let(:application) {
|
323
|
+
let(:application) { FactoryBot.create :application }
|
256
324
|
let(:scopes) { Doorkeeper::OAuth::Scopes.from_string('public write') }
|
257
325
|
let(:default_attributes) do
|
258
326
|
{
|
@@ -263,63 +331,63 @@ module Doorkeeper
|
|
263
331
|
end
|
264
332
|
|
265
333
|
it 'returns only one token' do
|
266
|
-
token =
|
334
|
+
token = FactoryBot.create :access_token, default_attributes
|
267
335
|
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
268
336
|
expect(last_token).to eq(token)
|
269
337
|
end
|
270
338
|
|
271
339
|
it 'accepts resource owner as object' do
|
272
340
|
resource_owner = double(to_key: true, id: 100)
|
273
|
-
token =
|
341
|
+
token = FactoryBot.create :access_token, default_attributes
|
274
342
|
last_token = AccessToken.matching_token_for(application, resource_owner, scopes)
|
275
343
|
expect(last_token).to eq(token)
|
276
344
|
end
|
277
345
|
|
278
346
|
it 'accepts nil as resource owner' do
|
279
|
-
token =
|
347
|
+
token = FactoryBot.create :access_token, default_attributes.merge(resource_owner_id: nil)
|
280
348
|
last_token = AccessToken.matching_token_for(application, nil, scopes)
|
281
349
|
expect(last_token).to eq(token)
|
282
350
|
end
|
283
351
|
|
284
352
|
it 'excludes revoked tokens' do
|
285
|
-
|
353
|
+
FactoryBot.create :access_token, default_attributes.merge(revoked_at: 1.day.ago)
|
286
354
|
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
287
355
|
expect(last_token).to be_nil
|
288
356
|
end
|
289
357
|
|
290
358
|
it 'matches the application' do
|
291
|
-
|
359
|
+
FactoryBot.create :access_token, default_attributes.merge(application: FactoryBot.create(:application))
|
292
360
|
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
293
361
|
expect(last_token).to be_nil
|
294
362
|
end
|
295
363
|
|
296
364
|
it 'matches the resource owner' do
|
297
|
-
|
365
|
+
FactoryBot.create :access_token, default_attributes.merge(resource_owner_id: 2)
|
298
366
|
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
299
367
|
expect(last_token).to be_nil
|
300
368
|
end
|
301
369
|
|
302
370
|
it 'matches token with fewer scopes' do
|
303
|
-
|
371
|
+
FactoryBot.create :access_token, default_attributes.merge(scopes: 'public')
|
304
372
|
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
305
373
|
expect(last_token).to be_nil
|
306
374
|
end
|
307
375
|
|
308
376
|
it 'matches token with different scopes' do
|
309
|
-
|
377
|
+
FactoryBot.create :access_token, default_attributes.merge(scopes: 'public email')
|
310
378
|
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
311
379
|
expect(last_token).to be_nil
|
312
380
|
end
|
313
381
|
|
314
382
|
it 'matches token with more scopes' do
|
315
|
-
|
383
|
+
FactoryBot.create :access_token, default_attributes.merge(scopes: 'public write email')
|
316
384
|
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
317
385
|
expect(last_token).to be_nil
|
318
386
|
end
|
319
387
|
|
320
388
|
it 'matches application scopes' do
|
321
|
-
application =
|
322
|
-
|
389
|
+
application = FactoryBot.create :application, scopes: "private read"
|
390
|
+
FactoryBot.create :access_token, default_attributes.merge(
|
323
391
|
application: application
|
324
392
|
)
|
325
393
|
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
@@ -327,14 +395,14 @@ module Doorkeeper
|
|
327
395
|
end
|
328
396
|
|
329
397
|
it 'returns the last created token' do
|
330
|
-
|
331
|
-
token =
|
398
|
+
FactoryBot.create :access_token, default_attributes.merge(created_at: 1.day.ago)
|
399
|
+
token = FactoryBot.create :access_token, default_attributes
|
332
400
|
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
333
401
|
expect(last_token).to eq(token)
|
334
402
|
end
|
335
403
|
|
336
404
|
it 'returns as_json hash' do
|
337
|
-
token =
|
405
|
+
token = FactoryBot.create :access_token, default_attributes
|
338
406
|
token_hash = {
|
339
407
|
resource_owner_id: token.resource_owner_id,
|
340
408
|
scopes: token.scopes,
|
@@ -4,7 +4,7 @@ module Doorkeeper
|
|
4
4
|
describe Application do
|
5
5
|
let(:require_owner) { Doorkeeper.configuration.instance_variable_set('@confirm_application_owner', true) }
|
6
6
|
let(:unset_require_owner) { Doorkeeper.configuration.instance_variable_set('@confirm_application_owner', false) }
|
7
|
-
let(:new_application) {
|
7
|
+
let(:new_application) { FactoryBot.build(:application) }
|
8
8
|
|
9
9
|
let(:uid) { SecureRandom.hex(8) }
|
10
10
|
let(:secret) { SecureRandom.hex(8) }
|
@@ -30,7 +30,7 @@ module Doorkeeper
|
|
30
30
|
context 'application owner is required' do
|
31
31
|
before(:each) do
|
32
32
|
require_owner
|
33
|
-
@owner =
|
33
|
+
@owner = FactoryBot.build_stubbed(:doorkeeper_testing_user)
|
34
34
|
end
|
35
35
|
|
36
36
|
it 'is invalid without an owner' do
|
@@ -49,6 +49,11 @@ module Doorkeeper
|
|
49
49
|
expect(new_application).not_to be_valid
|
50
50
|
end
|
51
51
|
|
52
|
+
it 'is invalid without determining confidentiality' do
|
53
|
+
new_application.confidential = nil
|
54
|
+
expect(new_application).not_to be_valid
|
55
|
+
end
|
56
|
+
|
52
57
|
it 'generates uid on create' do
|
53
58
|
expect(new_application.uid).to be_nil
|
54
59
|
new_application.save
|
@@ -80,17 +85,17 @@ module Doorkeeper
|
|
80
85
|
end
|
81
86
|
|
82
87
|
it 'checks uniqueness of uid' do
|
83
|
-
app1 =
|
84
|
-
app2 =
|
88
|
+
app1 = FactoryBot.create(:application)
|
89
|
+
app2 = FactoryBot.create(:application)
|
85
90
|
app2.uid = app1.uid
|
86
91
|
expect(app2).not_to be_valid
|
87
92
|
end
|
88
93
|
|
89
94
|
it 'expects database to throw an error when uids are the same' do
|
90
|
-
app1 =
|
91
|
-
app2 =
|
95
|
+
app1 = FactoryBot.create(:application)
|
96
|
+
app2 = FactoryBot.create(:application)
|
92
97
|
app2.uid = app1.uid
|
93
|
-
expect { app2.save!(validate: false) }.to raise_error(
|
98
|
+
expect { app2.save!(validate: false) }.to raise_error(uniqueness_error)
|
94
99
|
end
|
95
100
|
|
96
101
|
it 'generate secret on create' do
|
@@ -123,19 +128,52 @@ module Doorkeeper
|
|
123
128
|
end
|
124
129
|
|
125
130
|
it 'should destroy its access grants' do
|
126
|
-
|
131
|
+
FactoryBot.create(:access_grant, application: new_application)
|
127
132
|
expect { new_application.destroy }.to change { Doorkeeper::AccessGrant.count }.by(-1)
|
128
133
|
end
|
129
134
|
|
130
135
|
it 'should destroy its access tokens' do
|
131
|
-
|
132
|
-
|
136
|
+
FactoryBot.create(:access_token, application: new_application)
|
137
|
+
FactoryBot.create(:access_token, application: new_application, revoked_at: Time.now.utc)
|
133
138
|
expect do
|
134
139
|
new_application.destroy
|
135
140
|
end.to change { Doorkeeper::AccessToken.count }.by(-2)
|
136
141
|
end
|
137
142
|
end
|
138
143
|
|
144
|
+
describe :ordered_by do
|
145
|
+
let(:applications) { FactoryBot.create_list(:application, 5) }
|
146
|
+
|
147
|
+
context 'when a direction is not specified' do
|
148
|
+
it 'calls order with a default order of asc' do
|
149
|
+
names = applications.map(&:name).sort
|
150
|
+
expect(Application.ordered_by(:name).map(&:name)).to eq(names)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context 'when a direction is specified' do
|
155
|
+
it 'calls order with specified direction' do
|
156
|
+
names = applications.map(&:name).sort.reverse
|
157
|
+
expect(Application.ordered_by(:name, :desc).map(&:name)).to eq(names)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
describe "#redirect_uri=" do
|
163
|
+
context "when array of valid redirect_uris" do
|
164
|
+
it "should join by newline" do
|
165
|
+
new_application.redirect_uri = ['http://localhost/callback1', 'http://localhost/callback2']
|
166
|
+
expect(new_application.redirect_uri).to eq("http://localhost/callback1\nhttp://localhost/callback2")
|
167
|
+
end
|
168
|
+
end
|
169
|
+
context "when string of valid redirect_uris" do
|
170
|
+
it "should store as-is" do
|
171
|
+
new_application.redirect_uri = "http://localhost/callback1\nhttp://localhost/callback2"
|
172
|
+
expect(new_application.redirect_uri).to eq("http://localhost/callback1\nhttp://localhost/callback2")
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
139
177
|
describe :authorized_for do
|
140
178
|
let(:resource_owner) { double(:resource_owner, id: 10) }
|
141
179
|
|
@@ -144,43 +182,121 @@ module Doorkeeper
|
|
144
182
|
end
|
145
183
|
|
146
184
|
it 'returns only application for a specific resource owner' do
|
147
|
-
|
148
|
-
token =
|
185
|
+
FactoryBot.create(:access_token, resource_owner_id: resource_owner.id + 1)
|
186
|
+
token = FactoryBot.create(:access_token, resource_owner_id: resource_owner.id)
|
149
187
|
expect(Application.authorized_for(resource_owner)).to eq([token.application])
|
150
188
|
end
|
151
189
|
|
152
190
|
it 'excludes revoked tokens' do
|
153
|
-
|
191
|
+
FactoryBot.create(:access_token, resource_owner_id: resource_owner.id, revoked_at: 2.days.ago)
|
154
192
|
expect(Application.authorized_for(resource_owner)).to be_empty
|
155
193
|
end
|
156
194
|
|
157
195
|
it 'returns all applications that have been authorized' do
|
158
|
-
token1 =
|
159
|
-
token2 =
|
196
|
+
token1 = FactoryBot.create(:access_token, resource_owner_id: resource_owner.id)
|
197
|
+
token2 = FactoryBot.create(:access_token, resource_owner_id: resource_owner.id)
|
160
198
|
expect(Application.authorized_for(resource_owner)).to eq([token1.application, token2.application])
|
161
199
|
end
|
162
200
|
|
163
201
|
it 'returns only one application even if it has been authorized twice' do
|
164
|
-
application =
|
165
|
-
|
166
|
-
|
202
|
+
application = FactoryBot.create(:application)
|
203
|
+
FactoryBot.create(:access_token, resource_owner_id: resource_owner.id, application: application)
|
204
|
+
FactoryBot.create(:access_token, resource_owner_id: resource_owner.id, application: application)
|
167
205
|
expect(Application.authorized_for(resource_owner)).to eq([application])
|
168
206
|
end
|
207
|
+
end
|
169
208
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
209
|
+
describe :by_uid_and_secret do
|
210
|
+
context "when application is private/confidential" do
|
211
|
+
it "finds the application via uid/secret" do
|
212
|
+
app = FactoryBot.create :application
|
213
|
+
authenticated = Application.by_uid_and_secret(app.uid, app.secret)
|
214
|
+
expect(authenticated).to eq(app)
|
215
|
+
end
|
216
|
+
context "when secret is wrong" do
|
217
|
+
it "should not find the application" do
|
218
|
+
app = FactoryBot.create :application
|
219
|
+
authenticated = Application.by_uid_and_secret(app.uid, 'bad')
|
220
|
+
expect(authenticated).to eq(nil)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
context "when application is public/non-confidential" do
|
226
|
+
context "when secret is blank" do
|
227
|
+
it "should find the application" do
|
228
|
+
app = FactoryBot.create :application, confidential: false
|
229
|
+
authenticated = Application.by_uid_and_secret(app.uid, nil)
|
230
|
+
expect(authenticated).to eq(app)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
context "when secret is wrong" do
|
234
|
+
it "should not find the application" do
|
235
|
+
app = FactoryBot.create :application, confidential: false
|
236
|
+
authenticated = Application.by_uid_and_secret(app.uid, 'bad')
|
237
|
+
expect(authenticated).to eq(nil)
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
describe :confidential? do
|
244
|
+
subject { FactoryBot.create(:application, confidential: confidential).confidential? }
|
245
|
+
|
246
|
+
context 'when application is private/confidential' do
|
247
|
+
let(:confidential) { true }
|
248
|
+
it { expect(subject).to eq(true) }
|
249
|
+
end
|
250
|
+
|
251
|
+
context 'when application is public/non-confidential' do
|
252
|
+
let(:confidential) { false }
|
253
|
+
it { expect(subject).to eq(false) }
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
describe :confidential do
|
258
|
+
subject { FactoryBot.create(:application, confidential: confidential).confidential }
|
259
|
+
|
260
|
+
context 'when application is private/confidential' do
|
261
|
+
let(:confidential) { true }
|
262
|
+
it { expect(subject).to eq(true) }
|
263
|
+
end
|
264
|
+
|
265
|
+
context 'when application is public/non-confidential' do
|
266
|
+
let(:confidential) { false }
|
267
|
+
it { expect(subject).to eq(false) }
|
268
|
+
end
|
269
|
+
|
270
|
+
context 'when the application does not support confidentiality' do
|
271
|
+
let(:confidential) { false }
|
272
|
+
|
273
|
+
before { allow(Application).to receive(:supports_confidentiality?).and_return(false) }
|
274
|
+
|
275
|
+
it 'warns of the CVE' do
|
276
|
+
expect(ActiveSupport::Deprecation).to receive(:warn).with(
|
277
|
+
'You are susceptible to security bug ' \
|
278
|
+
'CVE-2018-1000211. Please follow instructions outlined in ' \
|
279
|
+
'Doorkeeper::CVE_2018_1000211_WARNING'
|
280
|
+
)
|
281
|
+
Application.new.confidential
|
282
|
+
end
|
283
|
+
|
284
|
+
it { expect(subject).to eq(true) }
|
176
285
|
end
|
177
286
|
end
|
178
287
|
|
179
|
-
describe :
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
288
|
+
describe :supports_confidentiality? do
|
289
|
+
context 'when no column' do
|
290
|
+
it 'returns false' do
|
291
|
+
expect(Application).to receive(:column_names).and_return(%w[foo bar])
|
292
|
+
expect(Application.supports_confidentiality?).to eq(false)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
context 'when column' do
|
296
|
+
it 'returns true' do
|
297
|
+
expect(Application).to receive(:column_names).and_return(%w[foo bar confidential])
|
298
|
+
expect(Application.supports_confidentiality?).to eq(true)
|
299
|
+
end
|
184
300
|
end
|
185
301
|
end
|
186
302
|
end
|