rack-restrict_access 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,311 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rack::RestrictAccess do
4
+ describe "initialize" do
5
+ it "should save the app as an instance variable" do
6
+ fake_app = double("app")
7
+ rs = Rack::RestrictAccess.new(fake_app)
8
+ expect(rs.instance_variable_get(:@app)).to eq(fake_app)
9
+ end
10
+
11
+ it "should set default @options" do
12
+ fake_app = double("app")
13
+ rs = Rack::RestrictAccess.new(fake_app)
14
+ expect(rs.instance_variable_get(:@options)).to eq({enabled: true, auth: true})
15
+ end
16
+
17
+ it "should execute block if given" do
18
+ expect_any_instance_of(Rack::RestrictAccess).to receive(:some_method)
19
+ fake_app = double("app")
20
+ Rack::RestrictAccess.new(fake_app) do
21
+ some_method
22
+ end
23
+ end
24
+ end
25
+
26
+ describe "options" do
27
+ it "should override current options" do
28
+ fake_app = double("app")
29
+ rs = Rack::RestrictAccess.new(fake_app) do
30
+ options auth: false
31
+ end
32
+ expect(rs.instance_variable_get(:@options)).to eq({enabled: true, auth: false})
33
+ end
34
+ end
35
+
36
+ describe "block" do
37
+ let (:fake_app) { double("app") }
38
+
39
+ it "should add a BlockFilter to block_filters" do
40
+ rs1 = Rack::RestrictAccess.new(fake_app)
41
+ expect(rs1.send(:block_filters)).to be_empty
42
+ rs1.block do
43
+ end
44
+ expect(rs1.send(:block_filters).length).to eq(1)
45
+ expect(rs1.send(:block_filters).all? {|f| f.is_a? Rack::RestrictAccess::BlockFilter }).to be true
46
+
47
+ rs2 = Rack::RestrictAccess.new(fake_app) do
48
+ block do
49
+ end
50
+ end
51
+ expect(rs2.send(:block_filters).length).to eq(1)
52
+ expect(rs2.send(:block_filters).all? {|f| f.is_a? Rack::RestrictAccess::BlockFilter }).to be true
53
+ end
54
+
55
+ it "should call given block on new BlockFilter" do
56
+ expect_any_instance_of(Rack::RestrictAccess::BlockFilter).to receive(:bogus_method)
57
+ Rack::RestrictAccess.new(fake_app) do
58
+ block do
59
+ bogus_method
60
+ end
61
+ end
62
+ end
63
+
64
+ it "should continue to add BlockFilters to block_filters if called repeatedly" do
65
+ rs = Rack::RestrictAccess.new(fake_app)
66
+ expect(rs.send(:block_filters)).to be_empty
67
+ rs.block do
68
+ end
69
+ expect(rs.send(:block_filters).length).to eq(1)
70
+ expect(rs.send(:block_filters).all? {|f| f.is_a? Rack::RestrictAccess::BlockFilter }).to be true
71
+
72
+ rs.block do
73
+ end
74
+ expect(rs.send(:block_filters).length).to eq(2)
75
+ expect(rs.send(:block_filters).all? {|f| f.is_a? Rack::RestrictAccess::BlockFilter }).to be true
76
+ end
77
+ end
78
+
79
+ describe "restrict" do
80
+ let (:fake_app) { double("app") }
81
+
82
+ it "should add a RestrictFilter to restrict_filters" do
83
+ rs1 = Rack::RestrictAccess.new(fake_app)
84
+ expect(rs1.send(:restrict_filters)).to eq([])
85
+ rs1.restrict do
86
+ end
87
+ expect(rs1.send(:restrict_filters).length).to eq(1)
88
+ expect(rs1.send(:restrict_filters).all? {|f| f.is_a? Rack::RestrictAccess::RestrictFilter }).to be true
89
+
90
+ rs2 = Rack::RestrictAccess.new(fake_app) do
91
+ restrict do
92
+ end
93
+ end
94
+ expect(rs2.send(:restrict_filters).length).to eq(1)
95
+ expect(rs2.send(:restrict_filters).all? {|f| f.is_a? Rack::RestrictAccess::RestrictFilter }).to be true
96
+ end
97
+
98
+ it "should call given block on new RestrictFilter" do
99
+ expect_any_instance_of(Rack::RestrictAccess::RestrictFilter).to receive(:bogus_method)
100
+ Rack::RestrictAccess.new(fake_app) do
101
+ restrict do
102
+ bogus_method
103
+ end
104
+ end
105
+ end
106
+
107
+ it "should continue to add RestrictFilters to restrict_filters if called repeatedly" do
108
+ rs = Rack::RestrictAccess.new(fake_app)
109
+ expect(rs.send(:restrict_filters)).to be_empty
110
+ rs.restrict do
111
+ end
112
+ expect(rs.send(:restrict_filters).length).to eq(1)
113
+ expect(rs.send(:restrict_filters).all? {|f| f.is_a? Rack::RestrictAccess::RestrictFilter }).to be true
114
+
115
+ rs.restrict do
116
+ end
117
+ expect(rs.send(:restrict_filters).length).to eq(2)
118
+ expect(rs.send(:restrict_filters).all? {|f| f.is_a? Rack::RestrictAccess::RestrictFilter }).to be true
119
+ end
120
+ end
121
+
122
+ describe "call" do
123
+ let(:fake_app) { double("app") }
124
+ it "should allow access by default" do
125
+ rs = Rack::RestrictAccess.new(fake_app)
126
+ expect(rs.send(:block_filters)).to eq([])
127
+ expect(rs.send(:allow_filters)).to eq([])
128
+ expect(rs.send(:restrict_filters)).to eq([])
129
+ expect(fake_app).to receive(:call).and_return([200, {"Content-Type" => "text/html"}, ["body"]])
130
+ expect(rs.call({})).to eq([200, {"Content-Type" => "text/html"}, ["body"]])
131
+ end
132
+
133
+ it "should block access when a BlockFilter applies to given path" do
134
+ env = {'PATH_INFO' => '/admin'}
135
+ rs = Rack::RestrictAccess.new(fake_app) do
136
+ block do
137
+ resources '/admin'
138
+ end
139
+ end
140
+ expect(rs.call(env)).to eq([403, {"Content-Type" => "text/html"}, ["<h1>Forbidden</h1>"]])
141
+
142
+ rs2 = Rack::RestrictAccess.new(fake_app) do
143
+ block do
144
+ all_resources!
145
+ end
146
+ end
147
+ expect(rs2.call(env)).to eq([403, {"Content-Type" => "text/html"}, ["<h1>Forbidden</h1>"]])
148
+ end
149
+
150
+ it "should block access when a BlockFilter applies to origin ip" do
151
+ env = {'REMOTE_ADDR' => '192.168.0.1'}
152
+ rs = Rack::RestrictAccess.new(fake_app) do
153
+ block do
154
+ origin_ips '192.168.0.1'
155
+ end
156
+ end
157
+ expect(rs.call(env)).to eq([403, {"Content-Type" => "text/html"}, ["<h1>Forbidden</h1>"]])
158
+ end
159
+
160
+ it "should restrict access when a RestrictFilter applies to given path" do
161
+ env = {'PATH_INFO' => '/admin'}
162
+ rs = Rack::RestrictAccess.new(fake_app) do
163
+ restrict do
164
+ resources '/admin'
165
+ credentials username: 'admin', password: 'pass'
166
+ end
167
+ end
168
+ expect(rs.call(env)).to eq([401, {"Content-Type"=>"text/plain", "Content-Length"=>"0", "WWW-Authenticate"=>"Basic realm=\"\""}, []])
169
+ end
170
+
171
+ it "should restrict access when a RestrictFilter applies to origin ip" do
172
+ env = {'REMOTE_ADDR' => '192.168.0.1'}
173
+ rs = Rack::RestrictAccess.new(fake_app) do
174
+ restrict do
175
+ origin_ips '192.168.0.1'
176
+ credentials username: 'admin', password: 'pass'
177
+ end
178
+ end
179
+ expect(rs.call(env)).to eq([401, {"Content-Type"=>"text/plain", "Content-Length"=>"0", "WWW-Authenticate"=>"Basic realm=\"\""}, []])
180
+ end
181
+
182
+ it "should not restrict access when RestrictFilter does not have any credentials to compare" do
183
+ env = {"PATH_INFO" => "/admin"}
184
+ rs = Rack::RestrictAccess.new(fake_app) do
185
+ restrict do
186
+ all_resources!
187
+ end
188
+ end
189
+ expect(fake_app).to receive(:call).with(env).and_return([200, {"Content-Type" => "text/html"}, ["body"]])
190
+ expect(rs.call(env)).to eq([200, {"Content-Type" => "text/html"}, ["body"]])
191
+ end
192
+
193
+ it "shoud not restrict access when @options[:auth_enabled] is not true" do
194
+ env = {"PATH_INFO" => "/admin"}
195
+ rs = Rack::RestrictAccess.new(fake_app) do
196
+ restrict do
197
+ all_resources!
198
+ end
199
+ end
200
+ expect(fake_app).to receive(:call).and_return([200, {"Content-Type" => "text/html"}, ["body"]])
201
+ expect(rs.call(env)).to eq([200, {"Content-Type" => "text/html"}, ["body"]])
202
+ end
203
+
204
+ it "should allow access when an AllowFilter applies to given path" do
205
+ env = {"PATH_INFO" => "/admin"}
206
+ expect(fake_app).to receive(:call).with(env).exactly(2).times.and_return([200, {"Content-Type" => "text/html"}, ["body"]])
207
+ rs1 = Rack::RestrictAccess.new(fake_app) do
208
+ block do
209
+ all_resources!
210
+ end
211
+
212
+ restrict do
213
+ all_resources!
214
+ end
215
+
216
+ allow do
217
+ resources "/admin"
218
+ end
219
+ end
220
+ expect(rs1.call(env)).to eq([200, {"Content-Type" => "text/html"}, ["body"]])
221
+
222
+ rs2 = Rack::RestrictAccess.new(fake_app) do
223
+ block do
224
+ all_resources!
225
+ end
226
+
227
+ restrict do
228
+ all_resources!
229
+ end
230
+
231
+ allow do
232
+ all_resources!
233
+ end
234
+ end
235
+ expect(rs2.call(env)).to eq([200, {"Content-Type" => "text/html"}, ["body"]])
236
+ end
237
+
238
+ it "should allow access when an AllowFilter applies to origin ip" do
239
+ env = {"REMOTE_ADDR" => "192.168.0.1"}
240
+ expect(fake_app).to receive(:call).with(env).and_return([200, {"Content-Type" => "text/html"}, ["body"]])
241
+ rs1 = Rack::RestrictAccess.new(fake_app) do
242
+ block do
243
+ all_resources!
244
+ end
245
+
246
+ restrict do
247
+ all_resources!
248
+ end
249
+
250
+ allow do
251
+ origin_ips "192.168.0.1"
252
+ end
253
+ end
254
+ expect(rs1.call(env)).to eq([200, {"Content-Type" => "text/html"}, ["body"]])
255
+ end
256
+
257
+ it "should follow the following precedence: AllowFilters > BlockFilters > RestrictFilters" do
258
+ env = {"REMOTE_ADDR" => "192.168.0.1", "PATH_INFO" => "/admin"}
259
+ success_response = [200, {"Content-Type" => "text/html"}, ["body"]]
260
+ blocked_response = [403, {"Content-Type" => "text/html"}, ["<h1>Forbidden</h1>"]]
261
+ restricted_response = [401, {"Content-Type"=>"text/plain", "Content-Length"=>"0", "WWW-Authenticate"=>"Basic realm=\"\""}, []]
262
+ expect(fake_app).to receive(:call).with(env).exactly(1).times.and_return(success_response)
263
+
264
+ allow_rs = Rack::RestrictAccess.new(fake_app) do
265
+ block do
266
+ all_resources!
267
+ end
268
+
269
+ restrict do
270
+ all_resources!
271
+ end
272
+
273
+ allow do
274
+ all_resources!
275
+ end
276
+ end
277
+ expect(allow_rs.call(env)).to eq(success_response)
278
+
279
+ block_rs = Rack::RestrictAccess.new(fake_app) do
280
+ restrict do
281
+ all_resources!
282
+ end
283
+
284
+ block do
285
+ all_resources!
286
+ end
287
+ end
288
+ expect(block_rs.call(env)).to eq(blocked_response)
289
+
290
+ restrict_rs = Rack::RestrictAccess.new(fake_app) do
291
+ restrict do
292
+ all_resources!
293
+ credentials username: 'user', password: '123'
294
+ end
295
+ end
296
+ expect(restrict_rs.call(env)).to eq(restricted_response)
297
+ end
298
+
299
+ it "should allow access if @options[:enabled] is false" do
300
+ rs = Rack::RestrictAccess.new(fake_app) do
301
+ options enabled: false
302
+ block do
303
+ all_resources!
304
+ end
305
+ end
306
+ expect(rs.instance_variable_get(:@options)[:enabled]).to be false
307
+ expect(fake_app).to receive(:call).and_return([200, {"Content-Type" => "text/html"}, ["body"]])
308
+ expect(rs.call({})).to eq([200, {"Content-Type" => "text/html"}, ["body"]])
309
+ end
310
+ end
311
+ end
@@ -0,0 +1,175 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rack::RestrictAccess::RestrictFilter do
4
+ it "should inherit from Filter" do
5
+ expect(Rack::RestrictAccess::RestrictFilter.superclass).to eq(Rack::RestrictAccess::Filter)
6
+ end
7
+
8
+ describe "initialize" do
9
+ it "should set defaults" do
10
+ restrict_filter = Rack::RestrictAccess::RestrictFilter.new
11
+ expect(restrict_filter.instance_variable_get(:@ips)).to eq([])
12
+ expect(restrict_filter.instance_variable_get(:@resources)).to eq([])
13
+ expect(restrict_filter.instance_variable_get(:@credentials)).to eq([])
14
+ end
15
+ end
16
+
17
+ describe "credentials" do
18
+ it "should do nothing if given no arguments" do
19
+ restrict_filter = Rack::RestrictAccess::RestrictFilter.new do
20
+ credentials
21
+ end
22
+ expect(restrict_filter.instance_variable_get(:@credentials))
23
+ .to eq([])
24
+ end
25
+
26
+ it "should save hash of username password pair to @credentials" do
27
+ restrict_filter = Rack::RestrictAccess::RestrictFilter.new do
28
+ credentials(username: 'admin', password: 'pass123')
29
+ end
30
+ expect(restrict_filter.instance_variable_get(:@credentials))
31
+ .to eq([{username: /^admin$/, password: /^pass123$/}])
32
+ end
33
+
34
+ it "should accept regexp values" do
35
+ restrict_filter = Rack::RestrictAccess::RestrictFilter.new do
36
+ credentials(username: /admin$/, password: /^pass/)
37
+ end
38
+ expect(restrict_filter.instance_variable_get(:@credentials))
39
+ .to eq([{username: /admin$/, password: /^pass/}])
40
+ end
41
+
42
+ it "should handle multiple hashes" do
43
+ creds1 = {username: 'u1', password: 'pass1'}
44
+ creds2 = {username: 'u2', password: 'pass2'}
45
+ restrict_filter = Rack::RestrictAccess::RestrictFilter.new do
46
+ credentials creds1, creds2
47
+ end
48
+ expect(restrict_filter.instance_variable_get(:@credentials))
49
+ .to eq([{username: /^u1$/, password: /^pass1$/}, {username: /^u2$/, password: /^pass2$/}])
50
+ end
51
+
52
+ it "should handle an array of hashes" do
53
+ cred_hashes = []
54
+ cred_hashes << {username: 'u1', password: 'pass1'}
55
+ cred_hashes << {username: /u2/, password: /pass2/}
56
+ restrict_filter = Rack::RestrictAccess::RestrictFilter.new do
57
+ credentials cred_hashes
58
+ end
59
+ expect(restrict_filter.instance_variable_get(:@credentials))
60
+ .to eq([{username: /^u1$/, password: /^pass1$/}, {username: /u2/, password: /pass2/}])
61
+ end
62
+
63
+ it "should handle delimited strings" do
64
+ simple_string = 'uname,pass'
65
+ restrict_filter1 = Rack::RestrictAccess::RestrictFilter.new do
66
+ credentials simple_string
67
+ end
68
+ expect(restrict_filter1.instance_variable_get(:@credentials))
69
+ .to eq([{username: /^uname$/, password: /^pass$/}])
70
+
71
+ longer_string = 'user1,pass1;user2,pass2'
72
+ restrict_filter2 = Rack::RestrictAccess::RestrictFilter.new do
73
+ credentials longer_string
74
+ end
75
+ expect(restrict_filter2.instance_variable_get(:@credentials))
76
+ .to eq([{username: /^user1$/, password: /^pass1$/}, {username: /^user2$/, password: /^pass2$/}])
77
+
78
+ complex_string = 'username1:password1 | username2 : password2|username3:password3'
79
+ restrict_filter3 = Rack::RestrictAccess::RestrictFilter.new do
80
+ credentials complex_string, credentials_delimiter: /\s*:\s*/, credential_pair_delimiter: /\s*\|\s*/
81
+ end
82
+ expect(restrict_filter3.instance_variable_get(:@credentials))
83
+ .to eq([{username: /^username1$/, password: /^password1$/}, {username: /^username2$/, password: /^password2$/}, {username: /^username3$/, password: /^password3$/}])
84
+ end
85
+
86
+ it "should handle multiple delimited strings" do
87
+ simple_string = 'uname,pass'
88
+ longer_string = 'user1,pass1;user2,pass2'
89
+ longest_string = 'username1,password1;username2,password2;username3,password3'
90
+ restrict_filter3 = Rack::RestrictAccess::RestrictFilter.new do
91
+ credentials simple_string, longer_string, longest_string
92
+ end
93
+ expect(restrict_filter3.instance_variable_get(:@credentials))
94
+ .to eq([{username: /^uname$/, password: /^pass$/},
95
+ {username: /^user1$/, password: /^pass1$/}, {username: /^user2$/, password: /^pass2$/},
96
+ {username: /^username1$/, password: /^password1$/}, {username: /^username2$/, password: /^password2$/}, {username: /^username3$/, password: /^password3$/}])
97
+ end
98
+
99
+ it "should handle an array of delimited strings and/or hashes" do
100
+ arr = []
101
+ arr << 'uname,pass'
102
+ arr << 'user1,pass1;user2,pass2'
103
+ arr << 'username1,password1;username2,password2;username3,password3'
104
+ restrict_filter3 = Rack::RestrictAccess::RestrictFilter.new do
105
+ credentials arr
106
+ end
107
+ expect(restrict_filter3.instance_variable_get(:@credentials))
108
+ .to eq([{username: /^uname$/, password: /^pass$/},
109
+ {username: /^user1$/, password: /^pass1$/}, {username: /^user2$/, password: /^pass2$/},
110
+ {username: /^username1$/, password: /^password1$/}, {username: /^username2$/, password: /^password2$/}, {username: /^username3$/, password: /^password3$/}])
111
+ end
112
+
113
+ it "should handle multiple arrays of delimited strings/hashes" do
114
+ arr1 = []
115
+ arr1 << 'uname,pass'
116
+ arr1 << 'user1,pass1;user2,pass2'
117
+ arr1 << 'username1,password1;username2,password2;username3,password3'
118
+
119
+ arr2 = []
120
+ arr2 << 'uname2,pass2'
121
+ arr2 << 'user21,pass21;user22,pass22'
122
+ arr2 << 'username21,password21;username22,password22;username23,password23'
123
+ restrict_filter3 = Rack::RestrictAccess::RestrictFilter.new do
124
+ credentials arr1, arr2
125
+ end
126
+ expect(restrict_filter3.instance_variable_get(:@credentials))
127
+ .to eq([{username: /^uname$/, password: /^pass$/},
128
+ {username: /^user1$/, password: /^pass1$/}, {username: /^user2$/, password: /^pass2$/},
129
+ {username: /^username1$/, password: /^password1$/}, {username: /^username2$/, password: /^password2$/}, {username: /^username3$/, password: /^password3$/},
130
+ {username: /^uname2$/, password: /^pass2$/},
131
+ {username: /^user21$/, password: /^pass21$/}, {username: /^user22$/, password: /^pass22$/},
132
+ {username: /^username21$/, password: /^password21$/}, {username: /^username22$/, password: /^password22$/}, {username: /^username23$/, password: /^password23$/}])
133
+ end
134
+
135
+ it "should continue to add to @credentials if called repeatedly" do
136
+ arr1 = []
137
+ arr1 << 'uname,pass'
138
+ arr1 << 'user1,pass1;user2,pass2'
139
+ arr1 << 'username1,password1;username2,password2;username3,password3'
140
+
141
+ arr2 = []
142
+ arr2 << 'uname2,pass2'
143
+ arr2 << 'user21,pass21;user22,pass22'
144
+ arr2 << 'username21,password21;username22,password22;username23,password23'
145
+ restrict_filter3 = Rack::RestrictAccess::RestrictFilter.new do
146
+ credentials arr1
147
+ end
148
+ restrict_filter3.credentials arr2
149
+ expect(restrict_filter3.instance_variable_get(:@credentials))
150
+ .to eq([{username: /^uname$/, password: /^pass$/},
151
+ {username: /^user1$/, password: /^pass1$/}, {username: /^user2$/, password: /^pass2$/},
152
+ {username: /^username1$/, password: /^password1$/}, {username: /^username2$/, password: /^password2$/}, {username: /^username3$/, password: /^password3$/},
153
+ {username: /^uname2$/, password: /^pass2$/},
154
+ {username: /^user21$/, password: /^pass21$/}, {username: /^user22$/, password: /^pass22$/},
155
+ {username: /^username21$/, password: /^password21$/}, {username: /^username22$/, password: /^password22$/}, {username: /^username23$/, password: /^password23$/}])
156
+ end
157
+ end
158
+
159
+ describe "credentials_match?" do
160
+ it "should return true if @credentials contains given username, password pair" do
161
+ restrict_filter = Rack::RestrictAccess::RestrictFilter.new do
162
+ credentials({username: 'admin1', password: 'hard_to_guess'}, {username: 'admin2', password: 'hard_to_guess2'})
163
+ end
164
+ expect(restrict_filter.credentials_match?(username: 'admin2', password: 'hard_to_guess2')).to be true
165
+ end
166
+
167
+ it "should return false if @credentials does not contain given username, password pair" do
168
+ restrict_filter = Rack::RestrictAccess::RestrictFilter.new do
169
+ credentials(username: 'admin1', password: 'hard_to_guess')
170
+ end
171
+ expect(restrict_filter.credentials_match?(username: 'adminfalse', password: 'hard_to_guess2')).to be false
172
+ expect(restrict_filter.credentials_match?(username: 'admin2', password: '')).to be false
173
+ end
174
+ end
175
+ end