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.
- data.tar.gz.sig +0 -0
- data/ChangeLog +57 -3
- data/Manifest.txt +3 -4
- data/Rakefile +1 -1
- data/bin/strelka +4 -7
- data/examples/.env +4 -0
- data/examples/Procfile +8 -0
- data/examples/apps/auth-demo +3 -5
- data/examples/apps/auth-demo2 +10 -9
- data/{data/strelka → examples}/apps/hello-world +1 -2
- data/examples/apps/sessions-demo +2 -2
- data/examples/config.yml +12 -1
- data/examples/gen-config.rb +5 -6
- data/examples/templates/auth-form.tmpl +4 -0
- data/examples/templates/auth-success.tmpl +3 -1
- data/lib/strelka.rb +15 -21
- data/lib/strelka/app.rb +53 -31
- data/lib/strelka/app/auth.rb +260 -132
- data/lib/strelka/app/sessions.rb +25 -31
- data/lib/strelka/authprovider/basic.rb +33 -9
- data/lib/strelka/authprovider/hostaccess.rb +1 -1
- data/lib/strelka/constants.rb +0 -11
- data/lib/strelka/cookie.rb +17 -1
- data/lib/strelka/httpresponse/negotiation.rb +1 -1
- data/lib/strelka/session/db.rb +49 -25
- data/lib/strelka/session/default.rb +39 -19
- data/spec/lib/helpers.rb +3 -24
- data/spec/strelka/app/auth_spec.rb +461 -177
- data/spec/strelka/app/sessions_spec.rb +7 -26
- data/spec/strelka/app_spec.rb +3 -3
- data/spec/strelka/authprovider/basic_spec.rb +4 -4
- data/spec/strelka/httprequest/session_spec.rb +1 -1
- data/spec/strelka/httpresponse/session_spec.rb +1 -1
- data/spec/strelka/session/db_spec.rb +6 -1
- data/spec/strelka/session/default_spec.rb +3 -3
- metadata +7 -8
- metadata.gz.sig +2 -2
- data/examples/apps/ws-echo +0 -17
- data/lib/strelka/logging.rb +0 -301
- data/spec/strelka/logging_spec.rb +0 -74
data/lib/strelka/app/auth.rb
CHANGED
@@ -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
|
127
|
-
#
|
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
|
-
#
|
130
|
-
#
|
131
|
-
#
|
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
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
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
|
-
#
|
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
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
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
|
-
###
|
334
|
-
###
|
335
|
-
###
|
336
|
-
### {
|
337
|
-
###
|
338
|
-
###
|
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
|
-
###
|
359
|
-
###
|
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 )
|
472
|
+
self.authenticate_and_authorize( request )
|
411
473
|
|
412
474
|
super
|
413
475
|
end
|
414
476
|
|
415
477
|
|
416
|
-
|
417
|
-
|
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
|
441
|
-
self.
|
442
|
-
self.
|
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 "
|
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 "
|
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
|
-
###
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
self.
|
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
|
-
###
|
487
|
-
###
|
488
|
-
###
|
489
|
-
def
|
490
|
-
|
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
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
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
|
-
|
502
|
-
provider.authorize( credentials, request, &callback )
|
630
|
+
return perms.compact.uniq
|
503
631
|
end
|
504
632
|
|
505
633
|
|