doorkeeper 4.4.3 → 5.0.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of doorkeeper might be problematic. Click here for more details.

Files changed (223) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.gitlab-ci.yml +16 -0
  4. data/.travis.yml +7 -0
  5. data/Appraisals +2 -2
  6. data/Dangerfile +64 -0
  7. data/Gemfile +1 -1
  8. data/NEWS.md +98 -8
  9. data/README.md +110 -12
  10. data/Rakefile +6 -0
  11. data/UPGRADE.md +2 -0
  12. data/app/assets/stylesheets/doorkeeper/admin/application.css +2 -2
  13. data/app/controllers/doorkeeper/application_controller.rb +6 -3
  14. data/app/controllers/doorkeeper/application_metal_controller.rb +6 -0
  15. data/app/controllers/doorkeeper/applications_controller.rb +46 -24
  16. data/app/controllers/doorkeeper/authorizations_controller.rb +55 -12
  17. data/app/controllers/doorkeeper/authorized_applications_controller.rb +21 -2
  18. data/app/controllers/doorkeeper/token_info_controller.rb +2 -0
  19. data/app/controllers/doorkeeper/tokens_controller.rb +4 -6
  20. data/app/helpers/doorkeeper/dashboard_helper.rb +9 -7
  21. data/app/validators/redirect_uri_validator.rb +5 -2
  22. data/app/views/doorkeeper/applications/_delete_form.html.erb +3 -1
  23. data/app/views/doorkeeper/applications/_form.html.erb +25 -24
  24. data/app/views/doorkeeper/applications/edit.html.erb +1 -1
  25. data/app/views/doorkeeper/applications/index.html.erb +17 -7
  26. data/app/views/doorkeeper/applications/new.html.erb +1 -1
  27. data/app/views/doorkeeper/applications/show.html.erb +6 -6
  28. data/app/views/doorkeeper/authorizations/error.html.erb +1 -1
  29. data/app/views/doorkeeper/authorizations/new.html.erb +4 -0
  30. data/app/views/layouts/doorkeeper/admin.html.erb +15 -15
  31. data/config/locales/en.yml +10 -1
  32. data/doorkeeper.gemspec +25 -26
  33. data/gemfiles/rails_5_2.gemfile +1 -1
  34. data/gemfiles/rails_master.gemfile +4 -1
  35. data/lib/doorkeeper/config.rb +81 -40
  36. data/lib/doorkeeper/engine.rb +6 -0
  37. data/lib/doorkeeper/errors.rb +17 -3
  38. data/lib/doorkeeper/grape/authorization_decorator.rb +2 -0
  39. data/lib/doorkeeper/grape/helpers.rb +3 -1
  40. data/lib/doorkeeper/helpers/controller.rb +9 -2
  41. data/lib/doorkeeper/models/access_grant_mixin.rb +73 -0
  42. data/lib/doorkeeper/models/access_token_mixin.rb +44 -25
  43. data/lib/doorkeeper/models/application_mixin.rb +2 -0
  44. data/lib/doorkeeper/models/concerns/accessible.rb +2 -0
  45. data/lib/doorkeeper/models/concerns/expirable.rb +2 -0
  46. data/lib/doorkeeper/models/concerns/orderable.rb +2 -0
  47. data/lib/doorkeeper/models/concerns/ownership.rb +2 -0
  48. data/lib/doorkeeper/models/concerns/revocable.rb +2 -0
  49. data/lib/doorkeeper/models/concerns/scopes.rb +3 -1
  50. data/lib/doorkeeper/oauth/authorization/code.rb +33 -8
  51. data/lib/doorkeeper/oauth/authorization/context.rb +17 -0
  52. data/lib/doorkeeper/oauth/authorization/token.rb +38 -14
  53. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +2 -0
  54. data/lib/doorkeeper/oauth/authorization_code_request.rb +29 -2
  55. data/lib/doorkeeper/oauth/base_request.rb +22 -9
  56. data/lib/doorkeeper/oauth/base_response.rb +2 -0
  57. data/lib/doorkeeper/oauth/client/credentials.rb +3 -1
  58. data/lib/doorkeeper/oauth/client.rb +1 -1
  59. data/lib/doorkeeper/oauth/client_credentials/creator.rb +4 -1
  60. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +7 -2
  61. data/lib/doorkeeper/oauth/client_credentials/validation.rb +5 -5
  62. data/lib/doorkeeper/oauth/client_credentials_request.rb +1 -3
  63. data/lib/doorkeeper/oauth/code_request.rb +2 -0
  64. data/lib/doorkeeper/oauth/code_response.rb +2 -0
  65. data/lib/doorkeeper/oauth/error.rb +2 -0
  66. data/lib/doorkeeper/oauth/error_response.rb +21 -3
  67. data/lib/doorkeeper/oauth/forbidden_token_response.rb +9 -2
  68. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +2 -8
  69. data/lib/doorkeeper/oauth/helpers/unique_token.rb +2 -0
  70. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +5 -2
  71. data/lib/doorkeeper/oauth/invalid_token_response.rb +18 -0
  72. data/lib/doorkeeper/oauth/password_access_token_request.rb +9 -4
  73. data/lib/doorkeeper/oauth/pre_authorization.rb +43 -11
  74. data/lib/doorkeeper/oauth/refresh_token_request.rb +16 -3
  75. data/lib/doorkeeper/oauth/scopes.rb +3 -1
  76. data/lib/doorkeeper/oauth/token.rb +7 -2
  77. data/lib/doorkeeper/oauth/token_introspection.rb +4 -2
  78. data/lib/doorkeeper/oauth/token_request.rb +2 -0
  79. data/lib/doorkeeper/oauth/token_response.rb +6 -2
  80. data/lib/doorkeeper/oauth.rb +13 -0
  81. data/lib/doorkeeper/orm/active_record/application.rb +75 -12
  82. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +26 -0
  83. data/lib/doorkeeper/orm/active_record.rb +4 -0
  84. data/lib/doorkeeper/rails/helpers.rb +6 -4
  85. data/lib/doorkeeper/rails/routes/mapper.rb +2 -0
  86. data/lib/doorkeeper/rails/routes/mapping.rb +2 -0
  87. data/lib/doorkeeper/rails/routes.rb +23 -8
  88. data/lib/doorkeeper/rake/db.rake +40 -0
  89. data/lib/doorkeeper/rake/setup.rake +6 -0
  90. data/lib/doorkeeper/rake.rb +14 -0
  91. data/lib/doorkeeper/request/authorization_code.rb +1 -1
  92. data/lib/doorkeeper/request/client_credentials.rb +1 -1
  93. data/lib/doorkeeper/request/code.rb +1 -1
  94. data/lib/doorkeeper/request/password.rb +1 -1
  95. data/lib/doorkeeper/request/refresh_token.rb +1 -1
  96. data/lib/doorkeeper/request/strategy.rb +2 -0
  97. data/lib/doorkeeper/request/token.rb +1 -1
  98. data/lib/doorkeeper/request.rb +29 -34
  99. data/lib/doorkeeper/server.rb +2 -0
  100. data/lib/doorkeeper/stale_records_cleaner.rb +20 -0
  101. data/lib/doorkeeper/validations.rb +2 -0
  102. data/lib/doorkeeper/version.rb +6 -24
  103. data/lib/doorkeeper.rb +20 -17
  104. data/lib/generators/doorkeeper/application_owner_generator.rb +23 -18
  105. data/lib/generators/doorkeeper/confidential_applications_generator.rb +32 -0
  106. data/lib/generators/doorkeeper/install_generator.rb +17 -9
  107. data/lib/generators/doorkeeper/migration_generator.rb +23 -18
  108. data/lib/generators/doorkeeper/pkce_generator.rb +32 -0
  109. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +29 -24
  110. data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
  111. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +6 -0
  112. data/lib/generators/doorkeeper/templates/initializer.rb +96 -13
  113. data/lib/generators/doorkeeper/templates/migration.rb.erb +2 -3
  114. data/lib/generators/doorkeeper/views_generator.rb +3 -1
  115. data/spec/controllers/application_metal_controller_spec.rb +50 -0
  116. data/spec/controllers/applications_controller_spec.rb +123 -14
  117. data/spec/controllers/authorizations_controller_spec.rb +334 -51
  118. data/spec/controllers/protected_resources_controller_spec.rb +60 -18
  119. data/spec/controllers/token_info_controller_spec.rb +4 -12
  120. data/spec/controllers/tokens_controller_spec.rb +17 -20
  121. data/spec/dummy/Rakefile +1 -1
  122. data/spec/dummy/app/assets/config/manifest.js +2 -0
  123. data/spec/dummy/app/controllers/custom_authorizations_controller.rb +1 -1
  124. data/spec/dummy/app/controllers/home_controller.rb +1 -2
  125. data/spec/dummy/config/application.rb +1 -1
  126. data/spec/dummy/config/boot.rb +2 -4
  127. data/spec/dummy/config/environment.rb +1 -1
  128. data/spec/dummy/config/environments/test.rb +5 -6
  129. data/spec/dummy/config/initializers/doorkeeper.rb +12 -6
  130. data/spec/dummy/config/initializers/new_framework_defaults.rb +2 -0
  131. data/spec/dummy/config/initializers/secret_token.rb +1 -1
  132. data/spec/dummy/config/routes.rb +3 -42
  133. data/spec/dummy/config.ru +1 -1
  134. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +4 -4
  135. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +1 -1
  136. data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +6 -0
  137. data/spec/dummy/db/migrate/{20180210183654_add_confidential_to_application.rb → 20180210183654_add_confidential_to_applications.rb} +1 -1
  138. data/spec/dummy/db/schema.rb +36 -36
  139. data/spec/dummy/script/rails +4 -3
  140. data/spec/factories.rb +6 -6
  141. data/spec/generators/application_owner_generator_spec.rb +1 -1
  142. data/spec/generators/confidential_applications_generator_spec.rb +45 -0
  143. data/spec/generators/install_generator_spec.rb +5 -2
  144. data/spec/generators/migration_generator_spec.rb +1 -1
  145. data/spec/generators/pkce_generator_spec.rb +43 -0
  146. data/spec/generators/previous_refresh_token_generator_spec.rb +1 -1
  147. data/spec/generators/templates/routes.rb +0 -1
  148. data/spec/generators/views_generator_spec.rb +2 -2
  149. data/spec/grape/grape_integration_spec.rb +2 -2
  150. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +1 -1
  151. data/spec/lib/config_spec.rb +105 -39
  152. data/spec/lib/doorkeeper_spec.rb +6 -131
  153. data/spec/lib/models/expirable_spec.rb +0 -3
  154. data/spec/lib/models/revocable_spec.rb +0 -2
  155. data/spec/lib/models/scopes_spec.rb +0 -4
  156. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -4
  157. data/spec/lib/oauth/authorization_code_request_spec.rb +17 -7
  158. data/spec/lib/oauth/base_request_spec.rb +49 -11
  159. data/spec/lib/oauth/base_response_spec.rb +1 -1
  160. data/spec/lib/oauth/client/credentials_spec.rb +2 -4
  161. data/spec/lib/oauth/client_credentials/creator_spec.rb +5 -1
  162. data/spec/lib/oauth/client_credentials/issuer_spec.rb +24 -7
  163. data/spec/lib/oauth/client_credentials/validation_spec.rb +4 -4
  164. data/spec/lib/oauth/client_credentials_integration_spec.rb +2 -2
  165. data/spec/lib/oauth/client_credentials_request_spec.rb +3 -5
  166. data/spec/lib/oauth/client_spec.rb +0 -3
  167. data/spec/lib/oauth/code_request_spec.rb +5 -3
  168. data/spec/lib/oauth/code_response_spec.rb +1 -1
  169. data/spec/lib/oauth/error_response_spec.rb +0 -3
  170. data/spec/lib/oauth/error_spec.rb +0 -2
  171. data/spec/lib/oauth/forbidden_token_response_spec.rb +1 -4
  172. data/spec/lib/oauth/helpers/scope_checker_spec.rb +8 -11
  173. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -1
  174. data/spec/lib/oauth/helpers/uri_checker_spec.rb +22 -13
  175. data/spec/lib/oauth/invalid_token_response_spec.rb +1 -4
  176. data/spec/lib/oauth/password_access_token_request_spec.rb +53 -6
  177. data/spec/lib/oauth/pre_authorization_spec.rb +33 -4
  178. data/spec/lib/oauth/refresh_token_request_spec.rb +22 -14
  179. data/spec/lib/oauth/scopes_spec.rb +0 -3
  180. data/spec/lib/oauth/token_request_spec.rb +8 -9
  181. data/spec/lib/oauth/token_response_spec.rb +0 -1
  182. data/spec/lib/oauth/token_spec.rb +40 -14
  183. data/spec/lib/request/strategy_spec.rb +0 -1
  184. data/spec/lib/server_spec.rb +7 -7
  185. data/spec/lib/stale_records_cleaner_spec.rb +89 -0
  186. data/spec/models/doorkeeper/access_grant_spec.rb +44 -1
  187. data/spec/models/doorkeeper/access_token_spec.rb +80 -32
  188. data/spec/models/doorkeeper/application_spec.rb +293 -221
  189. data/spec/requests/applications/applications_request_spec.rb +134 -1
  190. data/spec/requests/applications/authorized_applications_spec.rb +1 -1
  191. data/spec/requests/endpoints/authorization_spec.rb +3 -3
  192. data/spec/requests/endpoints/token_spec.rb +7 -5
  193. data/spec/requests/flows/authorization_code_errors_spec.rb +2 -2
  194. data/spec/requests/flows/authorization_code_spec.rb +258 -2
  195. data/spec/requests/flows/client_credentials_spec.rb +46 -6
  196. data/spec/requests/flows/implicit_grant_errors_spec.rb +3 -3
  197. data/spec/requests/flows/implicit_grant_spec.rb +38 -11
  198. data/spec/requests/flows/password_spec.rb +61 -3
  199. data/spec/requests/flows/refresh_token_spec.rb +59 -2
  200. data/spec/requests/flows/revoke_token_spec.rb +20 -20
  201. data/spec/requests/flows/skip_authorization_spec.rb +16 -11
  202. data/spec/requests/protected_resources/metal_spec.rb +1 -1
  203. data/spec/requests/protected_resources/private_api_spec.rb +3 -3
  204. data/spec/routing/custom_controller_routes_spec.rb +59 -7
  205. data/spec/routing/default_routes_spec.rb +2 -2
  206. data/spec/routing/scoped_routes_spec.rb +16 -2
  207. data/spec/spec_helper.rb +54 -3
  208. data/spec/spec_helper_integration.rb +2 -74
  209. data/spec/support/dependencies/{factory_girl.rb → factory_bot.rb} +0 -0
  210. data/spec/support/doorkeeper_rspec.rb +20 -0
  211. data/spec/support/helpers/authorization_request_helper.rb +4 -4
  212. data/spec/support/helpers/model_helper.rb +8 -4
  213. data/spec/support/helpers/request_spec_helper.rb +10 -2
  214. data/spec/support/helpers/url_helper.rb +18 -14
  215. data/spec/support/http_method_shim.rb +12 -16
  216. data/spec/support/shared/controllers_shared_context.rb +56 -0
  217. data/spec/validators/redirect_uri_validator_spec.rb +9 -3
  218. data/spec/version/version_spec.rb +3 -3
  219. data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
  220. metadata +54 -35
  221. data/lib/generators/doorkeeper/add_client_confidentiality_generator.rb +0 -31
  222. data/lib/generators/doorkeeper/templates/add_confidential_to_application_migration.rb.erb +0 -11
  223. data/spec/controllers/application_metal_controller.rb +0 -10
@@ -1,302 +1,374 @@
1
- require 'spec_helper_integration'
1
+ # frozen_string_literal: true
2
2
 
3
- module Doorkeeper
4
- 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) }
7
- let(:new_application) { FactoryBot.build(:application) }
3
+ require "spec_helper"
8
4
 
9
- let(:uid) { SecureRandom.hex(8) }
10
- let(:secret) { SecureRandom.hex(8) }
5
+ describe Doorkeeper::Application do
6
+ let(:require_owner) { Doorkeeper.configuration.instance_variable_set("@confirm_application_owner", true) }
7
+ let(:unset_require_owner) { Doorkeeper.configuration.instance_variable_set("@confirm_application_owner", false) }
8
+ let(:new_application) { FactoryBot.build(:application) }
11
9
 
12
- context 'application_owner is enabled' do
13
- before do
14
- Doorkeeper.configure do
15
- orm DOORKEEPER_ORM
16
- enable_application_owner
17
- end
18
- end
10
+ let(:uid) { SecureRandom.hex(8) }
11
+ let(:secret) { SecureRandom.hex(8) }
19
12
 
20
- context 'application owner is not required' do
21
- before(:each) do
22
- unset_require_owner
23
- end
13
+ it "is invalid without a name" do
14
+ new_application.name = nil
15
+ expect(new_application).not_to be_valid
16
+ end
24
17
 
25
- it 'is valid given valid attributes' do
26
- expect(new_application).to be_valid
27
- end
28
- end
18
+ it "is invalid without determining confidentiality" do
19
+ new_application.confidential = nil
20
+ expect(new_application).not_to be_valid
21
+ end
29
22
 
30
- context 'application owner is required' do
31
- before(:each) do
32
- require_owner
33
- @owner = FactoryBot.build_stubbed(:doorkeeper_testing_user)
34
- end
23
+ it "generates uid on create" do
24
+ expect(new_application.uid).to be_nil
25
+ new_application.save
26
+ expect(new_application.uid).not_to be_nil
27
+ end
35
28
 
36
- it 'is invalid without an owner' do
37
- expect(new_application).not_to be_valid
38
- end
29
+ it "generates uid on create if an empty string" do
30
+ new_application.uid = ""
31
+ new_application.save
32
+ expect(new_application.uid).not_to be_blank
33
+ end
39
34
 
40
- it 'is valid with an owner' do
41
- new_application.owner = @owner
42
- expect(new_application).to be_valid
43
- end
35
+ it "generates uid on create unless one is set" do
36
+ new_application.uid = uid
37
+ new_application.save
38
+ expect(new_application.uid).to eq(uid)
39
+ end
40
+
41
+ it "is invalid without uid" do
42
+ new_application.save
43
+ new_application.uid = nil
44
+ expect(new_application).not_to be_valid
45
+ end
46
+
47
+ it "checks uniqueness of uid" do
48
+ app1 = FactoryBot.create(:application)
49
+ app2 = FactoryBot.create(:application)
50
+ app2.uid = app1.uid
51
+ expect(app2).not_to be_valid
52
+ end
53
+
54
+ it "expects database to throw an error when uids are the same" do
55
+ app1 = FactoryBot.create(:application)
56
+ app2 = FactoryBot.create(:application)
57
+ app2.uid = app1.uid
58
+ expect { app2.save!(validate: false) }.to raise_error(uniqueness_error)
59
+ end
60
+
61
+ it "generate secret on create" do
62
+ expect(new_application.secret).to be_nil
63
+ new_application.save
64
+ expect(new_application.secret).not_to be_nil
65
+ end
66
+
67
+ it "generate secret on create if is blank string" do
68
+ new_application.secret = ""
69
+ new_application.save
70
+ expect(new_application.secret).not_to be_blank
71
+ end
72
+
73
+ it "generate secret on create unless one is set" do
74
+ new_application.secret = secret
75
+ new_application.save
76
+ expect(new_application.secret).to eq(secret)
77
+ end
78
+
79
+ it "is invalid without secret" do
80
+ new_application.save
81
+ new_application.secret = nil
82
+ expect(new_application).not_to be_valid
83
+ end
84
+
85
+ context "application_owner is enabled" do
86
+ before do
87
+ Doorkeeper.configure do
88
+ orm DOORKEEPER_ORM
89
+ enable_application_owner
44
90
  end
45
91
  end
46
92
 
47
- it 'is invalid without a name' do
48
- new_application.name = nil
49
- expect(new_application).not_to be_valid
50
- end
93
+ context "application owner is not required" do
94
+ before(:each) do
95
+ unset_require_owner
96
+ end
51
97
 
52
- it 'is invalid without determining confidentiality' do
53
- new_application.confidential = nil
54
- expect(new_application).not_to be_valid
98
+ it "is valid given valid attributes" do
99
+ expect(new_application).to be_valid
100
+ end
55
101
  end
56
102
 
57
- it 'generates uid on create' do
58
- expect(new_application.uid).to be_nil
59
- new_application.save
60
- expect(new_application.uid).not_to be_nil
61
- end
103
+ context "application owner is required" do
104
+ before do
105
+ require_owner
106
+ @owner = FactoryBot.build_stubbed(:doorkeeper_testing_user)
107
+ end
62
108
 
63
- it 'generates uid on create if an empty string' do
64
- new_application.uid = ''
65
- new_application.save
66
- expect(new_application.uid).not_to be_blank
67
- end
109
+ it "is invalid without an owner" do
110
+ expect(new_application).not_to be_valid
111
+ end
68
112
 
69
- it 'generates uid on create unless one is set' do
70
- new_application.uid = uid
71
- new_application.save
72
- expect(new_application.uid).to eq(uid)
113
+ it "is valid with an owner" do
114
+ new_application.owner = @owner
115
+ expect(new_application).to be_valid
116
+ end
73
117
  end
118
+ end
74
119
 
75
- it 'is invalid without uid' do
120
+ context "redirect URI" do
121
+ it "is invalid without redirect_uri" do
76
122
  new_application.save
77
- new_application.uid = nil
123
+ new_application.redirect_uri = nil
78
124
  expect(new_application).not_to be_valid
79
125
  end
126
+ end
80
127
 
81
- it 'is invalid without redirect_uri' do
128
+ describe "destroy related models on cascade" do
129
+ before(:each) do
82
130
  new_application.save
83
- new_application.redirect_uri = nil
84
- expect(new_application).not_to be_valid
85
131
  end
86
132
 
87
- it 'checks uniqueness of uid' do
88
- app1 = FactoryBot.create(:application)
89
- app2 = FactoryBot.create(:application)
90
- app2.uid = app1.uid
91
- expect(app2).not_to be_valid
92
- end
133
+ let(:resource_owner) { FactoryBot.create(:doorkeeper_testing_user) }
93
134
 
94
- it 'expects database to throw an error when uids are the same' do
95
- app1 = FactoryBot.create(:application)
96
- app2 = FactoryBot.create(:application)
97
- app2.uid = app1.uid
98
- expect { app2.save!(validate: false) }.to raise_error(uniqueness_error)
99
- end
135
+ it "should destroy its access grants" do
136
+ FactoryBot.create(
137
+ :access_grant,
138
+ application: new_application,
139
+ resource_owner_id: resource_owner.id,
140
+ )
100
141
 
101
- it 'generate secret on create' do
102
- expect(new_application.secret).to be_nil
103
- new_application.save
104
- expect(new_application.secret).not_to be_nil
142
+ expect { new_application.destroy }.to change { Doorkeeper::AccessGrant.count }.by(-1)
105
143
  end
106
144
 
107
- it 'generate secret on create if is blank string' do
108
- new_application.secret = ''
109
- new_application.save
110
- expect(new_application.secret).not_to be_blank
145
+ it "should destroy its access tokens" do
146
+ FactoryBot.create(:access_token, application: new_application)
147
+ FactoryBot.create(:access_token, application: new_application, revoked_at: Time.now.utc)
148
+ expect do
149
+ new_application.destroy
150
+ end.to change { Doorkeeper::AccessToken.count }.by(-2)
111
151
  end
152
+ end
112
153
 
113
- it 'generate secret on create unless one is set' do
114
- new_application.secret = secret
115
- new_application.save
116
- expect(new_application.secret).to eq(secret)
117
- end
154
+ describe "#ordered_by" do
155
+ let(:applications) { FactoryBot.create_list(:application, 5) }
118
156
 
119
- it 'is invalid without secret' do
120
- new_application.save
121
- new_application.secret = nil
122
- expect(new_application).not_to be_valid
157
+ context "when a direction is not specified" do
158
+ it "calls order with a default order of asc" do
159
+ names = applications.map(&:name).sort
160
+ expect(described_class.ordered_by(:name).map(&:name)).to eq(names)
161
+ end
123
162
  end
124
163
 
125
- describe 'destroy related models on cascade' do
126
- before(:each) do
127
- new_application.save
164
+ context "when a direction is specified" do
165
+ it "calls order with specified direction" do
166
+ names = applications.map(&:name).sort.reverse
167
+ expect(described_class.ordered_by(:name, :desc).map(&:name)).to eq(names)
128
168
  end
169
+ end
170
+ end
129
171
 
130
- it 'should destroy its access grants' do
131
- FactoryBot.create(:access_grant, application: new_application)
132
- expect { new_application.destroy }.to change { Doorkeeper::AccessGrant.count }.by(-1)
172
+ describe "#redirect_uri=" do
173
+ context "when array of valid redirect_uris" do
174
+ it "should join by newline" do
175
+ new_application.redirect_uri = ["http://localhost/callback1", "http://localhost/callback2"]
176
+ expect(new_application.redirect_uri).to eq("http://localhost/callback1\nhttp://localhost/callback2")
133
177
  end
134
-
135
- it 'should destroy its access tokens' do
136
- FactoryBot.create(:access_token, application: new_application)
137
- FactoryBot.create(:access_token, application: new_application, revoked_at: Time.now.utc)
138
- expect do
139
- new_application.destroy
140
- end.to change { Doorkeeper::AccessToken.count }.by(-2)
178
+ end
179
+ context "when string of valid redirect_uris" do
180
+ it "should store as-is" do
181
+ new_application.redirect_uri = "http://localhost/callback1\nhttp://localhost/callback2"
182
+ expect(new_application.redirect_uri).to eq("http://localhost/callback1\nhttp://localhost/callback2")
141
183
  end
142
184
  end
185
+ end
143
186
 
144
- describe :ordered_by do
145
- let(:applications) { FactoryBot.create_list(:application, 5) }
187
+ describe "#authorized_for" do
188
+ let(:resource_owner) { FactoryBot.create(:doorkeeper_testing_user) }
189
+ let(:other_resource_owner) { FactoryBot.create(:doorkeeper_testing_user) }
146
190
 
147
- context 'when a direction is not specified' do
148
- it 'calls order with a default order of asc' do
149
- names = applications.map(&:name).sort
150
- expect(Application.ordered_by(:name).map(&:name)).to eq(names)
151
- end
152
- end
191
+ it "is empty if the application is not authorized for anyone" do
192
+ expect(described_class.authorized_for(resource_owner)).to be_empty
193
+ end
153
194
 
154
- context 'when a direction is specified' do
155
- it 'calls order with specified direction' do
156
- names = applications.map(&:name).sort.reverse
157
- expect(Application.ordered_by(:name, :desc).map(&:name)).to eq(names)
158
- end
159
- end
195
+ it "returns only application for a specific resource owner" do
196
+ FactoryBot.create(
197
+ :access_token,
198
+ resource_owner_id: other_resource_owner.id,
199
+ )
200
+ token = FactoryBot.create(
201
+ :access_token,
202
+ resource_owner_id: resource_owner.id,
203
+ )
204
+ expect(described_class.authorized_for(resource_owner)).to eq([token.application])
160
205
  end
161
206
 
162
- describe "#redirect_uri=" do
163
- context "when array of valid redirect_uris" do
164
- it "should join by newline" do
165
- new_application.redirect_uri = ['http://localhost/callback1', 'http://localhost/callback2']
166
- expect(new_application.redirect_uri).to eq("http://localhost/callback1\nhttp://localhost/callback2")
167
- end
168
- end
169
- context "when string of valid redirect_uris" do
170
- it "should store as-is" do
171
- new_application.redirect_uri = "http://localhost/callback1\nhttp://localhost/callback2"
172
- expect(new_application.redirect_uri).to eq("http://localhost/callback1\nhttp://localhost/callback2")
173
- end
174
- end
207
+ it "excludes revoked tokens" do
208
+ FactoryBot.create(
209
+ :access_token,
210
+ resource_owner_id: resource_owner.id,
211
+ revoked_at: 2.days.ago,
212
+ )
213
+ expect(described_class.authorized_for(resource_owner)).to be_empty
175
214
  end
176
215
 
177
- describe :authorized_for do
178
- let(:resource_owner) { double(:resource_owner, id: 10) }
216
+ it "returns all applications that have been authorized" do
217
+ token1 = FactoryBot.create(
218
+ :access_token,
219
+ resource_owner_id: resource_owner.id,
220
+ )
221
+ token2 = FactoryBot.create(
222
+ :access_token,
223
+ resource_owner_id: resource_owner.id,
224
+ )
225
+ expect(described_class.authorized_for(resource_owner))
226
+ .to eq([token1.application, token2.application])
227
+ end
179
228
 
180
- it 'is empty if the application is not authorized for anyone' do
181
- expect(Application.authorized_for(resource_owner)).to be_empty
182
- end
229
+ it "returns only one application even if it has been authorized twice" do
230
+ application = FactoryBot.create(:application)
231
+ FactoryBot.create(
232
+ :access_token,
233
+ resource_owner_id: resource_owner.id,
234
+ application: application,
235
+ )
236
+ FactoryBot.create(
237
+ :access_token,
238
+ resource_owner_id: resource_owner.id,
239
+ application: application,
240
+ )
241
+ expect(described_class.authorized_for(resource_owner)).to eq([application])
242
+ end
243
+ end
183
244
 
184
- it 'returns only application for a specific resource owner' do
185
- FactoryBot.create(:access_token, resource_owner_id: resource_owner.id + 1)
186
- token = FactoryBot.create(:access_token, resource_owner_id: resource_owner.id)
187
- expect(Application.authorized_for(resource_owner)).to eq([token.application])
188
- end
245
+ describe "#revoke_tokens_and_grants_for" do
246
+ it "revokes all access tokens and access grants" do
247
+ application_id = 42
248
+ resource_owner = double
249
+ expect(Doorkeeper::AccessToken)
250
+ .to receive(:revoke_all_for).with(application_id, resource_owner)
251
+ expect(Doorkeeper::AccessGrant)
252
+ .to receive(:revoke_all_for).with(application_id, resource_owner)
189
253
 
190
- it 'excludes revoked tokens' do
191
- FactoryBot.create(:access_token, resource_owner_id: resource_owner.id, revoked_at: 2.days.ago)
192
- expect(Application.authorized_for(resource_owner)).to be_empty
193
- end
254
+ described_class.revoke_tokens_and_grants_for(application_id, resource_owner)
255
+ end
256
+ end
194
257
 
195
- it 'returns all applications that have been authorized' do
196
- token1 = FactoryBot.create(:access_token, resource_owner_id: resource_owner.id)
197
- token2 = FactoryBot.create(:access_token, resource_owner_id: resource_owner.id)
198
- expect(Application.authorized_for(resource_owner)).to eq([token1.application, token2.application])
258
+ describe "#by_uid_and_secret" do
259
+ context "when application is private/confidential" do
260
+ it "finds the application via uid/secret" do
261
+ app = FactoryBot.create :application
262
+ authenticated = described_class.by_uid_and_secret(app.uid, app.secret)
263
+ expect(authenticated).to eq(app)
199
264
  end
200
-
201
- it 'returns only one application even if it has been authorized twice' do
202
- application = FactoryBot.create(:application)
203
- FactoryBot.create(:access_token, resource_owner_id: resource_owner.id, application: application)
204
- FactoryBot.create(:access_token, resource_owner_id: resource_owner.id, application: application)
205
- expect(Application.authorized_for(resource_owner)).to eq([application])
265
+ context "when secret is wrong" do
266
+ it "should not find the application" do
267
+ app = FactoryBot.create :application
268
+ authenticated = described_class.by_uid_and_secret(app.uid, "bad")
269
+ expect(authenticated).to eq(nil)
270
+ end
206
271
  end
207
272
  end
208
273
 
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)
274
+ context "when application is public/non-confidential" do
275
+ context "when secret is blank" do
276
+ it "should find the application" do
277
+ app = FactoryBot.create :application, confidential: false
278
+ authenticated = described_class.by_uid_and_secret(app.uid, nil)
214
279
  expect(authenticated).to eq(app)
215
280
  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
281
  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
282
+ context "when secret is wrong" do
283
+ it "should not find the application" do
284
+ app = FactoryBot.create :application, confidential: false
285
+ authenticated = described_class.by_uid_and_secret(app.uid, "bad")
286
+ expect(authenticated).to eq(nil)
239
287
  end
240
288
  end
241
289
  end
290
+ end
242
291
 
243
- describe :confidential? do
244
- subject { FactoryBot.create(:application, confidential: confidential).confidential? }
292
+ describe "#confidential?" do
293
+ subject { FactoryBot.create(:application, confidential: confidential).confidential? }
245
294
 
246
- context 'when application is private/confidential' do
247
- let(:confidential) { true }
248
- it { expect(subject).to eq(true) }
249
- end
295
+ context "when application is private/confidential" do
296
+ let(:confidential) { true }
297
+ it { expect(subject).to eq(true) }
298
+ end
250
299
 
251
- context 'when application is public/non-confidential' do
252
- let(:confidential) { false }
253
- it { expect(subject).to eq(false) }
254
- end
300
+ context "when application is public/non-confidential" do
301
+ let(:confidential) { false }
302
+ it { expect(subject).to eq(false) }
255
303
  end
304
+ end
256
305
 
257
- describe :confidential do
258
- subject { FactoryBot.create(:application, confidential: confidential).confidential }
306
+ describe "#as_json" do
307
+ let(:app) { FactoryBot.create :application, secret: "123123123" }
259
308
 
260
- context 'when application is private/confidential' do
261
- let(:confidential) { true }
262
- it { expect(subject).to eq(true) }
309
+ # AR specific feature
310
+ if DOORKEEPER_ORM == :active_record
311
+ it "correctly works with #to_json" do
312
+ ActiveRecord::Base.include_root_in_json = true
313
+ expect(app.to_json(include_root_in_json: true)).to match(/application.+?:\{/)
314
+ ActiveRecord::Base.include_root_in_json = false
263
315
  end
316
+ end
264
317
 
265
- context 'when application is public/non-confidential' do
266
- let(:confidential) { false }
267
- it { expect(subject).to eq(false) }
318
+ context "when called without authorized resource owner" do
319
+ it "includes minimal set of attributes" do
320
+ expect(app.as_json).to match(
321
+ "id" => app.id,
322
+ "name" => app.name,
323
+ "created_at" => anything,
324
+ )
268
325
  end
269
326
 
270
- context 'when the application does not support confidentiality' do
271
- let(:confidential) { false }
327
+ it "includes application UID if it's public" do
328
+ app = FactoryBot.create :application, secret: "123123123", confidential: false
272
329
 
273
- before { allow(Application).to receive(:supports_confidentiality?).and_return(false) }
330
+ expect(app.as_json).to match(
331
+ "id" => app.id,
332
+ "name" => app.name,
333
+ "created_at" => anything,
334
+ "uid" => app.uid,
335
+ )
336
+ end
274
337
 
275
- it 'warns of the CVE' do
276
- expect(ActiveSupport::Deprecation).to receive(:warn).with(
277
- 'You are susceptible to security bug ' \
278
- 'CVE-2018-1000211. Please follow instructions outlined in ' \
279
- 'Doorkeeper::CVE_2018_1000211_WARNING'
338
+ it "respects custom options" do
339
+ expect(app.as_json(except: :id)).not_to include("id")
340
+ expect(app.as_json(only: %i[name created_at secret]))
341
+ .to match(
342
+ "name" => app.name,
343
+ "created_at" => anything,
280
344
  )
281
- Application.new.confidential
282
- end
283
-
284
- it { expect(subject).to eq(true) }
285
345
  end
286
346
  end
287
347
 
288
- describe :supports_confidentiality? do
289
- context 'when no column' do
290
- it 'returns false' do
291
- expect(Application).to receive(:column_names).and_return(%w[foo bar])
292
- expect(Application.supports_confidentiality?).to eq(false)
348
+ context "when called with authorized resource owner" do
349
+ let(:owner) { FactoryBot.create(:doorkeeper_testing_user) }
350
+ let(:other_owner) { FactoryBot.create(:doorkeeper_testing_user) }
351
+ let(:app) { FactoryBot.create(:application, secret: "123123123", owner: owner) }
352
+
353
+ before do
354
+ Doorkeeper.configure do
355
+ orm DOORKEEPER_ORM
356
+ enable_application_owner confirmation: false
293
357
  end
294
358
  end
295
- context 'when column' do
296
- it 'returns true' do
297
- expect(Application).to receive(:column_names).and_return(%w[foo bar confidential])
298
- expect(Application.supports_confidentiality?).to eq(true)
299
- end
359
+
360
+ it "includes all the attributes" do
361
+ expect(app.as_json(current_resource_owner: owner))
362
+ .to include(
363
+ "secret" => "123123123",
364
+ "redirect_uri" => app.redirect_uri,
365
+ "uid" => app.uid,
366
+ )
367
+ end
368
+
369
+ it "doesn't include unsafe attributes if current owner isn't the same as owner" do
370
+ expect(app.as_json(current_resource_owner: other_owner))
371
+ .not_to include("redirect_uri")
300
372
  end
301
373
  end
302
374
  end