doorkeeper 5.4.0.rc2 → 5.5.1

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

Potentially problematic release.


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

Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +90 -10
  3. data/README.md +4 -4
  4. data/app/controllers/doorkeeper/application_controller.rb +1 -0
  5. data/app/controllers/doorkeeper/authorizations_controller.rb +16 -5
  6. data/app/controllers/doorkeeper/authorized_applications_controller.rb +1 -1
  7. data/app/controllers/doorkeeper/token_info_controller.rb +12 -2
  8. data/app/controllers/doorkeeper/tokens_controller.rb +34 -26
  9. data/app/views/doorkeeper/applications/show.html.erb +16 -12
  10. data/app/views/doorkeeper/authorizations/form_post.html.erb +11 -0
  11. data/config/locales/en.yml +3 -1
  12. data/lib/doorkeeper.rb +5 -0
  13. data/lib/doorkeeper/config.rb +91 -62
  14. data/lib/doorkeeper/config/option.rb +1 -3
  15. data/lib/doorkeeper/config/validations.rb +53 -0
  16. data/lib/doorkeeper/engine.rb +1 -1
  17. data/lib/doorkeeper/grant_flow.rb +45 -0
  18. data/lib/doorkeeper/grant_flow/fallback_flow.rb +15 -0
  19. data/lib/doorkeeper/grant_flow/flow.rb +44 -0
  20. data/lib/doorkeeper/grant_flow/registry.rb +50 -0
  21. data/lib/doorkeeper/helpers/controller.rb +4 -0
  22. data/lib/doorkeeper/models/access_grant_mixin.rb +1 -2
  23. data/lib/doorkeeper/models/access_token_mixin.rb +4 -4
  24. data/lib/doorkeeper/models/concerns/revocable.rb +1 -1
  25. data/lib/doorkeeper/oauth/authorization/code.rb +5 -1
  26. data/lib/doorkeeper/oauth/authorization/context.rb +5 -5
  27. data/lib/doorkeeper/oauth/authorization/token.rb +11 -5
  28. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +1 -1
  29. data/lib/doorkeeper/oauth/authorization_code_request.rb +10 -17
  30. data/lib/doorkeeper/oauth/base_request.rb +1 -1
  31. data/lib/doorkeeper/oauth/client_credentials/creator.rb +2 -1
  32. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +1 -0
  33. data/lib/doorkeeper/oauth/code_request.rb +2 -2
  34. data/lib/doorkeeper/oauth/code_response.rb +17 -11
  35. data/lib/doorkeeper/oauth/error_response.rb +4 -3
  36. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +1 -3
  37. data/lib/doorkeeper/oauth/password_access_token_request.rb +23 -3
  38. data/lib/doorkeeper/oauth/pre_authorization.rb +33 -8
  39. data/lib/doorkeeper/oauth/refresh_token_request.rb +13 -0
  40. data/lib/doorkeeper/oauth/token.rb +3 -3
  41. data/lib/doorkeeper/oauth/token_introspection.rb +1 -5
  42. data/lib/doorkeeper/oauth/token_request.rb +1 -1
  43. data/lib/doorkeeper/orm/active_record.rb +5 -14
  44. data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +11 -1
  45. data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +9 -1
  46. data/lib/doorkeeper/orm/active_record/mixins/application.rb +26 -15
  47. data/lib/doorkeeper/orm/active_record/redirect_uri_validator.rb +5 -0
  48. data/lib/doorkeeper/rails/routes.rb +1 -3
  49. data/lib/doorkeeper/rake/db.rake +3 -3
  50. data/lib/doorkeeper/rake/setup.rake +5 -0
  51. data/lib/doorkeeper/request.rb +49 -12
  52. data/lib/doorkeeper/request/password.rb +1 -0
  53. data/lib/doorkeeper/server.rb +1 -1
  54. data/lib/doorkeeper/stale_records_cleaner.rb +4 -4
  55. data/lib/doorkeeper/version.rb +3 -7
  56. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +1 -1
  57. data/lib/generators/doorkeeper/templates/initializer.rb +9 -7
  58. metadata +26 -13
@@ -62,6 +62,19 @@ module Doorkeeper
62
62
  attributes[:previous_refresh_token] = refresh_token.refresh_token
63
63
  end
64
64
 
65
+ # RFC6749
66
+ # 1.5. Refresh Token
67
+ #
68
+ # Refresh tokens are issued to the client by the authorization server and are
69
+ # used to obtain a new access token when the current access token
70
+ # becomes invalid or expires, or to obtain additional access tokens
71
+ # with identical or narrower scope (access tokens may have a shorter
72
+ # lifetime and fewer permissions than authorized by the resource
73
+ # owner).
74
+ #
75
+ # Here we assume that TTL of the token received after refreshing should be
76
+ # the same as that of the original token.
77
+ #
65
78
  @access_token = server_config.access_token_model.create_for(
66
79
  application: refresh_token.application,
67
80
  resource_owner: resource_owner,
@@ -32,13 +32,13 @@ module Doorkeeper
32
32
 
33
33
  def from_bearer_authorization(request)
34
34
  pattern = /^Bearer /i
35
- header = request.authorization
35
+ header = request.authorization
36
36
  token_from_header(header, pattern) if match?(header, pattern)
37
37
  end
38
38
 
39
39
  def from_basic_authorization(request)
40
40
  pattern = /^Basic /i
41
- header = request.authorization
41
+ header = request.authorization
42
42
  token_from_basic_header(header, pattern) if match?(header, pattern)
43
43
  end
44
44
 
@@ -54,7 +54,7 @@ module Doorkeeper
54
54
  end
55
55
 
56
56
  def token_from_header(header, pattern)
57
- header.gsub pattern, ""
57
+ header.gsub(pattern, "")
58
58
  end
59
59
 
60
60
  def match?(header, pattern)
@@ -179,11 +179,7 @@ module Doorkeeper
179
179
  allow_introspection = Doorkeeper.config.allow_token_introspection
180
180
  return allow_introspection unless allow_introspection.respond_to?(:call)
181
181
 
182
- allow_introspection.call(
183
- @token,
184
- auth_client,
185
- auth_token,
186
- )
182
+ allow_introspection.call(@token, auth_client, auth_token)
187
183
  end
188
184
 
189
185
  # Allows to customize introspection response.
@@ -12,7 +12,7 @@ module Doorkeeper
12
12
 
13
13
  def authorize
14
14
  auth = Authorization::Token.new(pre_auth, resource_owner)
15
- auth.issue_token
15
+ auth.issue_token!
16
16
  CodeResponse.new(pre_auth, auth, response_on_fragment: true)
17
17
  end
18
18
 
@@ -20,9 +20,8 @@ module Doorkeeper
20
20
  require "doorkeeper/orm/active_record/access_token"
21
21
  require "doorkeeper/orm/active_record/application"
22
22
 
23
- if Doorkeeper.config.active_record_options[:establish_connection]
23
+ if (options = Doorkeeper.config.active_record_options[:establish_connection])
24
24
  Doorkeeper::Orm::ActiveRecord.models.each do |model|
25
- options = Doorkeeper.config.active_record_options[:establish_connection]
26
25
  model.establish_connection(options)
27
26
  end
28
27
  end
@@ -38,22 +37,14 @@ module Doorkeeper
38
37
  end
39
38
 
40
39
  def self.lazy_load(&block)
41
- # ActiveSupport has no public interface to check if something
42
- # already lazy-loaded :(
43
- loaded = ActiveSupport.instance_variable_get(:"@loaded") || {}
44
-
45
- if loaded.key?(:active_record)
46
- block.call
47
- else
48
- ActiveSupport.on_load(:active_record, {}, &block)
49
- end
40
+ ActiveSupport.on_load(:active_record, {}, &block)
50
41
  end
51
42
 
52
43
  def self.models
53
44
  [
54
- Doorkeeper::AccessGrant,
55
- Doorkeeper::AccessToken,
56
- Doorkeeper::Application,
45
+ Doorkeeper.config.access_grant_model,
46
+ Doorkeeper.config.access_token_model,
47
+ Doorkeeper.config.application_model,
57
48
  ]
58
49
  end
59
50
  end
@@ -5,7 +5,7 @@ module Doorkeeper::Orm::ActiveRecord::Mixins
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
- self.table_name = "#{table_name_prefix}oauth_access_grants#{table_name_suffix}"
8
+ self.table_name = compute_doorkeeper_table_name
9
9
 
10
10
  include ::Doorkeeper::AccessGrantMixin
11
11
 
@@ -54,5 +54,15 @@ module Doorkeeper::Orm::ActiveRecord::Mixins
54
54
  secret_strategy.store_secret(self, :token, @raw_token)
55
55
  end
56
56
  end
57
+
58
+ module ClassMethods
59
+ private
60
+
61
+ def compute_doorkeeper_table_name
62
+ table_name = "oauth_access_grant"
63
+ table_name = table_name.pluralize if pluralize_table_names
64
+ "#{table_name_prefix}#{table_name}#{table_name_suffix}"
65
+ end
66
+ end
57
67
  end
58
68
  end
@@ -5,7 +5,7 @@ module Doorkeeper::Orm::ActiveRecord::Mixins
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
- self.table_name = "#{table_name_prefix}oauth_access_tokens#{table_name_suffix}"
8
+ self.table_name = compute_doorkeeper_table_name
9
9
 
10
10
  include ::Doorkeeper::AccessTokenMixin
11
11
 
@@ -46,6 +46,14 @@ module Doorkeeper::Orm::ActiveRecord::Mixins
46
46
  def refresh_token_revoked_on_use?
47
47
  column_names.include?("previous_refresh_token")
48
48
  end
49
+
50
+ private
51
+
52
+ def compute_doorkeeper_table_name
53
+ table_name = "oauth_access_token"
54
+ table_name = table_name.pluralize if pluralize_table_names
55
+ "#{table_name_prefix}#{table_name}#{table_name_suffix}"
56
+ end
49
57
  end
50
58
  end
51
59
  end
@@ -5,7 +5,7 @@ module Doorkeeper::Orm::ActiveRecord::Mixins
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
- self.table_name = "#{table_name_prefix}oauth_applications#{table_name_suffix}"
8
+ self.table_name = compute_doorkeeper_table_name
9
9
 
10
10
  include ::Doorkeeper::ApplicationMixin
11
11
 
@@ -88,6 +88,17 @@ module Doorkeeper::Orm::ActiveRecord::Mixins
88
88
  Doorkeeper.configuration.authorize_resource_owner_for_client.call(self, resource_owner)
89
89
  end
90
90
 
91
+ # We need to hook into this method to allow serializing plan-text secrets
92
+ # when secrets hashing enabled.
93
+ #
94
+ # @param key [String] attribute name
95
+ #
96
+ def read_attribute_for_serialization(key)
97
+ return super unless key.to_s == "secret"
98
+
99
+ plaintext_secret || secret
100
+ end
101
+
91
102
  private
92
103
 
93
104
  def generate_uid
@@ -126,31 +137,23 @@ module Doorkeeper::Orm::ActiveRecord::Mixins
126
137
  only = Array.wrap(opts[:only]).map(&:to_s)
127
138
 
128
139
  only = if only.blank?
129
- serializable_attributes
140
+ client_serializable_attributes
130
141
  else
131
- only & serializable_attributes
142
+ only & client_serializable_attributes
132
143
  end
133
144
 
134
145
  only -= Array.wrap(opts[:except]).map(&:to_s) if opts.key?(:except)
135
146
  only.uniq
136
147
  end
137
148
 
138
- # We need to hook into this method to allow serializing plan-text secrets
139
- # when secrets hashing enabled.
140
- #
141
- # @param key [String] attribute name
142
- #
143
- def read_attribute_for_serialization(key)
144
- return super unless key.to_s == "secret"
145
-
146
- plaintext_secret || secret
147
- end
148
-
149
149
  # Collection of attributes that could be serialized for public.
150
150
  # Override this method if you need additional attributes to be serialized.
151
151
  #
152
152
  # @return [Array<String>] collection of serializable attributes
153
- def serializable_attributes
153
+ #
154
+ # NOTE: `serializable_attributes` method already taken by Rails >= 6
155
+ #
156
+ def client_serializable_attributes
154
157
  attributes = %w[id name created_at]
155
158
  attributes << "uid" unless confidential?
156
159
  attributes
@@ -182,6 +185,14 @@ module Doorkeeper::Orm::ActiveRecord::Mixins
182
185
  Doorkeeper.config.access_token_model.revoke_all_for(id, resource_owner)
183
186
  Doorkeeper.config.access_grant_model.revoke_all_for(id, resource_owner)
184
187
  end
188
+
189
+ private
190
+
191
+ def compute_doorkeeper_table_name
192
+ table_name = "oauth_application"
193
+ table_name = table_name.pluralize if pluralize_table_names
194
+ "#{table_name_prefix}#{table_name}#{table_name_suffix}"
195
+ end
185
196
  end
186
197
  end
187
198
  end
@@ -21,6 +21,7 @@ module Doorkeeper
21
21
  record.errors.add(attribute, :unspecified_scheme) if unspecified_scheme?(uri)
22
22
  record.errors.add(attribute, :relative_uri) if relative_uri?(uri)
23
23
  record.errors.add(attribute, :secured_uri) if invalid_ssl_uri?(uri)
24
+ record.errors.add(attribute, :invalid_uri) if unspecified_host?(uri)
24
25
  end
25
26
  end
26
27
  rescue URI::InvalidURIError
@@ -43,6 +44,10 @@ module Doorkeeper
43
44
  %w[localhost].include?(uri.try(:scheme))
44
45
  end
45
46
 
47
+ def unspecified_host?(uri)
48
+ uri.is_a?(URI::HTTP) && uri.host.nil?
49
+ end
50
+
46
51
  def relative_uri?(uri)
47
52
  uri.scheme.nil? && uri.host.nil?
48
53
  end
@@ -29,8 +29,6 @@ module Doorkeeper
29
29
 
30
30
  def initialize(routes, mapper = Mapper.new, &block)
31
31
  super
32
-
33
- @mapping.skips.push(:applications, :authorized_applications) if Doorkeeper.config.api_only
34
32
  end
35
33
 
36
34
  def generate_routes!(options)
@@ -38,7 +36,7 @@ module Doorkeeper
38
36
  map_route(:authorizations, :authorization_routes)
39
37
  map_route(:tokens, :token_routes)
40
38
  map_route(:tokens, :revoke_routes)
41
- map_route(:tokens, :introspect_routes)
39
+ map_route(:tokens, :introspect_routes) unless Doorkeeper.config.allow_token_introspection.is_a?(FalseClass)
42
40
  map_route(:applications, :application_routes)
43
41
  map_route(:authorized_applications, :authorized_applications_routes)
44
42
  map_route(:token_info, :token_info_routes)
@@ -13,7 +13,7 @@ namespace :doorkeeper do
13
13
  namespace :cleanup do
14
14
  desc "Removes stale access tokens"
15
15
  task revoked_tokens: "doorkeeper:setup" do
16
- cleaner = Doorkeeper::StaleRecordsCleaner.new(Doorkeeper::AccessToken)
16
+ cleaner = Doorkeeper::StaleRecordsCleaner.new(Doorkeeper.config.access_token_model)
17
17
  cleaner.clean_revoked
18
18
  end
19
19
 
@@ -26,13 +26,13 @@ namespace :doorkeeper do
26
26
 
27
27
  desc "Removes stale access grants"
28
28
  task revoked_grants: "doorkeeper:setup" do
29
- cleaner = Doorkeeper::StaleRecordsCleaner.new(Doorkeeper::AccessGrant)
29
+ cleaner = Doorkeeper::StaleRecordsCleaner.new(Doorkeeper.config.access_grant_model)
30
30
  cleaner.clean_revoked
31
31
  end
32
32
 
33
33
  desc "Removes expired (TTL passed) access grants"
34
34
  task expired_grants: "doorkeeper:setup" do
35
- cleaner = Doorkeeper::StaleRecordsCleaner.new(Doorkeeper::AccessGrant)
35
+ cleaner = Doorkeeper::StaleRecordsCleaner.new(Doorkeeper.config.access_grant_model)
36
36
  cleaner.clean_expired(Doorkeeper.config.authorization_code_expires_in)
37
37
  end
38
38
  end
@@ -2,5 +2,10 @@
2
2
 
3
3
  namespace :doorkeeper do
4
4
  task setup: :environment do
5
+ # Dirty hack to manually initialize AR because of lazy auto-loading,
6
+ # in other case we'll see NameError: uninitialized constant Doorkeeper::AccessToken
7
+ if Doorkeeper.config.orm == :active_record && defined?(::ActiveRecord::Base)
8
+ Object.const_get("::ActiveRecord::Base")
9
+ end
5
10
  end
6
11
  end
@@ -4,32 +4,69 @@ module Doorkeeper
4
4
  module Request
5
5
  class << self
6
6
  def authorization_strategy(response_type)
7
- build_strategy_class(response_type)
7
+ grant_flow = authorization_flows.detect do |flow|
8
+ flow.matches_response_type?(response_type)
9
+ end
10
+
11
+ if grant_flow
12
+ grant_flow.response_type_strategy
13
+ else
14
+ # [NOTE]: this will be removed in a newer versions of Doorkeeper.
15
+ # For retro-compatibility only
16
+ build_fallback_strategy_class(response_type)
17
+ end
8
18
  end
9
19
 
10
20
  def token_strategy(grant_type)
11
21
  raise Errors::MissingRequiredParameter, :grant_type if grant_type.blank?
12
22
 
13
- get_strategy(grant_type, token_grant_types)
14
- rescue NameError
15
- raise Errors::InvalidTokenStrategy
16
- end
23
+ grant_flow = token_flows.detect do |flow|
24
+ flow.matches_grant_type?(grant_type)
25
+ end
17
26
 
18
- def get_strategy(grant_type, available)
19
- raise NameError unless available.include?(grant_type.to_s)
27
+ if grant_flow
28
+ grant_flow.grant_type_strategy
29
+ else
30
+ # [NOTE]: this will be removed in a newer versions of Doorkeeper.
31
+ # For retro-compatibility only
32
+ raise Errors::InvalidTokenStrategy unless available.include?(grant_type.to_s)
20
33
 
21
- build_strategy_class(grant_type)
34
+ strategy_class = build_fallback_strategy_class(grant_type)
35
+ raise Errors::InvalidTokenStrategy unless strategy_class
36
+
37
+ strategy_class
38
+ end
22
39
  end
23
40
 
24
41
  private
25
42
 
26
- def token_grant_types
27
- Doorkeeper.config.token_grant_types
43
+ def authorization_flows
44
+ Doorkeeper.configuration.authorization_response_flows
45
+ end
46
+
47
+ def token_flows
48
+ Doorkeeper.configuration.token_grant_flows
28
49
  end
29
50
 
30
- def build_strategy_class(grant_or_request_type)
51
+ # [NOTE]: this will be removed in a newer versions of Doorkeeper.
52
+ # For retro-compatibility only
53
+ def available
54
+ Doorkeeper.config.deprecated_token_grant_types_resolver
55
+ end
56
+
57
+ def build_fallback_strategy_class(grant_or_request_type)
31
58
  strategy_class_name = grant_or_request_type.to_s.tr(" ", "_").camelize
32
- "Doorkeeper::Request::#{strategy_class_name}".constantize
59
+ fallback_strategy = "Doorkeeper::Request::#{strategy_class_name}".constantize
60
+
61
+ ::Kernel.warn <<~WARNING
62
+ [DOORKEEPER] #{fallback_strategy} found using fallback, it must be
63
+ registered using `Doorkeeper::GrantFlow.register(grant_flow_name, **options)`.
64
+ This functionality will be removed in a newer versions of Doorkeeper.
65
+ WARNING
66
+
67
+ fallback_strategy
68
+ rescue NameError
69
+ raise Errors::InvalidTokenStrategy
33
70
  end
34
71
  end
35
72
  end
@@ -9,6 +9,7 @@ module Doorkeeper
9
9
  @request ||= OAuth::PasswordAccessTokenRequest.new(
10
10
  Doorkeeper.config,
11
11
  client,
12
+ credentials,
12
13
  resource_owner,
13
14
  parameters,
14
15
  )
@@ -4,7 +4,7 @@ module Doorkeeper
4
4
  class Server
5
5
  attr_reader :context
6
6
 
7
- def initialize(context = nil)
7
+ def initialize(context)
8
8
  @context = context
9
9
  end
10
10
 
@@ -13,12 +13,12 @@ module Doorkeeper
13
13
  raise Doorkeeper::Errors::NoOrmCleaner, "'#{configured_orm}' ORM has no cleaner!"
14
14
  end
15
15
 
16
- def self.configured_orm
17
- Doorkeeper.config.orm
18
- end
19
-
20
16
  def self.new(base_scope)
21
17
  self.for(base_scope)
22
18
  end
19
+
20
+ def self.configured_orm
21
+ Doorkeeper.config.orm
22
+ end
23
23
  end
24
24
  end
@@ -1,16 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Doorkeeper
4
- def self.gem_version
5
- Gem::Version.new VERSION::STRING
6
- end
7
-
8
4
  module VERSION
9
5
  # Semantic versioning
10
6
  MAJOR = 5
11
- MINOR = 4
12
- TINY = 0
13
- PRE = "rc2"
7
+ MINOR = 5
8
+ TINY = 1
9
+ PRE = nil
14
10
 
15
11
  # Full version number
16
12
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")