Class: Msf::WebServices::Authentication::Strategies::ApiToken

Inherits:
Warden::Strategies::Base
  • Object
show all
Defined in:
lib/msf/core/web_services/authentication/strategies/api_token.rb

Direct Known Subclasses

AdminApiToken

Constant Summary collapse

AUTHORIZATION =
'HTTP_AUTHORIZATION'
AUTHORIZATION_SCHEME =
'Bearer'
AUTHORIZATION_PATTERN =
/\A#{AUTHORIZATION_SCHEME}\s+(?<token>\S.*)\z/.freeze

Instance Method Summary collapse

Instance Method Details

#auth_from_db(token) ⇒ Object

Authenticates the user associated with the API token from the DB



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/msf/core/web_services/authentication/strategies/api_token.rb', line 57

def auth_from_db(token)
  db_manager = env['msf.db_manager']

  # Reached when the application was never able to establish a database
  # connection. Reject rather than raising a 500 from a nil db_manager.
  throw(:warden, message: 'Authentication is not configured.', code: 401) if db_manager.nil?
  throw(:warden, message: 'Invalid API token.', code: 401) if blank_token?(token)

  user = db_manager.users(persistence_token: token).first

  validation_data = validate_user(user)
  if validation_data[:valid]
    success!(user)
  else
    throw(:warden, message: validation_data[:message], code: validation_data[:code])
  end
end

#auth_from_env(token) ⇒ Object

Authenticates the API token from an environment variable



86
87
88
89
90
91
92
93
94
95
# File 'lib/msf/core/web_services/authentication/strategies/api_token.rb', line 86

def auth_from_env(token)
  expected_token = request.env['msf.api_token']

  # Compared in constant time to avoid leaking the token a byte at a time.
  if !blank_token?(token) && !blank_token?(expected_token) && Rack::Utils.secure_compare(token, expected_token)
    success!(message: "Successful auth from token")
  else
    throw(:warden, message: 'Invalid API token.', code: 401)
  end
end

#auth_initialized?Boolean

Whether the application has completed authentication bootstrapping.

An application opts into the unauthenticated bootstrap flow - which allows an initial user account to be created before any credentials exist - by explicitly setting ‘msf.auth_initialized’ to false. Any other value, including the key being absent, requires authentication so that the strategy fails closed for applications that never advertise this state.

Returns:

  • (Boolean)

    true if authentication must be enforced; otherwise, false.



40
41
42
# File 'lib/msf/core/web_services/authentication/strategies/api_token.rb', line 40

def auth_initialized?
  request.env['msf.auth_initialized'] != false
end

#authenticate!Object

Authenticate the request.



20
21
22
23
24
25
26
27
28
29
# File 'lib/msf/core/web_services/authentication/strategies/api_token.rb', line 20

def authenticate!
  unless auth_initialized?
    return success!({ message: 'Initialize authentication by creating an initial user account.' })
  end

  token = bearer_token
  throw(:warden, message: 'Invalid API token.', code: 401) if blank_token?(token)

  request.env['msf.api_token'].nil? ? auth_from_db(token) : auth_from_env(token)
end

#bearer_tokenString?

The token carried by an Authorization header using the Bearer scheme. Tokens are only accepted here, never from the query string, so that they stay out of access logs.

Returns:

  • (String, nil)

    the token, or nil if the header is absent, uses a different scheme, or carries no token.



49
50
51
52
53
54
# File 'lib/msf/core/web_services/authentication/strategies/api_token.rb', line 49

def bearer_token
  authorization = request.env[AUTHORIZATION]
  return unless authorization.is_a?(String)

  AUTHORIZATION_PATTERN.match(authorization)&.[](:token)
end

#blank_token?(token) ⇒ Boolean

Returns true if the token is missing or contains no usable characters.

Returns:

  • (Boolean)

    true if the token is missing or contains no usable characters.



98
99
100
# File 'lib/msf/core/web_services/authentication/strategies/api_token.rb', line 98

def blank_token?(token)
  !token.is_a?(String) || token.strip.empty?
end

#valid?Boolean

Check if request contains valid data and should be authenticated.

Returns:

  • (Boolean)

    true if strategy should be run for the request; otherwise, false.



12
13
14
15
16
17
# File 'lib/msf/core/web_services/authentication/strategies/api_token.rb', line 12

def valid?
  # Run the strategy so that #authenticate! can grant the bootstrap exemption.
  return true unless auth_initialized?

  !bearer_token.nil?
end

#validate_user(user) ⇒ Hash

Validates the user associated with the API token.

Parameters:

  • :valid (Hash)

    a customizable set of options

  • :code (Hash)

    a customizable set of options

  • :message (Hash)

    a customizable set of options

Returns:

  • (Hash)

    User validation data



81
82
83
# File 'lib/msf/core/web_services/authentication/strategies/api_token.rb', line 81

def validate_user(user)
  !user.nil? ? {valid: true, code: 0, message: nil} : {valid: false, code: 401, message: "Invalid API token."}
end