doorkeeper 5.0.2 → 5.1.0

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 (214) hide show
  1. checksums.yaml +5 -5
  2. data/.hound.yml +2 -1
  3. data/.rubocop.yml +37 -4
  4. data/.travis.yml +11 -21
  5. data/Appraisals +29 -7
  6. data/Dangerfile +5 -2
  7. data/Gemfile +19 -5
  8. data/NEWS.md +80 -19
  9. data/README.md +75 -485
  10. data/Rakefile +10 -8
  11. data/app/controllers/doorkeeper/application_controller.rb +1 -2
  12. data/app/controllers/doorkeeper/application_metal_controller.rb +2 -13
  13. data/app/controllers/doorkeeper/applications_controller.rb +17 -5
  14. data/app/controllers/doorkeeper/token_info_controller.rb +2 -2
  15. data/app/controllers/doorkeeper/tokens_controller.rb +11 -11
  16. data/app/helpers/doorkeeper/dashboard_helper.rb +1 -1
  17. data/app/validators/redirect_uri_validator.rb +5 -2
  18. data/app/views/doorkeeper/applications/_form.html.erb +6 -0
  19. data/app/views/doorkeeper/applications/show.html.erb +1 -1
  20. data/app/views/layouts/doorkeeper/admin.html.erb +5 -3
  21. data/bin/console +16 -0
  22. data/config/locales/en.yml +1 -0
  23. data/doorkeeper.gemspec +24 -21
  24. data/gemfiles/rails_5_0.gemfile +9 -4
  25. data/gemfiles/rails_5_1.gemfile +9 -4
  26. data/gemfiles/rails_5_2.gemfile +10 -5
  27. data/gemfiles/rails_6_0.gemfile +17 -0
  28. data/gemfiles/rails_master.gemfile +9 -9
  29. data/lib/doorkeeper/config/option.rb +64 -0
  30. data/lib/doorkeeper/config.rb +191 -75
  31. data/lib/doorkeeper/engine.rb +1 -1
  32. data/lib/doorkeeper/grape/authorization_decorator.rb +4 -4
  33. data/lib/doorkeeper/grape/helpers.rb +3 -3
  34. data/lib/doorkeeper/helpers/controller.rb +3 -2
  35. data/lib/doorkeeper/models/access_grant_mixin.rb +20 -3
  36. data/lib/doorkeeper/models/access_token_mixin.rb +63 -19
  37. data/lib/doorkeeper/models/application_mixin.rb +43 -1
  38. data/lib/doorkeeper/models/concerns/expirable.rb +4 -2
  39. data/lib/doorkeeper/models/concerns/ownership.rb +1 -6
  40. data/lib/doorkeeper/models/concerns/reusable.rb +19 -0
  41. data/lib/doorkeeper/models/concerns/revocable.rb +2 -1
  42. data/lib/doorkeeper/models/concerns/scopes.rb +5 -1
  43. data/lib/doorkeeper/models/concerns/secret_storable.rb +108 -0
  44. data/lib/doorkeeper/oauth/authorization/code.rb +2 -2
  45. data/lib/doorkeeper/oauth/authorization/token.rb +12 -7
  46. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +1 -1
  47. data/lib/doorkeeper/oauth/authorization_code_request.rb +6 -4
  48. data/lib/doorkeeper/oauth/client.rb +1 -1
  49. data/lib/doorkeeper/oauth/client_credentials/validation.rb +5 -4
  50. data/lib/doorkeeper/oauth/client_credentials_request.rb +1 -1
  51. data/lib/doorkeeper/oauth/code_response.rb +2 -2
  52. data/lib/doorkeeper/oauth/error_response.rb +10 -6
  53. data/lib/doorkeeper/oauth/forbidden_token_response.rb +1 -1
  54. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +23 -8
  55. data/lib/doorkeeper/oauth/helpers/unique_token.rb +13 -1
  56. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +37 -1
  57. data/lib/doorkeeper/oauth/invalid_token_response.rb +5 -1
  58. data/lib/doorkeeper/oauth/password_access_token_request.rb +7 -2
  59. data/lib/doorkeeper/oauth/pre_authorization.rb +11 -5
  60. data/lib/doorkeeper/oauth/refresh_token_request.rb +5 -2
  61. data/lib/doorkeeper/oauth/scopes.rb +5 -3
  62. data/lib/doorkeeper/oauth/token.rb +2 -2
  63. data/lib/doorkeeper/oauth/token_introspection.rb +74 -8
  64. data/lib/doorkeeper/oauth/token_response.rb +9 -9
  65. data/lib/doorkeeper/oauth.rb +5 -5
  66. data/lib/doorkeeper/orm/active_record/access_grant.rb +27 -13
  67. data/lib/doorkeeper/orm/active_record/access_token.rb +6 -13
  68. data/lib/doorkeeper/orm/active_record/application.rb +26 -7
  69. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +10 -3
  70. data/lib/doorkeeper/orm/active_record.rb +6 -6
  71. data/lib/doorkeeper/rails/helpers.rb +1 -1
  72. data/lib/doorkeeper/rails/routes/mapping.rb +7 -7
  73. data/lib/doorkeeper/rails/routes.rb +11 -11
  74. data/lib/doorkeeper/rake/db.rake +13 -13
  75. data/lib/doorkeeper/rake.rb +1 -1
  76. data/lib/doorkeeper/request.rb +1 -1
  77. data/lib/doorkeeper/secret_storing/base.rb +64 -0
  78. data/lib/doorkeeper/secret_storing/bcrypt.rb +60 -0
  79. data/lib/doorkeeper/secret_storing/plain.rb +33 -0
  80. data/lib/doorkeeper/secret_storing/sha256_hash.rb +26 -0
  81. data/lib/doorkeeper/stale_records_cleaner.rb +1 -1
  82. data/lib/doorkeeper/version.rb +3 -3
  83. data/lib/doorkeeper.rb +69 -60
  84. data/lib/generators/doorkeeper/application_owner_generator.rb +10 -9
  85. data/lib/generators/doorkeeper/confidential_applications_generator.rb +10 -9
  86. data/lib/generators/doorkeeper/install_generator.rb +11 -9
  87. data/lib/generators/doorkeeper/migration_generator.rb +9 -9
  88. data/lib/generators/doorkeeper/pkce_generator.rb +10 -9
  89. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +10 -9
  90. data/lib/generators/doorkeeper/templates/initializer.rb +120 -13
  91. data/lib/generators/doorkeeper/templates/migration.rb.erb +15 -7
  92. data/lib/generators/doorkeeper/views_generator.rb +6 -4
  93. data/spec/controllers/application_metal_controller_spec.rb +24 -10
  94. data/spec/controllers/applications_controller_spec.rb +54 -52
  95. data/spec/controllers/authorizations_controller_spec.rb +139 -145
  96. data/spec/controllers/protected_resources_controller_spec.rb +78 -76
  97. data/spec/controllers/token_info_controller_spec.rb +14 -12
  98. data/spec/controllers/tokens_controller_spec.rb +167 -108
  99. data/spec/dummy/Rakefile +3 -1
  100. data/spec/dummy/app/controllers/application_controller.rb +3 -1
  101. data/spec/dummy/app/controllers/custom_authorizations_controller.rb +2 -0
  102. data/spec/dummy/app/controllers/full_protected_resources_controller.rb +4 -2
  103. data/spec/dummy/app/controllers/home_controller.rb +5 -3
  104. data/spec/dummy/app/controllers/metal_controller.rb +2 -0
  105. data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +4 -2
  106. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  107. data/spec/dummy/app/models/user.rb +2 -0
  108. data/spec/dummy/config/application.rb +25 -1
  109. data/spec/dummy/config/environments/development.rb +2 -0
  110. data/spec/dummy/config/environments/production.rb +2 -0
  111. data/spec/dummy/config/environments/test.rb +3 -1
  112. data/spec/dummy/config/initializers/backtrace_silencers.rb +2 -0
  113. data/spec/dummy/config/initializers/doorkeeper.rb +5 -2
  114. data/spec/dummy/config/initializers/secret_token.rb +3 -1
  115. data/spec/dummy/config/initializers/session_store.rb +3 -1
  116. data/spec/dummy/config/initializers/wrap_parameters.rb +2 -0
  117. data/spec/dummy/config.ru +3 -1
  118. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +17 -10
  119. data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +2 -0
  120. data/spec/dummy/db/schema.rb +1 -1
  121. data/spec/dummy/script/rails +5 -3
  122. data/spec/factories.rb +8 -6
  123. data/spec/generators/application_owner_generator_spec.rb +13 -26
  124. data/spec/generators/confidential_applications_generator_spec.rb +12 -28
  125. data/spec/generators/install_generator_spec.rb +17 -15
  126. data/spec/generators/migration_generator_spec.rb +13 -26
  127. data/spec/generators/pkce_generator_spec.rb +11 -26
  128. data/spec/generators/previous_refresh_token_generator_spec.rb +16 -29
  129. data/spec/generators/templates/routes.rb +2 -0
  130. data/spec/generators/views_generator_spec.rb +14 -12
  131. data/spec/grape/grape_integration_spec.rb +34 -32
  132. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +9 -7
  133. data/spec/lib/config_spec.rb +268 -99
  134. data/spec/lib/doorkeeper_spec.rb +3 -1
  135. data/spec/lib/models/expirable_spec.rb +22 -8
  136. data/spec/lib/models/reusable_spec.rb +40 -0
  137. data/spec/lib/models/revocable_spec.rb +8 -6
  138. data/spec/lib/models/scopes_spec.rb +27 -13
  139. data/spec/lib/models/secret_storable_spec.rb +135 -0
  140. data/spec/lib/oauth/authorization/uri_builder_spec.rb +17 -15
  141. data/spec/lib/oauth/authorization_code_request_spec.rb +34 -11
  142. data/spec/lib/oauth/base_request_spec.rb +20 -8
  143. data/spec/lib/oauth/base_response_spec.rb +3 -1
  144. data/spec/lib/oauth/client/credentials_spec.rb +24 -22
  145. data/spec/lib/oauth/client_credentials/creator_spec.rb +56 -10
  146. data/spec/lib/oauth/client_credentials/issuer_spec.rb +27 -18
  147. data/spec/lib/oauth/client_credentials/validation_spec.rb +20 -15
  148. data/spec/lib/oauth/client_credentials_integration_spec.rb +7 -5
  149. data/spec/lib/oauth/client_credentials_request_spec.rb +27 -21
  150. data/spec/lib/oauth/client_spec.rb +15 -13
  151. data/spec/lib/oauth/code_request_spec.rb +8 -6
  152. data/spec/lib/oauth/code_response_spec.rb +9 -7
  153. data/spec/lib/oauth/error_response_spec.rb +19 -11
  154. data/spec/lib/oauth/error_spec.rb +4 -2
  155. data/spec/lib/oauth/forbidden_token_response_spec.rb +7 -5
  156. data/spec/lib/oauth/helpers/scope_checker_spec.rb +68 -31
  157. data/spec/lib/oauth/helpers/unique_token_spec.rb +8 -6
  158. data/spec/lib/oauth/helpers/uri_checker_spec.rb +115 -95
  159. data/spec/lib/oauth/invalid_token_response_spec.rb +3 -1
  160. data/spec/lib/oauth/password_access_token_request_spec.rb +79 -30
  161. data/spec/lib/oauth/pre_authorization_spec.rb +80 -54
  162. data/spec/lib/oauth/refresh_token_request_spec.rb +36 -33
  163. data/spec/lib/oauth/scopes_spec.rb +63 -61
  164. data/spec/lib/oauth/token_request_spec.rb +79 -24
  165. data/spec/lib/oauth/token_response_spec.rb +40 -38
  166. data/spec/lib/oauth/token_spec.rb +60 -44
  167. data/spec/lib/request/strategy_spec.rb +3 -1
  168. data/spec/lib/secret_storing/base_spec.rb +60 -0
  169. data/spec/lib/secret_storing/bcrypt_spec.rb +49 -0
  170. data/spec/lib/secret_storing/plain_spec.rb +44 -0
  171. data/spec/lib/secret_storing/sha256_hash_spec.rb +48 -0
  172. data/spec/lib/server_spec.rb +16 -14
  173. data/spec/lib/stale_records_cleaner_spec.rb +17 -17
  174. data/spec/models/doorkeeper/access_grant_spec.rb +80 -15
  175. data/spec/models/doorkeeper/access_token_spec.rb +198 -73
  176. data/spec/models/doorkeeper/application_spec.rb +142 -45
  177. data/spec/requests/applications/applications_request_spec.rb +98 -66
  178. data/spec/requests/applications/authorized_applications_spec.rb +20 -18
  179. data/spec/requests/endpoints/authorization_spec.rb +25 -23
  180. data/spec/requests/endpoints/token_spec.rb +38 -36
  181. data/spec/requests/flows/authorization_code_errors_spec.rb +26 -24
  182. data/spec/requests/flows/authorization_code_spec.rb +193 -151
  183. data/spec/requests/flows/client_credentials_spec.rb +54 -52
  184. data/spec/requests/flows/implicit_grant_errors_spec.rb +10 -8
  185. data/spec/requests/flows/implicit_grant_spec.rb +27 -25
  186. data/spec/requests/flows/password_spec.rb +59 -55
  187. data/spec/requests/flows/refresh_token_spec.rb +45 -43
  188. data/spec/requests/flows/revoke_token_spec.rb +40 -54
  189. data/spec/requests/flows/skip_authorization_spec.rb +23 -21
  190. data/spec/requests/protected_resources/metal_spec.rb +7 -5
  191. data/spec/requests/protected_resources/private_api_spec.rb +35 -33
  192. data/spec/routing/custom_controller_routes_spec.rb +71 -65
  193. data/spec/routing/default_routes_spec.rb +22 -20
  194. data/spec/routing/scoped_routes_spec.rb +20 -18
  195. data/spec/spec_helper.rb +15 -13
  196. data/spec/spec_helper_integration.rb +3 -1
  197. data/spec/support/dependencies/factory_bot.rb +3 -1
  198. data/spec/support/doorkeeper_rspec.rb +3 -1
  199. data/spec/support/helpers/access_token_request_helper.rb +3 -1
  200. data/spec/support/helpers/authorization_request_helper.rb +4 -2
  201. data/spec/support/helpers/config_helper.rb +2 -0
  202. data/spec/support/helpers/model_helper.rb +3 -1
  203. data/spec/support/helpers/request_spec_helper.rb +5 -3
  204. data/spec/support/helpers/url_helper.rb +9 -7
  205. data/spec/support/http_method_shim.rb +4 -9
  206. data/spec/support/orm/active_record.rb +3 -1
  207. data/spec/support/shared/controllers_shared_context.rb +18 -16
  208. data/spec/support/shared/hashing_shared_context.rb +36 -0
  209. data/spec/support/shared/models_shared_examples.rb +12 -10
  210. data/spec/validators/redirect_uri_validator_spec.rb +74 -45
  211. data/spec/version/version_spec.rb +7 -5
  212. metadata +61 -28
  213. data/gemfiles/rails_4_2.gemfile +0 -13
  214. data/spec/dummy/config/initializers/new_framework_defaults.rb +0 -8
@@ -1,15 +1,19 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+ require "bcrypt"
2
5
 
3
6
  module Doorkeeper
4
7
  describe Application do
5
- let(:require_owner) { Doorkeeper.configuration.instance_variable_set('@confirm_application_owner', true) }
6
- let(:unset_require_owner) { Doorkeeper.configuration.instance_variable_set('@confirm_application_owner', false) }
8
+ let(:clazz) { Doorkeeper::Application }
9
+ let(:require_owner) { Doorkeeper.configuration.instance_variable_set("@confirm_application_owner", true) }
10
+ let(:unset_require_owner) { Doorkeeper.configuration.instance_variable_set("@confirm_application_owner", false) }
7
11
  let(:new_application) { FactoryBot.build(:application) }
8
12
 
9
13
  let(:uid) { SecureRandom.hex(8) }
10
14
  let(:secret) { SecureRandom.hex(8) }
11
15
 
12
- context 'application_owner is enabled' do
16
+ context "application_owner is enabled" do
13
17
  before do
14
18
  Doorkeeper.configure do
15
19
  orm DOORKEEPER_ORM
@@ -17,122 +21,215 @@ module Doorkeeper
17
21
  end
18
22
  end
19
23
 
20
- context 'application owner is not required' do
24
+ context "application owner is not required" do
21
25
  before(:each) do
22
26
  unset_require_owner
23
27
  end
24
28
 
25
- it 'is valid given valid attributes' do
29
+ it "is valid given valid attributes" do
26
30
  expect(new_application).to be_valid
27
31
  end
28
32
  end
29
33
 
30
- context 'application owner is required' do
34
+ context "application owner is required" do
31
35
  before(:each) do
32
36
  require_owner
33
37
  @owner = FactoryBot.build_stubbed(:doorkeeper_testing_user)
34
38
  end
35
39
 
36
- it 'is invalid without an owner' do
40
+ it "is invalid without an owner" do
37
41
  expect(new_application).not_to be_valid
38
42
  end
39
43
 
40
- it 'is valid with an owner' do
44
+ it "is valid with an owner" do
41
45
  new_application.owner = @owner
42
46
  expect(new_application).to be_valid
43
47
  end
44
48
  end
45
49
  end
46
50
 
47
- it 'is invalid without a name' do
51
+ it "is invalid without a name" do
48
52
  new_application.name = nil
49
53
  expect(new_application).not_to be_valid
50
54
  end
51
55
 
52
- it 'is invalid without determining confidentiality' do
56
+ it "is invalid without determining confidentiality" do
53
57
  new_application.confidential = nil
54
58
  expect(new_application).not_to be_valid
55
59
  end
56
60
 
57
- it 'generates uid on create' do
61
+ it "generates uid on create" do
58
62
  expect(new_application.uid).to be_nil
59
63
  new_application.save
60
64
  expect(new_application.uid).not_to be_nil
61
65
  end
62
66
 
63
- it 'generates uid on create if an empty string' do
64
- new_application.uid = ''
67
+ it "generates uid on create if an empty string" do
68
+ new_application.uid = ""
65
69
  new_application.save
66
70
  expect(new_application.uid).not_to be_blank
67
71
  end
68
72
 
69
- it 'generates uid on create unless one is set' do
73
+ it "generates uid on create unless one is set" do
70
74
  new_application.uid = uid
71
75
  new_application.save
72
76
  expect(new_application.uid).to eq(uid)
73
77
  end
74
78
 
75
- it 'is invalid without uid' do
79
+ it "is invalid without uid" do
76
80
  new_application.save
77
81
  new_application.uid = nil
78
82
  expect(new_application).not_to be_valid
79
83
  end
80
84
 
81
- it 'is invalid without redirect_uri' do
82
- new_application.save
83
- new_application.redirect_uri = nil
84
- expect(new_application).not_to be_valid
85
+ context "redirect URI" do
86
+ context "when grant flows allow blank redirect URI" do
87
+ before do
88
+ Doorkeeper.configure do
89
+ grant_flows %w[password client_credentials]
90
+ end
91
+ end
92
+
93
+ it "is valid without redirect_uri" do
94
+ new_application.save
95
+ new_application.redirect_uri = nil
96
+ expect(new_application).to be_valid
97
+ end
98
+ end
99
+
100
+ context "when grant flows require redirect URI" do
101
+ before do
102
+ Doorkeeper.configure do
103
+ grant_flows %w[password client_credentials authorization_code]
104
+ end
105
+ end
106
+
107
+ it "is invalid without redirect_uri" do
108
+ new_application.save
109
+ new_application.redirect_uri = nil
110
+ expect(new_application).not_to be_valid
111
+ end
112
+ end
113
+
114
+ context "when blank URI option disabled" do
115
+ before do
116
+ Doorkeeper.configure do
117
+ grant_flows %w[password client_credentials]
118
+ allow_blank_redirect_uri false
119
+ end
120
+ end
121
+
122
+ it "is invalid without redirect_uri" do
123
+ new_application.save
124
+ new_application.redirect_uri = nil
125
+ expect(new_application).not_to be_valid
126
+ end
127
+ end
85
128
  end
86
129
 
87
- it 'checks uniqueness of uid' do
130
+ it "checks uniqueness of uid" do
88
131
  app1 = FactoryBot.create(:application)
89
132
  app2 = FactoryBot.create(:application)
90
133
  app2.uid = app1.uid
91
134
  expect(app2).not_to be_valid
92
135
  end
93
136
 
94
- it 'expects database to throw an error when uids are the same' do
137
+ it "expects database to throw an error when uids are the same" do
95
138
  app1 = FactoryBot.create(:application)
96
139
  app2 = FactoryBot.create(:application)
97
140
  app2.uid = app1.uid
98
141
  expect { app2.save!(validate: false) }.to raise_error(uniqueness_error)
99
142
  end
100
143
 
101
- it 'generate secret on create' do
144
+ it "generate secret on create" do
102
145
  expect(new_application.secret).to be_nil
103
146
  new_application.save
104
147
  expect(new_application.secret).not_to be_nil
105
148
  end
106
149
 
107
- it 'generate secret on create if is blank string' do
108
- new_application.secret = ''
150
+ it "generate secret on create if is blank string" do
151
+ new_application.secret = ""
109
152
  new_application.save
110
153
  expect(new_application.secret).not_to be_blank
111
154
  end
112
155
 
113
- it 'generate secret on create unless one is set' do
156
+ it "generate secret on create unless one is set" do
114
157
  new_application.secret = secret
115
158
  new_application.save
116
159
  expect(new_application.secret).to eq(secret)
117
160
  end
118
161
 
119
- it 'is invalid without secret' do
162
+ it "is invalid without secret" do
120
163
  new_application.save
121
164
  new_application.secret = nil
122
165
  expect(new_application).not_to be_valid
123
166
  end
124
167
 
125
- describe 'destroy related models on cascade' do
168
+ context "with hashing enabled" do
169
+ include_context "with application hashing enabled"
170
+ let(:app) { FactoryBot.create :application }
171
+ let(:default_strategy) { Doorkeeper::SecretStoring::Sha256Hash }
172
+
173
+ it "uses SHA256 to avoid additional dependencies" do
174
+ # Ensure token was generated
175
+ app.validate
176
+ expect(app.secret).to eq(default_strategy.transform_secret(app.plaintext_secret))
177
+ end
178
+
179
+ context "when bcrypt strategy is configured" do
180
+ # In this text context, we have bcrypt loaded so `bcrypt_present?`
181
+ # will always be true
182
+ before do
183
+ Doorkeeper.configure do
184
+ hash_application_secrets using: "Doorkeeper::SecretStoring::BCrypt"
185
+ end
186
+ end
187
+
188
+ it "holds a volatile plaintext and BCrypt secret" do
189
+ expect(app.secret_strategy).to eq Doorkeeper::SecretStoring::BCrypt
190
+ expect(app.plaintext_secret).to be_a(String)
191
+ expect(app.secret).not_to eq(app.plaintext_secret)
192
+ expect { ::BCrypt::Password.create(app.secret) }.not_to raise_error
193
+ end
194
+ end
195
+
196
+ it "does not fallback to plain lookup by default" do
197
+ lookup = clazz.by_uid_and_secret(app.uid, app.secret)
198
+ expect(lookup).to eq(nil)
199
+
200
+ lookup = clazz.by_uid_and_secret(app.uid, app.plaintext_secret)
201
+ expect(lookup).to eq(app)
202
+ end
203
+
204
+ context "with fallback enabled" do
205
+ include_context "with token hashing and fallback lookup enabled"
206
+
207
+ it "provides plain and hashed lookup" do
208
+ lookup = clazz.by_uid_and_secret(app.uid, app.secret)
209
+ expect(lookup).to eq(app)
210
+
211
+ lookup = clazz.by_uid_and_secret(app.uid, app.plaintext_secret)
212
+ expect(lookup).to eq(app)
213
+ end
214
+ end
215
+
216
+ it "does not provide access to secret after loading" do
217
+ lookup = clazz.by_uid_and_secret(app.uid, app.plaintext_secret)
218
+ expect(lookup.plaintext_secret).to be_nil
219
+ end
220
+ end
221
+
222
+ describe "destroy related models on cascade" do
126
223
  before(:each) do
127
224
  new_application.save
128
225
  end
129
226
 
130
- it 'should destroy its access grants' do
227
+ it "should destroy its access grants" do
131
228
  FactoryBot.create(:access_grant, application: new_application)
132
229
  expect { new_application.destroy }.to change { Doorkeeper::AccessGrant.count }.by(-1)
133
230
  end
134
231
 
135
- it 'should destroy its access tokens' do
232
+ it "should destroy its access tokens" do
136
233
  FactoryBot.create(:access_token, application: new_application)
137
234
  FactoryBot.create(:access_token, application: new_application, revoked_at: Time.now.utc)
138
235
  expect do
@@ -144,15 +241,15 @@ module Doorkeeper
144
241
  describe :ordered_by do
145
242
  let(:applications) { FactoryBot.create_list(:application, 5) }
146
243
 
147
- context 'when a direction is not specified' do
148
- it 'calls order with a default order of asc' do
244
+ context "when a direction is not specified" do
245
+ it "calls order with a default order of asc" do
149
246
  names = applications.map(&:name).sort
150
247
  expect(Application.ordered_by(:name).map(&:name)).to eq(names)
151
248
  end
152
249
  end
153
250
 
154
- context 'when a direction is specified' do
155
- it 'calls order with specified direction' do
251
+ context "when a direction is specified" do
252
+ it "calls order with specified direction" do
156
253
  names = applications.map(&:name).sort.reverse
157
254
  expect(Application.ordered_by(:name, :desc).map(&:name)).to eq(names)
158
255
  end
@@ -162,7 +259,7 @@ module Doorkeeper
162
259
  describe "#redirect_uri=" do
163
260
  context "when array of valid redirect_uris" do
164
261
  it "should join by newline" do
165
- new_application.redirect_uri = ['http://localhost/callback1', 'http://localhost/callback2']
262
+ new_application.redirect_uri = ["http://localhost/callback1", "http://localhost/callback2"]
166
263
  expect(new_application.redirect_uri).to eq("http://localhost/callback1\nhttp://localhost/callback2")
167
264
  end
168
265
  end
@@ -177,28 +274,28 @@ module Doorkeeper
177
274
  describe :authorized_for do
178
275
  let(:resource_owner) { double(:resource_owner, id: 10) }
179
276
 
180
- it 'is empty if the application is not authorized for anyone' do
277
+ it "is empty if the application is not authorized for anyone" do
181
278
  expect(Application.authorized_for(resource_owner)).to be_empty
182
279
  end
183
280
 
184
- it 'returns only application for a specific resource owner' do
281
+ it "returns only application for a specific resource owner" do
185
282
  FactoryBot.create(:access_token, resource_owner_id: resource_owner.id + 1)
186
283
  token = FactoryBot.create(:access_token, resource_owner_id: resource_owner.id)
187
284
  expect(Application.authorized_for(resource_owner)).to eq([token.application])
188
285
  end
189
286
 
190
- it 'excludes revoked tokens' do
287
+ it "excludes revoked tokens" do
191
288
  FactoryBot.create(:access_token, resource_owner_id: resource_owner.id, revoked_at: 2.days.ago)
192
289
  expect(Application.authorized_for(resource_owner)).to be_empty
193
290
  end
194
291
 
195
- it 'returns all applications that have been authorized' do
292
+ it "returns all applications that have been authorized" do
196
293
  token1 = FactoryBot.create(:access_token, resource_owner_id: resource_owner.id)
197
294
  token2 = FactoryBot.create(:access_token, resource_owner_id: resource_owner.id)
198
295
  expect(Application.authorized_for(resource_owner)).to eq([token1.application, token2.application])
199
296
  end
200
297
 
201
- it 'returns only one application even if it has been authorized twice' do
298
+ it "returns only one application even if it has been authorized twice" do
202
299
  application = FactoryBot.create(:application)
203
300
  FactoryBot.create(:access_token, resource_owner_id: resource_owner.id, application: application)
204
301
  FactoryBot.create(:access_token, resource_owner_id: resource_owner.id, application: application)
@@ -207,7 +304,7 @@ module Doorkeeper
207
304
  end
208
305
 
209
306
  describe :revoke_tokens_and_grants_for do
210
- it 'revokes all access tokens and access grants' do
307
+ it "revokes all access tokens and access grants" do
211
308
  application_id = 42
212
309
  resource_owner = double
213
310
  expect(Doorkeeper::AccessToken)
@@ -229,7 +326,7 @@ module Doorkeeper
229
326
  context "when secret is wrong" do
230
327
  it "should not find the application" do
231
328
  app = FactoryBot.create :application
232
- authenticated = Application.by_uid_and_secret(app.uid, 'bad')
329
+ authenticated = Application.by_uid_and_secret(app.uid, "bad")
233
330
  expect(authenticated).to eq(nil)
234
331
  end
235
332
  end
@@ -246,7 +343,7 @@ module Doorkeeper
246
343
  context "when secret is wrong" do
247
344
  it "should not find the application" do
248
345
  app = FactoryBot.create :application, confidential: false
249
- authenticated = Application.by_uid_and_secret(app.uid, 'bad')
346
+ authenticated = Application.by_uid_and_secret(app.uid, "bad")
250
347
  expect(authenticated).to eq(nil)
251
348
  end
252
349
  end
@@ -256,12 +353,12 @@ module Doorkeeper
256
353
  describe :confidential? do
257
354
  subject { FactoryBot.create(:application, confidential: confidential).confidential? }
258
355
 
259
- context 'when application is private/confidential' do
356
+ context "when application is private/confidential" do
260
357
  let(:confidential) { true }
261
358
  it { expect(subject).to eq(true) }
262
359
  end
263
360
 
264
- context 'when application is public/non-confidential' do
361
+ context "when application is public/non-confidential" do
265
362
  let(:confidential) { false }
266
363
  it { expect(subject).to eq(false) }
267
364
  end
@@ -1,25 +1,27 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
2
 
3
- feature 'Adding applications' do
4
- context 'in application form' do
3
+ require "spec_helper"
4
+
5
+ feature "Adding applications" do
6
+ context "in application form" do
5
7
  background do
6
8
  i_am_logged_in
7
- visit '/oauth/applications/new'
9
+ visit "/oauth/applications/new"
8
10
  end
9
11
 
10
- scenario 'adding a valid app' do
11
- fill_in 'doorkeeper_application[name]', with: 'My Application'
12
- fill_in 'doorkeeper_application[redirect_uri]',
13
- with: 'https://example.com'
12
+ scenario "adding a valid app" do
13
+ fill_in "doorkeeper_application[name]", with: "My Application"
14
+ fill_in "doorkeeper_application[redirect_uri]",
15
+ with: "https://example.com"
14
16
 
15
- click_button 'Submit'
16
- i_should_see 'Application created'
17
- i_should_see 'My Application'
17
+ click_button "Submit"
18
+ i_should_see "Application created"
19
+ i_should_see "My Application"
18
20
  end
19
21
 
20
- scenario 'adding invalid app' do
21
- click_button 'Submit'
22
- i_should_see 'Whoops! Check your form for possible errors'
22
+ scenario "adding invalid app" do
23
+ click_button "Submit"
24
+ i_should_see "Whoops! Check your form for possible errors"
23
25
  end
24
26
 
25
27
  scenario "adding app ignoring bad scope" do
@@ -88,63 +90,93 @@ feature 'Adding applications' do
88
90
  click_button "Submit"
89
91
  i_should_see "Whoops! Check your form for possible errors"
90
92
  i_should_see Regexp.new(
91
- I18n.t('activerecord.errors.models.doorkeeper/application.attributes.scopes.not_match_configured'),
93
+ I18n.t("activerecord.errors.models.doorkeeper/application.attributes.scopes.not_match_configured"),
92
94
  true
93
95
  )
94
96
  end
97
+
98
+ context "redirect URI" do
99
+ scenario "adding app with blank redirect URI when configured flows requires redirect uri" do
100
+ config_is_set("grant_flows", %w[authorization_code implicit client_credentials])
101
+
102
+ fill_in "doorkeeper_application[name]", with: "My Application"
103
+ fill_in "doorkeeper_application[redirect_uri]",
104
+ with: ""
105
+
106
+ click_button "Submit"
107
+ i_should_see "Whoops! Check your form for possible errors"
108
+ end
109
+
110
+ scenario "adding app with blank redirect URI when configured flows without redirect uri" do
111
+ config_is_set("grant_flows", %w[client_credentials password])
112
+
113
+ # Visit it once again to consider grant flows
114
+ visit "/oauth/applications/new"
115
+
116
+ i_should_see I18n.t("doorkeeper.applications.help.blank_redirect_uri")
117
+
118
+ fill_in "doorkeeper_application[name]", with: "My Application"
119
+ fill_in "doorkeeper_application[redirect_uri]",
120
+ with: ""
121
+
122
+ click_button "Submit"
123
+ i_should_see "Application created"
124
+ i_should_see "My Application"
125
+ end
126
+ end
95
127
  end
96
128
  end
97
129
 
98
- feature 'Listing applications' do
130
+ feature "Listing applications" do
99
131
  background do
100
132
  i_am_logged_in
101
133
 
102
- FactoryBot.create :application, name: 'Oauth Dude'
103
- FactoryBot.create :application, name: 'Awesome App'
134
+ FactoryBot.create :application, name: "Oauth Dude"
135
+ FactoryBot.create :application, name: "Awesome App"
104
136
  end
105
137
 
106
- scenario 'application list' do
107
- visit '/oauth/applications'
138
+ scenario "application list" do
139
+ visit "/oauth/applications"
108
140
 
109
- i_should_see 'Awesome App'
110
- i_should_see 'Oauth Dude'
141
+ i_should_see "Awesome App"
142
+ i_should_see "Oauth Dude"
111
143
  end
112
144
  end
113
145
 
114
- feature 'Renders assets' do
115
- scenario 'admin stylesheets' do
116
- visit '/assets/doorkeeper/admin/application.css'
146
+ feature "Renders assets" do
147
+ scenario "admin stylesheets" do
148
+ visit "/assets/doorkeeper/admin/application.css"
117
149
 
118
- i_should_see 'Bootstrap'
119
- i_should_see '.doorkeeper-admin'
150
+ i_should_see "Bootstrap"
151
+ i_should_see ".doorkeeper-admin"
120
152
  end
121
153
 
122
- scenario 'application stylesheets' do
123
- visit '/assets/doorkeeper/application.css'
154
+ scenario "application stylesheets" do
155
+ visit "/assets/doorkeeper/application.css"
124
156
 
125
- i_should_see 'Bootstrap'
126
- i_should_see '#oauth-permissions'
127
- i_should_see '#container'
157
+ i_should_see "Bootstrap"
158
+ i_should_see "#oauth-permissions"
159
+ i_should_see "#container"
128
160
  end
129
161
  end
130
162
 
131
- feature 'Show application' do
163
+ feature "Show application" do
132
164
  given :app do
133
165
  i_am_logged_in
134
166
 
135
- FactoryBot.create :application, name: 'Just another oauth app'
167
+ FactoryBot.create :application, name: "Just another oauth app"
136
168
  end
137
169
 
138
- scenario 'visiting application page' do
170
+ scenario "visiting application page" do
139
171
  visit "/oauth/applications/#{app.id}"
140
172
 
141
- i_should_see 'Just another oauth app'
173
+ i_should_see "Just another oauth app"
142
174
  end
143
175
  end
144
176
 
145
- feature 'Edit application' do
177
+ feature "Edit application" do
146
178
  let :app do
147
- FactoryBot.create :application, name: 'OMG my app'
179
+ FactoryBot.create :application, name: "OMG my app"
148
180
  end
149
181
 
150
182
  background do
@@ -153,72 +185,72 @@ feature 'Edit application' do
153
185
  visit "/oauth/applications/#{app.id}/edit"
154
186
  end
155
187
 
156
- scenario 'updating a valid app' do
157
- fill_in 'doorkeeper_application[name]', with: 'Serious app'
158
- click_button 'Submit'
188
+ scenario "updating a valid app" do
189
+ fill_in "doorkeeper_application[name]", with: "Serious app"
190
+ click_button "Submit"
159
191
 
160
- i_should_see 'Application updated'
161
- i_should_see 'Serious app'
162
- i_should_not_see 'OMG my app'
192
+ i_should_see "Application updated"
193
+ i_should_see "Serious app"
194
+ i_should_not_see "OMG my app"
163
195
  end
164
196
 
165
- scenario 'updating an invalid app' do
166
- fill_in 'doorkeeper_application[name]', with: ''
167
- click_button 'Submit'
197
+ scenario "updating an invalid app" do
198
+ fill_in "doorkeeper_application[name]", with: ""
199
+ click_button "Submit"
168
200
 
169
- i_should_see 'Whoops! Check your form for possible errors'
201
+ i_should_see "Whoops! Check your form for possible errors"
170
202
  end
171
203
  end
172
204
 
173
- feature 'Remove application' do
205
+ feature "Remove application" do
174
206
  background do
175
207
  i_am_logged_in
176
208
 
177
209
  @app = FactoryBot.create :application
178
210
  end
179
211
 
180
- scenario 'deleting an application from list' do
181
- visit '/oauth/applications'
212
+ scenario "deleting an application from list" do
213
+ visit "/oauth/applications"
182
214
 
183
215
  i_should_see @app.name
184
216
 
185
217
  within(:css, "tr#application_#{@app.id}") do
186
- click_button 'Destroy'
218
+ click_button "Destroy"
187
219
  end
188
220
 
189
- i_should_see 'Application deleted'
221
+ i_should_see "Application deleted"
190
222
  i_should_not_see @app.name
191
223
  end
192
224
 
193
- scenario 'deleting an application from show' do
225
+ scenario "deleting an application from show" do
194
226
  visit "/oauth/applications/#{@app.id}"
195
- click_button 'Destroy'
227
+ click_button "Destroy"
196
228
 
197
- i_should_see 'Application deleted'
229
+ i_should_see "Application deleted"
198
230
  end
199
231
  end
200
232
 
201
- context 'when admin authenticator block is default' do
202
- let(:app) { FactoryBot.create :application, name: 'app' }
233
+ context "when admin authenticator block is default" do
234
+ let(:app) { FactoryBot.create :application, name: "app" }
203
235
 
204
- feature 'application list' do
205
- scenario 'fails with forbidden' do
206
- visit '/oauth/applications'
236
+ feature "application list" do
237
+ scenario "fails with forbidden" do
238
+ visit "/oauth/applications"
207
239
 
208
240
  should_have_status 403
209
241
  end
210
242
  end
211
243
 
212
- feature 'adding an app' do
213
- scenario 'fails with forbidden' do
214
- visit '/oauth/applications/new'
244
+ feature "adding an app" do
245
+ scenario "fails with forbidden" do
246
+ visit "/oauth/applications/new"
215
247
 
216
248
  should_have_status 403
217
249
  end
218
250
  end
219
251
 
220
- feature 'editing an app' do
221
- scenario 'fails with forbidden' do
252
+ feature "editing an app" do
253
+ scenario "fails with forbidden" do
222
254
  visit "/oauth/applications/#{app.id}/edit"
223
255
 
224
256
  should_have_status 403