[Jifty-commit] r3241 - in jifty/trunk: lib/Jifty t/TestApp/lib/TestApp/Model t/TestApp/t

jifty-commit at lists.jifty.org jifty-commit at lists.jifty.org
Sun May 13 22:02:24 EDT 2007


Author: sterling
Date: Sun May 13 22:02:23 2007
New Revision: 3241

Added:
   jifty/trunk/t/TestApp/t/before_access.t
Modified:
   jifty/trunk/   (props changed)
   jifty/trunk/lib/Jifty/Record.pm
   jifty/trunk/t/TestApp/lib/TestApp/Model/User.pm
   jifty/trunk/t/TestApp/t/11-current_user.t

Log:
 r5091 at dynpc145:  andrew | 2007-05-13 21:00:23 -0500
 Added the before_access trigger and a simple test for it. Also updated TestApp and the current_user test to make them compatible with the new before_access test.


Modified: jifty/trunk/lib/Jifty/Record.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Record.pm	(original)
+++ jifty/trunk/lib/Jifty/Record.pm	Sun May 13 22:02:23 2007
@@ -178,19 +178,93 @@
 Called before any attribute is changed on the object.
 ATTRIBUTES is a hash of the arguments passed to _set.
 
-
-
 =item delete
 
 Called before the object is deleted.
 
 =back
 
-The default implementation returns true if the current user is a
-superuser or a boostrap user.  If the user is looking to delegate the
-access control decision to another object (by creating a
-C<delegate_current_user_can> subroutine), it hands off to that
-routine.  Otherwise, it returns false.
+Models wishing to customize authorization checks should override this method. You you can do so like this:
+
+  sub current_user_can {
+      my ($self, $right, %args) = @_;
+
+      # Make any custom checks that return 1 to allow or return 0 to deny...
+      
+      # Fallback upon the default implementation to handle the
+      # SkipAccessControl configuration setting, superuser, bootstrap,
+      # delegation, and the before_access hook
+      return $self->SUPER::current_user_can($right, %args);
+  }
+
+If you are sure you don't want your model to fallback using the default implementation, you can replace the last line with whatever fallback policy required.
+
+=head3 Authorization steps
+
+The default implementation proceeds as follows:
+
+=over
+
+=item 1.
+
+If the C<SkipAccessControl> setting is set to a true value in the framework configuration section of F<etc/config.yml>, C<current_user_can> always returns true.
+
+=item 2.
+
+The method first attempts to call the C<before_access> hooks to check for any
+allow or denial. See L</The before_access hook>.
+
+=item 3.
+
+Next, the default implementation returns true if the current user is a
+superuser or a boostrap user.  
+
+=item 4.
+
+Then, if the model can perform delegation, usually by using
+L<Jifty::RightsFrom>, the access control decision is deferred to another object
+(via the C<delegate_current_user_can>
+subroutine).  
+
+=item 5.
+
+Otherwise, it returns false.
+
+=back
+
+=head3 The before_access hook
+
+This implementation may make use of a trigger called C<before_access> to make the decision. A new handler can be added to the trigger point by calling C<add_handler>:
+
+  $record->add_trigger(
+      name => 'before_access',
+      code => \&before_access,
+      abortable => 1,
+  );
+
+The C<before_access> handler will be passed the same arguments that were used to call C<current_user_can>, including the current record object, the operation being checked, and any arguments being passed to the operation.
+
+The C<before_access> handler should return one of three strings: C<'deny'>, C<'allow'>, or C<'ignore'>. The C<current_user_can> implementation reacts as follows to these results:
+
+=over
+
+=item 1.
+
+If a handler is abortable and aborts by returning a false value (such as C<undef>), C<current_user_can> returns false.
+
+=item 2.
+
+If any handler returns 'deny', C<current_user_can> returns false.
+
+=item 3.
+
+If any handler returns 'allow' and no handler returns 'deny', C<current_user_can> returns true.
+
+=item 4.
+
+In all other cases, the results of the handlers are ignored and C<current_user_can> proceeds to check using superuser, bootstrap, and delegation.
+
+=back
 
 =cut
 
@@ -198,10 +272,37 @@
     my $self  = shift;
     my $right = shift;
     
+    # Turn off access control for the whole application
     if (Jifty->config->framework('SkipAccessControl')) {
-	return 1;	
+	    return 1;	
+    }
+
+    my $hook_status = $self->call_trigger( before_access => $right, @_ );
+
+    # If not aborted...
+    if (defined $hook_status) {
+
+        # Compile the handler results
+        my %results;
+        $results{ $_->[0] }++ for (@{ $self->last_trigger_results });
+
+        # Deny always takes precedent
+        if ($results{deny}) {
+            return 0;
+        }
+
+        # Then allow...
+        elsif ($results{allow}) {
+            return 1;
+        }
+       
+        # Otherwise, no instruction from the handlers, move along...
     }
 
+    # Abort! Return false for safety
+    else {
+        return 0;
+    } 
 
     if (   $self->current_user->is_bootstrap_user
         or $self->current_user->is_superuser )

Modified: jifty/trunk/t/TestApp/lib/TestApp/Model/User.pm
==============================================================================
--- jifty/trunk/t/TestApp/lib/TestApp/Model/User.pm	(original)
+++ jifty/trunk/t/TestApp/lib/TestApp/Model/User.pm	Sun May 13 22:02:23 2007
@@ -38,9 +38,6 @@
 
 
 # Your model-specific methods go here.
-sub current_user_can {
-    return 1;
-}
 
 1;
 

Modified: jifty/trunk/t/TestApp/t/11-current_user.t
==============================================================================
--- jifty/trunk/t/TestApp/t/11-current_user.t	(original)
+++ jifty/trunk/t/TestApp/t/11-current_user.t	Sun May 13 22:02:23 2007
@@ -21,6 +21,9 @@
 my $system_user = TestApp::CurrentUser->superuser;
 ok($system_user, "Found a system user");
 
+# Make it so that all users have full access
+TestApp::Model::User->add_trigger( before_access => sub { 'allow' } );
+
 # Create two users
 my $o = TestApp::Model::User->new(current_user => $system_user);
 $o->create( name => 'A User', email => 'auser at example.com', 

Added: jifty/trunk/t/TestApp/t/before_access.t
==============================================================================
--- (empty file)
+++ jifty/trunk/t/TestApp/t/before_access.t	Sun May 13 22:02:23 2007
@@ -0,0 +1,33 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+
+use lib 't/lib';
+use Jifty::SubTest;
+
+use Jifty::Test tests => 4;
+
+use_ok('TestApp::Model::User');
+
+# Create a superuser, which will be denied access in a bit
+my $system_user = TestApp::CurrentUser->superuser;
+ok($system_user, 'Found a system user');
+
+# Associate a new rule that only names starting with bob can be created
+TestApp::Model::User->add_trigger( before_access => sub {
+    my ($self, $right, %args) = @_;
+    return 'ignore' unless $right eq 'create';
+    unless ($args{name} =~ /^bob/) {
+        return 'deny';
+    }
+    return 'ignore';
+});
+
+# Try creating non-bob, which will be denied
+my $o = TestApp::Model::User->new(current_user => $system_user);
+my ($id) = $o->create( name => 'nonbob', email => $$, password => $$ );
+ok(!$id, 'User could not be created');
+
+# Try creating bobette, which will be allowd
+($id) = $o->create( name => 'bobette', email => $$, password => $$ );
+ok($id, 'User could be created');


More information about the Jifty-commit mailing list