doorkeeper 4.3.0 → 4.3.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of doorkeeper might be problematic. Click here for more details.

Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE.md +7 -1
  3. data/.travis.yml +8 -4
  4. data/NEWS.md +16 -1
  5. data/README.md +54 -32
  6. data/SECURITY.md +3 -1
  7. data/doorkeeper.gemspec +2 -2
  8. data/lib/doorkeeper.rb +1 -0
  9. data/lib/doorkeeper/config.rb +3 -1
  10. data/lib/doorkeeper/models/access_grant_mixin.rb +1 -28
  11. data/lib/doorkeeper/models/access_token_mixin.rb +9 -34
  12. data/lib/doorkeeper/models/application_mixin.rb +1 -27
  13. data/lib/doorkeeper/models/concerns/orderable.rb +13 -0
  14. data/lib/doorkeeper/oauth/base_request.rb +7 -2
  15. data/lib/doorkeeper/oauth/invalid_token_response.rb +1 -1
  16. data/lib/doorkeeper/orm/active_record.rb +0 -1
  17. data/lib/doorkeeper/orm/active_record/access_grant.rb +28 -1
  18. data/lib/doorkeeper/orm/active_record/access_token.rb +24 -1
  19. data/lib/doorkeeper/orm/active_record/application.rb +21 -1
  20. data/lib/doorkeeper/version.rb +1 -1
  21. data/lib/generators/doorkeeper/templates/initializer.rb +11 -0
  22. data/spec/controllers/authorizations_controller_spec.rb +1 -1
  23. data/spec/controllers/tokens_controller_spec.rb +1 -1
  24. data/spec/dummy/config/initializers/doorkeeper.rb +11 -0
  25. data/spec/lib/oauth/authorization_code_request_spec.rb +3 -3
  26. data/spec/lib/oauth/base_request_spec.rb +1 -1
  27. data/spec/lib/oauth/error_spec.rb +1 -1
  28. data/spec/lib/oauth/password_access_token_request_spec.rb +3 -3
  29. data/spec/lib/oauth/refresh_token_request_spec.rb +3 -3
  30. data/spec/requests/flows/client_credentials_spec.rb +28 -0
  31. data/spec/requests/flows/password_spec.rb +39 -0
  32. data/spec/support/helpers/request_spec_helper.rb +1 -1
  33. data/spec/support/helpers/url_helper.rb +1 -0
  34. metadata +6 -5
  35. data/lib/doorkeeper/orm/active_record/base_record.rb +0 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 323927e89a9c1c31f4f5dda92873c1959f2455a9
4
- data.tar.gz: 956c2a288dbc09fa8cc4bcb7d809ef5dd53bd4ba
3
+ metadata.gz: 8d76a49e22bc442139a55528594bc6a3849fc53d
4
+ data.tar.gz: eeaca97997f68ca0017c2bbc350323cb1bc9df32
5
5
  SHA512:
6
- metadata.gz: a1dbfedef840dc12c3e3ce33ba854963df84aaed81b97bc1828b177ef3c9d9ab4454dda6f37abe75f855eb39561a8e524a047bdffd9ddf44bf8a80d9d24b5c59
7
- data.tar.gz: 27d2b543b67f67e750e8c317680b38583bb53473d8a0350aecccb7f9723ec00238b0ac07c72df3b2ace2ce74522f67d6e14811eb20acbb136497f71a368e4b2c
6
+ metadata.gz: 961beb33acfb9ba24831ec3e4fbcc2e4cbcc58ccd1a47bd0672aafe9e8e1d993918f1f5bd1ce7df4f3e20ae70a455c6cf698b697489b1247ff6eeecd89950ec0
7
+ data.tar.gz: ed000ab156a89e92973bc0d22896250ec73ddc52fd7adc6a229b9eb82d1517372b521477af5c394031b9af6164d373967937429093f24179104a6743f2778b87
@@ -14,6 +14,12 @@ Tell us what should happen
14
14
  Tell us what happens instead
15
15
 
16
16
  ### System configuration
17
+ You can help us to understand your problem if you will share some very
18
+ useful information about your project environment (don't forget to
19
+ remove any confidential data if it exists).
20
+
21
+ **Doorkeeper initializer**:
22
+
17
23
  **Ruby version**:
18
24
 
19
- **Gemfile.lock**
25
+ **Gemfile.lock**:
@@ -4,10 +4,10 @@ sudo: false
4
4
 
5
5
  rvm:
6
6
  - 2.1
7
- - 2.2.9
8
- - 2.3.6
9
- - 2.4.3
10
- - 2.5.0
7
+ - 2.2
8
+ - 2.3
9
+ - 2.4
10
+ - 2.5
11
11
 
12
12
  before_install:
13
13
  - gem update --system # Need for Ruby 2.5.0. https://github.com/travis-ci/travis-ci/issues/8978
@@ -30,5 +30,9 @@ matrix:
30
30
  rvm: 2.1
31
31
  - gemfile: gemfiles/rails_master.gemfile
32
32
  rvm: 2.1
33
+ - gemfile: gemfiles/rails_master.gemfile
34
+ rvm: 2.2
35
+ - gemfile: gemfiles/rails_master.gemfile
36
+ rvm: 2.3
33
37
  allow_failures:
34
38
  - gemfile: gemfiles/rails_master.gemfile
data/NEWS.md CHANGED
@@ -4,6 +4,18 @@ User-visible changes worth mentioning.
4
4
 
5
5
  ## master
6
6
 
7
+ Replace this text with you changelog entry. Look at the examples below.
8
+
9
+ ## 4.3.1
10
+
11
+ - Remove `BaseRecord` and introduce additional concern for ordering methods to fix
12
+ braking changes for Doorkeeper models.
13
+ - [#1032] Refactor BaseRequest callbacks into configurable lambdas
14
+ - [#1040] Clear mixins from ActiveRecord DSL and save only overridable API. It
15
+ allows to use this mixins in Doorkeeper ORM extensions with minimum code boilerplate.
16
+
17
+ ## 4.3.0
18
+
7
19
  - [#976] Fix to invalidate the second redirect URI when the first URI is the native URI
8
20
  - [#1035] Allow `Application#redirect_uri=` to handle array of URIs.
9
21
  - [#1036] Allow to forbid Application redirect URI's with specific rules.
@@ -22,7 +34,6 @@ User-visible changes worth mentioning.
22
34
  - [#1019] Remove translation not in use: `invalid_resource_owner`.
23
35
  - Use Ruby 2 hash style syntax (min required Ruby version = 2.1)
24
36
  - [#948] Make Scopes.<=> work with any "other" value.
25
- - [#970] Escape certain attributes in authorization forms.
26
37
  - [#974] Redirect URI is checked without query params within AuthorizationCodeRequest.
27
38
  - [#1004] More explicit help text for `native_redirect_uri`.
28
39
  - [#1023] Update Ruby versions and test against 2.5.0 on Travis CI.
@@ -30,6 +41,10 @@ User-visible changes worth mentioning.
30
41
  - [#1025] Improve documentation for adding foreign keys
31
42
  - [#1028] Make it possible to have composit strategy names.
32
43
 
44
+ ## 4.2.6
45
+
46
+ - [#970] Escape certain attributes in authorization forms.
47
+
33
48
  ## 4.2.5
34
49
 
35
50
  - [#936] Deprecate `Doorkeeper#configured?`, `Doorkeeper#database_installed?`, and
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Doorkeeper - awesome OAuth2 provider for your Rails app.
1
+ # Doorkeeper - awesome OAuth 2 provider for your Rails app.
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/doorkeeper.svg)](https://rubygems.org/gems/doorkeeper)
4
4
  [![Build Status](https://travis-ci.org/doorkeeper-gem/doorkeeper.svg?branch=master)](https://travis-ci.org/doorkeeper-gem/doorkeeper)
@@ -43,11 +43,13 @@ https://github.com/doorkeeper-gem/doorkeeper/releases
43
43
  - [Active Record](#active-record)
44
44
  - [MongoDB](#mongodb)
45
45
  - [Sequel](#sequel)
46
+ - [Couchbase](#couchbase)
46
47
  - [Routes](#routes)
47
48
  - [Authenticating](#authenticating)
48
49
  - [Internationalization (I18n)](#internationalization-i18n)
49
50
  - [Protecting resources with OAuth (a.k.a your API endpoint)](#protecting-resources-with-oauth-aka-your-api-endpoint)
50
- - [Protect your API with OAuth when using Grape](#protect-your-api-with-oauth-when-using-grape)
51
+ - [Ruby on Rails controllers](#ruby-on-rails-controllers)
52
+ - [Grape endpoints](#grape-endpoints)
51
53
  - [Route Constraints and other integrations](#route-constraints-and-other-integrations)
52
54
  - [Access Token Scopes](#access-token-scopes)
53
55
  - [Custom Access Token Generator](#custom-access-token-generator)
@@ -87,8 +89,8 @@ This will install the doorkeeper initializer into `config/initializers/doorkeepe
87
89
 
88
90
  #### Active Record
89
91
 
90
- By default doorkeeper is configured to use active record, so to start you have
91
- to generate the migration tables:
92
+ By default doorkeeper is configured to use Active Record, so to start you have
93
+ to generate the migration tables (supports Rails >= 5 migrations versioning):
92
94
 
93
95
  rails generate doorkeeper:migration
94
96
 
@@ -100,21 +102,26 @@ for each table that includes a `resource_owner_id` column:
100
102
  add_foreign_key :table_name, :users, column: :resource_owner_id
101
103
  ```
102
104
 
105
+ Then run migrations:
106
+
107
+ ```sh
108
+ rake db:migrate
109
+ ```
110
+
103
111
  Remember to add associations to your model so the related records are deleted.
104
112
  If you don't do this an `ActiveRecord::InvalidForeignKey`-error will be raised
105
113
  when you try to destroy a model with related access grants or access tokens.
106
114
 
107
115
  ```ruby
108
116
  class User < ApplicationRecord
109
- has_many :access_grants, class_name: "Doorkeeper::AccessGrant", foreign_key: :resource_owner_id, dependent: :delete_all # or :destroy if you need callbacks
110
- has_many :access_tokens, class_name: "Doorkeeper::AccessToken", foreign_key: :resource_owner_id, dependent: :delete_all # or :destroy if you need callbacks
111
- end
112
- ```
113
-
114
- Then run migrations:
117
+ has_many :access_grants, class_name: "Doorkeeper::AccessGrant",
118
+ foreign_key: :resource_owner_id,
119
+ dependent: :delete_all # or :destroy if you need callbacks
115
120
 
116
- ```sh
117
- rake db:migrate
121
+ has_many :access_tokens, class_name: "Doorkeeper::AccessToken",
122
+ foreign_key: :resource_owner_id,
123
+ dependent: :delete_all # or :destroy if you need callbacks
124
+ end
118
125
  ```
119
126
 
120
127
  #### MongoDB
@@ -132,6 +139,12 @@ Follow configuration instructions for setting up the necessary Doorkeeper ORM.
132
139
  [Sequel gem]: https://github.com/jeremyevans/sequel/
133
140
  [doorkeeper-sequel extension]: https://github.com/nbulaj/doorkeeper-sequel
134
141
 
142
+ #### Couchbase
143
+
144
+ Use [doorkeeper-couchbase] extension if you are using Couchbase database.
145
+
146
+ [doorkeeper-couchbase]: https://github.com/acaprojects/doorkeeper-couchbase
147
+
135
148
  ### Routes
136
149
 
137
150
  The installation script will also automatically add the Doorkeeper routes into
@@ -169,7 +182,7 @@ and authentication block in `config/initializers/doorkeeper.rb`:
169
182
  ``` ruby
170
183
  Doorkeeper.configure do
171
184
  resource_owner_authenticator do
172
- User.find_by_id(session[:current_user_id]) || redirect_to(login_url)
185
+ User.find_by(id: session[:current_user_id]) || redirect_to(login_url)
173
186
  end
174
187
  end
175
188
  ```
@@ -182,16 +195,17 @@ the methods defined over there.
182
195
  You may want to check other ways of authentication
183
196
  [here](https://github.com/doorkeeper-gem/doorkeeper/wiki/Authenticating-using-Clearance-or-DIY).
184
197
 
185
-
186
198
  ### Internationalization (I18n)
187
199
 
188
200
  See language files in [the I18n repository](https://github.com/doorkeeper-gem/doorkeeper-i18n).
189
201
 
190
-
191
202
  ## Protecting resources with OAuth (a.k.a your API endpoint)
192
203
 
193
- To protect your API with OAuth, you just need to setup `before_action`s
194
- specifying the actions you want to protect. For example:
204
+ ### Ruby on Rails controllers
205
+
206
+ To protect your controllers (usual one or `ActionController::API`) with OAuth,
207
+ you just need to setup `before_action`s specifying the actions you want to
208
+ protect. For example:
195
209
 
196
210
  ``` ruby
197
211
  class Api::V1::ProductsController < Api::V1::ApiController
@@ -204,16 +218,17 @@ end
204
218
  You can pass any option `before_action` accepts, such as `if`, `only`,
205
219
  `except`, and others.
206
220
 
207
- ### Protect your API with OAuth when using Grape
221
+ ### Grape endpoints
208
222
 
209
- As of [PR 567] doorkeeper has helpers for Grape >= 0.10. One of them is
210
- `doorkeeper_authorize!` and can be used in a similar way as an example above.
211
- Note that you have to use `require 'doorkeeper/grape/helpers'` and
212
- `helpers Doorkeeper::Grape::Helpers`.
223
+ Starting from version 2.2 Doorkeeper provides helpers for the
224
+ [Grape framework] >= 0.10. One of them is `doorkeeper_authorize!` that
225
+ can be used in a similar way as an example above to protect your API
226
+ with OAuth. Note that you have to use `require 'doorkeeper/grape/helpers'`
227
+ and `helpers Doorkeeper::Grape::Helpers` in your Grape API class.
213
228
 
214
229
  For more information about integration with Grape see the [Wiki].
215
230
 
216
- [PR 567]: https://github.com/doorkeeper-gem/doorkeeper/pull/567
231
+ [Grape framework]: https://github.com/ruby-grape/grape
217
232
  [Wiki]: https://github.com/doorkeeper-gem/doorkeeper/wiki/Grape-Integration
218
233
 
219
234
  ``` ruby
@@ -239,7 +254,6 @@ module API
239
254
  end
240
255
  ```
241
256
 
242
-
243
257
  ### Route Constraints and other integrations
244
258
 
245
259
  You can leverage the `Doorkeeper.authenticate` facade to easily extract a
@@ -254,7 +268,6 @@ module Constraint
254
268
  token = Doorkeeper.authenticate(request)
255
269
  token && token.accessible?
256
270
  end
257
-
258
271
  end
259
272
  end
260
273
  ```
@@ -326,8 +339,10 @@ JWT token support is available with
326
339
 
327
340
  ### Custom Base Controller
328
341
 
329
- By default Doorkeeper's main controller `Doorkeeper::ApplicationController` inherits from `ActionController::Base`.
330
- You may want to use your own controller to inherit from, to keep Doorkeeper controllers in the same context than the rest your app:
342
+ By default Doorkeeper's main controller `Doorkeeper::ApplicationController`
343
+ inherits from `ActionController::Base`. You may want to use your own
344
+ controller to inherit from, to keep Doorkeeper controllers in the same
345
+ context than the rest your app:
331
346
 
332
347
  ```ruby
333
348
  Doorkeeper.configure do
@@ -372,7 +387,7 @@ To protect the endpoint you should uncomment these lines:
372
387
  # config/initializers/doorkeeper.rb
373
388
  Doorkeeper.configure do
374
389
  admin_authenticator do |routes|
375
- Admin.find_by_id(session[:admin_id]) || redirect_to(routes.new_admin_session_url)
390
+ Admin.find_by(id: session[:admin_id]) || redirect_to(routes.new_admin_session_url)
376
391
  end
377
392
  end
378
393
  ```
@@ -387,6 +402,16 @@ For more information see the page
387
402
 
388
403
  - [Associate users to OAuth applications (ownership)](https://github.com/doorkeeper-gem/doorkeeper/wiki/Associate-users-to-OAuth-applications-%28ownership%29)
389
404
  - [CORS - Cross Origin Resource Sharing](https://github.com/doorkeeper-gem/doorkeeper/wiki/%5BCORS%5D-Cross-Origin-Resource-Sharing)
405
+ - see more on [Wiki page](https://github.com/doorkeeper-gem/doorkeeper/wiki)
406
+
407
+ ## Testing
408
+
409
+ You can use Doorkeeper models in your application test suite. Note that starting from
410
+ Doorkeeper 4.3.0 it uses [ActiveSupport lazy loading hooks](http://api.rubyonrails.org/classes/ActiveSupport/LazyLoadHooks.html)
411
+ to load models. There are [known issues](https://github.com/doorkeeper-gem/doorkeeper/issues/1043)
412
+ with the `factory_bot_rails` gem (it executes factories building before `ActiveRecord::Base`
413
+ is initialized using hooks in gem railtie, so you can catch a `uninitialized constant` error).
414
+ It is recommended to use pure `factory_bot` gem to solve this problem.
390
415
 
391
416
  ## Upgrading
392
417
 
@@ -413,8 +438,6 @@ tests with a specific ORM and Rails version:
413
438
  rails=4.2.0 orm=active_record bundle exec rake
414
439
  ```
415
440
 
416
- Or you might prefer to run `script/run_all` to integrate against all ORMs.
417
-
418
441
  ## Contributing
419
442
 
420
443
  Want to contribute and don't know where to start? Check out [features we're
@@ -430,7 +453,7 @@ page](https://github.com/doorkeeper-gem/doorkeeper/wiki/Contributing).
430
453
 
431
454
  ### Wiki
432
455
 
433
- You can find everything about doorkeeper in our [wiki
456
+ You can find everything about Doorkeeper in our [wiki
434
457
  here](https://github.com/doorkeeper-gem/doorkeeper/wiki).
435
458
 
436
459
  ### Screencast
@@ -452,7 +475,6 @@ here](https://github.com/doorkeeper-gem/doorkeeper/wiki/Testing-your-provider-wi
452
475
  Thanks to all our [awesome
453
476
  contributors](https://github.com/doorkeeper-gem/doorkeeper/graphs/contributors)!
454
477
 
455
-
456
478
  ### IETF Standards
457
479
 
458
480
  * [The OAuth 2.0 Authorization Framework](http://tools.ietf.org/html/rfc6749)
@@ -6,7 +6,9 @@ policy as outlined below:
6
6
 
7
7
  1. Do NOT open up a GitHub issue with your report. Security reports
8
8
  should be kept private until a possible fix is determined.
9
- 2. Send an email to Jon Moss, Doorkeeper's maintainer, at doorkeeper AT jonathanmoss.me. You should receive a prompt response.
9
+ 2. Send an email to Nikita Bulai at bulaj.nikita AT gmail.com or one of
10
+ the others Doorkeeper maintainers listed in gemspec. You should receive
11
+ a prompt response.
10
12
  3. Be patient. Since Doorkeeper is in a stable maintenance phase, we want to
11
13
  do as little as possible to rock the boat of the project.
12
14
 
@@ -5,8 +5,8 @@ require "doorkeeper/version"
5
5
  Gem::Specification.new do |s|
6
6
  s.name = "doorkeeper"
7
7
  s.version = Doorkeeper.gem_version
8
- s.authors = ["Felipe Elias Philipp", "Tute Costa", "Jon Moss"]
9
- s.email = %w(me@jonathanmoss.me)
8
+ s.authors = ["Felipe Elias Philipp", "Tute Costa", "Jon Moss", "Nikita Bulai"]
9
+ s.email = %w(bulaj.nikita@gmail.com)
10
10
  s.homepage = "https://github.com/doorkeeper-gem/doorkeeper"
11
11
  s.summary = "OAuth 2 provider for Rails and Grape"
12
12
  s.description = "Doorkeeper is an OAuth 2 provider for Rails and Grape."
@@ -34,6 +34,7 @@ require 'doorkeeper/oauth/token_introspection'
34
34
  require 'doorkeeper/oauth/invalid_token_response'
35
35
  require 'doorkeeper/oauth/forbidden_token_response'
36
36
 
37
+ require 'doorkeeper/models/concerns/orderable'
37
38
  require 'doorkeeper/models/concerns/scopes'
38
39
  require 'doorkeeper/models/concerns/expirable'
39
40
  require 'doorkeeper/models/concerns/revocable'
@@ -192,7 +192,9 @@ doorkeeper.
192
192
  ::Rails.logger.warn(I18n.t('doorkeeper.errors.messages.credential_flow_not_configured'))
193
193
  nil
194
194
  end)
195
-
195
+ option :before_successful_strategy_response, default: ->(_request) {}
196
+ option :after_successful_strategy_response,
197
+ default: ->(_request, _response) {}
196
198
  option :skip_authorization, default: ->(_routes) {}
197
199
  option :access_token_expires_in, default: 7200
198
200
  option :custom_access_token_expires_in, default: ->(_app) { nil }
@@ -6,25 +6,8 @@ module Doorkeeper
6
6
  include Models::Expirable
7
7
  include Models::Revocable
8
8
  include Models::Accessible
9
+ include Models::Orderable
9
10
  include Models::Scopes
10
- include ActiveModel::MassAssignmentSecurity if defined?(::ProtectedAttributes)
11
-
12
- included do
13
- belongs_to_options = {
14
- class_name: 'Doorkeeper::Application',
15
- inverse_of: :access_grants
16
- }
17
- if defined?(ActiveRecord::Base) && ActiveRecord::VERSION::MAJOR >= 5
18
- belongs_to_options[:optional] = true
19
- end
20
-
21
- belongs_to :application, belongs_to_options
22
-
23
- validates :resource_owner_id, :application_id, :token, :expires_in, :redirect_uri, presence: true
24
- validates :token, uniqueness: true
25
-
26
- before_validation :generate_token, on: :create
27
- end
28
11
 
29
12
  module ClassMethods
30
13
  # Searches for Doorkeeper::AccessGrant record with the
@@ -39,15 +22,5 @@ module Doorkeeper
39
22
  find_by(token: token.to_s)
40
23
  end
41
24
  end
42
-
43
- private
44
-
45
- # Generates token value with UniqueToken class.
46
- #
47
- # @return [String] token value
48
- #
49
- def generate_token
50
- self.token = UniqueToken.generate
51
- end
52
25
  end
53
26
  end
@@ -6,32 +6,8 @@ module Doorkeeper
6
6
  include Models::Expirable
7
7
  include Models::Revocable
8
8
  include Models::Accessible
9
+ include Models::Orderable
9
10
  include Models::Scopes
10
- include ActiveModel::MassAssignmentSecurity if defined?(::ProtectedAttributes)
11
-
12
- included do
13
- belongs_to_options = {
14
- class_name: 'Doorkeeper::Application',
15
- inverse_of: :access_tokens
16
- }
17
- if defined?(ActiveRecord::Base) && ActiveRecord::VERSION::MAJOR >= 5
18
- belongs_to_options[:optional] = true
19
- end
20
-
21
- belongs_to :application, belongs_to_options
22
-
23
- validates :token, presence: true, uniqueness: true
24
- validates :refresh_token, uniqueness: true, if: :use_refresh_token?
25
-
26
- # @attr_writer [Boolean, nil] use_refresh_token
27
- # indicates the possibility of using refresh token
28
- attr_writer :use_refresh_token
29
-
30
- before_validation :generate_token, on: :create
31
- before_validation :generate_refresh_token,
32
- on: :create,
33
- if: :use_refresh_token?
34
- end
35
11
 
36
12
  module ClassMethods
37
13
  # Returns an instance of the Doorkeeper::AccessToken with
@@ -110,7 +86,7 @@ module Doorkeeper
110
86
  # @param app_scopes [String]
111
87
  # Application scopes
112
88
  #
113
- # @return [Boolean] true if all scopes and blank or matches
89
+ # @return [Boolean] true if all scopes are blank or matches
114
90
  # and false in other cases
115
91
  #
116
92
  def scopes_match?(token_scopes, param_scopes, app_scopes)
@@ -231,7 +207,7 @@ module Doorkeeper
231
207
  # @return [String] refresh token value
232
208
  #
233
209
  def generate_refresh_token
234
- write_attribute :refresh_token, UniqueToken.generate
210
+ self.refresh_token = UniqueToken.generate
235
211
  end
236
212
 
237
213
  # Generates and sets the token value with the
@@ -247,12 +223,7 @@ module Doorkeeper
247
223
  def generate_token
248
224
  self.created_at ||= Time.now.utc
249
225
 
250
- generator = token_generator
251
- unless generator.respond_to?(:generate)
252
- raise Errors::UnableToGenerateToken, "#{generator} does not respond to `.generate`."
253
- end
254
-
255
- self.token = generator.generate(
226
+ self.token = token_generator.generate(
256
227
  resource_owner_id: resource_owner_id,
257
228
  scopes: scopes,
258
229
  application: application,
@@ -263,7 +234,11 @@ module Doorkeeper
263
234
 
264
235
  def token_generator
265
236
  generator_name = Doorkeeper.configuration.access_token_generator
266
- generator_name.constantize
237
+ generator = generator_name.constantize
238
+
239
+ return generator if generator.respond_to?(:generate)
240
+
241
+ raise Errors::UnableToGenerateToken, "#{generator} does not respond to `.generate`."
267
242
  rescue NameError
268
243
  raise Errors::TokenGeneratorNotFound, "#{generator_name} not found"
269
244
  end
@@ -3,19 +3,8 @@ module Doorkeeper
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  include OAuth::Helpers
6
+ include Models::Orderable
6
7
  include Models::Scopes
7
- include ActiveModel::MassAssignmentSecurity if defined?(::ProtectedAttributes)
8
-
9
- included do
10
- has_many :access_grants, dependent: :delete_all, class_name: 'Doorkeeper::AccessGrant'
11
- has_many :access_tokens, dependent: :delete_all, class_name: 'Doorkeeper::AccessToken'
12
-
13
- validates :name, :secret, :uid, presence: true
14
- validates :uid, uniqueness: true
15
- validates :redirect_uri, redirect_uri: true
16
-
17
- before_validation :generate_uid, :generate_secret, on: :create
18
- end
19
8
 
20
9
  module ClassMethods
21
10
  # Returns an instance of the Doorkeeper::Application with
@@ -51,20 +40,5 @@ module Doorkeeper
51
40
  def redirect_uri=(uris)
52
41
  super(uris.is_a?(Array) ? uris.join("\n") : uris)
53
42
  end
54
-
55
- private
56
-
57
- def has_scopes?
58
- Doorkeeper.configuration.orm != :active_record ||
59
- Doorkeeper::Application.column_names.include?("scopes")
60
- end
61
-
62
- def generate_uid
63
- self.uid = UniqueToken.generate if uid.blank?
64
- end
65
-
66
- def generate_secret
67
- self.secret = UniqueToken.generate if secret.blank?
68
- end
69
43
  end
70
44
  end
@@ -0,0 +1,13 @@
1
+ module Doorkeeper
2
+ module Models
3
+ module Orderable
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods
7
+ def ordered_by(attribute, direction = :asc)
8
+ order(attribute => direction)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -42,9 +42,14 @@ module Doorkeeper
42
42
  )
43
43
  end
44
44
 
45
- def before_successful_response; end
45
+ def before_successful_response
46
+ Doorkeeper.configuration.before_successful_strategy_response.call(self)
47
+ end
46
48
 
47
- def after_successful_response; end
49
+ def after_successful_response
50
+ Doorkeeper.configuration.after_successful_strategy_response.
51
+ call(self, @response)
52
+ end
48
53
  end
49
54
  end
50
55
  end
@@ -21,7 +21,7 @@ module Doorkeeper
21
21
  end
22
22
 
23
23
  def description
24
- scope = { scope: [:doorkeeper, :errors, :messages, :invalid_token] }
24
+ scope = { scope: %i[doorkeeper errors messages invalid_token] }
25
25
  @description ||= I18n.translate @reason, scope
26
26
  end
27
27
  end
@@ -5,7 +5,6 @@ module Doorkeeper
5
5
  module ActiveRecord
6
6
  def self.initialize_models!
7
7
  lazy_load do
8
- require 'doorkeeper/orm/active_record/base_record'
9
8
  require 'doorkeeper/orm/active_record/access_grant'
10
9
  require 'doorkeeper/orm/active_record/access_token'
11
10
  require 'doorkeeper/orm/active_record/application'
@@ -1,7 +1,34 @@
1
1
  module Doorkeeper
2
- class AccessGrant < BaseRecord
2
+ class AccessGrant < ActiveRecord::Base
3
3
  self.table_name = "#{table_name_prefix}oauth_access_grants#{table_name_suffix}".to_sym
4
4
 
5
5
  include AccessGrantMixin
6
+ include ActiveModel::MassAssignmentSecurity if defined?(::ProtectedAttributes)
7
+
8
+ belongs_to_options = {
9
+ class_name: 'Doorkeeper::Application',
10
+ inverse_of: :access_grants
11
+ }
12
+
13
+ if defined?(ActiveRecord::Base) && ActiveRecord::VERSION::MAJOR >= 5
14
+ belongs_to_options[:optional] = true
15
+ end
16
+
17
+ belongs_to :application, belongs_to_options
18
+
19
+ validates :resource_owner_id, :application_id, :token, :expires_in, :redirect_uri, presence: true
20
+ validates :token, uniqueness: true
21
+
22
+ before_validation :generate_token, on: :create
23
+
24
+ private
25
+
26
+ # Generates token value with UniqueToken class.
27
+ #
28
+ # @return [String] token value
29
+ #
30
+ def generate_token
31
+ self.token = UniqueToken.generate
32
+ end
6
33
  end
7
34
  end
@@ -1,8 +1,31 @@
1
1
  module Doorkeeper
2
- class AccessToken < BaseRecord
2
+ class AccessToken < ActiveRecord::Base
3
3
  self.table_name = "#{table_name_prefix}oauth_access_tokens#{table_name_suffix}".to_sym
4
4
 
5
5
  include AccessTokenMixin
6
+ include ActiveModel::MassAssignmentSecurity if defined?(::ProtectedAttributes)
7
+
8
+ belongs_to_options = {
9
+ class_name: 'Doorkeeper::Application',
10
+ inverse_of: :access_tokens
11
+ }
12
+
13
+ if defined?(ActiveRecord::Base) && ActiveRecord::VERSION::MAJOR >= 5
14
+ belongs_to_options[:optional] = true
15
+ end
16
+
17
+ belongs_to :application, belongs_to_options
18
+
19
+ validates :token, presence: true, uniqueness: true
20
+ validates :refresh_token, uniqueness: true, if: :use_refresh_token?
21
+
22
+ # @attr_writer [Boolean, nil] use_refresh_token
23
+ # indicates the possibility of using refresh token
24
+ attr_writer :use_refresh_token
25
+
26
+ before_validation :generate_token, on: :create
27
+ before_validation :generate_refresh_token,
28
+ on: :create, if: :use_refresh_token?
6
29
 
7
30
  # Searches for not revoked Access Tokens associated with the
8
31
  # specific Resource Owner.
@@ -1,8 +1,18 @@
1
1
  module Doorkeeper
2
- class Application < BaseRecord
2
+ class Application < ActiveRecord::Base
3
3
  self.table_name = "#{table_name_prefix}oauth_applications#{table_name_suffix}".to_sym
4
4
 
5
5
  include ApplicationMixin
6
+ include ActiveModel::MassAssignmentSecurity if defined?(::ProtectedAttributes)
7
+
8
+ has_many :access_grants, dependent: :delete_all, class_name: 'Doorkeeper::AccessGrant'
9
+ has_many :access_tokens, dependent: :delete_all, class_name: 'Doorkeeper::AccessToken'
10
+
11
+ validates :name, :secret, :uid, presence: true
12
+ validates :uid, uniqueness: true
13
+ validates :redirect_uri, redirect_uri: true
14
+
15
+ before_validation :generate_uid, :generate_secret, on: :create
6
16
 
7
17
  has_many :authorized_tokens, -> { where(revoked_at: nil) }, class_name: 'AccessToken'
8
18
  has_many :authorized_applications, through: :authorized_tokens, source: :application
@@ -20,5 +30,15 @@ module Doorkeeper
20
30
  resource_access_tokens = AccessToken.active_for(resource_owner)
21
31
  where(id: resource_access_tokens.select(:application_id).distinct)
22
32
  end
33
+
34
+ private
35
+
36
+ def generate_uid
37
+ self.uid = UniqueToken.generate if uid.blank?
38
+ end
39
+
40
+ def generate_secret
41
+ self.secret = UniqueToken.generate if secret.blank?
42
+ end
23
43
  end
24
44
  end
@@ -7,7 +7,7 @@ module Doorkeeper
7
7
  # Semantic versioning
8
8
  MAJOR = 4
9
9
  MINOR = 3
10
- TINY = 0
10
+ TINY = 1
11
11
 
12
12
  # Full version number
13
13
  STRING = [MAJOR, MINOR, TINY].compact.join('.')
@@ -116,6 +116,17 @@ Doorkeeper.configure do
116
116
  #
117
117
  # grant_flows %w[authorization_code client_credentials]
118
118
 
119
+ # Hook into the strategies' request & response life-cycle in case your
120
+ # application needs advanced customization or logging:
121
+ #
122
+ # before_successful_strategy_response do |request|
123
+ # puts "BEFORE HOOK FIRED! #{request}"
124
+ # end
125
+ #
126
+ # after_successful_strategy_response do |request, response|
127
+ # puts "AFTER HOOK FIRED! #{request}, #{response}"
128
+ # end
129
+
119
130
  # Under some circumstances you might want to have applications auto-approved,
120
131
  # so that the user skips the authorization step.
121
132
  # For example if dealing with a trusted application.
@@ -24,7 +24,7 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
24
24
  end
25
25
 
26
26
  def translated_error_message(key)
27
- I18n.translate key, scope: [:doorkeeper, :errors, :messages]
27
+ I18n.translate key, scope: %i[doorkeeper errors messages]
28
28
  end
29
29
 
30
30
  let(:client) { FactoryBot.create :application }
@@ -36,7 +36,7 @@ describe Doorkeeper::TokensController do
36
36
  allow(I18n).to receive(:translate).
37
37
  with(
38
38
  custom_message,
39
- hash_including(scope: [:doorkeeper, :errors, :messages]),
39
+ hash_including(scope: %i[doorkeeper errors messages]),
40
40
  ).
41
41
  and_return('Authorization custom message')
42
42
 
@@ -84,6 +84,17 @@ Doorkeeper.configure do
84
84
  #
85
85
  # grant_flows %w[authorization_code client_credentials]
86
86
 
87
+ # Hook into the strategies' request & response life-cycle in case your
88
+ # application needs advanced customization or logging:
89
+ #
90
+ # before_successful_strategy_response do |request|
91
+ # puts "BEFORE HOOK FIRED! #{request}"
92
+ # end
93
+ #
94
+ # after_successful_strategy_response do |request, response|
95
+ # puts "AFTER HOOK FIRED! #{request}, #{response}"
96
+ # end
97
+
87
98
  # Under some circumstances you might want to have applications auto-approved,
88
99
  # so that the user skips the authorization step.
89
100
  # For example if dealing with a trusted application.
@@ -81,9 +81,9 @@ module Doorkeeper::OAuth
81
81
  expect { subject.authorize }.to_not change { Doorkeeper::AccessToken.count }
82
82
  end
83
83
 
84
- it "calls BaseRequest callback methods" do
85
- expect_any_instance_of(BaseRequest).to receive(:before_successful_response).once
86
- expect_any_instance_of(BaseRequest).to receive(:after_successful_response).once
84
+ it "calls configured request callback methods" do
85
+ expect(Doorkeeper.configuration.before_successful_strategy_response).to receive(:call).with(subject).once
86
+ expect(Doorkeeper.configuration.after_successful_strategy_response).to receive(:call).with(subject, instance_of(Doorkeeper::OAuth::TokenResponse)).once
87
87
  subject.authorize
88
88
  end
89
89
 
@@ -69,7 +69,7 @@ module Doorkeeper::OAuth
69
69
  it "returns an ErrorResponse object" do
70
70
  error_description = I18n.translate(
71
71
  "server_error",
72
- scope: [:doorkeeper, :errors, :messages]
72
+ scope: %i[doorkeeper errors messages]
73
73
  )
74
74
 
75
75
  result = subject.authorize
@@ -13,7 +13,7 @@ module Doorkeeper::OAuth
13
13
  it 'is translated from translation messages' do
14
14
  expect(I18n).to receive(:translate).with(
15
15
  :some_error,
16
- scope: [:doorkeeper, :errors, :messages],
16
+ scope: %i[doorkeeper errors messages],
17
17
  default: :server_error
18
18
  )
19
19
  error.description
@@ -67,9 +67,9 @@ module Doorkeeper::OAuth
67
67
  end.to_not change { Doorkeeper::AccessToken.count }
68
68
  end
69
69
 
70
- it "calls BaseRequest callback methods" do
71
- expect_any_instance_of(BaseRequest).to receive(:before_successful_response).once
72
- expect_any_instance_of(BaseRequest).to receive(:after_successful_response).once
70
+ it "calls configured request callback methods" do
71
+ expect(Doorkeeper.configuration.before_successful_strategy_response).to receive(:call).with(subject).once
72
+ expect(Doorkeeper.configuration.after_successful_strategy_response).to receive(:call).with(subject, instance_of(Doorkeeper::OAuth::TokenResponse)).once
73
73
  subject.authorize
74
74
  end
75
75
 
@@ -44,9 +44,9 @@ module Doorkeeper::OAuth
44
44
  expect { subject.authorize }.to change { refresh_token.revoked? }.from(false).to(true)
45
45
  end
46
46
 
47
- it "calls BaseRequest callback methods" do
48
- expect_any_instance_of(BaseRequest).to receive(:before_successful_response).once
49
- expect_any_instance_of(BaseRequest).to receive(:after_successful_response).once
47
+ it "calls configured request callback methods" do
48
+ expect(Doorkeeper.configuration.before_successful_strategy_response).to receive(:call).with(subject).once
49
+ expect(Doorkeeper.configuration.after_successful_strategy_response).to receive(:call).with(subject, instance_of(Doorkeeper::OAuth::TokenResponse)).once
50
50
  subject.authorize
51
51
  end
52
52
 
@@ -22,6 +22,7 @@ describe 'Client Credentials Request' do
22
22
  context 'with scopes' do
23
23
  before do
24
24
  optional_scopes_exist :write
25
+ default_scopes_exist :public
25
26
  end
26
27
 
27
28
  it 'adds the scope to the token an returns in the response' do
@@ -33,6 +34,33 @@ describe 'Client Credentials Request' do
33
34
  should_have_json 'access_token', Doorkeeper::AccessToken.first.token
34
35
  should_have_json 'scope', 'write'
35
36
  end
37
+
38
+ context 'that are default' do
39
+ it 'adds the scope to the token an returns in the response' do
40
+ headers = authorization client.uid, client.secret
41
+ params = { grant_type: 'client_credentials', scope: 'public' }
42
+
43
+ post '/oauth/token', params, headers
44
+
45
+ should_have_json 'access_token', Doorkeeper::AccessToken.first.token
46
+ should_have_json 'scope', 'public'
47
+ end
48
+ end
49
+
50
+ context 'that are invalid' do
51
+ it 'does not authorize the client and returns the error' do
52
+ headers = authorization client.uid, client.secret
53
+ params = { grant_type: 'client_credentials', scope: 'random' }
54
+
55
+ post '/oauth/token', params, headers
56
+
57
+ should_have_json 'error', 'invalid_scope'
58
+ should_have_json 'error_description', translated_error_message(:invalid_scope)
59
+ should_not_have_json 'access_token'
60
+
61
+ expect(response.status).to eq(401)
62
+ end
63
+ end
36
64
  end
37
65
  end
38
66
 
@@ -77,6 +77,45 @@ describe 'Resource Owner Password Credentials Flow' do
77
77
  expect(Doorkeeper::AccessToken.count).to be(1)
78
78
  should_have_json 'access_token', Doorkeeper::AccessToken.first.token
79
79
  end
80
+
81
+ context 'with valid, default scope' do
82
+ before do
83
+ default_scopes_exist :public
84
+ end
85
+
86
+ it 'should issue new token' do
87
+ expect do
88
+ post password_token_endpoint_url(client: @client, resource_owner: @resource_owner, scope: 'public')
89
+ end.to change { Doorkeeper::AccessToken.count }.by(1)
90
+
91
+ token = Doorkeeper::AccessToken.first
92
+
93
+ expect(token.application_id).to eq @client.id
94
+ should_have_json 'access_token', token.token
95
+ should_have_json 'scope', 'public'
96
+ end
97
+ end
98
+ end
99
+
100
+ context 'with invalid scopes' do
101
+ subject do
102
+ post password_token_endpoint_url(client: @client,
103
+ resource_owner: @resource_owner,
104
+ scope: 'random')
105
+ end
106
+
107
+ it 'should not issue new token' do
108
+ expect { subject }.to_not(change { Doorkeeper::AccessToken.count })
109
+ end
110
+
111
+ it 'should return invalid_scope error' do
112
+ subject
113
+ should_have_json 'error', 'invalid_scope'
114
+ should_have_json 'error_description', translated_error_message(:invalid_scope)
115
+ should_not_have_json 'access_token'
116
+
117
+ expect(response.status).to eq(401)
118
+ end
80
119
  end
81
120
 
82
121
  context 'with invalid user credentials' do
@@ -77,7 +77,7 @@ module RequestSpecHelper
77
77
  end
78
78
 
79
79
  def translated_error_message(key)
80
- I18n.translate key, scope: [:doorkeeper, :errors, :messages]
80
+ I18n.translate key, scope: %i[doorkeeper errors messages]
81
81
  end
82
82
 
83
83
  def response_status_should_be(status)
@@ -17,6 +17,7 @@ module UrlHelper
17
17
  client_secret: options[:client_secret] || (options[:client] ? options[:client].secret : nil),
18
18
  username: options[:resource_owner_username] || (options[:resource_owner] ? options[:resource_owner].name : nil),
19
19
  password: options[:resource_owner_password] || (options[:resource_owner] ? options[:resource_owner].password : nil),
20
+ scope: options[:scope],
20
21
  grant_type: 'password'
21
22
  }
22
23
  "/oauth/token?#{build_query(parameters)}"
metadata CHANGED
@@ -1,16 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: doorkeeper
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.3.0
4
+ version: 4.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Felipe Elias Philipp
8
8
  - Tute Costa
9
9
  - Jon Moss
10
+ - Nikita Bulai
10
11
  autorequire:
11
12
  bindir: bin
12
13
  cert_chain: []
13
- date: 2018-02-23 00:00:00.000000000 Z
14
+ date: 2018-03-03 00:00:00.000000000 Z
14
15
  dependencies:
15
16
  - !ruby/object:Gem::Dependency
16
17
  name: railties
@@ -140,7 +141,7 @@ dependencies:
140
141
  version: '0'
141
142
  description: Doorkeeper is an OAuth 2 provider for Rails and Grape.
142
143
  email:
143
- - me@jonathanmoss.me
144
+ - bulaj.nikita@gmail.com
144
145
  executables: []
145
146
  extensions: []
146
147
  extra_rdoc_files: []
@@ -206,6 +207,7 @@ files:
206
207
  - lib/doorkeeper/models/application_mixin.rb
207
208
  - lib/doorkeeper/models/concerns/accessible.rb
208
209
  - lib/doorkeeper/models/concerns/expirable.rb
210
+ - lib/doorkeeper/models/concerns/orderable.rb
209
211
  - lib/doorkeeper/models/concerns/ownership.rb
210
212
  - lib/doorkeeper/models/concerns/revocable.rb
211
213
  - lib/doorkeeper/models/concerns/scopes.rb
@@ -242,7 +244,6 @@ files:
242
244
  - lib/doorkeeper/orm/active_record/access_grant.rb
243
245
  - lib/doorkeeper/orm/active_record/access_token.rb
244
246
  - lib/doorkeeper/orm/active_record/application.rb
245
- - lib/doorkeeper/orm/active_record/base_record.rb
246
247
  - lib/doorkeeper/rails/helpers.rb
247
248
  - lib/doorkeeper/rails/routes.rb
248
249
  - lib/doorkeeper/rails/routes/mapper.rb
@@ -412,7 +413,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
412
413
  version: '0'
413
414
  requirements: []
414
415
  rubyforge_project:
415
- rubygems_version: 2.5.2.2
416
+ rubygems_version: 2.6.11
416
417
  signing_key:
417
418
  specification_version: 4
418
419
  summary: OAuth 2 provider for Rails and Grape
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Doorkeeper
4
- class BaseRecord < ActiveRecord::Base
5
- self.abstract_class = true
6
-
7
- def self.ordered_by(attribute, direction = :asc)
8
- order(attribute => direction)
9
- end
10
- end
11
- end