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 Class Methods

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

Public Instance Methods

call(env) click to toggle source
   # File lib/rack/contrib/access.rb
52 def call(env)
53   request = Request.new(env)
54   ipmasks = ipmasks_for_path(env)
55   return forbidden! unless ip_authorized?(request, ipmasks)
56   status, headers, body = @app.call(env)
57   [status, headers, body]
58 end
forbidden!() click to toggle source
   # File lib/rack/contrib/access.rb
74 def forbidden!
75   [403, { 'Content-Type' => 'text/html', 'Content-Length' => '0' }, []]
76 end
ip_authorized?(request, ipmasks) click to toggle source
   # File lib/rack/contrib/access.rb
78 def ip_authorized?(request, ipmasks)
79   return true if ipmasks.nil?
80 
81   ipmasks.any? do |ip_mask|
82     ip_mask.include?(IPAddr.new(request.ip))
83   end
84 end
ipmasks_for_path(env) click to toggle source
   # File lib/rack/contrib/access.rb
60 def ipmasks_for_path(env)
61   path = env["PATH_INFO"].to_s
62   hHost, sName, sPort = env.values_at('HTTP_HOST','SERVER_NAME','SERVER_PORT')
63   @mapping.each do |host, location, match, ipmasks|
64     next unless (hHost == host || sName == host \
65         || (host.nil? && (hHost == sName || hHost == sName+':'+sPort)))
66     next unless path =~ match && rest = $1
67     next unless rest.empty? || rest[0] == ?/
68 
69     return ipmasks
70   end
71   nil
72 end
remap(mapping) click to toggle source
   # File lib/rack/contrib/access.rb
31 def remap(mapping)
32   mapping.map { |location, ipmasks|
33     if location =~ %r{\Ahttps?://(.*?)(/.*)}
34       host, location = $1, $2
35     else
36       host = nil
37     end
38 
39     unless location[0] == ?/
40       raise ArgumentError, "paths need to start with /"
41     end
42     location = location.chomp('/')
43     match = Regexp.new("^#{Regexp.quote(location).gsub('/', '/+')}(.*)", nil, 'n')
44 
45     ipmasks.collect! do |ipmask|
46       ipmask.is_a?(IPAddr) ? ipmask : IPAddr.new(ipmask)
47     end
48     [host, location, match, ipmasks]
49   }.sort_by { |(h, l, m, a)| [h ? -h.size : (-1.0 / 0.0), -l.size] }  # Longest path first
50 end