doorkeeper 4.2.6 → 4.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 (120) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE.md +19 -0
  3. data/.github/PULL_REQUEST_TEMPLATE.md +17 -0
  4. data/.gitignore +1 -1
  5. data/.hound.yml +2 -13
  6. data/.rubocop.yml +13 -0
  7. data/.travis.yml +13 -5
  8. data/Appraisals +6 -2
  9. data/CODE_OF_CONDUCT.md +46 -0
  10. data/Gemfile +1 -1
  11. data/NEWS.md +24 -0
  12. data/README.md +39 -9
  13. data/SECURITY.md +13 -0
  14. data/app/controllers/doorkeeper/application_controller.rb +1 -5
  15. data/app/controllers/doorkeeper/applications_controller.rb +14 -1
  16. data/app/controllers/doorkeeper/tokens_controller.rb +13 -1
  17. data/app/helpers/doorkeeper/dashboard_helper.rb +4 -2
  18. data/app/validators/redirect_uri_validator.rb +12 -2
  19. data/app/views/doorkeeper/applications/_form.html.erb +1 -1
  20. data/app/views/doorkeeper/authorized_applications/index.html.erb +0 -1
  21. data/config/locales/en.yml +3 -5
  22. data/doorkeeper.gemspec +4 -3
  23. data/gemfiles/rails_4_2.gemfile +6 -4
  24. data/gemfiles/rails_5_0.gemfile +4 -4
  25. data/gemfiles/rails_5_1.gemfile +6 -7
  26. data/gemfiles/rails_5_2.gemfile +12 -0
  27. data/gemfiles/rails_master.gemfile +14 -0
  28. data/lib/doorkeeper.rb +1 -0
  29. data/lib/doorkeeper/config.rb +55 -55
  30. data/lib/doorkeeper/engine.rb +3 -3
  31. data/lib/doorkeeper/grape/helpers.rb +13 -8
  32. data/lib/doorkeeper/helpers/controller.rb +8 -4
  33. data/lib/doorkeeper/models/access_token_mixin.rb +14 -7
  34. data/lib/doorkeeper/models/application_mixin.rb +11 -6
  35. data/lib/doorkeeper/models/concerns/expirable.rb +7 -5
  36. data/lib/doorkeeper/oauth/authorization/token.rb +22 -18
  37. data/lib/doorkeeper/oauth/authorization_code_request.rb +6 -1
  38. data/lib/doorkeeper/oauth/base_request.rb +5 -5
  39. data/lib/doorkeeper/oauth/client.rb +2 -2
  40. data/lib/doorkeeper/oauth/client/credentials.rb +2 -2
  41. data/lib/doorkeeper/oauth/error.rb +2 -2
  42. data/lib/doorkeeper/oauth/error_response.rb +1 -2
  43. data/lib/doorkeeper/oauth/forbidden_token_response.rb +1 -1
  44. data/lib/doorkeeper/oauth/invalid_token_response.rb +2 -3
  45. data/lib/doorkeeper/oauth/password_access_token_request.rb +1 -0
  46. data/lib/doorkeeper/oauth/refresh_token_request.rb +1 -0
  47. data/lib/doorkeeper/oauth/scopes.rb +18 -8
  48. data/lib/doorkeeper/oauth/token.rb +1 -1
  49. data/lib/doorkeeper/oauth/token_introspection.rb +128 -0
  50. data/lib/doorkeeper/orm/active_record.rb +20 -8
  51. data/lib/doorkeeper/orm/active_record/access_grant.rb +1 -1
  52. data/lib/doorkeeper/orm/active_record/access_token.rb +1 -23
  53. data/lib/doorkeeper/orm/active_record/application.rb +1 -1
  54. data/lib/doorkeeper/orm/active_record/base_record.rb +11 -0
  55. data/lib/doorkeeper/rails/helpers.rb +5 -6
  56. data/lib/doorkeeper/rails/routes.rb +9 -7
  57. data/lib/doorkeeper/request.rb +7 -1
  58. data/lib/doorkeeper/validations.rb +3 -2
  59. data/lib/doorkeeper/version.rb +13 -1
  60. data/lib/generators/doorkeeper/application_owner_generator.rb +11 -2
  61. data/lib/generators/doorkeeper/migration_generator.rb +13 -1
  62. data/lib/generators/doorkeeper/previous_refresh_token_generator.rb +7 -1
  63. data/lib/generators/doorkeeper/templates/{add_owner_to_application_migration.rb → add_owner_to_application_migration.rb.erb} +1 -1
  64. data/lib/generators/doorkeeper/templates/{add_previous_refresh_token_to_access_tokens.rb → add_previous_refresh_token_to_access_tokens.rb.erb} +1 -1
  65. data/lib/generators/doorkeeper/templates/initializer.rb +19 -3
  66. data/lib/generators/doorkeeper/templates/{migration.rb → migration.rb.erb} +1 -1
  67. data/spec/controllers/applications_controller_spec.rb +15 -4
  68. data/spec/controllers/authorizations_controller_spec.rb +5 -5
  69. data/spec/controllers/protected_resources_controller_spec.rb +28 -19
  70. data/spec/controllers/token_info_controller_spec.rb +17 -13
  71. data/spec/controllers/tokens_controller_spec.rb +138 -4
  72. data/spec/dummy/config/initializers/doorkeeper.rb +1 -1
  73. data/spec/dummy/config/initializers/{active_record_belongs_to_required_by_default.rb → new_framework_defaults.rb} +1 -1
  74. data/spec/dummy/config/initializers/secret_token.rb +0 -1
  75. data/spec/factories.rb +1 -1
  76. data/spec/generators/application_owner_generator_spec.rb +24 -5
  77. data/spec/generators/migration_generator_spec.rb +24 -3
  78. data/spec/generators/previous_refresh_token_generator_spec.rb +57 -0
  79. data/spec/grape/grape_integration_spec.rb +135 -0
  80. data/spec/helpers/doorkeeper/dashboard_helper_spec.rb +1 -1
  81. data/spec/lib/config_spec.rb +115 -12
  82. data/spec/lib/models/revocable_spec.rb +2 -2
  83. data/spec/lib/oauth/authorization_code_request_spec.rb +39 -11
  84. data/spec/lib/oauth/base_request_spec.rb +2 -7
  85. data/spec/lib/oauth/client_credentials/creator_spec.rb +1 -1
  86. data/spec/lib/oauth/client_credentials_integration_spec.rb +1 -1
  87. data/spec/lib/oauth/client_credentials_request_spec.rb +1 -0
  88. data/spec/lib/oauth/code_request_spec.rb +1 -3
  89. data/spec/lib/oauth/helpers/uri_checker_spec.rb +5 -0
  90. data/spec/lib/oauth/invalid_token_response_spec.rb +1 -1
  91. data/spec/lib/oauth/password_access_token_request_spec.rb +9 -3
  92. data/spec/lib/oauth/refresh_token_request_spec.rb +19 -7
  93. data/spec/lib/oauth/scopes_spec.rb +28 -1
  94. data/spec/lib/oauth/token_request_spec.rb +6 -8
  95. data/spec/lib/server_spec.rb +10 -0
  96. data/spec/models/doorkeeper/access_grant_spec.rb +1 -1
  97. data/spec/models/doorkeeper/access_token_spec.rb +72 -48
  98. data/spec/models/doorkeeper/application_spec.rb +51 -18
  99. data/spec/requests/applications/applications_request_spec.rb +5 -5
  100. data/spec/requests/endpoints/token_spec.rb +8 -1
  101. data/spec/requests/flows/authorization_code_spec.rb +1 -0
  102. data/spec/requests/flows/client_credentials_spec.rb +1 -1
  103. data/spec/requests/flows/implicit_grant_errors_spec.rb +2 -2
  104. data/spec/requests/flows/refresh_token_spec.rb +4 -4
  105. data/spec/requests/flows/revoke_token_spec.rb +15 -15
  106. data/spec/requests/protected_resources/metal_spec.rb +1 -1
  107. data/spec/requests/protected_resources/private_api_spec.rb +1 -1
  108. data/spec/routing/custom_controller_routes_spec.rb +4 -0
  109. data/spec/routing/default_routes_spec.rb +5 -1
  110. data/spec/spec_helper_integration.rb +15 -4
  111. data/spec/support/dependencies/factory_girl.rb +2 -2
  112. data/spec/support/helpers/access_token_request_helper.rb +1 -1
  113. data/spec/support/helpers/model_helper.rb +9 -4
  114. data/spec/support/helpers/request_spec_helper.rb +7 -3
  115. data/spec/support/helpers/url_helper.rb +8 -8
  116. data/spec/support/shared/controllers_shared_context.rb +2 -6
  117. data/spec/support/shared/models_shared_examples.rb +4 -4
  118. data/spec/validators/redirect_uri_validator_spec.rb +51 -6
  119. data/spec/version/version_spec.rb +15 -0
  120. metadata +42 -13
@@ -5,11 +5,13 @@ module Doorkeeper
5
5
  module Controller
6
6
  private
7
7
 
8
- def authenticate_resource_owner! # :doc:
8
+ # :doc:
9
+ def authenticate_resource_owner!
9
10
  current_resource_owner
10
11
  end
11
12
 
12
- def current_resource_owner # :doc:
13
+ # :doc:
14
+ def current_resource_owner
13
15
  instance_eval(&Doorkeeper.configuration.authenticate_resource_owner)
14
16
  end
15
17
 
@@ -17,7 +19,8 @@ module Doorkeeper
17
19
  instance_eval(&Doorkeeper.configuration.resource_owner_from_credentials)
18
20
  end
19
21
 
20
- def authenticate_admin! # :doc:
22
+ # :doc:
23
+ def authenticate_admin!
21
24
  instance_eval(&Doorkeeper.configuration.authenticate_admin)
22
25
  end
23
26
 
@@ -25,7 +28,8 @@ module Doorkeeper
25
28
  @server ||= Server.new(self)
26
29
  end
27
30
 
28
- def doorkeeper_token # :doc:
31
+ # :doc:
32
+ def doorkeeper_token
29
33
  @token ||= OAuth::Token.authenticate request, *config_methods
30
34
  end
31
35
 
@@ -68,11 +68,11 @@ module Doorkeeper
68
68
  # @param resource_owner [ActiveRecord::Base]
69
69
  # instance of the Resource Owner model
70
70
  #
71
- def revoke_all_for(application_id, resource_owner)
71
+ def revoke_all_for(application_id, resource_owner, clock = Time)
72
72
  where(application_id: application_id,
73
73
  resource_owner_id: resource_owner.id,
74
74
  revoked_at: nil).
75
- each(&:revoke)
75
+ update_all(revoked_at: clock.now.utc)
76
76
  end
77
77
 
78
78
  # Looking for not expired Access Token with a matching set of scopes
@@ -168,7 +168,7 @@ module Doorkeeper
168
168
  # nil if nothing was found
169
169
  #
170
170
  def last_authorized_token_for(application_id, resource_owner_id)
171
- send(order_method, created_at_desc).
171
+ ordered_by(:created_at, :desc).
172
172
  find_by(application_id: application_id,
173
173
  resource_owner_id: resource_owner_id,
174
174
  revoked_at: nil)
@@ -247,7 +247,11 @@ module Doorkeeper
247
247
  def generate_token
248
248
  self.created_at ||= Time.now.utc
249
249
 
250
- generator = Doorkeeper.configuration.access_token_generator.constantize
250
+ generator = token_generator
251
+ unless generator.respond_to?(:generate)
252
+ raise Errors::UnableToGenerateToken, "#{generator} does not respond to `.generate`."
253
+ end
254
+
251
255
  self.token = generator.generate(
252
256
  resource_owner_id: resource_owner_id,
253
257
  scopes: scopes,
@@ -255,10 +259,13 @@ module Doorkeeper
255
259
  expires_in: expires_in,
256
260
  created_at: created_at
257
261
  )
258
- rescue NoMethodError
259
- raise Errors::UnableToGenerateToken, "#{generator} does not respond to `.generate`."
262
+ end
263
+
264
+ def token_generator
265
+ generator_name = Doorkeeper.configuration.access_token_generator
266
+ generator_name.constantize
260
267
  rescue NameError
261
- raise Errors::TokenGeneratorNotFound, "#{generator} not found"
268
+ raise Errors::TokenGeneratorNotFound, "#{generator_name} not found"
262
269
  end
263
270
  end
264
271
  end
@@ -43,6 +43,15 @@ module Doorkeeper
43
43
  end
44
44
  end
45
45
 
46
+ # Set an application's valid redirect URIs.
47
+ #
48
+ # @param uris [String, Array] Newline-separated string or array the URI(s)
49
+ #
50
+ # @return [String] The redirect URI(s) seperated by newlines.
51
+ def redirect_uri=(uris)
52
+ super(uris.is_a?(Array) ? uris.join("\n") : uris)
53
+ end
54
+
46
55
  private
47
56
 
48
57
  def has_scopes?
@@ -51,15 +60,11 @@ module Doorkeeper
51
60
  end
52
61
 
53
62
  def generate_uid
54
- if uid.blank?
55
- self.uid = UniqueToken.generate
56
- end
63
+ self.uid = UniqueToken.generate if uid.blank?
57
64
  end
58
65
 
59
66
  def generate_secret
60
- if secret.blank?
61
- self.secret = UniqueToken.generate
62
- end
67
+ self.secret = UniqueToken.generate if secret.blank?
63
68
  end
64
69
  end
65
70
  end
@@ -6,7 +6,7 @@ module Doorkeeper
6
6
  #
7
7
  # @return [Boolean] true if object expired and false in other case
8
8
  def expired?
9
- expires_in && Time.now.utc > expired_time
9
+ expires_in && Time.now.utc > expires_at
10
10
  end
11
11
 
12
12
  # Calculates expiration time in seconds.
@@ -15,14 +15,16 @@ module Doorkeeper
15
15
  # or nil if object never expires.
16
16
  def expires_in_seconds
17
17
  return nil if expires_in.nil?
18
- expires = (created_at + expires_in.seconds) - Time.now.utc
18
+ expires = expires_at - Time.now.utc
19
19
  expires_sec = expires.seconds.round(0)
20
20
  expires_sec > 0 ? expires_sec : 0
21
21
  end
22
22
 
23
- private
24
-
25
- def expired_time
23
+ # Expiration time (date time of creation + TTL).
24
+ #
25
+ # @return [Time] expiration time in UTC
26
+ #
27
+ def expires_at
26
28
  created_at + expires_in.seconds
27
29
  end
28
30
  end
@@ -4,19 +4,33 @@ module Doorkeeper
4
4
  class Token
5
5
  attr_accessor :pre_auth, :resource_owner, :token
6
6
 
7
+ class << self
8
+ def access_token_expires_in(server, pre_auth_or_oauth_client)
9
+ if (expiration = custom_expiration(server, pre_auth_or_oauth_client))
10
+ expiration
11
+ else
12
+ server.access_token_expires_in
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def custom_expiration(server, pre_auth_or_oauth_client)
19
+ oauth_client = if pre_auth_or_oauth_client.respond_to?(:client)
20
+ pre_auth_or_oauth_client.client
21
+ else
22
+ pre_auth_or_oauth_client
23
+ end
24
+
25
+ server.custom_access_token_expires_in.call(oauth_client)
26
+ end
27
+ end
28
+
7
29
  def initialize(pre_auth, resource_owner)
8
30
  @pre_auth = pre_auth
9
31
  @resource_owner = resource_owner
10
32
  end
11
33
 
12
- def self.access_token_expires_in(server, pre_auth_or_oauth_client)
13
- if expiration = custom_expiration(server, pre_auth_or_oauth_client)
14
- expiration
15
- else
16
- server.access_token_expires_in
17
- end
18
- end
19
-
20
34
  def issue_token
21
35
  @token ||= AccessToken.find_or_create_for(
22
36
  pre_auth.client,
@@ -37,16 +51,6 @@ module Doorkeeper
37
51
 
38
52
  private
39
53
 
40
- def self.custom_expiration(server, pre_auth_or_oauth_client)
41
- oauth_client = if pre_auth_or_oauth_client.respond_to?(:client)
42
- pre_auth_or_oauth_client.client
43
- else
44
- pre_auth_or_oauth_client
45
- end
46
-
47
- server.custom_access_token_expires_in.call(oauth_client)
48
- end
49
-
50
54
  def configuration
51
55
  Doorkeeper.configuration
52
56
  end
@@ -4,6 +4,7 @@ module Doorkeeper
4
4
  validate :attributes, error: :invalid_request
5
5
  validate :client, error: :invalid_client
6
6
  validate :grant, error: :invalid_grant
7
+ # @see https://tools.ietf.org/html/rfc6749#section-5.2
7
8
  validate :redirect_uri, error: :invalid_grant
8
9
 
9
10
  attr_accessor :server, :grant, :client, :redirect_uri, :access_token
@@ -28,6 +29,7 @@ module Doorkeeper
28
29
  grant.scopes,
29
30
  server)
30
31
  end
32
+ super
31
33
  end
32
34
 
33
35
  def validate_attributes
@@ -44,7 +46,10 @@ module Doorkeeper
44
46
  end
45
47
 
46
48
  def validate_redirect_uri
47
- grant.redirect_uri == redirect_uri
49
+ Helpers::URIChecker.valid_for_authorization?(
50
+ redirect_uri,
51
+ grant.redirect_uri
52
+ )
48
53
  end
49
54
  end
50
55
  end
@@ -5,6 +5,7 @@ module Doorkeeper
5
5
 
6
6
  def authorize
7
7
  validate
8
+
8
9
  if valid?
9
10
  before_successful_response
10
11
  @response = TokenResponse.new(access_token)
@@ -37,14 +38,13 @@ module Doorkeeper
37
38
  resource_owner_id,
38
39
  scopes,
39
40
  Authorization::Token.access_token_expires_in(server, client),
40
- server.refresh_token_enabled?)
41
+ server.refresh_token_enabled?
42
+ )
41
43
  end
42
44
 
43
- def before_successful_response
44
- end
45
+ def before_successful_response; end
45
46
 
46
- def after_successful_response
47
- end
47
+ def after_successful_response; end
48
48
  end
49
49
  end
50
50
  end
@@ -12,7 +12,7 @@ module Doorkeeper
12
12
  end
13
13
 
14
14
  def self.find(uid, method = Application.method(:by_uid))
15
- if application = method.call(uid)
15
+ if (application = method.call(uid))
16
16
  new(application)
17
17
  end
18
18
  end
@@ -20,7 +20,7 @@ module Doorkeeper
20
20
  def self.authenticate(credentials, method = Application.method(:by_uid_and_secret))
21
21
  return false if credentials.blank?
22
22
 
23
- if application = method.call(credentials.uid, credentials.secret)
23
+ if (application = method.call(credentials.uid, credentials.secret))
24
24
  new(application)
25
25
  end
26
26
  end
@@ -1,7 +1,7 @@
1
1
  module Doorkeeper
2
2
  module OAuth
3
3
  class Client
4
- class Credentials < Struct.new(:uid, :secret)
4
+ Credentials = Struct.new(:uid, :secret) do
5
5
  class << self
6
6
  def from_request(request, *credentials_methods)
7
7
  credentials_methods.inject(nil) do |credentials, method|
@@ -18,7 +18,7 @@ module Doorkeeper
18
18
  def from_basic(request)
19
19
  authorization = request.authorization
20
20
  if authorization.present? && authorization =~ /^Basic (.*)/m
21
- Base64.decode64($1).split(/:/, 2)
21
+ Base64.decode64(Regexp.last_match(1)).split(/:/, 2)
22
22
  end
23
23
  end
24
24
  end
@@ -1,10 +1,10 @@
1
1
  module Doorkeeper
2
2
  module OAuth
3
- class Error < Struct.new(:name, :state)
3
+ Error = Struct.new(:name, :state) do
4
4
  def description
5
5
  I18n.translate(
6
6
  name,
7
- scope: [:doorkeeper, :errors, :messages],
7
+ scope: %i[doorkeeper errors messages],
8
8
  default: :server_error
9
9
  )
10
10
  end
@@ -4,8 +4,7 @@ module Doorkeeper
4
4
  include OAuth::Helpers
5
5
 
6
6
  def self.from_request(request, attributes = {})
7
- state = request.state if request.respond_to?(:state)
8
- new(attributes.merge(name: request.error, state: state))
7
+ new(attributes.merge(name: request.error, state: request.try(:state)))
9
8
  end
10
9
 
11
10
  delegate :name, :description, :state, to: :@error
@@ -21,7 +21,7 @@ module Doorkeeper
21
21
  end
22
22
 
23
23
  def description
24
- scope = { scope: [:doorkeeper, :scopes] }
24
+ scope = { scope: %i[doorkeeper scopes] }
25
25
  @description ||= @scopes.map { |r| I18n.translate r, scope }.join('\n')
26
26
  end
27
27
  end
@@ -4,10 +4,9 @@ module Doorkeeper
4
4
  attr_reader :reason
5
5
 
6
6
  def self.from_access_token(access_token, attributes = {})
7
- reason = case
8
- when access_token.try(:revoked?)
7
+ reason = if access_token.try(:revoked?)
9
8
  :revoked
10
- when access_token.try(:expired?)
9
+ elsif access_token.try(:expired?)
11
10
  :expired
12
11
  else
13
12
  :unknown
@@ -22,6 +22,7 @@ module Doorkeeper
22
22
 
23
23
  def before_successful_response
24
24
  find_or_create_access_token(client, resource_owner.id, scopes, server)
25
+ super
25
26
  end
26
27
 
27
28
  def validate_scopes
@@ -35,6 +35,7 @@ module Doorkeeper
35
35
  refresh_token.revoke unless refresh_token_revoked_on_use?
36
36
  create_access_token
37
37
  end
38
+ super
38
39
  end
39
40
 
40
41
  def refresh_token_revoked_on_use?
@@ -45,20 +45,30 @@ module Doorkeeper
45
45
  end
46
46
 
47
47
  def +(other)
48
- if other.is_a? Scopes
49
- self.class.from_array(all + other.all)
50
- else
51
- super(other)
52
- end
48
+ self.class.from_array(all + to_array(other))
53
49
  end
54
50
 
55
51
  def <=>(other)
56
- map(&:to_s).sort <=> other.map(&:to_s).sort
52
+ if other.respond_to?(:map)
53
+ map(&:to_s).sort <=> other.map(&:to_s).sort
54
+ else
55
+ super
56
+ end
57
57
  end
58
58
 
59
59
  def &(other)
60
- other_array = other.present? ? other.all : []
61
- self.class.from_array(all & other_array)
60
+ self.class.from_array(all & to_array(other))
61
+ end
62
+
63
+ private
64
+
65
+ def to_array(other)
66
+ case other
67
+ when Scopes
68
+ other.all
69
+ else
70
+ other.to_a
71
+ end
62
72
  end
63
73
  end
64
74
  end
@@ -11,7 +11,7 @@ module Doorkeeper
11
11
  end
12
12
 
13
13
  def authenticate(request, *methods)
14
- if token = from_request(request, *methods)
14
+ if (token = from_request(request, *methods))
15
15
  access_token = AccessToken.by_token(token)
16
16
  access_token.revoke_previous_refresh_token! if access_token
17
17
  access_token
@@ -0,0 +1,128 @@
1
+ module Doorkeeper
2
+ module OAuth
3
+ # RFC7662 OAuth 2.0 Token Introspection
4
+ #
5
+ # @see https://tools.ietf.org/html/rfc7662
6
+ class TokenIntrospection
7
+ attr_reader :server, :token
8
+ attr_reader :error
9
+
10
+ def initialize(server, token)
11
+ @server = server
12
+ @token = token
13
+
14
+ authorize!
15
+ end
16
+
17
+ def authorized?
18
+ @error.blank?
19
+ end
20
+
21
+ def to_json
22
+ active? ? success_response : failure_response
23
+ end
24
+
25
+ private
26
+
27
+ # If the protected resource uses OAuth 2.0 client credentials to
28
+ # authenticate to the introspection endpoint and its credentials are
29
+ # invalid, the authorization server responds with an HTTP 401
30
+ # (Unauthorized) as described in Section 5.2 of OAuth 2.0 [RFC6749].
31
+ #
32
+ # Endpoint must first validate the authentication.
33
+ # If the authentication is invalid, the endpoint should respond with
34
+ # an HTTP 401 status code and an invalid_client response.
35
+ #
36
+ # @see https://www.oauth.com/oauth2-servers/token-introspection-endpoint/
37
+ #
38
+ def authorize!
39
+ # Requested client authorization
40
+ if server.credentials
41
+ @error = :invalid_client unless authorized_client
42
+ else
43
+ # Requested bearer token authorization
44
+ @error = :invalid_request unless authorized_token
45
+ end
46
+ end
47
+
48
+ # Client Authentication
49
+ def authorized_client
50
+ @_authorized_client ||= server.credentials && server.client
51
+ end
52
+
53
+ # Bearer Token Authentication
54
+ def authorized_token
55
+ @_authorized_token ||=
56
+ OAuth::Token.authenticate(server.context.request, :from_bearer_authorization)
57
+ end
58
+
59
+ # 2.2. Introspection Response
60
+ def success_response
61
+ {
62
+ active: true,
63
+ scope: @token.scopes_string,
64
+ client_id: @token.try(:application).try(:uid),
65
+ token_type: @token.token_type,
66
+ exp: @token.expires_at.to_i,
67
+ iat: @token.created_at.to_i
68
+ }
69
+ end
70
+
71
+ # If the introspection call is properly authorized but the token is not
72
+ # active, does not exist on this server, or the protected resource is
73
+ # not allowed to introspect this particular token, then the
74
+ # authorization server MUST return an introspection response with the
75
+ # "active" field set to "false". Note that to avoid disclosing too
76
+ # much of the authorization server's state to a third party, the
77
+ # authorization server SHOULD NOT include any additional information
78
+ # about an inactive token, including why the token is inactive.
79
+ #
80
+ # @see https://tools.ietf.org/html/rfc7662 2.2. Introspection Response
81
+ #
82
+ def failure_response
83
+ {
84
+ active: false
85
+ }
86
+ end
87
+
88
+ # Boolean indicator of whether or not the presented token
89
+ # is currently active. The specifics of a token's "active" state
90
+ # will vary depending on the implementation of the authorization
91
+ # server and the information it keeps about its tokens, but a "true"
92
+ # value return for the "active" property will generally indicate
93
+ # that a given token has been issued by this authorization server,
94
+ # has not been revoked by the resource owner, and is within its
95
+ # given time window of validity (e.g., after its issuance time and
96
+ # before its expiration time).
97
+ #
98
+ # Any other error is considered an "inactive" token.
99
+ #
100
+ # * The token requested does not exist or is invalid
101
+ # * The token expired
102
+ # * The token was issued to a different client than is making this request
103
+ #
104
+ def active?
105
+ if authorized_client
106
+ valid_token? && authorized_for_client?
107
+ else
108
+ valid_token?
109
+ end
110
+ end
111
+
112
+ # Token can be valid only if it is not expired or revoked.
113
+ def valid_token?
114
+ @token.present? && @token.accessible?
115
+ end
116
+
117
+ # If token doesn't belong to some client, then it is public.
118
+ # Otherwise in it required for token to be connected to the same client.
119
+ def authorized_for_client?
120
+ if @token.application.present?
121
+ @token.application == authorized_client.application
122
+ else
123
+ true
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end