doorkeeper 5.0.0 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (241) hide show
  1. checksums.yaml +5 -5
  2. data/.hound.yml +2 -1
  3. data/.rubocop.yml +37 -4
  4. data/.travis.yml +16 -21
  5. data/Appraisals +29 -7
  6. data/Dangerfile +67 -0
  7. data/Gemfile +19 -5
  8. data/NEWS.md +107 -10
  9. data/README.md +75 -470
  10. data/Rakefile +10 -8
  11. data/app/controllers/doorkeeper/application_controller.rb +3 -2
  12. data/app/controllers/doorkeeper/application_metal_controller.rb +4 -13
  13. data/app/controllers/doorkeeper/applications_controller.rb +21 -7
  14. data/app/controllers/doorkeeper/authorizations_controller.rb +3 -3
  15. data/app/controllers/doorkeeper/authorized_applications_controller.rb +2 -0
  16. data/app/controllers/doorkeeper/token_info_controller.rb +4 -2
  17. data/app/controllers/doorkeeper/tokens_controller.rb +13 -11
  18. data/app/helpers/doorkeeper/dashboard_helper.rb +3 -1
  19. data/app/validators/redirect_uri_validator.rb +7 -2
  20. data/app/views/doorkeeper/applications/_form.html.erb +6 -0
  21. data/app/views/doorkeeper/applications/show.html.erb +1 -1
  22. data/app/views/layouts/doorkeeper/admin.html.erb +5 -3
  23. data/bin/console +16 -0
  24. data/config/locales/en.yml +1 -0
  25. data/doorkeeper.gemspec +28 -24
  26. data/gemfiles/rails_5_0.gemfile +9 -4
  27. data/gemfiles/rails_5_1.gemfile +9 -4
  28. data/gemfiles/rails_5_2.gemfile +10 -5
  29. data/gemfiles/rails_6_0.gemfile +17 -0
  30. data/gemfiles/rails_master.gemfile +9 -9
  31. data/lib/doorkeeper/config/option.rb +64 -0
  32. data/lib/doorkeeper/config.rb +197 -76
  33. data/lib/doorkeeper/engine.rb +3 -1
  34. data/lib/doorkeeper/errors.rb +17 -0
  35. data/lib/doorkeeper/grape/authorization_decorator.rb +6 -4
  36. data/lib/doorkeeper/grape/helpers.rb +5 -3
  37. data/lib/doorkeeper/helpers/controller.rb +5 -2
  38. data/lib/doorkeeper/models/access_grant_mixin.rb +25 -6
  39. data/lib/doorkeeper/models/access_token_mixin.rb +68 -22
  40. data/lib/doorkeeper/models/application_mixin.rb +45 -1
  41. data/lib/doorkeeper/models/concerns/accessible.rb +2 -0
  42. data/lib/doorkeeper/models/concerns/expirable.rb +6 -2
  43. data/lib/doorkeeper/models/concerns/orderable.rb +2 -0
  44. data/lib/doorkeeper/models/concerns/ownership.rb +3 -6
  45. data/lib/doorkeeper/models/concerns/reusable.rb +19 -0
  46. data/lib/doorkeeper/models/concerns/revocable.rb +4 -1
  47. data/lib/doorkeeper/models/concerns/scopes.rb +7 -1
  48. data/lib/doorkeeper/models/concerns/secret_storable.rb +108 -0
  49. data/lib/doorkeeper/oauth/authorization/code.rb +4 -2
  50. data/lib/doorkeeper/oauth/authorization/context.rb +2 -0
  51. data/lib/doorkeeper/oauth/authorization/token.rb +14 -7
  52. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +3 -1
  53. data/lib/doorkeeper/oauth/authorization_code_request.rb +8 -4
  54. data/lib/doorkeeper/oauth/base_request.rb +2 -0
  55. data/lib/doorkeeper/oauth/base_response.rb +2 -0
  56. data/lib/doorkeeper/oauth/client/credentials.rb +2 -0
  57. data/lib/doorkeeper/oauth/client.rb +3 -1
  58. data/lib/doorkeeper/oauth/client_credentials/creator.rb +2 -0
  59. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +2 -0
  60. data/lib/doorkeeper/oauth/client_credentials/validation.rb +7 -4
  61. data/lib/doorkeeper/oauth/client_credentials_request.rb +3 -1
  62. data/lib/doorkeeper/oauth/code_request.rb +2 -0
  63. data/lib/doorkeeper/oauth/code_response.rb +4 -2
  64. data/lib/doorkeeper/oauth/error.rb +2 -0
  65. data/lib/doorkeeper/oauth/error_response.rb +20 -6
  66. data/lib/doorkeeper/oauth/forbidden_token_response.rb +10 -3
  67. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +25 -8
  68. data/lib/doorkeeper/oauth/helpers/unique_token.rb +15 -1
  69. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +42 -3
  70. data/lib/doorkeeper/oauth/invalid_token_response.rb +22 -0
  71. data/lib/doorkeeper/oauth/password_access_token_request.rb +9 -2
  72. data/lib/doorkeeper/oauth/pre_authorization.rb +13 -5
  73. data/lib/doorkeeper/oauth/refresh_token_request.rb +15 -4
  74. data/lib/doorkeeper/oauth/scopes.rb +7 -3
  75. data/lib/doorkeeper/oauth/token.rb +4 -2
  76. data/lib/doorkeeper/oauth/token_introspection.rb +76 -8
  77. data/lib/doorkeeper/oauth/token_request.rb +2 -0
  78. data/lib/doorkeeper/oauth/token_response.rb +11 -9
  79. data/lib/doorkeeper/oauth.rb +5 -5
  80. data/lib/doorkeeper/orm/active_record/access_grant.rb +27 -13
  81. data/lib/doorkeeper/orm/active_record/access_token.rb +6 -13
  82. data/lib/doorkeeper/orm/active_record/application.rb +26 -7
  83. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +10 -3
  84. data/lib/doorkeeper/orm/active_record.rb +8 -6
  85. data/lib/doorkeeper/rails/helpers.rb +5 -1
  86. data/lib/doorkeeper/rails/routes/mapper.rb +2 -0
  87. data/lib/doorkeeper/rails/routes/mapping.rb +9 -7
  88. data/lib/doorkeeper/rails/routes.rb +19 -12
  89. data/lib/doorkeeper/rake/db.rake +17 -17
  90. data/lib/doorkeeper/rake.rb +1 -1
  91. data/lib/doorkeeper/request/authorization_code.rb +2 -0
  92. data/lib/doorkeeper/request/client_credentials.rb +2 -0
  93. data/lib/doorkeeper/request/code.rb +2 -0
  94. data/lib/doorkeeper/request/password.rb +2 -0
  95. data/lib/doorkeeper/request/refresh_token.rb +2 -0
  96. data/lib/doorkeeper/request/strategy.rb +2 -0
  97. data/lib/doorkeeper/request/token.rb +2 -0
  98. data/lib/doorkeeper/request.rb +3 -1
  99. data/lib/doorkeeper/secret_storing/base.rb +64 -0
  100. data/lib/doorkeeper/secret_storing/bcrypt.rb +60 -0
  101. data/lib/doorkeeper/secret_storing/plain.rb +33 -0
  102. data/lib/doorkeeper/secret_storing/sha256_hash.rb +26 -0
  103. data/lib/doorkeeper/server.rb +2 -0
  104. data/lib/doorkeeper/stale_records_cleaner.rb +20 -0
  105. data/lib/doorkeeper/validations.rb +2 -0
  106. data/lib/doorkeeper/version.rb +4 -2
  107. data/lib/doorkeeper.rb +69 -59
  108. data/lib/generators/doorkeeper/application_owner_generator.rb +10 -9
  109. data/lib/generators/doorkeeper/confidential_applications_generator.rb +10 -9
  110. data/lib/generators/doorkeeper/install_generator.rb +11 -9
  111. data/lib/generators/doorkeeper/migration_generator.rb +9 -9
  112. data/lib/generators/doorkeeper/pkce_generator.rb +10 -9
  113. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +10 -9
  114. data/lib/generators/doorkeeper/templates/initializer.rb +138 -13
  115. data/lib/generators/doorkeeper/templates/migration.rb.erb +17 -10
  116. data/lib/generators/doorkeeper/views_generator.rb +6 -4
  117. data/spec/controllers/application_metal_controller_spec.rb +24 -10
  118. data/spec/controllers/applications_controller_spec.rb +76 -78
  119. data/spec/controllers/authorizations_controller_spec.rb +189 -142
  120. data/spec/controllers/protected_resources_controller_spec.rb +111 -67
  121. data/spec/controllers/token_info_controller_spec.rb +14 -12
  122. data/spec/controllers/tokens_controller_spec.rb +170 -112
  123. data/spec/dummy/Rakefile +3 -1
  124. data/spec/dummy/app/controllers/application_controller.rb +3 -1
  125. data/spec/dummy/app/controllers/custom_authorizations_controller.rb +3 -1
  126. data/spec/dummy/app/controllers/full_protected_resources_controller.rb +4 -2
  127. data/spec/dummy/app/controllers/home_controller.rb +6 -5
  128. data/spec/dummy/app/controllers/metal_controller.rb +2 -0
  129. data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +4 -2
  130. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  131. data/spec/dummy/app/models/user.rb +2 -0
  132. data/spec/dummy/config/application.rb +26 -2
  133. data/spec/dummy/config/boot.rb +2 -4
  134. data/spec/dummy/config/environment.rb +1 -1
  135. data/spec/dummy/config/environments/development.rb +2 -0
  136. data/spec/dummy/config/environments/production.rb +2 -0
  137. data/spec/dummy/config/environments/test.rb +4 -2
  138. data/spec/dummy/config/initializers/backtrace_silencers.rb +2 -0
  139. data/spec/dummy/config/initializers/doorkeeper.rb +7 -3
  140. data/spec/dummy/config/initializers/secret_token.rb +3 -1
  141. data/spec/dummy/config/initializers/session_store.rb +3 -1
  142. data/spec/dummy/config/initializers/wrap_parameters.rb +2 -0
  143. data/spec/dummy/config.ru +3 -1
  144. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +20 -13
  145. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +1 -1
  146. data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +2 -0
  147. data/spec/dummy/db/schema.rb +1 -1
  148. data/spec/dummy/script/rails +7 -4
  149. data/spec/factories.rb +11 -9
  150. data/spec/generators/application_owner_generator_spec.rb +13 -26
  151. data/spec/generators/confidential_applications_generator_spec.rb +12 -28
  152. data/spec/generators/install_generator_spec.rb +19 -14
  153. data/spec/generators/migration_generator_spec.rb +13 -26
  154. data/spec/generators/pkce_generator_spec.rb +11 -26
  155. data/spec/generators/previous_refresh_token_generator_spec.rb +16 -29
  156. data/spec/generators/templates/routes.rb +2 -1
  157. data/spec/generators/views_generator_spec.rb +14 -12
  158. data/spec/grape/grape_integration_spec.rb +35 -33
  159. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +9 -7
  160. data/spec/lib/config_spec.rb +290 -104
  161. data/spec/lib/doorkeeper_spec.rb +8 -6
  162. data/spec/lib/models/expirable_spec.rb +22 -8
  163. data/spec/lib/models/reusable_spec.rb +40 -0
  164. data/spec/lib/models/revocable_spec.rb +8 -6
  165. data/spec/lib/models/scopes_spec.rb +27 -13
  166. data/spec/lib/models/secret_storable_spec.rb +135 -0
  167. data/spec/lib/oauth/authorization/uri_builder_spec.rb +17 -15
  168. data/spec/lib/oauth/authorization_code_request_spec.rb +43 -17
  169. data/spec/lib/oauth/base_request_spec.rb +24 -12
  170. data/spec/lib/oauth/base_response_spec.rb +3 -1
  171. data/spec/lib/oauth/client/credentials_spec.rb +26 -24
  172. data/spec/lib/oauth/client_credentials/creator_spec.rb +56 -10
  173. data/spec/lib/oauth/client_credentials/issuer_spec.rb +27 -20
  174. data/spec/lib/oauth/client_credentials/validation_spec.rb +21 -15
  175. data/spec/lib/oauth/client_credentials_integration_spec.rb +8 -6
  176. data/spec/lib/oauth/client_credentials_request_spec.rb +27 -21
  177. data/spec/lib/oauth/client_spec.rb +15 -13
  178. data/spec/lib/oauth/code_request_spec.rb +10 -8
  179. data/spec/lib/oauth/code_response_spec.rb +9 -7
  180. data/spec/lib/oauth/error_response_spec.rb +19 -11
  181. data/spec/lib/oauth/error_spec.rb +4 -2
  182. data/spec/lib/oauth/forbidden_token_response_spec.rb +7 -5
  183. data/spec/lib/oauth/helpers/scope_checker_spec.rb +68 -31
  184. data/spec/lib/oauth/helpers/unique_token_spec.rb +8 -6
  185. data/spec/lib/oauth/helpers/uri_checker_spec.rb +124 -93
  186. data/spec/lib/oauth/invalid_token_response_spec.rb +3 -1
  187. data/spec/lib/oauth/password_access_token_request_spec.rb +95 -34
  188. data/spec/lib/oauth/pre_authorization_spec.rb +80 -54
  189. data/spec/lib/oauth/refresh_token_request_spec.rb +46 -39
  190. data/spec/lib/oauth/scopes_spec.rb +63 -61
  191. data/spec/lib/oauth/token_request_spec.rb +80 -25
  192. data/spec/lib/oauth/token_response_spec.rb +40 -38
  193. data/spec/lib/oauth/token_spec.rb +64 -45
  194. data/spec/lib/request/strategy_spec.rb +3 -1
  195. data/spec/lib/secret_storing/base_spec.rb +60 -0
  196. data/spec/lib/secret_storing/bcrypt_spec.rb +49 -0
  197. data/spec/lib/secret_storing/plain_spec.rb +44 -0
  198. data/spec/lib/secret_storing/sha256_hash_spec.rb +48 -0
  199. data/spec/lib/server_spec.rb +20 -18
  200. data/spec/lib/{orm/active_record/stale_records_cleaner_spec.rb → stale_records_cleaner_spec.rb} +28 -18
  201. data/spec/models/doorkeeper/access_grant_spec.rb +80 -15
  202. data/spec/models/doorkeeper/access_token_spec.rb +212 -83
  203. data/spec/models/doorkeeper/application_spec.rb +146 -49
  204. data/spec/requests/applications/applications_request_spec.rb +100 -68
  205. data/spec/requests/applications/authorized_applications_spec.rb +20 -18
  206. data/spec/requests/endpoints/authorization_spec.rb +27 -25
  207. data/spec/requests/endpoints/token_spec.rb +38 -36
  208. data/spec/requests/flows/authorization_code_errors_spec.rb +27 -25
  209. data/spec/requests/flows/authorization_code_spec.rb +260 -158
  210. data/spec/requests/flows/client_credentials_spec.rb +54 -52
  211. data/spec/requests/flows/implicit_grant_errors_spec.rb +11 -9
  212. data/spec/requests/flows/implicit_grant_spec.rb +27 -25
  213. data/spec/requests/flows/password_spec.rb +64 -56
  214. data/spec/requests/flows/refresh_token_spec.rb +91 -32
  215. data/spec/requests/flows/revoke_token_spec.rb +49 -63
  216. data/spec/requests/flows/skip_authorization_spec.rb +23 -21
  217. data/spec/requests/protected_resources/metal_spec.rb +7 -5
  218. data/spec/requests/protected_resources/private_api_spec.rb +37 -35
  219. data/spec/routing/custom_controller_routes_spec.rb +71 -65
  220. data/spec/routing/default_routes_spec.rb +22 -20
  221. data/spec/routing/scoped_routes_spec.rb +20 -18
  222. data/spec/spec_helper.rb +15 -13
  223. data/spec/spec_helper_integration.rb +3 -1
  224. data/spec/support/dependencies/factory_bot.rb +3 -1
  225. data/spec/support/doorkeeper_rspec.rb +5 -2
  226. data/spec/support/helpers/access_token_request_helper.rb +3 -1
  227. data/spec/support/helpers/authorization_request_helper.rb +4 -2
  228. data/spec/support/helpers/config_helper.rb +2 -0
  229. data/spec/support/helpers/model_helper.rb +11 -5
  230. data/spec/support/helpers/request_spec_helper.rb +5 -3
  231. data/spec/support/helpers/url_helper.rb +20 -18
  232. data/spec/support/http_method_shim.rb +4 -9
  233. data/spec/support/orm/active_record.rb +3 -1
  234. data/spec/support/shared/controllers_shared_context.rb +68 -10
  235. data/spec/support/shared/hashing_shared_context.rb +36 -0
  236. data/spec/support/shared/models_shared_examples.rb +12 -10
  237. data/spec/validators/redirect_uri_validator_spec.rb +76 -47
  238. data/spec/version/version_spec.rb +7 -5
  239. metadata +70 -21
  240. data/gemfiles/rails_4_2.gemfile +0 -13
  241. data/spec/dummy/config/initializers/new_framework_defaults.rb +0 -10
@@ -1,12 +1,13 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
2
4
 
3
5
  describe Doorkeeper::TokensController do
4
- describe 'when authorization has succeeded' do
6
+ describe "when authorization has succeeded" do
5
7
  let(:token) { double(:token, authorize: true) }
6
8
 
7
-
8
- it 'returns the authorization' do
9
- skip 'verify need of these specs'
9
+ it "returns the authorization" do
10
+ skip "verify need of these specs"
10
11
 
11
12
  expect(token).to receive(:authorization)
12
13
 
@@ -14,28 +15,28 @@ describe Doorkeeper::TokensController do
14
15
  end
15
16
  end
16
17
 
17
- describe 'when authorization has failed' do
18
- it 'returns the error response' do
18
+ describe "when authorization has failed" do
19
+ it "returns the error response" do
19
20
  token = double(:token, authorize: false)
20
21
  allow(controller).to receive(:token) { token }
21
22
 
22
23
  post :create
23
24
 
24
- expect(response.status).to eq 401
25
- expect(response.headers['WWW-Authenticate']).to match(/Bearer/)
25
+ expect(response.status).to eq 400
26
+ expect(response.headers["WWW-Authenticate"]).to match(/Bearer/)
26
27
  end
27
28
  end
28
29
 
29
- describe 'when there is a failure due to a custom error' do
30
- it 'returns the error response with a custom message' do
30
+ describe "when there is a failure due to a custom error" do
31
+ it "returns the error response with a custom message" do
31
32
  # I18n looks for `doorkeeper.errors.messages.custom_message` in locale files
32
33
  custom_message = "my_message"
33
- allow(I18n).to receive(:translate).
34
- with(
34
+ allow(I18n).to receive(:translate)
35
+ .with(
35
36
  custom_message,
36
37
  hash_including(scope: %i[doorkeeper errors messages])
37
- ).
38
- and_return('Authorization custom message')
38
+ )
39
+ .and_return("Authorization custom message")
39
40
 
40
41
  doorkeeper_error = Doorkeeper::Errors::DoorkeeperError.new(custom_message)
41
42
 
@@ -47,41 +48,37 @@ describe Doorkeeper::TokensController do
47
48
  post :create
48
49
 
49
50
  expected_response_body = {
50
- "error" => custom_message,
51
- "error_description" => "Authorization custom message"
51
+ "error" => custom_message,
52
+ "error_description" => "Authorization custom message",
52
53
  }
53
- expect(response.status).to eq 401
54
- expect(response.headers['WWW-Authenticate']).to match(/Bearer/)
54
+ expect(response.status).to eq 400
55
+ expect(response.headers["WWW-Authenticate"]).to match(/Bearer/)
55
56
  expect(JSON.parse(response.body)).to eq expected_response_body
56
57
  end
57
58
  end
58
59
 
59
60
  # http://tools.ietf.org/html/rfc7009#section-2.2
60
- describe 'revoking tokens' do
61
+ describe "revoking tokens" do
61
62
  let(:client) { FactoryBot.create(:application) }
62
63
  let(:access_token) { FactoryBot.create(:access_token, application: client) }
63
64
 
64
- before(:each) do
65
- allow(controller).to receive(:token) { access_token }
66
- end
67
-
68
- context 'when associated app is public' do
65
+ context "when associated app is public" do
69
66
  let(:client) { FactoryBot.create(:application, confidential: false) }
70
67
 
71
- it 'returns 200' do
72
- post :revoke
68
+ it "returns 200" do
69
+ post :revoke, params: { token: access_token.token }
73
70
 
74
71
  expect(response.status).to eq 200
75
72
  end
76
73
 
77
- it 'revokes the access token' do
78
- post :revoke
74
+ it "revokes the access token" do
75
+ post :revoke, params: { token: access_token.token }
79
76
 
80
77
  expect(access_token.reload).to have_attributes(revoked?: true)
81
78
  end
82
79
  end
83
80
 
84
- context 'when associated app is confidential' do
81
+ context "when associated app is confidential" do
85
82
  let(:client) { FactoryBot.create(:application, confidential: true) }
86
83
  let(:oauth_client) { Doorkeeper::OAuth::Client.new(client) }
87
84
 
@@ -89,30 +86,30 @@ describe Doorkeeper::TokensController do
89
86
  allow_any_instance_of(Doorkeeper::Server).to receive(:client) { oauth_client }
90
87
  end
91
88
 
92
- it 'returns 200' do
93
- post :revoke
89
+ it "returns 200" do
90
+ post :revoke, params: { token: access_token.token }
94
91
 
95
92
  expect(response.status).to eq 200
96
93
  end
97
94
 
98
- it 'revokes the access token' do
99
- post :revoke
95
+ it "revokes the access token" do
96
+ post :revoke, params: { token: access_token.token }
100
97
 
101
98
  expect(access_token.reload).to have_attributes(revoked?: true)
102
99
  end
103
100
 
104
- context 'when authorization fails' do
101
+ context "when authorization fails" do
105
102
  let(:some_other_client) { FactoryBot.create(:application, confidential: true) }
106
103
  let(:oauth_client) { Doorkeeper::OAuth::Client.new(some_other_client) }
107
104
 
108
- it 'returns 200' do
109
- post :revoke
105
+ it "returns 200" do
106
+ post :revoke, params: { token: access_token.token }
110
107
 
111
108
  expect(response.status).to eq 200
112
109
  end
113
110
 
114
- it 'does not revoke the access token' do
115
- post :revoke
111
+ it "does not revoke the access token" do
112
+ post :revoke, params: { token: access_token.token }
116
113
 
117
114
  expect(access_token.reload).to have_attributes(revoked?: false)
118
115
  end
@@ -120,7 +117,7 @@ describe Doorkeeper::TokensController do
120
117
  end
121
118
  end
122
119
 
123
- describe 'authorize response memoization' do
120
+ describe "authorize response memoization" do
124
121
  it "memoizes the result of the authorization" do
125
122
  strategy = double(:strategy, authorize: true)
126
123
  expect(strategy).to receive(:authorize).once
@@ -134,138 +131,199 @@ describe Doorkeeper::TokensController do
134
131
  end
135
132
  end
136
133
 
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) }
134
+ describe "when requested token introspection" do
135
+ let(:client) { FactoryBot.create(:application) }
136
+ let(:access_token) { FactoryBot.create(:access_token, application: client) }
137
+ let(:token_for_introspection) { FactoryBot.create(:access_token, application: client) }
141
138
 
142
- it 'responds with full token introspection' do
143
- request.headers['Authorization'] = "Bearer #{access_token.token}"
139
+ context "authorized using valid Bearer token" do
140
+ it "responds with full token introspection" do
141
+ request.headers["Authorization"] = "Bearer #{access_token.token}"
144
142
 
145
- post :introspect, params: { token: access_token.token }
143
+ post :introspect, params: { token: token_for_introspection.token }
146
144
 
147
- should_have_json 'active', true
148
- expect(json_response).to include('client_id', 'token_type', 'exp', 'iat')
145
+ should_have_json "active", true
146
+ expect(json_response).to include("client_id", "token_type", "exp", "iat")
149
147
  end
150
148
  end
151
149
 
152
- context 'authorized using Client Authentication' do
153
- let(:client) { FactoryBot.create(:application) }
154
- let(:access_token) { FactoryBot.create(:access_token, application: client) }
150
+ context "authorized using valid Client Authentication" do
151
+ it "responds with full token introspection" do
152
+ request.headers["Authorization"] = basic_auth_header_for_client(client)
155
153
 
156
- it 'responds with full token introspection' do
157
- request.headers['Authorization'] = basic_auth_header_for_client(client)
154
+ post :introspect, params: { token: token_for_introspection.token }
158
155
 
159
- post :introspect, params: { token: access_token.token }
156
+ should_have_json "active", true
157
+ expect(json_response).to include("client_id", "token_type", "exp", "iat")
158
+ should_have_json "client_id", client.uid
159
+ end
160
+ end
160
161
 
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
162
+ context "using custom introspection response" do
163
+ before do
164
+ Doorkeeper.configure do
165
+ orm DOORKEEPER_ORM
166
+ custom_introspection_response do |_token, _context|
167
+ {
168
+ sub: "Z5O3upPC88QrAjx00dis",
169
+ aud: "https://protected.example.net/resource",
170
+ }
171
+ end
172
+ end
173
+ end
174
+
175
+ it "responds with full token introspection" do
176
+ request.headers["Authorization"] = "Bearer #{access_token.token}"
177
+
178
+ post :introspect, params: { token: token_for_introspection.token }
179
+
180
+ expect(json_response).to include("client_id", "token_type", "exp", "iat", "sub", "aud")
181
+ should_have_json "sub", "Z5O3upPC88QrAjx00dis"
182
+ should_have_json "aud", "https://protected.example.net/resource"
164
183
  end
165
184
  end
166
185
 
167
- context 'public access token' do
168
- let(:client) { FactoryBot.create(:application) }
169
- let(:access_token) { FactoryBot.create(:access_token, application: nil) }
186
+ context "public access token" do
187
+ let(:token_for_introspection) { FactoryBot.create(:access_token, application: nil) }
170
188
 
171
- it 'responds with full token introspection' do
172
- request.headers['Authorization'] = basic_auth_header_for_client(client)
189
+ it "responds with full token introspection" do
190
+ request.headers["Authorization"] = basic_auth_header_for_client(client)
173
191
 
174
- post :introspect, params: { token: access_token.token }
192
+ post :introspect, params: { token: token_for_introspection.token }
175
193
 
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
194
+ should_have_json "active", true
195
+ expect(json_response).to include("client_id", "token_type", "exp", "iat")
196
+ should_have_json "client_id", nil
179
197
  end
180
198
  end
181
199
 
182
- context 'token was issued to a different client than is making this request' do
183
- let(:client) { FactoryBot.create(:application) }
200
+ context "token was issued to a different client than is making this request" do
184
201
  let(:different_client) { FactoryBot.create(:application) }
185
- let(:access_token) { FactoryBot.create(:access_token, application: client) }
186
202
 
187
- it 'responds with only active state' do
188
- request.headers['Authorization'] = basic_auth_header_for_client(different_client)
203
+ it "responds with only active state" do
204
+ request.headers["Authorization"] = basic_auth_header_for_client(different_client)
189
205
 
190
- post :introspect, params: { token: access_token.token }
206
+ post :introspect, params: { token: token_for_introspection.token }
191
207
 
192
208
  expect(response).to be_successful
193
209
 
194
- should_have_json 'active', false
195
- expect(json_response).not_to include('client_id', 'token_type', 'exp', 'iat')
210
+ should_have_json "active", false
211
+ expect(json_response).not_to include("client_id", "token_type", "exp", "iat")
212
+ end
213
+ end
214
+
215
+ context "authorized using invalid Bearer token" do
216
+ let(:access_token) do
217
+ FactoryBot.create(:access_token, application: client, revoked_at: 1.day.ago)
218
+ end
219
+
220
+ it "responds with invalid token error" do
221
+ request.headers["Authorization"] = "Bearer #{access_token.token}"
222
+
223
+ post :introspect, params: { token: token_for_introspection.token }
224
+
225
+ response_status_should_be 401
226
+
227
+ should_not_have_json "active"
228
+ should_have_json "error", "invalid_token"
229
+ end
230
+ end
231
+
232
+ context "authorized using the Bearer token that need to be introspected" do
233
+ it "responds with invalid token error" do
234
+ request.headers["Authorization"] = "Bearer #{access_token.token}"
235
+
236
+ post :introspect, params: { token: access_token.token }
237
+
238
+ response_status_should_be 401
239
+
240
+ should_not_have_json "active"
241
+ should_have_json "error", "invalid_token"
196
242
  end
197
243
  end
198
244
 
199
- context 'using invalid credentials to authorize' do
200
- let(:client) { double(uid: '123123', secret: '666999') }
245
+ context "using invalid credentials to authorize" do
246
+ let(:client) { double(uid: "123123", secret: "666999") }
201
247
  let(:access_token) { FactoryBot.create(:access_token) }
202
248
 
203
- it 'responds with invalid_client error' do
204
- request.headers['Authorization'] = basic_auth_header_for_client(client)
249
+ it "responds with invalid_client error" do
250
+ request.headers["Authorization"] = basic_auth_header_for_client(client)
205
251
 
206
252
  post :introspect, params: { token: access_token.token }
207
253
 
208
254
  expect(response).not_to be_successful
209
255
  response_status_should_be 401
210
256
 
211
- should_not_have_json 'active'
212
- should_have_json 'error', 'invalid_client'
257
+ should_not_have_json "active"
258
+ should_have_json "error", "invalid_client"
213
259
  end
214
260
  end
215
261
 
216
- context 'using wrong token value' do
217
- let(:client) { FactoryBot.create(:application) }
218
- let(:access_token) { FactoryBot.create(:access_token, application: client) }
262
+ context "using wrong token value" do
263
+ context "authorized using client credentials" do
264
+ it "responds with only active state" do
265
+ request.headers["Authorization"] = basic_auth_header_for_client(client)
219
266
 
220
- it 'responds with only active state' do
221
- request.headers['Authorization'] = basic_auth_header_for_client(client)
267
+ post :introspect, params: { token: SecureRandom.hex(16) }
222
268
 
223
- post :introspect, params: { token: SecureRandom.hex(16) }
269
+ should_have_json "active", false
270
+ expect(json_response).not_to include("client_id", "token_type", "exp", "iat")
271
+ end
272
+ end
273
+
274
+ context "authorized using valid Bearer token" do
275
+ it "responds with only active state" do
276
+ request.headers["Authorization"] = "Bearer #{access_token.token}"
277
+
278
+ post :introspect, params: { token: SecureRandom.hex(16) }
224
279
 
225
- should_have_json 'active', false
226
- expect(json_response).not_to include('client_id', 'token_type', 'exp', 'iat')
280
+ should_have_json "active", false
281
+ expect(json_response).not_to include("client_id", "token_type", "exp", "iat")
282
+ end
227
283
  end
228
284
  end
229
285
 
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) }
286
+ context "when requested access token expired" do
287
+ let(:token_for_introspection) do
288
+ FactoryBot.create(:access_token, application: client, created_at: 1.year.ago)
289
+ end
233
290
 
234
- it 'responds with only active state' do
235
- request.headers['Authorization'] = basic_auth_header_for_client(client)
291
+ it "responds with only active state" do
292
+ request.headers["Authorization"] = basic_auth_header_for_client(client)
236
293
 
237
- post :introspect, params: { token: access_token.token }
294
+ post :introspect, params: { token: token_for_introspection.token }
238
295
 
239
- should_have_json 'active', false
240
- expect(json_response).not_to include('client_id', 'token_type', 'exp', 'iat')
296
+ should_have_json "active", false
297
+ expect(json_response).not_to include("client_id", "token_type", "exp", "iat")
241
298
  end
242
299
  end
243
300
 
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) }
301
+ context "when requested Access Token revoked" do
302
+ let(:token_for_introspection) do
303
+ FactoryBot.create(:access_token, application: client, revoked_at: 1.year.ago)
304
+ end
247
305
 
248
- it 'responds with only active state' do
249
- request.headers['Authorization'] = basic_auth_header_for_client(client)
306
+ it "responds with only active state" do
307
+ request.headers["Authorization"] = basic_auth_header_for_client(client)
250
308
 
251
- post :introspect, params: { token: access_token.token }
309
+ post :introspect, params: { token: token_for_introspection.token }
252
310
 
253
- should_have_json 'active', false
254
- expect(json_response).not_to include('client_id', 'token_type', 'exp', 'iat')
311
+ should_have_json "active", false
312
+ expect(json_response).not_to include("client_id", "token_type", "exp", "iat")
255
313
  end
256
314
  end
257
315
 
258
- context 'unauthorized (no bearer token or client credentials)' do
259
- let(:access_token) { FactoryBot.create(:access_token) }
316
+ context "unauthorized (no bearer token or client credentials)" do
317
+ let(:token_for_introspection) { FactoryBot.create(:access_token) }
260
318
 
261
- it 'responds with invalid_request error' do
262
- post :introspect, params: { token: access_token.token }
319
+ it "responds with invalid_request error" do
320
+ post :introspect, params: { token: token_for_introspection.token }
263
321
 
264
322
  expect(response).not_to be_successful
265
- response_status_should_be 401
323
+ response_status_should_be 400
266
324
 
267
- should_not_have_json 'active'
268
- should_have_json 'error', 'invalid_request'
325
+ should_not_have_json "active"
326
+ should_have_json "error", "invalid_request"
269
327
  end
270
328
  end
271
329
  end
data/spec/dummy/Rakefile CHANGED
@@ -1,7 +1,9 @@
1
1
  #!/usr/bin/env rake
2
+ # frozen_string_literal: true
3
+
2
4
  # Add your own tasks in files placed in lib/tasks ending in .rake,
3
5
  # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
4
6
 
5
- require File.expand_path('../config/application', __FILE__)
7
+ require File.expand_path("config/application", __dir__)
6
8
 
7
9
  Dummy::Application.load_tasks
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class ApplicationController < ActionController::Base
2
- protect_from_forgery
4
+ protect_from_forgery with: :exception
3
5
  end
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class CustomAuthorizationsController < ::ApplicationController
2
- %w(index show new create edit update destroy).each do |action|
4
+ %w[index show new create edit update destroy].each do |action|
3
5
  define_method action do
4
6
  render nothing: true
5
7
  end
@@ -1,12 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class FullProtectedResourcesController < ApplicationController
2
4
  before_action -> { doorkeeper_authorize! :write, :admin }, only: :show
3
5
  before_action :doorkeeper_authorize!, only: :index
4
6
 
5
7
  def index
6
- render plain: 'index'
8
+ render plain: "index"
7
9
  end
8
10
 
9
11
  def show
10
- render plain: 'show'
12
+ render plain: "show"
11
13
  end
12
14
  end
@@ -1,17 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class HomeController < ApplicationController
2
- def index
3
- end
4
+ def index; end
4
5
 
5
6
  def sign_in
6
7
  session[:user_id] = if Rails.env.development?
7
- User.first || User.create!(name: 'Joe', password: 'sekret')
8
+ User.first || User.create!(name: "Joe", password: "sekret")
8
9
  else
9
10
  User.first
10
11
  end
11
- redirect_to '/'
12
+ redirect_to "/"
12
13
  end
13
14
 
14
15
  def callback
15
- render plain: 'ok'
16
+ render plain: "ok"
16
17
  end
17
18
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class MetalController < ActionController::Metal
2
4
  include AbstractController::Callbacks
3
5
  include ActionController::Head
@@ -1,11 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class SemiProtectedResourcesController < ApplicationController
2
4
  before_action :doorkeeper_authorize!, only: :index
3
5
 
4
6
  def index
5
- render plain: 'protected index'
7
+ render plain: "protected index"
6
8
  end
7
9
 
8
10
  def show
9
- render plain: 'non protected show'
11
+ render plain: "non protected show"
10
12
  end
11
13
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ApplicationHelper
2
4
  def current_user
3
5
  @current_user ||= User.find_by_id(session[:user_id])
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class User < ActiveRecord::Base
2
4
  def self.authenticate!(name, password)
3
5
  User.where(name: name, password: password).first
@@ -1,6 +1,17 @@
1
- require File.expand_path('../boot', __FILE__)
1
+ require File.expand_path('boot', __dir__)
2
2
 
3
- require 'rails/all'
3
+ require "rails"
4
+
5
+ %w[
6
+ action_controller/railtie
7
+ action_view/railtie
8
+ sprockets/railtie
9
+ ].each do |railtie|
10
+ begin
11
+ require railtie
12
+ rescue LoadError
13
+ end
14
+ end
4
15
 
5
16
  Bundler.require(*Rails.groups)
6
17
 
@@ -16,6 +27,19 @@ require "#{orm}/railtie"
16
27
 
17
28
  module Dummy
18
29
  class Application < Rails::Application
30
+ if Rails.gem_version < Gem::Version.new('5.1')
31
+ config.action_controller.per_form_csrf_tokens = true
32
+ config.action_controller.forgery_protection_origin_check = true
33
+
34
+ ActiveSupport.to_time_preserves_timezone = true
35
+
36
+ config.active_record.belongs_to_required_by_default = true
37
+
38
+ config.ssl_options = { hsts: { subdomains: true } }
39
+ else
40
+ config.load_defaults "#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}"
41
+ end
42
+
19
43
  # Settings in config/environments/* take precedence over those specified here.
20
44
  # Application configuration should go into files in config/initializers
21
45
  # -- all .rb files in that directory are automatically loaded.
@@ -2,8 +2,6 @@ require 'rubygems'
2
2
  require 'bundler/setup'
3
3
 
4
4
  orm = ENV['BUNDLE_GEMFILE'].match(/Gemfile\.(.+)\.rb/)
5
- unless defined?(DOORKEEPER_ORM)
6
- DOORKEEPER_ORM = (orm && orm[1]) || :active_record
7
- end
5
+ DOORKEEPER_ORM = (orm && orm[1]) || :active_record unless defined?(DOORKEEPER_ORM)
8
6
 
9
- $LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__)
7
+ $LOAD_PATH.unshift File.expand_path('../../../lib', __dir__)
@@ -1,5 +1,5 @@
1
1
  # Load the rails application
2
- require File.expand_path('../application', __FILE__)
2
+ require File.expand_path('application', __dir__)
3
3
 
4
4
  # Initialize the rails application
5
5
  Rails.application.initialize!
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  Dummy::Application.configure do
2
4
  # Settings specified here will take precedence over those in config/application.rb
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  Dummy::Application.configure do
2
4
  # Settings specified here will take precedence over those in config/application.rb
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  Dummy::Application.configure do
2
4
  # Settings specified here will take precedence over those in config/application.rb
3
5
 
@@ -8,7 +10,7 @@ Dummy::Application.configure do
8
10
  config.cache_classes = true
9
11
 
10
12
  config.assets.enabled = true
11
- config.assets.version = '1.0'
13
+ config.assets.version = "1.0"
12
14
  config.assets.digest = false
13
15
 
14
16
  # Do not eager load code on boot. This avoids loading your whole application
@@ -24,7 +26,7 @@ Dummy::Application.configure do
24
26
  config.action_dispatch.show_exceptions = false
25
27
 
26
28
  # Disable request forgery protection in test environment
27
- config.action_controller.allow_forgery_protection = false
29
+ config.action_controller.allow_forgery_protection = false
28
30
 
29
31
  # Tell Action Mailer not to deliver emails to the real world.
30
32
  # The :test delivery method accumulates sent emails in the
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Be sure to restart your server when you modify this file.
2
4
 
3
5
  # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.