doorkeeper 4.2.5 → 5.0.0.rc1

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 (206) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE.md +25 -0
  3. data/.github/PULL_REQUEST_TEMPLATE.md +17 -0
  4. data/.gitignore +2 -1
  5. data/.hound.yml +2 -13
  6. data/.rubocop.yml +17 -0
  7. data/.travis.yml +19 -4
  8. data/Appraisals +8 -4
  9. data/CODE_OF_CONDUCT.md +46 -0
  10. data/Gemfile +1 -1
  11. data/NEWS.md +81 -0
  12. data/README.md +169 -34
  13. data/RELEASING.md +5 -12
  14. data/Rakefile +6 -0
  15. data/SECURITY.md +15 -0
  16. data/app/assets/stylesheets/doorkeeper/admin/application.css +2 -2
  17. data/app/controllers/doorkeeper/application_controller.rb +2 -5
  18. data/app/controllers/doorkeeper/application_metal_controller.rb +4 -0
  19. data/app/controllers/doorkeeper/applications_controller.rb +47 -13
  20. data/app/controllers/doorkeeper/authorizations_controller.rb +55 -12
  21. data/app/controllers/doorkeeper/authorized_applications_controller.rb +15 -1
  22. data/app/controllers/doorkeeper/tokens_controller.rb +15 -7
  23. data/app/helpers/doorkeeper/dashboard_helper.rb +8 -6
  24. data/app/validators/redirect_uri_validator.rb +13 -2
  25. data/app/views/doorkeeper/applications/_delete_form.html.erb +3 -1
  26. data/app/views/doorkeeper/applications/_form.html.erb +31 -19
  27. data/app/views/doorkeeper/applications/edit.html.erb +1 -1
  28. data/app/views/doorkeeper/applications/index.html.erb +18 -6
  29. data/app/views/doorkeeper/applications/new.html.erb +1 -1
  30. data/app/views/doorkeeper/applications/show.html.erb +8 -5
  31. data/app/views/doorkeeper/authorizations/error.html.erb +1 -1
  32. data/app/views/doorkeeper/authorizations/new.html.erb +5 -1
  33. data/app/views/doorkeeper/authorized_applications/index.html.erb +0 -1
  34. data/app/views/layouts/doorkeeper/admin.html.erb +15 -15
  35. data/config/locales/en.yml +18 -6
  36. data/doorkeeper.gemspec +6 -6
  37. data/gemfiles/rails_4_2.gemfile +6 -4
  38. data/gemfiles/rails_5_0.gemfile +4 -4
  39. data/gemfiles/rails_5_1.gemfile +6 -7
  40. data/gemfiles/rails_5_2.gemfile +12 -0
  41. data/gemfiles/rails_master.gemfile +14 -0
  42. data/lib/doorkeeper/config.rb +107 -68
  43. data/lib/doorkeeper/engine.rb +7 -3
  44. data/lib/doorkeeper/errors.rb +20 -5
  45. data/lib/doorkeeper/grape/helpers.rb +14 -9
  46. data/lib/doorkeeper/helpers/controller.rb +16 -22
  47. data/lib/doorkeeper/models/access_grant_mixin.rb +52 -23
  48. data/lib/doorkeeper/models/access_token_mixin.rb +51 -52
  49. data/lib/doorkeeper/models/application_mixin.rb +16 -30
  50. data/lib/doorkeeper/models/concerns/expirable.rb +7 -5
  51. data/lib/doorkeeper/models/concerns/orderable.rb +13 -0
  52. data/lib/doorkeeper/models/concerns/scopes.rb +1 -1
  53. data/lib/doorkeeper/oauth/authorization/code.rb +31 -8
  54. data/lib/doorkeeper/oauth/authorization/context.rb +15 -0
  55. data/lib/doorkeeper/oauth/authorization/token.rb +41 -20
  56. data/lib/doorkeeper/oauth/authorization_code_request.rb +33 -3
  57. data/lib/doorkeeper/oauth/base_request.rb +22 -7
  58. data/lib/doorkeeper/oauth/client/credentials.rb +6 -4
  59. data/lib/doorkeeper/oauth/client.rb +2 -2
  60. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +6 -1
  61. data/lib/doorkeeper/oauth/client_credentials/validation.rb +4 -2
  62. data/lib/doorkeeper/oauth/error.rb +2 -2
  63. data/lib/doorkeeper/oauth/error_response.rb +11 -4
  64. data/lib/doorkeeper/oauth/forbidden_token_response.rb +1 -1
  65. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +0 -8
  66. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +15 -0
  67. data/lib/doorkeeper/oauth/invalid_token_response.rb +3 -4
  68. data/lib/doorkeeper/oauth/password_access_token_request.rb +8 -4
  69. data/lib/doorkeeper/oauth/pre_authorization.rb +45 -13
  70. data/lib/doorkeeper/oauth/refresh_token_request.rb +7 -1
  71. data/lib/doorkeeper/oauth/scopes.rb +19 -9
  72. data/lib/doorkeeper/oauth/token.rb +6 -3
  73. data/lib/doorkeeper/oauth/token_introspection.rb +128 -0
  74. data/lib/doorkeeper/oauth/token_response.rb +4 -2
  75. data/lib/doorkeeper/oauth.rb +13 -0
  76. data/lib/doorkeeper/orm/active_record/access_grant.rb +27 -0
  77. data/lib/doorkeeper/orm/active_record/access_token.rb +21 -20
  78. data/lib/doorkeeper/orm/active_record/application.rb +34 -0
  79. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +26 -0
  80. data/lib/doorkeeper/orm/active_record.rb +21 -8
  81. data/lib/doorkeeper/rails/helpers.rb +7 -10
  82. data/lib/doorkeeper/rails/routes.rb +21 -7
  83. data/lib/doorkeeper/rake/db.rake +40 -0
  84. data/lib/doorkeeper/rake/setup.rake +6 -0
  85. data/lib/doorkeeper/rake.rb +14 -0
  86. data/lib/doorkeeper/request/password.rb +1 -11
  87. data/lib/doorkeeper/request.rb +29 -23
  88. data/lib/doorkeeper/validations.rb +3 -2
  89. data/lib/doorkeeper/version.rb +14 -1
  90. data/lib/doorkeeper.rb +6 -17
  91. data/lib/generators/doorkeeper/application_owner_generator.rb +26 -12
  92. data/lib/generators/doorkeeper/confidential_applications_generator.rb +32 -0
  93. data/lib/generators/doorkeeper/install_generator.rb +17 -9
  94. data/lib/generators/doorkeeper/migration_generator.rb +26 -9
  95. data/lib/generators/doorkeeper/pkce_generator.rb +32 -0
  96. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +31 -20
  97. data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
  98. data/lib/generators/doorkeeper/templates/{add_owner_to_application_migration.rb → add_owner_to_application_migration.rb.erb} +1 -1
  99. data/lib/generators/doorkeeper/templates/{add_previous_refresh_token_to_access_tokens.rb → add_previous_refresh_token_to_access_tokens.rb.erb} +1 -1
  100. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +6 -0
  101. data/lib/generators/doorkeeper/templates/initializer.rb +88 -10
  102. data/lib/generators/doorkeeper/templates/{migration.rb → migration.rb.erb} +2 -1
  103. data/lib/generators/doorkeeper/views_generator.rb +3 -1
  104. data/spec/controllers/application_metal_controller_spec.rb +50 -0
  105. data/spec/controllers/applications_controller_spec.rb +141 -17
  106. data/spec/controllers/authorizations_controller_spec.rb +277 -27
  107. data/spec/controllers/protected_resources_controller_spec.rb +44 -35
  108. data/spec/controllers/token_info_controller_spec.rb +17 -21
  109. data/spec/controllers/tokens_controller_spec.rb +142 -10
  110. data/spec/dummy/app/assets/config/manifest.js +2 -0
  111. data/spec/dummy/config/environments/test.rb +4 -5
  112. data/spec/dummy/config/initializers/doorkeeper.rb +18 -1
  113. data/spec/dummy/config/initializers/{active_record_belongs_to_required_by_default.rb → new_framework_defaults.rb} +5 -1
  114. data/spec/dummy/config/initializers/secret_token.rb +0 -1
  115. data/spec/dummy/config/routes.rb +3 -42
  116. data/spec/dummy/db/migrate/20111122132257_create_users.rb +3 -1
  117. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +3 -1
  118. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +3 -1
  119. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +3 -1
  120. data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +3 -1
  121. data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +6 -0
  122. data/spec/dummy/db/migrate/20180210183654_add_confidential_to_applications.rb +13 -0
  123. data/spec/dummy/db/schema.rb +38 -37
  124. data/spec/factories.rb +1 -1
  125. data/spec/generators/application_owner_generator_spec.rb +25 -6
  126. data/spec/generators/confidential_applications_generator_spec.rb +45 -0
  127. data/spec/generators/install_generator_spec.rb +1 -1
  128. data/spec/generators/migration_generator_spec.rb +25 -4
  129. data/spec/generators/pkce_generator_spec.rb +43 -0
  130. data/spec/generators/previous_refresh_token_generator_spec.rb +57 -0
  131. data/spec/generators/views_generator_spec.rb +1 -1
  132. data/spec/grape/grape_integration_spec.rb +135 -0
  133. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +2 -2
  134. data/spec/lib/config_spec.rb +170 -22
  135. data/spec/lib/doorkeeper_spec.rb +1 -126
  136. data/spec/lib/models/expirable_spec.rb +0 -4
  137. data/spec/lib/models/revocable_spec.rb +2 -4
  138. data/spec/lib/models/scopes_spec.rb +0 -4
  139. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -4
  140. data/spec/lib/oauth/authorization_code_request_spec.rb +63 -13
  141. data/spec/lib/oauth/base_request_spec.rb +19 -10
  142. data/spec/lib/oauth/base_response_spec.rb +1 -1
  143. data/spec/lib/oauth/client/credentials_spec.rb +5 -5
  144. data/spec/lib/oauth/client_credentials/creator_spec.rb +6 -2
  145. data/spec/lib/oauth/client_credentials/issuer_spec.rb +26 -7
  146. data/spec/lib/oauth/client_credentials/validation_spec.rb +2 -3
  147. data/spec/lib/oauth/client_credentials_integration_spec.rb +2 -2
  148. data/spec/lib/oauth/client_credentials_request_spec.rb +4 -5
  149. data/spec/lib/oauth/client_spec.rb +0 -3
  150. data/spec/lib/oauth/code_request_spec.rb +5 -5
  151. data/spec/lib/oauth/error_response_spec.rb +0 -3
  152. data/spec/lib/oauth/error_spec.rb +1 -3
  153. data/spec/lib/oauth/forbidden_token_response_spec.rb +1 -4
  154. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -3
  155. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -1
  156. data/spec/lib/oauth/helpers/uri_checker_spec.rb +115 -3
  157. data/spec/lib/oauth/invalid_token_response_spec.rb +2 -5
  158. data/spec/lib/oauth/password_access_token_request_spec.rb +46 -5
  159. data/spec/lib/oauth/pre_authorization_spec.rb +40 -6
  160. data/spec/lib/oauth/refresh_token_request_spec.rb +30 -14
  161. data/spec/lib/oauth/scopes_spec.rb +28 -4
  162. data/spec/lib/oauth/token_request_spec.rb +10 -13
  163. data/spec/lib/oauth/token_response_spec.rb +0 -1
  164. data/spec/lib/oauth/token_spec.rb +37 -14
  165. data/spec/lib/orm/active_record/stale_records_cleaner_spec.rb +79 -0
  166. data/spec/lib/request/strategy_spec.rb +0 -1
  167. data/spec/lib/server_spec.rb +10 -0
  168. data/spec/models/doorkeeper/access_grant_spec.rb +2 -2
  169. data/spec/models/doorkeeper/access_token_spec.rb +118 -60
  170. data/spec/models/doorkeeper/application_spec.rb +101 -23
  171. data/spec/requests/applications/applications_request_spec.rb +94 -6
  172. data/spec/requests/applications/authorized_applications_spec.rb +1 -1
  173. data/spec/requests/endpoints/authorization_spec.rb +1 -1
  174. data/spec/requests/endpoints/token_spec.rb +15 -6
  175. data/spec/requests/flows/authorization_code_errors_spec.rb +12 -2
  176. data/spec/requests/flows/authorization_code_spec.rb +198 -1
  177. data/spec/requests/flows/client_credentials_spec.rb +73 -5
  178. data/spec/requests/flows/implicit_grant_errors_spec.rb +3 -3
  179. data/spec/requests/flows/implicit_grant_spec.rb +38 -11
  180. data/spec/requests/flows/password_spec.rb +160 -24
  181. data/spec/requests/flows/refresh_token_spec.rb +6 -6
  182. data/spec/requests/flows/revoke_token_spec.rb +26 -26
  183. data/spec/requests/flows/skip_authorization_spec.rb +16 -11
  184. data/spec/requests/protected_resources/metal_spec.rb +2 -2
  185. data/spec/requests/protected_resources/private_api_spec.rb +2 -2
  186. data/spec/routing/custom_controller_routes_spec.rb +63 -7
  187. data/spec/routing/default_routes_spec.rb +6 -2
  188. data/spec/routing/scoped_routes_spec.rb +16 -2
  189. data/spec/spec_helper.rb +54 -3
  190. data/spec/spec_helper_integration.rb +2 -64
  191. data/spec/support/dependencies/factory_bot.rb +2 -0
  192. data/spec/support/doorkeeper_rspec.rb +19 -0
  193. data/spec/support/helpers/access_token_request_helper.rb +1 -1
  194. data/spec/support/helpers/authorization_request_helper.rb +4 -4
  195. data/spec/support/helpers/model_helper.rb +9 -4
  196. data/spec/support/helpers/request_spec_helper.rb +10 -6
  197. data/spec/support/helpers/url_helper.rb +15 -10
  198. data/spec/support/http_method_shim.rb +12 -16
  199. data/spec/support/shared/controllers_shared_context.rb +2 -6
  200. data/spec/support/shared/models_shared_examples.rb +4 -4
  201. data/spec/validators/redirect_uri_validator_spec.rb +58 -7
  202. data/spec/version/version_spec.rb +15 -0
  203. data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
  204. metadata +74 -34
  205. data/spec/controllers/application_metal_controller.rb +0 -10
  206. data/spec/support/dependencies/factory_girl.rb +0 -2
@@ -1,6 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'uri'
3
- require 'doorkeeper/oauth/helpers/uri_checker'
4
2
 
5
3
  module Doorkeeper::OAuth::Helpers
6
4
  describe URIChecker do
@@ -39,6 +37,16 @@ module Doorkeeper::OAuth::Helpers
39
37
  uri = 'http://'
40
38
  expect(URIChecker.valid?(uri)).to be_falsey
41
39
  end
40
+
41
+ it 'is invalid if is not an uri' do
42
+ uri = ' '
43
+ expect(URIChecker.valid?(uri)).to be_falsey
44
+ end
45
+
46
+ it 'is valid for native uris' do
47
+ uri = 'urn:ietf:wg:oauth:2.0:oob'
48
+ expect(URIChecker.valid?(uri)).to be_truthy
49
+ end
42
50
  end
43
51
 
44
52
  describe '.matches?' do
@@ -64,6 +72,44 @@ module Doorkeeper::OAuth::Helpers
64
72
  client_uri = 'http://example.com?app.co=test'
65
73
  expect(URIChecker.matches?(uri, client_uri)).to be_falsey
66
74
  end
75
+
76
+ context "client registered query params" do
77
+ it "doesn't allow query being absent" do
78
+ uri = 'http://app.co'
79
+ client_uri = 'http://app.co/?vendorId=AJ4L7XXW9'
80
+ expect(URIChecker.matches?(uri, client_uri)).to be_falsey
81
+ end
82
+
83
+ it "is false if query values differ but key same" do
84
+ uri = 'http://app.co/?vendorId=pancakes'
85
+ client_uri = 'http://app.co/?vendorId=waffles'
86
+ expect(URIChecker.matches?(uri, client_uri)).to be_falsey
87
+ end
88
+
89
+ it "is false if query values same but key differs" do
90
+ uri = 'http://app.co/?foo=pancakes'
91
+ client_uri = 'http://app.co/?bar=pancakes'
92
+ expect(URIChecker.matches?(uri, client_uri)).to be_falsey
93
+ end
94
+
95
+ it "is false if query present and match, but unknown queries present" do
96
+ uri = 'http://app.co/?vendorId=pancakes&unknown=query'
97
+ client_uri = 'http://app.co/?vendorId=waffles'
98
+ expect(URIChecker.matches?(uri, client_uri)).to be_falsey
99
+ end
100
+
101
+ it "is true if queries are present and matche" do
102
+ uri = 'http://app.co/?vendorId=AJ4L7XXW9&foo=bar'
103
+ client_uri = 'http://app.co/?vendorId=AJ4L7XXW9&foo=bar'
104
+ expect(URIChecker.matches?(uri, client_uri)).to be_truthy
105
+ end
106
+
107
+ it "is true if queries are present, match and in different order" do
108
+ uri = 'http://app.co/?bing=bang&foo=bar'
109
+ client_uri = 'http://app.co/?foo=bar&bing=bang'
110
+ expect(URIChecker.matches?(uri, client_uri)).to be_truthy
111
+ end
112
+ end
67
113
  end
68
114
 
69
115
  describe '.valid_for_authorization?' do
@@ -96,9 +142,75 @@ module Doorkeeper::OAuth::Helpers
96
142
  end
97
143
 
98
144
  it 'is false if invalid' do
99
- uri = client_uri = 'http://app.co/aaa?waffles=abc'
145
+ uri = 'http://app.co/aaa?pankcakes=abc'
146
+ client_uri = 'http://app.co/aaa?waffles=abc'
100
147
  expect(URIChecker.valid_for_authorization?(uri, client_uri)).to be false
101
148
  end
149
+
150
+ it 'calls .matches?' do
151
+ uri = 'http://app.co/aaa?pankcakes=abc'
152
+ client_uri = 'http://app.co/aaa?waffles=abc'
153
+ expect(URIChecker).to receive(:matches?).with(uri, client_uri).once
154
+ URIChecker.valid_for_authorization?(uri, client_uri)
155
+ end
156
+
157
+ it 'calls .valid?' do
158
+ uri = 'http://app.co/aaa?pankcakes=abc'
159
+ client_uri = 'http://app.co/aaa?waffles=abc'
160
+ expect(URIChecker).to receive(:valid?).with(uri).once
161
+ URIChecker.valid_for_authorization?(uri, client_uri)
162
+ end
163
+ end
164
+
165
+ describe '.query_matches?' do
166
+ it 'is true if no queries' do
167
+ expect(URIChecker.query_matches?('', '')).to be_truthy
168
+ expect(URIChecker.query_matches?(nil, nil)).to be_truthy
169
+ end
170
+
171
+ it 'is true if same query' do
172
+ expect(URIChecker.query_matches?('foo', 'foo')).to be_truthy
173
+ end
174
+
175
+ it 'is false if different query' do
176
+ expect(URIChecker.query_matches?('foo', 'bar')).to be_falsey
177
+ end
178
+
179
+ it 'is true if same queries' do
180
+ expect(URIChecker.query_matches?('foo&bar', 'foo&bar')).to be_truthy
181
+ end
182
+
183
+ it 'is true if same queries, different order' do
184
+ expect(URIChecker.query_matches?('foo&bar', 'bar&foo')).to be_truthy
185
+ end
186
+
187
+ it 'is false if one different query' do
188
+ expect(URIChecker.query_matches?('foo&bang', 'foo&bing')).to be_falsey
189
+ end
190
+
191
+ it 'is true if same query with same value' do
192
+ expect(URIChecker.query_matches?('foo=bar', 'foo=bar')).to be_truthy
193
+ end
194
+
195
+ it 'is true if same queries with same values' do
196
+ expect(URIChecker.query_matches?('foo=bar&bing=bang', 'foo=bar&bing=bang')).to be_truthy
197
+ end
198
+
199
+ it 'is true if same queries with same values, different order' do
200
+ expect(URIChecker.query_matches?('foo=bar&bing=bang', 'bing=bang&foo=bar')).to be_truthy
201
+ end
202
+
203
+ it 'is false if same query with different value' do
204
+ expect(URIChecker.query_matches?('foo=bar', 'foo=bang')).to be_falsey
205
+ end
206
+
207
+ it 'is false if some queries missing' do
208
+ expect(URIChecker.query_matches?('foo=bar', 'foo=bar&bing=bang')).to be_falsey
209
+ end
210
+
211
+ it 'is false if some queries different value' do
212
+ expect(URIChecker.query_matches?('foo=bar&bing=bang', 'foo=bar&bing=banana')).to be_falsey
213
+ end
102
214
  end
103
215
  end
104
216
  end
@@ -1,12 +1,9 @@
1
1
  require 'spec_helper'
2
- require 'active_model'
3
- require 'doorkeeper'
4
- require 'doorkeeper/oauth/invalid_token_response'
5
2
 
6
3
  module Doorkeeper::OAuth
7
4
  describe InvalidTokenResponse do
8
5
  describe "#name" do
9
- it { expect(subject.name).to eq(:invalid_token) }
6
+ it { expect(subject.name).to eq(:invalid_token) }
10
7
  end
11
8
 
12
9
  describe "#status" do
@@ -40,7 +37,7 @@ module Doorkeeper::OAuth
40
37
  end
41
38
  end
42
39
 
43
- context "unkown" do
40
+ context "unknown" do
44
41
  let(:access_token) { double(revoked?: false, expired?: false) }
45
42
 
46
43
  it "sets a description" do
@@ -1,4 +1,4 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  module Doorkeeper::OAuth
4
4
  describe PasswordAccessTokenRequest do
@@ -8,10 +8,12 @@ module Doorkeeper::OAuth
8
8
  default_scopes: Doorkeeper::OAuth::Scopes.new,
9
9
  access_token_expires_in: 2.hours,
10
10
  refresh_token_enabled?: false,
11
- custom_access_token_expires_in: ->(_app) { nil }
11
+ custom_access_token_expires_in: lambda { |context|
12
+ context.grant_type == Doorkeeper::OAuth::PASSWORD ? 1234 : nil
13
+ }
12
14
  )
13
15
  end
14
- let(:client) { FactoryGirl.create(:application) }
16
+ let(:client) { FactoryBot.create(:application) }
15
17
  let(:owner) { double :owner, id: 99 }
16
18
 
17
19
  subject do
@@ -22,6 +24,7 @@ module Doorkeeper::OAuth
22
24
  expect do
23
25
  subject.authorize
24
26
  end.to change { client.reload.access_tokens.count }.by(1)
27
+ expect(client.reload.access_tokens.sort_by(&:created_at).last.expires_in).to eq(1234)
25
28
  end
26
29
 
27
30
  it 'issues a new token without a client' do
@@ -53,7 +56,7 @@ module Doorkeeper::OAuth
53
56
  end
54
57
 
55
58
  it 'creates token even when there is already one (default)' do
56
- FactoryGirl.create(:access_token, application_id: client.id, resource_owner_id: owner.id)
59
+ FactoryBot.create(:access_token, application_id: client.id, resource_owner_id: owner.id)
57
60
  expect do
58
61
  subject.authorize
59
62
  end.to change { Doorkeeper::AccessToken.count }.by(1)
@@ -61,12 +64,18 @@ module Doorkeeper::OAuth
61
64
 
62
65
  it 'skips token creation if there is already one' do
63
66
  allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
64
- FactoryGirl.create(:access_token, application_id: client.id, resource_owner_id: owner.id)
67
+ FactoryBot.create(:access_token, application_id: client.id, resource_owner_id: owner.id)
65
68
  expect do
66
69
  subject.authorize
67
70
  end.to_not change { Doorkeeper::AccessToken.count }
68
71
  end
69
72
 
73
+ it "calls configured request callback methods" do
74
+ expect(Doorkeeper.configuration.before_successful_strategy_response).to receive(:call).with(subject).once
75
+ expect(Doorkeeper.configuration.after_successful_strategy_response).to receive(:call).with(subject, instance_of(Doorkeeper::OAuth::TokenResponse)).once
76
+ subject.authorize
77
+ end
78
+
70
79
  describe 'with scopes' do
71
80
  subject do
72
81
  PasswordAccessTokenRequest.new(server, client, owner, scope: 'public')
@@ -86,5 +95,37 @@ module Doorkeeper::OAuth
86
95
  expect(Doorkeeper::AccessToken.last.scopes).to include('public')
87
96
  end
88
97
  end
98
+
99
+ describe 'with custom expiry' do
100
+ let(:server) do
101
+ double(
102
+ :server,
103
+ default_scopes: Doorkeeper::OAuth::Scopes.new,
104
+ access_token_expires_in: 2.hours,
105
+ refresh_token_enabled?: false,
106
+ custom_access_token_expires_in: lambda { |context|
107
+ context.scopes.exists?('public') ? 222 : nil
108
+ }
109
+ )
110
+ end
111
+
112
+ it 'checks scopes' do
113
+ subject = PasswordAccessTokenRequest.new(server, client, owner, scope: 'public')
114
+ allow(server).to receive(:scopes).and_return(Doorkeeper::OAuth::Scopes.from_string('public'))
115
+ expect do
116
+ subject.authorize
117
+ end.to change { Doorkeeper::AccessToken.count }.by(1)
118
+ expect(Doorkeeper::AccessToken.last.expires_in).to eq(222)
119
+ end
120
+
121
+ it 'falls back to the default otherwise' do
122
+ subject = PasswordAccessTokenRequest.new(server, client, owner, scope: 'private')
123
+ allow(server).to receive(:scopes).and_return(Doorkeeper::OAuth::Scopes.from_string('private'))
124
+ expect do
125
+ subject.authorize
126
+ end.to change { Doorkeeper::AccessToken.count }.by(1)
127
+ expect(Doorkeeper::AccessToken.last.expires_in).to eq(2.hours)
128
+ end
129
+ end
89
130
  end
90
131
  end
@@ -1,13 +1,13 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  module Doorkeeper::OAuth
4
4
  describe PreAuthorization do
5
- let(:server) {
5
+ let(:server) do
6
6
  server = Doorkeeper.configuration
7
7
  allow(server).to receive(:default_scopes).and_return(Scopes.new)
8
8
  allow(server).to receive(:scopes).and_return(Scopes.from_string('public profile'))
9
9
  server
10
- }
10
+ end
11
11
 
12
12
  let(:application) do
13
13
  application = double :application
@@ -123,9 +123,19 @@ module Doorkeeper::OAuth
123
123
  expect(subject.scopes).to eq(Scopes.from_string('default'))
124
124
  end
125
125
 
126
- it 'accepts test uri' do
127
- subject.redirect_uri = 'urn:ietf:wg:oauth:2.0:oob'
128
- expect(subject).to be_authorizable
126
+ context 'with native redirect uri' do
127
+ let(:native_redirect_uri) { 'urn:ietf:wg:oauth:2.0:oob' }
128
+
129
+ it 'accepts redirect_uri when it matches with the client' do
130
+ subject.redirect_uri = native_redirect_uri
131
+ allow(subject.client).to receive(:redirect_uri) { native_redirect_uri }
132
+ expect(subject).to be_authorizable
133
+ end
134
+
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'
137
+ expect(subject).not_to be_authorizable
138
+ end
129
139
  end
130
140
 
131
141
  it 'matches the redirect uri against client\'s one' do
@@ -151,5 +161,29 @@ module Doorkeeper::OAuth
151
161
  subject.redirect_uri = nil
152
162
  expect(subject).not_to be_authorizable
153
163
  end
164
+
165
+ describe "as_json" do
166
+ let(:client_id) { "client_uid_123" }
167
+ let(:client_name) { "Acme Co." }
168
+
169
+ before do
170
+ allow(client).to receive(:uid).and_return client_id
171
+ allow(client).to receive(:name).and_return client_name
172
+ end
173
+
174
+ let(:json) { subject.as_json({}) }
175
+
176
+ it { is_expected.to respond_to :as_json }
177
+
178
+ it "returns correct values" do
179
+ expect(json[:client_id]).to eq client_id
180
+ expect(json[:redirect_uri]).to eq subject.redirect_uri
181
+ expect(json[:state]).to eq subject.state
182
+ expect(json[:response_type]).to eq subject.response_type
183
+ expect(json[:scope]).to eq subject.scope
184
+ expect(json[:client_name]).to eq client_name
185
+ expect(json[:status]).to eq I18n.t('doorkeeper.pre_authorization.status')
186
+ end
187
+ end
154
188
  end
155
189
  end
@@ -1,18 +1,21 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  module Doorkeeper::OAuth
4
4
  describe RefreshTokenRequest do
5
5
  before do
6
6
  allow(Doorkeeper::AccessToken).to receive(:refresh_token_revoked_on_use?).and_return(false)
7
7
  end
8
+
8
9
  let(:server) do
9
10
  double :server,
10
11
  access_token_expires_in: 2.minutes,
11
- custom_access_token_expires_in: -> (_oauth_client) { nil }
12
+ custom_access_token_expires_in: ->(_context) { nil }
12
13
  end
14
+
13
15
  let(:refresh_token) do
14
- FactoryGirl.create(:access_token, use_refresh_token: true)
16
+ FactoryBot.create(:access_token, use_refresh_token: true)
15
17
  end
18
+
16
19
  let(:client) { refresh_token.application }
17
20
  let(:credentials) { Client::Credentials.new(client.uid, client.secret) }
18
21
 
@@ -20,25 +23,35 @@ module Doorkeeper::OAuth
20
23
 
21
24
  it 'issues a new token for the client' do
22
25
  expect { subject.authorize }.to change { client.reload.access_tokens.count }.by(1)
23
- expect(client.reload.access_tokens.last.expires_in).to eq(120)
26
+ # #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)
24
28
  end
25
29
 
26
30
  it 'issues a new token for the client with custom expires_in' do
27
31
  server = double :server,
28
32
  access_token_expires_in: 2.minutes,
29
- custom_access_token_expires_in: ->(_oauth_client) { 1234 }
33
+ custom_access_token_expires_in: lambda { |context|
34
+ context.grant_type == Doorkeeper::OAuth::REFRESH_TOKEN ? 1234 : nil
35
+ }
30
36
 
31
37
  allow(Doorkeeper::AccessToken).to receive(:refresh_token_revoked_on_use?).and_return(false)
32
38
 
33
39
  RefreshTokenRequest.new(server, refresh_token, credentials).authorize
34
40
 
35
- expect(client.reload.access_tokens.last.expires_in).to eq(1234)
41
+ # #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)
36
43
  end
37
44
 
38
45
  it 'revokes the previous token' do
39
46
  expect { subject.authorize }.to change { refresh_token.revoked? }.from(false).to(true)
40
47
  end
41
48
 
49
+ 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
52
+ subject.authorize
53
+ end
54
+
42
55
  it 'requires the refresh token' do
43
56
  subject.refresh_token = nil
44
57
  subject.validate
@@ -52,7 +65,7 @@ module Doorkeeper::OAuth
52
65
  end
53
66
 
54
67
  it "requires the token's client and current client to match" do
55
- subject.client = FactoryGirl.create(:application)
68
+ subject.client = FactoryBot.create(:application)
56
69
  subject.validate
57
70
  expect(subject.error).to eq(:invalid_grant)
58
71
  end
@@ -74,7 +87,9 @@ module Doorkeeper::OAuth
74
87
  let(:server) do
75
88
  double :server,
76
89
  access_token_expires_in: 2.minutes,
77
- custom_access_token_expires_in: ->(_oauth_client) { 1234 }
90
+ custom_access_token_expires_in: lambda { |context|
91
+ context.grant_type == Doorkeeper::OAuth::REFRESH_TOKEN ? 1234 : nil
92
+ }
78
93
  end
79
94
 
80
95
  before do
@@ -93,13 +108,14 @@ module Doorkeeper::OAuth
93
108
  it 'sets the previous refresh token in the new access token' do
94
109
  subject.authorize
95
110
  expect(
96
- client.access_tokens.last.previous_refresh_token
111
+ # #sort_by used for MongoDB ORM extensions for valid ordering
112
+ client.access_tokens.sort_by(&:created_at).last.previous_refresh_token
97
113
  ).to eq(refresh_token.refresh_token)
98
114
  end
99
115
  end
100
116
 
101
117
  context 'clientless access tokens' do
102
- let!(:refresh_token) { FactoryGirl.create(:clientless_access_token, use_refresh_token: true) }
118
+ let!(:refresh_token) { FactoryBot.create(:clientless_access_token, use_refresh_token: true) }
103
119
 
104
120
  subject { RefreshTokenRequest.new server, refresh_token, nil }
105
121
 
@@ -110,7 +126,7 @@ module Doorkeeper::OAuth
110
126
 
111
127
  context 'with scopes' do
112
128
  let(:refresh_token) do
113
- FactoryGirl.create :access_token,
129
+ FactoryBot.create :access_token,
114
130
  use_refresh_token: true,
115
131
  scopes: 'public write'
116
132
  end
@@ -119,13 +135,13 @@ module Doorkeeper::OAuth
119
135
 
120
136
  it 'transfers scopes from the old token to the new token' do
121
137
  subject.authorize
122
- expect(Doorkeeper::AccessToken.last.scopes).to eq([:public, :write])
138
+ expect(Doorkeeper::AccessToken.last.scopes).to eq(%i[public write])
123
139
  end
124
140
 
125
141
  it 'reduces scopes to the provided scopes' do
126
142
  parameters[:scopes] = 'public'
127
143
  subject.authorize
128
- expect(Doorkeeper::AccessToken.last.scopes).to eq([:public])
144
+ expect(Doorkeeper::AccessToken.last.scopes).to eq(%i[public])
129
145
  end
130
146
 
131
147
  it 'validates that scopes are included in the original access token' do
@@ -139,7 +155,7 @@ module Doorkeeper::OAuth
139
155
  parameters[:scopes] = 'public update'
140
156
  parameters[:scope] = 'public'
141
157
  subject.authorize
142
- expect(Doorkeeper::AccessToken.last.scopes).to eq([:public])
158
+ expect(Doorkeeper::AccessToken.last.scopes).to eq(%i[public])
143
159
  end
144
160
 
145
161
  it 'uses params[:scope] in favor of scopes if present (invalid)' do
@@ -1,7 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'active_support/core_ext/module/delegation'
3
- require 'active_support/core_ext/string'
4
- require 'doorkeeper/oauth/scopes'
5
2
 
6
3
  module Doorkeeper::OAuth
7
4
  describe Scopes do
@@ -62,7 +59,7 @@ module Doorkeeper::OAuth
62
59
  describe '#+' do
63
60
  it 'can add to another scope object' do
64
61
  scopes = Scopes.from_string('public') + Scopes.from_string('admin')
65
- expect(scopes.all).to eq(%w(public admin))
62
+ expect(scopes.all).to eq(%w[public admin])
66
63
  end
67
64
 
68
65
  it 'does not change the existing object' do
@@ -70,6 +67,11 @@ module Doorkeeper::OAuth
70
67
  expect(origin.to_s).to eq('public')
71
68
  end
72
69
 
70
+ it 'can add an array to a scope object' do
71
+ scopes = Scopes.from_string('public') + ['admin']
72
+ expect(scopes.all).to eq(%w[public admin])
73
+ end
74
+
73
75
  it 'raises an error if cannot handle addition' do
74
76
  expect do
75
77
  Scopes.from_string('public') + 'admin'
@@ -77,6 +79,24 @@ module Doorkeeper::OAuth
77
79
  end
78
80
  end
79
81
 
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')
85
+ expect(scopes.all).to eq(%w[admin])
86
+ end
87
+
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')
92
+ end
93
+
94
+ it 'can get intersection with an array' do
95
+ scopes = Scopes.from_string('public admin') & %w[write admin]
96
+ expect(scopes.all).to eq(%w[admin])
97
+ end
98
+ end
99
+
80
100
  describe '#==' do
81
101
  it 'is equal to another set of scopes' do
82
102
  expect(Scopes.from_string('public')).to eq(Scopes.from_string('public'))
@@ -89,6 +109,10 @@ module Doorkeeper::OAuth
89
109
  it 'differs from another set of scopes when scopes are not the same' do
90
110
  expect(Scopes.from_string('public write')).not_to eq(Scopes.from_string('write'))
91
111
  end
112
+
113
+ it "does not raise an error when compared to a non-enumerable object" do
114
+ expect { Scopes.from_string("public") == false }.not_to raise_error
115
+ end
92
116
  end
93
117
 
94
118
  describe '#has_scopes?' do
@@ -1,11 +1,11 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  module Doorkeeper::OAuth
4
4
  describe TokenRequest do
5
5
  let :application do
6
- scopes = double(all: ['public'])
7
- double(:application, id: 9990, scopes: scopes)
6
+ FactoryBot.create(:application, scopes: "public")
8
7
  end
8
+
9
9
  let :pre_auth do
10
10
  double(
11
11
  :pre_auth,
@@ -38,9 +38,7 @@ module Doorkeeper::OAuth
38
38
 
39
39
  it 'does not create token when not authorizable' do
40
40
  allow(pre_auth).to receive(:authorizable?).and_return(false)
41
- expect do
42
- subject.authorize
43
- end.to_not change { Doorkeeper::AccessToken.count }
41
+ expect { subject.authorize }.not_to change { Doorkeeper::AccessToken.count }
44
42
  end
45
43
 
46
44
  it 'returns a error response' do
@@ -52,8 +50,8 @@ module Doorkeeper::OAuth
52
50
  before do
53
51
  Doorkeeper.configure do
54
52
  orm DOORKEEPER_ORM
55
- custom_access_token_expires_in do |_oauth_client|
56
- 1234
53
+ custom_access_token_expires_in do |context|
54
+ context.grant_type == Doorkeeper::OAuth::IMPLICIT ? 1234 : nil
57
55
  end
58
56
  end
59
57
  end
@@ -75,7 +73,7 @@ module Doorkeeper::OAuth
75
73
 
76
74
  it 'creates a new token if scopes do not match' do
77
75
  allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
78
- FactoryGirl.create(:access_token, application_id: pre_auth.client.id,
76
+ FactoryBot.create(:access_token, application_id: pre_auth.client.id,
79
77
  resource_owner_id: owner.id, scopes: '')
80
78
  expect do
81
79
  subject.authorize
@@ -86,12 +84,11 @@ module Doorkeeper::OAuth
86
84
  allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
87
85
  allow(application.scopes).to receive(:has_scopes?).and_return(true)
88
86
  allow(application.scopes).to receive(:all?).and_return(true)
89
- FactoryGirl.create(:access_token, application_id: pre_auth.client.id,
87
+
88
+ FactoryBot.create(:access_token, application_id: pre_auth.client.id,
90
89
  resource_owner_id: owner.id, scopes: 'public')
91
90
 
92
- expect do
93
- subject.authorize
94
- end.to_not change { Doorkeeper::AccessToken.count }
91
+ expect { subject.authorize }.not_to change { Doorkeeper::AccessToken.count }
95
92
  end
96
93
  end
97
94
  end
@@ -1,5 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'doorkeeper/oauth/token_response'
3
2
 
4
3
  module Doorkeeper::OAuth
5
4
  describe TokenResponse do
@@ -1,6 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'active_support/core_ext/string'
3
- require 'doorkeeper/oauth/token'
4
2
 
5
3
  module Doorkeeper
6
4
  unless defined?(AccessToken)
@@ -14,7 +12,7 @@ module Doorkeeper
14
12
  let(:request) { double.as_null_object }
15
13
 
16
14
  let(:method) do
17
- ->(request) { return 'token-value' }
15
+ ->(*) { 'token-value' }
18
16
  end
19
17
 
20
18
  it 'accepts anything that responds to #call' do
@@ -96,19 +94,44 @@ module Doorkeeper
96
94
  end
97
95
 
98
96
  describe :authenticate do
99
- it 'calls the finder if token was returned' do
100
- token = ->(_r) { 'token' }
101
- expect(AccessToken).to receive(:by_token).with('token')
102
- Token.authenticate double, token
97
+ context 'refresh tokens are disabled (default)' do
98
+ context 'refresh tokens are enabled' do
99
+ it 'does not revoke previous refresh_token if token was found' do
100
+ token = ->(_r) { 'token' }
101
+ expect(
102
+ AccessToken
103
+ ).to receive(:by_token).with('token').and_return(token)
104
+ expect(token).not_to receive(:revoke_previous_refresh_token!)
105
+ Token.authenticate double, token
106
+ end
107
+ end
108
+
109
+ it 'calls the finder if token was returned' do
110
+ token = ->(_r) { 'token' }
111
+ expect(AccessToken).to receive(:by_token).with('token')
112
+ Token.authenticate double, token
113
+ end
103
114
  end
104
115
 
105
- it 'revokes previous refresh_token if token was found' do
106
- token = ->(_r) { 'token' }
107
- expect(
108
- AccessToken
109
- ).to receive(:by_token).with('token').and_return(token)
110
- expect(token).to receive(:revoke_previous_refresh_token!)
111
- Token.authenticate double, token
116
+ context 'refresh tokens are enabled' do
117
+ before do
118
+ Doorkeeper.configure { use_refresh_token }
119
+ end
120
+
121
+ it 'revokes previous refresh_token if token was found' do
122
+ token = ->(_r) { 'token' }
123
+ expect(
124
+ AccessToken
125
+ ).to receive(:by_token).with('token').and_return(token)
126
+ expect(token).to receive(:revoke_previous_refresh_token!)
127
+ Token.authenticate double, token
128
+ end
129
+
130
+ it 'calls the finder if token was returned' do
131
+ token = ->(_r) { 'token' }
132
+ expect(AccessToken).to receive(:by_token).with('token')
133
+ Token.authenticate double, token
134
+ end
112
135
  end
113
136
  end
114
137
  end