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,66 +1,95 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
2
 
3
- feature 'Authorization Code Flow' do
3
+ require "spec_helper"
4
+
5
+ feature "Authorization Code Flow" do
4
6
  background do
5
- config_is_set(:authenticate_resource_owner) { User.first || redirect_to('/sign_in') }
7
+ config_is_set(:authenticate_resource_owner) { User.first || redirect_to("/sign_in") }
6
8
  client_exists
7
9
  create_resource_owner
8
10
  sign_in
9
11
  end
10
12
 
11
- scenario 'resource owner authorizes the client' do
13
+ scenario "resource owner authorizes the client" do
12
14
  visit authorization_endpoint_url(client: @client)
13
- click_on 'Authorize'
15
+ click_on "Authorize"
14
16
 
15
17
  access_grant_should_exist_for(@client, @resource_owner)
16
18
 
17
19
  i_should_be_on_client_callback(@client)
18
20
 
19
- url_should_have_param('code', Doorkeeper::AccessGrant.first.token)
20
- url_should_not_have_param('state')
21
- url_should_not_have_param('error')
21
+ url_should_have_param("code", Doorkeeper::AccessGrant.first.token)
22
+ url_should_not_have_param("state")
23
+ url_should_not_have_param("error")
22
24
  end
23
25
 
24
- scenario 'resource owner authorizes using test url' do
26
+ context "with grant hashing enabled" do
27
+ background do
28
+ config_is_set(:token_secret_strategy, ::Doorkeeper::SecretStoring::Sha256Hash)
29
+ end
30
+
31
+ scenario "Authorization Code Flow with hashing" do
32
+ @client.redirect_uri = Doorkeeper.configuration.native_redirect_uri
33
+ @client.save!
34
+ visit authorization_endpoint_url(client: @client)
35
+ click_on "Authorize"
36
+
37
+ access_grant_should_exist_for(@client, @resource_owner)
38
+
39
+ code = current_params["code"]
40
+ expect(code).not_to be_nil
41
+
42
+ hashed_code = Doorkeeper::AccessGrant.secret_strategy.transform_secret code
43
+ expect(hashed_code).to eq Doorkeeper::AccessGrant.first.token
44
+
45
+ expect(code).not_to eq(hashed_code)
46
+
47
+ i_should_see "Authorization code:"
48
+ i_should_see code
49
+ i_should_not_see hashed_code
50
+ end
51
+ end
52
+
53
+ scenario "resource owner authorizes using test url" do
25
54
  @client.redirect_uri = Doorkeeper.configuration.native_redirect_uri
26
55
  @client.save!
27
56
  visit authorization_endpoint_url(client: @client)
28
- click_on 'Authorize'
57
+ click_on "Authorize"
29
58
 
30
59
  access_grant_should_exist_for(@client, @resource_owner)
31
60
 
32
- url_should_have_param('code', Doorkeeper::AccessGrant.first.token)
33
- i_should_see 'Authorization code:'
61
+ url_should_have_param("code", Doorkeeper::AccessGrant.first.token)
62
+ i_should_see "Authorization code:"
34
63
  i_should_see Doorkeeper::AccessGrant.first.token
35
64
  end
36
65
 
37
- scenario 'resource owner authorizes the client with state parameter set' do
38
- visit authorization_endpoint_url(client: @client, state: 'return-me')
39
- click_on 'Authorize'
40
- url_should_have_param('code', Doorkeeper::AccessGrant.first.token)
41
- url_should_have_param('state', 'return-me')
42
- url_should_not_have_param('code_challenge_method')
66
+ scenario "resource owner authorizes the client with state parameter set" do
67
+ visit authorization_endpoint_url(client: @client, state: "return-me")
68
+ click_on "Authorize"
69
+ url_should_have_param("code", Doorkeeper::AccessGrant.first.token)
70
+ url_should_have_param("state", "return-me")
71
+ url_should_not_have_param("code_challenge_method")
43
72
  end
44
73
 
45
- scenario 'resource owner requests an access token with authorization code' do
74
+ scenario "resource owner requests an access token with authorization code" do
46
75
  visit authorization_endpoint_url(client: @client)
47
- click_on 'Authorize'
76
+ click_on "Authorize"
48
77
 
49
78
  authorization_code = Doorkeeper::AccessGrant.first.token
50
79
  create_access_token authorization_code, @client
51
80
 
52
81
  access_token_should_exist_for(@client, @resource_owner)
53
82
 
54
- should_not_have_json 'error'
83
+ should_not_have_json "error"
55
84
 
56
- should_have_json 'access_token', Doorkeeper::AccessToken.first.token
57
- should_have_json 'token_type', 'Bearer'
58
- should_have_json_within 'expires_in', Doorkeeper::AccessToken.first.expires_in, 1
85
+ should_have_json "access_token", Doorkeeper::AccessToken.first.token
86
+ should_have_json "token_type", "Bearer"
87
+ should_have_json_within "expires_in", Doorkeeper::AccessToken.first.expires_in, 1
59
88
  end
60
89
 
61
- scenario 'resource owner requests an access token with authorization code but without secret' do
90
+ scenario "resource owner requests an access token with authorization code but without secret" do
62
91
  visit authorization_endpoint_url(client: @client)
63
- click_on 'Authorize'
92
+ click_on "Authorize"
64
93
 
65
94
  authorization_code = Doorkeeper::AccessGrant.first.token
66
95
  page.driver.post token_endpoint_url(code: authorization_code, client_id: @client.uid,
@@ -68,277 +97,290 @@ feature 'Authorization Code Flow' do
68
97
 
69
98
  expect(Doorkeeper::AccessToken.count).to be_zero
70
99
 
71
- should_have_json 'error', 'invalid_client'
100
+ should_have_json "error", "invalid_client"
101
+ end
102
+
103
+ scenario "resource owner requests an access token with authorization code but without client id" do
104
+ visit authorization_endpoint_url(client: @client)
105
+ click_on "Authorize"
106
+
107
+ authorization_code = Doorkeeper::AccessGrant.first.token
108
+ page.driver.post token_endpoint_url(code: authorization_code, client_secret: @client.secret,
109
+ redirect_uri: @client.redirect_uri)
110
+
111
+ expect(Doorkeeper::AccessToken.count).to be_zero
112
+
113
+ should_have_json "error", "invalid_client"
72
114
  end
73
115
 
74
- scenario 'silently authorizes if matching token exists' do
116
+ scenario "silently authorizes if matching token exists" do
75
117
  default_scopes_exist :public, :write
76
118
 
77
119
  access_token_exists application: @client,
78
120
  expires_in: -100, # even expired token
79
121
  resource_owner_id: @resource_owner.id,
80
- scopes: 'public write'
122
+ scopes: "public write"
81
123
 
82
- visit authorization_endpoint_url(client: @client, scope: 'public write')
124
+ visit authorization_endpoint_url(client: @client, scope: "public write")
83
125
 
84
126
  response_status_should_be 200
85
- i_should_not_see 'Authorize'
127
+ i_should_not_see "Authorize"
86
128
  end
87
129
 
88
- context 'with PKCE' do
89
- context 'plain' do
90
- let(:code_challenge) { 'a45a9fea-0676-477e-95b1-a40f72ac3cfb' }
91
- let(:code_verifier) { 'a45a9fea-0676-477e-95b1-a40f72ac3cfb' }
130
+ context "with PKCE" do
131
+ context "plain" do
132
+ let(:code_challenge) { "a45a9fea-0676-477e-95b1-a40f72ac3cfb" }
133
+ let(:code_verifier) { "a45a9fea-0676-477e-95b1-a40f72ac3cfb" }
92
134
 
93
- scenario 'resource owner authorizes the client with code_challenge parameter set' do
135
+ scenario "resource owner authorizes the client with code_challenge parameter set" do
94
136
  visit authorization_endpoint_url(
95
137
  client: @client,
96
138
  code_challenge: code_challenge,
97
- code_challenge_method: 'plain'
139
+ code_challenge_method: "plain"
98
140
  )
99
- click_on 'Authorize'
141
+ click_on "Authorize"
100
142
 
101
- url_should_have_param('code', Doorkeeper::AccessGrant.first.token)
102
- url_should_not_have_param('code_challenge_method')
103
- url_should_not_have_param('code_challenge')
143
+ url_should_have_param("code", Doorkeeper::AccessGrant.first.token)
144
+ url_should_not_have_param("code_challenge_method")
145
+ url_should_not_have_param("code_challenge")
104
146
  end
105
147
 
106
- scenario 'mobile app requests an access token with authorization code but not pkce token' do
148
+ scenario "mobile app requests an access token with authorization code but not pkce token" do
107
149
  visit authorization_endpoint_url(client: @client)
108
- click_on 'Authorize'
150
+ click_on "Authorize"
109
151
 
110
- authorization_code = current_params['code']
152
+ authorization_code = current_params["code"]
111
153
  create_access_token authorization_code, @client, code_verifier
112
154
 
113
- should_have_json 'error', 'invalid_grant'
155
+ should_have_json "error", "invalid_grant"
114
156
  end
115
157
 
116
- scenario 'mobile app requests an access token with authorization code and plain code challenge method' do
158
+ scenario "mobile app requests an access token with authorization code and plain code challenge method" do
117
159
  visit authorization_endpoint_url(
118
160
  client: @client,
119
161
  code_challenge: code_challenge,
120
- code_challenge_method: 'plain'
162
+ code_challenge_method: "plain"
121
163
  )
122
- click_on 'Authorize'
164
+ click_on "Authorize"
123
165
 
124
- authorization_code = current_params['code']
166
+ authorization_code = current_params["code"]
125
167
  create_access_token authorization_code, @client, code_verifier
126
168
 
127
169
  access_token_should_exist_for(@client, @resource_owner)
128
170
 
129
- should_not_have_json 'error'
171
+ should_not_have_json "error"
130
172
 
131
- should_have_json 'access_token', Doorkeeper::AccessToken.first.token
132
- should_have_json 'token_type', 'Bearer'
133
- should_have_json_within 'expires_in', Doorkeeper::AccessToken.first.expires_in, 1
173
+ should_have_json "access_token", Doorkeeper::AccessToken.first.token
174
+ should_have_json "token_type", "Bearer"
175
+ should_have_json_within "expires_in", Doorkeeper::AccessToken.first.expires_in, 1
134
176
  end
135
177
 
136
- scenario 'mobile app requests an access token with authorization code and code_challenge' do
178
+ scenario "mobile app requests an access token with authorization code and code_challenge" do
137
179
  visit authorization_endpoint_url(client: @client,
138
180
  code_challenge: code_verifier,
139
- code_challenge_method: 'plain')
140
- click_on 'Authorize'
181
+ code_challenge_method: "plain")
182
+ click_on "Authorize"
141
183
 
142
- authorization_code = current_params['code']
184
+ authorization_code = current_params["code"]
143
185
  create_access_token authorization_code, @client, code_verifier: nil
144
186
 
145
- should_not_have_json 'access_token'
146
- should_have_json 'error', 'invalid_grant'
187
+ should_not_have_json "access_token"
188
+ should_have_json "error", "invalid_grant"
147
189
  end
148
190
  end
149
191
 
150
- context 's256' do
151
- let(:code_challenge) { 'Oz733NtQ0rJP8b04fgZMJMwprn6Iw8sMCT_9bR1q4tA' }
152
- let(:code_verifier) { 'a45a9fea-0676-477e-95b1-a40f72ac3cfb' }
192
+ context "s256" do
193
+ let(:code_challenge) { "Oz733NtQ0rJP8b04fgZMJMwprn6Iw8sMCT_9bR1q4tA" }
194
+ let(:code_verifier) { "a45a9fea-0676-477e-95b1-a40f72ac3cfb" }
153
195
 
154
- scenario 'resource owner authorizes the client with code_challenge parameter set' do
196
+ scenario "resource owner authorizes the client with code_challenge parameter set" do
155
197
  visit authorization_endpoint_url(
156
198
  client: @client,
157
199
  code_challenge: code_challenge,
158
- code_challenge_method: 'S256'
200
+ code_challenge_method: "S256"
159
201
  )
160
- click_on 'Authorize'
202
+ click_on "Authorize"
161
203
 
162
- url_should_have_param('code', Doorkeeper::AccessGrant.first.token)
163
- url_should_not_have_param('code_challenge_method')
164
- url_should_not_have_param('code_challenge')
204
+ url_should_have_param("code", Doorkeeper::AccessGrant.first.token)
205
+ url_should_not_have_param("code_challenge_method")
206
+ url_should_not_have_param("code_challenge")
165
207
  end
166
208
 
167
- scenario 'mobile app requests an access token with authorization code and S256 code challenge method' do
209
+ scenario "mobile app requests an access token with authorization code and S256 code challenge method" do
168
210
  visit authorization_endpoint_url(
169
211
  client: @client,
170
212
  code_challenge: code_challenge,
171
- code_challenge_method: 'S256'
213
+ code_challenge_method: "S256"
172
214
  )
173
- click_on 'Authorize'
215
+ click_on "Authorize"
174
216
 
175
- authorization_code = current_params['code']
217
+ authorization_code = current_params["code"]
176
218
  create_access_token authorization_code, @client, code_verifier
177
219
 
178
220
  access_token_should_exist_for(@client, @resource_owner)
179
221
 
180
- should_not_have_json 'error'
222
+ should_not_have_json "error"
181
223
 
182
- should_have_json 'access_token', Doorkeeper::AccessToken.first.token
183
- should_have_json 'token_type', 'Bearer'
184
- should_have_json_within 'expires_in', Doorkeeper::AccessToken.first.expires_in, 1
224
+ should_have_json "access_token", Doorkeeper::AccessToken.first.token
225
+ should_have_json "token_type", "Bearer"
226
+ should_have_json_within "expires_in", Doorkeeper::AccessToken.first.expires_in, 1
185
227
  end
186
228
 
187
- scenario 'mobile app requests an access token with authorization code and without code_verifier' do
229
+ scenario "mobile app requests an access token with authorization code and without code_verifier" do
188
230
  visit authorization_endpoint_url(
189
231
  client: @client,
190
232
  code_challenge: code_challenge,
191
- code_challenge_method: 'S256'
233
+ code_challenge_method: "S256"
192
234
  )
193
- click_on 'Authorize'
194
- authorization_code = current_params['code']
235
+ click_on "Authorize"
236
+ authorization_code = current_params["code"]
195
237
  create_access_token authorization_code, @client
196
- should_have_json 'error', 'invalid_request'
197
- should_not_have_json 'access_token'
238
+ should_have_json "error", "invalid_request"
239
+ should_not_have_json "access_token"
198
240
  end
199
241
 
200
- scenario 'mobile app requests an access token with authorization code and without secret' do
242
+ scenario "mobile app requests an access token with authorization code and without secret" do
201
243
  visit authorization_endpoint_url(
202
244
  client: @client,
203
245
  code_challenge: code_challenge,
204
- code_challenge_method: 'S256'
246
+ code_challenge_method: "S256"
205
247
  )
206
- click_on 'Authorize'
248
+ click_on "Authorize"
207
249
 
208
- authorization_code = current_params['code']
250
+ authorization_code = current_params["code"]
209
251
  page.driver.post token_endpoint_url(code: authorization_code, client_id: @client.uid,
210
252
  redirect_uri: @client.redirect_uri, code_verifier: code_verifier)
211
- should_have_json 'error', 'invalid_client'
212
- should_not_have_json 'access_token'
253
+ should_have_json "error", "invalid_client"
254
+ should_not_have_json "access_token"
213
255
  end
214
256
 
215
- scenario 'mobile app requests an access token with authorization code and without secret but is marked as not confidential' do
257
+ scenario "mobile app requests an access token with authorization code and without secret but is marked as not confidential" do
216
258
  @client.update_attribute :confidential, false
217
- visit authorization_endpoint_url(client: @client, code_challenge: code_challenge, code_challenge_method: 'S256')
218
- click_on 'Authorize'
259
+ visit authorization_endpoint_url(client: @client, code_challenge: code_challenge, code_challenge_method: "S256")
260
+ click_on "Authorize"
219
261
 
220
- authorization_code = current_params['code']
262
+ authorization_code = current_params["code"]
221
263
  page.driver.post token_endpoint_url(
222
264
  code: authorization_code,
223
265
  client_id: @client.uid,
224
266
  redirect_uri: @client.redirect_uri,
225
267
  code_verifier: code_verifier
226
268
  )
227
- should_not_have_json 'error'
269
+ should_not_have_json "error"
228
270
 
229
- should_have_json 'access_token', Doorkeeper::AccessToken.first.token
230
- should_have_json 'token_type', 'Bearer'
231
- should_have_json_within 'expires_in', Doorkeeper::AccessToken.first.expires_in, 1
271
+ should_have_json "access_token", Doorkeeper::AccessToken.first.token
272
+ should_have_json "token_type", "Bearer"
273
+ should_have_json_within "expires_in", Doorkeeper::AccessToken.first.expires_in, 1
232
274
  end
233
275
 
234
- scenario 'mobile app requests an access token with authorization code but no code verifier' do
276
+ scenario "mobile app requests an access token with authorization code but no code verifier" do
235
277
  visit authorization_endpoint_url(
236
278
  client: @client,
237
279
  code_challenge: code_challenge,
238
- code_challenge_method: 'S256'
280
+ code_challenge_method: "S256"
239
281
  )
240
- click_on 'Authorize'
282
+ click_on "Authorize"
241
283
 
242
- authorization_code = current_params['code']
284
+ authorization_code = current_params["code"]
243
285
  create_access_token authorization_code, @client
244
286
 
245
- should_not_have_json 'access_token'
246
- should_have_json 'error', 'invalid_request'
287
+ should_not_have_json "access_token"
288
+ should_have_json "error", "invalid_request"
247
289
  end
248
290
 
249
- scenario 'mobile app requests an access token with authorization code with wrong verifier' do
291
+ scenario "mobile app requests an access token with authorization code with wrong verifier" do
250
292
  visit authorization_endpoint_url(
251
293
  client: @client,
252
294
  code_challenge: code_challenge,
253
- code_challenge_method: 'S256'
295
+ code_challenge_method: "S256"
254
296
  )
255
- click_on 'Authorize'
297
+ click_on "Authorize"
256
298
 
257
- authorization_code = current_params['code']
258
- create_access_token authorization_code, @client, 'incorrect-code-verifier'
299
+ authorization_code = current_params["code"]
300
+ create_access_token authorization_code, @client, "incorrect-code-verifier"
259
301
 
260
- should_not_have_json 'access_token'
261
- should_have_json 'error', 'invalid_grant'
302
+ should_not_have_json "access_token"
303
+ should_have_json "error", "invalid_grant"
262
304
  end
263
305
 
264
- scenario 'code_challenge_mehthod in token request is totally ignored' do
306
+ scenario "code_challenge_mehthod in token request is totally ignored" do
265
307
  visit authorization_endpoint_url(
266
308
  client: @client,
267
309
  code_challenge: code_challenge,
268
- code_challenge_method: 'S256'
310
+ code_challenge_method: "S256"
269
311
  )
270
- click_on 'Authorize'
312
+ click_on "Authorize"
271
313
 
272
- authorization_code = current_params['code']
314
+ authorization_code = current_params["code"]
273
315
  page.driver.post token_endpoint_url(
274
316
  code: authorization_code,
275
317
  client: @client,
276
318
  code_verifier: code_challenge,
277
- code_challenge_method: 'plain'
319
+ code_challenge_method: "plain"
278
320
  )
279
321
 
280
- should_not_have_json 'access_token'
281
- should_have_json 'error', 'invalid_grant'
322
+ should_not_have_json "access_token"
323
+ should_have_json "error", "invalid_grant"
282
324
  end
283
325
 
284
- scenario 'expects to set code_challenge_method explicitely without fallback' do
326
+ scenario "expects to set code_challenge_method explicitely without fallback" do
285
327
  visit authorization_endpoint_url(client: @client, code_challenge: code_challenge)
286
- expect(page).to have_content('The code challenge method must be plain or S256.')
328
+ expect(page).to have_content("The code challenge method must be plain or S256.")
287
329
  end
288
330
  end
289
331
  end
290
332
 
291
- context 'when application scopes are present and no scope is passed' do
333
+ context "when application scopes are present and no scope is passed" do
292
334
  background do
293
- @client.update_attributes(scopes: 'public write read')
335
+ @client.update(scopes: "public write read")
294
336
  end
295
337
 
296
- scenario 'access grant has no scope' do
338
+ scenario "access grant has no scope" do
297
339
  default_scopes_exist :admin
298
340
  visit authorization_endpoint_url(client: @client)
299
- click_on 'Authorize'
341
+ click_on "Authorize"
300
342
  access_grant_should_exist_for(@client, @resource_owner)
301
343
  grant = Doorkeeper::AccessGrant.first
302
344
  expect(grant.scopes).to be_empty
303
345
  end
304
346
 
305
- scenario 'access grant have scopes which are common in application scopees and default scopes' do
347
+ scenario "access grant have scopes which are common in application scopees and default scopes" do
306
348
  default_scopes_exist :public, :write
307
349
  visit authorization_endpoint_url(client: @client)
308
- click_on 'Authorize'
350
+ click_on "Authorize"
309
351
  access_grant_should_exist_for(@client, @resource_owner)
310
352
  access_grant_should_have_scopes :public, :write
311
353
  end
312
354
  end
313
355
 
314
- context 'with scopes' do
356
+ context "with scopes" do
315
357
  background do
316
358
  default_scopes_exist :public
317
359
  optional_scopes_exist :write
318
360
  end
319
361
 
320
- scenario 'resource owner authorizes the client with default scopes' do
362
+ scenario "resource owner authorizes the client with default scopes" do
321
363
  visit authorization_endpoint_url(client: @client)
322
- click_on 'Authorize'
364
+ click_on "Authorize"
323
365
  access_grant_should_exist_for(@client, @resource_owner)
324
366
  access_grant_should_have_scopes :public
325
367
  end
326
368
 
327
- scenario 'resource owner authorizes the client with required scopes' do
328
- visit authorization_endpoint_url(client: @client, scope: 'public write')
329
- click_on 'Authorize'
369
+ scenario "resource owner authorizes the client with required scopes" do
370
+ visit authorization_endpoint_url(client: @client, scope: "public write")
371
+ click_on "Authorize"
330
372
  access_grant_should_have_scopes :public, :write
331
373
  end
332
374
 
333
- scenario 'resource owner authorizes the client with required scopes (without defaults)' do
334
- visit authorization_endpoint_url(client: @client, scope: 'write')
335
- click_on 'Authorize'
375
+ scenario "resource owner authorizes the client with required scopes (without defaults)" do
376
+ visit authorization_endpoint_url(client: @client, scope: "write")
377
+ click_on "Authorize"
336
378
  access_grant_should_have_scopes :write
337
379
  end
338
380
 
339
- scenario 'new access token matches required scopes' do
340
- visit authorization_endpoint_url(client: @client, scope: 'public write')
341
- click_on 'Authorize'
381
+ scenario "new access token matches required scopes" do
382
+ visit authorization_endpoint_url(client: @client, scope: "public write")
383
+ click_on "Authorize"
342
384
 
343
385
  authorization_code = Doorkeeper::AccessGrant.first.token
344
386
  create_access_token authorization_code, @client
@@ -347,36 +389,36 @@ feature 'Authorization Code Flow' do
347
389
  access_token_should_have_scopes :public, :write
348
390
  end
349
391
 
350
- scenario 'returns new token if scopes have changed' do
351
- client_is_authorized(@client, @resource_owner, scopes: 'public write')
352
- visit authorization_endpoint_url(client: @client, scope: 'public')
353
- click_on 'Authorize'
392
+ scenario "returns new token if scopes have changed" do
393
+ client_is_authorized(@client, @resource_owner, scopes: "public write")
394
+ visit authorization_endpoint_url(client: @client, scope: "public")
395
+ click_on "Authorize"
354
396
 
355
397
  authorization_code = Doorkeeper::AccessGrant.first.token
356
398
  create_access_token authorization_code, @client
357
399
 
358
400
  expect(Doorkeeper::AccessToken.count).to be(2)
359
401
 
360
- should_have_json 'access_token', Doorkeeper::AccessToken.last.token
402
+ should_have_json "access_token", Doorkeeper::AccessToken.last.token
361
403
  end
362
404
 
363
- scenario 'resource owner authorizes the client with extra scopes' do
364
- client_is_authorized(@client, @resource_owner, scopes: 'public')
365
- visit authorization_endpoint_url(client: @client, scope: 'public write')
366
- click_on 'Authorize'
405
+ scenario "resource owner authorizes the client with extra scopes" do
406
+ client_is_authorized(@client, @resource_owner, scopes: "public")
407
+ visit authorization_endpoint_url(client: @client, scope: "public write")
408
+ click_on "Authorize"
367
409
 
368
410
  authorization_code = Doorkeeper::AccessGrant.first.token
369
411
  create_access_token authorization_code, @client
370
412
 
371
413
  expect(Doorkeeper::AccessToken.count).to be(2)
372
414
 
373
- should_have_json 'access_token', Doorkeeper::AccessToken.last.token
415
+ should_have_json "access_token", Doorkeeper::AccessToken.last.token
374
416
  access_token_should_have_scopes :public, :write
375
417
  end
376
418
  end
377
419
  end
378
420
 
379
- describe 'Authorization Code Flow' do
421
+ describe "Authorization Code Flow" do
380
422
  before do
381
423
  Doorkeeper.configure do
382
424
  orm DOORKEEPER_ORM
@@ -386,20 +428,20 @@ describe 'Authorization Code Flow' do
386
428
  client_exists
387
429
  end
388
430
 
389
- context 'issuing a refresh token' do
431
+ context "issuing a refresh token" do
390
432
  before do
391
433
  authorization_code_exists application: @client
392
434
  end
393
435
 
394
- it 'second of simultaneous client requests get an error for revoked acccess token' do
436
+ it "second of simultaneous client requests get an error for revoked acccess token" do
395
437
  authorization_code = Doorkeeper::AccessGrant.first.token
396
438
  allow_any_instance_of(Doorkeeper::AccessGrant)
397
439
  .to receive(:revoked?).and_return(false, true)
398
440
 
399
441
  post token_endpoint_url(code: authorization_code, client: @client)
400
442
 
401
- should_not_have_json 'access_token'
402
- should_have_json 'error', 'invalid_grant'
443
+ should_not_have_json "access_token"
444
+ should_have_json "error", "invalid_grant"
403
445
  end
404
446
  end
405
447
  end