doorkeeper 4.2.5 → 5.0.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/.github/ISSUE_TEMPLATE.md +25 -0
  3. data/.github/PULL_REQUEST_TEMPLATE.md +17 -0
  4. data/.gitignore +2 -1
  5. data/.gitlab-ci.yml +16 -0
  6. data/.hound.yml +2 -13
  7. data/.rubocop.yml +17 -0
  8. data/.travis.yml +19 -4
  9. data/Appraisals +8 -4
  10. data/CODE_OF_CONDUCT.md +46 -0
  11. data/Gemfile +1 -1
  12. data/NEWS.md +115 -0
  13. data/README.md +175 -39
  14. data/RELEASING.md +5 -12
  15. data/Rakefile +6 -0
  16. data/SECURITY.md +15 -0
  17. data/UPGRADE.md +2 -0
  18. data/app/assets/stylesheets/doorkeeper/admin/application.css +2 -2
  19. data/app/controllers/doorkeeper/application_controller.rb +2 -5
  20. data/app/controllers/doorkeeper/application_metal_controller.rb +4 -0
  21. data/app/controllers/doorkeeper/applications_controller.rb +47 -13
  22. data/app/controllers/doorkeeper/authorizations_controller.rb +55 -12
  23. data/app/controllers/doorkeeper/authorized_applications_controller.rb +19 -2
  24. data/app/controllers/doorkeeper/tokens_controller.rb +24 -17
  25. data/app/helpers/doorkeeper/dashboard_helper.rb +8 -6
  26. data/app/validators/redirect_uri_validator.rb +13 -2
  27. data/app/views/doorkeeper/applications/_delete_form.html.erb +3 -1
  28. data/app/views/doorkeeper/applications/_form.html.erb +31 -19
  29. data/app/views/doorkeeper/applications/edit.html.erb +1 -1
  30. data/app/views/doorkeeper/applications/index.html.erb +18 -6
  31. data/app/views/doorkeeper/applications/new.html.erb +1 -1
  32. data/app/views/doorkeeper/applications/show.html.erb +8 -5
  33. data/app/views/doorkeeper/authorizations/error.html.erb +1 -1
  34. data/app/views/doorkeeper/authorizations/new.html.erb +5 -1
  35. data/app/views/doorkeeper/authorized_applications/index.html.erb +0 -1
  36. data/app/views/layouts/doorkeeper/admin.html.erb +15 -15
  37. data/config/locales/en.yml +19 -6
  38. data/doorkeeper.gemspec +20 -20
  39. data/gemfiles/rails_4_2.gemfile +6 -4
  40. data/gemfiles/rails_5_0.gemfile +4 -4
  41. data/gemfiles/rails_5_1.gemfile +6 -7
  42. data/gemfiles/rails_5_2.gemfile +12 -0
  43. data/gemfiles/rails_master.gemfile +17 -0
  44. data/lib/doorkeeper/config.rb +123 -71
  45. data/lib/doorkeeper/engine.rb +7 -3
  46. data/lib/doorkeeper/errors.rb +20 -5
  47. data/lib/doorkeeper/grape/helpers.rb +14 -9
  48. data/lib/doorkeeper/helpers/controller.rb +16 -22
  49. data/lib/doorkeeper/models/access_grant_mixin.rb +67 -23
  50. data/lib/doorkeeper/models/access_token_mixin.rb +54 -55
  51. data/lib/doorkeeper/models/application_mixin.rb +16 -30
  52. data/lib/doorkeeper/models/concerns/expirable.rb +7 -5
  53. data/lib/doorkeeper/models/concerns/orderable.rb +13 -0
  54. data/lib/doorkeeper/models/concerns/scopes.rb +1 -1
  55. data/lib/doorkeeper/oauth/authorization/code.rb +31 -8
  56. data/lib/doorkeeper/oauth/authorization/context.rb +15 -0
  57. data/lib/doorkeeper/oauth/authorization/token.rb +46 -20
  58. data/lib/doorkeeper/oauth/authorization_code_request.rb +33 -3
  59. data/lib/doorkeeper/oauth/base_request.rb +23 -7
  60. data/lib/doorkeeper/oauth/client/credentials.rb +6 -4
  61. data/lib/doorkeeper/oauth/client.rb +2 -4
  62. data/lib/doorkeeper/oauth/client_credentials/creator.rb +2 -1
  63. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +6 -3
  64. data/lib/doorkeeper/oauth/client_credentials/validation.rb +4 -6
  65. data/lib/doorkeeper/oauth/client_credentials_request.rb +0 -4
  66. data/lib/doorkeeper/oauth/error.rb +2 -2
  67. data/lib/doorkeeper/oauth/error_response.rb +11 -4
  68. data/lib/doorkeeper/oauth/forbidden_token_response.rb +1 -1
  69. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +0 -8
  70. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +15 -0
  71. data/lib/doorkeeper/oauth/invalid_token_response.rb +3 -4
  72. data/lib/doorkeeper/oauth/password_access_token_request.rb +8 -4
  73. data/lib/doorkeeper/oauth/pre_authorization.rb +45 -13
  74. data/lib/doorkeeper/oauth/refresh_token_request.rb +7 -1
  75. data/lib/doorkeeper/oauth/scopes.rb +19 -9
  76. data/lib/doorkeeper/oauth/token.rb +6 -3
  77. data/lib/doorkeeper/oauth/token_introspection.rb +128 -0
  78. data/lib/doorkeeper/oauth/token_response.rb +4 -2
  79. data/lib/doorkeeper/oauth.rb +13 -0
  80. data/lib/doorkeeper/orm/active_record/access_grant.rb +27 -0
  81. data/lib/doorkeeper/orm/active_record/access_token.rb +21 -20
  82. data/lib/doorkeeper/orm/active_record/application.rb +45 -0
  83. data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +26 -0
  84. data/lib/doorkeeper/orm/active_record.rb +21 -8
  85. data/lib/doorkeeper/rails/helpers.rb +7 -10
  86. data/lib/doorkeeper/rails/routes.rb +21 -7
  87. data/lib/doorkeeper/rake/db.rake +40 -0
  88. data/lib/doorkeeper/rake/setup.rake +6 -0
  89. data/lib/doorkeeper/rake.rb +14 -0
  90. data/lib/doorkeeper/request/authorization_code.rb +0 -2
  91. data/lib/doorkeeper/request/client_credentials.rb +0 -2
  92. data/lib/doorkeeper/request/code.rb +0 -2
  93. data/lib/doorkeeper/request/password.rb +1 -13
  94. data/lib/doorkeeper/request/refresh_token.rb +0 -2
  95. data/lib/doorkeeper/request/token.rb +0 -2
  96. data/lib/doorkeeper/request.rb +29 -30
  97. data/lib/doorkeeper/validations.rb +3 -2
  98. data/lib/doorkeeper/version.rb +14 -1
  99. data/lib/doorkeeper.rb +21 -17
  100. data/lib/generators/doorkeeper/application_owner_generator.rb +26 -12
  101. data/lib/generators/doorkeeper/confidential_applications_generator.rb +32 -0
  102. data/lib/generators/doorkeeper/install_generator.rb +17 -9
  103. data/lib/generators/doorkeeper/migration_generator.rb +26 -9
  104. data/lib/generators/doorkeeper/pkce_generator.rb +32 -0
  105. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +31 -20
  106. data/lib/generators/doorkeeper/templates/add_confidential_to_applications.rb.erb +13 -0
  107. data/lib/generators/doorkeeper/templates/{add_owner_to_application_migration.rb → add_owner_to_application_migration.rb.erb} +1 -1
  108. data/lib/generators/doorkeeper/templates/{add_previous_refresh_token_to_access_tokens.rb → add_previous_refresh_token_to_access_tokens.rb.erb} +1 -1
  109. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +6 -0
  110. data/lib/generators/doorkeeper/templates/initializer.rb +104 -12
  111. data/lib/generators/doorkeeper/templates/{migration.rb → migration.rb.erb} +2 -1
  112. data/lib/generators/doorkeeper/views_generator.rb +3 -1
  113. data/spec/controllers/application_metal_controller_spec.rb +50 -0
  114. data/spec/controllers/applications_controller_spec.rb +141 -17
  115. data/spec/controllers/authorizations_controller_spec.rb +304 -27
  116. data/spec/controllers/protected_resources_controller_spec.rb +44 -35
  117. data/spec/controllers/token_info_controller_spec.rb +17 -21
  118. data/spec/controllers/tokens_controller_spec.rb +201 -17
  119. data/spec/dummy/app/assets/config/manifest.js +2 -0
  120. data/spec/dummy/config/environments/test.rb +4 -5
  121. data/spec/dummy/config/initializers/doorkeeper.rb +23 -2
  122. data/spec/dummy/config/initializers/{active_record_belongs_to_required_by_default.rb → new_framework_defaults.rb} +5 -1
  123. data/spec/dummy/config/initializers/secret_token.rb +0 -1
  124. data/spec/dummy/config/routes.rb +3 -42
  125. data/spec/dummy/db/migrate/20111122132257_create_users.rb +3 -1
  126. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +3 -1
  127. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +3 -1
  128. data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +3 -1
  129. data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +3 -1
  130. data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +6 -0
  131. data/spec/dummy/db/migrate/20180210183654_add_confidential_to_applications.rb +13 -0
  132. data/spec/dummy/db/schema.rb +38 -37
  133. data/spec/factories.rb +1 -1
  134. data/spec/generators/application_owner_generator_spec.rb +25 -6
  135. data/spec/generators/confidential_applications_generator_spec.rb +45 -0
  136. data/spec/generators/install_generator_spec.rb +1 -1
  137. data/spec/generators/migration_generator_spec.rb +25 -4
  138. data/spec/generators/pkce_generator_spec.rb +43 -0
  139. data/spec/generators/previous_refresh_token_generator_spec.rb +57 -0
  140. data/spec/generators/views_generator_spec.rb +1 -1
  141. data/spec/grape/grape_integration_spec.rb +135 -0
  142. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +2 -2
  143. data/spec/lib/config_spec.rb +199 -22
  144. data/spec/lib/doorkeeper_spec.rb +1 -126
  145. data/spec/lib/models/expirable_spec.rb +0 -4
  146. data/spec/lib/models/revocable_spec.rb +2 -4
  147. data/spec/lib/models/scopes_spec.rb +0 -4
  148. data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -4
  149. data/spec/lib/oauth/authorization_code_request_spec.rb +63 -13
  150. data/spec/lib/oauth/base_request_spec.rb +43 -10
  151. data/spec/lib/oauth/base_response_spec.rb +1 -1
  152. data/spec/lib/oauth/client/credentials_spec.rb +5 -5
  153. data/spec/lib/oauth/client_credentials/creator_spec.rb +6 -2
  154. data/spec/lib/oauth/client_credentials/issuer_spec.rb +26 -7
  155. data/spec/lib/oauth/client_credentials/validation_spec.rb +2 -3
  156. data/spec/lib/oauth/client_credentials_integration_spec.rb +2 -2
  157. data/spec/lib/oauth/client_credentials_request_spec.rb +4 -5
  158. data/spec/lib/oauth/client_spec.rb +0 -3
  159. data/spec/lib/oauth/code_request_spec.rb +5 -5
  160. data/spec/lib/oauth/error_response_spec.rb +0 -3
  161. data/spec/lib/oauth/error_spec.rb +1 -3
  162. data/spec/lib/oauth/forbidden_token_response_spec.rb +1 -4
  163. data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -3
  164. data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -1
  165. data/spec/lib/oauth/helpers/uri_checker_spec.rb +115 -3
  166. data/spec/lib/oauth/invalid_token_response_spec.rb +2 -5
  167. data/spec/lib/oauth/password_access_token_request_spec.rb +46 -5
  168. data/spec/lib/oauth/pre_authorization_spec.rb +40 -6
  169. data/spec/lib/oauth/refresh_token_request_spec.rb +30 -14
  170. data/spec/lib/oauth/scopes_spec.rb +28 -4
  171. data/spec/lib/oauth/token_request_spec.rb +10 -13
  172. data/spec/lib/oauth/token_response_spec.rb +0 -1
  173. data/spec/lib/oauth/token_spec.rb +37 -14
  174. data/spec/lib/orm/active_record/stale_records_cleaner_spec.rb +79 -0
  175. data/spec/lib/request/strategy_spec.rb +0 -1
  176. data/spec/lib/server_spec.rb +10 -0
  177. data/spec/models/doorkeeper/access_grant_spec.rb +45 -2
  178. data/spec/models/doorkeeper/access_token_spec.rb +132 -64
  179. data/spec/models/doorkeeper/application_spec.rb +114 -23
  180. data/spec/requests/applications/applications_request_spec.rb +139 -6
  181. data/spec/requests/applications/authorized_applications_spec.rb +1 -1
  182. data/spec/requests/endpoints/authorization_spec.rb +1 -1
  183. data/spec/requests/endpoints/token_spec.rb +15 -6
  184. data/spec/requests/flows/authorization_code_errors_spec.rb +12 -2
  185. data/spec/requests/flows/authorization_code_spec.rb +199 -2
  186. data/spec/requests/flows/client_credentials_spec.rb +73 -5
  187. data/spec/requests/flows/implicit_grant_errors_spec.rb +3 -3
  188. data/spec/requests/flows/implicit_grant_spec.rb +38 -11
  189. data/spec/requests/flows/password_spec.rb +160 -24
  190. data/spec/requests/flows/refresh_token_spec.rb +6 -6
  191. data/spec/requests/flows/revoke_token_spec.rb +26 -26
  192. data/spec/requests/flows/skip_authorization_spec.rb +16 -11
  193. data/spec/requests/protected_resources/metal_spec.rb +2 -2
  194. data/spec/requests/protected_resources/private_api_spec.rb +2 -2
  195. data/spec/routing/custom_controller_routes_spec.rb +63 -7
  196. data/spec/routing/default_routes_spec.rb +6 -2
  197. data/spec/routing/scoped_routes_spec.rb +16 -2
  198. data/spec/spec_helper.rb +54 -3
  199. data/spec/spec_helper_integration.rb +2 -64
  200. data/spec/support/dependencies/factory_bot.rb +2 -0
  201. data/spec/support/doorkeeper_rspec.rb +19 -0
  202. data/spec/support/helpers/access_token_request_helper.rb +1 -1
  203. data/spec/support/helpers/authorization_request_helper.rb +4 -4
  204. data/spec/support/helpers/model_helper.rb +9 -4
  205. data/spec/support/helpers/request_spec_helper.rb +18 -6
  206. data/spec/support/helpers/url_helper.rb +15 -10
  207. data/spec/support/http_method_shim.rb +12 -16
  208. data/spec/support/shared/controllers_shared_context.rb +2 -6
  209. data/spec/support/shared/models_shared_examples.rb +4 -4
  210. data/spec/validators/redirect_uri_validator_spec.rb +58 -7
  211. data/spec/version/version_spec.rb +15 -0
  212. data/vendor/assets/stylesheets/doorkeeper/bootstrap.min.css +4 -5
  213. metadata +75 -33
  214. data/spec/controllers/application_metal_controller.rb +0 -10
  215. data/spec/support/dependencies/factory_girl.rb +0 -2
@@ -1,4 +1,4 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  module Doorkeeper::OAuth
4
4
  describe AuthorizationCodeRequest do
@@ -6,19 +6,26 @@ module Doorkeeper::OAuth
6
6
  double :server,
7
7
  access_token_expires_in: 2.days,
8
8
  refresh_token_enabled?: false,
9
- custom_access_token_expires_in: ->(_app) { nil }
9
+ custom_access_token_expires_in: lambda { |context|
10
+ context.grant_type == Doorkeeper::OAuth::AUTHORIZATION_CODE ? 1234 : nil
11
+ }
10
12
  end
11
- let(:grant) { FactoryGirl.create :access_grant }
13
+
14
+ let(:grant) { FactoryBot.create :access_grant }
12
15
  let(:client) { grant.application }
16
+ let(:redirect_uri) { client.redirect_uri }
17
+ let(:params) { { redirect_uri: redirect_uri } }
13
18
 
14
19
  subject do
15
- AuthorizationCodeRequest.new server, grant, client, redirect_uri: client.redirect_uri
20
+ AuthorizationCodeRequest.new server, grant, client, params
16
21
  end
17
22
 
18
23
  it 'issues a new token for the client' do
19
24
  expect do
20
25
  subject.authorize
21
26
  end.to change { client.reload.access_tokens.count }.by(1)
27
+
28
+ expect(client.reload.access_tokens.sort_by(&:created_at).last.expires_in).to eq(1234)
22
29
  end
23
30
 
24
31
  it "issues the token with same grant's scopes" do
@@ -27,9 +34,7 @@ module Doorkeeper::OAuth
27
34
  end
28
35
 
29
36
  it 'revokes the grant' do
30
- expect do
31
- subject.authorize
32
- end.to change { grant.reload.accessible? }
37
+ expect { subject.authorize }.to change { grant.reload.accessible? }
33
38
  end
34
39
 
35
40
  it 'requires the grant to be accessible' do
@@ -63,18 +68,63 @@ module Doorkeeper::OAuth
63
68
  end
64
69
 
65
70
  it "matches the client with grant's one" do
66
- subject.client = FactoryGirl.create :application
71
+ subject.client = FactoryBot.create :application
67
72
  subject.validate
68
73
  expect(subject.error).to eq(:invalid_grant)
69
74
  end
70
75
 
71
76
  it 'skips token creation if there is a matching one' do
72
- allow(Doorkeeper.configuration).to receive(:reuse_access_token).and_return(true)
73
- FactoryGirl.create(:access_token, application_id: client.id,
77
+ scopes = grant.scopes
78
+
79
+ Doorkeeper.configure do
80
+ orm DOORKEEPER_ORM
81
+ reuse_access_token
82
+ default_scopes(*scopes)
83
+ end
84
+
85
+ FactoryBot.create(:access_token, application_id: client.id,
74
86
  resource_owner_id: grant.resource_owner_id, scopes: grant.scopes.to_s)
75
- expect do
76
- subject.authorize
77
- end.to_not change { Doorkeeper::AccessToken.count }
87
+
88
+ expect { subject.authorize }.to_not change { Doorkeeper::AccessToken.count }
89
+ end
90
+
91
+ it "calls configured request callback methods" do
92
+ expect(Doorkeeper.configuration.before_successful_strategy_response).to receive(:call).with(subject).once
93
+ expect(Doorkeeper.configuration.after_successful_strategy_response).to receive(:call).with(subject, instance_of(Doorkeeper::OAuth::TokenResponse)).once
94
+ subject.authorize
95
+ end
96
+
97
+ context "when redirect_uri contains some query params" do
98
+ let(:redirect_uri) { client.redirect_uri + "?query=q" }
99
+
100
+ it "compares only host part with grant's redirect_uri" do
101
+ subject.validate
102
+ expect(subject.error).to eq(nil)
103
+ end
104
+ end
105
+
106
+ context "when redirect_uri is not an URI" do
107
+ let(:redirect_uri) { '123d#!s' }
108
+
109
+ it "responds with invalid_grant" do
110
+ subject.validate
111
+ expect(subject.error).to eq(:invalid_grant)
112
+ end
113
+ end
114
+
115
+ context "when redirect_uri is the native one" do
116
+ let(:redirect_uri) { 'urn:ietf:wg:oauth:2.0:oob' }
117
+
118
+ it "invalidates when redirect_uri of the grant is not native" do
119
+ subject.validate
120
+ expect(subject.error).to eq(:invalid_grant)
121
+ end
122
+
123
+ it "validates when redirect_uri of the grant is also native" do
124
+ allow(grant).to receive(:redirect_uri) { redirect_uri }
125
+ subject.validate
126
+ expect(subject.error).to eq(nil)
127
+ end
78
128
  end
79
129
  end
80
130
  end
@@ -1,4 +1,4 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  module Doorkeeper::OAuth
4
4
  describe BaseRequest do
@@ -13,19 +13,14 @@ module Doorkeeper::OAuth
13
13
  created_at: 0
14
14
  end
15
15
 
16
- let(:client) do
17
- double :client,
18
- id: '1'
19
- end
16
+ let(:client) { double :client, id: '1' }
20
17
 
21
- let(:scopes_array) do
22
- %w(public write)
23
- end
18
+ let(:scopes_array) { %w[public write] }
24
19
 
25
20
  let(:server) do
26
21
  double :server,
27
22
  access_token_expires_in: 100,
28
- custom_access_token_expires_in: ->(_) { nil },
23
+ custom_access_token_expires_in: ->(_context) { nil },
29
24
  refresh_token_enabled?: false
30
25
  end
31
26
 
@@ -74,7 +69,7 @@ module Doorkeeper::OAuth
74
69
  it "returns an ErrorResponse object" do
75
70
  error_description = I18n.translate(
76
71
  "server_error",
77
- scope: [:doorkeeper, :errors, :messages]
72
+ scope: %i[doorkeeper errors messages]
78
73
  )
79
74
 
80
75
  result = subject.authorize
@@ -110,6 +105,44 @@ module Doorkeeper::OAuth
110
105
 
111
106
  expect(result).to be_an_instance_of(Doorkeeper::AccessToken)
112
107
  end
108
+
109
+ it "respects custom_access_token_expires_in" do
110
+ server = double(:server,
111
+ access_token_expires_in: 100,
112
+ custom_access_token_expires_in: ->(context) { context.scopes == "public" ? 500 : nil },
113
+ refresh_token_enabled?: false)
114
+ result = subject.find_or_create_access_token(
115
+ client,
116
+ "1",
117
+ "public",
118
+ server
119
+ )
120
+ expect(result.expires_in).to eql(500)
121
+ end
122
+
123
+ it "respects use_refresh_token with a block" do
124
+ server = double(:server,
125
+ access_token_expires_in: 100,
126
+ custom_access_token_expires_in: ->(_context) { nil },
127
+ refresh_token_enabled?: lambda { |context|
128
+ context.scopes == "public"
129
+ })
130
+ result = subject.find_or_create_access_token(
131
+ client,
132
+ "1",
133
+ "public",
134
+ server
135
+ )
136
+ expect(result.refresh_token).to_not be_nil
137
+
138
+ result = subject.find_or_create_access_token(
139
+ client,
140
+ "1",
141
+ "private",
142
+ server
143
+ )
144
+ expect(result.refresh_token).to be_nil
145
+ end
113
146
  end
114
147
 
115
148
  describe "#scopes" do
@@ -1,4 +1,4 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  module Doorkeeper::OAuth
4
4
  describe BaseResponse do
@@ -1,22 +1,22 @@
1
1
  require 'spec_helper'
2
- require 'active_support/core_ext/string'
3
- require 'doorkeeper/oauth/client'
4
2
 
5
3
  class Doorkeeper::OAuth::Client
6
4
  describe Credentials do
7
5
  let(:client_id) { 'some-uid' }
8
6
  let(:client_secret) { 'some-secret' }
9
7
 
10
- it 'is blank when any of the credentials is blank' do
8
+ it 'is blank when the uid in credentials is blank' do
9
+ expect(Credentials.new(nil, nil)).to be_blank
11
10
  expect(Credentials.new(nil, 'something')).to be_blank
12
- expect(Credentials.new('something', nil)).to be_blank
11
+ expect(Credentials.new('something', nil)).to be_present
12
+ expect(Credentials.new('something', 'something')).to be_present
13
13
  end
14
14
 
15
15
  describe :from_request do
16
16
  let(:request) { double.as_null_object }
17
17
 
18
18
  let(:method) do
19
- ->(_request) { return 'uid', 'secret' }
19
+ ->(_request) { ['uid', 'secret'] }
20
20
  end
21
21
 
22
22
  it 'accepts anything that responds to #call' do
@@ -1,10 +1,14 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  class Doorkeeper::OAuth::ClientCredentialsRequest
4
4
  describe Creator do
5
- let(:client) { FactoryGirl.create :application }
5
+ let(:client) { FactoryBot.create :application }
6
6
  let(:scopes) { Doorkeeper::OAuth::Scopes.from_string('public') }
7
7
 
8
+ before do
9
+ default_scopes_exist :public
10
+ end
11
+
8
12
  it 'creates a new token' do
9
13
  expect do
10
14
  subject.call(client, scopes)
@@ -1,6 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'active_support/all'
3
- require 'doorkeeper/oauth/client_credentials/issuer'
4
2
 
5
3
  class Doorkeeper::OAuth::ClientCredentialsRequest
6
4
  describe Issuer do
@@ -9,7 +7,7 @@ class Doorkeeper::OAuth::ClientCredentialsRequest
9
7
  double(
10
8
  :server,
11
9
  access_token_expires_in: 100,
12
- custom_access_token_expires_in: ->(_app) { nil }
10
+ custom_access_token_expires_in: ->(_context) { nil }
13
11
  )
14
12
  end
15
13
  let(:validation) { double :validation, valid?: true }
@@ -63,23 +61,44 @@ class Doorkeeper::OAuth::ClientCredentialsRequest
63
61
  end
64
62
 
65
63
  context 'with custom expirations' do
66
- let(:custom_ttl) { 1233 }
64
+ let(:custom_ttl_grant) { 1234 }
65
+ let(:custom_ttl_scope) { 1235 }
66
+ let(:custom_scope) { 'special' }
67
67
  let(:server) do
68
68
  double(
69
69
  :server,
70
- custom_access_token_expires_in: ->(_app) { custom_ttl }
70
+ custom_access_token_expires_in: lambda { |context|
71
+ # scopes is normally an object but is a string in this test
72
+ if context.scopes == custom_scope
73
+ custom_ttl_scope
74
+ elsif context.grant_type == Doorkeeper::OAuth::CLIENT_CREDENTIALS
75
+ custom_ttl_grant
76
+ else
77
+ nil
78
+ end
79
+ }
71
80
  )
72
81
  end
73
82
 
74
- it 'creates with correct token parameters' do
83
+ it 'respects grant based rules' do
75
84
  expect(creator).to receive(:call).with(
76
85
  client,
77
86
  scopes,
78
- expires_in: custom_ttl,
87
+ expires_in: custom_ttl_grant,
79
88
  use_refresh_token: false
80
89
  )
81
90
  subject.create client, scopes, creator
82
91
  end
92
+
93
+ it 'respects scope based rules' do
94
+ expect(creator).to receive(:call).with(
95
+ client,
96
+ custom_scope,
97
+ expires_in: custom_ttl_scope,
98
+ use_refresh_token: false
99
+ )
100
+ subject.create client, custom_scope, creator
101
+ end
83
102
  end
84
103
  end
85
104
  end
@@ -1,6 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'active_support/all'
3
- require 'doorkeeper/oauth/client_credentials/validation'
4
2
 
5
3
  class Doorkeeper::OAuth::ClientCredentialsRequest
6
4
  describe Validation do
@@ -45,7 +43,8 @@ class Doorkeeper::OAuth::ClientCredentialsRequest
45
43
  allow(application).to receive(:scopes).and_return(application_scopes)
46
44
  allow(server).to receive(:scopes).and_return(server_scopes)
47
45
  allow(request).to receive(:scopes).and_return(
48
- Doorkeeper::OAuth::Scopes.from_string 'email')
46
+ Doorkeeper::OAuth::Scopes.from_string('email')
47
+ )
49
48
  expect(subject).not_to be_valid
50
49
  end
51
50
  end
@@ -1,11 +1,11 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  module Doorkeeper::OAuth
4
4
  describe ClientCredentialsRequest do
5
5
  let(:server) { Doorkeeper.configuration }
6
6
 
7
7
  context 'with a valid request' do
8
- let(:client) { FactoryGirl.create :application }
8
+ let(:client) { FactoryBot.create :application }
9
9
 
10
10
  it 'issues an access token' do
11
11
  request = ClientCredentialsRequest.new(server, client, {})
@@ -1,17 +1,16 @@
1
1
  require 'spec_helper'
2
- require 'active_support/all'
3
- require 'active_model'
4
- require 'doorkeeper/oauth/client_credentials_request'
5
2
 
6
3
  module Doorkeeper::OAuth
7
4
  describe ClientCredentialsRequest do
8
5
  let(:server) do
9
6
  double(
10
7
  default_scopes: nil,
11
- custom_access_token_expires_in: ->(_app) { nil }
8
+ access_token_expires_in: 2.hours,
9
+ custom_access_token_expires_in: ->(_context) { nil }
12
10
  )
13
11
  end
14
- let(:application) { double :application, scopes: Scopes.from_string('') }
12
+
13
+ let(:application) { FactoryBot.create(:application, scopes: '') }
15
14
  let(:client) { double :client, application: application }
16
15
  let(:token_creator) { double :issuer, create: true, token: double }
17
16
 
@@ -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/client'
5
2
 
6
3
  module Doorkeeper::OAuth
7
4
  describe Client do
@@ -1,4 +1,4 @@
1
- require 'spec_helper_integration'
1
+ require 'spec_helper'
2
2
 
3
3
  module Doorkeeper::OAuth
4
4
  describe CodeRequest do
@@ -10,7 +10,9 @@ module Doorkeeper::OAuth
10
10
  scopes: nil,
11
11
  state: nil,
12
12
  error: nil,
13
- authorizable?: true
13
+ authorizable?: true,
14
+ code_challenge: nil,
15
+ code_challenge_method: nil,
14
16
  )
15
17
  end
16
18
 
@@ -32,9 +34,7 @@ module Doorkeeper::OAuth
32
34
 
33
35
  it 'does not create grant when not authorizable' do
34
36
  allow(pre_auth).to receive(:authorizable?).and_return(false)
35
- expect do
36
- subject.authorize
37
- end.to_not change { Doorkeeper::AccessGrant.count }
37
+ expect { subject.authorize }.not_to change { Doorkeeper::AccessGrant.count }
38
38
  end
39
39
 
40
40
  it 'returns a error response' do
@@ -1,7 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'active_model'
3
- require 'doorkeeper/oauth/error'
4
- require 'doorkeeper/oauth/error_response'
5
2
 
6
3
  module Doorkeeper::OAuth
7
4
  describe ErrorResponse do
@@ -1,6 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'active_support/i18n'
3
- require 'doorkeeper/oauth/error'
4
2
 
5
3
  module Doorkeeper::OAuth
6
4
  describe Error do
@@ -13,7 +11,7 @@ module Doorkeeper::OAuth
13
11
  it 'is translated from translation messages' do
14
12
  expect(I18n).to receive(:translate).with(
15
13
  :some_error,
16
- scope: [:doorkeeper, :errors, :messages],
14
+ scope: %i[doorkeeper errors messages],
17
15
  default: :server_error
18
16
  )
19
17
  error.description
@@ -1,12 +1,9 @@
1
1
  require 'spec_helper'
2
- require 'active_model'
3
- require 'doorkeeper'
4
- require 'doorkeeper/oauth/forbidden_token_response'
5
2
 
6
3
  module Doorkeeper::OAuth
7
4
  describe ForbiddenTokenResponse do
8
5
  describe '#name' do
9
- it { expect(subject.name).to eq(:invalid_scope) }
6
+ it { expect(subject.name).to eq(:invalid_scope) }
10
7
  end
11
8
 
12
9
  describe '#status' do
@@ -1,7 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'active_support/core_ext/string'
3
- require 'doorkeeper/oauth/helpers/scope_checker'
4
- require 'doorkeeper/oauth/scopes'
5
2
 
6
3
  module Doorkeeper::OAuth::Helpers
7
4
  describe ScopeChecker, '.valid?' do
@@ -1,5 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'doorkeeper/oauth/helpers/unique_token'
3
2
 
4
3
  module Doorkeeper::OAuth::Helpers
5
4
  describe UniqueToken do
@@ -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