doorkeeper 5.0.3 → 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 (215) hide show
  1. checksums.yaml +4 -4
  2. data/.hound.yml +2 -1
  3. data/.rubocop.yml +37 -4
  4. data/.travis.yml +11 -21
  5. data/Appraisals +29 -7
  6. data/Dangerfile +5 -2
  7. data/Gemfile +19 -5
  8. data/NEWS.md +81 -21
  9. data/README.md +75 -485
  10. data/Rakefile +10 -8
  11. data/app/controllers/doorkeeper/application_controller.rb +1 -2
  12. data/app/controllers/doorkeeper/application_metal_controller.rb +2 -13
  13. data/app/controllers/doorkeeper/applications_controller.rb +20 -8
  14. data/app/controllers/doorkeeper/authorized_applications_controller.rb +1 -1
  15. data/app/controllers/doorkeeper/token_info_controller.rb +2 -2
  16. data/app/controllers/doorkeeper/tokens_controller.rb +11 -11
  17. data/app/helpers/doorkeeper/dashboard_helper.rb +1 -1
  18. data/app/validators/redirect_uri_validator.rb +5 -2
  19. data/app/views/doorkeeper/applications/_form.html.erb +6 -0
  20. data/app/views/doorkeeper/applications/show.html.erb +1 -1
  21. data/app/views/layouts/doorkeeper/admin.html.erb +5 -3
  22. data/bin/console +16 -0
  23. data/config/locales/en.yml +1 -0
  24. data/doorkeeper.gemspec +24 -21
  25. data/gemfiles/rails_5_0.gemfile +9 -4
  26. data/gemfiles/rails_5_1.gemfile +9 -4
  27. data/gemfiles/rails_5_2.gemfile +10 -5
  28. data/gemfiles/rails_6_0.gemfile +17 -0
  29. data/gemfiles/rails_master.gemfile +9 -9
  30. data/lib/doorkeeper/config/option.rb +64 -0
  31. data/lib/doorkeeper/config.rb +191 -75
  32. data/lib/doorkeeper/engine.rb +1 -1
  33. data/lib/doorkeeper/grape/authorization_decorator.rb +4 -4
  34. data/lib/doorkeeper/grape/helpers.rb +3 -3
  35. data/lib/doorkeeper/helpers/controller.rb +3 -2
  36. data/lib/doorkeeper/models/access_grant_mixin.rb +20 -3
  37. data/lib/doorkeeper/models/access_token_mixin.rb +63 -19
  38. data/lib/doorkeeper/models/application_mixin.rb +43 -1
  39. data/lib/doorkeeper/models/concerns/expirable.rb +4 -2
  40. data/lib/doorkeeper/models/concerns/ownership.rb +1 -6
  41. data/lib/doorkeeper/models/concerns/reusable.rb +19 -0
  42. data/lib/doorkeeper/models/concerns/revocable.rb +2 -1
  43. data/lib/doorkeeper/models/concerns/scopes.rb +5 -1
  44. data/lib/doorkeeper/models/concerns/secret_storable.rb +108 -0
  45. data/lib/doorkeeper/oauth/authorization/code.rb +2 -2
  46. data/lib/doorkeeper/oauth/authorization/token.rb +12 -7
  47. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +1 -1
  48. data/lib/doorkeeper/oauth/authorization_code_request.rb +6 -4
  49. data/lib/doorkeeper/oauth/client.rb +1 -1
  50. data/lib/doorkeeper/oauth/client_credentials/validation.rb +5 -4
  51. data/lib/doorkeeper/oauth/client_credentials_request.rb +1 -1
  52. data/lib/doorkeeper/oauth/code_response.rb +2 -2
  53. data/lib/doorkeeper/oauth/error_response.rb +10 -6
  54. data/lib/doorkeeper/oauth/forbidden_token_response.rb +1 -1
  55. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +23 -8
  56. data/lib/doorkeeper/oauth/helpers/unique_token.rb +13 -1
  57. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +37 -1
  58. data/lib/doorkeeper/oauth/invalid_token_response.rb +5 -1
  59. data/lib/doorkeeper/oauth/password_access_token_request.rb +7 -2
  60. data/lib/doorkeeper/oauth/pre_authorization.rb +11 -5
  61. data/lib/doorkeeper/oauth/refresh_token_request.rb +5 -2
  62. data/lib/doorkeeper/oauth/scopes.rb +5 -3
  63. data/lib/doorkeeper/oauth/token.rb +2 -2
  64. data/lib/doorkeeper/oauth/token_introspection.rb +74 -8
  65. data/lib/doorkeeper/oauth/token_response.rb +9 -9
  66. data/lib/doorkeeper/oauth.rb +5 -5
  67. data/lib/doorkeeper/orm/active_record/access_grant.rb +27 -13
  68. data/lib/doorkeeper/orm/active_record/access_token.rb +6 -13
  69. data/lib/doorkeeper/orm/active_record/application.rb +21 -57
  70. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +10 -3
  71. data/lib/doorkeeper/orm/active_record.rb +6 -6
  72. data/lib/doorkeeper/rails/helpers.rb +1 -1
  73. data/lib/doorkeeper/rails/routes/mapping.rb +7 -7
  74. data/lib/doorkeeper/rails/routes.rb +11 -11
  75. data/lib/doorkeeper/rake/db.rake +13 -13
  76. data/lib/doorkeeper/rake.rb +1 -1
  77. data/lib/doorkeeper/request.rb +1 -1
  78. data/lib/doorkeeper/secret_storing/base.rb +64 -0
  79. data/lib/doorkeeper/secret_storing/bcrypt.rb +60 -0
  80. data/lib/doorkeeper/secret_storing/plain.rb +33 -0
  81. data/lib/doorkeeper/secret_storing/sha256_hash.rb +26 -0
  82. data/lib/doorkeeper/stale_records_cleaner.rb +1 -1
  83. data/lib/doorkeeper/version.rb +3 -3
  84. data/lib/doorkeeper.rb +69 -60
  85. data/lib/generators/doorkeeper/application_owner_generator.rb +10 -9
  86. data/lib/generators/doorkeeper/confidential_applications_generator.rb +10 -9
  87. data/lib/generators/doorkeeper/install_generator.rb +11 -9
  88. data/lib/generators/doorkeeper/migration_generator.rb +9 -9
  89. data/lib/generators/doorkeeper/pkce_generator.rb +10 -9
  90. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +10 -9
  91. data/lib/generators/doorkeeper/templates/initializer.rb +120 -13
  92. data/lib/generators/doorkeeper/templates/migration.rb.erb +15 -7
  93. data/lib/generators/doorkeeper/views_generator.rb +6 -4
  94. data/spec/controllers/application_metal_controller_spec.rb +24 -10
  95. data/spec/controllers/applications_controller_spec.rb +54 -52
  96. data/spec/controllers/authorizations_controller_spec.rb +139 -145
  97. data/spec/controllers/protected_resources_controller_spec.rb +78 -76
  98. data/spec/controllers/token_info_controller_spec.rb +14 -12
  99. data/spec/controllers/tokens_controller_spec.rb +167 -108
  100. data/spec/dummy/Rakefile +3 -1
  101. data/spec/dummy/app/controllers/application_controller.rb +3 -1
  102. data/spec/dummy/app/controllers/custom_authorizations_controller.rb +2 -0
  103. data/spec/dummy/app/controllers/full_protected_resources_controller.rb +4 -2
  104. data/spec/dummy/app/controllers/home_controller.rb +5 -3
  105. data/spec/dummy/app/controllers/metal_controller.rb +2 -0
  106. data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +4 -2
  107. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  108. data/spec/dummy/app/models/user.rb +2 -0
  109. data/spec/dummy/config/application.rb +25 -1
  110. data/spec/dummy/config/environments/development.rb +2 -0
  111. data/spec/dummy/config/environments/production.rb +2 -0
  112. data/spec/dummy/config/environments/test.rb +3 -1
  113. data/spec/dummy/config/initializers/backtrace_silencers.rb +2 -0
  114. data/spec/dummy/config/initializers/doorkeeper.rb +5 -2
  115. data/spec/dummy/config/initializers/secret_token.rb +3 -1
  116. data/spec/dummy/config/initializers/session_store.rb +3 -1
  117. data/spec/dummy/config/initializers/wrap_parameters.rb +2 -0
  118. data/spec/dummy/config.ru +3 -1
  119. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +17 -10
  120. data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +2 -0
  121. data/spec/dummy/db/schema.rb +1 -1
  122. data/spec/dummy/script/rails +5 -3
  123. data/spec/factories.rb +8 -6
  124. data/spec/generators/application_owner_generator_spec.rb +13 -26
  125. data/spec/generators/confidential_applications_generator_spec.rb +12 -28
  126. data/spec/generators/install_generator_spec.rb +17 -15
  127. data/spec/generators/migration_generator_spec.rb +13 -26
  128. data/spec/generators/pkce_generator_spec.rb +11 -26
  129. data/spec/generators/previous_refresh_token_generator_spec.rb +16 -29
  130. data/spec/generators/templates/routes.rb +2 -0
  131. data/spec/generators/views_generator_spec.rb +14 -12
  132. data/spec/grape/grape_integration_spec.rb +34 -32
  133. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +9 -7
  134. data/spec/lib/config_spec.rb +268 -99
  135. data/spec/lib/doorkeeper_spec.rb +3 -1
  136. data/spec/lib/models/expirable_spec.rb +22 -8
  137. data/spec/lib/models/reusable_spec.rb +40 -0
  138. data/spec/lib/models/revocable_spec.rb +8 -6
  139. data/spec/lib/models/scopes_spec.rb +27 -13
  140. data/spec/lib/models/secret_storable_spec.rb +135 -0
  141. data/spec/lib/oauth/authorization/uri_builder_spec.rb +17 -15
  142. data/spec/lib/oauth/authorization_code_request_spec.rb +34 -11
  143. data/spec/lib/oauth/base_request_spec.rb +20 -8
  144. data/spec/lib/oauth/base_response_spec.rb +3 -1
  145. data/spec/lib/oauth/client/credentials_spec.rb +24 -22
  146. data/spec/lib/oauth/client_credentials/creator_spec.rb +56 -10
  147. data/spec/lib/oauth/client_credentials/issuer_spec.rb +27 -18
  148. data/spec/lib/oauth/client_credentials/validation_spec.rb +20 -15
  149. data/spec/lib/oauth/client_credentials_integration_spec.rb +7 -5
  150. data/spec/lib/oauth/client_credentials_request_spec.rb +27 -21
  151. data/spec/lib/oauth/client_spec.rb +15 -13
  152. data/spec/lib/oauth/code_request_spec.rb +8 -6
  153. data/spec/lib/oauth/code_response_spec.rb +9 -7
  154. data/spec/lib/oauth/error_response_spec.rb +19 -11
  155. data/spec/lib/oauth/error_spec.rb +4 -2
  156. data/spec/lib/oauth/forbidden_token_response_spec.rb +7 -5
  157. data/spec/lib/oauth/helpers/scope_checker_spec.rb +68 -31
  158. data/spec/lib/oauth/helpers/unique_token_spec.rb +8 -6
  159. data/spec/lib/oauth/helpers/uri_checker_spec.rb +115 -95
  160. data/spec/lib/oauth/invalid_token_response_spec.rb +3 -1
  161. data/spec/lib/oauth/password_access_token_request_spec.rb +79 -30
  162. data/spec/lib/oauth/pre_authorization_spec.rb +80 -54
  163. data/spec/lib/oauth/refresh_token_request_spec.rb +36 -33
  164. data/spec/lib/oauth/scopes_spec.rb +63 -61
  165. data/spec/lib/oauth/token_request_spec.rb +79 -24
  166. data/spec/lib/oauth/token_response_spec.rb +40 -38
  167. data/spec/lib/oauth/token_spec.rb +60 -44
  168. data/spec/lib/request/strategy_spec.rb +3 -1
  169. data/spec/lib/secret_storing/base_spec.rb +60 -0
  170. data/spec/lib/secret_storing/bcrypt_spec.rb +49 -0
  171. data/spec/lib/secret_storing/plain_spec.rb +44 -0
  172. data/spec/lib/secret_storing/sha256_hash_spec.rb +48 -0
  173. data/spec/lib/server_spec.rb +16 -14
  174. data/spec/lib/stale_records_cleaner_spec.rb +17 -17
  175. data/spec/models/doorkeeper/access_grant_spec.rb +80 -15
  176. data/spec/models/doorkeeper/access_token_spec.rb +198 -73
  177. data/spec/models/doorkeeper/application_spec.rb +280 -288
  178. data/spec/requests/applications/applications_request_spec.rb +98 -66
  179. data/spec/requests/applications/authorized_applications_spec.rb +20 -18
  180. data/spec/requests/endpoints/authorization_spec.rb +25 -23
  181. data/spec/requests/endpoints/token_spec.rb +38 -36
  182. data/spec/requests/flows/authorization_code_errors_spec.rb +26 -24
  183. data/spec/requests/flows/authorization_code_spec.rb +193 -151
  184. data/spec/requests/flows/client_credentials_spec.rb +54 -52
  185. data/spec/requests/flows/implicit_grant_errors_spec.rb +10 -8
  186. data/spec/requests/flows/implicit_grant_spec.rb +27 -25
  187. data/spec/requests/flows/password_spec.rb +59 -55
  188. data/spec/requests/flows/refresh_token_spec.rb +45 -43
  189. data/spec/requests/flows/revoke_token_spec.rb +40 -54
  190. data/spec/requests/flows/skip_authorization_spec.rb +23 -21
  191. data/spec/requests/protected_resources/metal_spec.rb +7 -5
  192. data/spec/requests/protected_resources/private_api_spec.rb +35 -33
  193. data/spec/routing/custom_controller_routes_spec.rb +71 -65
  194. data/spec/routing/default_routes_spec.rb +22 -20
  195. data/spec/routing/scoped_routes_spec.rb +20 -18
  196. data/spec/spec_helper.rb +15 -13
  197. data/spec/spec_helper_integration.rb +3 -1
  198. data/spec/support/dependencies/factory_bot.rb +3 -1
  199. data/spec/support/doorkeeper_rspec.rb +3 -1
  200. data/spec/support/helpers/access_token_request_helper.rb +3 -1
  201. data/spec/support/helpers/authorization_request_helper.rb +4 -2
  202. data/spec/support/helpers/config_helper.rb +2 -0
  203. data/spec/support/helpers/model_helper.rb +3 -1
  204. data/spec/support/helpers/request_spec_helper.rb +5 -3
  205. data/spec/support/helpers/url_helper.rb +9 -7
  206. data/spec/support/http_method_shim.rb +4 -9
  207. data/spec/support/orm/active_record.rb +3 -1
  208. data/spec/support/shared/controllers_shared_context.rb +18 -16
  209. data/spec/support/shared/hashing_shared_context.rb +36 -0
  210. data/spec/support/shared/models_shared_examples.rb +12 -10
  211. data/spec/validators/redirect_uri_validator_spec.rb +74 -45
  212. data/spec/version/version_spec.rb +7 -5
  213. metadata +60 -26
  214. data/gemfiles/rails_4_2.gemfile +0 -13
  215. data/spec/dummy/config/initializers/new_framework_defaults.rb +0 -8
@@ -1,11 +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
- it 'returns the authorization' do
8
- skip 'verify need of these specs'
9
+ it "returns the authorization" do
10
+ skip "verify need of these specs"
9
11
 
10
12
  expect(token).to receive(:authorization)
11
13
 
@@ -13,20 +15,20 @@ describe Doorkeeper::TokensController do
13
15
  end
14
16
  end
15
17
 
16
- describe 'when authorization has failed' do
17
- it 'returns the error response' do
18
+ describe "when authorization has failed" do
19
+ it "returns the error response" do
18
20
  token = double(:token, authorize: false)
19
21
  allow(controller).to receive(:token) { token }
20
22
 
21
23
  post :create
22
24
 
23
- expect(response.status).to eq 401
24
- expect(response.headers['WWW-Authenticate']).to match(/Bearer/)
25
+ expect(response.status).to eq 400
26
+ expect(response.headers["WWW-Authenticate"]).to match(/Bearer/)
25
27
  end
26
28
  end
27
29
 
28
- describe 'when there is a failure due to a custom error' do
29
- 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
30
32
  # I18n looks for `doorkeeper.errors.messages.custom_message` in locale files
31
33
  custom_message = "my_message"
32
34
  allow(I18n).to receive(:translate)
@@ -34,7 +36,7 @@ describe Doorkeeper::TokensController do
34
36
  custom_message,
35
37
  hash_including(scope: %i[doorkeeper errors messages])
36
38
  )
37
- .and_return('Authorization custom message')
39
+ .and_return("Authorization custom message")
38
40
 
39
41
  doorkeeper_error = Doorkeeper::Errors::DoorkeeperError.new(custom_message)
40
42
 
@@ -46,41 +48,37 @@ describe Doorkeeper::TokensController do
46
48
  post :create
47
49
 
48
50
  expected_response_body = {
49
- "error" => custom_message,
50
- "error_description" => "Authorization custom message"
51
+ "error" => custom_message,
52
+ "error_description" => "Authorization custom message",
51
53
  }
52
- expect(response.status).to eq 401
53
- expect(response.headers['WWW-Authenticate']).to match(/Bearer/)
54
+ expect(response.status).to eq 400
55
+ expect(response.headers["WWW-Authenticate"]).to match(/Bearer/)
54
56
  expect(JSON.parse(response.body)).to eq expected_response_body
55
57
  end
56
58
  end
57
59
 
58
60
  # http://tools.ietf.org/html/rfc7009#section-2.2
59
- describe 'revoking tokens' do
61
+ describe "revoking tokens" do
60
62
  let(:client) { FactoryBot.create(:application) }
61
63
  let(:access_token) { FactoryBot.create(:access_token, application: client) }
62
64
 
63
- before(:each) do
64
- allow(controller).to receive(:token) { access_token }
65
- end
66
-
67
- context 'when associated app is public' do
65
+ context "when associated app is public" do
68
66
  let(:client) { FactoryBot.create(:application, confidential: false) }
69
67
 
70
- it 'returns 200' do
71
- post :revoke
68
+ it "returns 200" do
69
+ post :revoke, params: { token: access_token.token }
72
70
 
73
71
  expect(response.status).to eq 200
74
72
  end
75
73
 
76
- it 'revokes the access token' do
77
- post :revoke
74
+ it "revokes the access token" do
75
+ post :revoke, params: { token: access_token.token }
78
76
 
79
77
  expect(access_token.reload).to have_attributes(revoked?: true)
80
78
  end
81
79
  end
82
80
 
83
- context 'when associated app is confidential' do
81
+ context "when associated app is confidential" do
84
82
  let(:client) { FactoryBot.create(:application, confidential: true) }
85
83
  let(:oauth_client) { Doorkeeper::OAuth::Client.new(client) }
86
84
 
@@ -88,30 +86,30 @@ describe Doorkeeper::TokensController do
88
86
  allow_any_instance_of(Doorkeeper::Server).to receive(:client) { oauth_client }
89
87
  end
90
88
 
91
- it 'returns 200' do
92
- post :revoke
89
+ it "returns 200" do
90
+ post :revoke, params: { token: access_token.token }
93
91
 
94
92
  expect(response.status).to eq 200
95
93
  end
96
94
 
97
- it 'revokes the access token' do
98
- post :revoke
95
+ it "revokes the access token" do
96
+ post :revoke, params: { token: access_token.token }
99
97
 
100
98
  expect(access_token.reload).to have_attributes(revoked?: true)
101
99
  end
102
100
 
103
- context 'when authorization fails' do
101
+ context "when authorization fails" do
104
102
  let(:some_other_client) { FactoryBot.create(:application, confidential: true) }
105
103
  let(:oauth_client) { Doorkeeper::OAuth::Client.new(some_other_client) }
106
104
 
107
- it 'returns 200' do
108
- post :revoke
105
+ it "returns 200" do
106
+ post :revoke, params: { token: access_token.token }
109
107
 
110
108
  expect(response.status).to eq 200
111
109
  end
112
110
 
113
- it 'does not revoke the access token' do
114
- post :revoke
111
+ it "does not revoke the access token" do
112
+ post :revoke, params: { token: access_token.token }
115
113
 
116
114
  expect(access_token.reload).to have_attributes(revoked?: false)
117
115
  end
@@ -119,7 +117,7 @@ describe Doorkeeper::TokensController do
119
117
  end
120
118
  end
121
119
 
122
- describe 'authorize response memoization' do
120
+ describe "authorize response memoization" do
123
121
  it "memoizes the result of the authorization" do
124
122
  strategy = double(:strategy, authorize: true)
125
123
  expect(strategy).to receive(:authorize).once
@@ -133,138 +131,199 @@ describe Doorkeeper::TokensController do
133
131
  end
134
132
  end
135
133
 
136
- describe 'when requested token introspection' do
137
- context 'authorized using Bearer token' do
138
- let(:client) { FactoryBot.create(:application) }
139
- 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) }
140
138
 
141
- it 'responds with full token introspection' do
142
- 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}"
143
142
 
144
- post :introspect, params: { token: access_token.token }
143
+ post :introspect, params: { token: token_for_introspection.token }
145
144
 
146
- should_have_json 'active', true
147
- 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")
148
147
  end
149
148
  end
150
149
 
151
- context 'authorized using Client Authentication' do
152
- let(:client) { FactoryBot.create(:application) }
153
- 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)
154
153
 
155
- it 'responds with full token introspection' do
156
- request.headers['Authorization'] = basic_auth_header_for_client(client)
154
+ post :introspect, params: { token: token_for_introspection.token }
157
155
 
158
- 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
159
161
 
160
- should_have_json 'active', true
161
- expect(json_response).to include('client_id', 'token_type', 'exp', 'iat')
162
- 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"
163
183
  end
164
184
  end
165
185
 
166
- context 'public access token' do
167
- let(:client) { FactoryBot.create(:application) }
168
- 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) }
169
188
 
170
- it 'responds with full token introspection' do
171
- 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)
172
191
 
173
- post :introspect, params: { token: access_token.token }
192
+ post :introspect, params: { token: token_for_introspection.token }
174
193
 
175
- should_have_json 'active', true
176
- expect(json_response).to include('client_id', 'token_type', 'exp', 'iat')
177
- 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
178
197
  end
179
198
  end
180
199
 
181
- context 'token was issued to a different client than is making this request' do
182
- let(:client) { FactoryBot.create(:application) }
200
+ context "token was issued to a different client than is making this request" do
183
201
  let(:different_client) { FactoryBot.create(:application) }
184
- let(:access_token) { FactoryBot.create(:access_token, application: client) }
185
202
 
186
- it 'responds with only active state' do
187
- 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)
188
205
 
189
- post :introspect, params: { token: access_token.token }
206
+ post :introspect, params: { token: token_for_introspection.token }
190
207
 
191
208
  expect(response).to be_successful
192
209
 
193
- should_have_json 'active', false
194
- 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")
195
212
  end
196
213
  end
197
214
 
198
- context 'using invalid credentials to authorize' do
199
- let(:client) { double(uid: '123123', secret: '666999') }
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"
242
+ end
243
+ end
244
+
245
+ context "using invalid credentials to authorize" do
246
+ let(:client) { double(uid: "123123", secret: "666999") }
200
247
  let(:access_token) { FactoryBot.create(:access_token) }
201
248
 
202
- it 'responds with invalid_client error' do
203
- 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)
204
251
 
205
252
  post :introspect, params: { token: access_token.token }
206
253
 
207
254
  expect(response).not_to be_successful
208
255
  response_status_should_be 401
209
256
 
210
- should_not_have_json 'active'
211
- should_have_json 'error', 'invalid_client'
257
+ should_not_have_json "active"
258
+ should_have_json "error", "invalid_client"
212
259
  end
213
260
  end
214
261
 
215
- context 'using wrong token value' do
216
- let(:client) { FactoryBot.create(:application) }
217
- 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)
266
+
267
+ post :introspect, params: { token: SecureRandom.hex(16) }
218
268
 
219
- it 'responds with only active state' do
220
- request.headers['Authorization'] = basic_auth_header_for_client(client)
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}"
221
277
 
222
- post :introspect, params: { token: SecureRandom.hex(16) }
278
+ post :introspect, params: { token: SecureRandom.hex(16) }
223
279
 
224
- should_have_json 'active', false
225
- 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
226
283
  end
227
284
  end
228
285
 
229
- context 'when requested Access Token expired' do
230
- let(:client) { FactoryBot.create(:application) }
231
- 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
232
290
 
233
- it 'responds with only active state' do
234
- 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)
235
293
 
236
- post :introspect, params: { token: access_token.token }
294
+ post :introspect, params: { token: token_for_introspection.token }
237
295
 
238
- should_have_json 'active', false
239
- 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")
240
298
  end
241
299
  end
242
300
 
243
- context 'when requested Access Token revoked' do
244
- let(:client) { FactoryBot.create(:application) }
245
- 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
246
305
 
247
- it 'responds with only active state' do
248
- 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)
249
308
 
250
- post :introspect, params: { token: access_token.token }
309
+ post :introspect, params: { token: token_for_introspection.token }
251
310
 
252
- should_have_json 'active', false
253
- 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")
254
313
  end
255
314
  end
256
315
 
257
- context 'unauthorized (no bearer token or client credentials)' do
258
- 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) }
259
318
 
260
- it 'responds with invalid_request error' do
261
- post :introspect, params: { token: access_token.token }
319
+ it "responds with invalid_request error" do
320
+ post :introspect, params: { token: token_for_introspection.token }
262
321
 
263
322
  expect(response).not_to be_successful
264
- response_status_should_be 401
323
+ response_status_should_be 400
265
324
 
266
- should_not_have_json 'active'
267
- should_have_json 'error', 'invalid_request'
325
+ should_not_have_json "active"
326
+ should_have_json "error", "invalid_request"
268
327
  end
269
328
  end
270
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', __dir__)
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,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class CustomAuthorizationsController < ::ApplicationController
2
4
  %w[index show new create edit update destroy].each do |action|
3
5
  define_method action do
@@ -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,16 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class HomeController < ApplicationController
2
4
  def index; end
3
5
 
4
6
  def sign_in
5
7
  session[:user_id] = if Rails.env.development?
6
- User.first || User.create!(name: 'Joe', password: 'sekret')
8
+ User.first || User.create!(name: "Joe", password: "sekret")
7
9
  else
8
10
  User.first
9
11
  end
10
- redirect_to '/'
12
+ redirect_to "/"
11
13
  end
12
14
 
13
15
  def callback
14
- render plain: 'ok'
16
+ render plain: "ok"
15
17
  end
16
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
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.
@@ -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
@@ -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.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  Doorkeeper.configure do
2
4
  # Change the ORM that doorkeeper will use.
3
5
  orm DOORKEEPER_ORM
@@ -5,7 +7,7 @@ Doorkeeper.configure do
5
7
  # This block will be called to check whether the resource owner is authenticated or not.
6
8
  resource_owner_authenticator do
7
9
  # Put your resource owner authentication logic here.
8
- User.where(id: session[:user_id]).first || redirect_to(root_url, alert: 'Needs sign in.')
10
+ User.where(id: session[:user_id]).first || redirect_to(root_url, alert: "Needs sign in.")
9
11
  end
10
12
 
11
13
  # If you didn't skip applications controller from Doorkeeper routes in your application routes.rb
@@ -66,7 +68,8 @@ Doorkeeper.configure do
66
68
  # Change the native redirect uri for client apps
67
69
  # When clients register with the following redirect uri, they won't be redirected to any server and
68
70
  # the authorization code will be displayed within the provider
69
- # The value can be any string. Use nil to disable this feature. When disabled, clients must provide a valid URL
71
+ # The value can be any string. Use nil to disable this feature.
72
+ # When disabled, clients must provide a valid URL
70
73
  # (Similar behaviour: https://developers.google.com/accounts/docs/OAuth2InstalledApp#choosingredirecturi)
71
74
  #
72
75
  # native_redirect_uri 'urn:ietf:wg:oauth:2.0:oob'
@@ -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
  # Your secret key for verifying the integrity of signed cookies.
@@ -5,4 +7,4 @@
5
7
  # Make sure the secret is at least 30 characters and all random,
6
8
  # no regular words or you'll be exposed to dictionary attacks.
7
9
  Dummy::Application.config.secret_key_base =
8
- 'c00157b5a1bb6181792f0f4a8a080485de7bab9987e6cf159'
10
+ "c00157b5a1bb6181792f0f4a8a080485de7bab9987e6cf159"