diff options
Diffstat (limited to 'Acl')
-rw-r--r-- | Acl/Dbal/AclProvider.php | 30 | ||||
-rw-r--r-- | Acl/Dbal/MutableAclProvider.php | 70 | ||||
-rw-r--r-- | Acl/Permission/MaskBuilder.php | 54 | ||||
-rw-r--r-- | Acl/README.md | 2 | ||||
-rw-r--r-- | Acl/Tests/Dbal/MutableAclProviderTest.php | 30 | ||||
-rw-r--r-- | Acl/Tests/Domain/AuditLoggerTest.php | 4 | ||||
-rw-r--r-- | Acl/composer.json | 2 |
7 files changed, 150 insertions, 42 deletions
diff --git a/Acl/Dbal/AclProvider.php b/Acl/Dbal/AclProvider.php index 96b6a4b..5bcaf82 100644 --- a/Acl/Dbal/AclProvider.php +++ b/Acl/Dbal/AclProvider.php @@ -176,13 +176,13 @@ class AclProvider implements AclProviderInterface if ((self::MAX_BATCH_SIZE === count($currentBatch) || ($i + 1) === $c) && count($currentBatch) > 0) { try { $loadedBatch = $this->lookupObjectIdentities($currentBatch, $sids, $oidLookup); - } catch (AclNotFoundException $aclNotFoundexception) { + } 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; + throw $aclNotFoundException; } } foreach ($loadedBatch as $loadedOid) { @@ -205,7 +205,8 @@ class AclProvider implements AclProviderInterface foreach ($oids as $oid) { if (!$result->contains($oid)) { if (1 === count($oids)) { - throw new AclNotFoundException(sprintf('No ACL found for %s.', $oid)); + $objectName = method_exists($oid, '__toString') ? $oid : get_class($oid); + throw new AclNotFoundException(sprintf('No ACL found for %s.', $objectName)); } $partialResultException = new NotAllAclsFoundException('The provider could not find ACLs for all object identities.'); @@ -294,7 +295,8 @@ SELECTCLAUSE; if (1 === count($types)) { $ids = array(); for ($i = 0; $i < $count; $i++) { - $ids[] = $this->connection->quote($batch[$i]->getIdentifier()); + $identifier = (string) $batch[$i]->getIdentifier(); + $ids[] = $this->connection->quote($identifier); } $sql .= sprintf( @@ -336,17 +338,17 @@ SELECTCLAUSE; $query = <<<FINDCHILDREN SELECT o.object_identifier, c.class_type FROM - {$this->options['oid_table_name']} as o - INNER JOIN {$this->options['class_table_name']} as c ON c.id = o.class_id - INNER JOIN {$this->options['oid_ancestors_table_name']} as a ON a.object_identity_id = o.id + {$this->options['oid_table_name']} o + INNER JOIN {$this->options['class_table_name']} c ON c.id = o.class_id + INNER JOIN {$this->options['oid_ancestors_table_name']} a ON a.object_identity_id = o.id WHERE a.ancestor_id = %d AND a.object_identity_id != a.ancestor_id FINDCHILDREN; } else { $query = <<<FINDCHILDREN SELECT o.object_identifier, c.class_type - FROM {$this->options['oid_table_name']} as o - INNER JOIN {$this->options['class_table_name']} as c ON c.id = o.class_id + FROM {$this->options['oid_table_name']} o + INNER JOIN {$this->options['class_table_name']} c ON c.id = o.class_id WHERE o.parent_object_identity_id = %d FINDCHILDREN; } @@ -374,8 +376,8 @@ QUERY; $query, $this->options['oid_table_name'], $this->options['class_table_name'], - $this->connection->quote($oid->getIdentifier()), - $this->connection->quote($oid->getType()) + $this->connection->quote((string) $oid->getIdentifier()), + $this->connection->quote((string) $oid->getType()) ); } @@ -430,8 +432,8 @@ QUERY; $ancestorIds = array(); foreach ($this->connection->executeQuery($sql)->fetchAll() as $data) { // FIXME: skip ancestors which are cached - - $ancestorIds[] = $data['ancestor_id']; + // Fix: Oracle returns keys in uppercase + $ancestorIds[] = reset($data); } return $ancestorIds; @@ -535,7 +537,7 @@ QUERY; $auditSuccess, $auditFailure, $username, - $securityIdentifier) = $data; + $securityIdentifier) = array_values($data); // has the ACL been hydrated during this hydration cycle? if (isset($acls[$aclId])) { diff --git a/Acl/Dbal/MutableAclProvider.php b/Acl/Dbal/MutableAclProvider.php index 2a4eac0..261d932 100644 --- a/Acl/Dbal/MutableAclProvider.php +++ b/Acl/Dbal/MutableAclProvider.php @@ -51,7 +51,8 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf public function createAcl(ObjectIdentityInterface $oid) { if (false !== $this->retrieveObjectIdentityPrimaryKey($oid)) { - throw new AclAlreadyExistsException(sprintf('%s is already associated with an ACL.', $oid)); + $objectName = method_exists($oid, '__toString') ? $oid : get_class($oid); + throw new AclAlreadyExistsException(sprintf('%s is already associated with an ACL.', $objectName)); } $this->connection->beginTransaction(); @@ -109,6 +110,18 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf } /** + * Deletes the security identity from the database. + * ACL entries have the CASCADE option on their foreign key so they will also get deleted + * + * @param SecurityIdentityInterface $sid + * @throws \InvalidArgumentException + */ + public function deleteSecurityIdentity(SecurityIdentityInterface $sid) + { + $this->connection->executeQuery($this->getDeleteSecurityIdentityIdSql($sid)); + } + + /** * {@inheritdoc} */ public function findAcls(array $oids, array $sids = array()) @@ -253,7 +266,7 @@ 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 + // we need to perform deletions before updating existing ACEs, in order to // preserve uniqueness of the order field if (isset($propertyChanges['classAces'])) { $this->updateOldAceProperty('classAces', $propertyChanges['classAces']); @@ -352,6 +365,17 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf } /** + * Updates a user security identity when the user's username changes + * + * @param UserSecurityIdentity $usid + * @param string $oldUsername + */ + public function updateUserSecurityIdentity(UserSecurityIdentity $usid, $oldUsername) + { + $this->connection->executeQuery($this->getUpdateUserSecurityIdentitySql($usid, $oldUsername)); + } + + /** * Constructs the SQL for deleting access control entries. * * @param int $oidPK @@ -360,7 +384,7 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf protected function getDeleteAccessControlEntriesSql($oidPK) { return sprintf( - 'DELETE FROM %s WHERE object_identity_id = %d', + 'DELETE FROM %s WHERE object_identity_id = %d', $this->options['entry_table_name'], $oidPK ); @@ -612,6 +636,21 @@ QUERY; } /** + * Constructs the SQL to delete a security identity. + * + * @param SecurityIdentityInterface $sid + * @throws \InvalidArgumentException + * @return string + */ + protected function getDeleteSecurityIdentityIdSql(SecurityIdentityInterface $sid) + { + $select = $this->getSelectSecurityIdentityIdSql($sid); + $delete = preg_replace('/^SELECT id FROM/', 'DELETE FROM', $select); + + return $delete; + } + + /** * Constructs the SQL for updating an object identity. * * @param int $pk @@ -634,6 +673,31 @@ QUERY; } /** + * Constructs the SQL for updating a user security identity. + * + * @param UserSecurityIdentity $usid + * @param string $oldUsername + * @return string + */ + protected function getUpdateUserSecurityIdentitySql(UserSecurityIdentity $usid, $oldUsername) + { + if ($usid->getUsername() == $oldUsername) { + throw new \InvalidArgumentException('There are no changes.'); + } + + $oldIdentifier = $usid->getClass().'-'.$oldUsername; + $newIdentifier = $usid->getClass().'-'.$usid->getUsername(); + + return sprintf( + 'UPDATE %s SET identifier = %s WHERE identifier = %s AND username = %s', + $this->options['sid_table_name'], + $this->connection->quote($newIdentifier), + $this->connection->quote($oldIdentifier), + $this->connection->getDatabasePlatform()->convertBooleans(true) + ); + } + + /** * Constructs the SQL for updating an ACE. * * @param int $pk diff --git a/Acl/Permission/MaskBuilder.php b/Acl/Permission/MaskBuilder.php index 8ca25bc..86200a8 100644 --- a/Acl/Permission/MaskBuilder.php +++ b/Acl/Permission/MaskBuilder.php @@ -96,13 +96,7 @@ class MaskBuilder */ public function add($mask) { - if (is_string($mask) && defined($name = 'static::MASK_'.strtoupper($mask))) { - $mask = constant($name); - } elseif (!is_int($mask)) { - throw new \InvalidArgumentException('$mask must be an integer.'); - } - - $this->mask |= $mask; + $this->mask |= $this->getMask($mask); return $this; } @@ -152,13 +146,7 @@ class MaskBuilder */ public function remove($mask) { - if (is_string($mask) && defined($name = 'static::MASK_'.strtoupper($mask))) { - $mask = constant($name); - } elseif (!is_int($mask)) { - throw new \InvalidArgumentException('$mask must be an integer.'); - } - - $this->mask &= ~$mask; + $this->mask &= ~$this->getMask($mask); return $this; } @@ -191,19 +179,43 @@ class MaskBuilder $reflection = new \ReflectionClass(get_called_class()); foreach ($reflection->getConstants() as $name => $cMask) { - if (0 !== strpos($name, 'MASK_')) { + if (0 !== strpos($name, 'MASK_') || $mask !== $cMask) { continue; } - if ($mask === $cMask) { - if (!defined($cName = 'static::CODE_'.substr($name, 5))) { - throw new \RuntimeException('There was no code defined for this mask.'); - } - - return constant($cName); + if (!defined($cName = 'static::CODE_'.substr($name, 5))) { + throw new \RuntimeException('There was no code defined for this mask.'); } + + return constant($cName); } throw new \InvalidArgumentException(sprintf('The mask "%d" is not supported.', $mask)); } + + /** + * Returns the mask for the passed code + * + * @param mixed $code + * + * @return int + * + * @throws \InvalidArgumentException + */ + private function getMask($code) + { + if (is_string($code)) { + if (!defined($name = sprintf('static::MASK_%s', strtoupper($code)))) { + throw new \InvalidArgumentException(sprintf('The code "%s" is not supported', $code)); + } + + return constant($name); + } + + if (!is_int($code)) { + throw new \InvalidArgumentException('$code must be an integer.'); + } + + return $code; + } } diff --git a/Acl/README.md b/Acl/README.md index 87e5092..6c009a3 100644 --- a/Acl/README.md +++ b/Acl/README.md @@ -11,7 +11,7 @@ Resources Documentation: -http://symfony.com/doc/2.4/book/security.html +http://symfony.com/doc/2.5/book/security.html Tests ----- diff --git a/Acl/Tests/Dbal/MutableAclProviderTest.php b/Acl/Tests/Dbal/MutableAclProviderTest.php index f74e04c..f0a68a0 100644 --- a/Acl/Tests/Dbal/MutableAclProviderTest.php +++ b/Acl/Tests/Dbal/MutableAclProviderTest.php @@ -410,6 +410,36 @@ class MutableAclProviderTest extends \PHPUnit_Framework_TestCase $provider->updateAcl($acl); } + public function testUpdateUserSecurityIdentity() + { + $provider = $this->getProvider(); + $acl = $provider->createAcl(new ObjectIdentity(1, 'Foo')); + $sid = new UserSecurityIdentity('johannes', 'FooClass'); + $acl->setEntriesInheriting(!$acl->isEntriesInheriting()); + + $acl->insertObjectAce($sid, 1); + $acl->insertClassAce($sid, 5, 0, false); + $acl->insertObjectAce($sid, 2, 1, true); + $acl->insertClassFieldAce('field', $sid, 2, 0, true); + $provider->updateAcl($acl); + + $newSid = new UserSecurityIdentity('mathieu', 'FooClass'); + $provider->updateUserSecurityIdentity($newSid, 'johannes'); + + $reloadProvider = $this->getProvider(); + $reloadedAcl = $reloadProvider->findAcl(new ObjectIdentity(1, 'Foo')); + + $this->assertNotSame($acl, $reloadedAcl); + $this->assertSame($acl->isEntriesInheriting(), $reloadedAcl->isEntriesInheriting()); + + $aces = $acl->getObjectAces(); + $reloadedAces = $reloadedAcl->getObjectAces(); + $this->assertEquals(count($aces), count($reloadedAces)); + foreach ($reloadedAces as $ace) { + $this->assertTrue($ace->getSecurityIdentity()->equals($newSid)); + } + } + /** * Data must have the following format: * array( diff --git a/Acl/Tests/Domain/AuditLoggerTest.php b/Acl/Tests/Domain/AuditLoggerTest.php index 6c600fb..15538d3 100644 --- a/Acl/Tests/Domain/AuditLoggerTest.php +++ b/Acl/Tests/Domain/AuditLoggerTest.php @@ -26,12 +26,12 @@ class AuditLoggerTest extends \PHPUnit_Framework_TestCase ->expects($this->once()) ->method('isAuditSuccess') ->will($this->returnValue($audit)) - ; + ; $ace ->expects($this->never()) ->method('isAuditFailure') - ; + ; } else { $ace ->expects($this->never()) diff --git a/Acl/composer.json b/Acl/composer.json index 0e68d9e..5f5787f 100644 --- a/Acl/composer.json +++ b/Acl/composer.json @@ -36,7 +36,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "2.4-dev" + "dev-master": "2.5-dev" } } } |