File: fail2ban_spec.rb

package info (click to toggle)
ruby-rack-attack 6.7.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 380 kB
  • sloc: ruby: 2,626; makefile: 4
file content (146 lines) | stat: -rw-r--r-- 4,167 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# frozen_string_literal: true

require_relative 'spec_helper'

describe 'Rack::Attack.Fail2Ban' do
  before do
    # Use a long findtime; failures due to cache key rotation less likely
    @cache = Rack::Attack.cache
    @findtime = 60
    @bantime  = 60
    Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new
    @f2b_options = { bantime: @bantime, findtime: @findtime, maxretry: 2 }

    Rack::Attack.blocklist('pentest') do |req|
      Rack::Attack::Fail2Ban.filter(req.ip, @f2b_options) { req.query_string =~ /OMGHAX/ }
    end
  end

  describe 'discriminator has not been banned' do
    describe 'making ok request' do
      it 'succeeds' do
        get '/', {}, 'REMOTE_ADDR' => '1.2.3.4'
        _(last_response.status).must_equal 200
      end
    end

    describe 'making failing request' do
      describe 'when not at maxretry' do
        before { get '/?foo=OMGHAX', {}, 'REMOTE_ADDR' => '1.2.3.4' }

        it 'fails' do
          _(last_response.status).must_equal 403
        end

        it 'increases fail count' do
          key = "rack::attack:#{Time.now.to_i / @findtime}:fail2ban:count:1.2.3.4"
          _(@cache.store.read(key)).must_equal 1
        end

        it 'is not banned' do
          key = "rack::attack:fail2ban:1.2.3.4"
          _(@cache.store.read(key)).must_be_nil
        end
      end

      describe 'when at maxretry' do
        before do
          # maxretry is 2 - so hit with an extra failed request first
          get '/?test=OMGHAX', {}, 'REMOTE_ADDR' => '1.2.3.4'
          get '/?foo=OMGHAX', {}, 'REMOTE_ADDR' => '1.2.3.4'
        end

        it 'fails' do
          _(last_response.status).must_equal 403
        end

        it 'increases fail count' do
          key = "rack::attack:#{Time.now.to_i / @findtime}:fail2ban:count:1.2.3.4"
          _(@cache.store.read(key)).must_equal 2
        end

        it 'is banned' do
          key = "rack::attack:fail2ban:ban:1.2.3.4"
          _(@cache.store.read(key)).must_equal 1
        end
      end

      describe 'reset after success' do
        before do
          get '/?test=OMGHAX', {}, 'REMOTE_ADDR' => '1.2.3.4'
          Rack::Attack::Fail2Ban.reset('1.2.3.4', @f2b_options)
          get '/', {}, 'REMOTE_ADDR' => '1.2.3.4'
        end

        it 'succeeds' do
          _(last_response.status).must_equal 200
        end

        it 'resets fail count' do
          key = "rack::attack:#{Time.now.to_i / @findtime}:fail2ban:count:1.2.3.4"
          assert_nil @cache.store.read(key)
        end

        it 'IP is not banned' do
          _(Rack::Attack::Fail2Ban.banned?('1.2.3.4')).must_equal false
        end
      end
    end
  end

  describe 'discriminator has been banned' do
    before do
      # maxretry is 2 - so hit enough times to get banned
      get '/?test=OMGHAX', {}, 'REMOTE_ADDR' => '1.2.3.4'
      get '/?foo=OMGHAX', {}, 'REMOTE_ADDR' => '1.2.3.4'
    end

    describe 'making request for other discriminator' do
      it 'succeeds' do
        get '/', {}, 'REMOTE_ADDR' => '2.2.3.4'

        _(last_response.status).must_equal 200
      end
    end

    describe 'making ok request' do
      before do
        get '/', {}, 'REMOTE_ADDR' => '1.2.3.4'
      end

      it 'fails' do
        _(last_response.status).must_equal 403
      end

      it 'does not increase fail count' do
        key = "rack::attack:#{Time.now.to_i / @findtime}:fail2ban:count:1.2.3.4"
        _(@cache.store.read(key)).must_equal 2
      end

      it 'is still banned' do
        key = "rack::attack:fail2ban:ban:1.2.3.4"
        _(@cache.store.read(key)).must_equal 1
      end
    end

    describe 'making failing request' do
      before do
        get '/?foo=OMGHAX', {}, 'REMOTE_ADDR' => '1.2.3.4'
      end

      it 'fails' do
        _(last_response.status).must_equal 403
      end

      it 'does not increase fail count' do
        key = "rack::attack:#{Time.now.to_i / @findtime}:fail2ban:count:1.2.3.4"
        _(@cache.store.read(key)).must_equal 2
      end

      it 'is still banned' do
        key = "rack::attack:fail2ban:ban:1.2.3.4"
        _(@cache.store.read(key)).must_equal 1
      end
    end
  end
end