class Conjur::Rack::Authenticator

Constants

RECOGNIZED_CLAIMS

Attributes

app[R]
options[R]

Public Class Methods

new(app, options = {}) click to toggle source

options:

:except

a list of request path patterns for which to skip authentication.

:optional

request path patterns for which authentication is optional.

# File lib/conjur/rack/authenticator.rb, line 50
def initialize app, options = {}
  @app = app
  @options = options
end

Public Instance Methods

call(rackenv) click to toggle source
# File lib/conjur/rack/authenticator.rb, line 65
def call rackenv
  # never store request-specific variables as application attributes
  Thread.current[:rack_env] = rackenv
  if authenticate?
    begin
      identity = verify_authorization_and_get_identity # [token, account]
      
      if identity
        conjur_rack[:token] = identity[0]
        conjur_rack[:account] = identity[1]
        conjur_rack[:identity] = identity
        conjur_rack[:privilege] = http_privilege
        conjur_rack[:remote_ip] = http_remote_ip
        conjur_rack[:audit_roles] = http_audit_roles
        conjur_rack[:audit_resources] = http_audit_resources
      end

    rescue Forbidden
      return error 403, $!.message
    rescue SecurityError, RestClient::Exception
      return error 401, $!.message
    end
  end
  begin
    @app.call rackenv
  ensure
    Thread.current[:rack_env] = nil
    Thread.current[:conjur_rack] = {}
  end
end
env() click to toggle source

threadsafe accessors, values are established explicitly below

# File lib/conjur/rack/authenticator.rb, line 56
def env; Thread.current[:rack_env] ; end

Protected Instance Methods

authenticate?() click to toggle source
# File lib/conjur/rack/authenticator.rb, line 156
def authenticate?
  path = http_path
  if options[:except]
    options[:except].find{|p| p.match(path)}.nil?
  else
    true
  end
end
conjur_rack() click to toggle source
# File lib/conjur/rack/authenticator.rb, line 98
def conjur_rack
  Conjur::Rack.conjur_rack
end
error(status, message) click to toggle source
# File lib/conjur/rack/authenticator.rb, line 113
def error status, message
  [status, { 'Content-Type' => 'text/plain', 'Content-Length' => message.length.to_s }, [message] ]
end
http_audit_resources() click to toggle source
# File lib/conjur/rack/authenticator.rb, line 186
def http_audit_resources
  env['HTTP_CONJUR_AUDIT_RESOURCES']
end
http_audit_roles() click to toggle source
# File lib/conjur/rack/authenticator.rb, line 182
def http_audit_roles
  env['HTTP_CONJUR_AUDIT_ROLES']
end
http_authorization() click to toggle source
# File lib/conjur/rack/authenticator.rb, line 169
def http_authorization
  env['HTTP_AUTHORIZATION']
end
http_path() click to toggle source
# File lib/conjur/rack/authenticator.rb, line 190
def http_path
  [ env['SCRIPT_NAME'], env['PATH_INFO'] ].join
end
http_privilege() click to toggle source
# File lib/conjur/rack/authenticator.rb, line 173
def http_privilege
  env['HTTP_X_CONJUR_PRIVILEGE']
end
http_remote_ip() click to toggle source
# File lib/conjur/rack/authenticator.rb, line 177
def http_remote_ip
  require 'rack/request'
  ::Rack::Request.new(env).ip
end
optional_paths() click to toggle source
# File lib/conjur/rack/authenticator.rb, line 165
def optional_paths
  options[:optional] || []
end
parsed_token() click to toggle source
# File lib/conjur/rack/authenticator.rb, line 117
def parsed_token
  token = http_authorization.to_s[/^Token token="(.*)"/, 1]
  token = token && JSON.parse(Base64.decode64(token))
  token = Slosilo::JWT token rescue token
rescue JSON::ParserError
  raise AuthorizationError.new("Malformed authorization token")
end
validate_token_and_get_account(token) click to toggle source
# File lib/conjur/rack/authenticator.rb, line 102
def validate_token_and_get_account token
  failure = SignatureError.new("Unauthorized: Invalid token")
  raise failure unless (signer = Slosilo.token_signer token)
  if signer == 'own'
    ENV['CONJUR_ACCOUNT'] or raise failure
  else
    raise failure unless signer =~ /\Aauthn:(.+)\z/
    $1
  end
end
verify_authorization_and_get_identity() click to toggle source
# File lib/conjur/rack/authenticator.rb, line 131
def verify_authorization_and_get_identity
  if token = parsed_token
    begin
      account = validate_token_and_get_account token
      if token.respond_to?(:claims)
        claims = token.claims
        raise AuthorizationError, "token contains unrecognized claims" unless \
            (claims.keys.map(&:to_s) - RECOGNIZED_CLAIMS).empty?
        if (cidr = claims['cidr'])
          raise Forbidden, "IP address rejected" unless \
              cidr.map(&IPAddr.method(:new)).any? { |c| c.include? http_remote_ip }
        end
      end
      return [token, account]
    end
  else
    path = http_path
    if optional_paths.find{|p| p.match(path)}.nil?
      raise AuthorizationError.new("Authorization missing")
    else
      nil
    end
  end
end