strelka 0.0.1.pre.244 → 0.0.1.pre.252

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data.tar.gz.sig +0 -0
  2. data/ChangeLog +57 -3
  3. data/Manifest.txt +3 -4
  4. data/Rakefile +1 -1
  5. data/bin/strelka +4 -7
  6. data/examples/.env +4 -0
  7. data/examples/Procfile +8 -0
  8. data/examples/apps/auth-demo +3 -5
  9. data/examples/apps/auth-demo2 +10 -9
  10. data/{data/strelka → examples}/apps/hello-world +1 -2
  11. data/examples/apps/sessions-demo +2 -2
  12. data/examples/config.yml +12 -1
  13. data/examples/gen-config.rb +5 -6
  14. data/examples/templates/auth-form.tmpl +4 -0
  15. data/examples/templates/auth-success.tmpl +3 -1
  16. data/lib/strelka.rb +15 -21
  17. data/lib/strelka/app.rb +53 -31
  18. data/lib/strelka/app/auth.rb +260 -132
  19. data/lib/strelka/app/sessions.rb +25 -31
  20. data/lib/strelka/authprovider/basic.rb +33 -9
  21. data/lib/strelka/authprovider/hostaccess.rb +1 -1
  22. data/lib/strelka/constants.rb +0 -11
  23. data/lib/strelka/cookie.rb +17 -1
  24. data/lib/strelka/httpresponse/negotiation.rb +1 -1
  25. data/lib/strelka/session/db.rb +49 -25
  26. data/lib/strelka/session/default.rb +39 -19
  27. data/spec/lib/helpers.rb +3 -24
  28. data/spec/strelka/app/auth_spec.rb +461 -177
  29. data/spec/strelka/app/sessions_spec.rb +7 -26
  30. data/spec/strelka/app_spec.rb +3 -3
  31. data/spec/strelka/authprovider/basic_spec.rb +4 -4
  32. data/spec/strelka/httprequest/session_spec.rb +1 -1
  33. data/spec/strelka/httpresponse/session_spec.rb +1 -1
  34. data/spec/strelka/session/db_spec.rb +6 -1
  35. data/spec/strelka/session/default_spec.rb +3 -3
  36. metadata +7 -8
  37. metadata.gz.sig +2 -2
  38. data/examples/apps/ws-echo +0 -17
  39. data/lib/strelka/logging.rb +0 -301
  40. data/spec/strelka/logging_spec.rb +0 -74
data/spec/lib/helpers.rb CHANGED
@@ -28,6 +28,7 @@ if ENV['COVERAGE']
28
28
  end
29
29
 
30
30
  require 'loggability'
31
+ require 'loggability/spechelpers'
31
32
  require 'configurability'
32
33
  require 'pathname'
33
34
  require 'tmpdir'
@@ -55,30 +56,6 @@ module Strelka::SpecHelpers
55
56
  end
56
57
 
57
58
 
58
- ### Reset the logging subsystem to its default state.
59
- def reset_logging
60
- Loggability.formatter = nil
61
- Loggability.output_to( $stderr )
62
- Loggability.level = :fatal
63
- end
64
-
65
-
66
- ### Alter the output of the default log formatter to be pretty in SpecMate output
67
- def setup_logging( level=:fatal )
68
-
69
- # Only do this when executing from a spec in TextMate
70
- if ENV['HTML_LOGGING'] || (ENV['TM_FILENAME'] && ENV['TM_FILENAME'] =~ /_spec\.rb/)
71
- logarray = []
72
- Thread.current['logger-output'] = logarray
73
- Loggability.output_to( logarray )
74
- Loggability.format_as( :html )
75
- Loggability.level = :debug
76
- else
77
- Loggability.level = level
78
- end
79
- end
80
-
81
-
82
59
  ### Set up a Mongrel2 configuration database according to the specified +dbspec+.
83
60
  ### Set up a Mongrel2 configuration database in memory.
84
61
  def setup_config_db
@@ -272,8 +249,10 @@ RSpec.configure do |c|
272
249
 
273
250
  c.mock_with( :rspec )
274
251
 
252
+ c.extend( Strelka::TestConstants )
275
253
  c.extend( Strelka::TestConstants )
276
254
  c.include( Strelka::TestConstants )
255
+ c.include( Loggability::SpecHelpers )
277
256
  c.include( Mongrel2::SpecHelpers )
278
257
  c.include( Strelka::SpecHelpers )
279
258
  # c.include( Strelka::Matchers )
@@ -89,12 +89,12 @@ describe Strelka::App::Auth do
89
89
  end
90
90
 
91
91
 
92
- it "applies auth to every request by default" do
92
+ it "applies authentication and authorization to every request by default" do
93
93
  app = @app.new
94
94
  req = @request_factory.get( '/api/v1' )
95
95
 
96
96
  app.auth_provider.should_receive( :authenticate ).and_return( 'anonymous' )
97
- app.auth_provider.should_receive( :authorize ).and_return( true )
97
+ app.auth_provider.should_receive( :authorize )
98
98
 
99
99
  res = app.handle( req )
100
100
 
@@ -117,300 +117,584 @@ describe Strelka::App::Auth do
117
117
  end
118
118
 
119
119
  it "has its auth config inherited by subclasses" do
120
- @app.class_eval do
121
- auth_provider :hostaccess
122
- authz_callback { true }
123
- end
124
120
  subclass = Class.new( @app )
125
121
 
126
- subclass.auth_provider.should == @app.auth_provider
127
- subclass.authz_callback.should == @app.authz_callback
128
122
  subclass.positive_auth_criteria.should == @app.positive_auth_criteria
129
123
  subclass.positive_auth_criteria.should_not equal( @app.positive_auth_criteria )
130
124
  subclass.negative_auth_criteria.should == @app.negative_auth_criteria
131
125
  subclass.negative_auth_criteria.should_not equal( @app.negative_auth_criteria )
126
+ subclass.positive_perms_criteria.should == @app.positive_perms_criteria
127
+ subclass.positive_perms_criteria.should_not equal( @app.positive_perms_criteria )
128
+ subclass.negative_perms_criteria.should == @app.negative_perms_criteria
129
+ subclass.negative_perms_criteria.should_not equal( @app.negative_perms_criteria )
132
130
  end
133
131
 
134
132
 
135
- context "that has negative auth criteria for the root" do
133
+ it "allows auth criteria to be declared with a string" do
134
+ @app.require_auth_for( '/string' )
135
+ app = @app.new
136
136
 
137
- before( :each ) do
138
- @app.no_auth_for( '/' )
139
- end
137
+ req = @request_factory.get( '/api/v1/string' )
138
+ app.request_should_auth?( req ).should be_true()
139
+ req = @request_factory.get( '/api/v1/strong' )
140
+ app.request_should_auth?( req ).should be_false()
141
+ req = @request_factory.get( '/api/v1/stri' )
142
+ app.request_should_auth?( req ).should be_false()
143
+ req = @request_factory.get( '/api/v1/string/long' )
144
+ app.request_should_auth?( req ).should be_false()
145
+ end
140
146
 
141
- it "knows that it has auth criteria" do
142
- @app.should have_auth_criteria()
147
+ it "allows auth criteria to be declared with a regexp" do
148
+ @app.require_auth_for( %r{/str[io]} )
149
+ app = @app.new
150
+
151
+ req = @request_factory.get( '/api/v1/stri' )
152
+ app.request_should_auth?( req ).should be_true()
153
+ req = @request_factory.get( '/api/v1/stro' )
154
+ app.request_should_auth?( req ).should be_true()
155
+ req = @request_factory.get( '/api/v1/string' ) # not right-bound
156
+ app.request_should_auth?( req ).should be_true()
157
+ req = @request_factory.get( '/api/v1/string/long' )
158
+ app.request_should_auth?( req ).should be_true()
159
+ req = @request_factory.get( '/api/v1/other/string/long' ) # Not left-bound
160
+ app.request_should_auth?( req ).should be_true()
161
+ req = @request_factory.get( '/api/v1/chatlog' ) # Not left-bound
162
+ app.request_should_auth?( req ).should be_false()
163
+ end
164
+
165
+ it "allows auth criteria to be declared with a string and a block" do
166
+ @app.require_auth_for( 'string' ) do |req|
167
+ req.verb != :GET
143
168
  end
144
169
 
145
- it "doesn't pass a request for the root path through auth" do
146
- req = @request_factory.get( '/api/v1/' )
170
+ app = @app.new
147
171
 
148
- app = @app.new
149
- app.auth_provider.should_not_receive( :authenticate )
150
- app.auth_provider.should_not_receive( :authorize )
172
+ req = @request_factory.get( '/api/v1/string' )
173
+ app.request_should_auth?( req ).should be_false()
174
+ req = @request_factory.post( '/api/v1/string' )
175
+ app.request_should_auth?( req ).should be_true()
176
+ req = @request_factory.put( '/api/v1/string' )
177
+ app.request_should_auth?( req ).should be_true()
178
+ req = @request_factory.delete( '/api/v1/string' )
179
+ app.request_should_auth?( req ).should be_true()
180
+ req = @request_factory.options( '/api/v1/string' )
181
+ app.request_should_auth?( req ).should be_true()
182
+ end
151
183
 
152
- app.handle( req )
184
+ it "allows auth criteria to be declared with a regexp and a block" do
185
+ @app.require_auth_for( %r{/regexp(?:/(?<username>\w+))?} ) do |req, match|
186
+ match[:username] ? true : false
153
187
  end
154
188
 
155
- it "passes a request for a path other than the root through auth" do
156
- req = @request_factory.get( '/api/v1/console' )
189
+ app = @app.new
157
190
 
158
- app = @app.new
159
- app.auth_provider.should_receive( :authenticate ).and_return( 'anonymous' )
160
- app.auth_provider.should_receive( :authorize ).and_return( true )
191
+ req = @request_factory.get( '/api/v1/regexp' )
192
+ app.request_should_auth?( req ).should be_false()
193
+ req = @request_factory.get( '/api/v1/regexp/a_username' )
194
+ app.request_should_auth?( req ).should be_true()
195
+ req = @request_factory.get( '/api/v1/regexp/%20not+a+username' )
196
+ app.request_should_auth?( req ).should be_false()
197
+ end
161
198
 
162
- app.handle( req )
199
+ it "allows auth criteria to be declared with just a block" do
200
+ @app.require_auth_for do |req|
201
+ path = req.app_path.gsub( %r{^/+|/+$}, '' )
202
+
203
+ (
204
+ path == 'strong' or
205
+ path =~ %r{^marlon_brando$}i or
206
+ req.verb == :POST or
207
+ req.content_type == 'application/x-www-form-urlencoded'
208
+ )
163
209
  end
164
210
 
211
+ app = @app.new
212
+
213
+ req = @request_factory.get( '/api/v1/strong' )
214
+ app.request_should_auth?( req ).should be_true()
215
+ req = @request_factory.get( '/api/v1/marlon_brando' )
216
+ app.request_should_auth?( req ).should be_true()
217
+ req = @request_factory.post( '/api/v1/somewhere' )
218
+ app.request_should_auth?( req ).should be_true()
219
+ req = @request_factory.put( '/api/v1/somewhere' )
220
+ req.content_type = 'application/x-www-form-urlencoded'
221
+ app.request_should_auth?( req ).should be_true()
222
+
223
+ req = @request_factory.get( '/api/v1/string' )
224
+ app.request_should_auth?( req ).should be_false()
225
+ req = @request_factory.get( '/api/v1/marlon_brando/2' )
226
+ app.request_should_auth?( req ).should be_false()
227
+ req = @request_factory.put( '/api/v1/somewhere' )
228
+ app.request_should_auth?( req ).should be_false()
229
+
165
230
  end
166
231
 
167
- context "that has negative auth criteria" do
168
232
 
169
- before( :each ) do
170
- @app.no_auth_for( '/login' )
171
- end
233
+ it "allows negative auth criteria to be declared with a string" do
234
+ @app.no_auth_for( '/string' )
235
+ app = @app.new
172
236
 
173
- it "knows that it has auth criteria" do
174
- @app.should have_auth_criteria()
175
- end
237
+ req = @request_factory.get( '/api/v1/string' )
238
+ app.request_should_auth?( req ).should be_false()
239
+ req = @request_factory.get( '/api/v1/strong' )
240
+ app.request_should_auth?( req ).should be_true()
241
+ req = @request_factory.get( '/api/v1/stri' )
242
+ app.request_should_auth?( req ).should be_true()
243
+ req = @request_factory.get( '/api/v1/string/long' )
244
+ app.request_should_auth?( req ).should be_true()
245
+ end
176
246
 
177
- it "doesn't pass a request that matches through auth" do
178
- req = @request_factory.get( '/api/v1/login' )
247
+ it "allows negative auth criteria to be declared with a regexp" do
248
+ @app.no_auth_for( %r{/str[io]} )
249
+ app = @app.new
179
250
 
180
- app = @app.new
181
- app.auth_provider.should_not_receive( :authenticate )
182
- app.auth_provider.should_not_receive( :authorize )
251
+ req = @request_factory.get( '/api/v1/stri' )
252
+ app.request_should_auth?( req ).should be_false()
253
+ req = @request_factory.get( '/api/v1/stro' )
254
+ app.request_should_auth?( req ).should be_false()
255
+ req = @request_factory.get( '/api/v1/string' ) # not right-bound
256
+ app.request_should_auth?( req ).should be_false()
257
+ req = @request_factory.get( '/api/v1/string/long' )
258
+ app.request_should_auth?( req ).should be_false()
259
+ req = @request_factory.get( '/api/v1/other/string/long' ) # Not left-bound
260
+ app.request_should_auth?( req ).should be_false()
261
+ req = @request_factory.get( '/api/v1/chat' )
262
+ app.request_should_auth?( req ).should be_true()
263
+ end
183
264
 
184
- app.handle( req )
265
+ it "allows negative auth criteria to be declared with a string and a block" do
266
+ @app.no_auth_for( 'string' ) do |req|
267
+ Strelka.log.debug "Checking request verb: %p" % [ req.verb ]
268
+ req.verb == :GET
185
269
  end
186
270
 
187
- it "passes a request that doesn't match through auth" do
188
- req = @request_factory.get( '/api/v1/console' )
271
+ app = @app.new
189
272
 
190
- app = @app.new
191
- app.auth_provider.should_receive( :authenticate ).and_return( 'anonymous' )
192
- app.auth_provider.should_receive( :authorize ).and_return( true )
273
+ req = @request_factory.get( '/api/v1/string' )
274
+ app.request_should_auth?( req ).should be_false()
275
+ req = @request_factory.get( '/api/v1/strong' )
276
+ app.request_should_auth?( req ).should be_true()
277
+ req = @request_factory.post( '/api/v1/string' )
278
+ app.request_should_auth?( req ).should be_true()
279
+ req = @request_factory.put( '/api/v1/string' )
280
+ app.request_should_auth?( req ).should be_true()
281
+ req = @request_factory.delete( '/api/v1/string' )
282
+ app.request_should_auth?( req ).should be_true()
283
+ req = @request_factory.options( '/api/v1/string' )
284
+ app.request_should_auth?( req ).should be_true()
285
+ end
193
286
 
194
- app.handle( req )
287
+ it "allows negative auth criteria to be declared with a regexp and a block" do
288
+ @app.no_auth_for( %r{/regexp(?:/(?<username>\w+))?} ) do |req, match|
289
+ match[:username] == 'guest'
195
290
  end
196
291
 
197
- end
292
+ app = @app.new
198
293
 
199
- context "that has a negative auth criteria block" do
294
+ req = @request_factory.get( '/api/v1/regexp' )
295
+ app.request_should_auth?( req ).should be_true()
296
+ req = @request_factory.get( '/api/v1/regexp/a_username' )
297
+ app.request_should_auth?( req ).should be_true()
298
+ req = @request_factory.get( '/api/v1/regexp/%20not+a+username' )
299
+ app.request_should_auth?( req ).should be_true()
300
+ req = @request_factory.get( '/api/v1/regexp/guest' )
301
+ app.request_should_auth?( req ).should be_false()
302
+ end
200
303
 
201
- before( :each ) do
202
- @app.no_auth_for do |req|
203
- req.notes[:skip_auth]
204
- end
304
+ it "allows negative auth criteria to be declared with just a block" do
305
+ @app.no_auth_for do |req|
306
+ req.app_path == '/foom' &&
307
+ req.verb == :GET &&
308
+ req.headers.accept.include?( 'text/plain' )
205
309
  end
206
310
 
207
- it "knows that it has auth criteria" do
208
- @app.should have_auth_criteria()
209
- end
311
+ app = @app.new
210
312
 
211
- it "doesn't pass a request for which the block returns true through auth" do
212
- req = @request_factory.get( '/api/v1/login' )
213
- req.notes[:skip_auth] = true
313
+ req = @request_factory.get( '/api/v1/foom' )
314
+ app.request_should_auth?( req ).should be_true()
315
+ req = @request_factory.post( '/api/v1/foom', :accept => 'text/plain, text/html; q=0.5' )
316
+ app.request_should_auth?( req ).should be_true()
317
+ req = @request_factory.get( '/api/v1/foom', :accept => 'text/plain, text/html; q=0.5' )
318
+ app.request_should_auth?( req ).should be_false()
214
319
 
215
- app = @app.new
216
- app.auth_provider.should_not_receive( :authenticate )
217
- app.auth_provider.should_not_receive( :authorize )
320
+ end
218
321
 
219
- app.handle( req )
220
- end
221
322
 
222
- it "passes a request for which the block returns false through auth" do
223
- req = @request_factory.get( '/api/v1/login' )
224
- req.notes[:skip_auth] = false
323
+ it "allows perms criteria to be declared with a string" do
324
+ @app.require_perms_for( '/string', :stringperm )
325
+ app = @app.new
225
326
 
226
- app = @app.new
227
- app.auth_provider.should_receive( :authenticate ).and_return( 'anonymous' )
228
- app.auth_provider.should_receive( :authorize ).and_return( true )
327
+ req = @request_factory.get( '/api/v1/string' )
328
+ app.required_perms_for( req ).should == [ :stringperm ]
329
+ req = @request_factory.get( '/api/v1/strong' )
330
+ app.required_perms_for( req ).should == []
331
+ end
229
332
 
230
- app.handle( req )
231
- end
333
+ it "allows perms criteria to be declared with a regexp" do
334
+ @app.require_perms_for( %r{^/admin}, :admin )
335
+ @app.require_perms_for( %r{/grant}, :grant )
336
+ app = @app.new
232
337
 
338
+ req = @request_factory.get( '/api/v1/admin' )
339
+ app.required_perms_for( req ).should == [ :admin ]
340
+ req = @request_factory.get( '/api/v1/admin/grant' )
341
+ app.required_perms_for( req ).should == [ :admin, :grant ]
342
+ req = @request_factory.get( '/api/v1/users' )
343
+ app.required_perms_for( req ).should == []
344
+ req = @request_factory.get( '/api/v1/users/grant' )
345
+ app.required_perms_for( req ).should == [ :grant ]
233
346
  end
234
347
 
348
+ it "allows perms criteria to be declared with a string and a block" do
349
+ @app.require_perms_for( '/string' ) do |req|
350
+ perms = [:stringperm, :otherperm]
351
+ perms << :rawdata if req.headers.accept && req.headers.accept =~ /json/i
352
+ perms
353
+ end
354
+ app = @app.new
235
355
 
236
- context "that has a negative auth criteria with both a pattern and a block" do
356
+ req = @request_factory.get( '/api/v1/string' )
357
+ app.required_perms_for( req ).should == [ :stringperm, :otherperm ]
358
+ req = @request_factory.get( '/api/v1/strong' )
359
+ app.required_perms_for( req ).should == []
360
+ end
237
361
 
238
- before( :each ) do
239
- @app.no_auth_for( %r{^/login/(?<username>\w+)} ) do |req, match|
240
- match[:username] != 'validuser'
241
- end
362
+ it "allows perms criteria to be declared with a regexp and a block" do
363
+ @app.require_perms_for( %r{^/admin(/(?<username>\w+))?} ) do |req, match|
364
+ perms = [:admin]
365
+ perms << match[:username].to_sym if match[:username]
366
+ perms
242
367
  end
368
+ app = @app.new
369
+
370
+ req = @request_factory.get( '/api/v1/admin' )
371
+ app.required_perms_for( req ).should == [ :admin ]
372
+ req = @request_factory.get( '/api/v1/admin/jzero' )
373
+ app.required_perms_for( req ).should == [ :admin, :jzero ]
374
+ req = @request_factory.get( '/api/v1/users' )
375
+ app.required_perms_for( req ).should == []
376
+ end
243
377
 
244
- it "knows that it has auth criteria" do
245
- @app.should have_auth_criteria()
378
+ it "allows perms criteria to be declared with just a block" do
379
+ @app.require_perms_for do |req|
380
+ req.app_path.scan( %r{/(\w+)} ).flatten.map( &:to_sym )
246
381
  end
382
+ app = @app.new
247
383
 
248
- it "doesn't pass a request through auth if the path matches and the block returns true" do
249
- req = @request_factory.get( '/api/v1/login/lyssa' )
384
+ req = @request_factory.get( '/api/v1/admin' )
385
+ app.required_perms_for( req ).should == [ :admin ]
386
+ req = @request_factory.get( '/api/v1/admin/jzero' )
387
+ app.required_perms_for( req ).should == [ :admin, :jzero ]
388
+ req = @request_factory.get( '/api/v1/users' )
389
+ app.required_perms_for( req ).should == [ :users ]
390
+ end
250
391
 
251
- app = @app.new
252
- app.auth_provider.should_not_receive( :authenticate )
253
- app.auth_provider.should_not_receive( :authorize )
392
+ it "allows negative perms criteria to be declared with a string" do
393
+ @app.no_perms_for( '/string' )
394
+ app = @app.new
254
395
 
255
- app.handle( req )
256
- end
396
+ req = @request_factory.get( '/api/v1/string' )
397
+ app.required_perms_for( req ).should be_empty()
398
+ req = @request_factory.get( '/api/v1/strong' )
399
+ app.required_perms_for( req ).should == [ :auth_test ] # default == appid
400
+ end
257
401
 
258
- it "passes a request through auth if the path doesn't match" do
259
- req = @request_factory.get( '/api/v1/console' )
402
+ it "allows negative perms criteria to be declared with a regexp" do
403
+ @app.no_perms_for( %r{^/signup} )
404
+ app = @app.new
260
405
 
261
- app = @app.new
262
- app.auth_provider.should_receive( :authenticate ).and_return( 'anonymous' )
263
- app.auth_provider.should_receive( :authorize ).and_return( true )
406
+ req = @request_factory.get( '/api/v1/signup' )
407
+ app.required_perms_for( req ).should be_empty()
408
+ req = @request_factory.get( '/api/v1/signup/reapply' )
409
+ app.required_perms_for( req ).should be_empty()
410
+ req = @request_factory.get( '/api/v1/index' )
411
+ app.required_perms_for( req ).should == [ :auth_test ]
412
+ end
264
413
 
265
- app.handle( req )
414
+ it "allows negative perms criteria to be declared with a string and a block" do
415
+ @app.no_perms_for( '/' ) do |req|
416
+ req.verb == :GET
266
417
  end
418
+ app = @app.new
267
419
 
268
- it "passes a request through auth if the path matches, but the the block returns false" do
269
- req = @request_factory.get( '/api/v1/login/validuser' )
420
+ req = @request_factory.get( '/api/v1' )
421
+ app.required_perms_for( req ).should be_empty()
422
+ req = @request_factory.post( '/api/v1' )
423
+ app.required_perms_for( req ).should == [ :auth_test ] # default == appid
424
+ req = @request_factory.get( '/api/v1/users' )
425
+ app.required_perms_for( req ).should == [ :auth_test ]
426
+ end
270
427
 
271
- app = @app.new
272
- app.auth_provider.should_receive( :authenticate ).and_return( 'anonymous' )
273
- app.auth_provider.should_receive( :authorize ).and_return( true )
428
+ it "allows negative perms criteria to be declared with a regexp and a block" do
429
+ @app.no_perms_for( %r{^/collection/(?<collname>[^/]+)} ) do |req, match|
430
+ public_collections = %w[degasse ione champhion]
431
+ collname = match[:collname]
432
+ if public_collections.include?( collname )
433
+ true
434
+ else
435
+ false
436
+ end
437
+ end
438
+ app = @app.new
274
439
 
275
- app.handle( req )
440
+ req = @request_factory.get( '/api/v1/collection' )
441
+ app.required_perms_for( req ).should == [ :auth_test ]
442
+ req = @request_factory.get( '/api/v1/collection/degasse' )
443
+ app.required_perms_for( req ).should be_empty()
444
+ req = @request_factory.get( '/api/v1/collection/ione' )
445
+ app.required_perms_for( req ).should be_empty()
446
+ req = @request_factory.get( '/api/v1/collection/champhion' )
447
+ app.required_perms_for( req ).should be_empty()
448
+ req = @request_factory.get( '/api/v1/collection/calindra' )
449
+ app.required_perms_for( req ).should == [ :auth_test ]
450
+ end
451
+
452
+ it "allows negative perms criteria to be declared with just a block" do
453
+ @app.no_perms_for do |req|
454
+ intranet = IPAddr.new( '10.0.0.0/8' )
455
+ intranet.include?( req.remote_ip )
276
456
  end
457
+ app = @app.new
277
458
 
459
+ req = @request_factory.get( '/api/v1/collection', x_forwarded_for: '10.0.1.68' )
460
+ app.required_perms_for( req ).should be_empty()
461
+ req = @request_factory.get( '/api/v1/collection', x_forwarded_for: '192.0.43.10' )
462
+ app.required_perms_for( req ).should == [ :auth_test ]
278
463
  end
279
464
 
280
465
 
281
466
  context "that has positive auth criteria" do
282
467
 
283
468
  before( :each ) do
284
- @app.require_auth_for( '/login' )
469
+ @app.require_auth_for( '/onlyauth' )
470
+ @app.require_auth_for( '/both' )
285
471
  end
286
472
 
287
- it "knows that it has auth criteria" do
288
- @app.should have_auth_criteria()
289
- end
473
+ context "and positive perms criteria" do
290
474
 
291
- it "passes requests that match through auth" do
292
- req = @request_factory.get( '/api/v1/login' )
475
+ before( :each ) do
476
+ @app.require_perms_for( '/both' )
477
+ @app.require_perms_for( '/onlyperms' )
478
+ end
293
479
 
294
- app = @app.new
295
- app.auth_provider.should_receive( :authenticate ).and_return( 'anonymous' )
296
- app.auth_provider.should_receive( :authorize ).and_return( true )
480
+ it "authorizes a request that only matches the perms criteria" do
481
+ req = @request_factory.get( '/api/v1/onlyperms' )
297
482
 
298
- app.handle( req )
299
- end
483
+ app = @app.new
484
+ app.auth_provider.should_not_receive( :authenticate )
485
+ app.auth_provider.should_receive( :authorize )
300
486
 
301
- it "doesn't pass requests that don't match through auth" do
302
- req = @request_factory.get( '/api/v1/console' )
487
+ app.handle( req )
488
+ end
303
489
 
304
- app = @app.new
305
- app.auth_provider.should_not_receive( :authenticate )
306
- app.auth_provider.should_not_receive( :authorize )
490
+ it "authenticates a request that only matches the auth criteria" do
491
+ req = @request_factory.get( '/api/v1/onlyauth' )
307
492
 
308
- app.handle( req )
309
- end
310
- end
493
+ app = @app.new
494
+ app.auth_provider.should_receive( :authenticate )
495
+ app.auth_provider.should_not_receive( :authorize )
311
496
 
497
+ app.handle( req )
498
+ end
312
499
 
313
- context "that has a positive auth criteria block" do
500
+ it "authenticates and authorizes a request that matches both" do
501
+ req = @request_factory.get( '/api/v1/both' )
314
502
 
315
- before( :each ) do
316
- @app.require_auth_for do |req|
317
- req.notes[:require_auth]
503
+ app = @app.new
504
+ app.auth_provider.should_receive( :authenticate )
505
+ app.auth_provider.should_receive( :authorize )
506
+
507
+ app.handle( req )
318
508
  end
319
- end
320
509
 
321
- it "knows that it has auth criteria" do
322
- @app.should have_auth_criteria()
323
- end
510
+ it "doesn't do either for a request that doesn't match either" do
511
+ req = @request_factory.get( '/api/v1/neither' )
324
512
 
325
- it "passes requests for which the block returns true through auth" do
326
- req = @request_factory.get( '/api/v1/login' )
327
- req.notes[:require_auth] = true
513
+ app = @app.new
514
+ app.auth_provider.should_not_receive( :authenticate )
515
+ app.auth_provider.should_not_receive( :authorize )
328
516
 
329
- app = @app.new
330
- app.auth_provider.should_receive( :authenticate ).and_return( 'anonymous' )
331
- app.auth_provider.should_receive( :authorize ).and_return( true )
517
+ app.handle( req )
518
+ end
332
519
 
333
- app.handle( req )
334
520
  end
335
521
 
336
- it "doesn't pass requests for which the block returns false through auth" do
337
- req = @request_factory.get( '/api/v1/console' )
338
- req.notes[:require_auth] = false
522
+ context "and negative perms criteria" do
339
523
 
340
- app = @app.new
341
- app.auth_provider.should_not_receive( :authenticate )
342
- app.auth_provider.should_not_receive( :authorize )
524
+ before( :each ) do
525
+ @app.no_perms_for( '/both' )
526
+ @app.no_perms_for( '/onlyperms' )
527
+ end
528
+
529
+ it "doesn't do either for a request that only matches the perms criteria" do
530
+ req = @request_factory.get( '/api/v1/onlyperms' )
531
+
532
+ app = @app.new
533
+ app.auth_provider.should_not_receive( :authenticate )
534
+ app.auth_provider.should_not_receive( :authorize )
535
+
536
+ app.handle( req )
537
+ end
538
+
539
+ it "authenticates and authorizes a request that only matches the auth criteria"do
540
+ req = @request_factory.get( '/api/v1/onlyauth' )
541
+
542
+ app = @app.new
543
+ app.auth_provider.should_receive( :authenticate )
544
+ app.auth_provider.should_receive( :authorize )
545
+
546
+ app.handle( req )
547
+ end
548
+
549
+ it "only authenticates a request that matches both" do
550
+ req = @request_factory.get( '/api/v1/both' )
551
+
552
+ app = @app.new
553
+ app.auth_provider.should_receive( :authenticate )
554
+ app.auth_provider.should_not_receive( :authorize )
555
+
556
+ app.handle( req )
557
+ end
558
+
559
+ it "only authorizes a request that doesn't match either" do
560
+ req = @request_factory.get( '/api/v1/neither' )
561
+
562
+ app = @app.new
563
+ app.auth_provider.should_not_receive( :authenticate )
564
+ app.auth_provider.should_receive( :authorize )
565
+
566
+ app.handle( req )
567
+ end
343
568
 
344
- app.handle( req )
345
569
  end
570
+
346
571
  end
347
572
 
348
573
 
349
- context "that has a positive auth criteria with both a pattern and a block" do
574
+ context "that has negative auth criteria" do
350
575
 
351
576
  before( :each ) do
352
- @app.require_auth_for( %r{^/login/(?<username>\w+)} ) do |req, match|
353
- match[:username] != 'guest'
354
- end
577
+ @app.no_auth_for( '/onlyauth' )
578
+ @app.no_auth_for( '/both' )
355
579
  end
356
580
 
357
- it "knows that it has auth criteria" do
358
- @app.should have_auth_criteria()
359
- end
581
+ context "and positive perms criteria" do
360
582
 
361
- it "passes a request through auth if the path matches and the block returns true" do
362
- req = @request_factory.get( '/api/v1/login/lyssa' )
583
+ before( :each ) do
584
+ @app.require_perms_for( '/both' )
585
+ @app.require_perms_for( '/onlyperms' )
586
+ end
363
587
 
364
- app = @app.new
365
- app.auth_provider.should_receive( :authenticate ).and_return( 'lyssa' )
366
- app.auth_provider.should_receive( :authorize ).and_return( true )
588
+ it "authenticates and authorizes a request that only matches the perms criteria" do
589
+ req = @request_factory.get( '/api/v1/onlyperms' )
367
590
 
368
- app.handle( req )
369
- end
591
+ app = @app.new
592
+ app.auth_provider.should_receive( :authenticate )
593
+ app.auth_provider.should_receive( :authorize )
370
594
 
371
- it "doesn't pass a request through auth if the path doesn't match" do
372
- req = @request_factory.get( '/api/v1/console' )
595
+ app.handle( req )
596
+ end
373
597
 
374
- app = @app.new
375
- app.auth_provider.should_not_receive( :authenticate )
376
- app.auth_provider.should_not_receive( :authorize )
598
+ it "doesn't do either for a request that only matches the auth criteria" do
599
+ req = @request_factory.get( '/api/v1/onlyauth' )
377
600
 
378
- app.handle( req )
379
- end
601
+ app = @app.new
602
+ app.auth_provider.should_not_receive( :authenticate )
603
+ app.auth_provider.should_not_receive( :authorize )
380
604
 
381
- it "doesn't pass a request through auth if the path matches, but the the block returns false" do
382
- req = @request_factory.get( '/api/v1/login/guest' )
605
+ app.handle( req )
606
+ end
383
607
 
384
- app = @app.new
385
- app.auth_provider.should_not_receive( :authenticate )
386
- app.auth_provider.should_not_receive( :authorize )
608
+ it "authorizes a request that matches both" do
609
+ req = @request_factory.get( '/api/v1/both' )
610
+
611
+ app = @app.new
612
+ app.auth_provider.should_not_receive( :authenticate )
613
+ app.auth_provider.should_receive( :authorize )
614
+
615
+ app.handle( req )
616
+ end
617
+
618
+ it "authenticates a request that doesn't match either" do
619
+ req = @request_factory.get( '/api/v1/neither' )
620
+
621
+ app = @app.new
622
+ app.auth_provider.should_receive( :authenticate )
623
+ app.auth_provider.should_not_receive( :authorize )
624
+
625
+ app.handle( req )
626
+ end
387
627
 
388
- app.handle( req )
389
628
  end
390
629
 
391
- end
630
+ context "and negative perms criteria" do
392
631
 
632
+ before( :each ) do
633
+ @app.no_perms_for( '/both' )
634
+ @app.no_perms_for( '/onlyperms' )
635
+ end
393
636
 
394
- it "can register an authorization callback with a block" do
395
- @app.authz_callback { :authz }
396
- @app.authz_callback.should be_a( Proc )
397
- end
637
+ it "authenticates for a request that only matches the perms criteria" do
638
+ req = @request_factory.get( '/api/v1/onlyperms' )
639
+
640
+ app = @app.new
641
+ app.auth_provider.should_receive( :authenticate )
642
+ app.auth_provider.should_not_receive( :authorize )
643
+
644
+ app.handle( req )
645
+ end
646
+
647
+ it "authorizes a request that only matches the auth criteria" do
648
+ req = @request_factory.get( '/api/v1/onlyauth' )
649
+
650
+ app = @app.new
651
+ app.auth_provider.should_not_receive( :authenticate )
652
+ app.auth_provider.should_receive( :authorize )
653
+
654
+ app.handle( req )
655
+ end
656
+
657
+ it "doesn't do either for a request that matches both" do
658
+ req = @request_factory.get( '/api/v1/both' )
659
+
660
+ app = @app.new
661
+ app.auth_provider.should_not_receive( :authenticate )
662
+ app.auth_provider.should_not_receive( :authorize )
663
+
664
+ app.handle( req )
665
+ end
666
+
667
+ it "authenticates and authorizes a request that doesn't match either" do
668
+ req = @request_factory.get( '/api/v1/neither' )
669
+
670
+ app = @app.new
671
+ app.auth_provider.should_receive( :authenticate )
672
+ app.auth_provider.should_receive( :authorize )
673
+
674
+ app.handle( req )
675
+ end
676
+
677
+ end
398
678
 
399
- it "can register an authorization callback with a callable object" do
400
- callback = Proc.new { :authz }
401
- @app.authz_callback( callback )
402
- @app.authz_callback.should == callback
403
679
  end
404
680
 
405
681
 
406
- context "that has an authz callback" do
682
+ context "that has overlapping perms criteria" do
407
683
 
408
684
  before( :each ) do
409
- @app.authz_callback { }
685
+ @app.require_perms_for( %r{^/admin.*}, :admin )
686
+ @app.require_perms_for( %r{^/admin/upload.*}, :upload )
410
687
  end
411
688
 
412
- it "yields authorization to the callback if authentication succeeds"
413
- it "responds with a 403 Forbidden response if the block doesn't return true"
689
+ it "authorizes with a union of the permissions of both of the criteria" do
690
+ req = @request_factory.get( '/api/v1/admin/upload' )
691
+
692
+ app = @app.new
693
+ app.auth_provider.stub!( :authenticate ).and_return( :credentials )
694
+ app.auth_provider.should_receive( :authorize ).with( :credentials, req, [:admin, :upload] )
695
+
696
+ app.handle( req )
697
+ end
414
698
 
415
699
  end
416
700