doorkeeper 3.1.0 → 4.2.6
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/.gitignore +5 -0
- data/.travis.yml +16 -12
- data/Appraisals +14 -0
- data/CONTRIBUTING.md +2 -0
- data/Gemfile +5 -5
- data/NEWS.md +83 -2
- data/README.md +73 -43
- data/RELEASING.md +5 -12
- data/Rakefile +1 -1
- data/app/controllers/doorkeeper/application_controller.rb +3 -1
- data/app/controllers/doorkeeper/application_metal_controller.rb +3 -2
- data/app/controllers/doorkeeper/applications_controller.rb +3 -7
- 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 +50 -14
- data/app/helpers/doorkeeper/dashboard_helper.rb +13 -11
- data/app/views/doorkeeper/applications/_delete_form.html.erb +1 -2
- data/app/views/doorkeeper/applications/_form.html.erb +1 -1
- data/app/views/doorkeeper/applications/show.html.erb +1 -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/layouts/doorkeeper/admin.html.erb +1 -1
- data/config/locales/en.yml +3 -2
- data/doorkeeper.gemspec +12 -10
- data/gemfiles/rails_4_2.gemfile +11 -0
- data/gemfiles/rails_5_0.gemfile +12 -0
- data/gemfiles/rails_5_1.gemfile +13 -0
- data/lib/doorkeeper/config.rb +73 -16
- data/lib/doorkeeper/engine.rb +11 -7
- data/lib/doorkeeper/errors.rb +18 -0
- data/lib/doorkeeper/grape/helpers.rb +2 -1
- data/lib/doorkeeper/helpers/controller.rb +8 -23
- data/lib/doorkeeper/models/access_grant_mixin.rb +21 -5
- data/lib/doorkeeper/models/access_token_mixin.rb +145 -23
- data/lib/doorkeeper/models/application_mixin.rb +21 -9
- data/lib/doorkeeper/models/concerns/accessible.rb +4 -0
- data/lib/doorkeeper/models/concerns/expirable.rb +10 -2
- data/lib/doorkeeper/models/concerns/ownership.rb +6 -1
- data/lib/doorkeeper/models/concerns/revocable.rb +37 -2
- data/lib/doorkeeper/oauth/authorization/uri_builder.rb +20 -18
- data/lib/doorkeeper/oauth/authorization_code_request.rb +1 -4
- data/lib/doorkeeper/oauth/{request_concern.rb → base_request.rb} +3 -1
- data/lib/doorkeeper/oauth/base_response.rb +29 -0
- data/lib/doorkeeper/oauth/client/credentials.rb +17 -6
- data/lib/doorkeeper/oauth/client.rb +0 -1
- 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_response.rb +9 -8
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +1 -1
- data/lib/doorkeeper/oauth/helpers/uri_checker.rb +2 -1
- data/lib/doorkeeper/oauth/invalid_token_response.rb +2 -0
- data/lib/doorkeeper/oauth/password_access_token_request.rb +7 -13
- data/lib/doorkeeper/oauth/refresh_token_request.rb +22 -14
- data/lib/doorkeeper/oauth/scopes.rb +2 -2
- data/lib/doorkeeper/oauth/token.rb +20 -21
- 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_token.rb +25 -0
- data/lib/doorkeeper/orm/active_record/application.rb +12 -12
- data/lib/doorkeeper/orm/active_record.rb +0 -16
- data/lib/doorkeeper/rails/helpers.rb +1 -3
- data/lib/doorkeeper/rails/routes/mapper.rb +4 -4
- data/lib/doorkeeper/rails/routes/mapping.rb +1 -1
- data/lib/doorkeeper/rails/routes.rb +4 -4
- data/lib/doorkeeper/request/authorization_code.rb +7 -1
- data/lib/doorkeeper/request/password.rb +11 -1
- data/lib/doorkeeper/request/refresh_token.rb +1 -1
- data/lib/doorkeeper/server.rb +0 -8
- data/lib/doorkeeper/version.rb +1 -1
- data/lib/doorkeeper.rb +8 -2
- data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +29 -0
- data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb +1 -1
- data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb +11 -0
- data/lib/generators/doorkeeper/templates/initializer.rb +8 -3
- data/lib/generators/doorkeeper/templates/migration.rb +23 -5
- data/spec/controllers/application_metal_controller.rb +10 -0
- data/spec/controllers/authorizations_controller_spec.rb +39 -24
- data/spec/controllers/protected_resources_controller_spec.rb +47 -18
- data/spec/controllers/tokens_controller_spec.rb +1 -1
- 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/active_record_belongs_to_required_by_default.rb +6 -0
- data/spec/dummy/config/initializers/doorkeeper.rb +2 -2
- data/spec/dummy/db/migrate/{20130902165751_create_doorkeeper_tables.rb → 20151223192035_create_doorkeeper_tables.rb} +24 -5
- data/spec/dummy/db/migrate/{20130902175349_add_owner_to_application.rb → 20151223200000_add_owner_to_application.rb} +0 -0
- data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +11 -0
- data/spec/dummy/db/schema.rb +23 -22
- data/spec/factories.rb +3 -1
- data/spec/lib/config_spec.rb +19 -2
- 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 +1 -1
- data/spec/lib/oauth/base_request_spec.rb +160 -0
- data/spec/lib/oauth/base_response_spec.rb +45 -0
- data/spec/lib/oauth/client/credentials_spec.rb +41 -0
- data/spec/lib/oauth/code_response_spec.rb +34 -0
- data/spec/lib/oauth/error_response_spec.rb +9 -9
- data/spec/lib/oauth/invalid_token_response_spec.rb +36 -8
- data/spec/lib/oauth/password_access_token_request_spec.rb +5 -5
- data/spec/lib/oauth/refresh_token_request_spec.rb +34 -3
- data/spec/lib/oauth/scopes_spec.rb +0 -1
- data/spec/lib/oauth/token_spec.rb +12 -5
- data/spec/lib/server_spec.rb +0 -3
- data/spec/models/doorkeeper/access_token_spec.rb +45 -1
- data/spec/models/doorkeeper/application_spec.rb +3 -11
- data/spec/requests/endpoints/authorization_spec.rb +5 -6
- data/spec/requests/flows/authorization_code_errors_spec.rb +11 -1
- data/spec/requests/flows/authorization_code_spec.rb +4 -12
- data/spec/requests/flows/password_spec.rb +26 -5
- data/spec/requests/flows/refresh_token_spec.rb +87 -17
- data/spec/requests/flows/revoke_token_spec.rb +100 -86
- data/spec/spec_helper.rb +2 -0
- data/spec/spec_helper_integration.rb +8 -1
- data/spec/support/helpers/model_helper.rb +27 -5
- data/spec/support/helpers/request_spec_helper.rb +12 -4
- data/spec/support/http_method_shim.rb +38 -0
- data/spec/support/shared/controllers_shared_context.rb +13 -4
- data/spec/support/shared/models_shared_examples.rb +1 -1
- metadata +72 -42
- 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/20141209001746_add_scopes_to_oauth_applications.rb +0 -5
- data/spec/lib/oauth/client/methods_spec.rb +0 -54
@@ -43,19 +43,19 @@ module Doorkeeper::OAuth
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
-
describe '.
|
46
|
+
describe '.headers' do
|
47
47
|
let(:error_response) { ErrorResponse.new(name: :some_error, state: :some_state) }
|
48
|
-
subject { error_response.
|
48
|
+
subject { error_response.headers }
|
49
49
|
|
50
|
-
it { expect(subject).to include
|
51
|
-
it { expect(subject).to include("error=\"#{error_response.name}\"") }
|
52
|
-
it { expect(subject).to include("error_description=\"#{error_response.description}\"") }
|
53
|
-
end
|
50
|
+
it { expect(subject).to include 'WWW-Authenticate' }
|
54
51
|
|
55
|
-
|
56
|
-
|
52
|
+
describe "WWW-Authenticate header" do
|
53
|
+
subject { error_response.headers["WWW-Authenticate"] }
|
57
54
|
|
58
|
-
|
55
|
+
it { expect(subject).to include("realm=\"#{error_response.realm}\"") }
|
56
|
+
it { expect(subject).to include("error=\"#{error_response.name}\"") }
|
57
|
+
it { expect(subject).to include("error_description=\"#{error_response.description}\"") }
|
58
|
+
end
|
59
59
|
end
|
60
60
|
end
|
61
61
|
end
|
@@ -5,23 +5,51 @@ require 'doorkeeper/oauth/invalid_token_response'
|
|
5
5
|
|
6
6
|
module Doorkeeper::OAuth
|
7
7
|
describe InvalidTokenResponse do
|
8
|
-
describe
|
8
|
+
describe "#name" do
|
9
9
|
it { expect(subject.name).to eq(:invalid_token) }
|
10
10
|
end
|
11
11
|
|
12
|
-
describe
|
12
|
+
describe "#status" do
|
13
13
|
it { expect(subject.status).to eq(:unauthorized) }
|
14
14
|
end
|
15
15
|
|
16
16
|
describe :from_access_token do
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
let(:response) { InvalidTokenResponse.from_access_token(access_token) }
|
18
|
+
|
19
|
+
context "revoked" do
|
20
|
+
let(:access_token) { double(revoked?: true, expired?: true) }
|
21
|
+
|
22
|
+
it "sets a description" do
|
23
|
+
expect(response.description).to include("revoked")
|
24
|
+
end
|
25
|
+
|
26
|
+
it "sets the reason" do
|
27
|
+
expect(response.reason).to eq(:revoked)
|
28
|
+
end
|
20
29
|
end
|
21
30
|
|
22
|
-
|
23
|
-
|
24
|
-
|
31
|
+
context "expired" do
|
32
|
+
let(:access_token) { double(revoked?: false, expired?: true) }
|
33
|
+
|
34
|
+
it "sets a description" do
|
35
|
+
expect(response.description).to include("expired")
|
36
|
+
end
|
37
|
+
|
38
|
+
it "sets the reason" do
|
39
|
+
expect(response.reason).to eq(:expired)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "unkown" do
|
44
|
+
let(:access_token) { double(revoked?: false, expired?: false) }
|
45
|
+
|
46
|
+
it "sets a description" do
|
47
|
+
expect(response.description).to include("invalid")
|
48
|
+
end
|
49
|
+
|
50
|
+
it "sets the reason" do
|
51
|
+
expect(response.reason).to eq(:unknown)
|
52
|
+
end
|
25
53
|
end
|
26
54
|
end
|
27
55
|
end
|
@@ -11,23 +11,22 @@ module Doorkeeper::OAuth
|
|
11
11
|
custom_access_token_expires_in: ->(_app) { nil }
|
12
12
|
)
|
13
13
|
end
|
14
|
-
let(:credentials) { Client::Credentials.new(client.uid, client.secret) }
|
15
14
|
let(:client) { FactoryGirl.create(:application) }
|
16
15
|
let(:owner) { double :owner, id: 99 }
|
17
16
|
|
18
17
|
subject do
|
19
|
-
PasswordAccessTokenRequest.new(server,
|
18
|
+
PasswordAccessTokenRequest.new(server, client, owner)
|
20
19
|
end
|
21
20
|
|
22
21
|
it 'issues a new token for the client' do
|
23
22
|
expect do
|
24
23
|
subject.authorize
|
25
|
-
end.to change { client.access_tokens.count }.by(1)
|
24
|
+
end.to change { client.reload.access_tokens.count }.by(1)
|
26
25
|
end
|
27
26
|
|
28
27
|
it 'issues a new token without a client' do
|
29
28
|
expect do
|
30
|
-
subject.
|
29
|
+
subject.client = nil
|
31
30
|
subject.authorize
|
32
31
|
end.to change { Doorkeeper::AccessToken.count }.by(1)
|
33
32
|
end
|
@@ -35,6 +34,7 @@ module Doorkeeper::OAuth
|
|
35
34
|
it 'does not issue a new token with an invalid client' do
|
36
35
|
expect do
|
37
36
|
subject.client = nil
|
37
|
+
subject.parameters = { client_id: 'bad_id' }
|
38
38
|
subject.authorize
|
39
39
|
end.to_not change { Doorkeeper::AccessToken.count }
|
40
40
|
|
@@ -48,7 +48,7 @@ module Doorkeeper::OAuth
|
|
48
48
|
end
|
49
49
|
|
50
50
|
it 'optionally accepts the client' do
|
51
|
-
subject.
|
51
|
+
subject.client = nil
|
52
52
|
expect(subject).to be_valid
|
53
53
|
end
|
54
54
|
|
@@ -2,6 +2,9 @@ require 'spec_helper_integration'
|
|
2
2
|
|
3
3
|
module Doorkeeper::OAuth
|
4
4
|
describe RefreshTokenRequest do
|
5
|
+
before do
|
6
|
+
allow(Doorkeeper::AccessToken).to receive(:refresh_token_revoked_on_use?).and_return(false)
|
7
|
+
end
|
5
8
|
let(:server) do
|
6
9
|
double :server,
|
7
10
|
access_token_expires_in: 2.minutes,
|
@@ -16,9 +19,7 @@ module Doorkeeper::OAuth
|
|
16
19
|
subject { RefreshTokenRequest.new server, refresh_token, credentials }
|
17
20
|
|
18
21
|
it 'issues a new token for the client' do
|
19
|
-
expect
|
20
|
-
subject.authorize
|
21
|
-
end.to change { client.access_tokens.count }.by(1)
|
22
|
+
expect { subject.authorize }.to change { client.reload.access_tokens.count }.by(1)
|
22
23
|
expect(client.reload.access_tokens.last.expires_in).to eq(120)
|
23
24
|
end
|
24
25
|
|
@@ -27,6 +28,8 @@ module Doorkeeper::OAuth
|
|
27
28
|
access_token_expires_in: 2.minutes,
|
28
29
|
custom_access_token_expires_in: ->(_oauth_client) { 1234 }
|
29
30
|
|
31
|
+
allow(Doorkeeper::AccessToken).to receive(:refresh_token_revoked_on_use?).and_return(false)
|
32
|
+
|
30
33
|
RefreshTokenRequest.new(server, refresh_token, credentials).authorize
|
31
34
|
|
32
35
|
expect(client.reload.access_tokens.last.expires_in).to eq(1234)
|
@@ -67,6 +70,34 @@ module Doorkeeper::OAuth
|
|
67
70
|
expect(subject).to be_valid
|
68
71
|
end
|
69
72
|
|
73
|
+
context 'refresh tokens expire on access token use' do
|
74
|
+
let(:server) do
|
75
|
+
double :server,
|
76
|
+
access_token_expires_in: 2.minutes,
|
77
|
+
custom_access_token_expires_in: ->(_oauth_client) { 1234 }
|
78
|
+
end
|
79
|
+
|
80
|
+
before do
|
81
|
+
allow(Doorkeeper::AccessToken).to receive(:refresh_token_revoked_on_use?).and_return(true)
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'issues a new token for the client' do
|
85
|
+
expect { subject.authorize }.to change { client.reload.access_tokens.count }.by(1)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'does not revoke the previous token' do
|
89
|
+
subject.authorize
|
90
|
+
expect(refresh_token).not_to be_revoked
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'sets the previous refresh token in the new access token' do
|
94
|
+
subject.authorize
|
95
|
+
expect(
|
96
|
+
client.access_tokens.last.previous_refresh_token
|
97
|
+
).to eq(refresh_token.refresh_token)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
70
101
|
context 'clientless access tokens' do
|
71
102
|
let!(:refresh_token) { FactoryGirl.create(:clientless_access_token, use_refresh_token: true) }
|
72
103
|
|
@@ -30,7 +30,7 @@ module Doorkeeper
|
|
30
30
|
it 'stops at the first credentials found' do
|
31
31
|
not_called_method = double
|
32
32
|
expect(not_called_method).not_to receive(:call)
|
33
|
-
Token.from_request request, ->(
|
33
|
+
Token.from_request request, ->(_r) {}, method, not_called_method
|
34
34
|
end
|
35
35
|
|
36
36
|
it 'returns the credential from extractor method' do
|
@@ -96,13 +96,20 @@ module Doorkeeper
|
|
96
96
|
end
|
97
97
|
|
98
98
|
describe :authenticate do
|
99
|
-
|
100
|
-
|
101
|
-
it 'calls the finder if token was found' do
|
102
|
-
token = ->(r) { 'token' }
|
99
|
+
it 'calls the finder if token was returned' do
|
100
|
+
token = ->(_r) { 'token' }
|
103
101
|
expect(AccessToken).to receive(:by_token).with('token')
|
104
102
|
Token.authenticate double, token
|
105
103
|
end
|
104
|
+
|
105
|
+
it 'revokes previous refresh_token if token was found' do
|
106
|
+
token = ->(_r) { 'token' }
|
107
|
+
expect(
|
108
|
+
AccessToken
|
109
|
+
).to receive(:by_token).with('token').and_return(token)
|
110
|
+
expect(token).to receive(:revoke_previous_refresh_token!)
|
111
|
+
Token.authenticate double, token
|
112
|
+
end
|
106
113
|
end
|
107
114
|
end
|
108
115
|
end
|
data/spec/lib/server_spec.rb
CHANGED
@@ -12,6 +12,11 @@ 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
|
FactoryGirl.create :access_token
|
@@ -21,6 +26,10 @@ module Doorkeeper
|
|
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]}"
|
@@ -37,6 +46,10 @@ module Doorkeeper
|
|
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}"
|
@@ -53,6 +66,10 @@ module Doorkeeper
|
|
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]}"
|
@@ -70,6 +87,10 @@ module Doorkeeper
|
|
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]}"
|
@@ -85,6 +106,23 @@ module Doorkeeper
|
|
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 = FactoryGirl.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
|
@@ -133,7 +171,7 @@ module Doorkeeper
|
|
133
171
|
expect do
|
134
172
|
token2.refresh_token = token1.refresh_token
|
135
173
|
token2.save(validate: false)
|
136
|
-
end.to raise_error(
|
174
|
+
end.to raise_error(uniqueness_error)
|
137
175
|
end
|
138
176
|
end
|
139
177
|
|
@@ -143,6 +181,12 @@ module Doorkeeper
|
|
143
181
|
subject.resource_owner_id = nil
|
144
182
|
expect(subject).to be_valid
|
145
183
|
end
|
184
|
+
|
185
|
+
it 'is valid without application_id' do
|
186
|
+
# For resource owner credentials flow
|
187
|
+
subject.application_id = nil
|
188
|
+
expect(subject).to be_valid
|
189
|
+
end
|
146
190
|
end
|
147
191
|
|
148
192
|
describe '#same_credential?' do
|
@@ -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 = FactoryGirl.build_stubbed(:
|
33
|
+
@owner = FactoryGirl.build_stubbed(:doorkeeper_testing_user)
|
34
34
|
end
|
35
35
|
|
36
36
|
it 'is invalid without an owner' do
|
@@ -90,7 +90,7 @@ module Doorkeeper
|
|
90
90
|
app1 = FactoryGirl.create(:application)
|
91
91
|
app2 = FactoryGirl.create(:application)
|
92
92
|
app2.uid = app1.uid
|
93
|
-
expect { app2.save!(validate: false) }.to raise_error(
|
93
|
+
expect { app2.save!(validate: false) }.to raise_error(uniqueness_error)
|
94
94
|
end
|
95
95
|
|
96
96
|
it 'generate secret on create' do
|
@@ -129,7 +129,7 @@ module Doorkeeper
|
|
129
129
|
|
130
130
|
it 'should destroy its access tokens' do
|
131
131
|
FactoryGirl.create(:access_token, application: new_application)
|
132
|
-
FactoryGirl.create(:access_token, application: new_application, revoked_at: Time.now)
|
132
|
+
FactoryGirl.create(:access_token, application: new_application, revoked_at: Time.now.utc)
|
133
133
|
expect do
|
134
134
|
new_application.destroy
|
135
135
|
end.to change { Doorkeeper::AccessToken.count }.by(-2)
|
@@ -166,14 +166,6 @@ module Doorkeeper
|
|
166
166
|
FactoryGirl.create(:access_token, resource_owner_id: resource_owner.id, application: application)
|
167
167
|
expect(Application.authorized_for(resource_owner)).to eq([application])
|
168
168
|
end
|
169
|
-
|
170
|
-
it 'should fail to mass assign a new application', if: ::Rails::VERSION::MAJOR < 4 do
|
171
|
-
mass_assign = { name: 'Something',
|
172
|
-
redirect_uri: 'http://somewhere.com/something',
|
173
|
-
uid: 123,
|
174
|
-
secret: 'something' }
|
175
|
-
expect(Application.create(mass_assign).uid).not_to eq(123)
|
176
|
-
end
|
177
169
|
end
|
178
170
|
|
179
171
|
describe :authenticate do
|
@@ -59,13 +59,12 @@ feature 'Authorization endpoint' do
|
|
59
59
|
end
|
60
60
|
|
61
61
|
scenario 'raises exception on forged requests' do
|
62
|
-
skip 'TODO: need to add request helpers to this feature spec'
|
63
|
-
allow_any_instance_of(ActionController::Base).to receive(:handle_unverified_request)
|
64
62
|
allowing_forgery_protection do
|
65
|
-
|
66
|
-
client_id:
|
67
|
-
|
68
|
-
|
63
|
+
expect {
|
64
|
+
page.driver.post authorization_endpoint_url(client_id: @client.uid,
|
65
|
+
redirect_uri: @client.redirect_uri,
|
66
|
+
response_type: 'code')
|
67
|
+
}.to raise_error(ActionController::InvalidAuthenticityToken)
|
69
68
|
end
|
70
69
|
end
|
71
70
|
end
|
@@ -1,9 +1,10 @@
|
|
1
1
|
require 'spec_helper_integration'
|
2
2
|
|
3
3
|
feature 'Authorization Code Flow Errors' do
|
4
|
+
let(:client_params) { {} }
|
4
5
|
background do
|
5
6
|
config_is_set(:authenticate_resource_owner) { User.first || redirect_to('/sign_in') }
|
6
|
-
client_exists
|
7
|
+
client_exists client_params
|
7
8
|
create_resource_owner
|
8
9
|
sign_in
|
9
10
|
end
|
@@ -12,6 +13,15 @@ feature 'Authorization Code Flow Errors' do
|
|
12
13
|
access_grant_should_not_exist
|
13
14
|
end
|
14
15
|
|
16
|
+
context "with a client trying to xss resource owner" do
|
17
|
+
let(:client_name) { "<div id='xss'>XSS</div>" }
|
18
|
+
let(:client_params) { { name: client_name } }
|
19
|
+
scenario "resource owner visit authorization endpoint" do
|
20
|
+
visit authorization_endpoint_url(client: @client)
|
21
|
+
expect(page).not_to have_css("#xss")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
15
25
|
context 'when access was denied' do
|
16
26
|
scenario 'redirects with error' do
|
17
27
|
visit authorization_endpoint_url(client: @client)
|
@@ -41,13 +41,11 @@ 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
|
-
|
46
44
|
visit authorization_endpoint_url(client: @client)
|
47
45
|
click_on 'Authorize'
|
48
46
|
|
49
47
|
authorization_code = Doorkeeper::AccessGrant.first.token
|
50
|
-
|
48
|
+
create_access_token authorization_code, @client
|
51
49
|
|
52
50
|
access_token_should_exist_for(@client, @resource_owner)
|
53
51
|
|
@@ -84,27 +82,23 @@ feature 'Authorization Code Flow' do
|
|
84
82
|
end
|
85
83
|
|
86
84
|
scenario 'new access token matches required scopes' do
|
87
|
-
skip 'TODO: need to add request helpers to this feature spec'
|
88
|
-
|
89
85
|
visit authorization_endpoint_url(client: @client, scope: 'public write')
|
90
86
|
click_on 'Authorize'
|
91
87
|
|
92
88
|
authorization_code = Doorkeeper::AccessGrant.first.token
|
93
|
-
|
89
|
+
create_access_token authorization_code, @client
|
94
90
|
|
95
91
|
access_token_should_exist_for(@client, @resource_owner)
|
96
92
|
access_token_should_have_scopes :public, :write
|
97
93
|
end
|
98
94
|
|
99
95
|
scenario 'returns new token if scopes have changed' do
|
100
|
-
skip 'TODO: need to add request helpers to this feature spec'
|
101
|
-
|
102
96
|
client_is_authorized(@client, @resource_owner, scopes: 'public write')
|
103
97
|
visit authorization_endpoint_url(client: @client, scope: 'public')
|
104
98
|
click_on 'Authorize'
|
105
99
|
|
106
100
|
authorization_code = Doorkeeper::AccessGrant.first.token
|
107
|
-
|
101
|
+
create_access_token authorization_code, @client
|
108
102
|
|
109
103
|
expect(Doorkeeper::AccessToken.count).to be(2)
|
110
104
|
|
@@ -112,14 +106,12 @@ feature 'Authorization Code Flow' do
|
|
112
106
|
end
|
113
107
|
|
114
108
|
scenario 'resource owner authorizes the client with extra scopes' do
|
115
|
-
skip 'TODO: need to add request helpers to this feature spec'
|
116
|
-
|
117
109
|
client_is_authorized(@client, @resource_owner, scopes: 'public')
|
118
110
|
visit authorization_endpoint_url(client: @client, scope: 'public write')
|
119
111
|
click_on 'Authorize'
|
120
112
|
|
121
113
|
authorization_code = Doorkeeper::AccessGrant.first.token
|
122
|
-
|
114
|
+
create_access_token authorization_code, @client
|
123
115
|
|
124
116
|
expect(Doorkeeper::AccessToken.count).to be(2)
|
125
117
|
|
@@ -24,14 +24,26 @@ describe 'Resource Owner Password Credentials Flow' do
|
|
24
24
|
end
|
25
25
|
|
26
26
|
context 'with valid user credentials' do
|
27
|
-
it 'should issue new token' do
|
27
|
+
it 'should issue new token with confidential client' do
|
28
28
|
expect do
|
29
29
|
post password_token_endpoint_url(client: @client, resource_owner: @resource_owner)
|
30
30
|
end.to change { Doorkeeper::AccessToken.count }.by(1)
|
31
31
|
|
32
32
|
token = Doorkeeper::AccessToken.first
|
33
33
|
|
34
|
-
|
34
|
+
expect(token.application_id).to eq @client.id
|
35
|
+
should_have_json 'access_token', token.token
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should issue new token with public client (only client_id present)' do
|
39
|
+
expect do
|
40
|
+
post password_token_endpoint_url(client_id: @client.uid, resource_owner: @resource_owner)
|
41
|
+
end.to change { Doorkeeper::AccessToken.count }.by(1)
|
42
|
+
|
43
|
+
token = Doorkeeper::AccessToken.first
|
44
|
+
|
45
|
+
expect(token.application_id).to eq @client.id
|
46
|
+
should_have_json 'access_token', token.token
|
35
47
|
end
|
36
48
|
|
37
49
|
it 'should issue new token without client credentials' do
|
@@ -41,7 +53,8 @@ describe 'Resource Owner Password Credentials Flow' do
|
|
41
53
|
|
42
54
|
token = Doorkeeper::AccessToken.first
|
43
55
|
|
44
|
-
|
56
|
+
expect(token.application_id).to be_nil
|
57
|
+
should_have_json 'access_token', token.token
|
45
58
|
end
|
46
59
|
|
47
60
|
it 'should issue a refresh token if enabled' do
|
@@ -51,7 +64,7 @@ describe 'Resource Owner Password Credentials Flow' do
|
|
51
64
|
|
52
65
|
token = Doorkeeper::AccessToken.first
|
53
66
|
|
54
|
-
should_have_json 'refresh_token',
|
67
|
+
should_have_json 'refresh_token', token.refresh_token
|
55
68
|
end
|
56
69
|
|
57
70
|
it 'should return the same token if it is still accessible' do
|
@@ -82,7 +95,7 @@ describe 'Resource Owner Password Credentials Flow' do
|
|
82
95
|
end
|
83
96
|
end
|
84
97
|
|
85
|
-
context 'with invalid client credentials' do
|
98
|
+
context 'with invalid confidential client credentials' do
|
86
99
|
it 'should not issue new token with bad client credentials' do
|
87
100
|
expect do
|
88
101
|
post password_token_endpoint_url(client_id: @client.uid,
|
@@ -91,4 +104,12 @@ describe 'Resource Owner Password Credentials Flow' do
|
|
91
104
|
end.to_not change { Doorkeeper::AccessToken.count }
|
92
105
|
end
|
93
106
|
end
|
107
|
+
|
108
|
+
context 'with invalid public client id' do
|
109
|
+
it 'should not issue new token with bad client id' do
|
110
|
+
expect do
|
111
|
+
post password_token_endpoint_url(client_id: 'bad_id', resource_owner: @resource_owner)
|
112
|
+
end.to_not change { Doorkeeper::AccessToken.count }
|
113
|
+
end
|
114
|
+
end
|
94
115
|
end
|