summaryrefslogtreecommitdiff
path: root/app/models/api_token.rb
blob: 5c7923d060513c55ff6bd2caa661f37438eca938 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#
# Works like a regular authentication Token, but is configured in the conf file for
# use by admins or testing.
#
# This is not actually a model, but it used in the place of the normal Token model
# when appropriate
#

require 'digest/sha2'

class ApiToken

  #
  # Searches static config to see if there is a matching api token string.
  # Return an ApiToken if successful, or nil otherwise.
  #
  def self.find_by_token(token, ip_address=nil)
    if APP_CONFIG["api_tokens"].nil? || APP_CONFIG["api_tokens"].empty?
      # no api auth tokens are configured
      return nil
    elsif ip_address && !ip_allowed?(ip_address)
      return nil
    elsif !token.is_a?(String) || token.size < 24
      # don't allow obviously invalid token strings
      return nil
    else
      token_digest = Digest::SHA512.hexdigest(token)
      username = self.static_auth_tokens[token_digest]
      if username
        if username == "monitor"
          return ApiMonitorToken.new
        elsif username == "admin"
          # not yet supported
          return nil
        end
      else
        return nil
      end
    end
  end

  private

  #
  # A static hash to represent the configured api auth tokens, in the form:
  #
  # {
  #    "<sha521 of token>" => "<username>"
  # }
  #
  # SHA512 is used here in order to prevent an attacker from discovering
  # the value for an auth token by measuring the string comparison time.
  #
  def self.static_auth_tokens
    @static_auth_tokens ||= APP_CONFIG["api_tokens"].inject({}) {|hsh, entry|
      if ["monitor", "admin"].include?(entry[0])
        hsh[Digest::SHA512.hexdigest(entry[1])] = entry[0]
      end
      hsh
    }.freeze
  end

  def self.ip_allowed?(ip)
    ip == "0.0.0.0" ||
    ip == "127.0.0.1" || (
      APP_CONFIG["api_tokens"] &&
      APP_CONFIG["api_tokens"]["allowed_ips"].is_a?(Array) &&
      APP_CONFIG["api_tokens"]["allowed_ips"].include?(ip)
    )
  end

end

class ApiAdminToken < ApiToken
  # not yet supported
  #def authenticate
  #  AdminUser.new
  #end
end

#
# These tokens used by the platform to run regular monitor tests
# of a production infrastructure.
#
class ApiMonitorToken < ApiToken
  def authenticate
    ApiMonitorUser.new
  end
end