doorkeeper 5.2.6 → 5.3.0

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

Potentially problematic release.


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

Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/Appraisals +2 -2
  3. data/CHANGELOG.md +15 -14
  4. data/Gemfile +2 -2
  5. data/app/controllers/doorkeeper/application_controller.rb +2 -2
  6. data/app/controllers/doorkeeper/application_metal_controller.rb +2 -2
  7. data/app/controllers/doorkeeper/applications_controller.rb +3 -3
  8. data/app/controllers/doorkeeper/authorizations_controller.rb +2 -2
  9. data/app/controllers/doorkeeper/authorized_applications_controller.rb +3 -3
  10. data/gemfiles/rails_5_0.gemfile +2 -2
  11. data/gemfiles/rails_5_1.gemfile +2 -2
  12. data/gemfiles/rails_5_2.gemfile +2 -2
  13. data/gemfiles/rails_6_0.gemfile +2 -2
  14. data/gemfiles/rails_master.gemfile +2 -2
  15. data/lib/doorkeeper.rb +2 -3
  16. data/lib/doorkeeper/config.rb +71 -39
  17. data/lib/doorkeeper/grape/helpers.rb +1 -1
  18. data/lib/doorkeeper/helpers/controller.rb +10 -8
  19. data/lib/doorkeeper/models/access_grant_mixin.rb +7 -6
  20. data/lib/doorkeeper/models/access_token_mixin.rb +55 -18
  21. data/lib/doorkeeper/models/application_mixin.rb +3 -3
  22. data/lib/doorkeeper/models/concerns/ownership.rb +1 -1
  23. data/lib/doorkeeper/models/concerns/reusable.rb +1 -1
  24. data/lib/doorkeeper/models/concerns/revocable.rb +0 -27
  25. data/lib/doorkeeper/oauth/authorization/code.rb +4 -4
  26. data/lib/doorkeeper/oauth/authorization/token.rb +9 -6
  27. data/lib/doorkeeper/oauth/authorization_code_request.rb +13 -6
  28. data/lib/doorkeeper/oauth/base_request.rb +8 -4
  29. data/lib/doorkeeper/oauth/client.rb +7 -8
  30. data/lib/doorkeeper/oauth/client_credentials/creator.rb +16 -9
  31. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +7 -7
  32. data/lib/doorkeeper/oauth/client_credentials/{validation.rb → validator.rb} +4 -4
  33. data/lib/doorkeeper/oauth/client_credentials_request.rb +1 -1
  34. data/lib/doorkeeper/oauth/code_response.rb +2 -2
  35. data/lib/doorkeeper/oauth/error.rb +1 -1
  36. data/lib/doorkeeper/oauth/error_response.rb +5 -5
  37. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +7 -5
  38. data/lib/doorkeeper/oauth/helpers/unique_token.rb +8 -5
  39. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +1 -1
  40. data/lib/doorkeeper/oauth/invalid_request_response.rb +3 -3
  41. data/lib/doorkeeper/oauth/invalid_token_response.rb +5 -2
  42. data/lib/doorkeeper/oauth/password_access_token_request.rb +3 -3
  43. data/lib/doorkeeper/oauth/pre_authorization.rb +7 -5
  44. data/lib/doorkeeper/oauth/refresh_token_request.rb +5 -5
  45. data/lib/doorkeeper/oauth/token.rb +2 -2
  46. data/lib/doorkeeper/oauth/token_introspection.rb +6 -6
  47. data/lib/doorkeeper/orm/active_record.rb +3 -3
  48. data/lib/doorkeeper/orm/active_record/access_grant.rb +4 -43
  49. data/lib/doorkeeper/orm/active_record/access_token.rb +4 -35
  50. data/lib/doorkeeper/orm/active_record/application.rb +3 -155
  51. data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +53 -0
  52. data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +47 -0
  53. data/lib/doorkeeper/orm/active_record/mixins/application.rb +128 -0
  54. data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +3 -3
  55. data/lib/doorkeeper/rails/helpers.rb +4 -4
  56. data/lib/doorkeeper/rails/routes.rb +5 -7
  57. data/lib/doorkeeper/rake/db.rake +3 -3
  58. data/lib/doorkeeper/request.rb +1 -1
  59. data/lib/doorkeeper/request/authorization_code.rb +3 -3
  60. data/lib/doorkeeper/request/client_credentials.rb +2 -2
  61. data/lib/doorkeeper/request/password.rb +2 -2
  62. data/lib/doorkeeper/request/refresh_token.rb +3 -3
  63. data/lib/doorkeeper/server.rb +1 -1
  64. data/lib/doorkeeper/stale_records_cleaner.rb +1 -1
  65. data/lib/doorkeeper/version.rb +2 -2
  66. data/lib/generators/doorkeeper/application_owner_generator.rb +1 -1
  67. data/lib/generators/doorkeeper/confidential_applications_generator.rb +1 -1
  68. data/lib/generators/doorkeeper/migration_generator.rb +1 -1
  69. data/lib/generators/doorkeeper/pkce_generator.rb +1 -1
  70. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +2 -2
  71. data/lib/generators/doorkeeper/templates/initializer.rb +39 -8
  72. data/spec/controllers/application_metal_controller_spec.rb +1 -1
  73. data/spec/controllers/applications_controller_spec.rb +3 -2
  74. data/spec/controllers/authorizations_controller_spec.rb +18 -18
  75. data/spec/controllers/protected_resources_controller_spec.rb +25 -17
  76. data/spec/controllers/token_info_controller_spec.rb +1 -1
  77. data/spec/controllers/tokens_controller_spec.rb +1 -1
  78. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +3 -3
  79. data/spec/dummy/db/migrate/20160320211015_add_previous_refresh_token_to_access_tokens.rb +1 -1
  80. data/spec/dummy/db/migrate/20180210183654_add_confidential_to_applications.rb +1 -1
  81. data/spec/generators/install_generator_spec.rb +1 -1
  82. data/spec/generators/previous_refresh_token_generator_spec.rb +2 -2
  83. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +1 -1
  84. data/spec/lib/config_spec.rb +61 -21
  85. data/spec/lib/doorkeeper_spec.rb +1 -1
  86. data/spec/lib/models/revocable_spec.rb +3 -3
  87. data/spec/lib/oauth/authorization_code_request_spec.rb +127 -125
  88. data/spec/lib/oauth/base_request_spec.rb +160 -158
  89. data/spec/lib/oauth/base_response_spec.rb +27 -29
  90. data/spec/lib/oauth/client/credentials_spec.rb +1 -1
  91. data/spec/lib/oauth/client_credentials/creator_spec.rb +42 -5
  92. data/spec/lib/oauth/client_credentials/issuer_spec.rb +12 -12
  93. data/spec/lib/oauth/client_credentials/validation_spec.rb +4 -4
  94. data/spec/lib/oauth/client_credentials_integration_spec.rb +16 -18
  95. data/spec/lib/oauth/client_credentials_request_spec.rb +78 -80
  96. data/spec/lib/oauth/client_spec.rb +26 -26
  97. data/spec/lib/oauth/code_request_spec.rb +34 -34
  98. data/spec/lib/oauth/code_response_spec.rb +21 -25
  99. data/spec/lib/oauth/error_response_spec.rb +42 -44
  100. data/spec/lib/oauth/error_spec.rb +12 -14
  101. data/spec/lib/oauth/forbidden_token_response_spec.rb +11 -13
  102. data/spec/lib/oauth/helpers/scope_checker_spec.rb +30 -18
  103. data/spec/lib/oauth/invalid_request_response_spec.rb +48 -50
  104. data/spec/lib/oauth/invalid_token_response_spec.rb +32 -34
  105. data/spec/lib/oauth/password_access_token_request_spec.rb +145 -147
  106. data/spec/lib/oauth/pre_authorization_spec.rb +159 -161
  107. data/spec/lib/oauth/refresh_token_request_spec.rb +138 -139
  108. data/spec/lib/oauth/scopes_spec.rb +104 -106
  109. data/spec/lib/oauth/token_request_spec.rb +115 -111
  110. data/spec/lib/oauth/token_response_spec.rb +71 -73
  111. data/spec/lib/oauth/token_spec.rb +121 -123
  112. data/spec/models/doorkeeper/access_grant_spec.rb +3 -5
  113. data/spec/models/doorkeeper/access_token_spec.rb +7 -7
  114. data/spec/models/doorkeeper/application_spec.rb +295 -373
  115. data/spec/requests/applications/applications_request_spec.rb +1 -1
  116. data/spec/requests/endpoints/authorization_spec.rb +5 -3
  117. data/spec/requests/flows/authorization_code_spec.rb +34 -22
  118. data/spec/requests/flows/client_credentials_spec.rb +1 -1
  119. data/spec/requests/flows/password_spec.rb +32 -12
  120. data/spec/requests/flows/refresh_token_spec.rb +19 -19
  121. data/spec/requests/flows/revoke_token_spec.rb +18 -12
  122. data/spec/spec_helper.rb +1 -4
  123. data/spec/support/shared/controllers_shared_context.rb +33 -23
  124. data/spec/validators/redirect_uri_validator_spec.rb +1 -1
  125. metadata +6 -5
  126. data/spec/support/http_method_shim.rb +0 -29
@@ -14,8 +14,8 @@ module Doorkeeper
14
14
 
15
15
  def authenticate(request, *methods)
16
16
  if (token = from_request(request, *methods))
17
- access_token = AccessToken.by_token(token)
18
- refresh_token_enabled = Doorkeeper.configuration.refresh_token_enabled?
17
+ access_token = Doorkeeper.config.access_token_model.by_token(token)
18
+ refresh_token_enabled = Doorkeeper.config.refresh_token_enabled?
19
19
  if access_token.present? && refresh_token_enabled
20
20
  access_token.revoke_previous_refresh_token!
21
21
  end
@@ -94,7 +94,7 @@ module Doorkeeper
94
94
  client_id: @token.try(:application).try(:uid),
95
95
  token_type: @token.token_type,
96
96
  exp: @token.expires_at.to_i,
97
- iat: @token.created_at.to_i
97
+ iat: @token.created_at.to_i,
98
98
  )
99
99
  end
100
100
 
@@ -174,15 +174,15 @@ module Doorkeeper
174
174
  authorized_token.token == @token&.token
175
175
  end
176
176
 
177
- # config constraints for introspection in Doorkeeper.configuration.allow_token_introspection
177
+ # Config constraints for introspection in Doorkeeper.config.allow_token_introspection
178
178
  def token_introspection_allowed?(auth_client: nil, auth_token: nil)
179
- allow_introspection = Doorkeeper.configuration.allow_token_introspection
179
+ allow_introspection = Doorkeeper.config.allow_token_introspection
180
180
  return allow_introspection unless allow_introspection.respond_to?(:call)
181
181
 
182
182
  allow_introspection.call(
183
183
  @token,
184
184
  auth_client,
185
- auth_token
185
+ auth_token,
186
186
  )
187
187
  end
188
188
 
@@ -193,9 +193,9 @@ module Doorkeeper
193
193
  # @see https://tools.ietf.org/html/rfc7662#section-2.2
194
194
  #
195
195
  def customize_response(response)
196
- customized_response = Doorkeeper.configuration.custom_introspection_response.call(
196
+ customized_response = Doorkeeper.config.custom_introspection_response.call(
197
197
  token,
198
- server.context
198
+ server.context,
199
199
  )
200
200
  return response if customized_response.blank?
201
201
 
@@ -20,9 +20,9 @@ module Doorkeeper
20
20
  require "doorkeeper/orm/active_record/access_token"
21
21
  require "doorkeeper/orm/active_record/application"
22
22
 
23
- if Doorkeeper.configuration.active_record_options[:establish_connection]
23
+ if Doorkeeper.config.active_record_options[:establish_connection]
24
24
  Doorkeeper::Orm::ActiveRecord.models.each do |model|
25
- options = Doorkeeper.configuration.active_record_options[:establish_connection]
25
+ options = Doorkeeper.config.active_record_options[:establish_connection]
26
26
  model.establish_connection(options)
27
27
  end
28
28
  end
@@ -33,7 +33,7 @@ module Doorkeeper
33
33
  lazy_load do
34
34
  require "doorkeeper/models/concerns/ownership"
35
35
 
36
- Doorkeeper::Application.send :include, Doorkeeper::Models::Ownership
36
+ Doorkeeper.config.application_model.send :include, Doorkeeper::Models::Ownership
37
37
  end
38
38
  end
39
39
 
@@ -1,48 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Doorkeeper
4
- class AccessGrant < ActiveRecord::Base
5
- self.table_name = "#{table_name_prefix}oauth_access_grants#{table_name_suffix}"
6
-
7
- include AccessGrantMixin
8
-
9
- belongs_to :application, class_name: "Doorkeeper::Application",
10
- optional: true, inverse_of: :access_grants
11
-
12
- validates :resource_owner_id,
13
- :application_id,
14
- :token,
15
- :expires_in,
16
- :redirect_uri,
17
- presence: true
18
-
19
- validates :token, uniqueness: { case_sensitive: true }
3
+ require "doorkeeper/orm/active_record/mixins/access_grant"
20
4
 
21
- before_validation :generate_token, on: :create
22
-
23
- # We keep a volatile copy of the raw token for initial communication
24
- # The stored refresh_token may be mapped and not available in cleartext.
25
- #
26
- # Some strategies allow restoring stored secrets (e.g. symmetric encryption)
27
- # while hashing strategies do not, so you cannot rely on this value
28
- # returning a present value for persisted tokens.
29
- def plaintext_token
30
- if secret_strategy.allows_restoring_secrets?
31
- secret_strategy.restore_secret(self, :token)
32
- else
33
- @raw_token
34
- end
35
- end
36
-
37
- private
38
-
39
- # Generates token value with UniqueToken class.
40
- #
41
- # @return [String] token value
42
- #
43
- def generate_token
44
- @raw_token = UniqueToken.generate
45
- secret_strategy.store_secret(self, :token, @raw_token)
46
- end
5
+ module Doorkeeper
6
+ class AccessGrant < ::ActiveRecord::Base
7
+ include Doorkeeper::Orm::ActiveRecord::Mixins::AccessGrant
47
8
  end
48
9
  end
@@ -1,40 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Doorkeeper
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: { case_sensitive: true }
13
- validates :refresh_token, uniqueness: { case_sensitive: true }, if: :use_refresh_token?
3
+ require "doorkeeper/orm/active_record/mixins/access_token"
14
4
 
15
- # @attr_writer [Boolean, nil] use_refresh_token
16
- # indicates the possibility of using refresh token
17
- attr_writer :use_refresh_token
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,162 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "doorkeeper/orm/active_record/redirect_uri_validator"
4
+ require "doorkeeper/orm/active_record/mixins/application"
4
5
 
5
6
  module Doorkeeper
6
- class Application < ActiveRecord::Base
7
- self.table_name = "#{table_name_prefix}oauth_applications#{table_name_suffix}"
8
-
9
- include ApplicationMixin
10
-
11
- has_many :access_grants, dependent: :delete_all, class_name: "Doorkeeper::AccessGrant"
12
- has_many :access_tokens, dependent: :delete_all, class_name: "Doorkeeper::AccessToken"
13
-
14
- validates :name, :secret, :uid, presence: true
15
- validates :uid, uniqueness: { case_sensitive: true }
16
- validates :redirect_uri, "doorkeeper/redirect_uri": true
17
- validates :confidential, inclusion: { in: [true, false] }
18
-
19
- validate :scopes_match_configured, if: :enforce_scopes?
20
-
21
- before_validation :generate_uid, :generate_secret, on: :create
22
-
23
- has_many :authorized_tokens, -> { where(revoked_at: nil) }, class_name: "AccessToken"
24
- has_many :authorized_applications, through: :authorized_tokens, source: :application
25
-
26
- # Returns Applications associated with active (not revoked) Access Tokens
27
- # that are owned by the specific Resource Owner.
28
- #
29
- # @param resource_owner [ActiveRecord::Base]
30
- # Resource Owner model instance
31
- #
32
- # @return [ActiveRecord::Relation]
33
- # Applications authorized for the Resource Owner
34
- #
35
- def self.authorized_for(resource_owner)
36
- resource_access_tokens = AccessToken.active_for(resource_owner)
37
- where(id: resource_access_tokens.select(:application_id).distinct)
38
- end
39
-
40
- # Revokes AccessToken and AccessGrant records that have not been revoked and
41
- # associated with the specific Application and Resource Owner.
42
- #
43
- # @param resource_owner [ActiveRecord::Base]
44
- # instance of the Resource Owner model
45
- #
46
- def self.revoke_tokens_and_grants_for(id, resource_owner)
47
- AccessToken.revoke_all_for(id, resource_owner)
48
- AccessGrant.revoke_all_for(id, resource_owner)
49
- end
50
-
51
- # Generates a new secret for this application, intended to be used
52
- # for rotating the secret or in case of compromise.
53
- #
54
- def renew_secret
55
- @raw_secret = UniqueToken.generate
56
- secret_strategy.store_secret(self, :secret, @raw_secret)
57
- end
58
-
59
- # We keep a volatile copy of the raw secret for initial communication
60
- # The stored refresh_token may be mapped and not available in cleartext.
61
- #
62
- # Some strategies allow restoring stored secrets (e.g. symmetric encryption)
63
- # while hashing strategies do not, so you cannot rely on this value
64
- # returning a present value for persisted tokens.
65
- def plaintext_secret
66
- if secret_strategy.allows_restoring_secrets?
67
- secret_strategy.restore_secret(self, :secret)
68
- else
69
- @raw_secret
70
- end
71
- end
72
-
73
- # Represents client as set of it's attributes in JSON format.
74
- # This is the right way how we want to override ActiveRecord #to_json.
75
- #
76
- # Respects privacy settings and serializes minimum set of attributes
77
- # for public/private clients and full set for authorized owners.
78
- #
79
- # @return [Hash] entity attributes for JSON
80
- #
81
- def as_json(options = {})
82
- # if application belongs to some owner we need to check if it's the same as
83
- # the one passed in the options or check if we render the client as an owner
84
- if (respond_to?(:owner) && owner && owner == options[:current_resource_owner]) ||
85
- options[:as_owner]
86
- # Owners can see all the client attributes, fallback to ActiveModel serialization
87
- super
88
- else
89
- # if application has no owner or it's owner doesn't match one from the options
90
- # we render only minimum set of attributes that could be exposed to a public
91
- only = extract_serializable_attributes(options)
92
- super(options.merge(only: only))
93
- end
94
- end
95
-
96
- # We need to hook into this method to allow serializing plan-text secrets
97
- # when secrets hashing enabled.
98
- #
99
- # @param key [String] attribute name
100
- #
101
- def read_attribute_for_serialization(key)
102
- return super unless key.to_s == "secret"
103
-
104
- plaintext_secret || secret
105
- end
106
-
107
- private
108
-
109
- def generate_uid
110
- self.uid = UniqueToken.generate if uid.blank?
111
- end
112
-
113
- def generate_secret
114
- return unless secret.blank?
115
- renew_secret
116
- end
117
-
118
- def scopes_match_configured
119
- if scopes.present? &&
120
- !ScopeChecker.valid?(scope_str: scopes.to_s,
121
- server_scopes: Doorkeeper.configuration.scopes)
122
- errors.add(:scopes, :not_match_configured)
123
- end
124
- end
125
-
126
- def enforce_scopes?
127
- Doorkeeper.configuration.enforce_configured_scopes?
128
- end
129
-
130
- # Helper method to extract collection of serializable attribute names
131
- # considering serialization options (like `only`, `except` and so on).
132
- #
133
- # @param options [Hash] serialization options
134
- #
135
- # @return [Array<String>]
136
- # collection of attributes to be serialized using #as_json
137
- #
138
- def extract_serializable_attributes(options = {})
139
- opts = options.try(:dup) || {}
140
- only = Array.wrap(opts[:only]).map(&:to_s)
141
-
142
- only = if only.blank?
143
- serializable_attributes
144
- else
145
- only & serializable_attributes
146
- end
147
-
148
- only -= Array.wrap(opts[:except]).map(&:to_s) if opts.key?(:except)
149
- only.uniq
150
- end
151
-
152
- # Collection of attributes that could be serialized for public.
153
- # Override this method if you need additional attributes to be serialized.
154
- #
155
- # @return [Array<String>] collection of serializable attributes
156
- def serializable_attributes
157
- attributes = %w[id name created_at]
158
- attributes << "uid" unless confidential?
159
- attributes
160
- end
7
+ class Application < ::ActiveRecord::Base
8
+ include ::Doorkeeper::Orm::ActiveRecord::Mixins::Application
161
9
  end
162
10
  end
@@ -0,0 +1,53 @@
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 = "#{table_name_prefix}oauth_access_grants#{table_name_suffix}"
9
+
10
+ include ::Doorkeeper::AccessGrantMixin
11
+
12
+ belongs_to :application, class_name: Doorkeeper.config.application_class,
13
+ optional: true,
14
+ inverse_of: :access_grants
15
+
16
+ validates :resource_owner_id,
17
+ :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
+ end
53
+ end
@@ -0,0 +1,47 @@
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 = "#{table_name_prefix}oauth_access_tokens#{table_name_suffix}"
9
+
10
+ include ::Doorkeeper::AccessTokenMixin
11
+
12
+ belongs_to :application, class_name: Doorkeeper.config.application_class,
13
+ inverse_of: :access_tokens,
14
+ optional: true
15
+
16
+ validates :token, presence: true, uniqueness: { case_sensitive: true }
17
+ validates :refresh_token, uniqueness: { case_sensitive: true }, if: :use_refresh_token?
18
+
19
+ # @attr_writer [Boolean, nil] use_refresh_token
20
+ # indicates the possibility of using refresh token
21
+ attr_writer :use_refresh_token
22
+
23
+ before_validation :generate_token, on: :create
24
+ before_validation :generate_refresh_token,
25
+ on: :create, if: :use_refresh_token?
26
+ end
27
+
28
+ class_methods do
29
+ # Searches for not revoked Access Tokens associated with the
30
+ # specific Resource Owner.
31
+ #
32
+ # @param resource_owner [ActiveRecord::Base]
33
+ # Resource Owner model instance
34
+ #
35
+ # @return [ActiveRecord::Relation]
36
+ # active Access Tokens for Resource Owner
37
+ #
38
+ def active_for(resource_owner)
39
+ where(resource_owner_id: resource_owner.id, revoked_at: nil)
40
+ end
41
+
42
+ def refresh_token_revoked_on_use?
43
+ column_names.include?("previous_refresh_token")
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,128 @@
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 = "#{table_name_prefix}oauth_applications#{table_name_suffix}"
9
+
10
+ include ::Doorkeeper::ApplicationMixin
11
+
12
+ has_many :access_grants,
13
+ foreign_key: :application_id,
14
+ dependent: :delete_all,
15
+ class_name: Doorkeeper.config.access_grant_class
16
+
17
+ has_many :access_tokens,
18
+ foreign_key: :application_id,
19
+ dependent: :delete_all,
20
+ class_name: Doorkeeper.config.access_token_class
21
+
22
+ validates :name, :secret, :uid, presence: true
23
+ validates :uid, uniqueness: { case_sensitive: true }
24
+ validates :redirect_uri, "doorkeeper/redirect_uri": true
25
+ validates :confidential, inclusion: { in: [true, false] }
26
+
27
+ validate :scopes_match_configured, if: :enforce_scopes?
28
+
29
+ before_validation :generate_uid, :generate_secret, on: :create
30
+
31
+ has_many :authorized_tokens,
32
+ -> { where(revoked_at: nil) },
33
+ foreign_key: :application_id,
34
+ class_name: Doorkeeper.config.access_token_class
35
+
36
+ has_many :authorized_applications,
37
+ through: :authorized_tokens,
38
+ source: :application
39
+
40
+ # Generates a new secret for this application, intended to be used
41
+ # for rotating the secret or in case of compromise.
42
+ #
43
+ # @return [String] new transformed secret value
44
+ #
45
+ def renew_secret
46
+ @raw_secret = Doorkeeper::OAuth::Helpers::UniqueToken.generate
47
+ secret_strategy.store_secret(self, :secret, @raw_secret)
48
+ end
49
+
50
+ # We keep a volatile copy of the raw secret for initial communication
51
+ # The stored refresh_token may be mapped and not available in cleartext.
52
+ #
53
+ # Some strategies allow restoring stored secrets (e.g. symmetric encryption)
54
+ # while hashing strategies do not, so you cannot rely on this value
55
+ # returning a present value for persisted tokens.
56
+ def plaintext_secret
57
+ if secret_strategy.allows_restoring_secrets?
58
+ secret_strategy.restore_secret(self, :secret)
59
+ else
60
+ @raw_secret
61
+ end
62
+ end
63
+
64
+ # This is the right way how we want to override ActiveRecord #to_json
65
+ #
66
+ # @return [String] entity attributes as JSON
67
+ #
68
+ def as_json(options = {})
69
+ hash = super
70
+
71
+ hash["secret"] = plaintext_secret if hash.key?("secret")
72
+ hash
73
+ end
74
+
75
+ private
76
+
77
+ def generate_uid
78
+ self.uid = Doorkeeper::OAuth::Helpers::UniqueToken.generate if uid.blank?
79
+ end
80
+
81
+ def generate_secret
82
+ return unless secret.blank?
83
+
84
+ renew_secret
85
+ end
86
+
87
+ def scopes_match_configured
88
+ if scopes.present? && !Doorkeeper::OAuth::Helpers::ScopeChecker.valid?(
89
+ scope_str: scopes.to_s,
90
+ server_scopes: Doorkeeper.config.scopes,
91
+ )
92
+ errors.add(:scopes, :not_match_configured)
93
+ end
94
+ end
95
+
96
+ def enforce_scopes?
97
+ Doorkeeper.config.enforce_configured_scopes?
98
+ end
99
+ end
100
+
101
+ class_methods do
102
+ # Returns Applications associated with active (not revoked) Access Tokens
103
+ # that are owned by the specific Resource Owner.
104
+ #
105
+ # @param resource_owner [ActiveRecord::Base]
106
+ # Resource Owner model instance
107
+ #
108
+ # @return [ActiveRecord::Relation]
109
+ # Applications authorized for the Resource Owner
110
+ #
111
+ def authorized_for(resource_owner)
112
+ resource_access_tokens = Doorkeeper.config.access_token_model.active_for(resource_owner)
113
+ where(id: resource_access_tokens.select(:application_id).distinct)
114
+ end
115
+
116
+ # Revokes AccessToken and AccessGrant records that have not been revoked and
117
+ # associated with the specific Application and Resource Owner.
118
+ #
119
+ # @param resource_owner [ActiveRecord::Base]
120
+ # instance of the Resource Owner model
121
+ #
122
+ def revoke_tokens_and_grants_for(id, resource_owner)
123
+ Doorkeeper.config.access_token_model.revoke_all_for(id, resource_owner)
124
+ Doorkeeper.config.access_grant_model.revoke_all_for(id, resource_owner)
125
+ end
126
+ end
127
+ end
128
+ end