doorkeeper 4.3.2 → 5.0.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +4 -0
  4. data/.travis.yml +2 -0
  5. data/Appraisals +2 -2
  6. data/Gemfile +1 -1
  7. data/NEWS.md +36 -0
  8. data/README.md +85 -3
  9. data/Rakefile +6 -0
  10. data/app/assets/stylesheets/doorkeeper/admin/application.css +2 -2
  11. data/app/controllers/doorkeeper/application_controller.rb +4 -3
  12. data/app/controllers/doorkeeper/application_metal_controller.rb +4 -0
  13. data/app/controllers/doorkeeper/applications_controller.rb +43 -22
  14. data/app/controllers/doorkeeper/authorizations_controller.rb +55 -12
  15. data/app/controllers/doorkeeper/authorized_applications_controller.rb +15 -1
  16. data/app/controllers/doorkeeper/tokens_controller.rb +2 -6
  17. data/app/helpers/doorkeeper/dashboard_helper.rb +7 -7
  18. data/app/validators/redirect_uri_validator.rb +3 -2
  19. data/app/views/doorkeeper/applications/_delete_form.html.erb +3 -1
  20. data/app/views/doorkeeper/applications/_form.html.erb +31 -19
  21. data/app/views/doorkeeper/applications/edit.html.erb +1 -1
  22. data/app/views/doorkeeper/applications/index.html.erb +18 -6
  23. data/app/views/doorkeeper/applications/new.html.erb +1 -1
  24. data/app/views/doorkeeper/applications/show.html.erb +8 -5
  25. data/app/views/doorkeeper/authorizations/error.html.erb +1 -1
  26. data/app/views/doorkeeper/authorizations/new.html.erb +4 -0
  27. data/app/views/layouts/doorkeeper/admin.html.erb +15 -15
  28. data/config/locales/en.yml +15 -1
  29. data/gemfiles/rails_5_2.gemfile +1 -1
  30. data/lib/doorkeeper/config.rb +60 -23
  31. data/lib/doorkeeper/engine.rb +4 -0
  32. data/lib/doorkeeper/errors.rb +2 -5
  33. data/lib/doorkeeper/grape/helpers.rb +1 -1
  34. data/lib/doorkeeper/helpers/controller.rb +7 -2
  35. data/lib/doorkeeper/models/access_grant_mixin.rb +56 -0
  36. data/lib/doorkeeper/models/access_token_mixin.rb +37 -20
  37. data/lib/doorkeeper/models/application_mixin.rb +8 -1
  38. data/lib/doorkeeper/models/concerns/scopes.rb +1 -1
  39. data/lib/doorkeeper/oauth/authorization/code.rb +31 -8
  40. data/lib/doorkeeper/oauth/authorization/context.rb +15 -0
  41. data/lib/doorkeeper/oauth/authorization/token.rb +23 -6
  42. data/lib/doorkeeper/oauth/authorization_code_request.rb +27 -2
  43. data/lib/doorkeeper/oauth/base_request.rb +18 -8
  44. data/lib/doorkeeper/oauth/client/credentials.rb +4 -2
  45. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +6 -1
  46. data/lib/doorkeeper/oauth/client_credentials/validation.rb +4 -2
  47. data/lib/doorkeeper/oauth/error_response.rb +11 -3
  48. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +0 -8
  49. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +1 -0
  50. data/lib/doorkeeper/oauth/password_access_token_request.rb +7 -4
  51. data/lib/doorkeeper/oauth/pre_authorization.rb +45 -13
  52. data/lib/doorkeeper/oauth/refresh_token_request.rb +6 -1
  53. data/lib/doorkeeper/oauth/scopes.rb +1 -1
  54. data/lib/doorkeeper/oauth/token.rb +5 -2
  55. data/lib/doorkeeper/oauth/token_introspection.rb +2 -2
  56. data/lib/doorkeeper/oauth/token_response.rb +4 -2
  57. data/lib/doorkeeper/oauth.rb +13 -0
  58. data/lib/doorkeeper/orm/active_record/application.rb +14 -0
  59. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +26 -0
  60. data/lib/doorkeeper/orm/active_record.rb +2 -0
  61. data/lib/doorkeeper/rails/helpers.rb +2 -4
  62. data/lib/doorkeeper/rails/routes.rb +13 -1
  63. data/lib/doorkeeper/rake/db.rake +40 -0
  64. data/lib/doorkeeper/rake/setup.rake +6 -0
  65. data/lib/doorkeeper/rake.rb +14 -0
  66. data/lib/doorkeeper/request/password.rb +1 -11
  67. data/lib/doorkeeper/request.rb +28 -28
  68. data/lib/doorkeeper/version.rb +5 -4
  69. data/lib/doorkeeper.rb +4 -17
  70. data/lib/generators/doorkeeper/application_owner_generator.rb +23 -18
  71. data/lib/generators/doorkeeper/confidential_applications_generator.rb +32 -0
  72. data/lib/generators/doorkeeper/install_generator.rb +17 -9
  73. data/lib/generators/doorkeeper/migration_generator.rb +23 -18
  74. data/lib/generators/doorkeeper/pkce_generator.rb +32 -0
  75. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +29 -24
  76. data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
  77. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +6 -0
  78. data/lib/generators/doorkeeper/templates/initializer.rb +60 -9
  79. data/lib/generators/doorkeeper/templates/migration.rb.erb +1 -0
  80. data/lib/generators/doorkeeper/views_generator.rb +3 -1
  81. data/spec/controllers/application_metal_controller_spec.rb +50 -0
  82. data/spec/controllers/applications_controller_spec.rb +126 -13
  83. data/spec/controllers/authorizations_controller_spec.rb +250 -15
  84. data/spec/controllers/protected_resources_controller_spec.rb +16 -16
  85. data/spec/controllers/token_info_controller_spec.rb +4 -12
  86. data/spec/controllers/tokens_controller_spec.rb +12 -14
  87. data/spec/dummy/app/assets/config/manifest.js +2 -0
  88. data/spec/dummy/config/environments/test.rb +4 -5
  89. data/spec/dummy/config/initializers/doorkeeper.rb +6 -0
  90. data/spec/dummy/config/initializers/new_framework_defaults.rb +4 -0
  91. data/spec/dummy/config/routes.rb +3 -42
  92. data/spec/dummy/db/migrate/20111122132257_create_users.rb +3 -1
  93. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +3 -1
  94. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +3 -1
  95. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +3 -1
  96. data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +3 -1
  97. data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +6 -0
  98. data/spec/dummy/db/migrate/20180210183654_add_confidential_to_applications.rb +13 -0
  99. data/spec/dummy/db/schema.rb +38 -37
  100. data/spec/generators/application_owner_generator_spec.rb +1 -1
  101. data/spec/generators/confidential_applications_generator_spec.rb +45 -0
  102. data/spec/generators/install_generator_spec.rb +1 -1
  103. data/spec/generators/migration_generator_spec.rb +1 -1
  104. data/spec/generators/pkce_generator_spec.rb +43 -0
  105. data/spec/generators/previous_refresh_token_generator_spec.rb +1 -1
  106. data/spec/generators/views_generator_spec.rb +1 -1
  107. data/spec/grape/grape_integration_spec.rb +1 -1
  108. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +1 -1
  109. data/spec/lib/config_spec.rb +59 -14
  110. data/spec/lib/doorkeeper_spec.rb +1 -126
  111. data/spec/lib/models/expirable_spec.rb +0 -3
  112. data/spec/lib/models/revocable_spec.rb +0 -2
  113. data/spec/lib/models/scopes_spec.rb +0 -4
  114. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -4
  115. data/spec/lib/oauth/authorization_code_request_spec.rb +24 -2
  116. data/spec/lib/oauth/base_request_spec.rb +16 -2
  117. data/spec/lib/oauth/base_response_spec.rb +1 -1
  118. data/spec/lib/oauth/client/credentials_spec.rb +5 -5
  119. data/spec/lib/oauth/client_credentials/creator_spec.rb +5 -1
  120. data/spec/lib/oauth/client_credentials/issuer_spec.rb +26 -7
  121. data/spec/lib/oauth/client_credentials/validation_spec.rb +2 -3
  122. data/spec/lib/oauth/client_credentials_integration_spec.rb +1 -1
  123. data/spec/lib/oauth/client_credentials_request_spec.rb +3 -5
  124. data/spec/lib/oauth/client_spec.rb +0 -3
  125. data/spec/lib/oauth/code_request_spec.rb +4 -2
  126. data/spec/lib/oauth/error_response_spec.rb +0 -3
  127. data/spec/lib/oauth/error_spec.rb +0 -2
  128. data/spec/lib/oauth/forbidden_token_response_spec.rb +1 -4
  129. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -3
  130. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -1
  131. data/spec/lib/oauth/helpers/uri_checker_spec.rb +5 -2
  132. data/spec/lib/oauth/invalid_token_response_spec.rb +1 -4
  133. data/spec/lib/oauth/password_access_token_request_spec.rb +37 -2
  134. data/spec/lib/oauth/pre_authorization_spec.rb +40 -6
  135. data/spec/lib/oauth/refresh_token_request_spec.rb +11 -7
  136. data/spec/lib/oauth/scopes_spec.rb +0 -3
  137. data/spec/lib/oauth/token_request_spec.rb +4 -5
  138. data/spec/lib/oauth/token_response_spec.rb +0 -1
  139. data/spec/lib/oauth/token_spec.rb +37 -14
  140. data/spec/lib/orm/active_record/stale_records_cleaner_spec.rb +79 -0
  141. data/spec/lib/request/strategy_spec.rb +0 -1
  142. data/spec/lib/server_spec.rb +1 -1
  143. data/spec/models/doorkeeper/access_grant_spec.rb +1 -1
  144. data/spec/models/doorkeeper/access_token_spec.rb +50 -16
  145. data/spec/models/doorkeeper/application_spec.rb +51 -6
  146. data/spec/requests/applications/applications_request_spec.rb +89 -1
  147. data/spec/requests/applications/authorized_applications_spec.rb +1 -1
  148. data/spec/requests/endpoints/authorization_spec.rb +1 -1
  149. data/spec/requests/endpoints/token_spec.rb +7 -5
  150. data/spec/requests/flows/authorization_code_errors_spec.rb +1 -1
  151. data/spec/requests/flows/authorization_code_spec.rb +197 -1
  152. data/spec/requests/flows/client_credentials_spec.rb +46 -6
  153. data/spec/requests/flows/implicit_grant_errors_spec.rb +1 -1
  154. data/spec/requests/flows/implicit_grant_spec.rb +38 -11
  155. data/spec/requests/flows/password_spec.rb +120 -23
  156. data/spec/requests/flows/refresh_token_spec.rb +2 -2
  157. data/spec/requests/flows/revoke_token_spec.rb +11 -11
  158. data/spec/requests/flows/skip_authorization_spec.rb +16 -11
  159. data/spec/requests/protected_resources/metal_spec.rb +1 -1
  160. data/spec/requests/protected_resources/private_api_spec.rb +1 -1
  161. data/spec/routing/custom_controller_routes_spec.rb +59 -7
  162. data/spec/routing/default_routes_spec.rb +2 -2
  163. data/spec/routing/scoped_routes_spec.rb +16 -2
  164. data/spec/spec_helper.rb +54 -3
  165. data/spec/spec_helper_integration.rb +2 -74
  166. data/spec/support/doorkeeper_rspec.rb +19 -0
  167. data/spec/support/helpers/authorization_request_helper.rb +4 -4
  168. data/spec/support/helpers/request_spec_helper.rb +2 -2
  169. data/spec/support/helpers/url_helper.rb +7 -3
  170. data/spec/support/http_method_shim.rb +12 -16
  171. data/spec/validators/redirect_uri_validator_spec.rb +7 -1
  172. data/spec/version/version_spec.rb +3 -3
  173. data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
  174. metadata +32 -8
  175. data/spec/controllers/application_metal_controller.rb +0 -10
  176. /data/spec/support/dependencies/{factory_girl.rb → factory_bot.rb} +0 -0
@@ -1,4 +1,4 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  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,49 +7,92 @@ 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
- end.to_not change { Doorkeeper::AccessToken.count }
13
+ end.to_not(change { Doorkeeper::AccessToken.count })
14
14
  end
15
15
  end
16
16
  end
17
17
 
18
18
  describe 'Resource Owner Password Credentials Flow' do
19
+ let(:client_attributes) { {} }
20
+
19
21
  before do
20
22
  config_is_set(:grant_flows, ["password"])
21
23
  config_is_set(:resource_owner_from_credentials) { User.authenticate! params[:username], params[:password] }
22
- client_exists
24
+ client_exists(client_attributes)
23
25
  create_resource_owner
24
26
  end
25
27
 
26
28
  context 'with valid user credentials' do
27
- it 'should issue new token with confidential client' do
28
- expect do
29
- post password_token_endpoint_url(client: @client, resource_owner: @resource_owner)
30
- end.to change { Doorkeeper::AccessToken.count }.by(1)
29
+ context "with non-confidential/public client" do
30
+ let(:client_attributes) { { confidential: false } }
31
31
 
32
- token = Doorkeeper::AccessToken.first
32
+ context "when client_secret absent" do
33
+ it "should issue new token" do
34
+ expect do
35
+ post password_token_endpoint_url(client_id: @client.uid, resource_owner: @resource_owner)
36
+ end.to change { Doorkeeper::AccessToken.count }.by(1)
33
37
 
34
- expect(token.application_id).to eq @client.id
35
- should_have_json 'access_token', token.token
38
+ token = Doorkeeper::AccessToken.first
39
+
40
+ expect(token.application_id).to eq @client.id
41
+ should_have_json 'access_token', token.token
42
+ end
43
+ end
44
+
45
+ context "when client_secret present" do
46
+ it "should issue new token" do
47
+ expect do
48
+ post password_token_endpoint_url(client: @client, resource_owner: @resource_owner)
49
+ end.to change { Doorkeeper::AccessToken.count }.by(1)
50
+
51
+ token = Doorkeeper::AccessToken.first
52
+
53
+ expect(token.application_id).to eq @client.id
54
+ should_have_json 'access_token', token.token
55
+ end
56
+
57
+ context "when client_secret incorrect" do
58
+ it "should not issue new token" do
59
+ expect do
60
+ post password_token_endpoint_url(client_id: @client.uid, client_secret: 'foobar', resource_owner: @resource_owner)
61
+ end.not_to(change { Doorkeeper::AccessToken.count })
62
+
63
+ expect(response).not_to be_ok
64
+ end
65
+ end
66
+ end
36
67
  end
37
68
 
38
- it 'should issue new token with public client (only client_id present)' do
39
- expect do
40
- post password_token_endpoint_url(client_id: @client.uid, resource_owner: @resource_owner)
41
- end.to change { Doorkeeper::AccessToken.count }.by(1)
69
+ context "with confidential/private client" do
70
+ it "should issue new token" do
71
+ expect do
72
+ post password_token_endpoint_url(client: @client, resource_owner: @resource_owner)
73
+ end.to change { Doorkeeper::AccessToken.count }.by(1)
42
74
 
43
- token = Doorkeeper::AccessToken.first
75
+ token = Doorkeeper::AccessToken.first
44
76
 
45
- expect(token.application_id).to eq @client.id
46
- should_have_json 'access_token', token.token
77
+ expect(token.application_id).to eq @client.id
78
+ should_have_json 'access_token', token.token
79
+ end
80
+
81
+ context "when client_secret absent" do
82
+ it "should not issue new token" do
83
+ expect do
84
+ post password_token_endpoint_url(client_id: @client.uid, resource_owner: @resource_owner)
85
+ end.not_to(change { Doorkeeper::AccessToken.count })
86
+
87
+ expect(response).not_to be_ok
88
+ end
89
+ end
47
90
  end
48
91
 
49
92
  it 'should issue new token without client credentials' do
50
93
  expect do
51
94
  post password_token_endpoint_url(resource_owner: @resource_owner)
52
- end.to change { Doorkeeper::AccessToken.count }.by(1)
95
+ end.to(change { Doorkeeper::AccessToken.count }.by(1))
53
96
 
54
97
  token = Doorkeeper::AccessToken.first
55
98
 
@@ -97,6 +140,60 @@ describe 'Resource Owner Password Credentials Flow' do
97
140
  end
98
141
  end
99
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
+
100
197
  context 'with invalid scopes' do
101
198
  subject do
102
199
  post password_token_endpoint_url(client: @client,
@@ -124,13 +221,13 @@ describe 'Resource Owner Password Credentials Flow' do
124
221
  post password_token_endpoint_url(client: @client,
125
222
  resource_owner_username: @resource_owner.name,
126
223
  resource_owner_password: 'wrongpassword')
127
- end.to_not change { Doorkeeper::AccessToken.count }
224
+ end.to_not(change { Doorkeeper::AccessToken.count })
128
225
  end
129
226
 
130
227
  it 'should not issue new token without credentials' do
131
228
  expect do
132
229
  post password_token_endpoint_url(client: @client)
133
- end.to_not change { Doorkeeper::AccessToken.count }
230
+ end.to_not(change { Doorkeeper::AccessToken.count })
134
231
  end
135
232
  end
136
233
 
@@ -140,7 +237,7 @@ describe 'Resource Owner Password Credentials Flow' do
140
237
  post password_token_endpoint_url(client_id: @client.uid,
141
238
  client_secret: 'bad_secret',
142
239
  resource_owner: @resource_owner)
143
- end.to_not change { Doorkeeper::AccessToken.count }
240
+ end.to_not(change { Doorkeeper::AccessToken.count })
144
241
  end
145
242
  end
146
243
 
@@ -148,7 +245,7 @@ describe 'Resource Owner Password Credentials Flow' do
148
245
  it 'should not issue new token with bad client id' do
149
246
  expect do
150
247
  post password_token_endpoint_url(client_id: 'bad_id', resource_owner: @resource_owner)
151
- end.to_not change { Doorkeeper::AccessToken.count }
248
+ end.to_not(change { Doorkeeper::AccessToken.count })
152
249
  end
153
250
  end
154
251
  end
@@ -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