Changeset 26439


Ignore:
Timestamp:
06/22/10 20:47:09 (7 years ago)
Author:
flack
Message:

merge ACL changes back into ragna branch, refs #1848

Location:
branches/ragnaroek/midcom/midcom.core/midcom
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • branches/ragnaroek/midcom/midcom.core/midcom/core/privilege.php

    r26290 r26439  
    4545        'privilegename'=> '',
    4646        'assignee' => null,
     47        'scope' => -1,
    4748        'classname' => '',
    4849        'value' => null
     
    125126    {
    126127        return isset($this->__privilege[$property]);
     128    }
     129
     130    private function _get_scope()
     131    {
     132        $scope = -1;
     133
     134        switch ($this->__privilege['assignee'])
     135        {
     136            case 'EVERYONE':
     137                $scope = MIDCOM_PRIVILEGE_SCOPE_EVERYONE;
     138                break;
     139            case 'USERS':
     140                $scope = MIDCOM_PRIVILEGE_SCOPE_USERS;
     141                break;
     142            case 'ANONYMOUS':
     143                $scope = MIDCOM_PRIVILEGE_SCOPE_ANONYMOUS;
     144                break;
     145            default:
     146                $assignee = $this->get_assignee();
     147                if (! $assignee)
     148                {
     149                    debug_push_class(__CLASS__, __FUNCTION__);
     150                    debug_print_r('Could not resolve the assignee of this privilege:', $this);
     151                    debug_pop();
     152                }
     153                else
     154                {
     155                    $scope = $assignee->scope;
     156                }
     157                break;
     158        }
     159
     160        return $scope;
    127161    }
    128162
     
    366400    public static function get_content_privileges($guid)
    367401    {
    368         $all_privileges = self::get_all_privileges($guid);
    369 
    370         $return = Array();
    371         foreach ($all_privileges as $privilege)
    372         {
    373             if ($privilege->assignee != 'SELF')
    374             {
    375                 $return[] = $privilege;
    376             }
    377         }
    378 
    379         return $return;
     402        return self::_get_privileges($guid, 'CONTENT');
    380403    }
    381404
     
    394417    public static function get_self_privileges($guid)
    395418    {
    396         $all_privileges = midcom_core_privilege::get_all_privileges($guid);
    397 
    398         $return = Array();
    399         foreach ($all_privileges as $privilege)
    400         {
    401             if ($privilege->assignee == 'SELF')
    402             {
    403                 $return[] = $privilege;
    404             }
    405         }
    406 
    407         return $return;
     419        return self::_get_privileges($guid, 'SELF');
    408420    }
    409421
     
    422434    public static function get_all_privileges($guid)
    423435    {
     436        $return = array_merge(self::get_content_privileges($guid), self::get_self_privileges($guid));
     437
     438        return $return;
     439    }
     440
     441    /**
     442     * This is a static helper function which lists all privileges assigned
     443     * an object unfiltered.
     444     *
     445     * This function is for use in the authentication framework only and may only
     446     * be called statically.
     447     *
     448     * @access protected
     449     * @param string GUID the GUID of the object for which we should look up privileges.
     450     * @return Array A list of midcom_core_privilege instances.
     451     * @static
     452     */
     453    private static function _get_privileges($guid, $type)
     454    {
    424455        static $cache = array();
    425456
    426         if (array_key_exists($guid, $cache))
    427         {
    428             $return = $cache[$guid];
     457        $cache_key = $type . '::' . $guid;
     458
     459        if (array_key_exists($cache_key, $cache))
     460        {
     461            $return = $cache[$cache_key];
    429462        }
    430463        else
    431464        {
    432             $return = $_MIDCOM->cache->memcache->get('ACL', $guid);
     465            $return = $_MIDCOM->cache->memcache->get('ACL', $cache_key);
    433466
    434467            if (! is_array($return))
    435468            {
    436469                // Didn't get privileges from cache, get them from DB
    437                 $return = self::_query_all_privileges($guid);
    438                 $_MIDCOM->cache->memcache->put('ACL', $guid, $return);
    439             }
    440 
    441             $cache[$guid] = $return;
     470                $return = self::_query_privileges($guid, $type);
     471                $_MIDCOM->cache->memcache->put('ACL', $cache_key, $return);
     472            }
     473
     474            $cache[$cache_key] = $return;
    442475        }
    443476
    444477        return $return;
    445478    }
     479
    446480
    447481    /**
     
    453487     * @access protected
    454488     * @param string $guid The GUID of the object for which to query ACL data.
     489     * @param string $type SELF or CONTENT
    455490     * @return Array A list of midcom_core_privilege instances.
    456491     * @static
    457492     */
    458     public static function _query_all_privileges($guid)
     493    protected static function _query_privileges($guid, $type)
    459494    {
    460495        $result = array();
     
    462497        $mc = new midgard_collector('midcom_core_privilege_db', 'objectguid', $guid);
    463498        $mc->add_constraint('value', '<>', MIDCOM_PRIVILEGE_INHERIT);
     499       
     500        if ($type == 'CONTENT')
     501        {
     502            $mc->add_constraint('assignee', '<>', 'SELF');
     503        }
     504        else
     505        {
     506            $mc->add_constraint('assignee', '=', 'SELF');
     507        }
     508
    464509        //FIXME:
    465510        $mc->set_key_property('guid');
     
    503548                continue;
    504549            }
     550            $privilege_object->scope = $privilege_object->_get_scope();
    505551            $return[] = $privilege_object;
    506552        }
     
    593639        }
    594640
    595         if (   is_null($user_id)
    596             || !$user_id
    597             || $user_id == 'EVERYONE'
    598             || $user_id == 'ANONYMOUS')
    599         {
    600             if (   $this->__privilege['assignee'] != 'EVERYONE'
    601                 && $this->__privilege['assignee'] != 'ANONYMOUS')
    602             {
     641        switch ($this->__privilege['assignee'])
     642        {
     643            case 'EVERYONE':
     644                return true;
     645                break;
     646            case 'ANONYMOUS':
     647                return ($user_id == 'EVERYONE' || $user_id == 'ANONYMOUS');
     648                break;
     649            case 'USERS':
     650                return ($user_id != 'ANONYMOUS' && $user_id != 'EVERYONE');
     651                break;
     652            default:
     653                if ($this->__privilege['assignee'] == $user_id)
     654                {
     655                    return true;
     656                }
     657                else if (strstr($this->__privilege['assignee'], 'group:') !== false)
     658                {
     659                    $user = $_MIDCOM->auth->get_user($user_id);
     660                    if (is_object($user))
     661                    {
     662                       return $user->is_in_group($this->__privilege['assignee']);
     663                    }
     664                }
    603665                return false;
    604             }
    605         }
    606         else
    607         {
    608             if ($this->__privilege['assignee'] == 'ANONYMOUS')
    609             {
    610                 return false;
    611             }
    612             if (    strstr($this->__privilege['assignee'], 'user:') !== false
    613                 && $this->__privilege['assignee'] != $user_id)
    614             {
    615                 return false;
    616             }
    617             if (strstr($this->__privilege['assignee'], 'group:') !== false)
    618             {
    619                 $user = $_MIDCOM->auth->get_user($user_id);
    620                 if (   !is_object($user)
    621                     || !$user->is_in_group($this->__privilege['assignee']))
    622                 {
    623                     return false;
    624                 }
    625             }
    626         }
    627         return true;
     666                break;
     667        }
    628668    }
    629669
     
    674714        $this->classname = $this->__privilege_object->classname;
    675715        $this->value = $this->__privilege_object->value;
     716        $this->scope = $this->_get_scope();
    676717    }
    677718
  • branches/ragnaroek/midcom/midcom.core/midcom/services/auth.php

    r26290 r26439  
    11531153            {
    11541154                $this->_group_cache[$id] = new midcom_core_group_midgard($object->id);
    1155             }
    1156         }
    1157         else if (   is_object($id)
    1158                  && is_a($id, 'midgard_group'))
    1159         {
    1160             $object = $id;
    1161             $id = "group:{$id->guid}";
    1162             if (! array_key_exists($id, $this->_group_cache))
    1163             {
    1164                 $this->_group_cache[$id] = new midcom_core_group_midgard($object);
    11651155            }
    11661156        }
  • branches/ragnaroek/midcom/midcom.core/midcom/services/auth/acl.php

    r26291 r26439  
    363363
    364364    /**
    365      * Returns the system-wide basic privilege set.
    366      *
    367      * @return Array Privilege Name / Value map.
    368      */
    369     function get_default_privileges()
    370     {
    371         return self::$_default_privileges;
    372     }
    373 
    374     /**
    375      * Returns the system-wide basic owner privilege set.
    376      *
    377      * @return Array Privilege Name / Value map.
    378      */
    379     function get_owner_default_privileges()
    380     {
    381         return self::$_owner_default_privileges;
    382     }
    383 
    384     /**
    385      * Merges a new set of default privileges into the current set.
    386      * Existing keys will be silently overwritten.
    387      *
    388      * This is usually only called by the framework startup and the
    389      * component loader.
    390      *
    391      * If only a single default value is set (type integer), then this value is taken
    392      * for the default and the owner privilege is unset (meaning INHERIT). If two
    393      * values (type array of integers) is set, the first privilege value is used for
    394      * default, the second one for the owner privilege set.
    395      *
    396      * @param Array $privileges An associative privilege_name => default_values listing.
    397      */
    398     function register_default_privileges ($privileges)
    399     {
    400         foreach ($privileges as $name => $values)
    401         {
    402             if (! is_array($values))
    403             {
    404                 $values = array($values, MIDCOM_PRIVILEGE_INHERIT);
    405             }
    406 
    407             self::$_default_privileges[$name] = $values[0];
    408             if ($values[1] != MIDCOM_PRIVILEGE_INHERIT)
    409             {
    410                 self::$_owner_default_privileges[$name] = $values[1];
    411             }
    412         }
    413     }
    414 
    415 
    416     /**
    417      * This helper function loads and prepares the list of class magic privileges for
    418      * usage. It will assign them to the $_*_default_class_privileges members.
    419      *
    420      * @param MidcomDBAObject $class An instance of the object for which the class defaults should be
    421      *     loaded. Be aware, that this may be a simply a default constructed class instance.
    422      * @access private
    423      */
    424     private function _load_class_magic_privileges(&$class)
    425     {
    426         // Check if we have loaded these privileges already...
    427         if (!isset($class->__mgdschema_class_name__))
    428         {
    429             $loadable_class = get_class($class);
    430         }
    431         else
    432         {
    433             $loadable_class = $class->__mgdschema_class_name__;
    434         }
    435 
    436         if (array_key_exists($loadable_class, self::$_default_magic_class_privileges))
    437         {
    438             return;
    439         }
    440 
    441         if (!method_exists($class, 'get_class_magic_default_privileges'))
    442         {
    443             self::$_default_magic_class_privileges[$loadable_class] = array
    444             (
    445                 'EVERYONE' => array(),
    446                 'ANONYMOUS' => array(),
    447                 'USERS' => array()
    448             );
    449             return;
    450         }
    451 
    452         $privs = $class->get_class_magic_default_privileges();
    453         self::$_default_magic_class_privileges[$loadable_class] = $privs;
    454 
    455         return;
    456     }
    457 
    458     /**
    459365     * This internal helper will initialize the default privileges array with all core
    460366     * privileges currently defined.
     
    494400
    495401    /**
     402     * Merges a new set of default privileges into the current set.
     403     * Existing keys will be silently overwritten.
     404     *
     405     * This is usually only called by the framework startup and the
     406     * component loader.
     407     *
     408     * If only a single default value is set (type integer), then this value is taken
     409     * for the default and the owner privilege is unset (meaning INHERIT). If two
     410     * values (type array of integers) is set, the first privilege value is used for
     411     * default, the second one for the owner privilege set.
     412     *
     413     * @param Array $privileges An associative privilege_name => default_values listing.
     414     */
     415    function register_default_privileges ($privileges)
     416    {
     417        foreach ($privileges as $name => $values)
     418        {
     419            if (! is_array($values))
     420            {
     421                $values = array($values, MIDCOM_PRIVILEGE_INHERIT);
     422            }
     423
     424            self::$_default_privileges[$name] = $values[0];
     425            if ($values[1] != MIDCOM_PRIVILEGE_INHERIT)
     426            {
     427                self::$_owner_default_privileges[$name] = $values[1];
     428            }
     429        }
     430    }
     431
     432    /**
     433     * Returns the system-wide basic privilege set.
     434     *
     435     * @return Array Privilege Name / Value map.
     436     */
     437    function get_default_privileges()
     438    {
     439        return self::$_default_privileges;
     440    }
     441
     442    /**
     443     * Returns the system-wide basic owner privilege set.
     444     *
     445     * @return Array Privilege Name / Value map.
     446     */
     447    function get_owner_default_privileges()
     448    {
     449        return self::$_owner_default_privileges;
     450    }
     451
     452
     453    /**
     454     * This helper function loads and prepares the list of class magic privileges for
     455     * usage. It will assign them to the $_*_default_class_privileges members.
     456     *
     457     * @param string $class The class name for which defaults should be loaded.
     458     * @access private
     459     */
     460    private function _load_class_magic_privileges($class)
     461    {
     462        // Check if we have loaded these privileges already...
     463        if (array_key_exists($class, self::$_default_magic_class_privileges))
     464        {
     465            return;
     466        }
     467
     468        $object = new $class();
     469
     470        if (!method_exists($object, 'get_class_magic_default_privileges'))
     471        {
     472            self::$_default_magic_class_privileges[$class] = array
     473            (
     474                'EVERYONE' => array(),
     475                'ANONYMOUS' => array(),
     476                'USERS' => array()
     477            );
     478            return;
     479        }
     480
     481        $privs = $object->get_class_magic_default_privileges();
     482
     483        self::$_default_magic_class_privileges[$class] = $privs;
     484
     485        return;
     486    }
     487
     488    private function _get_user_per_class_privileges($classname, $user)
     489    {
     490        static $cache = array();
     491
     492        $cache_id = $user->id . '::' . $classname;
     493
     494        if (array_key_exists($cache_id, $cache))
     495        {
     496            return $cache[$cache_id];
     497        }
     498
     499        $tmp_object = new $classname;
     500
     501        $cache[$cache_id] = $user->get_per_class_privileges($tmp_object);
     502
     503        return $cache[$cache_id];
     504    }
     505   
     506    /**
     507     * Determine the user identifier for accessing the privilege cache. This is the passed user's
     508     * identifier with the current user and anonymous as fallback
     509     *
     510     * @param mixed $user The user to check for as string or object.
     511     * @return string The identifier
     512     */
     513    public function get_user_id($user = null)
     514    {
     515        $user_id = 'ANONYMOUS';
     516
     517        // TODO: Clean if/else shorthands, make sure this works correctly for magic assignees as well
     518        if (is_null($user))
     519        {
     520            $user = $this->auth->user;
     521
     522            if (!empty($user))
     523            {
     524                $user_id = $user->id;
     525            }
     526        }
     527        else if (is_string($user))
     528        {
     529            if ($user != 'EVERYONE'
     530                && (    mgd_is_guid($user)
     531                    || is_numeric($user)))
     532            {
     533                $user = $this->auth->get_user($user);
     534                $user_id = $user->id;
     535            }
     536            else
     537            {
     538                $user_id = $user;
     539                $user = null;
     540            }
     541        }
     542        else if (is_object($user))
     543        {
     544            $user_id = $user->id;
     545        }
     546        else
     547        {
     548            $user_id = $user;
     549        }
     550
     551        return $user_id;
     552    }
     553
     554    /**
    496555     * This is a simple helper function which validates whether a given privilege
    497556     * exists by its name. Essentially this checks if a corresponding default privilege
     
    505564    {
    506565        return (array_key_exists($name, self::$_default_privileges));
    507     }
    508 
    509     /**
    510      * Checks whether a user has a certain privilege on the given (via guid and class) content object.
    511      * Works on the currently authenticated user by default, but can take another
    512      * user as an optional argument.
    513      *
    514      * @param string $privilege The privilege to check for
    515      * @param string $object_guid A Midgard GUID pointing to an object
    516      * @param string $object_class Class of the object in question
    517      * @param string $user_id The user against which to check the privilege, defaults to the currently authenticated user.
    518      *     You may specify "EVERYONE" instead of an object to check what an anonymous user can do.
    519      * @return boolean True if the privilege has been granted, false otherwise.
    520      */
    521     function can_do_byguid($privilege, $object_guid, $object_class, $user_id)
    522     {
    523         if ($this->_internal_sudo)
    524         {
    525             //debug_push_class(__CLASS__, __FUNCTION__);
    526             //debug_add('INTERNAL SUDO mode is enabled. Generic Read-Only mode set.', MIDCOM_LOG_DEBUG);
    527             //debug_pop();
    528             return $this->_can_do_internal_sudo($privilege);
    529         }
    530 
    531         if ($this->auth->_component_sudo)
    532         {
    533             return true;
    534         }
    535 
    536         $cache_key = "{$user_id}::{$object_guid}";
    537 
    538         if (!isset(self::$_privileges_cache[$cache_key]))
    539         {
    540             //debug_push_class(__CLASS__, __FUNCTION__);
    541             //debug_add("Cache {$privilege_key} miss, fetching privileges for {$object_guid}");
    542             //debug_pop();
    543 
    544             $this->_load_privileges_byguid($object_guid, $object_class, $user_id);
    545         }
    546 
    547         if (!array_key_exists($privilege, self::$_privileges_cache[$cache_key]))
    548         {
    549             debug_push_class(__CLASS__, __FUNCTION__);
    550             debug_add("The privilege {$privilege} is unknown at this point. Assuming not granted privilege.", MIDCOM_LOG_WARN);
    551             debug_pop();
    552             return false;
    553         }
    554 
    555         return self::$_privileges_cache[$cache_key][$privilege];
    556     }
    557 
    558     function can_do_byclass($privilege, $user, $class, $component)
    559     {
    560         if ($this->_internal_sudo)
    561         {
    562             debug_push_class(__CLASS__, __FUNCTION__);
    563             debug_add('INTERNAL SUDO mode is enabled. Generic Read-Only mode set.', MIDCOM_LOG_DEBUG);
    564             debug_pop();
    565             return $this->_can_do_internal_sudo($privilege);
    566         }
    567 
    568         // Initialize this one to be sure to have it.
    569         $default_magic_class_privileges = Array();
    570 
    571         if ($class !== null)
    572         {
    573             if (!is_object($class))
    574             {
    575                 if (!class_exists($class))
    576                 {
    577                     if (   is_null($component)
    578                         || !$_MIDCOM->componentloader->load_graceful($component))
    579                     {
    580                         debug_push_class(__CLASS__, __FUNCTION__);
    581                         debug_add("can_user_do check to undefined class '{$class}'.", MIDCOM_LOG_ERROR);
    582                         debug_pop();
    583                         return false;
    584                     }
    585                 }
    586 
    587                 $tmp_object = new $class();
    588             }
    589             else
    590             {
    591                 $tmp_object = $class;
    592             }
    593             $this->_load_class_magic_privileges($tmp_object);
    594         }
    595         else
    596         {
    597             $tmp_object = null;
    598         }
    599 
    600         if (is_null($user))
    601         {
    602             $user_privileges = Array();
    603             $user_per_class_privileges = Array();
    604             if ($tmp_object !== null)
    605             {
    606                 if (!isset($tmp_object->__mgdschema_class_name__))
    607                 {
    608                     $tmp_class_name = get_class($tmp_object);
    609                 }
    610                 else
    611                 {
    612                     $tmp_class_name = $tmp_object->__mgdschema_class_name__;
    613                 }
    614 
    615                 $default_magic_class_privileges = array_merge
    616                 (
    617                     self::$_default_magic_class_privileges[$tmp_class_name]['EVERYONE'],
    618                     self::$_default_magic_class_privileges[$tmp_class_name]['ANONYMOUS']
    619                 );
    620             }
    621         }
    622         else
    623         {
    624             $user_privileges = $user->get_privileges();
    625             if ($tmp_object === null)
    626             {
    627                 $user_per_class_privileges = array();
    628             }
    629             else
    630             {
    631                 if (!isset($tmp_object->__mgdschema_class_name__))
    632                 {
    633                     $tmp_class_name = get_class($tmp_object);
    634                 }
    635                 else
    636                 {
    637                     $tmp_class_name = $tmp_object->__mgdschema_class_name__;
    638                 }
    639 
    640                 $user_per_class_privileges = $user->get_per_class_privileges($tmp_object);
    641                 $default_magic_class_privileges = array_merge
    642                 (
    643                     self::$_default_magic_class_privileges[$tmp_class_name]['EVERYONE'],
    644                     self::$_default_magic_class_privileges[$tmp_class_name]['USERS']
    645                 );
    646             }
    647         }
    648 
    649         // Remember to synchronize this merging chain with the one in get_privileges();
    650         $full_privileges = array_merge
    651         (
    652             self::$_default_privileges,
    653             $default_magic_class_privileges,
    654             $user_privileges,
    655             $user_per_class_privileges
    656         );
    657 
    658         // Check for Ownership:
    659         if ($full_privileges['midgard:owner'] == MIDCOM_PRIVILEGE_ALLOW)
    660         {
    661             $full_privileges = array_merge
    662             (
    663                 $full_privileges,
    664                 $_MIDCOM->auth->get_owner_default_privileges()
    665             );
    666         }
    667 
    668         if (! array_key_exists($privilege, $full_privileges))
    669         {
    670             debug_push_class(__CLASS__, __FUNCTION__);
    671             debug_add("Warning, the privilege {$privilege} is unknown at this point. Assuming not granted privilege.");
    672             debug_pop();
    673             return false;
    674         }
    675 
    676         return ($full_privileges[$privilege] == MIDCOM_PRIVILEGE_ALLOW);
    677     }
    678 
    679     /**
    680      * This internal helper checks if a privilege is available during internal
    681      * sudo mode, as outlined in the corresponding variable.
    682      *
    683      * @param string $privilege The privilege to check for
    684      * @return boolean True if the privilege has been granted, false otherwise.
    685      * @access private
    686      * @see $_internal_sudo
    687      */
    688     private function _can_do_internal_sudo($privilege)
    689     {
    690         switch($privilege)
    691         {
    692             case 'midgard:create':
    693             case 'midgard:update':
    694             case 'midgard:delete':
    695             case 'midgard:privileges':
    696                 // We do not allow this, for security reasons.
    697                 return false;
    698 
    699             default:
    700                 // allow everything else.
    701                 return true;
    702         }
    703     }
    704 
    705     /**
    706      * Determine the user identifier for accessing the privilege cache. This is the passed user's
    707      * identifier with the current user and anonymous as fallback
    708      *
    709      * @param mixed $user The user to check for as string or object.
    710      * @return string The identifier
    711      */
    712     public function get_user_id($user = null)
    713     {
    714         $user_id = 'ANONYMOUS';
    715 
    716         // TODO: Clean if/else shorthands, make sure this works correctly for magic assignees as well
    717         if (is_null($user))
    718         {
    719             $user = $this->auth->user;
    720 
    721             if (!empty($user))
    722             {
    723                 $user_id = $user->id;
    724             }
    725         }
    726         else if (is_string($user))
    727         {
    728             if ($user != 'EVERYONE'
    729                 && (    mgd_is_guid($user)
    730                     || is_numeric($user)))
    731             {
    732                 $user = $this->auth->get_user($user);
    733                 $user_id = $user->id;
    734             }
    735             else
    736             {
    737                 $user_id = $user;
    738                 $user = null;
    739             }
    740         }
    741         else if (is_object($user))
    742         {
    743             $user_id = $user->id;
    744         }
    745         else
    746         {
    747             $user_id = $user;
    748         }
    749 
    750         return $user_id;
    751566    }
    752567
     
    768583    {
    769584        $cache_id = $user_id . '::' . $object_guid;
    770         if (array_key_exists($cache_id, self::$_privileges_cache))
    771         {
     585
     586        if (!array_key_exists($cache_id, self::$_privileges_cache))
     587        {
     588            if (   empty($object_guid)
     589                || empty($object_class))
     590            {
     591                /* No idea if there should be some special log message written */
     592                return array();
     593            }
     594
     595            if (!class_exists($object_class))
     596            {
     597                $_MIDCOM->generate_error(MIDCOM_ERRCRIT, "class '{$object_class}' does not exist");
     598                // This will exit()
     599            }
     600
    772601            $this->_load_privileges_byguid($object_guid, $object_class, $user_id);
    773602        }
    774603        return self::$_privileges_cache[$cache_id];
    775604    }
    776 
    777605
    778606    /**
     
    785613     *
    786614     * @param string $object_guid A Midgard GUID pointing to an object
    787      * @param string $object_class Class of the object in question
     615     * @param string $object_class DBA Class of the object in question
    788616     * @param string $user_id The user against which to check the privilege, defaults to the currently authenticated user.
    789617     *     You may specify "EVERYONE" instead of an object to check what an anonymous user can do.
     
    791619    private function _load_privileges_byguid($object_guid, $object_class, $user_id)
    792620    {
    793         /* No idea if there should be some special log message written */
    794         if (   empty($object_guid)
    795             || empty($object_class))
    796         {
    797             return array();
    798         }
    799 
    800         if (!class_exists($object_class))
    801         {
    802             $_MIDCOM->generate_error(MIDCOM_ERRCRIT, "class '{$object_class}' does not exist");
    803             // This will exit()
    804         }
    805 
    806         // Check for a cache Hit.
    807621        $cache_id = $user_id . '::' . $object_guid;
    808 
    809         if (array_key_exists($cache_id, self::$_privileges_cache))
    810         {
    811             return;
    812         }
    813622
    814623        self::$_privileges_cache[$cache_id] = array();
     
    818627        //debug_pop();
    819628
    820         /* FIXME! We create new instance of the same class, which means we will check privileges once again
    821          * for newly created object, which means we will create another one object once again.... and so on.
    822          * This may produce very ugly loops */
    823         $dummy_object_init = new $object_class();
    824         if ($_MIDCOM->dbclassloader->is_midcom_db_object($dummy_object_init))
    825         {
    826             $dummy_object = $dummy_object_init;
    827         }
    828         else
    829         {
    830             $dummy_object = $_MIDCOM->dbfactory->convert_midgard_to_midcom($dummy_object_init);
    831             if (is_null($dummy_object))
    832             {
    833                 debug_push_class(__CLASS__, __FUNCTION__);
    834                 debug_add('Failed to convert an object, falling back to an empty privilege set for the object in question. See debug level log for details.');
    835                 debug_pop();
    836                 return;
    837             }
    838         }
    839 
    840         $this->_load_class_magic_privileges($dummy_object);
    841         $dummy_object->__guid = $object_guid;
    842 
     629        $this->_load_class_magic_privileges($object_class);
    843630
    844631        // content privileges
    845         $content_privileges = self::_collect_content_privileges($dummy_object, $user_id);
     632        $content_privileges = self::_collect_content_privileges($object_guid, $user_id, $object_class);
    846633
    847634        $user = $this->auth->get_user($user_id);
     
    853640        {
    854641            $user_privileges = $user->get_privileges();
    855             $user_per_class_privileges = $user->get_per_class_privileges($dummy_object);
     642            $user_per_class_privileges = $this->_get_user_per_class_privileges($object_class, $user);
    856643        }
    857644        else
     
    867654        $full_privileges = array_merge(
    868655            self::$_default_privileges,
    869             self::$_default_magic_class_privileges[$dummy_object->__mgdschema_class_name__]['EVERYONE'],
    870             self::$_default_magic_class_privileges[$dummy_object->__mgdschema_class_name__][$dmcp_user],
     656            self::$_default_magic_class_privileges[$object_class]['EVERYONE'],
     657            self::$_default_magic_class_privileges[$object_class][$dmcp_user],
    871658            $user_privileges,
    872659            $user_per_class_privileges,
     
    902689     *
    903690     * @access private
    904      * @param mixed &$arg A reference to the GUID or the full object instance for which we should load privileges.
     691     * @param $guid The GUID for which we should load privileges.
    905692     * @param string $user_id The MidCOM user assignee for which we should collect the privileges.
     693     * @param $class The DBA classname
    906694     * @return Array An array of privilege_name => privilege_value pairs valid for the given user.
    907695     * @static
    908696     */
    909     private static function _collect_content_privileges($arg, $user_id)
    910     {
    911         // set $object and $guid
    912         if (mgd_is_guid($arg))
    913         {
    914             $object = null;
    915             $guid = $arg;
    916         }
    917         elseif (is_object($arg))
    918         {
    919             $object = $arg;
    920             $guid = null;
    921 
    922             if (   isset($object->guid)
    923                 && mgd_is_guid($object->guid))
    924             {
    925                 $guid = $object->guid;
    926             }
    927             elseif (   isset($object->__guid)
    928                     && mgd_is_guid($object->__guid))
    929             {
    930                 $guid = $object->__guid;
    931             }
    932         }
    933 
    934         // guid not found => err
    935         if ($guid === null)
    936         {
    937             return array();
    938         }
    939 
     697    private static function _collect_content_privileges($guid, $user_id, $class = null)
     698    {
    940699        static $cached_collected_privileges = array();
    941700
     
    957716        $_MIDCOM->auth->acl->_internal_sudo = true;
    958717
    959         // We need to be careful here in case we have non-persistent objects.
    960         if ($object !== null)
    961         {
    962             $parent_class = $object->get_dba_parent_class();
    963             $parent_guid = $_MIDCOM->dbfactory->get_parent_guid($guid, get_class($object));
    964         }
    965         else
    966         {
    967             $parent_class = null;
    968             $parent_guid = $_MIDCOM->dbfactory->get_parent_guid($guid);
    969         }
     718        $parent_guid = $_MIDCOM->dbfactory->get_parent_guid($guid, $class);
    970719
    971720        $_MIDCOM->auth->acl->_internal_sudo = $previous_sudo;
    972721        // <== out of SUDO
    973722
    974         if (   $parent_guid === null
    975             || $parent_guid == $guid)
     723        if (   $parent_guid == $guid
     724            || !mgd_is_guid($parent_guid))
    976725        {
    977726            $base_privileges = array();
    978727        }
    979         elseif ($parent_class === null)
     728        else
    980729        {
    981730            // recursion
    982731            $base_privileges = self::_collect_content_privileges($parent_guid, $user_id);
    983         }
    984         else
    985         {
    986             $parent_dummy_object = new $parent_class();
    987             $parent_dummy_object->__guid = $parent_guid;
    988 
    989             // recursion
    990             $base_privileges = self::_collect_content_privileges($parent_dummy_object, $user_id);
    991732        }
    992733
     
    1108849    }
    1109850
     851    function can_do_byclass($privilege, $user, $class, $component)
     852    {
     853        if ($this->_internal_sudo)
     854        {
     855            debug_push_class(__CLASS__, __FUNCTION__);
     856            debug_add('INTERNAL SUDO mode is enabled. Generic Read-Only mode set.', MIDCOM_LOG_DEBUG);
     857            debug_pop();
     858            return $this->_can_do_internal_sudo($privilege);
     859        }
     860
     861        // Initialize this one to be sure to have it.
     862        $default_magic_class_privileges = Array();
     863
     864        if ($class !== null)
     865        {
     866            if (!is_object($class))
     867            {
     868                if (!class_exists($class))
     869                {
     870                    if (   is_null($component)
     871                        || !$_MIDCOM->componentloader->load_graceful($component))
     872                    {
     873                        debug_push_class(__CLASS__, __FUNCTION__);
     874                        debug_add("can_user_do check to undefined class '{$class}'.", MIDCOM_LOG_ERROR);
     875                        debug_pop();
     876                        return false;
     877                    }
     878                }
     879
     880                $tmp_object = new $class();
     881            }
     882            else
     883            {
     884                $tmp_object = $class;
     885                $class = get_class($tmp_object);
     886            }
     887            $this->_load_class_magic_privileges($class);
     888        }
     889        else
     890        {
     891            $tmp_object = null;
     892        }
     893
     894        if (is_null($user))
     895        {
     896            $user_privileges = Array();
     897            $user_per_class_privileges = Array();
     898            if ($tmp_object !== null)
     899            {
     900                $default_magic_class_privileges = array_merge
     901                (
     902                    self::$_default_magic_class_privileges[$class]['EVERYONE'],
     903                    self::$_default_magic_class_privileges[$class]['ANONYMOUS']
     904                );
     905            }
     906        }
     907        else
     908        {
     909            $user_privileges = $user->get_privileges();
     910            if ($tmp_object === null)
     911            {
     912                $user_per_class_privileges = array();
     913            }
     914            else
     915            {
     916                $user_per_class_privileges = $user->get_per_class_privileges($tmp_object);
     917                $default_magic_class_privileges = array_merge
     918                (
     919                    self::$_default_magic_class_privileges[$class]['EVERYONE'],
     920                    self::$_default_magic_class_privileges[$class]['USERS']
     921                );
     922            }
     923        }
     924
     925        // Remember to synchronize this merging chain with the one in get_privileges();
     926        $full_privileges = array_merge
     927        (
     928            self::$_default_privileges,
     929            $default_magic_class_privileges,
     930            $user_privileges,
     931            $user_per_class_privileges
     932        );
     933
     934        // Check for Ownership:
     935        if ($full_privileges['midgard:owner'] == MIDCOM_PRIVILEGE_ALLOW)
     936        {
     937            $full_privileges = array_merge
     938            (
     939                $full_privileges,
     940                $_MIDCOM->auth->get_owner_default_privileges()
     941            );
     942        }
     943
     944        if (! array_key_exists($privilege, $full_privileges))
     945        {
     946            debug_push_class(__CLASS__, __FUNCTION__);
     947            debug_add("Warning, the privilege {$privilege} is unknown at this point. Assuming not granted privilege.");
     948            debug_pop();
     949            return false;
     950        }
     951
     952        return ($full_privileges[$privilege] == MIDCOM_PRIVILEGE_ALLOW);
     953    }
     954
     955    /**
     956     * Checks whether a user has a certain privilege on the given (via guid and class) content object.
     957     * Works on the currently authenticated user by default, but can take another
     958     * user as an optional argument.
     959     *
     960     * @param string $privilege The privilege to check for
     961     * @param string $object_guid A Midgard GUID pointing to an object
     962     * @param string $object_class Class of the object in question
     963     * @param string $user_id The user against which to check the privilege, defaults to the currently authenticated user.
     964     *     You may specify "EVERYONE" instead of an object to check what an anonymous user can do.
     965     * @return boolean True if the privilege has been granted, false otherwise.
     966     */
     967    function can_do_byguid($privilege, $object_guid, $object_class, $user_id)
     968    {
     969        if ($this->_internal_sudo)
     970        {
     971            //debug_push_class(__CLASS__, __FUNCTION__);
     972            //debug_add('INTERNAL SUDO mode is enabled. Generic Read-Only mode set.', MIDCOM_LOG_DEBUG);
     973            //debug_pop();
     974            return $this->_can_do_internal_sudo($privilege);
     975        }
     976
     977        if ($this->auth->_component_sudo)
     978        {
     979            return true;
     980        }
     981
     982        $cache_key = "{$user_id}::{$object_guid}";
     983
     984        if (!isset(self::$_privileges_cache[$cache_key]))
     985        {
     986            self::$_privileges_cache[$cache_key] = array();
     987        }
     988
     989        if (isset(self::$_privileges_cache[$cache_key][$privilege]))
     990        {
     991            return self::$_privileges_cache[$cache_key][$privilege];
     992        }
     993
     994        //debug_push_class(__CLASS__, __FUNCTION__);
     995        //debug_add("Cache {$privilege_key} miss, fetching privileges for {$object_guid}");
     996        //debug_pop();
     997
     998        if (self::_load_content_privilege($privilege, $object_guid, $object_class, $user_id))
     999        {
     1000            return self::$_privileges_cache[$cache_key][$privilege];
     1001        }
     1002
     1003        $user = $this->auth->get_user($user_id);
     1004
     1005        // user privileges
     1006        if (   is_object($user)
     1007            && method_exists($user, 'get_privileges')
     1008            && method_exists($user, 'get_per_class_privileges'))
     1009        {
     1010            $user_per_class_privileges = $this->_get_user_per_class_privileges($object_class, $user);
     1011
     1012            if (array_key_exists($privilege, $user_per_class_privileges))
     1013            {
     1014                self::$_privileges_cache[$cache_key][$privilege] = ($user_per_class_privileges[$privilege] == MIDCOM_PRIVILEGE_ALLOW);
     1015                return self::$_privileges_cache[$cache_key][$privilege];
     1016            }
     1017
     1018            $user_privileges = $user->get_privileges();
     1019
     1020            if (array_key_exists($privilege, $user_privileges))
     1021            {
     1022                self::$_privileges_cache[$cache_key][$privilege] = ($user_privileges[$privilege] == MIDCOM_PRIVILEGE_ALLOW);
     1023                return self::$_privileges_cache[$cache_key][$privilege];
     1024            }
     1025        }
     1026
     1027        $this->_load_class_magic_privileges($object_class);
     1028
     1029        // default magic class privileges user
     1030        $dmcp_user = is_null($this->auth->user) ? 'ANONYMOUS' : 'USERS';
     1031
     1032        if (array_key_exists($privilege, self::$_default_magic_class_privileges[$object_class][$dmcp_user]))
     1033        {
     1034            self::$_privileges_cache[$cache_key][$privilege] = (self::$_default_magic_class_privileges[$object_class][$dmcp_user][$privilege] == MIDCOM_PRIVILEGE_ALLOW);
     1035            return self::$_privileges_cache[$cache_key][$privilege];
     1036        }
     1037
     1038        if (array_key_exists($privilege, self::$_default_magic_class_privileges[$object_class]['EVERYONE']))
     1039        {
     1040            self::$_privileges_cache[$cache_key][$privilege] = (self::$_default_magic_class_privileges[$object_class]['EVERYONE'][$privilege] == MIDCOM_PRIVILEGE_ALLOW);
     1041            return self::$_privileges_cache[$cache_key][$privilege];
     1042        }
     1043
     1044        if (array_key_exists($privilege, self::$_default_privileges))
     1045        {
     1046            self::$_privileges_cache[$cache_key][$privilege] = (self::$_default_privileges[$privilege] == MIDCOM_PRIVILEGE_ALLOW);
     1047            return self::$_privileges_cache[$cache_key][$privilege];
     1048        }
     1049
     1050        debug_push_class(__CLASS__, __FUNCTION__);
     1051        debug_add("The privilege {$privilege} is unknown at this point. Assuming not granted privilege.", MIDCOM_LOG_WARN);
     1052        debug_pop();
     1053        return false;
     1054    }
     1055
     1056    /**
     1057     * Look up a specific content privilege and cache the result. This implements the same semantics
     1058     * as _collect_content_privileges, but only works for one privilege at a time, which allows us to cut
     1059     * a few corners and therefore be faster
     1060     *
     1061     * @param string $privilegename The privilege to check for
     1062     * @param string $object_guid A Midgard GUID pointing to an object
     1063     * @param string $object_class DBA Class of the object in question
     1064     * @param string $user_id The user against which to check the privilege, defaults to the currently authenticated user.
     1065     * @return boolean True when privilege was found, otherwise false
     1066     */
     1067    private static function _load_content_privilege($privilegename, $guid, $class, $user_id)
     1068    {
     1069        $cache_id = $user_id . '::' . $guid;
     1070
     1071        if (array_key_exists($privilegename, self::$_privileges_cache[$cache_id]))
     1072        {
     1073            return true;
     1074        }
     1075
     1076        $object_privileges = midcom_core_privilege::get_content_privileges($guid);
     1077
     1078        $last_scope = -1;
     1079        $last_owner_scope = -1;
     1080        $content_privilege = null;
     1081
     1082        foreach ($object_privileges as $privilege)
     1083        {
     1084            if (   $privilege->privilegename != $privilegename
     1085                ||  $privilege->scope <= $last_scope
     1086                || !$privilege->does_privilege_apply($user_id))
     1087            {
     1088                continue;
     1089            }
     1090
     1091            $last_scope = $privilege->scope;
     1092            $content_privilege = $privilege;
     1093        }
     1094
     1095        //owner privileges override everything but person privileges, so we have to cross-check those here
     1096        if (   $privilegename != 'midgard:owner'
     1097            && $last_scope < MIDCOM_PRIVILEGE_SCOPE_OWNER)
     1098        {
     1099            $owner_privileges = $_MIDCOM->auth->acl->get_owner_default_privileges();
     1100            if (array_key_exists($privilegename, $owner_privileges))
     1101            {
     1102                $found = self::_load_content_privilege('midgard:owner', $guid, $class, $user_id);
     1103                if (    $found
     1104                     && self::$_privileges_cache[$cache_id]['midgard:owner'])
     1105                {
     1106                    self::$_privileges_cache[$cache_id][$privilegename] = $owner_privileges[$privilegename];
     1107                    return true;
     1108                }
     1109            }
     1110        }
     1111
     1112        if (!is_null($content_privilege))
     1113        {
     1114            self::$_privileges_cache[$cache_id][$privilegename] = ($content_privilege->value == MIDCOM_PRIVILEGE_ALLOW);
     1115            return true;
     1116        }
     1117
     1118        //if nothing was found, we try to recurse to parent
     1119
     1120        // ==> into SUDO
     1121        $previous_sudo = $_MIDCOM->auth->acl->_internal_sudo;
     1122        $_MIDCOM->auth->acl->_internal_sudo = true;
     1123
     1124        $parent_guid = $_MIDCOM->dbfactory->get_parent_guid($guid, $class);
     1125
     1126        $_MIDCOM->auth->acl->_internal_sudo = $previous_sudo;
     1127        // <== out of SUDO
     1128
     1129        if (   $parent_guid == $guid
     1130            || !mgd_is_guid($parent_guid))
     1131        {
     1132            return false;
     1133        }
     1134        else
     1135        {
     1136            $parent_cache_id = $user_id . '::' . $parent_guid;
     1137            if (!array_key_exists($parent_cache_id, self::$_privileges_cache))
     1138            {
     1139                self::$_privileges_cache[$parent_cache_id] = array();
     1140            }
     1141
     1142            if (self::_load_content_privilege($privilegename, $parent_guid, null, $user_id))
     1143            {
     1144                self::$_privileges_cache[$cache_id][$privilegename] = self::$_privileges_cache[$parent_cache_id][$privilegename];
     1145                return true;
     1146            }
     1147            return false;
     1148        }
     1149    }
     1150
     1151    /**
     1152     * This internal helper checks if a privilege is available during internal
     1153     * sudo mode, as outlined in the corresponding variable.
     1154     *
     1155     * @param string $privilege The privilege to check for
     1156     * @return boolean True if the privilege has been granted, false otherwise.
     1157     * @access private
     1158     * @see $_internal_sudo
     1159     */
     1160    private function _can_do_internal_sudo($privilege)
     1161    {
     1162        switch($privilege)
     1163        {
     1164            case 'midgard:create':
     1165            case 'midgard:update':
     1166            case 'midgard:delete':
     1167            case 'midgard:privileges':
     1168                // We do not allow this, for security reasons.
     1169                return false;
     1170
     1171            default:
     1172                // allow everything else.
     1173                return true;
     1174        }
     1175    }
     1176
    11101177}
    11111178
  • branches/ragnaroek/midcom/midcom.core/midcom/services/cache/backend/memcached.php

    r24868 r26439  
    7070
    7171    /**
    72      * The constructor is empty yet.
     72     * We use persistant connections, so we let midcom assume the read/write
     73     * connection is always open
    7374     */
    7475    function __construct()
    7576    {
    7677        parent::__construct();
    77         // Nothing to do.
     78
     79        $this->_open_for_reading = true;
     80        $this->_open_for_writing = true;
    7881    }
    7982
Note: See TracChangeset for help on using the changeset viewer.