doorkeeper 2.1.4 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of doorkeeper might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.hound.yml +4 -0
- data/.travis.yml +5 -24
- data/CONTRIBUTING.md +23 -13
- data/Gemfile +3 -7
- data/{CHANGELOG.md → NEWS.md} +137 -42
- data/README.md +60 -46
- data/RELEASING.md +5 -3
- data/app/assets/stylesheets/doorkeeper/admin/application.css +1 -5
- data/app/controllers/doorkeeper/applications_controller.rb +2 -2
- data/app/helpers/doorkeeper/dashboard_helper.rb +1 -1
- data/app/validators/redirect_uri_validator.rb +1 -1
- data/app/views/doorkeeper/applications/_form.html.erb +13 -2
- data/app/views/doorkeeper/applications/show.html.erb +3 -2
- data/app/views/doorkeeper/authorizations/new.html.erb +1 -1
- data/app/views/layouts/doorkeeper/admin.html.erb +5 -2
- data/config/locales/en.yml +4 -32
- data/doorkeeper.gemspec +4 -8
- data/lib/doorkeeper/config.rb +20 -29
- data/lib/doorkeeper/engine.rb +7 -1
- data/lib/doorkeeper/errors.rb +12 -0
- data/lib/doorkeeper/grape/helpers.rb +1 -1
- data/lib/doorkeeper/helpers/controller.rb +6 -0
- data/lib/doorkeeper/models/access_grant_mixin.rb +3 -2
- data/lib/doorkeeper/models/access_token_mixin.rb +12 -4
- data/lib/doorkeeper/models/application_mixin.rb +11 -18
- data/lib/doorkeeper/models/concerns/revocable.rb +2 -2
- data/lib/doorkeeper/oauth/authorization/token.rb +15 -6
- data/lib/doorkeeper/oauth/authorization_code_request.rb +10 -5
- data/lib/doorkeeper/oauth/client.rb +9 -8
- data/lib/doorkeeper/oauth/client_credentials/creator.rb +3 -4
- data/lib/doorkeeper/oauth/error.rb +5 -1
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +1 -1
- data/lib/doorkeeper/oauth/refresh_token_request.rb +17 -7
- data/lib/doorkeeper/orm/active_record/access_grant.rb +2 -2
- data/lib/doorkeeper/orm/active_record/access_token.rb +2 -2
- data/lib/doorkeeper/orm/active_record/application.rb +2 -2
- data/lib/doorkeeper/orm/active_record.rb +22 -0
- data/lib/doorkeeper/rails/helpers.rb +19 -29
- data/lib/doorkeeper/request/authorization_code.rb +10 -15
- data/lib/doorkeeper/request/client_credentials.rb +9 -15
- data/lib/doorkeeper/request/code.rb +7 -13
- data/lib/doorkeeper/request/password.rb +10 -15
- data/lib/doorkeeper/request/refresh_token.rb +11 -13
- data/lib/doorkeeper/request/strategy.rb +17 -0
- data/lib/doorkeeper/request/token.rb +7 -13
- data/lib/doorkeeper/request.rb +18 -8
- data/lib/doorkeeper/server.rb +2 -2
- data/lib/doorkeeper/version.rb +1 -1
- data/lib/doorkeeper.rb +0 -4
- data/lib/generators/doorkeeper/templates/README +0 -20
- data/lib/generators/doorkeeper/templates/initializer.rb +5 -3
- data/lib/generators/doorkeeper/templates/migration.rb +8 -0
- data/spec/controllers/applications_controller_spec.rb +0 -1
- data/spec/controllers/protected_resources_controller_spec.rb +115 -14
- data/spec/controllers/token_info_controller_spec.rb +0 -4
- data/spec/controllers/tokens_controller_spec.rb +34 -3
- data/spec/dummy/app/models/user.rb +2 -24
- data/spec/dummy/config/application.rb +2 -1
- data/spec/dummy/config/initializers/doorkeeper.rb +0 -2
- data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +24 -0
- data/spec/lib/config_spec.rb +20 -4
- data/spec/lib/models/revocable_spec.rb +2 -2
- data/spec/lib/oauth/authorization_code_request_spec.rb +1 -1
- data/spec/lib/oauth/client/credentials_spec.rb +2 -2
- data/spec/lib/oauth/client_credentials/creator_spec.rb +25 -1
- data/spec/lib/oauth/error_response_spec.rb +7 -7
- data/spec/lib/oauth/error_spec.rb +9 -5
- data/spec/lib/oauth/helpers/scope_checker_spec.rb +3 -3
- data/spec/lib/oauth/password_access_token_request_spec.rb +1 -1
- data/spec/lib/oauth/pre_authorization_spec.rb +9 -10
- data/spec/lib/oauth/refresh_token_request_spec.rb +26 -6
- data/spec/lib/oauth/scopes_spec.rb +1 -1
- data/spec/lib/oauth/token_request_spec.rb +6 -3
- data/spec/lib/request/strategy_spec.rb +53 -0
- data/spec/lib/server_spec.rb +4 -2
- data/spec/models/doorkeeper/access_grant_spec.rb +5 -5
- data/spec/models/doorkeeper/access_token_spec.rb +102 -5
- data/spec/models/doorkeeper/application_spec.rb +13 -16
- data/spec/requests/applications/applications_request_spec.rb +1 -1
- data/spec/requests/endpoints/authorization_spec.rb +2 -1
- data/spec/requests/endpoints/token_spec.rb +9 -9
- data/spec/requests/flows/authorization_code_errors_spec.rb +4 -4
- data/spec/requests/flows/authorization_code_spec.rb +36 -2
- data/spec/requests/flows/implicit_grant_spec.rb +14 -5
- data/spec/requests/flows/password_spec.rb +14 -20
- data/spec/requests/flows/refresh_token_spec.rb +15 -7
- data/spec/requests/flows/revoke_token_spec.rb +9 -31
- data/spec/requests/protected_resources/metal_spec.rb +3 -3
- data/spec/requests/protected_resources/private_api_spec.rb +11 -0
- data/spec/routing/custom_controller_routes_spec.rb +1 -2
- data/spec/routing/default_routes_spec.rb +1 -2
- data/spec/routing/scoped_routes_spec.rb +0 -1
- data/spec/spec_helper_integration.rb +10 -7
- data/spec/support/helpers/access_token_request_helper.rb +1 -1
- data/spec/support/helpers/authorization_request_helper.rb +1 -1
- data/spec/support/helpers/config_helper.rb +1 -1
- data/spec/support/helpers/model_helper.rb +1 -1
- data/spec/support/helpers/request_spec_helper.rb +1 -1
- data/spec/support/helpers/url_helper.rb +1 -1
- data/spec/support/shared/models_shared_examples.rb +1 -1
- data/spec/validators/redirect_uri_validator_spec.rb +5 -0
- metadata +127 -98
- data/gemfiles/Gemfile.common.rb +0 -14
- data/gemfiles/Gemfile.mongo_mapper.rb +0 -5
- data/gemfiles/Gemfile.mongoid2.rb +0 -5
- data/gemfiles/Gemfile.mongoid3.rb +0 -4
- data/gemfiles/Gemfile.mongoid4.rb +0 -5
- data/lib/doorkeeper/generators/doorkeeper/mongo_mapper/indexes_generator.rb +0 -12
- data/lib/doorkeeper/generators/doorkeeper/mongo_mapper/templates/indexes.rb +0 -3
- data/lib/doorkeeper/orm/mongo_mapper/access_grant.rb +0 -24
- data/lib/doorkeeper/orm/mongo_mapper/access_token.rb +0 -43
- data/lib/doorkeeper/orm/mongo_mapper/application.rb +0 -29
- data/lib/doorkeeper/orm/mongo_mapper.rb +0 -11
- data/lib/doorkeeper/orm/mongoid2/access_grant.rb +0 -22
- data/lib/doorkeeper/orm/mongoid2/access_token.rb +0 -37
- data/lib/doorkeeper/orm/mongoid2/application.rb +0 -25
- data/lib/doorkeeper/orm/mongoid2/concerns/scopes.rb +0 -30
- data/lib/doorkeeper/orm/mongoid2.rb +0 -11
- data/lib/doorkeeper/orm/mongoid3/access_grant.rb +0 -22
- data/lib/doorkeeper/orm/mongoid3/access_token.rb +0 -37
- data/lib/doorkeeper/orm/mongoid3/application.rb +0 -25
- data/lib/doorkeeper/orm/mongoid3/concerns/scopes.rb +0 -30
- data/lib/doorkeeper/orm/mongoid3.rb +0 -11
- data/lib/doorkeeper/orm/mongoid4/access_grant.rb +0 -22
- data/lib/doorkeeper/orm/mongoid4/access_token.rb +0 -37
- data/lib/doorkeeper/orm/mongoid4/application.rb +0 -25
- data/lib/doorkeeper/orm/mongoid4/concerns/scopes.rb +0 -17
- data/lib/doorkeeper/orm/mongoid4.rb +0 -11
- data/spec/dummy/config/mongo.yml +0 -11
- data/spec/dummy/config/mongoid2.yml +0 -9
- data/spec/dummy/config/mongoid3.yml +0 -18
- data/spec/dummy/config/mongoid4.yml +0 -19
- data/spec/support/orm/mongo_mapper.rb +0 -10
- data/spec/support/orm/mongoid.rb +0 -10
@@ -4,14 +4,14 @@ module Doorkeeper::OAuth
|
|
4
4
|
describe PreAuthorization do
|
5
5
|
let(:server) {
|
6
6
|
server = Doorkeeper.configuration
|
7
|
-
server.
|
8
|
-
server.
|
7
|
+
allow(server).to receive(:default_scopes).and_return(Scopes.new)
|
8
|
+
allow(server).to receive(:scopes).and_return(Scopes.from_string('public profile'))
|
9
9
|
server
|
10
10
|
}
|
11
11
|
|
12
12
|
let(:application) do
|
13
13
|
application = double :application
|
14
|
-
application.
|
14
|
+
allow(application).to receive(:scopes).and_return(Scopes.from_string(''))
|
15
15
|
application
|
16
16
|
end
|
17
17
|
|
@@ -41,7 +41,7 @@ module Doorkeeper::OAuth
|
|
41
41
|
end
|
42
42
|
|
43
43
|
it 'accepts token as response type' do
|
44
|
-
server.
|
44
|
+
allow(server).to receive(:grant_flows).and_return(['implicit'])
|
45
45
|
subject.response_type = 'token'
|
46
46
|
expect(subject).to be_authorizable
|
47
47
|
end
|
@@ -53,7 +53,7 @@ module Doorkeeper::OAuth
|
|
53
53
|
end
|
54
54
|
|
55
55
|
it 'accepts "token" as response type' do
|
56
|
-
server.
|
56
|
+
allow(server).to receive(:grant_flows).and_return(['implicit'])
|
57
57
|
subject.response_type = 'token'
|
58
58
|
expect(subject).to be_authorizable
|
59
59
|
end
|
@@ -61,7 +61,7 @@ module Doorkeeper::OAuth
|
|
61
61
|
|
62
62
|
context 'when authorization code grant flow is disabled' do
|
63
63
|
before do
|
64
|
-
server.
|
64
|
+
allow(server).to receive(:grant_flows).and_return(['implicit'])
|
65
65
|
end
|
66
66
|
|
67
67
|
it 'does not accept "code" as response type' do
|
@@ -72,7 +72,7 @@ module Doorkeeper::OAuth
|
|
72
72
|
|
73
73
|
context 'when implicit grant flow is disabled' do
|
74
74
|
before do
|
75
|
-
server.
|
75
|
+
allow(server).to receive(:grant_flows).and_return(['authorization_code'])
|
76
76
|
end
|
77
77
|
|
78
78
|
it 'does not accept "token" as response type' do
|
@@ -96,7 +96,7 @@ module Doorkeeper::OAuth
|
|
96
96
|
context 'client application restricts valid scopes' do
|
97
97
|
let(:application) do
|
98
98
|
application = double :application
|
99
|
-
application.
|
99
|
+
allow(application).to receive(:scopes).and_return(Scopes.from_string('public nonsense'))
|
100
100
|
application
|
101
101
|
end
|
102
102
|
|
@@ -119,7 +119,7 @@ module Doorkeeper::OAuth
|
|
119
119
|
it 'uses default scopes when none is required' do
|
120
120
|
allow(server).to receive(:default_scopes).and_return(Scopes.from_string('default'))
|
121
121
|
subject.scope = nil
|
122
|
-
expect(subject.scope).to
|
122
|
+
expect(subject.scope).to eq('default')
|
123
123
|
expect(subject.scopes).to eq(Scopes.from_string('default'))
|
124
124
|
end
|
125
125
|
|
@@ -151,6 +151,5 @@ module Doorkeeper::OAuth
|
|
151
151
|
subject.redirect_uri = nil
|
152
152
|
expect(subject).not_to be_authorizable
|
153
153
|
end
|
154
|
-
|
155
154
|
end
|
156
155
|
end
|
@@ -2,10 +2,16 @@ require 'spec_helper_integration'
|
|
2
2
|
|
3
3
|
module Doorkeeper::OAuth
|
4
4
|
describe RefreshTokenRequest do
|
5
|
-
let(:server)
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
let(:server) do
|
6
|
+
double :server,
|
7
|
+
access_token_expires_in: 2.minutes,
|
8
|
+
custom_access_token_expires_in: -> (_oauth_client) { nil }
|
9
|
+
end
|
10
|
+
let(:refresh_token) do
|
11
|
+
FactoryGirl.create(:access_token, use_refresh_token: true)
|
12
|
+
end
|
13
|
+
let(:client) { refresh_token.application }
|
14
|
+
let(:credentials) { Client::Credentials.new(client.uid, client.secret) }
|
9
15
|
|
10
16
|
subject { RefreshTokenRequest.new server, refresh_token, credentials }
|
11
17
|
|
@@ -13,6 +19,17 @@ module Doorkeeper::OAuth
|
|
13
19
|
expect do
|
14
20
|
subject.authorize
|
15
21
|
end.to change { client.access_tokens.count }.by(1)
|
22
|
+
expect(client.reload.access_tokens.last.expires_in).to eq(120)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'issues a new token for the client with custom expires_in' do
|
26
|
+
server = double :server,
|
27
|
+
access_token_expires_in: 2.minutes,
|
28
|
+
custom_access_token_expires_in: ->(_oauth_client) { 1234 }
|
29
|
+
|
30
|
+
RefreshTokenRequest.new(server, refresh_token, credentials).authorize
|
31
|
+
|
32
|
+
expect(client.reload.access_tokens.last.expires_in).to eq(1234)
|
16
33
|
end
|
17
34
|
|
18
35
|
it 'revokes the previous token' do
|
@@ -61,7 +78,11 @@ module Doorkeeper::OAuth
|
|
61
78
|
end
|
62
79
|
|
63
80
|
context 'with scopes' do
|
64
|
-
let
|
81
|
+
let(:refresh_token) do
|
82
|
+
FactoryGirl.create :access_token,
|
83
|
+
use_refresh_token: true,
|
84
|
+
scopes: 'public write'
|
85
|
+
end
|
65
86
|
let(:parameters) { {} }
|
66
87
|
subject { RefreshTokenRequest.new server, refresh_token, credentials, parameters }
|
67
88
|
|
@@ -98,6 +119,5 @@ module Doorkeeper::OAuth
|
|
98
119
|
expect(subject.error).to eq(:invalid_scope)
|
99
120
|
end
|
100
121
|
end
|
101
|
-
|
102
122
|
end
|
103
123
|
end
|
@@ -67,14 +67,14 @@ module Doorkeeper::OAuth
|
|
67
67
|
|
68
68
|
context 'token reuse' do
|
69
69
|
it 'creates a new token if there are no matching tokens' do
|
70
|
-
Doorkeeper.configuration.
|
70
|
+
allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
|
71
71
|
expect do
|
72
72
|
subject.authorize
|
73
73
|
end.to change { Doorkeeper::AccessToken.count }.by(1)
|
74
74
|
end
|
75
75
|
|
76
76
|
it 'creates a new token if scopes do not match' do
|
77
|
-
Doorkeeper.configuration.
|
77
|
+
allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
|
78
78
|
FactoryGirl.create(:access_token, application_id: pre_auth.client.id,
|
79
79
|
resource_owner_id: owner.id, scopes: '')
|
80
80
|
expect do
|
@@ -83,9 +83,12 @@ module Doorkeeper::OAuth
|
|
83
83
|
end
|
84
84
|
|
85
85
|
it 'skips token creation if there is a matching one' do
|
86
|
-
Doorkeeper.configuration.
|
86
|
+
allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
|
87
|
+
allow(application.scopes).to receive(:has_scopes?).and_return(true)
|
88
|
+
allow(application.scopes).to receive(:all?).and_return(true)
|
87
89
|
FactoryGirl.create(:access_token, application_id: pre_auth.client.id,
|
88
90
|
resource_owner_id: owner.id, scopes: 'public')
|
91
|
+
|
89
92
|
expect do
|
90
93
|
subject.authorize
|
91
94
|
end.to_not change { Doorkeeper::AccessToken.count }
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'doorkeeper/request/strategy'
|
3
|
+
|
4
|
+
module Doorkeeper
|
5
|
+
module Request
|
6
|
+
describe Strategy do
|
7
|
+
let(:server) { double }
|
8
|
+
subject(:strategy) { Strategy.new(server) }
|
9
|
+
|
10
|
+
describe :initialize do
|
11
|
+
it "sets the server attribute" do
|
12
|
+
expect(strategy.server).to eq server
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe :request do
|
17
|
+
it "requires an implementation" do
|
18
|
+
expect { strategy.request }.to raise_exception NotImplementedError
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "a sample Strategy subclass" do
|
23
|
+
let(:fake_request) { double }
|
24
|
+
|
25
|
+
let(:strategy_class) do
|
26
|
+
subclass = Class.new(Strategy) do
|
27
|
+
class << self
|
28
|
+
attr_accessor :fake_request
|
29
|
+
end
|
30
|
+
|
31
|
+
def request
|
32
|
+
self.class.fake_request
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
subclass.fake_request = fake_request
|
37
|
+
subclass
|
38
|
+
end
|
39
|
+
|
40
|
+
subject(:strategy) { strategy_class.new(server) }
|
41
|
+
|
42
|
+
it "provides a request implementation" do
|
43
|
+
expect(strategy.request).to eq fake_request
|
44
|
+
end
|
45
|
+
|
46
|
+
it "authorizes the request" do
|
47
|
+
expect(fake_request).to receive :authorize
|
48
|
+
strategy.authorize
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/spec/lib/server_spec.rb
CHANGED
@@ -25,7 +25,9 @@ describe Doorkeeper::Server do
|
|
25
25
|
|
26
26
|
context 'when only Authorization Code strategy is enabled' do
|
27
27
|
before do
|
28
|
-
Doorkeeper.configuration.
|
28
|
+
allow(Doorkeeper.configuration).
|
29
|
+
to receive(:grant_flows).
|
30
|
+
and_return(['authorization_code'])
|
29
31
|
end
|
30
32
|
|
31
33
|
it 'raises error when using the disabled Implicit strategy' do
|
@@ -43,7 +45,7 @@ describe Doorkeeper::Server do
|
|
43
45
|
|
44
46
|
it 'builds the request with selected strategy' do
|
45
47
|
stub_const 'Doorkeeper::Request::Code', fake_class
|
46
|
-
expect(fake_class).to receive(:
|
48
|
+
expect(fake_class).to receive(:new).with(subject)
|
47
49
|
subject.authorization_request :code
|
48
50
|
end
|
49
51
|
end
|
@@ -3,7 +3,7 @@ require 'spec_helper_integration'
|
|
3
3
|
describe Doorkeeper::AccessGrant do
|
4
4
|
subject { FactoryGirl.build(:access_grant) }
|
5
5
|
|
6
|
-
it {
|
6
|
+
it { expect(subject).to be_valid }
|
7
7
|
|
8
8
|
it_behaves_like 'an accessible token'
|
9
9
|
it_behaves_like 'a revocable token'
|
@@ -14,23 +14,23 @@ describe Doorkeeper::AccessGrant do
|
|
14
14
|
describe 'validations' do
|
15
15
|
it 'is invalid without resource_owner_id' do
|
16
16
|
subject.resource_owner_id = nil
|
17
|
-
|
17
|
+
expect(subject).not_to be_valid
|
18
18
|
end
|
19
19
|
|
20
20
|
it 'is invalid without application_id' do
|
21
21
|
subject.application_id = nil
|
22
|
-
|
22
|
+
expect(subject).not_to be_valid
|
23
23
|
end
|
24
24
|
|
25
25
|
it 'is invalid without token' do
|
26
26
|
subject.save
|
27
27
|
subject.token = nil
|
28
|
-
|
28
|
+
expect(subject).not_to be_valid
|
29
29
|
end
|
30
30
|
|
31
31
|
it 'is invalid without expires_in' do
|
32
32
|
subject.expires_in = nil
|
33
|
-
|
33
|
+
expect(subject).not_to be_valid
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
@@ -4,7 +4,7 @@ module Doorkeeper
|
|
4
4
|
describe AccessToken do
|
5
5
|
subject { FactoryGirl.build(:access_token) }
|
6
6
|
|
7
|
-
it {
|
7
|
+
it { expect(subject).to be_valid }
|
8
8
|
|
9
9
|
it_behaves_like 'an accessible token'
|
10
10
|
it_behaves_like 'a revocable token'
|
@@ -12,6 +12,103 @@ module Doorkeeper
|
|
12
12
|
let(:factory_name) { :access_token }
|
13
13
|
end
|
14
14
|
|
15
|
+
describe :generate_token do
|
16
|
+
it 'generates a token using the default method' do
|
17
|
+
FactoryGirl.create :access_token
|
18
|
+
|
19
|
+
token = FactoryGirl.create :access_token
|
20
|
+
expect(token.token).to be_a(String)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'generates a token using a custom object' do
|
24
|
+
module CustomGeneratorArgs
|
25
|
+
def self.generate(opts = {})
|
26
|
+
"custom_generator_token_#{opts[:resource_owner_id]}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
Doorkeeper.configure do
|
31
|
+
orm DOORKEEPER_ORM
|
32
|
+
access_token_generator "Doorkeeper::CustomGeneratorArgs"
|
33
|
+
end
|
34
|
+
|
35
|
+
token = FactoryGirl.create :access_token
|
36
|
+
expect(token.token).to match(%r{custom_generator_token_\d+})
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'allows the custom generator to access the application details' do
|
40
|
+
module CustomGeneratorArgs
|
41
|
+
def self.generate(opts = {})
|
42
|
+
"custom_generator_token_#{opts[:application].name}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
Doorkeeper.configure do
|
47
|
+
orm DOORKEEPER_ORM
|
48
|
+
access_token_generator "Doorkeeper::CustomGeneratorArgs"
|
49
|
+
end
|
50
|
+
|
51
|
+
token = FactoryGirl.create :access_token
|
52
|
+
expect(token.token).to match(%r{custom_generator_token_Application \d+})
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'allows the custom generator to access the scopes' do
|
56
|
+
module CustomGeneratorArgs
|
57
|
+
def self.generate(opts = {})
|
58
|
+
"custom_generator_token_#{opts[:scopes].count}_#{opts[:scopes]}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
Doorkeeper.configure do
|
63
|
+
orm DOORKEEPER_ORM
|
64
|
+
access_token_generator "Doorkeeper::CustomGeneratorArgs"
|
65
|
+
end
|
66
|
+
|
67
|
+
token = FactoryGirl.create :access_token, scopes: 'public write'
|
68
|
+
|
69
|
+
expect(token.token).to eq 'custom_generator_token_2_public write'
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'allows the custom generator to access the expiry length' do
|
73
|
+
module CustomGeneratorArgs
|
74
|
+
def self.generate(opts = {})
|
75
|
+
"custom_generator_token_#{opts[:expires_in]}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
Doorkeeper.configure do
|
80
|
+
orm DOORKEEPER_ORM
|
81
|
+
access_token_generator "Doorkeeper::CustomGeneratorArgs"
|
82
|
+
end
|
83
|
+
|
84
|
+
token = FactoryGirl.create :access_token
|
85
|
+
expect(token.token).to eq 'custom_generator_token_7200'
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'raises an error if the custom object does not support generate' do
|
89
|
+
module NoGenerate
|
90
|
+
end
|
91
|
+
|
92
|
+
Doorkeeper.configure do
|
93
|
+
orm DOORKEEPER_ORM
|
94
|
+
access_token_generator "Doorkeeper::NoGenerate"
|
95
|
+
end
|
96
|
+
|
97
|
+
expect { FactoryGirl.create :access_token }.to(
|
98
|
+
raise_error(Doorkeeper::Errors::UnableToGenerateToken))
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'raises an error if the custom object does not exist' do
|
102
|
+
Doorkeeper.configure do
|
103
|
+
orm DOORKEEPER_ORM
|
104
|
+
access_token_generator "Doorkeeper::NotReal"
|
105
|
+
end
|
106
|
+
|
107
|
+
expect { FactoryGirl.create :access_token }.to(
|
108
|
+
raise_error(Doorkeeper::Errors::TokenGeneratorNotFound))
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
15
112
|
describe :refresh_token do
|
16
113
|
it 'has empty refresh token if it was not required' do
|
17
114
|
token = FactoryGirl.create :access_token
|
@@ -26,7 +123,7 @@ module Doorkeeper
|
|
26
123
|
it 'is not valid if token exists' do
|
27
124
|
token1 = FactoryGirl.create :access_token, use_refresh_token: true
|
28
125
|
token2 = FactoryGirl.create :access_token, use_refresh_token: true
|
29
|
-
token2.
|
126
|
+
token2.refresh_token = token1.refresh_token
|
30
127
|
expect(token2).not_to be_valid
|
31
128
|
end
|
32
129
|
|
@@ -34,9 +131,9 @@ module Doorkeeper
|
|
34
131
|
token1 = FactoryGirl.create :access_token, use_refresh_token: true
|
35
132
|
token2 = FactoryGirl.create :access_token, use_refresh_token: true
|
36
133
|
expect do
|
37
|
-
token2.
|
134
|
+
token2.refresh_token = token1.refresh_token
|
38
135
|
token2.save(validate: false)
|
39
|
-
end.to raise_error
|
136
|
+
end.to raise_error(ActiveRecord::RecordNotUnique)
|
40
137
|
end
|
41
138
|
end
|
42
139
|
|
@@ -44,7 +141,7 @@ module Doorkeeper
|
|
44
141
|
it 'is valid without resource_owner_id' do
|
45
142
|
# For client credentials flow
|
46
143
|
subject.resource_owner_id = nil
|
47
|
-
|
144
|
+
expect(subject).to be_valid
|
48
145
|
end
|
49
146
|
end
|
50
147
|
|
@@ -55,6 +55,12 @@ module Doorkeeper
|
|
55
55
|
expect(new_application.uid).not_to be_nil
|
56
56
|
end
|
57
57
|
|
58
|
+
it 'generates uid on create if an empty string' do
|
59
|
+
new_application.uid = ''
|
60
|
+
new_application.save
|
61
|
+
expect(new_application.uid).not_to be_blank
|
62
|
+
end
|
63
|
+
|
58
64
|
it 'generates uid on create unless one is set' do
|
59
65
|
new_application.uid = uid
|
60
66
|
new_application.save
|
@@ -84,7 +90,7 @@ module Doorkeeper
|
|
84
90
|
app1 = FactoryGirl.create(:application)
|
85
91
|
app2 = FactoryGirl.create(:application)
|
86
92
|
app2.uid = app1.uid
|
87
|
-
expect { app2.save!(validate: false) }.to raise_error
|
93
|
+
expect { app2.save!(validate: false) }.to raise_error(ActiveRecord::RecordNotUnique)
|
88
94
|
end
|
89
95
|
|
90
96
|
it 'generate secret on create' do
|
@@ -93,6 +99,12 @@ module Doorkeeper
|
|
93
99
|
expect(new_application.secret).not_to be_nil
|
94
100
|
end
|
95
101
|
|
102
|
+
it 'generate secret on create if is blank string' do
|
103
|
+
new_application.secret = ''
|
104
|
+
new_application.save
|
105
|
+
expect(new_application.secret).not_to be_blank
|
106
|
+
end
|
107
|
+
|
96
108
|
it 'generate secret on create unless one is set' do
|
97
109
|
new_application.secret = secret
|
98
110
|
new_application.save
|
@@ -171,20 +183,5 @@ module Doorkeeper
|
|
171
183
|
expect(authenticated).to eq(app)
|
172
184
|
end
|
173
185
|
end
|
174
|
-
|
175
|
-
if Doorkeeper.configuration.orm == :active_record
|
176
|
-
describe :scopes do
|
177
|
-
it 'fails on missing column with an upgrade notice' do
|
178
|
-
app = FactoryGirl.build :application
|
179
|
-
no_scopes_app = double(attributes: [])
|
180
|
-
allow(Application).to receive(:new).and_return(no_scopes_app)
|
181
|
-
|
182
|
-
expect { app.scopes }.to raise_error(
|
183
|
-
NameError,
|
184
|
-
/Missing column: `applications.scopes`/
|
185
|
-
)
|
186
|
-
end
|
187
|
-
end
|
188
|
-
end
|
189
186
|
end
|
190
187
|
end
|
@@ -59,7 +59,8 @@ feature 'Authorization endpoint' do
|
|
59
59
|
end
|
60
60
|
|
61
61
|
scenario 'raises exception on forged requests' do
|
62
|
-
|
62
|
+
skip 'TODO: need to add request helpers to this feature spec'
|
63
|
+
allow_any_instance_of(ActionController::Base).to receive(:handle_unverified_request)
|
63
64
|
allowing_forgery_protection do
|
64
65
|
post "/oauth/authorize",
|
65
66
|
client_id: @client.uid,
|
@@ -1,19 +1,19 @@
|
|
1
1
|
require 'spec_helper_integration'
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
describe 'Token endpoint' do
|
4
|
+
before do
|
5
5
|
client_exists
|
6
6
|
authorization_code_exists application: @client, scopes: 'public'
|
7
7
|
end
|
8
8
|
|
9
|
-
|
9
|
+
it 'respond with correct headers' do
|
10
10
|
post token_endpoint_url(code: @authorization.token, client: @client)
|
11
11
|
should_have_header 'Pragma', 'no-cache'
|
12
12
|
should_have_header 'Cache-Control', 'no-store'
|
13
13
|
should_have_header 'Content-Type', 'application/json; charset=utf-8'
|
14
14
|
end
|
15
15
|
|
16
|
-
|
16
|
+
it 'accepts client credentials with basic auth header' do
|
17
17
|
post token_endpoint_url(
|
18
18
|
code: @authorization.token,
|
19
19
|
redirect_uri: @client.redirect_uri
|
@@ -22,14 +22,14 @@ feature 'Token endpoint' do
|
|
22
22
|
should_have_json 'access_token', Doorkeeper::AccessToken.first.token
|
23
23
|
end
|
24
24
|
|
25
|
-
|
25
|
+
it 'returns null for expires_in when a permanent token is set' do
|
26
26
|
config_is_set(:access_token_expires_in, nil)
|
27
27
|
post token_endpoint_url(code: @authorization.token, client: @client)
|
28
28
|
should_have_json 'access_token', Doorkeeper::AccessToken.first.token
|
29
29
|
should_not_have_json 'expires_in'
|
30
30
|
end
|
31
31
|
|
32
|
-
|
32
|
+
it 'returns unsupported_grant_type for invalid grant_type param' do
|
33
33
|
post token_endpoint_url(code: @authorization.token, client: @client, grant_type: 'nothing')
|
34
34
|
|
35
35
|
should_not_have_json 'access_token'
|
@@ -37,7 +37,7 @@ feature 'Token endpoint' do
|
|
37
37
|
should_have_json 'error_description', translated_error_message('unsupported_grant_type')
|
38
38
|
end
|
39
39
|
|
40
|
-
|
40
|
+
it 'returns unsupported_grant_type for disabled grant flows' do
|
41
41
|
config_is_set(:grant_flows, ['implicit'])
|
42
42
|
post token_endpoint_url(code: @authorization.token, client: @client, grant_type: 'authorization_code')
|
43
43
|
|
@@ -46,7 +46,7 @@ feature 'Token endpoint' do
|
|
46
46
|
should_have_json 'error_description', translated_error_message('unsupported_grant_type')
|
47
47
|
end
|
48
48
|
|
49
|
-
|
49
|
+
it 'returns unsupported_grant_type when refresh_token is not in use' do
|
50
50
|
post token_endpoint_url(code: @authorization.token, client: @client, grant_type: 'refresh_token')
|
51
51
|
|
52
52
|
should_not_have_json 'access_token'
|
@@ -54,7 +54,7 @@ feature 'Token endpoint' do
|
|
54
54
|
should_have_json 'error_description', translated_error_message('unsupported_grant_type')
|
55
55
|
end
|
56
56
|
|
57
|
-
|
57
|
+
it 'returns invalid_request if grant_type is missing' do
|
58
58
|
post token_endpoint_url(code: @authorization.token, client: @client, grant_type: '')
|
59
59
|
|
60
60
|
should_not_have_json 'access_token'
|
@@ -34,13 +34,13 @@ feature 'Authorization Code Flow Errors' do
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
-
|
38
|
-
|
37
|
+
describe 'Authorization Code Flow Errors', 'after authorization' do
|
38
|
+
before do
|
39
39
|
client_exists
|
40
40
|
authorization_code_exists application: @client
|
41
41
|
end
|
42
42
|
|
43
|
-
|
43
|
+
it 'returns :invalid_grant error when posting an already revoked grant code' do
|
44
44
|
# First successful request
|
45
45
|
post token_endpoint_url(code: @authorization.token, client: @client)
|
46
46
|
|
@@ -54,7 +54,7 @@ feature 'Authorization Code Flow Errors', 'after authorization' do
|
|
54
54
|
should_have_json 'error_description', translated_error_message('invalid_grant')
|
55
55
|
end
|
56
56
|
|
57
|
-
|
57
|
+
it 'returns :invalid_grant error for invalid grant code' do
|
58
58
|
post token_endpoint_url(code: 'invalid', client: @client)
|
59
59
|
|
60
60
|
access_token_should_not_exist
|
@@ -41,6 +41,8 @@ feature 'Authorization Code Flow' do
|
|
41
41
|
end
|
42
42
|
|
43
43
|
scenario 'resource owner requests an access token with authorization code' do
|
44
|
+
skip 'TODO: need to add request helpers to this feature spec'
|
45
|
+
|
44
46
|
visit authorization_endpoint_url(client: @client)
|
45
47
|
click_on 'Authorize'
|
46
48
|
|
@@ -52,13 +54,13 @@ feature 'Authorization Code Flow' do
|
|
52
54
|
should_not_have_json 'error'
|
53
55
|
|
54
56
|
should_have_json 'access_token', Doorkeeper::AccessToken.first.token
|
55
|
-
should_have_json 'token_type',
|
57
|
+
should_have_json 'token_type', 'bearer'
|
56
58
|
should_have_json_within 'expires_in', Doorkeeper::AccessToken.first.expires_in, 1
|
57
59
|
end
|
58
60
|
|
59
61
|
context 'with scopes' do
|
60
62
|
background do
|
61
|
-
default_scopes_exist
|
63
|
+
default_scopes_exist :public
|
62
64
|
optional_scopes_exist :write
|
63
65
|
end
|
64
66
|
|
@@ -82,6 +84,8 @@ feature 'Authorization Code Flow' do
|
|
82
84
|
end
|
83
85
|
|
84
86
|
scenario 'new access token matches required scopes' do
|
87
|
+
skip 'TODO: need to add request helpers to this feature spec'
|
88
|
+
|
85
89
|
visit authorization_endpoint_url(client: @client, scope: 'public write')
|
86
90
|
click_on 'Authorize'
|
87
91
|
|
@@ -93,6 +97,8 @@ feature 'Authorization Code Flow' do
|
|
93
97
|
end
|
94
98
|
|
95
99
|
scenario 'returns new token if scopes have changed' do
|
100
|
+
skip 'TODO: need to add request helpers to this feature spec'
|
101
|
+
|
96
102
|
client_is_authorized(@client, @resource_owner, scopes: 'public write')
|
97
103
|
visit authorization_endpoint_url(client: @client, scope: 'public')
|
98
104
|
click_on 'Authorize'
|
@@ -106,6 +112,8 @@ feature 'Authorization Code Flow' do
|
|
106
112
|
end
|
107
113
|
|
108
114
|
scenario 'resource owner authorizes the client with extra scopes' do
|
115
|
+
skip 'TODO: need to add request helpers to this feature spec'
|
116
|
+
|
109
117
|
client_is_authorized(@client, @resource_owner, scopes: 'public')
|
110
118
|
visit authorization_endpoint_url(client: @client, scope: 'public write')
|
111
119
|
click_on 'Authorize'
|
@@ -120,3 +128,29 @@ feature 'Authorization Code Flow' do
|
|
120
128
|
end
|
121
129
|
end
|
122
130
|
end
|
131
|
+
|
132
|
+
describe 'Authorization Code Flow' do
|
133
|
+
before do
|
134
|
+
Doorkeeper.configure do
|
135
|
+
orm DOORKEEPER_ORM
|
136
|
+
use_refresh_token
|
137
|
+
end
|
138
|
+
client_exists
|
139
|
+
end
|
140
|
+
|
141
|
+
context 'issuing a refresh token' do
|
142
|
+
before do
|
143
|
+
authorization_code_exists application: @client
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'second of simultaneous client requests get an error for revoked acccess token' do
|
147
|
+
authorization_code = Doorkeeper::AccessGrant.first.token
|
148
|
+
allow_any_instance_of(Doorkeeper::AccessGrant).to receive(:revoked?).and_return(false, true)
|
149
|
+
|
150
|
+
post token_endpoint_url(code: authorization_code, client: @client)
|
151
|
+
|
152
|
+
should_not_have_json 'access_token'
|
153
|
+
should_have_json 'error', 'invalid_grant'
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|