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

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.
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
@@ -11,7 +11,6 @@ require 'strelka/plugins'
11
11
  require 'strelka/httprequest/auth'
12
12
  require 'strelka/authprovider'
13
13
 
14
-
15
14
  # Pluggable authentication and authorization for Strelka applications.
16
15
  #
17
16
  # Enabling the +:auth+ plugin by default causes all requests to your
@@ -31,6 +30,13 @@ require 'strelka/authprovider'
31
30
  # can implement one or both of the stages; see the API docs for Strelka::AuthProvider
32
31
  # for details on how to write your own plugin.
33
32
  #
33
+ # The provider for an application can be specified in the Configurability config file
34
+ # under the 'auth' section:
35
+ #
36
+ # ---
37
+ # auth:
38
+ # provider: basic
39
+ #
34
40
  #
35
41
  # == Applying Authentication
36
42
  #
@@ -123,20 +129,41 @@ require 'strelka/authprovider'
123
129
  # itself (especially a custom one), but typically authorization is particular to an application and
124
130
  # even particular actions within the application.
125
131
  #
126
- # To provide the particulars for your app's authorization, you can declare
127
- # a block with the +authz_callback+ directive.
132
+ # To facilitate mapping out what actions are available to whom, there is a
133
+ # declaration similar to require_auth_for that can define a set of permissions
134
+ # that are necessary for a request to be allowed:
128
135
  #
129
- # authz_callback do |request, user, *other_auth_info|
130
- # user.can?( request.app_path )
131
- # end
136
+ # # The app ID, which is the default permission
137
+ # ID = 'gemserver'
138
+ #
139
+ # # GET /app/admin/upload/install would require:
140
+ # # :gemserver, :admin, :upload, and :install
141
+ # # permissions. What those mean is up to the AuthProvider.
142
+ # require_perms_for ''
143
+ # require_perms_for %r{^/admin.*}, :admin
144
+ # require_perms_for %r{/upload}, :upload
145
+ # require_perms_for %r{/install}, :install
146
+ #
147
+ # and its negative corollary:
148
+ #
149
+ # no_perms_for '/login'
150
+ #
151
+ # Incoming requests are matched against +require_perms_for+ patterns, and the union
152
+ # of all matching permissions is gathered, then any +no_auth_for+ patterns
153
+ # are used to remove permissions from that set.
154
+ #
155
+ # If no require_perms_for patterns are declared, authorization is not checked, unless there is
156
+ # at least one no_perms_for pattern, in which case all requests that don't match the negative
157
+ # patterns are checked (with the permission set to the ID of the app).
158
+ #
159
+ # Authorization will be checked once authentication has succeeded. It will be called with at least the
160
+ # credentials object returned from the authentication stage and the request object. Some AuthProviders
161
+ # may opt to return authentication credentials as a User object of some kind (e.g., a database row,
162
+ # LDAP entry, model object, etc.), but the simpler ones just return the login of the authenticated
163
+ # +user+. The AuthProvider may also furnish additional useful arguments such as a database handle,
164
+ # permission objects, etc. to your authorization block. See the documentation for your chosen
165
+ # AuthProvider for details.
132
166
  #
133
- # The block will be called once authentication has succeeded, and any general authorization has been
134
- # checked. It will be called with at least the credentials object returned from the authentication
135
- # stage and the request object. Some AuthProviders may opt to return authentication credentials
136
- # as a User object of some kind (e.g., a database row, LDAP entry, model object, etc.), but the
137
- # simpler ones just return the login of the authenticated +user+. The AuthProvider may also
138
- # furnish additional useful arguments such as a database handle, permission objects, etc. to your
139
- # authorization block. See the documentation for your chosen AuthProvider for details.
140
167
  #
141
168
  # == Customizing Failure
142
169
  #
@@ -151,11 +178,10 @@ require 'strelka/authprovider'
151
178
  #
152
179
  # If you're using form-based session authentication (as opposed to basic
153
180
  # auth, which has its own UI), you can rewrite the response to instruct
154
- # the browser to go to a static HTML form instead:
181
+ # the browser to go to a static HTML form instead using the <tt>:errors</tt> plugin:
155
182
  #
156
183
  # class FormAuthApp < Strelka::App
157
184
  # plugins :errors, :auth, :sessions
158
- # auth_provider :session
159
185
  #
160
186
  # on_status HTTP::AUTH_REQUIRED do |res, status|
161
187
  # formuri = res.request.uri
@@ -178,7 +204,6 @@ require 'strelka/authprovider'
178
204
  #
179
205
  # class TemplateFormAuthApp < Strelka::App
180
206
  # plugins :auth, :errors, :templating
181
- # auth_provider :session
182
207
  #
183
208
  # layout 'examples/layout.tmpl'
184
209
  # templates \
@@ -194,58 +219,18 @@ require 'strelka/authprovider'
194
219
  #
195
220
  # end
196
221
  #
197
- # == Examples
198
- #
199
- # Here are a few more examples using a few different AuthProviders.
200
- #
201
- # # Guard every request the app does behind a simple passphrase
202
- # class MyGuardedApp < Strelka::App
203
- # plugins :auth
204
- #
205
- # auth_provider :passphrase
206
- # end
207
- #
208
- # # Require LDAP authentication for one route
209
- # class MyGuardedApp < Strelka::App
210
- # plugins :auth, :routing
211
- #
212
- # auth_provider :ldap
213
- # authz_callback do |user, request, directory|
214
- # authgroup = directory.ou( :appperms ).cn( :guarded_app )
215
- # authgroup.members.include?( user.dn )
216
- # end
217
- #
218
- # authenticated %r{^/admin}
219
- # end
220
- #
221
- # # Use a user table in a PostgreSQL database for authentication for
222
- # # all routes except one
223
- # class MyGuardedApp < Strelka::App
224
- # plugins :auth
225
- #
226
- # auth_provider :sequel
227
- # authz_callback do |user, request, db|
228
- # db[:permissions].filter( :user_id => user[:id] ).
229
- # filter( :permname => 'guardedapp' )
230
- # end
231
- #
232
- # unauthenticated %r{^/auth}
233
- #
234
- # # Only authenticated users can use this
235
- # post '/servers' do
236
- # # ...
237
- # end
238
- # end
239
- #
240
222
  module Strelka::App::Auth
241
223
  extend Strelka::Plugin,
242
224
  Strelka::MethodUtilities,
243
- Loggability
225
+ Loggability,
226
+ Configurability
244
227
  include Strelka::Constants
245
228
 
246
229
  # Loggability API -- set up logging under the 'strelka' log host
247
230
  log_to :strelka
248
231
 
232
+ # Configurability API -- configure the auth plugin via the 'auth' section of the config
233
+ config_key :auth
249
234
 
250
235
  # Plugins API -- Set up load order
251
236
  run_before :routing, :restresources
@@ -255,60 +240,89 @@ module Strelka::App::Auth
255
240
  # The name of the default plugin to use for authentication
256
241
  DEFAULT_AUTH_PROVIDER = :hostaccess
257
242
 
243
+ # Configuration defaults
244
+ CONFIG_DEFAULTS = {
245
+ provider: DEFAULT_AUTH_PROVIDER,
246
+ }
247
+
248
+
249
+
250
+ ##
251
+ # The Array of apps that have had the auth plugin installed; this is used to
252
+ # set up the AuthProvider when the configuration loads later.
253
+ singleton_attr_accessor :extended_apps
254
+ self.extended_apps = []
255
+
256
+
257
+ ### Configurability API -- configure the Auth plugin via the 'auth' section of the
258
+ ### unified config.
259
+ def self::configure( config=nil )
260
+ if config && config.provider?
261
+ self.log.debug "Setting up the %p AuthProvider for apps: %p" %
262
+ [ config.provider, self.extended_apps ]
263
+ self.extended_apps.each {|app| app.auth_provider = config.provider }
264
+ else
265
+ self.log.notice "Setting up the default AuthProvider for apps %p" % [ self.extended_apps ]
266
+ self.extended_apps.each {|app| app.auth_provider = DEFAULT_AUTH_PROVIDER }
267
+ end
268
+ end
269
+
258
270
 
259
271
  # Class methods to add to app classes that enable Auth
260
272
  module ClassMethods
261
273
 
262
- @auth_provider = nil
263
- @authz_callback = nil
264
- @positive_auth_criteria = {}
265
- @negative_auth_criteria = {}
274
+ ### Extension callback -- register objects that are extended so when the
275
+ ### auth plugin is configured, it can set the configured auto provider.
276
+ def self::extended( obj )
277
+ super
278
+ Strelka::App::Auth.extended_apps << obj
279
+ obj.auth_provider = Strelka::App::Auth::DEFAULT_AUTH_PROVIDER
280
+ end
281
+
282
+
283
+ @auth_provider = nil
284
+
285
+ @positive_auth_criteria = {}
286
+ @negative_auth_criteria = {}
287
+
288
+ @positive_perms_criteria = {}
289
+ @negative_perms_criteria = {}
290
+
291
+
292
+ ##
293
+ # The Strelka::AuthProvider subclass that will be used to provide authentication and
294
+ # authorization to instances of the app.
295
+ attr_reader :auth_provider
266
296
 
267
297
  ##
268
- # Arrays of criteria for applying and skipping auth for a request.
298
+ # Hashes of criteria for applying and skipping auth for a request, keyed by request pattern
269
299
  attr_reader :positive_auth_criteria, :negative_auth_criteria
270
300
 
301
+ ##
302
+ # Hashes of criteria for applying and skipping authorization for a request, keyed by request pattern
303
+ attr_reader :positive_perms_criteria, :negative_perms_criteria
304
+
271
305
 
272
306
  ### Extension callback -- add instance variables to extending objects.
273
307
  def inherited( subclass )
274
308
  super
275
309
  subclass.instance_variable_set( :@auth_provider, @auth_provider )
276
- subclass.instance_variable_set( :@authz_callback, @authz_callback.dup ) if @authz_callback
277
310
  subclass.instance_variable_set( :@positive_auth_criteria, @positive_auth_criteria.dup )
278
311
  subclass.instance_variable_set( :@negative_auth_criteria, @negative_auth_criteria.dup )
312
+ subclass.instance_variable_set( :@positive_perms_criteria, @positive_perms_criteria.dup )
313
+ subclass.instance_variable_set( :@negative_perms_criteria, @negative_perms_criteria.dup )
279
314
  end
280
315
 
281
316
 
282
- ### Get/set the authentication type.
283
- def auth_provider( type=nil )
284
- if type
285
- @auth_provider = Strelka::AuthProvider.get_subclass( type )
286
- end
287
-
288
- self.log.debug "Auth provider %p" % [ @auth_provider ]
289
- @auth_provider ||= Strelka::AuthProvider.get_subclass( DEFAULT_AUTH_PROVIDER )
290
- self.log.debug "Auth provider %p" % [ @auth_provider ]
317
+ ### Get/set the AuthProvider for the app to +type+, where +type+ can be an AuthProvider
318
+ ### class object or the name of one.
319
+ def auth_provider=( type )
320
+ @auth_provider = Strelka::AuthProvider.get_subclass( type )
321
+ self.log.debug "Auth provider set to %p" % [ @auth_provider ]
291
322
  return @auth_provider
292
323
  end
293
324
 
294
325
 
295
- ### Register a function to call after the user successfully authenticates to check
296
- ### for authorization or other criteria. The arguments to the function depend on
297
- ### which authentication plugin is used. Returning +true+ from this function will
298
- ### cause authorization to succeed, while returning a false value causes it to fail
299
- ### with a FORBIDDEN response. If no callback is set, and the provider doesn't
300
- ### provide authorization
301
- def authz_callback( callable=nil, &block )
302
- if callable
303
- @authz_callback = callable
304
- elsif block
305
- @authz_callback = block
306
- end
307
-
308
- return @authz_callback
309
- end
310
-
311
-
312
326
  ### Returns +true+ if there are any criteria for determining whether or
313
327
  ### not a request needs auth.
314
328
  def has_auth_criteria?
@@ -329,13 +343,19 @@ module Strelka::App::Auth
329
343
  return !self.negative_auth_criteria.empty?
330
344
  end
331
345
 
332
-
333
- ### Constrain auth to apply only to requests which match the given +criteria+,
334
- ### and/or the given +block+. The +criteria+ are either Strings or Regexps
335
- ### which are tested against
336
- ### {the request's #app_path}[rdoc-ref:Strelka::HTTPRequest#app_path]. The block
337
- ### should return a true-ish value if the request should undergo authentication
338
- ### and authorization.
346
+ ### :call-seq:
347
+ ### require_auth_for( string )
348
+ ### require_auth_for( regexp )
349
+ ### require_auth_for { |request| ... }
350
+ ### require_auth_for( string ) { |request| ... }
351
+ ### require_auth_for( regexp ) { |request, matchdata| ... }
352
+ ###
353
+ ### Constrain authentication to apply only to requests whose
354
+ ### {#app_path}[rdoc-ref:Strelka::HTTPRequest#app_path] matches
355
+ ### the given +string+ or +regexp+, and/or for which the given +block+ returns
356
+ ### a true value. +regexp+ patterns are matched as-is, and +string+ patterns are
357
+ ### matched exactly via <tt>==</tt> after stripping leading and trailing '/' characters
358
+ ### from both it and the #app_path.
339
359
  ### *NOTE:* using this declaration inverts the default security policy of
340
360
  ### restricting access to all requests.
341
361
  def require_auth_for( *criteria, &block )
@@ -355,8 +375,17 @@ module Strelka::App::Auth
355
375
  end
356
376
 
357
377
 
358
- ### Contrain auth to apply to all requests *except* those that match the
359
- ### given +criteria+.
378
+ ### :call-seq:
379
+ ### no_auth_for( string )
380
+ ### no_auth_for( regexp )
381
+ ### no_auth_for { |request| ... }
382
+ ### no_auth_for( string ) { |request| ... }
383
+ ### no_auth_for( regexp ) { |request, matchdata| ... }
384
+ ###
385
+ ### Constrain authentication to apply to requests *except* those whose
386
+ ### {#app_path}[rdoc-ref:Strelka::HTTPRequest#app_path] matches
387
+ ### the given +string+ or +regexp+, and/or for which the given +block+ returns
388
+ ### a true value.
360
389
  def no_auth_for( *criteria, &block )
361
390
  if self.has_positive_auth_criteria?
362
391
  raise ScriptError,
@@ -374,6 +403,39 @@ module Strelka::App::Auth
374
403
  end
375
404
 
376
405
 
406
+ ### Constrain authorization to apply only to requests which match the given
407
+ ### +pattern+. The +pattern+ is either a String or a Regexp which is tested against
408
+ ### {the request's #app_path}[rdoc-ref:Strelka::HTTPRequest#app_path]. The +perms+ should
409
+ ### be Symbols which indicate a set of permission types that must have been granted
410
+ ### in order to carry out the request. The block should also return one or more
411
+ ### permissions (as Symbols) if the request should undergo authorization, or nil
412
+ ### if it should not.
413
+ ### *NOTE:* using this declaration inverts the default security policy of
414
+ ### restricting access to all requests.
415
+ def require_perms_for( pattern=nil, *perms, &block )
416
+ block ||= Proc.new { perms }
417
+
418
+ pattern.gsub!( %r{^/+|/+$}, '' ) if pattern.respond_to?( :gsub! )
419
+ self.log.debug " adding require_perms (%p) for %p" % [ perms, pattern ]
420
+ self.positive_perms_criteria[ pattern ] = block
421
+ end
422
+
423
+
424
+ ### Register one or more exceptions to the permissions policy in effect for
425
+ ### requests whose {#app_path}[rdoc-ref:Strelka::HTTPRequest#app_path]
426
+ ### matches the specified +pattern+. The +block+ form should return +true+ if the request
427
+ ### it's called with should be allowed without authorization checks.
428
+ def no_perms_for( pattern=nil, &block )
429
+ raise LocalJumpError, "no block or pattern given" unless pattern || block
430
+
431
+ block ||= Proc.new { true }
432
+ pattern ||= /(?##{block.object_id})/
433
+
434
+ pattern.gsub!( %r{^/+|/+$}, '' ) if pattern.respond_to?( :gsub! )
435
+ self.log.debug " adding no_auth for %p" % [ pattern ]
436
+ self.negative_perms_criteria[ pattern ] = block
437
+ end
438
+
377
439
  end # module ClassMethods
378
440
 
379
441
 
@@ -407,15 +469,42 @@ module Strelka::App::Auth
407
469
  def handle_request( request, &block )
408
470
  self.log.debug "[:auth] Wrapping request in auth with a %p" % [ self.auth_provider ]
409
471
 
410
- self.authenticate_and_authorize( request ) if self.request_should_auth?( request )
472
+ self.authenticate_and_authorize( request )
411
473
 
412
474
  super
413
475
  end
414
476
 
415
477
 
416
- #########
417
- protected
418
- #########
478
+ ### Process authentication and authorization for the specified +request+.
479
+ def authenticate_and_authorize( request )
480
+ credentials = nil
481
+ credentials = self.provide_authentication( request ) if self.request_should_auth?( request )
482
+ request.authenticated_user = credentials
483
+
484
+ self.provide_authorization( credentials, request )
485
+ end
486
+
487
+
488
+ ### If the AuthProvider does authentication, try to extract authenticated credentials
489
+ ### from the +request+ and return them, throwing a :finish with
490
+ ### a properly-constructed 401 (Auth required) response if that fails.
491
+ def provide_authentication( request )
492
+ provider = self.auth_provider
493
+ self.log.info "Authenticating request using provider: %p" % [ provider ]
494
+ return provider.authenticate( request )
495
+ end
496
+
497
+
498
+ ### Process authorization for the given +credentials+ and +request+.
499
+ ### The +credentials+ argument is the opaque return value from a valid authentication, or
500
+ ### +nil+ if the request didn't require authentication.
501
+ def provide_authorization( credentials, request )
502
+ provider = self.auth_provider
503
+ perms = self.required_perms_for( request )
504
+ self.log.debug "Perms required: %p" % [ perms ]
505
+ provider.authorize( credentials, request, perms ) unless perms.empty?
506
+ end
507
+
419
508
 
420
509
  ### Returns +true+ if the given +request+ requires authentication.
421
510
  def request_should_auth?( request )
@@ -428,19 +517,21 @@ module Strelka::App::Auth
428
517
  criteria = self.class.positive_auth_criteria
429
518
  self.log.debug " checking %d positive auth criteria" % [ criteria.length ]
430
519
  return criteria.any? do |pattern, block|
431
- self.log.debug " %p -> %p" % [ pattern, block ]
432
520
  self.request_matches_criteria( request, pattern, &block )
433
521
  end
522
+ return false
434
523
 
435
524
  # If there are negative criteria, return false if the request matches any of them,
436
525
  # or true if they don't
437
526
  elsif self.class.has_negative_auth_criteria?
438
527
  criteria = self.class.negative_auth_criteria
439
528
  self.log.debug " checking %d negative auth criteria" % [ criteria.length ]
440
- return !criteria.any? do |pattern, block|
441
- self.log.debug " %p -> %p" % [ pattern, block ]
442
- self.request_matches_criteria( request, pattern, &block )
529
+ return false if criteria.any? do |pattern, block|
530
+ rval = self.request_matches_criteria( request, pattern, &block )
531
+ self.log.debug " matched: %p -> %p" % [ pattern, block ] if rval
532
+ rval
443
533
  end
534
+ return true
444
535
 
445
536
  else
446
537
  self.log.debug " no auth criteria; default to requiring auth"
@@ -449,24 +540,56 @@ module Strelka::App::Auth
449
540
  end
450
541
 
451
542
 
543
+ ### Return a permission Symbol derived from the app's ID.
544
+ def default_permission
545
+ return self.app_id.downcase.gsub(/\W+/, '_' ).to_sym
546
+ end
547
+
548
+
549
+ ### Gather the set of permissions that apply to the specified +request+ and return
550
+ ### them.
551
+ def required_perms_for( request )
552
+ self.log.debug "Gathering required perms for: %s %s" % [ request.verb, request.app_path ]
553
+
554
+ # Return the empty set if any negative auth criteria match
555
+ return [] if self.negative_perms_criteria_match?( request )
556
+
557
+ # If there aren't any positive criteria, default to requiring authorization with
558
+ # the app's ID as the permission
559
+ if self.class.positive_perms_criteria.empty?
560
+ return [ self.default_permission ]
561
+ end
562
+
563
+ # Apply positive auth criteria
564
+ return self.union_positive_perms_criteria( request )
565
+ end
566
+
567
+
568
+ #########
569
+ protected
570
+ #########
571
+
452
572
  ### Returns +true+ if there are positive auth criteria and the +request+ matches
453
573
  ### at least one of them.
454
574
  def request_matches_criteria( request, pattern )
575
+ self.log.debug "Testing request '%s %s' against pattern: %p" %
576
+ [ request.verb, request.app_path, pattern ]
577
+
455
578
  case pattern
456
579
  when nil
457
580
  self.log.debug " no pattern; calling the block"
458
581
  return yield( request )
459
582
 
460
583
  when Regexp
461
- self.log.debug " matching app_path with regexp: %p" % [ pattern ]
584
+ self.log.debug " checking app_path with regexp: %p" % [ pattern ]
462
585
  matchdata = pattern.match( request.app_path ) or return false
463
- self.log.debug " calling the block"
586
+ self.log.debug " matched: calling the block"
464
587
  return yield( request, matchdata )
465
588
 
466
589
  when String
467
- self.log.debug " matching app_path: %p" % [ pattern ]
590
+ self.log.debug " checking app_path: %p" % [ pattern ]
468
591
  request.app_path.gsub( %r{^/+|/+$}, '' ) == pattern or return false
469
- self.log.debug " calling the block"
592
+ self.log.debug " matched: calling the block"
470
593
  return yield( request )
471
594
 
472
595
  else
@@ -475,31 +598,36 @@ module Strelka::App::Auth
475
598
  end
476
599
 
477
600
 
478
- ### Process authentication and authorization for the specified +request+.
479
- def authenticate_and_authorize( request )
480
- credentials = self.provide_authentication( request )
481
- request.authenticated_user = credentials
482
- self.provide_authorization( credentials, request )
601
+ ### Returns +true+ if the +request+ matches at least one negative perms criteria
602
+ ### whose block also returns +true+ when called.
603
+ def negative_perms_criteria_match?( request )
604
+ self.log.debug " negative perm criteria: %p" % [ self.class.negative_perms_criteria ]
605
+ return self.class.negative_perms_criteria.any? do |pattern, block|
606
+ self.request_matches_criteria( request, pattern, &block )
607
+ end
483
608
  end
484
609
 
485
610
 
486
- ### If the AuthProvider does authentication, try to extract authenticated credentials
487
- ### from the +request+ and return them, throwing a :finish with
488
- ### a properly-constructed 401 (Auth required) response if that fails.
489
- def provide_authentication( request )
490
- provider = self.auth_provider
491
- self.log.info "Authenticating request using provider: %p" % [ provider ]
492
- return provider.authenticate( request )
493
- end
611
+ ### Find all positive perm criteria, calling each one's block with +request+ if its
612
+ ### pattern matches +path+, and assembling a union of all the permission sets
613
+ ### that result.
614
+ def union_positive_perms_criteria( request )
615
+ perms = []
494
616
 
617
+ self.log.debug " positive perm criteria: %p" % [ self.class.positive_perms_criteria ]
618
+ self.class.positive_perms_criteria.each do |pattern, block|
619
+ newperms = self.request_matches_criteria( request, pattern, &block ) or next
620
+ newperms = Array( newperms )
621
+ newperms << self.default_permission if newperms.empty?
495
622
 
496
- ### Process authorization for the given +credentials+ and +request+.
497
- def provide_authorization( credentials, request )
498
- provider = self.auth_provider
499
- callback = self.class.authz_callback
623
+ raise TypeError, "Permissions must be Symbols; got: %p" % [newperms] unless
624
+ newperms.all? {|perm| perm.is_a?(Symbol) }
625
+
626
+ self.log.debug " found new perms: %p" % [ newperms ]
627
+ perms += newperms
628
+ end
500
629
 
501
- self.log.info "Authorizing using credentials: %p, callback: %p" % [ credentials, callback ]
502
- provider.authorize( credentials, request, &callback )
630
+ return perms.compact.uniq
503
631
  end
504
632
 
505
633