pax_global_header 0000666 0000000 0000000 00000000064 14433205003 0014504 g ustar 00root root 0000000 0000000 52 comment=15b96b5dd6a65cafdc96b38ef3c3cebaa8b19cb7
security-acl-3.3.3/ 0000775 0000000 0000000 00000000000 14433205003 0014116 5 ustar 00root root 0000000 0000000 security-acl-3.3.3/.github/ 0000775 0000000 0000000 00000000000 14433205003 0015456 5 ustar 00root root 0000000 0000000 security-acl-3.3.3/.github/psalm/ 0000775 0000000 0000000 00000000000 14433205003 0016572 5 ustar 00root root 0000000 0000000 security-acl-3.3.3/.github/psalm/.gitignore 0000664 0000000 0000000 00000000007 14433205003 0020557 0 ustar 00root root 0000000 0000000 /cache
security-acl-3.3.3/.github/psalm/psalm.baseline.xml 0000664 0000000 0000000 00000000121 14433205003 0022203 0 ustar 00root root 0000000 0000000
security-acl-3.3.3/.github/workflows/ 0000775 0000000 0000000 00000000000 14433205003 0017513 5 ustar 00root root 0000000 0000000 security-acl-3.3.3/.github/workflows/ci.yml 0000664 0000000 0000000 00000003224 14433205003 0020632 0 ustar 00root root 0000000 0000000 name: CI
on:
pull_request:
push:
branches: [main]
jobs:
test:
name: 'Test ${{ matrix.deps }} on PHP ${{ matrix.php }}'
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
php: ['7.2.5', '7.3', '7.4', '8.0', '8.1', '8.2']
include:
- php: '7.4'
deps: lowest
deprecations: max[self]=0
- php: '8.0'
deps: highest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '${{ matrix.php }}'
coverage: none
- name: Configure composer
if: "${{ matrix.deps == 'highest' }}"
run: composer config minimum-stability dev
- name: Composer install
uses: ramsey/composer-install@v1
with:
dependency-versions: '${{ matrix.deps }}'
- name: Install PHPUnit
run: vendor/bin/simple-phpunit install
- name: Run tests
run: vendor/bin/simple-phpunit
env:
SYMFONY_DEPRECATIONS_HELPER: '${{ matrix.deprecations }}'
cs:
name: 'Code Style'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: PHP-CS-Fixer
uses: docker://oskarstark/php-cs-fixer-ga:3.11.0
with:
args: --diff --dry-run
security-acl-3.3.3/.github/workflows/psalm.yml 0000664 0000000 0000000 00000002252 14433205003 0021353 0 ustar 00root root 0000000 0000000 name: Static analysis
on:
pull_request: ~
defaults:
run:
shell: bash
jobs:
psalm:
name: Psalm
runs-on: Ubuntu-22.04
steps:
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.0'
ini-values: "memory_limit=-1"
coverage: none
- name: Checkout target branch
uses: actions/checkout@v2
with:
ref: ${{ github.base_ref }}
- name: Checkout PR
uses: actions/checkout@v2
- name: Install dependencies
run: |
composer remove --dev --no-update --no-interaction symfony/phpunit-bridge
composer require --no-update vimeo/psalm phpunit/phpunit:^9.5 psalm/plugin-phpunit
composer update --no-progress --ansi
git checkout -- composer.json
./vendor/bin/psalm --version
- name: Generate Psalm baseline
run: |
git checkout -m ${{ github.base_ref }}
./vendor/bin/psalm --set-baseline=.github/psalm/psalm.baseline.xml --no-progress
git checkout -m FETCH_HEAD
- name: Psalm
run: |
./vendor/bin/psalm --output-format=github --no-progress
security-acl-3.3.3/.gitignore 0000664 0000000 0000000 00000000136 14433205003 0016106 0 ustar 00root root 0000000 0000000 vendor/
composer.lock
phpunit.xml
.phpunit.result.cache
.php-cs-fixer.cache
.php-cs-fixer.php
security-acl-3.3.3/.php-cs-fixer.dist.php 0000664 0000000 0000000 00000000611 14433205003 0020152 0 ustar 00root root 0000000 0000000 setRules([
'@PHP71Migration' => true,
'@PHPUnit75Migration:risky' => true,
'@Symfony' => true,
'@Symfony:risky' => true,
'protected_to_private' => false,
])
->setRiskyAllowed(true)
->setFinder(
(new PhpCsFixer\Finder())
->in(__DIR__)
->append([__FILE__])
)
;
security-acl-3.3.3/CHANGELOG.md 0000664 0000000 0000000 00000000561 14433205003 0015731 0 ustar 00root root 0000000 0000000 CHANGELOG
=========
3.2.0
-----
* Change minimum PHP version to 7.2.5
* Add PSR-6 support for ACL caching
* Add support for `doctrine/cache` v2
* Drop support for Symfony 3
* Deprecate not implementing `__serialize()` and `__unserialize()` methods in
`AclInterface` and `EntryInterface` implementations. The methods will be
added to the interfaces in 4.0.
security-acl-3.3.3/Dbal/ 0000775 0000000 0000000 00000000000 14433205003 0014760 5 ustar 00root root 0000000 0000000 security-acl-3.3.3/Dbal/AclProvider.php 0000664 0000000 0000000 00000062653 14433205003 0017717 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Dbal;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Result;
use Symfony\Component\Security\Acl\Domain\Acl;
use Symfony\Component\Security\Acl\Domain\Entry;
use Symfony\Component\Security\Acl\Domain\FieldEntry;
use Symfony\Component\Security\Acl\Domain\ObjectIdentity;
use Symfony\Component\Security\Acl\Domain\RoleSecurityIdentity;
use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity;
use Symfony\Component\Security\Acl\Exception\AclNotFoundException;
use Symfony\Component\Security\Acl\Exception\NotAllAclsFoundException;
use Symfony\Component\Security\Acl\Model\AclCacheInterface;
use Symfony\Component\Security\Acl\Model\AclInterface;
use Symfony\Component\Security\Acl\Model\AclProviderInterface;
use Symfony\Component\Security\Acl\Model\ObjectIdentityInterface;
use Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface;
/**
* An ACL provider implementation.
*
* This provider assumes that all ACLs share the same PermissionGrantingStrategy.
*
* @author Johannes M. Schmitt
*/
class AclProvider implements AclProviderInterface
{
public const MAX_BATCH_SIZE = 30;
/**
* @var AclCacheInterface|null
*/
protected $cache;
/**
* @var Connection
*/
protected $connection;
protected $loadedAces = [];
protected $loadedAcls = [];
protected $options;
/**
* @var PermissionGrantingStrategyInterface
*/
private $permissionGrantingStrategy;
public function __construct(Connection $connection, PermissionGrantingStrategyInterface $permissionGrantingStrategy, array $options, AclCacheInterface $cache = null)
{
$this->cache = $cache;
$this->connection = $connection;
$this->options = $options;
$this->permissionGrantingStrategy = $permissionGrantingStrategy;
}
/**
* {@inheritdoc}
*/
public function findChildren(ObjectIdentityInterface $parentOid, $directChildrenOnly = false)
{
$sql = $this->getFindChildrenSql($parentOid, $directChildrenOnly);
$children = [];
foreach ($this->connection->executeQuery($sql)->fetchAllAssociative() as $data) {
$children[] = new ObjectIdentity($data['object_identifier'], $data['class_type']);
}
return $children;
}
/**
* {@inheritdoc}
*/
public function findAcl(ObjectIdentityInterface $oid, array $sids = [])
{
return $this->findAcls([$oid], $sids)->offsetGet($oid);
}
/**
* {@inheritdoc}
*/
public function findAcls(array $oids, array $sids = [])
{
/** @var \SplObjectStorage */
$result = new \SplObjectStorage();
$currentBatch = [];
$oidLookup = [];
for ($i = 0, $c = \count($oids); $i < $c; ++$i) {
$oid = $oids[$i];
$oidLookupKey = $oid->getIdentifier().$oid->getType();
$oidLookup[$oidLookupKey] = $oid;
$aclFound = false;
// check if result already contains an ACL
if ($result->contains($oid)) {
$aclFound = true;
}
// check if this ACL has already been hydrated
if (!$aclFound && isset($this->loadedAcls[$oid->getType()][$oid->getIdentifier()])) {
$acl = $this->loadedAcls[$oid->getType()][$oid->getIdentifier()];
if (!$acl->isSidLoaded($sids)) {
// FIXME: we need to load ACEs for the missing SIDs. This is never
// reached by the default implementation, since we do not
// filter by SID
throw new \RuntimeException('This is not supported by the default implementation.');
} else {
$result->attach($oid, $acl);
$aclFound = true;
}
}
// check if we can locate the ACL in the cache
if (!$aclFound && null !== $this->cache) {
$acl = $this->cache->getFromCacheByIdentity($oid);
if (null !== $acl) {
if ($acl->isSidLoaded($sids)) {
// check if any of the parents has been loaded since we need to
// ensure that there is only ever one ACL per object identity
$parentAcl = $acl->getParentAcl();
while (null !== $parentAcl) {
$parentOid = $parentAcl->getObjectIdentity();
if (isset($this->loadedAcls[$parentOid->getType()][$parentOid->getIdentifier()])) {
$acl->setParentAcl($this->loadedAcls[$parentOid->getType()][$parentOid->getIdentifier()]);
break;
} else {
$this->loadedAcls[$parentOid->getType()][$parentOid->getIdentifier()] = $parentAcl;
$this->updateAceIdentityMap($parentAcl);
}
$parentAcl = $parentAcl->getParentAcl();
}
$this->loadedAcls[$oid->getType()][$oid->getIdentifier()] = $acl;
$this->updateAceIdentityMap($acl);
$result->attach($oid, $acl);
$aclFound = true;
} else {
$this->cache->evictFromCacheByIdentity($oid);
foreach ($this->findChildren($oid) as $childOid) {
$this->cache->evictFromCacheByIdentity($childOid);
}
}
}
}
// looks like we have to load the ACL from the database
if (!$aclFound) {
$currentBatch[] = $oid;
}
// Is it time to load the current batch?
$currentBatchesCount = \count($currentBatch);
if ($currentBatchesCount > 0 && (self::MAX_BATCH_SIZE === $currentBatchesCount || ($i + 1) === $c)) {
try {
$loadedBatch = $this->lookupObjectIdentities($currentBatch, $sids, $oidLookup);
} catch (AclNotFoundException $e) {
if ($result->count()) {
$partialResultException = new NotAllAclsFoundException('The provider could not find ACLs for all object identities.');
$partialResultException->setPartialResult($result);
throw $partialResultException;
} else {
throw $e;
}
}
foreach ($loadedBatch as $loadedOid) {
$loadedAcl = $loadedBatch->offsetGet($loadedOid);
if (null !== $this->cache) {
$this->cache->putInCache($loadedAcl);
}
if (isset($oidLookup[$loadedOid->getIdentifier().$loadedOid->getType()])) {
$result->attach($loadedOid, $loadedAcl);
}
}
$currentBatch = [];
}
}
// check that we got ACLs for all the identities
foreach ($oids as $oid) {
if (!$result->contains($oid)) {
if (1 === \count($oids)) {
$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.');
$partialResultException->setPartialResult($result);
throw $partialResultException;
}
}
return $result;
}
/**
* Constructs the query used for looking up object identities and associated
* ACEs, and security identities.
*
* @return string
*/
protected function getLookupSql(array $ancestorIds)
{
// FIXME: add support for filtering by sids (right now we select all sids)
$sql = <<options['oid_table_name']} o
INNER JOIN {$this->options['class_table_name']} c ON c.id = o.class_id
LEFT JOIN {$this->options['entry_table_name']} e ON (
e.class_id = o.class_id AND (e.object_identity_id = o.id OR e.object_identity_id IS NULL)
)
LEFT JOIN {$this->options['sid_table_name']} s ON (
s.id = e.security_identity_id
)
WHERE (o.id =
SELECTCLAUSE;
$sql .= implode(' OR o.id = ', $ancestorIds).')';
return $sql;
}
protected function getAncestorLookupSql(array $batch)
{
$sql = <<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 (
SELECTCLAUSE;
$types = [];
$count = \count($batch);
for ($i = 0; $i < $count; ++$i) {
if (!isset($types[$batch[$i]->getType()])) {
$types[$batch[$i]->getType()] = true;
// if there is more than one type we can safely break out of the
// loop, because it is the differentiator factor on whether to
// query for only one or more class types
if (\count($types) > 1) {
break;
}
}
}
if (1 === \count($types)) {
$ids = [];
for ($i = 0; $i < $count; ++$i) {
$identifier = (string) $batch[$i]->getIdentifier();
$ids[] = $this->connection->quote($identifier);
}
$sql .= sprintf(
'(o.object_identifier IN (%s) AND c.class_type = %s)',
implode(',', $ids),
$this->connection->quote($batch[0]->getType())
);
} else {
$where = '(o.object_identifier = %s AND c.class_type = %s)';
for ($i = 0; $i < $count; ++$i) {
$sql .= sprintf(
$where,
$this->connection->quote($batch[$i]->getIdentifier()),
$this->connection->quote($batch[$i]->getType())
);
if ($i + 1 < $count) {
$sql .= ' OR ';
}
}
}
$sql .= ')';
return $sql;
}
/**
* Constructs the SQL for retrieving child object identities for the given
* object identities.
*
* @param bool $directChildrenOnly
*
* @return string
*/
protected function getFindChildrenSql(ObjectIdentityInterface $oid, $directChildrenOnly)
{
if (false === $directChildrenOnly) {
$query = <<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 = <<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;
}
return sprintf($query, $this->retrieveObjectIdentityPrimaryKey($oid));
}
/**
* Constructs the SQL for retrieving the primary key of the given object
* identity.
*
* @return string
*/
protected function getSelectObjectIdentityIdSql(ObjectIdentityInterface $oid)
{
$query = <<options['oid_table_name'],
$this->options['class_table_name'],
$this->connection->quote((string) $oid->getIdentifier()),
$this->connection->quote((string) $oid->getType())
);
}
/**
* Returns the primary key of the passed object identity.
*
* @return int
*/
final protected function retrieveObjectIdentityPrimaryKey(ObjectIdentityInterface $oid)
{
return $this->connection->executeQuery($this->getSelectObjectIdentityIdSql($oid))->fetchOne();
}
/**
* This method is called when an ACL instance is retrieved from the cache.
*/
private function updateAceIdentityMap(AclInterface $acl)
{
foreach (['classAces', 'classFieldAces', 'objectAces', 'objectFieldAces'] as $property) {
$reflection = new \ReflectionProperty($acl, $property);
$reflection->setAccessible(true);
$value = $reflection->getValue($acl);
if ('classAces' === $property || 'objectAces' === $property) {
$this->doUpdateAceIdentityMap($value);
} else {
foreach ($value as $field => $aces) {
$this->doUpdateAceIdentityMap($value[$field]);
}
}
$reflection->setValue($acl, $value);
$reflection->setAccessible(false);
}
}
/**
* Retrieves all the ids which need to be queried from the database
* including the ids of parent ACLs.
*
* @return array
*/
private function getAncestorIds(array $batch)
{
$sql = $this->getAncestorLookupSql($batch);
$ancestorIds = [];
foreach ($this->connection->executeQuery($sql)->fetchAllAssociative() as $data) {
// FIXME: skip ancestors which are cached
// Fix: Oracle returns keys in uppercase
$ancestorIds[] = reset($data);
}
return $ancestorIds;
}
/**
* Does either overwrite the passed ACE, or saves it in the global identity
* map to ensure every ACE only gets instantiated once.
*/
private function doUpdateAceIdentityMap(array &$aces)
{
foreach ($aces as $index => $ace) {
if (isset($this->loadedAces[$ace->getId()])) {
$aces[$index] = $this->loadedAces[$ace->getId()];
} else {
$this->loadedAces[$ace->getId()] = $ace;
}
}
}
/**
* This method is called for object identities which could not be retrieved
* from the cache, and for which thus a database query is required.
*
* @return \SplObjectStorage mapping object identities to ACL instances
*
* @throws AclNotFoundException
*/
private function lookupObjectIdentities(array $batch, array $sids, array $oidLookup)
{
$ancestorIds = $this->getAncestorIds($batch);
if (!$ancestorIds) {
throw new AclNotFoundException('There is no ACL for the given object identity.');
}
$sql = $this->getLookupSql($ancestorIds);
$stmt = $this->connection->executeQuery($sql);
return $this->hydrateObjectIdentities($stmt, $oidLookup, $sids);
}
/**
* This method is called to hydrate ACLs and ACEs.
*
* This method was designed for performance; thus, a lot of code has been
* inlined at the cost of readability, and maintainability.
*
* Keep in mind that changes to this method might severely reduce the
* performance of the entire ACL system.
*
* @return \SplObjectStorage
*
* @throws \RuntimeException
*/
private function hydrateObjectIdentities(Result $stmt, array $oidLookup, array $sids)
{
/** @var \SplObjectStorage */
$parentIdToFill = new \SplObjectStorage();
$acls = $aces = $emptyArray = [];
$oidCache = $oidLookup;
/** @var \SplObjectStorage */
$result = new \SplObjectStorage();
$loadedAces = &$this->loadedAces;
$loadedAcls = &$this->loadedAcls;
$permissionGrantingStrategy = $this->permissionGrantingStrategy;
// we need these to set protected properties on hydrated objects
$aclReflection = new \ReflectionClass(Acl::class);
$aclClassAcesProperty = $aclReflection->getProperty('classAces');
$aclClassAcesProperty->setAccessible(true);
$aclClassFieldAcesProperty = $aclReflection->getProperty('classFieldAces');
$aclClassFieldAcesProperty->setAccessible(true);
$aclObjectAcesProperty = $aclReflection->getProperty('objectAces');
$aclObjectAcesProperty->setAccessible(true);
$aclObjectFieldAcesProperty = $aclReflection->getProperty('objectFieldAces');
$aclObjectFieldAcesProperty->setAccessible(true);
$aclParentAclProperty = $aclReflection->getProperty('parentAcl');
$aclParentAclProperty->setAccessible(true);
// fetchAll() consumes more memory than consecutive calls to fetch(),
// but it is faster
foreach ($stmt->fetchAllNumeric() as $data) {
[$aclId,
$objectIdentifier,
$parentObjectIdentityId,
$entriesInheriting,
$classType,
$aceId,
$objectIdentityId,
$fieldName,
$aceOrder,
$mask,
$granting,
$grantingStrategy,
$auditSuccess,
$auditFailure,
$username,
$securityIdentifier] = array_values($data);
// FIX: remove duplicate slashes
$classType = str_replace('\\\\', '\\', $classType);
// has the ACL been hydrated during this hydration cycle?
if (isset($acls[$aclId])) {
$acl = $acls[$aclId];
// has the ACL been hydrated during any previous cycle, or was possibly loaded
// from cache?
} elseif (isset($loadedAcls[$classType][$objectIdentifier])) {
$acl = $loadedAcls[$classType][$objectIdentifier];
// keep reference in local array (saves us some hash calculations)
$acls[$aclId] = $acl;
// attach ACL to the result set; even though we do not enforce that every
// object identity has only one instance, we must make sure to maintain
// referential equality with the oids passed to findAcls()
$oidCacheKey = $objectIdentifier.$classType;
if (!isset($oidCache[$oidCacheKey])) {
$oidCache[$oidCacheKey] = $acl->getObjectIdentity();
}
$result->attach($oidCache[$oidCacheKey], $acl);
// so, this hasn't been hydrated yet
} else {
// create object identity if we haven't done so yet
$oidLookupKey = $objectIdentifier.$classType;
if (!isset($oidCache[$oidLookupKey])) {
$oidCache[$oidLookupKey] = new ObjectIdentity($objectIdentifier, $classType);
}
$acl = new Acl((int) $aclId, $oidCache[$oidLookupKey], $permissionGrantingStrategy, $emptyArray, (bool) $entriesInheriting);
// keep a local, and global reference to this ACL
$loadedAcls[$classType][$objectIdentifier] = $acl;
$acls[$aclId] = $acl;
// try to fill in parent ACL, or defer until all ACLs have been hydrated
if (null !== $parentObjectIdentityId) {
if (isset($acls[$parentObjectIdentityId])) {
$aclParentAclProperty->setValue($acl, $acls[$parentObjectIdentityId]);
} else {
$parentIdToFill->attach($acl, $parentObjectIdentityId);
}
}
$result->attach($oidCache[$oidLookupKey], $acl);
}
// check if this row contains an ACE record
if (null !== $aceId) {
// have we already hydrated ACEs for this ACL?
if (!isset($aces[$aclId])) {
$aces[$aclId] = [$emptyArray, $emptyArray, $emptyArray, $emptyArray];
}
// has this ACE already been hydrated during a previous cycle, or
// possible been loaded from cache?
// It is important to only ever have one ACE instance per actual row since
// some ACEs are shared between ACL instances
if (!isset($loadedAces[$aceId])) {
if (!isset($sids[$key = ($username ? '1' : '0').$securityIdentifier])) {
if ($username) {
$sids[$key] = new UserSecurityIdentity(
substr($securityIdentifier, 1 + $pos = strpos($securityIdentifier, '-')),
substr($securityIdentifier, 0, $pos)
);
} else {
$sids[$key] = new RoleSecurityIdentity($securityIdentifier);
}
}
if (null === $fieldName) {
$loadedAces[$aceId] = new Entry((int) $aceId, $acl, $sids[$key], $grantingStrategy, (int) $mask, (bool) $granting, (bool) $auditFailure, (bool) $auditSuccess);
} else {
$loadedAces[$aceId] = new FieldEntry((int) $aceId, $acl, $fieldName, $sids[$key], $grantingStrategy, (int) $mask, (bool) $granting, (bool) $auditFailure, (bool) $auditSuccess);
}
}
$ace = $loadedAces[$aceId];
// assign ACE to the correct property
if (null === $objectIdentityId) {
if (null === $fieldName) {
$aces[$aclId][0][$aceOrder] = $ace;
} else {
$aces[$aclId][1][$fieldName][$aceOrder] = $ace;
}
} else {
if (null === $fieldName) {
$aces[$aclId][2][$aceOrder] = $ace;
} else {
$aces[$aclId][3][$fieldName][$aceOrder] = $ace;
}
}
}
}
// We do not sort on database level since we only want certain subsets to be sorted,
// and we are going to read the entire result set anyway.
// Sorting on DB level increases query time by an order of magnitude while it is
// almost negligible when we use PHPs array sort functions.
foreach ($aces as $aclId => $aceData) {
$acl = $acls[$aclId];
ksort($aceData[0]);
$aclClassAcesProperty->setValue($acl, $aceData[0]);
foreach (array_keys($aceData[1]) as $fieldName) {
ksort($aceData[1][$fieldName]);
}
$aclClassFieldAcesProperty->setValue($acl, $aceData[1]);
ksort($aceData[2]);
$aclObjectAcesProperty->setValue($acl, $aceData[2]);
foreach (array_keys($aceData[3]) as $fieldName) {
ksort($aceData[3][$fieldName]);
}
$aclObjectFieldAcesProperty->setValue($acl, $aceData[3]);
}
// fill-in parent ACLs where this hasn't been done yet cause the parent ACL was not
// yet available
$processed = 0;
foreach ($parentIdToFill as $acl) {
$parentId = $parentIdToFill->offsetGet($acl);
// let's see if we have already hydrated this
if (isset($acls[$parentId])) {
$aclParentAclProperty->setValue($acl, $acls[$parentId]);
++$processed;
continue;
}
}
// reset reflection changes
$aclClassAcesProperty->setAccessible(false);
$aclClassFieldAcesProperty->setAccessible(false);
$aclObjectAcesProperty->setAccessible(false);
$aclObjectFieldAcesProperty->setAccessible(false);
$aclParentAclProperty->setAccessible(false);
// this should never be true if the database integrity hasn't been compromised
if ($processed < \count($parentIdToFill)) {
throw new \RuntimeException('Not all parent ids were populated. This implies an integrity problem.');
}
return $result;
}
}
security-acl-3.3.3/Dbal/MutableAclProvider.php 0000664 0000000 0000000 00000106476 14433205003 0021233 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Dbal;
use Doctrine\DBAL\Connection;
use Doctrine\Persistence\PropertyChangedListener;
use Symfony\Component\Security\Acl\Domain\Acl;
use Symfony\Component\Security\Acl\Domain\Entry;
use Symfony\Component\Security\Acl\Domain\RoleSecurityIdentity;
use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity;
use Symfony\Component\Security\Acl\Exception\AclAlreadyExistsException;
use Symfony\Component\Security\Acl\Exception\ConcurrentModificationException;
use Symfony\Component\Security\Acl\Model\AclCacheInterface;
use Symfony\Component\Security\Acl\Model\AclInterface;
use Symfony\Component\Security\Acl\Model\EntryInterface;
use Symfony\Component\Security\Acl\Model\MutableAclInterface;
use Symfony\Component\Security\Acl\Model\MutableAclProviderInterface;
use Symfony\Component\Security\Acl\Model\ObjectIdentityInterface;
use Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface;
use Symfony\Component\Security\Acl\Model\SecurityIdentityInterface;
/**
* An implementation of the MutableAclProviderInterface using Doctrine DBAL.
*
* @author Johannes M. Schmitt
*/
class MutableAclProvider extends AclProvider implements MutableAclProviderInterface, PropertyChangedListener
{
private $propertyChanges;
/**
* {@inheritdoc}
*/
public function __construct(Connection $connection, PermissionGrantingStrategyInterface $permissionGrantingStrategy, array $options, AclCacheInterface $cache = null)
{
parent::__construct($connection, $permissionGrantingStrategy, $options, $cache);
$this->propertyChanges = new \SplObjectStorage();
}
/**
* {@inheritdoc}
*/
public function createAcl(ObjectIdentityInterface $oid)
{
if (false !== $this->retrieveObjectIdentityPrimaryKey($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();
try {
$this->createObjectIdentity($oid);
$pk = $this->retrieveObjectIdentityPrimaryKey($oid);
$this->connection->executeStatement($this->getInsertObjectIdentityRelationSql($pk, $pk));
$this->connection->commit();
} catch (\Exception $e) {
$this->connection->rollBack();
throw $e;
}
// re-read the ACL from the database to ensure proper caching, etc.
return $this->findAcl($oid);
}
/**
* {@inheritdoc}
*/
public function deleteAcl(ObjectIdentityInterface $oid)
{
$this->connection->beginTransaction();
try {
foreach ($this->findChildren($oid, true) as $childOid) {
$this->deleteAcl($childOid);
}
$oidPK = $this->retrieveObjectIdentityPrimaryKey($oid);
$this->deleteAccessControlEntries($oidPK);
$this->deleteObjectIdentityRelations($oidPK);
$this->deleteObjectIdentity($oidPK);
$this->connection->commit();
} catch (\Exception $e) {
$this->connection->rollBack();
throw $e;
}
// evict the ACL from the in-memory identity map
if (isset($this->loadedAcls[$oid->getType()][$oid->getIdentifier()])) {
$this->propertyChanges->offsetUnset($this->loadedAcls[$oid->getType()][$oid->getIdentifier()]);
unset($this->loadedAcls[$oid->getType()][$oid->getIdentifier()]);
}
// evict the ACL from any caches
if (null !== $this->cache) {
$this->cache->evictFromCacheByIdentity($oid);
}
}
/**
* Deletes the security identity from the database.
* ACL entries have the CASCADE option on their foreign key so they will also get deleted.
*
* @throws \InvalidArgumentException
*/
public function deleteSecurityIdentity(SecurityIdentityInterface $sid)
{
$this->connection->executeStatement($this->getDeleteSecurityIdentityIdSql($sid));
}
/**
* {@inheritdoc}
*/
public function findAcls(array $oids, array $sids = [])
{
$result = parent::findAcls($oids, $sids);
foreach ($result as $oid) {
$acl = $result->offsetGet($oid);
if (false === $this->propertyChanges->contains($acl) && $acl instanceof MutableAclInterface) {
$acl->addPropertyChangedListener($this);
$this->propertyChanges->attach($acl, []);
}
$parentAcl = $acl->getParentAcl();
while (null !== $parentAcl) {
if (false === $this->propertyChanges->contains($parentAcl) && $acl instanceof MutableAclInterface) {
$parentAcl->addPropertyChangedListener($this);
$this->propertyChanges->attach($parentAcl, []);
}
$parentAcl = $parentAcl->getParentAcl();
}
}
return $result;
}
/**
* Implementation of PropertyChangedListener.
*
* This allows us to keep track of which values have been changed, so we don't
* have to do a full introspection when ->updateAcl() is called.
*
* @param mixed $sender
* @param string $propertyName
* @param mixed $oldValue
* @param mixed $newValue
*
* @return void
*
* @throws \InvalidArgumentException
*/
public function propertyChanged($sender, $propertyName, $oldValue, $newValue)
{
if (!$sender instanceof MutableAclInterface && !$sender instanceof EntryInterface) {
throw new \InvalidArgumentException('$sender must be an instance of MutableAclInterface, or EntryInterface.');
}
if ($sender instanceof EntryInterface) {
if (null === $sender->getId()) {
return;
}
$ace = $sender;
$sender = $ace->getAcl();
} else {
$ace = null;
}
if (false === $this->propertyChanges->contains($sender)) {
throw new \InvalidArgumentException('$sender is not being tracked by this provider.');
}
$propertyChanges = $this->propertyChanges->offsetGet($sender);
if (null === $ace) {
if (isset($propertyChanges[$propertyName])) {
$oldValue = $propertyChanges[$propertyName][0];
if ($oldValue === $newValue) {
unset($propertyChanges[$propertyName]);
} else {
$propertyChanges[$propertyName] = [$oldValue, $newValue];
}
} else {
$propertyChanges[$propertyName] = [$oldValue, $newValue];
}
} else {
if (!isset($propertyChanges['aces'])) {
$propertyChanges['aces'] = new \SplObjectStorage();
}
$acePropertyChanges = $propertyChanges['aces']->contains($ace) ? $propertyChanges['aces']->offsetGet($ace) : [];
if (isset($acePropertyChanges[$propertyName])) {
$oldValue = $acePropertyChanges[$propertyName][0];
if ($oldValue === $newValue) {
unset($acePropertyChanges[$propertyName]);
} else {
$acePropertyChanges[$propertyName] = [$oldValue, $newValue];
}
} else {
$acePropertyChanges[$propertyName] = [$oldValue, $newValue];
}
if (\count($acePropertyChanges) > 0) {
$propertyChanges['aces']->offsetSet($ace, $acePropertyChanges);
} else {
$propertyChanges['aces']->offsetUnset($ace);
if (0 === \count($propertyChanges['aces'])) {
unset($propertyChanges['aces']);
}
}
}
$this->propertyChanges->offsetSet($sender, $propertyChanges);
}
/**
* {@inheritdoc}
*/
public function updateAcl(MutableAclInterface $acl)
{
if (!$this->propertyChanges->contains($acl)) {
throw new \InvalidArgumentException('$acl is not tracked by this provider.');
}
$propertyChanges = $this->propertyChanges->offsetGet($acl);
// check if any changes were made to this ACL
if (0 === \count($propertyChanges)) {
return;
}
$sets = $sharedPropertyChanges = [];
$this->connection->beginTransaction();
try {
if (isset($propertyChanges['entriesInheriting'])) {
$sets[] = 'entries_inheriting = '.$this->connection->getDatabasePlatform()->convertBooleans($propertyChanges['entriesInheriting'][1]);
}
if (isset($propertyChanges['parentAcl'])) {
if (null === $propertyChanges['parentAcl'][1]) {
$sets[] = 'parent_object_identity_id = NULL';
} else {
$sets[] = 'parent_object_identity_id = '.(int) $propertyChanges['parentAcl'][1]->getId();
}
$this->regenerateAncestorRelations($acl);
$childAcls = $this->findAcls($this->findChildren($acl->getObjectIdentity(), false));
foreach ($childAcls as $childOid) {
$this->regenerateAncestorRelations($childAcls[$childOid]);
}
}
// check properties for deleted, and created ACEs, and perform deletions
// 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']);
}
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)
if (isset($propertyChanges['aces'])) {
$this->updateAces($propertyChanges['aces']);
}
// check properties for deleted, and created ACEs, and perform creations
if (isset($propertyChanges['classAces'])) {
$this->updateNewAceProperty('classAces', $propertyChanges['classAces']);
$sharedPropertyChanges['classAces'] = $propertyChanges['classAces'];
}
if (isset($propertyChanges['classFieldAces'])) {
$this->updateNewFieldAceProperty('classFieldAces', $propertyChanges['classFieldAces']);
$sharedPropertyChanges['classFieldAces'] = $propertyChanges['classFieldAces'];
}
if (isset($propertyChanges['objectAces'])) {
$this->updateNewAceProperty('objectAces', $propertyChanges['objectAces']);
}
if (isset($propertyChanges['objectFieldAces'])) {
$this->updateNewFieldAceProperty('objectFieldAces', $propertyChanges['objectFieldAces']);
}
// if there have been changes to shared properties, we need to synchronize other
// ACL instances for object identities of the same type that are already in-memory
if (\count($sharedPropertyChanges) > 0) {
$classAcesProperty = new \ReflectionProperty(Acl::class, 'classAces');
$classAcesProperty->setAccessible(true);
$classFieldAcesProperty = new \ReflectionProperty(Acl::class, 'classFieldAces');
$classFieldAcesProperty->setAccessible(true);
foreach ($this->loadedAcls[$acl->getObjectIdentity()->getType()] as $sameTypeAcl) {
if (isset($sharedPropertyChanges['classAces'])) {
if ($acl !== $sameTypeAcl && $classAcesProperty->getValue($sameTypeAcl) !== $sharedPropertyChanges['classAces'][0]) {
throw new ConcurrentModificationException('The "classAces" property has been modified concurrently.');
}
$classAcesProperty->setValue($sameTypeAcl, $sharedPropertyChanges['classAces'][1]);
}
if (isset($sharedPropertyChanges['classFieldAces'])) {
if ($acl !== $sameTypeAcl && $classFieldAcesProperty->getValue($sameTypeAcl) !== $sharedPropertyChanges['classFieldAces'][0]) {
throw new ConcurrentModificationException('The "classFieldAces" property has been modified concurrently.');
}
$classFieldAcesProperty->setValue($sameTypeAcl, $sharedPropertyChanges['classFieldAces'][1]);
}
}
}
// persist any changes to the acl_object_identities table
if (\count($sets) > 0) {
$this->connection->executeStatement($this->getUpdateObjectIdentitySql($acl->getId(), $sets));
}
$this->connection->commit();
} catch (\Exception $e) {
$this->connection->rollBack();
throw $e;
}
$this->propertyChanges->offsetSet($acl, []);
if (null !== $this->cache) {
if (\count($sharedPropertyChanges) > 0) {
// FIXME: Currently, there is no easy way to clear the cache for ACLs
// of a certain type. The problem here is that we need to make
// sure to clear the cache of all child ACLs as well, and these
// child ACLs might be of a different class type.
$this->cache->clearCache();
} else {
// if there are no shared property changes, it's sufficient to just delete
// the cache for this ACL
$this->cache->evictFromCacheByIdentity($acl->getObjectIdentity());
foreach ($this->findChildren($acl->getObjectIdentity()) as $childOid) {
$this->cache->evictFromCacheByIdentity($childOid);
}
}
}
}
/**
* Updates a user security identity when the user's username changes.
*
* @param string $oldUsername
*/
public function updateUserSecurityIdentity(UserSecurityIdentity $usid, $oldUsername)
{
$this->connection->executeStatement($this->getUpdateUserSecurityIdentitySql($usid, $oldUsername));
}
/**
* Constructs the SQL for deleting access control entries.
*
* @param int $oidPK
*
* @return string
*/
protected function getDeleteAccessControlEntriesSql($oidPK)
{
return sprintf(
'DELETE FROM %s WHERE object_identity_id = %d',
$this->options['entry_table_name'],
$oidPK
);
}
/**
* Constructs the SQL for deleting a specific ACE.
*
* @param int $acePK
*
* @return string
*/
protected function getDeleteAccessControlEntrySql($acePK)
{
return sprintf(
'DELETE FROM %s WHERE id = %d',
$this->options['entry_table_name'],
$acePK
);
}
/**
* Constructs the SQL for deleting an object identity.
*
* @param int $pk
*
* @return string
*/
protected function getDeleteObjectIdentitySql($pk)
{
return sprintf(
'DELETE FROM %s WHERE id = %d',
$this->options['oid_table_name'],
$pk
);
}
/**
* Constructs the SQL for deleting relation entries.
*
* @param int $pk
*
* @return string
*/
protected function getDeleteObjectIdentityRelationsSql($pk)
{
return sprintf(
'DELETE FROM %s WHERE object_identity_id = %d',
$this->options['oid_ancestors_table_name'],
$pk
);
}
/**
* Constructs the SQL for inserting an ACE.
*
* @param int $classId
* @param int|null $objectIdentityId
* @param string|null $field
* @param int $aceOrder
* @param int $securityIdentityId
* @param string $strategy
* @param int $mask
* @param bool $granting
* @param bool $auditSuccess
* @param bool $auditFailure
*
* @return string
*/
protected function getInsertAccessControlEntrySql($classId, $objectIdentityId, $field, $aceOrder, $securityIdentityId, $strategy, $mask, $granting, $auditSuccess, $auditFailure)
{
$query = <<options['entry_table_name'],
$classId,
null === $objectIdentityId ? 'NULL' : (int) $objectIdentityId,
null === $field ? 'NULL' : $this->connection->quote($field),
$aceOrder,
$securityIdentityId,
$mask,
$this->connection->getDatabasePlatform()->convertBooleans($granting),
$this->connection->quote($strategy),
$this->connection->getDatabasePlatform()->convertBooleans($auditSuccess),
$this->connection->getDatabasePlatform()->convertBooleans($auditFailure)
);
}
/**
* Constructs the SQL for inserting a new class type.
*
* @param string $classType
*
* @return string
*/
protected function getInsertClassSql($classType)
{
return sprintf(
'INSERT INTO %s (class_type) VALUES (%s)',
$this->options['class_table_name'],
$this->connection->quote($classType)
);
}
/**
* Constructs the SQL for inserting a relation entry.
*
* @param int $objectIdentityId
* @param int $ancestorId
*
* @return string
*/
protected function getInsertObjectIdentityRelationSql($objectIdentityId, $ancestorId)
{
return sprintf(
'INSERT INTO %s (object_identity_id, ancestor_id) VALUES (%d, %d)',
$this->options['oid_ancestors_table_name'],
$objectIdentityId,
$ancestorId
);
}
/**
* Constructs the SQL for inserting an object identity.
*
* @param string $identifier
* @param int $classId
* @param bool $entriesInheriting
*
* @return string
*/
protected function getInsertObjectIdentitySql($identifier, $classId, $entriesInheriting)
{
$query = <<options['oid_table_name'],
$classId,
$this->connection->quote($identifier),
$this->connection->getDatabasePlatform()->convertBooleans($entriesInheriting)
);
}
/**
* Constructs the SQL for inserting a security identity.
*
* @return string
*
* @throws \InvalidArgumentException
*/
protected function getInsertSecurityIdentitySql(SecurityIdentityInterface $sid)
{
if ($sid instanceof UserSecurityIdentity) {
$identifier = $sid->getClass().'-'.$sid->getUsername();
$username = true;
} elseif ($sid instanceof RoleSecurityIdentity) {
$identifier = $sid->getRole();
$username = false;
} else {
throw new \InvalidArgumentException('$sid must either be an instance of UserSecurityIdentity, or RoleSecurityIdentity.');
}
return sprintf(
'INSERT INTO %s (identifier, username) VALUES (%s, %s)',
$this->options['sid_table_name'],
$this->connection->quote($identifier),
$this->connection->getDatabasePlatform()->convertBooleans($username)
);
}
/**
* Constructs the SQL for selecting an ACE.
*
* @param int $classId
* @param int|null $oid
* @param string|null $field
* @param int $order
*
* @return string
*/
protected function getSelectAccessControlEntryIdSql($classId, $oid, $field, $order)
{
return sprintf(
'SELECT id FROM %s WHERE class_id = %d AND object_identity_id %s AND field_name %s AND ace_order = %d',
$this->options['entry_table_name'],
$classId,
null === $oid
? 'IS NULL'
: '= '.(int) $oid,
null === $field
? 'IS NULL'
: '= '.$this->connection->quote($field),
$order
);
}
/**
* Constructs the SQL for selecting the primary key associated with
* the passed class type.
*
* @param string $classType
*
* @return string
*/
protected function getSelectClassIdSql($classType)
{
return sprintf(
'SELECT id FROM %s WHERE class_type = %s',
$this->options['class_table_name'],
$this->connection->quote($classType)
);
}
/**
* Constructs the SQL for selecting the primary key of a security identity.
*
* @return string
*
* @throws \InvalidArgumentException
*/
protected function getSelectSecurityIdentityIdSql(SecurityIdentityInterface $sid)
{
if ($sid instanceof UserSecurityIdentity) {
$identifier = $sid->getClass().'-'.$sid->getUsername();
$username = true;
} elseif ($sid instanceof RoleSecurityIdentity) {
$identifier = $sid->getRole();
$username = false;
} else {
throw new \InvalidArgumentException('$sid must either be an instance of UserSecurityIdentity, or RoleSecurityIdentity.');
}
return sprintf(
'SELECT id FROM %s WHERE identifier = %s AND username = %s',
$this->options['sid_table_name'],
$this->connection->quote($identifier),
$this->connection->getDatabasePlatform()->convertBooleans($username)
);
}
/**
* Constructs the SQL to delete a security identity.
*
* @return string
*
* @throws \InvalidArgumentException
*/
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
*
* @return string
*
* @throws \InvalidArgumentException
*/
protected function getUpdateObjectIdentitySql($pk, array $changes)
{
if (0 === \count($changes)) {
throw new \InvalidArgumentException('There are no changes.');
}
return sprintf(
'UPDATE %s SET %s WHERE id = %d',
$this->options['oid_table_name'],
implode(', ', $changes),
$pk
);
}
/**
* Constructs the SQL for updating a user security identity.
*
* @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
*
* @return string
*
* @throws \InvalidArgumentException
*/
protected function getUpdateAccessControlEntrySql($pk, array $sets)
{
if (0 === \count($sets)) {
throw new \InvalidArgumentException('There are no changes.');
}
return sprintf(
'UPDATE %s SET %s WHERE id = %d',
$this->options['entry_table_name'],
implode(', ', $sets),
$pk
);
}
/**
* Creates the ACL for the passed object identity.
*/
private function createObjectIdentity(ObjectIdentityInterface $oid)
{
$classId = $this->createOrRetrieveClassId($oid->getType());
$this->connection->executeStatement($this->getInsertObjectIdentitySql($oid->getIdentifier(), $classId, true));
}
/**
* Returns the primary key for the passed class type.
*
* If the type does not yet exist in the database, it will be created.
*
* @param string $classType
*
* @return int
*/
private function createOrRetrieveClassId($classType)
{
if (false !== $id = $this->connection->executeQuery($this->getSelectClassIdSql($classType))->fetchOne()) {
return $id;
}
$this->connection->executeStatement($this->getInsertClassSql($classType));
return $this->connection->executeQuery($this->getSelectClassIdSql($classType))->fetchOne();
}
/**
* Returns the primary key for the passed security identity.
*
* If the security identity does not yet exist in the database, it will be
* created.
*
* @return int
*/
private function createOrRetrieveSecurityIdentityId(SecurityIdentityInterface $sid)
{
if (false !== $id = $this->connection->executeQuery($this->getSelectSecurityIdentityIdSql($sid))->fetchOne()) {
return $id;
}
$this->connection->executeStatement($this->getInsertSecurityIdentitySql($sid));
return $this->connection->executeQuery($this->getSelectSecurityIdentityIdSql($sid))->fetchOne();
}
/**
* Deletes all ACEs for the given object identity primary key.
*
* @param int $oidPK
*/
private function deleteAccessControlEntries($oidPK)
{
$this->connection->executeStatement($this->getDeleteAccessControlEntriesSql($oidPK));
}
/**
* Deletes the object identity from the database.
*
* @param int $pk
*/
private function deleteObjectIdentity($pk)
{
$this->connection->executeStatement($this->getDeleteObjectIdentitySql($pk));
}
/**
* Deletes all entries from the relations table from the database.
*
* @param int $pk
*/
private function deleteObjectIdentityRelations($pk)
{
$this->connection->executeStatement($this->getDeleteObjectIdentityRelationsSql($pk));
}
/**
* This regenerates the ancestor table which is used for fast read access.
*/
private function regenerateAncestorRelations(AclInterface $acl)
{
$pk = $acl->getId();
$this->connection->executeStatement($this->getDeleteObjectIdentityRelationsSql($pk));
$this->connection->executeStatement($this->getInsertObjectIdentityRelationSql($pk, $pk));
$parentAcl = $acl->getParentAcl();
while (null !== $parentAcl) {
$this->connection->executeStatement($this->getInsertObjectIdentityRelationSql($pk, $parentAcl->getId()));
$parentAcl = $parentAcl->getParentAcl();
}
}
/**
* This processes new entries changes on an ACE related property (classFieldAces, or objectFieldAces).
*
* @param string $name
*/
private function updateNewFieldAceProperty($name, array $changes)
{
$sids = new \SplObjectStorage();
$classIds = new \SplObjectStorage();
foreach ($changes[1] as $field => $new) {
for ($i = 0, $c = \count($new); $i < $c; ++$i) {
$ace = $new[$i];
if (null === $ace->getId()) {
if ($sids->contains($ace->getSecurityIdentity())) {
$sid = $sids->offsetGet($ace->getSecurityIdentity());
} else {
$sid = $this->createOrRetrieveSecurityIdentityId($ace->getSecurityIdentity());
}
$oid = $ace->getAcl()->getObjectIdentity();
if ($classIds->contains($oid)) {
$classId = $classIds->offsetGet($oid);
} else {
$classId = $this->createOrRetrieveClassId($oid->getType());
}
$objectIdentityId = 'classFieldAces' === $name ? null : $ace->getAcl()->getId();
$this->connection->executeStatement($this->getInsertAccessControlEntrySql($classId, $objectIdentityId, $field, $i, $sid, $ace->getStrategy(), $ace->getMask(), $ace->isGranting(), $ace->isAuditSuccess(), $ace->isAuditFailure()));
$aceId = $this->connection->executeQuery($this->getSelectAccessControlEntryIdSql($classId, $objectIdentityId, $field, $i))->fetchOne();
$this->loadedAces[$aceId] = $ace;
$aceIdProperty = new \ReflectionProperty(Entry::class, 'id');
$aceIdProperty->setAccessible(true);
$aceIdProperty->setValue($ace, (int) $aceId);
}
}
}
}
/**
* This processes old entries changes on an ACE related property (classFieldAces, or objectFieldAces).
*
* @param string $name
*/
private function updateOldFieldAceProperty($name, array $changes)
{
$currentIds = [];
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) {
$ace = $old[$i];
if (!isset($currentIds[$ace->getId()])) {
$this->connection->executeStatement($this->getDeleteAccessControlEntrySql($ace->getId()));
unset($this->loadedAces[$ace->getId()]);
}
}
}
}
/**
* This processes new entries changes on an ACE related property (classAces, or objectAces).
*
* @param string $name
*/
private function updateNewAceProperty($name, array $changes)
{
[$old, $new] = $changes;
$sids = new \SplObjectStorage();
$classIds = new \SplObjectStorage();
for ($i = 0, $c = \count($new); $i < $c; ++$i) {
$ace = $new[$i];
if (null === $ace->getId()) {
if ($sids->contains($ace->getSecurityIdentity())) {
$sid = $sids->offsetGet($ace->getSecurityIdentity());
} else {
$sid = $this->createOrRetrieveSecurityIdentityId($ace->getSecurityIdentity());
}
$oid = $ace->getAcl()->getObjectIdentity();
if ($classIds->contains($oid)) {
$classId = $classIds->offsetGet($oid);
} else {
$classId = $this->createOrRetrieveClassId($oid->getType());
}
$objectIdentityId = 'classAces' === $name ? null : $ace->getAcl()->getId();
$this->connection->executeStatement($this->getInsertAccessControlEntrySql($classId, $objectIdentityId, null, $i, $sid, $ace->getStrategy(), $ace->getMask(), $ace->isGranting(), $ace->isAuditSuccess(), $ace->isAuditFailure()));
$aceId = $this->connection->executeQuery($this->getSelectAccessControlEntryIdSql($classId, $objectIdentityId, null, $i))->fetchOne();
$this->loadedAces[$aceId] = $ace;
$aceIdProperty = new \ReflectionProperty($ace, 'id');
$aceIdProperty->setAccessible(true);
$aceIdProperty->setValue($ace, (int) $aceId);
}
}
}
/**
* This processes old entries changes on an ACE related property (classAces, or objectAces).
*
* @param string $name
*/
private function updateOldAceProperty($name, array $changes)
{
[$old, $new] = $changes;
$currentIds = [];
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()])) {
$this->connection->executeStatement($this->getDeleteAccessControlEntrySql($ace->getId()));
unset($this->loadedAces[$ace->getId()]);
}
}
}
/**
* Persists the changes which were made to ACEs to the database.
*/
private function updateAces(\SplObjectStorage $aces)
{
foreach ($aces as $ace) {
$this->updateAce($aces, $ace);
}
}
private function updateAce(\SplObjectStorage $aces, $ace)
{
$propertyChanges = $aces->offsetGet($ace);
$sets = [];
if (isset($propertyChanges['aceOrder'])
&& $propertyChanges['aceOrder'][1] > $propertyChanges['aceOrder'][0]
&& $propertyChanges == $aces->offsetGet($ace)) {
$aces->next();
if ($aces->valid()) {
$this->updateAce($aces, $aces->current());
}
}
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->executeStatement($this->getUpdateAccessControlEntrySql($ace->getId(), $sets));
}
}
security-acl-3.3.3/Dbal/Schema.php 0000664 0000000 0000000 00000014554 14433205003 0016702 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Dbal;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Platforms\SQLServerPlatform;
use Doctrine\DBAL\Schema\Schema as BaseSchema;
use Doctrine\DBAL\Schema\SchemaConfig;
/**
* The schema used for the ACL system.
*
* @author Johannes M. Schmitt
*/
final class Schema extends BaseSchema
{
protected $options;
protected $platform;
/**
* @param array $options the names for tables
*/
public function __construct(array $options, Connection $connection = null)
{
$schemaConfig = $this->createSchemaConfig($connection);
parent::__construct([], [], $schemaConfig);
$this->options = $options;
$this->platform = $connection ? $connection->getDatabasePlatform() : null;
$this->addClassTable();
$this->addSecurityIdentitiesTable();
$this->addObjectIdentitiesTable();
$this->addObjectIdentityAncestorsTable();
$this->addEntryTable();
}
/**
* Merges ACL schema with the given schema.
*/
public function addToSchema(BaseSchema $schema)
{
foreach ($this->getTables() as $table) {
$schema->_addTable($table);
}
foreach ($this->getSequences() as $sequence) {
$schema->_addSequence($sequence);
}
}
/**
* Adds the class table to the schema.
*/
protected function addClassTable()
{
$table = $this->createTable($this->options['class_table_name']);
$table->addColumn('id', 'integer', ['unsigned' => true, 'autoincrement' => true]);
$table->addColumn('class_type', 'string', ['length' => 200]);
$table->setPrimaryKey(['id']);
$table->addUniqueIndex(['class_type']);
}
/**
* Adds the entry table to the schema.
*/
protected function addEntryTable()
{
$table = $this->createTable($this->options['entry_table_name']);
$table->addColumn('id', 'integer', ['unsigned' => true, 'autoincrement' => true]);
$table->addColumn('class_id', 'integer', ['unsigned' => true]);
$table->addColumn('object_identity_id', 'integer', ['unsigned' => true, 'notnull' => false]);
$table->addColumn('field_name', 'string', ['length' => 50, 'notnull' => false]);
$table->addColumn('ace_order', 'smallint', ['unsigned' => true]);
$table->addColumn('security_identity_id', 'integer', ['unsigned' => true]);
$table->addColumn('mask', 'integer');
$table->addColumn('granting', 'boolean');
$table->addColumn('granting_strategy', 'string', ['length' => 30]);
$table->addColumn('audit_success', 'boolean');
$table->addColumn('audit_failure', 'boolean');
$table->setPrimaryKey(['id']);
$table->addUniqueIndex(['class_id', 'object_identity_id', 'field_name', 'ace_order']);
$table->addIndex(['class_id', 'object_identity_id', 'security_identity_id']);
$table->addForeignKeyConstraint($this->getTable($this->options['class_table_name']), ['class_id'], ['id'], ['onDelete' => 'CASCADE', 'onUpdate' => 'CASCADE']);
$table->addForeignKeyConstraint($this->getTable($this->options['oid_table_name']), ['object_identity_id'], ['id'], ['onDelete' => 'CASCADE', 'onUpdate' => 'CASCADE']);
$table->addForeignKeyConstraint($this->getTable($this->options['sid_table_name']), ['security_identity_id'], ['id'], ['onDelete' => 'CASCADE', 'onUpdate' => 'CASCADE']);
}
/**
* Adds the object identity table to the schema.
*/
protected function addObjectIdentitiesTable()
{
$table = $this->createTable($this->options['oid_table_name']);
$table->addColumn('id', 'integer', ['unsigned' => true, 'autoincrement' => true]);
$table->addColumn('class_id', 'integer', ['unsigned' => true]);
$table->addColumn('object_identifier', 'string', ['length' => 100]);
$table->addColumn('parent_object_identity_id', 'integer', ['unsigned' => true, 'notnull' => false]);
$table->addColumn('entries_inheriting', 'boolean');
$table->setPrimaryKey(['id']);
$table->addUniqueIndex(['object_identifier', 'class_id']);
$table->addIndex(['parent_object_identity_id']);
$table->addForeignKeyConstraint($table, ['parent_object_identity_id'], ['id']);
}
/**
* Adds the object identity relation table to the schema.
*/
protected function addObjectIdentityAncestorsTable()
{
$table = $this->createTable($this->options['oid_ancestors_table_name']);
$table->addColumn('object_identity_id', 'integer', ['unsigned' => true]);
$table->addColumn('ancestor_id', 'integer', ['unsigned' => true]);
$table->setPrimaryKey(['object_identity_id', 'ancestor_id']);
$oidTable = $this->getTable($this->options['oid_table_name']);
$action = 'CASCADE';
if ($this->platform instanceof SQLServerPlatform) {
// MS SQL Server does not support recursive cascading
$action = 'NO ACTION';
}
$table->addForeignKeyConstraint($oidTable, ['object_identity_id'], ['id'], ['onDelete' => $action, 'onUpdate' => $action]);
$table->addForeignKeyConstraint($oidTable, ['ancestor_id'], ['id'], ['onDelete' => $action, 'onUpdate' => $action]);
}
/**
* Adds the security identity table to the schema.
*/
protected function addSecurityIdentitiesTable()
{
$table = $this->createTable($this->options['sid_table_name']);
$table->addColumn('id', 'integer', ['unsigned' => true, 'autoincrement' => true]);
$table->addColumn('identifier', 'string', ['length' => 200]);
$table->addColumn('username', 'boolean');
$table->setPrimaryKey(['id']);
$table->addUniqueIndex(['identifier', 'username']);
}
private function createSchemaConfig(?Connection $connection): ?SchemaConfig
{
if (null === $connection) {
return null;
}
$schemaManager = method_exists($connection, 'createSchemaManager')
? $connection->createSchemaManager()
: $connection->getSchemaManager()
;
return $schemaManager->createSchemaConfig();
}
}
security-acl-3.3.3/Domain/ 0000775 0000000 0000000 00000000000 14433205003 0015325 5 ustar 00root root 0000000 0000000 security-acl-3.3.3/Domain/Acl.php 0000664 0000000 0000000 00000046345 14433205003 0016551 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Domain;
use Doctrine\Persistence\NotifyPropertyChanged;
use Doctrine\Persistence\PropertyChangedListener;
use Symfony\Component\Security\Acl\Model\AclInterface;
use Symfony\Component\Security\Acl\Model\AuditableAclInterface;
use Symfony\Component\Security\Acl\Model\EntryInterface;
use Symfony\Component\Security\Acl\Model\ObjectIdentityInterface;
use Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface;
use Symfony\Component\Security\Acl\Model\SecurityIdentityInterface;
/**
* An ACL implementation.
*
* Each object identity has exactly one associated ACL. Each ACL can have four
* different types of ACEs (class ACEs, object ACEs, class field ACEs, object field
* ACEs).
*
* You should not iterate over the ACEs yourself, but instead use isGranted(),
* or isFieldGranted(). These will utilize an implementation of PermissionGrantingStrategy
* internally.
*
* @author Johannes M. Schmitt
*/
class Acl implements AuditableAclInterface, NotifyPropertyChanged
{
private $parentAcl;
private $permissionGrantingStrategy;
private $objectIdentity;
private $classAces = [];
private $classFieldAces = [];
private $objectAces = [];
private $objectFieldAces = [];
private $id;
private $loadedSids;
private $entriesInheriting;
private $listeners = [];
/**
* Constructor.
*
* @param int $id
* @param bool $entriesInheriting
*/
public function __construct($id, ObjectIdentityInterface $objectIdentity, PermissionGrantingStrategyInterface $permissionGrantingStrategy, array $loadedSids, $entriesInheriting)
{
$this->id = $id;
$this->objectIdentity = $objectIdentity;
$this->permissionGrantingStrategy = $permissionGrantingStrategy;
$this->loadedSids = $loadedSids;
$this->entriesInheriting = $entriesInheriting;
}
/**
* Adds a property changed listener.
*
* @return void
*/
public function addPropertyChangedListener(PropertyChangedListener $listener)
{
$this->listeners[] = $listener;
}
/**
* {@inheritdoc}
*/
public function deleteClassAce(int $index)
{
$this->deleteAce('classAces', $index);
}
/**
* {@inheritdoc}
*/
public function deleteClassFieldAce(int $index, string $field)
{
$this->deleteFieldAce('classFieldAces', $index, $field);
}
/**
* {@inheritdoc}
*/
public function deleteObjectAce(int $index)
{
$this->deleteAce('objectAces', $index);
}
/**
* {@inheritdoc}
*/
public function deleteObjectFieldAce(int $index, string $field)
{
$this->deleteFieldAce('objectFieldAces', $index, $field);
}
/**
* {@inheritdoc}
*/
public function getClassAces()
{
return $this->classAces;
}
/**
* {@inheritdoc}
*/
public function getClassFieldAces(string $field)
{
return $this->classFieldAces[$field] ?? [];
}
/**
* {@inheritdoc}
*/
public function getObjectAces()
{
return $this->objectAces;
}
/**
* {@inheritdoc}
*/
public function getObjectFieldAces(string $field)
{
return $this->objectFieldAces[$field] ?? [];
}
/**
* {@inheritdoc}
*/
public function getId()
{
return $this->id;
}
/**
* {@inheritdoc}
*/
public function getObjectIdentity()
{
return $this->objectIdentity;
}
/**
* {@inheritdoc}
*/
public function getParentAcl()
{
return $this->parentAcl;
}
/**
* {@inheritdoc}
*/
public function insertClassAce(SecurityIdentityInterface $sid, int $mask, int $index = 0, bool $granting = true, ?string $strategy = null)
{
$this->insertAce('classAces', $index, $mask, $sid, $granting, $strategy);
}
/**
* {@inheritdoc}
*/
public function insertClassFieldAce(string $field, SecurityIdentityInterface $sid, int $mask, int $index = 0, bool $granting = true, ?string $strategy = null)
{
$this->insertFieldAce('classFieldAces', $index, $field, $mask, $sid, $granting, $strategy);
}
/**
* {@inheritdoc}
*/
public function insertObjectAce(SecurityIdentityInterface $sid, int $mask, int $index = 0, bool $granting = true, ?string $strategy = null)
{
$this->insertAce('objectAces', $index, $mask, $sid, $granting, $strategy);
}
/**
* {@inheritdoc}
*/
public function insertObjectFieldAce(string $field, SecurityIdentityInterface $sid, int $mask, int $index = 0, bool $granting = true, ?string $strategy = null)
{
$this->insertFieldAce('objectFieldAces', $index, $field, $mask, $sid, $granting, $strategy);
}
/**
* {@inheritdoc}
*/
public function isEntriesInheriting()
{
return $this->entriesInheriting;
}
/**
* {@inheritdoc}
*/
public function isFieldGranted(string $field, array $masks, array $securityIdentities, bool $administrativeMode = false)
{
return $this->permissionGrantingStrategy->isFieldGranted($this, $field, $masks, $securityIdentities, $administrativeMode);
}
/**
* {@inheritdoc}
*/
public function isGranted(array $masks, array $securityIdentities, bool $administrativeMode = false)
{
return $this->permissionGrantingStrategy->isGranted($this, $masks, $securityIdentities, $administrativeMode);
}
/**
* {@inheritdoc}
*/
public function isSidLoaded($securityIdentities)
{
if (!$this->loadedSids) {
return true;
}
if (!\is_array($securityIdentities)) {
$securityIdentities = [$securityIdentities];
}
foreach ($securityIdentities as $sid) {
if (!$sid instanceof SecurityIdentityInterface) {
throw new \InvalidArgumentException('$sid must be an instance of SecurityIdentityInterface.');
}
foreach ($this->loadedSids as $loadedSid) {
if ($loadedSid->equals($sid)) {
continue 2;
}
}
return false;
}
return true;
}
public function __serialize(): array
{
return [
null === $this->parentAcl ? null : $this->parentAcl->getId(),
$this->objectIdentity,
$this->classAces,
$this->classFieldAces,
$this->objectAces,
$this->objectFieldAces,
$this->id,
$this->loadedSids,
$this->entriesInheriting,
];
}
public function __unserialize(array $data): void
{
[$this->parentAcl,
$this->objectIdentity,
$this->classAces,
$this->classFieldAces,
$this->objectAces,
$this->objectFieldAces,
$this->id,
$this->loadedSids,
$this->entriesInheriting
] = $data;
$this->listeners = [];
}
/**
* @internal
*
* @final
*
* @return string
*/
public function serialize()
{
return serialize($this->__serialize());
}
/**
* @internal
*
* @final
*
* @param string $serialized
*/
public function unserialize($serialized)
{
$this->__unserialize(\is_array($serialized) ? $serialized : unserialize($serialized));
}
/**
* {@inheritdoc}
*/
public function setEntriesInheriting(bool $boolean)
{
if ($this->entriesInheriting !== $boolean) {
$this->onPropertyChanged('entriesInheriting', $this->entriesInheriting, $boolean);
$this->entriesInheriting = $boolean;
}
}
/**
* {@inheritdoc}
*/
public function setParentAcl(?AclInterface $acl = null)
{
if (null !== $acl && null === $acl->getId()) {
throw new \InvalidArgumentException('$acl must have an ID.');
}
if ($this->parentAcl !== $acl) {
$this->onPropertyChanged('parentAcl', $this->parentAcl, $acl);
$this->parentAcl = $acl;
}
}
/**
* {@inheritdoc}
*/
public function updateClassAce(int $index, int $mask, ?string $strategy = null)
{
$this->updateAce('classAces', $index, $mask, $strategy);
}
/**
* {@inheritdoc}
*/
public function updateClassFieldAce(int $index, string $field, int $mask, ?string $strategy = null)
{
$this->updateFieldAce('classFieldAces', $index, $field, $mask, $strategy);
}
/**
* {@inheritdoc}
*/
public function updateObjectAce(int $index, int $mask, ?string $strategy = null)
{
$this->updateAce('objectAces', $index, $mask, $strategy);
}
/**
* {@inheritdoc}
*/
public function updateObjectFieldAce(int $index, string $field, int $mask, ?string $strategy = null)
{
$this->updateFieldAce('objectFieldAces', $index, $field, $mask, $strategy);
}
/**
* {@inheritdoc}
*/
public function updateClassAuditing(int $index, bool $auditSuccess, bool $auditFailure)
{
$this->updateAuditing($this->classAces, $index, $auditSuccess, $auditFailure);
}
/**
* {@inheritdoc}
*/
public function updateClassFieldAuditing(int $index, string $field, bool $auditSuccess, bool $auditFailure)
{
if (!isset($this->classFieldAces[$field])) {
throw new \InvalidArgumentException(sprintf('There are no ACEs for field "%s".', $field));
}
$this->updateAuditing($this->classFieldAces[$field], $index, $auditSuccess, $auditFailure);
}
/**
* {@inheritdoc}
*/
public function updateObjectAuditing(int $index, bool $auditSuccess, bool $auditFailure)
{
$this->updateAuditing($this->objectAces, $index, $auditSuccess, $auditFailure);
}
/**
* {@inheritdoc}
*/
public function updateObjectFieldAuditing(int $index, string $field, bool $auditSuccess, bool $auditFailure)
{
if (!isset($this->objectFieldAces[$field])) {
throw new \InvalidArgumentException(sprintf('There are no ACEs for field "%s".', $field));
}
$this->updateAuditing($this->objectFieldAces[$field], $index, $auditSuccess, $auditFailure);
}
/**
* Deletes an ACE.
*
* @param string $property
* @param int $index
*
* @throws \OutOfBoundsException
*/
private function deleteAce($property, $index)
{
$aces = &$this->$property;
if (!isset($aces[$index])) {
throw new \OutOfBoundsException(sprintf('The index "%d" does not exist.', $index));
}
$oldValue = $this->$property;
unset($aces[$index]);
$this->$property = array_values($this->$property);
$this->onPropertyChanged($property, $oldValue, $this->$property);
for ($i = $index, $c = \count($this->$property); $i < $c; ++$i) {
$this->onEntryPropertyChanged($aces[$i], 'aceOrder', $i + 1, $i);
}
}
/**
* Deletes a field-based ACE.
*
* @param string $property
* @param int $index
* @param string $field
*
* @throws \OutOfBoundsException
*/
private function deleteFieldAce($property, $index, $field)
{
$aces = &$this->$property;
if (!isset($aces[$field][$index])) {
throw new \OutOfBoundsException(sprintf('The index "%d" does not exist.', $index));
}
$oldValue = $this->$property;
unset($aces[$field][$index]);
$aces[$field] = array_values($aces[$field]);
$this->onPropertyChanged($property, $oldValue, $this->$property);
for ($i = $index, $c = \count($aces[$field]); $i < $c; ++$i) {
$this->onEntryPropertyChanged($aces[$field][$i], 'aceOrder', $i + 1, $i);
}
}
/**
* Inserts an ACE.
*
* @param string $property
* @param int $index
* @param int $mask
* @param bool $granting
* @param string $strategy
*
* @throws \OutOfBoundsException
* @throws \InvalidArgumentException
*/
private function insertAce($property, $index, $mask, SecurityIdentityInterface $sid, $granting, $strategy = null)
{
if ($index < 0 || $index > \count($this->$property)) {
throw new \OutOfBoundsException(sprintf('The index must be in the interval [0, %d].', \count($this->$property)));
}
if (!\is_int($mask)) {
throw new \InvalidArgumentException('$mask must be an integer.');
}
if (null === $strategy) {
if (true === $granting) {
$strategy = PermissionGrantingStrategy::ALL;
} else {
$strategy = PermissionGrantingStrategy::ANY;
}
}
$aces = &$this->$property;
$oldValue = $this->$property;
if (isset($aces[$index])) {
$this->$property = array_merge(
\array_slice($this->$property, 0, $index),
[true],
\array_slice($this->$property, $index)
);
for ($i = $index, $c = \count($this->$property) - 1; $i < $c; ++$i) {
$this->onEntryPropertyChanged($aces[$i + 1], 'aceOrder', $i, $i + 1);
}
}
$aces[$index] = new Entry(null, $this, $sid, $strategy, $mask, $granting, false, false);
$this->onPropertyChanged($property, $oldValue, $this->$property);
}
/**
* Inserts a field-based ACE.
*
* @param string $property
* @param int $index
* @param string $field
* @param int $mask
* @param bool $granting
* @param string $strategy
*
* @throws \InvalidArgumentException
* @throws \OutOfBoundsException
*/
private function insertFieldAce($property, $index, $field, $mask, SecurityIdentityInterface $sid, $granting, $strategy = null)
{
$field = (string) $field;
if ('' === $field) {
throw new \InvalidArgumentException('$field cannot be empty.');
}
if (!\is_int($mask)) {
throw new \InvalidArgumentException('$mask must be an integer.');
}
if (null === $strategy) {
if (true === $granting) {
$strategy = PermissionGrantingStrategy::ALL;
} else {
$strategy = PermissionGrantingStrategy::ANY;
}
}
$aces = &$this->$property;
if (!isset($aces[$field])) {
$aces[$field] = [];
}
if ($index < 0 || $index > \count($aces[$field])) {
throw new \OutOfBoundsException(sprintf('The index must be in the interval [0, %d].', \count($this->$property)));
}
$oldValue = $aces;
if (isset($aces[$field][$index])) {
$aces[$field] = array_merge(
\array_slice($aces[$field], 0, $index),
[true],
\array_slice($aces[$field], $index)
);
for ($i = $index, $c = \count($aces[$field]) - 1; $i < $c; ++$i) {
$this->onEntryPropertyChanged($aces[$field][$i + 1], 'aceOrder', $i, $i + 1);
}
}
$aces[$field][$index] = new FieldEntry(null, $this, $field, $sid, $strategy, $mask, $granting, false, false);
$this->onPropertyChanged($property, $oldValue, $this->$property);
}
/**
* Updates an ACE.
*
* @param string $property
* @param int $index
* @param int $mask
* @param string $strategy
*
* @throws \OutOfBoundsException
*/
private function updateAce($property, $index, $mask, $strategy = null)
{
$aces = &$this->$property;
if (!isset($aces[$index])) {
throw new \OutOfBoundsException(sprintf('The index "%d" does not exist.', $index));
}
$ace = $aces[$index];
if ($mask !== $oldMask = $ace->getMask()) {
$this->onEntryPropertyChanged($ace, 'mask', $oldMask, $mask);
$ace->setMask($mask);
}
if (null !== $strategy && $strategy !== $oldStrategy = $ace->getStrategy()) {
$this->onEntryPropertyChanged($ace, 'strategy', $oldStrategy, $strategy);
$ace->setStrategy($strategy);
}
}
/**
* Updates auditing for an ACE.
*
* @param int $index
* @param bool $auditSuccess
* @param bool $auditFailure
*
* @throws \OutOfBoundsException
*/
private function updateAuditing(array &$aces, $index, $auditSuccess, $auditFailure)
{
if (!isset($aces[$index])) {
throw new \OutOfBoundsException(sprintf('The index "%d" does not exist.', $index));
}
if ($auditSuccess !== $aces[$index]->isAuditSuccess()) {
$this->onEntryPropertyChanged($aces[$index], 'auditSuccess', !$auditSuccess, $auditSuccess);
$aces[$index]->setAuditSuccess($auditSuccess);
}
if ($auditFailure !== $aces[$index]->isAuditFailure()) {
$this->onEntryPropertyChanged($aces[$index], 'auditFailure', !$auditFailure, $auditFailure);
$aces[$index]->setAuditFailure($auditFailure);
}
}
/**
* Updates a field-based ACE.
*
* @param string $property
* @param int $index
* @param string $field
* @param int $mask
* @param string $strategy
*
* @throws \InvalidArgumentException
* @throws \OutOfBoundsException
*/
private function updateFieldAce($property, $index, $field, $mask, $strategy = null)
{
$field = (string) $field;
if ('' === $field) {
throw new \InvalidArgumentException('$field cannot be empty.');
}
$aces = &$this->$property;
if (!isset($aces[$field][$index])) {
throw new \OutOfBoundsException(sprintf('The index "%d" does not exist.', $index));
}
$ace = $aces[$field][$index];
if ($mask !== $oldMask = $ace->getMask()) {
$this->onEntryPropertyChanged($ace, 'mask', $oldMask, $mask);
$ace->setMask($mask);
}
if (null !== $strategy && $strategy !== $oldStrategy = $ace->getStrategy()) {
$this->onEntryPropertyChanged($ace, 'strategy', $oldStrategy, $strategy);
$ace->setStrategy($strategy);
}
}
/**
* Called when a property of the ACL changes.
*
* @param string $name
* @param mixed $oldValue
* @param mixed $newValue
*/
private function onPropertyChanged($name, $oldValue, $newValue)
{
foreach ($this->listeners as $listener) {
$listener->propertyChanged($this, $name, $oldValue, $newValue);
}
}
/**
* Called when a property of an ACE associated with this ACL changes.
*
* @param string $name
* @param mixed $oldValue
* @param mixed $newValue
*/
private function onEntryPropertyChanged(EntryInterface $entry, $name, $oldValue, $newValue)
{
foreach ($this->listeners as $listener) {
$listener->propertyChanged($entry, $name, $oldValue, $newValue);
}
}
}
security-acl-3.3.3/Domain/AclCacheTrait.php 0000664 0000000 0000000 00000005570 14433205003 0020474 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Domain;
use Symfony\Component\Security\Acl\Model\AclInterface;
use Symfony\Component\Security\Acl\Model\ObjectIdentityInterface;
/**
* @author Johannes M. Schmitt
*
* @internal
*/
trait AclCacheTrait
{
private $prefix;
private $permissionGrantingStrategy;
/**
* Unserializes the ACL.
*/
private function unserializeAcl(string $serialized): ?AclInterface
{
$acl = unserialize($serialized);
if (null !== $parentId = $acl->getParentAcl()) {
$parentAcl = $this->getFromCacheById($parentId);
if (null === $parentAcl) {
return null;
}
$acl->setParentAcl($parentAcl);
}
$reflectionProperty = new \ReflectionProperty($acl, 'permissionGrantingStrategy');
$reflectionProperty->setAccessible(true);
$reflectionProperty->setValue($acl, $this->permissionGrantingStrategy);
$reflectionProperty->setAccessible(false);
$aceAclProperty = new \ReflectionProperty(Entry::class, 'acl');
$aceAclProperty->setAccessible(true);
foreach ($acl->getObjectAces() as $ace) {
$aceAclProperty->setValue($ace, $acl);
}
foreach ($acl->getClassAces() as $ace) {
$aceAclProperty->setValue($ace, $acl);
}
$aceClassFieldProperty = new \ReflectionProperty($acl, 'classFieldAces');
$aceClassFieldProperty->setAccessible(true);
foreach ($aceClassFieldProperty->getValue($acl) as $aces) {
foreach ($aces as $ace) {
$aceAclProperty->setValue($ace, $acl);
}
}
$aceClassFieldProperty->setAccessible(false);
$aceObjectFieldProperty = new \ReflectionProperty($acl, 'objectFieldAces');
$aceObjectFieldProperty->setAccessible(true);
foreach ($aceObjectFieldProperty->getValue($acl) as $aces) {
foreach ($aces as $ace) {
$aceAclProperty->setValue($ace, $acl);
}
}
$aceObjectFieldProperty->setAccessible(false);
$aceAclProperty->setAccessible(false);
return $acl;
}
/**
* Returns the key for the object identity.
*/
private function getDataKeyByIdentity(ObjectIdentityInterface $oid): string
{
return $this->prefix.md5($oid->getType()).sha1($oid->getType())
.'_'.md5($oid->getIdentifier()).sha1($oid->getIdentifier());
}
/**
* Returns the alias key for the object identity key.
*/
private function getAliasKeyForIdentity(string $aclId): string
{
return $this->prefix.$aclId;
}
}
security-acl-3.3.3/Domain/AclCollectionCache.php 0000664 0000000 0000000 00000004065 14433205003 0021502 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Domain;
use Symfony\Component\Security\Acl\Model\AclProviderInterface;
use Symfony\Component\Security\Acl\Model\ObjectIdentityRetrievalStrategyInterface;
use Symfony\Component\Security\Acl\Model\SecurityIdentityRetrievalStrategyInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
/**
* This service caches ACLs for an entire collection of objects.
*
* @author Johannes M. Schmitt
*/
class AclCollectionCache
{
private $aclProvider;
private $objectIdentityRetrievalStrategy;
private $securityIdentityRetrievalStrategy;
/**
* Constructor.
*/
public function __construct(AclProviderInterface $aclProvider, ObjectIdentityRetrievalStrategyInterface $oidRetrievalStrategy, SecurityIdentityRetrievalStrategyInterface $sidRetrievalStrategy)
{
$this->aclProvider = $aclProvider;
$this->objectIdentityRetrievalStrategy = $oidRetrievalStrategy;
$this->securityIdentityRetrievalStrategy = $sidRetrievalStrategy;
}
/**
* Batch loads ACLs for an entire collection; thus, it reduces the number
* of required queries considerably.
*
* @param mixed $collection anything that can be passed to foreach()
* @param TokenInterface[] $tokens an array of TokenInterface implementations
*/
public function cache($collection, array $tokens = [])
{
$sids = [];
foreach ($tokens as $token) {
$sids = array_merge($sids, $this->securityIdentityRetrievalStrategy->getSecurityIdentities($token));
}
$oids = [];
foreach ($collection as $domainObject) {
$oids[] = $this->objectIdentityRetrievalStrategy->getObjectIdentity($domainObject);
}
$this->aclProvider->findAcls($oids, $sids);
}
}
security-acl-3.3.3/Domain/AuditLogger.php 0000664 0000000 0000000 00000002410 14433205003 0020241 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Domain;
use Symfony\Component\Security\Acl\Model\AuditableEntryInterface;
use Symfony\Component\Security\Acl\Model\AuditLoggerInterface;
use Symfony\Component\Security\Acl\Model\EntryInterface;
/**
* Base audit logger implementation.
*
* @author Johannes M. Schmitt
*/
abstract class AuditLogger implements AuditLoggerInterface
{
/**
* Performs some checks if logging was requested.
*
* @param bool $granted
*/
public function logIfNeeded($granted, EntryInterface $ace)
{
if (!$ace instanceof AuditableEntryInterface) {
return;
}
if ($granted && $ace->isAuditSuccess()) {
$this->doLog($granted, $ace);
} elseif (!$granted && $ace->isAuditFailure()) {
$this->doLog($granted, $ace);
}
}
/**
* This method is only called when logging is needed.
*
* @param bool $granted
*/
abstract protected function doLog($granted, EntryInterface $ace);
}
security-acl-3.3.3/Domain/DoctrineAclCache.php 0000664 0000000 0000000 00000007143 14433205003 0021156 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Domain;
use Doctrine\Common\Cache\Cache;
use Doctrine\Common\Cache\CacheProvider;
use Symfony\Component\Security\Acl\Model\AclCacheInterface;
use Symfony\Component\Security\Acl\Model\AclInterface;
use Symfony\Component\Security\Acl\Model\ObjectIdentityInterface;
use Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface;
/**
* This class is a wrapper around the actual cache implementation.
*
* @author Johannes M. Schmitt
*/
class DoctrineAclCache implements AclCacheInterface
{
use AclCacheTrait;
public const PREFIX = 'sf2_acl_';
private $cache;
/**
* Constructor.
*
* @param string $prefix
*
* @throws \InvalidArgumentException
*/
public function __construct(Cache $cache, PermissionGrantingStrategyInterface $permissionGrantingStrategy, $prefix = self::PREFIX)
{
$prefix = (string) $prefix;
if ('' === $prefix) {
throw new \InvalidArgumentException('$prefix cannot be empty.');
}
$this->cache = $cache;
$this->permissionGrantingStrategy = $permissionGrantingStrategy;
$this->prefix = $prefix;
}
/**
* {@inheritdoc}
*/
public function clearCache()
{
if ($this->cache instanceof CacheProvider) {
$this->cache->deleteAll();
}
}
/**
* {@inheritdoc}
*/
public function evictFromCacheById($aclId)
{
$lookupKey = $this->getAliasKeyForIdentity($aclId);
if (!$this->cache->contains($lookupKey)) {
return;
}
$key = $this->cache->fetch($lookupKey);
if ($this->cache->contains($key)) {
$this->cache->delete($key);
}
$this->cache->delete($lookupKey);
}
/**
* {@inheritdoc}
*/
public function evictFromCacheByIdentity(ObjectIdentityInterface $oid)
{
$key = $this->getDataKeyByIdentity($oid);
if (!$this->cache->contains($key)) {
return;
}
$this->cache->delete($key);
}
/**
* {@inheritdoc}
*/
public function getFromCacheById($aclId)
{
$lookupKey = $this->getAliasKeyForIdentity($aclId);
if (!$this->cache->contains($lookupKey)) {
return;
}
$key = $this->cache->fetch($lookupKey);
if (!$this->cache->contains($key)) {
$this->cache->delete($lookupKey);
return;
}
return $this->unserializeAcl($this->cache->fetch($key));
}
/**
* {@inheritdoc}
*/
public function getFromCacheByIdentity(ObjectIdentityInterface $oid)
{
$key = $this->getDataKeyByIdentity($oid);
if (!$this->cache->contains($key)) {
return;
}
return $this->unserializeAcl($this->cache->fetch($key));
}
/**
* {@inheritdoc}
*/
public function putInCache(AclInterface $acl)
{
if (null === $acl->getId()) {
throw new \InvalidArgumentException('Transient ACLs cannot be cached.');
}
if (null !== $parentAcl = $acl->getParentAcl()) {
$this->putInCache($parentAcl);
}
$key = $this->getDataKeyByIdentity($acl->getObjectIdentity());
$this->cache->save($key, serialize($acl));
$this->cache->save($this->getAliasKeyForIdentity($acl->getId()), $key);
}
}
security-acl-3.3.3/Domain/Entry.php 0000664 0000000 0000000 00000010505 14433205003 0017140 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Domain;
use Symfony\Component\Security\Acl\Model\AclInterface;
use Symfony\Component\Security\Acl\Model\AuditableEntryInterface;
use Symfony\Component\Security\Acl\Model\SecurityIdentityInterface;
/**
* Auditable ACE implementation.
*
* @author Johannes M. Schmitt
*/
class Entry implements AuditableEntryInterface
{
private $acl;
private $mask;
private $id;
private $securityIdentity;
private $strategy;
private $auditFailure;
private $auditSuccess;
private $granting;
public function __construct(?int $id, AclInterface $acl, SecurityIdentityInterface $sid, string $strategy, int $mask, bool $granting, bool $auditFailure, bool $auditSuccess)
{
$this->id = $id;
$this->acl = $acl;
$this->securityIdentity = $sid;
$this->strategy = $strategy;
$this->mask = $mask;
$this->granting = $granting;
$this->auditFailure = $auditFailure;
$this->auditSuccess = $auditSuccess;
}
/**
* {@inheritdoc}
*/
public function getAcl()
{
return $this->acl;
}
/**
* {@inheritdoc}
*/
public function getMask()
{
return $this->mask;
}
/**
* {@inheritdoc}
*/
public function getId()
{
return $this->id;
}
/**
* {@inheritdoc}
*/
public function getSecurityIdentity()
{
return $this->securityIdentity;
}
/**
* {@inheritdoc}
*/
public function getStrategy()
{
return $this->strategy;
}
/**
* {@inheritdoc}
*/
public function isAuditFailure()
{
return $this->auditFailure;
}
/**
* {@inheritdoc}
*/
public function isAuditSuccess()
{
return $this->auditSuccess;
}
/**
* {@inheritdoc}
*/
public function isGranting()
{
return $this->granting;
}
/**
* Turns on/off auditing on permissions denials.
*
* Do never call this method directly. Use the respective methods on the
* AclInterface instead.
*
* @param bool $boolean
*/
public function setAuditFailure($boolean)
{
$this->auditFailure = $boolean;
}
/**
* Turns on/off auditing on permission grants.
*
* Do never call this method directly. Use the respective methods on the
* AclInterface instead.
*
* @param bool $boolean
*/
public function setAuditSuccess($boolean)
{
$this->auditSuccess = $boolean;
}
/**
* Sets the permission mask.
*
* Do never call this method directly. Use the respective methods on the
* AclInterface instead.
*
* @param int $mask
*/
public function setMask($mask)
{
$this->mask = $mask;
}
/**
* Sets the mask comparison strategy.
*
* Do never call this method directly. Use the respective methods on the
* AclInterface instead.
*
* @param string $strategy
*/
public function setStrategy($strategy)
{
$this->strategy = $strategy;
}
public function __serialize(): array
{
return [
$this->mask,
$this->id,
$this->securityIdentity,
$this->strategy,
$this->auditFailure,
$this->auditSuccess,
$this->granting,
];
}
public function __unserialize(array $data): void
{
[$this->mask,
$this->id,
$this->securityIdentity,
$this->strategy,
$this->auditFailure,
$this->auditSuccess,
$this->granting
] = $data;
}
/**
* @internal
*
* @final
*
* @return string
*/
public function serialize()
{
return serialize($this->__serialize());
}
/**
* @internal
*
* @final
*
* @param string $serialized
*/
public function unserialize($serialized)
{
$this->__unserialize(\is_array($serialized) ? $serialized : unserialize($serialized));
}
}
security-acl-3.3.3/Domain/FieldEntry.php 0000664 0000000 0000000 00000003017 14433205003 0020104 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Domain;
use Symfony\Component\Security\Acl\Model\AclInterface;
use Symfony\Component\Security\Acl\Model\FieldEntryInterface;
use Symfony\Component\Security\Acl\Model\SecurityIdentityInterface;
/**
* Field-aware ACE implementation which is auditable.
*
* @author Johannes M. Schmitt
*/
class FieldEntry extends Entry implements FieldEntryInterface
{
private $field;
public function __construct(?int $id, AclInterface $acl, string $field, SecurityIdentityInterface $sid, string $strategy, int $mask, bool $granting, bool $auditFailure, $auditSuccess)
{
parent::__construct($id, $acl, $sid, $strategy, $mask, $granting, $auditFailure, $auditSuccess);
$this->field = $field;
}
/**
* {@inheritdoc}
*/
public function getField()
{
return $this->field;
}
/**
* {@inheritdoc}
*/
public function __serialize(): array
{
return [$this->field, parent::__serialize()];
}
/**
* {@inheritdoc}
*/
public function __unserialize(array $data): void
{
[$this->field, $parentData] = $data;
$parentData = \is_array($parentData) ? $parentData : unserialize($parentData);
parent::__unserialize($parentData);
}
}
security-acl-3.3.3/Domain/ObjectIdentity.php 0000664 0000000 0000000 00000006141 14433205003 0020760 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Domain;
use Symfony\Component\Security\Acl\Exception\InvalidDomainObjectException;
use Symfony\Component\Security\Acl\Model\DomainObjectInterface;
use Symfony\Component\Security\Acl\Model\ObjectIdentityInterface;
use Symfony\Component\Security\Acl\Util\ClassUtils;
/**
* ObjectIdentity implementation.
*
* @author Johannes M. Schmitt
*/
final class ObjectIdentity implements ObjectIdentityInterface
{
private $identifier;
private $type;
/**
* Constructor.
*
* @param string $identifier
* @param string $type
*
* @throws \InvalidArgumentException
*/
public function __construct($identifier, $type)
{
if ('' === $identifier) {
throw new \InvalidArgumentException('$identifier cannot be empty.');
}
if (empty($type)) {
throw new \InvalidArgumentException('$type cannot be empty.');
}
$this->identifier = $identifier;
$this->type = $type;
}
/**
* Constructs an ObjectIdentity for the given domain object.
*
* @param object $domainObject
*
* @return ObjectIdentity
*
* @throws InvalidDomainObjectException
*/
public static function fromDomainObject($domainObject)
{
if (!\is_object($domainObject)) {
throw new InvalidDomainObjectException('$domainObject must be an object.');
}
try {
if ($domainObject instanceof DomainObjectInterface) {
return new self($domainObject->getObjectIdentifier(), ClassUtils::getRealClass($domainObject));
} elseif (method_exists($domainObject, 'getId')) {
return new self((string) $domainObject->getId(), ClassUtils::getRealClass($domainObject));
}
} catch (\InvalidArgumentException $e) {
throw new InvalidDomainObjectException($e->getMessage(), 0, $e);
}
throw new InvalidDomainObjectException('$domainObject must either implement the DomainObjectInterface, or have a method named "getId".');
}
/**
* {@inheritdoc}
*/
public function getIdentifier()
{
return $this->identifier;
}
/**
* {@inheritdoc}
*/
public function getType()
{
return $this->type;
}
/**
* {@inheritdoc}
*/
public function equals(ObjectIdentityInterface $identity)
{
// comparing the identifier with === might lead to problems, so we
// waive this restriction
return $this->identifier == $identity->getIdentifier()
&& $this->type === $identity->getType();
}
/**
* Returns a textual representation of this object identity.
*
* @return string
*/
public function __toString()
{
return sprintf('ObjectIdentity(%s, %s)', $this->identifier, $this->type);
}
}
security-acl-3.3.3/Domain/ObjectIdentityRetrievalStrategy.php 0000664 0000000 0000000 00000001665 14433205003 0024367 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Domain;
use Symfony\Component\Security\Acl\Exception\InvalidDomainObjectException;
use Symfony\Component\Security\Acl\Model\ObjectIdentityRetrievalStrategyInterface;
/**
* Strategy to be used for retrieving object identities from domain objects.
*
* @author Johannes M. Schmitt
*/
class ObjectIdentityRetrievalStrategy implements ObjectIdentityRetrievalStrategyInterface
{
/**
* {@inheritdoc}
*/
public function getObjectIdentity($domainObject)
{
try {
return ObjectIdentity::fromDomainObject($domainObject);
} catch (InvalidDomainObjectException $e) {
return;
}
}
}
security-acl-3.3.3/Domain/PermissionGrantingStrategy.php 0000664 0000000 0000000 00000016373 14433205003 0023415 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Domain;
use Symfony\Component\Security\Acl\Exception\NoAceFoundException;
use Symfony\Component\Security\Acl\Model\AclInterface;
use Symfony\Component\Security\Acl\Model\AuditLoggerInterface;
use Symfony\Component\Security\Acl\Model\EntryInterface;
use Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface;
use Symfony\Component\Security\Acl\Model\SecurityIdentityInterface;
/**
* The permission granting strategy to apply to the access control list.
*
* @author Johannes M. Schmitt
*/
class PermissionGrantingStrategy implements PermissionGrantingStrategyInterface
{
public const EQUAL = 'equal';
public const ALL = 'all';
public const ANY = 'any';
private $auditLogger;
/**
* Sets the audit logger.
*/
public function setAuditLogger(AuditLoggerInterface $auditLogger)
{
$this->auditLogger = $auditLogger;
}
/**
* {@inheritdoc}
*/
public function isGranted(AclInterface $acl, array $masks, array $sids, $administrativeMode = false)
{
try {
try {
$aces = $acl->getObjectAces();
if (!$aces) {
throw new NoAceFoundException();
}
return $this->hasSufficientPermissions($acl, $aces, $masks, $sids, $administrativeMode);
} catch (NoAceFoundException $e) {
$aces = $acl->getClassAces();
if (!$aces) {
throw $e;
}
return $this->hasSufficientPermissions($acl, $aces, $masks, $sids, $administrativeMode);
}
} catch (NoAceFoundException $e) {
if ($acl->isEntriesInheriting() && null !== $parentAcl = $acl->getParentAcl()) {
return $parentAcl->isGranted($masks, $sids, $administrativeMode);
}
throw $e;
}
}
/**
* {@inheritdoc}
*/
public function isFieldGranted(AclInterface $acl, $field, array $masks, array $sids, $administrativeMode = false)
{
try {
try {
$aces = $acl->getObjectFieldAces($field);
if (!$aces) {
throw new NoAceFoundException();
}
return $this->hasSufficientPermissions($acl, $aces, $masks, $sids, $administrativeMode);
} catch (NoAceFoundException $e) {
$aces = $acl->getClassFieldAces($field);
if (!$aces) {
throw $e;
}
return $this->hasSufficientPermissions($acl, $aces, $masks, $sids, $administrativeMode);
}
} catch (NoAceFoundException $e) {
if ($acl->isEntriesInheriting() && null !== $parentAcl = $acl->getParentAcl()) {
return $parentAcl->isFieldGranted($field, $masks, $sids, $administrativeMode);
}
throw $e;
}
}
/**
* Makes an authorization decision.
*
* The order of ACEs, and SIDs is significant; the order of permission masks
* not so much. It is important to note that the more specific security
* identities should be at the beginning of the SIDs array in order for this
* strategy to produce intuitive authorization decisions.
*
* First, we will iterate over permissions, then over security identities.
* For each combination of permission, and identity we will test the
* available ACEs until we find one which is applicable.
*
* The first applicable ACE will make the ultimate decision for the
* permission/identity combination. If it is granting, this method will return
* true, if it is denying, the method will continue to check the next
* permission/identity combination.
*
* This process is repeated until either a granting ACE is found, or no
* permission/identity combinations are left. Finally, we will either throw
* an NoAceFoundException, or deny access.
*
* @param EntryInterface[] $aces An array of ACE to check against
* @param array $masks An array of permission masks
* @param SecurityIdentityInterface[] $sids An array of SecurityIdentityInterface implementations
* @param bool $administrativeMode True turns off audit logging
*
* @return bool true, or false; either granting, or denying access respectively
*
* @throws NoAceFoundException
*/
private function hasSufficientPermissions(AclInterface $acl, array $aces, array $masks, array $sids, $administrativeMode)
{
$firstRejectedAce = null;
foreach ($masks as $requiredMask) {
foreach ($sids as $sid) {
foreach ($aces as $ace) {
if ($sid->equals($ace->getSecurityIdentity()) && $this->isAceApplicable($requiredMask, $ace)) {
if ($ace->isGranting()) {
if (!$administrativeMode && null !== $this->auditLogger) {
$this->auditLogger->logIfNeeded(true, $ace);
}
return true;
}
if (null === $firstRejectedAce) {
$firstRejectedAce = $ace;
}
break 2;
}
}
}
}
if (null !== $firstRejectedAce) {
if (!$administrativeMode && null !== $this->auditLogger) {
$this->auditLogger->logIfNeeded(false, $firstRejectedAce);
}
return false;
}
throw new NoAceFoundException();
}
/**
* Determines whether the ACE is applicable to the given permission/security
* identity combination.
*
* Per default, we support three different comparison strategies.
*
* Strategy ALL:
* The ACE will be considered applicable when all the turned-on bits in the
* required mask are also turned-on in the ACE mask.
*
* Strategy ANY:
* The ACE will be considered applicable when any of the turned-on bits in
* the required mask is also turned-on the in the ACE mask.
*
* Strategy EQUAL:
* The ACE will be considered applicable when the bitmasks are equal.
*
* @param int $requiredMask
*
* @return bool
*
* @throws \RuntimeException if the ACE strategy is not supported
*/
private function isAceApplicable($requiredMask, EntryInterface $ace)
{
$strategy = $ace->getStrategy();
if (self::ALL === $strategy) {
return $requiredMask === ($ace->getMask() & $requiredMask);
} elseif (self::ANY === $strategy) {
return 0 !== ($ace->getMask() & $requiredMask);
} elseif (self::EQUAL === $strategy) {
return $requiredMask === $ace->getMask();
}
throw new \RuntimeException(sprintf('The strategy "%s" is not supported.', $strategy));
}
}
security-acl-3.3.3/Domain/PsrAclCache.php 0000664 0000000 0000000 00000007314 14433205003 0020153 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Domain;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Security\Acl\Model\AclCacheInterface;
use Symfony\Component\Security\Acl\Model\AclInterface;
use Symfony\Component\Security\Acl\Model\ObjectIdentityInterface;
use Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface;
/**
* This class is a wrapper around a PSR-6 cache implementation.
*
* @author Michael Babker
*/
class PsrAclCache implements AclCacheInterface
{
use AclCacheTrait;
public const PREFIX = 'sf_acl_';
private $cache;
/**
* @throws \InvalidArgumentException When $prefix is empty
*/
public function __construct(CacheItemPoolInterface $cache, PermissionGrantingStrategyInterface $permissionGrantingStrategy, string $prefix = self::PREFIX)
{
if ('' === $prefix) {
throw new \InvalidArgumentException('$prefix cannot be empty.');
}
$this->cache = $cache;
$this->permissionGrantingStrategy = $permissionGrantingStrategy;
$this->prefix = $prefix;
}
/**
* {@inheritdoc}
*/
public function clearCache(): void
{
$this->cache->clear();
}
/**
* {@inheritdoc}
*/
public function evictFromCacheById($aclId): void
{
$lookupKey = $this->getAliasKeyForIdentity($aclId);
$cacheItem = $this->cache->getItem($lookupKey);
if (!$cacheItem->isHit()) {
return;
}
$this->cache->deleteItems([$cacheItem->get(), $lookupKey]);
}
/**
* {@inheritdoc}
*/
public function evictFromCacheByIdentity(ObjectIdentityInterface $oid): void
{
$this->cache->deleteItem($this->getDataKeyByIdentity($oid));
}
/**
* {@inheritdoc}
*/
public function getFromCacheById($aclId): ?AclInterface
{
$lookupKey = $this->getAliasKeyForIdentity($aclId);
$lookupKeyItem = $this->cache->getItem($lookupKey);
if (!$lookupKeyItem->isHit()) {
return null;
}
$key = $lookupKeyItem->get();
$keyItem = $this->cache->getItem($key);
if (!$keyItem->isHit()) {
$this->cache->deleteItem($lookupKey);
return null;
}
return $this->unserializeAcl($keyItem->get());
}
/**
* {@inheritdoc}
*/
public function getFromCacheByIdentity(ObjectIdentityInterface $oid): ?AclInterface
{
$key = $this->getDataKeyByIdentity($oid);
$cacheItem = $this->cache->getItem($key);
if (!$cacheItem->isHit()) {
return null;
}
return $this->unserializeAcl($cacheItem->get());
}
/**
* {@inheritdoc}
*/
public function putInCache(AclInterface $acl): void
{
if (null === $acl->getId()) {
throw new \InvalidArgumentException('Transient ACLs cannot be cached.');
}
if (null !== $parentAcl = $acl->getParentAcl()) {
$this->putInCache($parentAcl);
}
$key = $this->getDataKeyByIdentity($acl->getObjectIdentity());
$objectIdentityItem = $this->cache->getItem($key);
$objectIdentityItem->set(serialize($acl));
$this->cache->saveDeferred($objectIdentityItem);
$aliasKey = $this->getAliasKeyForIdentity($acl->getId());
$aliasItem = $this->cache->getItem($aliasKey);
$aliasItem->set($key);
$this->cache->saveDeferred($aliasItem);
$this->cache->commit();
}
}
security-acl-3.3.3/Domain/RoleSecurityIdentity.php 0000664 0000000 0000000 00000002477 14433205003 0022213 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Domain;
use Symfony\Component\Security\Acl\Model\SecurityIdentityInterface;
/**
* A SecurityIdentity implementation for roles.
*
* @author Johannes M. Schmitt
*/
final class RoleSecurityIdentity implements SecurityIdentityInterface
{
private $role;
public function __construct(string $role)
{
$this->role = $role;
}
/**
* Returns the role name.
*
* @return string
*/
public function getRole()
{
return $this->role;
}
/**
* {@inheritdoc}
*/
public function equals(SecurityIdentityInterface $sid)
{
if (!$sid instanceof self) {
return false;
}
return $this->role === $sid->getRole();
}
/**
* Returns a textual representation of this security identity.
*
* This is solely used for debugging purposes, not to make an equality decision.
*
* @return string
*/
public function __toString()
{
return sprintf('RoleSecurityIdentity(%s)', $this->role);
}
}
security-acl-3.3.3/Domain/SecurityIdentityRetrievalStrategy.php 0000664 0000000 0000000 00000006664 14433205003 0024774 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Domain;
use Symfony\Component\Security\Acl\Model\SecurityIdentityRetrievalStrategyInterface;
use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
use Symfony\Component\Security\Core\Authentication\Token\NullToken;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter;
use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
/**
* Strategy for retrieving security identities.
*
* @author Johannes M. Schmitt
*/
class SecurityIdentityRetrievalStrategy implements SecurityIdentityRetrievalStrategyInterface
{
private $roleHierarchy;
private $authenticationTrustResolver;
/**
* Constructor.
*/
public function __construct(RoleHierarchyInterface $roleHierarchy, AuthenticationTrustResolverInterface $authenticationTrustResolver)
{
$this->roleHierarchy = $roleHierarchy;
$this->authenticationTrustResolver = $authenticationTrustResolver;
}
/**
* {@inheritdoc}
*
* @return RoleSecurityIdentity[]
*/
public function getSecurityIdentities(TokenInterface $token)
{
$sids = [];
// add user security identity
if (!$token instanceof AnonymousToken && !$token instanceof NullToken) {
try {
$sids[] = UserSecurityIdentity::fromToken($token);
} catch (\InvalidArgumentException $e) {
// ignore, user has no user security identity
}
}
// add all reachable roles
foreach ($this->roleHierarchy->getReachableRoleNames($token->getRoleNames()) as $role) {
$sids[] = new RoleSecurityIdentity($role);
}
// add built-in special roles
if ($this->authenticationTrustResolver->isFullFledged($token)) {
$sids[] = new RoleSecurityIdentity(AuthenticatedVoter::IS_AUTHENTICATED_FULLY);
$sids[] = new RoleSecurityIdentity(AuthenticatedVoter::IS_AUTHENTICATED_REMEMBERED);
$this->addAnonymousRoles($sids);
} elseif ($this->authenticationTrustResolver->isRememberMe($token)) {
$sids[] = new RoleSecurityIdentity(AuthenticatedVoter::IS_AUTHENTICATED_REMEMBERED);
$this->addAnonymousRoles($sids);
} elseif ($this->isNotAuthenticated($token)) {
$this->addAnonymousRoles($sids);
}
return $sids;
}
private function isNotAuthenticated(TokenInterface $token): bool
{
if (method_exists($this->authenticationTrustResolver, 'isAuthenticated')) {
return !$this->authenticationTrustResolver->isAuthenticated($token);
}
return $this->authenticationTrustResolver->isAnonymous($token);
}
private function addAnonymousRoles(array &$sids)
{
$sids[] = new RoleSecurityIdentity('IS_AUTHENTICATED_ANONYMOUSLY');
if (\defined('\Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter::PUBLIC_ACCESS')) {
$sids[] = new RoleSecurityIdentity(AuthenticatedVoter::PUBLIC_ACCESS);
}
}
}
security-acl-3.3.3/Domain/UserSecurityIdentity.php 0000664 0000000 0000000 00000006071 14433205003 0022222 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Domain;
use Symfony\Component\Security\Acl\Model\SecurityIdentityInterface;
use Symfony\Component\Security\Acl\Util\ClassUtils;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* A SecurityIdentity implementation used for actual users.
*
* @author Johannes M. Schmitt
*/
final class UserSecurityIdentity implements SecurityIdentityInterface
{
private $username;
private $class;
/**
* Constructor.
*
* @param string $username the username representation
* @param string $class the user's fully qualified class name
*
* @throws \InvalidArgumentException
*/
public function __construct($username, $class)
{
if ('' === $username || null === $username) {
throw new \InvalidArgumentException('$username must not be empty.');
}
if (empty($class)) {
throw new \InvalidArgumentException('$class must not be empty.');
}
$this->username = (string) $username;
$this->class = $class;
}
/**
* Creates a user security identity from a UserInterface.
*
* @return UserSecurityIdentity
*/
public static function fromAccount(UserInterface $user)
{
return new self(method_exists($user, 'getUserIdentifier') ? $user->getUserIdentifier() : $user->getUsername(), ClassUtils::getRealClass($user));
}
/**
* Creates a user security identity from a TokenInterface.
*
* @return UserSecurityIdentity
*/
public static function fromToken(TokenInterface $token)
{
$user = $token->getUser();
if ($user instanceof UserInterface) {
return self::fromAccount($user);
}
return new self((string) $user, \is_object($user) ? ClassUtils::getRealClass($user) : ClassUtils::getRealClass($token));
}
/**
* Returns the username.
*
* @return string
*/
public function getUsername()
{
return $this->username;
}
/**
* Returns the user's class name.
*
* @return string
*/
public function getClass()
{
return $this->class;
}
/**
* {@inheritdoc}
*/
public function equals(SecurityIdentityInterface $sid)
{
if (!$sid instanceof self) {
return false;
}
return $this->username === $sid->getUsername()
&& $this->class === $sid->getClass();
}
/**
* A textual representation of this security identity.
*
* This is not used for equality comparison, but only for debugging.
*
* @return string
*/
public function __toString()
{
return sprintf('UserSecurityIdentity(%s, %s)', $this->username, $this->class);
}
}
security-acl-3.3.3/Exception/ 0000775 0000000 0000000 00000000000 14433205003 0016054 5 ustar 00root root 0000000 0000000 security-acl-3.3.3/Exception/AclAlreadyExistsException.php 0000664 0000000 0000000 00000001012 14433205003 0023637 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Exception;
/**
* This exception is thrown when someone tries to create an ACL for an object
* identity that already has one.
*
* @author Johannes M. Schmitt
*/
class AclAlreadyExistsException extends Exception
{
}
security-acl-3.3.3/Exception/AclNotFoundException.php 0000664 0000000 0000000 00000000775 14433205003 0022631 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Exception;
/**
* This exception is thrown when we cannot locate an ACL for a passed
* ObjectIdentity implementation.
*
* @author Johannes M. Schmitt
*/
class AclNotFoundException extends Exception
{
}
security-acl-3.3.3/Exception/ConcurrentModificationException.php 0000664 0000000 0000000 00000001037 14433205003 0025115 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Exception;
/**
* This exception is thrown whenever you change shared properties of more than
* one ACL of the same class type concurrently.
*
* @author Johannes M. Schmitt
*/
class ConcurrentModificationException extends Exception
{
}
security-acl-3.3.3/Exception/Exception.php 0000664 0000000 0000000 00000000651 14433205003 0020525 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Exception;
/**
* Base ACL exception.
*
* @author Johannes M. Schmitt
*/
class Exception extends \RuntimeException
{
}
security-acl-3.3.3/Exception/InvalidDomainObjectException.php 0000664 0000000 0000000 00000001025 14433205003 0024307 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Exception;
/**
* This exception is thrown when ObjectIdentity fails to construct an object
* identity from the passed domain object.
*
* @author Johannes M. Schmitt
*/
class InvalidDomainObjectException extends Exception
{
}
security-acl-3.3.3/Exception/NoAceFoundException.php 0000664 0000000 0000000 00000001205 14433205003 0022423 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Exception;
/**
* This exception is thrown when we cannot locate an ACE that matches the
* combination of permission masks and security identities.
*
* @author Johannes M. Schmitt
*/
class NoAceFoundException extends Exception
{
public function __construct()
{
parent::__construct('No applicable ACE was found.');
}
}
security-acl-3.3.3/Exception/NotAllAclsFoundException.php 0000664 0000000 0000000 00000002303 14433205003 0023432 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Exception;
use Symfony\Component\Security\Acl\Model\AclInterface;
use Symfony\Component\Security\Acl\Model\ObjectIdentityInterface;
/**
* This exception is thrown when you have requested ACLs for multiple object
* identities, but the AclProvider implementation failed to find ACLs for all
* identities.
*
* This exception contains the partial result.
*
* @author Johannes M. Schmitt
*/
class NotAllAclsFoundException extends AclNotFoundException
{
private $partialResult;
/**
* @param \SplObjectStorage $result
*/
public function setPartialResult(\SplObjectStorage $result)
{
$this->partialResult = $result;
}
/**
* Returns the partial result.
*
* @return \SplObjectStorage
*/
public function getPartialResult()
{
return $this->partialResult;
}
}
security-acl-3.3.3/Exception/SidNotLoadedException.php 0000664 0000000 0000000 00000001005 14433205003 0022751 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Exception;
/**
* This exception is thrown when ACEs for an SID are requested which has not
* been loaded from the database.
*
* @author Johannes M. Schmitt
*/
class SidNotLoadedException extends Exception
{
}
security-acl-3.3.3/LICENSE 0000664 0000000 0000000 00000002051 14433205003 0015121 0 ustar 00root root 0000000 0000000 Copyright (c) 2004-2021 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
security-acl-3.3.3/Model/ 0000775 0000000 0000000 00000000000 14433205003 0015156 5 ustar 00root root 0000000 0000000 security-acl-3.3.3/Model/AclCacheInterface.php 0000664 0000000 0000000 00000002567 14433205003 0021145 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Model;
/**
* AclCache Interface.
*
* @author Johannes M. Schmitt
*/
interface AclCacheInterface
{
/**
* Removes an ACL from the cache.
*
* @param string $aclId a serialized primary key
*/
public function evictFromCacheById($aclId);
/**
* Removes an ACL from the cache.
*
* The ACL which is returned, must reference the passed object identity.
*/
public function evictFromCacheByIdentity(ObjectIdentityInterface $oid);
/**
* Retrieves an ACL for the given object identity primary key from the cache.
*
* @param int $aclId
*
* @return AclInterface|null
*/
public function getFromCacheById($aclId);
/**
* Retrieves an ACL for the given object identity from the cache.
*
* @return AclInterface|null
*/
public function getFromCacheByIdentity(ObjectIdentityInterface $oid);
/**
* Stores a new ACL in the cache.
*/
public function putInCache(AclInterface $acl);
/**
* Removes all ACLs from the cache.
*/
public function clearCache();
}
security-acl-3.3.3/Model/AclInterface.php 0000664 0000000 0000000 00000005726 14433205003 0020221 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Model;
use Symfony\Component\Security\Acl\Exception\NoAceFoundException;
/**
* This interface represents an access control list (ACL) for a domain object.
* Each domain object can have exactly one associated ACL.
*
* An ACL contains all access control entries (ACE) for a given domain object.
* In order to avoid needing references to the domain object itself, implementations
* use ObjectIdentity implementations as an additional level of indirection.
*
* @author Johannes M. Schmitt
*
* @method array __serialize() returns all the necessary state of the object for serialization purposes
* @method void __unserialize(array $data) restores the object state from an array given by {@see __serialize}
*/
interface AclInterface extends \Serializable
{
/**
* Returns all class-based ACEs associated with this ACL.
*
* @return array
*/
public function getClassAces();
/**
* Returns all class-field-based ACEs associated with this ACL.
*
* @return array
*/
public function getClassFieldAces(string $field);
/**
* Returns all object-based ACEs associated with this ACL.
*
* @return array
*/
public function getObjectAces();
/**
* Returns all object-field-based ACEs associated with this ACL.
*
* @return array
*/
public function getObjectFieldAces(string $field);
/**
* Returns the object identity associated with this ACL.
*
* @return ObjectIdentityInterface
*/
public function getObjectIdentity();
/**
* Returns the parent ACL, or null if there is none.
*
* @return AclInterface|null
*/
public function getParentAcl();
/**
* Whether this ACL is inheriting ACEs from a parent ACL.
*
* @return bool
*/
public function isEntriesInheriting();
/**
* Determines whether field access is granted.
*
* @return bool
*/
public function isFieldGranted(string $field, array $masks, array $securityIdentities, bool $administrativeMode = false);
/**
* Determines whether access is granted.
*
* @return bool
*
* @throws NoAceFoundException when no ACE was applicable for this request
*/
public function isGranted(array $masks, array $securityIdentities, bool $administrativeMode = false);
/**
* Whether the ACL has loaded ACEs for all of the passed security identities.
*
* @param SecurityIdentityInterface|SecurityIdentityInterface[] $securityIdentities
*
* @return bool
*/
public function isSidLoaded($securityIdentities);
}
security-acl-3.3.3/Model/AclProviderInterface.php 0000664 0000000 0000000 00000003226 14433205003 0021725 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Model;
use Symfony\Component\Security\Acl\Exception\AclNotFoundException;
/**
* Provides a common interface for retrieving ACLs.
*
* @author Johannes M. Schmitt
*/
interface AclProviderInterface
{
/**
* Retrieves all child object identities from the database.
*
* @param bool $directChildrenOnly
*
* @return array returns an array of child 'ObjectIdentity's
*/
public function findChildren(ObjectIdentityInterface $parentOid, $directChildrenOnly = false);
/**
* Returns the ACL that belongs to the given object identity.
*
* @param SecurityIdentityInterface[] $sids
*
* @return AclInterface
*
* @throws AclNotFoundException when there is no ACL
*/
public function findAcl(ObjectIdentityInterface $oid, array $sids = []);
/**
* Returns the ACLs that belong to the given object identities.
*
* @param ObjectIdentityInterface[] $oids an array of ObjectIdentityInterface implementations
* @param SecurityIdentityInterface[] $sids an array of SecurityIdentityInterface implementations
*
* @return \SplObjectStorage mapping the passed object identities to ACLs
*
* @throws AclNotFoundException when we cannot find an ACL for all identities
*/
public function findAcls(array $oids, array $sids = []);
}
security-acl-3.3.3/Model/AuditLoggerInterface.php 0000664 0000000 0000000 00000001210 14433205003 0021710 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Model;
/**
* Interface for audit loggers.
*
* @author Johannes M. Schmitt
*/
interface AuditLoggerInterface
{
/**
* This method is called whenever access is granted, or denied, and
* administrative mode is turned off.
*
* @param bool $granted
*/
public function logIfNeeded($granted, EntryInterface $ace);
}
security-acl-3.3.3/Model/AuditableAclInterface.php 0000664 0000000 0000000 00000002174 14433205003 0022026 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Model;
/**
* This interface adds auditing capabilities to the ACL.
*
* @author Johannes M. Schmitt
*/
interface AuditableAclInterface extends MutableAclInterface
{
/**
* Updates auditing for class-based ACE.
*/
public function updateClassAuditing(int $index, bool $auditSuccess, bool $auditFailure);
/**
* Updates auditing for class-field-based ACE.
*/
public function updateClassFieldAuditing(int $index, string $field, bool $auditSuccess, bool $auditFailure);
/**
* Updates auditing for object-based ACE.
*/
public function updateObjectAuditing(int $index, bool $auditSuccess, bool $auditFailure);
/**
* Updates auditing for object-field-based ACE.
*/
public function updateObjectFieldAuditing(int $index, string $field, bool $auditSuccess, bool $auditFailure);
}
security-acl-3.3.3/Model/AuditableEntryInterface.php 0000664 0000000 0000000 00000001404 14433205003 0022423 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Model;
/**
* ACEs can implement this interface if they support auditing capabilities.
*
* @author Johannes M. Schmitt
*/
interface AuditableEntryInterface extends EntryInterface
{
/**
* Whether auditing for successful grants is turned on.
*
* @return bool
*/
public function isAuditFailure();
/**
* Whether auditing for successful denies is turned on.
*
* @return bool
*/
public function isAuditSuccess();
}
security-acl-3.3.3/Model/DomainObjectInterface.php 0000664 0000000 0000000 00000001310 14433205003 0022041 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Model;
/**
* This method can be implemented by domain objects which you want to store
* ACLs for if they do not have a getId() method, or getId() does not return
* a unique identifier.
*
* @author Johannes M. Schmitt
*/
interface DomainObjectInterface
{
/**
* Returns a unique identifier for this domain object.
*
* @return string
*/
public function getObjectIdentifier();
}
security-acl-3.3.3/Model/EntryInterface.php 0000664 0000000 0000000 00000003055 14433205003 0020614 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Model;
/**
* This class represents an individual entry in the ACL list.
*
* Instances MUST be immutable, as they are returned by the ACL and should not
* allow client modification.
*
* @author Johannes M. Schmitt
*
* @method array __serialize() returns all the necessary state of the object for serialization purposes
* @method void __unserialize(array $data) restores the object state from an array given by {@see __serialize}
*/
interface EntryInterface extends \Serializable
{
/**
* The ACL this ACE is associated with.
*
* @return AclInterface
*/
public function getAcl();
/**
* The primary key of this ACE.
*
* @return int|null
*/
public function getId();
/**
* The permission mask of this ACE.
*
* @return int
*/
public function getMask();
/**
* The security identity associated with this ACE.
*
* @return SecurityIdentityInterface
*/
public function getSecurityIdentity();
/**
* The strategy for comparing masks.
*
* @return string
*/
public function getStrategy();
/**
* Returns whether this ACE is granting, or denying.
*
* @return bool
*/
public function isGranting();
}
security-acl-3.3.3/Model/FieldEntryInterface.php 0000664 0000000 0000000 00000001126 14433205003 0021555 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Model;
/**
* Interface for entries which are restricted to specific fields.
*
* @author Johannes M. Schmitt
*/
interface FieldEntryInterface extends EntryInterface
{
/**
* Returns the field used for this entry.
*
* @return string
*/
public function getField();
}
security-acl-3.3.3/Model/MutableAclInterface.php 0000664 0000000 0000000 00000006144 14433205003 0021526 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Model;
/**
* This interface adds mutators for the AclInterface.
*
* All changes to Access Control Entries must go through this interface. Access
* Control Entries must never be modified directly.
*
* @author Johannes M. Schmitt
*/
interface MutableAclInterface extends AclInterface
{
/**
* Deletes a class-based ACE.
*/
public function deleteClassAce(int $index);
/**
* Deletes a class-field-based ACE.
*/
public function deleteClassFieldAce(int $index, string $field);
/**
* Deletes an object-based ACE.
*/
public function deleteObjectAce(int $index);
/**
* Deletes an object-field-based ACE.
*/
public function deleteObjectFieldAce(int $index, string $field);
/**
* Returns the primary key of this ACL.
*
* @return int
*/
public function getId();
/**
* Inserts a class-based ACE.
*/
public function insertClassAce(SecurityIdentityInterface $sid, int $mask, int $index = 0, bool $granting = true, ?string $strategy = null);
/**
* Inserts a class-field-based ACE.
*/
public function insertClassFieldAce(string $field, SecurityIdentityInterface $sid, int $mask, int $index = 0, bool $granting = true, ?string $strategy = null);
/**
* Inserts an object-based ACE.
*/
public function insertObjectAce(SecurityIdentityInterface $sid, int $mask, int $index = 0, bool $granting = true, ?string $strategy = null);
/**
* Inserts an object-field-based ACE.
*/
public function insertObjectFieldAce(string $field, SecurityIdentityInterface $sid, int $mask, int $index = 0, bool $granting = true, ?string $strategy = null);
/**
* Sets whether entries are inherited.
*/
public function setEntriesInheriting(bool $boolean);
/**
* Sets the parent ACL.
*/
public function setParentAcl(?AclInterface $acl = null);
/**
* Updates a class-based ACE.
*
* @param string|null $strategy if null the strategy should not be changed
*/
public function updateClassAce(int $index, int $mask, ?string $strategy = null);
/**
* Updates a class-field-based ACE.
*
* @param string|null $strategy if null the strategy should not be changed
*/
public function updateClassFieldAce(int $index, string $field, int $mask, ?string $strategy = null);
/**
* Updates an object-based ACE.
*
* @param string|null $strategy if null the strategy should not be changed
*/
public function updateObjectAce(int $index, int $mask, ?string $strategy = null);
/**
* Updates an object-field-based ACE.
*
* @param string|null $strategy if null the strategy should not be changed
*/
public function updateObjectFieldAce(int $index, string $field, int $mask, ?string $strategy = null);
}
security-acl-3.3.3/Model/MutableAclProviderInterface.php 0000664 0000000 0000000 00000003414 14433205003 0023236 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Model;
use Symfony\Component\Security\Acl\Exception\AclAlreadyExistsException;
/**
* Provides support for creating and storing ACL instances.
*
* @author Johannes M. Schmitt
*/
interface MutableAclProviderInterface extends AclProviderInterface
{
/**
* {@inheritdoc}
*
* @return MutableAclInterface
*/
public function findAcl(ObjectIdentityInterface $oid, array $sids = []);
/**
* {@inheritdoc}
*
* @return \SplObjectStorage mapping the passed object identities to ACLs
*/
public function findAcls(array $oids, array $sids = []);
/**
* Creates a new ACL for the given object identity.
*
* @return MutableAclInterface
*
* @throws AclAlreadyExistsException when there already is an ACL for the given
* object identity
*/
public function createAcl(ObjectIdentityInterface $oid);
/**
* Deletes the ACL for a given object identity.
*
* This will automatically trigger a delete for any child ACLs. If you don't
* want child ACLs to be deleted, you will have to set their parent ACL to null.
*/
public function deleteAcl(ObjectIdentityInterface $oid);
/**
* Persists any changes which were made to the ACL, or any associated
* access control entries.
*
* Changes to parent ACLs are not persisted.
*/
public function updateAcl(MutableAclInterface $acl);
}
security-acl-3.3.3/Model/ObjectIdentityInterface.php 0000664 0000000 0000000 00000002463 14433205003 0022435 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Model;
/**
* Represents the identity of an individual domain object instance.
*
* @author Johannes M. Schmitt
*/
interface ObjectIdentityInterface
{
/**
* We specifically require this method so we can check for object equality
* explicitly, and do not have to rely on referencial equality instead.
*
* Though in most cases, both checks should result in the same outcome.
*
* Referential Equality: $object1 === $object2
* Example for Object Equality: $object1->getId() === $object2->getId()
*
* @return bool
*/
public function equals(self $identity);
/**
* Obtains a unique identifier for this object. The identifier must not be
* re-used for other objects with the same type.
*
* @return string cannot return null
*/
public function getIdentifier();
/**
* Returns a type for the domain object. Typically, this is the PHP class name.
*
* @return string cannot return null
*/
public function getType();
}
security-acl-3.3.3/Model/ObjectIdentityRetrievalStrategyInterface.php 0000664 0000000 0000000 00000001254 14433205003 0026033 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Model;
/**
* Retrieves the object identity for a given domain object.
*
* @author Johannes M. Schmitt
*/
interface ObjectIdentityRetrievalStrategyInterface
{
/**
* Retrieves the object identity from a domain object.
*
* @param object $domainObject
*
* @return ObjectIdentityInterface
*/
public function getObjectIdentity($domainObject);
}
security-acl-3.3.3/Model/PermissionGrantingStrategyInterface.php 0000664 0000000 0000000 00000002022 14433205003 0025051 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Model;
/**
* Interface used by permission granting implementations.
*
* @author Johannes M. Schmitt
*/
interface PermissionGrantingStrategyInterface
{
/**
* Determines whether access to a domain object is to be granted.
*
* @param bool $administrativeMode
*
* @return bool
*/
public function isGranted(AclInterface $acl, array $masks, array $sids, $administrativeMode = false);
/**
* Determines whether access to a domain object's field is to be granted.
*
* @param string $field
* @param bool $administrativeMode
*
* @return bool
*/
public function isFieldGranted(AclInterface $acl, $field, array $masks, array $sids, $administrativeMode = false);
}
security-acl-3.3.3/Model/SecurityIdentityInterface.php 0000664 0000000 0000000 00000001344 14433205003 0023033 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Model;
/**
* This interface provides an additional level of indirection, so that
* we can work with abstracted versions of security objects and do
* not have to save the entire objects.
*
* @author Johannes M. Schmitt
*/
interface SecurityIdentityInterface
{
/**
* This method is used to compare two security identities in order to
* not rely on referential equality.
*/
public function equals(self $sid);
}
security-acl-3.3.3/Model/SecurityIdentityRetrievalStrategyInterface.php 0000664 0000000 0000000 00000001735 14433205003 0026440 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Model;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
/**
* Interface for retrieving security identities from tokens.
*
* @author Johannes M. Schmitt
*/
interface SecurityIdentityRetrievalStrategyInterface
{
/**
* Retrieves the available security identities for the given token.
*
* The order in which the security identities are returned is significant.
* Typically, security identities should be ordered from most specific to
* least specific.
*
* @return SecurityIdentityInterface[] An array of SecurityIdentityInterface implementations
*/
public function getSecurityIdentities(TokenInterface $token);
}
security-acl-3.3.3/Permission/ 0000775 0000000 0000000 00000000000 14433205003 0016246 5 ustar 00root root 0000000 0000000 security-acl-3.3.3/Permission/AbstractMaskBuilder.php 0000664 0000000 0000000 00000002700 14433205003 0022644 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Permission;
/**
* This abstract class implements nearly all the MaskBuilderInterface methods.
*/
abstract class AbstractMaskBuilder implements MaskBuilderInterface
{
/**
* @var int
*/
protected $mask;
/**
* Constructor.
*
* @param int $mask optional; defaults to 0
*/
public function __construct($mask = 0)
{
$this->set($mask);
}
/**
* {@inheritdoc}
*/
public function set($mask)
{
if (!\is_int($mask)) {
throw new \InvalidArgumentException('$mask must be an integer.');
}
$this->mask = $mask;
return $this;
}
/**
* {@inheritdoc}
*/
public function get()
{
return $this->mask;
}
/**
* {@inheritdoc}
*/
public function add($mask)
{
$this->mask |= $this->resolveMask($mask);
return $this;
}
/**
* {@inheritdoc}
*/
public function remove($mask)
{
$this->mask &= ~$this->resolveMask($mask);
return $this;
}
/**
* {@inheritdoc}
*/
public function reset()
{
$this->mask = 0;
return $this;
}
}
security-acl-3.3.3/Permission/BasicPermissionMap.php 0000664 0000000 0000000 00000006066 14433205003 0022517 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Permission;
/**
* This is basic permission map complements the masks which have been defined
* on the standard implementation of the MaskBuilder.
*
* @author Johannes M. Schmitt
*/
class BasicPermissionMap implements PermissionMapInterface, MaskBuilderRetrievalInterface
{
public const PERMISSION_VIEW = 'VIEW';
public const PERMISSION_EDIT = 'EDIT';
public const PERMISSION_CREATE = 'CREATE';
public const PERMISSION_DELETE = 'DELETE';
public const PERMISSION_UNDELETE = 'UNDELETE';
public const PERMISSION_OPERATOR = 'OPERATOR';
public const PERMISSION_MASTER = 'MASTER';
public const PERMISSION_OWNER = 'OWNER';
protected $map;
public function __construct()
{
$this->map = [
self::PERMISSION_VIEW => [
MaskBuilder::MASK_VIEW,
MaskBuilder::MASK_EDIT,
MaskBuilder::MASK_OPERATOR,
MaskBuilder::MASK_MASTER,
MaskBuilder::MASK_OWNER,
],
self::PERMISSION_EDIT => [
MaskBuilder::MASK_EDIT,
MaskBuilder::MASK_OPERATOR,
MaskBuilder::MASK_MASTER,
MaskBuilder::MASK_OWNER,
],
self::PERMISSION_CREATE => [
MaskBuilder::MASK_CREATE,
MaskBuilder::MASK_OPERATOR,
MaskBuilder::MASK_MASTER,
MaskBuilder::MASK_OWNER,
],
self::PERMISSION_DELETE => [
MaskBuilder::MASK_DELETE,
MaskBuilder::MASK_OPERATOR,
MaskBuilder::MASK_MASTER,
MaskBuilder::MASK_OWNER,
],
self::PERMISSION_UNDELETE => [
MaskBuilder::MASK_UNDELETE,
MaskBuilder::MASK_OPERATOR,
MaskBuilder::MASK_MASTER,
MaskBuilder::MASK_OWNER,
],
self::PERMISSION_OPERATOR => [
MaskBuilder::MASK_OPERATOR,
MaskBuilder::MASK_MASTER,
MaskBuilder::MASK_OWNER,
],
self::PERMISSION_MASTER => [
MaskBuilder::MASK_MASTER,
MaskBuilder::MASK_OWNER,
],
self::PERMISSION_OWNER => [
MaskBuilder::MASK_OWNER,
],
];
}
/**
* {@inheritdoc}
*/
public function getMasks($permission, $object)
{
if (!isset($this->map[$permission])) {
return;
}
return $this->map[$permission];
}
/**
* {@inheritdoc}
*/
public function contains($permission)
{
return isset($this->map[$permission]);
}
/**
* {@inheritdoc}
*/
public function getMaskBuilder()
{
return new MaskBuilder();
}
}
security-acl-3.3.3/Permission/MaskBuilder.php 0000664 0000000 0000000 00000011421 14433205003 0021160 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Permission;
/**
* This class allows you to build cumulative permissions easily, or convert
* masks to a human-readable format.
*
*
* $builder = new MaskBuilder();
* $builder
* ->add('view')
* ->add('create')
* ->add('edit')
* ;
* var_dump($builder->get()); // int(7)
* var_dump($builder->getPattern()); // string(32) ".............................ECV"
*
*
* We have defined some commonly used base permissions which you can use:
* - VIEW: the SID is allowed to view the domain object / field
* - CREATE: the SID is allowed to create new instances of the domain object / fields
* - EDIT: the SID is allowed to edit existing instances of the domain object / field
* - DELETE: the SID is allowed to delete domain objects
* - UNDELETE: the SID is allowed to recover domain objects from trash
* - OPERATOR: the SID is allowed to perform any action on the domain object
* except for granting others permissions
* - MASTER: the SID is allowed to perform any action on the domain object,
* and is allowed to grant other SIDs any permission except for
* MASTER and OWNER permissions
* - OWNER: the SID is owning the domain object in question and can perform any
* action on the domain object as well as grant any permission
*
* @author Johannes M. Schmitt
*/
class MaskBuilder extends AbstractMaskBuilder
{
public const MASK_VIEW = 1; // 1 << 0
public const MASK_CREATE = 2; // 1 << 1
public const MASK_EDIT = 4; // 1 << 2
public const MASK_DELETE = 8; // 1 << 3
public const MASK_UNDELETE = 16; // 1 << 4
public const MASK_OPERATOR = 32; // 1 << 5
public const MASK_MASTER = 64; // 1 << 6
public const MASK_OWNER = 128; // 1 << 7
public const MASK_IDDQD = 1073741823; // 1 << 0 | 1 << 1 | ... | 1 << 30
public const CODE_VIEW = 'V';
public const CODE_CREATE = 'C';
public const CODE_EDIT = 'E';
public const CODE_DELETE = 'D';
public const CODE_UNDELETE = 'U';
public const CODE_OPERATOR = 'O';
public const CODE_MASTER = 'M';
public const CODE_OWNER = 'N';
public const ALL_OFF = '................................';
public const OFF = '.';
public const ON = '*';
/**
* Returns a human-readable representation of the permission.
*
* @return string
*/
public function getPattern()
{
$pattern = self::ALL_OFF;
$length = \strlen($pattern);
$bitmask = str_pad(decbin($this->mask), $length, '0', \STR_PAD_LEFT);
for ($i = $length - 1; $i >= 0; --$i) {
if ('1' === $bitmask[$i]) {
try {
$pattern[$i] = self::getCode(1 << ($length - $i - 1));
} catch (\Exception $e) {
$pattern[$i] = self::ON;
}
}
}
return $pattern;
}
/**
* Returns the code for the passed mask.
*
* @param int $mask
*
* @return string
*
* @throws \InvalidArgumentException
* @throws \RuntimeException
*/
public static function getCode($mask)
{
if (!\is_int($mask)) {
throw new \InvalidArgumentException('$mask must be an integer.');
}
$reflection = new \ReflectionClass(static::class);
foreach ($reflection->getConstants() as $name => $cMask) {
if (0 !== strpos($name, 'MASK_') || $mask !== $cMask) {
continue;
}
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
*/
public function resolveMask($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;
}
}
security-acl-3.3.3/Permission/MaskBuilderInterface.php 0000664 0000000 0000000 00000002757 14433205003 0023015 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Permission;
/**
* This is the interface that must be implemented by mask builders.
*/
interface MaskBuilderInterface
{
/**
* Set the mask of this permission.
*
* @param int $mask
*
* @return MaskBuilderInterface
*
* @throws \InvalidArgumentException if $mask is not an integer
*/
public function set($mask);
/**
* Returns the mask of this permission.
*
* @return int
*/
public function get();
/**
* Adds a mask to the permission.
*
* @param mixed $mask
*
* @return MaskBuilderInterface
*
* @throws \InvalidArgumentException
*/
public function add($mask);
/**
* Removes a mask from the permission.
*
* @param mixed $mask
*
* @return MaskBuilderInterface
*
* @throws \InvalidArgumentException
*/
public function remove($mask);
/**
* Resets the PermissionBuilder.
*
* @return MaskBuilderInterface
*/
public function reset();
/**
* Returns the mask for the passed code.
*
* @param mixed $code
*
* @return int
*
* @throws \InvalidArgumentException
*/
public function resolveMask($code);
}
security-acl-3.3.3/Permission/MaskBuilderRetrievalInterface.php 0000664 0000000 0000000 00000001043 14433205003 0024656 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Permission;
/**
* Retrieves the MaskBuilder.
*/
interface MaskBuilderRetrievalInterface
{
/**
* Returns a new instance of the MaskBuilder used in the permissionMap.
*
* @return MaskBuilderInterface
*/
public function getMaskBuilder();
}
security-acl-3.3.3/Permission/PermissionMapInterface.php 0000664 0000000 0000000 00000002003 14433205003 0023361 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Permission;
/**
* This is the interface that must be implemented by permission maps.
*
* @author Johannes M. Schmitt
*/
interface PermissionMapInterface
{
/**
* Returns an array of bitmasks.
*
* The security identity must have been granted access to at least one of
* these bitmasks.
*
* @param string $permission
* @param object $object
*
* @return array|null may return null if permission/object combination is not supported
*/
public function getMasks($permission, $object);
/**
* Whether this map contains the given permission.
*
* @param string $permission
*
* @return bool
*/
public function contains($permission);
}
security-acl-3.3.3/README.md 0000664 0000000 0000000 00000001173 14433205003 0015377 0 ustar 00root root 0000000 0000000 Security Component - ACL (Access Control List)
==============================================
Security provides an infrastructure for sophisticated authorization systems,
which makes it possible to easily separate the actual authorization logic from
so called user providers that hold the users credentials. It is inspired by
the Java Spring framework.
Resources
---------
Documentation:
https://github.com/symfony/acl-bundle/blob/main/src/Resources/doc/index.rst
Tests
-----
You can run the unit tests with the following command:
$ cd path/to/Symfony/Component/Security/Acl/
$ composer.phar install --dev
$ phpunit
security-acl-3.3.3/Resources/ 0000775 0000000 0000000 00000000000 14433205003 0016070 5 ustar 00root root 0000000 0000000 security-acl-3.3.3/Resources/bin/ 0000775 0000000 0000000 00000000000 14433205003 0016640 5 ustar 00root root 0000000 0000000 security-acl-3.3.3/Resources/bin/generateSql.php 0000664 0000000 0000000 00000002346 14433205003 0021630 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
require_once __DIR__.'/../../vendor/autoload.php';
use Symfony\Component\Finder\Finder;
use Symfony\Component\Security\Acl\Dbal\Schema;
$schema = new Schema([
'class_table_name' => 'acl_classes',
'entry_table_name' => 'acl_entries',
'oid_table_name' => 'acl_object_identities',
'oid_ancestors_table_name' => 'acl_object_identity_ancestors',
'sid_table_name' => 'acl_security_identities',
]);
$reflection = new ReflectionClass('Doctrine\\DBAL\\Platforms\\AbstractPlatform');
$finder = new Finder();
$finder->name('*Platform.php')->in(dirname($reflection->getFileName()));
foreach ($finder as $file) {
$className = 'Doctrine\\DBAL\\Platforms\\'.$file->getBasename('.php');
$reflection = new ReflectionClass($className);
if ($reflection->isAbstract()) {
continue;
}
$platform = $reflection->newInstance();
$targetFile = sprintf(__DIR__.'/../schema/%s.sql', $platform->getName());
file_put_contents($targetFile, implode("\n\n", $schema->toSql($platform)));
}
security-acl-3.3.3/Resources/schema/ 0000775 0000000 0000000 00000000000 14433205003 0017330 5 ustar 00root root 0000000 0000000 security-acl-3.3.3/Resources/schema/db2.sql 0000664 0000000 0000000 00000006653 14433205003 0020532 0 ustar 00root root 0000000 0000000 CREATE TABLE acl_classes (id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL, class_type VARCHAR(200) NOT NULL, PRIMARY KEY(id))
CREATE UNIQUE INDEX UNIQ_69DD750638A36066 ON acl_classes (class_type)
CREATE TABLE acl_security_identities (id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL, identifier VARCHAR(200) NOT NULL, username SMALLINT NOT NULL, PRIMARY KEY(id))
CREATE UNIQUE INDEX UNIQ_8835EE78772E836AF85E0677 ON acl_security_identities (identifier, username)
COMMENT ON COLUMN acl_security_identities.username IS '(DC2Type:boolean)'
CREATE TABLE acl_object_identities (id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL, parent_object_identity_id INTEGER DEFAULT NULL, class_id INTEGER NOT NULL, object_identifier VARCHAR(100) NOT NULL, entries_inheriting SMALLINT NOT NULL, PRIMARY KEY(id))
CREATE UNIQUE INDEX UNIQ_9407E5494B12AD6EA000B10 ON acl_object_identities (object_identifier, class_id)
CREATE INDEX IDX_9407E54977FA751A ON acl_object_identities (parent_object_identity_id)
COMMENT ON COLUMN acl_object_identities.entries_inheriting IS '(DC2Type:boolean)'
CREATE TABLE acl_object_identity_ancestors (object_identity_id INTEGER NOT NULL, ancestor_id INTEGER NOT NULL, PRIMARY KEY(object_identity_id, ancestor_id))
CREATE INDEX IDX_825DE2993D9AB4A6 ON acl_object_identity_ancestors (object_identity_id)
CREATE INDEX IDX_825DE299C671CEA1 ON acl_object_identity_ancestors (ancestor_id)
CREATE TABLE acl_entries (id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL, class_id INTEGER NOT NULL, object_identity_id INTEGER DEFAULT NULL, security_identity_id INTEGER NOT NULL, field_name VARCHAR(50) DEFAULT NULL, ace_order SMALLINT NOT NULL, mask INTEGER NOT NULL, granting SMALLINT NOT NULL, granting_strategy VARCHAR(30) NOT NULL, audit_success SMALLINT NOT NULL, audit_failure SMALLINT NOT NULL, PRIMARY KEY(id))
CREATE UNIQUE INDEX UNIQ_46C8B806EA000B103D9AB4A64DEF17BCE4289BF4 ON acl_entries (class_id, object_identity_id, field_name, ace_order)
CREATE INDEX IDX_46C8B806EA000B103D9AB4A6DF9183C9 ON acl_entries (class_id, object_identity_id, security_identity_id)
CREATE INDEX IDX_46C8B806EA000B10 ON acl_entries (class_id)
CREATE INDEX IDX_46C8B8063D9AB4A6 ON acl_entries (object_identity_id)
CREATE INDEX IDX_46C8B806DF9183C9 ON acl_entries (security_identity_id)
COMMENT ON COLUMN acl_entries.granting IS '(DC2Type:boolean)'
COMMENT ON COLUMN acl_entries.audit_success IS '(DC2Type:boolean)'
COMMENT ON COLUMN acl_entries.audit_failure IS '(DC2Type:boolean)'
ALTER TABLE acl_object_identities ADD CONSTRAINT FK_9407E54977FA751A FOREIGN KEY (parent_object_identity_id) REFERENCES acl_object_identities (id)
ALTER TABLE acl_object_identity_ancestors ADD CONSTRAINT FK_825DE2993D9AB4A6 FOREIGN KEY (object_identity_id) REFERENCES acl_object_identities (id) ON UPDATE CASCADE ON DELETE CASCADE
ALTER TABLE acl_object_identity_ancestors ADD CONSTRAINT FK_825DE299C671CEA1 FOREIGN KEY (ancestor_id) REFERENCES acl_object_identities (id) ON UPDATE CASCADE ON DELETE CASCADE
ALTER TABLE acl_entries ADD CONSTRAINT FK_46C8B806EA000B10 FOREIGN KEY (class_id) REFERENCES acl_classes (id) ON UPDATE CASCADE ON DELETE CASCADE
ALTER TABLE acl_entries ADD CONSTRAINT FK_46C8B8063D9AB4A6 FOREIGN KEY (object_identity_id) REFERENCES acl_object_identities (id) ON UPDATE CASCADE ON DELETE CASCADE
ALTER TABLE acl_entries ADD CONSTRAINT FK_46C8B806DF9183C9 FOREIGN KEY (security_identity_id) REFERENCES acl_security_identities (id) ON UPDATE CASCADE ON DELETE CASCADE security-acl-3.3.3/Resources/schema/drizzle.sql 0000664 0000000 0000000 00000005526 14433205003 0021544 0 ustar 00root root 0000000 0000000 CREATE TABLE acl_classes (id INT AUTO_INCREMENT NOT NULL, class_type VARCHAR(200) NOT NULL, UNIQUE INDEX UNIQ_69DD750638A36066 (class_type), PRIMARY KEY(id)) COLLATE utf8_unicode_ci ENGINE = InnoDB
CREATE TABLE acl_security_identities (id INT AUTO_INCREMENT NOT NULL, identifier VARCHAR(200) NOT NULL, username BOOLEAN NOT NULL, UNIQUE INDEX UNIQ_8835EE78772E836AF85E0677 (identifier, username), PRIMARY KEY(id)) COLLATE utf8_unicode_ci ENGINE = InnoDB
CREATE TABLE acl_object_identities (id INT AUTO_INCREMENT NOT NULL, parent_object_identity_id INT DEFAULT NULL, class_id INT NOT NULL, object_identifier VARCHAR(100) NOT NULL, entries_inheriting BOOLEAN NOT NULL, UNIQUE INDEX UNIQ_9407E5494B12AD6EA000B10 (object_identifier, class_id), INDEX IDX_9407E54977FA751A (parent_object_identity_id), PRIMARY KEY(id)) COLLATE utf8_unicode_ci ENGINE = InnoDB
CREATE TABLE acl_object_identity_ancestors (object_identity_id INT NOT NULL, ancestor_id INT NOT NULL, INDEX IDX_825DE2993D9AB4A6 (object_identity_id), INDEX IDX_825DE299C671CEA1 (ancestor_id), PRIMARY KEY(object_identity_id, ancestor_id)) COLLATE utf8_unicode_ci ENGINE = InnoDB
CREATE TABLE acl_entries (id INT AUTO_INCREMENT NOT NULL, class_id INT NOT NULL, object_identity_id INT DEFAULT NULL, security_identity_id INT NOT NULL, field_name VARCHAR(50) DEFAULT NULL, ace_order INT NOT NULL, mask INT NOT NULL, granting BOOLEAN NOT NULL, granting_strategy VARCHAR(30) NOT NULL, audit_success BOOLEAN NOT NULL, audit_failure BOOLEAN NOT NULL, UNIQUE INDEX UNIQ_46C8B806EA000B103D9AB4A64DEF17BCE4289BF4 (class_id, object_identity_id, field_name, ace_order), INDEX IDX_46C8B806EA000B103D9AB4A6DF9183C9 (class_id, object_identity_id, security_identity_id), INDEX IDX_46C8B806EA000B10 (class_id), INDEX IDX_46C8B8063D9AB4A6 (object_identity_id), INDEX IDX_46C8B806DF9183C9 (security_identity_id), PRIMARY KEY(id)) COLLATE utf8_unicode_ci ENGINE = InnoDB
ALTER TABLE acl_object_identities ADD CONSTRAINT FK_9407E54977FA751A FOREIGN KEY (parent_object_identity_id) REFERENCES acl_object_identities (id)
ALTER TABLE acl_object_identity_ancestors ADD CONSTRAINT FK_825DE2993D9AB4A6 FOREIGN KEY (object_identity_id) REFERENCES acl_object_identities (id) ON UPDATE CASCADE ON DELETE CASCADE
ALTER TABLE acl_object_identity_ancestors ADD CONSTRAINT FK_825DE299C671CEA1 FOREIGN KEY (ancestor_id) REFERENCES acl_object_identities (id) ON UPDATE CASCADE ON DELETE CASCADE
ALTER TABLE acl_entries ADD CONSTRAINT FK_46C8B806EA000B10 FOREIGN KEY (class_id) REFERENCES acl_classes (id) ON UPDATE CASCADE ON DELETE CASCADE
ALTER TABLE acl_entries ADD CONSTRAINT FK_46C8B8063D9AB4A6 FOREIGN KEY (object_identity_id) REFERENCES acl_object_identities (id) ON UPDATE CASCADE ON DELETE CASCADE
ALTER TABLE acl_entries ADD CONSTRAINT FK_46C8B806DF9183C9 FOREIGN KEY (security_identity_id) REFERENCES acl_security_identities (id) ON UPDATE CASCADE ON DELETE CASCADE security-acl-3.3.3/Resources/schema/mssql.sql 0000664 0000000 0000000 00000006203 14433205003 0021211 0 ustar 00root root 0000000 0000000 CREATE TABLE acl_classes (id INT IDENTITY NOT NULL, class_type NVARCHAR(200) NOT NULL, PRIMARY KEY (id))
CREATE UNIQUE INDEX UNIQ_69DD750638A36066 ON acl_classes (class_type) WHERE class_type IS NOT NULL
CREATE TABLE acl_security_identities (id INT IDENTITY NOT NULL, identifier NVARCHAR(200) NOT NULL, username BIT NOT NULL, PRIMARY KEY (id))
CREATE UNIQUE INDEX UNIQ_8835EE78772E836AF85E0677 ON acl_security_identities (identifier, username) WHERE identifier IS NOT NULL AND username IS NOT NULL
CREATE TABLE acl_object_identities (id INT IDENTITY NOT NULL, parent_object_identity_id INT, class_id INT NOT NULL, object_identifier NVARCHAR(100) NOT NULL, entries_inheriting BIT NOT NULL, PRIMARY KEY (id))
CREATE UNIQUE INDEX UNIQ_9407E5494B12AD6EA000B10 ON acl_object_identities (object_identifier, class_id) WHERE object_identifier IS NOT NULL AND class_id IS NOT NULL
CREATE INDEX IDX_9407E54977FA751A ON acl_object_identities (parent_object_identity_id)
CREATE TABLE acl_object_identity_ancestors (object_identity_id INT NOT NULL, ancestor_id INT NOT NULL, PRIMARY KEY (object_identity_id, ancestor_id))
CREATE INDEX IDX_825DE2993D9AB4A6 ON acl_object_identity_ancestors (object_identity_id)
CREATE INDEX IDX_825DE299C671CEA1 ON acl_object_identity_ancestors (ancestor_id)
CREATE TABLE acl_entries (id INT IDENTITY NOT NULL, class_id INT NOT NULL, object_identity_id INT, security_identity_id INT NOT NULL, field_name NVARCHAR(50), ace_order SMALLINT NOT NULL, mask INT NOT NULL, granting BIT NOT NULL, granting_strategy NVARCHAR(30) NOT NULL, audit_success BIT NOT NULL, audit_failure BIT NOT NULL, PRIMARY KEY (id))
CREATE UNIQUE INDEX UNIQ_46C8B806EA000B103D9AB4A64DEF17BCE4289BF4 ON acl_entries (class_id, object_identity_id, field_name, ace_order) WHERE class_id IS NOT NULL AND object_identity_id IS NOT NULL AND field_name IS NOT NULL AND ace_order IS NOT NULL
CREATE INDEX IDX_46C8B806EA000B103D9AB4A6DF9183C9 ON acl_entries (class_id, object_identity_id, security_identity_id)
CREATE INDEX IDX_46C8B806EA000B10 ON acl_entries (class_id)
CREATE INDEX IDX_46C8B8063D9AB4A6 ON acl_entries (object_identity_id)
CREATE INDEX IDX_46C8B806DF9183C9 ON acl_entries (security_identity_id)
ALTER TABLE acl_object_identities ADD CONSTRAINT FK_9407E54977FA751A FOREIGN KEY (parent_object_identity_id) REFERENCES acl_object_identities (id)
ALTER TABLE acl_object_identity_ancestors ADD CONSTRAINT FK_825DE2993D9AB4A6 FOREIGN KEY (object_identity_id) REFERENCES acl_object_identities (id) ON UPDATE CASCADE ON DELETE CASCADE
ALTER TABLE acl_object_identity_ancestors ADD CONSTRAINT FK_825DE299C671CEA1 FOREIGN KEY (ancestor_id) REFERENCES acl_object_identities (id) ON UPDATE CASCADE ON DELETE CASCADE
ALTER TABLE acl_entries ADD CONSTRAINT FK_46C8B806EA000B10 FOREIGN KEY (class_id) REFERENCES acl_classes (id) ON UPDATE CASCADE ON DELETE CASCADE
ALTER TABLE acl_entries ADD CONSTRAINT FK_46C8B8063D9AB4A6 FOREIGN KEY (object_identity_id) REFERENCES acl_object_identities (id) ON UPDATE CASCADE ON DELETE CASCADE
ALTER TABLE acl_entries ADD CONSTRAINT FK_46C8B806DF9183C9 FOREIGN KEY (security_identity_id) REFERENCES acl_security_identities (id) ON UPDATE CASCADE ON DELETE CASCADE security-acl-3.3.3/Resources/schema/mysql.sql 0000664 0000000 0000000 00000006147 14433205003 0021226 0 ustar 00root root 0000000 0000000 CREATE TABLE acl_classes (id INT UNSIGNED AUTO_INCREMENT NOT NULL, class_type VARCHAR(200) NOT NULL, UNIQUE INDEX UNIQ_69DD750638A36066 (class_type), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB
CREATE TABLE acl_security_identities (id INT UNSIGNED AUTO_INCREMENT NOT NULL, identifier VARCHAR(200) NOT NULL, username TINYINT(1) NOT NULL, UNIQUE INDEX UNIQ_8835EE78772E836AF85E0677 (identifier, username), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB
CREATE TABLE acl_object_identities (id INT UNSIGNED AUTO_INCREMENT NOT NULL, parent_object_identity_id INT UNSIGNED DEFAULT NULL, class_id INT UNSIGNED NOT NULL, object_identifier VARCHAR(100) NOT NULL, entries_inheriting TINYINT(1) NOT NULL, UNIQUE INDEX UNIQ_9407E5494B12AD6EA000B10 (object_identifier, class_id), INDEX IDX_9407E54977FA751A (parent_object_identity_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB
CREATE TABLE acl_object_identity_ancestors (object_identity_id INT UNSIGNED NOT NULL, ancestor_id INT UNSIGNED NOT NULL, INDEX IDX_825DE2993D9AB4A6 (object_identity_id), INDEX IDX_825DE299C671CEA1 (ancestor_id), PRIMARY KEY(object_identity_id, ancestor_id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB
CREATE TABLE acl_entries (id INT UNSIGNED AUTO_INCREMENT NOT NULL, class_id INT UNSIGNED NOT NULL, object_identity_id INT UNSIGNED DEFAULT NULL, security_identity_id INT UNSIGNED NOT NULL, field_name VARCHAR(50) DEFAULT NULL, ace_order SMALLINT UNSIGNED NOT NULL, mask INT NOT NULL, granting TINYINT(1) NOT NULL, granting_strategy VARCHAR(30) NOT NULL, audit_success TINYINT(1) NOT NULL, audit_failure TINYINT(1) NOT NULL, UNIQUE INDEX UNIQ_46C8B806EA000B103D9AB4A64DEF17BCE4289BF4 (class_id, object_identity_id, field_name, ace_order), INDEX IDX_46C8B806EA000B103D9AB4A6DF9183C9 (class_id, object_identity_id, security_identity_id), INDEX IDX_46C8B806EA000B10 (class_id), INDEX IDX_46C8B8063D9AB4A6 (object_identity_id), INDEX IDX_46C8B806DF9183C9 (security_identity_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB
ALTER TABLE acl_object_identities ADD CONSTRAINT FK_9407E54977FA751A FOREIGN KEY (parent_object_identity_id) REFERENCES acl_object_identities (id)
ALTER TABLE acl_object_identity_ancestors ADD CONSTRAINT FK_825DE2993D9AB4A6 FOREIGN KEY (object_identity_id) REFERENCES acl_object_identities (id) ON UPDATE CASCADE ON DELETE CASCADE
ALTER TABLE acl_object_identity_ancestors ADD CONSTRAINT FK_825DE299C671CEA1 FOREIGN KEY (ancestor_id) REFERENCES acl_object_identities (id) ON UPDATE CASCADE ON DELETE CASCADE
ALTER TABLE acl_entries ADD CONSTRAINT FK_46C8B806EA000B10 FOREIGN KEY (class_id) REFERENCES acl_classes (id) ON UPDATE CASCADE ON DELETE CASCADE
ALTER TABLE acl_entries ADD CONSTRAINT FK_46C8B8063D9AB4A6 FOREIGN KEY (object_identity_id) REFERENCES acl_object_identities (id) ON UPDATE CASCADE ON DELETE CASCADE
ALTER TABLE acl_entries ADD CONSTRAINT FK_46C8B806DF9183C9 FOREIGN KEY (security_identity_id) REFERENCES acl_security_identities (id) ON UPDATE CASCADE ON DELETE CASCADE security-acl-3.3.3/Resources/schema/oracle.sql 0000664 0000000 0000000 00000016512 14433205003 0021323 0 ustar 00root root 0000000 0000000 CREATE TABLE acl_classes (id NUMBER(10) NOT NULL, class_type VARCHAR2(200) NOT NULL, PRIMARY KEY(id))
DECLARE
constraints_Count NUMBER;
BEGIN
SELECT COUNT(CONSTRAINT_NAME) INTO constraints_Count FROM USER_CONSTRAINTS WHERE TABLE_NAME = 'ACL_CLASSES' AND CONSTRAINT_TYPE = 'P';
IF constraints_Count = 0 OR constraints_Count = '' THEN
EXECUTE IMMEDIATE 'ALTER TABLE ACL_CLASSES ADD CONSTRAINT ACL_CLASSES_AI_PK PRIMARY KEY (ID)';
END IF;
END;
CREATE SEQUENCE ACL_CLASSES_SEQ START WITH 1 MINVALUE 1 INCREMENT BY 1
CREATE TRIGGER ACL_CLASSES_AI_PK
BEFORE INSERT
ON ACL_CLASSES
FOR EACH ROW
DECLARE
last_Sequence NUMBER;
last_InsertID NUMBER;
BEGIN
SELECT ACL_CLASSES_SEQ.NEXTVAL INTO :NEW.ID FROM DUAL;
IF (:NEW.ID IS NULL OR :NEW.ID = 0) THEN
SELECT ACL_CLASSES_SEQ.NEXTVAL INTO :NEW.ID FROM DUAL;
ELSE
SELECT NVL(Last_Number, 0) INTO last_Sequence
FROM User_Sequences
WHERE Sequence_Name = 'ACL_CLASSES_SEQ';
SELECT :NEW.ID INTO last_InsertID FROM DUAL;
WHILE (last_InsertID > last_Sequence) LOOP
SELECT ACL_CLASSES_SEQ.NEXTVAL INTO last_Sequence FROM DUAL;
END LOOP;
END IF;
END;
CREATE UNIQUE INDEX UNIQ_69DD750638A36066 ON acl_classes (class_type)
CREATE TABLE acl_security_identities (id NUMBER(10) NOT NULL, identifier VARCHAR2(200) NOT NULL, username NUMBER(1) NOT NULL, PRIMARY KEY(id))
DECLARE
constraints_Count NUMBER;
BEGIN
SELECT COUNT(CONSTRAINT_NAME) INTO constraints_Count FROM USER_CONSTRAINTS WHERE TABLE_NAME = 'ACL_SECURITY_IDENTITIES' AND CONSTRAINT_TYPE = 'P';
IF constraints_Count = 0 OR constraints_Count = '' THEN
EXECUTE IMMEDIATE 'ALTER TABLE ACL_SECURITY_IDENTITIES ADD CONSTRAINT ACL_SECURITY_IDENTITIES_AI_PK PRIMARY KEY (ID)';
END IF;
END;
CREATE SEQUENCE ACL_SECURITY_IDENTITIES_SEQ START WITH 1 MINVALUE 1 INCREMENT BY 1
CREATE TRIGGER ACL_SECURITY_IDENTITIES_AI_PK
BEFORE INSERT
ON ACL_SECURITY_IDENTITIES
FOR EACH ROW
DECLARE
last_Sequence NUMBER;
last_InsertID NUMBER;
BEGIN
SELECT ACL_SECURITY_IDENTITIES_SEQ.NEXTVAL INTO :NEW.ID FROM DUAL;
IF (:NEW.ID IS NULL OR :NEW.ID = 0) THEN
SELECT ACL_SECURITY_IDENTITIES_SEQ.NEXTVAL INTO :NEW.ID FROM DUAL;
ELSE
SELECT NVL(Last_Number, 0) INTO last_Sequence
FROM User_Sequences
WHERE Sequence_Name = 'ACL_SECURITY_IDENTITIES_SEQ';
SELECT :NEW.ID INTO last_InsertID FROM DUAL;
WHILE (last_InsertID > last_Sequence) LOOP
SELECT ACL_SECURITY_IDENTITIES_SEQ.NEXTVAL INTO last_Sequence FROM DUAL;
END LOOP;
END IF;
END;
CREATE UNIQUE INDEX UNIQ_8835EE78772E836AF85E0677 ON acl_security_identities (identifier, username)
CREATE TABLE acl_object_identities (id NUMBER(10) NOT NULL, parent_object_identity_id NUMBER(10) DEFAULT NULL NULL, class_id NUMBER(10) NOT NULL, object_identifier VARCHAR2(100) NOT NULL, entries_inheriting NUMBER(1) NOT NULL, PRIMARY KEY(id))
DECLARE
constraints_Count NUMBER;
BEGIN
SELECT COUNT(CONSTRAINT_NAME) INTO constraints_Count FROM USER_CONSTRAINTS WHERE TABLE_NAME = 'ACL_OBJECT_IDENTITIES' AND CONSTRAINT_TYPE = 'P';
IF constraints_Count = 0 OR constraints_Count = '' THEN
EXECUTE IMMEDIATE 'ALTER TABLE ACL_OBJECT_IDENTITIES ADD CONSTRAINT ACL_OBJECT_IDENTITIES_AI_PK PRIMARY KEY (ID)';
END IF;
END;
CREATE SEQUENCE ACL_OBJECT_IDENTITIES_SEQ START WITH 1 MINVALUE 1 INCREMENT BY 1
CREATE TRIGGER ACL_OBJECT_IDENTITIES_AI_PK
BEFORE INSERT
ON ACL_OBJECT_IDENTITIES
FOR EACH ROW
DECLARE
last_Sequence NUMBER;
last_InsertID NUMBER;
BEGIN
SELECT ACL_OBJECT_IDENTITIES_SEQ.NEXTVAL INTO :NEW.ID FROM DUAL;
IF (:NEW.ID IS NULL OR :NEW.ID = 0) THEN
SELECT ACL_OBJECT_IDENTITIES_SEQ.NEXTVAL INTO :NEW.ID FROM DUAL;
ELSE
SELECT NVL(Last_Number, 0) INTO last_Sequence
FROM User_Sequences
WHERE Sequence_Name = 'ACL_OBJECT_IDENTITIES_SEQ';
SELECT :NEW.ID INTO last_InsertID FROM DUAL;
WHILE (last_InsertID > last_Sequence) LOOP
SELECT ACL_OBJECT_IDENTITIES_SEQ.NEXTVAL INTO last_Sequence FROM DUAL;
END LOOP;
END IF;
END;
CREATE UNIQUE INDEX UNIQ_9407E5494B12AD6EA000B10 ON acl_object_identities (object_identifier, class_id)
CREATE INDEX IDX_9407E54977FA751A ON acl_object_identities (parent_object_identity_id)
CREATE TABLE acl_object_identity_ancestors (object_identity_id NUMBER(10) NOT NULL, ancestor_id NUMBER(10) NOT NULL, PRIMARY KEY(object_identity_id, ancestor_id))
CREATE INDEX IDX_825DE2993D9AB4A6 ON acl_object_identity_ancestors (object_identity_id)
CREATE INDEX IDX_825DE299C671CEA1 ON acl_object_identity_ancestors (ancestor_id)
CREATE TABLE acl_entries (id NUMBER(10) NOT NULL, class_id NUMBER(10) NOT NULL, object_identity_id NUMBER(10) DEFAULT NULL NULL, security_identity_id NUMBER(10) NOT NULL, field_name VARCHAR2(50) DEFAULT NULL NULL, ace_order NUMBER(5) NOT NULL, mask NUMBER(10) NOT NULL, granting NUMBER(1) NOT NULL, granting_strategy VARCHAR2(30) NOT NULL, audit_success NUMBER(1) NOT NULL, audit_failure NUMBER(1) NOT NULL, PRIMARY KEY(id))
DECLARE
constraints_Count NUMBER;
BEGIN
SELECT COUNT(CONSTRAINT_NAME) INTO constraints_Count FROM USER_CONSTRAINTS WHERE TABLE_NAME = 'ACL_ENTRIES' AND CONSTRAINT_TYPE = 'P';
IF constraints_Count = 0 OR constraints_Count = '' THEN
EXECUTE IMMEDIATE 'ALTER TABLE ACL_ENTRIES ADD CONSTRAINT ACL_ENTRIES_AI_PK PRIMARY KEY (ID)';
END IF;
END;
CREATE SEQUENCE ACL_ENTRIES_SEQ START WITH 1 MINVALUE 1 INCREMENT BY 1
CREATE TRIGGER ACL_ENTRIES_AI_PK
BEFORE INSERT
ON ACL_ENTRIES
FOR EACH ROW
DECLARE
last_Sequence NUMBER;
last_InsertID NUMBER;
BEGIN
SELECT ACL_ENTRIES_SEQ.NEXTVAL INTO :NEW.ID FROM DUAL;
IF (:NEW.ID IS NULL OR :NEW.ID = 0) THEN
SELECT ACL_ENTRIES_SEQ.NEXTVAL INTO :NEW.ID FROM DUAL;
ELSE
SELECT NVL(Last_Number, 0) INTO last_Sequence
FROM User_Sequences
WHERE Sequence_Name = 'ACL_ENTRIES_SEQ';
SELECT :NEW.ID INTO last_InsertID FROM DUAL;
WHILE (last_InsertID > last_Sequence) LOOP
SELECT ACL_ENTRIES_SEQ.NEXTVAL INTO last_Sequence FROM DUAL;
END LOOP;
END IF;
END;
CREATE UNIQUE INDEX UNIQ_46C8B806EA000B103D9AB4A64DEF17BCE4289BF4 ON acl_entries (class_id, object_identity_id, field_name, ace_order)
CREATE INDEX IDX_46C8B806EA000B103D9AB4A6DF9183C9 ON acl_entries (class_id, object_identity_id, security_identity_id)
CREATE INDEX IDX_46C8B806EA000B10 ON acl_entries (class_id)
CREATE INDEX IDX_46C8B8063D9AB4A6 ON acl_entries (object_identity_id)
CREATE INDEX IDX_46C8B806DF9183C9 ON acl_entries (security_identity_id)
ALTER TABLE acl_object_identities ADD CONSTRAINT FK_9407E54977FA751A FOREIGN KEY (parent_object_identity_id) REFERENCES acl_object_identities (id)
ALTER TABLE acl_object_identity_ancestors ADD CONSTRAINT FK_825DE2993D9AB4A6 FOREIGN KEY (object_identity_id) REFERENCES acl_object_identities (id) ON DELETE CASCADE
ALTER TABLE acl_object_identity_ancestors ADD CONSTRAINT FK_825DE299C671CEA1 FOREIGN KEY (ancestor_id) REFERENCES acl_object_identities (id) ON DELETE CASCADE
ALTER TABLE acl_entries ADD CONSTRAINT FK_46C8B806EA000B10 FOREIGN KEY (class_id) REFERENCES acl_classes (id) ON DELETE CASCADE
ALTER TABLE acl_entries ADD CONSTRAINT FK_46C8B8063D9AB4A6 FOREIGN KEY (object_identity_id) REFERENCES acl_object_identities (id) ON DELETE CASCADE
ALTER TABLE acl_entries ADD CONSTRAINT FK_46C8B806DF9183C9 FOREIGN KEY (security_identity_id) REFERENCES acl_security_identities (id) ON DELETE CASCADE security-acl-3.3.3/Resources/schema/postgresql.sql 0000664 0000000 0000000 00000006153 14433205003 0022261 0 ustar 00root root 0000000 0000000 CREATE TABLE acl_classes (id SERIAL NOT NULL, class_type VARCHAR(200) NOT NULL, PRIMARY KEY(id))
CREATE UNIQUE INDEX UNIQ_69DD750638A36066 ON acl_classes (class_type)
CREATE TABLE acl_security_identities (id SERIAL NOT NULL, identifier VARCHAR(200) NOT NULL, username BOOLEAN NOT NULL, PRIMARY KEY(id))
CREATE UNIQUE INDEX UNIQ_8835EE78772E836AF85E0677 ON acl_security_identities (identifier, username)
CREATE TABLE acl_object_identities (id SERIAL NOT NULL, parent_object_identity_id INT DEFAULT NULL, class_id INT NOT NULL, object_identifier VARCHAR(100) NOT NULL, entries_inheriting BOOLEAN NOT NULL, PRIMARY KEY(id))
CREATE UNIQUE INDEX UNIQ_9407E5494B12AD6EA000B10 ON acl_object_identities (object_identifier, class_id)
CREATE INDEX IDX_9407E54977FA751A ON acl_object_identities (parent_object_identity_id)
CREATE TABLE acl_object_identity_ancestors (object_identity_id INT NOT NULL, ancestor_id INT NOT NULL, PRIMARY KEY(object_identity_id, ancestor_id))
CREATE INDEX IDX_825DE2993D9AB4A6 ON acl_object_identity_ancestors (object_identity_id)
CREATE INDEX IDX_825DE299C671CEA1 ON acl_object_identity_ancestors (ancestor_id)
CREATE TABLE acl_entries (id SERIAL NOT NULL, class_id INT NOT NULL, object_identity_id INT DEFAULT NULL, security_identity_id INT NOT NULL, field_name VARCHAR(50) DEFAULT NULL, ace_order SMALLINT NOT NULL, mask INT NOT NULL, granting BOOLEAN NOT NULL, granting_strategy VARCHAR(30) NOT NULL, audit_success BOOLEAN NOT NULL, audit_failure BOOLEAN NOT NULL, PRIMARY KEY(id))
CREATE UNIQUE INDEX UNIQ_46C8B806EA000B103D9AB4A64DEF17BCE4289BF4 ON acl_entries (class_id, object_identity_id, field_name, ace_order)
CREATE INDEX IDX_46C8B806EA000B103D9AB4A6DF9183C9 ON acl_entries (class_id, object_identity_id, security_identity_id)
CREATE INDEX IDX_46C8B806EA000B10 ON acl_entries (class_id)
CREATE INDEX IDX_46C8B8063D9AB4A6 ON acl_entries (object_identity_id)
CREATE INDEX IDX_46C8B806DF9183C9 ON acl_entries (security_identity_id)
ALTER TABLE acl_object_identities ADD CONSTRAINT FK_9407E54977FA751A FOREIGN KEY (parent_object_identity_id) REFERENCES acl_object_identities (id) NOT DEFERRABLE INITIALLY IMMEDIATE
ALTER TABLE acl_object_identity_ancestors ADD CONSTRAINT FK_825DE2993D9AB4A6 FOREIGN KEY (object_identity_id) REFERENCES acl_object_identities (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE
ALTER TABLE acl_object_identity_ancestors ADD CONSTRAINT FK_825DE299C671CEA1 FOREIGN KEY (ancestor_id) REFERENCES acl_object_identities (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE
ALTER TABLE acl_entries ADD CONSTRAINT FK_46C8B806EA000B10 FOREIGN KEY (class_id) REFERENCES acl_classes (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE
ALTER TABLE acl_entries ADD CONSTRAINT FK_46C8B8063D9AB4A6 FOREIGN KEY (object_identity_id) REFERENCES acl_object_identities (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE
ALTER TABLE acl_entries ADD CONSTRAINT FK_46C8B806DF9183C9 FOREIGN KEY (security_identity_id) REFERENCES acl_security_identities (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE security-acl-3.3.3/Resources/schema/sqlanywhere.sql 0000664 0000000 0000000 00000006016 14433205003 0022416 0 ustar 00root root 0000000 0000000 CREATE TABLE acl_classes (id UNSIGNED INT IDENTITY NOT NULL, class_type VARCHAR(200) NOT NULL, PRIMARY KEY (id))
CREATE UNIQUE INDEX UNIQ_69DD750638A36066 ON acl_classes (class_type)
CREATE TABLE acl_security_identities (id UNSIGNED INT IDENTITY NOT NULL, identifier VARCHAR(200) NOT NULL, username BIT NOT NULL, PRIMARY KEY (id))
CREATE UNIQUE INDEX UNIQ_8835EE78772E836AF85E0677 ON acl_security_identities (identifier, username)
CREATE TABLE acl_object_identities (id UNSIGNED INT IDENTITY NOT NULL, parent_object_identity_id UNSIGNED INT DEFAULT NULL, class_id UNSIGNED INT NOT NULL, object_identifier VARCHAR(100) NOT NULL, entries_inheriting BIT NOT NULL, PRIMARY KEY (id))
CREATE UNIQUE INDEX UNIQ_9407E5494B12AD6EA000B10 ON acl_object_identities (object_identifier, class_id)
CREATE INDEX IDX_9407E54977FA751A ON acl_object_identities (parent_object_identity_id)
CREATE TABLE acl_object_identity_ancestors (object_identity_id UNSIGNED INT NOT NULL, ancestor_id UNSIGNED INT NOT NULL, PRIMARY KEY (object_identity_id, ancestor_id))
CREATE INDEX IDX_825DE2993D9AB4A6 ON acl_object_identity_ancestors (object_identity_id)
CREATE INDEX IDX_825DE299C671CEA1 ON acl_object_identity_ancestors (ancestor_id)
CREATE TABLE acl_entries (id UNSIGNED INT IDENTITY NOT NULL, class_id UNSIGNED INT NOT NULL, object_identity_id UNSIGNED INT DEFAULT NULL, security_identity_id UNSIGNED INT NOT NULL, field_name VARCHAR(50) DEFAULT NULL, ace_order UNSIGNED SMALLINT NOT NULL, mask INT NOT NULL, granting BIT NOT NULL, granting_strategy VARCHAR(30) NOT NULL, audit_success BIT NOT NULL, audit_failure BIT NOT NULL, PRIMARY KEY (id))
CREATE UNIQUE INDEX UNIQ_46C8B806EA000B103D9AB4A64DEF17BCE4289BF4 ON acl_entries (class_id, object_identity_id, field_name, ace_order)
CREATE INDEX IDX_46C8B806EA000B103D9AB4A6DF9183C9 ON acl_entries (class_id, object_identity_id, security_identity_id)
CREATE INDEX IDX_46C8B806EA000B10 ON acl_entries (class_id)
CREATE INDEX IDX_46C8B8063D9AB4A6 ON acl_entries (object_identity_id)
CREATE INDEX IDX_46C8B806DF9183C9 ON acl_entries (security_identity_id)
ALTER TABLE acl_object_identities ADD CONSTRAINT FK_9407E54977FA751A FOREIGN KEY (parent_object_identity_id) REFERENCES acl_object_identities (id)
ALTER TABLE acl_object_identity_ancestors ADD CONSTRAINT FK_825DE2993D9AB4A6 FOREIGN KEY (object_identity_id) REFERENCES acl_object_identities (id) ON UPDATE CASCADE ON DELETE CASCADE
ALTER TABLE acl_object_identity_ancestors ADD CONSTRAINT FK_825DE299C671CEA1 FOREIGN KEY (ancestor_id) REFERENCES acl_object_identities (id) ON UPDATE CASCADE ON DELETE CASCADE
ALTER TABLE acl_entries ADD CONSTRAINT FK_46C8B806EA000B10 FOREIGN KEY (class_id) REFERENCES acl_classes (id) ON UPDATE CASCADE ON DELETE CASCADE
ALTER TABLE acl_entries ADD CONSTRAINT FK_46C8B8063D9AB4A6 FOREIGN KEY (object_identity_id) REFERENCES acl_object_identities (id) ON UPDATE CASCADE ON DELETE CASCADE
ALTER TABLE acl_entries ADD CONSTRAINT FK_46C8B806DF9183C9 FOREIGN KEY (security_identity_id) REFERENCES acl_security_identities (id) ON UPDATE CASCADE ON DELETE CASCADE security-acl-3.3.3/Resources/schema/sqlite.sql 0000664 0000000 0000000 00000006045 14433205003 0021357 0 ustar 00root root 0000000 0000000 CREATE TABLE acl_classes (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, class_type VARCHAR(200) NOT NULL)
CREATE UNIQUE INDEX UNIQ_69DD750638A36066 ON acl_classes (class_type)
CREATE TABLE acl_security_identities (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, identifier VARCHAR(200) NOT NULL, username BOOLEAN NOT NULL)
CREATE UNIQUE INDEX UNIQ_8835EE78772E836AF85E0677 ON acl_security_identities (identifier, username)
CREATE TABLE acl_object_identities (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, parent_object_identity_id INTEGER UNSIGNED DEFAULT NULL, class_id INTEGER UNSIGNED NOT NULL, object_identifier VARCHAR(100) NOT NULL, entries_inheriting BOOLEAN NOT NULL, CONSTRAINT FK_9407E54977FA751A FOREIGN KEY (parent_object_identity_id) REFERENCES acl_object_identities (id) NOT DEFERRABLE INITIALLY IMMEDIATE)
CREATE UNIQUE INDEX UNIQ_9407E5494B12AD6EA000B10 ON acl_object_identities (object_identifier, class_id)
CREATE INDEX IDX_9407E54977FA751A ON acl_object_identities (parent_object_identity_id)
CREATE TABLE acl_object_identity_ancestors (object_identity_id INTEGER UNSIGNED NOT NULL, ancestor_id INTEGER UNSIGNED NOT NULL, PRIMARY KEY(object_identity_id, ancestor_id), CONSTRAINT FK_825DE2993D9AB4A6 FOREIGN KEY (object_identity_id) REFERENCES acl_object_identities (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_825DE299C671CEA1 FOREIGN KEY (ancestor_id) REFERENCES acl_object_identities (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE)
CREATE INDEX IDX_825DE2993D9AB4A6 ON acl_object_identity_ancestors (object_identity_id)
CREATE INDEX IDX_825DE299C671CEA1 ON acl_object_identity_ancestors (ancestor_id)
CREATE TABLE acl_entries (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, class_id INTEGER UNSIGNED NOT NULL, object_identity_id INTEGER UNSIGNED DEFAULT NULL, security_identity_id INTEGER UNSIGNED NOT NULL, field_name VARCHAR(50) DEFAULT NULL, ace_order SMALLINT UNSIGNED NOT NULL, mask INTEGER NOT NULL, granting BOOLEAN NOT NULL, granting_strategy VARCHAR(30) NOT NULL, audit_success BOOLEAN NOT NULL, audit_failure BOOLEAN NOT NULL, CONSTRAINT FK_46C8B806EA000B10 FOREIGN KEY (class_id) REFERENCES acl_classes (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_46C8B8063D9AB4A6 FOREIGN KEY (object_identity_id) REFERENCES acl_object_identities (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_46C8B806DF9183C9 FOREIGN KEY (security_identity_id) REFERENCES acl_security_identities (id) ON UPDATE CASCADE ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE)
CREATE UNIQUE INDEX UNIQ_46C8B806EA000B103D9AB4A64DEF17BCE4289BF4 ON acl_entries (class_id, object_identity_id, field_name, ace_order)
CREATE INDEX IDX_46C8B806EA000B103D9AB4A6DF9183C9 ON acl_entries (class_id, object_identity_id, security_identity_id)
CREATE INDEX IDX_46C8B806EA000B10 ON acl_entries (class_id)
CREATE INDEX IDX_46C8B8063D9AB4A6 ON acl_entries (object_identity_id)
CREATE INDEX IDX_46C8B806DF9183C9 ON acl_entries (security_identity_id) security-acl-3.3.3/Tests/ 0000775 0000000 0000000 00000000000 14433205003 0015220 5 ustar 00root root 0000000 0000000 security-acl-3.3.3/Tests/Dbal/ 0000775 0000000 0000000 00000000000 14433205003 0016062 5 ustar 00root root 0000000 0000000 security-acl-3.3.3/Tests/Dbal/AclProviderBenchmarkTest.php 0000664 0000000 0000000 00000020626 14433205003 0023466 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Tests\Dbal;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DriverManager;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Security\Acl\Dbal\AclProvider;
use Symfony\Component\Security\Acl\Dbal\Schema;
use Symfony\Component\Security\Acl\Domain\ObjectIdentity;
use Symfony\Component\Security\Acl\Domain\PermissionGrantingStrategy;
/**
* @group benchmark
*/
class AclProviderBenchmarkTest extends TestCase
{
/** @var Connection */
protected $connection;
protected $insertClassStmt;
protected $insertSidStmt;
protected $insertOidAncestorStmt;
protected $insertOidStmt;
protected $insertEntryStmt;
protected function setUp(): void
{
try {
$this->connection = DriverManager::getConnection([
'driver' => 'pdo_mysql',
'host' => 'localhost',
'user' => 'root',
'dbname' => 'testdb',
]);
$this->connection->connect();
} catch (\Exception $e) {
$this->markTestSkipped('Unable to connect to the database: '.$e->getMessage());
}
}
protected function tearDown(): void
{
$this->connection = null;
}
public function testFindAcls()
{
// $this->generateTestData();
// get some random test object identities from the database
$oids = [];
$stmt = $this->connection->executeQuery('SELECT object_identifier, class_type FROM acl_object_identities o INNER JOIN acl_classes c ON c.id = o.class_id ORDER BY RAND() LIMIT 25');
foreach ($stmt->fetchAllAssociative() as $oid) {
$oids[] = new ObjectIdentity($oid['object_identifier'], $oid['class_type']);
}
$provider = $this->getProvider();
$start = microtime(true);
$provider->findAcls($oids);
$time = microtime(true) - $start;
echo 'Total Time: '.$time."s\n";
}
/**
* This generates a huge amount of test data to be used mainly for benchmarking
* purposes, not so much for testing. That's why it's not called by default.
*/
protected function generateTestData()
{
$sm = $this->connection->createSchemaManager();
$sm->dropDatabase('testdb');
$sm->createDatabase('testdb');
$this->connection->executeStatement('USE testdb');
// import the schema
$schema = new Schema($options = $this->getOptions());
foreach ($schema->toSql($this->connection->getDatabasePlatform()) as $sql) {
$this->connection->executeStatement($sql);
}
// setup prepared statements
$this->insertClassStmt = $this->connection->prepare('INSERT INTO acl_classes (id, class_type) VALUES (?, ?)');
$this->insertSidStmt = $this->connection->prepare('INSERT INTO acl_security_identities (id, identifier, username) VALUES (?, ?, ?)');
$this->insertOidStmt = $this->connection->prepare('INSERT INTO acl_object_identities (id, class_id, object_identifier, parent_object_identity_id, entries_inheriting) VALUES (?, ?, ?, ?, ?)');
$this->insertEntryStmt = $this->connection->prepare('INSERT INTO acl_entries (id, class_id, object_identity_id, field_name, ace_order, security_identity_id, mask, granting, granting_strategy, audit_success, audit_failure) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
$this->insertOidAncestorStmt = $this->connection->prepare('INSERT INTO acl_object_identity_ancestors (object_identity_id, ancestor_id) VALUES (?, ?)');
for ($i = 0; $i < 40000; ++$i) {
$this->generateAclHierarchy();
}
}
protected function generateAclHierarchy()
{
$rootId = $this->generateAcl($this->chooseClassId(), null, []);
$this->generateAclLevel(rand(1, 15), $rootId, [$rootId]);
}
protected function generateAclLevel($depth, $parentId, $ancestors)
{
$level = \count($ancestors);
for ($i = 0, $t = rand(1, 10); $i < $t; ++$i) {
$id = $this->generateAcl($this->chooseClassId(), $parentId, $ancestors);
if ($level < $depth) {
$this->generateAclLevel($depth, $id, array_merge($ancestors, [$id]));
}
}
}
protected function chooseClassId()
{
static $id = 1000;
if (1000 === $id || ($id < 1500 && rand(0, 1))) {
$this->insertClassStmt->executeStatement([$id, $this->getRandomString(rand(20, 100), 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\\_')]);
++$id;
return $id - 1;
} else {
return rand(1000, $id - 1);
}
}
protected function generateAcl($classId, $parentId, $ancestors)
{
static $id = 1000;
$this->insertOidStmt->executeStatement([
$id,
$classId,
$this->getRandomString(rand(20, 50)),
$parentId,
rand(0, 1),
]);
$this->insertOidAncestorStmt->executeStatement([$id, $id]);
foreach ($ancestors as $ancestor) {
$this->insertOidAncestorStmt->executeStatement([$id, $ancestor]);
}
$this->generateAces($classId, $id);
++$id;
return $id - 1;
}
protected function chooseSid()
{
static $id = 1000;
if (1000 === $id || ($id < 11000 && rand(0, 1))) {
$this->insertSidStmt->executeStatement([
$id,
$this->getRandomString(rand(5, 30)),
rand(0, 1),
]);
++$id;
return $id - 1;
} else {
return rand(1000, $id - 1);
}
}
protected function generateAces($classId, $objectId)
{
static $id = 1000;
$sids = [];
$fieldOrder = [];
for ($i = 0; $i <= 30; ++$i) {
$fieldName = rand(0, 1) ? null : $this->getRandomString(rand(10, 20));
do {
$sid = $this->chooseSid();
} while (\array_key_exists($sid, $sids) && \in_array($fieldName, $sids[$sid], true));
$fieldOrder[$fieldName] = \array_key_exists($fieldName, $fieldOrder) ? $fieldOrder[$fieldName] + 1 : 0;
if (!isset($sids[$sid])) {
$sids[$sid] = [];
}
$sids[$sid][] = $fieldName;
$strategy = rand(0, 2);
if (0 === $strategy) {
$strategy = PermissionGrantingStrategy::ALL;
} elseif (1 === $strategy) {
$strategy = PermissionGrantingStrategy::ANY;
} else {
$strategy = PermissionGrantingStrategy::EQUAL;
}
// id, cid, oid, field, order, sid, mask, granting, strategy, a success, a failure
$this->insertEntryStmt->executeStatement([
$id,
$classId,
rand(0, 5) ? $objectId : null,
$fieldName,
$fieldOrder[$fieldName],
$sid,
$this->generateMask(),
rand(0, 1),
$strategy,
rand(0, 1),
rand(0, 1),
]);
++$id;
}
}
protected function generateMask()
{
$i = rand(1, 30);
$mask = 0;
while ($i <= 30) {
$mask |= 1 << rand(0, 30);
++$i;
}
return $mask;
}
protected function getRandomString($length, $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789')
{
$s = '';
$cLength = \strlen($chars);
while (\strlen($s) < $length) {
$s .= $chars[mt_rand(0, $cLength - 1)];
}
return $s;
}
protected function getOptions()
{
return [
'oid_table_name' => 'acl_object_identities',
'oid_ancestors_table_name' => 'acl_object_identity_ancestors',
'class_table_name' => 'acl_classes',
'sid_table_name' => 'acl_security_identities',
'entry_table_name' => 'acl_entries',
];
}
protected function getStrategy()
{
return new PermissionGrantingStrategy();
}
protected function getProvider()
{
return new AclProvider($this->connection, $this->getStrategy(), $this->getOptions());
}
}
security-acl-3.3.3/Tests/Dbal/AclProviderTest.php 0000664 0000000 0000000 00000023016 14433205003 0021647 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Tests\Dbal;
use Doctrine\DBAL\DriverManager;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Security\Acl\Dbal\AclProvider;
use Symfony\Component\Security\Acl\Dbal\Schema;
use Symfony\Component\Security\Acl\Domain\Acl;
use Symfony\Component\Security\Acl\Domain\Entry;
use Symfony\Component\Security\Acl\Domain\ObjectIdentity;
use Symfony\Component\Security\Acl\Domain\PermissionGrantingStrategy;
use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity;
use Symfony\Component\Security\Acl\Exception\AclNotFoundException;
use Symfony\Component\Security\Acl\Exception\NotAllAclsFoundException;
/**
* @requires extension pdo_sqlite
*/
class AclProviderTest extends TestCase
{
private $connection;
/**
* @expectedMessage There is no ACL for the given object identity.
*/
public function testFindAclThrowsExceptionWhenNoAclExists()
{
$this->expectException(AclNotFoundException::class);
$this->getProvider()->findAcl(new ObjectIdentity('foo', 'foo'));
}
public function testFindAclsThrowsExceptionUnlessAnACLIsFoundForEveryOID()
{
$oids = [];
$oids[] = new ObjectIdentity('1', 'foo');
$oids[] = new ObjectIdentity('foo', 'foo');
try {
$this->getProvider()->findAcls($oids);
$this->fail('Provider did not throw an expected exception.');
} catch (\Exception $e) {
$this->assertInstanceOf(AclNotFoundException::class, $e);
$this->assertInstanceOf(NotAllAclsFoundException::class, $e);
$partialResult = $e->getPartialResult();
$this->assertTrue($partialResult->contains($oids[0]));
$this->assertFalse($partialResult->contains($oids[1]));
}
}
public function testFindAcls()
{
$oids = [];
$oids[] = new ObjectIdentity('1', 'foo');
$oids[] = new ObjectIdentity('2', 'foo');
$provider = $this->getProvider();
$acls = $provider->findAcls($oids);
$this->assertInstanceOf('SplObjectStorage', $acls);
$this->assertCount(2, $acls);
$this->assertInstanceOf(Acl::class, $acl0 = $acls->offsetGet($oids[0]));
$this->assertInstanceOf(Acl::class, $acl1 = $acls->offsetGet($oids[1]));
$this->assertTrue($oids[0]->equals($acl0->getObjectIdentity()));
$this->assertTrue($oids[1]->equals($acl1->getObjectIdentity()));
}
public function testFindAclsWithDifferentTypes()
{
$oids = [];
$oids[] = new ObjectIdentity('123', 'Bundle\SomeVendor\MyBundle\Entity\SomeEntity');
$oids[] = new ObjectIdentity('123', 'Bundle\MyBundle\Entity\AnotherEntity');
$provider = $this->getProvider();
$acls = $provider->findAcls($oids);
$this->assertInstanceOf('SplObjectStorage', $acls);
$this->assertCount(2, $acls);
$this->assertInstanceOf(Acl::class, $acl0 = $acls->offsetGet($oids[0]));
$this->assertInstanceOf(Acl::class, $acl1 = $acls->offsetGet($oids[1]));
$this->assertTrue($oids[0]->equals($acl0->getObjectIdentity()));
$this->assertTrue($oids[1]->equals($acl1->getObjectIdentity()));
}
public function testFindAclCachesAclInMemory()
{
$oid = new ObjectIdentity('1', 'foo');
$provider = $this->getProvider();
$acl = $provider->findAcl($oid);
$this->assertSame($acl, $cAcl = $provider->findAcl($oid));
$cAces = $cAcl->getObjectAces();
foreach ($acl->getObjectAces() as $index => $ace) {
$this->assertSame($ace, $cAces[$index]);
}
}
public function testFindAcl()
{
$oid = new ObjectIdentity('1', 'foo');
$provider = $this->getProvider();
$acl = $provider->findAcl($oid);
$this->assertInstanceOf(Acl::class, $acl);
$this->assertTrue($oid->equals($acl->getObjectIdentity()));
$this->assertEquals(4, $acl->getId());
$this->assertCount(0, $acl->getClassAces());
$this->assertCount(0, $this->getField($acl, 'classFieldAces'));
$this->assertCount(3, $acl->getObjectAces());
$this->assertCount(0, $this->getField($acl, 'objectFieldAces'));
$aces = $acl->getObjectAces();
$this->assertInstanceOf(Entry::class, $aces[0]);
$this->assertTrue($aces[0]->isGranting());
$this->assertTrue($aces[0]->isAuditSuccess());
$this->assertTrue($aces[0]->isAuditFailure());
$this->assertEquals('all', $aces[0]->getStrategy());
$this->assertSame(2, $aces[0]->getMask());
// check ACE are in correct order
$i = 0;
foreach ($aces as $index => $ace) {
$this->assertEquals($i, $index);
++$i;
}
$sid = $aces[0]->getSecurityIdentity();
$this->assertInstanceOf(UserSecurityIdentity::class, $sid);
$this->assertEquals('john.doe', $sid->getUsername());
$this->assertEquals('SomeClass', $sid->getClass());
}
protected function setUp(): void
{
$this->connection = DriverManager::getConnection([
'driver' => 'pdo_sqlite',
'memory' => true,
]);
// import the schema
$schema = new Schema($this->getOptions());
foreach ($schema->toSql($this->connection->getDatabasePlatform()) as $sql) {
$this->connection->executeStatement($sql);
}
// populate the schema with some test data
$insertClassStmt = $this->connection->prepare('INSERT INTO acl_classes (id, class_type) VALUES (?, ?)');
foreach ($this->getClassData() as $data) {
$insertClassStmt->executeStatement($data);
}
$insertSidStmt = $this->connection->prepare('INSERT INTO acl_security_identities (id, identifier, username) VALUES (?, ?, ?)');
foreach ($this->getSidData() as $data) {
$insertSidStmt->executeStatement($data);
}
$insertOidStmt = $this->connection->prepare('INSERT INTO acl_object_identities (id, class_id, object_identifier, parent_object_identity_id, entries_inheriting) VALUES (?, ?, ?, ?, ?)');
foreach ($this->getOidData() as $data) {
$insertOidStmt->executeStatement($data);
}
$insertEntryStmt = $this->connection->prepare('INSERT INTO acl_entries (id, class_id, object_identity_id, field_name, ace_order, security_identity_id, mask, granting, granting_strategy, audit_success, audit_failure) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
foreach ($this->getEntryData() as $data) {
$insertEntryStmt->executeStatement($data);
}
$insertOidAncestorStmt = $this->connection->prepare('INSERT INTO acl_object_identity_ancestors (object_identity_id, ancestor_id) VALUES (?, ?)');
foreach ($this->getOidAncestorData() as $data) {
$insertOidAncestorStmt->executeStatement($data);
}
}
protected function tearDown(): void
{
$this->connection = null;
}
protected function getField($object, $field)
{
$reflection = new \ReflectionProperty($object, $field);
$reflection->setAccessible(true);
return $reflection->getValue($object);
}
protected function getEntryData()
{
// id, cid, oid, field, order, sid, mask, granting, strategy, a success, a failure
return [
[1, 1, 1, null, 0, 1, 1, 1, 'all', 1, 1],
[2, 1, 1, null, 1, 2, 1 << 2 | 1 << 1, 0, 'any', 0, 0],
[3, 3, 4, null, 0, 1, 2, 1, 'all', 1, 1],
[4, 3, 4, null, 2, 2, 1, 1, 'all', 1, 1],
[5, 3, 4, null, 1, 3, 1, 1, 'all', 1, 1],
];
}
protected function getOidData()
{
// id, cid, oid, parent_oid, entries_inheriting
return [
[1, 1, '123', null, 1],
[2, 2, '123', 1, 1],
[3, 2, 'i:3:123', 1, 1],
[4, 3, '1', 2, 1],
[5, 3, '2', 2, 1],
];
}
protected function getOidAncestorData()
{
return [
[1, 1],
[2, 1],
[2, 2],
[3, 1],
[3, 3],
[4, 2],
[4, 1],
[4, 4],
[5, 2],
[5, 1],
[5, 5],
];
}
protected function getSidData()
{
return [
[1, 'SomeClass-john.doe', 1],
[2, 'MyClass-john.doe@foo.com', 1],
[3, 'FooClass-123', 1],
[4, 'MooClass-ROLE_USER', 1],
[5, 'ROLE_USER', 0],
[6, 'IS_AUTHENTICATED_FULLY', 0],
];
}
protected function getClassData()
{
return [
[1, 'Bundle\SomeVendor\MyBundle\Entity\SomeEntity'],
[2, 'Bundle\MyBundle\Entity\AnotherEntity'],
[3, 'foo'],
];
}
protected function getOptions()
{
return [
'oid_table_name' => 'acl_object_identities',
'oid_ancestors_table_name' => 'acl_object_identity_ancestors',
'class_table_name' => 'acl_classes',
'sid_table_name' => 'acl_security_identities',
'entry_table_name' => 'acl_entries',
];
}
protected function getStrategy(): PermissionGrantingStrategy
{
return new PermissionGrantingStrategy();
}
protected function getProvider(): AclProvider
{
return new AclProvider($this->connection, $this->getStrategy(), $this->getOptions());
}
}
security-acl-3.3.3/Tests/Dbal/MutableAclProviderTest.php 0000664 0000000 0000000 00000053213 14433205003 0023163 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Tests\Dbal;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\DriverManager;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Security\Acl\Dbal\AclProvider;
use Symfony\Component\Security\Acl\Dbal\MutableAclProvider;
use Symfony\Component\Security\Acl\Dbal\Schema;
use Symfony\Component\Security\Acl\Domain\Acl;
use Symfony\Component\Security\Acl\Domain\Entry;
use Symfony\Component\Security\Acl\Domain\ObjectIdentity;
use Symfony\Component\Security\Acl\Domain\PermissionGrantingStrategy;
use Symfony\Component\Security\Acl\Domain\RoleSecurityIdentity;
use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity;
use Symfony\Component\Security\Acl\Exception\AclNotFoundException;
use Symfony\Component\Security\Acl\Exception\ConcurrentModificationException;
use Symfony\Component\Security\Acl\Model\AuditableEntryInterface;
use Symfony\Component\Security\Acl\Model\EntryInterface;
use Symfony\Component\Security\Acl\Model\FieldEntryInterface;
/**
* @requires extension pdo_sqlite
*/
class MutableAclProviderTest extends TestCase
{
protected $connection;
public static function assertAceEquals(EntryInterface $a, EntryInterface $b)
{
self::assertInstanceOf(\get_class($a), $b);
foreach (['getId', 'getMask', 'getStrategy', 'isGranting'] as $getter) {
self::assertSame($a->$getter(), $b->$getter());
}
self::assertTrue($a->getSecurityIdentity()->equals($b->getSecurityIdentity()));
self::assertSame($a->getAcl()->getId(), $b->getAcl()->getId());
if ($a instanceof AuditableEntryInterface) {
self::assertSame($a->isAuditSuccess(), $b->isAuditSuccess());
self::assertSame($a->isAuditFailure(), $b->isAuditFailure());
}
if ($a instanceof FieldEntryInterface) {
self::assertSame($a->getField(), $b->getField());
}
}
public function testCreateAclThrowsExceptionWhenAclAlreadyExists()
{
$this->expectException(\Symfony\Component\Security\Acl\Exception\AclAlreadyExistsException::class);
$provider = $this->getProvider();
$oid = new ObjectIdentity('123456', 'FOO');
$provider->createAcl($oid);
$provider->createAcl($oid);
}
public function testCreateAcl()
{
$provider = $this->getProvider();
$oid = new ObjectIdentity('123456', 'FOO');
$acl = $provider->createAcl($oid);
$cachedAcl = $provider->findAcl($oid);
$this->assertInstanceOf(Acl::class, $acl);
$this->assertSame($acl, $cachedAcl);
$this->assertTrue($acl->getObjectIdentity()->equals($oid));
}
public function testDeleteAcl()
{
$provider = $this->getProvider();
$oid = new ObjectIdentity(1, 'Foo');
$acl = $provider->createAcl($oid);
$provider->deleteAcl($oid);
$loadedAcls = $this->getField($provider, 'loadedAcls');
$this->assertCount(0, $loadedAcls['Foo']);
try {
$provider->findAcl($oid);
$this->fail('ACL has not been properly deleted.');
} catch (AclNotFoundException $e) {
}
}
public function testDeleteAclDeletesChildren()
{
$provider = $this->getProvider();
$acl = $provider->createAcl(new ObjectIdentity(1, 'Foo'));
$parentAcl = $provider->createAcl(new ObjectIdentity(2, 'Foo'));
$acl->setParentAcl($parentAcl);
$provider->updateAcl($acl);
$provider->deleteAcl($parentAcl->getObjectIdentity());
$this->expectException(AclNotFoundException::class);
$this->expectExceptionMessage('There is no ACL for the given object identity.');
$provider->findAcl(new ObjectIdentity(1, 'Foo'));
}
public function testFindAclsAddsPropertyListener()
{
$provider = $this->getProvider();
$acl = $provider->createAcl(new ObjectIdentity(1, 'Foo'));
$propertyChanges = $this->getField($provider, 'propertyChanges');
$this->assertCount(1, $propertyChanges);
$this->assertTrue($propertyChanges->contains($acl));
$this->assertEquals([], $propertyChanges->offsetGet($acl));
$listeners = $this->getField($acl, 'listeners');
$this->assertSame($provider, $listeners[0]);
}
public function testFindAclsAddsPropertyListenerOnlyOnce()
{
$provider = $this->getProvider();
$acl = $provider->createAcl(new ObjectIdentity(1, 'Foo'));
$acl = $provider->findAcl(new ObjectIdentity(1, 'Foo'));
$propertyChanges = $this->getField($provider, 'propertyChanges');
$this->assertCount(1, $propertyChanges);
$this->assertTrue($propertyChanges->contains($acl));
$this->assertEquals([], $propertyChanges->offsetGet($acl));
$listeners = $this->getField($acl, 'listeners');
$this->assertCount(1, $listeners);
$this->assertSame($provider, $listeners[0]);
}
public function testFindAclsAddsPropertyListenerToParentAcls()
{
$provider = $this->getProvider();
$this->importAcls($provider, [
'main' => [
'object_identifier' => '1',
'class_type' => 'foo',
'parent_acl' => 'parent',
],
'parent' => [
'object_identifier' => '1',
'class_type' => 'anotherFoo',
],
]);
$propertyChanges = $this->getField($provider, 'propertyChanges');
$this->assertCount(0, $propertyChanges);
$acl = $provider->findAcl(new ObjectIdentity('1', 'foo'));
$this->assertCount(2, $propertyChanges);
$this->assertTrue($propertyChanges->contains($acl));
$this->assertTrue($propertyChanges->contains($acl->getParentAcl()));
}
public function testPropertyChangedDoesNotTrackUnmanagedAcls()
{
$this->expectException(\InvalidArgumentException::class);
$provider = $this->getProvider();
$acl = new Acl(1, new ObjectIdentity(1, 'foo'), new PermissionGrantingStrategy(), [], false);
$provider->propertyChanged($acl, 'classAces', [], ['foo']);
}
public function testPropertyChangedTracksChangesToAclProperties()
{
$provider = $this->getProvider();
$acl = $provider->createAcl(new ObjectIdentity(1, 'Foo'));
$propertyChanges = $this->getField($provider, 'propertyChanges');
$provider->propertyChanged($acl, 'entriesInheriting', false, true);
$changes = $propertyChanges->offsetGet($acl);
$this->assertTrue(isset($changes['entriesInheriting']));
$this->assertFalse($changes['entriesInheriting'][0]);
$this->assertTrue($changes['entriesInheriting'][1]);
$provider->propertyChanged($acl, 'entriesInheriting', true, false);
$provider->propertyChanged($acl, 'entriesInheriting', false, true);
$provider->propertyChanged($acl, 'entriesInheriting', true, false);
$changes = $propertyChanges->offsetGet($acl);
$this->assertFalse(isset($changes['entriesInheriting']));
}
public function testPropertyChangedTracksChangesToAceProperties()
{
$provider = $this->getProvider();
$acl = $provider->createAcl(new ObjectIdentity(1, 'Foo'));
$ace = new Entry(1, $acl, new UserSecurityIdentity('foo', 'FooClass'), 'all', 1, true, true, true);
$ace2 = new Entry(2, $acl, new UserSecurityIdentity('foo', 'FooClass'), 'all', 1, true, true, true);
$propertyChanges = $this->getField($provider, 'propertyChanges');
$provider->propertyChanged($ace, 'mask', 1, 3);
$changes = $propertyChanges->offsetGet($acl);
$this->assertTrue(isset($changes['aces']));
$this->assertInstanceOf('\SplObjectStorage', $changes['aces']);
$this->assertTrue($changes['aces']->contains($ace));
$aceChanges = $changes['aces']->offsetGet($ace);
$this->assertTrue(isset($aceChanges['mask']));
$this->assertEquals(1, $aceChanges['mask'][0]);
$this->assertEquals(3, $aceChanges['mask'][1]);
$provider->propertyChanged($ace, 'strategy', 'all', 'any');
$changes = $propertyChanges->offsetGet($acl);
$this->assertTrue(isset($changes['aces']));
$this->assertInstanceOf('\SplObjectStorage', $changes['aces']);
$this->assertTrue($changes['aces']->contains($ace));
$aceChanges = $changes['aces']->offsetGet($ace);
$this->assertTrue(isset($aceChanges['mask']));
$this->assertTrue(isset($aceChanges['strategy']));
$this->assertEquals('all', $aceChanges['strategy'][0]);
$this->assertEquals('any', $aceChanges['strategy'][1]);
$provider->propertyChanged($ace, 'mask', 3, 1);
$changes = $propertyChanges->offsetGet($acl);
$aceChanges = $changes['aces']->offsetGet($ace);
$this->assertFalse(isset($aceChanges['mask']));
$this->assertTrue(isset($aceChanges['strategy']));
$provider->propertyChanged($ace2, 'mask', 1, 3);
$provider->propertyChanged($ace, 'strategy', 'any', 'all');
$changes = $propertyChanges->offsetGet($acl);
$this->assertTrue(isset($changes['aces']));
$this->assertFalse($changes['aces']->contains($ace));
$this->assertTrue($changes['aces']->contains($ace2));
$provider->propertyChanged($ace2, 'mask', 3, 4);
$provider->propertyChanged($ace2, 'mask', 4, 1);
$changes = $propertyChanges->offsetGet($acl);
$this->assertFalse(isset($changes['aces']));
}
public function testUpdateAclDoesNotAcceptUntrackedAcls()
{
$this->expectException(\InvalidArgumentException::class);
$provider = $this->getProvider();
$acl = new Acl(1, new ObjectIdentity(1, 'Foo'), new PermissionGrantingStrategy(), [], true);
$provider->updateAcl($acl);
}
public function testUpdateDoesNothingWhenThereAreNoChanges()
{
$con = $this->createMock(Connection::class);
$con
->expects($this->never())
->method('beginTransaction')
;
$con
->expects($this->never())
->method('executeUpdate')
;
$provider = new MutableAclProvider($con, new PermissionGrantingStrategy(), []);
$acl = new Acl(1, new ObjectIdentity(1, 'Foo'), new PermissionGrantingStrategy(), [], true);
$propertyChanges = $this->getField($provider, 'propertyChanges');
$propertyChanges->offsetSet($acl, []);
$provider->updateAcl($acl);
}
public function testUpdateAclThrowsExceptionOnConcurrentModificationOfSharedProperties()
{
$provider = $this->getProvider();
$acl1 = $provider->createAcl(new ObjectIdentity(1, 'Foo'));
$acl2 = $provider->createAcl(new ObjectIdentity(2, 'Foo'));
$acl3 = $provider->createAcl(new ObjectIdentity(1, 'AnotherFoo'));
$sid = new RoleSecurityIdentity('ROLE_FOO');
$acl1->insertClassAce($sid, 1);
$acl3->insertClassAce($sid, 1);
$provider->updateAcl($acl1);
$provider->updateAcl($acl3);
$acl2->insertClassAce($sid, 16);
$provider->updateAcl($acl2);
$acl1->insertClassAce($sid, 3);
$acl2->insertClassAce($sid, 5);
$this->expectException(ConcurrentModificationException::class);
$this->expectExceptionMessage('The "classAces" property has been modified concurrently.');
$provider->updateAcl($acl1);
}
public function testUpdateAcl()
{
$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);
$acl->updateObjectAce(0, 3);
$acl->deleteObjectAce(1);
$acl->updateObjectAuditing(0, true, false);
$acl->updateClassFieldAce(0, 'field', 15);
$provider->updateAcl($acl);
$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 ($aces as $index => $ace) {
$this->assertAceEquals($ace, $reloadedAces[$index]);
}
}
public function testUpdateAclWorksForChangingTheParentAcl()
{
$provider = $this->getProvider();
$acl = $provider->createAcl(new ObjectIdentity(1, 'Foo'));
$parentAcl = $provider->createAcl(new ObjectIdentity(1, 'AnotherFoo'));
$acl->setParentAcl($parentAcl);
$provider->updateAcl($acl);
$reloadProvider = $this->getProvider();
$reloadedAcl = $reloadProvider->findAcl(new ObjectIdentity(1, 'Foo'));
$this->assertNotSame($acl, $reloadedAcl);
$this->assertSame($parentAcl->getId(), $reloadedAcl->getParentAcl()->getId());
}
public function testUpdateAclUpdatesChildAclsCorrectly()
{
$provider = $this->getProvider();
$acl = $provider->createAcl(new ObjectIdentity(1, 'Foo'));
$parentAcl = $provider->createAcl(new ObjectIdentity(1, 'Bar'));
$acl->setParentAcl($parentAcl);
$provider->updateAcl($acl);
$parentParentAcl = $provider->createAcl(new ObjectIdentity(1, 'Baz'));
$parentAcl->setParentAcl($parentParentAcl);
$provider->updateAcl($parentAcl);
$newParentParentAcl = $provider->createAcl(new ObjectIdentity(2, 'Baz'));
$parentAcl->setParentAcl($newParentParentAcl);
$provider->updateAcl($parentAcl);
$reloadProvider = $this->getProvider();
$reloadedAcl = $reloadProvider->findAcl(new ObjectIdentity(1, 'Foo'));
$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);
$acls = $provider->findAcl($oid);
$this->assertCount(3, $acls->getObjectFieldAces($fieldName));
}
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);
$acls = $provider->findAcl($oid);
$this->assertCount(2, $acls->getObjectFieldAces($fieldName));
}
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));
}
}
/**
* Imports acls.
*
* Data must have the following format:
* array(
* *name* => array(
* 'object_identifier' => *required*
* 'class_type' => *required*,
* 'parent_acl' => *name (optional)*
* ),
* )
*
* @throws \InvalidArgumentException
* @throws \Exception
*/
protected function importAcls(AclProvider $provider, array $data)
{
$aclIds = $parentAcls = [];
$con = $this->getField($provider, 'connection');
$con->beginTransaction();
try {
foreach ($data as $name => $aclData) {
if (!isset($aclData['object_identifier'], $aclData['class_type'])) {
throw new \InvalidArgumentException('"object_identifier", and "class_type" must be present.');
}
$this->callMethod($provider, 'createObjectIdentity', [new ObjectIdentity($aclData['object_identifier'], $aclData['class_type'])]);
$aclId = $con->lastInsertId();
$aclIds[$name] = $aclId;
$sql = $this->callMethod($provider, 'getInsertObjectIdentityRelationSql', [$aclId, $aclId]);
$con->executeStatement($sql);
if (isset($aclData['parent_acl'])) {
if (isset($aclIds[$aclData['parent_acl']])) {
$con->executeStatement('UPDATE acl_object_identities SET parent_object_identity_id = '.$aclIds[$aclData['parent_acl']].' WHERE id = '.$aclId);
$con->executeStatement($this->callMethod($provider, 'getInsertObjectIdentityRelationSql', [$aclId, $aclIds[$aclData['parent_acl']]]));
} else {
$parentAcls[$aclId] = $aclData['parent_acl'];
}
}
}
foreach ($parentAcls as $aclId => $name) {
if (!isset($aclIds[$name])) {
throw new \InvalidArgumentException(sprintf('"%s" does not exist.', $name));
}
$con->executeStatement(sprintf('UPDATE acl_object_identities SET parent_object_identity_id = %d WHERE id = %d', $aclIds[$name], $aclId));
$con->executeStatement($this->callMethod($provider, 'getInsertObjectIdentityRelationSql', [$aclId, $aclIds[$name]]));
}
$con->commit();
} catch (\Exception $e) {
$con->rollBack();
throw $e;
}
}
protected function callMethod($object, $method, array $args)
{
$method = new \ReflectionMethod($object, $method);
$method->setAccessible(true);
return $method->invokeArgs($object, $args);
}
protected function setUp(): void
{
$this->connection = DriverManager::getConnection([
'driver' => 'pdo_sqlite',
'memory' => true,
]);
// import the schema
$schema = new Schema($this->getOptions());
foreach ($schema->toSql($this->connection->getDatabasePlatform()) as $sql) {
$this->connection->executeStatement($sql);
}
}
protected function tearDown(): void
{
$this->connection = null;
}
protected function getField($object, $field)
{
$reflection = new \ReflectionProperty($object, $field);
$reflection->setAccessible(true);
return $reflection->getValue($object);
}
public function setField($object, $field, $value)
{
$reflection = new \ReflectionProperty($object, $field);
$reflection->setAccessible(true);
$reflection->setValue($object, $value);
$reflection->setAccessible(false);
}
protected function getOptions()
{
return [
'oid_table_name' => 'acl_object_identities',
'oid_ancestors_table_name' => 'acl_object_identity_ancestors',
'class_table_name' => 'acl_classes',
'sid_table_name' => 'acl_security_identities',
'entry_table_name' => 'acl_entries',
];
}
protected function getStrategy()
{
return new PermissionGrantingStrategy();
}
protected function getProvider($cache = null)
{
return new MutableAclProvider($this->connection, $this->getStrategy(), $this->getOptions(), $cache);
}
}
security-acl-3.3.3/Tests/Domain/ 0000775 0000000 0000000 00000000000 14433205003 0016427 5 ustar 00root root 0000000 0000000 security-acl-3.3.3/Tests/Domain/AclTest.php 0000664 0000000 0000000 00000040466 14433205003 0020511 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Tests\Domain;
use Doctrine\Persistence\PropertyChangedListener;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Security\Acl\Domain\Acl;
use Symfony\Component\Security\Acl\Domain\Entry;
use Symfony\Component\Security\Acl\Domain\ObjectIdentity;
use Symfony\Component\Security\Acl\Domain\PermissionGrantingStrategy;
use Symfony\Component\Security\Acl\Domain\RoleSecurityIdentity;
use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity;
use Symfony\Component\Security\Acl\Model\PermissionGrantingStrategyInterface;
class AclTest extends TestCase
{
public function testConstructor()
{
$acl = new Acl(1, $oid = new ObjectIdentity('foo', 'foo'), $permissionStrategy = new PermissionGrantingStrategy(), [], true);
$this->assertSame(1, $acl->getId());
$this->assertSame($oid, $acl->getObjectIdentity());
$this->assertNull($acl->getParentAcl());
$this->assertTrue($acl->isEntriesInheriting());
}
/**
* @dataProvider getDeleteAceTests
*/
public function testDeleteAceThrowsExceptionOnInvalidIndex($type)
{
$acl = $this->getAcl();
$this->expectException(\OutOfBoundsException::class);
$acl->{'delete'.$type.'Ace'}(0);
}
/**
* @dataProvider getDeleteAceTests
*/
public function testDeleteAce($type)
{
$acl = $this->getAcl();
$acl->{'insert'.$type.'Ace'}(new RoleSecurityIdentity('foo'), 1);
$acl->{'insert'.$type.'Ace'}(new RoleSecurityIdentity('foo'), 2, 1);
$acl->{'insert'.$type.'Ace'}(new RoleSecurityIdentity('foo'), 3, 2);
$listener = $this->getListener([
$type.'Aces', 'aceOrder', 'aceOrder', $type.'Aces',
]);
$acl->addPropertyChangedListener($listener);
$this->assertCount(3, $acl->{'get'.$type.'Aces'}());
$acl->{'delete'.$type.'Ace'}(0);
$this->assertCount(2, $aces = $acl->{'get'.$type.'Aces'}());
$this->assertEquals(2, $aces[0]->getMask());
$this->assertEquals(3, $aces[1]->getMask());
$acl->{'delete'.$type.'Ace'}(1);
$this->assertCount(1, $aces = $acl->{'get'.$type.'Aces'}());
$this->assertEquals(2, $aces[0]->getMask());
}
public function getDeleteAceTests()
{
return [
['class'],
['object'],
];
}
/**
* @dataProvider getDeleteFieldAceTests
*/
public function testDeleteFieldAceThrowsExceptionOnInvalidIndex($type)
{
$acl = $this->getAcl();
$this->expectException(\OutOfBoundsException::class);
$acl->{'delete'.$type.'Ace'}(0, 'foo');
}
/**
* @dataProvider getDeleteFieldAceTests
*/
public function testDeleteFieldAce($type)
{
$acl = $this->getAcl();
$acl->{'insert'.$type.'Ace'}('foo', new RoleSecurityIdentity('foo'), 1, 0);
$acl->{'insert'.$type.'Ace'}('foo', new RoleSecurityIdentity('foo'), 2, 1);
$acl->{'insert'.$type.'Ace'}('foo', new RoleSecurityIdentity('foo'), 3, 2);
$listener = $this->getListener([
$type.'Aces', 'aceOrder', 'aceOrder', $type.'Aces',
]);
$acl->addPropertyChangedListener($listener);
$this->assertCount(3, $acl->{'get'.$type.'Aces'}('foo'));
$acl->{'delete'.$type.'Ace'}(0, 'foo');
$this->assertCount(2, $aces = $acl->{'get'.$type.'Aces'}('foo'));
$this->assertEquals(2, $aces[0]->getMask());
$this->assertEquals(3, $aces[1]->getMask());
$acl->{'delete'.$type.'Ace'}(1, 'foo');
$this->assertCount(1, $aces = $acl->{'get'.$type.'Aces'}('foo'));
$this->assertEquals(2, $aces[0]->getMask());
}
public function getDeleteFieldAceTests()
{
return [
['classField'],
['objectField'],
];
}
/**
* @dataProvider getInsertAceTests
*/
public function testInsertAce($property, $method)
{
$acl = $this->getAcl();
$listener = $this->getListener([
$property, 'aceOrder', $property, 'aceOrder', $property,
]);
$acl->addPropertyChangedListener($listener);
$sid = new RoleSecurityIdentity('foo');
$acl->$method($sid, 1);
$acl->$method($sid, 2);
$acl->$method($sid, 3, 1, false);
$this->assertCount(3, $aces = $acl->{'get'.$property}());
$this->assertEquals(2, $aces[0]->getMask());
$this->assertEquals(3, $aces[1]->getMask());
$this->assertEquals(1, $aces[2]->getMask());
}
/**
* @dataProvider getInsertAceTests
*/
public function testInsertClassAceThrowsExceptionOnInvalidIndex($property, $method)
{
$acl = $this->getAcl();
$this->expectException(\OutOfBoundsException::class);
$acl->$method(new RoleSecurityIdentity('foo'), 1, 1);
}
public function getInsertAceTests()
{
return [
['classAces', 'insertClassAce'],
['objectAces', 'insertObjectAce'],
];
}
/**
* @dataProvider getInsertFieldAceTests
*/
public function testInsertClassFieldAce($property, $method)
{
$acl = $this->getAcl();
$listener = $this->getListener([
$property, $property, 'aceOrder', $property,
'aceOrder', 'aceOrder', $property,
]);
$acl->addPropertyChangedListener($listener);
$sid = new RoleSecurityIdentity('foo');
$acl->$method('foo', $sid, 1);
$acl->$method('foo2', $sid, 1);
$acl->$method('foo', $sid, 3);
$acl->$method('foo', $sid, 2);
$this->assertCount(3, $aces = $acl->{'get'.$property}('foo'));
$this->assertCount(1, $acl->{'get'.$property}('foo2'));
$this->assertEquals(2, $aces[0]->getMask());
$this->assertEquals(3, $aces[1]->getMask());
$this->assertEquals(1, $aces[2]->getMask());
}
/**
* @dataProvider getInsertFieldAceTests
*/
public function testInsertClassFieldAceThrowsExceptionOnInvalidIndex($property, $method)
{
$acl = $this->getAcl();
$this->expectException(\OutOfBoundsException::class);
$acl->$method('foo', new RoleSecurityIdentity('foo'), 1, 1);
}
public function getInsertFieldAceTests()
{
return [
['classFieldAces', 'insertClassFieldAce'],
['objectFieldAces', 'insertObjectFieldAce'],
];
}
public function testIsFieldGranted()
{
$sids = [new RoleSecurityIdentity('ROLE_FOO'), new RoleSecurityIdentity('ROLE_IDDQD')];
$masks = [1, 2, 4];
$strategy = $this->createMock(PermissionGrantingStrategyInterface::class);
$acl = new Acl(1, new ObjectIdentity(1, 'foo'), $strategy, [], true);
$strategy
->expects($this->once())
->method('isFieldGranted')
->with($this->equalTo($acl), $this->equalTo('foo'), $this->equalTo($masks), $this->equalTo($sids), $this->isTrue())
->willReturn(true)
;
$this->assertTrue($acl->isFieldGranted('foo', $masks, $sids, true));
}
public function testIsGranted()
{
$sids = [new RoleSecurityIdentity('ROLE_FOO'), new RoleSecurityIdentity('ROLE_IDDQD')];
$masks = [1, 2, 4];
$strategy = $this->createMock(PermissionGrantingStrategyInterface::class);
$acl = new Acl(1, new ObjectIdentity(1, 'foo'), $strategy, [], true);
$strategy
->expects($this->once())
->method('isGranted')
->with($this->equalTo($acl), $this->equalTo($masks), $this->equalTo($sids), $this->isTrue())
->willReturn(true)
;
$this->assertTrue($acl->isGranted($masks, $sids, true));
}
public function testSetGetParentAcl()
{
$acl = $this->getAcl();
$parentAcl = $this->getAcl();
$listener = $this->getListener(['parentAcl']);
$acl->addPropertyChangedListener($listener);
$this->assertNull($acl->getParentAcl());
$acl->setParentAcl($parentAcl);
$this->assertSame($parentAcl, $acl->getParentAcl());
$acl->setParentAcl(null);
$this->assertNull($acl->getParentAcl());
}
public function testSetIsEntriesInheriting()
{
$acl = $this->getAcl();
$listener = $this->getListener(['entriesInheriting']);
$acl->addPropertyChangedListener($listener);
$this->assertTrue($acl->isEntriesInheriting());
$acl->setEntriesInheriting(false);
$this->assertFalse($acl->isEntriesInheriting());
}
public function testIsSidLoadedWhenAllSidsAreLoaded()
{
$acl = $this->getAcl();
$this->assertTrue($acl->isSidLoaded(new UserSecurityIdentity('foo', 'Foo')));
$this->assertTrue($acl->isSidLoaded(new RoleSecurityIdentity('ROLE_FOO', 'Foo')));
}
public function testIsSidLoaded()
{
$acl = new Acl(1, new ObjectIdentity('1', 'foo'), new PermissionGrantingStrategy(), [new UserSecurityIdentity('foo', 'Foo'), new UserSecurityIdentity('johannes', 'Bar')], true);
$this->assertTrue($acl->isSidLoaded(new UserSecurityIdentity('foo', 'Foo')));
$this->assertTrue($acl->isSidLoaded(new UserSecurityIdentity('johannes', 'Bar')));
$this->assertTrue($acl->isSidLoaded([
new UserSecurityIdentity('foo', 'Foo'),
new UserSecurityIdentity('johannes', 'Bar'),
]));
$this->assertFalse($acl->isSidLoaded(new RoleSecurityIdentity('ROLE_FOO')));
$this->assertFalse($acl->isSidLoaded(new UserSecurityIdentity('schmittjoh@gmail.com', 'Moo')));
$this->assertFalse($acl->isSidLoaded([
new UserSecurityIdentity('foo', 'Foo'),
new UserSecurityIdentity('johannes', 'Bar'),
new RoleSecurityIdentity('ROLE_FOO'),
]));
}
/**
* @dataProvider getUpdateAceTests
*/
public function testUpdateAceThrowsOutOfBoundsExceptionOnInvalidIndex($type)
{
$acl = $this->getAcl();
$this->expectException(\OutOfBoundsException::class);
$acl->{'update'.$type}(0, 1);
}
/**
* @dataProvider getUpdateAceTests
*/
public function testUpdateAce($type)
{
$acl = $this->getAcl();
$acl->{'insert'.$type}(new RoleSecurityIdentity('foo'), 1);
$listener = $this->getListener([
'mask', 'mask', 'strategy',
]);
$acl->addPropertyChangedListener($listener);
$aces = $acl->{'get'.$type.'s'}();
$ace = reset($aces);
$this->assertEquals(1, $ace->getMask());
$this->assertEquals('all', $ace->getStrategy());
$acl->{'update'.$type}(0, 3);
$this->assertEquals(3, $ace->getMask());
$this->assertEquals('all', $ace->getStrategy());
$acl->{'update'.$type}(0, 1, 'foo');
$this->assertEquals(1, $ace->getMask());
$this->assertEquals('foo', $ace->getStrategy());
}
public function getUpdateAceTests()
{
return [
['classAce'],
['objectAce'],
];
}
/**
* @dataProvider getUpdateFieldAceTests
*/
public function testUpdateFieldAceThrowsExceptionOnInvalidIndex($type)
{
$acl = $this->getAcl();
$this->expectException(\OutOfBoundsException::class);
$acl->{'update'.$type}(0, 'foo', 1);
}
/**
* @dataProvider getUpdateFieldAceTests
*/
public function testUpdateFieldAce($type)
{
$acl = $this->getAcl();
$acl->{'insert'.$type}('foo', new UserSecurityIdentity('foo', 'Foo'), 1);
$listener = $this->getListener([
'mask', 'mask', 'strategy',
]);
$acl->addPropertyChangedListener($listener);
$aces = $acl->{'get'.$type.'s'}('foo');
$ace = reset($aces);
$this->assertEquals(1, $ace->getMask());
$this->assertEquals('all', $ace->getStrategy());
$acl->{'update'.$type}(0, 'foo', 3);
$this->assertEquals(3, $ace->getMask());
$this->assertEquals('all', $ace->getStrategy());
$acl->{'update'.$type}(0, 'foo', 1, 'foo');
$this->assertEquals(1, $ace->getMask());
$this->assertEquals('foo', $ace->getStrategy());
}
public function getUpdateFieldAceTests()
{
return [
['classFieldAce'],
['objectFieldAce'],
];
}
/**
* @dataProvider getUpdateAuditingTests
*/
public function testUpdateAuditingThrowsExceptionOnInvalidIndex($type)
{
$acl = $this->getAcl();
$this->expectException(\OutOfBoundsException::class);
$acl->{'update'.$type.'Auditing'}(0, true, false);
}
/**
* @dataProvider getUpdateAuditingTests
*/
public function testUpdateAuditing($type)
{
$acl = $this->getAcl();
$acl->{'insert'.$type.'Ace'}(new RoleSecurityIdentity('foo'), 1);
$listener = $this->getListener([
'auditFailure', 'auditSuccess', 'auditFailure',
]);
$acl->addPropertyChangedListener($listener);
$aces = $acl->{'get'.$type.'Aces'}();
$ace = reset($aces);
$this->assertFalse($ace->isAuditSuccess());
$this->assertFalse($ace->isAuditFailure());
$acl->{'update'.$type.'Auditing'}(0, false, true);
$this->assertFalse($ace->isAuditSuccess());
$this->assertTrue($ace->isAuditFailure());
$acl->{'update'.$type.'Auditing'}(0, true, false);
$this->assertTrue($ace->isAuditSuccess());
$this->assertFalse($ace->isAuditFailure());
}
public function getUpdateAuditingTests()
{
return [
['class'],
['object'],
];
}
/**
* @dataProvider getUpdateFieldAuditingTests
*/
public function testUpdateFieldAuditingThrowsExceptionOnInvalidField($type)
{
$acl = $this->getAcl();
$this->expectException(\InvalidArgumentException::class);
$acl->{'update'.$type.'Auditing'}(0, 'foo', true, true);
}
/**
* @dataProvider getUpdateFieldAuditingTests
*/
public function testUpdateFieldAuditingThrowsExceptionOnInvalidIndex($type)
{
$acl = $this->getAcl();
$acl->{'insert'.$type.'Ace'}('foo', new RoleSecurityIdentity('foo'), 1);
$this->expectException(\OutOfBoundsException::class);
$acl->{'update'.$type.'Auditing'}(1, 'foo', true, false);
}
/**
* @dataProvider getUpdateFieldAuditingTests
*/
public function testUpdateFieldAuditing($type)
{
$acl = $this->getAcl();
$acl->{'insert'.$type.'Ace'}('foo', new RoleSecurityIdentity('foo'), 1);
$listener = $this->getListener([
'auditSuccess', 'auditSuccess', 'auditFailure',
]);
$acl->addPropertyChangedListener($listener);
$aces = $acl->{'get'.$type.'Aces'}('foo');
$ace = reset($aces);
$this->assertFalse($ace->isAuditSuccess());
$this->assertFalse($ace->isAuditFailure());
$acl->{'update'.$type.'Auditing'}(0, 'foo', true, false);
$this->assertTrue($ace->isAuditSuccess());
$this->assertFalse($ace->isAuditFailure());
$acl->{'update'.$type.'Auditing'}(0, 'foo', false, true);
$this->assertFalse($ace->isAuditSuccess());
$this->assertTrue($ace->isAuditFailure());
}
public function getUpdateFieldAuditingTests()
{
return [
['classField'],
['objectField'],
];
}
protected function getListener($expectedChanges)
{
$aceProperties = ['aceOrder', 'mask', 'strategy', 'auditSuccess', 'auditFailure'];
$arguments = [];
$listener = $this->createMock(PropertyChangedListener::class);
foreach ($expectedChanges as $index => $property) {
if (\in_array($property, $aceProperties)) {
$class = Entry::class;
} else {
$class = Acl::class;
}
$arguments[] = [$this->isInstanceOf($class), $this->equalTo($property)];
}
$listener
->method('propertyChanged')
->withConsecutive(...$arguments)
;
return $listener;
}
protected function getAcl()
{
return new Acl(1, new ObjectIdentity(1, 'foo'), new PermissionGrantingStrategy(), [], true);
}
}
security-acl-3.3.3/Tests/Domain/AuditLoggerTest.php 0000664 0000000 0000000 00000004112 14433205003 0022204 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Tests\Domain;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Security\Acl\Domain\AuditLogger;
use Symfony\Component\Security\Acl\Tests\Fixtures\SerializableAuditableEntryInterface;
class AuditLoggerTest extends TestCase
{
/**
* @dataProvider getTestLogData
*/
public function testLogIfNeeded($granting, $audit)
{
$logger = $this->getLogger();
$ace = $this->getEntry();
if (true === $granting) {
$ace
->expects($this->once())
->method('isAuditSuccess')
->willReturn($audit)
;
$ace
->expects($this->never())
->method('isAuditFailure')
;
} else {
$ace
->expects($this->never())
->method('isAuditSuccess')
;
$ace
->expects($this->once())
->method('isAuditFailure')
->willReturn($audit)
;
}
if (true === $audit) {
$logger
->expects($this->once())
->method('doLog')
->with($this->equalTo($granting), $this->equalTo($ace))
;
} else {
$logger
->expects($this->never())
->method('doLog')
;
}
$logger->logIfNeeded($granting, $ace);
}
public function getTestLogData()
{
return [
[true, false],
[true, true],
[false, false],
[false, true],
];
}
protected function getEntry()
{
return $this->createMock(SerializableAuditableEntryInterface::class);
}
protected function getLogger()
{
return $this->getMockForAbstractClass(AuditLogger::class);
}
}
security-acl-3.3.3/Tests/Domain/DoctrineAclCacheTest.php 0000664 0000000 0000000 00000006274 14433205003 0023124 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Tests\Domain;
use Doctrine\Common\Cache\Psr6\DoctrineProvider;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Security\Acl\Domain\Acl;
use Symfony\Component\Security\Acl\Domain\DoctrineAclCache;
use Symfony\Component\Security\Acl\Domain\ObjectIdentity;
use Symfony\Component\Security\Acl\Domain\PermissionGrantingStrategy;
use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity;
class DoctrineAclCacheTest extends TestCase
{
protected $permissionGrantingStrategy;
/**
* @dataProvider getEmptyValue
*/
public function testConstructorDoesNotAcceptEmptyPrefix($empty)
{
$this->expectException(\InvalidArgumentException::class);
new DoctrineAclCache(DoctrineProvider::wrap(new ArrayAdapter()), $this->getPermissionGrantingStrategy(), $empty);
}
public function getEmptyValue()
{
return [
[null],
[false],
[''],
];
}
public function test()
{
$cache = $this->getCache();
$aclWithParent = $this->getAcl(1);
$acl = $this->getAcl();
$cache->putInCache($aclWithParent);
$cache->putInCache($acl);
$cachedAcl = $cache->getFromCacheByIdentity($acl->getObjectIdentity());
$this->assertEquals($acl->getId(), $cachedAcl->getId());
$this->assertNull($acl->getParentAcl());
$cachedAclWithParent = $cache->getFromCacheByIdentity($aclWithParent->getObjectIdentity());
$this->assertEquals($aclWithParent->getId(), $cachedAclWithParent->getId());
$this->assertNotNull($cachedParentAcl = $cachedAclWithParent->getParentAcl());
$this->assertEquals($aclWithParent->getParentAcl()->getId(), $cachedParentAcl->getId());
}
protected function getAcl($depth = 0)
{
static $id = 1;
$acl = new Acl($id, new ObjectIdentity($id, 'foo'), $this->getPermissionGrantingStrategy(), [], $depth > 0);
// insert some ACEs
$sid = new UserSecurityIdentity('johannes', 'Foo');
$acl->insertClassAce($sid, 1);
$acl->insertClassFieldAce('foo', $sid, 1);
$acl->insertObjectAce($sid, 1);
$acl->insertObjectFieldAce('foo', $sid, 1);
++$id;
if ($depth > 0) {
$acl->setParentAcl($this->getAcl($depth - 1));
}
return $acl;
}
protected function getPermissionGrantingStrategy()
{
if (null === $this->permissionGrantingStrategy) {
$this->permissionGrantingStrategy = new PermissionGrantingStrategy();
}
return $this->permissionGrantingStrategy;
}
protected function getCache($cacheDriver = null, $prefix = DoctrineAclCache::PREFIX)
{
if (null === $cacheDriver) {
$cacheDriver = DoctrineProvider::wrap(new ArrayAdapter());
}
return new DoctrineAclCache($cacheDriver, $this->getPermissionGrantingStrategy(), $prefix);
}
}
security-acl-3.3.3/Tests/Domain/EntryTest.php 0000664 0000000 0000000 00000006762 14433205003 0021114 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Tests\Domain;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Security\Acl\Domain\Entry;
use Symfony\Component\Security\Acl\Model\SecurityIdentityInterface;
use Symfony\Component\Security\Acl\Tests\Fixtures\SerializableAclInterface;
class EntryTest extends TestCase
{
public function testConstructor()
{
$ace = $this->getAce($acl = $this->getAcl(), $sid = $this->getSid());
$this->assertEquals(123, $ace->getId());
$this->assertSame($acl, $ace->getAcl());
$this->assertSame($sid, $ace->getSecurityIdentity());
$this->assertEquals('foostrat', $ace->getStrategy());
$this->assertEquals(123456, $ace->getMask());
$this->assertTrue($ace->isGranting());
$this->assertTrue($ace->isAuditSuccess());
$this->assertFalse($ace->isAuditFailure());
}
public function testSetAuditSuccess()
{
$ace = $this->getAce();
$this->assertTrue($ace->isAuditSuccess());
$ace->setAuditSuccess(false);
$this->assertFalse($ace->isAuditSuccess());
$ace->setAuditSuccess(true);
$this->assertTrue($ace->isAuditSuccess());
}
public function testSetAuditFailure()
{
$ace = $this->getAce();
$this->assertFalse($ace->isAuditFailure());
$ace->setAuditFailure(true);
$this->assertTrue($ace->isAuditFailure());
$ace->setAuditFailure(false);
$this->assertFalse($ace->isAuditFailure());
}
public function testSetMask()
{
$ace = $this->getAce();
$this->assertEquals(123456, $ace->getMask());
$ace->setMask(4321);
$this->assertEquals(4321, $ace->getMask());
}
public function testSetStrategy()
{
$ace = $this->getAce();
$this->assertEquals('foostrat', $ace->getStrategy());
$ace->setStrategy('foo');
$this->assertEquals('foo', $ace->getStrategy());
}
public function testSerializeUnserialize()
{
$ace = $this->getAce();
$serialized = serialize($ace);
$uAce = unserialize($serialized);
$this->assertNull($uAce->getAcl());
$this->assertInstanceOf(SecurityIdentityInterface::class, $uAce->getSecurityIdentity());
$this->assertEquals($ace->getId(), $uAce->getId());
$this->assertEquals($ace->getMask(), $uAce->getMask());
$this->assertEquals($ace->getStrategy(), $uAce->getStrategy());
$this->assertEquals($ace->isGranting(), $uAce->isGranting());
$this->assertEquals($ace->isAuditSuccess(), $uAce->isAuditSuccess());
$this->assertEquals($ace->isAuditFailure(), $uAce->isAuditFailure());
}
protected function getAce($acl = null, $sid = null)
{
if (null === $acl) {
$acl = $this->getAcl();
}
if (null === $sid) {
$sid = $this->getSid();
}
return new Entry(
123,
$acl,
$sid,
'foostrat',
123456,
true,
false,
true
);
}
protected function getAcl()
{
return $this->createMock(SerializableAclInterface::class);
}
protected function getSid()
{
return $this->createMock(SecurityIdentityInterface::class);
}
}
security-acl-3.3.3/Tests/Domain/FieldEntryTest.php 0000664 0000000 0000000 00000005574 14433205003 0022060 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Tests\Domain;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Security\Acl\Domain\FieldEntry;
use Symfony\Component\Security\Acl\Model\SecurityIdentityInterface;
use Symfony\Component\Security\Acl\Tests\Fixtures\SerializableAclInterface;
class FieldEntryTest extends TestCase
{
public function testConstructor()
{
$ace = $this->getAce();
$this->assertEquals('foo', $ace->getField());
}
public function testSerializeUnserialize()
{
$ace = $this->getAce();
$serialized = serialize($ace);
$uAce = unserialize($serialized);
$this->assertNull($uAce->getAcl());
$this->assertInstanceOf(SecurityIdentityInterface::class, $uAce->getSecurityIdentity());
$this->assertEquals($ace->getId(), $uAce->getId());
$this->assertEquals($ace->getField(), $uAce->getField());
$this->assertEquals($ace->getMask(), $uAce->getMask());
$this->assertEquals($ace->getStrategy(), $uAce->getStrategy());
$this->assertEquals($ace->isGranting(), $uAce->isGranting());
$this->assertEquals($ace->isAuditSuccess(), $uAce->isAuditSuccess());
$this->assertEquals($ace->isAuditFailure(), $uAce->isAuditFailure());
}
public function testSerializeUnserializeMoreAceWithSameSecurityIdentity()
{
$sid = $this->getSid();
$aceFirst = $this->getAce(null, $sid);
$aceSecond = $this->getAce(null, $sid);
// as used in DoctrineAclCache::putInCache (line 142)
$serialized = serialize([[
'fieldOne' => [$aceFirst],
'fieldTwo' => [$aceSecond],
]]);
$unserialized = unserialize($serialized);
$uAceFirst = $unserialized[0]['fieldOne'][0];
$uAceSecond = $unserialized[0]['fieldTwo'][0];
$this->assertInstanceOf(SecurityIdentityInterface::class, $uAceFirst->getSecurityIdentity());
$this->assertInstanceOf(SecurityIdentityInterface::class, $uAceSecond->getSecurityIdentity());
}
protected function getAce($acl = null, $sid = null)
{
if (null === $acl) {
$acl = $this->getAcl();
}
if (null === $sid) {
$sid = $this->getSid();
}
return new FieldEntry(
123,
$acl,
'foo',
$sid,
'foostrat',
123456,
true,
false,
true
);
}
protected function getAcl()
{
return $this->createMock(SerializableAclInterface::class);
}
protected function getSid()
{
return $this->createMock(SecurityIdentityInterface::class);
}
}
security-acl-3.3.3/Tests/Domain/ObjectIdentityRetrievalStrategyTest.php 0000664 0000000 0000000 00000002201 14433205003 0026314 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Tests\Domain;
use Symfony\Component\Security\Acl\Domain\ObjectIdentityRetrievalStrategy;
class ObjectIdentityRetrievalStrategyTest extends \PHPUnit\Framework\TestCase
{
public function testGetObjectIdentityReturnsNullForInvalidDomainObject()
{
$strategy = new ObjectIdentityRetrievalStrategy();
$this->assertNull($strategy->getObjectIdentity('foo'));
}
public function testGetObjectIdentity()
{
$strategy = new ObjectIdentityRetrievalStrategy();
$domainObject = new DomainObject();
$objectIdentity = $strategy->getObjectIdentity($domainObject);
$this->assertEquals($domainObject->getId(), $objectIdentity->getIdentifier());
$this->assertEquals(\get_class($domainObject), $objectIdentity->getType());
}
}
class DomainObject
{
public function getId()
{
return 'foo';
}
}
security-acl-3.3.3/Tests/Domain/ObjectIdentityTest.php 0000664 0000000 0000000 00000010663 14433205003 0022726 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Tests\Domain
{
use Symfony\Component\Security\Acl\Domain\ObjectIdentity;
use Symfony\Component\Security\Acl\Model\DomainObjectInterface;
class ObjectIdentityTest extends \PHPUnit\Framework\TestCase
{
public function testConstructor()
{
$id = new ObjectIdentity('fooid', 'footype');
$this->assertEquals('fooid', $id->getIdentifier());
$this->assertEquals('footype', $id->getType());
}
// Test that constructor never changes passed type, even with proxies
public function testConstructorWithProxy()
{
$id = new ObjectIdentity('fooid', 'Acme\DemoBundle\Proxy\__CG__\Symfony\Component\Security\Acl\Tests\Domain\TestDomainObject');
$this->assertEquals('fooid', $id->getIdentifier());
$this->assertEquals('Acme\DemoBundle\Proxy\__CG__\Symfony\Component\Security\Acl\Tests\Domain\TestDomainObject', $id->getType());
}
public function testFromDomainObjectPrefersInterfaceOverGetId()
{
$domainObject = new class() implements DomainObjectInterface {
public function getObjectIdentifier()
{
return 'getObjectIdentifier()';
}
public function getId()
{
return 'getId()';
}
};
$id = ObjectIdentity::fromDomainObject($domainObject);
$this->assertEquals('getObjectIdentifier()', $id->getIdentifier());
}
public function testFromDomainObjectWithoutInterface()
{
$id = ObjectIdentity::fromDomainObject(new TestDomainObject());
$this->assertEquals('getId()', $id->getIdentifier());
$this->assertEquals(TestDomainObject::class, $id->getType());
}
public function testFromDomainObjectWithProxy()
{
$id = ObjectIdentity::fromDomainObject(new \Acme\DemoBundle\Proxy\__CG__\Symfony\Component\Security\Acl\Tests\Domain\TestDomainObject());
$this->assertEquals('getId()', $id->getIdentifier());
$this->assertEquals(TestDomainObject::class, $id->getType());
}
public function testFromDomainObjectWithoutInterfaceEnforcesStringIdentifier()
{
$domainObject = new TestDomainObject();
$domainObject->id = 1;
$id = ObjectIdentity::fromDomainObject($domainObject);
$this->assertSame('1', $id->getIdentifier());
$this->assertEquals(TestDomainObject::class, $id->getType());
}
public function testFromDomainObjectWithoutInterfaceAllowsZeroAsIdentifier()
{
$domainObject = new TestDomainObject();
$domainObject->id = '0';
$id = ObjectIdentity::fromDomainObject($domainObject);
$this->assertSame('0', $id->getIdentifier());
$this->assertEquals(TestDomainObject::class, $id->getType());
}
/**
* @dataProvider getCompareData
*/
public function testEquals($oid1, $oid2, $equal)
{
if ($equal) {
$this->assertTrue($oid1->equals($oid2));
} else {
$this->assertFalse($oid1->equals($oid2));
}
}
public function getCompareData()
{
return [
[new ObjectIdentity('123', 'foo'), new ObjectIdentity('123', 'foo'), true],
[new ObjectIdentity('123', 'foo'), new ObjectIdentity(123, 'foo'), true],
[new ObjectIdentity('1', 'foo'), new ObjectIdentity('2', 'foo'), false],
[new ObjectIdentity('1', 'bla'), new ObjectIdentity('1', 'blub'), false],
];
}
}
class TestDomainObject
{
public $id = 'getId()';
public function getObjectIdentifier()
{
return 'getObjectIdentifier()';
}
public function getId()
{
return $this->id;
}
}
}
namespace Acme\DemoBundle\Proxy\__CG__\Symfony\Component\Security\Acl\Tests\Domain
{
class TestDomainObject extends \Symfony\Component\Security\Acl\Tests\Domain\TestDomainObject
{
}
}
security-acl-3.3.3/Tests/Domain/PermissionGrantingStrategyTest.php 0000664 0000000 0000000 00000014470 14433205003 0025353 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Tests\Domain;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Security\Acl\Domain\Acl;
use Symfony\Component\Security\Acl\Domain\ObjectIdentity;
use Symfony\Component\Security\Acl\Domain\PermissionGrantingStrategy;
use Symfony\Component\Security\Acl\Domain\RoleSecurityIdentity;
use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity;
use Symfony\Component\Security\Acl\Exception\NoAceFoundException;
use Symfony\Component\Security\Acl\Model\AuditLoggerInterface;
class PermissionGrantingStrategyTest extends TestCase
{
public function testIsGrantedObjectAcesHavePriority()
{
$strategy = new PermissionGrantingStrategy();
$acl = $this->getAcl($strategy);
$sid = new UserSecurityIdentity('johannes', 'Foo');
$acl->insertClassAce($sid, 1);
$acl->insertObjectAce($sid, 1, 0, false);
$this->assertFalse($strategy->isGranted($acl, [1], [$sid]));
}
public function testIsGrantedFallsBackToClassAcesIfNoApplicableObjectAceWasFound()
{
$strategy = new PermissionGrantingStrategy();
$acl = $this->getAcl($strategy);
$sid = new UserSecurityIdentity('johannes', 'Foo');
$acl->insertClassAce($sid, 1);
$this->assertTrue($strategy->isGranted($acl, [1], [$sid]));
}
public function testIsGrantedFavorsLocalAcesOverParentAclAces()
{
$strategy = new PermissionGrantingStrategy();
$sid = new UserSecurityIdentity('johannes', 'Foo');
$acl = $this->getAcl($strategy);
$acl->insertClassAce($sid, 1);
$parentAcl = $this->getAcl($strategy);
$acl->setParentAcl($parentAcl);
$parentAcl->insertClassAce($sid, 1, 0, false);
$this->assertTrue($strategy->isGranted($acl, [1], [$sid]));
}
public function testIsGrantedFallsBackToParentAcesIfNoLocalAcesAreApplicable()
{
$strategy = new PermissionGrantingStrategy();
$sid = new UserSecurityIdentity('johannes', 'Foo');
$anotherSid = new UserSecurityIdentity('ROLE_USER', 'Foo');
$acl = $this->getAcl($strategy);
$acl->insertClassAce($anotherSid, 1, 0, false);
$parentAcl = $this->getAcl($strategy);
$acl->setParentAcl($parentAcl);
$parentAcl->insertClassAce($sid, 1);
$this->assertTrue($strategy->isGranted($acl, [1], [$sid]));
}
public function testIsGrantedReturnsExceptionIfNoAceIsFound()
{
$strategy = new PermissionGrantingStrategy();
$acl = $this->getAcl($strategy);
$sid = new UserSecurityIdentity('johannes', 'Foo');
$this->expectException(NoAceFoundException::class);
$strategy->isGranted($acl, [1], [$sid]);
}
public function testIsGrantedFirstApplicableEntryMakesUltimateDecisionForPermissionIdentityCombination()
{
$strategy = new PermissionGrantingStrategy();
$acl = $this->getAcl($strategy);
$sid = new UserSecurityIdentity('johannes', 'Foo');
$aSid = new RoleSecurityIdentity('ROLE_USER');
$acl->insertClassAce($aSid, 1);
$acl->insertClassAce($sid, 1, 1, false);
$acl->insertClassAce($sid, 1, 2);
$this->assertFalse($strategy->isGranted($acl, [1], [$sid, $aSid]));
$acl->insertObjectAce($sid, 1, 0, false);
$acl->insertObjectAce($aSid, 1, 1);
$this->assertFalse($strategy->isGranted($acl, [1], [$sid, $aSid]));
}
public function testIsGrantedCallsAuditLoggerOnGrant()
{
$strategy = new PermissionGrantingStrategy();
$acl = $this->getAcl($strategy);
$sid = new UserSecurityIdentity('johannes', 'Foo');
$logger = $this->createMock(AuditLoggerInterface::class);
$logger
->expects($this->once())
->method('logIfNeeded')
;
$strategy->setAuditLogger($logger);
$acl->insertObjectAce($sid, 1);
$acl->updateObjectAuditing(0, true, false);
$this->assertTrue($strategy->isGranted($acl, [1], [$sid]));
}
public function testIsGrantedCallsAuditLoggerOnDeny()
{
$strategy = new PermissionGrantingStrategy();
$acl = $this->getAcl($strategy);
$sid = new UserSecurityIdentity('johannes', 'Foo');
$logger = $this->createMock(AuditLoggerInterface::class);
$logger
->expects($this->once())
->method('logIfNeeded')
;
$strategy->setAuditLogger($logger);
$acl->insertObjectAce($sid, 1, 0, false);
$acl->updateObjectAuditing(0, false, true);
$this->assertFalse($strategy->isGranted($acl, [1], [$sid]));
}
/**
* @dataProvider getAllStrategyTests
*/
public function testIsGrantedStrategies($maskStrategy, $aceMask, $requiredMask, $result)
{
$strategy = new PermissionGrantingStrategy();
$acl = $this->getAcl($strategy);
$sid = new UserSecurityIdentity('johannes', 'Foo');
$acl->insertObjectAce($sid, $aceMask, 0, true, $maskStrategy);
if (false === $result) {
$this->expectException(NoAceFoundException::class);
$this->expectExceptionMessage('No applicable ACE was found.');
$strategy->isGranted($acl, [$requiredMask], [$sid]);
} else {
$this->assertTrue($strategy->isGranted($acl, [$requiredMask], [$sid]));
}
}
public function getAllStrategyTests()
{
return [
['all', 1 << 0 | 1 << 1, 1 << 0, true],
['all', 1 << 0 | 1 << 1, 1 << 2, false],
['all', 1 << 0 | 1 << 10, 1 << 0 | 1 << 10, true],
['all', 1 << 0 | 1 << 1, 1 << 0 | 1 << 1 || 1 << 2, false],
['any', 1 << 0 | 1 << 1, 1 << 0, true],
['any', 1 << 0 | 1 << 1, 1 << 0 | 1 << 2, true],
['any', 1 << 0 | 1 << 1, 1 << 2, false],
['equal', 1 << 0 | 1 << 1, 1 << 0, false],
['equal', 1 << 0 | 1 << 1, 1 << 1, false],
['equal', 1 << 0 | 1 << 1, 1 << 0 | 1 << 1, true],
];
}
protected function getAcl($strategy)
{
static $id = 1;
return new Acl($id++, new ObjectIdentity(1, 'Foo'), $strategy, [], true);
}
}
security-acl-3.3.3/Tests/Domain/PsrAclCacheTest.php 0000664 0000000 0000000 00000005575 14433205003 0022124 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Tests\Domain;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Security\Acl\Domain\Acl;
use Symfony\Component\Security\Acl\Domain\ObjectIdentity;
use Symfony\Component\Security\Acl\Domain\PermissionGrantingStrategy;
use Symfony\Component\Security\Acl\Domain\PsrAclCache;
use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity;
class PsrAclCacheTest extends TestCase
{
protected $permissionGrantingStrategy;
public function testConstructorDoesNotAcceptEmptyPrefix()
{
$this->expectException(\InvalidArgumentException::class);
new PsrAclCache(new ArrayAdapter(), $this->getPermissionGrantingStrategy(), '');
}
public function test()
{
$cache = $this->getCache();
$aclWithParent = $this->getAcl(1);
$acl = $this->getAcl();
$cache->putInCache($aclWithParent);
$cache->putInCache($acl);
$cachedAcl = $cache->getFromCacheByIdentity($acl->getObjectIdentity());
$this->assertEquals($acl->getId(), $cachedAcl->getId());
$this->assertNull($acl->getParentAcl());
$cachedAclWithParent = $cache->getFromCacheByIdentity($aclWithParent->getObjectIdentity());
$this->assertEquals($aclWithParent->getId(), $cachedAclWithParent->getId());
$this->assertNotNull($cachedParentAcl = $cachedAclWithParent->getParentAcl());
$this->assertEquals($aclWithParent->getParentAcl()->getId(), $cachedParentAcl->getId());
}
protected function getAcl($depth = 0)
{
static $id = 1;
$acl = new Acl($id, new ObjectIdentity($id, 'foo'), $this->getPermissionGrantingStrategy(), [], $depth > 0);
// insert some ACEs
$sid = new UserSecurityIdentity('johannes', 'Foo');
$acl->insertClassAce($sid, 1);
$acl->insertClassFieldAce('foo', $sid, 1);
$acl->insertObjectAce($sid, 1);
$acl->insertObjectFieldAce('foo', $sid, 1);
++$id;
if ($depth > 0) {
$acl->setParentAcl($this->getAcl($depth - 1));
}
return $acl;
}
protected function getPermissionGrantingStrategy()
{
if (null === $this->permissionGrantingStrategy) {
$this->permissionGrantingStrategy = new PermissionGrantingStrategy();
}
return $this->permissionGrantingStrategy;
}
protected function getCache($cacheDriver = null, $prefix = PsrAclCache::PREFIX)
{
if (null === $cacheDriver) {
$cacheDriver = new ArrayAdapter();
}
return new PsrAclCache($cacheDriver, $this->getPermissionGrantingStrategy(), $prefix);
}
}
security-acl-3.3.3/Tests/Domain/RoleSecurityIdentityTest.php 0000664 0000000 0000000 00000002636 14433205003 0024152 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Tests\Domain;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Security\Acl\Domain\RoleSecurityIdentity;
use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity;
use Symfony\Component\Security\Acl\Model\SecurityIdentityInterface;
class RoleSecurityIdentityTest extends TestCase
{
public function testConstructor()
{
$id = new RoleSecurityIdentity('ROLE_FOO');
$this->assertEquals('ROLE_FOO', $id->getRole());
}
/**
* @dataProvider getCompareData
*/
public function testEquals(RoleSecurityIdentity $id1, SecurityIdentityInterface $id2, bool $equal)
{
if ($equal) {
$this->assertTrue($id1->equals($id2));
} else {
$this->assertFalse($id1->equals($id2));
}
}
public function getCompareData(): array
{
return [
[new RoleSecurityIdentity('ROLE_FOO'), new RoleSecurityIdentity('ROLE_FOO'), true],
[new RoleSecurityIdentity('ROLE_USER'), new RoleSecurityIdentity('ROLE_FOO'), false],
[new RoleSecurityIdentity('ROLE_FOO'), new UserSecurityIdentity('ROLE_FOO', 'Foo'), false],
];
}
}
security-acl-3.3.3/Tests/Domain/SecurityIdentityRetrievalStrategyTest.php 0000664 0000000 0000000 00000025141 14433205003 0026725 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Tests\Domain;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Security\Acl\Domain\RoleSecurityIdentity;
use Symfony\Component\Security\Acl\Domain\SecurityIdentityRetrievalStrategy;
use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity;
use Symfony\Component\Security\Acl\Tests\Fixtures\Account;
use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
use Symfony\Component\Security\Core\Authentication\Token\AbstractToken;
use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
use Symfony\Component\Security\Core\Authentication\Token\NullToken;
use Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter;
use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
use Symfony\Component\Security\Core\User\UserInterface;
class SecurityIdentityRetrievalStrategyTest extends TestCase
{
/**
* @dataProvider getSecurityIdentityRetrievalTests
*/
public function testGetSecurityIdentities($user, array $roles, string $authenticationStatus, array $sids)
{
$token = class_exists(NullToken::class) ? new NullToken() : new AnonymousToken('', '');
if ('anonymous' !== $authenticationStatus) {
$class = '';
if (\is_string($user)) {
$class = 'MyCustomTokenImpl';
}
$token = $this->getMockBuilder(AbstractToken::class)
->setMockClassName($class)
->getMock();
$token
->expects($this->once())
->method('getRoleNames')
->willReturn(['foo'])
;
$token
->expects($this->once())
->method('getUser')
->willReturn($user)
;
}
$strategy = $this->getStrategy($roles, $authenticationStatus);
$extractedSids = $strategy->getSecurityIdentities($token);
foreach ($extractedSids as $index => $extractedSid) {
if (!isset($sids[$index])) {
$this->fail(sprintf('Expected SID at index %d, but there was none.', $index));
}
if (false === $sids[$index]->equals($extractedSid)) {
$this->fail(sprintf('Index: %d, expected SID "%s", but got "%s".', $index, $sids[$index], (string) $extractedSid));
}
}
}
/**
* @group legacy
*
* @dataProvider getDeprecatedSecurityIdentityRetrievalTests
*/
public function testDeprecatedGetSecurityIdentities($user, array $roles, string $authenticationStatus, array $sids)
{
if (method_exists(AuthenticationTrustResolverInterface::class, 'isAuthenticated')) {
$this->markTestSkipped();
}
if ('anonymous' === $authenticationStatus) {
$token = $this->getMockBuilder(AnonymousToken::class)
->disableOriginalConstructor()
->getMock();
} else {
$class = '';
if (\is_string($user)) {
$class = 'MyCustomTokenImpl';
}
$token = $this->getMockBuilder(AbstractToken::class)
->setMockClassName($class)
->getMock();
}
$strategy = $this->getStrategy($roles, $authenticationStatus);
$token
->expects($this->once())
->method('getRoleNames')
->willReturn(['foo'])
;
if ('anonymous' === $authenticationStatus) {
$token
->expects($this->never())
->method('getUser')
;
} else {
$token
->expects($this->once())
->method('getUser')
->willReturn($user)
;
}
$extractedSids = $strategy->getSecurityIdentities($token);
foreach ($extractedSids as $index => $extractedSid) {
if (!isset($sids[$index])) {
$this->fail(sprintf('Expected SID at index %d, but there was none.', $index));
}
if (false === $sids[$index]->equals($extractedSid)) {
$this->fail(sprintf('Index: %d, expected SID "%s", but got "%s".', $index, $sids[$index], (string) $extractedSid));
}
}
}
public function getSecurityIdentityRetrievalTests(): array
{
$anonymousRoles = [new RoleSecurityIdentity('IS_AUTHENTICATED_ANONYMOUSLY')];
if (\defined('\Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter::PUBLIC_ACCESS')) {
$anonymousRoles[] = new RoleSecurityIdentity(AuthenticatedVoter::PUBLIC_ACCESS);
}
return [
[new Account('johannes'), ['ROLE_USER', 'ROLE_SUPERADMIN'], 'fullFledged', array_merge([
new UserSecurityIdentity('johannes', Account::class),
new RoleSecurityIdentity('ROLE_USER'),
new RoleSecurityIdentity('ROLE_SUPERADMIN'),
new RoleSecurityIdentity('IS_AUTHENTICATED_FULLY'),
new RoleSecurityIdentity('IS_AUTHENTICATED_REMEMBERED'),
], $anonymousRoles)],
[new CustomUserImpl('johannes'), ['ROLE_FOO'], 'fullFledged', array_merge([
new UserSecurityIdentity('johannes', CustomUserImpl::class),
new RoleSecurityIdentity('ROLE_FOO'),
new RoleSecurityIdentity('IS_AUTHENTICATED_FULLY'),
new RoleSecurityIdentity('IS_AUTHENTICATED_REMEMBERED'),
], $anonymousRoles)],
[new Account('foo'), ['ROLE_FOO'], 'rememberMe', array_merge([
new UserSecurityIdentity('foo', Account::class),
new RoleSecurityIdentity('ROLE_FOO'),
new RoleSecurityIdentity('IS_AUTHENTICATED_REMEMBERED'),
], $anonymousRoles)],
['guest', [], 'anonymous', $anonymousRoles],
];
}
public function getDeprecatedSecurityIdentityRetrievalTests()
{
$anonymousRoles = [new RoleSecurityIdentity('IS_AUTHENTICATED_ANONYMOUSLY')];
if (\defined('\Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter::PUBLIC_ACCESS')) {
$anonymousRoles[] = new RoleSecurityIdentity(AuthenticatedVoter::PUBLIC_ACCESS);
}
return [
['johannes', ['ROLE_FOO'], 'fullFledged', array_merge([
new UserSecurityIdentity('johannes', 'MyCustomTokenImpl'),
new RoleSecurityIdentity('ROLE_FOO'),
new RoleSecurityIdentity('IS_AUTHENTICATED_FULLY'),
new RoleSecurityIdentity('IS_AUTHENTICATED_REMEMBERED'),
], $anonymousRoles)],
['guest', ['ROLE_FOO'], 'anonymous', array_merge([
new RoleSecurityIdentity('ROLE_FOO'),
], $anonymousRoles)],
];
}
private function getStrategy(array $roles, string $authenticationStatus): SecurityIdentityRetrievalStrategy
{
$roleHierarchy = new class($roles) implements RoleHierarchyInterface {
private $roles;
public function __construct(array $roles)
{
$this->roles = $roles;
}
public function getReachableRoleNames(array $roles): array
{
return $this->roles;
}
};
$trustResolverMockBuild = $this->getMockBuilder(AuthenticationTrustResolverInterface::class);
if (\defined('\Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter::PUBLIC_ACCESS')) {
if (method_exists(AuthenticationTrustResolverInterface::class, 'isAuthenticated')) {
$trustResolver = $trustResolverMockBuild->getMock();
} else {
$trustResolver = $trustResolverMockBuild
->onlyMethods(['isAnonymous', 'isRememberMe', 'isFullFledged'])
->addMethods(['isAuthenticated'])
->getMock()
;
}
$trustResolver
->method('isAuthenticated')
->willReturn('anonymous' !== $authenticationStatus);
} else {
$trustResolver = $trustResolverMockBuild->getMock();
$trustResolver
->method('isAnonymous')
->willReturn('anonymous' === $authenticationStatus);
}
if ('fullFledged' === $authenticationStatus) {
$trustResolver
->expects($this->once())
->method('isFullFledged')
->willReturn(true)
;
$trustResolver
->expects($this->never())
->method('isRememberMe')
;
} elseif ('rememberMe' === $authenticationStatus) {
$trustResolver
->expects($this->once())
->method('isFullFledged')
->willReturn(false)
;
$trustResolver
->expects($this->once())
->method('isRememberMe')
->willReturn(true)
;
} else {
if (method_exists(AuthenticationTrustResolverInterface::class, 'isAuthenticated')) {
$trustResolver
->method('isAuthenticated')
->willReturn(false)
;
} else {
$trustResolver
->method('isAnonymous')
->willReturn(true);
}
$trustResolver
->expects($this->once())
->method('isFullFledged')
->willReturn(false)
;
$trustResolver
->expects($this->once())
->method('isRememberMe')
->willReturn(false)
;
}
return new SecurityIdentityRetrievalStrategy($roleHierarchy, $trustResolver);
}
}
class CustomUserImpl implements UserInterface
{
protected $name;
public function __construct($name)
{
$this->name = $name;
}
public function __toString()
{
return $this->name;
}
public function getRoles(): array
{
return [];
}
public function eraseCredentials()
{
}
public function getUserIdentifier(): string
{
return $this->name;
}
public function getPassword()
{
return null;
}
public function getSalt()
{
return null;
}
public function getUsername(): string
{
return $this->getUserIdentifier();
}
}
security-acl-3.3.3/Tests/Domain/UserSecurityIdentityTest.php 0000664 0000000 0000000 00000005214 14433205003 0024162 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Tests\Domain;
use Symfony\Component\Security\Acl\Domain\RoleSecurityIdentity;
use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity;
use Symfony\Component\Security\Acl\Model\SecurityIdentityInterface;
use Symfony\Component\Security\Acl\Tests\Fixtures\Account;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
class UserSecurityIdentityTest extends \PHPUnit\Framework\TestCase
{
public function testConstructor()
{
$id = new UserSecurityIdentity('foo', 'Foo');
$this->assertEquals('foo', $id->getUsername());
$this->assertEquals('Foo', $id->getClass());
}
// Test that constructor never changes the type, even for proxies
public function testConstructorWithProxy()
{
$id = new UserSecurityIdentity('foo', 'Acme\DemoBundle\Proxy\__CG__\Symfony\Component\Security\Acl\Tests\Domain\Foo');
$this->assertEquals('foo', $id->getUsername());
$this->assertEquals('Acme\DemoBundle\Proxy\__CG__\Symfony\Component\Security\Acl\Tests\Domain\Foo', $id->getClass());
}
/**
* @dataProvider getCompareData
*/
public function testEquals(UserSecurityIdentity $id1, SecurityIdentityInterface $id2, bool $equal)
{
$this->assertSame($equal, $id1->equals($id2));
}
public function getCompareData(): array
{
$account = new Account('foo');
$token = $this->createMock(TokenInterface::class);
$token
->expects($this->any())
->method('getUser')
->willReturn($account)
;
return [
[new UserSecurityIdentity('foo', 'Foo'), new UserSecurityIdentity('foo', 'Foo'), true],
[new UserSecurityIdentity('foo', 'Bar'), new UserSecurityIdentity('foo', 'Foo'), false],
[new UserSecurityIdentity('foo', 'Foo'), new UserSecurityIdentity('bar', 'Foo'), false],
[new UserSecurityIdentity('foo', 'Foo'), UserSecurityIdentity::fromAccount($account), false],
[new UserSecurityIdentity('bla', 'Foo'), new UserSecurityIdentity('blub', 'Foo'), false],
[new UserSecurityIdentity('foo', 'Foo'), new RoleSecurityIdentity('foo'), false],
[new UserSecurityIdentity('foo', 'Foo'), UserSecurityIdentity::fromToken($token), false],
[new UserSecurityIdentity('foo', Account::class), UserSecurityIdentity::fromToken($token), true],
];
}
}
security-acl-3.3.3/Tests/Fixtures/ 0000775 0000000 0000000 00000000000 14433205003 0017031 5 ustar 00root root 0000000 0000000 security-acl-3.3.3/Tests/Fixtures/Account.php 0000664 0000000 0000000 00000001447 14433205003 0021144 0 ustar 00root root 0000000 0000000 identifier = $identifier;
}
public function getUserIdentifier(): string
{
return $this->identifier;
}
public function getUsername(): string
{
return $this->getUserIdentifier();
}
public function getRoles(): array
{
return ['ROLE_USER'];
}
public function getPassword(): ?string
{
return null;
}
public function getSalt(): ?string
{
return null;
}
public function eraseCredentials(): void
{
}
}
security-acl-3.3.3/Tests/Fixtures/SerializableAclInterface.php 0000664 0000000 0000000 00000000426 14433205003 0024413 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Tests\Permission;
use Symfony\Component\Security\Acl\Permission\BasicPermissionMap;
class BasicPermissionMapTest extends \PHPUnit\Framework\TestCase
{
public function testGetMasksReturnsNullWhenNotSupportedMask()
{
$map = new BasicPermissionMap();
$this->assertNull($map->getMasks('IS_AUTHENTICATED_REMEMBERED', null));
}
}
security-acl-3.3.3/Tests/Permission/MaskBuilderTest.php 0000664 0000000 0000000 00000005722 14433205003 0023131 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Tests\Permission;
use Symfony\Component\Security\Acl\Permission\MaskBuilder;
class MaskBuilderTest extends \PHPUnit\Framework\TestCase
{
/**
* @dataProvider getInvalidConstructorData
*/
public function testConstructorWithNonInteger($invalidMask)
{
$this->expectException(\InvalidArgumentException::class);
new MaskBuilder($invalidMask);
}
public function getInvalidConstructorData()
{
return [
[234.463],
['asdgasdf'],
[[]],
[new \stdClass()],
];
}
public function testConstructorWithoutArguments()
{
$builder = new MaskBuilder();
$this->assertEquals(0, $builder->get());
}
public function testConstructor()
{
$builder = new MaskBuilder(123456);
$this->assertEquals(123456, $builder->get());
}
public function testAddAndRemove()
{
$builder = new MaskBuilder();
$builder
->add('view')
->add('eDiT')
->add('ownEr')
;
$mask = $builder->get();
$this->assertEquals(MaskBuilder::MASK_VIEW, $mask & MaskBuilder::MASK_VIEW);
$this->assertEquals(MaskBuilder::MASK_EDIT, $mask & MaskBuilder::MASK_EDIT);
$this->assertEquals(MaskBuilder::MASK_OWNER, $mask & MaskBuilder::MASK_OWNER);
$this->assertEquals(0, $mask & MaskBuilder::MASK_MASTER);
$this->assertEquals(0, $mask & MaskBuilder::MASK_CREATE);
$this->assertEquals(0, $mask & MaskBuilder::MASK_DELETE);
$this->assertEquals(0, $mask & MaskBuilder::MASK_UNDELETE);
$builder->remove('edit')->remove('OWner');
$mask = $builder->get();
$this->assertEquals(0, $mask & MaskBuilder::MASK_EDIT);
$this->assertEquals(0, $mask & MaskBuilder::MASK_OWNER);
$this->assertEquals(MaskBuilder::MASK_VIEW, $mask & MaskBuilder::MASK_VIEW);
}
public function testGetPattern()
{
$builder = new MaskBuilder();
$this->assertEquals(MaskBuilder::ALL_OFF, $builder->getPattern());
$builder->add('view');
$this->assertEquals(str_repeat('.', 31).'V', $builder->getPattern());
$builder->add('owner');
$this->assertEquals(str_repeat('.', 24).'N......V', $builder->getPattern());
$builder->add(1 << 10);
$this->assertEquals(str_repeat('.', 21).MaskBuilder::ON.'..N......V', $builder->getPattern());
}
public function testReset()
{
$builder = new MaskBuilder();
$this->assertEquals(0, $builder->get());
$builder->add('view');
$this->assertTrue($builder->get() > 0);
$builder->reset();
$this->assertEquals(0, $builder->get());
}
}
security-acl-3.3.3/Tests/Voter/ 0000775 0000000 0000000 00000000000 14433205003 0016317 5 ustar 00root root 0000000 0000000 security-acl-3.3.3/Tests/Voter/AclVoterTest.php 0000664 0000000 0000000 00000033114 14433205003 0021411 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Tests\Voter;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Security\Acl\Domain\ObjectIdentity;
use Symfony\Component\Security\Acl\Domain\RoleSecurityIdentity;
use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity;
use Symfony\Component\Security\Acl\Exception\AclNotFoundException;
use Symfony\Component\Security\Acl\Exception\NoAceFoundException;
use Symfony\Component\Security\Acl\Model\AclProviderInterface;
use Symfony\Component\Security\Acl\Model\ObjectIdentityRetrievalStrategyInterface;
use Symfony\Component\Security\Acl\Model\SecurityIdentityRetrievalStrategyInterface;
use Symfony\Component\Security\Acl\Permission\PermissionMapInterface;
use Symfony\Component\Security\Acl\Tests\Fixtures\SerializableAclInterface;
use Symfony\Component\Security\Acl\Voter\AclVoter;
use Symfony\Component\Security\Acl\Voter\FieldVote;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
class AclVoterTest extends TestCase
{
/**
* @dataProvider getSupportsAttributeTests
*/
public function testSupportsAttribute($attribute, $supported)
{
[$voter, , $permissionMap] = $this->getVoter(true, false);
$permissionMap
->expects($this->once())
->method('contains')
->with($this->identicalTo($attribute))
->willReturn($supported)
;
$this->assertSame($supported, $voter->supportsAttribute($attribute));
}
/**
* @dataProvider getSupportsAttributeNonStringTests
*/
public function testSupportsAttributeNonString($attribute)
{
[$voter] = $this->getVoter(true, false);
$this->assertFalse($voter->supportsAttribute($attribute));
}
public function getSupportsAttributeTests()
{
return [
['foo', true],
['foo', false],
];
}
public function getSupportsAttributeNonStringTests()
{
return [
[new \stdClass()],
[1],
[true],
[[]],
];
}
/**
* @dataProvider getSupportsClassTests
*/
public function testSupportsClass($class)
{
[$voter] = $this->getVoter();
$this->assertTrue($voter->supportsClass($class));
}
public function getSupportsClassTests()
{
return [
['foo'],
['bar'],
['moo'],
];
}
public function testVote()
{
[$voter, , $permissionMap] = $this->getVoter();
$permissionMap
->expects($this->atLeastOnce())
->method('getMasks')
->willReturn(null)
;
$this->assertSame(VoterInterface::ACCESS_ABSTAIN, $voter->vote($this->getToken(), null, ['VIEW', 'EDIT', 'DELETE']));
}
/**
* @dataProvider getTrueFalseTests
*/
public function testVoteWhenNoObjectIsPassed($allowIfObjectIdentityUnavailable)
{
[$voter, , $permissionMap] = $this->getVoter($allowIfObjectIdentityUnavailable);
$permissionMap
->expects($this->once())
->method('getMasks')
->willReturn([])
;
if ($allowIfObjectIdentityUnavailable) {
$vote = VoterInterface::ACCESS_GRANTED;
} else {
$vote = VoterInterface::ACCESS_ABSTAIN;
}
$this->assertSame($vote, $voter->vote($this->getToken(), null, ['VIEW']));
}
/**
* @dataProvider getTrueFalseTests
*/
public function testVoteWhenOidStrategyReturnsNull($allowIfUnavailable)
{
[$voter, , $permissionMap, $oidStrategy] = $this->getVoter($allowIfUnavailable);
$permissionMap
->expects($this->once())
->method('getMasks')
->willReturn([])
;
$oidStrategy
->expects($this->once())
->method('getObjectIdentity')
->willReturn(null)
;
if ($allowIfUnavailable) {
$vote = VoterInterface::ACCESS_GRANTED;
} else {
$vote = VoterInterface::ACCESS_ABSTAIN;
}
$this->assertSame($vote, $voter->vote($this->getToken(), new \stdClass(), ['VIEW']));
}
public function getTrueFalseTests()
{
return [[true], [false]];
}
public function testVoteNoAclFound()
{
[$voter, $provider, $permissionMap, $oidStrategy, $sidStrategy] = $this->getVoter();
$permissionMap
->expects($this->once())
->method('getMasks')
->willReturn([])
;
$oidStrategy
->expects($this->once())
->method('getObjectIdentity')
->willReturn($oid = new ObjectIdentity('1', 'Foo'))
;
$sidStrategy
->expects($this->once())
->method('getSecurityIdentities')
->willReturn($sids = [new UserSecurityIdentity('johannes', 'Foo'), new RoleSecurityIdentity('ROLE_FOO')])
;
$provider
->expects($this->once())
->method('findAcl')
->with($this->equalTo($oid), $this->equalTo($sids))
->will($this->throwException(new AclNotFoundException('Not found.')))
;
$this->assertSame(VoterInterface::ACCESS_DENIED, $voter->vote($this->getToken(), new \stdClass(), ['VIEW']));
}
/**
* @dataProvider getTrueFalseTests
*/
public function testVoteGrantsAccess($grant)
{
[$voter, $provider, $permissionMap, $oidStrategy, $sidStrategy] = $this->getVoter();
$permissionMap
->expects($this->once())
->method('getMasks')
->with($this->equalTo('VIEW'))
->willReturn($masks = [1, 2, 3])
;
$oidStrategy
->expects($this->once())
->method('getObjectIdentity')
->willReturn($oid = new ObjectIdentity('1', 'Foo'))
;
$sidStrategy
->expects($this->once())
->method('getSecurityIdentities')
->willReturn($sids = [new UserSecurityIdentity('johannes', 'Foo'), new RoleSecurityIdentity('ROLE_FOO')])
;
$provider
->expects($this->once())
->method('findAcl')
->with($this->equalTo($oid), $this->equalTo($sids))
->willReturn($acl = $this->createMock(SerializableAclInterface::class))
;
$acl
->expects($this->once())
->method('isGranted')
->with($this->identicalTo($masks), $this->equalTo($sids), $this->isFalse())
->willReturn($grant)
;
if ($grant) {
$vote = VoterInterface::ACCESS_GRANTED;
} else {
$vote = VoterInterface::ACCESS_DENIED;
}
$this->assertSame($vote, $voter->vote($this->getToken(), new \stdClass(), ['VIEW']));
}
public function testVoteNoAceFound()
{
[$voter, $provider, $permissionMap, $oidStrategy, $sidStrategy] = $this->getVoter();
$permissionMap
->expects($this->once())
->method('getMasks')
->with($this->equalTo('VIEW'))
->willReturn($masks = [1, 2, 3])
;
$oidStrategy
->expects($this->once())
->method('getObjectIdentity')
->willReturn($oid = new ObjectIdentity('1', 'Foo'))
;
$sidStrategy
->expects($this->once())
->method('getSecurityIdentities')
->willReturn($sids = [new UserSecurityIdentity('johannes', 'Foo'), new RoleSecurityIdentity('ROLE_FOO')])
;
$provider
->expects($this->once())
->method('findAcl')
->with($this->equalTo($oid), $this->equalTo($sids))
->willReturn($acl = $this->createMock(SerializableAclInterface::class))
;
$acl
->expects($this->once())
->method('isGranted')
->with($this->identicalTo($masks), $this->equalTo($sids), $this->isFalse())
->will($this->throwException(new NoAceFoundException('No ACE')))
;
$this->assertSame(VoterInterface::ACCESS_DENIED, $voter->vote($this->getToken(), new \stdClass(), ['VIEW']));
}
/**
* @dataProvider getTrueFalseTests
*/
public function testVoteGrantsFieldAccess($grant)
{
[$voter, $provider, $permissionMap, $oidStrategy, $sidStrategy] = $this->getVoter();
$permissionMap
->expects($this->once())
->method('getMasks')
->with($this->equalTo('VIEW'))
->willReturn($masks = [1, 2, 3])
;
$oidStrategy
->expects($this->once())
->method('getObjectIdentity')
->willReturn($oid = new ObjectIdentity('1', 'Foo'))
;
$sidStrategy
->expects($this->once())
->method('getSecurityIdentities')
->willReturn($sids = [new UserSecurityIdentity('johannes', 'Foo'), new RoleSecurityIdentity('ROLE_FOO')])
;
$provider
->expects($this->once())
->method('findAcl')
->with($this->equalTo($oid), $this->equalTo($sids))
->willReturn($acl = $this->createMock(SerializableAclInterface::class))
;
$acl
->expects($this->once())
->method('isFieldGranted')
->with($this->identicalTo('foo'), $this->identicalTo($masks), $this->equalTo($sids), $this->isFalse())
->willReturn($grant)
;
if ($grant) {
$vote = VoterInterface::ACCESS_GRANTED;
} else {
$vote = VoterInterface::ACCESS_DENIED;
}
$this->assertSame($vote, $voter->vote($this->getToken(), new FieldVote(new \stdClass(), 'foo'), ['VIEW']));
}
public function testVoteNoFieldAceFound()
{
[$voter, $provider, $permissionMap, $oidStrategy, $sidStrategy] = $this->getVoter();
$permissionMap
->expects($this->once())
->method('getMasks')
->with($this->equalTo('VIEW'))
->willReturn($masks = [1, 2, 3])
;
$oidStrategy
->expects($this->once())
->method('getObjectIdentity')
->willReturn($oid = new ObjectIdentity('1', 'Foo'))
;
$sidStrategy
->expects($this->once())
->method('getSecurityIdentities')
->willReturn($sids = [new UserSecurityIdentity('johannes', 'Foo'), new RoleSecurityIdentity('ROLE_FOO')])
;
$provider
->expects($this->once())
->method('findAcl')
->with($this->equalTo($oid), $this->equalTo($sids))
->willReturn($acl = $this->createMock(SerializableAclInterface::class))
;
$acl
->expects($this->once())
->method('isFieldGranted')
->with($this->identicalTo('foo'), $this->identicalTo($masks), $this->equalTo($sids), $this->isFalse())
->will($this->throwException(new NoAceFoundException('No ACE')))
;
$this->assertSame(VoterInterface::ACCESS_DENIED, $voter->vote($this->getToken(), new FieldVote(new \stdClass(), 'foo'), ['VIEW']));
}
public function testWhenReceivingAnObjectIdentityInterfaceWeDontRetrieveANewObjectIdentity()
{
[$voter, $provider, $permissionMap, $oidStrategy, $sidStrategy] = $this->getVoter();
$oid = new ObjectIdentity('someID', 'someType');
$permissionMap
->expects($this->once())
->method('getMasks')
->with($this->equalTo('VIEW'))
->willReturn($masks = [1, 2, 3])
;
$oidStrategy
->expects($this->never())
->method('getObjectIdentity')
;
$sidStrategy
->expects($this->once())
->method('getSecurityIdentities')
->willReturn($sids = [new UserSecurityIdentity('johannes', 'Foo'), new RoleSecurityIdentity('ROLE_FOO')])
;
$provider
->expects($this->once())
->method('findAcl')
->with($this->equalTo($oid), $this->equalTo($sids))
->willReturn($acl = $this->createMock(SerializableAclInterface::class))
;
$acl
->expects($this->once())
->method('isGranted')
->with($this->identicalTo($masks), $this->equalTo($sids), $this->isFalse())
->will($this->throwException(new NoAceFoundException('No ACE')))
;
$voter->vote($this->getToken(), $oid, ['VIEW']);
}
protected function getToken()
{
return $this->createMock(TokenInterface::class);
}
protected function getVoter($allowIfObjectIdentityUnavailable = true, $alwaysContains = true)
{
$provider = $this->createMock(AclProviderInterface::class);
$permissionMap = $this->createMock(PermissionMapInterface::class);
$oidStrategy = $this->createMock(ObjectIdentityRetrievalStrategyInterface::class);
$sidStrategy = $this->createMock(SecurityIdentityRetrievalStrategyInterface::class);
if ($alwaysContains) {
$permissionMap
->expects($this->any())
->method('contains')
->willReturn(true);
}
return [
new AclVoter($provider, $oidStrategy, $sidStrategy, $permissionMap, null, $allowIfObjectIdentityUnavailable),
$provider,
$permissionMap,
$oidStrategy,
$sidStrategy,
];
}
}
security-acl-3.3.3/Util/ 0000775 0000000 0000000 00000000000 14433205003 0015033 5 ustar 00root root 0000000 0000000 security-acl-3.3.3/Util/ClassUtils.php 0000664 0000000 0000000 00000003106 14433205003 0017632 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Util;
use Doctrine\Common\Util\ClassUtils as DoctrineClassUtils;
/**
* Class related functionality for objects that
* might or might not be proxy objects at the moment.
*
* @see DoctrineClassUtils
*
* @author Johannes Schmitt
* @author Iltar van der Berg
*/
final class ClassUtils
{
/**
* Marker for Proxy class names.
*
* @var string
*/
public const MARKER = '__CG__';
/**
* Length of the proxy marker.
*
* @var int
*/
public const MARKER_LENGTH = 6;
/**
* This class should not be instantiated.
*/
private function __construct()
{
}
/**
* Gets the real class name of a class name that could be a proxy.
*
* @param string|object $object
*
* @return string
*/
public static function getRealClass($object)
{
$class = \is_object($object) ? \get_class($object) : $object;
if (class_exists(DoctrineClassUtils::class)) {
return DoctrineClassUtils::getRealClass($class);
}
// fallback in case doctrine common is not installed
if (false === $pos = strrpos($class, '\\'.self::MARKER.'\\')) {
return $class;
}
return substr($class, $pos + self::MARKER_LENGTH + 2);
}
}
security-acl-3.3.3/Voter/ 0000775 0000000 0000000 00000000000 14433205003 0015215 5 ustar 00root root 0000000 0000000 security-acl-3.3.3/Voter/AclVoter.php 0000664 0000000 0000000 00000013204 14433205003 0017445 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Voter;
use Psr\Log\LoggerInterface;
use Symfony\Component\Security\Acl\Exception\AclNotFoundException;
use Symfony\Component\Security\Acl\Exception\NoAceFoundException;
use Symfony\Component\Security\Acl\Model\AclProviderInterface;
use Symfony\Component\Security\Acl\Model\ObjectIdentityInterface;
use Symfony\Component\Security\Acl\Model\ObjectIdentityRetrievalStrategyInterface;
use Symfony\Component\Security\Acl\Model\SecurityIdentityRetrievalStrategyInterface;
use Symfony\Component\Security\Acl\Permission\PermissionMapInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
/**
* This voter can be used as a base class for implementing your own permissions.
*
* @author Johannes M. Schmitt
*/
class AclVoter implements VoterInterface
{
private $aclProvider;
private $permissionMap;
private $objectIdentityRetrievalStrategy;
private $securityIdentityRetrievalStrategy;
private $allowIfObjectIdentityUnavailable;
private $logger;
public function __construct(AclProviderInterface $aclProvider, ObjectIdentityRetrievalStrategyInterface $oidRetrievalStrategy, SecurityIdentityRetrievalStrategyInterface $sidRetrievalStrategy, PermissionMapInterface $permissionMap, LoggerInterface $logger = null, $allowIfObjectIdentityUnavailable = true)
{
$this->aclProvider = $aclProvider;
$this->permissionMap = $permissionMap;
$this->objectIdentityRetrievalStrategy = $oidRetrievalStrategy;
$this->securityIdentityRetrievalStrategy = $sidRetrievalStrategy;
$this->logger = $logger;
$this->allowIfObjectIdentityUnavailable = $allowIfObjectIdentityUnavailable;
}
public function supportsAttribute($attribute)
{
return \is_string($attribute) && $this->permissionMap->contains($attribute);
}
public function vote(TokenInterface $token, $subject, array $attributes)
{
foreach ($attributes as $attribute) {
if (!$this->supportsAttribute($attribute)) {
continue;
}
if (null === $masks = $this->permissionMap->getMasks($attribute, $subject)) {
continue;
}
if (null === $subject) {
if (null !== $this->logger) {
$this->logger->debug(sprintf('Object identity unavailable. Voting to %s.', $this->allowIfObjectIdentityUnavailable ? 'grant access' : 'abstain'));
}
return $this->allowIfObjectIdentityUnavailable ? self::ACCESS_GRANTED : self::ACCESS_ABSTAIN;
} elseif ($subject instanceof FieldVote) {
$field = $subject->getField();
$subject = $subject->getDomainObject();
} else {
$field = null;
}
if ($subject instanceof ObjectIdentityInterface) {
$oid = $subject;
} elseif (null === $oid = $this->objectIdentityRetrievalStrategy->getObjectIdentity($subject)) {
if (null !== $this->logger) {
$this->logger->debug(sprintf('Object identity unavailable. Voting to %s.', $this->allowIfObjectIdentityUnavailable ? 'grant access' : 'abstain'));
}
return $this->allowIfObjectIdentityUnavailable ? self::ACCESS_GRANTED : self::ACCESS_ABSTAIN;
}
if (!$this->supportsClass($oid->getType())) {
return self::ACCESS_ABSTAIN;
}
$sids = $this->securityIdentityRetrievalStrategy->getSecurityIdentities($token);
try {
$acl = $this->aclProvider->findAcl($oid, $sids);
if (null === $field && $acl->isGranted($masks, $sids, false)) {
if (null !== $this->logger) {
$this->logger->debug('ACL found, permission granted. Voting to grant access.');
}
return self::ACCESS_GRANTED;
} elseif (null !== $field && $acl->isFieldGranted($field, $masks, $sids, false)) {
if (null !== $this->logger) {
$this->logger->debug('ACL found, permission granted. Voting to grant access.');
}
return self::ACCESS_GRANTED;
}
if (null !== $this->logger) {
$this->logger->debug('ACL found, insufficient permissions. Voting to deny access.');
}
return self::ACCESS_DENIED;
} catch (AclNotFoundException $e) {
if (null !== $this->logger) {
$this->logger->debug('No ACL found for the object identity. Voting to deny access.');
}
return self::ACCESS_DENIED;
} catch (NoAceFoundException $e) {
if (null !== $this->logger) {
$this->logger->debug('ACL found, no ACE applicable. Voting to deny access.');
}
return self::ACCESS_DENIED;
}
}
// no attribute was supported
return self::ACCESS_ABSTAIN;
}
/**
* You can override this method when writing a voter for a specific domain
* class.
*
* @param string $class The class name
*
* @return bool
*/
public function supportsClass($class)
{
return true;
}
}
security-acl-3.3.3/Voter/FieldVote.php 0000664 0000000 0000000 00000001510 14433205003 0017604 0 ustar 00root root 0000000 0000000
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Acl\Voter;
/**
* This class is a lightweight wrapper around field vote requests which does
* not violate any interface contracts.
*
* @author Johannes M. Schmitt
*/
class FieldVote
{
private $domainObject;
private $field;
public function __construct($domainObject, $field)
{
$this->domainObject = $domainObject;
$this->field = $field;
}
public function getDomainObject()
{
return $this->domainObject;
}
public function getField()
{
return $this->field;
}
}
security-acl-3.3.3/composer.json 0000664 0000000 0000000 00000002420 14433205003 0016636 0 ustar 00root root 0000000 0000000 {
"name": "symfony/security-acl",
"type": "library",
"description": "Symfony Security Component - ACL (Access Control List)",
"keywords": [],
"homepage": "https://symfony.com",
"license": "MIT",
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"require": {
"php": ">=7.2.5",
"symfony/security-core": "^4.4|^5.0|^6.0|^7.0"
},
"require-dev": {
"symfony/cache": "^4.4|^5.0|^6.0|^7.0",
"symfony/finder": "^4.4|^5.0|^6.0|^7.0",
"symfony/phpunit-bridge": "^5.2|^6.0|^7.0",
"doctrine/cache": "^1.11|^2.0",
"doctrine/common": "^2.2|^3",
"doctrine/persistence": "^1.3.3|^2|^3",
"doctrine/dbal": "^2.13.1|^3.1",
"psr/log": "^1|^2|^3"
},
"autoload": {
"psr-4": { "Symfony\\Component\\Security\\Acl\\": "" },
"exclude-from-classmap": [
"/Tests/"
]
},
"conflict": {
"doctrine/cache": "<1.11",
"doctrine/dbal": "<2.13.1|~3.0.0"
},
"extra": {
"branch-alias": {
"dev-main": "3.x-dev"
}
}
}
security-acl-3.3.3/phpunit.xml.dist 0000664 0000000 0000000 00000001667 14433205003 0017303 0 ustar 00root root 0000000 0000000
./Tests/
./
./Resources
./Tests
./vendor
benchmark
security-acl-3.3.3/psalm.xml 0000664 0000000 0000000 00000001165 14433205003 0015757 0 ustar 00root root 0000000 0000000