From af1053e149a2db93c4af996bd65c43fbb0739ea5 Mon Sep 17 00:00:00 2001 From: Toni Uebernickel Date: Fri, 3 Feb 2012 23:52:37 +0100 Subject: [PATCH] add AuditableAcl(Provider) * update provider class to AuditableAclProvider * change auditing default to be more reasonable, 90% use case: log failures only * add transformers to Model\Acl\Entry converting from/to Security\Acl\Domain\Entry * fix MutableAclProvider to use getAcl method instead of creating MutableAcl directly * re-factor MutableAcl::updateAce and MutableAclProvider::persistAcl to use Entry transformers --- Model/Acl/Entry.php | 62 +++++ Resources/config/acl_schema.xml | 2 +- Resources/config/propel.xml | 2 +- Security/Acl/AuditableAclProvider.php | 41 ++++ Security/Acl/Domain/AuditableAcl.php | 112 +++++++++ Security/Acl/Domain/MutableAcl.php | 39 +--- Security/Acl/MutableAclProvider.php | 25 +- Tests/Model/Acl/EntryTest.php | 88 +++++++ .../Security/Acl/AuditableAclProviderTest.php | 87 +++++++ .../Security/Acl/Domain/AuditableAclTest.php | 214 ++++++++++++++++++ 10 files changed, 630 insertions(+), 42 deletions(-) create mode 100644 Security/Acl/AuditableAclProvider.php create mode 100644 Security/Acl/Domain/AuditableAcl.php create mode 100644 Tests/Model/Acl/EntryTest.php create mode 100644 Tests/Security/Acl/AuditableAclProviderTest.php create mode 100644 Tests/Security/Acl/Domain/AuditableAclTest.php diff --git a/Model/Acl/Entry.php b/Model/Acl/Entry.php index 46ec499..07000f6 100644 --- a/Model/Acl/Entry.php +++ b/Model/Acl/Entry.php @@ -12,7 +12,69 @@ namespace Propel\PropelBundle\Model\Acl; use Propel\PropelBundle\Model\Acl\om\BaseEntry; +use Propel\PropelBundle\Security\Acl\Domain\Entry as AclEntry; +use Propel\PropelBundle\Security\Acl\Domain\FieldEntry as AclFieldEntry; + +use Symfony\Component\Security\Acl\Model\AclInterface; +use Symfony\Component\Security\Acl\Model\EntryInterface; +use Symfony\Component\Security\Acl\Model\AuditableEntryInterface; +use Symfony\Component\Security\Acl\Model\FieldEntryInterface; + class Entry extends BaseEntry { + /** + * Transform a given ACL entry into a Entry model. + * + * The entry will not be persisted! + * + * @param EntryInterface $aclEntry + * + * @return Entry + */ + public static function fromAclEntry(EntryInterface $aclEntry) + { + $entry = new self(); + // Already persisted before? + if ($aclEntry->getId()) { + $entry->setId($aclEntry->getId()); + } + + $entry + ->setMask($aclEntry->getMask()) + ->setGranting($aclEntry->isGranting()) + ->setGrantingStrategy($aclEntry->getStrategy()) + ->setSecurityIdentity(SecurityIdentity::fromAclIdentity($aclEntry->getSecurityIdentity())) + ; + + if ($aclEntry instanceof FieldEntryInterface) { + $entry->setFieldName($aclEntry->getField()); + } + + if ($aclEntry instanceof AuditableEntryInterface) { + $entry + ->setAuditFailure($aclEntry->isAuditFailure()) + ->setAuditSuccess($aclEntry->isAuditSuccess()) + ; + } + + return $entry; + } + + /** + * Transform a given model entry into an ACL related Entry (ACE). + * + * @param Entry $modelEntry + * @param AclInterface $acl + * + * @return EntryInterface + */ + public static function toAclEntry(Entry $modelEntry, AclInterface $acl) + { + if (null === $modelEntry->getFieldName()) { + return new AclEntry($modelEntry, $acl); + } else { + return new AclFieldEntry($modelEntry, $acl); + } + } } diff --git a/Resources/config/acl_schema.xml b/Resources/config/acl_schema.xml index d39fba3..65d2383 100644 --- a/Resources/config/acl_schema.xml +++ b/Resources/config/acl_schema.xml @@ -66,7 +66,7 @@ - + diff --git a/Resources/config/propel.xml b/Resources/config/propel.xml index f1b1102..93d598a 100644 --- a/Resources/config/propel.xml +++ b/Resources/config/propel.xml @@ -13,7 +13,7 @@ Symfony\Bridge\Propel1\Form\Type\ModelType Propel\PropelBundle\Twig\Extension\SyntaxExtension Symfony\Bridge\Propel1\Form\PropelTypeGuesser - Propel\PropelBundle\Security\Acl\MutableAclProvider + Propel\PropelBundle\Security\Acl\AuditableAclProvider diff --git a/Security/Acl/AuditableAclProvider.php b/Security/Acl/AuditableAclProvider.php new file mode 100644 index 0000000..3baa094 --- /dev/null +++ b/Security/Acl/AuditableAclProvider.php @@ -0,0 +1,41 @@ + + */ +class AuditableAclProvider extends MutableAclProvider +{ + /** + * Get an ACL for this provider. + * + * @param PropelCollection $collection + * @param ObjectIdentityInterface $objectIdentity + * @param array $loadedSecurityIdentities + * @param AclInterface $parentAcl + * @param bool $inherited + * + * @return AuditableAcl + */ + protected function getAcl(PropelCollection $collection, ObjectIdentityInterface $objectIdentity, array $loadedSecurityIdentities = array(), AclInterface $parentAcl = null, $inherited = true) + { + return new AuditableAcl($collection, $objectIdentity, $this->permissionGrantingStrategy, $loadedSecurityIdentities, $parentAcl, $inherited, $this->connection); + } +} \ No newline at end of file diff --git a/Security/Acl/Domain/AuditableAcl.php b/Security/Acl/Domain/AuditableAcl.php new file mode 100644 index 0000000..c4223b7 --- /dev/null +++ b/Security/Acl/Domain/AuditableAcl.php @@ -0,0 +1,112 @@ + + */ +class AuditableAcl extends MutableAcl implements AuditableAclInterface +{ + /** + * Updates auditing for class-based ACE + * + * @param integer $index + * @param bool $auditSuccess + * @param bool $auditFailure + */ + public function updateClassAuditing($index, $auditSuccess, $auditFailure) + { + $this->updateAuditing($this->classAces, $index, $auditSuccess, $auditFailure); + } + + /** + * Updates auditing for class-field-based ACE + * + * @param integer $index + * @param string $field + * @param bool $auditSuccess + * @param bool $auditFailure + */ + public function updateClassFieldAuditing($index, $field, $auditSuccess, $auditFailure) + { + $this->validateField($this->classFieldAces, $field); + $this->updateAuditing($this->classFieldAces[$field], $index, $auditSuccess, $auditFailure); + } + + /** + * Updates auditing for object-based ACE + * + * @param integer $index + * @param bool $auditSuccess + * @param bool $auditFailure + */ + public function updateObjectAuditing($index, $auditSuccess, $auditFailure) + { + $this->updateAuditing($this->objectAces, $index, $auditSuccess, $auditFailure); + } + + /** + * Updates auditing for object-field-based ACE + * + * @param integer $index + * @param string $field + * @param bool $auditSuccess + * @param bool $auditFailure + */ + public function updateObjectFieldAuditing($index, $field, $auditSuccess, $auditFailure) + { + $this->validateField($this->objectFieldAces, $field); + $this->updateAuditing($this->objectFieldAces[$field], $index, $auditSuccess, $auditFailure); + } + + /** + * Update auditing on a single ACE. + * + * @throws InvalidArgumentException + * + * @param array $list + * @param int $index + * @param bool $auditSuccess + * @param bool $auditFailure + * + * @return AuditableAcl $this + */ + protected function updateAuditing(array &$list, $index, $auditSuccess, $auditFailure) + { + if (!is_bool($auditSuccess) or !is_bool($auditFailure)) { + throw new InvalidArgumentException('The given auditing flags are invalid. Please provide boolean only.'); + } + + $this->validateIndex($list, $index); + + $entry = ModelEntry::fromAclEntry($list[$index]) + ->setAuditSuccess($auditSuccess) + ->setAuditFailure($auditFailure) + ; + + $list[$index] = ModelEntry::toAclEntry($entry, $this); + + return $this; + } +} \ No newline at end of file diff --git a/Security/Acl/Domain/MutableAcl.php b/Security/Acl/Domain/MutableAcl.php index ce84294..48c5e2c 100644 --- a/Security/Acl/Domain/MutableAcl.php +++ b/Security/Acl/Domain/MutableAcl.php @@ -265,7 +265,7 @@ class MutableAcl extends Acl implements MutableAclInterface { $this ->validateField($this->classFieldAces, $field) - ->updateAce($this->classFieldAces[$field], $index, $mask, $strategy, $field) + ->updateAce($this->classFieldAces[$field], $index, $mask, $strategy) ; } @@ -292,7 +292,7 @@ class MutableAcl extends Acl implements MutableAclInterface public function updateObjectFieldAce($index, $field, $mask, $strategy = null) { $this->validateField($this->objectFieldAces, $field); - $this->updateAce($this->objectFieldAces[$field], $index, $mask, $strategy, $field); + $this->updateAce($this->objectFieldAces[$field], $index, $mask, $strategy); } /** @@ -388,40 +388,19 @@ class MutableAcl extends Acl implements MutableAclInterface * * @return MutableAcl $this */ - protected function updateAce(array &$list, $index, $mask, $strategy = null, $field = null) + protected function updateAce(array &$list, $index, $mask, $strategy = null) { $this->validateIndex($list, $index); - $beforeAce = $list[$index]; - /* @var $beforeAce Entry */ - $entry = new ModelEntry(); + $entry = ModelEntry::fromAclEntry($list[$index]); - // Already persisted before? - if ($beforeAce->getId()) { - $entry->setId($beforeAce->getId()); + // Apply updates + $entry->setMask($mask); + if (null !== $strategy) { + $entry->setGrantingStrategy($strategy); } - if (null === $strategy) { - $strategy = $beforeAce->getStrategy(); - } - - $entry - ->setMask($mask) - ->setGranting($beforeAce->isGranting()) - ->setGrantingStrategy($strategy) - ->setSecurityIdentity(SecurityIdentity::fromAclIdentity($beforeAce->getSecurityIdentity())) - ; - - if (null !== $field) { - $this->updateFields($field); - - $entry->setFieldName($field); - $newAce = new FieldEntry($entry, $this); - } else { - $newAce = new Entry($entry, $this); - } - - $list[$index] = $newAce; + $list[$index] = ModelEntry::toAclEntry($entry, $this); return $this; } diff --git a/Security/Acl/MutableAclProvider.php b/Security/Acl/MutableAclProvider.php index d50226a..50aec2c 100644 --- a/Security/Acl/MutableAclProvider.php +++ b/Security/Acl/MutableAclProvider.php @@ -37,6 +37,7 @@ use Symfony\Component\Security\Acl\Domain\FieldEntry; use Symfony\Component\Security\Acl\Model\AclInterface; use Symfony\Component\Security\Acl\Model\EntryInterface; use Symfony\Component\Security\Acl\Model\FieldEntryInterface; +use Symfony\Component\Security\Acl\Model\AuditableEntryInterface; use Symfony\Component\Security\Acl\Model\AclCacheInterface; use Symfony\Component\Security\Acl\Model\MutableAclInterface; use Symfony\Component\Security\Acl\Model\MutableAclProviderInterface; @@ -96,7 +97,7 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf $objIdentity->save($this->connection); } - return new MutableAcl($entries, $objectIdentity, $this->permissionGrantingStrategy, array(), null, false, $this->connection); + return $this->getAcl($entries, $objectIdentity, array(), null, false); } /** @@ -230,26 +231,30 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf foreach ($accessControlEntries as $order => $eachAce) { // If the given ACE has never been persisted, create a new one. if (null === $entry = $this->getPersistedAce($eachAce, $objectIdentity, $object)) { - $entry = new ModelEntry(); + $entry = ModelEntry::fromAclEntry($eachAce); } if (in_array($entry->getId(), $entries)) { - $entry = new ModelEntry(); - } - - if ($eachAce instanceof FieldEntryInterface) { - $entry->setFieldName($eachAce->getField()); + $entry = ModelEntry::fromAclEntry($eachAce); } + // Apply possible changes from local ACE. $entry ->setAceOrder($order) ->setAclClass($objectIdentity->getAclClass()) ->setMask($eachAce->getMask()) - ->setGranting($eachAce->isGranting()) - ->setGrantingStrategy($eachAce->getStrategy()) - ->setSecurityIdentity(SecurityIdentity::fromAclIdentity($eachAce->getSecurityIdentity())) ; + if ($eachAce instanceof AuditableEntryInterface) { + if (is_bool($eachAce->isAuditSuccess())) { + $entry->setAuditSuccess($eachAce->isAuditSuccess()); + } + + if (is_bool($eachAce->isAuditFailure())) { + $entry->setAuditFailure($eachAce->isAuditFailure()); + } + } + if (true === $object) { $entry->setObjectIdentity($objectIdentity); } diff --git a/Tests/Model/Acl/EntryTest.php b/Tests/Model/Acl/EntryTest.php new file mode 100644 index 0000000..696f1a1 --- /dev/null +++ b/Tests/Model/Acl/EntryTest.php @@ -0,0 +1,88 @@ + + */ +class EntryTest extends AclTestCase +{ + public function testToAclEntry() + { + $acl = $this->getMock('Propel\PropelBundle\Security\Acl\Domain\AuditableAcl', array(), array(), '', false, false); + $entry = $this->createModelEntry(); + + $aclEntry = ModelEntry::toAclEntry($entry, $acl); + $this->assertInstanceOf('Propel\PropelBundle\Security\Acl\Domain\Entry', $aclEntry); + $this->assertSame($acl, $aclEntry->getAcl()); + $this->assertEquals(42, $aclEntry->getId()); + $this->assertTrue($aclEntry->isAuditFailure()); + $this->assertFalse($aclEntry->isAuditSuccess()); + $this->assertEquals('all', $aclEntry->getStrategy()); + $this->assertTrue($aclEntry->isGranting()); + $this->assertEquals(64, $aclEntry->getMask()); + + return $aclEntry; + } + + /** + * @depends testToAclEntry + */ + public function testToAclEntryFieldEntry() + { + $acl = $this->getMock('Propel\PropelBundle\Security\Acl\Domain\AuditableAcl', array(), array(), '', false, false); + $entry = $this->createModelEntry(); + $entry->setFieldName('name'); + + $aclEntry = ModelEntry::toAclEntry($entry, $acl); + $this->assertInstanceOf('Propel\PropelBundle\Security\Acl\Domain\FieldEntry', $aclEntry); + } + + /** + * @depends testToAclEntry + */ + public function testFromAclEntry($aclEntry) + { + $modelEntry = ModelEntry::fromAclEntry($aclEntry); + + $this->assertInstanceOf('Propel\PropelBundle\Model\Acl\Entry', $modelEntry); + $this->assertEquals(42, $modelEntry->getId()); + $this->assertTrue($modelEntry->getAuditFailure()); + $this->assertFalse($modelEntry->getAuditSuccess()); + $this->assertEquals('all', $modelEntry->getGrantingStrategy()); + $this->assertTrue($modelEntry->getGranting()); + $this->assertEquals(64, $modelEntry->getMask()); + } + + protected function createModelEntry() + { + $entry = new ModelEntry(); + $entry + ->setId(42) + ->setAclClass($this->getAclClass()) + ->setSecurityIdentity(SecurityIdentity::fromAclIdentity($this->getRoleSecurityIdentity())) + ->setAuditFailure(true) + ->setAuditSuccess(false) + ->setGrantingStrategy('all') + ->setGranting(true) + ->setMask(64) + ; + + return $entry; + } +} \ No newline at end of file diff --git a/Tests/Security/Acl/AuditableAclProviderTest.php b/Tests/Security/Acl/AuditableAclProviderTest.php new file mode 100644 index 0000000..18de2c0 --- /dev/null +++ b/Tests/Security/Acl/AuditableAclProviderTest.php @@ -0,0 +1,87 @@ + + */ +class AuditableAclProviderTest extends AclTestCase +{ + public function testCreateAcl() + { + $acl = $this->getAclProvider()->createAcl($this->getAclObjectIdentity(1)); + + $this->assertNotEmpty($acl); + $this->assertInstanceOf('Propel\PropelBundle\Security\Acl\Domain\AuditableAcl', $acl); + $this->assertEquals(1, $acl->getId()); + } + + /** + * @depends testCreateAcl + */ + public function testUpdatePersistsAuditing() + { + $acl = $this->getAclProvider()->createAcl($this->getAclObjectIdentity(1)); + $acl->insertObjectAce($this->getRoleSecurityIdentity(), 64); + $this->getAclProvider()->updateAcl($acl); + + $entries = EntryQuery::create()->find($this->con); + $this->assertCount(1, $entries); + // default values + $this->assertFalse($entries[0]->getAuditSuccess()); + $this->assertTrue($entries[0]->getAuditFailure()); + + $acl->updateObjectAuditing(0, true, true); + $this->getAclProvider()->updateAcl($acl); + + $entries = EntryQuery::create()->find($this->con); + $this->assertCount(1, $entries); + $this->assertTrue($entries[0]->getAuditSuccess()); + $this->assertTrue($entries[0]->getAuditFailure()); + + $acl->updateObjectAuditing(0, false, true); + $this->getAclProvider()->updateAcl($acl); + + $entries = EntryQuery::create()->find($this->con); + $this->assertCount(1, $entries); + $this->assertFalse($entries[0]->getAuditSuccess()); + $this->assertTrue($entries[0]->getAuditFailure()); + + $acl->updateObjectAuditing(0, true, false); + $this->getAclProvider()->updateAcl($acl); + + $entries = EntryQuery::create()->find($this->con); + $this->assertCount(1, $entries); + $this->assertTrue($entries[0]->getAuditSuccess()); + $this->assertFalse($entries[0]->getAuditFailure()); + + $acl->updateObjectAuditing(0, false, false); + $this->getAclProvider()->updateAcl($acl); + + $entries = EntryQuery::create()->find($this->con); + $this->assertCount(1, $entries); + $this->assertFalse($entries[0]->getAuditSuccess()); + $this->assertFalse($entries[0]->getAuditFailure()); + } + + protected function getAclProvider() + { + return new AuditableAclProvider(new PermissionGrantingStrategy(), $this->con); + } +} \ No newline at end of file diff --git a/Tests/Security/Acl/Domain/AuditableAclTest.php b/Tests/Security/Acl/Domain/AuditableAclTest.php new file mode 100644 index 0000000..6f99576 --- /dev/null +++ b/Tests/Security/Acl/Domain/AuditableAclTest.php @@ -0,0 +1,214 @@ + + */ +class AuditableAclTest extends AclTestCase +{ + public function testUpdateAuditingInvalidIndex() + { + $collection = new PropelCollection(); + $collection->setModel('Propel\PropelBundle\Model\Acl\Entry'); + + $acl = new AuditableAcl($collection, $this->getAclObjectIdentity(), new PermissionGrantingStrategy()); + + $this->setExpectedException('OutOfBoundsException'); + $acl->updateObjectAuditing(0, false, false); + } + + public function testUpdateAuditingInvalidField() + { + $collection = new PropelCollection(); + $collection->setModel('Propel\PropelBundle\Model\Acl\Entry'); + + $obj = $this->createModelObjectIdentity(1); + $entry = $this->createEntry(); + $entry + ->setObjectIdentity($obj) + ->setFieldName('name') + ->setSecurityIdentity(SecurityIdentity::fromAclIdentity($this->getRoleSecurityIdentity())) + ->setAclClass($this->getAclClass()) + ; + $collection->append($entry); + $acl = new AuditableAcl($collection, $this->getAclObjectIdentity(), new PermissionGrantingStrategy()); + + $this->setExpectedException('InvalidArgumentException'); + $acl->updateObjectFieldAuditing(0, 'foo', false, false); + } + + public function testUpdateAuditingInvalidFlag() + { + $collection = new PropelCollection(); + $collection->setModel('Propel\PropelBundle\Model\Acl\Entry'); + + $obj = $this->createModelObjectIdentity(1); + $entry = $this->createEntry(); + $entry + ->setObjectIdentity($obj) + ->setSecurityIdentity(SecurityIdentity::fromAclIdentity($this->getRoleSecurityIdentity())) + ->setAclClass($this->getAclClass()) + ; + $collection->append($entry); + $acl = new AuditableAcl($collection, $this->getAclObjectIdentity(), new PermissionGrantingStrategy()); + + $this->setExpectedException('InvalidArgumentException'); + $acl->updateObjectAuditing(0, 'foo', 'bar'); + } + + public function testUpdateObjectAuditing() + { + $collection = new PropelCollection(); + $collection->setModel('Propel\PropelBundle\Model\Acl\Entry'); + + $obj = $this->createModelObjectIdentity(1); + $entry = $this->createEntry(); + $entry + ->setObjectIdentity($obj) + ->setSecurityIdentity(SecurityIdentity::fromAclIdentity($this->getRoleSecurityIdentity())) + ->setAclClass($this->getAclClass()) + ; + $collection->append($entry); + $acl = new AuditableAcl($collection, $this->getAclObjectIdentity(), new PermissionGrantingStrategy()); + + $aces = $acl->getObjectAces(); + $this->assertCount(1, $aces); + + $acl->updateObjectAuditing(0, true, true); + $aces = $acl->getObjectAces(); + $this->assertTrue($aces[0]->isAuditSuccess()); + $this->assertTrue($aces[0]->isAuditFailure()); + + $acl->updateObjectAuditing(0, false, true); + $aces = $acl->getObjectAces(); + $this->assertFalse($aces[0]->isAuditSuccess()); + $this->assertTrue($aces[0]->isAuditFailure()); + + $acl->updateObjectAuditing(0, true, false); + $aces = $acl->getObjectAces(); + $this->assertTrue($aces[0]->isAuditSuccess()); + $this->assertFalse($aces[0]->isAuditFailure()); + + $acl->updateObjectAuditing(0, false, false); + $aces = $acl->getObjectAces(); + $this->assertFalse($aces[0]->isAuditSuccess()); + $this->assertFalse($aces[0]->isAuditFailure()); + } + + /** + * @depends testUpdateObjectAuditing + */ + public function testUpdateObjectFieldAuditing() + { + $collection = new PropelCollection(); + $collection->setModel('Propel\PropelBundle\Model\Acl\Entry'); + + $obj = $this->createModelObjectIdentity(1); + $entry = $this->createEntry(); + $entry + ->setFieldName('name') + ->setObjectIdentity($obj) + ->setSecurityIdentity(SecurityIdentity::fromAclIdentity($this->getRoleSecurityIdentity())) + ->setAclClass($this->getAclClass()) + ; + $collection->append($entry); + + $acl = new AuditableAcl($collection, $this->getAclObjectIdentity(), new PermissionGrantingStrategy()); + + $aces = $acl->getObjectFieldAces('name'); + $this->assertCount(1, $aces); + + $acl->updateObjectFieldAuditing(0, 'name', true, true); + $aces = $acl->getObjectFieldAces('name'); + $this->assertTrue($aces[0]->isAuditSuccess()); + $this->assertTrue($aces[0]->isAuditFailure()); + + $acl->updateObjectFieldAuditing(0, 'name', false, false); + $aces = $acl->getObjectFieldAces('name'); + $this->assertFalse($aces[0]->isAuditSuccess()); + $this->assertFalse($aces[0]->isAuditFailure()); + } + + /** + * @depends testUpdateObjectAuditing + */ + public function testUpdateClassAuditing() + { + $collection = new PropelCollection(); + $collection->setModel('Propel\PropelBundle\Model\Acl\Entry'); + + $entry = $this->createEntry(); + $entry + ->setSecurityIdentity(SecurityIdentity::fromAclIdentity($this->getRoleSecurityIdentity())) + ->setAclClass($this->getAclClass()) + ; + $collection->append($entry); + + $acl = new AuditableAcl($collection, $this->getAclObjectIdentity(), new PermissionGrantingStrategy()); + + $aces = $acl->getClassAces(); + $this->assertCount(1, $aces); + + $acl->updateClassAuditing(0, true, true); + $aces = $acl->getClassAces('name'); + $this->assertTrue($aces[0]->isAuditSuccess()); + $this->assertTrue($aces[0]->isAuditFailure()); + + $acl->updateClassAuditing(0, false, false); + $aces = $acl->getClassAces(); + $this->assertFalse($aces[0]->isAuditSuccess()); + $this->assertFalse($aces[0]->isAuditFailure()); + } + + /** + * @depends testUpdateObjectAuditing + */ + public function testUpdateClassFieldAuditing() + { + $collection = new PropelCollection(); + $collection->setModel('Propel\PropelBundle\Model\Acl\Entry'); + + $entry = $this->createEntry(); + $entry + ->setFieldName('name') + ->setSecurityIdentity(SecurityIdentity::fromAclIdentity($this->getRoleSecurityIdentity())) + ->setAclClass($this->getAclClass()) + ; + $collection->append($entry); + + $acl = new AuditableAcl($collection, $this->getAclObjectIdentity(), new PermissionGrantingStrategy()); + + $aces = $acl->getClassFieldAces('name'); + $this->assertCount(1, $aces); + + $acl->updateClassFieldAuditing(0, 'name', true, true); + $aces = $acl->getClassFieldAces('name'); + $this->assertTrue($aces[0]->isAuditSuccess()); + $this->assertTrue($aces[0]->isAuditFailure()); + + $acl->updateClassFieldAuditing(0, 'name', false, false); + $aces = $acl->getClassFieldAces('name'); + $this->assertFalse($aces[0]->isAuditSuccess()); + $this->assertFalse($aces[0]->isAuditFailure()); + } +} \ No newline at end of file