diff options
author | realmfoo <konstantin.leboev@gmail.com> | 2011-08-10 10:59:19 +0400 |
---|---|---|
committer | realmfoo <konstantin.leboev@gmail.com> | 2011-08-10 10:59:19 +0400 |
commit | b33e8d2376f20761911faa654d85790d61a29019 (patch) | |
tree | 91ef528a24e416523bb25859a702d8d859a0e2af | |
parent | 111f1e758a0919556c2c2fdd8fd8779303113f30 (diff) | |
parent | 77b520411cafe3f32f1f52d27dd806ee6110504d (diff) | |
download | symfony-security-b33e8d2376f20761911faa654d85790d61a29019.zip symfony-security-b33e8d2376f20761911faa654d85790d61a29019.tar.gz symfony-security-b33e8d2376f20761911faa654d85790d61a29019.tar.bz2 |
merge from master
94 files changed, 544 insertions, 310 deletions
diff --git a/Acl/Dbal/MutableAclProvider.php b/Acl/Dbal/MutableAclProvider.php index 62667c8..9050cf8 100644 --- a/Acl/Dbal/MutableAclProvider.php +++ b/Acl/Dbal/MutableAclProvider.php @@ -246,6 +246,10 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf } $this->regenerateAncestorRelations($acl); + $childAcls = $this->findAcls($this->findChildren($acl->getObjectIdentity(), false)); + foreach ($childAcls as $childOid) { + $this->regenerateAncestorRelations($childAcls[$childOid]); + } } // this includes only updates of existing ACEs, but neither the creation, nor diff --git a/Acl/Dbal/Schema.php b/Acl/Dbal/Schema.php index 09d60aa..dd8cf08 100644 --- a/Acl/Dbal/Schema.php +++ b/Acl/Dbal/Schema.php @@ -142,4 +142,4 @@ final class Schema extends BaseSchema $table->setPrimaryKey(array('id')); $table->addUniqueIndex(array('identifier', 'username')); } -}
\ No newline at end of file +} diff --git a/Acl/Domain/AclCollectionCache.php b/Acl/Domain/AclCollectionCache.php index 6614724..c4f5fdd 100644 --- a/Acl/Domain/AclCollectionCache.php +++ b/Acl/Domain/AclCollectionCache.php @@ -63,4 +63,4 @@ class AclCollectionCache $this->aclProvider->findAcls($oids, $sids); } -}
\ No newline at end of file +} diff --git a/Acl/Domain/AuditLogger.php b/Acl/Domain/AuditLogger.php index 9f95d06..d6d7d9d 100644 --- a/Acl/Domain/AuditLogger.php +++ b/Acl/Domain/AuditLogger.php @@ -45,9 +45,9 @@ abstract class AuditLogger implements AuditLoggerInterface /** * This method is only called when logging is needed * - * @param Boolean $granted + * @param Boolean $granted * @param EntryInterface $ace * @return void */ abstract protected function doLog($granted, EntryInterface $ace); -}
\ No newline at end of file +} diff --git a/Acl/Domain/DoctrineAclCache.php b/Acl/Domain/DoctrineAclCache.php index 64241e2..21e5149 100644 --- a/Acl/Domain/DoctrineAclCache.php +++ b/Acl/Domain/DoctrineAclCache.php @@ -165,7 +165,7 @@ class DoctrineAclCache implements AclCacheInterface $reflectionProperty->setValue($acl, $this->permissionGrantingStrategy); $reflectionProperty->setAccessible(false); - $aceAclProperty = new \ReflectionProperty('Symfony\Component\Security\Acl\Domain\Entry', 'id'); + $aceAclProperty = new \ReflectionProperty('Symfony\Component\Security\Acl\Domain\Entry', 'acl'); $aceAclProperty->setAccessible(true); foreach ($acl->getObjectAces() as $ace) { diff --git a/Acl/Domain/FieldEntry.php b/Acl/Domain/FieldEntry.php index 5ff6921..4167ba4 100644 --- a/Acl/Domain/FieldEntry.php +++ b/Acl/Domain/FieldEntry.php @@ -72,4 +72,4 @@ class FieldEntry extends Entry implements FieldEntryInterface list($this->field, $parentStr) = unserialize($serialized); parent::unserialize($parentStr); } -}
\ No newline at end of file +} diff --git a/Acl/Domain/ObjectIdentity.php b/Acl/Domain/ObjectIdentity.php index f55f8a5..3bf1fe1 100644 --- a/Acl/Domain/ObjectIdentity.php +++ b/Acl/Domain/ObjectIdentity.php @@ -20,7 +20,7 @@ use Symfony\Component\Security\Acl\Model\ObjectIdentityInterface; * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ -class ObjectIdentity implements ObjectIdentityInterface +final class ObjectIdentity implements ObjectIdentityInterface { private $identifier; private $type; @@ -52,7 +52,7 @@ class ObjectIdentity implements ObjectIdentityInterface * @throws \InvalidArgumentException * @return ObjectIdentity */ - public static function fromDomainObject($domainObject) + static public function fromDomainObject($domainObject) { if (!is_object($domainObject)) { throw new InvalidDomainObjectException('$domainObject must be an object.'); @@ -107,4 +107,4 @@ class ObjectIdentity implements ObjectIdentityInterface { return sprintf('ObjectIdentity(%s, %s)', $this->identifier, $this->type); } -}
\ No newline at end of file +} diff --git a/Acl/Domain/ObjectIdentityRetrievalStrategy.php b/Acl/Domain/ObjectIdentityRetrievalStrategy.php index 00b5b6b..acd3b2c 100644 --- a/Acl/Domain/ObjectIdentityRetrievalStrategy.php +++ b/Acl/Domain/ObjectIdentityRetrievalStrategy.php @@ -32,4 +32,4 @@ class ObjectIdentityRetrievalStrategy implements ObjectIdentityRetrievalStrategy return null; } } -}
\ No newline at end of file +} diff --git a/Acl/Domain/RoleSecurityIdentity.php b/Acl/Domain/RoleSecurityIdentity.php index d3694e6..51d3d0c 100644 --- a/Acl/Domain/RoleSecurityIdentity.php +++ b/Acl/Domain/RoleSecurityIdentity.php @@ -19,7 +19,7 @@ use Symfony\Component\Security\Core\Role\Role; * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ -class RoleSecurityIdentity implements SecurityIdentityInterface +final class RoleSecurityIdentity implements SecurityIdentityInterface { private $role; @@ -71,4 +71,4 @@ class RoleSecurityIdentity implements SecurityIdentityInterface { return sprintf('RoleSecurityIdentity(%s)', $this->role); } -}
\ No newline at end of file +} diff --git a/Acl/Domain/SecurityIdentityRetrievalStrategy.php b/Acl/Domain/SecurityIdentityRetrievalStrategy.php index d16a978..d9e118b 100644 --- a/Acl/Domain/SecurityIdentityRetrievalStrategy.php +++ b/Acl/Domain/SecurityIdentityRetrievalStrategy.php @@ -79,4 +79,4 @@ class SecurityIdentityRetrievalStrategy implements SecurityIdentityRetrievalStra return $sids; } -}
\ No newline at end of file +} diff --git a/Acl/Domain/UserSecurityIdentity.php b/Acl/Domain/UserSecurityIdentity.php index ac63080..b6cae4a 100644 --- a/Acl/Domain/UserSecurityIdentity.php +++ b/Acl/Domain/UserSecurityIdentity.php @@ -20,7 +20,7 @@ use Symfony\Component\Security\Acl\Model\SecurityIdentityInterface; * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ -class UserSecurityIdentity implements SecurityIdentityInterface +final class UserSecurityIdentity implements SecurityIdentityInterface { private $username; private $class; @@ -40,7 +40,7 @@ class UserSecurityIdentity implements SecurityIdentityInterface throw new \InvalidArgumentException('$class must not be empty.'); } - $this->username = $username; + $this->username = (string) $username; $this->class = $class; } @@ -50,7 +50,7 @@ class UserSecurityIdentity implements SecurityIdentityInterface * @param UserInterface $user * @return UserSecurityIdentity */ - public static function fromAccount(UserInterface $user) + static public function fromAccount(UserInterface $user) { return new self($user->getUsername(), get_class($user)); } @@ -61,7 +61,7 @@ class UserSecurityIdentity implements SecurityIdentityInterface * @param TokenInterface $token * @return UserSecurityIdentity */ - public static function fromToken(TokenInterface $token) + static public function fromToken(TokenInterface $token) { $user = $token->getUser(); @@ -116,4 +116,4 @@ class UserSecurityIdentity implements SecurityIdentityInterface { return sprintf('UserSecurityIdentity(%s, %s)', $this->username, $this->class); } -}
\ No newline at end of file +} diff --git a/Acl/Exception/AclAlreadyExistsException.php b/Acl/Exception/AclAlreadyExistsException.php index 18658b7..512da7f 100644 --- a/Acl/Exception/AclAlreadyExistsException.php +++ b/Acl/Exception/AclAlreadyExistsException.php @@ -19,4 +19,4 @@ namespace Symfony\Component\Security\Acl\Exception; */ class AclAlreadyExistsException extends Exception { -}
\ No newline at end of file +} diff --git a/Acl/Exception/AclNotFoundException.php b/Acl/Exception/AclNotFoundException.php index 8de1ea5..bd66c00 100644 --- a/Acl/Exception/AclNotFoundException.php +++ b/Acl/Exception/AclNotFoundException.php @@ -19,4 +19,4 @@ namespace Symfony\Component\Security\Acl\Exception; */ class AclNotFoundException extends Exception { -}
\ No newline at end of file +} diff --git a/Acl/Exception/ConcurrentModificationException.php b/Acl/Exception/ConcurrentModificationException.php index 34d2775..a527d9c 100644 --- a/Acl/Exception/ConcurrentModificationException.php +++ b/Acl/Exception/ConcurrentModificationException.php @@ -19,4 +19,4 @@ namespace Symfony\Component\Security\Acl\Exception; */ class ConcurrentModificationException extends Exception { -}
\ No newline at end of file +} diff --git a/Acl/Exception/Exception.php b/Acl/Exception/Exception.php index f99cb05..d381c57 100644 --- a/Acl/Exception/Exception.php +++ b/Acl/Exception/Exception.php @@ -18,4 +18,4 @@ namespace Symfony\Component\Security\Acl\Exception; */ class Exception extends \Exception { -}
\ No newline at end of file +} diff --git a/Acl/Exception/InvalidDomainObjectException.php b/Acl/Exception/InvalidDomainObjectException.php index 20e91b5..fc1a646 100644 --- a/Acl/Exception/InvalidDomainObjectException.php +++ b/Acl/Exception/InvalidDomainObjectException.php @@ -19,4 +19,4 @@ namespace Symfony\Component\Security\Acl\Exception; */ class InvalidDomainObjectException extends Exception { -}
\ No newline at end of file +} diff --git a/Acl/Exception/NoAceFoundException.php b/Acl/Exception/NoAceFoundException.php index 994efc0..4d194d9 100644 --- a/Acl/Exception/NoAceFoundException.php +++ b/Acl/Exception/NoAceFoundException.php @@ -23,4 +23,4 @@ class NoAceFoundException extends Exception { parent::__construct('No applicable ACE was found.'); } -}
\ No newline at end of file +} diff --git a/Acl/Exception/NotAllAclsFoundException.php b/Acl/Exception/NotAllAclsFoundException.php index 820d933..8e7a08f 100644 --- a/Acl/Exception/NotAllAclsFoundException.php +++ b/Acl/Exception/NotAllAclsFoundException.php @@ -44,4 +44,4 @@ class NotAllAclsFoundException extends AclNotFoundException { return $this->partialResult; } -}
\ No newline at end of file +} diff --git a/Acl/Exception/SidNotLoadedException.php b/Acl/Exception/SidNotLoadedException.php index 0353f92..cb8c4cc 100644 --- a/Acl/Exception/SidNotLoadedException.php +++ b/Acl/Exception/SidNotLoadedException.php @@ -19,4 +19,4 @@ namespace Symfony\Component\Security\Acl\Exception; */ class SidNotLoadedException extends Exception { -}
\ No newline at end of file +} diff --git a/Acl/Model/AclCacheInterface.php b/Acl/Model/AclCacheInterface.php index 30be707..bc6c11f 100644 --- a/Acl/Model/AclCacheInterface.php +++ b/Acl/Model/AclCacheInterface.php @@ -66,4 +66,4 @@ interface AclCacheInterface * @return void */ function clearCache(); -}
\ No newline at end of file +} diff --git a/Acl/Model/AclInterface.php b/Acl/Model/AclInterface.php index e8119fe..9094560 100644 --- a/Acl/Model/AclInterface.php +++ b/Acl/Model/AclInterface.php @@ -103,4 +103,4 @@ interface AclInterface extends \Serializable * @return Boolean */ function isSidLoaded($securityIdentities); -}
\ No newline at end of file +} diff --git a/Acl/Model/AclProviderInterface.php b/Acl/Model/AclProviderInterface.php index 9d1075d..12f55e0 100644 --- a/Acl/Model/AclProviderInterface.php +++ b/Acl/Model/AclProviderInterface.php @@ -46,4 +46,4 @@ interface AclProviderInterface * @return \SplObjectStorage mapping the passed object identities to ACLs */ function findAcls(array $oids, array $sids = array()); -}
\ No newline at end of file +} diff --git a/Acl/Model/AuditLoggerInterface.php b/Acl/Model/AuditLoggerInterface.php index a2afd41..dceb76b 100644 --- a/Acl/Model/AuditLoggerInterface.php +++ b/Acl/Model/AuditLoggerInterface.php @@ -27,4 +27,4 @@ interface AuditLoggerInterface * @return void */ function logIfNeeded($granted, EntryInterface $ace); -}
\ No newline at end of file +} diff --git a/Acl/Model/AuditableAclInterface.php b/Acl/Model/AuditableAclInterface.php index 953cf0d..2a6d619 100644 --- a/Acl/Model/AuditableAclInterface.php +++ b/Acl/Model/AuditableAclInterface.php @@ -60,4 +60,4 @@ interface AuditableAclInterface extends MutableAclInterface * @return void */ function updateObjectFieldAuditing($index, $field, $auditSuccess, $auditFailure); -}
\ No newline at end of file +} diff --git a/Acl/Model/AuditableEntryInterface.php b/Acl/Model/AuditableEntryInterface.php index e79e309..40c4484 100644 --- a/Acl/Model/AuditableEntryInterface.php +++ b/Acl/Model/AuditableEntryInterface.php @@ -31,4 +31,4 @@ interface AuditableEntryInterface extends EntryInterface * @return Boolean */ function isAuditSuccess(); -}
\ No newline at end of file +} diff --git a/Acl/Model/DomainObjectInterface.php b/Acl/Model/DomainObjectInterface.php index fb89858..50bc4c3 100644 --- a/Acl/Model/DomainObjectInterface.php +++ b/Acl/Model/DomainObjectInterface.php @@ -26,4 +26,4 @@ interface DomainObjectInterface * @return string */ function getObjectIdentifier(); -}
\ No newline at end of file +} diff --git a/Acl/Model/EntryInterface.php b/Acl/Model/EntryInterface.php index 8de4ff3..6fe0dc8 100644 --- a/Acl/Model/EntryInterface.php +++ b/Acl/Model/EntryInterface.php @@ -62,4 +62,4 @@ interface EntryInterface extends \Serializable * @return Boolean */ function isGranting(); -}
\ No newline at end of file +} diff --git a/Acl/Model/FieldEntryInterface.php b/Acl/Model/FieldEntryInterface.php index 68aa10c..a35ddb4 100644 --- a/Acl/Model/FieldEntryInterface.php +++ b/Acl/Model/FieldEntryInterface.php @@ -24,4 +24,4 @@ interface FieldEntryInterface extends EntryInterface * @return string */ function getField(); -}
\ No newline at end of file +} diff --git a/Acl/Model/MutableAclInterface.php b/Acl/Model/MutableAclInterface.php index 9a64709..54a3f8e 100644 --- a/Acl/Model/MutableAclInterface.php +++ b/Acl/Model/MutableAclInterface.php @@ -169,4 +169,4 @@ interface MutableAclInterface extends AclInterface * @return void */ function updateObjectFieldAce($index, $field, $mask, $strategy = null); -}
\ No newline at end of file +} diff --git a/Acl/Model/MutableAclProviderInterface.php b/Acl/Model/MutableAclProviderInterface.php index eab1dda..c04eb31 100644 --- a/Acl/Model/MutableAclProviderInterface.php +++ b/Acl/Model/MutableAclProviderInterface.php @@ -49,4 +49,4 @@ interface MutableAclProviderInterface extends AclProviderInterface * @return void */ function updateAcl(MutableAclInterface $acl); -}
\ No newline at end of file +} diff --git a/Acl/Model/ObjectIdentityInterface.php b/Acl/Model/ObjectIdentityInterface.php index d4621c1..7e892bf 100644 --- a/Acl/Model/ObjectIdentityInterface.php +++ b/Acl/Model/ObjectIdentityInterface.php @@ -46,4 +46,4 @@ interface ObjectIdentityInterface * @return string cannot return null */ function getType(); -}
\ No newline at end of file +} diff --git a/Acl/Model/ObjectIdentityRetrievalStrategyInterface.php b/Acl/Model/ObjectIdentityRetrievalStrategyInterface.php index df7a1a9..e53c3da 100644 --- a/Acl/Model/ObjectIdentityRetrievalStrategyInterface.php +++ b/Acl/Model/ObjectIdentityRetrievalStrategyInterface.php @@ -25,4 +25,4 @@ interface ObjectIdentityRetrievalStrategyInterface * @return ObjectIdentityInterface */ function getObjectIdentity($domainObject); -}
\ No newline at end of file +} diff --git a/Acl/Model/PermissionGrantingStrategyInterface.php b/Acl/Model/PermissionGrantingStrategyInterface.php index 882eb08..7afdfac 100644 --- a/Acl/Model/PermissionGrantingStrategyInterface.php +++ b/Acl/Model/PermissionGrantingStrategyInterface.php @@ -22,9 +22,9 @@ interface PermissionGrantingStrategyInterface * Determines whether access to a domain object is to be granted * * @param AclInterface $acl - * @param array $masks - * @param array $sids - * @param Boolean $administrativeMode + * @param array $masks + * @param array $sids + * @param Boolean $administrativeMode * @return Boolean */ function isGranted(AclInterface $acl, array $masks, array $sids, $administrativeMode = false); @@ -41,4 +41,4 @@ interface PermissionGrantingStrategyInterface * @return Boolean */ function isFieldGranted(AclInterface $acl, $field, array $masks, array $sids, $administrativeMode = false); -}
\ No newline at end of file +} diff --git a/Acl/Model/SecurityIdentityInterface.php b/Acl/Model/SecurityIdentityInterface.php index 778bbbf..1833630 100644 --- a/Acl/Model/SecurityIdentityInterface.php +++ b/Acl/Model/SecurityIdentityInterface.php @@ -28,4 +28,4 @@ interface SecurityIdentityInterface * @return void */ function equals(SecurityIdentityInterface $identity); -}
\ No newline at end of file +} diff --git a/Acl/Model/SecurityIdentityRetrievalStrategyInterface.php b/Acl/Model/SecurityIdentityRetrievalStrategyInterface.php index 3353be4..3bbbaa4 100644 --- a/Acl/Model/SecurityIdentityRetrievalStrategyInterface.php +++ b/Acl/Model/SecurityIdentityRetrievalStrategyInterface.php @@ -31,4 +31,4 @@ interface SecurityIdentityRetrievalStrategyInterface * @return array of SecurityIdentityInterface implementations */ function getSecurityIdentities(TokenInterface $token); -}
\ No newline at end of file +} diff --git a/Acl/Permission/BasicPermissionMap.php b/Acl/Permission/BasicPermissionMap.php index 18006ff..b2bcf65 100644 --- a/Acl/Permission/BasicPermissionMap.php +++ b/Acl/Permission/BasicPermissionMap.php @@ -84,10 +84,10 @@ class BasicPermissionMap implements PermissionMapInterface /** * {@inheritDoc} */ - public function getMasks($permission) + public function getMasks($permission, $object) { if (!isset($this->map[$permission])) { - throw new \InvalidArgumentException(sprintf('The permission "%s" is not supported by this implementation.', $permission)); + return null; } return $this->map[$permission]; @@ -100,4 +100,4 @@ class BasicPermissionMap implements PermissionMapInterface { return isset($this->map[$permission]); } -}
\ No newline at end of file +} diff --git a/Acl/Permission/MaskBuilder.php b/Acl/Permission/MaskBuilder.php index 9965228..f7a6a3a 100644 --- a/Acl/Permission/MaskBuilder.php +++ b/Acl/Permission/MaskBuilder.php @@ -92,7 +92,7 @@ class MaskBuilder */ public function add($mask) { - if (is_string($mask) && defined($name = 'self::MASK_'.strtoupper($mask))) { + if (is_string($mask) && defined($name = 'static::MASK_'.strtoupper($mask))) { $mask = constant($name); } else if (!is_int($mask)) { throw new \InvalidArgumentException('$mask must be an integer.'); @@ -145,7 +145,7 @@ class MaskBuilder */ public function remove($mask) { - if (is_string($mask) && defined($name = 'self::MASK_'.strtoupper($mask))) { + if (is_string($mask) && defined($name = 'static::MASK_'.strtoupper($mask))) { $mask = constant($name); } else if (!is_int($mask)) { throw new \InvalidArgumentException('$mask must be an integer.'); @@ -176,7 +176,7 @@ class MaskBuilder * @throws \RuntimeException * @return string */ - public static function getCode($mask) + static public function getCode($mask) { if (!is_int($mask)) { throw new \InvalidArgumentException('$mask must be an integer.'); @@ -189,7 +189,7 @@ class MaskBuilder } if ($mask === $cMask) { - if (!defined($cName = 'self::CODE_'.substr($name, 5))) { + if (!defined($cName = 'static::CODE_'.substr($name, 5))) { throw new \RuntimeException('There was no code defined for this mask.'); } @@ -199,4 +199,4 @@ class MaskBuilder throw new \InvalidArgumentException(sprintf('The mask "%d" is not supported.', $mask)); } -}
\ No newline at end of file +} diff --git a/Acl/Permission/PermissionMapInterface.php b/Acl/Permission/PermissionMapInterface.php index bc4ca08..c2e49d5 100644 --- a/Acl/Permission/PermissionMapInterface.php +++ b/Acl/Permission/PermissionMapInterface.php @@ -25,9 +25,10 @@ interface PermissionMapInterface * these bitmasks. * * @param string $permission - * @return array + * @param object $object + * @return array may return null if permission/object combination is not supported */ - function getMasks($permission); + function getMasks($permission, $object); /** * Whether this map contains the given permission @@ -36,4 +37,4 @@ interface PermissionMapInterface * @return Boolean */ function contains($permission); -}
\ No newline at end of file +} diff --git a/Acl/Resources/bin/generateSql.php b/Acl/Resources/bin/generateSql.php index 68094eb..dc247d4 100644 --- a/Acl/Resources/bin/generateSql.php +++ b/Acl/Resources/bin/generateSql.php @@ -1,5 +1,14 @@ <?php +/* + * This file is part of the Symfony framework. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + require_once __DIR__.'/../../../../ClassLoader/UniversalClassLoader.php'; use Symfony\Component\ClassLoader\UniversalClassLoader; @@ -30,7 +39,7 @@ $finder = new Finder(); $finder->name('*Platform.php')->in(dirname($reflection->getFileName())); foreach ($finder as $file) { require_once $file->getPathName(); - $className = 'Doctrine\\DBAL\\Platforms\\' . $file->getBasename('.php'); + $className = 'Doctrine\\DBAL\\Platforms\\'.$file->getBasename('.php'); $reflection = new ReflectionClass($className); if ($reflection->isAbstract()) { diff --git a/Acl/Voter/AclVoter.php b/Acl/Voter/AclVoter.php index 140628c..574b5c2 100644 --- a/Acl/Voter/AclVoter.php +++ b/Acl/Voter/AclVoter.php @@ -57,36 +57,29 @@ class AclVoter implements VoterInterface public function vote(TokenInterface $token, $object, array $attributes) { - $firstCall = true; foreach ($attributes as $attribute) { - if (!$this->supportsAttribute($attribute)) { + if (null === $masks = $this->permissionMap->getMasks($attribute, $object)) { continue; } - if ($firstCall) { - $firstCall = false; - - if (null === $object) { - 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; - } else if ($object instanceof FieldVote) { - $field = $object->getField(); - $object = $object->getDomainObject(); - } else { - $field = null; + if (null === $object) { + if (null !== $this->logger) { + $this->logger->debug(sprintf('Object identity unavailable. Voting to %s', $this->allowIfObjectIdentityUnavailable? 'grant access' : 'abstain')); } - if ($object instanceof ObjectIdentityInterface) { - $oid = $object; - } else if (null === $oid = $this->objectIdentityRetrievalStrategy->getObjectIdentity($object)) { - 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; + } else if ($object instanceof FieldVote) { + $field = $object->getField(); + $object = $object->getDomainObject(); + } else { + $field = null; + } - return $this->allowIfObjectIdentityUnavailable ? self::ACCESS_GRANTED : self::ACCESS_ABSTAIN; + if ($object instanceof ObjectIdentityInterface) { + $oid = $object; + } else if (null === $oid = $this->objectIdentityRetrievalStrategy->getObjectIdentity($object)) { + if (null !== $this->logger) { + $this->logger->debug(sprintf('Object identity unavailable. Voting to %s', $this->allowIfObjectIdentityUnavailable? 'grant access' : 'abstain')); } if (!$this->supportsClass($oid->getType())) { @@ -95,25 +88,20 @@ class AclVoter implements VoterInterface $sids = $this->securityIdentityRetrievalStrategy->getSecurityIdentities($token); - try { - $acl = $this->aclProvider->findAcl($oid, $sids); - } catch (AclNotFoundException $noAcl) { - if (null !== $this->logger) { - $this->logger->debug('No ACL found for the object identity. Voting to deny access.'); - } - - return self::ACCESS_DENIED; - } + return $this->allowIfObjectIdentityUnavailable ? self::ACCESS_GRANTED : self::ACCESS_ABSTAIN; } + $sids = $this->securityIdentityRetrievalStrategy->getSecurityIdentities($token); try { - if (null === $field && $acl->isGranted($this->permissionMap->getMasks($attribute), $sids, false)) { + $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; - } else if (null !== $field && $acl->isFieldGranted($field, $this->permissionMap->getMasks($attribute), $sids, false)) { + } else if (null !== $field && $acl->isFieldGranted($field, $masks, $sids, false)) { if (null !== $this->logger) { $this->logger->debug('ACL found, permission granted. Voting to grant access'); } @@ -126,6 +114,12 @@ class AclVoter implements VoterInterface } return self::ACCESS_DENIED; + } catch (AclNotFoundException $noAcl) { + if (null !== $this->logger) { + $this->logger->debug('No ACL found for the object identity. Voting to deny access.'); + } + + return self::ACCESS_DENIED; } catch (NoAceFoundException $noAce) { if (null !== $this->logger) { $this->logger->debug('ACL found, no ACE applicable. Voting to deny access.'); diff --git a/Acl/Voter/FieldVote.php b/Acl/Voter/FieldVote.php index 01f0c20..8782f76 100644 --- a/Acl/Voter/FieldVote.php +++ b/Acl/Voter/FieldVote.php @@ -37,4 +37,4 @@ class FieldVote { return $this->field; } -}
\ No newline at end of file +} diff --git a/Core/Authentication/Provider/AnonymousAuthenticationProvider.php b/Core/Authentication/Provider/AnonymousAuthenticationProvider.php index c48a27e..ea91075 100644 --- a/Core/Authentication/Provider/AnonymousAuthenticationProvider.php +++ b/Core/Authentication/Provider/AnonymousAuthenticationProvider.php @@ -43,7 +43,7 @@ class AnonymousAuthenticationProvider implements AuthenticationProviderInterface return null; } - if ($this->key != $token->getKey()) { + if ($this->key !== $token->getKey()) { throw new BadCredentialsException('The Token does not contain the expected key.'); } diff --git a/Core/Authentication/Provider/RememberMeAuthenticationProvider.php b/Core/Authentication/Provider/RememberMeAuthenticationProvider.php index 940288b..fb687b2 100644 --- a/Core/Authentication/Provider/RememberMeAuthenticationProvider.php +++ b/Core/Authentication/Provider/RememberMeAuthenticationProvider.php @@ -1,4 +1,14 @@ <?php + +/* + * This file is part of the Symfony framework. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + namespace Symfony\Component\Security\Core\Authentication\Provider; use Symfony\Component\Security\Core\User\UserCheckerInterface; @@ -43,4 +53,4 @@ class RememberMeAuthenticationProvider implements AuthenticationProviderInterfac { return $token instanceof RememberMeToken && $token->getProviderKey() === $this->providerKey; } -}
\ No newline at end of file +} diff --git a/Core/Authentication/RememberMe/InMemoryTokenProvider.php b/Core/Authentication/RememberMe/InMemoryTokenProvider.php index c432b0e..4653900 100644 --- a/Core/Authentication/RememberMe/InMemoryTokenProvider.php +++ b/Core/Authentication/RememberMe/InMemoryTokenProvider.php @@ -1,5 +1,14 @@ <?php +/* + * This file is part of the Symfony framework. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + namespace Symfony\Component\Security\Core\Authentication\RememberMe; use Symfony\Component\Security\Core\Exception\TokenNotFoundException; @@ -47,4 +56,4 @@ class InMemoryTokenProvider implements TokenProviderInterface { $this->tokens[$token->getSeries()] = $token; } -}
\ No newline at end of file +} diff --git a/Core/Authentication/RememberMe/PersistentToken.php b/Core/Authentication/RememberMe/PersistentToken.php index 55e6b89..d9029f5 100644 --- a/Core/Authentication/RememberMe/PersistentToken.php +++ b/Core/Authentication/RememberMe/PersistentToken.php @@ -104,4 +104,4 @@ final class PersistentToken implements PersistentTokenInterface { return $this->lastUsed; } -}
\ No newline at end of file +} diff --git a/Core/Authentication/RememberMe/PersistentTokenInterface.php b/Core/Authentication/RememberMe/PersistentTokenInterface.php index fe1db51..004a9b7 100644 --- a/Core/Authentication/RememberMe/PersistentTokenInterface.php +++ b/Core/Authentication/RememberMe/PersistentTokenInterface.php @@ -20,6 +20,12 @@ namespace Symfony\Component\Security\Core\Authentication\RememberMe; interface PersistentTokenInterface { /** + * Returns the class of the user + * @return string + */ + function getClass(); + + /** * Returns the username * @return string */ @@ -42,4 +48,4 @@ interface PersistentTokenInterface * @return \DateTime */ function getLastUsed(); -}
\ No newline at end of file +} diff --git a/Core/Authentication/RememberMe/TokenProviderInterface.php b/Core/Authentication/RememberMe/TokenProviderInterface.php index 1ec9c80..b48bd4d 100644 --- a/Core/Authentication/RememberMe/TokenProviderInterface.php +++ b/Core/Authentication/RememberMe/TokenProviderInterface.php @@ -48,4 +48,4 @@ interface TokenProviderInterface * @param PersistentTokenInterface $token */ function createNewToken(PersistentTokenInterface $token); -}
\ No newline at end of file +} diff --git a/Core/Authentication/Token/RememberMeToken.php b/Core/Authentication/Token/RememberMeToken.php index 7978427..81ab1c2 100644 --- a/Core/Authentication/Token/RememberMeToken.php +++ b/Core/Authentication/Token/RememberMeToken.php @@ -27,8 +27,8 @@ class RememberMeToken extends AbstractToken * Constructor. * * @param UserInterface $user - * @param string $providerKey - * @param string $key + * @param string $providerKey + * @param string $key */ public function __construct(UserInterface $user, $providerKey, $key) { parent::__construct($user->getRoles()); @@ -92,4 +92,4 @@ class RememberMeToken extends AbstractToken list($this->key, $this->providerKey, $parentStr) = unserialize($serialized); parent::unserialize($parentStr); } -}
\ No newline at end of file +} diff --git a/Core/Encoder/EncoderFactory.php b/Core/Encoder/EncoderFactory.php index d6441d9..d7ae32d 100644 --- a/Core/Encoder/EncoderFactory.php +++ b/Core/Encoder/EncoderFactory.php @@ -66,4 +66,4 @@ class EncoderFactory implements EncoderFactoryInterface return $reflection->newInstanceArgs($config['arguments']); } -}
\ No newline at end of file +} diff --git a/Core/Encoder/EncoderFactoryInterface.php b/Core/Encoder/EncoderFactoryInterface.php index 62cc9aa..811c262 100644 --- a/Core/Encoder/EncoderFactoryInterface.php +++ b/Core/Encoder/EncoderFactoryInterface.php @@ -27,4 +27,4 @@ interface EncoderFactoryInterface * @return PasswordEncoderInterface never null */ function getEncoder(UserInterface $user); -}
\ No newline at end of file +} diff --git a/Core/Exception/CookieTheftException.php b/Core/Exception/CookieTheftException.php index 83e61d7..09ec79e 100644 --- a/Core/Exception/CookieTheftException.php +++ b/Core/Exception/CookieTheftException.php @@ -19,4 +19,4 @@ namespace Symfony\Component\Security\Core\Exception; */ class CookieTheftException extends AuthenticationException { -}
\ No newline at end of file +} diff --git a/Core/Exception/InvalidCsrfTokenException.php b/Core/Exception/InvalidCsrfTokenException.php index f19bcbf..51adb69 100644 --- a/Core/Exception/InvalidCsrfTokenException.php +++ b/Core/Exception/InvalidCsrfTokenException.php @@ -1,5 +1,14 @@ <?php +/* + * This file is part of the Symfony framework. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + namespace Symfony\Component\Security\Core\Exception; /** @@ -9,4 +18,4 @@ namespace Symfony\Component\Security\Core\Exception; */ class InvalidCsrfTokenException extends AuthenticationException { -}
\ No newline at end of file +} diff --git a/Core/Exception/SessionUnavailableException.php b/Core/Exception/SessionUnavailableException.php new file mode 100644 index 0000000..a00a503 --- /dev/null +++ b/Core/Exception/SessionUnavailableException.php @@ -0,0 +1,27 @@ +<?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\Core\Exception; + +/** + * This exception is thrown when no session is available. + * + * Possible reasons for this are: + * + * a) The session timed-out because the user waited too long. + * b) The user has disabled cookies, and a new session is started on each + * request. + * + * @author Johannes M. Schmitt <schmittjoh@gmail.com> + */ +class SessionUnavailableException extends AuthenticationException +{ +} diff --git a/Core/Exception/UnsupportedUserException.php b/Core/Exception/UnsupportedUserException.php index 5be9bc4..6529fa9 100644 --- a/Core/Exception/UnsupportedUserException.php +++ b/Core/Exception/UnsupportedUserException.php @@ -19,4 +19,4 @@ namespace Symfony\Component\Security\Core\Exception; */ class UnsupportedUserException extends AuthenticationServiceException { -}
\ No newline at end of file +} diff --git a/Core/SecurityContextInterface.php b/Core/SecurityContextInterface.php index 41815fb..d57c409 100644 --- a/Core/SecurityContextInterface.php +++ b/Core/SecurityContextInterface.php @@ -1,5 +1,14 @@ <?php +/* + * This file is part of the Symfony framework. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + namespace Symfony\Component\Security\Core; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; @@ -38,4 +47,4 @@ interface SecurityContextInterface * @return Boolean */ function isGranted($attributes, $object = null); -}
\ No newline at end of file +} diff --git a/Core/User/ChainUserProvider.php b/Core/User/ChainUserProvider.php index 6417f99..e6aca32 100644 --- a/Core/User/ChainUserProvider.php +++ b/Core/User/ChainUserProvider.php @@ -1,5 +1,14 @@ <?php +/* + * This file is part of the Symfony framework. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + namespace Symfony\Component\Security\Core\User; use Symfony\Component\Security\Core\Exception\UnsupportedUserException; @@ -41,11 +50,11 @@ class ChainUserProvider implements UserProviderInterface /** * {@inheritDoc} */ - public function loadUser(UserInterface $user) + public function refreshUser(UserInterface $user) { foreach ($this->providers as $provider) { try { - return $provider->loadUser($user); + return $provider->refreshUser($user); } catch (UnsupportedUserException $unsupported) { // try next one } @@ -67,4 +76,4 @@ class ChainUserProvider implements UserProviderInterface return false; } -}
\ No newline at end of file +} diff --git a/Core/User/EntityUserProvider.php b/Core/User/EntityUserProvider.php deleted file mode 100644 index 61dd708..0000000 --- a/Core/User/EntityUserProvider.php +++ /dev/null @@ -1,85 +0,0 @@ -<?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\Core\User; - -use Doctrine\ORM\EntityManager; -use Symfony\Component\Security\Core\Exception\UnsupportedUserException; -use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; - -/** - * Wrapper around a Doctrine EntityManager. - * - * Provides easy to use provisioning for Doctrine entity users. - * - * @author Fabien Potencier <fabien@symfony.com> - * @author Johannes M. Schmitt <schmittjoh@gmail.com> - */ -class EntityUserProvider implements UserProviderInterface -{ - private $class; - private $repository; - private $property; - - public function __construct(EntityManager $em, $class, $property = null) - { - $this->class = $class; - - if (false !== strpos($this->class, ':')) { - $this->class = $em->getClassMetadata($class)->name; - } - - $this->repository = $em->getRepository($class); - $this->property = $property; - } - - /** - * {@inheritdoc} - */ - public function loadUserByUsername($username) - { - if (null !== $this->property) { - $user = $this->repository->findOneBy(array($this->property => $username)); - } else { - if (!$this->repository instanceof UserProviderInterface) { - throw new \InvalidArgumentException(sprintf('The Doctrine repository "%s" must implement UserProviderInterface.', get_class($this->repository))); - } - - $user = $this->repository->loadUserByUsername($username); - } - - if (null === $user) { - throw new UsernameNotFoundException(sprintf('User "%s" not found.', $username)); - } - - return $user; - } - - /** - * {@inheritDoc} - */ - public function loadUser(UserInterface $user) - { - if (!$user instanceof $this->class) { - throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user))); - } - - return $this->loadUserByUsername($user->getUsername()); - } - - /** - * {@inheritDoc} - */ - public function supportsClass($class) - { - return $class === $this->class; - } -} diff --git a/Core/User/InMemoryUserProvider.php b/Core/User/InMemoryUserProvider.php index e73eb95..eae2083 100644 --- a/Core/User/InMemoryUserProvider.php +++ b/Core/User/InMemoryUserProvider.php @@ -78,7 +78,7 @@ class InMemoryUserProvider implements UserProviderInterface /** * {@inheritDoc} */ - public function loadUser(UserInterface $user) + public function refreshUser(UserInterface $user) { if (!$user instanceof User) { throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user))); diff --git a/Core/User/UserProviderInterface.php b/Core/User/UserProviderInterface.php index 79be191..11fd62c 100644 --- a/Core/User/UserProviderInterface.php +++ b/Core/User/UserProviderInterface.php @@ -33,7 +33,7 @@ interface UserProviderInterface function loadUserByUsername($username); /** - * Loads the user for the account interface. + * Refreshes the user for the account interface. * * It is up to the implementation if it decides to reload the user data * from the database, or if it simply merges the passed User into the @@ -44,7 +44,7 @@ interface UserProviderInterface * * @return UserInterface */ - function loadUser(UserInterface $user); + function refreshUser(UserInterface $user); /** * Whether this provider supports the given user class @@ -54,4 +54,4 @@ interface UserProviderInterface * @return Boolean */ function supportsClass($class); -}
\ No newline at end of file +} diff --git a/Http/Authentication/AuthenticationFailureHandlerInterface.php b/Http/Authentication/AuthenticationFailureHandlerInterface.php index 5b619bc..d5d0067 100644 --- a/Http/Authentication/AuthenticationFailureHandlerInterface.php +++ b/Http/Authentication/AuthenticationFailureHandlerInterface.php @@ -1,5 +1,14 @@ <?php +/* + * This file is part of the Symfony framework. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + namespace Symfony\Component\Security\Http\Authentication; use Symfony\Component\Security\Core\Exception\AuthenticationException; @@ -27,4 +36,4 @@ interface AuthenticationFailureHandlerInterface * @return Response the response to return */ function onAuthenticationFailure(Request $request, AuthenticationException $exception); -}
\ No newline at end of file +} diff --git a/Http/Authentication/AuthenticationSuccessHandlerInterface.php b/Http/Authentication/AuthenticationSuccessHandlerInterface.php index 4cdd976..3d7c561 100644 --- a/Http/Authentication/AuthenticationSuccessHandlerInterface.php +++ b/Http/Authentication/AuthenticationSuccessHandlerInterface.php @@ -1,5 +1,14 @@ <?php +/* + * This file is part of the Symfony framework. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + namespace Symfony\Component\Security\Http\Authentication; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; @@ -27,4 +36,4 @@ interface AuthenticationSuccessHandlerInterface * @return Response the response to return */ function onAuthenticationSuccess(Request $request, TokenInterface $token); -}
\ No newline at end of file +} diff --git a/Http/Authorization/AccessDeniedHandlerInterface.php b/Http/Authorization/AccessDeniedHandlerInterface.php index 42ac266..798e611 100644 --- a/Http/Authorization/AccessDeniedHandlerInterface.php +++ b/Http/Authorization/AccessDeniedHandlerInterface.php @@ -1,5 +1,14 @@ <?php +/* + * This file is part of the Symfony framework. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + namespace Symfony\Component\Security\Http\Authorization; use Symfony\Component\HttpFoundation\Request; diff --git a/Http/EntryPoint/BasicAuthenticationEntryPoint.php b/Http/EntryPoint/BasicAuthenticationEntryPoint.php index 4f13c90..6ba3872 100644 --- a/Http/EntryPoint/BasicAuthenticationEntryPoint.php +++ b/Http/EntryPoint/BasicAuthenticationEntryPoint.php @@ -34,7 +34,7 @@ class BasicAuthenticationEntryPoint implements AuthenticationEntryPointInterface { $response = new Response(); $response->headers->set('WWW-Authenticate', sprintf('Basic realm="%s"', $this->realmName)); - $response->setStatusCode(401, $authException->getMessage()); + $response->setStatusCode(401, $authException ? $authException->getMessage() : null); return $response; } diff --git a/Http/EntryPoint/DigestAuthenticationEntryPoint.php b/Http/EntryPoint/DigestAuthenticationEntryPoint.php index e422cb0..66f1e42 100644 --- a/Http/EntryPoint/DigestAuthenticationEntryPoint.php +++ b/Http/EntryPoint/DigestAuthenticationEntryPoint.php @@ -57,7 +57,7 @@ class DigestAuthenticationEntryPoint implements AuthenticationEntryPointInterfac $response = new Response(); $response->headers->set('WWW-Authenticate', $authenticateHeader); - $response->setStatusCode(401, $authException->getMessage()); + $response->setStatusCode(401, $authException ? $authException->getMessage() : null); return $response; } diff --git a/Http/EntryPoint/FormAuthenticationEntryPoint.php b/Http/EntryPoint/FormAuthenticationEntryPoint.php index 12f077f..2170e9e 100644 --- a/Http/EntryPoint/FormAuthenticationEntryPoint.php +++ b/Http/EntryPoint/FormAuthenticationEntryPoint.php @@ -12,10 +12,9 @@ namespace Symfony\Component\Security\Http\EntryPoint; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; +use Symfony\Component\Security\Http\HttpUtils; use Symfony\Component\HttpKernel\HttpKernelInterface; /** @@ -28,17 +27,20 @@ class FormAuthenticationEntryPoint implements AuthenticationEntryPointInterface private $loginPath; private $useForward; private $httpKernel; + private $httpUtils; /** * Constructor * * @param HttpKernelInterface $kernel + * @param HttpUtils $httpUtils An HttpUtils instance * @param string $loginPath The path to the login form * @param Boolean $useForward Whether to forward or redirect to the login form */ - public function __construct(HttpKernelInterface $kernel, $loginPath, $useForward = false) + public function __construct(HttpKernelInterface $kernel, HttpUtils $httpUtils, $loginPath, $useForward = false) { $this->httpKernel = $kernel; + $this->httpUtils = $httpUtils; $this->loginPath = $loginPath; $this->useForward = (Boolean) $useForward; } @@ -49,9 +51,11 @@ class FormAuthenticationEntryPoint implements AuthenticationEntryPointInterface public function start(Request $request, AuthenticationException $authException = null) { if ($this->useForward) { - return $this->httpKernel->handle(Request::create($this->loginPath), HttpKernelInterface::SUB_REQUEST); + $subRequest = $this->httpUtils->createRequest($request, $this->loginPath); + + return $this->httpKernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST); } - return new RedirectResponse(0 !== strpos($this->loginPath, 'http') ? $request->getUriForPath($this->loginPath) : $this->loginPath, 302); + return $this->httpUtils->createRedirectResponse($request, $this->loginPath); } } diff --git a/Http/EntryPoint/RetryAuthenticationEntryPoint.php b/Http/EntryPoint/RetryAuthenticationEntryPoint.php index cb549e6..12ba538 100644 --- a/Http/EntryPoint/RetryAuthenticationEntryPoint.php +++ b/Http/EntryPoint/RetryAuthenticationEntryPoint.php @@ -40,7 +40,7 @@ class RetryAuthenticationEntryPoint implements AuthenticationEntryPointInterface $scheme = $request->isSecure() ? 'http' : 'https'; if ('http' === $scheme && 80 != $this->httpPort) { $port = ':'.$this->httpPort; - } elseif ('https' === $scheme && 443 != $this->httpPort) { + } elseif ('https' === $scheme && 443 != $this->httpsPort) { $port = ':'.$this->httpsPort; } else { $port = ''; diff --git a/Http/Event/InteractiveLoginEvent.php b/Http/Event/InteractiveLoginEvent.php index 1d16cb6..f242501 100644 --- a/Http/Event/InteractiveLoginEvent.php +++ b/Http/Event/InteractiveLoginEvent.php @@ -36,4 +36,4 @@ class InteractiveLoginEvent extends Event { return $this->authenticationToken; } -}
\ No newline at end of file +} diff --git a/Http/Event/SwitchUserEvent.php b/Http/Event/SwitchUserEvent.php index 03ca003..4a7dcaf 100644 --- a/Http/Event/SwitchUserEvent.php +++ b/Http/Event/SwitchUserEvent.php @@ -36,4 +36,4 @@ class SwitchUserEvent extends Event { return $this->targetUser; } -}
\ No newline at end of file +} diff --git a/Http/Firewall.php b/Http/Firewall.php index 774303d..9d05f86 100644 --- a/Http/Firewall.php +++ b/Http/Firewall.php @@ -30,7 +30,6 @@ class Firewall { private $map; private $dispatcher; - private $currentListeners; /** * Constructor. @@ -42,7 +41,6 @@ class Firewall { $this->map = $map; $this->dispatcher = $dispatcher; - $this->currentListeners = array(); } /** @@ -50,7 +48,7 @@ class Firewall * * @param GetResponseEvent $event An GetResponseEvent instance */ - public function onCoreRequest(GetResponseEvent $event) + public function onKernelRequest(GetResponseEvent $event) { if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) { return; diff --git a/Http/Firewall/AbstractAuthenticationListener.php b/Http/Firewall/AbstractAuthenticationListener.php index 2b2db40..f5969d8 100644 --- a/Http/Firewall/AbstractAuthenticationListener.php +++ b/Http/Firewall/AbstractAuthenticationListener.php @@ -18,17 +18,17 @@ use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface; use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; +use Symfony\Component\Security\Core\Exception\SessionUnavailableException; use Symfony\Component\HttpKernel\Log\LoggerInterface; use Symfony\Component\HttpKernel\HttpKernelInterface; -use Symfony\Component\HttpKernel\Events as KernelEvents; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Security\Http\Event\InteractiveLoginEvent; -use Symfony\Component\Security\Http\Events; +use Symfony\Component\Security\Http\SecurityEvents; +use Symfony\Component\Security\Http\HttpUtils; /** * The AbstractAuthenticationListener is the preferred base class for all @@ -59,17 +59,24 @@ abstract class AbstractAuthenticationListener implements ListenerInterface private $successHandler; private $failureHandler; private $rememberMeServices; + private $httpUtils; /** * Constructor. * - * @param SecurityContextInterface $securityContext A SecurityContext instance - * @param AuthenticationManagerInterface $authenticationManager An AuthenticationManagerInterface instance - * @param array $options An array of options for the processing of a successful, or failed authentication attempt - * @param LoggerInterface $logger A LoggerInterface instance - * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance + * @param SecurityContextInterface $securityContext A SecurityContext instance + * @param AuthenticationManagerInterface $authenticationManager An AuthenticationManagerInterface instance + * @param SessionAuthenticationStrategyInterface $sessionStrategy + * @param HttpUtils $httpUtils An HttpUtilsInterface instance + * @param string $providerKey + * @param array $options An array of options for the processing of a + * successful, or failed authentication attempt + * @param AuthenticationSuccessHandlerInterface $successHandler + * @param AuthenticationFailureHandlerInterface $failureHandler + * @param LoggerInterface $logger A LoggerInterface instance + * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance */ - public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, $providerKey, array $options = array(), AuthenticationSuccessHandlerInterface $successHandler = null, AuthenticationFailureHandlerInterface $failureHandler = null, LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null) + public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, array $options = array(), AuthenticationSuccessHandlerInterface $successHandler = null, AuthenticationFailureHandlerInterface $failureHandler = null, LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null) { if (empty($providerKey)) { throw new \InvalidArgumentException('$providerKey must not be empty.'); @@ -93,6 +100,7 @@ abstract class AbstractAuthenticationListener implements ListenerInterface ), $options); $this->logger = $logger; $this->dispatcher = $dispatcher; + $this->httpUtils = $httpUtils; } /** @@ -118,7 +126,15 @@ abstract class AbstractAuthenticationListener implements ListenerInterface return; } + if (!$request->hasSession()) { + throw new \RuntimeException('This authentication method requires a session.'); + } + try { + if (!$request->hasPreviousSession()) { + throw new SessionUnavailableException('Your session has timed-out, or you have disabled cookies.'); + } + if (null === $returnValue = $this->attemptAuthentication($request)) { return; } @@ -152,7 +168,7 @@ abstract class AbstractAuthenticationListener implements ListenerInterface */ protected function requiresAuthentication(Request $request) { - return $this->options['check_path'] === $request->getPathInfo(); + return $this->httpUtils->checkRequestPath($request, $this->options['check_path']); } /** @@ -169,7 +185,7 @@ abstract class AbstractAuthenticationListener implements ListenerInterface private function onFailure(GetResponseEvent $event, Request $request, AuthenticationException $failed) { if (null !== $this->logger) { - $this->logger->debug(sprintf('Authentication request failed: %s', $failed->getMessage())); + $this->logger->info(sprintf('Authentication request failed: %s', $failed->getMessage())); } $this->securityContext->setToken(null); @@ -187,7 +203,7 @@ abstract class AbstractAuthenticationListener implements ListenerInterface $this->logger->debug(sprintf('Forwarding to %s', $this->options['failure_path'])); } - $subRequest = Request::create($this->options['failure_path']); + $subRequest = $this->httpUtils->createRequest($request, $this->options['failure_path']); $subRequest->attributes->set(SecurityContextInterface::AUTHENTICATION_ERROR, $failed); return $event->getKernel()->handle($subRequest, HttpKernelInterface::SUB_REQUEST); @@ -199,13 +215,13 @@ abstract class AbstractAuthenticationListener implements ListenerInterface $request->getSession()->set(SecurityContextInterface::AUTHENTICATION_ERROR, $failed); - return new RedirectResponse(0 !== strpos($this->options['failure_path'], 'http') ? $request->getUriForPath($this->options['failure_path']) : $this->options['failure_path'], 302); + return $this->httpUtils->createRedirectResponse($request, $this->options['failure_path']); } private function onSuccess(GetResponseEvent $event, Request $request, TokenInterface $token) { if (null !== $this->logger) { - $this->logger->debug('User has been authenticated successfully'); + $this->logger->info(sprintf('User "%s" has been authenticated successfully', $token->getUsername())); } $this->securityContext->setToken($token); @@ -216,14 +232,13 @@ abstract class AbstractAuthenticationListener implements ListenerInterface if (null !== $this->dispatcher) { $loginEvent = new InteractiveLoginEvent($request, $token); - $this->dispatcher->dispatch(Events::onSecurityInteractiveLogin, $loginEvent); + $this->dispatcher->dispatch(SecurityEvents::INTERACTIVE_LOGIN, $loginEvent); } if (null !== $this->successHandler) { $response = $this->successHandler->onAuthenticationSuccess($request, $token); } else { - $path = $this->determineTargetUrl($request); - $response = new RedirectResponse(0 !== strpos($path, 'http') ? $request->getUriForPath($path) : $path, 302); + $response = $this->httpUtils->createRedirectResponse($request, $this->determineTargetUrl($request)); } if (null !== $this->rememberMeServices) { diff --git a/Http/Firewall/AbstractPreAuthenticatedListener.php b/Http/Firewall/AbstractPreAuthenticatedListener.php index 88faa27..66d0ea1 100644 --- a/Http/Firewall/AbstractPreAuthenticatedListener.php +++ b/Http/Firewall/AbstractPreAuthenticatedListener.php @@ -16,9 +16,8 @@ use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterfac use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Http\Event\InteractiveLoginEvent; -use Symfony\Component\Security\Http\Events; +use Symfony\Component\Security\Http\SecurityEvents; use Symfony\Component\HttpKernel\Event\GetResponseEvent; -use Symfony\Component\HttpKernel\Events as KernelEvents; use Symfony\Component\HttpKernel\Log\LoggerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\EventDispatcher\EventDispatcherInterface; @@ -76,19 +75,19 @@ abstract class AbstractPreAuthenticatedListener implements ListenerInterface $token = $this->authenticationManager->authenticate(new PreAuthenticatedToken($user, $credentials, $this->providerKey)); if (null !== $this->logger) { - $this->logger->debug(sprintf('Authentication success: %s', $token)); + $this->logger->info(sprintf('Authentication success: %s', $token)); } $this->securityContext->setToken($token); if (null !== $this->dispatcher) { $loginEvent = new InteractiveLoginEvent($request, $token); - $this->dispatcher->dispatch(Events::onSecurityInteractiveLogin, $loginEvent); + $this->dispatcher->dispatch(SecurityEvents::INTERACTIVE_LOGIN, $loginEvent); } } catch (AuthenticationException $failed) { $this->securityContext->setToken(null); if (null !== $this->logger) { - $this->logger->debug(sprintf("Cleared security context due to exception: %s", $failed->getMessage())); + $this->logger->info(sprintf("Cleared security context due to exception: %s", $failed->getMessage())); } } } diff --git a/Http/Firewall/AccessListener.php b/Http/Firewall/AccessListener.php index bbcd932..877b6c3 100644 --- a/Http/Firewall/AccessListener.php +++ b/Http/Firewall/AccessListener.php @@ -11,13 +11,12 @@ namespace Symfony\Component\Security\Http\Firewall; -use Symfony\Component\Security\Core\SecurityContext; +use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface; use Symfony\Component\Security\Http\AccessMap; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; use Symfony\Component\HttpKernel\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; -use Symfony\Component\HttpKernel\Events; use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException; use Symfony\Component\Security\Core\Exception\AccessDeniedException; @@ -34,7 +33,7 @@ class AccessListener implements ListenerInterface private $authManager; private $logger; - public function __construct(SecurityContext $context, AccessDecisionManagerInterface $accessDecisionManager, AccessMap $map, AuthenticationManagerInterface $authManager, LoggerInterface $logger = null) + public function __construct(SecurityContextInterface $context, AccessDecisionManagerInterface $accessDecisionManager, AccessMap $map, AuthenticationManagerInterface $authManager, LoggerInterface $logger = null) { $this->context = $context; $this->accessDecisionManager = $accessDecisionManager; diff --git a/Http/Firewall/AnonymousAuthenticationListener.php b/Http/Firewall/AnonymousAuthenticationListener.php index 36cf878..d00865d 100644 --- a/Http/Firewall/AnonymousAuthenticationListener.php +++ b/Http/Firewall/AnonymousAuthenticationListener.php @@ -14,7 +14,6 @@ namespace Symfony\Component\Security\Http\Firewall; use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\HttpKernel\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; -use Symfony\Component\HttpKernel\Events; use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken; /** @@ -50,7 +49,7 @@ class AnonymousAuthenticationListener implements ListenerInterface $this->context->setToken(new AnonymousToken($this->key, 'anon.', array())); if (null !== $this->logger) { - $this->logger->debug(sprintf('Populated SecurityContext with an anonymous Token')); + $this->logger->info(sprintf('Populated SecurityContext with an anonymous Token')); } } } diff --git a/Http/Firewall/BasicAuthenticationListener.php b/Http/Firewall/BasicAuthenticationListener.php index d35d8d5..9669853 100644 --- a/Http/Firewall/BasicAuthenticationListener.php +++ b/Http/Firewall/BasicAuthenticationListener.php @@ -16,7 +16,6 @@ use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterfac use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; use Symfony\Component\HttpKernel\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; -use Symfony\Component\HttpKernel\Events; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\Exception\AuthenticationException; @@ -68,7 +67,7 @@ class BasicAuthenticationListener implements ListenerInterface } if (null !== $this->logger) { - $this->logger->debug(sprintf('Basic Authentication Authorization header found for user "%s"', $username)); + $this->logger->info(sprintf('Basic Authentication Authorization header found for user "%s"', $username)); } try { @@ -78,7 +77,7 @@ class BasicAuthenticationListener implements ListenerInterface $this->securityContext->setToken(null); if (null !== $this->logger) { - $this->logger->debug(sprintf('Authentication request failed: %s', $failed->getMessage())); + $this->logger->info(sprintf('Authentication request failed for user "%s": %s', $username, $failed->getMessage())); } if ($this->ignoreFailure) { diff --git a/Http/Firewall/ChannelListener.php b/Http/Firewall/ChannelListener.php index 1677a02..847753f 100644 --- a/Http/Firewall/ChannelListener.php +++ b/Http/Firewall/ChannelListener.php @@ -15,7 +15,6 @@ use Symfony\Component\Security\Http\AccessMap; use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; use Symfony\Component\HttpKernel\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; -use Symfony\Component\HttpKernel\Events; /** * ChannelListener switches the HTTP protocol based on the access control @@ -49,7 +48,7 @@ class ChannelListener implements ListenerInterface if ('https' === $channel && !$request->isSecure()) { if (null !== $this->logger) { - $this->logger->debug('Redirecting to HTTPS'); + $this->logger->info('Redirecting to HTTPS'); } $response = $this->authenticationEntryPoint->start($request); @@ -61,7 +60,7 @@ class ChannelListener implements ListenerInterface if ('http' === $channel && $request->isSecure()) { if (null !== $this->logger) { - $this->logger->debug('Redirecting to HTTP'); + $this->logger->info('Redirecting to HTTP'); } $response = $this->authenticationEntryPoint->start($request); diff --git a/Http/Firewall/ContextListener.php b/Http/Firewall/ContextListener.php index 331a1e3..6fb77e9 100644 --- a/Http/Firewall/ContextListener.php +++ b/Http/Firewall/ContextListener.php @@ -16,7 +16,7 @@ use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\Event\FilterResponseEvent; -use Symfony\Component\HttpKernel\Events; +use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; @@ -47,9 +47,10 @@ class ContextListener implements ListenerInterface $this->context = $context; $this->userProviders = $userProviders; $this->contextKey = $contextKey; + $this->logger = $logger; if (null !== $dispatcher) { - $dispatcher->addListener(Events::onCoreResponse, $this); + $dispatcher->addListener(KernelEvents::RESPONSE, array($this, 'onKernelResponse')); } } @@ -86,7 +87,7 @@ class ContextListener implements ListenerInterface * * @param FilterResponseEvent $event A FilterResponseEvent instance */ - public function onCoreResponse(FilterResponseEvent $event) + public function onKernelResponse(FilterResponseEvent $event) { if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) { return; @@ -127,7 +128,7 @@ class ContextListener implements ListenerInterface foreach ($this->userProviders as $provider) { try { - $token->setUser($provider->loadUser($user)); + $token->setUser($provider->refreshUser($user)); if (null !== $this->logger) { $this->logger->debug(sprintf('Username "%s" was reloaded from user provider.', $user->getUsername())); @@ -138,7 +139,7 @@ class ContextListener implements ListenerInterface // let's try the next user provider } catch (UsernameNotFoundException $notFound) { if (null !== $this->logger) { - $this->logger->debug(sprintf('Username "%s" could not be found.', $user->getUsername())); + $this->logger->warn(sprintf('Username "%s" could not be found.', $user->getUsername())); } return null; diff --git a/Http/Firewall/DigestAuthenticationListener.php b/Http/Firewall/DigestAuthenticationListener.php index 867899e..5c529da 100644 --- a/Http/Firewall/DigestAuthenticationListener.php +++ b/Http/Firewall/DigestAuthenticationListener.php @@ -16,7 +16,6 @@ use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\Security\Http\EntryPoint\DigestAuthenticationEntryPoint; use Symfony\Component\HttpKernel\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; -use Symfony\Component\HttpKernel\Events; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\Exception\BadCredentialsException; use Symfony\Component\Security\Core\Exception\AuthenticationServiceException; @@ -115,7 +114,7 @@ class DigestAuthenticationListener implements ListenerInterface } if (null !== $this->logger) { - $this->logger->debug(sprintf('Authentication success for user "%s" with response "%s"', $digestAuth->getUsername(), $digestAuth->getResponse())); + $this->logger->info(sprintf('Authentication success for user "%s" with response "%s"', $digestAuth->getUsername(), $digestAuth->getResponse())); } $this->securityContext->setToken(new UsernamePasswordToken($user, $user->getPassword(), $this->providerKey)); @@ -126,7 +125,7 @@ class DigestAuthenticationListener implements ListenerInterface $this->securityContext->setToken(null); if (null !== $this->logger) { - $this->logger->debug($authException); + $this->logger->info($authException); } $event->setResponse($this->authenticationEntryPoint->start($request, $authException)); diff --git a/Http/Firewall/ExceptionListener.php b/Http/Firewall/ExceptionListener.php index 4840a63..46ffde8 100644 --- a/Http/Firewall/ExceptionListener.php +++ b/Http/Firewall/ExceptionListener.php @@ -16,15 +16,17 @@ use Symfony\Component\Security\Http\Authorization\AccessDeniedHandlerInterface; use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface; use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; -use Symfony\Component\HttpKernel\Log\LoggerInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken; use Symfony\Component\Security\Core\Exception\InsufficientAuthenticationException; +use Symfony\Component\Security\Http\HttpUtils; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Log\LoggerInterface; use Symfony\Component\HttpKernel\HttpKernelInterface; -use Symfony\Component\HttpKernel\Events; +use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** @@ -41,11 +43,13 @@ class ExceptionListener private $authenticationTrustResolver; private $errorPage; private $logger; + private $httpUtils; - public function __construct(SecurityContextInterface $context, AuthenticationTrustResolverInterface $trustResolver, AuthenticationEntryPointInterface $authenticationEntryPoint = null, $errorPage = null, AccessDeniedHandlerInterface $accessDeniedHandler = null, LoggerInterface $logger = null) + public function __construct(SecurityContextInterface $context, AuthenticationTrustResolverInterface $trustResolver, HttpUtils $httpUtils, AuthenticationEntryPointInterface $authenticationEntryPoint = null, $errorPage = null, AccessDeniedHandlerInterface $accessDeniedHandler = null, LoggerInterface $logger = null) { $this->context = $context; $this->accessDeniedHandler = $accessDeniedHandler; + $this->httpUtils = $httpUtils; $this->authenticationEntryPoint = $authenticationEntryPoint; $this->authenticationTrustResolver = $trustResolver; $this->errorPage = $errorPage; @@ -53,13 +57,13 @@ class ExceptionListener } /** - * Registers a onCoreException listener to take care of security exceptions. + * Registers a onKernelException listener to take care of security exceptions. * * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance */ public function register(EventDispatcherInterface $dispatcher) { - $dispatcher->addListener(Events::onCoreException, $this); + $dispatcher->addListener(KernelEvents::EXCEPTION, array($this, 'onKernelException')); } /** @@ -67,11 +71,16 @@ class ExceptionListener * * @param GetResponseForExceptionEvent $event An GetResponseForExceptionEvent instance */ - public function onCoreException(GetResponseForExceptionEvent $event) + public function onKernelException(GetResponseForExceptionEvent $event) { $exception = $event->getException(); $request = $event->getRequest(); + // determine the actual cause for the exception + while (null !== $previous = $exception->getPrevious()) { + $exception = $previous; + } + if ($exception instanceof AuthenticationException) { if (null !== $this->logger) { $this->logger->info(sprintf('Authentication exception occurred; redirecting to authentication entry point (%s)', $exception->getMessage())); @@ -88,7 +97,7 @@ class ExceptionListener $token = $this->context->getToken(); if (!$this->authenticationTrustResolver->isFullFledged($token)) { if (null !== $this->logger) { - $this->logger->info('Access denied (user is not fully authenticated); redirecting to authentication entry point'); + $this->logger->debug('Access denied (user is not fully authenticated); redirecting to authentication entry point'); } try { @@ -100,7 +109,7 @@ class ExceptionListener } } else { if (null !== $this->logger) { - $this->logger->info('Access is denied (and user is neither anonymous, nor remember-me)'); + $this->logger->debug('Access is denied (and user is neither anonymous, nor remember-me)'); } try { @@ -110,16 +119,16 @@ class ExceptionListener if (!$response instanceof Response) { return; } - } else { - if (null === $this->errorPage) { - return; - } - - $subRequest = Request::create($this->errorPage); + } elseif (null !== $this->errorPage) { + $subRequest = $this->httpUtils->createRequest($request, $this->errorPage); $subRequest->attributes->set(SecurityContextInterface::ACCESS_DENIED_ERROR, $exception); $response = $event->getKernel()->handle($subRequest, HttpKernelInterface::SUB_REQUEST, true); $response->setStatusCode(403); + } else { + $event->setException(new AccessDeniedHttpException($exception->getMessage(), $exception)); + + return; } } catch (\Exception $e) { if (null !== $this->logger) { @@ -140,8 +149,6 @@ class ExceptionListener private function startAuthentication(Request $request, AuthenticationException $authException) { - $this->context->setToken(null); - if (null === $this->authenticationEntryPoint) { throw $authException; } diff --git a/Http/Firewall/ListenerInterface.php b/Http/Firewall/ListenerInterface.php index 9d5084e..822f641 100644 --- a/Http/Firewall/ListenerInterface.php +++ b/Http/Firewall/ListenerInterface.php @@ -27,4 +27,4 @@ interface ListenerInterface * @param GetResponseEvent $event */ function handle(GetResponseEvent $event); -}
\ No newline at end of file +} diff --git a/Http/Firewall/LogoutListener.php b/Http/Firewall/LogoutListener.php index 8ff9c8b..06454a3 100644 --- a/Http/Firewall/LogoutListener.php +++ b/Http/Firewall/LogoutListener.php @@ -15,10 +15,10 @@ use Symfony\Component\Security\Http\Logout\LogoutSuccessHandlerInterface; use Symfony\Component\Security\Http\Logout\LogoutHandlerInterface; use Symfony\Component\Security\Core\SecurityContextInterface; +use Symfony\Component\Security\Http\HttpUtils; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpKernel\Event\GetResponseEvent; -use Symfony\Component\HttpKernel\Events; /** * LogoutListener logout users. @@ -32,18 +32,21 @@ class LogoutListener implements ListenerInterface private $targetUrl; private $handlers; private $successHandler; + private $httpUtils; /** * Constructor * * @param SecurityContextInterface $securityContext - * @param string $logoutPath The path that starts the logout process - * @param string $targetUrl The URL to redirect to after logout + * @param HttpUtils $httpUtils An HttpUtilsInterface instance + * @param string $logoutPath The path that starts the logout process + * @param string $targetUrl The URL to redirect to after logout * @param LogoutSuccessHandlerInterface $successHandler */ - public function __construct(SecurityContextInterface $securityContext, $logoutPath, $targetUrl = '/', LogoutSuccessHandlerInterface $successHandler = null) + public function __construct(SecurityContextInterface $securityContext, HttpUtils $httpUtils, $logoutPath, $targetUrl = '/', LogoutSuccessHandlerInterface $successHandler = null) { $this->securityContext = $securityContext; + $this->httpUtils = $httpUtils; $this->logoutPath = $logoutPath; $this->targetUrl = $targetUrl; $this->successHandler = $successHandler; @@ -70,7 +73,7 @@ class LogoutListener implements ListenerInterface { $request = $event->getRequest(); - if ($this->logoutPath !== $request->getPathInfo()) { + if (!$this->httpUtils->checkRequestPath($request, $this->logoutPath)) { return; } @@ -81,7 +84,7 @@ class LogoutListener implements ListenerInterface throw new \RuntimeException('Logout Success Handler did not return a Response.'); } } else { - $response = new RedirectResponse(0 !== strpos($this->targetUrl, 'http') ? $request->getUriForPath($this->targetUrl) : $this->targetUrl, 302); + $response = $this->httpUtils->createRedirectResponse($request, $this->targetUrl); } // handle multiple logout attempts gracefully diff --git a/Http/Firewall/RememberMeListener.php b/Http/Firewall/RememberMeListener.php index 10ed8c6..0b3bc78 100644 --- a/Http/Firewall/RememberMeListener.php +++ b/Http/Firewall/RememberMeListener.php @@ -6,7 +6,6 @@ use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\Event\FilterResponseEvent; -use Symfony\Component\HttpKernel\Events as KernelEvents; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; @@ -15,7 +14,7 @@ use Symfony\Component\Security\Core\Exception\CookieTheftException; use Symfony\Component\Security\Core\SecurityContext; use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface; use Symfony\Component\Security\Http\Event\InteractiveLoginEvent; -use Symfony\Component\Security\Http\Events; +use Symfony\Component\Security\Http\SecurityEvents; use Symfony\Component\EventDispatcher\EventDispatcherInterface; /* @@ -80,7 +79,7 @@ class RememberMeListener implements ListenerInterface if (null !== $this->dispatcher) { $loginEvent = new InteractiveLoginEvent($request, $token); - $this->dispatcher->dispatch(Events::onSecurityInteractiveLogin, $loginEvent); + $this->dispatcher->dispatch(SecurityEvents::INTERACTIVE_LOGIN, $loginEvent); } if (null !== $this->logger) { @@ -88,7 +87,7 @@ class RememberMeListener implements ListenerInterface } } catch (AuthenticationException $failed) { if (null !== $this->logger) { - $this->logger->debug( + $this->logger->warn( 'SecurityContext not populated with remember-me token as the' .' AuthenticationManager rejected the AuthenticationToken returned' .' by the RememberMeServices: '.$failed->getMessage() @@ -98,4 +97,4 @@ class RememberMeListener implements ListenerInterface $this->rememberMeServices->loginFail($request); } } -}
\ No newline at end of file +} diff --git a/Http/Firewall/SwitchUserListener.php b/Http/Firewall/SwitchUserListener.php index 0977cb1..8e45508 100644 --- a/Http/Firewall/SwitchUserListener.php +++ b/Http/Firewall/SwitchUserListener.php @@ -27,7 +27,7 @@ use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Http\Event\SwitchUserEvent; -use Symfony\Component\Security\Http\Events; +use Symfony\Component\Security\Http\SecurityEvents; use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** @@ -88,7 +88,7 @@ class SwitchUserListener implements ListenerInterface $this->securityContext->setToken($this->attemptSwitchUser($request)); } catch (AuthenticationException $e) { if (null !== $this->logger) { - $this->logger->debug(sprintf('Switch User failed: "%s"', $e->getMessage())); + $this->logger->warn(sprintf('Switch User failed: "%s"', $e->getMessage())); } } } @@ -120,7 +120,7 @@ class SwitchUserListener implements ListenerInterface $username = $request->get($this->usernameParameter); if (null !== $this->logger) { - $this->logger->debug(sprintf('Attempt to switch to user "%s"', $username)); + $this->logger->info(sprintf('Attempt to switch to user "%s"', $username)); } $user = $this->provider->loadUserByUsername($username); @@ -133,7 +133,7 @@ class SwitchUserListener implements ListenerInterface if (null !== $this->dispatcher) { $switchEvent = new SwitchUserEvent($request, $token->getUser()); - $this->dispatcher->dispatch(Events::onSecuritySwitchUser, $switchEvent); + $this->dispatcher->dispatch(SecurityEvents::SWITCH_USER, $switchEvent); } return $token; @@ -154,7 +154,7 @@ class SwitchUserListener implements ListenerInterface if (null !== $this->dispatcher) { $switchEvent = new SwitchUserEvent($request, $original->getUser()); - $this->dispatcher->dispatch(Events::onSecuritySwitchUser, $switchEvent); + $this->dispatcher->dispatch(SecurityEvents::SWITCH_USER, $switchEvent); } return $original; diff --git a/Http/Firewall/UsernamePasswordFormAuthenticationListener.php b/Http/Firewall/UsernamePasswordFormAuthenticationListener.php index 4ad456c..bd2cec1 100644 --- a/Http/Firewall/UsernamePasswordFormAuthenticationListener.php +++ b/Http/Firewall/UsernamePasswordFormAuthenticationListener.php @@ -17,6 +17,7 @@ use Symfony\Component\HttpKernel\Log\LoggerInterface; use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface; use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface; use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface; +use Symfony\Component\Security\Http\HttpUtils; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException; @@ -36,13 +37,13 @@ class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationL /** * {@inheritdoc} */ - public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, $providerKey, array $options = array(), AuthenticationSuccessHandlerInterface $successHandler = null, AuthenticationFailureHandlerInterface $failureHandler = null, LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfProviderInterface $csrfProvider = null) + public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, array $options = array(), AuthenticationSuccessHandlerInterface $successHandler = null, AuthenticationFailureHandlerInterface $failureHandler = null, LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfProviderInterface $csrfProvider = null) { - parent::__construct($securityContext, $authenticationManager, $sessionStrategy, $providerKey, array_merge(array( + parent::__construct($securityContext, $authenticationManager, $sessionStrategy, $httpUtils, $providerKey, array_merge(array( 'username_parameter' => '_username', 'password_parameter' => '_password', 'csrf_parameter' => '_csrf_token', - 'csrf_page_id' => 'form_login', + 'intention' => 'authenticate', 'post_only' => true, ), $options), $successHandler, $failureHandler, $logger, $dispatcher); @@ -63,9 +64,9 @@ class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationL } if (null !== $this->csrfProvider) { - $csrfToken = $request->get($this->options['csrf_parameter']); + $csrfToken = $request->get($this->options['csrf_parameter'], null, true); - if (false === $this->csrfProvider->isCsrfTokenValid($this->options['csrf_page_id'], $csrfToken)) { + if (false === $this->csrfProvider->isCsrfTokenValid($this->options['intention'], $csrfToken)) { throw new InvalidCsrfTokenException('Invalid CSRF token.'); } } @@ -77,4 +78,4 @@ class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationL return $this->authenticationManager->authenticate(new UsernamePasswordToken($username, $password, $this->providerKey)); } -}
\ No newline at end of file +} diff --git a/Http/FirewallMapInterface.php b/Http/FirewallMapInterface.php index 575b96f..99bac06 100644 --- a/Http/FirewallMapInterface.php +++ b/Http/FirewallMapInterface.php @@ -1,5 +1,14 @@ <?php +/* + * This file is part of the Symfony framework. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + namespace Symfony\Component\Security\Http; use Symfony\Component\HttpFoundation\Request; @@ -25,4 +34,4 @@ interface FirewallMapInterface * @return array of the format array(array(AuthenticationListener), ExceptionListener) */ function getListeners(Request $request); -}
\ No newline at end of file +} diff --git a/Http/HttpUtils.php b/Http/HttpUtils.php new file mode 100644 index 0000000..a293538 --- /dev/null +++ b/Http/HttpUtils.php @@ -0,0 +1,145 @@ +<?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\Http; + +use Symfony\Component\Security\Core\SecurityContextInterface; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RedirectResponse; +use Symfony\Component\Routing\RouterInterface; + +/** + * Encapsulates the logic needed to create sub-requests, redirect the user, and match URLs. + * + * @author Fabien Potencier <fabien@symfony.com> + */ +class HttpUtils +{ + private $router; + + /** + * Constructor. + * + * @param RouterInterface $router An RouterInterface instance + */ + public function __construct(RouterInterface $router = null) + { + $this->router = $router; + } + + /** + * Creates a redirect Response. + * + * @param Request $request A Request instance + * @param string $path A path (an absolute path (/foo), an absolute URL (http://...), or a route name (foo)) + * @param integer $status The status code + * + * @return Response A RedirectResponse instance + */ + public function createRedirectResponse(Request $request, $path, $status = 302) + { + if ('/' === $path[0]) { + $path = $request->getUriForPath($path); + } elseif (0 !== strpos($path, 'http')) { + $this->resetLocale($request); + $path = $this->generateUrl($path, true); + } + + return new RedirectResponse($path, $status); + } + + /** + * Creates a Request. + * + * @param Request $request The current Request instance + * @param string $path A path (an absolute path (/foo), an absolute URL (http://...), or a route name (foo)) + * + * @return Request A Request instance + */ + public function createRequest(Request $request, $path) + { + if ($path && '/' !== $path[0] && 0 !== strpos($path, 'http')) { + $this->resetLocale($request); + $path = $this->generateUrl($path, true); + } + + $newRequest = Request::create($path, 'get', array(), $request->cookies->all(), array(), $request->server->all()); + if ($session = $request->getSession()) { + $newRequest->setSession($session); + } + + if ($request->attributes->has(SecurityContextInterface::AUTHENTICATION_ERROR)) { + $newRequest->attributes->set(SecurityContextInterface::AUTHENTICATION_ERROR, $request->attributes->get(SecurityContextInterface::AUTHENTICATION_ERROR)); + } + if ($request->attributes->has(SecurityContextInterface::ACCESS_DENIED_ERROR)) { + $newRequest->attributes->set(SecurityContextInterface::ACCESS_DENIED_ERROR, $request->attributes->get(SecurityContextInterface::ACCESS_DENIED_ERROR)); + } + if ($request->attributes->has(SecurityContextInterface::LAST_USERNAME)) { + $newRequest->attributes->set(SecurityContextInterface::LAST_USERNAME, $request->attributes->get(SecurityContextInterface::LAST_USERNAME)); + } + + return $newRequest; + } + + /** + * Checks that a given path matches the Request. + * + * @param Request $request A Request instance + * @param string $path A path (an absolute path (/foo), an absolute URL (http://...), or a route name (foo)) + * + * @return Boolean true if the path is the same as the one from the Request, false otherwise + */ + public function checkRequestPath(Request $request, $path) + { + if ('/' !== $path[0]) { + try { + $parameters = $this->router->match($request->getPathInfo()); + + return $path === $parameters['_route']; + } catch (\Exception $e) { + return false; + } + } + + return $path === $request->getPathInfo(); + } + + // hack (don't have a better solution for now) + private function resetLocale(Request $request) + { + $context = $this->router->getContext(); + if ($context->getParameter('_locale')) { + return; + } + + try { + $parameters = $this->router->match($request->getPathInfo()); + + if (isset($parameters['_locale'])) { + $context->setParameter('_locale', $parameters['_locale']); + } elseif ($session = $request->getSession()) { + $context->setParameter('_locale', $session->getLocale()); + } + } catch (\Exception $e) { + // let's hope user doesn't use the locale in the path + } + } + + private function generateUrl($route, $absolute = false) + { + if (null === $this->router) { + throw new \LogicException('You must provide a RouterInterface instance to be able to use routes.'); + } + + return $this->router->generate($route, array(), $absolute); + } +} diff --git a/Http/Logout/LogoutHandlerInterface.php b/Http/Logout/LogoutHandlerInterface.php index e3f0995..6d5c519 100644 --- a/Http/Logout/LogoutHandlerInterface.php +++ b/Http/Logout/LogoutHandlerInterface.php @@ -33,4 +33,4 @@ interface LogoutHandlerInterface * @return void */ function logout(Request $request, Response $response, TokenInterface $token); -}
\ No newline at end of file +} diff --git a/Http/Logout/LogoutSuccessHandlerInterface.php b/Http/Logout/LogoutSuccessHandlerInterface.php index e3e80bc..5592771 100644 --- a/Http/Logout/LogoutSuccessHandlerInterface.php +++ b/Http/Logout/LogoutSuccessHandlerInterface.php @@ -1,5 +1,14 @@ <?php +/* + * This file is part of the Symfony framework. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + namespace Symfony\Component\Security\Http\Logout; use Symfony\Component\HttpFoundation\Request; @@ -25,4 +34,4 @@ interface LogoutSuccessHandlerInterface * @return Response never null */ function onLogoutSuccess(Request $request); -}
\ No newline at end of file +} diff --git a/Http/Logout/SessionLogoutHandler.php b/Http/Logout/SessionLogoutHandler.php index bfb5ecd..9fd49d1 100644 --- a/Http/Logout/SessionLogoutHandler.php +++ b/Http/Logout/SessionLogoutHandler.php @@ -34,4 +34,4 @@ class SessionLogoutHandler implements LogoutHandlerInterface { $request->getSession()->invalidate(); } -}
\ No newline at end of file +} diff --git a/Http/RememberMe/AbstractRememberMeServices.php b/Http/RememberMe/AbstractRememberMeServices.php index a7c63ef..2118a86 100644 --- a/Http/RememberMe/AbstractRememberMeServices.php +++ b/Http/RememberMe/AbstractRememberMeServices.php @@ -112,7 +112,7 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface } if (null !== $this->logger) { - $this->logger->debug('Remember-me cookie accepted.'); + $this->logger->info('Remember-me cookie accepted.'); } return new RememberMeToken($user, $this->providerKey, $this->key); @@ -122,11 +122,11 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface throw $theft; } catch (UsernameNotFoundException $notFound) { if (null !== $this->logger) { - $this->logger->debug('User for remember-me cookie not found.'); + $this->logger->info('User for remember-me cookie not found.'); } } catch (UnsupportedUserException $unSupported) { if (null !== $this->logger) { - $this->logger->debug('User class for remember-me cookie not supported.'); + $this->logger->warn('User class for remember-me cookie not supported.'); } } catch (AuthenticationException $invalid) { if (null !== $this->logger) { @@ -285,7 +285,7 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface return true; } - $parameter = $request->request->get($this->options['remember_me_parameter']); + $parameter = $request->request->get($this->options['remember_me_parameter'], null, true); if ($parameter === null && null !== $this->logger) { $this->logger->debug(sprintf('Did not send remember-me cookie (remember-me parameter "%s" was not sent).', $this->options['remember_me_parameter'])); diff --git a/Http/RememberMe/PersistentTokenBasedRememberMeServices.php b/Http/RememberMe/PersistentTokenBasedRememberMeServices.php index f2a0249..eb622a4 100644 --- a/Http/RememberMe/PersistentTokenBasedRememberMeServices.php +++ b/Http/RememberMe/PersistentTokenBasedRememberMeServices.php @@ -150,4 +150,4 @@ class PersistentTokenBasedRememberMeServices extends AbstractRememberMeServices return base64_encode(hash('sha512', uniqid(mt_rand(), true), true)); } -}
\ No newline at end of file +} diff --git a/Http/RememberMe/RememberMeServicesInterface.php b/Http/RememberMe/RememberMeServicesInterface.php index 5c56c18..c6b0ada 100644 --- a/Http/RememberMe/RememberMeServicesInterface.php +++ b/Http/RememberMe/RememberMeServicesInterface.php @@ -80,4 +80,4 @@ interface RememberMeServicesInterface * @return void */ function loginSuccess(Request $request, Response $response, TokenInterface $token); -}
\ No newline at end of file +} diff --git a/Http/Events.php b/Http/SecurityEvents.php index c0aa65d..a6c4e42 100644 --- a/Http/Events.php +++ b/Http/SecurityEvents.php @@ -11,9 +11,9 @@ namespace Symfony\Component\Security\Http; -final class Events +final class SecurityEvents { - const onSecurityInteractiveLogin = 'onSecurityInteractiveLogin'; + const INTERACTIVE_LOGIN = 'security.interactive_login'; - const onSecuritySwitchUser = 'onSecuritySwitchUser'; -}
\ No newline at end of file + const SWITCH_USER = 'security.switch_user'; +} diff --git a/Http/Session/SessionAuthenticationStrategy.php b/Http/Session/SessionAuthenticationStrategy.php index dea34be..7e0c20a 100644 --- a/Http/Session/SessionAuthenticationStrategy.php +++ b/Http/Session/SessionAuthenticationStrategy.php @@ -1,5 +1,14 @@ <?php +/* + * This file is part of the Symfony framework. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + namespace Symfony\Component\Security\Http\Session; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; @@ -39,14 +48,16 @@ class SessionAuthenticationStrategy implements SessionAuthenticationStrategyInte case self::MIGRATE: $request->getSession()->migrate(); + return; case self::INVALIDATE: $request->getSession()->invalidate(); + return; default: throw new \RuntimeException(sprintf('Invalid session authentication strategy "%s"', $this->strategy)); } } -}
\ No newline at end of file +} diff --git a/Http/Session/SessionAuthenticationStrategyInterface.php b/Http/Session/SessionAuthenticationStrategyInterface.php index b248fd7..54924ac 100644 --- a/Http/Session/SessionAuthenticationStrategyInterface.php +++ b/Http/Session/SessionAuthenticationStrategyInterface.php @@ -1,5 +1,14 @@ <?php +/* + * This file is part of the Symfony framework. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * This source file is subject to the MIT license that is bundled + * with this source code in the file LICENSE. + */ + namespace Symfony\Component\Security\Http\Session; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; @@ -27,4 +36,4 @@ interface SessionAuthenticationStrategyInterface * @return void */ function onAuthentication(Request $request, TokenInterface $token); -}
\ No newline at end of file +} |