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,4 +1,6 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
2
4
 
3
5
  module Doorkeeper::OAuth
4
6
  describe PasswordAccessTokenRequest do
@@ -16,11 +18,15 @@ module Doorkeeper::OAuth
16
18
  let(:client) { FactoryBot.create(:application) }
17
19
  let(:owner) { double :owner, id: 99 }
18
20
 
21
+ before do
22
+ allow(server).to receive(:option_defined?).with(:custom_access_token_expires_in).and_return(true)
23
+ end
24
+
19
25
  subject do
20
26
  PasswordAccessTokenRequest.new(server, client, owner)
21
27
  end
22
28
 
23
- it 'issues a new token for the client' do
29
+ it "issues a new token for the client" do
24
30
  expect do
25
31
  subject.authorize
26
32
  end.to change { client.reload.access_tokens.count }.by(1)
@@ -28,35 +34,35 @@ module Doorkeeper::OAuth
28
34
  expect(client.reload.access_tokens.max_by(&:created_at).expires_in).to eq(1234)
29
35
  end
30
36
 
31
- it 'issues a new token without a client' do
37
+ it "issues a new token without a client" do
32
38
  expect do
33
39
  subject.client = nil
34
40
  subject.authorize
35
41
  end.to change { Doorkeeper::AccessToken.count }.by(1)
36
42
  end
37
43
 
38
- it 'does not issue a new token with an invalid client' do
44
+ it "does not issue a new token with an invalid client" do
39
45
  expect do
40
46
  subject.client = nil
41
- subject.parameters = { client_id: 'bad_id' }
47
+ subject.parameters = { client_id: "bad_id" }
42
48
  subject.authorize
43
49
  end.not_to(change { Doorkeeper::AccessToken.count })
44
50
 
45
51
  expect(subject.error).to eq(:invalid_client)
46
52
  end
47
53
 
48
- it 'requires the owner' do
54
+ it "requires the owner" do
49
55
  subject.resource_owner = nil
50
56
  subject.validate
51
57
  expect(subject.error).to eq(:invalid_grant)
52
58
  end
53
59
 
54
- it 'optionally accepts the client' do
60
+ it "optionally accepts the client" do
55
61
  subject.client = nil
56
62
  expect(subject).to be_valid
57
63
  end
58
64
 
59
- it 'creates token even when there is already one (default)' do
65
+ it "creates token even when there is already one (default)" do
60
66
  FactoryBot.create(:access_token, application_id: client.id, resource_owner_id: owner.id)
61
67
 
62
68
  expect do
@@ -64,7 +70,7 @@ module Doorkeeper::OAuth
64
70
  end.to change { Doorkeeper::AccessToken.count }.by(1)
65
71
  end
66
72
 
67
- it 'skips token creation if there is already one' do
73
+ it "skips token creation if there is already one reusable" do
68
74
  allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
69
75
  FactoryBot.create(:access_token, application_id: client.id, resource_owner_id: owner.id)
70
76
 
@@ -73,6 +79,16 @@ module Doorkeeper::OAuth
73
79
  end.not_to(change { Doorkeeper::AccessToken.count })
74
80
  end
75
81
 
82
+ it "creates token when there is already one but non reusable" do
83
+ allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
84
+ FactoryBot.create(:access_token, application_id: client.id, resource_owner_id: owner.id)
85
+ allow_any_instance_of(Doorkeeper::AccessToken).to receive(:reusable?).and_return(false)
86
+
87
+ expect do
88
+ subject.authorize
89
+ end.to change { Doorkeeper::AccessToken.count }.by(1)
90
+ end
91
+
76
92
  it "calls configured request callback methods" do
77
93
  expect(Doorkeeper.configuration.before_successful_strategy_response)
78
94
  .to receive(:call).with(subject).once
@@ -83,28 +99,53 @@ module Doorkeeper::OAuth
83
99
  subject.authorize
84
100
  end
85
101
 
86
- describe 'with scopes' do
102
+ describe "with scopes" do
87
103
  subject do
88
- PasswordAccessTokenRequest.new(server, client, owner, scope: 'public')
104
+ PasswordAccessTokenRequest.new(server, client, owner, scope: "public")
89
105
  end
90
106
 
91
- it 'validates the current scope' do
92
- allow(server).to receive(:scopes).and_return(Doorkeeper::OAuth::Scopes.from_string('another'))
93
- subject.validate
94
- expect(subject.error).to eq(:invalid_scope)
107
+ context "when scopes_by_grant_type is not configured for grant_type" do
108
+ it "returns error when scopes are invalid" do
109
+ allow(server).to receive(:scopes).and_return(Doorkeeper::OAuth::Scopes.from_string("another"))
110
+ subject.validate
111
+ expect(subject.error).to eq(:invalid_scope)
112
+ end
113
+
114
+ it "creates the token with scopes if scopes are valid" do
115
+ allow(server).to receive(:scopes).and_return(Doorkeeper::OAuth::Scopes.from_string("public"))
116
+ expect do
117
+ subject.authorize
118
+ end.to change { Doorkeeper::AccessToken.count }.by(1)
119
+
120
+ expect(Doorkeeper::AccessToken.last.scopes).to include("public")
121
+ end
95
122
  end
96
123
 
97
- it 'creates the token with scopes' do
98
- allow(server).to receive(:scopes).and_return(Doorkeeper::OAuth::Scopes.from_string('public'))
99
- expect do
100
- subject.authorize
101
- end.to change { Doorkeeper::AccessToken.count }.by(1)
102
-
103
- expect(Doorkeeper::AccessToken.last.scopes).to include('public')
124
+ context "when scopes_by_grant_type is configured for grant_type" do
125
+ it "returns error when scopes are valid but not permitted for grant_type" do
126
+ allow(server)
127
+ .to receive(:scopes).and_return(Doorkeeper::OAuth::Scopes.from_string("public"))
128
+ allow(Doorkeeper.configuration)
129
+ .to receive(:scopes_by_grant_type).and_return(password: "another")
130
+ subject.validate
131
+ expect(subject.error).to eq(:invalid_scope)
132
+ end
133
+
134
+ it "creates the token with scopes if scopes are valid and permitted for grant_type" do
135
+ allow(server).to receive(:scopes).and_return(Doorkeeper::OAuth::Scopes.from_string("public"))
136
+ allow(Doorkeeper.configuration)
137
+ .to receive(:scopes_by_grant_type).and_return(password: [:public])
138
+
139
+ expect do
140
+ subject.authorize
141
+ end.to change { Doorkeeper::AccessToken.count }.by(1)
142
+
143
+ expect(Doorkeeper::AccessToken.last.scopes).to include("public")
144
+ end
104
145
  end
105
146
  end
106
147
 
107
- describe 'with custom expiry' do
148
+ describe "with custom expiry" do
108
149
  let(:server) do
109
150
  double(
110
151
  :server,
@@ -112,14 +153,22 @@ module Doorkeeper::OAuth
112
153
  access_token_expires_in: 2.hours,
113
154
  refresh_token_enabled?: false,
114
155
  custom_access_token_expires_in: lambda { |context|
115
- context.scopes.exists?('public') ? 222 : nil
156
+ if context.scopes.exists?("public")
157
+ 222
158
+ elsif context.scopes.exists?("magic")
159
+ Float::INFINITY
160
+ end
116
161
  }
117
162
  )
118
163
  end
119
164
 
120
- it 'checks scopes' do
121
- subject = PasswordAccessTokenRequest.new(server, client, owner, scope: 'public')
122
- allow(server).to receive(:scopes).and_return(Doorkeeper::OAuth::Scopes.from_string('public'))
165
+ before do
166
+ allow(server).to receive(:option_defined?).with(:custom_access_token_expires_in).and_return(true)
167
+ end
168
+
169
+ it "checks scopes" do
170
+ subject = PasswordAccessTokenRequest.new(server, client, owner, scope: "public")
171
+ allow(server).to receive(:scopes).and_return(Doorkeeper::OAuth::Scopes.from_string("public"))
123
172
 
124
173
  expect do
125
174
  subject.authorize
@@ -128,9 +177,9 @@ module Doorkeeper::OAuth
128
177
  expect(Doorkeeper::AccessToken.last.expires_in).to eq(222)
129
178
  end
130
179
 
131
- it 'falls back to the default otherwise' do
132
- subject = PasswordAccessTokenRequest.new(server, client, owner, scope: 'private')
133
- allow(server).to receive(:scopes).and_return(Doorkeeper::OAuth::Scopes.from_string('private'))
180
+ it "falls back to the default otherwise" do
181
+ subject = PasswordAccessTokenRequest.new(server, client, owner, scope: "private")
182
+ allow(server).to receive(:scopes).and_return(Doorkeeper::OAuth::Scopes.from_string("private"))
134
183
 
135
184
  expect do
136
185
  subject.authorize
@@ -1,29 +1,31 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
2
4
 
3
5
  module Doorkeeper::OAuth
4
6
  describe PreAuthorization do
5
7
  let(:server) do
6
8
  server = Doorkeeper.configuration
7
9
  allow(server).to receive(:default_scopes).and_return(Scopes.new)
8
- allow(server).to receive(:scopes).and_return(Scopes.from_string('public profile'))
10
+ allow(server).to receive(:scopes).and_return(Scopes.from_string("public profile"))
9
11
  server
10
12
  end
11
13
 
12
14
  let(:application) do
13
15
  application = double :application
14
- allow(application).to receive(:scopes).and_return(Scopes.from_string(''))
16
+ allow(application).to receive(:scopes).and_return(Scopes.from_string(""))
15
17
  application
16
18
  end
17
19
 
18
20
  let(:client) do
19
- double :client, redirect_uri: 'http://tst.com/auth', application: application
21
+ double :client, redirect_uri: "http://tst.com/auth", application: application
20
22
  end
21
23
 
22
24
  let :attributes do
23
25
  {
24
- response_type: 'code',
25
- redirect_uri: 'http://tst.com/auth',
26
- state: 'save-this'
26
+ response_type: "code",
27
+ redirect_uri: "http://tst.com/auth",
28
+ state: "save-this",
27
29
  }
28
30
  end
29
31
 
@@ -31,133 +33,157 @@ module Doorkeeper::OAuth
31
33
  PreAuthorization.new(server, client, attributes)
32
34
  end
33
35
 
34
- it 'is authorizable when request is valid' do
36
+ it "is authorizable when request is valid" do
35
37
  expect(subject).to be_authorizable
36
38
  end
37
39
 
38
- it 'accepts code as response type' do
39
- subject.response_type = 'code'
40
+ it "accepts code as response type" do
41
+ subject.response_type = "code"
40
42
  expect(subject).to be_authorizable
41
43
  end
42
44
 
43
- it 'accepts token as response type' do
44
- allow(server).to receive(:grant_flows).and_return(['implicit'])
45
- subject.response_type = 'token'
45
+ it "accepts token as response type" do
46
+ allow(server).to receive(:grant_flows).and_return(["implicit"])
47
+ subject.response_type = "token"
46
48
  expect(subject).to be_authorizable
47
49
  end
48
50
 
49
- context 'when using default grant flows' do
51
+ context "when using default grant flows" do
50
52
  it 'accepts "code" as response type' do
51
- subject.response_type = 'code'
53
+ subject.response_type = "code"
52
54
  expect(subject).to be_authorizable
53
55
  end
54
56
 
55
57
  it 'accepts "token" as response type' do
56
- allow(server).to receive(:grant_flows).and_return(['implicit'])
57
- subject.response_type = 'token'
58
+ allow(server).to receive(:grant_flows).and_return(["implicit"])
59
+ subject.response_type = "token"
58
60
  expect(subject).to be_authorizable
59
61
  end
60
62
  end
61
63
 
62
- context 'when authorization code grant flow is disabled' do
64
+ context "when authorization code grant flow is disabled" do
63
65
  before do
64
- allow(server).to receive(:grant_flows).and_return(['implicit'])
66
+ allow(server).to receive(:grant_flows).and_return(["implicit"])
65
67
  end
66
68
 
67
69
  it 'does not accept "code" as response type' do
68
- subject.response_type = 'code'
70
+ subject.response_type = "code"
69
71
  expect(subject).not_to be_authorizable
70
72
  end
71
73
  end
72
74
 
73
- context 'when implicit grant flow is disabled' do
75
+ context "when implicit grant flow is disabled" do
74
76
  before do
75
- allow(server).to receive(:grant_flows).and_return(['authorization_code'])
77
+ allow(server).to receive(:grant_flows).and_return(["authorization_code"])
76
78
  end
77
79
 
78
80
  it 'does not accept "token" as response type' do
79
- subject.response_type = 'token'
81
+ subject.response_type = "token"
80
82
  expect(subject).not_to be_authorizable
81
83
  end
82
84
  end
83
85
 
84
- context 'client application does not restrict valid scopes' do
85
- it 'accepts valid scopes' do
86
- subject.scope = 'public'
86
+ context "client application does not restrict valid scopes" do
87
+ it "accepts valid scopes" do
88
+ subject.scope = "public"
89
+ expect(subject).to be_authorizable
90
+ end
91
+
92
+ it "rejects (globally) non-valid scopes" do
93
+ subject.scope = "invalid"
94
+ expect(subject).not_to be_authorizable
95
+ end
96
+
97
+ it "accepts scopes which are permitted for grant_type" do
98
+ allow(server).to receive(:scopes_by_grant_type).and_return(authorization_code: [:public])
99
+ subject.scope = "public"
87
100
  expect(subject).to be_authorizable
88
101
  end
89
102
 
90
- it 'rejects (globally) non-valid scopes' do
91
- subject.scope = 'invalid'
103
+ it "rejects scopes which are not permitted for grant_type" do
104
+ allow(server).to receive(:scopes_by_grant_type).and_return(authorization_code: [:profile])
105
+ subject.scope = "public"
92
106
  expect(subject).not_to be_authorizable
93
107
  end
94
108
  end
95
109
 
96
- context 'client application restricts valid scopes' do
110
+ context "client application restricts valid scopes" do
97
111
  let(:application) do
98
112
  application = double :application
99
- allow(application).to receive(:scopes).and_return(Scopes.from_string('public nonsense'))
113
+ allow(application).to receive(:scopes).and_return(Scopes.from_string("public nonsense"))
100
114
  application
101
115
  end
102
116
 
103
- it 'accepts valid scopes' do
104
- subject.scope = 'public'
117
+ it "accepts valid scopes" do
118
+ subject.scope = "public"
105
119
  expect(subject).to be_authorizable
106
120
  end
107
121
 
108
- it 'rejects (globally) non-valid scopes' do
109
- subject.scope = 'invalid'
122
+ it "rejects (globally) non-valid scopes" do
123
+ subject.scope = "invalid"
110
124
  expect(subject).not_to be_authorizable
111
125
  end
112
126
 
113
- it 'rejects (application level) non-valid scopes' do
114
- subject.scope = 'profile'
127
+ it "rejects (application level) non-valid scopes" do
128
+ subject.scope = "profile"
115
129
  expect(subject).to_not be_authorizable
116
130
  end
131
+
132
+ it "accepts scopes which are permitted for grant_type" do
133
+ allow(server).to receive(:scopes_by_grant_type).and_return(authorization_code: [:public])
134
+ subject.scope = "public"
135
+ expect(subject).to be_authorizable
136
+ end
137
+
138
+ it "rejects scopes which are not permitted for grant_type" do
139
+ allow(server).to receive(:scopes_by_grant_type).and_return(authorization_code: [:profile])
140
+ subject.scope = "public"
141
+ expect(subject).not_to be_authorizable
142
+ end
117
143
  end
118
144
 
119
- it 'uses default scopes when none is required' do
120
- allow(server).to receive(:default_scopes).and_return(Scopes.from_string('default'))
145
+ it "uses default scopes when none is required" do
146
+ allow(server).to receive(:default_scopes).and_return(Scopes.from_string("default"))
121
147
  subject.scope = nil
122
- expect(subject.scope).to eq('default')
123
- expect(subject.scopes).to eq(Scopes.from_string('default'))
148
+ expect(subject.scope).to eq("default")
149
+ expect(subject.scopes).to eq(Scopes.from_string("default"))
124
150
  end
125
151
 
126
- context 'with native redirect uri' do
127
- let(:native_redirect_uri) { 'urn:ietf:wg:oauth:2.0:oob' }
152
+ context "with native redirect uri" do
153
+ let(:native_redirect_uri) { "urn:ietf:wg:oauth:2.0:oob" }
128
154
 
129
- it 'accepts redirect_uri when it matches with the client' do
155
+ it "accepts redirect_uri when it matches with the client" do
130
156
  subject.redirect_uri = native_redirect_uri
131
157
  allow(subject.client).to receive(:redirect_uri) { native_redirect_uri }
132
158
  expect(subject).to be_authorizable
133
159
  end
134
160
 
135
- it 'invalidates redirect_uri when it does\'n match with the client' do
136
- subject.redirect_uri = 'urn:ietf:wg:oauth:2.0:oob'
161
+ it "invalidates redirect_uri when it does'n match with the client" do
162
+ subject.redirect_uri = "urn:ietf:wg:oauth:2.0:oob"
137
163
  expect(subject).not_to be_authorizable
138
164
  end
139
165
  end
140
166
 
141
- it 'matches the redirect uri against client\'s one' do
142
- subject.redirect_uri = 'http://nothesame.com'
167
+ it "matches the redirect uri against client's one" do
168
+ subject.redirect_uri = "http://nothesame.com"
143
169
  expect(subject).not_to be_authorizable
144
170
  end
145
171
 
146
- it 'stores the state' do
147
- expect(subject.state).to eq('save-this')
172
+ it "stores the state" do
173
+ expect(subject.state).to eq("save-this")
148
174
  end
149
175
 
150
- it 'rejects if response type is not allowed' do
151
- subject.response_type = 'whops'
176
+ it "rejects if response type is not allowed" do
177
+ subject.response_type = "whops"
152
178
  expect(subject).not_to be_authorizable
153
179
  end
154
180
 
155
- it 'requires an existing client' do
181
+ it "requires an existing client" do
156
182
  subject.client = nil
157
183
  expect(subject).not_to be_authorizable
158
184
  end
159
185
 
160
- it 'requires a redirect uri' do
186
+ it "requires a redirect uri" do
161
187
  subject.redirect_uri = nil
162
188
  expect(subject).not_to be_authorizable
163
189
  end
@@ -182,7 +208,7 @@ module Doorkeeper::OAuth
182
208
  expect(json[:response_type]).to eq subject.response_type
183
209
  expect(json[:scope]).to eq subject.scope
184
210
  expect(json[:client_name]).to eq client_name
185
- expect(json[:status]).to eq I18n.t('doorkeeper.pre_authorization.status')
211
+ expect(json[:status]).to eq I18n.t("doorkeeper.pre_authorization.status")
186
212
  end
187
213
  end
188
214
  end
@@ -1,15 +1,12 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
2
4
 
3
5
  module Doorkeeper::OAuth
4
6
  describe RefreshTokenRequest do
5
- before do
6
- allow(Doorkeeper::AccessToken).to receive(:refresh_token_revoked_on_use?).and_return(false)
7
- end
8
-
9
7
  let(:server) do
10
8
  double :server,
11
- access_token_expires_in: 2.minutes,
12
- custom_access_token_expires_in: ->(_context) { nil }
9
+ access_token_expires_in: 2.minutes
13
10
  end
14
11
 
15
12
  let(:refresh_token) do
@@ -19,21 +16,27 @@ module Doorkeeper::OAuth
19
16
  let(:client) { refresh_token.application }
20
17
  let(:credentials) { Client::Credentials.new(client.uid, client.secret) }
21
18
 
19
+ before do
20
+ allow(Doorkeeper::AccessToken).to receive(:refresh_token_revoked_on_use?).and_return(false)
21
+ allow(server).to receive(:option_defined?).with(:custom_access_token_expires_in).and_return(false)
22
+ end
23
+
22
24
  subject { RefreshTokenRequest.new server, refresh_token, credentials }
23
25
 
24
- it 'issues a new token for the client' do
26
+ it "issues a new token for the client" do
25
27
  expect { subject.authorize }.to change { client.reload.access_tokens.count }.by(1)
26
28
  # #sort_by used for MongoDB ORM extensions for valid ordering
27
29
  expect(client.reload.access_tokens.max_by(&:created_at).expires_in).to eq(120)
28
30
  end
29
31
 
30
- it 'issues a new token for the client with custom expires_in' do
32
+ it "issues a new token for the client with custom expires_in" do
31
33
  server = double :server,
32
34
  access_token_expires_in: 2.minutes,
33
35
  custom_access_token_expires_in: lambda { |context|
34
36
  context.grant_type == Doorkeeper::OAuth::REFRESH_TOKEN ? 1234 : nil
35
37
  }
36
38
 
39
+ allow(server).to receive(:option_defined?).with(:custom_access_token_expires_in).and_return(true)
37
40
  allow(Doorkeeper::AccessToken).to receive(:refresh_token_revoked_on_use?).and_return(false)
38
41
 
39
42
  RefreshTokenRequest.new(server, refresh_token, credentials).authorize
@@ -42,7 +45,7 @@ module Doorkeeper::OAuth
42
45
  expect(client.reload.access_tokens.max_by(&:created_at).expires_in).to eq(1234)
43
46
  end
44
47
 
45
- it 'revokes the previous token' do
48
+ it "revokes the previous token" do
46
49
  expect { subject.authorize }.to change { refresh_token.revoked? }.from(false).to(true)
47
50
  end
48
51
 
@@ -56,13 +59,13 @@ module Doorkeeper::OAuth
56
59
  subject.authorize
57
60
  end
58
61
 
59
- it 'requires the refresh token' do
62
+ it "requires the refresh token" do
60
63
  subject.refresh_token = nil
61
64
  subject.validate
62
65
  expect(subject.error).to eq(:invalid_request)
63
66
  end
64
67
 
65
- it 'requires credentials to be valid if provided' do
68
+ it "requires credentials to be valid if provided" do
66
69
  subject.client = nil
67
70
  subject.validate
68
71
  expect(subject.error).to eq(:invalid_client)
@@ -74,20 +77,20 @@ module Doorkeeper::OAuth
74
77
  expect(subject.error).to eq(:invalid_grant)
75
78
  end
76
79
 
77
- it 'rejects revoked tokens' do
80
+ it "rejects revoked tokens" do
78
81
  refresh_token.revoke
79
82
  subject.validate
80
83
  expect(subject.error).to eq(:invalid_grant)
81
84
  end
82
85
 
83
- it 'accepts expired tokens' do
86
+ it "accepts expired tokens" do
84
87
  refresh_token.expires_in = -1
85
88
  refresh_token.save
86
89
  subject.validate
87
90
  expect(subject).to be_valid
88
91
  end
89
92
 
90
- context 'refresh tokens expire on access token use' do
93
+ context "refresh tokens expire on access token use" do
91
94
  let(:server) do
92
95
  double :server,
93
96
  access_token_expires_in: 2.minutes,
@@ -100,16 +103,16 @@ module Doorkeeper::OAuth
100
103
  allow(Doorkeeper::AccessToken).to receive(:refresh_token_revoked_on_use?).and_return(true)
101
104
  end
102
105
 
103
- it 'issues a new token for the client' do
106
+ it "issues a new token for the client" do
104
107
  expect { subject.authorize }.to change { client.reload.access_tokens.count }.by(1)
105
108
  end
106
109
 
107
- it 'does not revoke the previous token' do
110
+ it "does not revoke the previous token" do
108
111
  subject.authorize
109
112
  expect(refresh_token).not_to be_revoked
110
113
  end
111
114
 
112
- it 'sets the previous refresh token in the new access token' do
115
+ it "sets the previous refresh token in the new access token" do
113
116
  subject.authorize
114
117
  expect(
115
118
  # #sort_by used for MongoDB ORM extensions for valid ordering
@@ -118,53 +121,53 @@ module Doorkeeper::OAuth
118
121
  end
119
122
  end
120
123
 
121
- context 'clientless access tokens' do
124
+ context "clientless access tokens" do
122
125
  let!(:refresh_token) { FactoryBot.create(:clientless_access_token, use_refresh_token: true) }
123
126
 
124
127
  subject { RefreshTokenRequest.new server, refresh_token, nil }
125
128
 
126
- it 'issues a new token without a client' do
129
+ it "issues a new token without a client" do
127
130
  expect { subject.authorize }.to change { Doorkeeper::AccessToken.count }.by(1)
128
131
  end
129
132
  end
130
133
 
131
- context 'with scopes' do
134
+ context "with scopes" do
132
135
  let(:refresh_token) do
133
136
  FactoryBot.create :access_token,
134
137
  use_refresh_token: true,
135
- scopes: 'public write'
138
+ scopes: "public write"
136
139
  end
137
140
  let(:parameters) { {} }
138
141
  subject { RefreshTokenRequest.new server, refresh_token, credentials, parameters }
139
142
 
140
- it 'transfers scopes from the old token to the new token' do
143
+ it "transfers scopes from the old token to the new token" do
141
144
  subject.authorize
142
145
  expect(Doorkeeper::AccessToken.last.scopes).to eq(%i[public write])
143
146
  end
144
147
 
145
- it 'reduces scopes to the provided scopes' do
146
- parameters[:scopes] = 'public'
148
+ it "reduces scopes to the provided scopes" do
149
+ parameters[:scopes] = "public"
147
150
  subject.authorize
148
151
  expect(Doorkeeper::AccessToken.last.scopes).to eq(%i[public])
149
152
  end
150
153
 
151
- it 'validates that scopes are included in the original access token' do
152
- parameters[:scopes] = 'public update'
154
+ it "validates that scopes are included in the original access token" do
155
+ parameters[:scopes] = "public update"
153
156
 
154
157
  subject.validate
155
158
  expect(subject.error).to eq(:invalid_scope)
156
159
  end
157
160
 
158
- it 'uses params[:scope] in favor of scopes if present (valid)' do
159
- parameters[:scopes] = 'public update'
160
- parameters[:scope] = 'public'
161
+ it "uses params[:scope] in favor of scopes if present (valid)" do
162
+ parameters[:scopes] = "public update"
163
+ parameters[:scope] = "public"
161
164
  subject.authorize
162
165
  expect(Doorkeeper::AccessToken.last.scopes).to eq(%i[public])
163
166
  end
164
167
 
165
- it 'uses params[:scope] in favor of scopes if present (invalid)' do
166
- parameters[:scopes] = 'public'
167
- parameters[:scope] = 'public update'
168
+ it "uses params[:scope] in favor of scopes if present (invalid)" do
169
+ parameters[:scopes] = "public"
170
+ parameters[:scope] = "public update"
168
171
 
169
172
  subject.validate
170
173
  expect(subject.error).to eq(:invalid_scope)