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.

Files changed (137) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +5 -0
  4. data/.travis.yml +16 -12
  5. data/Appraisals +14 -0
  6. data/CONTRIBUTING.md +2 -0
  7. data/Gemfile +5 -5
  8. data/NEWS.md +83 -2
  9. data/README.md +73 -43
  10. data/RELEASING.md +5 -12
  11. data/Rakefile +1 -1
  12. data/app/controllers/doorkeeper/application_controller.rb +3 -1
  13. data/app/controllers/doorkeeper/application_metal_controller.rb +3 -2
  14. data/app/controllers/doorkeeper/applications_controller.rb +3 -7
  15. data/app/controllers/doorkeeper/authorizations_controller.rb +1 -1
  16. data/app/controllers/doorkeeper/authorized_applications_controller.rb +1 -1
  17. data/app/controllers/doorkeeper/tokens_controller.rb +50 -14
  18. data/app/helpers/doorkeeper/dashboard_helper.rb +13 -11
  19. data/app/views/doorkeeper/applications/_delete_form.html.erb +1 -2
  20. data/app/views/doorkeeper/applications/_form.html.erb +1 -1
  21. data/app/views/doorkeeper/applications/show.html.erb +1 -1
  22. data/app/views/doorkeeper/authorizations/new.html.erb +1 -1
  23. data/app/views/doorkeeper/authorized_applications/_delete_form.html.erb +1 -2
  24. data/app/views/layouts/doorkeeper/admin.html.erb +1 -1
  25. data/config/locales/en.yml +3 -2
  26. data/doorkeeper.gemspec +12 -10
  27. data/gemfiles/rails_4_2.gemfile +11 -0
  28. data/gemfiles/rails_5_0.gemfile +12 -0
  29. data/gemfiles/rails_5_1.gemfile +13 -0
  30. data/lib/doorkeeper/config.rb +73 -16
  31. data/lib/doorkeeper/engine.rb +11 -7
  32. data/lib/doorkeeper/errors.rb +18 -0
  33. data/lib/doorkeeper/grape/helpers.rb +2 -1
  34. data/lib/doorkeeper/helpers/controller.rb +8 -23
  35. data/lib/doorkeeper/models/access_grant_mixin.rb +21 -5
  36. data/lib/doorkeeper/models/access_token_mixin.rb +145 -23
  37. data/lib/doorkeeper/models/application_mixin.rb +21 -9
  38. data/lib/doorkeeper/models/concerns/accessible.rb +4 -0
  39. data/lib/doorkeeper/models/concerns/expirable.rb +10 -2
  40. data/lib/doorkeeper/models/concerns/ownership.rb +6 -1
  41. data/lib/doorkeeper/models/concerns/revocable.rb +37 -2
  42. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +20 -18
  43. data/lib/doorkeeper/oauth/authorization_code_request.rb +1 -4
  44. data/lib/doorkeeper/oauth/{request_concern.rb → base_request.rb} +3 -1
  45. data/lib/doorkeeper/oauth/base_response.rb +29 -0
  46. data/lib/doorkeeper/oauth/client/credentials.rb +17 -6
  47. data/lib/doorkeeper/oauth/client.rb +0 -1
  48. data/lib/doorkeeper/oauth/client_credentials/creator.rb +1 -1
  49. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +3 -2
  50. data/lib/doorkeeper/oauth/client_credentials/validation.rb +1 -1
  51. data/lib/doorkeeper/oauth/client_credentials_request.rb +8 -8
  52. data/lib/doorkeeper/oauth/code_response.rb +16 -16
  53. data/lib/doorkeeper/oauth/error_response.rb +9 -8
  54. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +1 -1
  55. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +2 -1
  56. data/lib/doorkeeper/oauth/invalid_token_response.rb +2 -0
  57. data/lib/doorkeeper/oauth/password_access_token_request.rb +7 -13
  58. data/lib/doorkeeper/oauth/refresh_token_request.rb +22 -14
  59. data/lib/doorkeeper/oauth/scopes.rb +2 -2
  60. data/lib/doorkeeper/oauth/token.rb +20 -21
  61. data/lib/doorkeeper/oauth/token_request.rb +1 -2
  62. data/lib/doorkeeper/oauth/token_response.rb +1 -1
  63. data/lib/doorkeeper/orm/active_record/access_token.rb +25 -0
  64. data/lib/doorkeeper/orm/active_record/application.rb +12 -12
  65. data/lib/doorkeeper/orm/active_record.rb +0 -16
  66. data/lib/doorkeeper/rails/helpers.rb +1 -3
  67. data/lib/doorkeeper/rails/routes/mapper.rb +4 -4
  68. data/lib/doorkeeper/rails/routes/mapping.rb +1 -1
  69. data/lib/doorkeeper/rails/routes.rb +4 -4
  70. data/lib/doorkeeper/request/authorization_code.rb +7 -1
  71. data/lib/doorkeeper/request/password.rb +11 -1
  72. data/lib/doorkeeper/request/refresh_token.rb +1 -1
  73. data/lib/doorkeeper/server.rb +0 -8
  74. data/lib/doorkeeper/version.rb +1 -1
  75. data/lib/doorkeeper.rb +8 -2
  76. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +29 -0
  77. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb +1 -1
  78. data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb +11 -0
  79. data/lib/generators/doorkeeper/templates/initializer.rb +8 -3
  80. data/lib/generators/doorkeeper/templates/migration.rb +23 -5
  81. data/spec/controllers/application_metal_controller.rb +10 -0
  82. data/spec/controllers/authorizations_controller_spec.rb +39 -24
  83. data/spec/controllers/protected_resources_controller_spec.rb +47 -18
  84. data/spec/controllers/tokens_controller_spec.rb +1 -1
  85. data/spec/dummy/app/controllers/full_protected_resources_controller.rb +4 -4
  86. data/spec/dummy/app/controllers/home_controller.rb +1 -1
  87. data/spec/dummy/app/controllers/metal_controller.rb +1 -1
  88. data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +3 -3
  89. data/spec/dummy/app/models/user.rb +0 -4
  90. data/spec/dummy/config/application.rb +2 -36
  91. data/spec/dummy/config/environment.rb +1 -1
  92. data/spec/dummy/config/environments/test.rb +4 -15
  93. data/spec/dummy/config/initializers/active_record_belongs_to_required_by_default.rb +6 -0
  94. data/spec/dummy/config/initializers/doorkeeper.rb +2 -2
  95. data/spec/dummy/db/migrate/{20130902165751_create_doorkeeper_tables.rb → 20151223192035_create_doorkeeper_tables.rb} +24 -5
  96. data/spec/dummy/db/migrate/{20130902175349_add_owner_to_application.rb → 20151223200000_add_owner_to_application.rb} +0 -0
  97. data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +11 -0
  98. data/spec/dummy/db/schema.rb +23 -22
  99. data/spec/factories.rb +3 -1
  100. data/spec/lib/config_spec.rb +19 -2
  101. data/spec/lib/doorkeeper_spec.rb +135 -13
  102. data/spec/lib/models/expirable_spec.rb +0 -1
  103. data/spec/lib/models/revocable_spec.rb +27 -4
  104. data/spec/lib/oauth/authorization/uri_builder_spec.rb +1 -2
  105. data/spec/lib/oauth/authorization_code_request_spec.rb +1 -1
  106. data/spec/lib/oauth/base_request_spec.rb +160 -0
  107. data/spec/lib/oauth/base_response_spec.rb +45 -0
  108. data/spec/lib/oauth/client/credentials_spec.rb +41 -0
  109. data/spec/lib/oauth/code_response_spec.rb +34 -0
  110. data/spec/lib/oauth/error_response_spec.rb +9 -9
  111. data/spec/lib/oauth/invalid_token_response_spec.rb +36 -8
  112. data/spec/lib/oauth/password_access_token_request_spec.rb +5 -5
  113. data/spec/lib/oauth/refresh_token_request_spec.rb +34 -3
  114. data/spec/lib/oauth/scopes_spec.rb +0 -1
  115. data/spec/lib/oauth/token_spec.rb +12 -5
  116. data/spec/lib/server_spec.rb +0 -3
  117. data/spec/models/doorkeeper/access_token_spec.rb +45 -1
  118. data/spec/models/doorkeeper/application_spec.rb +3 -11
  119. data/spec/requests/endpoints/authorization_spec.rb +5 -6
  120. data/spec/requests/flows/authorization_code_errors_spec.rb +11 -1
  121. data/spec/requests/flows/authorization_code_spec.rb +4 -12
  122. data/spec/requests/flows/password_spec.rb +26 -5
  123. data/spec/requests/flows/refresh_token_spec.rb +87 -17
  124. data/spec/requests/flows/revoke_token_spec.rb +100 -86
  125. data/spec/spec_helper.rb +2 -0
  126. data/spec/spec_helper_integration.rb +8 -1
  127. data/spec/support/helpers/model_helper.rb +27 -5
  128. data/spec/support/helpers/request_spec_helper.rb +12 -4
  129. data/spec/support/http_method_shim.rb +38 -0
  130. data/spec/support/shared/controllers_shared_context.rb +13 -4
  131. data/spec/support/shared/models_shared_examples.rb +1 -1
  132. metadata +72 -42
  133. data/lib/doorkeeper/oauth/client/methods.rb +0 -18
  134. data/lib/generators/doorkeeper/application_scopes_generator.rb +0 -34
  135. data/lib/generators/doorkeeper/templates/add_scopes_to_oauth_applications.rb +0 -5
  136. data/spec/dummy/db/migrate/20141209001746_add_scopes_to_oauth_applications.rb +0 -5
  137. 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 '.authenticate_info' do
46
+ describe '.headers' do
47
47
  let(:error_response) { ErrorResponse.new(name: :some_error, state: :some_state) }
48
- subject { error_response.authenticate_info }
48
+ subject { error_response.headers }
49
49
 
50
- it { expect(subject).to include("realm=\"#{error_response.realm}\"") }
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
- describe '.headers' do
56
- subject { ErrorResponse.new(name: :some_error, state: :some_state).headers }
52
+ describe "WWW-Authenticate header" do
53
+ subject { error_response.headers["WWW-Authenticate"] }
57
54
 
58
- it { expect(subject).to include 'WWW-Authenticate' }
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 '#name' do
8
+ describe "#name" do
9
9
  it { expect(subject.name).to eq(:invalid_token) }
10
10
  end
11
11
 
12
- describe '#status' do
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
- it 'revoked' do
18
- response = InvalidTokenResponse.from_access_token double(revoked?: true, expired?: true)
19
- expect(response.description).to include('revoked')
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
- it 'expired' do
23
- response = InvalidTokenResponse.from_access_token double(revoked?: false, expired?: true)
24
- expect(response.description).to include('expired')
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, credentials, owner)
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.credentials = nil
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.credentials = nil
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 do
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
 
@@ -67,7 +67,6 @@ module Doorkeeper::OAuth
67
67
 
68
68
  it 'does not change the existing object' do
69
69
  origin = Scopes.from_string('public')
70
- new_scope = origin + Scopes.from_string('admin')
71
70
  expect(origin.to_s).to eq('public')
72
71
  end
73
72
 
@@ -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, ->(r) {}, method, not_called_method
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
- let(:finder) { double :finder }
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
@@ -1,7 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'active_support/all'
3
- require 'doorkeeper/errors'
4
- require 'doorkeeper/server'
5
2
 
6
3
  describe Doorkeeper::Server do
7
4
  let(:fake_class) { double :fake_class }
@@ -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(ActiveRecord::RecordNotUnique)
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(:user)
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(ActiveRecord::RecordNotUnique)
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
- post "/oauth/authorize",
66
- client_id: @client.uid,
67
- redirect_uri: @client.redirect_uri,
68
- response_type: 'code'
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
- post token_endpoint_url(code: authorization_code, client: @client)
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
- post token_endpoint_url(code: authorization_code, client: @client)
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
- post token_endpoint_url(code: authorization_code, client: @client)
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
- post token_endpoint_url(code: authorization_code, client: @client)
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
- should_have_json 'access_token', token.token
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
- should_have_json 'access_token', token.token
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', token.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