rack-ip_filter 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # Rack::IpFilter
2
2
 
3
- TODO: Write a gem description
3
+ A Rack middleware component which does simple White and Black list filtering of remote IP Adresses.
4
+
5
+ Provides support for CIDR notation for ranges as well as specific addresses.
4
6
 
5
7
  ## Installation
6
8
 
@@ -18,7 +20,29 @@ Or install it yourself as:
18
20
 
19
21
  ## Usage
20
22
 
21
- TODO: Write usage instructions here
23
+ First require:
24
+
25
+ require 'rack/ip_filter'
26
+
27
+ For Rails, you can insert the middleware in your `config/application.rb`:
28
+
29
+ IP_WHITELIST = %w(192.168.2.0/24 127.0.0.1)
30
+
31
+ module YourApp
32
+ class Application < Rails::Application
33
+ config.middleware.use Rack::IpFilter, IpFilter::WhiteList.new(::IP_WHITELIST)
34
+ end
35
+ end
36
+
37
+ See example/app.rb for a simple Sinatra app which illustrates proper usage.
38
+
39
+ ## Options
40
+
41
+ Rack::IpFilter takes two arguments, the first is an object that responds to `approved?` and returns a boolean.
42
+ The second argument is the path to apply the filter, defaults to root: `'/'`.
43
+
44
+ IpFilter::WhiteList and IpFilter::Black list ship with the gem and explicitly allow or block remote ip addresses
45
+ respectively.
22
46
 
23
47
  ## Contributing
24
48
 
@@ -0,0 +1,22 @@
1
+ require 'sinatra/base'
2
+
3
+ $LOAD_PATH << File.dirname(__FILE__) + '/../lib'
4
+
5
+ require 'rack/ip_filter'
6
+
7
+ # rackup -s thin app.rb
8
+ # http://localhost:9292/test
9
+ class App < Sinatra::Base
10
+
11
+ use Rack::IpFilter, IpFilter::WhiteList.new('192.168.2.0/24', '127.0.0.1'), '/'
12
+ use Rack::IpFilter, IpFilter::WhiteList.new('127.0.0.1'), '/admin'
13
+ use Rack::IpFilter, IpFilter::BlackList.new('192.168.2.23'), '/'
14
+
15
+ set :root, File.dirname(__FILE__)
16
+
17
+ get '/test' do
18
+ content_type "text/plain"
19
+ body "Hello world!"
20
+ end
21
+
22
+ end
@@ -1 +1,11 @@
1
+ require 'ipaddr'
2
+ require 'ip_filter/list'
3
+ require 'ip_filter/white_list'
4
+ require 'ip_filter/black_list'
1
5
  require 'rack/ip_filter'
6
+
7
+ module IpFilter
8
+
9
+ VERSION = '0.1.0'
10
+
11
+ end
@@ -0,0 +1,9 @@
1
+ module IpFilter
2
+
3
+ class BlackList < List
4
+
5
+ def approved?(remote_ip)
6
+ !any?(remote_ip)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ module IpFilter
2
+
3
+ class List
4
+ def initialize(*list)
5
+ @list = list.flatten.map { |ip| IPAddr.new(ip) }
6
+ end
7
+
8
+ def any?(remote_ip)
9
+ @list.any? { |ip| ip.include?(remote_ip) }
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,9 @@
1
+ module IpFilter
2
+
3
+ class WhiteList < List
4
+
5
+ def approved?(remote_ip)
6
+ any?(remote_ip)
7
+ end
8
+ end
9
+ end
@@ -1,36 +1,28 @@
1
- require 'netaddr'
1
+ require 'ip_filter'
2
2
 
3
3
  module Rack
4
4
 
5
5
  class IpFilter
6
6
 
7
- VERSION = "0.0.2"
8
-
9
- def initialize(app, ip_whitelist, path)
10
- @app = app
11
- @ip_whitelist = ip_whitelist.map { |ip| NetAddr::CIDR.create(ip) }
7
+ def initialize(app, list, path = '/')
8
+ @app = app
12
9
  @path = path
10
+ @list = list
13
11
  end
14
12
 
15
13
  def call(env)
16
- if white_listed?(env)
14
+ if approved?(env)
17
15
  @app.call(env)
18
16
  else
19
17
  forbidden!
20
18
  end
21
19
  end
22
-
23
- def white_listed?(env)
24
- return true unless env['REQUEST_PATH'] =~ /^#{@path}/
25
-
26
- remote_addr = remote_address(env)
27
- remote_addr == '127.0.0.1' || @ip_whitelist.any? { |ip_range| ip_range.contains?(remote_addr) }
28
- end
29
20
 
30
- def black_listed?(env)
31
-
21
+ def approved?(env)
22
+ return true unless path_match?(env['REQUEST_PATH'])
23
+ @list.approved?(remote_address(env))
32
24
  end
33
-
25
+
34
26
  def remote_address(env)
35
27
  if env['HTTP_X_FORWARDED_FOR']
36
28
  env['HTTP_X_FORWARDED_FOR'].split(',').first.strip
@@ -43,5 +35,9 @@ module Rack
43
35
  [403, { 'Content-Type' => 'text/html', 'Content-Length' => '0' }, []]
44
36
  end
45
37
 
38
+ def path_match?(path)
39
+ path =~ /^#{@path}/
40
+ end
41
+
46
42
  end
47
43
  end
@@ -1,7 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  lib = File.expand_path('../lib/', __FILE__)
3
3
  $:.unshift lib unless $:.include?(lib)
4
- require 'rack/ip_filter'
4
+ require 'ip_filter'
5
5
 
6
6
  Gem::Specification.new do |gem|
7
7
  gem.authors = ["Mike Evans"]
@@ -18,5 +18,5 @@ Gem::Specification.new do |gem|
18
18
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
19
19
  gem.name = "rack-ip_filter"
20
20
  gem.require_paths = ["lib"]
21
- gem.version = Rack::IpFilter::VERSION
21
+ gem.version = IpFilter::VERSION
22
22
  end
@@ -1,4 +1,5 @@
1
1
  require 'minitest/autorun'
2
+ require 'ip_filter'
2
3
  require 'rack'
3
4
  require 'rack/test'
4
5
  require 'rack/ip_filter'
@@ -0,0 +1,26 @@
1
+ require 'helper'
2
+
3
+ class TestWhiteList < MiniTest::Unit::TestCase
4
+
5
+ def setup
6
+ @range = '192.168.2.0/24'
7
+ @included = '192.168.2.100'
8
+ @not_included = '192.168.3.0'
9
+ end
10
+
11
+ def test_ip_approved
12
+ list = IpFilter::WhiteList.new(@range)
13
+ assert !list.approved?(@included)
14
+ end
15
+
16
+ def test_ip_restricted
17
+ list = IpFilter::WhiteList.new(@range)
18
+ assert list.approved?(@not_included)
19
+ end
20
+
21
+ def test_allows_arrays
22
+ list = IpFilter::WhiteList.new([@range, @not_included])
23
+ assert !list.approved?(@included)
24
+ end
25
+
26
+ end
@@ -1,43 +1,47 @@
1
1
  require 'helper'
2
2
 
3
- class IpWhitelistTest < MiniTest::Unit::TestCase
3
+ class TestRackIpFilter < MiniTest::Unit::TestCase
4
4
  include Rack::Test::Methods
5
5
 
6
- LOCAL_IP = '127.0.0.1'
7
- GOOD_IP = '24.40.64.23'
8
- BAD_IP = '9.9.9.9'
6
+ def setup
7
+ @range = '24.40.64.0/20'
8
+ @local = '127.0.0.1'
9
+ @good = '24.40.64.23'
10
+ @bad = '9.9.9.9'
11
+ @list = [@range, @local]
12
+ end
9
13
 
10
14
  def app
11
- Rack::IpFilter.new(lambda {|env| [200, {}, []] }, ['24.40.64.0/20'], '/')
15
+ Rack::IpFilter.new(lambda {|env| [200, {}, []] }, IpFilter::WhiteList.new(@list), '/')
12
16
  end
13
17
 
14
18
  def test_local_ip_address_admitted
15
- get '/', {}, { 'REQUEST_PATH' => '/', 'REMOTE_ADDR' => LOCAL_IP }
19
+ get '/', {}, { 'REQUEST_PATH' => '/', 'REMOTE_ADDR' => @local }
16
20
  assert last_response.ok?
17
21
  end
18
22
 
19
23
  def test_allowed_remote_ip_address_admitted
20
- get '/', {}, { 'REQUEST_PATH' => '/', 'REMOTE_ADDR' => GOOD_IP }
24
+ get '/', {}, { 'REQUEST_PATH' => '/', 'REMOTE_ADDR' => @good }
21
25
  assert last_response.ok?
22
26
  end
23
27
 
24
28
  def test_outside_remote_ip_address_rejected
25
- get '/', {}, { 'REQUEST_PATH' => '/', 'REMOTE_ADDR' => BAD_IP }
29
+ get '/', {}, { 'REQUEST_PATH' => '/', 'REMOTE_ADDR' => @bad }
26
30
  assert !last_response.ok?
27
31
  end
28
32
 
29
33
  def test_local_ip_address_admitted_via_proxy
30
- get '/', {}, { 'REQUEST_PATH' => '/', 'HTTP_X_FORWARDED_FOR' => [LOCAL_IP, BAD_IP].join(', ') }
34
+ get '/', {}, { 'REQUEST_PATH' => '/', 'HTTP_X_FORWARDED_FOR' => [@local, @bad].join(', ') }
31
35
  assert last_response.ok?
32
36
  end
33
37
 
34
38
  def test_allowed_remote_ip_address_admitted_via_proxy
35
- get '/', {}, { 'REQUEST_PATH' => '/', 'HTTP_X_FORWARDED_FOR' => [GOOD_IP, BAD_IP].join(', ') }
39
+ get '/', {}, { 'REQUEST_PATH' => '/', 'HTTP_X_FORWARDED_FOR' => [@good, @bad].join(', ') }
36
40
  assert last_response.ok?
37
41
  end
38
42
 
39
43
  def test_outside_remote_ip_address_rejected_via_proxy
40
- get '/', {}, { 'REQUEST_PATH' => '/', 'HTTP_X_FORWARDED_FOR' => [BAD_IP, GOOD_IP].join(', ') }
44
+ get '/', {}, { 'REQUEST_PATH' => '/', 'HTTP_X_FORWARDED_FOR' => [@bad, @good].join(', ') }
41
45
  assert !last_response.ok?
42
46
  end
43
47
 
@@ -0,0 +1,26 @@
1
+ require 'helper'
2
+
3
+ class TestWhiteList < MiniTest::Unit::TestCase
4
+
5
+ def setup
6
+ @range = '192.168.2.0/24'
7
+ @included = '192.168.2.100'
8
+ @not_included = '192.168.3.0'
9
+ end
10
+
11
+ def test_ip_approved
12
+ list = IpFilter::WhiteList.new(@range)
13
+ assert list.approved?(@included)
14
+ end
15
+
16
+ def test_ip_restricted
17
+ list = IpFilter::WhiteList.new(@range)
18
+ assert !list.approved?(@not_included)
19
+ end
20
+
21
+ def test_allows_arrays
22
+ list = IpFilter::WhiteList.new([@range, @not_included])
23
+ assert list.approved?(@included)
24
+ end
25
+
26
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-ip_filter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-10 00:00:00.000000000 Z
12
+ date: 2012-05-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: netaddr
16
- requirement: &70234347589200 !ruby/object:Gem::Requirement
16
+ requirement: &70211260750580 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70234347589200
24
+ version_requirements: *70211260750580
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rack
27
- requirement: &70234347588740 !ruby/object:Gem::Requirement
27
+ requirement: &70211260744980 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70234347588740
35
+ version_requirements: *70211260744980
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rack-test
38
- requirement: &70234347588320 !ruby/object:Gem::Requirement
38
+ requirement: &70211260760140 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70234347588320
46
+ version_requirements: *70211260760140
47
47
  description: White and clacklist IPs
48
48
  email:
49
49
  - mike@urlgonomics.com
@@ -56,11 +56,17 @@ files:
56
56
  - LICENSE
57
57
  - README.md
58
58
  - Rakefile
59
+ - example/app.rb
59
60
  - lib/ip_filter.rb
61
+ - lib/ip_filter/black_list.rb
62
+ - lib/ip_filter/list.rb
63
+ - lib/ip_filter/white_list.rb
60
64
  - lib/rack/ip_filter.rb
61
65
  - rack-ip_filter.gemspec
62
66
  - test/helper.rb
63
- - test/test_ip_filter.rb
67
+ - test/test_black_list.rb
68
+ - test/test_rack_ip_filter.rb
69
+ - test/test_white_list.rb
64
70
  homepage: ''
65
71
  licenses: []
66
72
  post_install_message:
@@ -87,4 +93,6 @@ specification_version: 3
87
93
  summary: ''
88
94
  test_files:
89
95
  - test/helper.rb
90
- - test/test_ip_filter.rb
96
+ - test/test_black_list.rb
97
+ - test/test_rack_ip_filter.rb
98
+ - test/test_white_list.rb