230 lines
6.3 KiB
PHP
230 lines
6.3 KiB
PHP
<?php
|
|
|
|
/*
|
|
* This file is part of the Symfony package.
|
|
*
|
|
* (c) Fabien Potencier <fabien@symfony.com>
|
|
*
|
|
* 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 <schmittjoh@gmail.com>
|
|
*/
|
|
class DoctrineAclCache implements AclCacheInterface
|
|
{
|
|
const PREFIX = 'sf2_acl_';
|
|
|
|
private $cache;
|
|
private $prefix;
|
|
private $permissionGrantingStrategy;
|
|
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* @param Cache $cache
|
|
* @param PermissionGrantingStrategyInterface $permissionGrantingStrategy
|
|
* @param string $prefix
|
|
*
|
|
* @throws \InvalidArgumentException
|
|
*/
|
|
public function __construct(Cache $cache, PermissionGrantingStrategyInterface $permissionGrantingStrategy, $prefix = self::PREFIX)
|
|
{
|
|
if (0 === strlen($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);
|
|
}
|
|
|
|
/**
|
|
* Unserializes the ACL.
|
|
*
|
|
* @param string $serialized
|
|
*
|
|
* @return AclInterface
|
|
*/
|
|
private function unserializeAcl($serialized)
|
|
{
|
|
$acl = unserialize($serialized);
|
|
|
|
if (null !== $parentId = $acl->getParentAcl()) {
|
|
$parentAcl = $this->getFromCacheById($parentId);
|
|
|
|
if (null === $parentAcl) {
|
|
return;
|
|
}
|
|
|
|
$acl->setParentAcl($parentAcl);
|
|
}
|
|
|
|
$reflectionProperty = new \ReflectionProperty($acl, 'permissionGrantingStrategy');
|
|
$reflectionProperty->setAccessible(true);
|
|
$reflectionProperty->setValue($acl, $this->permissionGrantingStrategy);
|
|
$reflectionProperty->setAccessible(false);
|
|
|
|
$aceAclProperty = new \ReflectionProperty('Symfony\Component\Security\Acl\Domain\Entry', '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.
|
|
*
|
|
* @param ObjectIdentityInterface $oid
|
|
*
|
|
* @return string
|
|
*/
|
|
private function getDataKeyByIdentity(ObjectIdentityInterface $oid)
|
|
{
|
|
return $this->prefix.md5($oid->getType()).sha1($oid->getType())
|
|
.'_'.md5($oid->getIdentifier()).sha1($oid->getIdentifier());
|
|
}
|
|
|
|
/**
|
|
* Returns the alias key for the object identity key.
|
|
*
|
|
* @param string $aclId
|
|
*
|
|
* @return string
|
|
*/
|
|
private function getAliasKeyForIdentity($aclId)
|
|
{
|
|
return $this->prefix.$aclId;
|
|
}
|
|
}
|