doorkeeper 4.4.3 → 5.0.0

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 (181) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.gitlab-ci.yml +16 -0
  4. data/.travis.yml +2 -0
  5. data/Appraisals +2 -2
  6. data/Gemfile +1 -1
  7. data/NEWS.md +61 -8
  8. data/README.md +92 -9
  9. data/Rakefile +6 -0
  10. data/UPGRADE.md +2 -0
  11. data/app/assets/stylesheets/doorkeeper/admin/application.css +2 -2
  12. data/app/controllers/doorkeeper/application_controller.rb +4 -3
  13. data/app/controllers/doorkeeper/application_metal_controller.rb +4 -0
  14. data/app/controllers/doorkeeper/applications_controller.rb +42 -22
  15. data/app/controllers/doorkeeper/authorizations_controller.rb +55 -12
  16. data/app/controllers/doorkeeper/authorized_applications_controller.rb +19 -2
  17. data/app/controllers/doorkeeper/tokens_controller.rb +2 -6
  18. data/app/helpers/doorkeeper/dashboard_helper.rb +7 -7
  19. data/app/validators/redirect_uri_validator.rb +3 -2
  20. data/app/views/doorkeeper/applications/_delete_form.html.erb +3 -1
  21. data/app/views/doorkeeper/applications/_form.html.erb +25 -24
  22. data/app/views/doorkeeper/applications/edit.html.erb +1 -1
  23. data/app/views/doorkeeper/applications/index.html.erb +17 -7
  24. data/app/views/doorkeeper/applications/new.html.erb +1 -1
  25. data/app/views/doorkeeper/applications/show.html.erb +6 -6
  26. data/app/views/doorkeeper/authorizations/error.html.erb +1 -1
  27. data/app/views/doorkeeper/authorizations/new.html.erb +4 -0
  28. data/app/views/layouts/doorkeeper/admin.html.erb +15 -15
  29. data/config/locales/en.yml +10 -1
  30. data/doorkeeper.gemspec +18 -20
  31. data/gemfiles/rails_5_2.gemfile +1 -1
  32. data/gemfiles/rails_master.gemfile +4 -1
  33. data/lib/doorkeeper/config.rb +75 -39
  34. data/lib/doorkeeper/engine.rb +4 -0
  35. data/lib/doorkeeper/errors.rb +2 -5
  36. data/lib/doorkeeper/grape/helpers.rb +1 -1
  37. data/lib/doorkeeper/helpers/controller.rb +7 -2
  38. data/lib/doorkeeper/models/access_grant_mixin.rb +71 -0
  39. data/lib/doorkeeper/models/access_token_mixin.rb +39 -22
  40. data/lib/doorkeeper/models/concerns/scopes.rb +1 -1
  41. data/lib/doorkeeper/oauth/authorization/code.rb +31 -8
  42. data/lib/doorkeeper/oauth/authorization/context.rb +15 -0
  43. data/lib/doorkeeper/oauth/authorization/token.rb +36 -14
  44. data/lib/doorkeeper/oauth/authorization_code_request.rb +27 -2
  45. data/lib/doorkeeper/oauth/base_request.rb +20 -9
  46. data/lib/doorkeeper/oauth/client/credentials.rb +1 -1
  47. data/lib/doorkeeper/oauth/client.rb +0 -2
  48. data/lib/doorkeeper/oauth/client_credentials/creator.rb +2 -1
  49. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +6 -3
  50. data/lib/doorkeeper/oauth/client_credentials/validation.rb +4 -6
  51. data/lib/doorkeeper/oauth/client_credentials_request.rb +0 -4
  52. data/lib/doorkeeper/oauth/error_response.rb +11 -3
  53. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +0 -8
  54. data/lib/doorkeeper/oauth/password_access_token_request.rb +7 -4
  55. data/lib/doorkeeper/oauth/pre_authorization.rb +41 -11
  56. data/lib/doorkeeper/oauth/refresh_token_request.rb +6 -1
  57. data/lib/doorkeeper/oauth/scopes.rb +1 -1
  58. data/lib/doorkeeper/oauth/token.rb +5 -2
  59. data/lib/doorkeeper/oauth/token_introspection.rb +2 -2
  60. data/lib/doorkeeper/oauth/token_response.rb +4 -2
  61. data/lib/doorkeeper/oauth.rb +13 -0
  62. data/lib/doorkeeper/orm/active_record/application.rb +22 -14
  63. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +26 -0
  64. data/lib/doorkeeper/orm/active_record.rb +2 -0
  65. data/lib/doorkeeper/rails/helpers.rb +2 -4
  66. data/lib/doorkeeper/rails/routes.rb +14 -6
  67. data/lib/doorkeeper/rake/db.rake +40 -0
  68. data/lib/doorkeeper/rake/setup.rake +6 -0
  69. data/lib/doorkeeper/rake.rb +14 -0
  70. data/lib/doorkeeper/request/authorization_code.rb +0 -2
  71. data/lib/doorkeeper/request/client_credentials.rb +0 -2
  72. data/lib/doorkeeper/request/code.rb +0 -2
  73. data/lib/doorkeeper/request/password.rb +0 -2
  74. data/lib/doorkeeper/request/refresh_token.rb +0 -2
  75. data/lib/doorkeeper/request/token.rb +0 -2
  76. data/lib/doorkeeper/request.rb +28 -35
  77. data/lib/doorkeeper/version.rb +5 -25
  78. data/lib/doorkeeper.rb +19 -17
  79. data/lib/generators/doorkeeper/application_owner_generator.rb +23 -18
  80. data/lib/generators/doorkeeper/confidential_applications_generator.rb +32 -0
  81. data/lib/generators/doorkeeper/install_generator.rb +17 -9
  82. data/lib/generators/doorkeeper/migration_generator.rb +23 -18
  83. data/lib/generators/doorkeeper/pkce_generator.rb +32 -0
  84. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +29 -24
  85. data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
  86. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +6 -0
  87. data/lib/generators/doorkeeper/templates/initializer.rb +76 -11
  88. data/lib/generators/doorkeeper/views_generator.rb +3 -1
  89. data/spec/controllers/application_metal_controller_spec.rb +50 -0
  90. data/spec/controllers/applications_controller_spec.rb +126 -13
  91. data/spec/controllers/authorizations_controller_spec.rb +277 -47
  92. data/spec/controllers/protected_resources_controller_spec.rb +16 -16
  93. data/spec/controllers/token_info_controller_spec.rb +4 -12
  94. data/spec/controllers/tokens_controller_spec.rb +13 -15
  95. data/spec/dummy/app/assets/config/manifest.js +2 -0
  96. data/spec/dummy/config/environments/test.rb +4 -5
  97. data/spec/dummy/config/initializers/doorkeeper.rb +10 -5
  98. data/spec/dummy/config/initializers/new_framework_defaults.rb +4 -0
  99. data/spec/dummy/config/routes.rb +3 -42
  100. data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +6 -0
  101. data/spec/dummy/db/migrate/{20180210183654_add_confidential_to_application.rb → 20180210183654_add_confidential_to_applications.rb} +1 -1
  102. data/spec/dummy/db/schema.rb +36 -36
  103. data/spec/generators/application_owner_generator_spec.rb +1 -1
  104. data/spec/generators/confidential_applications_generator_spec.rb +45 -0
  105. data/spec/generators/install_generator_spec.rb +1 -1
  106. data/spec/generators/migration_generator_spec.rb +1 -1
  107. data/spec/generators/pkce_generator_spec.rb +43 -0
  108. data/spec/generators/previous_refresh_token_generator_spec.rb +1 -1
  109. data/spec/generators/views_generator_spec.rb +1 -1
  110. data/spec/grape/grape_integration_spec.rb +1 -1
  111. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +1 -1
  112. data/spec/lib/config_spec.rb +80 -31
  113. data/spec/lib/doorkeeper_spec.rb +1 -126
  114. data/spec/lib/models/expirable_spec.rb +0 -3
  115. data/spec/lib/models/revocable_spec.rb +0 -2
  116. data/spec/lib/models/scopes_spec.rb +0 -4
  117. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -4
  118. data/spec/lib/oauth/authorization_code_request_spec.rb +9 -2
  119. data/spec/lib/oauth/base_request_spec.rb +40 -2
  120. data/spec/lib/oauth/base_response_spec.rb +1 -1
  121. data/spec/lib/oauth/client/credentials_spec.rb +1 -3
  122. data/spec/lib/oauth/client_credentials/creator_spec.rb +5 -1
  123. data/spec/lib/oauth/client_credentials/issuer_spec.rb +26 -7
  124. data/spec/lib/oauth/client_credentials/validation_spec.rb +2 -3
  125. data/spec/lib/oauth/client_credentials_integration_spec.rb +1 -1
  126. data/spec/lib/oauth/client_credentials_request_spec.rb +3 -5
  127. data/spec/lib/oauth/client_spec.rb +0 -3
  128. data/spec/lib/oauth/code_request_spec.rb +4 -2
  129. data/spec/lib/oauth/error_response_spec.rb +0 -3
  130. data/spec/lib/oauth/error_spec.rb +0 -2
  131. data/spec/lib/oauth/forbidden_token_response_spec.rb +1 -4
  132. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -3
  133. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -1
  134. data/spec/lib/oauth/helpers/uri_checker_spec.rb +5 -7
  135. data/spec/lib/oauth/invalid_token_response_spec.rb +1 -4
  136. data/spec/lib/oauth/password_access_token_request_spec.rb +37 -2
  137. data/spec/lib/oauth/pre_authorization_spec.rb +33 -4
  138. data/spec/lib/oauth/refresh_token_request_spec.rb +11 -7
  139. data/spec/lib/oauth/scopes_spec.rb +0 -3
  140. data/spec/lib/oauth/token_request_spec.rb +4 -5
  141. data/spec/lib/oauth/token_response_spec.rb +0 -1
  142. data/spec/lib/oauth/token_spec.rb +37 -14
  143. data/spec/lib/orm/active_record/stale_records_cleaner_spec.rb +79 -0
  144. data/spec/lib/request/strategy_spec.rb +0 -1
  145. data/spec/lib/server_spec.rb +1 -1
  146. data/spec/models/doorkeeper/access_grant_spec.rb +44 -1
  147. data/spec/models/doorkeeper/access_token_spec.rb +66 -22
  148. data/spec/models/doorkeeper/application_spec.rb +14 -47
  149. data/spec/requests/applications/applications_request_spec.rb +134 -1
  150. data/spec/requests/applications/authorized_applications_spec.rb +1 -1
  151. data/spec/requests/endpoints/authorization_spec.rb +1 -1
  152. data/spec/requests/endpoints/token_spec.rb +7 -5
  153. data/spec/requests/flows/authorization_code_errors_spec.rb +1 -1
  154. data/spec/requests/flows/authorization_code_spec.rb +197 -1
  155. data/spec/requests/flows/client_credentials_spec.rb +46 -6
  156. data/spec/requests/flows/implicit_grant_errors_spec.rb +1 -1
  157. data/spec/requests/flows/implicit_grant_spec.rb +38 -11
  158. data/spec/requests/flows/password_spec.rb +56 -2
  159. data/spec/requests/flows/refresh_token_spec.rb +2 -2
  160. data/spec/requests/flows/revoke_token_spec.rb +11 -11
  161. data/spec/requests/flows/skip_authorization_spec.rb +16 -11
  162. data/spec/requests/protected_resources/metal_spec.rb +1 -1
  163. data/spec/requests/protected_resources/private_api_spec.rb +1 -1
  164. data/spec/routing/custom_controller_routes_spec.rb +59 -7
  165. data/spec/routing/default_routes_spec.rb +2 -2
  166. data/spec/routing/scoped_routes_spec.rb +16 -2
  167. data/spec/spec_helper.rb +54 -3
  168. data/spec/spec_helper_integration.rb +2 -74
  169. data/spec/support/dependencies/{factory_girl.rb → factory_bot.rb} +0 -0
  170. data/spec/support/doorkeeper_rspec.rb +19 -0
  171. data/spec/support/helpers/authorization_request_helper.rb +4 -4
  172. data/spec/support/helpers/request_spec_helper.rb +10 -2
  173. data/spec/support/helpers/url_helper.rb +7 -3
  174. data/spec/support/http_method_shim.rb +12 -16
  175. data/spec/validators/redirect_uri_validator_spec.rb +7 -1
  176. data/spec/version/version_spec.rb +3 -3
  177. data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
  178. metadata +37 -33
  179. data/lib/generators/doorkeeper/add_client_confidentiality_generator.rb +0 -31
  180. data/lib/generators/doorkeeper/templates/add_confidential_to_application_migration.rb.erb +0 -11
  181. data/spec/controllers/application_metal_controller.rb +0 -10
@@ -1,4 +1,4 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  feature 'Authorization Code Flow' do
4
4
  background do
@@ -39,6 +39,7 @@ feature 'Authorization Code Flow' do
39
39
  click_on 'Authorize'
40
40
  url_should_have_param('code', Doorkeeper::AccessGrant.first.token)
41
41
  url_should_have_param('state', 'return-me')
42
+ url_should_not_have_param('code_challenge_method')
42
43
  end
43
44
 
44
45
  scenario 'resource owner requests an access token with authorization code' do
@@ -57,6 +58,201 @@ feature 'Authorization Code Flow' do
57
58
  should_have_json_within 'expires_in', Doorkeeper::AccessToken.first.expires_in, 1
58
59
  end
59
60
 
61
+ scenario 'resource owner requests an access token with authorization code but without secret' do
62
+ visit authorization_endpoint_url(client: @client)
63
+ click_on 'Authorize'
64
+
65
+ authorization_code = Doorkeeper::AccessGrant.first.token
66
+ page.driver.post token_endpoint_url(code: authorization_code, client_id: @client.uid,
67
+ redirect_uri: @client.redirect_uri)
68
+
69
+ expect(Doorkeeper::AccessToken).not_to exist
70
+
71
+ should_have_json 'error', 'invalid_client'
72
+ end
73
+
74
+ context 'with PKCE' do
75
+ context 'plain' do
76
+ let(:code_challenge) { 'a45a9fea-0676-477e-95b1-a40f72ac3cfb' }
77
+ let(:code_verifier) { 'a45a9fea-0676-477e-95b1-a40f72ac3cfb' }
78
+
79
+ scenario 'resource owner authorizes the client with code_challenge parameter set' do
80
+ visit authorization_endpoint_url(client: @client, code_challenge: code_challenge, code_challenge_method: 'plain')
81
+ click_on 'Authorize'
82
+
83
+ url_should_have_param('code', Doorkeeper::AccessGrant.first.token)
84
+ url_should_not_have_param('code_challenge_method')
85
+ url_should_not_have_param('code_challenge')
86
+ end
87
+
88
+ scenario 'mobile app requests an access token with authorization code but not pkce token' do
89
+ visit authorization_endpoint_url(client: @client)
90
+ click_on 'Authorize'
91
+
92
+ authorization_code = current_params['code']
93
+ create_access_token authorization_code, @client, code_verifier
94
+
95
+ should_have_json 'error', 'invalid_grant'
96
+ end
97
+
98
+ scenario 'mobile app requests an access token with authorization code and plain code challenge method' do
99
+ visit authorization_endpoint_url(client: @client, code_challenge: code_challenge, code_challenge_method: 'plain')
100
+ click_on 'Authorize'
101
+
102
+ authorization_code = current_params['code']
103
+ create_access_token authorization_code, @client, code_verifier
104
+
105
+ access_token_should_exist_for(@client, @resource_owner)
106
+
107
+ should_not_have_json 'error'
108
+
109
+ should_have_json 'access_token', Doorkeeper::AccessToken.first.token
110
+ should_have_json 'token_type', 'Bearer'
111
+ should_have_json_within 'expires_in', Doorkeeper::AccessToken.first.expires_in, 1
112
+ end
113
+
114
+ scenario 'mobile app requests an access token with authorization code and code_challenge' do
115
+ visit authorization_endpoint_url(client: @client,
116
+ code_challenge: code_verifier,
117
+ code_challenge_method: 'plain')
118
+ click_on 'Authorize'
119
+
120
+ authorization_code = current_params['code']
121
+ create_access_token authorization_code, @client, code_verifier: nil
122
+
123
+ should_not_have_json 'access_token'
124
+ should_have_json 'error', 'invalid_grant'
125
+ end
126
+ end
127
+
128
+ context 's256' do
129
+ let(:code_challenge) { 'Oz733NtQ0rJP8b04fgZMJMwprn6Iw8sMCT_9bR1q4tA' }
130
+ let(:code_verifier) { 'a45a9fea-0676-477e-95b1-a40f72ac3cfb' }
131
+
132
+ scenario 'resource owner authorizes the client with code_challenge parameter set' do
133
+ visit authorization_endpoint_url(client: @client, code_challenge: code_challenge, code_challenge_method: 'S256')
134
+ click_on 'Authorize'
135
+
136
+ url_should_have_param('code', Doorkeeper::AccessGrant.first.token)
137
+ url_should_not_have_param('code_challenge_method')
138
+ url_should_not_have_param('code_challenge')
139
+ end
140
+
141
+ scenario 'mobile app requests an access token with authorization code and S256 code challenge method' do
142
+ visit authorization_endpoint_url(client: @client, code_challenge: code_challenge, code_challenge_method: 'S256')
143
+ click_on 'Authorize'
144
+
145
+ authorization_code = current_params['code']
146
+ create_access_token authorization_code, @client, code_verifier
147
+
148
+ access_token_should_exist_for(@client, @resource_owner)
149
+
150
+ should_not_have_json 'error'
151
+
152
+ should_have_json 'access_token', Doorkeeper::AccessToken.first.token
153
+ should_have_json 'token_type', 'Bearer'
154
+ should_have_json_within 'expires_in', Doorkeeper::AccessToken.first.expires_in, 1
155
+ end
156
+
157
+ scenario 'mobile app requests an access token with authorization code and without code_verifier' do
158
+ visit authorization_endpoint_url(client: @client, code_challenge: code_challenge, code_challenge_method: 'S256')
159
+ click_on 'Authorize'
160
+ authorization_code = current_params['code']
161
+ create_access_token authorization_code, @client
162
+ should_have_json 'error', 'invalid_request'
163
+ should_not_have_json 'access_token'
164
+ end
165
+
166
+ scenario 'mobile app requests an access token with authorization code and without secret' do
167
+ visit authorization_endpoint_url(client: @client, code_challenge: code_challenge, code_challenge_method: 'S256')
168
+ click_on 'Authorize'
169
+
170
+ authorization_code = current_params['code']
171
+ page.driver.post token_endpoint_url(code: authorization_code, client_id: @client.uid,
172
+ redirect_uri: @client.redirect_uri, code_verifier: code_verifier)
173
+ should_have_json 'error', 'invalid_client'
174
+ should_not_have_json 'access_token'
175
+ end
176
+
177
+ scenario 'mobile app requests an access token with authorization code and without secret but is marked as not confidential' do
178
+ @client.update_attribute :confidential, false
179
+ visit authorization_endpoint_url(client: @client, code_challenge: code_challenge, code_challenge_method: 'S256')
180
+ click_on 'Authorize'
181
+
182
+ authorization_code = current_params['code']
183
+ page.driver.post token_endpoint_url(code: authorization_code, client_id: @client.uid,
184
+ redirect_uri: @client.redirect_uri, code_verifier: code_verifier)
185
+ should_not_have_json 'error'
186
+
187
+ should_have_json 'access_token', Doorkeeper::AccessToken.first.token
188
+ should_have_json 'token_type', 'Bearer'
189
+ should_have_json_within 'expires_in', Doorkeeper::AccessToken.first.expires_in, 1
190
+ end
191
+
192
+ scenario 'mobile app requests an access token with authorization code but no code verifier' do
193
+ visit authorization_endpoint_url(client: @client, code_challenge: code_challenge, code_challenge_method: 'S256')
194
+ click_on 'Authorize'
195
+
196
+ authorization_code = current_params['code']
197
+ create_access_token authorization_code, @client
198
+
199
+ should_not_have_json 'access_token'
200
+ should_have_json 'error', 'invalid_request'
201
+ end
202
+
203
+ scenario 'mobile app requests an access token with authorization code with wrong verifier' do
204
+ visit authorization_endpoint_url(client: @client, code_challenge: code_challenge, code_challenge_method: 'S256')
205
+ click_on 'Authorize'
206
+
207
+ authorization_code = current_params['code']
208
+ create_access_token authorization_code, @client, 'incorrect-code-verifier'
209
+
210
+ should_not_have_json 'access_token'
211
+ should_have_json 'error', 'invalid_grant'
212
+ end
213
+
214
+ scenario 'code_challenge_mehthod in token request is totally ignored' do
215
+ visit authorization_endpoint_url(client: @client, code_challenge: code_challenge, code_challenge_method: 'S256')
216
+ click_on 'Authorize'
217
+
218
+ authorization_code = current_params['code']
219
+ page.driver.post token_endpoint_url(code: authorization_code, client: @client, code_verifier: code_challenge,
220
+ code_challenge_method: 'plain')
221
+
222
+ should_not_have_json 'access_token'
223
+ should_have_json 'error', 'invalid_grant'
224
+ end
225
+
226
+ scenario 'expects to set code_challenge_method explicitely without fallback' do
227
+ visit authorization_endpoint_url(client: @client, code_challenge: code_challenge)
228
+ expect(page).to have_content('The code challenge method must be plain or S256.')
229
+ end
230
+ end
231
+ end
232
+
233
+ context 'when application scopes are present and no scope is passed' do
234
+ background do
235
+ @client.update_attributes(scopes: 'public write read')
236
+ end
237
+
238
+ scenario 'access grant has no scope' do
239
+ default_scopes_exist :admin
240
+ visit authorization_endpoint_url(client: @client)
241
+ click_on 'Authorize'
242
+ access_grant_should_exist_for(@client, @resource_owner)
243
+ grant = Doorkeeper::AccessGrant.first
244
+ expect(grant.scopes).to be_empty
245
+ end
246
+
247
+ scenario 'access grant have scopes which are common in application scopees and default scopes' do
248
+ default_scopes_exist :public, :write
249
+ visit authorization_endpoint_url(client: @client)
250
+ click_on 'Authorize'
251
+ access_grant_should_exist_for(@client, @resource_owner)
252
+ access_grant_should_have_scopes :public, :write
253
+ end
254
+ end
255
+
60
256
  context 'with scopes' do
61
257
  background do
62
258
  default_scopes_exist :public
@@ -1,4 +1,4 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  describe 'Client Credentials Request' do
4
4
  let(:client) { FactoryBot.create :application }
@@ -8,7 +8,7 @@ describe 'Client Credentials Request' do
8
8
  headers = authorization client.uid, client.secret
9
9
  params = { grant_type: 'client_credentials' }
10
10
 
11
- post '/oauth/token', params, headers
11
+ post '/oauth/token', params: params, headers: headers
12
12
 
13
13
  should_have_json 'access_token', Doorkeeper::AccessToken.first.token
14
14
  should_have_json_within 'expires_in', Doorkeeper.configuration.access_token_expires_in, 1
@@ -29,7 +29,7 @@ describe 'Client Credentials Request' do
29
29
  headers = authorization client.uid, client.secret
30
30
  params = { grant_type: 'client_credentials', scope: 'write' }
31
31
 
32
- post '/oauth/token', params, headers
32
+ post '/oauth/token', params: params, headers: headers
33
33
 
34
34
  should_have_json 'access_token', Doorkeeper::AccessToken.first.token
35
35
  should_have_json 'scope', 'write'
@@ -40,7 +40,7 @@ describe 'Client Credentials Request' do
40
40
  headers = authorization client.uid, client.secret
41
41
  params = { grant_type: 'client_credentials', scope: 'public' }
42
42
 
43
- post '/oauth/token', params, headers
43
+ post '/oauth/token', params: params, headers: headers
44
44
 
45
45
  should_have_json 'access_token', Doorkeeper::AccessToken.first.token
46
46
  should_have_json 'scope', 'public'
@@ -52,7 +52,7 @@ describe 'Client Credentials Request' do
52
52
  headers = authorization client.uid, client.secret
53
53
  params = { grant_type: 'client_credentials', scope: 'random' }
54
54
 
55
- post '/oauth/token', params, headers
55
+ post '/oauth/token', params: params, headers: headers
56
56
 
57
57
  should_have_json 'error', 'invalid_scope'
58
58
  should_have_json 'error_description', translated_error_message(:invalid_scope)
@@ -64,12 +64,52 @@ describe 'Client Credentials Request' do
64
64
  end
65
65
  end
66
66
 
67
+ context 'when application scopes contain some of the default scopes and no scope is passed' do
68
+ before do
69
+ client.update_attributes(scopes: 'read write public')
70
+ end
71
+
72
+ it 'issues new token with one default scope that are present in application scopes' do
73
+ default_scopes_exist :public
74
+
75
+ headers = authorization client.uid, client.secret
76
+ params = { grant_type: 'client_credentials' }
77
+
78
+ expect do
79
+ post '/oauth/token', params: params, headers: headers
80
+ end.to change { Doorkeeper::AccessToken.count }.by(1)
81
+
82
+ token = Doorkeeper::AccessToken.first
83
+
84
+ expect(token.application_id).to eq client.id
85
+ should_have_json 'access_token', token.token
86
+ should_have_json 'scope', 'public'
87
+ end
88
+
89
+ it 'issues new token with multiple default scopes that are present in application scopes' do
90
+ default_scopes_exist :public, :read, :update
91
+
92
+ headers = authorization client.uid, client.secret
93
+ params = { grant_type: 'client_credentials' }
94
+
95
+ expect do
96
+ post '/oauth/token', params: params, headers: headers
97
+ end.to change { Doorkeeper::AccessToken.count }.by(1)
98
+
99
+ token = Doorkeeper::AccessToken.first
100
+
101
+ expect(token.application_id).to eq client.id
102
+ should_have_json 'access_token', token.token
103
+ should_have_json 'scope', 'public read'
104
+ end
105
+ end
106
+
67
107
  context 'an invalid request' do
68
108
  it 'does not authorize the client and returns the error' do
69
109
  headers = {}
70
110
  params = { grant_type: 'client_credentials' }
71
111
 
72
- post '/oauth/token', params, headers
112
+ post '/oauth/token', params: params, headers: headers
73
113
 
74
114
  should_have_json 'error', 'invalid_client'
75
115
  should_have_json 'error_description', translated_error_message(:invalid_client)
@@ -1,4 +1,4 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  feature 'Implicit Grant Flow Errors' do
4
4
  background do
@@ -1,4 +1,4 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  feature 'Implicit Grant Flow (feature spec)' do
4
4
  background do
@@ -17,6 +17,29 @@ feature 'Implicit Grant Flow (feature spec)' do
17
17
 
18
18
  i_should_be_on_client_callback @client
19
19
  end
20
+
21
+ context 'when application scopes are present and no scope is passed' do
22
+ background do
23
+ @client.update_attributes(scopes: 'public write read')
24
+ end
25
+
26
+ scenario 'access token has no scopes' do
27
+ default_scopes_exist :admin
28
+ visit authorization_endpoint_url(client: @client, response_type: 'token')
29
+ click_on 'Authorize'
30
+ access_token_should_exist_for @client, @resource_owner
31
+ token = Doorkeeper::AccessToken.first
32
+ expect(token.scopes).to be_empty
33
+ end
34
+
35
+ scenario 'access token has scopes which are common in application scopees and default scopes' do
36
+ default_scopes_exist :public, :write
37
+ visit authorization_endpoint_url(client: @client, response_type: 'token')
38
+ click_on 'Authorize'
39
+ access_token_should_exist_for @client, @resource_owner
40
+ access_token_should_have_scopes :public, :write
41
+ end
42
+ end
20
43
  end
21
44
 
22
45
  describe 'Implicit Grant Flow (request spec)' do
@@ -34,11 +57,13 @@ describe 'Implicit Grant Flow (request spec)' do
34
57
  token = client_is_authorized(@client, @resource_owner)
35
58
 
36
59
  post "/oauth/authorize",
37
- client_id: @client.uid,
38
- state: '',
39
- redirect_uri: @client.redirect_uri,
40
- response_type: 'token',
41
- commit: 'Authorize'
60
+ params: {
61
+ client_id: @client.uid,
62
+ state: '',
63
+ redirect_uri: @client.redirect_uri,
64
+ response_type: 'token',
65
+ commit: 'Authorize'
66
+ }
42
67
 
43
68
  expect(response.location).not_to include(token.token)
44
69
  end
@@ -49,11 +74,13 @@ describe 'Implicit Grant Flow (request spec)' do
49
74
  token = client_is_authorized(@client, @resource_owner)
50
75
 
51
76
  post "/oauth/authorize",
52
- client_id: @client.uid,
53
- state: '',
54
- redirect_uri: @client.redirect_uri,
55
- response_type: 'token',
56
- commit: 'Authorize'
77
+ params: {
78
+ client_id: @client.uid,
79
+ state: '',
80
+ redirect_uri: @client.redirect_uri,
81
+ response_type: 'token',
82
+ commit: 'Authorize'
83
+ }
57
84
 
58
85
  expect(response.location).to include(token.token)
59
86
  end
@@ -1,4 +1,4 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  describe 'Resource Owner Password Credentials Flow not set up' do
4
4
  before do
@@ -7,7 +7,7 @@ describe 'Resource Owner Password Credentials Flow not set up' do
7
7
  end
8
8
 
9
9
  context 'with valid user credentials' do
10
- it 'doesn\'t issue new token' do
10
+ it 'does not issue new token' do
11
11
  expect do
12
12
  post password_token_endpoint_url(client: @client, resource_owner: @resource_owner)
13
13
  end.to_not(change { Doorkeeper::AccessToken.count })
@@ -140,6 +140,60 @@ describe 'Resource Owner Password Credentials Flow' do
140
140
  end
141
141
  end
142
142
 
143
+ context 'when application scopes are present and differs from configured default scopes and no scope is passed' do
144
+ before do
145
+ default_scopes_exist :public
146
+ @client.update_attributes(scopes: 'abc')
147
+ end
148
+
149
+ it 'issues new token without any scope' do
150
+ expect do
151
+ post password_token_endpoint_url(client: @client, resource_owner: @resource_owner)
152
+ end.to change { Doorkeeper::AccessToken.count }.by(1)
153
+
154
+ token = Doorkeeper::AccessToken.first
155
+
156
+ expect(token.application_id).to eq @client.id
157
+ expect(token.scopes).to be_empty
158
+ should_have_json 'access_token', token.token
159
+ should_not_have_json 'scope'
160
+ end
161
+ end
162
+
163
+ context 'when application scopes contain some of the default scopes and no scope is passed' do
164
+ before do
165
+ @client.update_attributes(scopes: 'read write public')
166
+ end
167
+
168
+ it 'issues new token with one default scope that are present in application scopes' do
169
+ default_scopes_exist :public, :admin
170
+
171
+ expect do
172
+ post password_token_endpoint_url(client: @client, resource_owner: @resource_owner)
173
+ end.to change { Doorkeeper::AccessToken.count }.by(1)
174
+
175
+ token = Doorkeeper::AccessToken.first
176
+
177
+ expect(token.application_id).to eq @client.id
178
+ should_have_json 'access_token', token.token
179
+ should_have_json 'scope', 'public'
180
+ end
181
+
182
+ it 'issues new token with multiple default scopes that are present in application scopes' do
183
+ default_scopes_exist :public, :read, :update
184
+
185
+ expect do
186
+ post password_token_endpoint_url(client: @client, resource_owner: @resource_owner)
187
+ end.to change { Doorkeeper::AccessToken.count }.by(1)
188
+
189
+ token = Doorkeeper::AccessToken.first
190
+
191
+ expect(token.application_id).to eq @client.id
192
+ should_have_json 'access_token', token.token
193
+ should_have_json 'scope', 'public read'
194
+ end
195
+ end
196
+
143
197
  context 'with invalid scopes' do
144
198
  subject do
145
199
  post password_token_endpoint_url(client: @client,
@@ -1,4 +1,4 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  describe 'Refresh Token Flow' do
4
4
  before do
@@ -14,7 +14,7 @@ describe 'Refresh Token Flow' do
14
14
  authorization_code_exists application: @client
15
15
  end
16
16
 
17
- it 'client gets the refresh token and refreshses it' do
17
+ it 'client gets the refresh token and refreshes it' do
18
18
  post token_endpoint_url(code: @authorization.token, client: @client)
19
19
 
20
20
  token = Doorkeeper::AccessToken.first
@@ -1,4 +1,4 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  describe 'Revoke Token Flow' do
4
4
  before do
@@ -24,7 +24,7 @@ describe 'Revoke Token Flow' do
24
24
  end
25
25
 
26
26
  it 'should revoke the access token provided' do
27
- post revocation_token_endpoint_url, { token: access_token.token }, headers
27
+ post revocation_token_endpoint_url, params: { token: access_token.token }, headers: headers
28
28
 
29
29
  access_token.reload
30
30
 
@@ -33,7 +33,7 @@ describe 'Revoke Token Flow' do
33
33
  end
34
34
 
35
35
  it 'should revoke the refresh token provided' do
36
- post revocation_token_endpoint_url, { token: access_token.refresh_token }, headers
36
+ post revocation_token_endpoint_url, params: { token: access_token.refresh_token }, headers: headers
37
37
 
38
38
  access_token.reload
39
39
 
@@ -44,7 +44,7 @@ describe 'Revoke Token Flow' do
44
44
  context 'with invalid token to revoke' do
45
45
  it 'should not revoke any tokens and respond successfully' do
46
46
  num_prev_revoked_tokens = Doorkeeper::AccessToken.where(revoked_at: nil).count
47
- post revocation_token_endpoint_url, { token: 'I_AM_AN_INVALID_TOKEN' }, headers
47
+ post revocation_token_endpoint_url, params: { token: 'I_AM_AN_INVALID_TOKEN' }, headers: headers
48
48
 
49
49
  # The authorization server responds with HTTP status code 200 even if
50
50
  # token is invalid
@@ -60,7 +60,7 @@ describe 'Revoke Token Flow' do
60
60
  { 'HTTP_AUTHORIZATION' => "Basic #{credentials}" }
61
61
  end
62
62
  it 'should not revoke any tokens and respond successfully' do
63
- post revocation_token_endpoint_url, { token: access_token.token }, headers
63
+ post revocation_token_endpoint_url, params: { token: access_token.token }, headers: headers
64
64
 
65
65
  access_token.reload
66
66
 
@@ -71,7 +71,7 @@ describe 'Revoke Token Flow' do
71
71
 
72
72
  context 'with no credentials and a valid token' do
73
73
  it 'should not revoke any tokens and respond successfully' do
74
- post revocation_token_endpoint_url, { token: access_token.token }
74
+ post revocation_token_endpoint_url, params: { token: access_token.token }
75
75
 
76
76
  access_token.reload
77
77
 
@@ -90,7 +90,7 @@ describe 'Revoke Token Flow' do
90
90
  end
91
91
 
92
92
  it 'should not revoke the token as its unauthorized' do
93
- post revocation_token_endpoint_url, { token: access_token.token }, headers
93
+ post revocation_token_endpoint_url, params: { token: access_token.token }, headers: headers
94
94
 
95
95
  access_token.reload
96
96
 
@@ -109,7 +109,7 @@ describe 'Revoke Token Flow' do
109
109
  end
110
110
 
111
111
  it 'should revoke the access token provided' do
112
- post revocation_token_endpoint_url, { token: access_token.token }
112
+ post revocation_token_endpoint_url, params: { token: access_token.token }
113
113
 
114
114
  access_token.reload
115
115
 
@@ -118,7 +118,7 @@ describe 'Revoke Token Flow' do
118
118
  end
119
119
 
120
120
  it 'should revoke the refresh token provided' do
121
- post revocation_token_endpoint_url, { token: access_token.refresh_token }
121
+ post revocation_token_endpoint_url, params: { token: access_token.refresh_token }
122
122
 
123
123
  access_token.reload
124
124
 
@@ -135,7 +135,7 @@ describe 'Revoke Token Flow' do
135
135
  end
136
136
 
137
137
  it 'should not revoke the access token provided' do
138
- post revocation_token_endpoint_url, { token: access_token.token }
138
+ post revocation_token_endpoint_url, params: { token: access_token.token }
139
139
 
140
140
  access_token.reload
141
141
 
@@ -144,7 +144,7 @@ describe 'Revoke Token Flow' do
144
144
  end
145
145
 
146
146
  it 'should not revoke the refresh token provided' do
147
- post revocation_token_endpoint_url, { token: access_token.token }
147
+ post revocation_token_endpoint_url, params: { token: access_token.token }
148
148
 
149
149
  access_token.reload
150
150
 
@@ -1,4 +1,4 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  feature 'Skip authorization form' do
4
4
  background do
@@ -15,13 +15,24 @@ feature 'Skip authorization form' do
15
15
  end
16
16
 
17
17
  scenario 'skips the authorization and return a new grant code' do
18
- client_is_authorized(@client, @resource_owner, scopes: 'public')
19
- visit authorization_endpoint_url(client: @client)
18
+ client_is_authorized(@client, @resource_owner, scopes: "public")
19
+ visit authorization_endpoint_url(client: @client, scope: "public")
20
+
21
+ i_should_not_see "Authorize"
22
+ client_should_be_authorized @client
23
+ i_should_be_on_client_callback @client
24
+ url_should_have_param "code", Doorkeeper::AccessGrant.first.token
25
+ end
26
+
27
+ scenario "skips the authorization if other scopes are not requested" do
28
+ client_exists scopes: "public read write"
29
+ client_is_authorized(@client, @resource_owner, scopes: "public")
30
+ visit authorization_endpoint_url(client: @client, scope: "public")
20
31
 
21
- i_should_not_see 'Authorize'
32
+ i_should_not_see "Authorize"
22
33
  client_should_be_authorized @client
23
34
  i_should_be_on_client_callback @client
24
- url_should_have_param 'code', Doorkeeper::AccessGrant.first.token
35
+ url_should_have_param "code", Doorkeeper::AccessGrant.first.token
25
36
  end
26
37
 
27
38
  scenario 'does not skip authorization when scopes differ (new request has fewer scopes)' do
@@ -43,12 +54,6 @@ feature 'Skip authorization form' do
43
54
  access_grant_should_have_scopes :public
44
55
  end
45
56
 
46
- scenario 'doesn not skip authorization when scopes are greater' do
47
- client_is_authorized(@client, @resource_owner, scopes: 'public')
48
- visit authorization_endpoint_url(client: @client, scope: 'public write')
49
- i_should_see 'Authorize'
50
- end
51
-
52
57
  scenario 'creates grant with new scope when scopes are greater' do
53
58
  client_is_authorized(@client, @resource_owner, scopes: 'public')
54
59
  visit authorization_endpoint_url(client: @client, scope: 'public write')
@@ -1,4 +1,4 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  describe 'ActionController::Metal API' do
4
4
  before do
@@ -1,4 +1,4 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  feature 'Private API' do
4
4
  background do