module ChefPlugin::Authentication::InstanceMethods

Public Instance Methods

authenticate_chef_signature(request) click to toggle source
# File lib/smart_proxy_chef_plugin/authentication.rb, line 34
def authenticate_chef_signature(request)
  logger.debug('starting chef signature authentication')
  case request.request_method
    when 'POST'
      content = request.env["rack.input"].read
    when 'GET'
      content = request.env['HTTP_X_FOREMAN_CLIENT']
    else
      log_halt 401, "Don't know how to authenticate #{request.request_method} requests"
  end

  auth = true
  if ChefPlugin::Plugin.settings.chef_authenticate_nodes
    client_name = request.env['HTTP_X_FOREMAN_CLIENT']
    logger.debug("header HTTP_X_FOREMAN_CLIENT: #{client_name}")
    signature   = request.env['HTTP_X_FOREMAN_SIGNATURE']

    log_halt 401, "Failed to authenticate node #{client_name}. Missing some headers" if client_name.nil? or signature.nil?
    auth = verify_signature_request(client_name, signature, content)
  end

  if auth
    log_halt 406, "Body is empty for node #{client_name}" if content.nil?
    logger.debug("#{client_name} authenticated successfully")
    return true
  else
    log_halt 401, "Failed to authenticate node #{client_name}"
  end
end
verify_signature_request(client_name, signature,body) click to toggle source
# File lib/smart_proxy_chef_plugin/authentication.rb, line 17
def verify_signature_request(client_name, signature,body)
  #We need to retrieve client public key to verify signature
  begin
    client = get_connection.clients.fetch(client_name)
  rescue StandardError => e
    log_halt 401, "Failed to authenticate node: " + e.message + "\n#{e.backtrace.join("\n")}"
  end

  log_halt 401, "Could not find client with name #{client_name}" if client.nil?
  public_key = OpenSSL::PKey::RSA.new(client.public_key)

  #signature is base64 encoded
  decoded_signature = Base64.decode64(signature)
  hash_body = Digest::SHA256.hexdigest(body)
  public_key.verify(OpenSSL::Digest::SHA256.new, decoded_signature, hash_body)
end