Changeset 26289


Ignore:
Timestamp:
06/07/10 11:44:37 (7 years ago)
Author:
flack
Message:

move lowlevel ACL code into its own class for better maintainability, refs #1848

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

Legend:

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

    r26287 r26289  
    203203        if (!$_MIDCOM->auth->admin)
    204204        {
    205             $this->_user_id = $_MIDCOM->auth->get_user_id();
     205            $this->_user_id = $_MIDCOM->auth->acl->get_user_id();
    206206        }
    207207
     
    288288        {
    289289            if (    $this->_user_id
    290                 && !$_MIDCOM->auth->can_do_byguid('midgard:read', $object_guid, $classname, $this->_user_id))
     290                && !$_MIDCOM->auth->acl->can_do_byguid('midgard:read', $object_guid, $classname, $this->_user_id))
    291291            {
    292292                debug_add("Failed to load result, read privilege on {$object_guid} not granted for the current user.", MIDCOM_LOG_INFO);
     
    334334        $classname = $this->_real_class;
    335335
    336         $user_id = false;
    337         if (!$_MIDCOM->auth->admin)
    338         {
    339             $user_id = $_MIDCOM->auth->get_user_id();
    340         }
    341 
    342336        foreach ($result as $object_guid => $empty_copy)
    343337        {
     
    350344
    351345            if (    $this->_user_id
    352                 && !$_MIDCOM->auth->can_do_byguid('midgard:read', $object_guid, $classname, $this->_user_id))
     346                && !$_MIDCOM->auth->acl->can_do_byguid('midgard:read', $object_guid, $classname, $this->_user_id))
    353347            {
    354348                debug_add("Failed to load result, read privilege on {$object_guid} not granted for the current user.", MIDCOM_LOG_INFO);
     
    389383    {
    390384        if (   $this->_user_id
    391             && !$_MIDCOM->auth->can_do_byguid('midgard:read', $key, $this->_real_class, $this->_user_id))
     385            && !$_MIDCOM->auth->acl->can_do_byguid('midgard:read', $key, $this->_real_class, $this->_user_id))
    392386        {
    393387            midcom_application::set_error(MGD_ERR_ACCESS_DENIED);
     
    400394    {
    401395        if (   $this->_user_id
    402             && !$_MIDCOM->auth->can_do_byguid('midgard:read', $key, $this->_real_class, $this->_user_id))
     396            && !$_MIDCOM->auth->acl->can_do_byguid('midgard:read', $key, $this->_real_class, $this->_user_id))
    403397        {
    404398            midcom_application::set_error(MGD_ERR_ACCESS_DENIED);
  • branches/ragnaroek/midcom/midcom.core/midcom/core/privilege.php

    r26285 r26289  
    268268    {
    269269        // 1. Privilege name
    270         if (! $_MIDCOM->auth->privilege_exists($this->privilegename))
     270        if (! $_MIDCOM->auth->acl->privilege_exists($this->privilegename))
    271271        {
    272272            debug_push_class(__CLASS__, __FUNCTION__);
    273273            debug_add("The privilege name '{$this->privilegename}' is unknown to the system. Perhaps the corresponding component is not loaded?",
    274274                MIDCOM_LOG_INFO);
    275             debug_print_r('Available privileges:', $_MIDCOM->auth->_default_privileges);
    276275            debug_pop();
    277276            return false;
     
    707706        // assigned to a single object.
    708707        $valid_privileges = array();
    709         $valid_privileges[MIDCOM_PRIVILEGE_SCOPE_OWNER] = $_MIDCOM->auth->get_owner_default_privileges();
     708        $valid_privileges[MIDCOM_PRIVILEGE_SCOPE_OWNER] = $_MIDCOM->auth->acl->get_owner_default_privileges();
    710709
    711710        $object_privileges = self::get_content_privileges($guid);
  • branches/ragnaroek/midcom/midcom.core/midcom/helper/_componentloader.php

    r25680 r26289  
    214214    {
    215215        $GLOBALS['midcom_errstr'] = '';
    216                        
     216
    217217        if (empty($path))
    218218        {
     
    560560            {
    561561                $manifest_data = file_get_contents($filename);
    562                
     562
    563563                $this->_add_class_definitions($manifest_data, $directory);
    564564
    565565                $code .= "\$_MIDCOM->componentloader->load_manifest(
    566                     new midcom_core_manifest(   
     566                    new midcom_core_manifest(
    567567                    '{$filename}', array({$manifest_data})));\n";
    568568            }
     
    617617            $manifest_data = preg_replace($search, "$1 => array\n(\n" . $definitions . ")\n", $manifest_data);
    618618        }
    619        
     619
    620620
    621621    }
     
    638638
    639639        // Register Privileges
    640         $_MIDCOM->auth->register_default_privileges($manifest->privileges);
     640        $_MIDCOM->auth->acl->register_default_privileges($manifest->privileges);
    641641
    642642        // Register watches
     
    879879                continue;
    880880            }
    881            
     881
    882882            if ($dependency == 'midcom')
    883883            {
     
    885885                continue;
    886886            }
    887            
     887
    888888            $dependencies[] = $dependency;
    889889            $subdependencies = $this->get_component_dependencies($dependency);
     
    10051005            return $this->manifests[$component]->_raw_data['icon'];
    10061006        }
    1007        
     1007
    10081008        if (!$provide_fallback)
    10091009        {
  • branches/ragnaroek/midcom/midcom.core/midcom/services/auth.php

    r26287 r26289  
    1111 * Main Authentication/Authorization service class, it provides means to authenticate
    1212 * users and to check for permissions.
    13  *
    14  * Unless further qualified, "Midgard Content Objects" can be either pre-mgdschema
    15  * or mgdschema objects. The only necessary constraint is that a MidCOM base class
    16  * (midgard_baseclasses_database_*) must be available.
    17  *
    18  * This implementation is based on the general idea outlined in mRFC 15
    19  * ( http://www.midgard-project.org/development/mrfc/0015/ ),
    20  * MidCOM Authentication and Access Control service. <i>Developers Note:</i> Be aware that
    21  * the basic requirements for the ACL system undergone a major chance during the implementation,
    22  * as the DBA layer with full access control even for database I/O was added. The proposals
    23  * from the mRFC are largely outdated therefore. What is documented on the main MidCOM
    24  * documentation has to take priority obviously.
    25  *
    26  * <b>Privilege definition</b>
    27  *
    28  * Privileges are represented by the class midcom_core_privilege and basically consist
    29  * of three parts: Name, Assignee and Value:
    30  *
    31  * The privilege name is a unique identifier for the privilege. The mRFC 15 defines the
    32  * syntax to be $component:$name, where $component is either the name of the component
    33  * or one of 'midgard' or 'midcom' for core privileges. Valid privilege names are for
    34  * example 'net.nehmer.static:do_something' or 'midgard:update'.
    35  *
    36  * The assignee is the entity to which the privilege applies, this can be one of several
    37  * things, depending on where the privilege is taken into effect, I'll explain this below
    38  * in more detail:
    39  *
    40  * On content objects (generally every object in the system used during 'normal operation'):
    41  *
    42  * - A Midgard User encapsulated by a midcom_core_user object.
    43  * - A Midgard Group encapsulated by a midcom_core_group object or subtype thereof.
    44  * - The magic assignee 'EVERYONE', which applies the privilege to every user unconditionally,
    45  *   even to unauthenticated users.
    46  * - The magic assignee 'USERS', which applies to all authenticated users.
    47  * - The magic assignee 'ANONYMOUS, which applies to all unauthenticated users.
    48  * - The magic assignee 'OWNER', which applies for all object owners.
    49  *
    50  * On users and groups during authentication (when building the basic privilege set for the user,
    51  * which applies generally):
    52  *
    53  * - The magic string 'SELF', which denotes that the privilege is set for the user in general for
    54  *   every content object. SELF privileges may be restricted to a class by using the classname
    55  *   property available at both midcom_core_privilege and various DBA interface functions.
    56  *
    57  * The value is one of MIDCOM_PRIVILEGE_ALLOW or MIDCOM_PRIVILEGE_DENY, which either grants or
    58  * revokes a privilege. Be aware, that unsetting a privilege does not set it to MIDCOM_PRIVILEGE_DENY,
    59  * but clears the entry completely, which means that the privilege value inherited from the parents
    60  * is now in effect.
    61  *
    62  * <b>How are privileges read and merged</b>
    63  *
    64  * First, you have to understand, that there are actually three distinct sources where a privilege
    65  * comes from: The systemwide defaults, the currently authenticated user and the content object
    66  * which is being operated on. We'll look into this distinction first, before we get on to the order
    67  * in which they are merged.
    68  *
    69  * <i>Systemwide default privileges</i>
    70  *
    71  * This is analogous to the MidCOM default configuration, they are taken into account globally to each
    72  * and every check whether a privilege is granted. Whenever a privilege is defined, there is also a
    73  * default value (either ALLOW or DENY) assigned to it. They serve as a basis for all privilege sets
    74  * and ensure, that there is a value set for all privileges.
    75  *
    76  * These defaults are defined by the MidCOM core and the components respectively and are very restrictive,
    77  * basically granting read-only access to all non sensitive information.
    78  *
    79  * Currently, there is no way to influence these privileges unless you are a developer and writing new
    80  * components.
    81  *
    82  * <i>Class specific, systemwide default privileges (for magic assignees only)</i>
    83  *
    84  * Often you want to have a number of default privileges for certain classes in general. For regular
    85  * users/groups you can easily assign them to the corresponding users/groups, there is one special
    86  * case which cannot be covered there at this time: You cannot set defaults applicable for the magic
    87  * assignees EVERYONE, USERS and ANONYMOUS. This is normally only of interest for component authors,
    88  * which want to have some special privileges assigned for their objects, where the global defaults
    89  * do no longer suffice.
    90  *
    91  * These privileges are queried using a static callback of the DBA classes in question, see the following
    92  * example:
    93  *
    94  * <code>
    95  * function get_class_magic_default_privileges()
    96  * {
    97  *     return Array (
    98  *         'EVERYONE' => Array(),
    99  *         'ANONYMOUS' => Array(),
    100  *         'USERS' => Array('midcom:create' => MIDCOM_PRIVILEGE_ALLOW)
    101  *     );
    102  * }
    103  * </code>
    104  *
    105  * See also the documentation of the $_default_magic_class_privileges member for further details.
    106  *
    107  * <i>User / Group specific privileges</i>
    108  *
    109  * This kind of privileges are rights, assigned directly to a user. Similar to the systemwide defaults,
    110  * they too apply to any operation done by the user / group respectively throughout the system. The magic
    111  * assignee SELF is used to denote such privileges, which can obviously only be assigned to users or
    112  * groups. These privileges are loaded at the time of user authentication only.
    113  *
    114  * You should use these privileges carefully, due to their global nature. If you assign the privilege
    115  * midgard:delete to a user, this means that the user can now delete all objects he can read, unless
    116  * there are again restricting privileges set to content objects.
    117  *
    118  * To be more flexible in the control over the top level objects, you may add a classname which restricts
    119  * the validity of the privilege to a class and all of its descendants.
    120  *
    121  * <i>Content object privileges</i>
    122  *
    123  * This is the kind of privilege that will be used most often. They are associated with any content
    124  * object in the system, and are read on every access to a content object. As you can see in the
    125  * introduction, you have the most flexibility here.
    126  *
    127  * The basic idea is, that you can assign privileges based on the combination of users/groups and
    128  * content objects. In other words, you can say the user x has the privilege midgard:update for
    129  * this object (and its descendants) only. This works with (virtual) groups as well.
    130  *
    131  * The possible assignees here are either a user, a group or one of the magic assignees EVERYONE,
    132  * USERS or ANONYMOuS, as outlined above.
    133  *
    134  * Be aware, that Midgard Persons and Groups count as content object when loaded from the database
    135  * in a tool like net.nemein.personnel, as the groups are not used for authentication but for
    136  * regular site operation there. Therefore, the SELF privileges mentioned above are not taken into
    137  * account when determining the content object privileges!
    138  *
    139  * <i>Privilege merging</i>
    140  *
    141  * This is, where we get to the guts of privileges, as this is not trivial (but nevertheless
    142  * straight-forward I hope). The general idea is based on the scope of object a privilege applies:
    143  *
    144  * System default privileges obviously have the largest scope, they apply to everyone. The next
    145  * smaller scope are privileges which are assigned to groups in general, followed by privileges
    146  * assigned directly to a user.
    147  *
    148  * From this point on, the privileges of the content objects are next in line, starting at the
    149  * top-level objects again (for example a root topic). The smallest scope finally then has the
    150  * object that is being accessed itself.
    151  *
    152  * Let us visualize this a bit:
    153  *
    154  * <pre>
    155  * ^ larger scope     System default privileges
    156  * |                  Class specific magic assignee default privileges
    157  * |                  Root Midgard group
    158  * |                  ... more parent Midgard groups ...
    159  * |                  Direct Midgard group membership
    160  * |                  Virtual group memberships
    161  * |                  User
    162  * |                  SELF privileges limited to a class
    163  * |                  Root content object
    164  * |                  ... more parent objects ...
    165  * v smaller scope    Accessed content object
    166  * </pre>
    167  *
    168  * Privileges assigned to a specific user always override owner privileges; owner privileges are
    169  * calculated on a per-content-object bases, and are merged just before the final user privileges are
    170  * merged into the privilege set. It is of no importance from where you get ownership at that point.
    171  *
    172  * Implementation notes: Internally, MidCOM separates the "user privilege set" which is everything
    173  * down to the line User above, and the content object privileges, which constitutes of the rest.
    174  * This separation has been done for performance reasons, as the user's privileges are loaded
    175  * immediately upon authentication of the user, and the privileges of the actual content objects
    176  * are merged into this set then. Normally, this should be of no importance for ACL users, but it
    177  * explains the more complex graph in the original mRFC.
    178  *
    179  * <b>Predefined Privileges</b>
    180  *
    181  * The MidCOM core defines a set of core privileges, which fall in two categories:
    182  *
    183  * <i>Midgard Core Privileges</i>
    184  *
    185  * These privileges are part of the MidCOM Database Abstraction layer (MidCOM DBA) and have been
    186  * originally proposed by me in a mail to the Midgard developers list. They will move into the
    187  * core level eventually, but for the time being MidCOM will control them. Unless otherwise noted,
    188  * all privileges are denied by default and no difference between owner and normal default privileges
    189  * is made.
    190  *
    191  * - <i>midgard:read</i> controls read access to the object, if denied, you cannot load the object
    192  *   from the database. This privilege is granted by default, and supersedes the current ViewerGroups
    193  *   implementation.
    194  * - <i>midgard:update</i> controls updating of objects. Be aware, that you need to be able to read
    195  *   the object before updating it, it is granted by default only for owners.
    196  * - <i>midgard:delete</i> controls deletion of objects. Be aware, that you need to be able to read
    197  *   the object before updating it, it is granted by default only for owners.
    198  * - <i>midgard:create</i> allows you to create new content objects as children on whatever content
    199  *   object that you have the create privilege for. This means, you can create an article if and only
    200  *   if you have create permission for either the parent article (if you create a so-called 'reply
    201  *   article') or the parent topic, it is granted by default only for owners.
    202  * - <i>midgard:parameters</i> allows the manipulation of parameters on the current object if and
    203  *   only if the user also has the midgard:update privilege on the object. This privileges is granted
    204  *   by default and covers the full set of parameter operations (create, update and delete).
    205  * - <i>midgard:attachments</i> is analogous to midgard:parameters but covers attachments instead
    206  *   and is also granted by default.
    207  * - <i>midgard:autoserve_attachment</i> controls, whether an attachment may be autoserved using
    208  *   the midcom-serveattachment handler. This is granted by default, allowing every attachment
    209  *   to be served using the default URL methods. Denying this right allows component authors to
    210  *   build more sophisticated access control restrictions to attachments.
    211  * - <i>midgard:privileges</i> allows the user to change the permissions on the objects they are
    212  *   granted for. You also need midgard:update and midgard:parameters to properly execute these
    213  *   operations.
    214  * - <i>midgard:owner</i> indicates that the user who has this privilege set is an owner of the
    215  *   given content object.
    216  *
    217  * <i>MidCOM Core Privileges</i>
    218  *
    219  * - <i>midcom:approve</i> grants the user the right to approve or unapprove objects.
    220  * - <i>midcom:component_config</i> grants the user access to configuration management system,
    221  *   it is granted by default only for owners.
    222  * - <i>midcom:isonline</i> is needed to see the online state of another user. It is not granted
    223  *   by default.
    224  * - <i>midcom:vgroup_register</i> allows the user to add virtual groups to the system. This
    225  *   privilege is granted by default.
    226  * - <i>midcom:vgroup_delete</i> allows the user to delete virtual groups from the system. This
    227  *   privilege is granted by default.
    228  *
    229  * DEPRECATION NOTE: The vgroup registering / deletion commands will be denied in the long run
    230  * by default, for security reasons. Exact plan is not yet available though.
    231  *
    232  * <b>Assigning Privileges</b>
    233  *
    234  * You assign privileges by using the DBA set_privilege method, whose static implementation can
    235  * be found in midcom_baseclasses_core_dbobject::set_privilege(). Here is a quick overview over
    236  * that API, which naturally only works on MidCOM DBA level objects:
    237  *
    238  * - TODO: Update with the set/unset call variants
    239  * - TODO: Add get_privilege
    240  *
    241  * <pre>
    242  * Array get_privileges();
    243  * midcom_core_privilege create_new_privilege_object($name, $assignee = null, $value = MIDCOM_PRIVILEGE_ALLOW)
    244  * boolean set_privilege(midcom_core_privilege $privilege);
    245  * boolean unset_all_privileges();
    246  * boolean unset_privilege(midcom_core_privilege $privilege);
    247  * </pre>
    248  *
    249  * These calls operate only on the privileges of the given object. They do not do any merging
    250  * whatsoever, this is the job of the auth framework itself (midcom_services_auth).
    251  *
    252  * Unsetting a privilege does not deny it, but clears the privilege specification on the current
    253  * object and sets it to INHERIT internally. As you might have guessed, if you want to clear
    254  * all privileges on a given object, call unset_all_privileges() on the DBA object in question.
    255  *
    256  * See the documentation of the DBA layer for more information on these five calls.
    257  *
    258  * <b>Checking Privileges</b>
    259  *
    260  * This class overs various methods to verify the privilege state of a user, all of them prefixed
    261  * with can_* for privileges and is_* for membership checks.
    262  *
    263  * Each function is available in a simple check version, which returns true or false, and a
    264  * require_* prefixed variant, which has no return value. The require variants of these calls
    265  * instead check if the given condition is met, if yes, they return silently, otherwise they
    266  * throw an access denied error.
    26713 *
    26814 * <b>Authentication</b>
     
    31056
    31157    /**
    312      * Internal listing of all default privileges currently registered in the system. This
    313      * is a privilege name/value map.
    314      *
    315      * @todo This should be cached, as it would require loading all components by default.
    316      *     The component manifest might help here too.
    317      *
    318      * @var array
    319      * @access private
    320      */
    321     var $_default_privileges = Array();
    322 
    323     /**
    324      * Internal listing of all default owner privileges currently registered in the system.
    325      * All privileges not set in this list will be inherited. This is a privilege name/value
    326      * map.
    327      *
    328      * @todo This should be cached, as it would require loading all components by default.
    329      *     The component manifest might help here too.
    330      *
    331      * @var array
    332      * @access private
    333      */
    334     var $_owner_default_privileges = Array();
    335 
    336     /**
    337      * This listing contains all magic privileges assigned to the existing classes. It is a
    338      * multi-level array, example entry:
    339      *
    340      * <pre>
    341      * 'class_name' => Array
    342      * (
    343      *     'EVERYONE' => Array(),
    344      *     'ANONYMOUS' => Array(),
    345      *     'USERS' => Array
    346      *     (
    347      *         'midcom:create' => MIDCOM_PRIVILEGE_ALLOW,
    348      *         'midcom:update' => MIDCOM_PRIVILEGE_ALLOW
    349      *     ),
    350      * )
    351      * </pre>
    352      *
    353      * @todo This should be cached, as it would require loading all components by default.
    354      *     The component manifest might help here too.
    355      *
    356      * @var array
    357      * @access private
    358      */
    359     var $_default_magic_class_privileges = Array();
     58     * This is a reference to the ACL management system.
     59     *
     60     * @var midcom_services_auth_acl
     61     * @access public
     62     */
     63    var $acl = null;
    36064
    36165    /**
     
    38488     */
    38589    var $_user_cache = Array();
    386 
    387     /**
    388      * Internal cache of the effective privileges of users on content objects, this is
    389      * an associative array using a combination of the user identifier and the object's
    390      * guid as index. The privileges for the anonymous user use the magic
    391      * EVERYONE as user identifier.
    392      *
    393      * @var Array
    394      * @access private
    395      */
    396     private static $_privileges_cache = Array();
    39790
    39891    /**
     
    475168    {
    476169        $this->sessionmgr = new midcom_services_auth_sessionmgr($this);
     170        $this->acl = new midcom_services_auth_acl($this);
     171
    477172
    478173        // Midgard 8.09beta compatibility: ensure that Midgard's sitegroup ID is always int
     
    482177        }
    483178
    484         $this->_register_core_privileges();
    485179        $this->_initialize_user_from_midgard();
    486180        $this->_prepare_authentication_drivers();
     
    763457
    764458    /**
    765      * This internal helper will initialize the default privileges array with all core
    766      * privileges currently defined.
    767      *
    768      * @see $_default_privileges
    769      * @access protected
    770      */
    771     function _register_core_privileges()
    772     {
    773         $this->register_default_privileges(
    774             Array
    775             (
    776                 // Midgard core level privileges
    777                 'midgard:update' => Array (MIDCOM_PRIVILEGE_DENY, MIDCOM_PRIVILEGE_ALLOW),
    778                 'midgard:delete' => Array (MIDCOM_PRIVILEGE_DENY, MIDCOM_PRIVILEGE_ALLOW),
    779                 'midgard:create' => Array (MIDCOM_PRIVILEGE_DENY, MIDCOM_PRIVILEGE_ALLOW),
    780                 'midgard:read' => Array (MIDCOM_PRIVILEGE_ALLOW, MIDCOM_PRIVILEGE_ALLOW),
    781                 'midgard:parameters' => Array (MIDCOM_PRIVILEGE_ALLOW, MIDCOM_PRIVILEGE_ALLOW),
    782                 'midgard:attachments' => Array (MIDCOM_PRIVILEGE_ALLOW, MIDCOM_PRIVILEGE_ALLOW),
    783                 'midgard:autoserve_attachment' => MIDCOM_PRIVILEGE_ALLOW,
    784                 'midgard:privileges' => Array (MIDCOM_PRIVILEGE_DENY, MIDCOM_PRIVILEGE_ALLOW),
    785                 'midgard:owner' => MIDCOM_PRIVILEGE_DENY,
    786 
    787                 // MidCOM core level privileges
    788                 'midcom:approve' => MIDCOM_PRIVILEGE_DENY,
    789                 'midcom:component_config' => Array (MIDCOM_PRIVILEGE_DENY, MIDCOM_PRIVILEGE_ALLOW),
    790                 'midcom:urlname' => MIDCOM_PRIVILEGE_DENY,
    791                 'midcom:isonline' => Array (MIDCOM_PRIVILEGE_DENY, MIDCOM_PRIVILEGE_ALLOW),
    792                 'midcom:vgroup_register' => MIDCOM_PRIVILEGE_ALLOW,
    793                 'midcom:vgroup_delete' => MIDCOM_PRIVILEGE_ALLOW,
    794                 'midcom:ajax' => MIDCOM_PRIVILEGE_DENY,
    795                 'midcom:centralized_toolbar' => MIDCOM_PRIVILEGE_DENY,
    796                 'midcom:unlock' => MIDCOM_PRIVILEGE_DENY,
    797             )
    798         );
    799     }
    800 
    801     /**
    802459     * This internal helper checks if a privilege is available during internal
    803460     * sudo mode, as outlined in the corresponding variable.
     
    869526        }
    870527
    871         $user_id = $this->get_user_id($user);
    872 
    873         return $this->can_do_byguid($privilege, $content_object->guid, get_class($content_object), $user_id);
    874     }
    875 
    876     /**
    877      * Checks whether a user has a certain privilege on the given (via guid and class) content object.
    878      * Works on the currently authenticated user by default, but can take another
    879      * user as an optional argument.
    880      *
    881      * @param string $privilege The privilege to check for
    882      * @param string $object_guid A Midgard GUID pointing to an object
    883      * @param string $object_class Class of the object in question
    884      * @param string $user_id The user against which to check the privilege, defaults to the currently authenticated user.
    885      *     You may specify "EVERYONE" instead of an object to check what an anonymous user can do.
    886      * @return boolean True if the privilege has been granted, false otherwise.
    887      */
    888     function can_do_byguid($privilege, $object_guid, $object_class, $user_id)
    889     {
    890         if ($this->_internal_sudo)
    891         {
    892             //debug_push_class(__CLASS__, __FUNCTION__);
    893             //debug_add('INTERNAL SUDO mode is enabled. Generic Read-Only mode set.', MIDCOM_LOG_DEBUG);
    894             //debug_pop();
    895             return $this->_can_do_internal_sudo($privilege);
    896         }
    897 
    898         if ($this->_component_sudo)
    899         {
    900             return true;
    901         }
    902 
    903         $cache_key = "{$user_id}::{$object_guid}";
    904 
    905         if (!isset(self::$_privileges_cache[$cache_key]))
    906         {
    907             //debug_push_class(__CLASS__, __FUNCTION__);
    908             //debug_add("Cache {$privilege_key} miss, fetching privileges for {$object_guid}");
    909             //debug_pop();
    910 
    911             $this->_load_privileges_byguid($object_guid, $object_class, $user_id);
    912         }
    913 
    914         if (!array_key_exists($privilege, self::$_privileges_cache[$cache_key]))
    915         {
    916             debug_push_class(__CLASS__, __FUNCTION__);
    917             debug_add("The privilege {$privilege} is unknown at this point. Assuming not granted privilege.", MIDCOM_LOG_WARN);
    918             debug_pop();
    919             return false;
    920         }
    921 
    922         return self::$_privileges_cache[$cache_key][$privilege];
     528        $user_id = $this->acl->get_user_id($user);
     529
     530        return $this->acl->can_do_byguid($privilege, $content_object->guid, get_class($content_object), $user_id);
    923531    }
    924532
     
    984592        }
    985593
    986         // Initialize this one to be sure to have it.
    987         $default_magic_class_privileges = Array();
    988 
    989         if ($class !== null)
    990         {
    991             if (!is_object($class))
    992             {
    993                 if (!class_exists($class))
    994                 {
    995                     if (   is_null($component)
    996                         || !$_MIDCOM->componentloader->load_graceful($component))
    997                     {
    998                         debug_push_class(__CLASS__, __FUNCTION__);
    999                         debug_add("can_user_do check to undefined class '{$class}'.", MIDCOM_LOG_ERROR);
    1000                         debug_pop();
    1001                         return false;
    1002                     }
    1003                 }
    1004 
    1005                 $tmp_object = new $class();
    1006             }
    1007             else
    1008             {
    1009                 $tmp_object = $class;
    1010             }
    1011             $this->_load_class_magic_privileges($tmp_object);
    1012         }
    1013         else
    1014         {
    1015             $tmp_object = null;
    1016         }
    1017 
    1018         if (is_null($user))
    1019         {
    1020             $user_privileges = Array();
    1021             $user_per_class_privileges = Array();
    1022             if ($tmp_object !== null)
    1023             {
    1024                 if (!isset($tmp_object->__mgdschema_class_name__))
    1025                 {
    1026                     $tmp_class_name = get_class($tmp_object);
    1027                 }
    1028                 else
    1029                 {
    1030                     $tmp_class_name = $tmp_object->__mgdschema_class_name__;
    1031                 }
    1032 
    1033                 $default_magic_class_privileges = array_merge
    1034                 (
    1035                     $this->_default_magic_class_privileges[$tmp_class_name]['EVERYONE'],
    1036                     $this->_default_magic_class_privileges[$tmp_class_name]['ANONYMOUS']
    1037                 );
    1038             }
    1039         }
    1040         else
    1041         {
    1042             $user_privileges = $user->get_privileges();
    1043             if ($tmp_object === null)
    1044             {
    1045                 $user_per_class_privileges = Array();
    1046             }
    1047             else
    1048             {
    1049                 if (!isset($tmp_object->__mgdschema_class_name__))
    1050                 {
    1051                     $tmp_class_name = get_class($tmp_object);
    1052                 }
    1053                 else
    1054                 {
    1055                     $tmp_class_name = $tmp_object->__mgdschema_class_name__;
    1056                 }
    1057 
    1058                 $user_per_class_privileges = $user->get_per_class_privileges($tmp_object);
    1059                 $default_magic_class_privileges = array_merge
    1060                 (
    1061                     $this->_default_magic_class_privileges[$tmp_class_name]['EVERYONE'],
    1062                     $this->_default_magic_class_privileges[$tmp_class_name]['USERS']
    1063                 );
    1064             }
    1065         }
    1066 
    1067         // Remember to synchronize this merging chain with the one in get_privileges();
    1068         $full_privileges = array_merge
    1069         (
    1070             $this->_default_privileges,
    1071             $default_magic_class_privileges,
    1072             $user_privileges,
    1073             $user_per_class_privileges
    1074         );
    1075 
    1076         // Check for Ownership:
    1077         if ($full_privileges['midgard:owner'] == MIDCOM_PRIVILEGE_ALLOW)
    1078         {
    1079             $full_privileges = array_merge
    1080             (
    1081                 $full_privileges,
    1082                 $_MIDCOM->auth->get_owner_default_privileges()
    1083             );
    1084         }
    1085 
    1086         if (! array_key_exists($privilege, $full_privileges))
    1087         {
    1088             debug_push_class(__CLASS__, __FUNCTION__);
    1089             debug_add("Warning, the privilege {$privilege} is unknown at this point. Assuming not granted privilege.");
    1090             debug_pop();
    1091             return false;
    1092         }
    1093 
    1094594        debug_pop();
    1095 
    1096         return ($full_privileges[$privilege] == MIDCOM_PRIVILEGE_ALLOW);
    1097     }
    1098 
    1099     /**
    1100      * Determine the user identifier for accessing the privilege cache. This is the passed user's
    1101      * identifier with the current user and anonymous as fallback
    1102      *
    1103      * @param mixed $user The user to check for as string or object.
    1104      * @return string The identifier
    1105      */
    1106     public function get_user_id($user = null)
    1107     {
    1108         $user_id = 'ANONYMOUS';
    1109 
    1110         // TODO: Clean if/else shorthands, make sure this works correctly for magic assignees as well
    1111         if (is_null($user))
    1112         {
    1113             $user = $this->user;
    1114 
    1115             if (!empty($user))
    1116             {
    1117                 $user_id = $user->id;
    1118             }
    1119         }
    1120         else if (is_string($user))
    1121         {
    1122             if ($user != 'EVERYONE'
    1123                 && (    mgd_is_guid($user)
    1124                     || is_numeric($user)))
    1125             {
    1126                 $user = $_MIDCOM->auth->get_user($user);
    1127                 $user_id = $user->id;
    1128             }
    1129             else
    1130             {
    1131                 $user_id = $user;
    1132                 $user = null;
    1133             }
    1134         }
    1135         else if (is_object($user))
    1136         {
    1137             $user_id = $user->id;
    1138         }
    1139         else
    1140         {
    1141             $user_id = $user;
    1142         }
    1143 
    1144         return $user_id;
     595        return $this->acl->can_do_byclass($privilege, $user, $class, $component);
    1145596    }
    1146597
     
    1160611    function get_privileges(&$content_object, $user = null)
    1161612    {
    1162         $user_id = $this->get_user_id($user);
    1163         $this->_load_privileges_byguid($content_object->guid, get_class($content_object), $user_id);
    1164         return ;
    1165     }
    1166 
    1167     /**
    1168      * Returns a full listing of all currently known privileges for a certain object/user
    1169      * combination (object is specified by guid/class combination)
    1170      *
    1171      * The information is cached per object-guid during runtime, so that repeated checks
    1172      * to the same object do not cause repeating checks. Be aware that this means, that
    1173      * new privileges set are not guaranteed to take effect until the next request.
    1174      *
    1175      * @param string $object_guid A Midgard GUID pointing to an object
    1176      * @param string $object_class Class of the object in question
    1177      * @param string $user_id The user against which to check the privilege, defaults to the currently authenticated user.
    1178      *     You may specify "EVERYONE" instead of an object to check what an anonymous user can do.
    1179      */
    1180     private function _load_privileges_byguid($object_guid, $object_class, $user_id)
    1181     {
    1182         /* No idea if there should be some special log message written */
    1183         if (   empty($object_guid)
    1184             || empty($object_class))
    1185         {
    1186             return array();
    1187         }
    1188 
    1189         if (!class_exists($object_class))
    1190         {
    1191             $_MIDCOM->generate_error(MIDCOM_ERRCRIT, "class '{$object_class}' does not exist");
    1192             // This will exit()
    1193         }
    1194 
    1195         // Check for a cache Hit.
    1196         $cache_id = "{$user_id}::{$object_guid}";
    1197 
    1198         if (array_key_exists($cache_id, self::$_privileges_cache))
    1199         {
    1200             return;
    1201         }
    1202 
    1203         self::$_privileges_cache[$cache_id] = array();
    1204 
    1205         //debug_push_class(__CLASS__, __FUNCTION__);
    1206         //debug_add("Cache miss for {$cache_id}");
    1207         //debug_pop();
    1208 
    1209         /* FIXME! We create new instance of the same class, which means we will check privileges once again
    1210          * for newly created object, which means we will create another one object once again.... and so on.
    1211          * This may produce very ugly loops */
    1212         $dummy_object_init = new $object_class();
    1213         if ($_MIDCOM->dbclassloader->is_midcom_db_object($dummy_object_init))
    1214         {
    1215             $dummy_object = $dummy_object_init;
    1216         }
    1217         else
    1218         {
    1219             $dummy_object = $_MIDCOM->dbfactory->convert_midgard_to_midcom($dummy_object_init);
    1220             if (is_null($dummy_object))
    1221             {
    1222                 debug_push_class(__CLASS__, __FUNCTION__);
    1223                 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.');
    1224                 debug_pop();
    1225                 return;
    1226             }
    1227         }
    1228 
    1229         $this->_load_class_magic_privileges($dummy_object);
    1230         $dummy_object->__guid = $object_guid;
    1231 
    1232 
    1233         // content privileges
    1234         $content_privileges = midcom_core_privilege::collect_content_privileges($dummy_object, $user_id);
    1235 
    1236         $user = $this->get_user($user_id);
    1237 
    1238         // user privileges
    1239         if (   is_object($user)
    1240             && method_exists($user, 'get_privileges')
    1241             && method_exists($user, 'get_per_class_privileges'))
    1242         {
    1243             $user_privileges = $user->get_privileges();
    1244             $user_per_class_privileges = $user->get_per_class_privileges($dummy_object);
    1245         }
    1246         else
    1247         {
    1248             $user_privileges = array();
    1249             $user_per_class_privileges = array();
    1250         }
    1251 
    1252         // default magic class privileges user
    1253         $dmcp_user = is_null($this->user) ? 'ANONYMOUS' : 'USERS';
    1254 
    1255         // Remember to sync this merging chain with can_user_do.
    1256         $full_privileges = array_merge(
    1257             $this->_default_privileges,
    1258             $this->_default_magic_class_privileges[$dummy_object->__mgdschema_class_name__]['EVERYONE'],
    1259             $this->_default_magic_class_privileges[$dummy_object->__mgdschema_class_name__][$dmcp_user],
    1260             $user_privileges,
    1261             $user_per_class_privileges,
    1262             $content_privileges
    1263         );
    1264 
    1265         // cache for future queries
    1266         foreach ($full_privileges as $priv => $value)
    1267         {
    1268             $full_privileges[$priv] = ($value == MIDCOM_PRIVILEGE_ALLOW);
    1269         }
    1270         self::$_privileges_cache[$cache_id] = $full_privileges;
    1271     }
    1272 
     613        $user_id = $this->acl->get_user_id($user);
     614
     615        return $this->acl->get_privileges_byguid($content_object->guid, get_class($content_object), $user_id);
     616    }
    1273617
    1274618    /**
     
    1560904            // Figure out how to update midcom auth status
    1561905            $_MIDCOM->auth->_initialize_user_from_midgard();
    1562         }
    1563     }
    1564 
    1565     /**
    1566      * Merges a new set of default privileges into the current set.
    1567      * Existing keys will be silently overwritten.
    1568      *
    1569      * This is usually only called by the framework startup and the
    1570      * component loader.
    1571      *
    1572      * If only a single default value is set (type integer), then this value is taken
    1573      * for the default and the owner privilege is unset (meaning INHERIT). If two
    1574      * values (type array of integers) is set, the first privilege value is used for
    1575      * default, the second one for the owner privilege set.
    1576      *
    1577      * @param Array $privileges An associative privilege_name => default_values listing.
    1578      */
    1579     function register_default_privileges ($privileges)
    1580     {
    1581         foreach ($privileges as $name => $values)
    1582         {
    1583             if (! is_array($values))
    1584             {
    1585                 $values = Array($values, MIDCOM_PRIVILEGE_INHERIT);
    1586             }
    1587 
    1588             $this->_default_privileges[$name] = $values[0];
    1589             if ($values[1] != MIDCOM_PRIVILEGE_INHERIT)
    1590             {
    1591                 $this->_owner_default_privileges[$name] = $values[1];
    1592             }
    1593906        }
    1594907    }
     
    19801293
    19811294    /**
    1982      * This is a simple helper function which validates whether a given privilege
    1983      * exists by its name. Essentially this checks if a corresponding default privilege
    1984      * has been registered in the system.
    1985      *
    1986      * @todo This call should load the component associated to the privilege on demand.
    1987      * @param string $name The name of the privilege to check.
    1988      * @return boolean Indicating whether the privilege does exist.
    1989      */
    1990     function privilege_exists($name)
    1991     {
    1992         return array_key_exists($name, $this->_default_privileges);
    1993     }
    1994 
    1995     /**
    19961295     * Delete a registered virtual group in the system. This requires the privilege
    19971296     * midcom:vgroup_delete assigned to the user (there is no content object checked).
     
    24831782    }
    24841783
    2485     /**
    2486      * Returns the system-wide basic privilege set.
    2487      *
    2488      * @return Array Privilege Name / Value map.
    2489      */
    2490     function get_default_privileges()
    2491     {
    2492         return $this->_default_privileges;
    2493     }
    2494 
    2495     /**
    2496      * Returns the system-wide basic owner privilege set.
    2497      *
    2498      * @return Array Privilege Name / Value map.
    2499      */
    2500     function get_owner_default_privileges()
    2501     {
    2502         return $this->_owner_default_privileges;
    2503     }
    2504 
    2505     /**
    2506      * This helper function loads and prepares the list of class magic privileges for
    2507      * usage. It will assign them to the $_*_default_class_privileges members.
    2508      *
    2509      * @param MidcomDBAObject $classname An instance of the object for which the class defaults should be
    2510      *     loaded. Be aware, that this may be a simply a default constructed class instance.
    2511      * @access private
    2512      */
    2513     function _load_class_magic_privileges(&$class)
    2514     {
    2515         // Check if we have loaded these privileges already...
    2516         if (!isset($class->__mgdschema_class_name__))
    2517         {
    2518             $loadable_class = get_class($class);
    2519         }
    2520         else
    2521         {
    2522             $loadable_class = $class->__mgdschema_class_name__;
    2523         }
    2524 
    2525         if (array_key_exists($loadable_class, $this->_default_magic_class_privileges))
    2526         {
    2527             return;
    2528         }
    2529 
    2530         if (!method_exists($class, 'get_class_magic_default_privileges'))
    2531         {
    2532             $this->_default_magic_class_privileges[$loadable_class] = array
    2533             (
    2534                 'EVERYONE' => array(),
    2535                 'ANONYMOUS' => array(),
    2536                 'USERS' => array()
    2537             );
    2538             return;
    2539         }
    2540 
    2541         $privs = $class->get_class_magic_default_privileges();
    2542         $this->_default_magic_class_privileges[$loadable_class] = $privs;
    2543 
    2544         return;
    2545     }
    2546 
    25471784}
    2548 
    25491785?>
Note: See TracChangeset for help on using the changeset viewer.