doorkeeper 4.3.2 → 5.0.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +4 -0
  4. data/.travis.yml +2 -0
  5. data/Appraisals +2 -2
  6. data/Gemfile +1 -1
  7. data/NEWS.md +36 -0
  8. data/README.md +85 -3
  9. data/Rakefile +6 -0
  10. data/app/assets/stylesheets/doorkeeper/admin/application.css +2 -2
  11. data/app/controllers/doorkeeper/application_controller.rb +4 -3
  12. data/app/controllers/doorkeeper/application_metal_controller.rb +4 -0
  13. data/app/controllers/doorkeeper/applications_controller.rb +43 -22
  14. data/app/controllers/doorkeeper/authorizations_controller.rb +55 -12
  15. data/app/controllers/doorkeeper/authorized_applications_controller.rb +15 -1
  16. data/app/controllers/doorkeeper/tokens_controller.rb +2 -6
  17. data/app/helpers/doorkeeper/dashboard_helper.rb +7 -7
  18. data/app/validators/redirect_uri_validator.rb +3 -2
  19. data/app/views/doorkeeper/applications/_delete_form.html.erb +3 -1
  20. data/app/views/doorkeeper/applications/_form.html.erb +31 -19
  21. data/app/views/doorkeeper/applications/edit.html.erb +1 -1
  22. data/app/views/doorkeeper/applications/index.html.erb +18 -6
  23. data/app/views/doorkeeper/applications/new.html.erb +1 -1
  24. data/app/views/doorkeeper/applications/show.html.erb +8 -5
  25. data/app/views/doorkeeper/authorizations/error.html.erb +1 -1
  26. data/app/views/doorkeeper/authorizations/new.html.erb +4 -0
  27. data/app/views/layouts/doorkeeper/admin.html.erb +15 -15
  28. data/config/locales/en.yml +15 -1
  29. data/gemfiles/rails_5_2.gemfile +1 -1
  30. data/lib/doorkeeper/config.rb +60 -23
  31. data/lib/doorkeeper/engine.rb +4 -0
  32. data/lib/doorkeeper/errors.rb +2 -5
  33. data/lib/doorkeeper/grape/helpers.rb +1 -1
  34. data/lib/doorkeeper/helpers/controller.rb +7 -2
  35. data/lib/doorkeeper/models/access_grant_mixin.rb +56 -0
  36. data/lib/doorkeeper/models/access_token_mixin.rb +37 -20
  37. data/lib/doorkeeper/models/application_mixin.rb +8 -1
  38. data/lib/doorkeeper/models/concerns/scopes.rb +1 -1
  39. data/lib/doorkeeper/oauth/authorization/code.rb +31 -8
  40. data/lib/doorkeeper/oauth/authorization/context.rb +15 -0
  41. data/lib/doorkeeper/oauth/authorization/token.rb +23 -6
  42. data/lib/doorkeeper/oauth/authorization_code_request.rb +27 -2
  43. data/lib/doorkeeper/oauth/base_request.rb +18 -8
  44. data/lib/doorkeeper/oauth/client/credentials.rb +4 -2
  45. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +6 -1
  46. data/lib/doorkeeper/oauth/client_credentials/validation.rb +4 -2
  47. data/lib/doorkeeper/oauth/error_response.rb +11 -3
  48. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +0 -8
  49. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +1 -0
  50. data/lib/doorkeeper/oauth/password_access_token_request.rb +7 -4
  51. data/lib/doorkeeper/oauth/pre_authorization.rb +45 -13
  52. data/lib/doorkeeper/oauth/refresh_token_request.rb +6 -1
  53. data/lib/doorkeeper/oauth/scopes.rb +1 -1
  54. data/lib/doorkeeper/oauth/token.rb +5 -2
  55. data/lib/doorkeeper/oauth/token_introspection.rb +2 -2
  56. data/lib/doorkeeper/oauth/token_response.rb +4 -2
  57. data/lib/doorkeeper/oauth.rb +13 -0
  58. data/lib/doorkeeper/orm/active_record/application.rb +14 -0
  59. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +26 -0
  60. data/lib/doorkeeper/orm/active_record.rb +2 -0
  61. data/lib/doorkeeper/rails/helpers.rb +2 -4
  62. data/lib/doorkeeper/rails/routes.rb +13 -1
  63. data/lib/doorkeeper/rake/db.rake +40 -0
  64. data/lib/doorkeeper/rake/setup.rake +6 -0
  65. data/lib/doorkeeper/rake.rb +14 -0
  66. data/lib/doorkeeper/request/password.rb +1 -11
  67. data/lib/doorkeeper/request.rb +28 -28
  68. data/lib/doorkeeper/version.rb +5 -4
  69. data/lib/doorkeeper.rb +4 -17
  70. data/lib/generators/doorkeeper/application_owner_generator.rb +23 -18
  71. data/lib/generators/doorkeeper/confidential_applications_generator.rb +32 -0
  72. data/lib/generators/doorkeeper/install_generator.rb +17 -9
  73. data/lib/generators/doorkeeper/migration_generator.rb +23 -18
  74. data/lib/generators/doorkeeper/pkce_generator.rb +32 -0
  75. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +29 -24
  76. data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
  77. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +6 -0
  78. data/lib/generators/doorkeeper/templates/initializer.rb +60 -9
  79. data/lib/generators/doorkeeper/templates/migration.rb.erb +1 -0
  80. data/lib/generators/doorkeeper/views_generator.rb +3 -1
  81. data/spec/controllers/application_metal_controller_spec.rb +50 -0
  82. data/spec/controllers/applications_controller_spec.rb +126 -13
  83. data/spec/controllers/authorizations_controller_spec.rb +250 -15
  84. data/spec/controllers/protected_resources_controller_spec.rb +16 -16
  85. data/spec/controllers/token_info_controller_spec.rb +4 -12
  86. data/spec/controllers/tokens_controller_spec.rb +12 -14
  87. data/spec/dummy/app/assets/config/manifest.js +2 -0
  88. data/spec/dummy/config/environments/test.rb +4 -5
  89. data/spec/dummy/config/initializers/doorkeeper.rb +6 -0
  90. data/spec/dummy/config/initializers/new_framework_defaults.rb +4 -0
  91. data/spec/dummy/config/routes.rb +3 -42
  92. data/spec/dummy/db/migrate/20111122132257_create_users.rb +3 -1
  93. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +3 -1
  94. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +3 -1
  95. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +3 -1
  96. data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +3 -1
  97. data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +6 -0
  98. data/spec/dummy/db/migrate/20180210183654_add_confidential_to_applications.rb +13 -0
  99. data/spec/dummy/db/schema.rb +38 -37
  100. data/spec/generators/application_owner_generator_spec.rb +1 -1
  101. data/spec/generators/confidential_applications_generator_spec.rb +45 -0
  102. data/spec/generators/install_generator_spec.rb +1 -1
  103. data/spec/generators/migration_generator_spec.rb +1 -1
  104. data/spec/generators/pkce_generator_spec.rb +43 -0
  105. data/spec/generators/previous_refresh_token_generator_spec.rb +1 -1
  106. data/spec/generators/views_generator_spec.rb +1 -1
  107. data/spec/grape/grape_integration_spec.rb +1 -1
  108. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +1 -1
  109. data/spec/lib/config_spec.rb +59 -14
  110. data/spec/lib/doorkeeper_spec.rb +1 -126
  111. data/spec/lib/models/expirable_spec.rb +0 -3
  112. data/spec/lib/models/revocable_spec.rb +0 -2
  113. data/spec/lib/models/scopes_spec.rb +0 -4
  114. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -4
  115. data/spec/lib/oauth/authorization_code_request_spec.rb +24 -2
  116. data/spec/lib/oauth/base_request_spec.rb +16 -2
  117. data/spec/lib/oauth/base_response_spec.rb +1 -1
  118. data/spec/lib/oauth/client/credentials_spec.rb +5 -5
  119. data/spec/lib/oauth/client_credentials/creator_spec.rb +5 -1
  120. data/spec/lib/oauth/client_credentials/issuer_spec.rb +26 -7
  121. data/spec/lib/oauth/client_credentials/validation_spec.rb +2 -3
  122. data/spec/lib/oauth/client_credentials_integration_spec.rb +1 -1
  123. data/spec/lib/oauth/client_credentials_request_spec.rb +3 -5
  124. data/spec/lib/oauth/client_spec.rb +0 -3
  125. data/spec/lib/oauth/code_request_spec.rb +4 -2
  126. data/spec/lib/oauth/error_response_spec.rb +0 -3
  127. data/spec/lib/oauth/error_spec.rb +0 -2
  128. data/spec/lib/oauth/forbidden_token_response_spec.rb +1 -4
  129. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -3
  130. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -1
  131. data/spec/lib/oauth/helpers/uri_checker_spec.rb +5 -2
  132. data/spec/lib/oauth/invalid_token_response_spec.rb +1 -4
  133. data/spec/lib/oauth/password_access_token_request_spec.rb +37 -2
  134. data/spec/lib/oauth/pre_authorization_spec.rb +40 -6
  135. data/spec/lib/oauth/refresh_token_request_spec.rb +11 -7
  136. data/spec/lib/oauth/scopes_spec.rb +0 -3
  137. data/spec/lib/oauth/token_request_spec.rb +4 -5
  138. data/spec/lib/oauth/token_response_spec.rb +0 -1
  139. data/spec/lib/oauth/token_spec.rb +37 -14
  140. data/spec/lib/orm/active_record/stale_records_cleaner_spec.rb +79 -0
  141. data/spec/lib/request/strategy_spec.rb +0 -1
  142. data/spec/lib/server_spec.rb +1 -1
  143. data/spec/models/doorkeeper/access_grant_spec.rb +1 -1
  144. data/spec/models/doorkeeper/access_token_spec.rb +50 -16
  145. data/spec/models/doorkeeper/application_spec.rb +51 -6
  146. data/spec/requests/applications/applications_request_spec.rb +89 -1
  147. data/spec/requests/applications/authorized_applications_spec.rb +1 -1
  148. data/spec/requests/endpoints/authorization_spec.rb +1 -1
  149. data/spec/requests/endpoints/token_spec.rb +7 -5
  150. data/spec/requests/flows/authorization_code_errors_spec.rb +1 -1
  151. data/spec/requests/flows/authorization_code_spec.rb +197 -1
  152. data/spec/requests/flows/client_credentials_spec.rb +46 -6
  153. data/spec/requests/flows/implicit_grant_errors_spec.rb +1 -1
  154. data/spec/requests/flows/implicit_grant_spec.rb +38 -11
  155. data/spec/requests/flows/password_spec.rb +120 -23
  156. data/spec/requests/flows/refresh_token_spec.rb +2 -2
  157. data/spec/requests/flows/revoke_token_spec.rb +11 -11
  158. data/spec/requests/flows/skip_authorization_spec.rb +16 -11
  159. data/spec/requests/protected_resources/metal_spec.rb +1 -1
  160. data/spec/requests/protected_resources/private_api_spec.rb +1 -1
  161. data/spec/routing/custom_controller_routes_spec.rb +59 -7
  162. data/spec/routing/default_routes_spec.rb +2 -2
  163. data/spec/routing/scoped_routes_spec.rb +16 -2
  164. data/spec/spec_helper.rb +54 -3
  165. data/spec/spec_helper_integration.rb +2 -74
  166. data/spec/support/doorkeeper_rspec.rb +19 -0
  167. data/spec/support/helpers/authorization_request_helper.rb +4 -4
  168. data/spec/support/helpers/request_spec_helper.rb +2 -2
  169. data/spec/support/helpers/url_helper.rb +7 -3
  170. data/spec/support/http_method_shim.rb +12 -16
  171. data/spec/validators/redirect_uri_validator_spec.rb +7 -1
  172. data/spec/version/version_spec.rb +3 -3
  173. data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
  174. metadata +32 -8
  175. data/spec/controllers/application_metal_controller.rb +0 -10
  176. /data/spec/support/dependencies/{factory_girl.rb → factory_bot.rb} +0 -0
@@ -1,4 +1,4 @@
1
- require 'spec_helper_integration'
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: -> (_oauth_client) { nil }
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: ->(_oauth_client) { 1234 }
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: ->(_oauth_client) { 1234 }
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([:public, :write])
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([:public])
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([:public])
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,7 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'active_support/core_ext/module/delegation'
3
- require 'active_support/core_ext/string'
4
- require 'doorkeeper/oauth/scopes'
5
2
 
6
3
  module Doorkeeper::OAuth
7
4
  describe Scopes do
@@ -1,10 +1,9 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  module Doorkeeper::OAuth
4
4
  describe TokenRequest do
5
5
  let :application do
6
- scopes = double(all: ['public'])
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 |_oauth_client|
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,5 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'doorkeeper/oauth/token_response'
3
2
 
4
3
  module Doorkeeper::OAuth
5
4
  describe TokenResponse do
@@ -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
- ->(request) { return 'token-value' }
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
- it 'calls the finder if token was returned' do
100
- token = ->(_r) { 'token' }
101
- expect(AccessToken).to receive(:by_token).with('token')
102
- Token.authenticate double, token
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
- 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
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
@@ -1,5 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'doorkeeper/request/strategy'
3
2
 
4
3
  module Doorkeeper
5
4
  module Request
@@ -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 composit strategy name' do
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 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  describe Doorkeeper::AccessGrant do
4
4
  subject { FactoryBot.build(:access_grant) }
@@ -1,4 +1,4 @@
1
- require 'spec_helper_integration'
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(opts = {})
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) { FactoryBot.create :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 'matches the application' do
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 'matches the resource owner' do
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 'matches token with fewer scopes' do
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 'matches token with different scopes' do
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 'matches token with more scopes' do
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 'matches application scopes' do
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 'returns the last created token' do
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
- token = FactoryBot.create :access_token, default_attributes
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(token)
434
+ expect(last_token).to eq(matching_token)
402
435
  end
436
+ end
403
437
 
404
- it 'returns as_json hash' do
405
- token = FactoryBot.create :access_token, default_attributes
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 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  module Doorkeeper
4
4
  describe Application do
@@ -49,6 +49,11 @@ module Doorkeeper
49
49
  expect(new_application).not_to be_valid
50
50
  end
51
51
 
52
+ it 'is invalid without determining confidentiality' do
53
+ new_application.confidential = nil
54
+ expect(new_application).not_to be_valid
55
+ end
56
+
52
57
  it 'generates uid on create' do
53
58
  expect(new_application.uid).to be_nil
54
59
  new_application.save
@@ -201,11 +206,51 @@ module Doorkeeper
201
206
  end
202
207
  end
203
208
 
204
- describe :authenticate do
205
- it 'finds the application via uid/secret' do
206
- app = FactoryBot.create :application
207
- authenticated = Application.by_uid_and_secret(app.uid, app.secret)
208
- expect(authenticated).to eq(app)
209
+ describe :by_uid_and_secret do
210
+ context "when application is private/confidential" do
211
+ it "finds the application via uid/secret" do
212
+ app = FactoryBot.create :application
213
+ authenticated = Application.by_uid_and_secret(app.uid, app.secret)
214
+ expect(authenticated).to eq(app)
215
+ end
216
+ context "when secret is wrong" do
217
+ it "should not find the application" do
218
+ app = FactoryBot.create :application
219
+ authenticated = Application.by_uid_and_secret(app.uid, 'bad')
220
+ expect(authenticated).to eq(nil)
221
+ end
222
+ end
223
+ end
224
+
225
+ context "when application is public/non-confidential" do
226
+ context "when secret is blank" do
227
+ it "should find the application" do
228
+ app = FactoryBot.create :application, confidential: false
229
+ authenticated = Application.by_uid_and_secret(app.uid, nil)
230
+ expect(authenticated).to eq(app)
231
+ end
232
+ end
233
+ context "when secret is wrong" do
234
+ it "should not find the application" do
235
+ app = FactoryBot.create :application, confidential: false
236
+ authenticated = Application.by_uid_and_secret(app.uid, 'bad')
237
+ expect(authenticated).to eq(nil)
238
+ end
239
+ end
240
+ end
241
+ end
242
+
243
+ describe :confidential? do
244
+ subject { FactoryBot.create(:application, confidential: confidential).confidential? }
245
+
246
+ context 'when application is private/confidential' do
247
+ let(:confidential) { true }
248
+ it { expect(subject).to eq(true) }
249
+ end
250
+
251
+ context 'when application is public/non-confidential' do
252
+ let(:confidential) { false }
253
+ it { expect(subject).to eq(false) }
209
254
  end
210
255
  end
211
256
  end
@@ -1,4 +1,4 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  feature 'Adding applications' do
4
4
  context 'in application form' do
@@ -20,6 +20,77 @@ feature 'Adding applications' do
20
20
  click_button 'Submit'
21
21
  i_should_see 'Whoops! Check your form for possible errors'
22
22
  end
23
+
24
+ scenario "adding app ignoring bad scope" do
25
+ config_is_set("enforce_configured_scopes", false)
26
+
27
+ fill_in "doorkeeper_application[name]", with: "My Application"
28
+ fill_in "doorkeeper_application[redirect_uri]",
29
+ with: "https://example.com"
30
+ fill_in "doorkeeper_application[scopes]", with: "blahblah"
31
+
32
+ click_button "Submit"
33
+ i_should_see "Application created"
34
+ i_should_see "My Application"
35
+ end
36
+
37
+ scenario "adding app validating bad scope" do
38
+ config_is_set("enforce_configured_scopes", true)
39
+
40
+ fill_in "doorkeeper_application[name]", with: "My Application"
41
+ fill_in "doorkeeper_application[redirect_uri]",
42
+ with: "https://example.com"
43
+ fill_in "doorkeeper_application[scopes]", with: "blahblah"
44
+
45
+ click_button "Submit"
46
+ i_should_see "Whoops! Check your form for possible errors"
47
+ end
48
+
49
+ scenario "adding app validating scope, blank scope is accepted" do
50
+ config_is_set("enforce_configured_scopes", true)
51
+
52
+ fill_in "doorkeeper_application[name]", with: "My Application"
53
+ fill_in "doorkeeper_application[redirect_uri]",
54
+ with: "https://example.com"
55
+ fill_in "doorkeeper_application[scopes]", with: ""
56
+
57
+ click_button "Submit"
58
+ i_should_see "Application created"
59
+ i_should_see "My Application"
60
+ end
61
+
62
+ scenario "adding app validating scope, multiple scopes configured" do
63
+ config_is_set("enforce_configured_scopes", true)
64
+ scopes = Doorkeeper::OAuth::Scopes.from_array(%w(read write admin))
65
+ config_is_set("optional_scopes", scopes)
66
+
67
+ fill_in "doorkeeper_application[name]", with: "My Application"
68
+ fill_in "doorkeeper_application[redirect_uri]",
69
+ with: "https://example.com"
70
+ fill_in "doorkeeper_application[scopes]", with: "read write"
71
+
72
+ click_button "Submit"
73
+ i_should_see "Application created"
74
+ i_should_see "My Application"
75
+ end
76
+
77
+ scenario "adding app validating scope, bad scope with multiple scopes configured" do
78
+ config_is_set("enforce_configured_scopes", true)
79
+ scopes = Doorkeeper::OAuth::Scopes.from_array(%w(read write admin))
80
+ config_is_set("optional_scopes", scopes)
81
+
82
+ fill_in "doorkeeper_application[name]", with: "My Application"
83
+ fill_in "doorkeeper_application[redirect_uri]",
84
+ with: "https://example.com"
85
+ fill_in "doorkeeper_application[scopes]", with: "read blah"
86
+
87
+ click_button "Submit"
88
+ i_should_see "Whoops! Check your form for possible errors"
89
+ i_should_see Regexp.new(
90
+ I18n.t('activerecord.errors.models.doorkeeper/application.attributes.scopes.not_match_configured'),
91
+ true
92
+ )
93
+ end
23
94
  end
24
95
  end
25
96
 
@@ -36,6 +107,23 @@ feature 'Listing applications' do
36
107
  end
37
108
  end
38
109
 
110
+ feature 'Renders assets' do
111
+ scenario 'admin stylesheets' do
112
+ visit '/assets/doorkeeper/admin/application.css'
113
+
114
+ i_should_see 'Bootstrap'
115
+ i_should_see '.doorkeeper-admin'
116
+ end
117
+
118
+ scenario 'application stylesheets' do
119
+ visit '/assets/doorkeeper/application.css'
120
+
121
+ i_should_see 'Bootstrap'
122
+ i_should_see '#oauth-permissions'
123
+ i_should_see '#container'
124
+ end
125
+ end
126
+
39
127
  feature 'Show application' do
40
128
  given :app do
41
129
  FactoryBot.create :application, name: 'Just another oauth app'
@@ -1,4 +1,4 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  feature 'Authorized applications' do
4
4
  background do
@@ -1,4 +1,4 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  feature 'Authorization endpoint' do
4
4
  background do
@@ -1,4 +1,4 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  describe 'Token endpoint' do
4
4
  before do
@@ -21,10 +21,12 @@ describe 'Token endpoint' do
21
21
  end
22
22
 
23
23
  it 'accepts client credentials with basic auth header' do
24
- post token_endpoint_url(
25
- code: @authorization.token,
26
- redirect_uri: @client.redirect_uri
27
- ), {}, 'HTTP_AUTHORIZATION' => basic_auth_header_for_client(@client)
24
+ post token_endpoint_url,
25
+ params: {
26
+ code: @authorization.token,
27
+ redirect_uri: @client.redirect_uri
28
+ },
29
+ headers: { 'HTTP_AUTHORIZATION' => basic_auth_header_for_client(@client) }
28
30
 
29
31
  should_have_json 'access_token', Doorkeeper::AccessToken.first.token
30
32
  end
@@ -1,4 +1,4 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  feature 'Authorization Code Flow Errors' do
4
4
  let(:client_params) { {} }