Skip to content

Instantly share code, notes, and snippets.

@ianks
Last active March 14, 2017 19:03
Show Gist options
  • Save ianks/ea9b12c5f4c3d80aa0aeb0ffac73df13 to your computer and use it in GitHub Desktop.
Save ianks/ea9b12c5f4c3d80aa0aeb0ffac73df13 to your computer and use it in GitHub Desktop.
Rails engine for AWS Kibana Auth
# frozen_string_literal: true
require 'aws-sdk'
# This will create an engine mounted at your subdomain of choice.
# If you wanted it to be `kibana.example.com`, set KIBANA_SUBDOMAIN="kibana".
# The engine can be routed in Rails like so:
# Rails.application.routes.draw do
# constraints subdomain: ENV.fetch('KIBANA_SUBDOMAIN') do
# mount Rack::Kibana, at: '/'
# end
# end
require 'aws-sdk'
module Rack
class Kibana
class << self
extend Memoist
def conn
config = { url: ENV.fetch('ELASTICSEARCH_URL') }
credentials = Aws::Credentials.new ENV.fetch('AWS_ACCESS_KEY_ID'),
ENV.fetch('AWS_SECRET_ACCESS_KEY')
Faraday.new(**config) do |f|
f.request :aws_signers_v4,
credentials: credentials,
service_name: 'es',
region: 'us-west-1'
f.adapter :typhoeus
end
end
memoize :conn
def call(env)
return unauthorized_response(env) unless authorized?(env)
res = proxy_request(env)
[res.status, res.headers, [res.body]]
end
private
def proxy_request(e)
Kibana.conn.run_request(method(e), uri(e), body(e), headers(e))
end
def unauthorized_response(env)
env['warden']&.custom_failure!
[401, { 'WWW-Authenticate' => 'Basic' }, []]
end
def authorized?(env)
auth = Rack::Auth::Basic::Request.new(env)
return false unless auth.provided? && auth.basic? && auth.credentials
email, pw = auth.credentials
Rails.cache.fetch([Admin, email, bcrypt(pw)], expires_in: 2.hours) do
Admin.find_by(email: email)&.authenticate(pw)
end
end
def bcrypt(password)
cost = BCrypt::Engine::MIN_COST
BCrypt::Password.create(password, cost: cost)
end
def body(env)
env['rack.input'].read(env['CONTENT_LENGTH'].to_i)
end
def uri(env)
env['REQUEST_URI']
end
def method(env)
env['REQUEST_METHOD'].downcase.to_sym
end
def headers(env)
blacklist = ['HTTP_CONNECTION']
whitelist = ['CONTENT_TYPE']
env
&.select { |k, _v| k.start_with?('HTTP_') || whitelist.include?(k) }
&.reject! { |k, _v| blacklist.include?(k) }
&.transform_keys! { |k| normalize_header_key!(k) }
end
def normalize_header_key!(k)
k.sub(/^HTTP_/, '').sub('_', '-').downcase!
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment