doorkeeper 4.2.5 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (215) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE.md +25 -0
  3. data/.github/PULL_REQUEST_TEMPLATE.md +17 -0
  4. data/.gitignore +2 -1
  5. data/.gitlab-ci.yml +16 -0
  6. data/.hound.yml +2 -13
  7. data/.rubocop.yml +17 -0
  8. data/.travis.yml +19 -4
  9. data/Appraisals +8 -4
  10. data/CODE_OF_CONDUCT.md +46 -0
  11. data/Gemfile +1 -1
  12. data/NEWS.md +115 -0
  13. data/README.md +175 -39
  14. data/RELEASING.md +5 -12
  15. data/Rakefile +6 -0
  16. data/SECURITY.md +15 -0
  17. data/UPGRADE.md +2 -0
  18. data/app/assets/stylesheets/doorkeeper/admin/application.css +2 -2
  19. data/app/controllers/doorkeeper/application_controller.rb +2 -5
  20. data/app/controllers/doorkeeper/application_metal_controller.rb +4 -0
  21. data/app/controllers/doorkeeper/applications_controller.rb +47 -13
  22. data/app/controllers/doorkeeper/authorizations_controller.rb +55 -12
  23. data/app/controllers/doorkeeper/authorized_applications_controller.rb +19 -2
  24. data/app/controllers/doorkeeper/tokens_controller.rb +24 -17
  25. data/app/helpers/doorkeeper/dashboard_helper.rb +8 -6
  26. data/app/validators/redirect_uri_validator.rb +13 -2
  27. data/app/views/doorkeeper/applications/_delete_form.html.erb +3 -1
  28. data/app/views/doorkeeper/applications/_form.html.erb +31 -19
  29. data/app/views/doorkeeper/applications/edit.html.erb +1 -1
  30. data/app/views/doorkeeper/applications/index.html.erb +18 -6
  31. data/app/views/doorkeeper/applications/new.html.erb +1 -1
  32. data/app/views/doorkeeper/applications/show.html.erb +8 -5
  33. data/app/views/doorkeeper/authorizations/error.html.erb +1 -1
  34. data/app/views/doorkeeper/authorizations/new.html.erb +5 -1
  35. data/app/views/doorkeeper/authorized_applications/index.html.erb +0 -1
  36. data/app/views/layouts/doorkeeper/admin.html.erb +15 -15
  37. data/config/locales/en.yml +19 -6
  38. data/doorkeeper.gemspec +20 -20
  39. data/gemfiles/rails_4_2.gemfile +6 -4
  40. data/gemfiles/rails_5_0.gemfile +4 -4
  41. data/gemfiles/rails_5_1.gemfile +6 -7
  42. data/gemfiles/rails_5_2.gemfile +12 -0
  43. data/gemfiles/rails_master.gemfile +17 -0
  44. data/lib/doorkeeper/config.rb +123 -71
  45. data/lib/doorkeeper/engine.rb +7 -3
  46. data/lib/doorkeeper/errors.rb +20 -5
  47. data/lib/doorkeeper/grape/helpers.rb +14 -9
  48. data/lib/doorkeeper/helpers/controller.rb +16 -22
  49. data/lib/doorkeeper/models/access_grant_mixin.rb +67 -23
  50. data/lib/doorkeeper/models/access_token_mixin.rb +54 -55
  51. data/lib/doorkeeper/models/application_mixin.rb +16 -30
  52. data/lib/doorkeeper/models/concerns/expirable.rb +7 -5
  53. data/lib/doorkeeper/models/concerns/orderable.rb +13 -0
  54. data/lib/doorkeeper/models/concerns/scopes.rb +1 -1
  55. data/lib/doorkeeper/oauth/authorization/code.rb +31 -8
  56. data/lib/doorkeeper/oauth/authorization/context.rb +15 -0
  57. data/lib/doorkeeper/oauth/authorization/token.rb +46 -20
  58. data/lib/doorkeeper/oauth/authorization_code_request.rb +33 -3
  59. data/lib/doorkeeper/oauth/base_request.rb +23 -7
  60. data/lib/doorkeeper/oauth/client/credentials.rb +6 -4
  61. data/lib/doorkeeper/oauth/client.rb +2 -4
  62. data/lib/doorkeeper/oauth/client_credentials/creator.rb +2 -1
  63. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +6 -3
  64. data/lib/doorkeeper/oauth/client_credentials/validation.rb +4 -6
  65. data/lib/doorkeeper/oauth/client_credentials_request.rb +0 -4
  66. data/lib/doorkeeper/oauth/error.rb +2 -2
  67. data/lib/doorkeeper/oauth/error_response.rb +11 -4
  68. data/lib/doorkeeper/oauth/forbidden_token_response.rb +1 -1
  69. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +0 -8
  70. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +15 -0
  71. data/lib/doorkeeper/oauth/invalid_token_response.rb +3 -4
  72. data/lib/doorkeeper/oauth/password_access_token_request.rb +8 -4
  73. data/lib/doorkeeper/oauth/pre_authorization.rb +45 -13
  74. data/lib/doorkeeper/oauth/refresh_token_request.rb +7 -1
  75. data/lib/doorkeeper/oauth/scopes.rb +19 -9
  76. data/lib/doorkeeper/oauth/token.rb +6 -3
  77. data/lib/doorkeeper/oauth/token_introspection.rb +128 -0
  78. data/lib/doorkeeper/oauth/token_response.rb +4 -2
  79. data/lib/doorkeeper/oauth.rb +13 -0
  80. data/lib/doorkeeper/orm/active_record/access_grant.rb +27 -0
  81. data/lib/doorkeeper/orm/active_record/access_token.rb +21 -20
  82. data/lib/doorkeeper/orm/active_record/application.rb +45 -0
  83. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +26 -0
  84. data/lib/doorkeeper/orm/active_record.rb +21 -8
  85. data/lib/doorkeeper/rails/helpers.rb +7 -10
  86. data/lib/doorkeeper/rails/routes.rb +21 -7
  87. data/lib/doorkeeper/rake/db.rake +40 -0
  88. data/lib/doorkeeper/rake/setup.rake +6 -0
  89. data/lib/doorkeeper/rake.rb +14 -0
  90. data/lib/doorkeeper/request/authorization_code.rb +0 -2
  91. data/lib/doorkeeper/request/client_credentials.rb +0 -2
  92. data/lib/doorkeeper/request/code.rb +0 -2
  93. data/lib/doorkeeper/request/password.rb +1 -13
  94. data/lib/doorkeeper/request/refresh_token.rb +0 -2
  95. data/lib/doorkeeper/request/token.rb +0 -2
  96. data/lib/doorkeeper/request.rb +29 -30
  97. data/lib/doorkeeper/validations.rb +3 -2
  98. data/lib/doorkeeper/version.rb +14 -1
  99. data/lib/doorkeeper.rb +21 -17
  100. data/lib/generators/doorkeeper/application_owner_generator.rb +26 -12
  101. data/lib/generators/doorkeeper/confidential_applications_generator.rb +32 -0
  102. data/lib/generators/doorkeeper/install_generator.rb +17 -9
  103. data/lib/generators/doorkeeper/migration_generator.rb +26 -9
  104. data/lib/generators/doorkeeper/pkce_generator.rb +32 -0
  105. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +31 -20
  106. data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
  107. data/lib/generators/doorkeeper/templates/{add_owner_to_application_migration.rb → add_owner_to_application_migration.rb.erb} +1 -1
  108. data/lib/generators/doorkeeper/templates/{add_previous_refresh_token_to_access_tokens.rb → add_previous_refresh_token_to_access_tokens.rb.erb} +1 -1
  109. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +6 -0
  110. data/lib/generators/doorkeeper/templates/initializer.rb +104 -12
  111. data/lib/generators/doorkeeper/templates/{migration.rb → migration.rb.erb} +2 -1
  112. data/lib/generators/doorkeeper/views_generator.rb +3 -1
  113. data/spec/controllers/application_metal_controller_spec.rb +50 -0
  114. data/spec/controllers/applications_controller_spec.rb +141 -17
  115. data/spec/controllers/authorizations_controller_spec.rb +304 -27
  116. data/spec/controllers/protected_resources_controller_spec.rb +44 -35
  117. data/spec/controllers/token_info_controller_spec.rb +17 -21
  118. data/spec/controllers/tokens_controller_spec.rb +201 -17
  119. data/spec/dummy/app/assets/config/manifest.js +2 -0
  120. data/spec/dummy/config/environments/test.rb +4 -5
  121. data/spec/dummy/config/initializers/doorkeeper.rb +23 -2
  122. data/spec/dummy/config/initializers/{active_record_belongs_to_required_by_default.rb → new_framework_defaults.rb} +5 -1
  123. data/spec/dummy/config/initializers/secret_token.rb +0 -1
  124. data/spec/dummy/config/routes.rb +3 -42
  125. data/spec/dummy/db/migrate/20111122132257_create_users.rb +3 -1
  126. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +3 -1
  127. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +3 -1
  128. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +3 -1
  129. data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +3 -1
  130. data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +6 -0
  131. data/spec/dummy/db/migrate/20180210183654_add_confidential_to_applications.rb +13 -0
  132. data/spec/dummy/db/schema.rb +38 -37
  133. data/spec/factories.rb +1 -1
  134. data/spec/generators/application_owner_generator_spec.rb +25 -6
  135. data/spec/generators/confidential_applications_generator_spec.rb +45 -0
  136. data/spec/generators/install_generator_spec.rb +1 -1
  137. data/spec/generators/migration_generator_spec.rb +25 -4
  138. data/spec/generators/pkce_generator_spec.rb +43 -0
  139. data/spec/generators/previous_refresh_token_generator_spec.rb +57 -0
  140. data/spec/generators/views_generator_spec.rb +1 -1
  141. data/spec/grape/grape_integration_spec.rb +135 -0
  142. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +2 -2
  143. data/spec/lib/config_spec.rb +199 -22
  144. data/spec/lib/doorkeeper_spec.rb +1 -126
  145. data/spec/lib/models/expirable_spec.rb +0 -4
  146. data/spec/lib/models/revocable_spec.rb +2 -4
  147. data/spec/lib/models/scopes_spec.rb +0 -4
  148. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -4
  149. data/spec/lib/oauth/authorization_code_request_spec.rb +63 -13
  150. data/spec/lib/oauth/base_request_spec.rb +43 -10
  151. data/spec/lib/oauth/base_response_spec.rb +1 -1
  152. data/spec/lib/oauth/client/credentials_spec.rb +5 -5
  153. data/spec/lib/oauth/client_credentials/creator_spec.rb +6 -2
  154. data/spec/lib/oauth/client_credentials/issuer_spec.rb +26 -7
  155. data/spec/lib/oauth/client_credentials/validation_spec.rb +2 -3
  156. data/spec/lib/oauth/client_credentials_integration_spec.rb +2 -2
  157. data/spec/lib/oauth/client_credentials_request_spec.rb +4 -5
  158. data/spec/lib/oauth/client_spec.rb +0 -3
  159. data/spec/lib/oauth/code_request_spec.rb +5 -5
  160. data/spec/lib/oauth/error_response_spec.rb +0 -3
  161. data/spec/lib/oauth/error_spec.rb +1 -3
  162. data/spec/lib/oauth/forbidden_token_response_spec.rb +1 -4
  163. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -3
  164. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -1
  165. data/spec/lib/oauth/helpers/uri_checker_spec.rb +115 -3
  166. data/spec/lib/oauth/invalid_token_response_spec.rb +2 -5
  167. data/spec/lib/oauth/password_access_token_request_spec.rb +46 -5
  168. data/spec/lib/oauth/pre_authorization_spec.rb +40 -6
  169. data/spec/lib/oauth/refresh_token_request_spec.rb +30 -14
  170. data/spec/lib/oauth/scopes_spec.rb +28 -4
  171. data/spec/lib/oauth/token_request_spec.rb +10 -13
  172. data/spec/lib/oauth/token_response_spec.rb +0 -1
  173. data/spec/lib/oauth/token_spec.rb +37 -14
  174. data/spec/lib/orm/active_record/stale_records_cleaner_spec.rb +79 -0
  175. data/spec/lib/request/strategy_spec.rb +0 -1
  176. data/spec/lib/server_spec.rb +10 -0
  177. data/spec/models/doorkeeper/access_grant_spec.rb +45 -2
  178. data/spec/models/doorkeeper/access_token_spec.rb +132 -64
  179. data/spec/models/doorkeeper/application_spec.rb +114 -23
  180. data/spec/requests/applications/applications_request_spec.rb +139 -6
  181. data/spec/requests/applications/authorized_applications_spec.rb +1 -1
  182. data/spec/requests/endpoints/authorization_spec.rb +1 -1
  183. data/spec/requests/endpoints/token_spec.rb +15 -6
  184. data/spec/requests/flows/authorization_code_errors_spec.rb +12 -2
  185. data/spec/requests/flows/authorization_code_spec.rb +199 -2
  186. data/spec/requests/flows/client_credentials_spec.rb +73 -5
  187. data/spec/requests/flows/implicit_grant_errors_spec.rb +3 -3
  188. data/spec/requests/flows/implicit_grant_spec.rb +38 -11
  189. data/spec/requests/flows/password_spec.rb +160 -24
  190. data/spec/requests/flows/refresh_token_spec.rb +6 -6
  191. data/spec/requests/flows/revoke_token_spec.rb +26 -26
  192. data/spec/requests/flows/skip_authorization_spec.rb +16 -11
  193. data/spec/requests/protected_resources/metal_spec.rb +2 -2
  194. data/spec/requests/protected_resources/private_api_spec.rb +2 -2
  195. data/spec/routing/custom_controller_routes_spec.rb +63 -7
  196. data/spec/routing/default_routes_spec.rb +6 -2
  197. data/spec/routing/scoped_routes_spec.rb +16 -2
  198. data/spec/spec_helper.rb +54 -3
  199. data/spec/spec_helper_integration.rb +2 -64
  200. data/spec/support/dependencies/factory_bot.rb +2 -0
  201. data/spec/support/doorkeeper_rspec.rb +19 -0
  202. data/spec/support/helpers/access_token_request_helper.rb +1 -1
  203. data/spec/support/helpers/authorization_request_helper.rb +4 -4
  204. data/spec/support/helpers/model_helper.rb +9 -4
  205. data/spec/support/helpers/request_spec_helper.rb +18 -6
  206. data/spec/support/helpers/url_helper.rb +15 -10
  207. data/spec/support/http_method_shim.rb +12 -16
  208. data/spec/support/shared/controllers_shared_context.rb +2 -6
  209. data/spec/support/shared/models_shared_examples.rb +4 -4
  210. data/spec/validators/redirect_uri_validator_spec.rb +58 -7
  211. data/spec/version/version_spec.rb +15 -0
  212. data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
  213. metadata +75 -33
  214. data/spec/controllers/application_metal_controller.rb +0 -10
  215. data/spec/support/dependencies/factory_girl.rb +0 -2
@@ -1,4 +1,4 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  module ControllerActions
4
4
  def index
@@ -9,11 +9,9 @@ module ControllerActions
9
9
  render plain: 'show'
10
10
  end
11
11
 
12
- def doorkeeper_unauthorized_render_options(*)
13
- end
12
+ def doorkeeper_unauthorized_render_options(*); end
14
13
 
15
- def doorkeeper_forbidden_render_options(*)
16
- end
14
+ def doorkeeper_forbidden_render_options(*); end
17
15
  end
18
16
 
19
17
  describe 'doorkeeper authorize filter' do
@@ -35,12 +33,12 @@ describe 'doorkeeper authorize filter' do
35
33
 
36
34
  it 'access_token param' do
37
35
  expect(Doorkeeper::AccessToken).to receive(:by_token).with(token_string).and_return(token)
38
- get :index, access_token: token_string
36
+ get :index, params: { access_token: token_string }
39
37
  end
40
38
 
41
39
  it 'bearer_token param' do
42
40
  expect(Doorkeeper::AccessToken).to receive(:by_token).with(token_string).and_return(token)
43
- get :index, bearer_token: token_string
41
+ get :index, params: { bearer_token: token_string }
44
42
  end
45
43
 
46
44
  it 'Authorization header' do
@@ -59,7 +57,7 @@ describe 'doorkeeper authorize filter' do
59
57
  expect(Doorkeeper::AccessToken).to receive(:by_token).exactly(2).times.and_return(token)
60
58
  request.env['HTTP_AUTHORIZATION'] = "Bearer #{token_string}"
61
59
  get :index
62
- controller.send(:remove_instance_variable, :@_doorkeeper_token)
60
+ controller.send(:remove_instance_variable, :@doorkeeper_token)
63
61
  get :index
64
62
  end
65
63
  end
@@ -73,25 +71,25 @@ describe 'doorkeeper authorize filter' do
73
71
 
74
72
  context 'with valid token', token: :valid do
75
73
  it 'allows into index action' do
76
- get :index, access_token: token_string
77
- expect(response).to be_success
74
+ get :index, params: { access_token: token_string }
75
+ expect(response).to be_successful
78
76
  end
79
77
 
80
78
  it 'allows into show action' do
81
- get :show, id: '4', access_token: token_string
82
- expect(response).to be_success
79
+ get :show, params: { id: '4', access_token: token_string }
80
+ expect(response).to be_successful
83
81
  end
84
82
  end
85
83
 
86
84
  context 'with invalid token', token: :invalid do
87
85
  it 'does not allow into index action' do
88
- get :index, access_token: token_string
86
+ get :index, params: { access_token: token_string }
89
87
  expect(response.status).to eq 401
90
88
  expect(response.header['WWW-Authenticate']).to match(/^Bearer/)
91
89
  end
92
90
 
93
91
  it 'does not allow into show action' do
94
- get :show, id: '4', access_token: token_string
92
+ get :show, params: { id: '4', access_token: token_string }
95
93
  expect(response.status).to eq 401
96
94
  expect(response.header['WWW-Authenticate']).to match(/^Bearer/)
97
95
  end
@@ -109,15 +107,16 @@ describe 'doorkeeper authorize filter' do
109
107
 
110
108
  it 'allows if the token has particular scopes' do
111
109
  token = double(Doorkeeper::AccessToken,
112
- accessible?: true, scopes: %w(write public),
110
+ accessible?: true, scopes: %w[write public],
113
111
  previous_refresh_token: "",
114
112
  revoke_previous_refresh_token!: true)
115
113
  expect(token).to receive(:acceptable?).with([:write]).and_return(true)
116
114
  expect(
117
115
  Doorkeeper::AccessToken
118
116
  ).to receive(:by_token).with(token_string).and_return(token)
119
- get :index, access_token: token_string
120
- expect(response).to be_success
117
+
118
+ get :index, params: { access_token: token_string }
119
+ expect(response).to be_successful
121
120
  end
122
121
 
123
122
  it 'does not allow if the token does not include given scope' do
@@ -129,7 +128,8 @@ describe 'doorkeeper authorize filter' do
129
128
  Doorkeeper::AccessToken
130
129
  ).to receive(:by_token).with(token_string).and_return(token)
131
130
  expect(token).to receive(:acceptable?).with([:write]).and_return(false)
132
- get :index, access_token: token_string
131
+
132
+ get :index, params: { access_token: token_string }
133
133
  expect(response.status).to eq 403
134
134
  expect(response.header).to_not include('WWW-Authenticate')
135
135
  end
@@ -146,27 +146,30 @@ describe 'doorkeeper authorize filter' do
146
146
  before do
147
147
  module ControllerActions
148
148
  remove_method :doorkeeper_unauthorized_render_options
149
+
149
150
  def doorkeeper_unauthorized_render_options(error: nil)
150
151
  { json: ActiveSupport::JSON.encode(error_message: error.description) }
151
152
  end
152
153
  end
153
154
  end
155
+
154
156
  after do
155
157
  module ControllerActions
156
158
  remove_method :doorkeeper_unauthorized_render_options
159
+
157
160
  def doorkeeper_unauthorized_render_options(error: nil)
158
161
  end
159
162
  end
160
163
  end
161
164
 
162
165
  it 'it renders a custom JSON response', token: :invalid do
163
- get :index, access_token: token_string
166
+ get :index, params: { access_token: token_string }
164
167
  expect(response.status).to eq 401
165
168
  expect(response.content_type).to eq('application/json')
166
169
  expect(response.header['WWW-Authenticate']).to match(/^Bearer/)
167
- parsed_body = JSON.parse(response.body)
168
- expect(parsed_body).not_to be_nil
169
- expect(parsed_body['error_message']).to match('token is invalid')
170
+
171
+ expect(json_response).not_to be_nil
172
+ expect(json_response['error_message']).to match('token is invalid')
170
173
  end
171
174
  end
172
175
 
@@ -174,21 +177,23 @@ describe 'doorkeeper authorize filter' do
174
177
  before do
175
178
  module ControllerActions
176
179
  remove_method :doorkeeper_unauthorized_render_options
177
- def doorkeeper_unauthorized_render_options(error: nil)
180
+
181
+ def doorkeeper_unauthorized_render_options(**)
178
182
  { plain: 'Unauthorized' }
179
183
  end
180
184
  end
181
185
  end
186
+
182
187
  after do
183
188
  module ControllerActions
184
189
  remove_method :doorkeeper_unauthorized_render_options
185
- def doorkeeper_unauthorized_render_options(error: nil)
186
- end
190
+
191
+ def doorkeeper_unauthorized_render_options(error: nil); end
187
192
  end
188
193
  end
189
194
 
190
195
  it 'it renders a custom text response', token: :invalid do
191
- get :index, access_token: token_string
196
+ get :index, params: { access_token: token_string }
192
197
  expect(response.status).to eq 401
193
198
  expect(response.content_type).to eq('text/plain')
194
199
  expect(response.header['WWW-Authenticate']).to match(/^Bearer/)
@@ -206,8 +211,8 @@ describe 'doorkeeper authorize filter' do
206
211
  after do
207
212
  module ControllerActions
208
213
  remove_method :doorkeeper_forbidden_render_options
209
- def doorkeeper_forbidden_render_options(*)
210
- end
214
+
215
+ def doorkeeper_forbidden_render_options(*); end
211
216
  end
212
217
  end
213
218
 
@@ -223,12 +228,14 @@ describe 'doorkeeper authorize filter' do
223
228
  expired?: false, previous_refresh_token: "",
224
229
  revoke_previous_refresh_token!: true)
225
230
  end
231
+
226
232
  let(:token_string) { '1A2DUWE' }
227
233
 
228
234
  context 'with a JSON custom render' do
229
235
  before do
230
236
  module ControllerActions
231
237
  remove_method :doorkeeper_forbidden_render_options
238
+
232
239
  def doorkeeper_forbidden_render_options(*)
233
240
  { json: { error_message: 'Forbidden' } }
234
241
  end
@@ -236,13 +243,13 @@ describe 'doorkeeper authorize filter' do
236
243
  end
237
244
 
238
245
  it 'renders a custom JSON response' do
239
- get :index, access_token: token_string
246
+ get :index, params: { access_token: token_string }
240
247
  expect(response.header).to_not include('WWW-Authenticate')
241
248
  expect(response.content_type).to eq('application/json')
242
249
  expect(response.status).to eq 403
243
- parsed_body = JSON.parse(response.body)
244
- expect(parsed_body).not_to be_nil
245
- expect(parsed_body['error_message']).to match('Forbidden')
250
+
251
+ expect(json_response).not_to be_nil
252
+ expect(json_response['error_message']).to match('Forbidden')
246
253
  end
247
254
  end
248
255
 
@@ -258,7 +265,7 @@ describe 'doorkeeper authorize filter' do
258
265
  end
259
266
 
260
267
  it 'overrides the default status code' do
261
- get :index, access_token: token_string
268
+ get :index, params: { access_token: token_string }
262
269
  expect(response.status).to eq 404
263
270
  end
264
271
  end
@@ -267,6 +274,7 @@ describe 'doorkeeper authorize filter' do
267
274
  before do
268
275
  module ControllerActions
269
276
  remove_method :doorkeeper_forbidden_render_options
277
+
270
278
  def doorkeeper_forbidden_render_options(*)
271
279
  { plain: 'Forbidden' }
272
280
  end
@@ -274,7 +282,7 @@ describe 'doorkeeper authorize filter' do
274
282
  end
275
283
 
276
284
  it 'renders a custom status code and text response' do
277
- get :index, access_token: token_string
285
+ get :index, params: { access_token: token_string }
278
286
  expect(response.header).to_not include('WWW-Authenticate')
279
287
  expect(response.status).to eq 403
280
288
  expect(response.body).to eq('Forbidden')
@@ -285,6 +293,7 @@ describe 'doorkeeper authorize filter' do
285
293
  before do
286
294
  module ControllerActions
287
295
  remove_method :doorkeeper_forbidden_render_options
296
+
288
297
  def doorkeeper_forbidden_render_options(*)
289
298
  { respond_not_found_when_forbidden: true, plain: 'Not Found' }
290
299
  end
@@ -292,7 +301,7 @@ describe 'doorkeeper authorize filter' do
292
301
  end
293
302
 
294
303
  it 'overrides the default status code' do
295
- get :index, access_token: token_string
304
+ get :index, params: { access_token: token_string }
296
305
  expect(response.status).to eq 404
297
306
  end
298
307
  end
@@ -1,36 +1,27 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  describe Doorkeeper::TokenInfoController do
4
- describe 'when requesting tokeninfo with valid token' do
5
- let(:doorkeeper_token) { FactoryGirl.create(:access_token) }
6
-
7
- before(:each) do
8
- allow(controller).to receive(:doorkeeper_token) { doorkeeper_token }
9
- end
10
-
11
- def do_get
12
- get :show
13
- end
4
+ describe 'when requesting token info with valid token' do
5
+ let(:doorkeeper_token) { FactoryBot.create(:access_token) }
14
6
 
15
7
  describe 'successful request' do
8
+ it 'responds with token info' do
9
+ get :show, params: { access_token: doorkeeper_token.token }
16
10
 
17
- it 'responds with tokeninfo' do
18
- do_get
19
11
  expect(response.body).to eq(doorkeeper_token.to_json)
20
12
  end
21
13
 
22
14
  it 'responds with a 200 status' do
23
- do_get
15
+ get :show, params: { access_token: doorkeeper_token.token }
16
+
24
17
  expect(response.status).to eq 200
25
18
  end
26
19
  end
27
20
 
28
21
  describe 'invalid token response' do
29
- before(:each) do
30
- allow(controller).to receive(:doorkeeper_token).and_return(nil)
31
- end
32
22
  it 'responds with 401 when doorkeeper_token is not valid' do
33
- do_get
23
+ get :show
24
+
34
25
  expect(response.status).to eq 401
35
26
  expect(response.headers['WWW-Authenticate']).to match(/^Bearer/)
36
27
  end
@@ -38,14 +29,19 @@ describe Doorkeeper::TokenInfoController do
38
29
  it 'responds with 401 when doorkeeper_token is invalid, expired or revoked' do
39
30
  allow(controller).to receive(:doorkeeper_token).and_return(doorkeeper_token)
40
31
  allow(doorkeeper_token).to receive(:accessible?).and_return(false)
41
- do_get
32
+
33
+ get :show
34
+
42
35
  expect(response.status).to eq 401
43
36
  expect(response.headers['WWW-Authenticate']).to match(/^Bearer/)
44
37
  end
45
38
 
46
39
  it 'responds body message for error' do
47
- do_get
48
- expect(response.body).to eq(Doorkeeper::OAuth::ErrorResponse.new(name: :invalid_request, status: :unauthorized).body.to_json)
40
+ get :show
41
+
42
+ expect(response.body).to eq(
43
+ Doorkeeper::OAuth::ErrorResponse.new(name: :invalid_request, status: :unauthorized).body.to_json
44
+ )
49
45
  end
50
46
  end
51
47
  end
@@ -1,14 +1,9 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  describe Doorkeeper::TokensController do
4
4
  describe 'when authorization has succeeded' do
5
- let :token do
6
- double(:token, authorize: true)
7
- end
5
+ let(:token) { double(:token, authorize: true) }
8
6
 
9
- before do
10
- allow(controller).to receive(:token) { token }
11
- end
12
7
 
13
8
  it 'returns the authorization' do
14
9
  skip 'verify need of these specs'
@@ -38,7 +33,7 @@ describe Doorkeeper::TokensController do
38
33
  allow(I18n).to receive(:translate).
39
34
  with(
40
35
  custom_message,
41
- hash_including(scope: [:doorkeeper, :errors, :messages]),
36
+ hash_including(scope: %i[doorkeeper errors messages])
42
37
  ).
43
38
  and_return('Authorization custom message')
44
39
 
@@ -57,19 +52,71 @@ describe Doorkeeper::TokensController do
57
52
  }
58
53
  expect(response.status).to eq 401
59
54
  expect(response.headers['WWW-Authenticate']).to match(/Bearer/)
60
- expect(JSON.load(response.body)).to eq expected_response_body
55
+ expect(JSON.parse(response.body)).to eq expected_response_body
61
56
  end
62
57
  end
63
58
 
64
- describe 'when revoke authorization has failed' do
65
- # http://tools.ietf.org/html/rfc7009#section-2.2
66
- it 'returns no error response' do
67
- token = double(:token, authorize: false, application_id?: true)
68
- allow(controller).to receive(:token) { token }
59
+ # http://tools.ietf.org/html/rfc7009#section-2.2
60
+ describe 'revoking tokens' do
61
+ let(:client) { FactoryBot.create(:application) }
62
+ let(:access_token) { FactoryBot.create(:access_token, application: client) }
63
+
64
+ before(:each) do
65
+ allow(controller).to receive(:token) { access_token }
66
+ end
67
+
68
+ context 'when associated app is public' do
69
+ let(:client) { FactoryBot.create(:application, confidential: false) }
70
+
71
+ it 'returns 200' do
72
+ post :revoke
73
+
74
+ expect(response.status).to eq 200
75
+ end
76
+
77
+ it 'revokes the access token' do
78
+ post :revoke
79
+
80
+ expect(access_token.reload).to have_attributes(revoked?: true)
81
+ end
82
+ end
83
+
84
+ context 'when associated app is confidential' do
85
+ let(:client) { FactoryBot.create(:application, confidential: true) }
86
+ let(:oauth_client) { Doorkeeper::OAuth::Client.new(client) }
87
+
88
+ before(:each) do
89
+ allow_any_instance_of(Doorkeeper::Server).to receive(:client) { oauth_client }
90
+ end
91
+
92
+ it 'returns 200' do
93
+ post :revoke
94
+
95
+ expect(response.status).to eq 200
96
+ end
97
+
98
+ it 'revokes the access token' do
99
+ post :revoke
69
100
 
70
- post :revoke
101
+ expect(access_token.reload).to have_attributes(revoked?: true)
102
+ end
103
+
104
+ context 'when authorization fails' do
105
+ let(:some_other_client) { FactoryBot.create(:application, confidential: true) }
106
+ let(:oauth_client) { Doorkeeper::OAuth::Client.new(some_other_client) }
107
+
108
+ it 'returns 200' do
109
+ post :revoke
71
110
 
72
- expect(response.status).to eq 200
111
+ expect(response.status).to eq 200
112
+ end
113
+
114
+ it 'does not revoke the access token' do
115
+ post :revoke
116
+
117
+ expect(access_token.reload).to have_attributes(revoked?: false)
118
+ end
119
+ end
73
120
  end
74
121
  end
75
122
 
@@ -79,10 +126,147 @@ describe Doorkeeper::TokensController do
79
126
  expect(strategy).to receive(:authorize).once
80
127
  allow(controller).to receive(:strategy) { strategy }
81
128
  allow(controller).to receive(:create) do
82
- controller.send :authorize_response
129
+ 2.times { controller.send :authorize_response }
130
+ controller.render json: {}, status: :ok
83
131
  end
84
132
 
85
133
  post :create
86
134
  end
87
135
  end
136
+
137
+ describe 'when requested token introspection' do
138
+ context 'authorized using Bearer token' do
139
+ let(:client) { FactoryBot.create(:application) }
140
+ let(:access_token) { FactoryBot.create(:access_token, application: client) }
141
+
142
+ it 'responds with full token introspection' do
143
+ request.headers['Authorization'] = "Bearer #{access_token.token}"
144
+
145
+ post :introspect, params: { token: access_token.token }
146
+
147
+ should_have_json 'active', true
148
+ expect(json_response).to include('client_id', 'token_type', 'exp', 'iat')
149
+ end
150
+ end
151
+
152
+ context 'authorized using Client Authentication' do
153
+ let(:client) { FactoryBot.create(:application) }
154
+ let(:access_token) { FactoryBot.create(:access_token, application: client) }
155
+
156
+ it 'responds with full token introspection' do
157
+ request.headers['Authorization'] = basic_auth_header_for_client(client)
158
+
159
+ post :introspect, params: { token: access_token.token }
160
+
161
+ should_have_json 'active', true
162
+ expect(json_response).to include('client_id', 'token_type', 'exp', 'iat')
163
+ should_have_json 'client_id', client.uid
164
+ end
165
+ end
166
+
167
+ context 'public access token' do
168
+ let(:client) { FactoryBot.create(:application) }
169
+ let(:access_token) { FactoryBot.create(:access_token, application: nil) }
170
+
171
+ it 'responds with full token introspection' do
172
+ request.headers['Authorization'] = basic_auth_header_for_client(client)
173
+
174
+ post :introspect, params: { token: access_token.token }
175
+
176
+ should_have_json 'active', true
177
+ expect(json_response).to include('client_id', 'token_type', 'exp', 'iat')
178
+ should_have_json 'client_id', nil
179
+ end
180
+ end
181
+
182
+ context 'token was issued to a different client than is making this request' do
183
+ let(:client) { FactoryBot.create(:application) }
184
+ let(:different_client) { FactoryBot.create(:application) }
185
+ let(:access_token) { FactoryBot.create(:access_token, application: client) }
186
+
187
+ it 'responds with only active state' do
188
+ request.headers['Authorization'] = basic_auth_header_for_client(different_client)
189
+
190
+ post :introspect, params: { token: access_token.token }
191
+
192
+ expect(response).to be_successful
193
+
194
+ should_have_json 'active', false
195
+ expect(json_response).not_to include('client_id', 'token_type', 'exp', 'iat')
196
+ end
197
+ end
198
+
199
+ context 'using invalid credentials to authorize' do
200
+ let(:client) { double(uid: '123123', secret: '666999') }
201
+ let(:access_token) { FactoryBot.create(:access_token) }
202
+
203
+ it 'responds with invalid_client error' do
204
+ request.headers['Authorization'] = basic_auth_header_for_client(client)
205
+
206
+ post :introspect, params: { token: access_token.token }
207
+
208
+ expect(response).not_to be_successful
209
+ response_status_should_be 401
210
+
211
+ should_not_have_json 'active'
212
+ should_have_json 'error', 'invalid_client'
213
+ end
214
+ end
215
+
216
+ context 'using wrong token value' do
217
+ let(:client) { FactoryBot.create(:application) }
218
+ let(:access_token) { FactoryBot.create(:access_token, application: client) }
219
+
220
+ it 'responds with only active state' do
221
+ request.headers['Authorization'] = basic_auth_header_for_client(client)
222
+
223
+ post :introspect, params: { token: SecureRandom.hex(16) }
224
+
225
+ should_have_json 'active', false
226
+ expect(json_response).not_to include('client_id', 'token_type', 'exp', 'iat')
227
+ end
228
+ end
229
+
230
+ context 'when requested Access Token expired' do
231
+ let(:client) { FactoryBot.create(:application) }
232
+ let(:access_token) { FactoryBot.create(:access_token, application: client, created_at: 1.year.ago) }
233
+
234
+ it 'responds with only active state' do
235
+ request.headers['Authorization'] = basic_auth_header_for_client(client)
236
+
237
+ post :introspect, params: { token: access_token.token }
238
+
239
+ should_have_json 'active', false
240
+ expect(json_response).not_to include('client_id', 'token_type', 'exp', 'iat')
241
+ end
242
+ end
243
+
244
+ context 'when requested Access Token revoked' do
245
+ let(:client) { FactoryBot.create(:application) }
246
+ let(:access_token) { FactoryBot.create(:access_token, application: client, revoked_at: 1.year.ago) }
247
+
248
+ it 'responds with only active state' do
249
+ request.headers['Authorization'] = basic_auth_header_for_client(client)
250
+
251
+ post :introspect, params: { token: access_token.token }
252
+
253
+ should_have_json 'active', false
254
+ expect(json_response).not_to include('client_id', 'token_type', 'exp', 'iat')
255
+ end
256
+ end
257
+
258
+ context 'unauthorized (no bearer token or client credentials)' do
259
+ let(:access_token) { FactoryBot.create(:access_token) }
260
+
261
+ it 'responds with invalid_request error' do
262
+ post :introspect, params: { token: access_token.token }
263
+
264
+ expect(response).not_to be_successful
265
+ response_status_should_be 401
266
+
267
+ should_not_have_json 'active'
268
+ should_have_json 'error', 'invalid_request'
269
+ end
270
+ end
271
+ end
88
272
  end
@@ -0,0 +1,2 @@
1
+ // JS and CSS bundles
2
+ //
@@ -7,6 +7,10 @@ Dummy::Application.configure do
7
7
  # and recreated between test runs. Don't rely on the data there!
8
8
  config.cache_classes = true
9
9
 
10
+ config.assets.enabled = true
11
+ config.assets.version = '1.0'
12
+ config.assets.digest = false
13
+
10
14
  # Do not eager load code on boot. This avoids loading your whole application
11
15
  # just for the purpose of running a single test. If you are using a tool that
12
16
  # preloads Rails for running tests, you may have to set it to true.
@@ -36,9 +40,4 @@ Dummy::Application.configure do
36
40
  config.active_support.deprecation = :stderr
37
41
 
38
42
  config.eager_load = true
39
-
40
- if DOORKEEPER_ORM == :active_record
41
- config.active_record.table_name_prefix = TABLE_NAME_PREFIX.to_s
42
- config.active_record.table_name_suffix = TABLE_NAME_SUFFIX.to_s
43
- end
44
43
  end
@@ -8,7 +8,11 @@ Doorkeeper.configure do
8
8
  User.where(id: session[:user_id]).first || redirect_to(root_url, alert: 'Needs sign in.')
9
9
  end
10
10
 
11
- # If you want to restrict access to the web interface for adding oauth authorized applications, you need to declare the block below.
11
+ # If you didn't skip applications controller from Doorkeeper routes in your application routes.rb
12
+ # file then you need to declare this block in order to restrict access to the web interface for
13
+ # adding oauth authorized applications. In other case it will return 403 Forbidden response
14
+ # every time somebody will try to access the admin web interface.
15
+ #
12
16
  # admin_authenticator do
13
17
  # # Put your admin authentication logic here.
14
18
  # # Example implementation:
@@ -29,6 +33,12 @@ Doorkeeper.configure do
29
33
  # Issue access tokens with refresh token (disabled by default)
30
34
  use_refresh_token
31
35
 
36
+ # Forbids creating/updating applications with arbitrary scopes that are
37
+ # not in configuration, i.e. `default_scopes` or `optional_scopes`.
38
+ # (disabled by default)
39
+ #
40
+ # enforce_configured_scopes
41
+
32
42
  # Provide support for an owner to be assigned to each registered application (disabled by default)
33
43
  # Optional parameter confirmation: true (default false) if you want to enforce ownership of
34
44
  # a registered application
@@ -82,7 +92,18 @@ Doorkeeper.configure do
82
92
  # http://tools.ietf.org/html/rfc6819#section-4.4.2
83
93
  # http://tools.ietf.org/html/rfc6819#section-4.4.3
84
94
  #
85
- # grant_flows %w(authorization_code client_credentials)
95
+ # grant_flows %w[authorization_code client_credentials]
96
+
97
+ # Hook into the strategies' request & response life-cycle in case your
98
+ # application needs advanced customization or logging:
99
+ #
100
+ # before_successful_strategy_response do |request|
101
+ # puts "BEFORE HOOK FIRED! #{request}"
102
+ # end
103
+ #
104
+ # after_successful_strategy_response do |request, response|
105
+ # puts "AFTER HOOK FIRED! #{request}, #{response}"
106
+ # end
86
107
 
87
108
  # Under some circumstances you might want to have applications auto-approved,
88
109
  # so that the user skips the authorization step.
@@ -1,6 +1,10 @@
1
1
  # Require `belongs_to` associations by default. This is a new Rails 5.0
2
2
  # default, so it is introduced as a configuration option to ensure that apps
3
3
  # made on earlier versions of Rails are not affected when upgrading.
4
- if Rails.version.to_i >= 5
4
+ if Rails::VERSION::MAJOR >= 5
5
5
  Rails.application.config.active_record.belongs_to_required_by_default = true
6
+
7
+ if Rails::VERSION::MINOR >= 2
8
+ Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true
9
+ end
6
10
  end
@@ -5,5 +5,4 @@
5
5
  # Make sure the secret is at least 30 characters and all random,
6
6
  # no regular words or you'll be exposed to dictionary attacks.
7
7
  Dummy::Application.config.secret_key_base =
8
- Dummy::Application.config.secret_token =
9
8
  'c00157b5a1bb6181792f0f4a8a080485de7bab9987e6cf159dc74c4f0573345c1bfa713b5d756e1491fc0b098567e8a619e2f8d268eda86a20a720d05d633780'