class Rack::Access

Rack middleware for limiting access based on IP address

Options:

path => ipmasks      ipmasks: Array of remote addresses which are allowed to access

Examples:

use Rack::Access, '/backend' => [ '127.0.0.1',  '192.168.1.0/24' ]

Attributes

options[R]

Public Instance Methods

call(env) click to toggle source
# File lib/rack/contrib/access.rb, line 50
def call(env)
  @original_request = Request.new(env)
  ipmasks = ipmasks_for_path(env)
  return forbidden! unless ip_authorized?(ipmasks)
  status, headers, body = @app.call(env)
  [status, headers, body]
end
forbidden!() click to toggle source
# File lib/rack/contrib/access.rb, line 72
def forbidden!
  [403, { 'Content-Type' => 'text/html', 'Content-Length' => '0' }, []]
end
ip_authorized?(ipmasks) click to toggle source
# File lib/rack/contrib/access.rb, line 76
def ip_authorized?(ipmasks)
  return true if ipmasks.nil?

  ipmasks.any? do |ip_mask|
    ip_mask.include?(IPAddr.new(@original_request.ip))
  end
end
ipmasks_for_path(env) click to toggle source
# File lib/rack/contrib/access.rb, line 58
def ipmasks_for_path(env)
  path = env["PATH_INFO"].to_s
  hHost, sName, sPort = env.values_at('HTTP_HOST','SERVER_NAME','SERVER_PORT')
  @mapping.each do |host, location, match, ipmasks|
    next unless (hHost == host || sName == host              || (host.nil? && (hHost == sName || hHost == sName+':'+sPort)))
    next unless path =~ match && rest = $1
    next unless rest.empty? || rest[0] == /

    return ipmasks
  end
  nil
end
remap(mapping) click to toggle source
# File lib/rack/contrib/access.rb, line 29
def remap(mapping)
  mapping.map { |location, ipmasks|
    if location =~ %r{\Ahttps?://(.*?)(/.*)}
      host, location = $1, $2
    else
      host = nil
    end

    unless location[0] == /
      raise ArgumentError, "paths need to start with /"
    end
    location = location.chomp('/')
    match = Regexp.new("^#{Regexp.quote(location).gsub('/', '/+')}(.*)", nil, 'n')

    ipmasks.collect! do |ipmask|
      ipmask.is_a?(IPAddr) ? ipmask : IPAddr.new(ipmask)
    end
    [host, location, match, ipmasks]
  }.sort_by { |(h, l, m, a)| [h ? -h.size : (-1.0 / 0.0), -l.size] }  # Longest path first
end

Public Class Methods

new(app, options = {}) click to toggle source
# File lib/rack/contrib/access.rb, line 23
def initialize(app, options = {})
  @app = app
  mapping = options.empty? ? {"/" => ["127.0.0.1"]} : options
  @mapping = remap(mapping)
end