doorkeeper 5.0.2 → 5.1.0.rc2
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 +5 -5
- data/.travis.yml +17 -4
- data/Appraisals +29 -3
- data/Dangerfile +5 -2
- data/Gemfile +14 -4
- data/NEWS.md +64 -19
- data/README.md +68 -487
- data/app/controllers/doorkeeper/token_info_controller.rb +1 -1
- data/app/controllers/doorkeeper/tokens_controller.rb +7 -7
- data/app/views/doorkeeper/applications/show.html.erb +1 -1
- data/app/views/layouts/doorkeeper/admin.html.erb +5 -3
- data/bin/console +15 -0
- data/doorkeeper.gemspec +3 -2
- data/gemfiles/rails_4_2.gemfile +8 -4
- data/gemfiles/rails_5_0.gemfile +9 -5
- data/gemfiles/rails_5_1.gemfile +9 -5
- data/gemfiles/rails_5_2.gemfile +9 -5
- data/gemfiles/rails_6_0.gemfile +16 -0
- data/gemfiles/rails_master.gemfile +8 -9
- data/lib/doorkeeper/config.rb +164 -11
- data/lib/doorkeeper/helpers/controller.rb +3 -2
- data/lib/doorkeeper/models/access_grant_mixin.rb +16 -1
- data/lib/doorkeeper/models/access_token_mixin.rb +54 -10
- data/lib/doorkeeper/models/application_mixin.rb +42 -1
- data/lib/doorkeeper/models/concerns/expirable.rb +3 -2
- data/lib/doorkeeper/models/concerns/reusable.rb +19 -0
- data/lib/doorkeeper/models/concerns/scopes.rb +5 -1
- data/lib/doorkeeper/models/concerns/secret_storable.rb +106 -0
- data/lib/doorkeeper/oauth/authorization/code.rb +1 -1
- data/lib/doorkeeper/oauth/authorization/token.rb +4 -2
- data/lib/doorkeeper/oauth/authorization_code_request.rb +1 -1
- data/lib/doorkeeper/oauth/client.rb +1 -1
- data/lib/doorkeeper/oauth/client_credentials/validation.rb +4 -3
- data/lib/doorkeeper/oauth/code_response.rb +2 -2
- data/lib/doorkeeper/oauth/error_response.rb +5 -1
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +23 -8
- data/lib/doorkeeper/oauth/helpers/unique_token.rb +12 -1
- data/lib/doorkeeper/oauth/helpers/uri_checker.rb +32 -0
- data/lib/doorkeeper/oauth/invalid_token_response.rb +4 -0
- data/lib/doorkeeper/oauth/password_access_token_request.rb +7 -2
- data/lib/doorkeeper/oauth/pre_authorization.rb +8 -3
- data/lib/doorkeeper/oauth/refresh_token_request.rb +4 -1
- data/lib/doorkeeper/oauth/token_introspection.rb +72 -6
- data/lib/doorkeeper/oauth/token_response.rb +2 -2
- data/lib/doorkeeper/orm/active_record/access_grant.rb +23 -2
- data/lib/doorkeeper/orm/active_record/application.rb +20 -2
- data/lib/doorkeeper/secret_storing/base.rb +63 -0
- data/lib/doorkeeper/secret_storing/bcrypt.rb +59 -0
- data/lib/doorkeeper/secret_storing/plain.rb +33 -0
- data/lib/doorkeeper/secret_storing/sha256_hash.rb +25 -0
- data/lib/doorkeeper/version.rb +3 -3
- data/lib/doorkeeper.rb +7 -0
- data/lib/generators/doorkeeper/templates/initializer.rb +90 -8
- data/spec/controllers/application_metal_controller_spec.rb +18 -4
- data/spec/controllers/authorizations_controller_spec.rb +3 -3
- data/spec/controllers/token_info_controller_spec.rb +1 -1
- data/spec/controllers/tokens_controller_spec.rb +85 -41
- data/spec/dummy/app/controllers/application_controller.rb +1 -1
- data/spec/dummy/config/application.rb +12 -1
- data/spec/factories.rb +3 -3
- data/spec/lib/config_spec.rb +168 -0
- data/spec/lib/models/expirable_spec.rb +12 -0
- data/spec/lib/models/reusable_spec.rb +40 -0
- data/spec/lib/models/scopes_spec.rb +13 -1
- data/spec/lib/models/secret_storable_spec.rb +113 -0
- data/spec/lib/oauth/authorization_code_request_spec.rb +18 -1
- data/spec/lib/oauth/base_request_spec.rb +7 -7
- data/spec/lib/oauth/client_credentials/creator_spec.rb +51 -7
- data/spec/lib/oauth/client_credentials/validation_spec.rb +3 -0
- data/spec/lib/oauth/error_response_spec.rb +7 -1
- data/spec/lib/oauth/helpers/scope_checker_spec.rb +52 -17
- data/spec/lib/oauth/helpers/uri_checker_spec.rb +20 -2
- data/spec/lib/oauth/password_access_token_request_spec.rb +43 -12
- data/spec/lib/oauth/pre_authorization_spec.rb +24 -0
- data/spec/lib/oauth/token_request_spec.rb +16 -1
- data/spec/lib/oauth/token_response_spec.rb +13 -13
- data/spec/lib/oauth/token_spec.rb +14 -0
- data/spec/lib/secret_storing/base_spec.rb +60 -0
- data/spec/lib/secret_storing/bcrypt_spec.rb +49 -0
- data/spec/lib/secret_storing/plain_spec.rb +44 -0
- data/spec/lib/secret_storing/sha256_hash_spec.rb +48 -0
- data/spec/models/doorkeeper/access_grant_spec.rb +61 -0
- data/spec/models/doorkeeper/access_token_spec.rb +123 -0
- data/spec/models/doorkeeper/application_spec.rb +56 -0
- data/spec/requests/flows/authorization_code_spec.rb +41 -1
- data/spec/requests/flows/client_credentials_spec.rb +2 -2
- data/spec/requests/flows/implicit_grant_spec.rb +1 -1
- data/spec/requests/flows/password_spec.rb +7 -5
- data/spec/requests/flows/revoke_token_spec.rb +14 -30
- data/spec/routing/custom_controller_routes_spec.rb +4 -0
- data/spec/spec_helper.rb +2 -1
- data/spec/support/ruby_2_6_rails_4_2_patch.rb +14 -0
- data/spec/support/shared/hashing_shared_context.rb +36 -0
- metadata +59 -22
|
@@ -16,11 +16,31 @@ module Doorkeeper
|
|
|
16
16
|
|
|
17
17
|
belongs_to :application, belongs_to_options
|
|
18
18
|
|
|
19
|
-
validates :resource_owner_id,
|
|
19
|
+
validates :resource_owner_id,
|
|
20
|
+
:application_id,
|
|
21
|
+
:token,
|
|
22
|
+
:expires_in,
|
|
23
|
+
:redirect_uri,
|
|
24
|
+
presence: true
|
|
25
|
+
|
|
20
26
|
validates :token, uniqueness: true
|
|
21
27
|
|
|
22
28
|
before_validation :generate_token, on: :create
|
|
23
29
|
|
|
30
|
+
# We keep a volatile copy of the raw token for initial communication
|
|
31
|
+
# The stored refresh_token may be mapped and not available in cleartext.
|
|
32
|
+
#
|
|
33
|
+
# Some strategies allow restoring stored secrets (e.g. symmetric encryption)
|
|
34
|
+
# while hashing strategies do not, so you cannot rely on this value
|
|
35
|
+
# returning a present value for persisted tokens.
|
|
36
|
+
def plaintext_token
|
|
37
|
+
if secret_strategy.allows_restoring_secrets?
|
|
38
|
+
secret_strategy.restore_secret(self, :token)
|
|
39
|
+
else
|
|
40
|
+
@raw_token
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
24
44
|
private
|
|
25
45
|
|
|
26
46
|
# Generates token value with UniqueToken class.
|
|
@@ -28,7 +48,8 @@ module Doorkeeper
|
|
|
28
48
|
# @return [String] token value
|
|
29
49
|
#
|
|
30
50
|
def generate_token
|
|
31
|
-
|
|
51
|
+
@raw_token = UniqueToken.generate
|
|
52
|
+
secret_strategy.store_secret(self, :token, @raw_token)
|
|
32
53
|
end
|
|
33
54
|
end
|
|
34
55
|
end
|
|
@@ -45,6 +45,20 @@ module Doorkeeper
|
|
|
45
45
|
AccessGrant.revoke_all_for(id, resource_owner)
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
+
# We keep a volatile copy of the raw secret for initial communication
|
|
49
|
+
# The stored refresh_token may be mapped and not available in cleartext.
|
|
50
|
+
#
|
|
51
|
+
# Some strategies allow restoring stored secrets (e.g. symmetric encryption)
|
|
52
|
+
# while hashing strategies do not, so you cannot rely on this value
|
|
53
|
+
# returning a present value for persisted tokens.
|
|
54
|
+
def plaintext_secret
|
|
55
|
+
if secret_strategy.allows_restoring_secrets?
|
|
56
|
+
secret_strategy.restore_secret(self, :secret)
|
|
57
|
+
else
|
|
58
|
+
@raw_secret
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
48
62
|
private
|
|
49
63
|
|
|
50
64
|
def generate_uid
|
|
@@ -52,12 +66,16 @@ module Doorkeeper
|
|
|
52
66
|
end
|
|
53
67
|
|
|
54
68
|
def generate_secret
|
|
55
|
-
|
|
69
|
+
return unless secret.blank?
|
|
70
|
+
|
|
71
|
+
@raw_secret = UniqueToken.generate
|
|
72
|
+
secret_strategy.store_secret(self, :secret, @raw_secret)
|
|
56
73
|
end
|
|
57
74
|
|
|
58
75
|
def scopes_match_configured
|
|
59
76
|
if scopes.present? &&
|
|
60
|
-
!ScopeChecker.valid?(scopes.to_s,
|
|
77
|
+
!ScopeChecker.valid?(scope_str: scopes.to_s,
|
|
78
|
+
server_scopes: Doorkeeper.configuration.scopes)
|
|
61
79
|
errors.add(:scopes, :not_match_configured)
|
|
62
80
|
end
|
|
63
81
|
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
module Doorkeeper
|
|
2
|
+
module SecretStoring
|
|
3
|
+
|
|
4
|
+
##
|
|
5
|
+
# Base class for secret storing, including common helpers
|
|
6
|
+
class Base
|
|
7
|
+
##
|
|
8
|
+
# Return the value to be stored by the database
|
|
9
|
+
# used for looking up a database value.
|
|
10
|
+
# @param plain_secret The plain secret input / generated
|
|
11
|
+
def self.transform_secret(plain_secret)
|
|
12
|
+
raise NotImplementedError
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
##
|
|
16
|
+
# Transform and store the given secret attribute => value
|
|
17
|
+
# pair used for safely storing the attribute
|
|
18
|
+
# @param resource The model instance being modified
|
|
19
|
+
# @param attribute The secret attribute
|
|
20
|
+
# @param plain_secret The plain secret input / generated
|
|
21
|
+
def self.store_secret(resource, attribute, plain_secret)
|
|
22
|
+
transformed_value = self.transform_secret plain_secret
|
|
23
|
+
resource.public_send :"#{attribute}=", transformed_value
|
|
24
|
+
|
|
25
|
+
transformed_value
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
##
|
|
29
|
+
# Return the restored value from the database
|
|
30
|
+
# @param resource The resource instance to act on
|
|
31
|
+
# @param attribute The secret attribute to restore
|
|
32
|
+
# as retrieved from the database.
|
|
33
|
+
def self.restore_secret(resource, attribute)
|
|
34
|
+
raise NotImplementedError
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
##
|
|
38
|
+
# Determines whether this strategy supports restoring
|
|
39
|
+
# secrets from the database. This allows detecting users
|
|
40
|
+
# trying to use a non-restorable strategy with +reuse_access_tokens+.
|
|
41
|
+
def self.allows_restoring_secrets?
|
|
42
|
+
false
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
##
|
|
46
|
+
# Determines what secrets this strategy is applicable for
|
|
47
|
+
def self.validate_for(model)
|
|
48
|
+
valid = %i[token application]
|
|
49
|
+
return true if valid.include?(model.to_sym)
|
|
50
|
+
|
|
51
|
+
raise ArgumentError, "'#{name}' can not be used for #{model}."
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
##
|
|
55
|
+
# Securely compare the given +input+ value with a +stored+ value
|
|
56
|
+
# processed by +transform_secret+.
|
|
57
|
+
def self.secret_matches?(input, stored)
|
|
58
|
+
transformed_input = transform_secret(input)
|
|
59
|
+
ActiveSupport::SecurityUtils.secure_compare transformed_input, stored
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
module Doorkeeper
|
|
2
|
+
module SecretStoring
|
|
3
|
+
|
|
4
|
+
##
|
|
5
|
+
# Plain text secret storing, which is the default
|
|
6
|
+
# but also provides fallback lookup if
|
|
7
|
+
# other secret storing mechanisms are enabled.
|
|
8
|
+
class BCrypt < Base
|
|
9
|
+
##
|
|
10
|
+
# Return the value to be stored by the database
|
|
11
|
+
# @param plain_secret The plain secret input / generated
|
|
12
|
+
def self.transform_secret(plain_secret)
|
|
13
|
+
::BCrypt::Password.create(plain_secret.to_s)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
##
|
|
17
|
+
# Securely compare the given +input+ value with a +stored+ value
|
|
18
|
+
# processed by +transform_secret+.
|
|
19
|
+
def self.secret_matches?(input, stored)
|
|
20
|
+
::BCrypt::Password.new(stored.to_s) == input.to_s
|
|
21
|
+
rescue ::BCrypt::Errors::InvalidHash
|
|
22
|
+
false
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
##
|
|
26
|
+
# Determines whether this strategy supports restoring
|
|
27
|
+
# secrets from the database. This allows detecting users
|
|
28
|
+
# trying to use a non-restorable strategy with +reuse_access_tokens+.
|
|
29
|
+
def self.allows_restoring_secrets?
|
|
30
|
+
false
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
##
|
|
34
|
+
# Determines what secrets this strategy is applicable for
|
|
35
|
+
def self.validate_for(model)
|
|
36
|
+
unless model.to_sym == :application
|
|
37
|
+
raise ArgumentError,
|
|
38
|
+
"'#{name}' can only be used for storing application secrets."
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
unless bcrypt_present?
|
|
42
|
+
raise ArgumentError,
|
|
43
|
+
"'#{name}' requires the 'bcrypt' gem being loaded."
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
true
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
##
|
|
50
|
+
# Test if we can require the BCrypt gem
|
|
51
|
+
def self.bcrypt_present?
|
|
52
|
+
require 'bcrypt'
|
|
53
|
+
true
|
|
54
|
+
rescue LoadError
|
|
55
|
+
false
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Doorkeeper
|
|
2
|
+
module SecretStoring
|
|
3
|
+
|
|
4
|
+
##
|
|
5
|
+
# Plain text secret storing, which is the default
|
|
6
|
+
# but also provides fallback lookup if
|
|
7
|
+
# other secret storing mechanisms are enabled.
|
|
8
|
+
class Plain < Base
|
|
9
|
+
|
|
10
|
+
##
|
|
11
|
+
# Return the value to be stored by the database
|
|
12
|
+
# @param plain_secret The plain secret input / generated
|
|
13
|
+
def self.transform_secret(plain_secret)
|
|
14
|
+
plain_secret
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
##
|
|
18
|
+
# Return the restored value from the database
|
|
19
|
+
# @param resource The resource instance to act on
|
|
20
|
+
# @param attribute The secret attribute to restore
|
|
21
|
+
# as retrieved from the database.
|
|
22
|
+
def self.restore_secret(resource, attribute)
|
|
23
|
+
resource.public_send attribute
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
##
|
|
27
|
+
# Plain values obviously allow restoring
|
|
28
|
+
def self.allows_restoring_secrets?
|
|
29
|
+
true
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Doorkeeper
|
|
2
|
+
module SecretStoring
|
|
3
|
+
|
|
4
|
+
##
|
|
5
|
+
# Plain text secret storing, which is the default
|
|
6
|
+
# but also provides fallback lookup if
|
|
7
|
+
# other secret storing mechanisms are enabled.
|
|
8
|
+
class Sha256Hash < Base
|
|
9
|
+
##
|
|
10
|
+
# Return the value to be stored by the database
|
|
11
|
+
# @param plain_secret The plain secret input / generated
|
|
12
|
+
def self.transform_secret(plain_secret)
|
|
13
|
+
::Digest::SHA256.hexdigest plain_secret
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
##
|
|
17
|
+
# Determines whether this strategy supports restoring
|
|
18
|
+
# secrets from the database. This allows detecting users
|
|
19
|
+
# trying to use a non-restorable strategy with +reuse_access_tokens+.
|
|
20
|
+
def self.allows_restoring_secrets?
|
|
21
|
+
false
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
data/lib/doorkeeper/version.rb
CHANGED
data/lib/doorkeeper.rb
CHANGED
|
@@ -51,11 +51,18 @@ require 'doorkeeper/oauth/token_introspection'
|
|
|
51
51
|
require 'doorkeeper/oauth/invalid_token_response'
|
|
52
52
|
require 'doorkeeper/oauth/forbidden_token_response'
|
|
53
53
|
|
|
54
|
+
require 'doorkeeper/secret_storing/base'
|
|
55
|
+
require 'doorkeeper/secret_storing/plain'
|
|
56
|
+
require 'doorkeeper/secret_storing/sha256_hash'
|
|
57
|
+
require 'doorkeeper/secret_storing/bcrypt'
|
|
58
|
+
|
|
54
59
|
require 'doorkeeper/models/concerns/orderable'
|
|
55
60
|
require 'doorkeeper/models/concerns/scopes'
|
|
56
61
|
require 'doorkeeper/models/concerns/expirable'
|
|
62
|
+
require 'doorkeeper/models/concerns/reusable'
|
|
57
63
|
require 'doorkeeper/models/concerns/revocable'
|
|
58
64
|
require 'doorkeeper/models/concerns/accessible'
|
|
65
|
+
require 'doorkeeper/models/concerns/secret_storable'
|
|
59
66
|
|
|
60
67
|
require 'doorkeeper/models/access_grant_mixin'
|
|
61
68
|
require 'doorkeeper/models/access_token_mixin'
|
|
@@ -64,7 +64,7 @@ Doorkeeper.configure do
|
|
|
64
64
|
|
|
65
65
|
# The controller Doorkeeper::ApplicationController inherits from.
|
|
66
66
|
# Defaults to ActionController::Base.
|
|
67
|
-
# See https://
|
|
67
|
+
# See https://doorkeeper.gitbook.io/guides/configuration/other-configurations#custom-base-controller
|
|
68
68
|
#
|
|
69
69
|
# base_controller 'ApplicationController'
|
|
70
70
|
|
|
@@ -75,8 +75,63 @@ Doorkeeper.configure do
|
|
|
75
75
|
# doesn't updates existing token expiration time, it will create a new token instead.
|
|
76
76
|
# Rationale: https://github.com/doorkeeper-gem/doorkeeper/issues/383
|
|
77
77
|
#
|
|
78
|
+
# You can not enable this option together with +hash_token_secrets+.
|
|
79
|
+
#
|
|
78
80
|
# reuse_access_token
|
|
79
81
|
|
|
82
|
+
# Set a limit for token_reuse if using reuse_access_token option
|
|
83
|
+
#
|
|
84
|
+
# This option limits token_reusability to some extent.
|
|
85
|
+
# If not set then access_token will be reused unless it expires.
|
|
86
|
+
# Rationale: https://github.com/doorkeeper-gem/doorkeeper/issues/1189
|
|
87
|
+
#
|
|
88
|
+
# This option should be a percentage(i.e. (0,100])
|
|
89
|
+
#
|
|
90
|
+
# token_reuse_limit 100
|
|
91
|
+
|
|
92
|
+
# Hash access and refresh tokens before persisting them.
|
|
93
|
+
# This will disable the possibility to use +reuse_access_token+
|
|
94
|
+
# since plain values can no longer be retrieved.
|
|
95
|
+
#
|
|
96
|
+
# Note: If you are already a user of doorkeeper and have existing tokens
|
|
97
|
+
# in your installation, they will be invalid without enabling the additional
|
|
98
|
+
# setting `fallback_to_plain_secrets` below.
|
|
99
|
+
#
|
|
100
|
+
# hash_token_secrets
|
|
101
|
+
# By default, token secrets will be hashed using the
|
|
102
|
+
# +Doorkeeper::Hashing::SHA256+ strategy.
|
|
103
|
+
#
|
|
104
|
+
# If you wish to use another hashing implementation, you can override
|
|
105
|
+
# this strategy as follows:
|
|
106
|
+
#
|
|
107
|
+
# hash_token_secrets using: '::Doorkeeper::Hashing::MyCustomHashImpl'
|
|
108
|
+
#
|
|
109
|
+
# Keep in mind that changing the hashing function will invalidate all existing
|
|
110
|
+
# secrets, if there are any.
|
|
111
|
+
|
|
112
|
+
# Hash application secrets before persisting them.
|
|
113
|
+
#
|
|
114
|
+
# hash_application_secrets
|
|
115
|
+
#
|
|
116
|
+
# By default, applications will be hashed
|
|
117
|
+
# with the +Doorkeeper::SecretStoring::SHA256+ strategy.
|
|
118
|
+
#
|
|
119
|
+
# If you wish to use bcrypt for application secret hashing, uncomment
|
|
120
|
+
# this line instead:
|
|
121
|
+
#
|
|
122
|
+
# hash_application_secrets using: '::Doorkeeper::SecretStoring::BCrypt'
|
|
123
|
+
|
|
124
|
+
# When the above option is enabled,
|
|
125
|
+
# and a hashed token or secret is not found,
|
|
126
|
+
# you can allow to fall back to another strategy.
|
|
127
|
+
# For users upgrading doorkeeper and wishing to enable hashing,
|
|
128
|
+
# you will probably want to enable the fallback to plain tokens.
|
|
129
|
+
#
|
|
130
|
+
# This will ensure that old access tokens and secrets
|
|
131
|
+
# will remain valid even if the hashing above is enabled.
|
|
132
|
+
#
|
|
133
|
+
# fallback_to_plain_secrets
|
|
134
|
+
|
|
80
135
|
# Issue access tokens with refresh token (disabled by default), you may also
|
|
81
136
|
# pass a block which accepts `context` to customize when to give a refresh
|
|
82
137
|
# token or not. Similar to `custom_access_token_expires_in`, `context` has
|
|
@@ -88,12 +143,6 @@ Doorkeeper.configure do
|
|
|
88
143
|
#
|
|
89
144
|
# use_refresh_token
|
|
90
145
|
|
|
91
|
-
# Forbids creating/updating applications with arbitrary scopes that are
|
|
92
|
-
# not in configuration, i.e. `default_scopes` or `optional_scopes`.
|
|
93
|
-
# (disabled by default)
|
|
94
|
-
#
|
|
95
|
-
# enforce_configured_scopes
|
|
96
|
-
|
|
97
146
|
# Provide support for an owner to be assigned to each registered application (disabled by default)
|
|
98
147
|
# Optional parameter confirmation: true (default false) if you want to enforce ownership of
|
|
99
148
|
# a registered application
|
|
@@ -108,6 +157,21 @@ Doorkeeper.configure do
|
|
|
108
157
|
# default_scopes :public
|
|
109
158
|
# optional_scopes :write, :update
|
|
110
159
|
|
|
160
|
+
# Define scopes_by_grant_type to restrict only certain scopes for grant_type
|
|
161
|
+
# By default, all the scopes will be available for all the grant types.
|
|
162
|
+
#
|
|
163
|
+
# Keys to this hash should be the name of grant_type and
|
|
164
|
+
# values should be the array of scopes for that grant type.
|
|
165
|
+
# Note: scopes should be from configured_scopes(i.e. deafult or optional)
|
|
166
|
+
#
|
|
167
|
+
# scopes_by_grant_type password: [:write], client_credentials: [:update]
|
|
168
|
+
|
|
169
|
+
# Forbids creating/updating applications with arbitrary scopes that are
|
|
170
|
+
# not in configuration, i.e. `default_scopes` or `optional_scopes`.
|
|
171
|
+
# (disabled by default)
|
|
172
|
+
#
|
|
173
|
+
# enforce_configured_scopes
|
|
174
|
+
|
|
111
175
|
# Change the way client credentials are retrieved from the request object.
|
|
112
176
|
# By default it retrieves first from the `HTTP_AUTHORIZATION` header, then
|
|
113
177
|
# falls back to the `:client_id` and `:client_secret` params from the `params` object.
|
|
@@ -165,6 +229,24 @@ Doorkeeper.configure do
|
|
|
165
229
|
#
|
|
166
230
|
# handle_auth_errors :raise
|
|
167
231
|
|
|
232
|
+
# Customize token introspection response.
|
|
233
|
+
# Allows to add your own fields to default one that are required by the OAuth spec
|
|
234
|
+
# for the introspection response. It could be `sub`, `aud` and so on.
|
|
235
|
+
# This configuration option can be a proc, lambda or any Ruby object responds
|
|
236
|
+
# to `.call` method and result of it's invocation must be a Hash.
|
|
237
|
+
#
|
|
238
|
+
# custom_introspection_response do |token, context|
|
|
239
|
+
# {
|
|
240
|
+
# "sub": "Z5O3upPC88QrAjx00dis",
|
|
241
|
+
# "aud": "https://protected.example.net/resource",
|
|
242
|
+
# "username": User.find(token.resource_owner_id).username
|
|
243
|
+
# }
|
|
244
|
+
# end
|
|
245
|
+
#
|
|
246
|
+
# or
|
|
247
|
+
#
|
|
248
|
+
# custom_introspection_response CustomIntrospectionResponder
|
|
249
|
+
|
|
168
250
|
# Specify what grant flows are enabled in array of Strings. The valid
|
|
169
251
|
# strings and the flows they enable are:
|
|
170
252
|
#
|
|
@@ -195,7 +277,7 @@ Doorkeeper.configure do
|
|
|
195
277
|
# end
|
|
196
278
|
|
|
197
279
|
# Hook into Authorization flow in order to implement Single Sign Out
|
|
198
|
-
# or add
|
|
280
|
+
# or add any other functionality.
|
|
199
281
|
#
|
|
200
282
|
# before_successful_authorization do |controller|
|
|
201
283
|
# Rails.logger.info(params.inspect)
|
|
@@ -7,6 +7,10 @@ describe Doorkeeper::ApplicationMetalController do
|
|
|
7
7
|
def index
|
|
8
8
|
render json: {}, status: 200
|
|
9
9
|
end
|
|
10
|
+
|
|
11
|
+
def create
|
|
12
|
+
render json: {}, status: 200
|
|
13
|
+
end
|
|
10
14
|
end
|
|
11
15
|
|
|
12
16
|
it "lazy run hooks" do
|
|
@@ -22,13 +26,18 @@ describe Doorkeeper::ApplicationMetalController do
|
|
|
22
26
|
context 'enabled' do
|
|
23
27
|
let(:flag) { true }
|
|
24
28
|
|
|
25
|
-
it '200 for the
|
|
26
|
-
get :index, params: {}
|
|
29
|
+
it 'returns a 200 for the requests without body' do
|
|
30
|
+
get :index, params: {}
|
|
27
31
|
expect(response).to have_http_status 200
|
|
28
32
|
end
|
|
29
33
|
|
|
30
|
-
it 'returns a
|
|
31
|
-
|
|
34
|
+
it 'returns a 200 for the requests with body and correct media type' do
|
|
35
|
+
post :create, params: {}, as: :url_encoded_form
|
|
36
|
+
expect(response).to have_http_status 200
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'returns a 415 for the requests with body and incorrect media type' do
|
|
40
|
+
post :create, params: {}, as: :json
|
|
32
41
|
expect(response).to have_http_status 415
|
|
33
42
|
end
|
|
34
43
|
end
|
|
@@ -45,6 +54,11 @@ describe Doorkeeper::ApplicationMetalController do
|
|
|
45
54
|
get :index, as: :json
|
|
46
55
|
expect(response).to have_http_status 200
|
|
47
56
|
end
|
|
57
|
+
|
|
58
|
+
it 'returns a 200 for the requests with body and incorrect media type' do
|
|
59
|
+
post :create, params: {}, as: :json
|
|
60
|
+
expect(response).to have_http_status 200
|
|
61
|
+
end
|
|
48
62
|
end
|
|
49
63
|
end
|
|
50
64
|
end
|
|
@@ -91,7 +91,7 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
|
|
|
91
91
|
end
|
|
92
92
|
|
|
93
93
|
it "includes access token in fragment" do
|
|
94
|
-
expect(redirect_uri.match(/access_token=([a-
|
|
94
|
+
expect(redirect_uri.match(/access_token=([a-zA-Z0-9\-_]+)&?/)[1]).to eq(Doorkeeper::AccessToken.first.token)
|
|
95
95
|
end
|
|
96
96
|
|
|
97
97
|
it "includes token type in fragment" do
|
|
@@ -165,7 +165,7 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
|
|
|
165
165
|
let(:redirect_uri) { response_json_body['redirect_uri'] }
|
|
166
166
|
|
|
167
167
|
it 'renders 400 error' do
|
|
168
|
-
expect(response.status).to eq
|
|
168
|
+
expect(response.status).to eq 400
|
|
169
169
|
end
|
|
170
170
|
|
|
171
171
|
it 'includes correct redirect URI' do
|
|
@@ -408,7 +408,7 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
|
|
|
408
408
|
expect(redirect_uri.match(/token_type=(\w+)&?/)[1]).to eq "Bearer"
|
|
409
409
|
expect(redirect_uri.match(/expires_in=(\d+)&?/)[1].to_i).to eq 1234
|
|
410
410
|
expect(
|
|
411
|
-
redirect_uri.match(/access_token=([a-
|
|
411
|
+
redirect_uri.match(/access_token=([a-zA-Z0-9\-_]+)&?/)[1]
|
|
412
412
|
).to eq Doorkeeper::AccessToken.first.token
|
|
413
413
|
end
|
|
414
414
|
|
|
@@ -40,7 +40,7 @@ describe Doorkeeper::TokenInfoController do
|
|
|
40
40
|
get :show
|
|
41
41
|
|
|
42
42
|
expect(response.body).to eq(
|
|
43
|
-
Doorkeeper::OAuth::
|
|
43
|
+
Doorkeeper::OAuth::InvalidTokenResponse.new.body.to_json
|
|
44
44
|
)
|
|
45
45
|
end
|
|
46
46
|
end
|