From: Sam H. v. a. <we...@ma...> - 2005-01-28 00:39:56
|
Log Message: ----------- HEAD backport: expansion of Mike's caching fixes. (sh002i) Tags: ---- rel-2-1-patches Modified Files: -------------- webwork2/lib: WeBWorK.pm webwork2/lib/WeBWorK: Authz.pm Revision Data ------------- Index: WeBWorK.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK.pm,v retrieving revision 1.68.2.1 retrieving revision 1.68.2.2 diff -Llib/WeBWorK.pm -Llib/WeBWorK.pm -u -r1.68.2.1 -r1.68.2.2 --- lib/WeBWorK.pm +++ lib/WeBWorK.pm @@ -224,7 +224,7 @@ } debug("Create an authz object (Authen needs it to check login permission)...\n"); - $authz = new WeBWorK::Authz($r, $ce, $db); + $authz = new WeBWorK::Authz($r); debug("(here's the authz object: $authz)\n"); $r->authz($authz); @@ -234,6 +234,9 @@ if ($authenOK) { my $userID = $r->param("user"); debug("Hi, $userID, glad you made it.\n"); + + # tell authorizer to cache this user's permission level + $authz->setCachedUser($userID); debug("Now we deal with the effective user:\n"); my $eUserID = $r->param("effectiveUser") || $userID; Index: Authz.pm =================================================================== RCS file: /webwork/cvs/system/webwork2/lib/WeBWorK/Authz.pm,v retrieving revision 1.17.2.1 retrieving revision 1.17.2.2 diff -Llib/WeBWorK/Authz.pm -Llib/WeBWorK/Authz.pm -u -r1.17.2.1 -r1.17.2.2 --- lib/WeBWorK/Authz.pm +++ lib/WeBWorK/Authz.pm @@ -20,52 +20,184 @@ WeBWorK::Authz - check user permissions. +=head1 SYNOPSIS + + # create new authorizer -- $r is a WeBWorK::Request object. + my $authz = new WeBWorK::Authz($r); + + # tell authorizer to cache permission level of user spammy. + $authz->setCachedUser("spammy"); + + # this call will use the cached data. + if ($authz->hasPermissions("spammy", "eat_breakfast")) { + eat_breakfast(); + } + + # this call will not use the cached data, and will cause a database lookup. + if ($authz->hasPermissions("hammy", "go_to_bed")) { + go_to_bed(); + } + +=head1 DESCRIPTION + +WeBWorK::Authen determines if a user is authorized to perform a specific +activity, based on the user's PermissionLevel record in the WeBWorK database and +the contents of the %permissionLevels hash in the course environment. + +=head2 Format of the %permissionLevels hash + +%permissionLevels maps text strings describing activities to numeric permission +levels. The definitive list of activities is contained in the default version of +%permissionLevels, in the file F<conf/global.conf.dist>. + +A user is able to engage in an activity if their permission level is greater +than or equal to the level associated with the activity. If the level associated +with an activity is undefiend, then no user is permitted to perform the +activity, regardless of their permission level. + =cut use strict; use warnings; +################################################################################ + +=head1 CONSTRUCTOR + +=over + +=item WeBWorK::Authz->new($r) + +Creates a new authorizer instance. $r is a WeBWorK::Request object. It must +already have its C<ce> and C<db> fields set. + +=cut sub new { - my ($invocant, $r, $ce, $db) = @_; + my ($invocant, $r) = @_; my $class = ref($invocant) || $invocant; my $self = { r => $r, }; - my $user = $r->param("user"); - return 0 unless defined($user); - my $Permission = $db->getPermissionLevel($user); # checked - return 0 unless defined $Permission; - my $permissionLevel = $Permission->permission(); - return 0 unless defined $permissionLevel and $permissionLevel ne ""; - - my $permissionLevels = $ce->{permissionLevels}; - $self->{permissionLevels} = $permissionLevels; - $self->{permissionLevel} = $permissionLevel; bless $self, $class; return $self; } -# This module assumes that neither the permissionLevels nor the permissionLevel -# changes between the time an authz module is created and the time it's used. +=back + +=cut + +################################################################################ + +=head1 METHODS + +=over + +=item setCachedUser($userID) + +Caches the PermissionLevel of the user $userID in an existing authorizer. If a +user's PermissionLevel is cached, it will be used whenever hasPermissions() is +called on the same user. Only one user can be cached at a time. This is used by +WeBWorK to cache the "real" user. + +=cut + +sub setCachedUser { + my ($self, $userID) = @_; + my $r = $self->{r}; + my $db = $r->db; + + delete $self->{userID}; + delete $self->{PermissionLevel}; + + if (defined $userID) { + $self->{userID} = $userID; + my $PermissionLevel = $db->getPermissionLevel($userID); # checked + if (defined $PermissionLevel) { + # store permission level record in database to avoid later database calls + $self->{PermissionLevel} = $PermissionLevel; + } + } else { + warn "setCachedUser() called with userID undefined.\n"; + } +} + +=item hasPermissions($userID, $activity) + +Checks the %permissionLevels hash in the course environment to determine if the +user $userID has permission to engage in the activity $activity. If the user's +permission level is greater than or equal to the level associated with $activty, +a true value is returned. Otherwise, a false value is returned. + +If $userID has been cached using the setCachedUser() call, the cached data is +used. Otherwise, the user's PermissionLevel is looked up in the WeBWorK +database. + +If the user does not have a PermissionLevel record, the permission level record +is empty, or the activity does not appear in %permissionLevels, hasPermissions() +assumes that the user does not have permission. + +=cut # This currently only uses two of it's arguments, but it accepts any number, in # case in the future calculating certain permissions requires more information. sub hasPermissions { - my ($self, $user, $activity) = @_; - my $permissionLevels = $self->{permissionLevels}; - my $permissionLevel = $self->{permissionLevel}; + my ($self, $userID, $activity) = @_; + my $r = $self->{r}; + my $ce = $r->ce; + my $db = $r->db; + + my $PermissionLevel; + + my $cachedUserID = $self->{userID}; + if (defined $cachedUserID and $cachedUserID ne "" and $cachedUserID eq $userID) { + # this is the same user -- we can skip the database call + $PermissionLevel = $self->{PermissionLevel}; + } else { + # a different user, or no user was defined before + my $prettyCachedUserID = defined $cachedUserID ? "'$cachedUserID'" : "undefined"; + #warn "hasPermissions called with user '$userID', but cached user is $prettyCachedUserID. Accessing database.\n"; + $PermissionLevel = $db->getPermissionLevel($userID); # checked + } + + my $permission_level; + + if (defined $PermissionLevel) { + $permission_level = $PermissionLevel->permission; + } else { + # uh, oh. this user has no permission level record! + warn "User '$userID' has no PermissionLevel record -- assuming no permission.\n"; + return 0; + } + + unless (defined $permission_level and $permission_level ne "") { + warn "User '$userID' has empty permission level -- assuming no permission.\n"; + return 0; + } + + my $permissionLevels = $ce->{permissionLevels}; if (exists $permissionLevels->{$activity}) { if (defined $permissionLevels->{$activity}) { - return $permissionLevel >= $permissionLevels->{$activity}; + return $permission_level >= $permissionLevels->{$activity}; } else { - return 0; + return 0; # nobody has permission to do this } } else { - die "Activity '$activity' not found in %permissionLevels. Can't continue.\n"; + warn "Activity '$activity' not found in %permissionLevels -- assuming no permission.\n"; + return 0; } - } + +=back + +=cut + +=head1 AUTHOR + +Written by Dennis Lambe, malsyned at math.rochester.edu. Modified by Sam +Hathaway, sh002i at math.rochester.edu. + +=cut 1; |