Author: david
Date: Thu Oct 22 13:25:45 2009
New Revision: 3798

Log:
Optimize alogrithm for determining user repository access permissions. Fixes 
issue #1080.

Modified:
   trunk/apps/qubit/modules/informationobject/actions/listAction.class.php
   trunk/plugins/qbAclPlugin/lib/QubitAcl.class.php

Modified: 
trunk/apps/qubit/modules/informationobject/actions/listAction.class.php
==============================================================================
--- trunk/apps/qubit/modules/informationobject/actions/listAction.class.php     
Thu Oct 22 11:14:11 2009        (r3797)
+++ trunk/apps/qubit/modules/informationobject/actions/listAction.class.php     
Thu Oct 22 13:25:45 2009        (r3798)
@@ -80,50 +80,83 @@
     {
       $query = $request->query;
     }
-
-    // Filter out objects in forbidden repositories (no read access)
-    if (0 < count($deniedRepositories = 
QubitAcl::deniedRepositories(QubitInformationObject::getRoot(), 
QubitAclAction::READ_ID)))
+    $repositoryAccess = QubitAcl::getRepositoryAccess(QubitAclAction::READ_ID);
+    if (1 == count($repositoryAccess))
     {
-      // If all repositories are denied, re-route user
-      if (array('*') == $deniedRepositories)
+      // If all repositories are denied 'read' access, re-route user to login
+      if (array('id' => '*', 'access' => QubitAcl::DENY) == $repositoryAccess)
       {
         QubitAcl::forwardUnauthorized();
       }
-
+    }
+    else
+    {
       $subquery = new Zend_Search_Lucene_Search_Query_MultiTerm();
-      foreach ($deniedRepositories as $repositoryId)
+      while ($repo = array_shift($repositoryAccess))
       {
-        $subquery->addTerm(new Zend_Search_Lucene_Index_Term($repositoryId, 
'repositoryid'));
+        if ('*' != $repo['id'])
+        {
+          $subquery->addTerm(new Zend_Search_Lucene_Index_Term($repo['id'], 
'repositoryid'));
+          if (QubitAcl::DENY == $repo['access'])
+          {
+            $deniedRepositories[] = $repo['id'];
+          }
+        }
+        else
+        {
+          if (QubitAcl::DENY == $repo['access'])
+          {
+            // Require repos to be specifically allowed (all others prohibited)
+            $query->addSubquery($subquery, true /* required */);
+          }
+          else
+          {
+            // Prohibit specified repos (all others allowed)
+            $query->addSubquery($subquery, false /* prohibited */);
+          }
+        }
       }
-
-      $query->addSubquery($subquery, false /* prohibited */);
     }
 
     // Filter out 'draft' items by repository
-    $deniedStatusRepos = 
QubitAcl::deniedRepositories(QubitInformationObject::getRoot(), 
QubitAclAction::VIEW_DRAFT_ID);
-    if (0 < count($deniedStatusRepos))
+    $repositoryViewDrafts = 
QubitAcl::getRepositoryAccess(QubitAclAction::VIEW_DRAFT_ID);
+    if (1 == count($repositoryViewDrafts))
     {
-      if (array('*') == $deniedStatusRepos)
+      if (array('id' => '*', 'access' => QubitAcl::DENY) == 
$repositoryViewDrafts)
       {
         // Don't show *any* draft info objects
         $query->addSubquery(new Zend_Search_Lucene_Search_Query_Term(new 
Zend_Search_Lucene_Index_Term(QubitTerm::PUBLICATION_STATUS_DRAFT_ID, 
'publicationStatusId')), false);
       }
-      else
+    }
+    else
+    {
+      $subquery = new Zend_Search_Lucene_Search_Query_MultiTerm();
+      while ($repo = array_shift($repositoryViewDrafts))
       {
-        $subquery = new Zend_Search_Lucene_Search_Query_MultiTerm();
-        foreach ($deniedStatusRepos as $repositoryId)
+        // Don't bother excluding repos (again) that have no read access at all
+        if (in_array($repo['id'], $deniedRepositories))
         {
-          // Don't bother excluding repos (again) that have no read access at 
all
-          if (in_array($repositoryId, $deniedRepositories))
-          {
-            continue;
-          }
+          continue;
+        }
 
-          $subquery->addTerm(new Zend_Search_Lucene_Index_Term($repositoryId, 
'repositoryid'), true);
+        if ('*' != $repo['id'])
+        {
+          $subquery->addTerm(new Zend_Search_Lucene_Index_Term($repo['id'], 
'repositoryid'), true);
           $subquery->addTerm(new 
Zend_Search_Lucene_Index_Term(QubitTerm::PUBLICATION_STATUS_DRAFT_ID, 
'publicationStatusId'), true);
         }
-
-        $query->addSubquery($subquery, false /* prohibited */);
+        else
+        {
+          if (QubitAcl::DENY == $repo['access'])
+          {
+            // Require repos to be specifically allowed (all others prohibited)
+            $query->addSubquery($subquery, true /* required */);
+          }
+          else
+          {
+            // Prohibit specified repos (all others allowed)
+            $query->addSubquery($subquery, false /* prohibited */);
+          }
+        }
       }
     }
 

Modified: trunk/plugins/qbAclPlugin/lib/QubitAcl.class.php
==============================================================================
--- trunk/plugins/qbAclPlugin/lib/QubitAcl.class.php    Thu Oct 22 11:14:11 
2009        (r3797)
+++ trunk/plugins/qbAclPlugin/lib/QubitAcl.class.php    Thu Oct 22 13:25:45 
2009        (r3798)
@@ -320,34 +320,102 @@
     return self::evalGrantDeny($grantDeny);
   }
 
-  public static function deniedRepositories($informationObject, $actionId, 
$options = array())
+  /**
+   * Add permissions to repository access array
+   *
+   * @param $repositoryAccess input access array
+   * @param $permissions QubitQuery permission list
+   * @return array output access array
+   */
+  public static function addRepositoryAccess($repositoryAccess, $permissions)
   {
-    $deniedRepositories = array();
-
-    if (!$informationObject instanceof QubitInformationObject)
+    foreach ($permissions as $permission)
     {
+      if (null === $permission->grantDeny)
+      {
+        continue;
+      }
+
+      $access = (1 == $permission->grantDeny) ? self::GRANT : self::DENY;
+
+      // If no repository specified, then apply rule to all repositories
+      if (null === ($repository = $permission->getRepository()))
+      {
+        $repositoryAccess[] = array('id' => '*', 'access' => $access);
+        break;
+      }
 
-      return;
+      // Add repository access if it isn't set already
+      else if (!in_array($repository->id, array_keys($repositoryAccess)))
+      {
+        $repositoryAccess[] = array('id' => $repository->id, 'access' => 
$access);
+      }
     }
 
-    // get repository list
-    $repositories = QubitRepository::getAll();
+    return $repositoryAccess;
+  }
 
-    foreach ($repositories as $repository)
+  /**
+   * List the repository access rules for the current user
+   *
+   * @param $actionId integer Access privilige being requested
+   * @param $options array optional parameters
+   * @return array
+   */
+  public static function getRepositoryAccess(QubitAclAction $actionId, 
$options = array())
+  {
+    $repositoryAccess = array();
+
+    // Test user permissions
+    $criteria = new Criteria;
+    $criteria->add(QubitAclPermission::ACTION_ID, $actionId);
+    $criteria->add(QubitAclPermission::USER_ID, 
sfContext::getInstance()->getUser()->getUserId());
+    $criteria->addDescendingOrderByColumn(QubitAclPermission::ID);
+
+    if (0 < count($permissions = QubitAclPermission::get($criteria)))
+    {
+      $repositoryAccess = self::addRepositoryAccess($repositoryAccess, 
$permissions);
+    }
+
+    if (0 == count($repositoryAccess) || '*' != 
$repositoryAccess[count($repositoryAccess) - 1]['id'])
     {
-      $options['parameters'] = array('repositoryId' => $repository->id);
-      if (!self::check($informationObject, $actionId, $options))
+      // Test user group permissions
+      $userGroupIds = array();
+      foreach (sfContext::getInstance()->getUser()->listGroups() as $group)
       {
-        $deniedRepositories[] = $repository->id;
+        $userGroupIds[] = $group->id;
+      }
+
+      $criteria = new Criteria;
+      $criteria->add(QubitAclPermission::ACTION_ID, $actionId);
+      $criteria->add(QubitAclPermission::GROUP_ID, $userGroupIds, 
Criteria::IN);
+      $criteria->addDescendingOrderByColumn(QubitAclPermission::ID);
+
+      if (0 < count($permissions = QubitAclPermission::get($criteria)))
+      {
+        $repositoryAccess = self::addRepositoryAccess($repositoryAccess, 
$permissions);
       }
     }
 
-    if (0 < count($repositories) && count($repositories) == 
count($deniedRepositories))
+    // Default is to deny access if no permissions specified
+    if (0 == count($repositoryAccess) || '*' != 
$repositoryAccess[count($repositoryAccess) - 1]['id'])
     {
-      $deniedRepositories = array('*');
+      $repositoryAccess[] = array('id' => '*', 'access' => self::DENY);
+    }
+
+    // Collapse access rules so that e.g.
+    // ('1' => deny, '2' => allow, '*' => deny) -> ('2' => allow, '*' => deny)
+    // ('1' => deny, '2' => allow, '*' => allow) -> (1' => deny, '*' => allow)
+    $globalPermission = $repositoryAccess[count($repositoryAccess) - 
1]['access'];
+    foreach ($repositoryAccess as $i => $val)
+    {
+      if ('*' != $val['id'] && $globalPermission == $val['access'])
+      {
+        unset($repositoryAccess[$i]);
+      }
     }
 
-    return $deniedRepositories;
+    return $repositoryAccess;
   }
 
   public static function forwardUnauthorized()

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Qubit Toolkit Commits" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.ca/group/qubit-commits?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to