"Fossies" - the Fresh Open Source Software Archive

Member "absence-v2.1/cgi-bin/AbsenceAuthorization.pm" (20 Oct 2013, 14816 Bytes) of package /linux/www/web-absence-2.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Perl source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "AbsenceAuthorization.pm" see the Fossies "Dox" file reference documentation.

    1 #---------------------------------------------------------------------
    2 # authentication & authorization
    3 # $Id: AbsenceAuthorization.pm 111 2013-10-20 17:57:24Z urban $
    4 # copyright Robert Urban
    5 #---------------------------------------------------------------------
    6 
    7 #======================================================================
    8 #    This file is part of Absence.
    9 #
   10 #    Absence is free software: you can redistribute it and/or modify
   11 #    it under the terms of the GNU General Public License as published by
   12 #    the Free Software Foundation, either version 3 of the License, or
   13 #    (at your option) any later version.
   14 #
   15 #    Absence is distributed in the hope that it will be useful,
   16 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
   17 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   18 #    GNU General Public License for more details.
   19 #
   20 #    You should have received a copy of the GNU General Public License
   21 #    along with Absence.  If not, see <http://www.gnu.org/licenses/>.
   22 #======================================================================
   23 
   24 package AbsenceAuthorization;
   25 
   26 use Data::Dumper;
   27 
   28 use AbsenceDB;
   29 
   30 BEGIN {
   31     # an instance has been specified
   32     if (exists($ENV{INSTANCE_NAME})) {
   33         $cookie_name = "absence-auth-$ENV{INSTANCE_NAME}";
   34     } else {
   35         $cookie_name = 'absence-auth';
   36     }
   37 }
   38 
   39 use AbsenceConfig;
   40 use AbsenceLog;
   41 
   42 my $AUTH        = AbsenceConfig::fetch('authentication');
   43 #my $AUTH_TYPE  = AbsenceConfig::fetch('auth_type');
   44 #my $SECRET     = AbsenceConfig::fetch('secret');
   45 #my $TOP_PAGE   = AbsenceConfig::fetch('top_page');
   46 my $SUPER_USER  = 0;
   47 
   48 my $DEBUG       = 0;
   49 my $VERSION     = '2.0.1';
   50 
   51 sub checkSuperuser
   52 {
   53     my $user_id = shift;
   54 
   55     if (!$AUTH || AbsenceDB::isSuperuser($user_id)) {
   56         return $SUPER_USER = 1;
   57     }
   58 
   59     return $SUPER_USER = 0;
   60 }
   61 
   62 sub dbg
   63 {
   64     my $msg = shift;
   65 
   66     $DEBUG && abslog("DEBUG: $msg");
   67 }
   68 
   69 sub allowWriteForPerson
   70 {
   71     my ($user_id, $pid) = @_;
   72 
   73     $AUTH || return 1;
   74 
   75     return AbsenceDB::authorizeAccessToObject($user_id, $pid, 'write');
   76 }
   77 
   78 sub allowReadForGroup
   79 {
   80     my ($user_id, $gid) = @_;
   81 
   82     $AUTH || return 1;
   83 
   84     return AbsenceDB::authorizeAccessToGroup($user_id, $gid, 'read');
   85 }
   86 
   87 sub allowWriteForGroup
   88 {
   89     my ($user_id, $gid) = @_;
   90 
   91     $AUTH || return 1;
   92 
   93     return AbsenceDB::authorizeAccessToGroup($user_id, $gid, 'write');
   94 }
   95 
   96 sub allowAdminForGroup
   97 {
   98     my ($user, $gid) = @_;
   99 
  100     $AUTH || return 1;
  101 
  102     return AbsenceDB::authorizeAccessToGroup($user_id, $gid, 'admin');
  103 }
  104 
  105 #-----------------------------------------------------------------
  106 # what groups is $user allowed to see?
  107 #-----------------------------------------------------------------
  108 sub getReadGroups
  109 {
  110     my $user_id = shift;
  111 
  112     $AUTH || return (AbsenceDB::getGroups());
  113 
  114     return AbsenceDB::findReadableGroups($user_id);
  115 }
  116 
  117 #-----------------------------------------------------------------
  118 # what people is $user allowed to manage?
  119 #-----------------------------------------------------------------
  120 sub getAdminPeople
  121 {
  122     my ($user_id, $op) = @_;
  123 
  124     $AUTH || return (AbsenceDB::getPeople(0));
  125     
  126     return AbsenceDB::findAdministratableObjects($user_id, $op);
  127 }
  128 
  129 #-----------------------------------------------------------------
  130 # getAdminUsers() returns a list of users whom $user is allowed
  131 # to administer.  The list depends on what the admin operation
  132 # is.  If the operation ($op) is "delete", a list consists of
  133 # all the users that only have access to groups for which $user
  134 # has admin privs.  Thus, a group administrator can only delete
  135 # a user if the user only has read/write/admin privs for groups
  136 # that the group administrator has admin privs for...
  137 #-----------------------------------------------------------------
  138 sub getAdminUsers
  139 {
  140     my ($user_id, $op) = @_;
  141 
  142     $AUTH || return AbsenceDB::getUsers();
  143 
  144     return AbsenceDB::findAdministratableUsers($user_id, $op);
  145 }
  146 
  147 #-----------------------------------------------------------------
  148 # return true if all set $gref1 contains all members of set $gref2
  149 #-----------------------------------------------------------------
  150 sub superset
  151 {
  152     my ($gref1, $gref2) = @_;
  153 
  154     my $count = 0;
  155     foreach my $mem (@{$gref2}) {
  156         if (inListN($mem, $gref1)) {
  157             $count++;
  158         }
  159     }
  160 
  161     dbg("superset: count=[$count], len(gref2) = [".@{$gref2}."]");
  162     ($count == @{$gref2}) && return 1;
  163     return 0;
  164 }
  165 
  166 #-----------------------------------------------------------------
  167 # adminForAllGroups() is passed a person-id to check and a list
  168 # of groups for which the user has admin-privs.  It checks if
  169 # the person in question is only a member of groups for which
  170 # the user has admin-privs.  returns true if this is the case,
  171 # false if not.
  172 #
  173 # ONLY USED BY getAdminPeople_old()
  174 #-----------------------------------------------------------------
  175 sub adminForAllGroups
  176 {
  177     my ($pid, $gref) = @_;
  178 
  179     # first get list of groups to which person belongs
  180     my $pgref = AbsenceDB::getPerson($pid, 'group');
  181     my $count = 0;
  182     foreach my $g (@{$pgref}) {
  183         if (inListN($g, $gref)) {
  184             $count++;
  185         }
  186     }
  187     if ($count == @{$pgref}) {
  188         return 1;
  189     }
  190     return 0;
  191 }
  192 
  193 sub getAdminGroups
  194 {
  195     my $user_id = shift;
  196 
  197     $AUTH || return AbsenceDB::getGroups();
  198 
  199     return AbsenceDB::findAdminGroups($user_id);
  200 }
  201 
  202 #-----------------------------------------------------------------
  203 # divideGroups()
  204 # 
  205 # given a user-id for an administrator ($user_id) and a user-id
  206 # for a managed object ($uid), divideGroups() determines which
  207 # groups are administratable by $user_id (and therefore 'visible')
  208 # and which groups are not administratable, and therefore invisible.
  209 #-----------------------------------------------------------------
  210 sub divideGroups
  211 {
  212     my ($a_uid, $o_uid) = @_;
  213 
  214     my @o_groups = AbsenceDB::getUserGroups($o_uid);
  215 
  216     my (@vis, @invis);
  217 
  218     foreach my $gid (@o_groups) {
  219         AbsenceDB::authorizeAccessToGroup($a_uid, $gid, 'admin')
  220             ? push(@vis, $gid)
  221             : push(@invis, $gid);
  222     }
  223 
  224     (\@vis, \@invis);
  225 }
  226 
  227 sub divideGroups2
  228 {
  229     my ($user_id, $uid) = @_;
  230 
  231     my $oid = AbsenceDB::getOidForUid($uid)
  232         || die "oid not found for uid [$uid]";
  233 
  234     my @o_groups = AbsenceDB::getObjectGroups($oid);
  235     my @admgrps = AbsenceDB::findAdminGroups($user_id);
  236 
  237     if (AbsenceDB::isSuperuser($user_id)) {
  238         return (\@o_groups, []);
  239     }
  240 
  241     my (@vis, @invis);
  242 
  243     foreach my $gid (@o_groups) {
  244         if (inListN($gid, \@admgrps)) {
  245             push(@vis, $gid);
  246         } else {
  247             push(@invis, $gid);
  248         }
  249     }
  250 
  251     (\@vis, \@invis);
  252 }
  253 
  254 sub adminAll
  255 {
  256     my $user_id = shift;
  257 
  258     AbsenceDB::isSuperuser($user_id) && return 1;
  259     return 0;
  260 }
  261 
  262 sub getAdminAcls
  263 {
  264     my ($a_uid, $o_uid) = @_;
  265 
  266     my $acls = AbsenceDB::getUserAcls($o_uid);
  267     $DEBUG && abslog("dump of \$acls for uid=[$o_uid]:\n".Dumper($acls)."\n--end--");
  268     defined($acls) || return { object => [], group => [] };
  269 
  270     $SUPER_USER && return $acls;
  271 
  272     if (AbsenceDB::isSuperuser($o_uid)) {
  273         # group-admin is trying to modify super-user
  274         return { object => [], group => [] };
  275     }
  276 
  277     my ($gvisref, $ginvref) = divideGroupAcls($a_uid, $o_uid, $acls->{group});
  278     my ($pvisref, $pinvref) = dividePersonAcls($a_uid, $acls->{object});
  279 
  280     return {object => $pvisref, group => $gvisref};
  281 }
  282 
  283 sub convertToInternal
  284 {
  285     my $acl_ref = shift;
  286 
  287     $DEBUG && abslog("convertToInternal: \$acl_ref=\n".Dumper($acl_ref)."\n--end--");
  288     my (@g, @o);
  289 
  290     foreach my $oacl (@{ $acl_ref->{object} }) {
  291         my $targ = defined($oacl->{ref_id}) ? $oacl->{ref_id} : $oacl->{magic};
  292         push(@o, [ $oacl->{level} => $targ ]);
  293     }
  294     foreach my $gacl (@{ $acl_ref->{group} }) {
  295         my $targ = defined($oacl->{ref_id}) ? $oacl->{ref_id} : $oacl->{magic};
  296         push(@g, [ $oacl->{level} => $targ ]);
  297     }
  298 
  299     $DEBUG && abslog("convertToInternal: \@g=\n".Dumper(\@g)."\n--end--");
  300     return { object => \@o, group => \@g };
  301 }
  302 
  303 sub dividePersonAcls
  304 {
  305     my ($a_uid, $acls) = @_;
  306 
  307     my @admppl = getAdminPeople($a_uid);
  308     my (@vis, @invis);
  309 
  310     foreach my $acl (@{$acls}) {
  311         if ($acl->{target} eq 'self') {
  312             push(@vis, $acl );
  313         } elsif (inListN($acl->{target}, \@admppl)) {
  314             push(@vis, $acl);
  315         } else {
  316             push(@invis, $acl);
  317         }
  318     }
  319 
  320     return (\@vis, \@invis);
  321 }
  322 
  323 sub dividePersonAcls_noconvert
  324 {
  325     my ($a_uid, $o_acls) = @_;
  326 
  327     my @admppl = getAdminPeople($a_uid);
  328     my (@vis, @invis);
  329 
  330     foreach my $acl (@{$o_acls}) {
  331         if ($acl->{magic} eq 'self') {
  332             push(@vis, $acl);
  333         } elsif (inListN($acl->{ref_id}, \@admppl)) {
  334             push(@vis, $acl);
  335         } else {
  336             push(@invis, $acl);
  337         }
  338     }
  339 
  340     return (\@vis, \@invis);
  341 }
  342 
  343 #-------------------------------------------------------------
  344 # selfAllowed()
  345 #
  346 # determine whether the magic value 'self' should be allowed
  347 # in a group access record.
  348 #
  349 # This is done by first checking whether the object to be modified
  350 # (really the associated user) already has a 'self' magic-value.  If
  351 # not, only a super-user may add one, after that the groups to which the
  352 # object to # be modified is a member are compared with the groups over
  353 # which the admin-user
  354 # has admin-privs.  The admin-user groups must be a supserset of
  355 # the groups to which the object to be modified belongs
  356 #-------------------------------------------------------------
  357 sub selfAllowed
  358 {
  359     my ($a_uid, $o_uid) = @_;
  360 
  361     defined($o_uid) || return 1;
  362     AbsenceDB::isSuperuser($a_uid) && return 1;
  363  
  364     AbsenceDB::userHasMagicAccess($o_uid, 'group', 'self') || return 0;
  365 
  366     my @o_groups = AbsenceDB::getUserGroups($a_uid);
  367     my @a_groups = AbsenceDB::findAdminGroups($a_uid);
  368     superset(\@a_groups, \@o_groups) && return 1;
  369     return 0;
  370 }
  371 
  372 sub deleteElement
  373 {
  374     my($el, $lref) = @_;
  375 
  376     my $count = 0;
  377     my $match = 0;
  378     foreach my $tmp (@$lref) {
  379         if ($tmp eq $el) {
  380             $match = 1;
  381             last;
  382         }
  383         $count++;
  384     }
  385 
  386     if ($match) {
  387         splice(@$lref, $count, 1);
  388     }
  389 }
  390 
  391 #------------------------------------------------------------------
  392 # divideGroupAcls() is big fun.  It sorts all the ACLs for $uid
  393 # into two groups.  The first group contains the ACLs that $user
  394 # is allowed to administer.  The second groups contains the ACLs
  395 # that $user is not allowed to administer.
  396 #------------------------------------------------------------------
  397 sub divideGroupAcls
  398 {
  399     my ($a_uid, $o_uid, $acls) = @_;
  400 
  401     my @admgrps = getAdminGroups($a_uid);
  402 
  403     my %rules;
  404 
  405     foreach my $acl (@{ $acls }) {
  406         #if ($acl->{target} =~ /^\d+$/) {
  407             $rules{ $acl->{target} } = $acl->{level};
  408         #}
  409     }
  410 
  411     #---------------------------------------------------------------
  412     # if $uid has an group-ACL containing "self", I must check if
  413     # $user has admin privs for all groups that $uid is a member of.
  414     # If $user does not have admin privs for all these groups,
  415     # the rule containing "self" must be converted into individual
  416     # rules containing references to real groups.
  417     #---------------------------------------------------------------
  418     my $lev;
  419     #if ($lev = AbsenceDB::userHasMagicAccess($a_uid, 'group', 'self')) {
  420     if (exists($rules{self})) {
  421         my @o_groups = AbsenceDB::getUserGroups($o_uid);
  422         if (!superset(\@admgrps, \@o_groups)) {
  423             foreach my $gid (@o_groups) {
  424                 if (!exists($rules{$gid}) || ($rules{$gid} < $lev)) {
  425                     $rules{$gid} = $lev;
  426                 }
  427             }
  428             delete($rules{self});
  429         }
  430     }
  431 
  432     #---------------------------------------------------------------
  433     # if there is a rule containing "all", I must do the same thing
  434     # as described above for "self".
  435     #---------------------------------------------------------------
  436     #if ($lev = AbsenceDB::userHasMagicAccess($a_uid, 'group', 'all')) {
  437     if (exists($rules{all})) {
  438         if ($lev != 4) {
  439             foreach my $gid (AbsenceDB::getGroups()) {
  440                 if (!exists($rules{$gid}) || ($rules{$gid} < $lev)) {
  441                     $rules{$gid} = $lev;
  442                 }
  443             }
  444             delete($rules{all});
  445         }
  446     }
  447 
  448     #---------------------------------------------------------------
  449     # now I can go through my list of rules and divide into the
  450     # two groups.  If a rule refers to a group for which $user has
  451     # admin privs, it goes on the visable list, otherwise on the
  452     # invisible list.
  453     #---------------------------------------------------------------
  454     my (@vis, @invis);
  455     foreach my $gid (keys(%rules)) {
  456         my $ref = { level => $rules{$gid}, target => $gid };
  457         if ($gid eq 'self') {
  458             push(@vis, $ref);
  459         } elsif ($gid eq 'all') {
  460             push(@invis, $ref);
  461         } elsif (inListN($gid, \@admgrps)) {
  462             push(@vis, $ref);
  463         } else {
  464             push(@invis, $ref);
  465         }
  466     }
  467 
  468     return (\@vis, \@invis);
  469 }
  470 
  471 sub divideGroupAcls_noconvert
  472 {
  473     my ($a_uid, $o_uid) = @_;
  474 
  475     my $acls = AbsenceDB::getUserAcls($o_uid);
  476     my @admgrps = getAdminGroups($user);
  477 
  478     my %rules;
  479 
  480     foreach my $acl (@{ $acls->{group} }) {
  481         if (!defined($acl->{magic})) {
  482             $rules{ $acl->{ref_id} } = $acl;
  483         }
  484     }
  485 
  486     #---------------------------------------------------------------
  487     # if $o_uid has an group-ACL containing "self", I must check if
  488     # $a_uid has admin privs for all groups that $uid is a member of.
  489     # If $user does not have admin privs for all these groups,
  490     # the rule containing "self" must be converted into individual
  491     # rules containing references to real groups.
  492     #---------------------------------------------------------------
  493     my $lev;
  494     if ($lev = AbsenceDB::userHasMagicAccess($o_uid, 'group', 'self')) {
  495         my @o_groups = AbsenceDB::getUserGroups($o_uid);
  496         if (!superset(\@admgrps, \@o_groups)) {
  497             foreach my $gid (@o_groups) {
  498                 if (!exists($rules{$gid}) || ($rules{$gid} < $lev)) {
  499                     $rules{$gid} = {
  500                         level   => $lev,
  501                         user_id => $o_uid,
  502                         ref_id  => $gid,
  503                         type    => 'group',
  504                     };
  505                 }
  506             }
  507         } else {
  508             $rules{self} = {
  509                 level   => $lev,
  510                 user_id => $o_uid,
  511                 type    => 'group',
  512                 magic   => 'self',
  513             };
  514         }
  515     }
  516 
  517     #---------------------------------------------------------------
  518     # if there is a rule containing "all", I must do the same thing
  519     # as described above for "self".
  520     #---------------------------------------------------------------
  521     if ($lev = AbsenceDB::userHasMagicAccess($a_uid, 'group', 'all')) {
  522         if ($lev != 4) {
  523             foreach my $gid (AbsenceDB::getGroups()) {
  524                 if (!exists($rules{$gid}) || ($rules{$gid} < $lev)) {
  525                     $rules{$gid} = {
  526                         level   => $lev,
  527                         user_id => $o_uid,
  528                         ref_id  => $gid,
  529                         type    => 'group',
  530                     };
  531                 }
  532             }
  533         } else {
  534             $rules{all} = {
  535                 level   => $lev,
  536                 user_id => $o_uid,
  537                 type    => 'group',
  538                 magic   => 'all',
  539             };
  540         }
  541     }
  542 
  543     #---------------------------------------------------------------
  544     # now I can go through my list of rules and divide into the
  545     # two groups.  If a rule refers to a group for which $user has
  546     # admin privs, it goes on the visable list, otherwise on the
  547     # invisible list.
  548     #---------------------------------------------------------------
  549     my (@vis, @invis);
  550     foreach my $gid (keys(%rules)) {
  551         if ($gid eq 'self') {
  552             push(@vis, $rules{$gid});
  553         } elsif ($gid eq 'all') {
  554             push(@invis, $rules{$gid});
  555         } elsif (inListN($gid, \@admgrps)) {
  556             push(@vis, $rules{$gid});
  557         } else {
  558             push(@invis, $rules{$gid});
  559         }
  560     }
  561 
  562     return (\@vis, \@invis);
  563 }
  564 
  565 sub inListN
  566 {
  567     my ($thing, $lref) = @_;
  568 
  569     foreach my $elem (@{$lref}) {
  570         ($elem == $thing) && return 1;
  571     }
  572 
  573     return 0;
  574 }
  575 
  576 1;