summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFabien Potencier <fabien.potencier@gmail.com>2013-11-23 22:11:41 +0100
committerFabien Potencier <fabien.potencier@gmail.com>2013-11-23 22:11:41 +0100
commit79b21cbc2358461695473de6a5b4e6a92ae18674 (patch)
treee02b73dd7e69d0f8cf957aef187bec1713b8e4bd
parent2d03373e16a1f3f7947a0bf980ab76ecca61a310 (diff)
parent209339c87ca122559536159fbf528156624bda65 (diff)
downloadsymfony-security-79b21cbc2358461695473de6a5b4e6a92ae18674.zip
symfony-security-79b21cbc2358461695473de6a5b4e6a92ae18674.tar.gz
symfony-security-79b21cbc2358461695473de6a5b4e6a92ae18674.tar.bz2
Merge branch '2.2' into 2.3
* 2.2: No Entity Manager defined exception fixed CS [Acl] Fix for issue #9433 [Validator] fix docblock typos [DependencyInjection] removed the unused Reference and Parameter classes use statements from the compiled container class Fix mistake in translation's service definition. if handler_id is identical to null fix CS fix Fixed ModelChoiceList tests in Propel1 bridge. [AclProvider] Fix incorrect behaviour when partial results returned from cache Check if the pipe array is empty before calling stream_select() re-factor Propel1 ModelChoiceList [Locale] fixed the failing test described in #9455 [Process] fix phpdoc and timeout of 0 bug #9445 [BrowserKit] fixed protocol-relative url redirection Conflicts: src/Symfony/Component/BrowserKit/Tests/ClientTest.php src/Symfony/Component/Locale/Tests/Stub/StubIntlDateFormatterTest.php
-rw-r--r--Acl/Dbal/AclProvider.php13
-rw-r--r--Acl/Dbal/MutableAclProvider.php127
-rw-r--r--Tests/Acl/Dbal/MutableAclProviderTest.php48
3 files changed, 158 insertions, 30 deletions
diff --git a/Acl/Dbal/AclProvider.php b/Acl/Dbal/AclProvider.php
index 822a160..1d1cb16 100644
--- a/Acl/Dbal/AclProvider.php
+++ b/Acl/Dbal/AclProvider.php
@@ -165,8 +165,17 @@ class AclProvider implements AclProviderInterface
// Is it time to load the current batch?
if ((self::MAX_BATCH_SIZE === count($currentBatch) || ($i + 1) === $c) && count($currentBatch) > 0) {
- $loadedBatch = $this->lookupObjectIdentities($currentBatch, $sids, $oidLookup);
-
+ try {
+ $loadedBatch = $this->lookupObjectIdentities($currentBatch, $sids, $oidLookup);
+ } catch (AclNotFoundException $aclNotFoundexception) {
+ if ($result->count()) {
+ $partialResultException = new NotAllAclsFoundException('The provider could not find ACLs for all object identities.');
+ $partialResultException->setPartialResult($result);
+ throw $partialResultException;
+ } else {
+ throw $aclNotFoundexception;
+ }
+ }
foreach ($loadedBatch as $loadedOid) {
$loadedAcl = $loadedBatch->offsetGet($loadedOid);
diff --git a/Acl/Dbal/MutableAclProvider.php b/Acl/Dbal/MutableAclProvider.php
index 0ac4fa7..29d3cfd 100644
--- a/Acl/Dbal/MutableAclProvider.php
+++ b/Acl/Dbal/MutableAclProvider.php
@@ -252,6 +252,22 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf
}
}
+ // check properties for deleted, and created ACEs, and perform deletions
+ // we need to perfom deletions before updating existing ACEs, in order to
+ // preserve uniqueness of the order field
+ if (isset($propertyChanges['classAces'])) {
+ $this->updateOldAceProperty('classAces', $propertyChanges['classAces']);
+ }
+ if (isset($propertyChanges['classFieldAces'])) {
+ $this->updateOldFieldAceProperty('classFieldAces', $propertyChanges['classFieldAces']);
+ }
+ if (isset($propertyChanges['objectAces'])) {
+ $this->updateOldAceProperty('objectAces', $propertyChanges['objectAces']);
+ }
+ if (isset($propertyChanges['objectFieldAces'])) {
+ $this->updateOldFieldAceProperty('objectFieldAces', $propertyChanges['objectFieldAces']);
+ }
+
// this includes only updates of existing ACEs, but neither the creation, nor
// the deletion of ACEs; these are tracked by changes to the ACL's respective
// properties (classAces, classFieldAces, objectAces, objectFieldAces)
@@ -259,20 +275,20 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf
$this->updateAces($propertyChanges['aces']);
}
- // check properties for deleted, and created ACEs
+ // check properties for deleted, and created ACEs, and perform creations
if (isset($propertyChanges['classAces'])) {
- $this->updateAceProperty('classAces', $propertyChanges['classAces']);
+ $this->updateNewAceProperty('classAces', $propertyChanges['classAces']);
$sharedPropertyChanges['classAces'] = $propertyChanges['classAces'];
}
if (isset($propertyChanges['classFieldAces'])) {
- $this->updateFieldAceProperty('classFieldAces', $propertyChanges['classFieldAces']);
+ $this->updateNewFieldAceProperty('classFieldAces', $propertyChanges['classFieldAces']);
$sharedPropertyChanges['classFieldAces'] = $propertyChanges['classFieldAces'];
}
if (isset($propertyChanges['objectAces'])) {
- $this->updateAceProperty('objectAces', $propertyChanges['objectAces']);
+ $this->updateNewAceProperty('objectAces', $propertyChanges['objectAces']);
}
if (isset($propertyChanges['objectFieldAces'])) {
- $this->updateFieldAceProperty('objectFieldAces', $propertyChanges['objectFieldAces']);
+ $this->updateNewFieldAceProperty('objectFieldAces', $propertyChanges['objectFieldAces']);
}
// if there have been changes to shared properties, we need to synchronize other
@@ -740,12 +756,12 @@ QUERY;
}
/**
- * This processes changes on an ACE related property (classFieldAces, or objectFieldAces).
+ * This processes new entries changes on an ACE related property (classFieldAces, or objectFieldAces).
*
* @param string $name
* @param array $changes
*/
- private function updateFieldAceProperty($name, array $changes)
+ private function updateNewFieldAceProperty($name, array $changes)
{
$sids = new \SplObjectStorage();
$classIds = new \SplObjectStorage();
@@ -782,9 +798,29 @@ QUERY;
}
}
}
+ }
+
+ /**
+ * This process old entries changes on an ACE related property (classFieldAces, or objectFieldAces).
+ *
+ * @param string $name
+ * @param array $changes
+ */
+ private function updateOldFieldAceProperty($ane, array $changes)
+ {
+ $currentIds = array();
+ foreach ($changes[1] as $field => $new) {
+ for ($i = 0, $c = count($new); $i < $c; $i++) {
+ $ace = $new[$i];
+
+ if (null !== $ace->getId()) {
+ $currentIds[$ace->getId()] = true;
+ }
+ }
+ }
foreach ($changes[0] as $old) {
- for ($i=0,$c=count($old); $i<$c; $i++) {
+ for ($i = 0, $c = count($old); $i < $c; $i++) {
$ace = $old[$i];
if (!isset($currentIds[$ace->getId()])) {
@@ -796,12 +832,12 @@ QUERY;
}
/**
- * This processes changes on an ACE related property (classAces, or objectAces).
+ * This processes new entries changes on an ACE related property (classAces, or objectAces).
*
* @param string $name
* @param array $changes
*/
- private function updateAceProperty($name, array $changes)
+ private function updateNewAceProperty($name, array $changes)
{
list($old, $new) = $changes;
@@ -838,8 +874,28 @@ QUERY;
$currentIds[$ace->getId()] = true;
}
}
+ }
- for ($i=0,$c=count($old); $i<$c; $i++) {
+ /**
+ * This processes old entries changes on an ACE related property (classAces, or objectAces).
+ *
+ * @param string $name
+ * @param array $changes
+ */
+ private function updateOldAceProperty($name, array $changes)
+ {
+ list($old, $new) = $changes;
+ $currentIds = array();
+
+ for ($i=0,$c=count($new); $i<$c; $i++) {
+ $ace = $new[$i];
+
+ if (null !== $ace->getId()) {
+ $currentIds[$ace->getId()] = true;
+ }
+ }
+
+ for ($i = 0, $c = count($old); $i < $c; $i++) {
$ace = $old[$i];
if (!isset($currentIds[$ace->getId()])) {
@@ -857,26 +913,41 @@ QUERY;
private function updateAces(\SplObjectStorage $aces)
{
foreach ($aces as $ace) {
- $propertyChanges = $aces->offsetGet($ace);
- $sets = array();
+ $this->updateAce($aces, $ace);
+ }
+ }
- if (isset($propertyChanges['mask'])) {
- $sets[] = sprintf('mask = %d', $propertyChanges['mask'][1]);
- }
- if (isset($propertyChanges['strategy'])) {
- $sets[] = sprintf('granting_strategy = %s', $this->connection->quote($propertyChanges['strategy']));
- }
- if (isset($propertyChanges['aceOrder'])) {
- $sets[] = sprintf('ace_order = %d', $propertyChanges['aceOrder'][1]);
- }
- if (isset($propertyChanges['auditSuccess'])) {
- $sets[] = sprintf('audit_success = %s', $this->connection->getDatabasePlatform()->convertBooleans($propertyChanges['auditSuccess'][1]));
- }
- if (isset($propertyChanges['auditFailure'])) {
- $sets[] = sprintf('audit_failure = %s', $this->connection->getDatabasePlatform()->convertBooleans($propertyChanges['auditFailure'][1]));
+ private function updateAce(\SplObjectStorage $aces, $ace)
+ {
+ $propertyChanges = $aces->offsetGet($ace);
+ $sets = array();
+
+ if (isset($propertyChanges['aceOrder'])
+ && $propertyChanges['aceOrder'][1] > $propertyChanges['aceOrder'][0]
+ && $propertyChanges == $aces->offsetGet($ace)) {
+ $aces->next();
+ if ($aces->valid()) {
+ $this->updateAce($aces, $aces->current());
+ }
}
- $this->connection->executeQuery($this->getUpdateAccessControlEntrySql($ace->getId(), $sets));
+ if (isset($propertyChanges['mask'])) {
+ $sets[] = sprintf('mask = %d', $propertyChanges['mask'][1]);
}
+ if (isset($propertyChanges['strategy'])) {
+ $sets[] = sprintf('granting_strategy = %s', $this->connection->quote($propertyChanges['strategy']));
+ }
+ if (isset($propertyChanges['aceOrder'])) {
+ $sets[] = sprintf('ace_order = %d', $propertyChanges['aceOrder'][1]);
+ }
+ if (isset($propertyChanges['auditSuccess'])) {
+ $sets[] = sprintf('audit_success = %s', $this->connection->getDatabasePlatform()->convertBooleans($propertyChanges['auditSuccess'][1]));
+ }
+ if (isset($propertyChanges['auditFailure'])) {
+ $sets[] = sprintf('audit_failure = %s', $this->connection->getDatabasePlatform()->convertBooleans($propertyChanges['auditFailure'][1]));
+ }
+
+ $this->connection->executeQuery($this->getUpdateAccessControlEntrySql($ace->getId(), $sets));
}
+
}
diff --git a/Tests/Acl/Dbal/MutableAclProviderTest.php b/Tests/Acl/Dbal/MutableAclProviderTest.php
index edcdd4d..00a2228 100644
--- a/Tests/Acl/Dbal/MutableAclProviderTest.php
+++ b/Tests/Acl/Dbal/MutableAclProviderTest.php
@@ -359,6 +359,54 @@ class MutableAclProviderTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($newParentParentAcl->getId(), $reloadedAcl->getParentAcl()->getParentAcl()->getId());
}
+ public function testUpdateAclInsertingMultipleObjectFieldAcesThrowsDBConstraintViolations()
+ {
+ $provider = $this->getProvider();
+ $oid = new ObjectIdentity(1, 'Foo');
+ $sid1 = new UserSecurityIdentity('johannes', 'FooClass');
+ $sid2 = new UserSecurityIdentity('guilro', 'FooClass');
+ $sid3 = new UserSecurityIdentity('bmaz', 'FooClass');
+ $fieldName = 'fieldName';
+
+ $acl = $provider->createAcl($oid);
+ $acl->insertObjectFieldAce($fieldName, $sid1, 4);
+ $provider->updateAcl($acl);
+
+ $acl = $provider->findAcl($oid);
+ $acl->insertObjectFieldAce($fieldName, $sid2, 4);
+ $provider->updateAcl($acl);
+
+ $acl = $provider->findAcl($oid);
+ $acl->insertObjectFieldAce($fieldName, $sid3, 4);
+ $provider->updateAcl($acl);
+ }
+
+ public function testUpdateAclDeletingObjectFieldAcesThrowsDBConstraintViolations()
+ {
+ $provider = $this->getProvider();
+ $oid = new ObjectIdentity(1, 'Foo');
+ $sid1 = new UserSecurityIdentity('johannes', 'FooClass');
+ $sid2 = new UserSecurityIdentity('guilro', 'FooClass');
+ $sid3 = new UserSecurityIdentity('bmaz', 'FooClass');
+ $fieldName = 'fieldName';
+
+ $acl = $provider->createAcl($oid);
+ $acl->insertObjectFieldAce($fieldName, $sid1, 4);
+ $provider->updateAcl($acl);
+
+ $acl = $provider->findAcl($oid);
+ $acl->insertObjectFieldAce($fieldName, $sid2, 4);
+ $provider->updateAcl($acl);
+
+ $index = 0;
+ $acl->deleteObjectFieldAce($index, $fieldName);
+ $provider->updateAcl($acl);
+
+ $acl = $provider->findAcl($oid);
+ $acl->insertObjectFieldAce($fieldName, $sid3, 4);
+ $provider->updateAcl($acl);
+ }
+
/**
* Data must have the following format:
* array(