doorkeeper 5.0.0 → 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 (241) hide show
  1. checksums.yaml +5 -5
  2. data/.hound.yml +2 -1
  3. data/.rubocop.yml +37 -4
  4. data/.travis.yml +16 -21
  5. data/Appraisals +29 -7
  6. data/Dangerfile +67 -0
  7. data/Gemfile +19 -5
  8. data/NEWS.md +107 -10
  9. data/README.md +75 -470
  10. data/Rakefile +10 -8
  11. data/app/controllers/doorkeeper/application_controller.rb +3 -2
  12. data/app/controllers/doorkeeper/application_metal_controller.rb +4 -13
  13. data/app/controllers/doorkeeper/applications_controller.rb +21 -7
  14. data/app/controllers/doorkeeper/authorizations_controller.rb +3 -3
  15. data/app/controllers/doorkeeper/authorized_applications_controller.rb +2 -0
  16. data/app/controllers/doorkeeper/token_info_controller.rb +4 -2
  17. data/app/controllers/doorkeeper/tokens_controller.rb +13 -11
  18. data/app/helpers/doorkeeper/dashboard_helper.rb +3 -1
  19. data/app/validators/redirect_uri_validator.rb +7 -2
  20. data/app/views/doorkeeper/applications/_form.html.erb +6 -0
  21. data/app/views/doorkeeper/applications/show.html.erb +1 -1
  22. data/app/views/layouts/doorkeeper/admin.html.erb +5 -3
  23. data/bin/console +16 -0
  24. data/config/locales/en.yml +1 -0
  25. data/doorkeeper.gemspec +28 -24
  26. data/gemfiles/rails_5_0.gemfile +9 -4
  27. data/gemfiles/rails_5_1.gemfile +9 -4
  28. data/gemfiles/rails_5_2.gemfile +10 -5
  29. data/gemfiles/rails_6_0.gemfile +17 -0
  30. data/gemfiles/rails_master.gemfile +9 -9
  31. data/lib/doorkeeper/config/option.rb +64 -0
  32. data/lib/doorkeeper/config.rb +197 -76
  33. data/lib/doorkeeper/engine.rb +3 -1
  34. data/lib/doorkeeper/errors.rb +17 -0
  35. data/lib/doorkeeper/grape/authorization_decorator.rb +6 -4
  36. data/lib/doorkeeper/grape/helpers.rb +5 -3
  37. data/lib/doorkeeper/helpers/controller.rb +5 -2
  38. data/lib/doorkeeper/models/access_grant_mixin.rb +25 -6
  39. data/lib/doorkeeper/models/access_token_mixin.rb +68 -22
  40. data/lib/doorkeeper/models/application_mixin.rb +45 -1
  41. data/lib/doorkeeper/models/concerns/accessible.rb +2 -0
  42. data/lib/doorkeeper/models/concerns/expirable.rb +6 -2
  43. data/lib/doorkeeper/models/concerns/orderable.rb +2 -0
  44. data/lib/doorkeeper/models/concerns/ownership.rb +3 -6
  45. data/lib/doorkeeper/models/concerns/reusable.rb +19 -0
  46. data/lib/doorkeeper/models/concerns/revocable.rb +4 -1
  47. data/lib/doorkeeper/models/concerns/scopes.rb +7 -1
  48. data/lib/doorkeeper/models/concerns/secret_storable.rb +108 -0
  49. data/lib/doorkeeper/oauth/authorization/code.rb +4 -2
  50. data/lib/doorkeeper/oauth/authorization/context.rb +2 -0
  51. data/lib/doorkeeper/oauth/authorization/token.rb +14 -7
  52. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +3 -1
  53. data/lib/doorkeeper/oauth/authorization_code_request.rb +8 -4
  54. data/lib/doorkeeper/oauth/base_request.rb +2 -0
  55. data/lib/doorkeeper/oauth/base_response.rb +2 -0
  56. data/lib/doorkeeper/oauth/client/credentials.rb +2 -0
  57. data/lib/doorkeeper/oauth/client.rb +3 -1
  58. data/lib/doorkeeper/oauth/client_credentials/creator.rb +2 -0
  59. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +2 -0
  60. data/lib/doorkeeper/oauth/client_credentials/validation.rb +7 -4
  61. data/lib/doorkeeper/oauth/client_credentials_request.rb +3 -1
  62. data/lib/doorkeeper/oauth/code_request.rb +2 -0
  63. data/lib/doorkeeper/oauth/code_response.rb +4 -2
  64. data/lib/doorkeeper/oauth/error.rb +2 -0
  65. data/lib/doorkeeper/oauth/error_response.rb +20 -6
  66. data/lib/doorkeeper/oauth/forbidden_token_response.rb +10 -3
  67. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +25 -8
  68. data/lib/doorkeeper/oauth/helpers/unique_token.rb +15 -1
  69. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +42 -3
  70. data/lib/doorkeeper/oauth/invalid_token_response.rb +22 -0
  71. data/lib/doorkeeper/oauth/password_access_token_request.rb +9 -2
  72. data/lib/doorkeeper/oauth/pre_authorization.rb +13 -5
  73. data/lib/doorkeeper/oauth/refresh_token_request.rb +15 -4
  74. data/lib/doorkeeper/oauth/scopes.rb +7 -3
  75. data/lib/doorkeeper/oauth/token.rb +4 -2
  76. data/lib/doorkeeper/oauth/token_introspection.rb +76 -8
  77. data/lib/doorkeeper/oauth/token_request.rb +2 -0
  78. data/lib/doorkeeper/oauth/token_response.rb +11 -9
  79. data/lib/doorkeeper/oauth.rb +5 -5
  80. data/lib/doorkeeper/orm/active_record/access_grant.rb +27 -13
  81. data/lib/doorkeeper/orm/active_record/access_token.rb +6 -13
  82. data/lib/doorkeeper/orm/active_record/application.rb +26 -7
  83. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +10 -3
  84. data/lib/doorkeeper/orm/active_record.rb +8 -6
  85. data/lib/doorkeeper/rails/helpers.rb +5 -1
  86. data/lib/doorkeeper/rails/routes/mapper.rb +2 -0
  87. data/lib/doorkeeper/rails/routes/mapping.rb +9 -7
  88. data/lib/doorkeeper/rails/routes.rb +19 -12
  89. data/lib/doorkeeper/rake/db.rake +17 -17
  90. data/lib/doorkeeper/rake.rb +1 -1
  91. data/lib/doorkeeper/request/authorization_code.rb +2 -0
  92. data/lib/doorkeeper/request/client_credentials.rb +2 -0
  93. data/lib/doorkeeper/request/code.rb +2 -0
  94. data/lib/doorkeeper/request/password.rb +2 -0
  95. data/lib/doorkeeper/request/refresh_token.rb +2 -0
  96. data/lib/doorkeeper/request/strategy.rb +2 -0
  97. data/lib/doorkeeper/request/token.rb +2 -0
  98. data/lib/doorkeeper/request.rb +3 -1
  99. data/lib/doorkeeper/secret_storing/base.rb +64 -0
  100. data/lib/doorkeeper/secret_storing/bcrypt.rb +60 -0
  101. data/lib/doorkeeper/secret_storing/plain.rb +33 -0
  102. data/lib/doorkeeper/secret_storing/sha256_hash.rb +26 -0
  103. data/lib/doorkeeper/server.rb +2 -0
  104. data/lib/doorkeeper/stale_records_cleaner.rb +20 -0
  105. data/lib/doorkeeper/validations.rb +2 -0
  106. data/lib/doorkeeper/version.rb +4 -2
  107. data/lib/doorkeeper.rb +69 -59
  108. data/lib/generators/doorkeeper/application_owner_generator.rb +10 -9
  109. data/lib/generators/doorkeeper/confidential_applications_generator.rb +10 -9
  110. data/lib/generators/doorkeeper/install_generator.rb +11 -9
  111. data/lib/generators/doorkeeper/migration_generator.rb +9 -9
  112. data/lib/generators/doorkeeper/pkce_generator.rb +10 -9
  113. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +10 -9
  114. data/lib/generators/doorkeeper/templates/initializer.rb +138 -13
  115. data/lib/generators/doorkeeper/templates/migration.rb.erb +17 -10
  116. data/lib/generators/doorkeeper/views_generator.rb +6 -4
  117. data/spec/controllers/application_metal_controller_spec.rb +24 -10
  118. data/spec/controllers/applications_controller_spec.rb +76 -78
  119. data/spec/controllers/authorizations_controller_spec.rb +189 -142
  120. data/spec/controllers/protected_resources_controller_spec.rb +111 -67
  121. data/spec/controllers/token_info_controller_spec.rb +14 -12
  122. data/spec/controllers/tokens_controller_spec.rb +170 -112
  123. data/spec/dummy/Rakefile +3 -1
  124. data/spec/dummy/app/controllers/application_controller.rb +3 -1
  125. data/spec/dummy/app/controllers/custom_authorizations_controller.rb +3 -1
  126. data/spec/dummy/app/controllers/full_protected_resources_controller.rb +4 -2
  127. data/spec/dummy/app/controllers/home_controller.rb +6 -5
  128. data/spec/dummy/app/controllers/metal_controller.rb +2 -0
  129. data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +4 -2
  130. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  131. data/spec/dummy/app/models/user.rb +2 -0
  132. data/spec/dummy/config/application.rb +26 -2
  133. data/spec/dummy/config/boot.rb +2 -4
  134. data/spec/dummy/config/environment.rb +1 -1
  135. data/spec/dummy/config/environments/development.rb +2 -0
  136. data/spec/dummy/config/environments/production.rb +2 -0
  137. data/spec/dummy/config/environments/test.rb +4 -2
  138. data/spec/dummy/config/initializers/backtrace_silencers.rb +2 -0
  139. data/spec/dummy/config/initializers/doorkeeper.rb +7 -3
  140. data/spec/dummy/config/initializers/secret_token.rb +3 -1
  141. data/spec/dummy/config/initializers/session_store.rb +3 -1
  142. data/spec/dummy/config/initializers/wrap_parameters.rb +2 -0
  143. data/spec/dummy/config.ru +3 -1
  144. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +20 -13
  145. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +1 -1
  146. data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +2 -0
  147. data/spec/dummy/db/schema.rb +1 -1
  148. data/spec/dummy/script/rails +7 -4
  149. data/spec/factories.rb +11 -9
  150. data/spec/generators/application_owner_generator_spec.rb +13 -26
  151. data/spec/generators/confidential_applications_generator_spec.rb +12 -28
  152. data/spec/generators/install_generator_spec.rb +19 -14
  153. data/spec/generators/migration_generator_spec.rb +13 -26
  154. data/spec/generators/pkce_generator_spec.rb +11 -26
  155. data/spec/generators/previous_refresh_token_generator_spec.rb +16 -29
  156. data/spec/generators/templates/routes.rb +2 -1
  157. data/spec/generators/views_generator_spec.rb +14 -12
  158. data/spec/grape/grape_integration_spec.rb +35 -33
  159. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +9 -7
  160. data/spec/lib/config_spec.rb +290 -104
  161. data/spec/lib/doorkeeper_spec.rb +8 -6
  162. data/spec/lib/models/expirable_spec.rb +22 -8
  163. data/spec/lib/models/reusable_spec.rb +40 -0
  164. data/spec/lib/models/revocable_spec.rb +8 -6
  165. data/spec/lib/models/scopes_spec.rb +27 -13
  166. data/spec/lib/models/secret_storable_spec.rb +135 -0
  167. data/spec/lib/oauth/authorization/uri_builder_spec.rb +17 -15
  168. data/spec/lib/oauth/authorization_code_request_spec.rb +43 -17
  169. data/spec/lib/oauth/base_request_spec.rb +24 -12
  170. data/spec/lib/oauth/base_response_spec.rb +3 -1
  171. data/spec/lib/oauth/client/credentials_spec.rb +26 -24
  172. data/spec/lib/oauth/client_credentials/creator_spec.rb +56 -10
  173. data/spec/lib/oauth/client_credentials/issuer_spec.rb +27 -20
  174. data/spec/lib/oauth/client_credentials/validation_spec.rb +21 -15
  175. data/spec/lib/oauth/client_credentials_integration_spec.rb +8 -6
  176. data/spec/lib/oauth/client_credentials_request_spec.rb +27 -21
  177. data/spec/lib/oauth/client_spec.rb +15 -13
  178. data/spec/lib/oauth/code_request_spec.rb +10 -8
  179. data/spec/lib/oauth/code_response_spec.rb +9 -7
  180. data/spec/lib/oauth/error_response_spec.rb +19 -11
  181. data/spec/lib/oauth/error_spec.rb +4 -2
  182. data/spec/lib/oauth/forbidden_token_response_spec.rb +7 -5
  183. data/spec/lib/oauth/helpers/scope_checker_spec.rb +68 -31
  184. data/spec/lib/oauth/helpers/unique_token_spec.rb +8 -6
  185. data/spec/lib/oauth/helpers/uri_checker_spec.rb +124 -93
  186. data/spec/lib/oauth/invalid_token_response_spec.rb +3 -1
  187. data/spec/lib/oauth/password_access_token_request_spec.rb +95 -34
  188. data/spec/lib/oauth/pre_authorization_spec.rb +80 -54
  189. data/spec/lib/oauth/refresh_token_request_spec.rb +46 -39
  190. data/spec/lib/oauth/scopes_spec.rb +63 -61
  191. data/spec/lib/oauth/token_request_spec.rb +80 -25
  192. data/spec/lib/oauth/token_response_spec.rb +40 -38
  193. data/spec/lib/oauth/token_spec.rb +64 -45
  194. data/spec/lib/request/strategy_spec.rb +3 -1
  195. data/spec/lib/secret_storing/base_spec.rb +60 -0
  196. data/spec/lib/secret_storing/bcrypt_spec.rb +49 -0
  197. data/spec/lib/secret_storing/plain_spec.rb +44 -0
  198. data/spec/lib/secret_storing/sha256_hash_spec.rb +48 -0
  199. data/spec/lib/server_spec.rb +20 -18
  200. data/spec/lib/{orm/active_record/stale_records_cleaner_spec.rb → stale_records_cleaner_spec.rb} +28 -18
  201. data/spec/models/doorkeeper/access_grant_spec.rb +80 -15
  202. data/spec/models/doorkeeper/access_token_spec.rb +212 -83
  203. data/spec/models/doorkeeper/application_spec.rb +146 -49
  204. data/spec/requests/applications/applications_request_spec.rb +100 -68
  205. data/spec/requests/applications/authorized_applications_spec.rb +20 -18
  206. data/spec/requests/endpoints/authorization_spec.rb +27 -25
  207. data/spec/requests/endpoints/token_spec.rb +38 -36
  208. data/spec/requests/flows/authorization_code_errors_spec.rb +27 -25
  209. data/spec/requests/flows/authorization_code_spec.rb +260 -158
  210. data/spec/requests/flows/client_credentials_spec.rb +54 -52
  211. data/spec/requests/flows/implicit_grant_errors_spec.rb +11 -9
  212. data/spec/requests/flows/implicit_grant_spec.rb +27 -25
  213. data/spec/requests/flows/password_spec.rb +64 -56
  214. data/spec/requests/flows/refresh_token_spec.rb +91 -32
  215. data/spec/requests/flows/revoke_token_spec.rb +49 -63
  216. data/spec/requests/flows/skip_authorization_spec.rb +23 -21
  217. data/spec/requests/protected_resources/metal_spec.rb +7 -5
  218. data/spec/requests/protected_resources/private_api_spec.rb +37 -35
  219. data/spec/routing/custom_controller_routes_spec.rb +71 -65
  220. data/spec/routing/default_routes_spec.rb +22 -20
  221. data/spec/routing/scoped_routes_spec.rb +20 -18
  222. data/spec/spec_helper.rb +15 -13
  223. data/spec/spec_helper_integration.rb +3 -1
  224. data/spec/support/dependencies/factory_bot.rb +3 -1
  225. data/spec/support/doorkeeper_rspec.rb +5 -2
  226. data/spec/support/helpers/access_token_request_helper.rb +3 -1
  227. data/spec/support/helpers/authorization_request_helper.rb +4 -2
  228. data/spec/support/helpers/config_helper.rb +2 -0
  229. data/spec/support/helpers/model_helper.rb +11 -5
  230. data/spec/support/helpers/request_spec_helper.rb +5 -3
  231. data/spec/support/helpers/url_helper.rb +20 -18
  232. data/spec/support/http_method_shim.rb +4 -9
  233. data/spec/support/orm/active_record.rb +3 -1
  234. data/spec/support/shared/controllers_shared_context.rb +68 -10
  235. data/spec/support/shared/hashing_shared_context.rb +36 -0
  236. data/spec/support/shared/models_shared_examples.rb +12 -10
  237. data/spec/validators/redirect_uri_validator_spec.rb +76 -47
  238. data/spec/version/version_spec.rb +7 -5
  239. metadata +70 -21
  240. data/gemfiles/rails_4_2.gemfile +0 -13
  241. data/spec/dummy/config/initializers/new_framework_defaults.rb +0 -10
@@ -1,31 +1,94 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
2
4
 
3
5
  module Doorkeeper
4
6
  describe AccessToken do
7
+ let(:clazz) { Doorkeeper::AccessToken }
5
8
  subject { FactoryBot.build(:access_token) }
6
9
 
7
10
  it { expect(subject).to be_valid }
8
11
 
9
- it_behaves_like 'an accessible token'
10
- it_behaves_like 'a revocable token'
11
- it_behaves_like 'a unique token' do
12
+ it_behaves_like "an accessible token"
13
+ it_behaves_like "a revocable token"
14
+ it_behaves_like "a unique token" do
12
15
  let(:factory_name) { :access_token }
13
16
  end
14
17
 
15
18
  module CustomGeneratorArgs
16
- def self.generate
17
- end
19
+ def self.generate; end
18
20
  end
19
21
 
20
22
  describe :generate_token do
21
- it 'generates a token using the default method' do
23
+ it "generates a token using the default method" do
22
24
  FactoryBot.create :access_token
23
25
 
24
26
  token = FactoryBot.create :access_token
25
27
  expect(token.token).to be_a(String)
26
28
  end
27
29
 
28
- it 'generates a token using a custom object' do
30
+ context "with hashing enabled" do
31
+ let(:token) { FactoryBot.create :access_token }
32
+ include_context "with token hashing enabled"
33
+
34
+ it "holds a volatile plaintext token when created" do
35
+ expect(token.plaintext_token).to be_a(String)
36
+ expect(token.token)
37
+ .to eq(hashed_or_plain_token_func.call(token.plaintext_token))
38
+
39
+ # Finder method only finds the hashed token
40
+ loaded = clazz.find_by(token: token.token)
41
+ expect(loaded).to eq(token)
42
+ expect(loaded.plaintext_token).to be_nil
43
+ expect(loaded.token).to eq(token.token)
44
+ end
45
+
46
+ it "does not find_by plain text tokens" do
47
+ expect(clazz.find_by(token: token.plaintext_token)).to be_nil
48
+ end
49
+
50
+ describe "with having a plain text token" do
51
+ let(:plain_text_token) { "plain text token" }
52
+ let(:access_token) { FactoryBot.create :access_token }
53
+
54
+ before do
55
+ # Assume we have a plain text token from before activating the option
56
+ access_token.update_column(:token, plain_text_token)
57
+ end
58
+
59
+ context "without fallback lookup" do
60
+ it "does not provide lookups with either through by_token" do
61
+ expect(clazz.by_token(plain_text_token)).to eq(nil)
62
+ expect(clazz.by_token(access_token.token)).to eq(nil)
63
+
64
+ # And it does not touch the token
65
+ access_token.reload
66
+ expect(access_token.token).to eq(plain_text_token)
67
+ end
68
+ end
69
+
70
+ context "with fallback lookup" do
71
+ include_context "with token hashing and fallback lookup enabled"
72
+
73
+ it "upgrades a plain token when falling back to it" do
74
+ # Side-effect: This will automatically upgrade the token
75
+ expect(clazz).to receive(:upgrade_fallback_value).and_call_original
76
+ expect(clazz.by_token(plain_text_token)).to eq(access_token)
77
+
78
+ # Will find subsequently by hashing the token
79
+ expect(clazz.by_token(plain_text_token)).to eq(access_token)
80
+
81
+ # And it modifies the token value
82
+ access_token.reload
83
+ expect(access_token.token).not_to eq(plain_text_token)
84
+ expect(clazz.find_by(token: plain_text_token)).to eq(nil)
85
+ expect(clazz.find_by(token: access_token.token)).not_to be_nil
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ it "generates a token using a custom object" do
29
92
  eigenclass = class << CustomGeneratorArgs; self; end
30
93
  eigenclass.class_eval do
31
94
  remove_method :generate
@@ -42,10 +105,10 @@ module Doorkeeper
42
105
  end
43
106
 
44
107
  token = FactoryBot.create :access_token
45
- expect(token.token).to match(%r{custom_generator_token_\d+})
108
+ expect(token.token).to match(/custom_generator_token_\d+/)
46
109
  end
47
110
 
48
- it 'allows the custom generator to access the application details' do
111
+ it "allows the custom generator to access the application details" do
49
112
  eigenclass = class << CustomGeneratorArgs; self; end
50
113
  eigenclass.class_eval do
51
114
  remove_method :generate
@@ -62,10 +125,10 @@ module Doorkeeper
62
125
  end
63
126
 
64
127
  token = FactoryBot.create :access_token
65
- expect(token.token).to match(%r{custom_generator_token_Application \d+})
128
+ expect(token.token).to match(/custom_generator_token_Application \d+/)
66
129
  end
67
130
 
68
- it 'allows the custom generator to access the scopes' do
131
+ it "allows the custom generator to access the scopes" do
69
132
  eigenclass = class << CustomGeneratorArgs; self; end
70
133
  eigenclass.class_eval do
71
134
  remove_method :generate
@@ -81,12 +144,12 @@ module Doorkeeper
81
144
  access_token_generator "Doorkeeper::CustomGeneratorArgs"
82
145
  end
83
146
 
84
- token = FactoryBot.create :access_token, scopes: 'public write'
147
+ token = FactoryBot.create :access_token, scopes: "public write"
85
148
 
86
- expect(token.token).to eq 'custom_generator_token_2_public write'
149
+ expect(token.token).to eq "custom_generator_token_2_public write"
87
150
  end
88
151
 
89
- it 'allows the custom generator to access the expiry length' do
152
+ it "allows the custom generator to access the expiry length" do
90
153
  eigenclass = class << CustomGeneratorArgs; self; end
91
154
  eigenclass.class_eval do
92
155
  remove_method :generate
@@ -103,10 +166,10 @@ module Doorkeeper
103
166
  end
104
167
 
105
168
  token = FactoryBot.create :access_token
106
- expect(token.token).to eq 'custom_generator_token_7200'
169
+ expect(token.token).to eq "custom_generator_token_7200"
107
170
  end
108
171
 
109
- it 'allows the custom generator to access the created time' do
172
+ it "allows the custom generator to access the created time" do
110
173
  module CustomGeneratorArgs
111
174
  def self.generate(opts = {})
112
175
  "custom_generator_token_#{opts[:created_at].to_i}"
@@ -123,7 +186,7 @@ module Doorkeeper
123
186
  expect(token.token).to eq "custom_generator_token_#{created_at.to_i}"
124
187
  end
125
188
 
126
- it 'raises an error if the custom object does not support generate' do
189
+ it "raises an error if the custom object does not support generate" do
127
190
  module NoGenerate
128
191
  end
129
192
 
@@ -137,7 +200,7 @@ module Doorkeeper
137
200
  )
138
201
  end
139
202
 
140
- it 'raises original error if something went wrong in custom generator' do
203
+ it "raises original error if something went wrong in custom generator" do
141
204
  eigenclass = class << CustomGeneratorArgs; self; end
142
205
  eigenclass.class_eval do
143
206
  remove_method :generate
@@ -145,7 +208,7 @@ module Doorkeeper
145
208
 
146
209
  module CustomGeneratorArgs
147
210
  def self.generate(_opts = {})
148
- raise LoadError, 'custom behaviour'
211
+ raise LoadError, "custom behaviour"
149
212
  end
150
213
  end
151
214
 
@@ -159,7 +222,7 @@ module Doorkeeper
159
222
  )
160
223
  end
161
224
 
162
- it 'raises an error if the custom object does not exist' do
225
+ it "raises an error if the custom object does not exist" do
163
226
  Doorkeeper.configure do
164
227
  orm DOORKEEPER_ORM
165
228
  access_token_generator "Doorkeeper::NotReal"
@@ -172,24 +235,24 @@ module Doorkeeper
172
235
  end
173
236
 
174
237
  describe :refresh_token do
175
- it 'has empty refresh token if it was not required' do
238
+ it "has empty refresh token if it was not required" do
176
239
  token = FactoryBot.create :access_token
177
240
  expect(token.refresh_token).to be_nil
178
241
  end
179
242
 
180
- it 'generates a refresh token if it was requested' do
243
+ it "generates a refresh token if it was requested" do
181
244
  token = FactoryBot.create :access_token, use_refresh_token: true
182
245
  expect(token.refresh_token).not_to be_nil
183
246
  end
184
247
 
185
- it 'is not valid if token exists' do
248
+ it "is not valid if token exists" do
186
249
  token1 = FactoryBot.create :access_token, use_refresh_token: true
187
250
  token2 = FactoryBot.create :access_token, use_refresh_token: true
188
251
  token2.refresh_token = token1.refresh_token
189
252
  expect(token2).not_to be_valid
190
253
  end
191
254
 
192
- it 'expects database to raise an error if refresh tokens are the same' do
255
+ it "expects database to raise an error if refresh tokens are the same" do
193
256
  token1 = FactoryBot.create :access_token, use_refresh_token: true
194
257
  token2 = FactoryBot.create :access_token, use_refresh_token: true
195
258
  expect do
@@ -197,26 +260,85 @@ module Doorkeeper
197
260
  token2.save(validate: false)
198
261
  end.to raise_error(uniqueness_error)
199
262
  end
263
+
264
+ context "with hashing enabled" do
265
+ include_context "with token hashing enabled"
266
+ let(:token) { FactoryBot.create :access_token, use_refresh_token: true }
267
+
268
+ it "holds a volatile refresh token when created" do
269
+ expect(token.plaintext_refresh_token).to be_a(String)
270
+ expect(token.refresh_token)
271
+ .to eq(hashed_or_plain_token_func.call(token.plaintext_refresh_token))
272
+
273
+ # Finder method only finds the hashed token
274
+ loaded = clazz.find_by(refresh_token: token.refresh_token)
275
+ expect(loaded).to eq(token)
276
+ expect(loaded.plaintext_refresh_token).to be_nil
277
+ expect(loaded.refresh_token).to eq(token.refresh_token)
278
+ end
279
+
280
+ it "does not find_by plain text refresh tokens" do
281
+ expect(clazz.find_by(refresh_token: token.plaintext_refresh_token)).to be_nil
282
+ end
283
+
284
+ describe "with having a plain text token" do
285
+ let(:plain_refresh_token) { "plain refresh token" }
286
+ let(:access_token) { FactoryBot.create :access_token }
287
+
288
+ before do
289
+ # Assume we have a plain text token from before activating the option
290
+ access_token.update_column(:refresh_token, plain_refresh_token)
291
+ end
292
+
293
+ context "without fallback lookup" do
294
+ it "does not provide lookups with either through by_token" do
295
+ expect(clazz.by_refresh_token(plain_refresh_token)).to eq(nil)
296
+ expect(clazz.by_refresh_token(access_token.refresh_token)).to eq(nil)
297
+
298
+ # And it does not touch the token
299
+ access_token.reload
300
+ expect(access_token.refresh_token).to eq(plain_refresh_token)
301
+ end
302
+ end
303
+
304
+ context "with fallback lookup" do
305
+ include_context "with token hashing and fallback lookup enabled"
306
+
307
+ it "upgrades a plain token when falling back to it" do
308
+ # Side-effect: This will automatically upgrade the token
309
+ expect(clazz).to receive(:upgrade_fallback_value).and_call_original
310
+ expect(clazz.by_refresh_token(plain_refresh_token)).to eq(access_token)
311
+
312
+ # Will find subsequently by hashing the token
313
+ expect(clazz.by_refresh_token(plain_refresh_token)).to eq(access_token)
314
+
315
+ # And it modifies the token value
316
+ access_token.reload
317
+ expect(access_token.refresh_token).not_to eq(plain_refresh_token)
318
+ expect(clazz.find_by(refresh_token: plain_refresh_token)).to eq(nil)
319
+ expect(clazz.find_by(refresh_token: access_token.refresh_token)).not_to be_nil
320
+ end
321
+ end
322
+ end
323
+ end
200
324
  end
201
325
 
202
- describe 'validations' do
203
- it 'is valid without resource_owner_id' do
326
+ describe "validations" do
327
+ it "is valid without resource_owner_id" do
204
328
  # For client credentials flow
205
329
  subject.resource_owner_id = nil
206
330
  expect(subject).to be_valid
207
331
  end
208
332
 
209
- it 'is valid without application_id' do
333
+ it "is valid without application_id" do
210
334
  # For resource owner credentials flow
211
335
  subject.application_id = nil
212
336
  expect(subject).to be_valid
213
337
  end
214
338
  end
215
339
 
216
- describe '#same_credential?' do
217
-
218
- context 'with default parameters' do
219
-
340
+ describe "#same_credential?" do
341
+ context "with default parameters" do
220
342
  let(:resource_owner_id) { 100 }
221
343
  let(:application) { FactoryBot.create :application }
222
344
  let(:default_attributes) do
@@ -224,80 +346,87 @@ module Doorkeeper
224
346
  end
225
347
  let(:access_token1) { FactoryBot.create :access_token, default_attributes }
226
348
 
227
- context 'the second token has the same owner and same app' do
349
+ context "the second token has the same owner and same app" do
228
350
  let(:access_token2) { FactoryBot.create :access_token, default_attributes }
229
- it 'success' do
351
+ it "success" do
230
352
  expect(access_token1.same_credential?(access_token2)).to be_truthy
231
353
  end
232
354
  end
233
355
 
234
- context 'the second token has same owner and different app' do
356
+ context "the second token has same owner and different app" do
235
357
  let(:other_application) { FactoryBot.create :application }
236
- let(:access_token2) { FactoryBot.create :access_token, application: other_application, resource_owner_id: resource_owner_id }
358
+ let(:access_token2) do
359
+ FactoryBot.create :access_token,
360
+ application: other_application,
361
+ resource_owner_id: resource_owner_id
362
+ end
237
363
 
238
- it 'fail' do
364
+ it "fail" do
239
365
  expect(access_token1.same_credential?(access_token2)).to be_falsey
240
366
  end
241
367
  end
242
368
 
243
- context 'the second token has different owner and different app' do
244
-
369
+ context "the second token has different owner and different app" do
245
370
  let(:other_application) { FactoryBot.create :application }
246
- let(:access_token2) { FactoryBot.create :access_token, application: other_application, resource_owner_id: 42 }
371
+ let(:access_token2) do
372
+ FactoryBot.create :access_token, application: other_application, resource_owner_id: 42
373
+ end
247
374
 
248
- it 'fail' do
375
+ it "fail" do
249
376
  expect(access_token1.same_credential?(access_token2)).to be_falsey
250
377
  end
251
378
  end
252
379
 
253
- context 'the second token has different owner and same app' do
254
- let(:access_token2) { FactoryBot.create :access_token, application: application, resource_owner_id: 42 }
380
+ context "the second token has different owner and same app" do
381
+ let(:access_token2) do
382
+ FactoryBot.create :access_token, application: application, resource_owner_id: 42
383
+ end
255
384
 
256
- it 'fail' do
385
+ it "fail" do
257
386
  expect(access_token1.same_credential?(access_token2)).to be_falsey
258
387
  end
259
388
  end
260
389
  end
261
390
  end
262
391
 
263
- describe '#acceptable?' do
264
- context 'a token that is not accessible' do
392
+ describe "#acceptable?" do
393
+ context "a token that is not accessible" do
265
394
  let(:token) { FactoryBot.create(:access_token, created_at: 6.hours.ago) }
266
395
 
267
- it 'should return false' do
396
+ it "should return false" do
268
397
  expect(token.acceptable?(nil)).to be false
269
398
  end
270
399
  end
271
400
 
272
- context 'a token that has the incorrect scopes' do
401
+ context "a token that has the incorrect scopes" do
273
402
  let(:token) { FactoryBot.create(:access_token) }
274
403
 
275
- it 'should return false' do
276
- expect(token.acceptable?(['public'])).to be false
404
+ it "should return false" do
405
+ expect(token.acceptable?(["public"])).to be false
277
406
  end
278
407
  end
279
408
 
280
- context 'a token is acceptable with the correct scopes' do
409
+ context "a token is acceptable with the correct scopes" do
281
410
  let(:token) do
282
411
  token = FactoryBot.create(:access_token)
283
- token[:scopes] = 'public'
412
+ token[:scopes] = "public"
284
413
  token
285
414
  end
286
415
 
287
- it 'should return true' do
288
- expect(token.acceptable?(['public'])).to be true
416
+ it "should return true" do
417
+ expect(token.acceptable?(["public"])).to be true
289
418
  end
290
419
  end
291
420
  end
292
421
 
293
- describe '.revoke_all_for' do
422
+ describe ".revoke_all_for" do
294
423
  let(:resource_owner) { double(id: 100) }
295
424
  let(:application) { FactoryBot.create :application }
296
425
  let(:default_attributes) do
297
426
  { application: application, resource_owner_id: resource_owner.id }
298
427
  end
299
428
 
300
- it 'revokes all tokens for given application and resource owner' do
429
+ it "revokes all tokens for given application and resource owner" do
301
430
  FactoryBot.create :access_token, default_attributes
302
431
  AccessToken.revoke_all_for application.id, resource_owner
303
432
  AccessToken.all.each do |token|
@@ -305,7 +434,7 @@ module Doorkeeper
305
434
  end
306
435
  end
307
436
 
308
- it 'matches application' do
437
+ it "matches application" do
309
438
  access_token_for_different_app = FactoryBot.create(
310
439
  :access_token,
311
440
  default_attributes.merge(application: FactoryBot.create(:application))
@@ -316,7 +445,7 @@ module Doorkeeper
316
445
  expect(access_token_for_different_app.reload).not_to be_revoked
317
446
  end
318
447
 
319
- it 'matches resource owner' do
448
+ it "matches resource owner" do
320
449
  access_token_for_different_owner = FactoryBot.create(
321
450
  :access_token,
322
451
  default_attributes.merge(resource_owner_id: 90)
@@ -328,15 +457,15 @@ module Doorkeeper
328
457
  end
329
458
  end
330
459
 
331
- describe '.matching_token_for' do
460
+ describe ".matching_token_for" do
332
461
  let(:resource_owner_id) { 100 }
333
462
  let(:application) { FactoryBot.create :application }
334
- let(:scopes) { Doorkeeper::OAuth::Scopes.from_string('public write') }
463
+ let(:scopes) { Doorkeeper::OAuth::Scopes.from_string("public write") }
335
464
  let(:default_attributes) do
336
465
  {
337
466
  application: application,
338
467
  resource_owner_id: resource_owner_id,
339
- scopes: scopes.to_s
468
+ scopes: scopes.to_s,
340
469
  }
341
470
  end
342
471
 
@@ -344,26 +473,26 @@ module Doorkeeper
344
473
  default_scopes_exist(*scopes.all)
345
474
  end
346
475
 
347
- it 'returns only one token' do
476
+ it "returns only one token" do
348
477
  token = FactoryBot.create :access_token, default_attributes
349
478
  last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
350
479
  expect(last_token).to eq(token)
351
480
  end
352
481
 
353
- it 'accepts resource owner as object' do
482
+ it "accepts resource owner as object" do
354
483
  resource_owner = double(to_key: true, id: 100)
355
484
  token = FactoryBot.create :access_token, default_attributes
356
485
  last_token = AccessToken.matching_token_for(application, resource_owner, scopes)
357
486
  expect(last_token).to eq(token)
358
487
  end
359
488
 
360
- it 'accepts nil as resource owner' do
489
+ it "accepts nil as resource owner" do
361
490
  token = FactoryBot.create :access_token, default_attributes.merge(resource_owner_id: nil)
362
491
  last_token = AccessToken.matching_token_for(application, nil, scopes)
363
492
  expect(last_token).to eq(token)
364
493
  end
365
494
 
366
- it 'excludes revoked tokens' do
495
+ it "excludes revoked tokens" do
367
496
  FactoryBot.create :access_token, default_attributes.merge(revoked_at: 1.day.ago)
368
497
  last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
369
498
  expect(last_token).to be_nil
@@ -382,32 +511,32 @@ module Doorkeeper
382
511
  end
383
512
 
384
513
  it "excludes tokens with fewer scopes" do
385
- FactoryBot.create :access_token, default_attributes.merge(scopes: 'public')
514
+ FactoryBot.create :access_token, default_attributes.merge(scopes: "public")
386
515
  last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
387
516
  expect(last_token).to be_nil
388
517
  end
389
518
 
390
- it 'excludes tokens with different scopes' do
391
- FactoryBot.create :access_token, default_attributes.merge(scopes: 'public email')
519
+ it "excludes tokens with different scopes" do
520
+ FactoryBot.create :access_token, default_attributes.merge(scopes: "public email")
392
521
  last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
393
522
  expect(last_token).to be_nil
394
523
  end
395
524
 
396
- it 'excludes tokens with additional scopes' do
397
- FactoryBot.create :access_token, default_attributes.merge(scopes: 'public write email')
525
+ it "excludes tokens with additional scopes" do
526
+ FactoryBot.create :access_token, default_attributes.merge(scopes: "public write email")
398
527
  last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
399
528
  expect(last_token).to be_nil
400
529
  end
401
530
 
402
- it 'excludes tokens with scopes that are not present in server scopes' do
531
+ it "excludes tokens with scopes that are not present in server scopes" do
403
532
  FactoryBot.create :access_token, default_attributes.merge(
404
- application: application, scopes: 'public read'
533
+ application: application, scopes: "public read"
405
534
  )
406
535
  last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
407
536
  expect(last_token).to be_nil
408
537
  end
409
538
 
410
- it 'excludes tokens with scopes that are not present in application scopes' do
539
+ it "excludes tokens with scopes that are not present in application scopes" do
411
540
  application = FactoryBot.create :application, scopes: "private read"
412
541
  FactoryBot.create :access_token, default_attributes.merge(
413
542
  application: application
@@ -416,11 +545,11 @@ module Doorkeeper
416
545
  expect(last_token).to be_nil
417
546
  end
418
547
 
419
- it 'does not match token if empty scope requested and token/app scopes present' do
548
+ it "does not match token if empty scope requested and token/app scopes present" do
420
549
  application = FactoryBot.create :application, scopes: "sample:scope"
421
550
  app_params = {
422
551
  application_id: application.id, scopes: "sample:scope",
423
- resource_owner_id: 100
552
+ resource_owner_id: 100,
424
553
  }
425
554
  FactoryBot.create :access_token, app_params
426
555
  empty_scopes = Doorkeeper::OAuth::Scopes.from_string("")
@@ -428,17 +557,17 @@ module Doorkeeper
428
557
  expect(last_token).to be_nil
429
558
  end
430
559
 
431
- it 'matches token if empty scope requested and no token scopes present' do
560
+ it "matches token if empty scope requested and no token scopes present" do
432
561
  empty_scopes = Doorkeeper::OAuth::Scopes.from_string("")
433
562
  token = FactoryBot.create :access_token, default_attributes.merge(scopes: empty_scopes)
434
563
  last_token = AccessToken.matching_token_for(application, 100, empty_scopes)
435
564
  expect(last_token).to eq(token)
436
565
  end
437
566
 
438
- it 'returns the last matching token' do
567
+ it "returns the last matching token" do
439
568
  FactoryBot.create :access_token, default_attributes.merge(created_at: 1.day.ago)
440
569
  matching_token = FactoryBot.create :access_token, default_attributes
441
- FactoryBot.create :access_token, default_attributes.merge(scopes: 'public')
570
+ FactoryBot.create :access_token, default_attributes.merge(scopes: "public")
442
571
 
443
572
  last_token = AccessToken.matching_token_for(application, resource_owner_id, scopes)
444
573
  expect(last_token).to eq(matching_token)
@@ -449,11 +578,11 @@ module Doorkeeper
449
578
  it "returns as_json hash" do
450
579
  token = FactoryBot.create :access_token
451
580
  token_hash = {
452
- resource_owner_id: token.resource_owner_id,
453
- scope: token.scopes,
454
- expires_in: token.expires_in_seconds,
455
- application: { uid: token.application.uid },
456
- created_at: token.created_at.to_i
581
+ resource_owner_id: token.resource_owner_id,
582
+ scope: token.scopes,
583
+ expires_in: token.expires_in_seconds,
584
+ application: { uid: token.application.uid },
585
+ created_at: token.created_at.to_i,
457
586
  }
458
587
  expect(token.as_json).to eq token_hash
459
588
  end