doorkeeper 5.1.2 → 5.6.6
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/{NEWS.md → CHANGELOG.md} +314 -27
- data/README.md +39 -22
- data/app/controllers/doorkeeper/application_controller.rb +3 -2
- data/app/controllers/doorkeeper/application_metal_controller.rb +3 -2
- data/app/controllers/doorkeeper/applications_controller.rb +5 -4
- data/app/controllers/doorkeeper/authorizations_controller.rb +76 -25
- data/app/controllers/doorkeeper/authorized_applications_controller.rb +5 -5
- data/app/controllers/doorkeeper/token_info_controller.rb +12 -2
- data/app/controllers/doorkeeper/tokens_controller.rb +99 -28
- data/app/helpers/doorkeeper/dashboard_helper.rb +1 -1
- data/app/views/doorkeeper/applications/_form.html.erb +1 -7
- data/app/views/doorkeeper/applications/show.html.erb +35 -14
- data/app/views/doorkeeper/authorizations/error.html.erb +3 -1
- data/app/views/doorkeeper/authorizations/form_post.html.erb +15 -0
- data/app/views/doorkeeper/authorizations/new.html.erb +16 -14
- data/config/locales/en.yml +16 -3
- data/lib/doorkeeper/config/abstract_builder.rb +28 -0
- data/lib/doorkeeper/config/option.rb +20 -2
- data/lib/doorkeeper/config/validations.rb +53 -0
- data/lib/doorkeeper/config.rb +300 -136
- data/lib/doorkeeper/engine.rb +10 -3
- data/lib/doorkeeper/errors.rb +13 -18
- data/lib/doorkeeper/grant_flow/fallback_flow.rb +15 -0
- data/lib/doorkeeper/grant_flow/flow.rb +44 -0
- data/lib/doorkeeper/grant_flow/registry.rb +50 -0
- data/lib/doorkeeper/grant_flow.rb +45 -0
- data/lib/doorkeeper/grape/helpers.rb +7 -3
- data/lib/doorkeeper/helpers/controller.rb +36 -11
- data/lib/doorkeeper/models/access_grant_mixin.rb +23 -19
- data/lib/doorkeeper/models/access_token_mixin.rb +195 -52
- data/lib/doorkeeper/models/application_mixin.rb +8 -7
- data/lib/doorkeeper/models/concerns/expirable.rb +1 -1
- data/lib/doorkeeper/models/concerns/expiration_time_sql_math.rb +88 -0
- data/lib/doorkeeper/models/concerns/ownership.rb +1 -1
- data/lib/doorkeeper/models/concerns/polymorphic_resource_owner.rb +30 -0
- data/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
- data/lib/doorkeeper/models/concerns/reusable.rb +1 -1
- data/lib/doorkeeper/models/concerns/revocable.rb +1 -28
- data/lib/doorkeeper/models/concerns/scopes.rb +5 -1
- data/lib/doorkeeper/models/concerns/secret_storable.rb +1 -3
- data/lib/doorkeeper/oauth/authorization/code.rb +31 -14
- data/lib/doorkeeper/oauth/authorization/context.rb +5 -5
- data/lib/doorkeeper/oauth/authorization/token.rb +30 -19
- data/lib/doorkeeper/oauth/authorization/uri_builder.rb +4 -4
- data/lib/doorkeeper/oauth/authorization_code_request.rb +51 -22
- data/lib/doorkeeper/oauth/base_request.rb +21 -22
- data/lib/doorkeeper/oauth/client/credentials.rb +2 -4
- data/lib/doorkeeper/oauth/client.rb +8 -9
- data/lib/doorkeeper/oauth/client_credentials/creator.rb +42 -5
- data/lib/doorkeeper/oauth/client_credentials/issuer.rb +10 -8
- data/lib/doorkeeper/oauth/client_credentials/{validation.rb → validator.rb} +14 -5
- data/lib/doorkeeper/oauth/client_credentials_request.rb +8 -7
- data/lib/doorkeeper/oauth/code_request.rb +6 -12
- data/lib/doorkeeper/oauth/code_response.rb +24 -14
- data/lib/doorkeeper/oauth/error.rb +1 -1
- data/lib/doorkeeper/oauth/error_response.rb +11 -13
- data/lib/doorkeeper/oauth/forbidden_token_response.rb +2 -1
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +8 -12
- data/lib/doorkeeper/oauth/helpers/unique_token.rb +10 -7
- data/lib/doorkeeper/oauth/helpers/uri_checker.rb +19 -23
- data/lib/doorkeeper/oauth/hooks/context.rb +21 -0
- data/lib/doorkeeper/oauth/invalid_request_response.rb +43 -0
- data/lib/doorkeeper/oauth/invalid_token_response.rb +7 -4
- data/lib/doorkeeper/oauth/nonstandard.rb +39 -0
- data/lib/doorkeeper/oauth/password_access_token_request.rb +34 -11
- data/lib/doorkeeper/oauth/pre_authorization.rb +114 -44
- data/lib/doorkeeper/oauth/refresh_token_request.rb +54 -34
- data/lib/doorkeeper/oauth/token.rb +6 -7
- data/lib/doorkeeper/oauth/token_introspection.rb +28 -22
- data/lib/doorkeeper/oauth/token_request.rb +6 -20
- data/lib/doorkeeper/oauth/token_response.rb +2 -3
- data/lib/doorkeeper/orm/active_record/access_grant.rb +4 -43
- data/lib/doorkeeper/orm/active_record/access_token.rb +4 -35
- data/lib/doorkeeper/orm/active_record/application.rb +5 -149
- data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +63 -0
- data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +77 -0
- data/lib/doorkeeper/orm/active_record/mixins/application.rb +210 -0
- data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +66 -0
- data/lib/doorkeeper/orm/active_record/stale_records_cleaner.rb +5 -2
- data/lib/doorkeeper/orm/active_record.rb +29 -22
- data/lib/doorkeeper/rails/helpers.rb +4 -4
- data/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
- data/lib/doorkeeper/rails/routes/mapper.rb +2 -2
- data/lib/doorkeeper/rails/routes/registry.rb +45 -0
- data/lib/doorkeeper/rails/routes.rb +28 -27
- data/lib/doorkeeper/rake/db.rake +6 -6
- data/lib/doorkeeper/request/authorization_code.rb +5 -3
- data/lib/doorkeeper/request/client_credentials.rb +2 -2
- data/lib/doorkeeper/request/password.rb +3 -2
- data/lib/doorkeeper/request/refresh_token.rb +5 -4
- data/lib/doorkeeper/request/strategy.rb +2 -2
- data/lib/doorkeeper/request.rb +49 -17
- data/lib/doorkeeper/server.rb +7 -11
- data/lib/doorkeeper/stale_records_cleaner.rb +6 -2
- data/lib/doorkeeper/version.rb +2 -6
- data/lib/doorkeeper.rb +183 -80
- data/lib/generators/doorkeeper/application_owner_generator.rb +1 -1
- data/lib/generators/doorkeeper/confidential_applications_generator.rb +2 -2
- data/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
- data/lib/generators/doorkeeper/migration_generator.rb +1 -1
- data/lib/generators/doorkeeper/pkce_generator.rb +1 -1
- data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +7 -7
- data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +3 -1
- data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb +2 -0
- data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +2 -0
- data/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
- data/lib/generators/doorkeeper/templates/initializer.rb +230 -50
- data/lib/generators/doorkeeper/templates/migration.rb.erb +31 -9
- metadata +61 -327
- data/.coveralls.yml +0 -1
- data/.github/ISSUE_TEMPLATE.md +0 -25
- data/.github/PULL_REQUEST_TEMPLATE.md +0 -17
- data/.gitignore +0 -20
- data/.gitlab-ci.yml +0 -16
- data/.hound.yml +0 -3
- data/.rspec +0 -1
- data/.rubocop.yml +0 -50
- data/.travis.yml +0 -35
- data/Appraisals +0 -40
- data/CODE_OF_CONDUCT.md +0 -46
- data/CONTRIBUTING.md +0 -47
- data/Dangerfile +0 -67
- data/Gemfile +0 -24
- data/RELEASING.md +0 -10
- data/Rakefile +0 -28
- data/SECURITY.md +0 -15
- data/UPGRADE.md +0 -2
- data/app/validators/redirect_uri_validator.rb +0 -50
- data/bin/console +0 -16
- data/doorkeeper.gemspec +0 -34
- data/gemfiles/rails_5_0.gemfile +0 -17
- data/gemfiles/rails_5_1.gemfile +0 -17
- data/gemfiles/rails_5_2.gemfile +0 -17
- data/gemfiles/rails_6_0.gemfile +0 -17
- data/gemfiles/rails_master.gemfile +0 -17
- data/spec/controllers/application_metal_controller_spec.rb +0 -64
- data/spec/controllers/applications_controller_spec.rb +0 -180
- data/spec/controllers/authorizations_controller_spec.rb +0 -527
- data/spec/controllers/protected_resources_controller_spec.rb +0 -353
- data/spec/controllers/token_info_controller_spec.rb +0 -50
- data/spec/controllers/tokens_controller_spec.rb +0 -330
- data/spec/dummy/Rakefile +0 -9
- data/spec/dummy/app/assets/config/manifest.js +0 -2
- data/spec/dummy/app/controllers/application_controller.rb +0 -5
- data/spec/dummy/app/controllers/custom_authorizations_controller.rb +0 -9
- data/spec/dummy/app/controllers/full_protected_resources_controller.rb +0 -14
- data/spec/dummy/app/controllers/home_controller.rb +0 -18
- data/spec/dummy/app/controllers/metal_controller.rb +0 -13
- data/spec/dummy/app/controllers/semi_protected_resources_controller.rb +0 -13
- data/spec/dummy/app/helpers/application_helper.rb +0 -7
- data/spec/dummy/app/models/user.rb +0 -7
- data/spec/dummy/app/views/home/index.html.erb +0 -0
- data/spec/dummy/app/views/layouts/application.html.erb +0 -14
- data/spec/dummy/config/application.rb +0 -47
- data/spec/dummy/config/boot.rb +0 -7
- data/spec/dummy/config/database.yml +0 -15
- data/spec/dummy/config/environment.rb +0 -5
- data/spec/dummy/config/environments/development.rb +0 -31
- data/spec/dummy/config/environments/production.rb +0 -64
- data/spec/dummy/config/environments/test.rb +0 -45
- data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -9
- data/spec/dummy/config/initializers/doorkeeper.rb +0 -121
- data/spec/dummy/config/initializers/secret_token.rb +0 -10
- data/spec/dummy/config/initializers/session_store.rb +0 -10
- data/spec/dummy/config/initializers/wrap_parameters.rb +0 -16
- data/spec/dummy/config/locales/doorkeeper.en.yml +0 -5
- data/spec/dummy/config/routes.rb +0 -13
- data/spec/dummy/config.ru +0 -6
- data/spec/dummy/db/migrate/20111122132257_create_users.rb +0 -11
- data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +0 -7
- data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +0 -69
- data/spec/dummy/db/migrate/20151223200000_add_owner_to_application.rb +0 -9
- data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +0 -13
- data/spec/dummy/db/migrate/20170822064514_enable_pkce.rb +0 -8
- data/spec/dummy/db/migrate/20180210183654_add_confidential_to_applications.rb +0 -13
- data/spec/dummy/db/schema.rb +0 -68
- data/spec/dummy/public/404.html +0 -26
- data/spec/dummy/public/422.html +0 -26
- data/spec/dummy/public/500.html +0 -26
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +0 -9
- data/spec/factories.rb +0 -30
- data/spec/generators/application_owner_generator_spec.rb +0 -28
- data/spec/generators/confidential_applications_generator_spec.rb +0 -29
- data/spec/generators/install_generator_spec.rb +0 -36
- data/spec/generators/migration_generator_spec.rb +0 -28
- data/spec/generators/pkce_generator_spec.rb +0 -28
- data/spec/generators/previous_refresh_token_generator_spec.rb +0 -44
- data/spec/generators/templates/routes.rb +0 -4
- data/spec/generators/views_generator_spec.rb +0 -29
- data/spec/grape/grape_integration_spec.rb +0 -137
- data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +0 -26
- data/spec/lib/config_spec.rb +0 -697
- data/spec/lib/doorkeeper_spec.rb +0 -27
- data/spec/lib/models/expirable_spec.rb +0 -61
- data/spec/lib/models/reusable_spec.rb +0 -40
- data/spec/lib/models/revocable_spec.rb +0 -59
- data/spec/lib/models/scopes_spec.rb +0 -53
- data/spec/lib/models/secret_storable_spec.rb +0 -135
- data/spec/lib/oauth/authorization/uri_builder_spec.rb +0 -39
- data/spec/lib/oauth/authorization_code_request_spec.rb +0 -156
- data/spec/lib/oauth/base_request_spec.rb +0 -205
- data/spec/lib/oauth/base_response_spec.rb +0 -47
- data/spec/lib/oauth/client/credentials_spec.rb +0 -90
- data/spec/lib/oauth/client_credentials/creator_spec.rb +0 -94
- data/spec/lib/oauth/client_credentials/issuer_spec.rb +0 -112
- data/spec/lib/oauth/client_credentials/validation_spec.rb +0 -59
- data/spec/lib/oauth/client_credentials_integration_spec.rb +0 -29
- data/spec/lib/oauth/client_credentials_request_spec.rb +0 -109
- data/spec/lib/oauth/client_spec.rb +0 -38
- data/spec/lib/oauth/code_request_spec.rb +0 -47
- data/spec/lib/oauth/code_response_spec.rb +0 -36
- data/spec/lib/oauth/error_response_spec.rb +0 -66
- data/spec/lib/oauth/error_spec.rb +0 -23
- data/spec/lib/oauth/forbidden_token_response_spec.rb +0 -22
- data/spec/lib/oauth/helpers/scope_checker_spec.rb +0 -98
- data/spec/lib/oauth/helpers/unique_token_spec.rb +0 -21
- data/spec/lib/oauth/helpers/uri_checker_spec.rb +0 -247
- data/spec/lib/oauth/invalid_token_response_spec.rb +0 -55
- data/spec/lib/oauth/password_access_token_request_spec.rb +0 -192
- data/spec/lib/oauth/pre_authorization_spec.rb +0 -215
- data/spec/lib/oauth/refresh_token_request_spec.rb +0 -177
- data/spec/lib/oauth/scopes_spec.rb +0 -148
- data/spec/lib/oauth/token_request_spec.rb +0 -150
- data/spec/lib/oauth/token_response_spec.rb +0 -86
- data/spec/lib/oauth/token_spec.rb +0 -158
- data/spec/lib/request/strategy_spec.rb +0 -54
- data/spec/lib/secret_storing/base_spec.rb +0 -60
- data/spec/lib/secret_storing/bcrypt_spec.rb +0 -49
- data/spec/lib/secret_storing/plain_spec.rb +0 -44
- data/spec/lib/secret_storing/sha256_hash_spec.rb +0 -48
- data/spec/lib/server_spec.rb +0 -61
- data/spec/lib/stale_records_cleaner_spec.rb +0 -89
- data/spec/models/doorkeeper/access_grant_spec.rb +0 -144
- data/spec/models/doorkeeper/access_token_spec.rb +0 -591
- data/spec/models/doorkeeper/application_spec.rb +0 -472
- data/spec/requests/applications/applications_request_spec.rb +0 -259
- data/spec/requests/applications/authorized_applications_spec.rb +0 -32
- data/spec/requests/endpoints/authorization_spec.rb +0 -73
- data/spec/requests/endpoints/token_spec.rb +0 -75
- data/spec/requests/flows/authorization_code_errors_spec.rb +0 -78
- data/spec/requests/flows/authorization_code_spec.rb +0 -447
- data/spec/requests/flows/client_credentials_spec.rb +0 -128
- data/spec/requests/flows/implicit_grant_errors_spec.rb +0 -34
- data/spec/requests/flows/implicit_grant_spec.rb +0 -90
- data/spec/requests/flows/password_spec.rb +0 -259
- data/spec/requests/flows/refresh_token_spec.rb +0 -233
- data/spec/requests/flows/revoke_token_spec.rb +0 -143
- data/spec/requests/flows/skip_authorization_spec.rb +0 -66
- data/spec/requests/protected_resources/metal_spec.rb +0 -16
- data/spec/requests/protected_resources/private_api_spec.rb +0 -83
- data/spec/routing/custom_controller_routes_spec.rb +0 -133
- data/spec/routing/default_routes_spec.rb +0 -41
- data/spec/routing/scoped_routes_spec.rb +0 -47
- data/spec/spec_helper.rb +0 -57
- data/spec/spec_helper_integration.rb +0 -4
- data/spec/support/dependencies/factory_bot.rb +0 -4
- data/spec/support/doorkeeper_rspec.rb +0 -22
- data/spec/support/helpers/access_token_request_helper.rb +0 -13
- data/spec/support/helpers/authorization_request_helper.rb +0 -43
- data/spec/support/helpers/config_helper.rb +0 -11
- data/spec/support/helpers/model_helper.rb +0 -78
- data/spec/support/helpers/request_spec_helper.rb +0 -98
- data/spec/support/helpers/url_helper.rb +0 -62
- data/spec/support/http_method_shim.rb +0 -29
- data/spec/support/orm/active_record.rb +0 -5
- data/spec/support/shared/controllers_shared_context.rb +0 -123
- data/spec/support/shared/hashing_shared_context.rb +0 -36
- data/spec/support/shared/models_shared_examples.rb +0 -54
- data/spec/validators/redirect_uri_validator_spec.rb +0 -158
- data/spec/version/version_spec.rb +0 -17
@@ -1,40 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
class AccessToken < ActiveRecord::Base
|
5
|
-
self.table_name = "#{table_name_prefix}oauth_access_tokens#{table_name_suffix}"
|
6
|
-
|
7
|
-
include AccessTokenMixin
|
8
|
-
|
9
|
-
belongs_to :application, class_name: "Doorkeeper::Application",
|
10
|
-
inverse_of: :access_tokens, optional: true
|
11
|
-
|
12
|
-
validates :token, presence: true, uniqueness: true
|
13
|
-
validates :refresh_token, uniqueness: true, if: :use_refresh_token?
|
3
|
+
require "doorkeeper/orm/active_record/mixins/access_token"
|
14
4
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
before_validation :generate_token, on: :create
|
20
|
-
before_validation :generate_refresh_token,
|
21
|
-
on: :create, if: :use_refresh_token?
|
22
|
-
|
23
|
-
# Searches for not revoked Access Tokens associated with the
|
24
|
-
# specific Resource Owner.
|
25
|
-
#
|
26
|
-
# @param resource_owner [ActiveRecord::Base]
|
27
|
-
# Resource Owner model instance
|
28
|
-
#
|
29
|
-
# @return [ActiveRecord::Relation]
|
30
|
-
# active Access Tokens for Resource Owner
|
31
|
-
#
|
32
|
-
def self.active_for(resource_owner)
|
33
|
-
where(resource_owner_id: resource_owner.id, revoked_at: nil)
|
34
|
-
end
|
35
|
-
|
36
|
-
def self.refresh_token_revoked_on_use?
|
37
|
-
column_names.include?("previous_refresh_token")
|
38
|
-
end
|
5
|
+
module Doorkeeper
|
6
|
+
class AccessToken < ::ActiveRecord::Base
|
7
|
+
include Doorkeeper::Orm::ActiveRecord::Mixins::AccessToken
|
39
8
|
end
|
40
9
|
end
|
@@ -1,154 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
self.table_name = "#{table_name_prefix}oauth_applications#{table_name_suffix}"
|
6
|
-
|
7
|
-
include ApplicationMixin
|
8
|
-
|
9
|
-
has_many :access_grants, dependent: :delete_all, class_name: "Doorkeeper::AccessGrant"
|
10
|
-
has_many :access_tokens, dependent: :delete_all, class_name: "Doorkeeper::AccessToken"
|
11
|
-
|
12
|
-
validates :name, :secret, :uid, presence: true
|
13
|
-
validates :uid, uniqueness: true
|
14
|
-
validates :redirect_uri, redirect_uri: true
|
15
|
-
validates :confidential, inclusion: { in: [true, false] }
|
16
|
-
|
17
|
-
validate :scopes_match_configured, if: :enforce_scopes?
|
18
|
-
|
19
|
-
before_validation :generate_uid, :generate_secret, on: :create
|
20
|
-
|
21
|
-
has_many :authorized_tokens, -> { where(revoked_at: nil) }, class_name: "AccessToken"
|
22
|
-
has_many :authorized_applications, through: :authorized_tokens, source: :application
|
23
|
-
|
24
|
-
# Returns Applications associated with active (not revoked) Access Tokens
|
25
|
-
# that are owned by the specific Resource Owner.
|
26
|
-
#
|
27
|
-
# @param resource_owner [ActiveRecord::Base]
|
28
|
-
# Resource Owner model instance
|
29
|
-
#
|
30
|
-
# @return [ActiveRecord::Relation]
|
31
|
-
# Applications authorized for the Resource Owner
|
32
|
-
#
|
33
|
-
def self.authorized_for(resource_owner)
|
34
|
-
resource_access_tokens = AccessToken.active_for(resource_owner)
|
35
|
-
where(id: resource_access_tokens.select(:application_id).distinct)
|
36
|
-
end
|
37
|
-
|
38
|
-
# Revokes AccessToken and AccessGrant records that have not been revoked and
|
39
|
-
# associated with the specific Application and Resource Owner.
|
40
|
-
#
|
41
|
-
# @param resource_owner [ActiveRecord::Base]
|
42
|
-
# instance of the Resource Owner model
|
43
|
-
#
|
44
|
-
def self.revoke_tokens_and_grants_for(id, resource_owner)
|
45
|
-
AccessToken.revoke_all_for(id, resource_owner)
|
46
|
-
AccessGrant.revoke_all_for(id, resource_owner)
|
47
|
-
end
|
48
|
-
|
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.
|
51
|
-
#
|
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)
|
58
|
-
else
|
59
|
-
@raw_secret
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
# Represents client as set of it's attributes in JSON format.
|
64
|
-
# This is the right way how we want to override ActiveRecord #to_json.
|
65
|
-
#
|
66
|
-
# Respects privacy settings and serializes minimum set of attributes
|
67
|
-
# for public/private clients and full set for authorized owners.
|
68
|
-
#
|
69
|
-
# @return [Hash] entity attributes for JSON
|
70
|
-
#
|
71
|
-
def as_json(options = {})
|
72
|
-
# if application belongs to some owner we need to check if it's the same as
|
73
|
-
# the one passed in the options or check if we render the client as an owner
|
74
|
-
if (respond_to?(:owner) && owner && owner == options[:current_resource_owner]) ||
|
75
|
-
options[:as_owner]
|
76
|
-
# Owners can see all the client attributes, fallback to ActiveModel serialization
|
77
|
-
super
|
78
|
-
else
|
79
|
-
# if application has no owner or it's owner doesn't match one from the options
|
80
|
-
# we render only minimum set of attributes that could be exposed to a public
|
81
|
-
only = extract_serializable_attributes(options)
|
82
|
-
super(options.merge(only: only))
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
# We need to hook into this method to allow serializing plan-text secrets
|
87
|
-
# when secrets hashing enabled.
|
88
|
-
#
|
89
|
-
# @param key [String] attribute name
|
90
|
-
#
|
91
|
-
def read_attribute_for_serialization(key)
|
92
|
-
return super unless key.to_s == "secret"
|
3
|
+
require "doorkeeper/orm/active_record/redirect_uri_validator"
|
4
|
+
require "doorkeeper/orm/active_record/mixins/application"
|
93
5
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
private
|
98
|
-
|
99
|
-
def generate_uid
|
100
|
-
self.uid = UniqueToken.generate if uid.blank?
|
101
|
-
end
|
102
|
-
|
103
|
-
def generate_secret
|
104
|
-
return unless secret.blank?
|
105
|
-
|
106
|
-
@raw_secret = UniqueToken.generate
|
107
|
-
secret_strategy.store_secret(self, :secret, @raw_secret)
|
108
|
-
end
|
109
|
-
|
110
|
-
def scopes_match_configured
|
111
|
-
if scopes.present? &&
|
112
|
-
!ScopeChecker.valid?(scope_str: scopes.to_s,
|
113
|
-
server_scopes: Doorkeeper.configuration.scopes)
|
114
|
-
errors.add(:scopes, :not_match_configured)
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
def enforce_scopes?
|
119
|
-
Doorkeeper.configuration.enforce_configured_scopes?
|
120
|
-
end
|
121
|
-
|
122
|
-
# Helper method to extract collection of serializable attribute names
|
123
|
-
# considering serialization options (like `only`, `except` and so on).
|
124
|
-
#
|
125
|
-
# @param options [Hash] serialization options
|
126
|
-
#
|
127
|
-
# @return [Array<String>]
|
128
|
-
# collection of attributes to be serialized using #as_json
|
129
|
-
#
|
130
|
-
def extract_serializable_attributes(options = {})
|
131
|
-
opts = options.try(:dup) || {}
|
132
|
-
only = Array.wrap(opts[:only]).map(&:to_s)
|
133
|
-
|
134
|
-
only = if only.blank?
|
135
|
-
serializable_attributes
|
136
|
-
else
|
137
|
-
only & serializable_attributes
|
138
|
-
end
|
139
|
-
|
140
|
-
only -= Array.wrap(opts[:except]).map(&:to_s) if opts.key?(:except)
|
141
|
-
only.uniq
|
142
|
-
end
|
143
|
-
|
144
|
-
# Collection of attributes that could be serialized for public.
|
145
|
-
# Override this method if you need additional attributes to be serialized.
|
146
|
-
#
|
147
|
-
# @return [Array<String>] collection of serializable attributes
|
148
|
-
def serializable_attributes
|
149
|
-
attributes = %w[id name created_at]
|
150
|
-
attributes << "uid" unless confidential?
|
151
|
-
attributes
|
152
|
-
end
|
6
|
+
module Doorkeeper
|
7
|
+
class Application < ::ActiveRecord::Base
|
8
|
+
include ::Doorkeeper::Orm::ActiveRecord::Mixins::Application
|
153
9
|
end
|
154
10
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Doorkeeper::Orm::ActiveRecord::Mixins
|
4
|
+
module AccessGrant
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
self.table_name = compute_doorkeeper_table_name
|
9
|
+
self.strict_loading_by_default = false if respond_to?(:strict_loading_by_default)
|
10
|
+
|
11
|
+
include ::Doorkeeper::AccessGrantMixin
|
12
|
+
|
13
|
+
belongs_to :application, class_name: Doorkeeper.config.application_class.to_s,
|
14
|
+
optional: true,
|
15
|
+
inverse_of: :access_grants
|
16
|
+
|
17
|
+
validates :application_id,
|
18
|
+
:token,
|
19
|
+
:expires_in,
|
20
|
+
:redirect_uri,
|
21
|
+
presence: true
|
22
|
+
|
23
|
+
validates :token, uniqueness: { case_sensitive: true }
|
24
|
+
|
25
|
+
before_validation :generate_token, on: :create
|
26
|
+
|
27
|
+
# We keep a volatile copy of the raw token for initial communication
|
28
|
+
# The stored refresh_token may be mapped and not available in cleartext.
|
29
|
+
#
|
30
|
+
# Some strategies allow restoring stored secrets (e.g. symmetric encryption)
|
31
|
+
# while hashing strategies do not, so you cannot rely on this value
|
32
|
+
# returning a present value for persisted tokens.
|
33
|
+
def plaintext_token
|
34
|
+
if secret_strategy.allows_restoring_secrets?
|
35
|
+
secret_strategy.restore_secret(self, :token)
|
36
|
+
else
|
37
|
+
@raw_token
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
# Generates token value with UniqueToken class.
|
44
|
+
#
|
45
|
+
# @return [String] token value
|
46
|
+
#
|
47
|
+
def generate_token
|
48
|
+
@raw_token = Doorkeeper::OAuth::Helpers::UniqueToken.generate
|
49
|
+
secret_strategy.store_secret(self, :token, @raw_token)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
module ClassMethods
|
54
|
+
private
|
55
|
+
|
56
|
+
def compute_doorkeeper_table_name
|
57
|
+
table_name = "oauth_access_grant"
|
58
|
+
table_name = table_name.pluralize if pluralize_table_names
|
59
|
+
"#{table_name_prefix}#{table_name}#{table_name_suffix}"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Doorkeeper::Orm::ActiveRecord::Mixins
|
4
|
+
module AccessToken
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
self.table_name = compute_doorkeeper_table_name
|
9
|
+
self.strict_loading_by_default = false if respond_to?(:strict_loading_by_default)
|
10
|
+
|
11
|
+
include ::Doorkeeper::AccessTokenMixin
|
12
|
+
|
13
|
+
belongs_to :application, class_name: Doorkeeper.config.application_class.to_s,
|
14
|
+
inverse_of: :access_tokens,
|
15
|
+
optional: true
|
16
|
+
|
17
|
+
validates :token, presence: true, uniqueness: { case_sensitive: true }
|
18
|
+
validates :refresh_token, uniqueness: { case_sensitive: true }, if: :use_refresh_token?
|
19
|
+
|
20
|
+
# @attr_writer [Boolean, nil] use_refresh_token
|
21
|
+
# indicates the possibility of using refresh token
|
22
|
+
attr_writer :use_refresh_token
|
23
|
+
|
24
|
+
before_validation :generate_token, on: :create
|
25
|
+
before_validation :generate_refresh_token,
|
26
|
+
on: :create, if: :use_refresh_token?
|
27
|
+
end
|
28
|
+
|
29
|
+
module ClassMethods
|
30
|
+
# Searches for not revoked Access Tokens associated with the
|
31
|
+
# specific Resource Owner.
|
32
|
+
#
|
33
|
+
# @param resource_owner [ActiveRecord::Base]
|
34
|
+
# Resource Owner model instance
|
35
|
+
#
|
36
|
+
# @return [ActiveRecord::Relation]
|
37
|
+
# active Access Tokens for Resource Owner
|
38
|
+
#
|
39
|
+
def active_for(resource_owner)
|
40
|
+
by_resource_owner(resource_owner).where(revoked_at: nil)
|
41
|
+
end
|
42
|
+
|
43
|
+
def refresh_token_revoked_on_use?
|
44
|
+
column_names.include?("previous_refresh_token")
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns non-expired and non-revoked access tokens
|
48
|
+
def not_expired
|
49
|
+
relation = where(revoked_at: nil)
|
50
|
+
|
51
|
+
if supports_expiration_time_math?
|
52
|
+
# have not reached the expiration time or it never expires
|
53
|
+
relation.where("#{expiration_time_sql} > ?", Time.now.utc).or(
|
54
|
+
relation.where(expires_in: nil)
|
55
|
+
)
|
56
|
+
else
|
57
|
+
::Kernel.warn <<~WARNING.squish
|
58
|
+
[DOORKEEPER] Doorkeeper doesn't support expiration time math for your database adapter (#{adapter_name}).
|
59
|
+
Please add a class method `custom_expiration_time_sql` for your AccessToken class/mixin to provide a custom
|
60
|
+
SQL expression to calculate access token expiration time. See lib/doorkeeper/orm/active_record/mixins/access_token.rb
|
61
|
+
for more details.
|
62
|
+
WARNING
|
63
|
+
|
64
|
+
relation
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def compute_doorkeeper_table_name
|
71
|
+
table_name = "oauth_access_token"
|
72
|
+
table_name = table_name.pluralize if pluralize_table_names
|
73
|
+
"#{table_name_prefix}#{table_name}#{table_name_suffix}"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,210 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Doorkeeper::Orm::ActiveRecord::Mixins
|
4
|
+
module Application
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
self.table_name = compute_doorkeeper_table_name
|
9
|
+
self.strict_loading_by_default = false if respond_to?(:strict_loading_by_default)
|
10
|
+
|
11
|
+
include ::Doorkeeper::ApplicationMixin
|
12
|
+
|
13
|
+
has_many :access_grants,
|
14
|
+
foreign_key: :application_id,
|
15
|
+
dependent: :delete_all,
|
16
|
+
class_name: Doorkeeper.config.access_grant_class.to_s
|
17
|
+
|
18
|
+
has_many :access_tokens,
|
19
|
+
foreign_key: :application_id,
|
20
|
+
dependent: :delete_all,
|
21
|
+
class_name: Doorkeeper.config.access_token_class.to_s
|
22
|
+
|
23
|
+
validates :name, :secret, :uid, presence: true
|
24
|
+
validates :uid, uniqueness: { case_sensitive: true }
|
25
|
+
validates :redirect_uri, "doorkeeper/redirect_uri": true
|
26
|
+
validates :confidential, inclusion: { in: [true, false] }
|
27
|
+
|
28
|
+
validate :scopes_match_configured, if: :enforce_scopes?
|
29
|
+
|
30
|
+
before_validation :generate_uid, :generate_secret, on: :create
|
31
|
+
|
32
|
+
has_many :authorized_tokens,
|
33
|
+
-> { where(revoked_at: nil) },
|
34
|
+
foreign_key: :application_id,
|
35
|
+
class_name: Doorkeeper.config.access_token_class.to_s
|
36
|
+
|
37
|
+
has_many :authorized_applications,
|
38
|
+
through: :authorized_tokens,
|
39
|
+
source: :application
|
40
|
+
|
41
|
+
# Generates a new secret for this application, intended to be used
|
42
|
+
# for rotating the secret or in case of compromise.
|
43
|
+
#
|
44
|
+
# @return [String] new transformed secret value
|
45
|
+
#
|
46
|
+
def renew_secret
|
47
|
+
@raw_secret = secret_generator.generate
|
48
|
+
secret_strategy.store_secret(self, :secret, @raw_secret)
|
49
|
+
end
|
50
|
+
|
51
|
+
# We keep a volatile copy of the raw secret for initial communication
|
52
|
+
# The stored refresh_token may be mapped and not available in cleartext.
|
53
|
+
#
|
54
|
+
# Some strategies allow restoring stored secrets (e.g. symmetric encryption)
|
55
|
+
# while hashing strategies do not, so you cannot rely on this value
|
56
|
+
# returning a present value for persisted tokens.
|
57
|
+
def plaintext_secret
|
58
|
+
if secret_strategy.allows_restoring_secrets?
|
59
|
+
secret_strategy.restore_secret(self, :secret)
|
60
|
+
else
|
61
|
+
@raw_secret
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Represents client as set of it's attributes in JSON format.
|
66
|
+
# This is the right way how we want to override ActiveRecord #to_json.
|
67
|
+
#
|
68
|
+
# Respects privacy settings and serializes minimum set of attributes
|
69
|
+
# for public/private clients and full set for authorized owners.
|
70
|
+
#
|
71
|
+
# @return [Hash] entity attributes for JSON
|
72
|
+
#
|
73
|
+
def as_json(options = {})
|
74
|
+
# if application belongs to some owner we need to check if it's the same as
|
75
|
+
# the one passed in the options or check if we render the client as an owner
|
76
|
+
if (respond_to?(:owner) && owner && owner == options[:current_resource_owner]) ||
|
77
|
+
options[:as_owner]
|
78
|
+
# Owners can see all the client attributes, fallback to ActiveModel serialization
|
79
|
+
super
|
80
|
+
else
|
81
|
+
# if application has no owner or it's owner doesn't match one from the options
|
82
|
+
# we render only minimum set of attributes that could be exposed to a public
|
83
|
+
only = extract_serializable_attributes(options)
|
84
|
+
super(options.merge(only: only))
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def authorized_for_resource_owner?(resource_owner)
|
89
|
+
Doorkeeper.configuration.authorize_resource_owner_for_client.call(self, resource_owner)
|
90
|
+
end
|
91
|
+
|
92
|
+
# We need to hook into this method to allow serializing plan-text secrets
|
93
|
+
# when secrets hashing enabled.
|
94
|
+
#
|
95
|
+
# @param key [String] attribute name
|
96
|
+
#
|
97
|
+
def read_attribute_for_serialization(key)
|
98
|
+
return super unless key.to_s == "secret"
|
99
|
+
|
100
|
+
plaintext_secret || secret
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def secret_generator
|
106
|
+
generator_name = Doorkeeper.config.application_secret_generator
|
107
|
+
generator = generator_name.constantize
|
108
|
+
|
109
|
+
return generator if generator.respond_to?(:generate)
|
110
|
+
|
111
|
+
raise Errors::UnableToGenerateToken, "#{generator} does not respond to `.generate`."
|
112
|
+
rescue NameError
|
113
|
+
raise Errors::TokenGeneratorNotFound, "#{generator_name} not found"
|
114
|
+
end
|
115
|
+
|
116
|
+
def generate_uid
|
117
|
+
self.uid = Doorkeeper::OAuth::Helpers::UniqueToken.generate if uid.blank?
|
118
|
+
end
|
119
|
+
|
120
|
+
def generate_secret
|
121
|
+
return if secret.present?
|
122
|
+
|
123
|
+
renew_secret
|
124
|
+
end
|
125
|
+
|
126
|
+
def scopes_match_configured
|
127
|
+
if scopes.present? && !Doorkeeper::OAuth::Helpers::ScopeChecker.valid?(
|
128
|
+
scope_str: scopes.to_s,
|
129
|
+
server_scopes: Doorkeeper.config.scopes,
|
130
|
+
)
|
131
|
+
errors.add(:scopes, :not_match_configured)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def enforce_scopes?
|
136
|
+
Doorkeeper.config.enforce_configured_scopes?
|
137
|
+
end
|
138
|
+
|
139
|
+
# Helper method to extract collection of serializable attribute names
|
140
|
+
# considering serialization options (like `only`, `except` and so on).
|
141
|
+
#
|
142
|
+
# @param options [Hash] serialization options
|
143
|
+
#
|
144
|
+
# @return [Array<String>]
|
145
|
+
# collection of attributes to be serialized using #as_json
|
146
|
+
#
|
147
|
+
def extract_serializable_attributes(options = {})
|
148
|
+
opts = options.try(:dup) || {}
|
149
|
+
only = Array.wrap(opts[:only]).map(&:to_s)
|
150
|
+
|
151
|
+
only = if only.blank?
|
152
|
+
client_serializable_attributes
|
153
|
+
else
|
154
|
+
only & client_serializable_attributes
|
155
|
+
end
|
156
|
+
|
157
|
+
only -= Array.wrap(opts[:except]).map(&:to_s) if opts.key?(:except)
|
158
|
+
only.uniq
|
159
|
+
end
|
160
|
+
|
161
|
+
# Collection of attributes that could be serialized for public.
|
162
|
+
# Override this method if you need additional attributes to be serialized.
|
163
|
+
#
|
164
|
+
# @return [Array<String>] collection of serializable attributes
|
165
|
+
#
|
166
|
+
# NOTE: `serializable_attributes` method already taken by Rails >= 6
|
167
|
+
#
|
168
|
+
def client_serializable_attributes
|
169
|
+
attributes = %w[id name created_at]
|
170
|
+
attributes << "uid" unless confidential?
|
171
|
+
attributes
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
module ClassMethods
|
176
|
+
# Returns Applications associated with active (not revoked) Access Tokens
|
177
|
+
# that are owned by the specific Resource Owner.
|
178
|
+
#
|
179
|
+
# @param resource_owner [ActiveRecord::Base]
|
180
|
+
# Resource Owner model instance
|
181
|
+
#
|
182
|
+
# @return [ActiveRecord::Relation]
|
183
|
+
# Applications authorized for the Resource Owner
|
184
|
+
#
|
185
|
+
def authorized_for(resource_owner)
|
186
|
+
resource_access_tokens = Doorkeeper.config.access_token_model.active_for(resource_owner)
|
187
|
+
where(id: resource_access_tokens.select(:application_id).distinct)
|
188
|
+
end
|
189
|
+
|
190
|
+
# Revokes AccessToken and AccessGrant records that have not been revoked and
|
191
|
+
# associated with the specific Application and Resource Owner.
|
192
|
+
#
|
193
|
+
# @param resource_owner [ActiveRecord::Base]
|
194
|
+
# instance of the Resource Owner model
|
195
|
+
#
|
196
|
+
def revoke_tokens_and_grants_for(id, resource_owner)
|
197
|
+
Doorkeeper.config.access_token_model.revoke_all_for(id, resource_owner)
|
198
|
+
Doorkeeper.config.access_grant_model.revoke_all_for(id, resource_owner)
|
199
|
+
end
|
200
|
+
|
201
|
+
private
|
202
|
+
|
203
|
+
def compute_doorkeeper_table_name
|
204
|
+
table_name = "oauth_application"
|
205
|
+
table_name = table_name.pluralize if pluralize_table_names
|
206
|
+
"#{table_name_prefix}#{table_name}#{table_name_suffix}"
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "uri"
|
4
|
+
|
5
|
+
module Doorkeeper
|
6
|
+
# ActiveModel validator for redirect URI validation in according
|
7
|
+
# to OAuth standards and Doorkeeper configuration.
|
8
|
+
class RedirectUriValidator < ActiveModel::EachValidator
|
9
|
+
def validate_each(record, attribute, value)
|
10
|
+
if value.blank?
|
11
|
+
return if Doorkeeper.config.allow_blank_redirect_uri?(record)
|
12
|
+
|
13
|
+
record.errors.add(attribute, :blank)
|
14
|
+
else
|
15
|
+
value.split.each do |val|
|
16
|
+
next if oob_redirect_uri?(val)
|
17
|
+
|
18
|
+
uri = ::URI.parse(val)
|
19
|
+
record.errors.add(attribute, :forbidden_uri) if forbidden_uri?(uri)
|
20
|
+
record.errors.add(attribute, :fragment_present) unless uri.fragment.nil?
|
21
|
+
record.errors.add(attribute, :unspecified_scheme) if unspecified_scheme?(uri)
|
22
|
+
record.errors.add(attribute, :relative_uri) if relative_uri?(uri)
|
23
|
+
record.errors.add(attribute, :secured_uri) if invalid_ssl_uri?(uri)
|
24
|
+
record.errors.add(attribute, :invalid_uri) if unspecified_host?(uri)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
rescue URI::InvalidURIError
|
28
|
+
record.errors.add(attribute, :invalid_uri)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def oob_redirect_uri?(uri)
|
34
|
+
Doorkeeper::OAuth::NonStandard::IETF_WG_OAUTH2_OOB_METHODS.include?(uri)
|
35
|
+
end
|
36
|
+
|
37
|
+
def forbidden_uri?(uri)
|
38
|
+
Doorkeeper.config.forbid_redirect_uri.call(uri)
|
39
|
+
end
|
40
|
+
|
41
|
+
def unspecified_scheme?(uri)
|
42
|
+
return true if uri.opaque.present?
|
43
|
+
|
44
|
+
%w[localhost].include?(uri.try(:scheme))
|
45
|
+
end
|
46
|
+
|
47
|
+
def unspecified_host?(uri)
|
48
|
+
uri.is_a?(URI::HTTP) && uri.host.blank?
|
49
|
+
end
|
50
|
+
|
51
|
+
def relative_uri?(uri)
|
52
|
+
uri.scheme.nil? && uri.host.blank?
|
53
|
+
end
|
54
|
+
|
55
|
+
def invalid_ssl_uri?(uri)
|
56
|
+
forces_ssl = Doorkeeper.config.force_ssl_in_redirect_uri
|
57
|
+
non_https = uri.try(:scheme) == "http"
|
58
|
+
|
59
|
+
if forces_ssl.respond_to?(:call)
|
60
|
+
forces_ssl.call(uri) && non_https
|
61
|
+
else
|
62
|
+
forces_ssl && non_https
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -15,7 +15,8 @@ module Doorkeeper
|
|
15
15
|
def clean_revoked
|
16
16
|
table = @base_scope.arel_table
|
17
17
|
|
18
|
-
@base_scope
|
18
|
+
@base_scope
|
19
|
+
.where.not(revoked_at: nil)
|
19
20
|
.where(table[:revoked_at].lt(Time.current))
|
20
21
|
.in_batches(&:delete_all)
|
21
22
|
end
|
@@ -24,7 +25,9 @@ module Doorkeeper
|
|
24
25
|
def clean_expired(ttl)
|
25
26
|
table = @base_scope.arel_table
|
26
27
|
|
27
|
-
@base_scope
|
28
|
+
@base_scope
|
29
|
+
.where.not(expires_in: nil)
|
30
|
+
.where(table[:created_at].lt(Time.current - ttl))
|
28
31
|
.in_batches(&:delete_all)
|
29
32
|
end
|
30
33
|
end
|