doorkeeper 5.0.0 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (241) hide show
  1. checksums.yaml +5 -5
  2. data/.hound.yml +2 -1
  3. data/.rubocop.yml +37 -4
  4. data/.travis.yml +16 -21
  5. data/Appraisals +29 -7
  6. data/Dangerfile +67 -0
  7. data/Gemfile +19 -5
  8. data/NEWS.md +107 -10
  9. data/README.md +75 -470
  10. data/Rakefile +10 -8
  11. data/app/controllers/doorkeeper/application_controller.rb +3 -2
  12. data/app/controllers/doorkeeper/application_metal_controller.rb +4 -13
  13. data/app/controllers/doorkeeper/applications_controller.rb +21 -7
  14. data/app/controllers/doorkeeper/authorizations_controller.rb +3 -3
  15. data/app/controllers/doorkeeper/authorized_applications_controller.rb +2 -0
  16. data/app/controllers/doorkeeper/token_info_controller.rb +4 -2
  17. data/app/controllers/doorkeeper/tokens_controller.rb +13 -11
  18. data/app/helpers/doorkeeper/dashboard_helper.rb +3 -1
  19. data/app/validators/redirect_uri_validator.rb +7 -2
  20. data/app/views/doorkeeper/applications/_form.html.erb +6 -0
  21. data/app/views/doorkeeper/applications/show.html.erb +1 -1
  22. data/app/views/layouts/doorkeeper/admin.html.erb +5 -3
  23. data/bin/console +16 -0
  24. data/config/locales/en.yml +1 -0
  25. data/doorkeeper.gemspec +28 -24
  26. data/gemfiles/rails_5_0.gemfile +9 -4
  27. data/gemfiles/rails_5_1.gemfile +9 -4
  28. data/gemfiles/rails_5_2.gemfile +10 -5
  29. data/gemfiles/rails_6_0.gemfile +17 -0
  30. data/gemfiles/rails_master.gemfile +9 -9
  31. data/lib/doorkeeper/config/option.rb +64 -0
  32. data/lib/doorkeeper/config.rb +197 -76
  33. data/lib/doorkeeper/engine.rb +3 -1
  34. data/lib/doorkeeper/errors.rb +17 -0
  35. data/lib/doorkeeper/grape/authorization_decorator.rb +6 -4
  36. data/lib/doorkeeper/grape/helpers.rb +5 -3
  37. data/lib/doorkeeper/helpers/controller.rb +5 -2
  38. data/lib/doorkeeper/models/access_grant_mixin.rb +25 -6
  39. data/lib/doorkeeper/models/access_token_mixin.rb +68 -22
  40. data/lib/doorkeeper/models/application_mixin.rb +45 -1
  41. data/lib/doorkeeper/models/concerns/accessible.rb +2 -0
  42. data/lib/doorkeeper/models/concerns/expirable.rb +6 -2
  43. data/lib/doorkeeper/models/concerns/orderable.rb +2 -0
  44. data/lib/doorkeeper/models/concerns/ownership.rb +3 -6
  45. data/lib/doorkeeper/models/concerns/reusable.rb +19 -0
  46. data/lib/doorkeeper/models/concerns/revocable.rb +4 -1
  47. data/lib/doorkeeper/models/concerns/scopes.rb +7 -1
  48. data/lib/doorkeeper/models/concerns/secret_storable.rb +108 -0
  49. data/lib/doorkeeper/oauth/authorization/code.rb +4 -2
  50. data/lib/doorkeeper/oauth/authorization/context.rb +2 -0
  51. data/lib/doorkeeper/oauth/authorization/token.rb +14 -7
  52. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +3 -1
  53. data/lib/doorkeeper/oauth/authorization_code_request.rb +8 -4
  54. data/lib/doorkeeper/oauth/base_request.rb +2 -0
  55. data/lib/doorkeeper/oauth/base_response.rb +2 -0
  56. data/lib/doorkeeper/oauth/client/credentials.rb +2 -0
  57. data/lib/doorkeeper/oauth/client.rb +3 -1
  58. data/lib/doorkeeper/oauth/client_credentials/creator.rb +2 -0
  59. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +2 -0
  60. data/lib/doorkeeper/oauth/client_credentials/validation.rb +7 -4
  61. data/lib/doorkeeper/oauth/client_credentials_request.rb +3 -1
  62. data/lib/doorkeeper/oauth/code_request.rb +2 -0
  63. data/lib/doorkeeper/oauth/code_response.rb +4 -2
  64. data/lib/doorkeeper/oauth/error.rb +2 -0
  65. data/lib/doorkeeper/oauth/error_response.rb +20 -6
  66. data/lib/doorkeeper/oauth/forbidden_token_response.rb +10 -3
  67. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +25 -8
  68. data/lib/doorkeeper/oauth/helpers/unique_token.rb +15 -1
  69. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +42 -3
  70. data/lib/doorkeeper/oauth/invalid_token_response.rb +22 -0
  71. data/lib/doorkeeper/oauth/password_access_token_request.rb +9 -2
  72. data/lib/doorkeeper/oauth/pre_authorization.rb +13 -5
  73. data/lib/doorkeeper/oauth/refresh_token_request.rb +15 -4
  74. data/lib/doorkeeper/oauth/scopes.rb +7 -3
  75. data/lib/doorkeeper/oauth/token.rb +4 -2
  76. data/lib/doorkeeper/oauth/token_introspection.rb +76 -8
  77. data/lib/doorkeeper/oauth/token_request.rb +2 -0
  78. data/lib/doorkeeper/oauth/token_response.rb +11 -9
  79. data/lib/doorkeeper/oauth.rb +5 -5
  80. data/lib/doorkeeper/orm/active_record/access_grant.rb +27 -13
  81. data/lib/doorkeeper/orm/active_record/access_token.rb +6 -13
  82. data/lib/doorkeeper/orm/active_record/application.rb +26 -7
  83. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +10 -3
  84. data/lib/doorkeeper/orm/active_record.rb +8 -6
  85. data/lib/doorkeeper/rails/helpers.rb +5 -1
  86. data/lib/doorkeeper/rails/routes/mapper.rb +2 -0
  87. data/lib/doorkeeper/rails/routes/mapping.rb +9 -7
  88. data/lib/doorkeeper/rails/routes.rb +19 -12
  89. data/lib/doorkeeper/rake/db.rake +17 -17
  90. data/lib/doorkeeper/rake.rb +1 -1
  91. data/lib/doorkeeper/request/authorization_code.rb +2 -0
  92. data/lib/doorkeeper/request/client_credentials.rb +2 -0
  93. data/lib/doorkeeper/request/code.rb +2 -0
  94. data/lib/doorkeeper/request/password.rb +2 -0
  95. data/lib/doorkeeper/request/refresh_token.rb +2 -0
  96. data/lib/doorkeeper/request/strategy.rb +2 -0
  97. data/lib/doorkeeper/request/token.rb +2 -0
  98. data/lib/doorkeeper/request.rb +3 -1
  99. data/lib/doorkeeper/secret_storing/base.rb +64 -0
  100. data/lib/doorkeeper/secret_storing/bcrypt.rb +60 -0
  101. data/lib/doorkeeper/secret_storing/plain.rb +33 -0
  102. data/lib/doorkeeper/secret_storing/sha256_hash.rb +26 -0
  103. data/lib/doorkeeper/server.rb +2 -0
  104. data/lib/doorkeeper/stale_records_cleaner.rb +20 -0
  105. data/lib/doorkeeper/validations.rb +2 -0
  106. data/lib/doorkeeper/version.rb +4 -2
  107. data/lib/doorkeeper.rb +69 -59
  108. data/lib/generators/doorkeeper/application_owner_generator.rb +10 -9
  109. data/lib/generators/doorkeeper/confidential_applications_generator.rb +10 -9
  110. data/lib/generators/doorkeeper/install_generator.rb +11 -9
  111. data/lib/generators/doorkeeper/migration_generator.rb +9 -9
  112. data/lib/generators/doorkeeper/pkce_generator.rb +10 -9
  113. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +10 -9
  114. data/lib/generators/doorkeeper/templates/initializer.rb +138 -13
  115. data/lib/generators/doorkeeper/templates/migration.rb.erb +17 -10
  116. data/lib/generators/doorkeeper/views_generator.rb +6 -4
  117. data/spec/controllers/application_metal_controller_spec.rb +24 -10
  118. data/spec/controllers/applications_controller_spec.rb +76 -78
  119. data/spec/controllers/authorizations_controller_spec.rb +189 -142
  120. data/spec/controllers/protected_resources_controller_spec.rb +111 -67
  121. data/spec/controllers/token_info_controller_spec.rb +14 -12
  122. data/spec/controllers/tokens_controller_spec.rb +170 -112
  123. data/spec/dummy/Rakefile +3 -1
  124. data/spec/dummy/app/controllers/application_controller.rb +3 -1
  125. data/spec/dummy/app/controllers/custom_authorizations_controller.rb +3 -1
  126. data/spec/dummy/app/controllers/full_protected_resources_controller.rb +4 -2
  127. data/spec/dummy/app/controllers/home_controller.rb +6 -5
  128. data/spec/dummy/app/controllers/metal_controller.rb +2 -0
  129. data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +4 -2
  130. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  131. data/spec/dummy/app/models/user.rb +2 -0
  132. data/spec/dummy/config/application.rb +26 -2
  133. data/spec/dummy/config/boot.rb +2 -4
  134. data/spec/dummy/config/environment.rb +1 -1
  135. data/spec/dummy/config/environments/development.rb +2 -0
  136. data/spec/dummy/config/environments/production.rb +2 -0
  137. data/spec/dummy/config/environments/test.rb +4 -2
  138. data/spec/dummy/config/initializers/backtrace_silencers.rb +2 -0
  139. data/spec/dummy/config/initializers/doorkeeper.rb +7 -3
  140. data/spec/dummy/config/initializers/secret_token.rb +3 -1
  141. data/spec/dummy/config/initializers/session_store.rb +3 -1
  142. data/spec/dummy/config/initializers/wrap_parameters.rb +2 -0
  143. data/spec/dummy/config.ru +3 -1
  144. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +20 -13
  145. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +1 -1
  146. data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +2 -0
  147. data/spec/dummy/db/schema.rb +1 -1
  148. data/spec/dummy/script/rails +7 -4
  149. data/spec/factories.rb +11 -9
  150. data/spec/generators/application_owner_generator_spec.rb +13 -26
  151. data/spec/generators/confidential_applications_generator_spec.rb +12 -28
  152. data/spec/generators/install_generator_spec.rb +19 -14
  153. data/spec/generators/migration_generator_spec.rb +13 -26
  154. data/spec/generators/pkce_generator_spec.rb +11 -26
  155. data/spec/generators/previous_refresh_token_generator_spec.rb +16 -29
  156. data/spec/generators/templates/routes.rb +2 -1
  157. data/spec/generators/views_generator_spec.rb +14 -12
  158. data/spec/grape/grape_integration_spec.rb +35 -33
  159. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +9 -7
  160. data/spec/lib/config_spec.rb +290 -104
  161. data/spec/lib/doorkeeper_spec.rb +8 -6
  162. data/spec/lib/models/expirable_spec.rb +22 -8
  163. data/spec/lib/models/reusable_spec.rb +40 -0
  164. data/spec/lib/models/revocable_spec.rb +8 -6
  165. data/spec/lib/models/scopes_spec.rb +27 -13
  166. data/spec/lib/models/secret_storable_spec.rb +135 -0
  167. data/spec/lib/oauth/authorization/uri_builder_spec.rb +17 -15
  168. data/spec/lib/oauth/authorization_code_request_spec.rb +43 -17
  169. data/spec/lib/oauth/base_request_spec.rb +24 -12
  170. data/spec/lib/oauth/base_response_spec.rb +3 -1
  171. data/spec/lib/oauth/client/credentials_spec.rb +26 -24
  172. data/spec/lib/oauth/client_credentials/creator_spec.rb +56 -10
  173. data/spec/lib/oauth/client_credentials/issuer_spec.rb +27 -20
  174. data/spec/lib/oauth/client_credentials/validation_spec.rb +21 -15
  175. data/spec/lib/oauth/client_credentials_integration_spec.rb +8 -6
  176. data/spec/lib/oauth/client_credentials_request_spec.rb +27 -21
  177. data/spec/lib/oauth/client_spec.rb +15 -13
  178. data/spec/lib/oauth/code_request_spec.rb +10 -8
  179. data/spec/lib/oauth/code_response_spec.rb +9 -7
  180. data/spec/lib/oauth/error_response_spec.rb +19 -11
  181. data/spec/lib/oauth/error_spec.rb +4 -2
  182. data/spec/lib/oauth/forbidden_token_response_spec.rb +7 -5
  183. data/spec/lib/oauth/helpers/scope_checker_spec.rb +68 -31
  184. data/spec/lib/oauth/helpers/unique_token_spec.rb +8 -6
  185. data/spec/lib/oauth/helpers/uri_checker_spec.rb +124 -93
  186. data/spec/lib/oauth/invalid_token_response_spec.rb +3 -1
  187. data/spec/lib/oauth/password_access_token_request_spec.rb +95 -34
  188. data/spec/lib/oauth/pre_authorization_spec.rb +80 -54
  189. data/spec/lib/oauth/refresh_token_request_spec.rb +46 -39
  190. data/spec/lib/oauth/scopes_spec.rb +63 -61
  191. data/spec/lib/oauth/token_request_spec.rb +80 -25
  192. data/spec/lib/oauth/token_response_spec.rb +40 -38
  193. data/spec/lib/oauth/token_spec.rb +64 -45
  194. data/spec/lib/request/strategy_spec.rb +3 -1
  195. data/spec/lib/secret_storing/base_spec.rb +60 -0
  196. data/spec/lib/secret_storing/bcrypt_spec.rb +49 -0
  197. data/spec/lib/secret_storing/plain_spec.rb +44 -0
  198. data/spec/lib/secret_storing/sha256_hash_spec.rb +48 -0
  199. data/spec/lib/server_spec.rb +20 -18
  200. data/spec/lib/{orm/active_record/stale_records_cleaner_spec.rb → stale_records_cleaner_spec.rb} +28 -18
  201. data/spec/models/doorkeeper/access_grant_spec.rb +80 -15
  202. data/spec/models/doorkeeper/access_token_spec.rb +212 -83
  203. data/spec/models/doorkeeper/application_spec.rb +146 -49
  204. data/spec/requests/applications/applications_request_spec.rb +100 -68
  205. data/spec/requests/applications/authorized_applications_spec.rb +20 -18
  206. data/spec/requests/endpoints/authorization_spec.rb +27 -25
  207. data/spec/requests/endpoints/token_spec.rb +38 -36
  208. data/spec/requests/flows/authorization_code_errors_spec.rb +27 -25
  209. data/spec/requests/flows/authorization_code_spec.rb +260 -158
  210. data/spec/requests/flows/client_credentials_spec.rb +54 -52
  211. data/spec/requests/flows/implicit_grant_errors_spec.rb +11 -9
  212. data/spec/requests/flows/implicit_grant_spec.rb +27 -25
  213. data/spec/requests/flows/password_spec.rb +64 -56
  214. data/spec/requests/flows/refresh_token_spec.rb +91 -32
  215. data/spec/requests/flows/revoke_token_spec.rb +49 -63
  216. data/spec/requests/flows/skip_authorization_spec.rb +23 -21
  217. data/spec/requests/protected_resources/metal_spec.rb +7 -5
  218. data/spec/requests/protected_resources/private_api_spec.rb +37 -35
  219. data/spec/routing/custom_controller_routes_spec.rb +71 -65
  220. data/spec/routing/default_routes_spec.rb +22 -20
  221. data/spec/routing/scoped_routes_spec.rb +20 -18
  222. data/spec/spec_helper.rb +15 -13
  223. data/spec/spec_helper_integration.rb +3 -1
  224. data/spec/support/dependencies/factory_bot.rb +3 -1
  225. data/spec/support/doorkeeper_rspec.rb +5 -2
  226. data/spec/support/helpers/access_token_request_helper.rb +3 -1
  227. data/spec/support/helpers/authorization_request_helper.rb +4 -2
  228. data/spec/support/helpers/config_helper.rb +2 -0
  229. data/spec/support/helpers/model_helper.rb +11 -5
  230. data/spec/support/helpers/request_spec_helper.rb +5 -3
  231. data/spec/support/helpers/url_helper.rb +20 -18
  232. data/spec/support/http_method_shim.rb +4 -9
  233. data/spec/support/orm/active_record.rb +3 -1
  234. data/spec/support/shared/controllers_shared_context.rb +68 -10
  235. data/spec/support/shared/hashing_shared_context.rb +36 -0
  236. data/spec/support/shared/models_shared_examples.rb +12 -10
  237. data/spec/validators/redirect_uri_validator_spec.rb +76 -47
  238. data/spec/version/version_spec.rb +7 -5
  239. metadata +70 -21
  240. data/gemfiles/rails_4_2.gemfile +0 -13
  241. data/spec/dummy/config/initializers/new_framework_defaults.rb +0 -10
@@ -1,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,46 +16,56 @@ 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
- expect(client.reload.access_tokens.sort_by(&:created_at).last.expires_in).to eq(120)
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
40
43
 
41
44
  # #sort_by used for MongoDB ORM extensions for valid ordering
42
- expect(client.reload.access_tokens.sort_by(&:created_at).last.expires_in).to eq(1234)
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
 
49
52
  it "calls configured request callback methods" do
50
- expect(Doorkeeper.configuration.before_successful_strategy_response).to receive(:call).with(subject).once
51
- expect(Doorkeeper.configuration.after_successful_strategy_response).to receive(:call).with(subject, instance_of(Doorkeeper::OAuth::TokenResponse)).once
53
+ expect(Doorkeeper.configuration.before_successful_strategy_response)
54
+ .to receive(:call).with(subject).once
55
+
56
+ expect(Doorkeeper.configuration.after_successful_strategy_response)
57
+ .to receive(:call).with(subject, instance_of(Doorkeeper::OAuth::TokenResponse)).once
58
+
52
59
  subject.authorize
53
60
  end
54
61
 
55
- it 'requires the refresh token' do
62
+ it "requires the refresh token" do
56
63
  subject.refresh_token = nil
57
64
  subject.validate
58
65
  expect(subject.error).to eq(:invalid_request)
59
66
  end
60
67
 
61
- it 'requires credentials to be valid if provided' do
68
+ it "requires credentials to be valid if provided" do
62
69
  subject.client = nil
63
70
  subject.validate
64
71
  expect(subject.error).to eq(:invalid_client)
@@ -70,20 +77,20 @@ module Doorkeeper::OAuth
70
77
  expect(subject.error).to eq(:invalid_grant)
71
78
  end
72
79
 
73
- it 'rejects revoked tokens' do
80
+ it "rejects revoked tokens" do
74
81
  refresh_token.revoke
75
82
  subject.validate
76
83
  expect(subject.error).to eq(:invalid_grant)
77
84
  end
78
85
 
79
- it 'accepts expired tokens' do
86
+ it "accepts expired tokens" do
80
87
  refresh_token.expires_in = -1
81
88
  refresh_token.save
82
89
  subject.validate
83
90
  expect(subject).to be_valid
84
91
  end
85
92
 
86
- context 'refresh tokens expire on access token use' do
93
+ context "refresh tokens expire on access token use" do
87
94
  let(:server) do
88
95
  double :server,
89
96
  access_token_expires_in: 2.minutes,
@@ -96,71 +103,71 @@ module Doorkeeper::OAuth
96
103
  allow(Doorkeeper::AccessToken).to receive(:refresh_token_revoked_on_use?).and_return(true)
97
104
  end
98
105
 
99
- it 'issues a new token for the client' do
106
+ it "issues a new token for the client" do
100
107
  expect { subject.authorize }.to change { client.reload.access_tokens.count }.by(1)
101
108
  end
102
109
 
103
- it 'does not revoke the previous token' do
110
+ it "does not revoke the previous token" do
104
111
  subject.authorize
105
112
  expect(refresh_token).not_to be_revoked
106
113
  end
107
114
 
108
- 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
109
116
  subject.authorize
110
117
  expect(
111
118
  # #sort_by used for MongoDB ORM extensions for valid ordering
112
- client.access_tokens.sort_by(&:created_at).last.previous_refresh_token
119
+ client.access_tokens.max_by(&:created_at).previous_refresh_token
113
120
  ).to eq(refresh_token.refresh_token)
114
121
  end
115
122
  end
116
123
 
117
- context 'clientless access tokens' do
124
+ context "clientless access tokens" do
118
125
  let!(:refresh_token) { FactoryBot.create(:clientless_access_token, use_refresh_token: true) }
119
126
 
120
127
  subject { RefreshTokenRequest.new server, refresh_token, nil }
121
128
 
122
- it 'issues a new token without a client' do
129
+ it "issues a new token without a client" do
123
130
  expect { subject.authorize }.to change { Doorkeeper::AccessToken.count }.by(1)
124
131
  end
125
132
  end
126
133
 
127
- context 'with scopes' do
134
+ context "with scopes" do
128
135
  let(:refresh_token) do
129
136
  FactoryBot.create :access_token,
130
- use_refresh_token: true,
131
- scopes: 'public write'
137
+ use_refresh_token: true,
138
+ scopes: "public write"
132
139
  end
133
140
  let(:parameters) { {} }
134
141
  subject { RefreshTokenRequest.new server, refresh_token, credentials, parameters }
135
142
 
136
- 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
137
144
  subject.authorize
138
145
  expect(Doorkeeper::AccessToken.last.scopes).to eq(%i[public write])
139
146
  end
140
147
 
141
- it 'reduces scopes to the provided scopes' do
142
- parameters[:scopes] = 'public'
148
+ it "reduces scopes to the provided scopes" do
149
+ parameters[:scopes] = "public"
143
150
  subject.authorize
144
151
  expect(Doorkeeper::AccessToken.last.scopes).to eq(%i[public])
145
152
  end
146
153
 
147
- it 'validates that scopes are included in the original access token' do
148
- parameters[:scopes] = 'public update'
154
+ it "validates that scopes are included in the original access token" do
155
+ parameters[:scopes] = "public update"
149
156
 
150
157
  subject.validate
151
158
  expect(subject.error).to eq(:invalid_scope)
152
159
  end
153
160
 
154
- it 'uses params[:scope] in favor of scopes if present (valid)' do
155
- parameters[:scopes] = 'public update'
156
- 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"
157
164
  subject.authorize
158
165
  expect(Doorkeeper::AccessToken.last.scopes).to eq(%i[public])
159
166
  end
160
167
 
161
- it 'uses params[:scope] in favor of scopes if present (invalid)' do
162
- parameters[:scopes] = 'public'
163
- 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"
164
171
 
165
172
  subject.validate
166
173
  expect(subject.error).to eq(:invalid_scope)
@@ -1,113 +1,115 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
2
4
 
3
5
  module Doorkeeper::OAuth
4
6
  describe Scopes do
5
- describe '#add' do
6
- it 'allows you to add scopes with symbols' do
7
+ describe "#add" do
8
+ it "allows you to add scopes with symbols" do
7
9
  subject.add :public
8
- expect(subject.all).to eq(['public'])
10
+ expect(subject.all).to eq(["public"])
9
11
  end
10
12
 
11
- it 'allows you to add scopes with strings' do
12
- subject.add 'public'
13
- expect(subject.all).to eq(['public'])
13
+ it "allows you to add scopes with strings" do
14
+ subject.add "public"
15
+ expect(subject.all).to eq(["public"])
14
16
  end
15
17
 
16
- it 'do not add already included scopes' do
18
+ it "do not add already included scopes" do
17
19
  subject.add :public
18
20
  subject.add :public
19
- expect(subject.all).to eq(['public'])
21
+ expect(subject.all).to eq(["public"])
20
22
  end
21
23
  end
22
24
 
23
- describe '#exists' do
25
+ describe "#exists" do
24
26
  before do
25
27
  subject.add :public
26
28
  end
27
29
 
28
- it 'returns true if scope with given name is present' do
29
- expect(subject.exists?('public')).to be_truthy
30
+ it "returns true if scope with given name is present" do
31
+ expect(subject.exists?("public")).to be_truthy
30
32
  end
31
33
 
32
- it 'returns false if scope with given name does not exist' do
33
- expect(subject.exists?('other')).to be_falsey
34
+ it "returns false if scope with given name does not exist" do
35
+ expect(subject.exists?("other")).to be_falsey
34
36
  end
35
37
 
36
- it 'handles symbols' do
38
+ it "handles symbols" do
37
39
  expect(subject.exists?(:public)).to be_truthy
38
40
  expect(subject.exists?(:other)).to be_falsey
39
41
  end
40
42
  end
41
43
 
42
- describe '.from_string' do
43
- let(:string) { 'public write' }
44
+ describe ".from_string" do
45
+ let(:string) { "public write" }
44
46
 
45
47
  subject { Scopes.from_string(string) }
46
48
 
47
49
  it { expect(subject).to be_a(Scopes) }
48
50
 
49
- describe '#all' do
50
- it 'should be an array of the expected scopes' do
51
+ describe "#all" do
52
+ it "should be an array of the expected scopes" do
51
53
  scopes_array = subject.all
52
54
  expect(scopes_array.size).to eq(2)
53
- expect(scopes_array).to include('public')
54
- expect(scopes_array).to include('write')
55
+ expect(scopes_array).to include("public")
56
+ expect(scopes_array).to include("write")
55
57
  end
56
58
  end
57
59
  end
58
60
 
59
- describe '#+' do
60
- it 'can add to another scope object' do
61
- scopes = Scopes.from_string('public') + Scopes.from_string('admin')
61
+ describe "#+" do
62
+ it "can add to another scope object" do
63
+ scopes = Scopes.from_string("public") + Scopes.from_string("admin")
62
64
  expect(scopes.all).to eq(%w[public admin])
63
65
  end
64
66
 
65
- it 'does not change the existing object' do
66
- origin = Scopes.from_string('public')
67
- expect(origin.to_s).to eq('public')
67
+ it "does not change the existing object" do
68
+ origin = Scopes.from_string("public")
69
+ expect(origin.to_s).to eq("public")
68
70
  end
69
71
 
70
- it 'can add an array to a scope object' do
71
- scopes = Scopes.from_string('public') + ['admin']
72
+ it "can add an array to a scope object" do
73
+ scopes = Scopes.from_string("public") + ["admin"]
72
74
  expect(scopes.all).to eq(%w[public admin])
73
75
  end
74
76
 
75
- it 'raises an error if cannot handle addition' do
77
+ it "raises an error if cannot handle addition" do
76
78
  expect do
77
- Scopes.from_string('public') + 'admin'
79
+ Scopes.from_string("public") + "admin"
78
80
  end.to raise_error(NoMethodError)
79
81
  end
80
82
  end
81
83
 
82
- describe '#&' do
83
- it 'can get intersection with another scope object' do
84
- scopes = Scopes.from_string('public admin') & Scopes.from_string('write admin')
84
+ describe "#&" do
85
+ it "can get intersection with another scope object" do
86
+ scopes = Scopes.from_string("public admin") & Scopes.from_string("write admin")
85
87
  expect(scopes.all).to eq(%w[admin])
86
88
  end
87
89
 
88
- it 'does not change the existing object' do
89
- origin = Scopes.from_string('public admin')
90
- origin & Scopes.from_string('write admin')
91
- expect(origin.to_s).to eq('public admin')
90
+ it "does not change the existing object" do
91
+ origin = Scopes.from_string("public admin")
92
+ origin & Scopes.from_string("write admin")
93
+ expect(origin.to_s).to eq("public admin")
92
94
  end
93
95
 
94
- it 'can get intersection with an array' do
95
- scopes = Scopes.from_string('public admin') & %w[write admin]
96
+ it "can get intersection with an array" do
97
+ scopes = Scopes.from_string("public admin") & %w[write admin]
96
98
  expect(scopes.all).to eq(%w[admin])
97
99
  end
98
100
  end
99
101
 
100
- describe '#==' do
101
- it 'is equal to another set of scopes' do
102
- expect(Scopes.from_string('public')).to eq(Scopes.from_string('public'))
102
+ describe "#==" do
103
+ it "is equal to another set of scopes" do
104
+ expect(Scopes.from_string("public")).to eq(Scopes.from_string("public"))
103
105
  end
104
106
 
105
- it 'is equal to another set of scopes with no particular order' do
106
- expect(Scopes.from_string('public write')).to eq(Scopes.from_string('write public'))
107
+ it "is equal to another set of scopes with no particular order" do
108
+ expect(Scopes.from_string("public write")).to eq(Scopes.from_string("write public"))
107
109
  end
108
110
 
109
- it 'differs from another set of scopes when scopes are not the same' do
110
- expect(Scopes.from_string('public write')).not_to eq(Scopes.from_string('write'))
111
+ it "differs from another set of scopes when scopes are not the same" do
112
+ expect(Scopes.from_string("public write")).not_to eq(Scopes.from_string("write"))
111
113
  end
112
114
 
113
115
  it "does not raise an error when compared to a non-enumerable object" do
@@ -115,31 +117,31 @@ module Doorkeeper::OAuth
115
117
  end
116
118
  end
117
119
 
118
- describe '#has_scopes?' do
119
- subject { Scopes.from_string('public admin') }
120
+ describe "#has_scopes?" do
121
+ subject { Scopes.from_string("public admin") }
120
122
 
121
- it 'returns true when at least one scope is included' do
122
- expect(subject.has_scopes?(Scopes.from_string('public'))).to be_truthy
123
+ it "returns true when at least one scope is included" do
124
+ expect(subject.has_scopes?(Scopes.from_string("public"))).to be_truthy
123
125
  end
124
126
 
125
- it 'returns true when all scopes are included' do
126
- expect(subject.has_scopes?(Scopes.from_string('public admin'))).to be_truthy
127
+ it "returns true when all scopes are included" do
128
+ expect(subject.has_scopes?(Scopes.from_string("public admin"))).to be_truthy
127
129
  end
128
130
 
129
- it 'is true if all scopes are included in any order' do
130
- expect(subject.has_scopes?(Scopes.from_string('admin public'))).to be_truthy
131
+ it "is true if all scopes are included in any order" do
132
+ expect(subject.has_scopes?(Scopes.from_string("admin public"))).to be_truthy
131
133
  end
132
134
 
133
- it 'is false if no scopes are included' do
134
- expect(subject.has_scopes?(Scopes.from_string('notexistent'))).to be_falsey
135
+ it "is false if no scopes are included" do
136
+ expect(subject.has_scopes?(Scopes.from_string("notexistent"))).to be_falsey
135
137
  end
136
138
 
137
- it 'returns false when any scope is not included' do
138
- expect(subject.has_scopes?(Scopes.from_string('public nope'))).to be_falsey
139
+ it "returns false when any scope is not included" do
140
+ expect(subject.has_scopes?(Scopes.from_string("public nope"))).to be_falsey
139
141
  end
140
142
 
141
- it 'is false if no scopes are included even for existing ones' do
142
- expect(subject.has_scopes?(Scopes.from_string('public admin notexistent'))).to be_falsey
143
+ it "is false if no scopes are included even for existing ones" do
144
+ expect(subject.has_scopes?(Scopes.from_string("public admin notexistent"))).to be_falsey
143
145
  end
144
146
  end
145
147
  end
@@ -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 TokenRequest do
@@ -10,9 +12,9 @@ module Doorkeeper::OAuth
10
12
  double(
11
13
  :pre_auth,
12
14
  client: application,
13
- redirect_uri: 'http://tst.com/cb',
15
+ redirect_uri: "http://tst.com/cb",
14
16
  state: nil,
15
- scopes: Scopes.from_string('public'),
17
+ scopes: Scopes.from_string("public"),
16
18
  error: nil,
17
19
  authorizable?: true
18
20
  )
@@ -26,69 +28,122 @@ module Doorkeeper::OAuth
26
28
  TokenRequest.new(pre_auth, owner)
27
29
  end
28
30
 
29
- it 'creates an access token' do
31
+ it "creates an access token" do
30
32
  expect do
31
33
  subject.authorize
32
34
  end.to change { Doorkeeper::AccessToken.count }.by(1)
33
35
  end
34
36
 
35
- it 'returns a code response' do
37
+ it "returns a code response" do
36
38
  expect(subject.authorize).to be_a(CodeResponse)
37
39
  end
38
40
 
39
- it 'does not create token when not authorizable' do
41
+ it "does not create token when not authorizable" do
40
42
  allow(pre_auth).to receive(:authorizable?).and_return(false)
41
- expect { subject.authorize }.not_to change { Doorkeeper::AccessToken.count }
43
+ expect { subject.authorize }.not_to(change { Doorkeeper::AccessToken.count })
42
44
  end
43
45
 
44
- it 'returns a error response' do
46
+ it "returns a error response" do
45
47
  allow(pre_auth).to receive(:authorizable?).and_return(false)
46
48
  expect(subject.authorize).to be_a(ErrorResponse)
47
49
  end
48
50
 
49
- context 'with custom expirations' do
50
- before do
51
- Doorkeeper.configure do
52
- orm DOORKEEPER_ORM
53
- custom_access_token_expires_in do |context|
54
- context.grant_type == Doorkeeper::OAuth::IMPLICIT ? 1234 : nil
51
+ describe "with custom expiration" do
52
+ context "when proper TTL returned" do
53
+ before do
54
+ Doorkeeper.configure do
55
+ orm DOORKEEPER_ORM
56
+ custom_access_token_expires_in do |context|
57
+ context.grant_type == Doorkeeper::OAuth::IMPLICIT ? 1234 : nil
58
+ end
55
59
  end
56
60
  end
61
+
62
+ it "should use the custom ttl" do
63
+ subject.authorize
64
+ token = Doorkeeper::AccessToken.first
65
+ expect(token.expires_in).to eq(1234)
66
+ end
57
67
  end
58
68
 
59
- it 'should use the custom ttl' do
60
- subject.authorize
61
- token = Doorkeeper::AccessToken.first
62
- expect(token.expires_in).to eq(1234)
69
+ context "when nil TTL returned" do
70
+ before do
71
+ Doorkeeper.configure do
72
+ orm DOORKEEPER_ORM
73
+ access_token_expires_in 654
74
+ custom_access_token_expires_in do |_context|
75
+ nil
76
+ end
77
+ end
78
+ end
79
+
80
+ it "should fallback to access_token_expires_in" do
81
+ subject.authorize
82
+ token = Doorkeeper::AccessToken.first
83
+ expect(token.expires_in).to eq(654)
84
+ end
85
+ end
86
+
87
+ context "when infinite TTL returned" do
88
+ before do
89
+ Doorkeeper.configure do
90
+ orm DOORKEEPER_ORM
91
+ access_token_expires_in 654
92
+ custom_access_token_expires_in do |_context|
93
+ Float::INFINITY
94
+ end
95
+ end
96
+ end
97
+
98
+ it "should fallback to access_token_expires_in" do
99
+ subject.authorize
100
+ token = Doorkeeper::AccessToken.first
101
+ expect(token.expires_in).to be_nil
102
+ end
63
103
  end
64
104
  end
65
105
 
66
- context 'token reuse' do
67
- it 'creates a new token if there are no matching tokens' do
106
+ context "token reuse" do
107
+ it "creates a new token if there are no matching tokens" do
68
108
  allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
69
109
  expect do
70
110
  subject.authorize
71
111
  end.to change { Doorkeeper::AccessToken.count }.by(1)
72
112
  end
73
113
 
74
- it 'creates a new token if scopes do not match' do
114
+ it "creates a new token if scopes do not match" do
75
115
  allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
76
116
  FactoryBot.create(:access_token, application_id: pre_auth.client.id,
77
- resource_owner_id: owner.id, scopes: '')
117
+ resource_owner_id: owner.id, scopes: "")
78
118
  expect do
79
119
  subject.authorize
80
120
  end.to change { Doorkeeper::AccessToken.count }.by(1)
81
121
  end
82
122
 
83
- it 'skips token creation if there is a matching one' do
123
+ it "skips token creation if there is a matching one reusable" do
124
+ allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
125
+ allow(application.scopes).to receive(:has_scopes?).and_return(true)
126
+ allow(application.scopes).to receive(:all?).and_return(true)
127
+
128
+ FactoryBot.create(:access_token, application_id: pre_auth.client.id,
129
+ resource_owner_id: owner.id, scopes: "public")
130
+
131
+ expect { subject.authorize }.not_to(change { Doorkeeper::AccessToken.count })
132
+ end
133
+
134
+ it "creates new token if there is a matching one but non reusable" do
84
135
  allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
85
136
  allow(application.scopes).to receive(:has_scopes?).and_return(true)
86
137
  allow(application.scopes).to receive(:all?).and_return(true)
87
138
 
88
139
  FactoryBot.create(:access_token, application_id: pre_auth.client.id,
89
- resource_owner_id: owner.id, scopes: 'public')
140
+ resource_owner_id: owner.id, scopes: "public")
141
+
142
+ allow_any_instance_of(Doorkeeper::AccessToken).to receive(:reusable?).and_return(false)
90
143
 
91
- expect { subject.authorize }.not_to change { Doorkeeper::AccessToken.count }
144
+ expect do
145
+ subject.authorize
146
+ end.to change { Doorkeeper::AccessToken.count }.by(1)
92
147
  end
93
148
  end
94
149
  end