doorkeeper 5.0.3 → 5.1.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 +4 -4
- data/.hound.yml +2 -1
- data/.rubocop.yml +37 -4
- data/.travis.yml +11 -21
- data/Appraisals +29 -7
- data/Dangerfile +5 -2
- data/Gemfile +19 -5
- data/NEWS.md +81 -21
- data/README.md +75 -485
- data/Rakefile +10 -8
- data/app/controllers/doorkeeper/application_controller.rb +1 -2
- data/app/controllers/doorkeeper/application_metal_controller.rb +2 -13
- data/app/controllers/doorkeeper/applications_controller.rb +20 -8
- data/app/controllers/doorkeeper/authorized_applications_controller.rb +1 -1
- data/app/controllers/doorkeeper/token_info_controller.rb +2 -2
- data/app/controllers/doorkeeper/tokens_controller.rb +11 -11
- data/app/helpers/doorkeeper/dashboard_helper.rb +1 -1
- data/app/validators/redirect_uri_validator.rb +5 -2
- data/app/views/doorkeeper/applications/_form.html.erb +6 -0
- data/app/views/doorkeeper/applications/show.html.erb +1 -1
- data/app/views/layouts/doorkeeper/admin.html.erb +5 -3
- data/bin/console +16 -0
- data/config/locales/en.yml +1 -0
- data/doorkeeper.gemspec +24 -21
- data/gemfiles/rails_5_0.gemfile +9 -4
- data/gemfiles/rails_5_1.gemfile +9 -4
- data/gemfiles/rails_5_2.gemfile +10 -5
- data/gemfiles/rails_6_0.gemfile +17 -0
- data/gemfiles/rails_master.gemfile +9 -9
- data/lib/doorkeeper/config/option.rb +64 -0
- data/lib/doorkeeper/config.rb +191 -75
- data/lib/doorkeeper/engine.rb +1 -1
- data/lib/doorkeeper/grape/authorization_decorator.rb +4 -4
- data/lib/doorkeeper/grape/helpers.rb +3 -3
- data/lib/doorkeeper/helpers/controller.rb +3 -2
- data/lib/doorkeeper/models/access_grant_mixin.rb +20 -3
- data/lib/doorkeeper/models/access_token_mixin.rb +63 -19
- data/lib/doorkeeper/models/application_mixin.rb +43 -1
- data/lib/doorkeeper/models/concerns/expirable.rb +4 -2
- data/lib/doorkeeper/models/concerns/ownership.rb +1 -6
- data/lib/doorkeeper/models/concerns/reusable.rb +19 -0
- data/lib/doorkeeper/models/concerns/revocable.rb +2 -1
- data/lib/doorkeeper/models/concerns/scopes.rb +5 -1
- data/lib/doorkeeper/models/concerns/secret_storable.rb +108 -0
- data/lib/doorkeeper/oauth/authorization/code.rb +2 -2
- data/lib/doorkeeper/oauth/authorization/token.rb +12 -7
- data/lib/doorkeeper/oauth/authorization/uri_builder.rb +1 -1
- data/lib/doorkeeper/oauth/authorization_code_request.rb +6 -4
- data/lib/doorkeeper/oauth/client.rb +1 -1
- data/lib/doorkeeper/oauth/client_credentials/validation.rb +5 -4
- data/lib/doorkeeper/oauth/client_credentials_request.rb +1 -1
- data/lib/doorkeeper/oauth/code_response.rb +2 -2
- data/lib/doorkeeper/oauth/error_response.rb +10 -6
- data/lib/doorkeeper/oauth/forbidden_token_response.rb +1 -1
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +23 -8
- data/lib/doorkeeper/oauth/helpers/unique_token.rb +13 -1
- data/lib/doorkeeper/oauth/helpers/uri_checker.rb +37 -1
- data/lib/doorkeeper/oauth/invalid_token_response.rb +5 -1
- data/lib/doorkeeper/oauth/password_access_token_request.rb +7 -2
- data/lib/doorkeeper/oauth/pre_authorization.rb +11 -5
- data/lib/doorkeeper/oauth/refresh_token_request.rb +5 -2
- data/lib/doorkeeper/oauth/scopes.rb +5 -3
- data/lib/doorkeeper/oauth/token.rb +2 -2
- data/lib/doorkeeper/oauth/token_introspection.rb +74 -8
- data/lib/doorkeeper/oauth/token_response.rb +9 -9
- data/lib/doorkeeper/oauth.rb +5 -5
- data/lib/doorkeeper/orm/active_record/access_grant.rb +27 -13
- data/lib/doorkeeper/orm/active_record/access_token.rb +6 -13
- data/lib/doorkeeper/orm/active_record/application.rb +21 -57
- data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +10 -3
- data/lib/doorkeeper/orm/active_record.rb +6 -6
- data/lib/doorkeeper/rails/helpers.rb +1 -1
- data/lib/doorkeeper/rails/routes/mapping.rb +7 -7
- data/lib/doorkeeper/rails/routes.rb +11 -11
- data/lib/doorkeeper/rake/db.rake +13 -13
- data/lib/doorkeeper/rake.rb +1 -1
- data/lib/doorkeeper/request.rb +1 -1
- data/lib/doorkeeper/secret_storing/base.rb +64 -0
- data/lib/doorkeeper/secret_storing/bcrypt.rb +60 -0
- data/lib/doorkeeper/secret_storing/plain.rb +33 -0
- data/lib/doorkeeper/secret_storing/sha256_hash.rb +26 -0
- data/lib/doorkeeper/stale_records_cleaner.rb +1 -1
- data/lib/doorkeeper/version.rb +3 -3
- data/lib/doorkeeper.rb +69 -60
- data/lib/generators/doorkeeper/application_owner_generator.rb +10 -9
- data/lib/generators/doorkeeper/confidential_applications_generator.rb +10 -9
- data/lib/generators/doorkeeper/install_generator.rb +11 -9
- data/lib/generators/doorkeeper/migration_generator.rb +9 -9
- data/lib/generators/doorkeeper/pkce_generator.rb +10 -9
- data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +10 -9
- data/lib/generators/doorkeeper/templates/initializer.rb +120 -13
- data/lib/generators/doorkeeper/templates/migration.rb.erb +15 -7
- data/lib/generators/doorkeeper/views_generator.rb +6 -4
- data/spec/controllers/application_metal_controller_spec.rb +24 -10
- data/spec/controllers/applications_controller_spec.rb +54 -52
- data/spec/controllers/authorizations_controller_spec.rb +139 -145
- data/spec/controllers/protected_resources_controller_spec.rb +78 -76
- data/spec/controllers/token_info_controller_spec.rb +14 -12
- data/spec/controllers/tokens_controller_spec.rb +167 -108
- data/spec/dummy/Rakefile +3 -1
- data/spec/dummy/app/controllers/application_controller.rb +3 -1
- data/spec/dummy/app/controllers/custom_authorizations_controller.rb +2 -0
- data/spec/dummy/app/controllers/full_protected_resources_controller.rb +4 -2
- data/spec/dummy/app/controllers/home_controller.rb +5 -3
- data/spec/dummy/app/controllers/metal_controller.rb +2 -0
- data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +4 -2
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/models/user.rb +2 -0
- data/spec/dummy/config/application.rb +25 -1
- data/spec/dummy/config/environments/development.rb +2 -0
- data/spec/dummy/config/environments/production.rb +2 -0
- data/spec/dummy/config/environments/test.rb +3 -1
- data/spec/dummy/config/initializers/backtrace_silencers.rb +2 -0
- data/spec/dummy/config/initializers/doorkeeper.rb +5 -2
- data/spec/dummy/config/initializers/secret_token.rb +3 -1
- data/spec/dummy/config/initializers/session_store.rb +3 -1
- data/spec/dummy/config/initializers/wrap_parameters.rb +2 -0
- data/spec/dummy/config.ru +3 -1
- data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +17 -10
- data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +2 -0
- data/spec/dummy/db/schema.rb +1 -1
- data/spec/dummy/script/rails +5 -3
- data/spec/factories.rb +8 -6
- data/spec/generators/application_owner_generator_spec.rb +13 -26
- data/spec/generators/confidential_applications_generator_spec.rb +12 -28
- data/spec/generators/install_generator_spec.rb +17 -15
- data/spec/generators/migration_generator_spec.rb +13 -26
- data/spec/generators/pkce_generator_spec.rb +11 -26
- data/spec/generators/previous_refresh_token_generator_spec.rb +16 -29
- data/spec/generators/templates/routes.rb +2 -0
- data/spec/generators/views_generator_spec.rb +14 -12
- data/spec/grape/grape_integration_spec.rb +34 -32
- data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +9 -7
- data/spec/lib/config_spec.rb +268 -99
- data/spec/lib/doorkeeper_spec.rb +3 -1
- data/spec/lib/models/expirable_spec.rb +22 -8
- data/spec/lib/models/reusable_spec.rb +40 -0
- data/spec/lib/models/revocable_spec.rb +8 -6
- data/spec/lib/models/scopes_spec.rb +27 -13
- data/spec/lib/models/secret_storable_spec.rb +135 -0
- data/spec/lib/oauth/authorization/uri_builder_spec.rb +17 -15
- data/spec/lib/oauth/authorization_code_request_spec.rb +34 -11
- data/spec/lib/oauth/base_request_spec.rb +20 -8
- data/spec/lib/oauth/base_response_spec.rb +3 -1
- data/spec/lib/oauth/client/credentials_spec.rb +24 -22
- data/spec/lib/oauth/client_credentials/creator_spec.rb +56 -10
- data/spec/lib/oauth/client_credentials/issuer_spec.rb +27 -18
- data/spec/lib/oauth/client_credentials/validation_spec.rb +20 -15
- data/spec/lib/oauth/client_credentials_integration_spec.rb +7 -5
- data/spec/lib/oauth/client_credentials_request_spec.rb +27 -21
- data/spec/lib/oauth/client_spec.rb +15 -13
- data/spec/lib/oauth/code_request_spec.rb +8 -6
- data/spec/lib/oauth/code_response_spec.rb +9 -7
- data/spec/lib/oauth/error_response_spec.rb +19 -11
- data/spec/lib/oauth/error_spec.rb +4 -2
- data/spec/lib/oauth/forbidden_token_response_spec.rb +7 -5
- data/spec/lib/oauth/helpers/scope_checker_spec.rb +68 -31
- data/spec/lib/oauth/helpers/unique_token_spec.rb +8 -6
- data/spec/lib/oauth/helpers/uri_checker_spec.rb +115 -95
- data/spec/lib/oauth/invalid_token_response_spec.rb +3 -1
- data/spec/lib/oauth/password_access_token_request_spec.rb +79 -30
- data/spec/lib/oauth/pre_authorization_spec.rb +80 -54
- data/spec/lib/oauth/refresh_token_request_spec.rb +36 -33
- data/spec/lib/oauth/scopes_spec.rb +63 -61
- data/spec/lib/oauth/token_request_spec.rb +79 -24
- data/spec/lib/oauth/token_response_spec.rb +40 -38
- data/spec/lib/oauth/token_spec.rb +60 -44
- data/spec/lib/request/strategy_spec.rb +3 -1
- data/spec/lib/secret_storing/base_spec.rb +60 -0
- data/spec/lib/secret_storing/bcrypt_spec.rb +49 -0
- data/spec/lib/secret_storing/plain_spec.rb +44 -0
- data/spec/lib/secret_storing/sha256_hash_spec.rb +48 -0
- data/spec/lib/server_spec.rb +16 -14
- data/spec/lib/stale_records_cleaner_spec.rb +17 -17
- data/spec/models/doorkeeper/access_grant_spec.rb +80 -15
- data/spec/models/doorkeeper/access_token_spec.rb +198 -73
- data/spec/models/doorkeeper/application_spec.rb +280 -288
- data/spec/requests/applications/applications_request_spec.rb +98 -66
- data/spec/requests/applications/authorized_applications_spec.rb +20 -18
- data/spec/requests/endpoints/authorization_spec.rb +25 -23
- data/spec/requests/endpoints/token_spec.rb +38 -36
- data/spec/requests/flows/authorization_code_errors_spec.rb +26 -24
- data/spec/requests/flows/authorization_code_spec.rb +193 -151
- data/spec/requests/flows/client_credentials_spec.rb +54 -52
- data/spec/requests/flows/implicit_grant_errors_spec.rb +10 -8
- data/spec/requests/flows/implicit_grant_spec.rb +27 -25
- data/spec/requests/flows/password_spec.rb +59 -55
- data/spec/requests/flows/refresh_token_spec.rb +45 -43
- data/spec/requests/flows/revoke_token_spec.rb +40 -54
- data/spec/requests/flows/skip_authorization_spec.rb +23 -21
- data/spec/requests/protected_resources/metal_spec.rb +7 -5
- data/spec/requests/protected_resources/private_api_spec.rb +35 -33
- data/spec/routing/custom_controller_routes_spec.rb +71 -65
- data/spec/routing/default_routes_spec.rb +22 -20
- data/spec/routing/scoped_routes_spec.rb +20 -18
- data/spec/spec_helper.rb +15 -13
- data/spec/spec_helper_integration.rb +3 -1
- data/spec/support/dependencies/factory_bot.rb +3 -1
- data/spec/support/doorkeeper_rspec.rb +3 -1
- data/spec/support/helpers/access_token_request_helper.rb +3 -1
- data/spec/support/helpers/authorization_request_helper.rb +4 -2
- data/spec/support/helpers/config_helper.rb +2 -0
- data/spec/support/helpers/model_helper.rb +3 -1
- data/spec/support/helpers/request_spec_helper.rb +5 -3
- data/spec/support/helpers/url_helper.rb +9 -7
- data/spec/support/http_method_shim.rb +4 -9
- data/spec/support/orm/active_record.rb +3 -1
- data/spec/support/shared/controllers_shared_context.rb +18 -16
- data/spec/support/shared/hashing_shared_context.rb +36 -0
- data/spec/support/shared/models_shared_examples.rb +12 -10
- data/spec/validators/redirect_uri_validator_spec.rb +74 -45
- data/spec/version/version_spec.rb +7 -5
- metadata +60 -26
- data/gemfiles/rails_4_2.gemfile +0 -13
- data/spec/dummy/config/initializers/new_framework_defaults.rb +0 -8
|
@@ -1,12 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Doorkeeper
|
|
2
4
|
class Application < ActiveRecord::Base
|
|
3
|
-
self.table_name = "#{table_name_prefix}oauth_applications#{table_name_suffix}"
|
|
5
|
+
self.table_name = "#{table_name_prefix}oauth_applications#{table_name_suffix}"
|
|
4
6
|
|
|
5
7
|
include ApplicationMixin
|
|
6
|
-
include ActiveModel::MassAssignmentSecurity if defined?(::ProtectedAttributes)
|
|
7
8
|
|
|
8
|
-
has_many :access_grants, dependent: :delete_all, class_name:
|
|
9
|
-
has_many :access_tokens, dependent: :delete_all, class_name:
|
|
9
|
+
has_many :access_grants, dependent: :delete_all, class_name: "Doorkeeper::AccessGrant"
|
|
10
|
+
has_many :access_tokens, dependent: :delete_all, class_name: "Doorkeeper::AccessToken"
|
|
10
11
|
|
|
11
12
|
validates :name, :secret, :uid, presence: true
|
|
12
13
|
validates :uid, uniqueness: true
|
|
@@ -17,7 +18,7 @@ module Doorkeeper
|
|
|
17
18
|
|
|
18
19
|
before_validation :generate_uid, :generate_secret, on: :create
|
|
19
20
|
|
|
20
|
-
has_many :authorized_tokens, -> { where(revoked_at: nil) }, class_name:
|
|
21
|
+
has_many :authorized_tokens, -> { where(revoked_at: nil) }, class_name: "AccessToken"
|
|
21
22
|
has_many :authorized_applications, through: :authorized_tokens, source: :application
|
|
22
23
|
|
|
23
24
|
# Returns Applications associated with active (not revoked) Access Tokens
|
|
@@ -45,26 +46,17 @@ module Doorkeeper
|
|
|
45
46
|
AccessGrant.revoke_all_for(id, resource_owner)
|
|
46
47
|
end
|
|
47
48
|
|
|
48
|
-
#
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
# Respects privacy settings and serializes minimum set of attributes
|
|
52
|
-
# for public/private clients and full set for authorized owners.
|
|
53
|
-
#
|
|
54
|
-
# @return [Hash] entity attributes for JSON
|
|
49
|
+
# We keep a volatile copy of the raw secret for initial communication
|
|
50
|
+
# The stored refresh_token may be mapped and not available in cleartext.
|
|
55
51
|
#
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
super
|
|
52
|
+
# Some strategies allow restoring stored secrets (e.g. symmetric encryption)
|
|
53
|
+
# while hashing strategies do not, so you cannot rely on this value
|
|
54
|
+
# returning a present value for persisted tokens.
|
|
55
|
+
def plaintext_secret
|
|
56
|
+
if secret_strategy.allows_restoring_secrets?
|
|
57
|
+
secret_strategy.restore_secret(self, :secret)
|
|
63
58
|
else
|
|
64
|
-
|
|
65
|
-
# we render only minimum set of attributes that could be exposed to a public
|
|
66
|
-
only = extract_serializable_attributes(options)
|
|
67
|
-
super(options.merge(only: only))
|
|
59
|
+
@raw_secret
|
|
68
60
|
end
|
|
69
61
|
end
|
|
70
62
|
|
|
@@ -75,12 +67,16 @@ module Doorkeeper
|
|
|
75
67
|
end
|
|
76
68
|
|
|
77
69
|
def generate_secret
|
|
78
|
-
|
|
70
|
+
return unless secret.blank?
|
|
71
|
+
|
|
72
|
+
@raw_secret = UniqueToken.generate
|
|
73
|
+
secret_strategy.store_secret(self, :secret, @raw_secret)
|
|
79
74
|
end
|
|
80
75
|
|
|
81
76
|
def scopes_match_configured
|
|
82
77
|
if scopes.present? &&
|
|
83
|
-
!ScopeChecker.valid?(scopes.to_s,
|
|
78
|
+
!ScopeChecker.valid?(scope_str: scopes.to_s,
|
|
79
|
+
server_scopes: Doorkeeper.configuration.scopes)
|
|
84
80
|
errors.add(:scopes, :not_match_configured)
|
|
85
81
|
end
|
|
86
82
|
end
|
|
@@ -88,37 +84,5 @@ module Doorkeeper
|
|
|
88
84
|
def enforce_scopes?
|
|
89
85
|
Doorkeeper.configuration.enforce_configured_scopes?
|
|
90
86
|
end
|
|
91
|
-
|
|
92
|
-
# Helper method to extract collection of serializable attribute names
|
|
93
|
-
# considering serialization options (like `only`, `except` and so on).
|
|
94
|
-
#
|
|
95
|
-
# @param options [Hash] serialization options
|
|
96
|
-
#
|
|
97
|
-
# @return [Array<String>]
|
|
98
|
-
# collection of attributes to be serialized using #as_json
|
|
99
|
-
#
|
|
100
|
-
def extract_serializable_attributes(options = {})
|
|
101
|
-
opts = options.try(:dup) || {}
|
|
102
|
-
only = Array.wrap(opts[:only]).map(&:to_s)
|
|
103
|
-
|
|
104
|
-
only = if only.blank?
|
|
105
|
-
serializable_attributes
|
|
106
|
-
else
|
|
107
|
-
only & serializable_attributes
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
only -= Array.wrap(opts[:except]).map(&:to_s) if opts.key?(:except)
|
|
111
|
-
only.uniq
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
# Collection of attributes that could be serialized for public.
|
|
115
|
-
# Override this method if you need additional attributes to be serialized.
|
|
116
|
-
#
|
|
117
|
-
# @return [Array<String>] collection of serializable attributes
|
|
118
|
-
def serializable_attributes
|
|
119
|
-
attributes = %w[id name created_at]
|
|
120
|
-
attributes << "uid" unless confidential?
|
|
121
|
-
attributes
|
|
122
|
-
end
|
|
123
87
|
end
|
|
124
88
|
end
|
|
@@ -3,22 +3,29 @@
|
|
|
3
3
|
module Doorkeeper
|
|
4
4
|
module Orm
|
|
5
5
|
module ActiveRecord
|
|
6
|
+
# Helper class to clear stale and non-active tokens and grants.
|
|
7
|
+
# Used by Doorkeeper Rake tasks.
|
|
8
|
+
#
|
|
6
9
|
class StaleRecordsCleaner
|
|
7
10
|
def initialize(base_scope)
|
|
8
11
|
@base_scope = base_scope
|
|
9
12
|
end
|
|
10
13
|
|
|
14
|
+
# Clears revoked records
|
|
11
15
|
def clean_revoked
|
|
12
16
|
table = @base_scope.arel_table
|
|
17
|
+
|
|
13
18
|
@base_scope.where.not(revoked_at: nil)
|
|
14
|
-
|
|
15
|
-
|
|
19
|
+
.where(table[:revoked_at].lt(Time.current))
|
|
20
|
+
.in_batches(&:delete_all)
|
|
16
21
|
end
|
|
17
22
|
|
|
23
|
+
# Clears expired records
|
|
18
24
|
def clean_expired(ttl)
|
|
19
25
|
table = @base_scope.arel_table
|
|
26
|
+
|
|
20
27
|
@base_scope.where(table[:created_at].lt(Time.current - ttl))
|
|
21
|
-
|
|
28
|
+
.in_batches(&:delete_all)
|
|
22
29
|
end
|
|
23
30
|
end
|
|
24
31
|
end
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require "active_support/lazy_load_hooks"
|
|
4
4
|
|
|
5
|
-
require
|
|
5
|
+
require "doorkeeper/orm/active_record/stale_records_cleaner"
|
|
6
6
|
|
|
7
7
|
module Doorkeeper
|
|
8
8
|
module Orm
|
|
9
9
|
module ActiveRecord
|
|
10
10
|
def self.initialize_models!
|
|
11
11
|
lazy_load do
|
|
12
|
-
require
|
|
13
|
-
require
|
|
14
|
-
require
|
|
12
|
+
require "doorkeeper/orm/active_record/access_grant"
|
|
13
|
+
require "doorkeeper/orm/active_record/access_token"
|
|
14
|
+
require "doorkeeper/orm/active_record/application"
|
|
15
15
|
|
|
16
16
|
if Doorkeeper.configuration.active_record_options[:establish_connection]
|
|
17
17
|
[Doorkeeper::AccessGrant, Doorkeeper::AccessToken, Doorkeeper::Application].each do |model|
|
|
@@ -24,7 +24,7 @@ module Doorkeeper
|
|
|
24
24
|
|
|
25
25
|
def self.initialize_application_owner!
|
|
26
26
|
lazy_load do
|
|
27
|
-
require
|
|
27
|
+
require "doorkeeper/models/concerns/ownership"
|
|
28
28
|
|
|
29
29
|
Doorkeeper::Application.send :include, Doorkeeper::Models::Ownership
|
|
30
30
|
end
|
|
@@ -8,17 +8,17 @@ module Doorkeeper
|
|
|
8
8
|
|
|
9
9
|
def initialize
|
|
10
10
|
@controllers = {
|
|
11
|
-
authorizations:
|
|
12
|
-
applications:
|
|
13
|
-
authorized_applications:
|
|
14
|
-
tokens:
|
|
15
|
-
token_info:
|
|
11
|
+
authorizations: "doorkeeper/authorizations",
|
|
12
|
+
applications: "doorkeeper/applications",
|
|
13
|
+
authorized_applications: "doorkeeper/authorized_applications",
|
|
14
|
+
tokens: "doorkeeper/tokens",
|
|
15
|
+
token_info: "doorkeeper/token_info",
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
@as = {
|
|
19
19
|
authorizations: :authorization,
|
|
20
20
|
tokens: :token,
|
|
21
|
-
token_info: :token_info
|
|
21
|
+
token_info: :token_info,
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
@skips = []
|
|
@@ -27,7 +27,7 @@ module Doorkeeper
|
|
|
27
27
|
def [](routes)
|
|
28
28
|
{
|
|
29
29
|
controllers: @controllers[routes],
|
|
30
|
-
as: @as[routes]
|
|
30
|
+
as: @as[routes],
|
|
31
31
|
}
|
|
32
32
|
end
|
|
33
33
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
3
|
+
require "doorkeeper/rails/routes/mapping"
|
|
4
|
+
require "doorkeeper/rails/routes/mapper"
|
|
5
5
|
|
|
6
6
|
module Doorkeeper
|
|
7
7
|
module Rails
|
|
@@ -32,7 +32,7 @@ module Doorkeeper
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
def generate_routes!(options)
|
|
35
|
-
routes.scope options[:scope] ||
|
|
35
|
+
routes.scope options[:scope] || "oauth", as: "oauth" do
|
|
36
36
|
map_route(:authorizations, :authorization_routes)
|
|
37
37
|
map_route(:tokens, :token_routes)
|
|
38
38
|
map_route(:tokens, :revoke_routes)
|
|
@@ -56,37 +56,37 @@ module Doorkeeper
|
|
|
56
56
|
def authorization_routes(mapping)
|
|
57
57
|
routes.resource(
|
|
58
58
|
:authorization,
|
|
59
|
-
path:
|
|
59
|
+
path: "authorize",
|
|
60
60
|
only: %i[create destroy],
|
|
61
61
|
as: mapping[:as],
|
|
62
62
|
controller: mapping[:controllers]
|
|
63
63
|
) do
|
|
64
|
-
routes.get
|
|
65
|
-
routes.get
|
|
64
|
+
routes.get "/native", action: :show, on: :member
|
|
65
|
+
routes.get "/", action: :new, on: :member
|
|
66
66
|
end
|
|
67
67
|
end
|
|
68
68
|
|
|
69
69
|
def token_routes(mapping)
|
|
70
70
|
routes.resource(
|
|
71
71
|
:token,
|
|
72
|
-
path:
|
|
72
|
+
path: "token",
|
|
73
73
|
only: [:create], as: mapping[:as],
|
|
74
74
|
controller: mapping[:controllers]
|
|
75
75
|
)
|
|
76
76
|
end
|
|
77
77
|
|
|
78
78
|
def revoke_routes(mapping)
|
|
79
|
-
routes.post
|
|
79
|
+
routes.post "revoke", controller: mapping[:controllers], action: :revoke
|
|
80
80
|
end
|
|
81
81
|
|
|
82
82
|
def introspect_routes(mapping)
|
|
83
|
-
routes.post
|
|
83
|
+
routes.post "introspect", controller: mapping[:controllers], action: :introspect
|
|
84
84
|
end
|
|
85
85
|
|
|
86
86
|
def token_info_routes(mapping)
|
|
87
87
|
routes.resource(
|
|
88
88
|
:token_info,
|
|
89
|
-
path:
|
|
89
|
+
path: "token/info",
|
|
90
90
|
only: [:show], as: mapping[:as],
|
|
91
91
|
controller: mapping[:controllers]
|
|
92
92
|
)
|
|
@@ -96,7 +96,7 @@ module Doorkeeper
|
|
|
96
96
|
routes.resources :doorkeeper_applications,
|
|
97
97
|
controller: mapping[:controllers],
|
|
98
98
|
as: :applications,
|
|
99
|
-
path:
|
|
99
|
+
path: "applications"
|
|
100
100
|
end
|
|
101
101
|
|
|
102
102
|
def authorized_applications_routes(mapping)
|
data/lib/doorkeeper/rake/db.rake
CHANGED
|
@@ -2,36 +2,36 @@
|
|
|
2
2
|
|
|
3
3
|
namespace :doorkeeper do
|
|
4
4
|
namespace :db do
|
|
5
|
-
desc
|
|
5
|
+
desc "Removes stale data from doorkeeper related database tables"
|
|
6
6
|
task cleanup: [
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
"doorkeeper:db:cleanup:revoked_tokens",
|
|
8
|
+
"doorkeeper:db:cleanup:expired_tokens",
|
|
9
|
+
"doorkeeper:db:cleanup:revoked_grants",
|
|
10
|
+
"doorkeeper:db:cleanup:expired_grants",
|
|
11
11
|
]
|
|
12
12
|
|
|
13
13
|
namespace :cleanup do
|
|
14
|
-
desc
|
|
15
|
-
task revoked_tokens:
|
|
14
|
+
desc "Removes stale access tokens"
|
|
15
|
+
task revoked_tokens: "doorkeeper:setup" do
|
|
16
16
|
cleaner = Doorkeeper::StaleRecordsCleaner.new(Doorkeeper::AccessToken)
|
|
17
17
|
cleaner.clean_revoked
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
desc
|
|
21
|
-
task expired_tokens:
|
|
20
|
+
desc "Removes expired (TTL passed) access tokens"
|
|
21
|
+
task expired_tokens: "doorkeeper:setup" do
|
|
22
22
|
expirable_tokens = Doorkeeper::AccessToken.where(refresh_token: nil)
|
|
23
23
|
cleaner = Doorkeeper::StaleRecordsCleaner.new(expirable_tokens)
|
|
24
24
|
cleaner.clean_expired(Doorkeeper.configuration.access_token_expires_in)
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
-
desc
|
|
28
|
-
task revoked_grants:
|
|
27
|
+
desc "Removes stale access grants"
|
|
28
|
+
task revoked_grants: "doorkeeper:setup" do
|
|
29
29
|
cleaner = Doorkeeper::StaleRecordsCleaner.new(Doorkeeper::AccessGrant)
|
|
30
30
|
cleaner.clean_revoked
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
-
desc
|
|
34
|
-
task expired_grants:
|
|
33
|
+
desc "Removes expired (TTL passed) access grants"
|
|
34
|
+
task expired_grants: "doorkeeper:setup" do
|
|
35
35
|
cleaner = Doorkeeper::StaleRecordsCleaner.new(Doorkeeper::AccessGrant)
|
|
36
36
|
cleaner.clean_expired(Doorkeeper.configuration.authorization_code_expires_in)
|
|
37
37
|
end
|
data/lib/doorkeeper/rake.rb
CHANGED
data/lib/doorkeeper/request.rb
CHANGED
|
@@ -33,7 +33,7 @@ module Doorkeeper
|
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
def build_strategy_class(grant_or_request_type)
|
|
36
|
-
strategy_class_name = grant_or_request_type.to_s.tr(
|
|
36
|
+
strategy_class_name = grant_or_request_type.to_s.tr(" ", "_").camelize
|
|
37
37
|
"Doorkeeper::Request::#{strategy_class_name}".constantize
|
|
38
38
|
end
|
|
39
39
|
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Doorkeeper
|
|
4
|
+
module SecretStoring
|
|
5
|
+
##
|
|
6
|
+
# Base class for secret storing, including common helpers
|
|
7
|
+
class Base
|
|
8
|
+
##
|
|
9
|
+
# Return the value to be stored by the database
|
|
10
|
+
# used for looking up a database value.
|
|
11
|
+
# @param plain_secret The plain secret input / generated
|
|
12
|
+
def self.transform_secret(_plain_secret)
|
|
13
|
+
raise NotImplementedError
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
##
|
|
17
|
+
# Transform and store the given secret attribute => value
|
|
18
|
+
# pair used for safely storing the attribute
|
|
19
|
+
# @param resource The model instance being modified
|
|
20
|
+
# @param attribute The secret attribute
|
|
21
|
+
# @param plain_secret The plain secret input / generated
|
|
22
|
+
def self.store_secret(resource, attribute, plain_secret)
|
|
23
|
+
transformed_value = transform_secret(plain_secret)
|
|
24
|
+
resource.public_send(:"#{attribute}=", transformed_value)
|
|
25
|
+
|
|
26
|
+
transformed_value
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
##
|
|
30
|
+
# Return the restored value from the database
|
|
31
|
+
# @param resource The resource instance to act on
|
|
32
|
+
# @param attribute The secret attribute to restore
|
|
33
|
+
# as retrieved from the database.
|
|
34
|
+
def self.restore_secret(_resource, _attribute)
|
|
35
|
+
raise NotImplementedError
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
##
|
|
39
|
+
# Determines whether this strategy supports restoring
|
|
40
|
+
# secrets from the database. This allows detecting users
|
|
41
|
+
# trying to use a non-restorable strategy with +reuse_access_tokens+.
|
|
42
|
+
def self.allows_restoring_secrets?
|
|
43
|
+
false
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
##
|
|
47
|
+
# Determines what secrets this strategy is applicable for
|
|
48
|
+
def self.validate_for(model)
|
|
49
|
+
valid = %i[token application]
|
|
50
|
+
return true if valid.include?(model.to_sym)
|
|
51
|
+
|
|
52
|
+
raise ArgumentError, "'#{name}' can not be used for #{model}."
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
##
|
|
56
|
+
# Securely compare the given +input+ value with a +stored+ value
|
|
57
|
+
# processed by +transform_secret+.
|
|
58
|
+
def self.secret_matches?(input, stored)
|
|
59
|
+
transformed_input = transform_secret(input)
|
|
60
|
+
ActiveSupport::SecurityUtils.secure_compare transformed_input, stored
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Doorkeeper
|
|
4
|
+
module SecretStoring
|
|
5
|
+
##
|
|
6
|
+
# Plain text secret storing, which is the default
|
|
7
|
+
# but also provides fallback lookup if
|
|
8
|
+
# other secret storing mechanisms are enabled.
|
|
9
|
+
class BCrypt < Base
|
|
10
|
+
##
|
|
11
|
+
# Return the value to be stored by the database
|
|
12
|
+
# @param plain_secret The plain secret input / generated
|
|
13
|
+
def self.transform_secret(plain_secret)
|
|
14
|
+
::BCrypt::Password.create(plain_secret.to_s)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
##
|
|
18
|
+
# Securely compare the given +input+ value with a +stored+ value
|
|
19
|
+
# processed by +transform_secret+.
|
|
20
|
+
def self.secret_matches?(input, stored)
|
|
21
|
+
::BCrypt::Password.new(stored.to_s) == input.to_s
|
|
22
|
+
rescue ::BCrypt::Errors::InvalidHash
|
|
23
|
+
false
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
##
|
|
27
|
+
# Determines whether this strategy supports restoring
|
|
28
|
+
# secrets from the database. This allows detecting users
|
|
29
|
+
# trying to use a non-restorable strategy with +reuse_access_tokens+.
|
|
30
|
+
def self.allows_restoring_secrets?
|
|
31
|
+
false
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
##
|
|
35
|
+
# Determines what secrets this strategy is applicable for
|
|
36
|
+
def self.validate_for(model)
|
|
37
|
+
unless model.to_sym == :application
|
|
38
|
+
raise ArgumentError,
|
|
39
|
+
"'#{name}' can only be used for storing application secrets."
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
unless bcrypt_present?
|
|
43
|
+
raise ArgumentError,
|
|
44
|
+
"'#{name}' requires the 'bcrypt' gem being loaded."
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
true
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
##
|
|
51
|
+
# Test if we can require the BCrypt gem
|
|
52
|
+
def self.bcrypt_present?
|
|
53
|
+
require "bcrypt"
|
|
54
|
+
true
|
|
55
|
+
rescue LoadError
|
|
56
|
+
false
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Doorkeeper
|
|
4
|
+
module SecretStoring
|
|
5
|
+
##
|
|
6
|
+
# Plain text secret storing, which is the default
|
|
7
|
+
# but also provides fallback lookup if
|
|
8
|
+
# other secret storing mechanisms are enabled.
|
|
9
|
+
class Plain < Base
|
|
10
|
+
##
|
|
11
|
+
# Return the value to be stored by the database
|
|
12
|
+
# @param plain_secret The plain secret input / generated
|
|
13
|
+
def self.transform_secret(plain_secret)
|
|
14
|
+
plain_secret
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
##
|
|
18
|
+
# Return the restored value from the database
|
|
19
|
+
# @param resource The resource instance to act on
|
|
20
|
+
# @param attribute The secret attribute to restore
|
|
21
|
+
# as retrieved from the database.
|
|
22
|
+
def self.restore_secret(resource, attribute)
|
|
23
|
+
resource.public_send(attribute)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
##
|
|
27
|
+
# Plain values obviously allow restoring
|
|
28
|
+
def self.allows_restoring_secrets?
|
|
29
|
+
true
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Doorkeeper
|
|
4
|
+
module SecretStoring
|
|
5
|
+
##
|
|
6
|
+
# Plain text secret storing, which is the default
|
|
7
|
+
# but also provides fallback lookup if
|
|
8
|
+
# other secret storing mechanisms are enabled.
|
|
9
|
+
class Sha256Hash < Base
|
|
10
|
+
##
|
|
11
|
+
# Return the value to be stored by the database
|
|
12
|
+
# @param plain_secret The plain secret input / generated
|
|
13
|
+
def self.transform_secret(plain_secret)
|
|
14
|
+
::Digest::SHA256.hexdigest plain_secret
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
##
|
|
18
|
+
# Determines whether this strategy supports restoring
|
|
19
|
+
# secrets from the database. This allows detecting users
|
|
20
|
+
# trying to use a non-restorable strategy with +reuse_access_tokens+.
|
|
21
|
+
def self.allows_restoring_secrets?
|
|
22
|
+
false
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
data/lib/doorkeeper/version.rb
CHANGED
|
@@ -8,11 +8,11 @@ module Doorkeeper
|
|
|
8
8
|
module VERSION
|
|
9
9
|
# Semantic versioning
|
|
10
10
|
MAJOR = 5
|
|
11
|
-
MINOR =
|
|
12
|
-
TINY =
|
|
11
|
+
MINOR = 1
|
|
12
|
+
TINY = 0
|
|
13
13
|
PRE = nil
|
|
14
14
|
|
|
15
15
|
# Full version number
|
|
16
|
-
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(
|
|
16
|
+
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
|
|
17
17
|
end
|
|
18
18
|
end
|