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.
- 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
|
|