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.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE.md +7 -1
- data/.travis.yml +8 -4
- data/NEWS.md +16 -1
- data/README.md +54 -32
- data/SECURITY.md +3 -1
- data/doorkeeper.gemspec +2 -2
- data/lib/doorkeeper.rb +1 -0
- data/lib/doorkeeper/config.rb +3 -1
- data/lib/doorkeeper/models/access_grant_mixin.rb +1 -28
- data/lib/doorkeeper/models/access_token_mixin.rb +9 -34
- data/lib/doorkeeper/models/application_mixin.rb +1 -27
- data/lib/doorkeeper/models/concerns/orderable.rb +13 -0
- data/lib/doorkeeper/oauth/base_request.rb +7 -2
- data/lib/doorkeeper/oauth/invalid_token_response.rb +1 -1
- data/lib/doorkeeper/orm/active_record.rb +0 -1
- data/lib/doorkeeper/orm/active_record/access_grant.rb +28 -1
- data/lib/doorkeeper/orm/active_record/access_token.rb +24 -1
- data/lib/doorkeeper/orm/active_record/application.rb +21 -1
- data/lib/doorkeeper/version.rb +1 -1
- data/lib/generators/doorkeeper/templates/initializer.rb +11 -0
- data/spec/controllers/authorizations_controller_spec.rb +1 -1
- data/spec/controllers/tokens_controller_spec.rb +1 -1
- data/spec/dummy/config/initializers/doorkeeper.rb +11 -0
- data/spec/lib/oauth/authorization_code_request_spec.rb +3 -3
- data/spec/lib/oauth/base_request_spec.rb +1 -1
- data/spec/lib/oauth/error_spec.rb +1 -1
- data/spec/lib/oauth/password_access_token_request_spec.rb +3 -3
- data/spec/lib/oauth/refresh_token_request_spec.rb +3 -3
- data/spec/requests/flows/client_credentials_spec.rb +28 -0
- data/spec/requests/flows/password_spec.rb +39 -0
- data/spec/support/helpers/request_spec_helper.rb +1 -1
- data/spec/support/helpers/url_helper.rb +1 -0
- metadata +6 -5
- 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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8d76a49e22bc442139a55528594bc6a3849fc53d
|
4
|
+
data.tar.gz: eeaca97997f68ca0017c2bbc350323cb1bc9df32
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 961beb33acfb9ba24831ec3e4fbcc2e4cbcc58ccd1a47bd0672aafe9e8e1d993918f1f5bd1ce7df4f3e20ae70a455c6cf698b697489b1247ff6eeecd89950ec0
|
7
|
+
data.tar.gz: ed000ab156a89e92973bc0d22896250ec73ddc52fd7adc6a229b9eb82d1517372b521477af5c394031b9af6164d373967937429093f24179104a6743f2778b87
|
data/.github/ISSUE_TEMPLATE.md
CHANGED
@@ -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**:
|
data/.travis.yml
CHANGED
@@ -4,10 +4,10 @@ sudo: false
|
|
4
4
|
|
5
5
|
rvm:
|
6
6
|
- 2.1
|
7
|
-
- 2.2
|
8
|
-
- 2.3
|
9
|
-
- 2.4
|
10
|
-
- 2.5
|
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
|
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
|
-
- [
|
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
|
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",
|
110
|
-
|
111
|
-
|
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
|
-
|
117
|
-
|
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.
|
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
|
-
|
194
|
-
|
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
|
-
###
|
221
|
+
### Grape endpoints
|
208
222
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
`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
|
-
[
|
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`
|
330
|
-
You may want to use your own
|
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.
|
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
|
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)
|
data/SECURITY.md
CHANGED
@@ -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
|
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
|
|
data/doorkeeper.gemspec
CHANGED
@@ -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(
|
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."
|
data/lib/doorkeeper.rb
CHANGED
@@ -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'
|
data/lib/doorkeeper/config.rb
CHANGED
@@ -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
|
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
|
-
|
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
|
-
|
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
|
@@ -42,9 +42,14 @@ module Doorkeeper
|
|
42
42
|
)
|
43
43
|
end
|
44
44
|
|
45
|
-
def before_successful_response
|
45
|
+
def before_successful_response
|
46
|
+
Doorkeeper.configuration.before_successful_strategy_response.call(self)
|
47
|
+
end
|
46
48
|
|
47
|
-
def after_successful_response
|
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
|
@@ -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 <
|
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 <
|
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 <
|
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
|
data/lib/doorkeeper/version.rb
CHANGED
@@ -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: [
|
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: [
|
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
|
85
|
-
|
86
|
-
|
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
|
|
@@ -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: [
|
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
|
71
|
-
|
72
|
-
|
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
|
48
|
-
|
49
|
-
|
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
|
@@ -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.
|
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-
|
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
|
-
-
|
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.
|
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
|