doorkeeper-sequel 1.5.0 → 2.4.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.
- checksums.yaml +5 -5
- data/.editorconfig +6 -0
- data/.gitignore +1 -0
- data/.gitmodules +0 -1
- data/.rubocop.yml +29 -2
- data/.travis.yml +3 -12
- data/CHANGELOG.md +13 -3
- data/Gemfile +13 -9
- data/README.md +18 -3
- data/Rakefile +22 -18
- data/config/locales/en.yml +11 -0
- data/doorkeeper-sequel.gemspec +27 -23
- data/gemfiles/rails-5.0.gemfile +9 -6
- data/gemfiles/rails-5.1.gemfile +9 -6
- data/gemfiles/rails-5.2.gemfile +9 -6
- data/gemfiles/rails-6.0.gemfile +14 -0
- data/lib/doorkeeper-sequel.rb +21 -17
- data/lib/doorkeeper-sequel/gem_version.rb +5 -3
- data/lib/doorkeeper-sequel/generators/application_owner_generator.rb +5 -3
- data/lib/doorkeeper-sequel/generators/concerns/migration_actions.rb +8 -6
- data/lib/doorkeeper-sequel/generators/confidential_applications_generator.rb +5 -3
- data/lib/doorkeeper-sequel/generators/migration_generator.rb +5 -3
- data/lib/doorkeeper-sequel/generators/pkce_generator.rb +16 -0
- data/lib/doorkeeper-sequel/generators/polymorphic_resource_owner_generator.rb +16 -0
- data/lib/doorkeeper-sequel/generators/previous_refresh_token_generator.rb +5 -3
- data/lib/doorkeeper-sequel/generators/templates/add_confidential_to_application_migration.rb +2 -0
- data/lib/doorkeeper-sequel/generators/templates/add_owner_to_application.rb +3 -1
- data/lib/doorkeeper-sequel/generators/templates/add_previous_refresh_token_to_access_tokens.rb +3 -1
- data/lib/doorkeeper-sequel/generators/templates/create_doorkeeper_tables.rb +7 -3
- data/lib/doorkeeper-sequel/generators/templates/enable_pkce_migration.rb +10 -0
- data/lib/doorkeeper-sequel/generators/templates/enable_polymorphic_resource_owner_migration.rb +15 -0
- data/lib/doorkeeper-sequel/mixins/access_grant_mixin.rb +45 -7
- data/lib/doorkeeper-sequel/mixins/access_token_mixin.rb +154 -42
- data/lib/doorkeeper-sequel/mixins/application_mixin.rb +116 -22
- data/lib/doorkeeper-sequel/mixins/concerns/ownership.rb +2 -0
- data/lib/doorkeeper-sequel/mixins/concerns/sequel_compat.rb +33 -3
- data/lib/doorkeeper-sequel/railtie.rb +3 -1
- data/lib/doorkeeper-sequel/tasks/doorkeeper-sequel.rake +20 -3
- data/lib/doorkeeper-sequel/validators/redirect_uri_validator.rb +35 -6
- data/lib/doorkeeper-sequel/version.rb +3 -1
- data/lib/doorkeeper/orm/sequel.rb +11 -4
- data/lib/doorkeeper/orm/sequel/access_grant.rb +18 -0
- data/lib/doorkeeper/orm/sequel/access_token.rb +6 -0
- data/lib/doorkeeper/orm/sequel/application.rb +34 -3
- data/lib/doorkeeper/orm/sequel/stale_records_cleaner.rb +26 -0
- data/lib/doorkeeper/redirect_uri_validator.rb +9 -0
- data/spec/stubs/config/initializers/db.rb +6 -1
- data/spec/stubs/spec_helper_integration.rb +9 -11
- metadata +225 -235
- data/gemfiles/rails-4.2.gemfile +0 -13
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
gemspec path: ".."
|
6
|
+
|
7
|
+
gem "bcrypt", "~> 3.1"
|
8
|
+
gem "rails", "~> 6.0.0", "<= 6.1"
|
9
|
+
gem "sequel", ">= 4.0"
|
10
|
+
gem "sqlite3", "~> 1.3.5"
|
11
|
+
|
12
|
+
group :test do
|
13
|
+
gem "rspec-rails", "~> 4.0"
|
14
|
+
end
|
data/lib/doorkeeper-sequel.rb
CHANGED
@@ -1,28 +1,32 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
require "doorkeeper-sequel/version"
|
4
|
+
|
5
|
+
require "doorkeeper-sequel/railtie" if defined?(::Rails)
|
6
6
|
|
7
|
-
require
|
8
|
-
require
|
7
|
+
require "doorkeeper"
|
8
|
+
require "doorkeeper/redirect_uri_validator"
|
9
|
+
require "doorkeeper/oauth/nonstandard"
|
10
|
+
require "thor/group"
|
9
11
|
|
10
|
-
require
|
11
|
-
require
|
12
|
-
require
|
13
|
-
require
|
12
|
+
require "doorkeeper-sequel/generators/concerns/migration_actions"
|
13
|
+
require "doorkeeper-sequel/generators/application_owner_generator"
|
14
|
+
require "doorkeeper-sequel/generators/migration_generator"
|
15
|
+
require "doorkeeper-sequel/generators/previous_refresh_token_generator"
|
16
|
+
require "doorkeeper-sequel/generators/confidential_applications_generator"
|
17
|
+
require "doorkeeper-sequel/generators/polymorphic_resource_owner_generator"
|
14
18
|
|
15
|
-
require
|
16
|
-
require
|
17
|
-
require
|
18
|
-
require
|
19
|
+
require "doorkeeper-sequel/mixins/concerns/sequel_compat"
|
20
|
+
require "doorkeeper-sequel/mixins/access_token_mixin"
|
21
|
+
require "doorkeeper-sequel/mixins/access_grant_mixin"
|
22
|
+
require "doorkeeper-sequel/mixins/application_mixin"
|
19
23
|
|
20
|
-
require
|
24
|
+
require "doorkeeper/orm/sequel"
|
21
25
|
|
22
26
|
module DoorkeeperSequel
|
23
27
|
def load_locales
|
24
|
-
locales_dir = File.expand_path(
|
25
|
-
locales = Dir[File.join(locales_dir,
|
28
|
+
locales_dir = File.expand_path("../config/locales", __dir__)
|
29
|
+
locales = Dir[File.join(locales_dir, "*.yml")]
|
26
30
|
|
27
31
|
I18n.load_path |= locales
|
28
32
|
end
|
@@ -1,13 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module DoorkeeperSequel
|
2
4
|
def self.gem_version
|
3
5
|
Gem::Version.new VERSION::STRING
|
4
6
|
end
|
5
7
|
|
6
8
|
module VERSION
|
7
|
-
MAJOR =
|
8
|
-
MINOR =
|
9
|
+
MAJOR = 2
|
10
|
+
MINOR = 4
|
9
11
|
TINY = 0
|
10
12
|
|
11
|
-
STRING = [MAJOR, MINOR, TINY].compact.join(
|
13
|
+
STRING = [MAJOR, MINOR, TINY].compact.join(".")
|
12
14
|
end
|
13
15
|
end
|
@@ -1,14 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module DoorkeeperSequel
|
2
4
|
class ApplicationOwnerGenerator < ::Thor::Group
|
3
5
|
include ::Thor::Actions
|
4
6
|
include MigrationActions
|
5
7
|
|
6
|
-
source_root File.expand_path(
|
8
|
+
source_root File.expand_path("templates", __dir__)
|
7
9
|
|
8
|
-
desc
|
10
|
+
desc "Provide support for client application ownership."
|
9
11
|
|
10
12
|
def install
|
11
|
-
create_migration
|
13
|
+
create_migration "add_owner_to_application.rb"
|
12
14
|
end
|
13
15
|
end
|
14
16
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module DoorkeeperSequel
|
2
4
|
module MigrationActions
|
3
5
|
extend ::ActiveSupport::Concern
|
@@ -9,7 +11,7 @@ module DoorkeeperSequel
|
|
9
11
|
end
|
10
12
|
|
11
13
|
def migration_template
|
12
|
-
File.expand_path(
|
14
|
+
File.expand_path("templates/migration.rb", __dir__)
|
13
15
|
end
|
14
16
|
|
15
17
|
private
|
@@ -19,20 +21,20 @@ module DoorkeeperSequel
|
|
19
21
|
end
|
20
22
|
|
21
23
|
def new_migration_number
|
22
|
-
current_number = current_migration_number(
|
24
|
+
current_number = current_migration_number("db/migrate")
|
23
25
|
|
24
26
|
# possible numeric migration
|
25
|
-
if current_number
|
27
|
+
if current_number&.start_with?("0")
|
26
28
|
# generate the same name as used by the developer
|
27
|
-
"%.#{current_number.length}d"
|
29
|
+
format("%.#{current_number.length}d", (current_number.to_i + 1))
|
28
30
|
else
|
29
|
-
Time.now.utc.strftime(
|
31
|
+
Time.now.utc.strftime("%Y%m%d%H%M%S")
|
30
32
|
end
|
31
33
|
end
|
32
34
|
|
33
35
|
def current_migration_number(dirname)
|
34
36
|
migration_lookup_at(dirname).collect do |file|
|
35
|
-
File.basename(file).split(
|
37
|
+
File.basename(file).split("_").first
|
36
38
|
end.max
|
37
39
|
end
|
38
40
|
|
@@ -1,14 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module DoorkeeperSequel
|
2
4
|
class ConfidentialApplicationsGenerator < ::Thor::Group
|
3
5
|
include ::Thor::Actions
|
4
6
|
include MigrationActions
|
5
7
|
|
6
|
-
source_root File.expand_path(
|
8
|
+
source_root File.expand_path("templates", __dir__)
|
7
9
|
|
8
|
-
desc
|
10
|
+
desc "Add confidential column to Doorkeeper applications."
|
9
11
|
|
10
12
|
def install
|
11
|
-
create_migration
|
13
|
+
create_migration "add_confidential_to_application_migration"
|
12
14
|
end
|
13
15
|
end
|
14
16
|
end
|
@@ -1,14 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module DoorkeeperSequel
|
2
4
|
class MigrationGenerator < ::Thor::Group
|
3
5
|
include ::Thor::Actions
|
4
6
|
include MigrationActions
|
5
7
|
|
6
|
-
source_root File.expand_path(
|
8
|
+
source_root File.expand_path("templates", __dir__)
|
7
9
|
|
8
|
-
desc
|
10
|
+
desc "Installs Doorkeeper Sequel migration file."
|
9
11
|
|
10
12
|
def install
|
11
|
-
create_migration
|
13
|
+
create_migration "create_doorkeeper_tables.rb"
|
12
14
|
end
|
13
15
|
end
|
14
16
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DoorkeeperSequel
|
4
|
+
class PkceGenerator < ::Thor::Group
|
5
|
+
include ::Thor::Actions
|
6
|
+
include MigrationActions
|
7
|
+
|
8
|
+
source_root File.expand_path("templates", __dir__)
|
9
|
+
|
10
|
+
desc "Provide support for PKCE."
|
11
|
+
|
12
|
+
def install
|
13
|
+
create_migration "enable_pkce_migration.rb.erb"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DoorkeeperSequel
|
4
|
+
class PolymorphicResourceOwnerGenerator < ::Thor::Group
|
5
|
+
include ::Thor::Actions
|
6
|
+
include MigrationActions
|
7
|
+
|
8
|
+
source_root File.expand_path("templates", __dir__)
|
9
|
+
|
10
|
+
desc "Provide support for Polymorphic Resource Owner."
|
11
|
+
|
12
|
+
def install
|
13
|
+
create_migration "enable_polymorphic_resource_owner_migration.rb.erb"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -1,14 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module DoorkeeperSequel
|
2
4
|
class PreviousRefreshTokenGenerator < ::Thor::Group
|
3
5
|
include ::Thor::Actions
|
4
6
|
include MigrationActions
|
5
7
|
|
6
|
-
source_root File.expand_path(
|
8
|
+
source_root File.expand_path("templates", __dir__)
|
7
9
|
|
8
|
-
desc
|
10
|
+
desc "Support revoke refresh token on access token use"
|
9
11
|
|
10
12
|
def install
|
11
|
-
create_migration
|
13
|
+
create_migration "add_previous_refresh_token_to_access_tokens.rb"
|
12
14
|
end
|
13
15
|
end
|
14
16
|
end
|
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
Sequel.migration do
|
2
4
|
change do
|
3
5
|
alter_table(:oauth_applications) do
|
4
6
|
add_column :owner_id, Integer, null: true
|
5
7
|
add_column :owner_type, String, null: true
|
6
|
-
add_index [
|
8
|
+
add_index %i[owner_id owner_type]
|
7
9
|
end
|
8
10
|
end
|
9
11
|
end
|
data/lib/doorkeeper-sequel/generators/templates/add_previous_refresh_token_to_access_tokens.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
Sequel.migration do
|
2
4
|
change do
|
3
5
|
alter_table(:oauth_access_tokens) do
|
4
|
-
add_column :previous_refresh_token, String, default:
|
6
|
+
add_column :previous_refresh_token, String, default: "", null: false
|
5
7
|
end
|
6
8
|
end
|
7
9
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
Sequel.migration do
|
2
4
|
change do
|
3
5
|
create_table :oauth_applications do
|
@@ -7,7 +9,7 @@ Sequel.migration do
|
|
7
9
|
column :uid, String, size: 255, null: false, index: { unique: true }
|
8
10
|
column :secret, String, size: 255, null: false
|
9
11
|
|
10
|
-
column :scopes, String, size: 255, null: false, default:
|
12
|
+
column :scopes, String, size: 255, null: false, default: ""
|
11
13
|
column :redirect_uri, String
|
12
14
|
column :confidential, TrueClass, null: false, default: true
|
13
15
|
|
@@ -19,7 +21,8 @@ Sequel.migration do
|
|
19
21
|
primary_key :id
|
20
22
|
foreign_key :application_id, :oauth_applications, null: false, on_delete: :cascade
|
21
23
|
|
22
|
-
column :resource_owner_id, Integer, null: false
|
24
|
+
column :resource_owner_id, Integer, null: false, index: true
|
25
|
+
column :resource_owner_type, String, null: false, index: true
|
23
26
|
|
24
27
|
column :token, String, size: 255, null: false, index: { unique: true }
|
25
28
|
column :expires_in, Integer, null: false
|
@@ -34,6 +37,7 @@ Sequel.migration do
|
|
34
37
|
foreign_key :application_id, :oauth_applications, null: false, on_delete: :cascade
|
35
38
|
|
36
39
|
column :resource_owner_id, Integer, index: true
|
40
|
+
column :resource_owner_type, String, index: true
|
37
41
|
|
38
42
|
# If you use a custom token generator you may need to change this column
|
39
43
|
# from string to text, so that it accepts tokens larger than 255
|
@@ -50,7 +54,7 @@ Sequel.migration do
|
|
50
54
|
# previous tokens are revoked as soon as a new access token is created.
|
51
55
|
# Comment out this line if you'd rather have refresh tokens
|
52
56
|
# instantly revoked.
|
53
|
-
column :previous_refresh_token, String, size: 255, null: false, default:
|
57
|
+
column :previous_refresh_token, String, size: 255, null: false, default: ""
|
54
58
|
column :expires_in, Integer
|
55
59
|
column :revoked_at, DateTime
|
56
60
|
column :created_at, DateTime, null: false
|
data/lib/doorkeeper-sequel/generators/templates/enable_polymorphic_resource_owner_migration.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Sequel.migration do
|
4
|
+
change do
|
5
|
+
alter_table(:oauth_access_grants) do
|
6
|
+
add_column :resource_owner_type, String, default: nil
|
7
|
+
add_index [:resource_owner_id, :resource_owner_type]
|
8
|
+
end
|
9
|
+
|
10
|
+
alter_table(:oauth_access_tokens) do
|
11
|
+
add_column :resource_owner_type, String, default: nil
|
12
|
+
add_index [:resource_owner_id, :resource_owner_type]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module DoorkeeperSequel
|
2
4
|
module AccessGrantMixin
|
3
5
|
extend ActiveSupport::Concern
|
@@ -7,16 +9,17 @@ module DoorkeeperSequel
|
|
7
9
|
include Doorkeeper::Models::Expirable
|
8
10
|
include Doorkeeper::Models::Revocable
|
9
11
|
include Doorkeeper::Models::Accessible
|
12
|
+
include Doorkeeper::Models::SecretStorable
|
10
13
|
include Doorkeeper::Models::Scopes
|
11
14
|
|
12
15
|
included do
|
13
16
|
plugin :validation_helpers
|
14
17
|
plugin :timestamps
|
15
|
-
|
16
|
-
many_to_one :application, class: 'Doorkeeper::Application'
|
18
|
+
many_to_one :application, class: "Doorkeeper::Application"
|
17
19
|
|
18
20
|
set_allowed_columns :resource_owner_id, :application_id,
|
19
|
-
:expires_in, :redirect_uri, :scopes
|
21
|
+
:expires_in, :redirect_uri, :scopes, :code_challenge, :code_challenge_method,
|
22
|
+
:token
|
20
23
|
|
21
24
|
def before_validation
|
22
25
|
generate_token if new?
|
@@ -25,22 +28,57 @@ module DoorkeeperSequel
|
|
25
28
|
|
26
29
|
def validate
|
27
30
|
super
|
28
|
-
validates_presence [
|
29
|
-
|
31
|
+
validates_presence %i[resource_owner_id application_id
|
32
|
+
token expires_in redirect_uri]
|
30
33
|
validates_unique [:token]
|
31
34
|
end
|
32
35
|
end
|
33
36
|
|
34
37
|
module ClassMethods
|
35
38
|
def by_token(token)
|
36
|
-
|
39
|
+
find_by_plaintext_token(:token, token)
|
40
|
+
end
|
41
|
+
|
42
|
+
def find_by(params)
|
43
|
+
first(params)
|
44
|
+
end
|
45
|
+
|
46
|
+
def revoke_all_for(application_id, resource_owner, clock = Time)
|
47
|
+
where(application_id: application_id,
|
48
|
+
resource_owner_id: resource_owner.id,
|
49
|
+
revoked_at: nil)
|
50
|
+
.update(revoked_at: clock.now.utc)
|
51
|
+
end
|
52
|
+
|
53
|
+
def generate_code_challenge(code_verifier)
|
54
|
+
padded_result = Base64.urlsafe_encode64(Digest::SHA256.digest(code_verifier))
|
55
|
+
padded_result.split("=")[0] # Remove any trailing '='
|
56
|
+
end
|
57
|
+
|
58
|
+
def pkce_supported?
|
59
|
+
new.pkce_supported?
|
60
|
+
end
|
61
|
+
|
62
|
+
def secret_strategy
|
63
|
+
::Doorkeeper.configuration.token_secret_strategy
|
64
|
+
end
|
65
|
+
|
66
|
+
def fallback_secret_strategy
|
67
|
+
::Doorkeeper.configuration.token_secret_fallback_strategy
|
37
68
|
end
|
38
69
|
end
|
39
70
|
|
40
71
|
private
|
41
72
|
|
73
|
+
# Generates token value with UniqueToken class.
|
74
|
+
#
|
75
|
+
# @return [String] token value
|
76
|
+
#
|
42
77
|
def generate_token
|
43
|
-
self
|
78
|
+
return nil unless self[:token].nil?
|
79
|
+
|
80
|
+
@raw_token = UniqueToken.generate
|
81
|
+
secret_strategy.store_secret(self, :token, @raw_token)
|
44
82
|
end
|
45
83
|
end
|
46
84
|
end
|
@@ -1,24 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module DoorkeeperSequel
|
2
4
|
module AccessTokenMixin
|
3
5
|
extend ActiveSupport::Concern
|
4
6
|
|
5
7
|
include SequelCompat
|
6
8
|
include Doorkeeper::OAuth::Helpers
|
7
|
-
include Doorkeeper::Models::Expirable
|
8
9
|
include Doorkeeper::Models::Revocable
|
10
|
+
include Doorkeeper::Models::Expirable
|
11
|
+
include Doorkeeper::Models::Reusable
|
9
12
|
include Doorkeeper::Models::Accessible
|
13
|
+
include Doorkeeper::Models::SecretStorable
|
10
14
|
include Doorkeeper::Models::Scopes
|
15
|
+
include Doorkeeper::Models::ResourceOwnerable
|
11
16
|
|
12
17
|
included do
|
13
18
|
plugin :validation_helpers
|
14
19
|
plugin :timestamps
|
15
20
|
|
16
|
-
|
21
|
+
|
22
|
+
many_to_one :application, class: "Doorkeeper::Application"
|
23
|
+
many_to_one :resource_owner, polymorphic: true
|
17
24
|
|
18
25
|
attr_writer :use_refresh_token
|
19
26
|
|
20
|
-
set_allowed_columns :application_id, :resource_owner_id, :
|
21
|
-
|
27
|
+
set_allowed_columns :application_id, :resource_owner_id, :resource_owner_type,
|
28
|
+
:expires_in, :scopes, :use_refresh_token,
|
29
|
+
:previous_refresh_token, :token, :refresh_token
|
22
30
|
|
23
31
|
def before_validation
|
24
32
|
if new?
|
@@ -44,11 +52,15 @@ module DoorkeeperSequel
|
|
44
52
|
|
45
53
|
module ClassMethods
|
46
54
|
def by_token(token)
|
47
|
-
|
55
|
+
find_by_plaintext_token(:token, token)
|
56
|
+
end
|
57
|
+
|
58
|
+
def find_by(params)
|
59
|
+
first(params)
|
48
60
|
end
|
49
61
|
|
50
62
|
def by_refresh_token(refresh_token)
|
51
|
-
|
63
|
+
find_by_plaintext_token(:refresh_token, refresh_token)
|
52
64
|
end
|
53
65
|
|
54
66
|
def revoke_all_for(application_id, resource_owner, clock = Time)
|
@@ -57,6 +69,10 @@ module DoorkeeperSequel
|
|
57
69
|
revoked_at: nil)
|
58
70
|
.update(revoked_at: clock.now.utc)
|
59
71
|
end
|
72
|
+
|
73
|
+
def by_previous_refresh_token(previous_refresh_token)
|
74
|
+
where(refresh_token: previous_refresh_token).first
|
75
|
+
end
|
60
76
|
|
61
77
|
def matching_token_for(application, resource_owner_or_id, scopes)
|
62
78
|
resource_owner_id = if resource_owner_or_id.respond_to?(:to_key)
|
@@ -64,63 +80,127 @@ module DoorkeeperSequel
|
|
64
80
|
else
|
65
81
|
resource_owner_or_id
|
66
82
|
end
|
67
|
-
|
68
|
-
|
69
|
-
token
|
83
|
+
tokens = authorized_tokens_for(application.try(:id), resource_owner_id).all
|
84
|
+
tokens.detect do |token|
|
85
|
+
scopes_match?(token.scopes, scopes, application.try(:scopes))
|
70
86
|
end
|
71
87
|
end
|
72
88
|
|
89
|
+
def find_matching_token(relation, application, scopes)
|
90
|
+
return nil unless relation
|
91
|
+
|
92
|
+
matching_tokens = []
|
93
|
+
|
94
|
+
tokens = relation.select do |token|
|
95
|
+
scopes_match?(token.scopes, scopes, application.try(:scopes))
|
96
|
+
end
|
97
|
+
|
98
|
+
matching_tokens.concat(tokens)
|
99
|
+
matching_tokens.max_by(&:created_at)
|
100
|
+
end
|
101
|
+
|
73
102
|
def scopes_match?(token_scopes, param_scopes, app_scopes)
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
103
|
+
return true if token_scopes.empty? && param_scopes.empty?
|
104
|
+
|
105
|
+
(token_scopes.sort == param_scopes.sort) &&
|
106
|
+
Doorkeeper::OAuth::Helpers::ScopeChecker.valid?(
|
107
|
+
scope_str: param_scopes.to_s,
|
108
|
+
server_scopes: Doorkeeper.configuration.scopes,
|
109
|
+
app_scopes: app_scopes
|
79
110
|
)
|
80
111
|
end
|
81
112
|
|
82
|
-
def
|
113
|
+
def authorized_tokens_for(application_id, resource_owner)
|
114
|
+
by_resource_owner(resource_owner).where(application_id: application_id,
|
115
|
+
revoked_at: nil).order(Sequel.desc(:created_at))
|
116
|
+
end
|
117
|
+
|
118
|
+
def find_or_create_for(*args)
|
119
|
+
attributes = if args.size > 1
|
120
|
+
{
|
121
|
+
application: args[0],
|
122
|
+
resource_owner: args[1],
|
123
|
+
scopes: args[2],
|
124
|
+
expires_in: args[3],
|
125
|
+
use_refresh_token: args[4],
|
126
|
+
}
|
127
|
+
else
|
128
|
+
args.first
|
129
|
+
end
|
130
|
+
|
131
|
+
application = attributes[:application]
|
132
|
+
resource_owner = attributes[:resource_owner]
|
133
|
+
scopes = attributes[:scopes]
|
134
|
+
expires_in = attributes[:expires_in]
|
135
|
+
use_refresh_token = attributes[:use_refresh_token]
|
136
|
+
|
83
137
|
if Doorkeeper.configuration.reuse_access_token
|
84
|
-
access_token = matching_token_for(application,
|
85
|
-
return access_token if access_token
|
138
|
+
access_token = matching_token_for(application, resource_owner, scopes)
|
139
|
+
return access_token if access_token&.reusable?
|
86
140
|
end
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
scopes: scopes
|
141
|
+
|
142
|
+
create_for(
|
143
|
+
application: application,
|
144
|
+
resource_owner: resource_owner,
|
145
|
+
scopes: scopes,
|
92
146
|
expires_in: expires_in,
|
93
|
-
use_refresh_token: use_refresh_token
|
147
|
+
use_refresh_token: use_refresh_token,
|
94
148
|
)
|
95
149
|
end
|
150
|
+
|
151
|
+
def create_for(application:, resource_owner:, scopes:, **token_attributes)
|
152
|
+
token_attributes[:application_id] = application&.id
|
153
|
+
token_attributes[:scopes] = scopes.to_s
|
154
|
+
|
155
|
+
if Doorkeeper.config.polymorphic_resource_owner?
|
156
|
+
token_attributes[:resource_owner] = resource_owner
|
157
|
+
else
|
158
|
+
token_attributes[:resource_owner_id] = resource_owner_id_for(resource_owner)
|
159
|
+
end
|
160
|
+
|
161
|
+
create!(token_attributes)
|
162
|
+
end
|
96
163
|
|
97
164
|
def last_authorized_token_for(application_id, resource_owner_id)
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
165
|
+
authorized_tokens_for(application_id, resource_owner_id).first
|
166
|
+
end
|
167
|
+
|
168
|
+
def secret_strategy
|
169
|
+
::Doorkeeper.configuration.token_secret_strategy
|
170
|
+
end
|
171
|
+
|
172
|
+
def fallback_secret_strategy
|
173
|
+
::Doorkeeper.configuration.token_secret_fallback_strategy
|
174
|
+
end
|
175
|
+
|
176
|
+
def polymorphic_resource_owner?
|
177
|
+
columns.include?(:resource_owner_type)
|
103
178
|
end
|
104
179
|
end
|
105
180
|
|
106
181
|
def token_type
|
107
|
-
|
182
|
+
"Bearer"
|
108
183
|
end
|
109
184
|
|
110
185
|
def use_refresh_token?
|
186
|
+
@use_refresh_token ||= false
|
111
187
|
!!@use_refresh_token
|
112
188
|
end
|
113
189
|
|
114
190
|
def as_json(_options = {})
|
115
191
|
{
|
116
192
|
resource_owner_id: resource_owner_id,
|
117
|
-
|
118
|
-
|
193
|
+
scope: scopes,
|
194
|
+
expires_in: expires_in_seconds,
|
119
195
|
application: { uid: application.try(:uid) },
|
120
|
-
created_at: created_at.to_i
|
121
|
-
}
|
196
|
+
created_at: created_at.to_i,
|
197
|
+
}.tap do |json|
|
198
|
+
if Doorkeeper.configuration.polymorphic_resource_owner?
|
199
|
+
json[:resource_owner_type] = resource_owner_type
|
200
|
+
end
|
201
|
+
end
|
122
202
|
end
|
123
|
-
|
203
|
+
|
124
204
|
# It indicates whether the tokens have the same credential
|
125
205
|
def same_credential?(access_token)
|
126
206
|
application_id == access_token.application_id &&
|
@@ -131,32 +211,64 @@ module DoorkeeperSequel
|
|
131
211
|
accessible? && includes_scope?(*scopes)
|
132
212
|
end
|
133
213
|
|
214
|
+
def plaintext_refresh_token
|
215
|
+
if secret_strategy.allows_restoring_secrets?
|
216
|
+
secret_strategy.restore_secret(self, :refresh_token)
|
217
|
+
else
|
218
|
+
@raw_refresh_token
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def plaintext_token
|
223
|
+
if secret_strategy.allows_restoring_secrets?
|
224
|
+
secret_strategy.restore_secret(self, :token)
|
225
|
+
else
|
226
|
+
@raw_token
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
# Revokes token with `:refresh_token` equal to `:previous_refresh_token`
|
231
|
+
# and clears `:previous_refresh_token` attribute.
|
232
|
+
#
|
233
|
+
def revoke_previous_refresh_token!
|
234
|
+
return unless self.class.refresh_token_revoked_on_use?
|
235
|
+
|
236
|
+
old_refresh_token&.revoke
|
237
|
+
update(previous_refresh_token: "")
|
238
|
+
end
|
239
|
+
|
134
240
|
private
|
135
241
|
|
242
|
+
def old_refresh_token
|
243
|
+
@old_refresh_token ||= self.class.by_previous_refresh_token(previous_refresh_token)
|
244
|
+
end
|
245
|
+
|
136
246
|
def generate_refresh_token
|
137
|
-
|
247
|
+
@raw_refresh_token = UniqueToken.generate
|
248
|
+
secret_strategy.store_secret(self, :refresh_token, @raw_refresh_token)
|
138
249
|
end
|
139
250
|
|
140
251
|
def generate_token
|
141
252
|
self[:created_at] ||= Time.now.utc
|
142
253
|
|
143
|
-
|
144
|
-
unless generator.respond_to?(:generate)
|
145
|
-
raise Doorkeeper::Errors::UnableToGenerateToken, "#{generator} does not respond to `.generate`."
|
146
|
-
end
|
147
|
-
|
148
|
-
self[:token] = generator.generate(
|
254
|
+
@raw_token = token_generator.generate(
|
149
255
|
resource_owner_id: resource_owner_id,
|
150
256
|
scopes: scopes,
|
151
257
|
application: application,
|
152
258
|
expires_in: expires_in,
|
153
259
|
created_at: created_at
|
154
260
|
)
|
261
|
+
secret_strategy.store_secret(self, :token, @raw_token)
|
262
|
+
@raw_token
|
155
263
|
end
|
156
264
|
|
157
265
|
def token_generator
|
158
266
|
generator_name = Doorkeeper.configuration.access_token_generator
|
159
|
-
generator_name.constantize
|
267
|
+
generator = generator_name.constantize
|
268
|
+
|
269
|
+
return generator if generator.respond_to?(:generate)
|
270
|
+
|
271
|
+
raise Doorkeeper::Errors::UnableToGenerateToken, "#{generator} does not respond to `.generate`."
|
160
272
|
rescue NameError
|
161
273
|
raise Doorkeeper::Errors::TokenGeneratorNotFound, "#{generator_name} not found"
|
162
274
|
end
|