class Auther::Gatekeeper

Rack middleware that guards access to sensitive routes. rubocop:disable Metrics/ClassLength

Attributes

application[R]
environment[R]
settings[R]

Public Class Methods

new(application, settings = {}) click to toggle source
# File lib/auther/gatekeeper.rb, line 11
def initialize application, settings = {}
  @application = application
  @settings = Auther::Settings.new settings
end

Public Instance Methods

call(environment) click to toggle source
# File lib/auther/gatekeeper.rb, line 16
def call environment
  @environment = environment

  if authorized? request.path
    application.call environment
  else
    session[Auther::Keymaster.redirect_url_key] = request.path
    denied_response = response
    denied_response.redirect settings.url
    denied_response.finish
  end
end

Private Instance Methods

account_authenticated?(account) click to toggle source

rubocop:disable Metrics/AbcSize

# File lib/auther/gatekeeper.rb, line 94
def account_authenticated? account
  keymaster = Auther::Keymaster.new account.fetch(:name)
  cipher = Auther::Cipher.new settings.secret

  session_login = cipher.decrypt session[keymaster.login_key]
  session_password = cipher.decrypt session[keymaster.password_key]
  account_login = cipher.decrypt account.fetch(:encrypted_login)
  account_password = cipher.decrypt account.fetch(:encrypted_password)

  session_login == account_login && session_password == account_password
end
account_authorized?(account, path) click to toggle source
# File lib/auther/gatekeeper.rb, line 116
def account_authorized? account, path
  all_paths = excluded_paths
  account_paths = clean_paths account.fetch(:paths)
  restricted_paths = all_paths - account_paths

  authorized = !restricted_paths.include?(path)
  log_authorization authorized, account.fetch(:name), all_paths, request.path
  authorized
end
authenticated?(account) click to toggle source

rubocop:enable Metrics/AbcSize

# File lib/auther/gatekeeper.rb, line 107
def authenticated? account
  authenticated = account_authenticated? account
  log_authentication authenticated, account.fetch(:name)
  authenticated
rescue ActiveSupport::MessageEncryptor::InvalidMessage
  log_info %(Authentication failed! Invalid credential(s) for "#{account.fetch :name}" account.)
  false
end
authorized?(path) click to toggle source
# File lib/auther/gatekeeper.rb, line 126
def authorized? path
  if excluded_matched_paths(path).any?
    log_info %(Requested path "#{request.path}" found in excluded paths: ) +
             %(#{excluded_paths}.)
    account = find_account
    account && authenticated?(account) && account_authorized?(account, path)
  else
    true
  end
end
clean_paths(paths) click to toggle source
# File lib/auther/gatekeeper.rb, line 80
def clean_paths paths
  paths.map { |path| path.chomp "/" }
end
excluded_matched_paths(path) click to toggle source
# File lib/auther/gatekeeper.rb, line 89
def excluded_matched_paths path
  excluded_paths.select { |excluded_path| path.include? excluded_path }
end
excluded_paths() click to toggle source
# File lib/auther/gatekeeper.rb, line 84
def excluded_paths
  paths = settings.accounts.map { |account| clean_paths account.fetch(:paths) }
  paths.flatten.uniq
end
find_account() click to toggle source

rubocop:enable Metrics/ParameterLists

# File lib/auther/gatekeeper.rb, line 71
def find_account
  session["auther_init"] = true # Force session to initialize.
  account_name = Auther::Keymaster.get_account_name session
  account = settings.find_account account_name

  account ? log_info("Account found.") : log_info("Account unknown.")
  account
end
log_authentication(authenticated, account_name) click to toggle source
# File lib/auther/gatekeeper.rb, line 49
def log_authentication authenticated, account_name
  if authenticated
    log_info %(Authentication passed. Account: "#{account_name}".)
  else
    log_info %(Authentication failed! Account: "#{account_name}".)
  end
end
log_authorization(authorized, account_name, excludes, request_path) click to toggle source

rubocop:disable Metrics/ParameterLists

# File lib/auther/gatekeeper.rb, line 58
def log_authorization authorized, account_name, excludes, request_path
  details = %(Account: "#{account_name}". ) +
            %(Excludes: #{excludes}. ) +
            %(Request Path: "#{request_path}".)

  if authorized
    log_info %(Authorization passed. #{details})
  else
    log_info %(Authorization failed! #{details})
  end
end
log_info(message) click to toggle source
# File lib/auther/gatekeeper.rb, line 44
def log_info message
  id = "[#{Auther::Keymaster.namespace}]"
  logger.info [id, message].join(": ")
end
request() click to toggle source
# File lib/auther/gatekeeper.rb, line 35
def request
  Rack::Request.new environment
end
response() click to toggle source
# File lib/auther/gatekeeper.rb, line 39
def response
  status, headers, body = application.call environment
  Rack::Response.new body, status, headers
end
session() click to toggle source
# File lib/auther/gatekeeper.rb, line 31
def session
  environment.fetch "rack.session"
end