doorkeeper 4.4.3 → 5.0.0.rc1
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/.gitignore +1 -0
- data/.travis.yml +2 -0
- data/Appraisals +2 -2
- data/Gemfile +1 -1
- data/NEWS.md +36 -17
- data/README.md +85 -3
- data/Rakefile +6 -0
- data/app/assets/stylesheets/doorkeeper/admin/application.css +2 -2
- data/app/controllers/doorkeeper/application_controller.rb +4 -3
- data/app/controllers/doorkeeper/application_metal_controller.rb +4 -0
- data/app/controllers/doorkeeper/applications_controller.rb +42 -22
- data/app/controllers/doorkeeper/authorizations_controller.rb +55 -12
- data/app/controllers/doorkeeper/authorized_applications_controller.rb +15 -1
- data/app/controllers/doorkeeper/tokens_controller.rb +12 -15
- data/app/helpers/doorkeeper/dashboard_helper.rb +7 -7
- data/app/validators/redirect_uri_validator.rb +3 -2
- data/app/views/doorkeeper/applications/_delete_form.html.erb +3 -1
- data/app/views/doorkeeper/applications/_form.html.erb +25 -24
- data/app/views/doorkeeper/applications/edit.html.erb +1 -1
- data/app/views/doorkeeper/applications/index.html.erb +17 -7
- data/app/views/doorkeeper/applications/new.html.erb +1 -1
- data/app/views/doorkeeper/applications/show.html.erb +6 -6
- data/app/views/doorkeeper/authorizations/error.html.erb +1 -1
- data/app/views/doorkeeper/authorizations/new.html.erb +4 -0
- data/app/views/layouts/doorkeeper/admin.html.erb +15 -15
- data/config/locales/en.yml +9 -1
- data/doorkeeper.gemspec +0 -2
- data/gemfiles/rails_5_2.gemfile +1 -1
- data/lib/doorkeeper/config.rb +58 -35
- data/lib/doorkeeper/engine.rb +4 -0
- data/lib/doorkeeper/errors.rb +2 -5
- data/lib/doorkeeper/grape/helpers.rb +1 -1
- data/lib/doorkeeper/helpers/controller.rb +7 -2
- data/lib/doorkeeper/models/access_grant_mixin.rb +56 -0
- data/lib/doorkeeper/models/access_token_mixin.rb +38 -21
- data/lib/doorkeeper/models/concerns/scopes.rb +1 -1
- data/lib/doorkeeper/oauth/authorization/code.rb +31 -8
- data/lib/doorkeeper/oauth/authorization/context.rb +15 -0
- data/lib/doorkeeper/oauth/authorization/token.rb +23 -6
- data/lib/doorkeeper/oauth/authorization_code_request.rb +27 -2
- data/lib/doorkeeper/oauth/base_request.rb +18 -8
- data/lib/doorkeeper/oauth/client/credentials.rb +1 -1
- data/lib/doorkeeper/oauth/client_credentials/issuer.rb +6 -1
- data/lib/doorkeeper/oauth/client_credentials/validation.rb +4 -2
- data/lib/doorkeeper/oauth/error_response.rb +11 -3
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +0 -8
- data/lib/doorkeeper/oauth/password_access_token_request.rb +7 -4
- data/lib/doorkeeper/oauth/pre_authorization.rb +41 -11
- data/lib/doorkeeper/oauth/refresh_token_request.rb +6 -1
- data/lib/doorkeeper/oauth/scopes.rb +1 -1
- data/lib/doorkeeper/oauth/token.rb +5 -2
- data/lib/doorkeeper/oauth/token_introspection.rb +2 -2
- data/lib/doorkeeper/oauth/token_response.rb +4 -2
- data/lib/doorkeeper/oauth.rb +13 -0
- data/lib/doorkeeper/orm/active_record/application.rb +13 -16
- data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +26 -0
- data/lib/doorkeeper/orm/active_record.rb +2 -0
- data/lib/doorkeeper/rails/helpers.rb +2 -4
- data/lib/doorkeeper/rails/routes.rb +14 -6
- data/lib/doorkeeper/rake/db.rake +40 -0
- data/lib/doorkeeper/rake/setup.rake +6 -0
- data/lib/doorkeeper/rake.rb +14 -0
- data/lib/doorkeeper/request.rb +28 -28
- data/lib/doorkeeper/version.rb +5 -25
- data/lib/doorkeeper.rb +4 -17
- data/lib/generators/doorkeeper/application_owner_generator.rb +23 -18
- data/lib/generators/doorkeeper/confidential_applications_generator.rb +32 -0
- data/lib/generators/doorkeeper/install_generator.rb +17 -9
- data/lib/generators/doorkeeper/migration_generator.rb +23 -18
- data/lib/generators/doorkeeper/pkce_generator.rb +32 -0
- data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +29 -24
- data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
- data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +6 -0
- data/lib/generators/doorkeeper/templates/initializer.rb +60 -9
- data/lib/generators/doorkeeper/views_generator.rb +3 -1
- data/spec/controllers/application_metal_controller_spec.rb +50 -0
- data/spec/controllers/applications_controller_spec.rb +126 -13
- data/spec/controllers/authorizations_controller_spec.rb +252 -49
- data/spec/controllers/protected_resources_controller_spec.rb +16 -16
- data/spec/controllers/token_info_controller_spec.rb +4 -12
- data/spec/controllers/tokens_controller_spec.rb +19 -73
- data/spec/dummy/app/assets/config/manifest.js +2 -0
- data/spec/dummy/config/environments/test.rb +4 -5
- data/spec/dummy/config/initializers/doorkeeper.rb +5 -4
- data/spec/dummy/config/initializers/new_framework_defaults.rb +4 -0
- data/spec/dummy/config/routes.rb +3 -42
- data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +6 -0
- data/spec/dummy/db/migrate/{20180210183654_add_confidential_to_application.rb → 20180210183654_add_confidential_to_applications.rb} +1 -1
- data/spec/dummy/db/schema.rb +36 -36
- data/spec/generators/application_owner_generator_spec.rb +1 -1
- data/spec/generators/confidential_applications_generator_spec.rb +45 -0
- data/spec/generators/install_generator_spec.rb +1 -1
- data/spec/generators/migration_generator_spec.rb +1 -1
- data/spec/generators/pkce_generator_spec.rb +43 -0
- data/spec/generators/previous_refresh_token_generator_spec.rb +1 -1
- data/spec/generators/views_generator_spec.rb +1 -1
- data/spec/grape/grape_integration_spec.rb +1 -1
- data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +1 -1
- data/spec/lib/config_spec.rb +51 -31
- data/spec/lib/doorkeeper_spec.rb +1 -126
- data/spec/lib/models/expirable_spec.rb +0 -3
- data/spec/lib/models/revocable_spec.rb +0 -2
- data/spec/lib/models/scopes_spec.rb +0 -4
- data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -4
- data/spec/lib/oauth/authorization_code_request_spec.rb +9 -2
- data/spec/lib/oauth/base_request_spec.rb +16 -2
- data/spec/lib/oauth/base_response_spec.rb +1 -1
- data/spec/lib/oauth/client/credentials_spec.rb +1 -3
- data/spec/lib/oauth/client_credentials/creator_spec.rb +5 -1
- data/spec/lib/oauth/client_credentials/issuer_spec.rb +26 -7
- data/spec/lib/oauth/client_credentials/validation_spec.rb +2 -3
- data/spec/lib/oauth/client_credentials_integration_spec.rb +1 -1
- data/spec/lib/oauth/client_credentials_request_spec.rb +3 -5
- data/spec/lib/oauth/client_spec.rb +0 -3
- data/spec/lib/oauth/code_request_spec.rb +4 -2
- data/spec/lib/oauth/error_response_spec.rb +0 -3
- data/spec/lib/oauth/error_spec.rb +0 -2
- data/spec/lib/oauth/forbidden_token_response_spec.rb +1 -4
- data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -3
- data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -1
- data/spec/lib/oauth/helpers/uri_checker_spec.rb +5 -7
- data/spec/lib/oauth/invalid_token_response_spec.rb +1 -4
- data/spec/lib/oauth/password_access_token_request_spec.rb +37 -2
- data/spec/lib/oauth/pre_authorization_spec.rb +33 -4
- data/spec/lib/oauth/refresh_token_request_spec.rb +11 -7
- data/spec/lib/oauth/scopes_spec.rb +0 -3
- data/spec/lib/oauth/token_request_spec.rb +4 -5
- data/spec/lib/oauth/token_response_spec.rb +0 -1
- data/spec/lib/oauth/token_spec.rb +37 -14
- data/spec/lib/orm/active_record/stale_records_cleaner_spec.rb +79 -0
- data/spec/lib/request/strategy_spec.rb +0 -1
- data/spec/lib/server_spec.rb +1 -1
- data/spec/models/doorkeeper/access_grant_spec.rb +1 -1
- data/spec/models/doorkeeper/access_token_spec.rb +50 -16
- data/spec/models/doorkeeper/application_spec.rb +1 -47
- data/spec/requests/applications/applications_request_spec.rb +89 -1
- data/spec/requests/applications/authorized_applications_spec.rb +1 -1
- data/spec/requests/endpoints/authorization_spec.rb +1 -1
- data/spec/requests/endpoints/token_spec.rb +7 -5
- data/spec/requests/flows/authorization_code_errors_spec.rb +1 -1
- data/spec/requests/flows/authorization_code_spec.rb +198 -2
- data/spec/requests/flows/client_credentials_spec.rb +46 -6
- data/spec/requests/flows/implicit_grant_errors_spec.rb +1 -1
- data/spec/requests/flows/implicit_grant_spec.rb +38 -11
- data/spec/requests/flows/password_spec.rb +56 -2
- data/spec/requests/flows/refresh_token_spec.rb +2 -2
- data/spec/requests/flows/revoke_token_spec.rb +11 -11
- data/spec/requests/flows/skip_authorization_spec.rb +16 -11
- 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 +59 -7
- data/spec/routing/default_routes_spec.rb +2 -2
- data/spec/routing/scoped_routes_spec.rb +16 -2
- data/spec/spec_helper.rb +54 -3
- data/spec/spec_helper_integration.rb +2 -74
- data/spec/support/dependencies/{factory_girl.rb → factory_bot.rb} +0 -0
- data/spec/support/doorkeeper_rspec.rb +19 -0
- data/spec/support/helpers/authorization_request_helper.rb +4 -4
- data/spec/support/helpers/request_spec_helper.rb +2 -2
- data/spec/support/helpers/url_helper.rb +7 -3
- data/spec/support/http_method_shim.rb +12 -16
- data/spec/validators/redirect_uri_validator_spec.rb +7 -1
- data/spec/version/version_spec.rb +3 -3
- data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
- metadata +33 -31
- data/lib/generators/doorkeeper/add_client_confidentiality_generator.rb +0 -31
- data/lib/generators/doorkeeper/templates/add_confidential_to_application_migration.rb.erb +0 -11
- data/spec/controllers/application_metal_controller.rb +0 -10
@@ -1,15 +1,8 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'uri'
|
3
|
-
require 'doorkeeper/oauth/helpers/uri_checker'
|
4
2
|
|
5
3
|
module Doorkeeper::OAuth::Helpers
|
6
4
|
describe URIChecker do
|
7
5
|
describe '.valid?' do
|
8
|
-
it 'is valid for native uris' do
|
9
|
-
uri = 'urn:ietf:wg:oauth:2.0:oob'
|
10
|
-
expect(URIChecker.valid?(uri)).to be_truthy
|
11
|
-
end
|
12
|
-
|
13
6
|
it 'is valid for valid uris' do
|
14
7
|
uri = 'http://app.co'
|
15
8
|
expect(URIChecker.valid?(uri)).to be_truthy
|
@@ -49,6 +42,11 @@ module Doorkeeper::OAuth::Helpers
|
|
49
42
|
uri = ' '
|
50
43
|
expect(URIChecker.valid?(uri)).to be_falsey
|
51
44
|
end
|
45
|
+
|
46
|
+
it 'is valid for native uris' do
|
47
|
+
uri = 'urn:ietf:wg:oauth:2.0:oob'
|
48
|
+
expect(URIChecker.valid?(uri)).to be_truthy
|
49
|
+
end
|
52
50
|
end
|
53
51
|
|
54
52
|
describe '.matches?' do
|
@@ -1,12 +1,9 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'active_model'
|
3
|
-
require 'doorkeeper'
|
4
|
-
require 'doorkeeper/oauth/invalid_token_response'
|
5
2
|
|
6
3
|
module Doorkeeper::OAuth
|
7
4
|
describe InvalidTokenResponse do
|
8
5
|
describe "#name" do
|
9
|
-
it
|
6
|
+
it { expect(subject.name).to eq(:invalid_token) }
|
10
7
|
end
|
11
8
|
|
12
9
|
describe "#status" do
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
module Doorkeeper::OAuth
|
4
4
|
describe PasswordAccessTokenRequest do
|
@@ -8,7 +8,9 @@ module Doorkeeper::OAuth
|
|
8
8
|
default_scopes: Doorkeeper::OAuth::Scopes.new,
|
9
9
|
access_token_expires_in: 2.hours,
|
10
10
|
refresh_token_enabled?: false,
|
11
|
-
custom_access_token_expires_in:
|
11
|
+
custom_access_token_expires_in: lambda { |context|
|
12
|
+
context.grant_type == Doorkeeper::OAuth::PASSWORD ? 1234 : nil
|
13
|
+
}
|
12
14
|
)
|
13
15
|
end
|
14
16
|
let(:client) { FactoryBot.create(:application) }
|
@@ -22,6 +24,7 @@ module Doorkeeper::OAuth
|
|
22
24
|
expect do
|
23
25
|
subject.authorize
|
24
26
|
end.to change { client.reload.access_tokens.count }.by(1)
|
27
|
+
expect(client.reload.access_tokens.sort_by(&:created_at).last.expires_in).to eq(1234)
|
25
28
|
end
|
26
29
|
|
27
30
|
it 'issues a new token without a client' do
|
@@ -92,5 +95,37 @@ module Doorkeeper::OAuth
|
|
92
95
|
expect(Doorkeeper::AccessToken.last.scopes).to include('public')
|
93
96
|
end
|
94
97
|
end
|
98
|
+
|
99
|
+
describe 'with custom expiry' do
|
100
|
+
let(:server) do
|
101
|
+
double(
|
102
|
+
:server,
|
103
|
+
default_scopes: Doorkeeper::OAuth::Scopes.new,
|
104
|
+
access_token_expires_in: 2.hours,
|
105
|
+
refresh_token_enabled?: false,
|
106
|
+
custom_access_token_expires_in: lambda { |context|
|
107
|
+
context.scopes.exists?('public') ? 222 : nil
|
108
|
+
}
|
109
|
+
)
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'checks scopes' do
|
113
|
+
subject = PasswordAccessTokenRequest.new(server, client, owner, scope: 'public')
|
114
|
+
allow(server).to receive(:scopes).and_return(Doorkeeper::OAuth::Scopes.from_string('public'))
|
115
|
+
expect do
|
116
|
+
subject.authorize
|
117
|
+
end.to change { Doorkeeper::AccessToken.count }.by(1)
|
118
|
+
expect(Doorkeeper::AccessToken.last.expires_in).to eq(222)
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'falls back to the default otherwise' do
|
122
|
+
subject = PasswordAccessTokenRequest.new(server, client, owner, scope: 'private')
|
123
|
+
allow(server).to receive(:scopes).and_return(Doorkeeper::OAuth::Scopes.from_string('private'))
|
124
|
+
expect do
|
125
|
+
subject.authorize
|
126
|
+
end.to change { Doorkeeper::AccessToken.count }.by(1)
|
127
|
+
expect(Doorkeeper::AccessToken.last.expires_in).to eq(2.hours)
|
128
|
+
end
|
129
|
+
end
|
95
130
|
end
|
96
131
|
end
|
@@ -1,13 +1,13 @@
|
|
1
|
-
require '
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
module Doorkeeper::OAuth
|
4
4
|
describe PreAuthorization do
|
5
|
-
let(:server)
|
5
|
+
let(:server) do
|
6
6
|
server = Doorkeeper.configuration
|
7
7
|
allow(server).to receive(:default_scopes).and_return(Scopes.new)
|
8
8
|
allow(server).to receive(:scopes).and_return(Scopes.from_string('public profile'))
|
9
9
|
server
|
10
|
-
|
10
|
+
end
|
11
11
|
|
12
12
|
let(:application) do
|
13
13
|
application = double :application
|
@@ -133,11 +133,16 @@ module Doorkeeper::OAuth
|
|
133
133
|
end
|
134
134
|
|
135
135
|
it 'invalidates redirect_uri when it does\'n match with the client' do
|
136
|
-
subject.redirect_uri =
|
136
|
+
subject.redirect_uri = 'urn:ietf:wg:oauth:2.0:oob'
|
137
137
|
expect(subject).not_to be_authorizable
|
138
138
|
end
|
139
139
|
end
|
140
140
|
|
141
|
+
it 'matches the redirect uri against client\'s one' do
|
142
|
+
subject.redirect_uri = 'http://nothesame.com'
|
143
|
+
expect(subject).not_to be_authorizable
|
144
|
+
end
|
145
|
+
|
141
146
|
it 'stores the state' do
|
142
147
|
expect(subject.state).to eq('save-this')
|
143
148
|
end
|
@@ -156,5 +161,29 @@ module Doorkeeper::OAuth
|
|
156
161
|
subject.redirect_uri = nil
|
157
162
|
expect(subject).not_to be_authorizable
|
158
163
|
end
|
164
|
+
|
165
|
+
describe "as_json" do
|
166
|
+
let(:client_id) { "client_uid_123" }
|
167
|
+
let(:client_name) { "Acme Co." }
|
168
|
+
|
169
|
+
before do
|
170
|
+
allow(client).to receive(:uid).and_return client_id
|
171
|
+
allow(client).to receive(:name).and_return client_name
|
172
|
+
end
|
173
|
+
|
174
|
+
let(:json) { subject.as_json({}) }
|
175
|
+
|
176
|
+
it { is_expected.to respond_to :as_json }
|
177
|
+
|
178
|
+
it "returns correct values" do
|
179
|
+
expect(json[:client_id]).to eq client_id
|
180
|
+
expect(json[:redirect_uri]).to eq subject.redirect_uri
|
181
|
+
expect(json[:state]).to eq subject.state
|
182
|
+
expect(json[:response_type]).to eq subject.response_type
|
183
|
+
expect(json[:scope]).to eq subject.scope
|
184
|
+
expect(json[:client_name]).to eq client_name
|
185
|
+
expect(json[:status]).to eq I18n.t('doorkeeper.pre_authorization.status')
|
186
|
+
end
|
187
|
+
end
|
159
188
|
end
|
160
189
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
module Doorkeeper::OAuth
|
4
4
|
describe RefreshTokenRequest do
|
@@ -9,7 +9,7 @@ module Doorkeeper::OAuth
|
|
9
9
|
let(:server) do
|
10
10
|
double :server,
|
11
11
|
access_token_expires_in: 2.minutes,
|
12
|
-
custom_access_token_expires_in: ->
|
12
|
+
custom_access_token_expires_in: ->(_context) { nil }
|
13
13
|
end
|
14
14
|
|
15
15
|
let(:refresh_token) do
|
@@ -30,7 +30,9 @@ module Doorkeeper::OAuth
|
|
30
30
|
it 'issues a new token for the client with custom expires_in' do
|
31
31
|
server = double :server,
|
32
32
|
access_token_expires_in: 2.minutes,
|
33
|
-
custom_access_token_expires_in:
|
33
|
+
custom_access_token_expires_in: lambda { |context|
|
34
|
+
context.grant_type == Doorkeeper::OAuth::REFRESH_TOKEN ? 1234 : nil
|
35
|
+
}
|
34
36
|
|
35
37
|
allow(Doorkeeper::AccessToken).to receive(:refresh_token_revoked_on_use?).and_return(false)
|
36
38
|
|
@@ -85,7 +87,9 @@ module Doorkeeper::OAuth
|
|
85
87
|
let(:server) do
|
86
88
|
double :server,
|
87
89
|
access_token_expires_in: 2.minutes,
|
88
|
-
custom_access_token_expires_in:
|
90
|
+
custom_access_token_expires_in: lambda { |context|
|
91
|
+
context.grant_type == Doorkeeper::OAuth::REFRESH_TOKEN ? 1234 : nil
|
92
|
+
}
|
89
93
|
end
|
90
94
|
|
91
95
|
before do
|
@@ -131,13 +135,13 @@ module Doorkeeper::OAuth
|
|
131
135
|
|
132
136
|
it 'transfers scopes from the old token to the new token' do
|
133
137
|
subject.authorize
|
134
|
-
expect(Doorkeeper::AccessToken.last.scopes).to eq([
|
138
|
+
expect(Doorkeeper::AccessToken.last.scopes).to eq(%i[public write])
|
135
139
|
end
|
136
140
|
|
137
141
|
it 'reduces scopes to the provided scopes' do
|
138
142
|
parameters[:scopes] = 'public'
|
139
143
|
subject.authorize
|
140
|
-
expect(Doorkeeper::AccessToken.last.scopes).to eq([
|
144
|
+
expect(Doorkeeper::AccessToken.last.scopes).to eq(%i[public])
|
141
145
|
end
|
142
146
|
|
143
147
|
it 'validates that scopes are included in the original access token' do
|
@@ -151,7 +155,7 @@ module Doorkeeper::OAuth
|
|
151
155
|
parameters[:scopes] = 'public update'
|
152
156
|
parameters[:scope] = 'public'
|
153
157
|
subject.authorize
|
154
|
-
expect(Doorkeeper::AccessToken.last.scopes).to eq([
|
158
|
+
expect(Doorkeeper::AccessToken.last.scopes).to eq(%i[public])
|
155
159
|
end
|
156
160
|
|
157
161
|
it 'uses params[:scope] in favor of scopes if present (invalid)' do
|
@@ -1,10 +1,9 @@
|
|
1
|
-
require '
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
module Doorkeeper::OAuth
|
4
4
|
describe TokenRequest do
|
5
5
|
let :application do
|
6
|
-
|
7
|
-
double(:application, id: 9990, scopes: scopes)
|
6
|
+
FactoryBot.create(:application, scopes: "public")
|
8
7
|
end
|
9
8
|
|
10
9
|
let :pre_auth do
|
@@ -51,8 +50,8 @@ module Doorkeeper::OAuth
|
|
51
50
|
before do
|
52
51
|
Doorkeeper.configure do
|
53
52
|
orm DOORKEEPER_ORM
|
54
|
-
custom_access_token_expires_in do |
|
55
|
-
1234
|
53
|
+
custom_access_token_expires_in do |context|
|
54
|
+
context.grant_type == Doorkeeper::OAuth::IMPLICIT ? 1234 : nil
|
56
55
|
end
|
57
56
|
end
|
58
57
|
end
|
@@ -1,6 +1,4 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'active_support/core_ext/string'
|
3
|
-
require 'doorkeeper/oauth/token'
|
4
2
|
|
5
3
|
module Doorkeeper
|
6
4
|
unless defined?(AccessToken)
|
@@ -14,7 +12,7 @@ module Doorkeeper
|
|
14
12
|
let(:request) { double.as_null_object }
|
15
13
|
|
16
14
|
let(:method) do
|
17
|
-
->(
|
15
|
+
->(*) { 'token-value' }
|
18
16
|
end
|
19
17
|
|
20
18
|
it 'accepts anything that responds to #call' do
|
@@ -96,19 +94,44 @@ module Doorkeeper
|
|
96
94
|
end
|
97
95
|
|
98
96
|
describe :authenticate do
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
97
|
+
context 'refresh tokens are disabled (default)' do
|
98
|
+
context 'refresh tokens are enabled' do
|
99
|
+
it 'does not revoke previous refresh_token if token was found' do
|
100
|
+
token = ->(_r) { 'token' }
|
101
|
+
expect(
|
102
|
+
AccessToken
|
103
|
+
).to receive(:by_token).with('token').and_return(token)
|
104
|
+
expect(token).not_to receive(:revoke_previous_refresh_token!)
|
105
|
+
Token.authenticate double, token
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'calls the finder if token was returned' do
|
110
|
+
token = ->(_r) { 'token' }
|
111
|
+
expect(AccessToken).to receive(:by_token).with('token')
|
112
|
+
Token.authenticate double, token
|
113
|
+
end
|
103
114
|
end
|
104
115
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
116
|
+
context 'refresh tokens are enabled' do
|
117
|
+
before do
|
118
|
+
Doorkeeper.configure { use_refresh_token }
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'revokes previous refresh_token if token was found' do
|
122
|
+
token = ->(_r) { 'token' }
|
123
|
+
expect(
|
124
|
+
AccessToken
|
125
|
+
).to receive(:by_token).with('token').and_return(token)
|
126
|
+
expect(token).to receive(:revoke_previous_refresh_token!)
|
127
|
+
Token.authenticate double, token
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'calls the finder if token was returned' do
|
131
|
+
token = ->(_r) { 'token' }
|
132
|
+
expect(AccessToken).to receive(:by_token).with('token')
|
133
|
+
Token.authenticate double, token
|
134
|
+
end
|
112
135
|
end
|
113
136
|
end
|
114
137
|
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Doorkeeper::Orm::ActiveRecord::StaleRecordsCleaner do
|
6
|
+
let(:cleaner) { described_class.new(model) }
|
7
|
+
let(:models_by_name) do
|
8
|
+
{
|
9
|
+
access_token: Doorkeeper::AccessToken,
|
10
|
+
access_grant: Doorkeeper::AccessGrant
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
%i[access_token access_grant].each do |model_name|
|
15
|
+
context "(#{model_name})" do
|
16
|
+
let(:model) { models_by_name.fetch(model_name) }
|
17
|
+
|
18
|
+
describe '#clean_revoked' do
|
19
|
+
subject { cleaner.clean_revoked }
|
20
|
+
|
21
|
+
context 'with revoked record' do
|
22
|
+
before do
|
23
|
+
FactoryBot.create model_name, revoked_at: Time.current - 1.minute
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'removes the record' do
|
27
|
+
expect { subject }.to change { model.count }.to(0)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'with record revoked in the future' do
|
32
|
+
before do
|
33
|
+
FactoryBot.create model_name, revoked_at: Time.current + 1.minute
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'keeps the record' do
|
37
|
+
expect { subject }.not_to change { model.count }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'with unrevoked record' do
|
42
|
+
before do
|
43
|
+
FactoryBot.create model_name, revoked_at: nil
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'keeps the record' do
|
47
|
+
expect { subject }.not_to change { model.count }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#clean_expired' do
|
53
|
+
subject { cleaner.clean_expired(ttl) }
|
54
|
+
let(:ttl) { 500 }
|
55
|
+
let(:expiry_border) { ttl.seconds.ago }
|
56
|
+
|
57
|
+
context 'with record that is expired' do
|
58
|
+
before do
|
59
|
+
FactoryBot.create model_name, created_at: expiry_border - 1.minute
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'removes the record' do
|
63
|
+
expect { subject }.to change { model.count }.to(0)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'with record that is not expired' do
|
68
|
+
before do
|
69
|
+
FactoryBot.create model_name, created_at: expiry_border + 1.minute
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'keeps the record' do
|
73
|
+
expect { subject }.not_to change { model.count }
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/spec/lib/server_spec.rb
CHANGED
@@ -46,7 +46,7 @@ describe Doorkeeper::Server do
|
|
46
46
|
subject.authorization_request :code
|
47
47
|
end
|
48
48
|
|
49
|
-
it 'builds the request with
|
49
|
+
it 'builds the request with composite strategy name' do
|
50
50
|
allow(Doorkeeper.configuration).
|
51
51
|
to receive(:authorization_response_types).
|
52
52
|
and_return(['id_token token'])
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
module Doorkeeper
|
4
4
|
describe AccessToken do
|
@@ -144,7 +144,7 @@ module Doorkeeper
|
|
144
144
|
end
|
145
145
|
|
146
146
|
module CustomGeneratorArgs
|
147
|
-
def self.generate(
|
147
|
+
def self.generate(_opts = {})
|
148
148
|
raise LoadError, 'custom behaviour'
|
149
149
|
end
|
150
150
|
end
|
@@ -218,7 +218,7 @@ module Doorkeeper
|
|
218
218
|
context 'with default parameters' do
|
219
219
|
|
220
220
|
let(:resource_owner_id) { 100 }
|
221
|
-
let(:application)
|
221
|
+
let(:application) { FactoryBot.create :application }
|
222
222
|
let(:default_attributes) do
|
223
223
|
{ application: application, resource_owner_id: resource_owner_id }
|
224
224
|
end
|
@@ -330,6 +330,10 @@ module Doorkeeper
|
|
330
330
|
}
|
331
331
|
end
|
332
332
|
|
333
|
+
before do
|
334
|
+
default_scopes_exist(*scopes.all)
|
335
|
+
end
|
336
|
+
|
333
337
|
it 'returns only one token' do
|
334
338
|
token = FactoryBot.create :access_token, default_attributes
|
335
339
|
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
@@ -355,37 +359,45 @@ module Doorkeeper
|
|
355
359
|
expect(last_token).to be_nil
|
356
360
|
end
|
357
361
|
|
358
|
-
it
|
362
|
+
it "excludes tokens with a different application" do
|
359
363
|
FactoryBot.create :access_token, default_attributes.merge(application: FactoryBot.create(:application))
|
360
364
|
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
361
365
|
expect(last_token).to be_nil
|
362
366
|
end
|
363
367
|
|
364
|
-
it
|
368
|
+
it "excludes tokens with a different resource owner" do
|
365
369
|
FactoryBot.create :access_token, default_attributes.merge(resource_owner_id: 2)
|
366
370
|
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
367
371
|
expect(last_token).to be_nil
|
368
372
|
end
|
369
373
|
|
370
|
-
it
|
374
|
+
it "excludes tokens with fewer scopes" do
|
371
375
|
FactoryBot.create :access_token, default_attributes.merge(scopes: 'public')
|
372
376
|
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
373
377
|
expect(last_token).to be_nil
|
374
378
|
end
|
375
379
|
|
376
|
-
it '
|
380
|
+
it 'excludes tokens with different scopes' do
|
377
381
|
FactoryBot.create :access_token, default_attributes.merge(scopes: 'public email')
|
378
382
|
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
379
383
|
expect(last_token).to be_nil
|
380
384
|
end
|
381
385
|
|
382
|
-
it '
|
386
|
+
it 'excludes tokens with additional scopes' do
|
383
387
|
FactoryBot.create :access_token, default_attributes.merge(scopes: 'public write email')
|
384
388
|
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
385
389
|
expect(last_token).to be_nil
|
386
390
|
end
|
387
391
|
|
388
|
-
it '
|
392
|
+
it 'excludes tokens with scopes that are not present in server scopes' do
|
393
|
+
FactoryBot.create :access_token, default_attributes.merge(
|
394
|
+
application: application, scopes: 'public read'
|
395
|
+
)
|
396
|
+
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
397
|
+
expect(last_token).to be_nil
|
398
|
+
end
|
399
|
+
|
400
|
+
it 'excludes tokens with scopes that are not present in application scopes' do
|
389
401
|
application = FactoryBot.create :application, scopes: "private read"
|
390
402
|
FactoryBot.create :access_token, default_attributes.merge(
|
391
403
|
application: application
|
@@ -394,25 +406,47 @@ module Doorkeeper
|
|
394
406
|
expect(last_token).to be_nil
|
395
407
|
end
|
396
408
|
|
397
|
-
it '
|
409
|
+
it 'does not match token if empty scope requested and token/app scopes present' do
|
410
|
+
application = FactoryBot.create :application, scopes: "sample:scope"
|
411
|
+
app_params = {
|
412
|
+
application_id: application.id, scopes: "sample:scope",
|
413
|
+
resource_owner_id: 100
|
414
|
+
}
|
415
|
+
FactoryBot.create :access_token, app_params
|
416
|
+
empty_scopes = Doorkeeper::OAuth::Scopes.from_string("")
|
417
|
+
last_token = AccessToken.matching_token_for(application, 100, empty_scopes)
|
418
|
+
expect(last_token).to be_nil
|
419
|
+
end
|
420
|
+
|
421
|
+
it 'matches token if empty scope requested and no token scopes present' do
|
422
|
+
empty_scopes = Doorkeeper::OAuth::Scopes.from_string("")
|
423
|
+
token = FactoryBot.create :access_token, default_attributes.merge(scopes: empty_scopes)
|
424
|
+
last_token = AccessToken.matching_token_for(application, 100, empty_scopes)
|
425
|
+
expect(last_token).to eq(token)
|
426
|
+
end
|
427
|
+
|
428
|
+
it 'returns the last matching token' do
|
398
429
|
FactoryBot.create :access_token, default_attributes.merge(created_at: 1.day.ago)
|
399
|
-
|
430
|
+
matching_token = FactoryBot.create :access_token, default_attributes
|
431
|
+
FactoryBot.create :access_token, default_attributes.merge(scopes: 'public')
|
432
|
+
|
400
433
|
last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
|
401
|
-
expect(last_token).to eq(
|
434
|
+
expect(last_token).to eq(matching_token)
|
402
435
|
end
|
436
|
+
end
|
403
437
|
|
404
|
-
|
405
|
-
|
438
|
+
describe "#as_json" do
|
439
|
+
it "returns as_json hash" do
|
440
|
+
token = FactoryBot.create :access_token
|
406
441
|
token_hash = {
|
407
442
|
resource_owner_id: token.resource_owner_id,
|
408
443
|
scopes: token.scopes,
|
409
444
|
expires_in_seconds: token.expires_in_seconds,
|
410
445
|
application: { uid: token.application.uid },
|
411
|
-
created_at: token.created_at.to_i
|
446
|
+
created_at: token.created_at.to_i
|
412
447
|
}
|
413
448
|
expect(token.as_json).to eq token_hash
|
414
449
|
end
|
415
450
|
end
|
416
|
-
|
417
451
|
end
|
418
452
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
module Doorkeeper
|
4
4
|
describe Application do
|
@@ -253,51 +253,5 @@ module Doorkeeper
|
|
253
253
|
it { expect(subject).to eq(false) }
|
254
254
|
end
|
255
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) }
|
285
|
-
end
|
286
|
-
end
|
287
|
-
|
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
|
300
|
-
end
|
301
|
-
end
|
302
256
|
end
|
303
257
|
end
|