rack-restrict_access 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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