doorkeeper 5.3.3 → 5.4.0.rc1

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 (120) hide show
  1. checksums.yaml +4 -4
  2. data/Appraisals +0 -14
  3. data/CHANGELOG.md +35 -10
  4. data/Dangerfile +7 -7
  5. data/Dockerfile +2 -2
  6. data/Gemfile +9 -9
  7. data/README.md +6 -4
  8. data/app/controllers/doorkeeper/applications_controller.rb +7 -7
  9. data/app/controllers/doorkeeper/authorizations_controller.rb +31 -12
  10. data/app/controllers/doorkeeper/authorized_applications_controller.rb +3 -3
  11. data/app/controllers/doorkeeper/tokens_controller.rb +57 -20
  12. data/app/views/doorkeeper/applications/show.html.erb +19 -2
  13. data/bin/console +14 -0
  14. data/config/locales/en.yml +3 -1
  15. data/doorkeeper.gemspec +1 -1
  16. data/gemfiles/rails_5_0.gemfile +8 -7
  17. data/gemfiles/rails_5_1.gemfile +8 -7
  18. data/gemfiles/rails_5_2.gemfile +8 -7
  19. data/gemfiles/rails_6_0.gemfile +8 -7
  20. data/gemfiles/rails_master.gemfile +8 -7
  21. data/lib/doorkeeper.rb +106 -79
  22. data/lib/doorkeeper/config.rb +40 -17
  23. data/lib/doorkeeper/config/abstract_builder.rb +28 -0
  24. data/lib/doorkeeper/config/option.rb +28 -14
  25. data/lib/doorkeeper/grape/helpers.rb +1 -1
  26. data/lib/doorkeeper/models/access_grant_mixin.rb +9 -11
  27. data/lib/doorkeeper/models/access_token_mixin.rb +100 -41
  28. data/lib/doorkeeper/models/concerns/resource_ownerable.rb +47 -0
  29. data/lib/doorkeeper/models/concerns/revocable.rb +1 -1
  30. data/lib/doorkeeper/models/concerns/scopes.rb +5 -1
  31. data/lib/doorkeeper/models/concerns/secret_storable.rb +1 -3
  32. data/lib/doorkeeper/oauth/authorization/code.rb +14 -5
  33. data/lib/doorkeeper/oauth/authorization/context.rb +2 -2
  34. data/lib/doorkeeper/oauth/authorization/token.rb +7 -11
  35. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +4 -4
  36. data/lib/doorkeeper/oauth/authorization_code_request.rb +18 -8
  37. data/lib/doorkeeper/oauth/base_request.rb +11 -19
  38. data/lib/doorkeeper/oauth/client.rb +1 -1
  39. data/lib/doorkeeper/oauth/client/credentials.rb +2 -4
  40. data/lib/doorkeeper/oauth/client_credentials/creator.rb +25 -7
  41. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +3 -2
  42. data/lib/doorkeeper/oauth/client_credentials/validator.rb +1 -1
  43. data/lib/doorkeeper/oauth/client_credentials_request.rb +8 -7
  44. data/lib/doorkeeper/oauth/code_request.rb +1 -1
  45. data/lib/doorkeeper/oauth/code_response.rb +6 -2
  46. data/lib/doorkeeper/oauth/error_response.rb +2 -4
  47. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +1 -5
  48. data/lib/doorkeeper/oauth/hooks/context.rb +21 -0
  49. data/lib/doorkeeper/oauth/invalid_token_response.rb +2 -2
  50. data/lib/doorkeeper/oauth/password_access_token_request.rb +3 -5
  51. data/lib/doorkeeper/oauth/pre_authorization.rb +32 -27
  52. data/lib/doorkeeper/oauth/refresh_token_request.rb +18 -22
  53. data/lib/doorkeeper/oauth/token.rb +1 -1
  54. data/lib/doorkeeper/oauth/token_introspection.rb +3 -3
  55. data/lib/doorkeeper/oauth/token_request.rb +2 -2
  56. data/lib/doorkeeper/oauth/token_response.rb +1 -1
  57. data/lib/doorkeeper/orm/active_record/mixins/access_grant.rb +7 -2
  58. data/lib/doorkeeper/orm/active_record/mixins/access_token.rb +6 -2
  59. data/lib/doorkeeper/orm/active_record/mixins/application.rb +9 -64
  60. data/lib/doorkeeper/rails/routes.rb +13 -17
  61. data/lib/doorkeeper/rails/routes/abstract_router.rb +35 -0
  62. data/lib/doorkeeper/rails/routes/mapper.rb +2 -2
  63. data/lib/doorkeeper/rails/routes/registry.rb +45 -0
  64. data/lib/doorkeeper/request/strategy.rb +2 -2
  65. data/lib/doorkeeper/server.rb +3 -3
  66. data/lib/doorkeeper/version.rb +3 -3
  67. data/lib/generators/doorkeeper/confidential_applications_generator.rb +1 -1
  68. data/lib/generators/doorkeeper/enable_polymorphic_resource_owner_generator.rb +39 -0
  69. data/lib/generators/doorkeeper/templates/add_owner_to_application_migration.rb.erb +2 -0
  70. data/lib/generators/doorkeeper/templates/add_previous_refresh_token_to_access_tokens.rb.erb +2 -0
  71. data/lib/generators/doorkeeper/templates/enable_pkce_migration.rb.erb +2 -0
  72. data/lib/generators/doorkeeper/templates/enable_polymorphic_resource_owner_migration.rb.erb +17 -0
  73. data/lib/generators/doorkeeper/templates/initializer.rb +39 -3
  74. data/lib/generators/doorkeeper/templates/migration.rb.erb +2 -0
  75. data/spec/controllers/applications_controller_spec.rb +2 -2
  76. data/spec/controllers/authorizations_controller_spec.rb +165 -30
  77. data/spec/controllers/tokens_controller_spec.rb +6 -5
  78. data/spec/dummy/app/helpers/application_helper.rb +1 -1
  79. data/spec/dummy/app/models/user.rb +5 -1
  80. data/spec/dummy/config/application.rb +6 -4
  81. data/spec/dummy/config/boot.rb +4 -4
  82. data/spec/dummy/config/environment.rb +1 -1
  83. data/spec/dummy/config/routes.rb +4 -4
  84. data/spec/dummy/db/migrate/20151223192035_create_doorkeeper_tables.rb +2 -2
  85. data/spec/dummy/db/schema.rb +3 -1
  86. data/spec/factories.rb +1 -1
  87. data/spec/generators/enable_polymorphic_resource_owner_generator_spec.rb +47 -0
  88. data/spec/lib/config_spec.rb +15 -11
  89. data/spec/lib/models/revocable_spec.rb +2 -3
  90. data/spec/lib/models/scopes_spec.rb +8 -0
  91. data/spec/lib/oauth/authorization_code_request_spec.rb +25 -15
  92. data/spec/lib/oauth/base_request_spec.rb +6 -20
  93. data/spec/lib/oauth/client_credentials/creator_spec.rb +90 -89
  94. data/spec/lib/oauth/client_credentials/issuer_spec.rb +84 -86
  95. data/spec/lib/oauth/client_credentials/validation_spec.rb +38 -40
  96. data/spec/lib/oauth/client_credentials_request_spec.rb +5 -4
  97. data/spec/lib/oauth/code_request_spec.rb +1 -1
  98. data/spec/lib/oauth/code_response_spec.rb +5 -1
  99. data/spec/lib/oauth/error_response_spec.rb +1 -1
  100. data/spec/lib/oauth/password_access_token_request_spec.rb +24 -13
  101. data/spec/lib/oauth/pre_authorization_spec.rb +13 -18
  102. data/spec/lib/oauth/refresh_token_request_spec.rb +19 -30
  103. data/spec/lib/oauth/token_request_spec.rb +14 -7
  104. data/spec/lib/option_spec.rb +51 -0
  105. data/spec/lib/stale_records_cleaner_spec.rb +18 -5
  106. data/spec/models/doorkeeper/access_grant_spec.rb +18 -4
  107. data/spec/models/doorkeeper/access_token_spec.rb +507 -479
  108. data/spec/models/doorkeeper/application_spec.rb +22 -62
  109. data/spec/requests/endpoints/token_spec.rb +5 -1
  110. data/spec/requests/flows/authorization_code_errors_spec.rb +4 -1
  111. data/spec/requests/flows/authorization_code_spec.rb +6 -1
  112. data/spec/requests/flows/client_credentials_spec.rb +41 -0
  113. data/spec/requests/flows/refresh_token_spec.rb +16 -8
  114. data/spec/requests/flows/revoke_token_spec.rb +143 -104
  115. data/spec/support/helpers/access_token_request_helper.rb +1 -0
  116. data/spec/support/helpers/authorization_request_helper.rb +4 -4
  117. data/spec/support/helpers/config_helper.rb +1 -1
  118. data/spec/support/shared/controllers_shared_context.rb +2 -2
  119. data/spec/support/shared/models_shared_examples.rb +6 -4
  120. metadata +16 -5
@@ -25,9 +25,7 @@ module Doorkeeper
25
25
  # @return [Boolean]
26
26
  # Whether input matches secret as per the secret strategy
27
27
  #
28
- def secret_matches?(input, secret)
29
- secret_strategy.secret_matches?(input, secret)
30
- end
28
+ delegate :secret_matches?, to: :secret_strategy
31
29
 
32
30
  # Returns an instance of the Doorkeeper::AccessToken with
33
31
  # specific token value.
@@ -4,7 +4,7 @@ module Doorkeeper
4
4
  module OAuth
5
5
  module Authorization
6
6
  class Code
7
- attr_accessor :pre_auth, :resource_owner, :token
7
+ attr_reader :pre_auth, :resource_owner, :token
8
8
 
9
9
  def initialize(pre_auth, resource_owner)
10
10
  @pre_auth = pre_auth
@@ -12,7 +12,9 @@ module Doorkeeper
12
12
  end
13
13
 
14
14
  def issue_token
15
- @token ||= Doorkeeper.config.access_grant_model.create!(access_grant_attributes)
15
+ return @token if defined?(@token)
16
+
17
+ @token = Doorkeeper.config.access_grant_model.create!(access_grant_attributes)
16
18
  end
17
19
 
18
20
  def oob_redirect
@@ -26,13 +28,20 @@ module Doorkeeper
26
28
  end
27
29
 
28
30
  def access_grant_attributes
29
- pkce_attributes.merge(
31
+ attributes = {
30
32
  application_id: pre_auth.client.id,
31
- resource_owner_id: resource_owner.id,
32
33
  expires_in: authorization_code_expires_in,
33
34
  redirect_uri: pre_auth.redirect_uri,
34
35
  scopes: pre_auth.scopes.to_s,
35
- )
36
+ }
37
+
38
+ if Doorkeeper.config.polymorphic_resource_owner?
39
+ attributes[:resource_owner] = resource_owner
40
+ else
41
+ attributes[:resource_owner_id] = resource_owner.id
42
+ end
43
+
44
+ pkce_attributes.merge(attributes)
36
45
  end
37
46
 
38
47
  def pkce_attributes
@@ -7,9 +7,9 @@ module Doorkeeper
7
7
  attr_reader :client, :grant_type, :scopes
8
8
 
9
9
  def initialize(client, grant_type, scopes)
10
- @client = client
10
+ @client = client
11
11
  @grant_type = grant_type
12
- @scopes = scopes
12
+ @scopes = scopes
13
13
  end
14
14
  end
15
15
  end
@@ -4,7 +4,7 @@ module Doorkeeper
4
4
  module OAuth
5
5
  module Authorization
6
6
  class Token
7
- attr_accessor :pre_auth, :resource_owner, :token
7
+ attr_reader :pre_auth, :resource_owner, :token
8
8
 
9
9
  class << self
10
10
  def build_context(pre_auth_or_oauth_client, grant_type, scopes)
@@ -57,12 +57,12 @@ module Doorkeeper
57
57
  pre_auth.scopes,
58
58
  )
59
59
 
60
- @token = configuration.access_token_model.find_or_create_for(
61
- pre_auth.client,
62
- resource_owner.id,
63
- pre_auth.scopes,
64
- self.class.access_token_expires_in(configuration, context),
65
- false,
60
+ @token = Doorkeeper.config.access_token_model.find_or_create_for(
61
+ application: pre_auth.client,
62
+ resource_owner: resource_owner,
63
+ scopes: pre_auth.scopes,
64
+ expires_in: self.class.access_token_expires_in(Doorkeeper.config, context),
65
+ use_refresh_token: false,
66
66
  )
67
67
  end
68
68
 
@@ -76,10 +76,6 @@ module Doorkeeper
76
76
 
77
77
  private
78
78
 
79
- def configuration
80
- Doorkeeper.config
81
- end
82
-
83
79
  def controller
84
80
  @controller ||= begin
85
81
  mapping = Doorkeeper::Rails::Routes.mapping[:token_info] || {}
@@ -8,9 +8,9 @@ module Doorkeeper
8
8
  class URIBuilder
9
9
  class << self
10
10
  def uri_with_query(url, parameters = {})
11
- uri = URI.parse(url)
11
+ uri = URI.parse(url)
12
12
  original_query = Rack::Utils.parse_query(uri.query)
13
- uri.query = build_query(original_query.merge(parameters))
13
+ uri.query = build_query(original_query.merge(parameters))
14
14
  uri.to_s
15
15
  end
16
16
 
@@ -23,8 +23,8 @@ module Doorkeeper
23
23
  private
24
24
 
25
25
  def build_query(parameters = {})
26
- parameters = parameters.reject { |_, v| v.blank? }
27
- Rack::Utils.build_query parameters
26
+ parameters = parameters.reject { |_, value| value.blank? }
27
+ Rack::Utils.build_query(parameters)
28
28
  end
29
29
  end
30
30
  end
@@ -11,9 +11,8 @@ module Doorkeeper
11
11
  validate :redirect_uri, error: :invalid_grant
12
12
  validate :code_verifier, error: :invalid_grant
13
13
 
14
- attr_accessor :server, :grant, :client, :redirect_uri, :access_token,
15
- :code_verifier
16
- attr_reader :invalid_request_reason, :missing_param
14
+ attr_reader :grant, :client, :redirect_uri, :access_token, :code_verifier,
15
+ :invalid_request_reason, :missing_param
17
16
 
18
17
  def initialize(server, grant, client, parameters = {})
19
18
  @server = server
@@ -33,19 +32,30 @@ module Doorkeeper
33
32
 
34
33
  grant.revoke
35
34
 
35
+ resource_owner = if Doorkeeper.config.polymorphic_resource_owner?
36
+ grant.resource_owner
37
+ else
38
+ grant.resource_owner_id
39
+ end
40
+
36
41
  find_or_create_access_token(
37
42
  grant.application,
38
- grant.resource_owner_id,
43
+ resource_owner,
39
44
  grant.scopes,
40
45
  server,
41
46
  )
42
47
  end
48
+
43
49
  super
44
50
  end
45
51
 
52
+ def pkce_supported?
53
+ Doorkeeper.config.access_grant_model.pkce_supported?
54
+ end
55
+
46
56
  def validate_pkce_support
47
57
  @invalid_request_reason = :not_support_pkce if grant &&
48
- !grant.pkce_supported? &&
58
+ !pkce_supported? &&
49
59
  code_verifier.present?
50
60
 
51
61
  @invalid_request_reason.nil?
@@ -78,11 +88,11 @@ module Doorkeeper
78
88
  )
79
89
  end
80
90
 
81
- # if either side (server or client) request pkce, check the verifier
82
- # against the DB - if pkce is supported
91
+ # if either side (server or client) request PKCE, check the verifier
92
+ # against the DB - if PKCE is supported
83
93
  def validate_code_verifier
84
94
  return true unless grant.uses_pkce? || code_verifier
85
- return false unless grant.pkce_supported?
95
+ return false unless pkce_supported?
86
96
 
87
97
  if grant.code_challenge_method == "S256"
88
98
  grant.code_challenge == generate_code_challenge(code_verifier)
@@ -5,11 +5,11 @@ module Doorkeeper
5
5
  class BaseRequest
6
6
  include Validations
7
7
 
8
- attr_reader :grant_type
8
+ attr_reader :grant_type, :server
9
9
 
10
- def authorize
11
- validate
10
+ delegate :default_scopes, to: :server
12
11
 
12
+ def authorize
13
13
  if valid?
14
14
  before_successful_response
15
15
  @response = TokenResponse.new(access_token)
@@ -26,22 +26,14 @@ module Doorkeeper
26
26
  @scopes ||= build_scopes
27
27
  end
28
28
 
29
- def default_scopes
30
- server.default_scopes
31
- end
32
-
33
- def valid?
34
- error.nil?
35
- end
36
-
37
- def find_or_create_access_token(client, resource_owner_id, scopes, server)
29
+ def find_or_create_access_token(client, resource_owner, scopes, server)
38
30
  context = Authorization::Token.build_context(client, grant_type, scopes)
39
31
  @access_token = server_config.access_token_model.find_or_create_for(
40
- client,
41
- resource_owner_id,
42
- scopes,
43
- Authorization::Token.access_token_expires_in(server, context),
44
- Authorization::Token.refresh_token_enabled?(server, context),
32
+ application: client,
33
+ resource_owner: resource_owner,
34
+ scopes: scopes,
35
+ expires_in: Authorization::Token.access_token_expires_in(server, context),
36
+ use_refresh_token: Authorization::Token.refresh_token_enabled?(server, context),
45
37
  )
46
38
  end
47
39
 
@@ -63,10 +55,10 @@ module Doorkeeper
63
55
  if @original_scopes.present?
64
56
  OAuth::Scopes.from_string(@original_scopes)
65
57
  else
66
- client_scopes = @client.try(:scopes)
58
+ client_scopes = @client&.scopes
67
59
  return default_scopes if client_scopes.blank?
68
60
 
69
- default_scopes & @client.scopes
61
+ default_scopes & client_scopes
70
62
  end
71
63
  end
72
64
  end
@@ -3,7 +3,7 @@
3
3
  module Doorkeeper
4
4
  module OAuth
5
5
  class Client
6
- attr_accessor :application
6
+ attr_reader :application
7
7
 
8
8
  delegate :id, :name, :uid, :redirect_uri, :scopes, to: :@application
9
9
 
@@ -9,7 +9,7 @@ module Doorkeeper
9
9
  credentials_methods.inject(nil) do |_, method|
10
10
  method = self.method(method) if method.is_a?(Symbol)
11
11
  credentials = Credentials.new(*method.call(request))
12
- break credentials unless credentials.blank?
12
+ break credentials if credentials.present?
13
13
  end
14
14
  end
15
15
 
@@ -27,9 +27,7 @@ module Doorkeeper
27
27
 
28
28
  # Public clients may have their secret blank, but "credentials" are
29
29
  # still present
30
- def blank?
31
- uid.blank?
32
- end
30
+ delegate :blank?, to: :uid
33
31
  end
34
32
  end
35
33
  end
@@ -2,24 +2,42 @@
2
2
 
3
3
  module Doorkeeper
4
4
  module OAuth
5
- class ClientCredentialsRequest < BaseRequest
5
+ module ClientCredentials
6
6
  class Creator
7
7
  def call(client, scopes, attributes = {})
8
+ existing_token = nil
9
+
8
10
  if lookup_existing_token?
9
11
  existing_token = find_existing_token_for(client, scopes)
10
12
  return existing_token if server_config.reuse_access_token && existing_token&.reusable?
11
-
12
- existing_token&.revoke if server_config.revoke_previous_client_credentials_token
13
13
  end
14
14
 
15
- server_config.access_token_model.find_or_create_for(
16
- client, nil, scopes, attributes[:expires_in],
17
- attributes[:use_refresh_token],
18
- )
15
+ with_revocation(existing_token: existing_token) do
16
+ server_config.access_token_model.find_or_create_for(
17
+ application: client,
18
+ resource_owner: nil,
19
+ scopes: scopes,
20
+ **attributes,
21
+ )
22
+ end
19
23
  end
20
24
 
21
25
  private
22
26
 
27
+ def with_revocation(existing_token:)
28
+ if existing_token && server_config.revoke_previous_client_credentials_token
29
+ existing_token.with_lock do
30
+ raise Errors::DoorkeeperError, :invalid_token_reuse if existing_token.revoked?
31
+
32
+ existing_token.revoke
33
+
34
+ yield
35
+ end
36
+ else
37
+ yield
38
+ end
39
+ end
40
+
23
41
  def lookup_existing_token?
24
42
  server_config.reuse_access_token || server_config.revoke_previous_client_credentials_token
25
43
  end
@@ -2,9 +2,9 @@
2
2
 
3
3
  module Doorkeeper
4
4
  module OAuth
5
- class ClientCredentialsRequest < BaseRequest
5
+ module ClientCredentials
6
6
  class Issuer
7
- attr_accessor :token, :validator, :error
7
+ attr_reader :token, :validator, :error
8
8
 
9
9
  def initialize(server, validator)
10
10
  @server = server
@@ -19,6 +19,7 @@ module Doorkeeper
19
19
  @token = false
20
20
  @error = validator.error
21
21
  end
22
+
22
23
  @token
23
24
  end
24
25
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Doorkeeper
4
4
  module OAuth
5
- class ClientCredentialsRequest < BaseRequest
5
+ module ClientCredentials
6
6
  class Validator
7
7
  include Validations
8
8
  include OAuth::Helpers
@@ -3,18 +3,12 @@
3
3
  module Doorkeeper
4
4
  module OAuth
5
5
  class ClientCredentialsRequest < BaseRequest
6
- attr_accessor :server, :client, :original_scopes
7
- attr_reader :response
8
- attr_writer :issuer
6
+ attr_reader :client, :original_scopes, :response
9
7
 
10
8
  alias error_response response
11
9
 
12
10
  delegate :error, to: :issuer
13
11
 
14
- def issuer
15
- @issuer ||= Issuer.new(server, Validator.new(server, self))
16
- end
17
-
18
12
  def initialize(server, client, parameters = {})
19
13
  @client = client
20
14
  @server = server
@@ -26,6 +20,13 @@ module Doorkeeper
26
20
  issuer.token
27
21
  end
28
22
 
23
+ def issuer
24
+ @issuer ||= ClientCredentials::Issuer.new(
25
+ server,
26
+ ClientCredentials::Validator.new(server, self),
27
+ )
28
+ end
29
+
29
30
  private
30
31
 
31
32
  def valid?
@@ -3,7 +3,7 @@
3
3
  module Doorkeeper
4
4
  module OAuth
5
5
  class CodeRequest
6
- attr_accessor :pre_auth, :resource_owner
6
+ attr_reader :pre_auth, :resource_owner
7
7
 
8
8
  def initialize(pre_auth, resource_owner)
9
9
  @pre_auth = pre_auth
@@ -5,7 +5,7 @@ module Doorkeeper
5
5
  class CodeResponse < BaseResponse
6
6
  include OAuth::Helpers
7
7
 
8
- attr_accessor :pre_auth, :auth, :response_on_fragment
8
+ attr_reader :pre_auth, :auth, :response_on_fragment
9
9
 
10
10
  def initialize(pre_auth, auth, options = {})
11
11
  @pre_auth = pre_auth
@@ -17,8 +17,12 @@ module Doorkeeper
17
17
  true
18
18
  end
19
19
 
20
+ def issued_token
21
+ auth.token
22
+ end
23
+
20
24
  def redirect_uri
21
- if URIChecker.oob_uri? pre_auth.redirect_uri
25
+ if URIChecker.oob_uri?(pre_auth.redirect_uri)
22
26
  auth.oob_redirect
23
27
  elsif response_on_fragment
24
28
  Authorization::URIBuilder.uri_with_fragment(
@@ -67,10 +67,8 @@ module Doorkeeper
67
67
 
68
68
  protected
69
69
 
70
- delegate :realm, to: :configuration
71
-
72
- def configuration
73
- Doorkeeper.config
70
+ def realm
71
+ Doorkeeper.config.realm
74
72
  end
75
73
 
76
74
  def exception_class
@@ -27,11 +27,7 @@ module Doorkeeper
27
27
  private
28
28
 
29
29
  def valid_scopes(server_scopes, app_scopes)
30
- if app_scopes.present?
31
- app_scopes
32
- else
33
- server_scopes
34
- end
30
+ app_scopes.presence || server_scopes
35
31
  end
36
32
 
37
33
  def permitted_to_grant_type?