diff options
257 files changed, 9192 insertions, 1392 deletions
diff --git a/Acl/.gitignore b/Acl/.gitignore new file mode 100644 index 0000000..c49a5d8 --- /dev/null +++ b/Acl/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/Acl/Dbal/AclProvider.php b/Acl/Dbal/AclProvider.php index bba5824..6709023 100644 --- a/Acl/Dbal/AclProvider.php +++ b/Acl/Dbal/AclProvider.php @@ -206,7 +206,8 @@ class AclProvider implements AclProviderInterface foreach ($oids as $oid) { if (!$result->contains($oid)) { if (1 === count($oids)) { - throw new AclNotFoundException(sprintf('No ACL found for %s.', $oid)); + $objectName = method_exists($oid, '__toString') ? $oid : get_class($oid); + throw new AclNotFoundException(sprintf('No ACL found for %s.', $objectName)); } $partialResultException = new NotAllAclsFoundException('The provider could not find ACLs for all object identities.'); @@ -296,7 +297,8 @@ SELECTCLAUSE; if (1 === count($types)) { $ids = array(); for ($i = 0; $i < $count; ++$i) { - $ids[] = $this->connection->quote($batch[$i]->getIdentifier()); + $identifier = (string) $batch[$i]->getIdentifier(); + $ids[] = $this->connection->quote($identifier); } $sql .= sprintf( @@ -339,17 +341,17 @@ SELECTCLAUSE; $query = <<<FINDCHILDREN SELECT o.object_identifier, c.class_type FROM - {$this->options['oid_table_name']} as o - INNER JOIN {$this->options['class_table_name']} as c ON c.id = o.class_id - INNER JOIN {$this->options['oid_ancestors_table_name']} as a ON a.object_identity_id = o.id + {$this->options['oid_table_name']} o + INNER JOIN {$this->options['class_table_name']} c ON c.id = o.class_id + INNER JOIN {$this->options['oid_ancestors_table_name']} a ON a.object_identity_id = o.id WHERE a.ancestor_id = %d AND a.object_identity_id != a.ancestor_id FINDCHILDREN; } else { $query = <<<FINDCHILDREN SELECT o.object_identifier, c.class_type - FROM {$this->options['oid_table_name']} as o - INNER JOIN {$this->options['class_table_name']} as c ON c.id = o.class_id + FROM {$this->options['oid_table_name']} o + INNER JOIN {$this->options['class_table_name']} c ON c.id = o.class_id WHERE o.parent_object_identity_id = %d FINDCHILDREN; } @@ -378,8 +380,8 @@ QUERY; $query, $this->options['oid_table_name'], $this->options['class_table_name'], - $this->connection->quote($oid->getIdentifier()), - $this->connection->quote($oid->getType()) + $this->connection->quote((string) $oid->getIdentifier()), + $this->connection->quote((string) $oid->getType()) ); } @@ -435,8 +437,8 @@ QUERY; $ancestorIds = array(); foreach ($this->connection->executeQuery($sql)->fetchAll() as $data) { // FIXME: skip ancestors which are cached - - $ancestorIds[] = $data['ancestor_id']; + // Fix: Oracle returns keys in uppercase + $ancestorIds[] = reset($data); } return $ancestorIds; @@ -542,7 +544,7 @@ QUERY; $auditSuccess, $auditFailure, $username, - $securityIdentifier) = $data; + $securityIdentifier) = array_values($data); // has the ACL been hydrated during this hydration cycle? if (isset($acls[$aclId])) { diff --git a/Acl/Dbal/MutableAclProvider.php b/Acl/Dbal/MutableAclProvider.php index 40ed471..273625a 100644 --- a/Acl/Dbal/MutableAclProvider.php +++ b/Acl/Dbal/MutableAclProvider.php @@ -51,7 +51,8 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf public function createAcl(ObjectIdentityInterface $oid) { if (false !== $this->retrieveObjectIdentityPrimaryKey($oid)) { - throw new AclAlreadyExistsException(sprintf('%s is already associated with an ACL.', $oid)); + $objectName = method_exists($oid, '__toString') ? $oid : get_class($oid); + throw new AclAlreadyExistsException(sprintf('%s is already associated with an ACL.', $objectName)); } $this->connection->beginTransaction(); @@ -109,6 +110,19 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf } /** + * Deletes the security identity from the database. + * ACL entries have the CASCADE option on their foreign key so they will also get deleted. + * + * @param SecurityIdentityInterface $sid + * + * @throws \InvalidArgumentException + */ + public function deleteSecurityIdentity(SecurityIdentityInterface $sid) + { + $this->connection->executeQuery($this->getDeleteSecurityIdentityIdSql($sid)); + } + + /** * {@inheritdoc} */ public function findAcls(array $oids, array $sids = array()) @@ -352,6 +366,17 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf } /** + * Updates a user security identity when the user's username changes. + * + * @param UserSecurityIdentity $usid + * @param string $oldUsername + */ + public function updateUserSecurityIdentity(UserSecurityIdentity $usid, $oldUsername) + { + $this->connection->executeQuery($this->getUpdateUserSecurityIdentitySql($usid, $oldUsername)); + } + + /** * Constructs the SQL for deleting access control entries. * * @param int $oidPK @@ -626,6 +651,23 @@ QUERY; } /** + * Constructs the SQL to delete a security identity. + * + * @param SecurityIdentityInterface $sid + * + * @throws \InvalidArgumentException + * + * @return string + */ + protected function getDeleteSecurityIdentityIdSql(SecurityIdentityInterface $sid) + { + $select = $this->getSelectSecurityIdentityIdSql($sid); + $delete = preg_replace('/^SELECT id FROM/', 'DELETE FROM', $select); + + return $delete; + } + + /** * Constructs the SQL for updating an object identity. * * @param int $pk @@ -650,6 +692,32 @@ QUERY; } /** + * Constructs the SQL for updating a user security identity. + * + * @param UserSecurityIdentity $usid + * @param string $oldUsername + * + * @return string + */ + protected function getUpdateUserSecurityIdentitySql(UserSecurityIdentity $usid, $oldUsername) + { + if ($usid->getUsername() == $oldUsername) { + throw new \InvalidArgumentException('There are no changes.'); + } + + $oldIdentifier = $usid->getClass().'-'.$oldUsername; + $newIdentifier = $usid->getClass().'-'.$usid->getUsername(); + + return sprintf( + 'UPDATE %s SET identifier = %s WHERE identifier = %s AND username = %s', + $this->options['sid_table_name'], + $this->connection->quote($newIdentifier), + $this->connection->quote($oldIdentifier), + $this->connection->getDatabasePlatform()->convertBooleans(true) + ); + } + + /** * Constructs the SQL for updating an ACE. * * @param int $pk diff --git a/Acl/Domain/Acl.php b/Acl/Domain/Acl.php index 365fc37..fb70738 100644 --- a/Acl/Domain/Acl.php +++ b/Acl/Domain/Acl.php @@ -38,14 +38,14 @@ class Acl implements AuditableAclInterface, NotifyPropertyChanged private $parentAcl; private $permissionGrantingStrategy; private $objectIdentity; - private $classAces; - private $classFieldAces; - private $objectAces; - private $objectFieldAces; + private $classAces = array(); + private $classFieldAces = array(); + private $objectAces = array(); + private $objectFieldAces = array(); private $id; private $loadedSids; private $entriesInheriting; - private $listeners; + private $listeners = array(); /** * Constructor. @@ -56,19 +56,13 @@ class Acl implements AuditableAclInterface, NotifyPropertyChanged * @param array $loadedSids * @param bool $entriesInheriting */ - public function __construct($id, ObjectIdentityInterface $objectIdentity, PermissionGrantingStrategyInterface $permissionGrantingStrategy, array $loadedSids = array(), $entriesInheriting) + public function __construct($id, ObjectIdentityInterface $objectIdentity, PermissionGrantingStrategyInterface $permissionGrantingStrategy, array $loadedSids, $entriesInheriting) { $this->id = $id; $this->objectIdentity = $objectIdentity; $this->permissionGrantingStrategy = $permissionGrantingStrategy; $this->loadedSids = $loadedSids; $this->entriesInheriting = $entriesInheriting; - $this->parentAcl = null; - $this->classAces = array(); - $this->classFieldAces = array(); - $this->objectAces = array(); - $this->objectFieldAces = array(); - $this->listeners = array(); } /** diff --git a/Acl/Exception/Exception.php b/Acl/Exception/Exception.php index a38c8ee..f1e1001 100644 --- a/Acl/Exception/Exception.php +++ b/Acl/Exception/Exception.php @@ -16,6 +16,6 @@ namespace Symfony\Component\Security\Acl\Exception; * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ -class Exception extends \Exception +class Exception extends \RuntimeException { } diff --git a/Acl/LICENSE b/Acl/LICENSE new file mode 100644 index 0000000..12a7453 --- /dev/null +++ b/Acl/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2004-2016 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Acl/Permission/AbstractMaskBuilder.php b/Acl/Permission/AbstractMaskBuilder.php new file mode 100644 index 0000000..93f1755 --- /dev/null +++ b/Acl/Permission/AbstractMaskBuilder.php @@ -0,0 +1,85 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Acl\Permission; + +/** + * This abstract class implements nearly all the MaskBuilderInterface methods. + */ +abstract class AbstractMaskBuilder implements MaskBuilderInterface +{ + /** + * @var int + */ + protected $mask; + + /** + * Constructor. + * + * @param int $mask optional; defaults to 0 + */ + public function __construct($mask = 0) + { + $this->set($mask); + } + + /** + * {@inheritdoc} + */ + public function set($mask) + { + if (!is_int($mask)) { + throw new \InvalidArgumentException('$mask must be an integer.'); + } + + $this->mask = $mask; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function get() + { + return $this->mask; + } + + /** + * {@inheritdoc} + */ + public function add($mask) + { + $this->mask |= $this->resolveMask($mask); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function remove($mask) + { + $this->mask &= ~$this->resolveMask($mask); + + return $this; + } + + /** + * {@inheritdoc} + */ + public function reset() + { + $this->mask = 0; + + return $this; + } +} diff --git a/Acl/Permission/BasicPermissionMap.php b/Acl/Permission/BasicPermissionMap.php index 4e26c02..fa5437d 100644 --- a/Acl/Permission/BasicPermissionMap.php +++ b/Acl/Permission/BasicPermissionMap.php @@ -17,7 +17,7 @@ namespace Symfony\Component\Security\Acl\Permission; * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ -class BasicPermissionMap implements PermissionMapInterface +class BasicPermissionMap implements PermissionMapInterface, MaskBuilderRetrievalInterface { const PERMISSION_VIEW = 'VIEW'; const PERMISSION_EDIT = 'EDIT'; @@ -105,4 +105,12 @@ class BasicPermissionMap implements PermissionMapInterface { return isset($this->map[$permission]); } + + /** + * {@inheritdoc} + */ + public function getMaskBuilder() + { + return new MaskBuilder(); + } } diff --git a/Acl/Permission/MaskBuilder.php b/Acl/Permission/MaskBuilder.php index ca25c70..0b5f388 100644 --- a/Acl/Permission/MaskBuilder.php +++ b/Acl/Permission/MaskBuilder.php @@ -42,7 +42,7 @@ namespace Symfony\Component\Security\Acl\Permission; * * @author Johannes M. Schmitt <schmittjoh@gmail.com> */ -class MaskBuilder +class MaskBuilder extends AbstractMaskBuilder { const MASK_VIEW = 1; // 1 << 0 const MASK_CREATE = 2; // 1 << 1 @@ -67,56 +67,6 @@ class MaskBuilder const OFF = '.'; const ON = '*'; - private $mask; - - /** - * Constructor. - * - * @param int $mask optional; defaults to 0 - * - * @throws \InvalidArgumentException - */ - public function __construct($mask = 0) - { - if (!is_int($mask)) { - throw new \InvalidArgumentException('$mask must be an integer.'); - } - - $this->mask = $mask; - } - - /** - * Adds a mask to the permission. - * - * @param mixed $mask - * - * @return MaskBuilder - * - * @throws \InvalidArgumentException - */ - public function add($mask) - { - if (is_string($mask) && defined($name = 'static::MASK_'.strtoupper($mask))) { - $mask = constant($name); - } elseif (!is_int($mask)) { - throw new \InvalidArgumentException('$mask must be an integer.'); - } - - $this->mask |= $mask; - - return $this; - } - - /** - * Returns the mask of this permission. - * - * @return int - */ - public function get() - { - return $this->mask; - } - /** * Returns a human-readable representation of the permission. * @@ -142,40 +92,6 @@ class MaskBuilder } /** - * Removes a mask from the permission. - * - * @param mixed $mask - * - * @return MaskBuilder - * - * @throws \InvalidArgumentException - */ - public function remove($mask) - { - if (is_string($mask) && defined($name = 'static::MASK_'.strtoupper($mask))) { - $mask = constant($name); - } elseif (!is_int($mask)) { - throw new \InvalidArgumentException('$mask must be an integer.'); - } - - $this->mask &= ~$mask; - - return $this; - } - - /** - * Resets the PermissionBuilder. - * - * @return MaskBuilder - */ - public function reset() - { - $this->mask = 0; - - return $this; - } - - /** * Returns the code for the passed mask. * * @param int $mask @@ -193,19 +109,43 @@ class MaskBuilder $reflection = new \ReflectionClass(get_called_class()); foreach ($reflection->getConstants() as $name => $cMask) { - if (0 !== strpos($name, 'MASK_')) { + if (0 !== strpos($name, 'MASK_') || $mask !== $cMask) { continue; } - if ($mask === $cMask) { - if (!defined($cName = 'static::CODE_'.substr($name, 5))) { - throw new \RuntimeException('There was no code defined for this mask.'); - } - - return constant($cName); + if (!defined($cName = 'static::CODE_'.substr($name, 5))) { + throw new \RuntimeException('There was no code defined for this mask.'); } + + return constant($cName); } throw new \InvalidArgumentException(sprintf('The mask "%d" is not supported.', $mask)); } + + /** + * Returns the mask for the passed code. + * + * @param mixed $code + * + * @return int + * + * @throws \InvalidArgumentException + */ + public function resolveMask($code) + { + if (is_string($code)) { + if (!defined($name = sprintf('static::MASK_%s', strtoupper($code)))) { + throw new \InvalidArgumentException(sprintf('The code "%s" is not supported', $code)); + } + + return constant($name); + } + + if (!is_int($code)) { + throw new \InvalidArgumentException('$code must be an integer.'); + } + + return $code; + } } diff --git a/Acl/Permission/MaskBuilderInterface.php b/Acl/Permission/MaskBuilderInterface.php new file mode 100644 index 0000000..ef183de --- /dev/null +++ b/Acl/Permission/MaskBuilderInterface.php @@ -0,0 +1,76 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Acl\Permission; + +/** + * This is the interface that must be implemented by mask builders. + */ +interface MaskBuilderInterface +{ + /** + * Set the mask of this permission. + * + * @param int $mask + * + * @return MaskBuilderInterface + * + * @throws \InvalidArgumentException if $mask is not an integer + */ + public function set($mask); + + /** + * Returns the mask of this permission. + * + * @return int + */ + public function get(); + + /** + * Adds a mask to the permission. + * + * @param mixed $mask + * + * @return MaskBuilderInterface + * + * @throws \InvalidArgumentException + */ + public function add($mask); + + /** + * Removes a mask from the permission. + * + * @param mixed $mask + * + * @return MaskBuilderInterface + * + * @throws \InvalidArgumentException + */ + public function remove($mask); + + /** + * Resets the PermissionBuilder. + * + * @return MaskBuilderInterface + */ + public function reset(); + + /** + * Returns the mask for the passed code. + * + * @param mixed $code + * + * @return int + * + * @throws \InvalidArgumentException + */ + public function resolveMask($code); +} diff --git a/Acl/Permission/MaskBuilderRetrievalInterface.php b/Acl/Permission/MaskBuilderRetrievalInterface.php new file mode 100644 index 0000000..2cde262 --- /dev/null +++ b/Acl/Permission/MaskBuilderRetrievalInterface.php @@ -0,0 +1,25 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Acl\Permission; + +/** + * Retrieves the MaskBuilder. + */ +interface MaskBuilderRetrievalInterface +{ + /** + * Returns a new instance of the MaskBuilder used in the permissionMap. + * + * @return MaskBuilderInterface + */ + public function getMaskBuilder(); +} diff --git a/Acl/README.md b/Acl/README.md new file mode 100644 index 0000000..a6048fd --- /dev/null +++ b/Acl/README.md @@ -0,0 +1,16 @@ +Security Component - ACL (Access Control List) +============================================== + +Security provides an infrastructure for sophisticated authorization systems, +which makes it possible to easily separate the actual authorization logic from +so called user providers that hold the users credentials. It is inspired by +the Java Spring framework. + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/components/security/index.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/Acl/Resources/schema/drizzle.sql b/Acl/Resources/schema/drizzle.sql index 378f114..9398c29 100644 --- a/Acl/Resources/schema/drizzle.sql +++ b/Acl/Resources/schema/drizzle.sql @@ -1,12 +1,12 @@ -CREATE TABLE acl_classes (id INT AUTO_INCREMENT NOT NULL, class_type VARCHAR(200) NOT NULL, PRIMARY KEY(id), UNIQUE INDEX UNIQ_69DD750638A36066 (class_type)) +CREATE TABLE acl_classes (id INT AUTO_INCREMENT NOT NULL, class_type VARCHAR(200) NOT NULL, UNIQUE INDEX UNIQ_69DD750638A36066 (class_type), PRIMARY KEY(id)) COLLATE utf8_unicode_ci ENGINE = InnoDB -CREATE TABLE acl_security_identities (id INT AUTO_INCREMENT NOT NULL, identifier VARCHAR(200) NOT NULL, username BOOLEAN NOT NULL, PRIMARY KEY(id), UNIQUE INDEX UNIQ_8835EE78772E836AF85E0677 (identifier, username)) +CREATE TABLE acl_security_identities (id INT AUTO_INCREMENT NOT NULL, identifier VARCHAR(200) NOT NULL, username BOOLEAN NOT NULL, UNIQUE INDEX UNIQ_8835EE78772E836AF85E0677 (identifier, username), PRIMARY KEY(id)) COLLATE utf8_unicode_ci ENGINE = InnoDB -CREATE TABLE acl_object_identities (id INT AUTO_INCREMENT NOT NULL, parent_object_identity_id INT DEFAULT NULL, class_id INT NOT NULL, object_identifier VARCHAR(100) NOT NULL, entries_inheriting BOOLEAN NOT NULL, PRIMARY KEY(id), UNIQUE INDEX UNIQ_9407E5494B12AD6EA000B10 (object_identifier, class_id), INDEX IDX_9407E54977FA751A (parent_object_identity_id)) +CREATE TABLE acl_object_identities (id INT AUTO_INCREMENT NOT NULL, parent_object_identity_id INT DEFAULT NULL, class_id INT NOT NULL, object_identifier VARCHAR(100) NOT NULL, entries_inheriting BOOLEAN NOT NULL, UNIQUE INDEX UNIQ_9407E5494B12AD6EA000B10 (object_identifier, class_id), INDEX IDX_9407E54977FA751A (parent_object_identity_id), PRIMARY KEY(id)) COLLATE utf8_unicode_ci ENGINE = InnoDB -CREATE TABLE acl_object_identity_ancestors (object_identity_id INT NOT NULL, ancestor_id INT NOT NULL, PRIMARY KEY(object_identity_id, ancestor_id), INDEX IDX_825DE2993D9AB4A6 (object_identity_id), INDEX IDX_825DE299C671CEA1 (ancestor_id)) +CREATE TABLE acl_object_identity_ancestors (object_identity_id INT NOT NULL, ancestor_id INT NOT NULL, INDEX IDX_825DE2993D9AB4A6 (object_identity_id), INDEX IDX_825DE299C671CEA1 (ancestor_id), PRIMARY KEY(object_identity_id, ancestor_id)) COLLATE utf8_unicode_ci ENGINE = InnoDB -CREATE TABLE acl_entries (id INT AUTO_INCREMENT NOT NULL, class_id INT NOT NULL, object_identity_id INT DEFAULT NULL, security_identity_id INT NOT NULL, field_name VARCHAR(50) DEFAULT NULL, ace_order INT NOT NULL, mask INT NOT NULL, granting BOOLEAN NOT NULL, granting_strategy VARCHAR(30) NOT NULL, audit_success BOOLEAN NOT NULL, audit_failure BOOLEAN NOT NULL, PRIMARY KEY(id), UNIQUE INDEX UNIQ_46C8B806EA000B103D9AB4A64DEF17BCE4289BF4 (class_id, object_identity_id, field_name, ace_order), INDEX IDX_46C8B806EA000B103D9AB4A6DF9183C9 (class_id, object_identity_id, security_identity_id), INDEX IDX_46C8B806EA000B10 (class_id), INDEX IDX_46C8B8063D9AB4A6 (object_identity_id), INDEX IDX_46C8B806DF9183C9 (security_identity_id)) +CREATE TABLE acl_entries (id INT AUTO_INCREMENT NOT NULL, class_id INT NOT NULL, object_identity_id INT DEFAULT NULL, security_identity_id INT NOT NULL, field_name VARCHAR(50) DEFAULT NULL, ace_order INT NOT NULL, mask INT NOT NULL, granting BOOLEAN NOT NULL, granting_strategy VARCHAR(30) NOT NULL, audit_success BOOLEAN NOT NULL, audit_failure BOOLEAN NOT NULL, UNIQUE INDEX UNIQ_46C8B806EA000B103D9AB4A64DEF17BCE4289BF4 (class_id, object_identity_id, field_name, ace_order), INDEX IDX_46C8B806EA000B103D9AB4A6DF9183C9 (class_id, object_identity_id, security_identity_id), INDEX IDX_46C8B806EA000B10 (class_id), INDEX IDX_46C8B8063D9AB4A6 (object_identity_id), INDEX IDX_46C8B806DF9183C9 (security_identity_id), PRIMARY KEY(id)) COLLATE utf8_unicode_ci ENGINE = InnoDB ALTER TABLE acl_object_identities ADD CONSTRAINT FK_9407E54977FA751A FOREIGN KEY (parent_object_identity_id) REFERENCES acl_object_identities (id) diff --git a/Acl/Resources/schema/mssql.sql b/Acl/Resources/schema/mssql.sql index 1b4733c..8126f78 100644 --- a/Acl/Resources/schema/mssql.sql +++ b/Acl/Resources/schema/mssql.sql @@ -1,24 +1,24 @@ -CREATE TABLE acl_classes (id INT UNSIGNED IDENTITY NOT NULL, class_type NVARCHAR(200) NOT NULL, PRIMARY KEY (id)) +CREATE TABLE acl_classes (id INT IDENTITY NOT NULL, class_type NVARCHAR(200) NOT NULL, PRIMARY KEY (id)) CREATE UNIQUE INDEX UNIQ_69DD750638A36066 ON acl_classes (class_type) WHERE class_type IS NOT NULL -CREATE TABLE acl_security_identities (id INT UNSIGNED IDENTITY NOT NULL, identifier NVARCHAR(200) NOT NULL, username BIT NOT NULL, PRIMARY KEY (id)) +CREATE TABLE acl_security_identities (id INT IDENTITY NOT NULL, identifier NVARCHAR(200) NOT NULL, username BIT NOT NULL, PRIMARY KEY (id)) CREATE UNIQUE INDEX UNIQ_8835EE78772E836AF85E0677 ON acl_security_identities (identifier, username) WHERE identifier IS NOT NULL AND username IS NOT NULL -CREATE TABLE acl_object_identities (id INT UNSIGNED IDENTITY NOT NULL, parent_object_identity_id INT UNSIGNED DEFAULT NULL, class_id INT UNSIGNED NOT NULL, object_identifier NVARCHAR(100) NOT NULL, entries_inheriting BIT NOT NULL, PRIMARY KEY (id)) +CREATE TABLE acl_object_identities (id INT IDENTITY NOT NULL, parent_object_identity_id INT, class_id INT NOT NULL, object_identifier NVARCHAR(100) NOT NULL, entries_inheriting BIT NOT NULL, PRIMARY KEY (id)) CREATE UNIQUE INDEX UNIQ_9407E5494B12AD6EA000B10 ON acl_object_identities (object_identifier, class_id) WHERE object_identifier IS NOT NULL AND class_id IS NOT NULL CREATE INDEX IDX_9407E54977FA751A ON acl_object_identities (parent_object_identity_id) -CREATE TABLE acl_object_identity_ancestors (object_identity_id INT UNSIGNED NOT NULL, ancestor_id INT UNSIGNED NOT NULL, PRIMARY KEY (object_identity_id, ancestor_id)) +CREATE TABLE acl_object_identity_ancestors (object_identity_id INT NOT NULL, ancestor_id INT NOT NULL, PRIMARY KEY (object_identity_id, ancestor_id)) CREATE INDEX IDX_825DE2993D9AB4A6 ON acl_object_identity_ancestors (object_identity_id) CREATE INDEX IDX_825DE299C671CEA1 ON acl_object_identity_ancestors (ancestor_id) -CREATE TABLE acl_entries (id INT UNSIGNED IDENTITY NOT NULL, class_id INT UNSIGNED NOT NULL, object_identity_id INT UNSIGNED DEFAULT NULL, security_identity_id INT UNSIGNED NOT NULL, field_name NVARCHAR(50) DEFAULT NULL, ace_order SMALLINT UNSIGNED NOT NULL, mask INT NOT NULL, granting BIT NOT NULL, granting_strategy NVARCHAR(30) NOT NULL, audit_success BIT NOT NULL, audit_failure BIT NOT NULL, PRIMARY KEY (id)) +CREATE TABLE acl_entries (id INT IDENTITY NOT NULL, class_id INT NOT NULL, object_identity_id INT, security_identity_id INT NOT NULL, field_name NVARCHAR(50), ace_order SMALLINT NOT NULL, mask INT NOT NULL, granting BIT NOT NULL, granting_strategy NVARCHAR(30) NOT NULL, audit_success BIT NOT NULL, audit_failure BIT NOT NULL, PRIMARY KEY (id)) CREATE UNIQUE INDEX UNIQ_46C8B806EA000B103D9AB4A64DEF17BCE4289BF4 ON acl_entries (class_id, object_identity_id, field_name, ace_order) WHERE class_id IS NOT NULL AND object_identity_id IS NOT NULL AND field_name IS NOT NULL AND ace_order IS NOT NULL diff --git a/Acl/Resources/schema/mysql.sql b/Acl/Resources/schema/mysql.sql index db01e95..1c63f4d 100644 --- a/Acl/Resources/schema/mysql.sql +++ b/Acl/Resources/schema/mysql.sql @@ -1,12 +1,12 @@ -CREATE TABLE acl_classes (id INT UNSIGNED AUTO_INCREMENT NOT NULL, class_type VARCHAR(200) NOT NULL, UNIQUE INDEX UNIQ_69DD750638A36066 (class_type), PRIMARY KEY(id)) ENGINE = InnoDB +CREATE TABLE acl_classes (id INT UNSIGNED AUTO_INCREMENT NOT NULL, class_type VARCHAR(200) NOT NULL, UNIQUE INDEX UNIQ_69DD750638A36066 (class_type), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB -CREATE TABLE acl_security_identities (id INT UNSIGNED AUTO_INCREMENT NOT NULL, identifier VARCHAR(200) NOT NULL, username TINYINT(1) NOT NULL, UNIQUE INDEX UNIQ_8835EE78772E836AF85E0677 (identifier, username), PRIMARY KEY(id)) ENGINE = InnoDB +CREATE TABLE acl_security_identities (id INT UNSIGNED AUTO_INCREMENT NOT NULL, identifier VARCHAR(200) NOT NULL, username TINYINT(1) NOT NULL, UNIQUE INDEX UNIQ_8835EE78772E836AF85E0677 (identifier, username), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB -CREATE TABLE acl_object_identities (id INT UNSIGNED AUTO_INCREMENT NOT NULL, parent_object_identity_id INT UNSIGNED DEFAULT NULL, class_id INT UNSIGNED NOT NULL, object_identifier VARCHAR(100) NOT NULL, entries_inheriting TINYINT(1) NOT NULL, UNIQUE INDEX UNIQ_9407E5494B12AD6EA000B10 (object_identifier, class_id), INDEX IDX_9407E54977FA751A (parent_object_identity_id), PRIMARY KEY(id)) ENGINE = InnoDB +CREATE TABLE acl_object_identities (id INT UNSIGNED AUTO_INCREMENT NOT NULL, parent_object_identity_id INT UNSIGNED DEFAULT NULL, class_id INT UNSIGNED NOT NULL, object_identifier VARCHAR(100) NOT NULL, entries_inheriting TINYINT(1) NOT NULL, UNIQUE INDEX UNIQ_9407E5494B12AD6EA000B10 (object_identifier, class_id), INDEX IDX_9407E54977FA751A (parent_object_identity_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB -CREATE TABLE acl_object_identity_ancestors (object_identity_id INT UNSIGNED NOT NULL, ancestor_id INT UNSIGNED NOT NULL, INDEX IDX_825DE2993D9AB4A6 (object_identity_id), INDEX IDX_825DE299C671CEA1 (ancestor_id), PRIMARY KEY(object_identity_id, ancestor_id)) ENGINE = InnoDB +CREATE TABLE acl_object_identity_ancestors (object_identity_id INT UNSIGNED NOT NULL, ancestor_id INT UNSIGNED NOT NULL, INDEX IDX_825DE2993D9AB4A6 (object_identity_id), INDEX IDX_825DE299C671CEA1 (ancestor_id), PRIMARY KEY(object_identity_id, ancestor_id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB -CREATE TABLE acl_entries (id INT UNSIGNED AUTO_INCREMENT NOT NULL, class_id INT UNSIGNED NOT NULL, object_identity_id INT UNSIGNED DEFAULT NULL, security_identity_id INT UNSIGNED NOT NULL, field_name VARCHAR(50) DEFAULT NULL, ace_order SMALLINT UNSIGNED NOT NULL, mask INT NOT NULL, granting TINYINT(1) NOT NULL, granting_strategy VARCHAR(30) NOT NULL, audit_success TINYINT(1) NOT NULL, audit_failure TINYINT(1) NOT NULL, UNIQUE INDEX UNIQ_46C8B806EA000B103D9AB4A64DEF17BCE4289BF4 (class_id, object_identity_id, field_name, ace_order), INDEX IDX_46C8B806EA000B103D9AB4A6DF9183C9 (class_id, object_identity_id, security_identity_id), INDEX IDX_46C8B806EA000B10 (class_id), INDEX IDX_46C8B8063D9AB4A6 (object_identity_id), INDEX IDX_46C8B806DF9183C9 (security_identity_id), PRIMARY KEY(id)) ENGINE = InnoDB +CREATE TABLE acl_entries (id INT UNSIGNED AUTO_INCREMENT NOT NULL, class_id INT UNSIGNED NOT NULL, object_identity_id INT UNSIGNED DEFAULT NULL, security_identity_id INT UNSIGNED NOT NULL, field_name VARCHAR(50) DEFAULT NULL, ace_order SMALLINT UNSIGNED NOT NULL, mask INT NOT NULL, granting TINYINT(1) NOT NULL, granting_strategy VARCHAR(30) NOT NULL, audit_success TINYINT(1) NOT NULL, audit_failure TINYINT(1) NOT NULL, UNIQUE INDEX UNIQ_46C8B806EA000B103D9AB4A64DEF17BCE4289BF4 (class_id, object_identity_id, field_name, ace_order), INDEX IDX_46C8B806EA000B103D9AB4A6DF9183C9 (class_id, object_identity_id, security_identity_id), INDEX IDX_46C8B806EA000B10 (class_id), INDEX IDX_46C8B8063D9AB4A6 (object_identity_id), INDEX IDX_46C8B806DF9183C9 (security_identity_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB ALTER TABLE acl_object_identities ADD CONSTRAINT FK_9407E54977FA751A FOREIGN KEY (parent_object_identity_id) REFERENCES acl_object_identities (id) diff --git a/Acl/Resources/schema/oracle.sql b/Acl/Resources/schema/oracle.sql index 9896cf0..94821dc 100644 --- a/Acl/Resources/schema/oracle.sql +++ b/Acl/Resources/schema/oracle.sql @@ -5,7 +5,7 @@ DECLARE BEGIN SELECT COUNT(CONSTRAINT_NAME) INTO constraints_Count FROM USER_CONSTRAINTS WHERE TABLE_NAME = 'ACL_CLASSES' AND CONSTRAINT_TYPE = 'P'; IF constraints_Count = 0 OR constraints_Count = '' THEN - EXECUTE IMMEDIATE 'ALTER TABLE ACL_CLASSES ADD CONSTRAINT ACL_CLASSES_AI_PK PRIMARY KEY (id)'; + EXECUTE IMMEDIATE 'ALTER TABLE ACL_CLASSES ADD CONSTRAINT ACL_CLASSES_AI_PK PRIMARY KEY (ID)'; END IF; END; @@ -19,14 +19,14 @@ DECLARE last_Sequence NUMBER; last_InsertID NUMBER; BEGIN - SELECT ACL_CLASSES_SEQ.NEXTVAL INTO :NEW.id FROM DUAL; - IF (:NEW.id IS NULL OR :NEW.id = 0) THEN - SELECT ACL_CLASSES_SEQ.NEXTVAL INTO :NEW.id FROM DUAL; + SELECT ACL_CLASSES_SEQ.NEXTVAL INTO :NEW.ID FROM DUAL; + IF (:NEW.ID IS NULL OR :NEW.ID = 0) THEN + SELECT ACL_CLASSES_SEQ.NEXTVAL INTO :NEW.ID FROM DUAL; ELSE SELECT NVL(Last_Number, 0) INTO last_Sequence FROM User_Sequences WHERE Sequence_Name = 'ACL_CLASSES_SEQ'; - SELECT :NEW.id INTO last_InsertID FROM DUAL; + SELECT :NEW.ID INTO last_InsertID FROM DUAL; WHILE (last_InsertID > last_Sequence) LOOP SELECT ACL_CLASSES_SEQ.NEXTVAL INTO last_Sequence FROM DUAL; END LOOP; @@ -42,7 +42,7 @@ DECLARE BEGIN SELECT COUNT(CONSTRAINT_NAME) INTO constraints_Count FROM USER_CONSTRAINTS WHERE TABLE_NAME = 'ACL_SECURITY_IDENTITIES' AND CONSTRAINT_TYPE = 'P'; IF constraints_Count = 0 OR constraints_Count = '' THEN - EXECUTE IMMEDIATE 'ALTER TABLE ACL_SECURITY_IDENTITIES ADD CONSTRAINT ACL_SECURITY_IDENTITIES_AI_PK PRIMARY KEY (id)'; + EXECUTE IMMEDIATE 'ALTER TABLE ACL_SECURITY_IDENTITIES ADD CONSTRAINT ACL_SECURITY_IDENTITIES_AI_PK PRIMARY KEY (ID)'; END IF; END; @@ -56,14 +56,14 @@ DECLARE last_Sequence NUMBER; last_InsertID NUMBER; BEGIN - SELECT ACL_SECURITY_IDENTITIES_SEQ.NEXTVAL INTO :NEW.id FROM DUAL; - IF (:NEW.id IS NULL OR :NEW.id = 0) THEN - SELECT ACL_SECURITY_IDENTITIES_SEQ.NEXTVAL INTO :NEW.id FROM DUAL; + SELECT ACL_SECURITY_IDENTITIES_SEQ.NEXTVAL INTO :NEW.ID FROM DUAL; + IF (:NEW.ID IS NULL OR :NEW.ID = 0) THEN + SELECT ACL_SECURITY_IDENTITIES_SEQ.NEXTVAL INTO :NEW.ID FROM DUAL; ELSE SELECT NVL(Last_Number, 0) INTO last_Sequence FROM User_Sequences WHERE Sequence_Name = 'ACL_SECURITY_IDENTITIES_SEQ'; - SELECT :NEW.id INTO last_InsertID FROM DUAL; + SELECT :NEW.ID INTO last_InsertID FROM DUAL; WHILE (last_InsertID > last_Sequence) LOOP SELECT ACL_SECURITY_IDENTITIES_SEQ.NEXTVAL INTO last_Sequence FROM DUAL; END LOOP; @@ -72,14 +72,14 @@ END; CREATE UNIQUE INDEX UNIQ_8835EE78772E836AF85E0677 ON acl_security_identities (identifier, username) -CREATE TABLE acl_object_identities (id NUMBER(10) NOT NULL, parent_object_identity_id NUMBER(10) DEFAULT NULL, class_id NUMBER(10) NOT NULL, object_identifier VARCHAR2(100) NOT NULL, entries_inheriting NUMBER(1) NOT NULL, PRIMARY KEY(id)) +CREATE TABLE acl_object_identities (id NUMBER(10) NOT NULL, parent_object_identity_id NUMBER(10) DEFAULT NULL NULL, class_id NUMBER(10) NOT NULL, object_identifier VARCHAR2(100) NOT NULL, entries_inheriting NUMBER(1) NOT NULL, PRIMARY KEY(id)) DECLARE constraints_Count NUMBER; BEGIN SELECT COUNT(CONSTRAINT_NAME) INTO constraints_Count FROM USER_CONSTRAINTS WHERE TABLE_NAME = 'ACL_OBJECT_IDENTITIES' AND CONSTRAINT_TYPE = 'P'; IF constraints_Count = 0 OR constraints_Count = '' THEN - EXECUTE IMMEDIATE 'ALTER TABLE ACL_OBJECT_IDENTITIES ADD CONSTRAINT ACL_OBJECT_IDENTITIES_AI_PK PRIMARY KEY (id)'; + EXECUTE IMMEDIATE 'ALTER TABLE ACL_OBJECT_IDENTITIES ADD CONSTRAINT ACL_OBJECT_IDENTITIES_AI_PK PRIMARY KEY (ID)'; END IF; END; @@ -93,14 +93,14 @@ DECLARE last_Sequence NUMBER; last_InsertID NUMBER; BEGIN - SELECT ACL_OBJECT_IDENTITIES_SEQ.NEXTVAL INTO :NEW.id FROM DUAL; - IF (:NEW.id IS NULL OR :NEW.id = 0) THEN - SELECT ACL_OBJECT_IDENTITIES_SEQ.NEXTVAL INTO :NEW.id FROM DUAL; + SELECT ACL_OBJECT_IDENTITIES_SEQ.NEXTVAL INTO :NEW.ID FROM DUAL; + IF (:NEW.ID IS NULL OR :NEW.ID = 0) THEN + SELECT ACL_OBJECT_IDENTITIES_SEQ.NEXTVAL INTO :NEW.ID FROM DUAL; ELSE SELECT NVL(Last_Number, 0) INTO last_Sequence FROM User_Sequences WHERE Sequence_Name = 'ACL_OBJECT_IDENTITIES_SEQ'; - SELECT :NEW.id INTO last_InsertID FROM DUAL; + SELECT :NEW.ID INTO last_InsertID FROM DUAL; WHILE (last_InsertID > last_Sequence) LOOP SELECT ACL_OBJECT_IDENTITIES_SEQ.NEXTVAL INTO last_Sequence FROM DUAL; END LOOP; @@ -117,14 +117,14 @@ CREATE INDEX IDX_825DE2993D9AB4A6 ON acl_object_identity_ancestors (object_ident CREATE INDEX IDX_825DE299C671CEA1 ON acl_object_identity_ancestors (ancestor_id) -CREATE TABLE acl_entries (id NUMBER(10) NOT NULL, class_id NUMBER(10) NOT NULL, object_identity_id NUMBER(10) DEFAULT NULL, security_identity_id NUMBER(10) NOT NULL, field_name VARCHAR2(50) DEFAULT NULL, ace_order NUMBER(5) NOT NULL, mask NUMBER(10) NOT NULL, granting NUMBER(1) NOT NULL, granting_strategy VARCHAR2(30) NOT NULL, audit_success NUMBER(1) NOT NULL, audit_failure NUMBER(1) NOT NULL, PRIMARY KEY(id)) +CREATE TABLE acl_entries (id NUMBER(10) NOT NULL, class_id NUMBER(10) NOT NULL, object_identity_id NUMBER(10) DEFAULT NULL NULL, security_identity_id NUMBER(10) NOT NULL, field_name VARCHAR2(50) DEFAULT NULL NULL, ace_order NUMBER(5) NOT NULL, mask NUMBER(10) NOT NULL, granting NUMBER(1) NOT NULL, granting_strategy VARCHAR2(30) NOT NULL, audit_success NUMBER(1) NOT NULL, audit_failure NUMBER(1) NOT NULL, PRIMARY KEY(id)) DECLARE constraints_Count NUMBER; BEGIN SELECT COUNT(CONSTRAINT_NAME) INTO constraints_Count FROM USER_CONSTRAINTS WHERE TABLE_NAME = 'ACL_ENTRIES' AND CONSTRAINT_TYPE = 'P'; IF constraints_Count = 0 OR constraints_Count = '' THEN - EXECUTE IMMEDIATE 'ALTER TABLE ACL_ENTRIES ADD CONSTRAINT ACL_ENTRIES_AI_PK PRIMARY KEY (id)'; + EXECUTE IMMEDIATE 'ALTER TABLE ACL_ENTRIES ADD CONSTRAINT ACL_ENTRIES_AI_PK PRIMARY KEY (ID)'; END IF; END; @@ -138,14 +138,14 @@ DECLARE last_Sequence NUMBER; last_InsertID NUMBER; BEGIN - SELECT ACL_ENTRIES_SEQ.NEXTVAL INTO :NEW.id FROM DUAL; - IF (:NEW.id IS NULL OR :NEW.id = 0) THEN - SELECT ACL_ENTRIES_SEQ.NEXTVAL INTO :NEW.id FROM DUAL; + SELECT ACL_ENTRIES_SEQ.NEXTVAL INTO :NEW.ID FROM DUAL; + IF (:NEW.ID IS NULL OR :NEW.ID = 0) THEN + SELECT ACL_ENTRIES_SEQ.NEXTVAL INTO :NEW.ID FROM DUAL; ELSE SELECT NVL(Last_Number, 0) INTO last_Sequence FROM User_Sequences WHERE Sequence_Name = 'ACL_ENTRIES_SEQ'; - SELECT :NEW.id INTO last_InsertID FROM DUAL; + SELECT :NEW.ID INTO last_InsertID FROM DUAL; WHILE (last_InsertID > last_Sequence) LOOP SELECT ACL_ENTRIES_SEQ.NEXTVAL INTO last_Sequence FROM DUAL; END LOOP; diff --git a/Acl/Resources/schema/sqlanywhere.sql b/Acl/Resources/schema/sqlanywhere.sql new file mode 100644 index 0000000..d73b102 --- /dev/null +++ b/Acl/Resources/schema/sqlanywhere.sql @@ -0,0 +1,43 @@ +CREATE TABLE acl_classes (id UNSIGNED INT IDENTITY NOT NULL, class_type VARCHAR(200) NOT NULL, PRIMARY KEY (id)) + +CREATE UNIQUE INDEX UNIQ_69DD750638A36066 ON acl_classes (class_type) + +CREATE TABLE acl_security_identities (id UNSIGNED INT IDENTITY NOT NULL, identifier VARCHAR(200) NOT NULL, username BIT NOT NULL, PRIMARY KEY (id)) + +CREATE UNIQUE INDEX UNIQ_8835EE78772E836AF85E0677 ON acl_security_identities (identifier, username) + +CREATE TABLE acl_object_identities (id UNSIGNED INT IDENTITY NOT NULL, parent_object_identity_id UNSIGNED INT DEFAULT NULL, class_id UNSIGNED INT NOT NULL, object_identifier VARCHAR(100) NOT NULL, entries_inheriting BIT NOT NULL, PRIMARY KEY (id)) + +CREATE UNIQUE INDEX UNIQ_9407E5494B12AD6EA000B10 ON acl_object_identities (object_identifier, class_id) + +CREATE INDEX IDX_9407E54977FA751A ON acl_object_identities (parent_object_identity_id) + +CREATE TABLE acl_object_identity_ancestors (object_identity_id UNSIGNED INT NOT NULL, ancestor_id UNSIGNED INT NOT NULL, PRIMARY KEY (object_identity_id, ancestor_id)) + +CREATE INDEX IDX_825DE2993D9AB4A6 ON acl_object_identity_ancestors (object_identity_id) + +CREATE INDEX IDX_825DE299C671CEA1 ON acl_object_identity_ancestors (ancestor_id) + +CREATE TABLE acl_entries (id UNSIGNED INT IDENTITY NOT NULL, class_id UNSIGNED INT NOT NULL, object_identity_id UNSIGNED INT DEFAULT NULL, security_identity_id UNSIGNED INT NOT NULL, field_name VARCHAR(50) DEFAULT NULL, ace_order UNSIGNED SMALLINT NOT NULL, mask INT NOT NULL, granting BIT NOT NULL, granting_strategy VARCHAR(30) NOT NULL, audit_success BIT NOT NULL, audit_failure BIT NOT NULL, PRIMARY KEY (id)) + +CREATE UNIQUE INDEX UNIQ_46C8B806EA000B103D9AB4A64DEF17BCE4289BF4 ON acl_entries (class_id, object_identity_id, field_name, ace_order) + +CREATE INDEX IDX_46C8B806EA000B103D9AB4A6DF9183C9 ON acl_entries (class_id, object_identity_id, security_identity_id) + +CREATE INDEX IDX_46C8B806EA000B10 ON acl_entries (class_id) + +CREATE INDEX IDX_46C8B8063D9AB4A6 ON acl_entries (object_identity_id) + +CREATE INDEX IDX_46C8B806DF9183C9 ON acl_entries (security_identity_id) + +ALTER TABLE acl_object_identities ADD CONSTRAINT FK_9407E54977FA751A FOREIGN KEY (parent_object_identity_id) REFERENCES acl_object_identities (id) + +ALTER TABLE acl_object_identity_ancestors ADD CONSTRAINT FK_825DE2993D9AB4A6 FOREIGN KEY (object_identity_id) REFERENCES acl_object_identities (id) ON UPDATE CASCADE ON DELETE CASCADE + +ALTER TABLE acl_object_identity_ancestors ADD CONSTRAINT FK_825DE299C671CEA1 FOREIGN KEY (ancestor_id) REFERENCES acl_object_identities (id) ON UPDATE CASCADE ON DELETE CASCADE + +ALTER TABLE acl_entries ADD CONSTRAINT FK_46C8B806EA000B10 FOREIGN KEY (class_id) REFERENCES acl_classes (id) ON UPDATE CASCADE ON DELETE CASCADE + +ALTER TABLE acl_entries ADD CONSTRAINT FK_46C8B8063D9AB4A6 FOREIGN KEY (object_identity_id) REFERENCES acl_object_identities (id) ON UPDATE CASCADE ON DELETE CASCADE + +ALTER TABLE acl_entries ADD CONSTRAINT FK_46C8B806DF9183C9 FOREIGN KEY (security_identity_id) REFERENCES acl_security_identities (id) ON UPDATE CASCADE ON DELETE CASCADE
\ No newline at end of file diff --git a/Acl/Resources/schema/sqlite.sql b/Acl/Resources/schema/sqlite.sql index 21c9f67..4429bfa 100644 --- a/Acl/Resources/schema/sqlite.sql +++ b/Acl/Resources/schema/sqlite.sql @@ -1,24 +1,24 @@ -CREATE TABLE acl_classes (id INTEGER NOT NULL, class_type VARCHAR(200) NOT NULL, PRIMARY KEY("id")) +CREATE TABLE acl_classes (id INTEGER NOT NULL, class_type VARCHAR(200) NOT NULL, PRIMARY KEY(id)) CREATE UNIQUE INDEX UNIQ_69DD750638A36066 ON acl_classes (class_type) -CREATE TABLE acl_security_identities (id INTEGER NOT NULL, identifier VARCHAR(200) NOT NULL, username BOOLEAN NOT NULL, PRIMARY KEY("id")) +CREATE TABLE acl_security_identities (id INTEGER NOT NULL, identifier VARCHAR(200) NOT NULL, username BOOLEAN NOT NULL, PRIMARY KEY(id)) CREATE UNIQUE INDEX UNIQ_8835EE78772E836AF85E0677 ON acl_security_identities (identifier, username) -CREATE TABLE acl_object_identities (id INTEGER NOT NULL, parent_object_identity_id INTEGER DEFAULT NULL, class_id INTEGER NOT NULL, object_identifier VARCHAR(100) NOT NULL, entries_inheriting BOOLEAN NOT NULL, PRIMARY KEY("id")) +CREATE TABLE acl_object_identities (id INTEGER NOT NULL, parent_object_identity_id INTEGER UNSIGNED DEFAULT NULL, class_id INTEGER UNSIGNED NOT NULL, object_identifier VARCHAR(100) NOT NULL, entries_inheriting BOOLEAN NOT NULL, PRIMARY KEY(id), CONSTRAINT FK_9407E54977FA751A FOREIGN KEY (parent_object_identity_id) REFERENCES acl_object_identities (id) NOT DEFERRABLE INITIALLY IMMEDIATE) CREATE UNIQUE INDEX UNIQ_9407E5494B12AD6EA000B10 ON acl_object_identities (object_identifier, class_id) CREATE INDEX IDX_9407E54977FA751A ON acl_object_identities (parent_object_identity_id) -CREATE TABLE acl_object_identity_ancestors (object_identity_id INTEGER NOT NULL, ancestor_id INTEGER NOT NULL, PRIMARY KEY("object_identity_id", "ancestor_id")) +CREATE TABLE acl_object_identity_ancestors (object_identity_id INTEGER UNSIGNED NOT NULL, ancestor_id INTEGER UNSIGNED NOT NULL, PRIMARY KEY(object_identity_id, ancestor_id), CONSTRAINT FK_825DE2993D9AB4A6 FOREIGN KEY (object_identity_id) REFERENCES acl_object_identities (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_825DE299C671CEA1 FOREIGN KEY (ancestor_id) REFERENCES acl_object_identities (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE) CREATE INDEX IDX_825DE2993D9AB4A6 ON acl_object_identity_ancestors (object_identity_id) CREATE INDEX IDX_825DE299C671CEA1 ON acl_object_identity_ancestors (ancestor_id) -CREATE TABLE acl_entries (id INTEGER NOT NULL, class_id INTEGER NOT NULL, object_identity_id INTEGER DEFAULT NULL, security_identity_id INTEGER NOT NULL, field_name VARCHAR(50) DEFAULT NULL, ace_order INTEGER NOT NULL, mask INTEGER NOT NULL, granting BOOLEAN NOT NULL, granting_strategy VARCHAR(30) NOT NULL, audit_success BOOLEAN NOT NULL, audit_failure BOOLEAN NOT NULL, PRIMARY KEY("id")) +CREATE TABLE acl_entries (id INTEGER NOT NULL, class_id INTEGER UNSIGNED NOT NULL, object_identity_id INTEGER UNSIGNED DEFAULT NULL, security_identity_id INTEGER UNSIGNED NOT NULL, field_name VARCHAR(50) DEFAULT NULL, ace_order SMALLINT UNSIGNED NOT NULL, mask INTEGER NOT NULL, granting BOOLEAN NOT NULL, granting_strategy VARCHAR(30) NOT NULL, audit_success BOOLEAN NOT NULL, audit_failure BOOLEAN NOT NULL, PRIMARY KEY(id), CONSTRAINT FK_46C8B806EA000B10 FOREIGN KEY (class_id) REFERENCES acl_classes (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_46C8B8063D9AB4A6 FOREIGN KEY (object_identity_id) REFERENCES acl_object_identities (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_46C8B806DF9183C9 FOREIGN KEY (security_identity_id) REFERENCES acl_security_identities (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE) CREATE UNIQUE INDEX UNIQ_46C8B806EA000B103D9AB4A64DEF17BCE4289BF4 ON acl_entries (class_id, object_identity_id, field_name, ace_order) diff --git a/Tests/Acl/Dbal/AclProviderBenchmarkTest.php b/Acl/Tests/Dbal/AclProviderBenchmarkTest.php index 0c35475..c95b474 100644 --- a/Tests/Acl/Dbal/AclProviderBenchmarkTest.php +++ b/Acl/Tests/Dbal/AclProviderBenchmarkTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Acl\Dbal; +namespace Symfony\Component\Security\Acl\Tests\Dbal; use Symfony\Component\Security\Acl\Dbal\AclProvider; use Symfony\Component\Security\Acl\Domain\PermissionGrantingStrategy; diff --git a/Tests/Acl/Dbal/AclProviderTest.php b/Acl/Tests/Dbal/AclProviderTest.php index afbcb56..680c6c3 100644 --- a/Tests/Acl/Dbal/AclProviderTest.php +++ b/Acl/Tests/Dbal/AclProviderTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Acl\Dbal; +namespace Symfony\Component\Security\Acl\Tests\Dbal; use Symfony\Component\Security\Acl\Dbal\AclProvider; use Symfony\Component\Security\Acl\Domain\PermissionGrantingStrategy; diff --git a/Tests/Acl/Dbal/MutableAclProviderTest.php b/Acl/Tests/Dbal/MutableAclProviderTest.php index 3213406..c2169e4 100644 --- a/Tests/Acl/Dbal/MutableAclProviderTest.php +++ b/Acl/Tests/Dbal/MutableAclProviderTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Acl\Dbal; +namespace Symfony\Component\Security\Acl\Tests\Dbal; use Symfony\Component\Security\Acl\Domain\RoleSecurityIdentity; use Symfony\Component\Security\Acl\Model\FieldEntryInterface; @@ -413,6 +413,36 @@ class MutableAclProviderTest extends \PHPUnit_Framework_TestCase $provider->updateAcl($acl); } + public function testUpdateUserSecurityIdentity() + { + $provider = $this->getProvider(); + $acl = $provider->createAcl(new ObjectIdentity(1, 'Foo')); + $sid = new UserSecurityIdentity('johannes', 'FooClass'); + $acl->setEntriesInheriting(!$acl->isEntriesInheriting()); + + $acl->insertObjectAce($sid, 1); + $acl->insertClassAce($sid, 5, 0, false); + $acl->insertObjectAce($sid, 2, 1, true); + $acl->insertClassFieldAce('field', $sid, 2, 0, true); + $provider->updateAcl($acl); + + $newSid = new UserSecurityIdentity('mathieu', 'FooClass'); + $provider->updateUserSecurityIdentity($newSid, 'johannes'); + + $reloadProvider = $this->getProvider(); + $reloadedAcl = $reloadProvider->findAcl(new ObjectIdentity(1, 'Foo')); + + $this->assertNotSame($acl, $reloadedAcl); + $this->assertSame($acl->isEntriesInheriting(), $reloadedAcl->isEntriesInheriting()); + + $aces = $acl->getObjectAces(); + $reloadedAces = $reloadedAcl->getObjectAces(); + $this->assertEquals(count($aces), count($reloadedAces)); + foreach ($reloadedAces as $ace) { + $this->assertTrue($ace->getSecurityIdentity()->equals($newSid)); + } + } + /** * Imports acls. * diff --git a/Tests/Acl/Domain/AclTest.php b/Acl/Tests/Domain/AclTest.php index 9be4a94..84b9ba9 100644 --- a/Tests/Acl/Domain/AclTest.php +++ b/Acl/Tests/Domain/AclTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Acl\Domain; +namespace Symfony\Component\Security\Acl\Tests\Domain; use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity; use Symfony\Component\Security\Acl\Domain\RoleSecurityIdentity; diff --git a/Tests/Acl/Domain/AuditLoggerTest.php b/Acl/Tests/Domain/AuditLoggerTest.php index c8522b4..15538d3 100644 --- a/Tests/Acl/Domain/AuditLoggerTest.php +++ b/Acl/Tests/Domain/AuditLoggerTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Acl\Domain; +namespace Symfony\Component\Security\Acl\Tests\Domain; class AuditLoggerTest extends \PHPUnit_Framework_TestCase { @@ -26,12 +26,12 @@ class AuditLoggerTest extends \PHPUnit_Framework_TestCase ->expects($this->once()) ->method('isAuditSuccess') ->will($this->returnValue($audit)) - ; + ; $ace ->expects($this->never()) ->method('isAuditFailure') - ; + ; } else { $ace ->expects($this->never()) diff --git a/Tests/Acl/Domain/DoctrineAclCacheTest.php b/Acl/Tests/Domain/DoctrineAclCacheTest.php index 54f932d..255f7f4 100644 --- a/Tests/Acl/Domain/DoctrineAclCacheTest.php +++ b/Acl/Tests/Domain/DoctrineAclCacheTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Acl\Domain; +namespace Symfony\Component\Security\Acl\Tests\Domain; use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity; use Symfony\Component\Security\Acl\Domain\ObjectIdentity; diff --git a/Tests/Acl/Domain/EntryTest.php b/Acl/Tests/Domain/EntryTest.php index 966f2f1..ab8e481 100644 --- a/Tests/Acl/Domain/EntryTest.php +++ b/Acl/Tests/Domain/EntryTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Acl\Domain; +namespace Symfony\Component\Security\Acl\Tests\Domain; use Symfony\Component\Security\Acl\Domain\Entry; diff --git a/Tests/Acl/Domain/FieldEntryTest.php b/Acl/Tests/Domain/FieldEntryTest.php index 7f0cbc0..735e2e8 100644 --- a/Tests/Acl/Domain/FieldEntryTest.php +++ b/Acl/Tests/Domain/FieldEntryTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Acl\Domain; +namespace Symfony\Component\Security\Acl\Tests\Domain; use Symfony\Component\Security\Acl\Domain\FieldEntry; diff --git a/Tests/Acl/Domain/ObjectIdentityRetrievalStrategyTest.php b/Acl/Tests/Domain/ObjectIdentityRetrievalStrategyTest.php index e89e1ef..59fc3bd 100644 --- a/Tests/Acl/Domain/ObjectIdentityRetrievalStrategyTest.php +++ b/Acl/Tests/Domain/ObjectIdentityRetrievalStrategyTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Acl\Domain; +namespace Symfony\Component\Security\Acl\Tests\Domain; use Symfony\Component\Security\Acl\Domain\ObjectIdentityRetrievalStrategy; diff --git a/Tests/Acl/Domain/ObjectIdentityTest.php b/Acl/Tests/Domain/ObjectIdentityTest.php index 312f433..770ada7 100644 --- a/Tests/Acl/Domain/ObjectIdentityTest.php +++ b/Acl/Tests/Domain/ObjectIdentityTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Acl\Domain +namespace Symfony\Component\Security\Acl\Tests\Domain { use Symfony\Component\Security\Acl\Domain\ObjectIdentity; use Symfony\Component\Security\Acl\Model\DomainObjectInterface; @@ -27,10 +27,10 @@ namespace Symfony\Component\Security\Tests\Acl\Domain // Test that constructor never changes passed type, even with proxies public function testConstructorWithProxy() { - $id = new ObjectIdentity('fooid', 'Acme\DemoBundle\Proxy\__CG__\Symfony\Component\Security\Tests\Acl\Domain\TestDomainObject'); + $id = new ObjectIdentity('fooid', 'Acme\DemoBundle\Proxy\__CG__\Symfony\Component\Security\Acl\Tests\Domain\TestDomainObject'); $this->assertEquals('fooid', $id->getIdentifier()); - $this->assertEquals('Acme\DemoBundle\Proxy\__CG__\Symfony\Component\Security\Tests\Acl\Domain\TestDomainObject', $id->getType()); + $this->assertEquals('Acme\DemoBundle\Proxy\__CG__\Symfony\Component\Security\Acl\Tests\Domain\TestDomainObject', $id->getType()); } public function testFromDomainObjectPrefersInterfaceOverGetId() @@ -45,14 +45,14 @@ namespace Symfony\Component\Security\Tests\Acl\Domain { $id = ObjectIdentity::fromDomainObject(new TestDomainObject()); $this->assertEquals('getId()', $id->getIdentifier()); - $this->assertEquals('Symfony\Component\Security\Tests\Acl\Domain\TestDomainObject', $id->getType()); + $this->assertEquals('Symfony\Component\Security\Acl\Tests\Domain\TestDomainObject', $id->getType()); } public function testFromDomainObjectWithProxy() { - $id = ObjectIdentity::fromDomainObject(new \Acme\DemoBundle\Proxy\__CG__\Symfony\Component\Security\Tests\Acl\Domain\TestDomainObject()); + $id = ObjectIdentity::fromDomainObject(new \Acme\DemoBundle\Proxy\__CG__\Symfony\Component\Security\Acl\Tests\Domain\TestDomainObject()); $this->assertEquals('getId()', $id->getIdentifier()); - $this->assertEquals('Symfony\Component\Security\Tests\Acl\Domain\TestDomainObject', $id->getType()); + $this->assertEquals('Symfony\Component\Security\Acl\Tests\Domain\TestDomainObject', $id->getType()); } public function testFromDomainObjectWithoutInterfaceEnforcesStringIdentifier() @@ -62,7 +62,7 @@ namespace Symfony\Component\Security\Tests\Acl\Domain $id = ObjectIdentity::fromDomainObject($domainObject); $this->assertSame('1', $id->getIdentifier()); - $this->assertEquals('Symfony\Component\Security\Tests\Acl\Domain\TestDomainObject', $id->getType()); + $this->assertEquals('Symfony\Component\Security\Acl\Tests\Domain\TestDomainObject', $id->getType()); } public function testFromDomainObjectWithoutInterfaceAllowsZeroAsIdentifier() @@ -72,7 +72,7 @@ namespace Symfony\Component\Security\Tests\Acl\Domain $id = ObjectIdentity::fromDomainObject($domainObject); $this->assertSame('0', $id->getIdentifier()); - $this->assertEquals('Symfony\Component\Security\Tests\Acl\Domain\TestDomainObject', $id->getType()); + $this->assertEquals('Symfony\Component\Security\Acl\Tests\Domain\TestDomainObject', $id->getType()); } /** @@ -127,9 +127,9 @@ namespace Symfony\Component\Security\Tests\Acl\Domain } } -namespace Acme\DemoBundle\Proxy\__CG__\Symfony\Component\Security\Tests\Acl\Domain +namespace Acme\DemoBundle\Proxy\__CG__\Symfony\Component\Security\Acl\Tests\Domain { - class TestDomainObject extends \Symfony\Component\Security\Tests\Acl\Domain\TestDomainObject + class TestDomainObject extends \Symfony\Component\Security\Acl\Tests\Domain\TestDomainObject { } } diff --git a/Tests/Acl/Domain/PermissionGrantingStrategyTest.php b/Acl/Tests/Domain/PermissionGrantingStrategyTest.php index fd33f8d..34ef690 100644 --- a/Tests/Acl/Domain/PermissionGrantingStrategyTest.php +++ b/Acl/Tests/Domain/PermissionGrantingStrategyTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Acl\Domain; +namespace Symfony\Component\Security\Acl\Tests\Domain; use Symfony\Component\Security\Acl\Domain\ObjectIdentity; use Symfony\Component\Security\Acl\Domain\RoleSecurityIdentity; diff --git a/Tests/Acl/Domain/RoleSecurityIdentityTest.php b/Acl/Tests/Domain/RoleSecurityIdentityTest.php index 341f33c..ad5f236 100644 --- a/Tests/Acl/Domain/RoleSecurityIdentityTest.php +++ b/Acl/Tests/Domain/RoleSecurityIdentityTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Acl\Domain; +namespace Symfony\Component\Security\Acl\Tests\Domain; use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity; use Symfony\Component\Security\Core\Role\Role; diff --git a/Tests/Acl/Domain/SecurityIdentityRetrievalStrategyTest.php b/Acl/Tests/Domain/SecurityIdentityRetrievalStrategyTest.php index e5fb4ed..160c27c 100644 --- a/Tests/Acl/Domain/SecurityIdentityRetrievalStrategyTest.php +++ b/Acl/Tests/Domain/SecurityIdentityRetrievalStrategyTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Acl\Domain; +namespace Symfony\Component\Security\Acl\Tests\Domain; use Symfony\Component\Security\Acl\Domain\RoleSecurityIdentity; use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity; @@ -88,7 +88,7 @@ class SecurityIdentityRetrievalStrategyTest extends \PHPUnit_Framework_TestCase new RoleSecurityIdentity('IS_AUTHENTICATED_ANONYMOUSLY'), )), array(new CustomUserImpl('johannes'), array('ROLE_FOO'), 'fullFledged', array( - new UserSecurityIdentity('johannes', 'Symfony\Component\Security\Tests\Acl\Domain\CustomUserImpl'), + new UserSecurityIdentity('johannes', 'Symfony\Component\Security\Acl\Tests\Domain\CustomUserImpl'), new RoleSecurityIdentity('ROLE_FOO'), new RoleSecurityIdentity('IS_AUTHENTICATED_FULLY'), new RoleSecurityIdentity('IS_AUTHENTICATED_REMEMBERED'), diff --git a/Tests/Acl/Domain/UserSecurityIdentityTest.php b/Acl/Tests/Domain/UserSecurityIdentityTest.php index 1d6a3c5..09d3f0d 100644 --- a/Tests/Acl/Domain/UserSecurityIdentityTest.php +++ b/Acl/Tests/Domain/UserSecurityIdentityTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Acl\Domain; +namespace Symfony\Component\Security\Acl\Tests\Domain; use Symfony\Component\Security\Acl\Domain\RoleSecurityIdentity; use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity; @@ -27,10 +27,10 @@ class UserSecurityIdentityTest extends \PHPUnit_Framework_TestCase // Test that constructor never changes the type, even for proxies public function testConstructorWithProxy() { - $id = new UserSecurityIdentity('foo', 'Acme\DemoBundle\Proxy\__CG__\Symfony\Component\Security\Tests\Acl\Domain\Foo'); + $id = new UserSecurityIdentity('foo', 'Acme\DemoBundle\Proxy\__CG__\Symfony\Component\Security\Acl\Tests\Domain\Foo'); $this->assertEquals('foo', $id->getUsername()); - $this->assertEquals('Acme\DemoBundle\Proxy\__CG__\Symfony\Component\Security\Tests\Acl\Domain\Foo', $id->getClass()); + $this->assertEquals('Acme\DemoBundle\Proxy\__CG__\Symfony\Component\Security\Acl\Tests\Domain\Foo', $id->getClass()); } /** diff --git a/Tests/Acl/Permission/BasicPermissionMapTest.php b/Acl/Tests/Permission/BasicPermissionMapTest.php index 743634b..2afe588 100644 --- a/Tests/Acl/Permission/BasicPermissionMapTest.php +++ b/Acl/Tests/Permission/BasicPermissionMapTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Acl\Permission; +namespace Symfony\Component\Security\Acl\Tests\Permission; use Symfony\Component\Security\Acl\Permission\BasicPermissionMap; diff --git a/Tests/Acl/Permission/MaskBuilderTest.php b/Acl/Tests/Permission/MaskBuilderTest.php index de034e3..8245669 100644 --- a/Tests/Acl/Permission/MaskBuilderTest.php +++ b/Acl/Tests/Permission/MaskBuilderTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Acl\Permission; +namespace Symfony\Component\Security\Acl\Tests\Permission; use Symfony\Component\Security\Acl\Permission\MaskBuilder; diff --git a/Tests/Acl/Voter/AclVoterTest.php b/Acl/Tests/Voter/AclVoterTest.php index 8544b19..2148135 100644 --- a/Tests/Acl/Voter/AclVoterTest.php +++ b/Acl/Tests/Voter/AclVoterTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Acl\Voter; +namespace Symfony\Component\Security\Acl\Tests\Voter; use Symfony\Component\Security\Acl\Exception\NoAceFoundException; use Symfony\Component\Security\Acl\Voter\FieldVote; diff --git a/Acl/Voter/AclVoter.php b/Acl/Voter/AclVoter.php index 4a8533a..ec6024a 100644 --- a/Acl/Voter/AclVoter.php +++ b/Acl/Voter/AclVoter.php @@ -64,7 +64,7 @@ class AclVoter implements VoterInterface if (null === $object) { if (null !== $this->logger) { - $this->logger->debug(sprintf('Object identity unavailable. Voting to %s', $this->allowIfObjectIdentityUnavailable ? 'grant access' : 'abstain')); + $this->logger->debug(sprintf('Object identity unavailable. Voting to %s.', $this->allowIfObjectIdentityUnavailable ? 'grant access' : 'abstain')); } return $this->allowIfObjectIdentityUnavailable ? self::ACCESS_GRANTED : self::ACCESS_ABSTAIN; @@ -79,7 +79,7 @@ class AclVoter implements VoterInterface $oid = $object; } elseif (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')); + $this->logger->debug(sprintf('Object identity unavailable. Voting to %s.', $this->allowIfObjectIdentityUnavailable ? 'grant access' : 'abstain')); } return $this->allowIfObjectIdentityUnavailable ? self::ACCESS_GRANTED : self::ACCESS_ABSTAIN; @@ -96,13 +96,13 @@ class AclVoter implements VoterInterface if (null === $field && $acl->isGranted($masks, $sids, false)) { if (null !== $this->logger) { - $this->logger->debug('ACL found, permission granted. Voting to grant access'); + $this->logger->debug('ACL found, permission granted. Voting to grant access.'); } return self::ACCESS_GRANTED; } elseif (null !== $field && $acl->isFieldGranted($field, $masks, $sids, false)) { if (null !== $this->logger) { - $this->logger->debug('ACL found, permission granted. Voting to grant access'); + $this->logger->debug('ACL found, permission granted. Voting to grant access.'); } return self::ACCESS_GRANTED; diff --git a/Acl/composer.json b/Acl/composer.json new file mode 100644 index 0000000..b292742 --- /dev/null +++ b/Acl/composer.json @@ -0,0 +1,44 @@ +{ + "name": "symfony/security-acl", + "type": "library", + "description": "Symfony Security Component - ACL (Access Control List)", + "keywords": [], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=5.3.9", + "symfony/security-core": "~2.4" + }, + "require-dev": { + "doctrine/common": "~2.2", + "doctrine/dbal": "~2.2", + "psr/log": "~1.0" + }, + "suggest": { + "symfony/class-loader": "For using the ACL generateSql script", + "symfony/finder": "For using the ACL generateSql script", + "doctrine/dbal": "For using the built-in ACL implementation" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\Security\\Acl\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + } +} diff --git a/Acl/phpunit.xml.dist b/Acl/phpunit.xml.dist new file mode 100644 index 0000000..b1ea047 --- /dev/null +++ b/Acl/phpunit.xml.dist @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<phpunit backupGlobals="false" + backupStaticAttributes="false" + colors="true" + convertErrorsToExceptions="true" + convertNoticesToExceptions="true" + convertWarningsToExceptions="true" + processIsolation="false" + stopOnFailure="false" + syntaxCheck="false" + bootstrap="vendor/autoload.php" +> + <php> + <ini name="error_reporting" value="-1" /> + </php> + + <testsuites> + <testsuite name="Symfony Security Component ACL Test Suite"> + <directory>./Tests/</directory> + </testsuite> + </testsuites> + + <filter> + <whitelist> + <directory>./</directory> + <exclude> + <directory>./Resources</directory> + <directory>./Tests</directory> + <directory>./vendor</directory> + </exclude> + </whitelist> + </filter> +</phpunit> diff --git a/CHANGELOG.md b/CHANGELOG.md index 92f8073..22eb9cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,32 @@ CHANGELOG ========= +2.7.0 +----- + + * added LogoutUrlGenerator + * added the triggering of the `Symfony\Component\Security\Http\SecurityEvents::INTERACTIVE_LOGIN` in `Symfony\Component\Security\Http\Firewall\SimplePreAuthenticationListener` + * The MaskBuilder logic has been abstracted in the `Symfony\Component\Security\Acl\Permission\AbstractMaskBuilder` + and described in the `Symfony\Component\Security\Acl\Permission\MaskBuilderInterface` + * added interface `Symfony\Component\Security\Acl\Permission\MaskBuilderRetrievalInterface` + +2.6.0 +----- + + * added Symfony\Component\Security\Http\Authentication\AuthenticationUtils + * Deprecated the `SecurityContext` class in favor of the `AuthorizationChecker` and `TokenStorage` classes + +2.4.0 +----- + + * Translations in the `src/Symfony/Component/Security/Resources/translations/` directory are deprecated, ones in `src/Symfony/Component/Security/Core/Resources/translations/` must be used instead. + * The switch user listener now preserves the query string when switching a user + * The remember-me cookie hashes now use HMAC, which means that current cookies will be invalidated + * added simpler customization options + * structured component into three sub-components Acl, Core and Http + * added Csrf sub-component + * changed Http sub-component to depend on Csrf sub-component instead of the Form component + 2.3.0 ----- diff --git a/Core/.gitignore b/Core/.gitignore new file mode 100644 index 0000000..c49a5d8 --- /dev/null +++ b/Core/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/Core/Authentication/AuthenticationProviderManager.php b/Core/Authentication/AuthenticationProviderManager.php index f713e8f..16de8da 100644 --- a/Core/Authentication/AuthenticationProviderManager.php +++ b/Core/Authentication/AuthenticationProviderManager.php @@ -48,6 +48,12 @@ class AuthenticationProviderManager implements AuthenticationManagerInterface throw new \InvalidArgumentException('You must at least add one authentication provider.'); } + foreach ($providers as $provider) { + if (!$provider instanceof AuthenticationProviderInterface) { + throw new \InvalidArgumentException(sprintf('Provider "%s" must implement the AuthenticationProviderInterface.', get_class($provider))); + } + } + $this->providers = $providers; $this->eraseCredentials = (bool) $eraseCredentials; } diff --git a/Core/Authentication/Provider/PreAuthenticatedAuthenticationProvider.php b/Core/Authentication/Provider/PreAuthenticatedAuthenticationProvider.php index 87b7114..4f73254 100644 --- a/Core/Authentication/Provider/PreAuthenticatedAuthenticationProvider.php +++ b/Core/Authentication/Provider/PreAuthenticatedAuthenticationProvider.php @@ -47,28 +47,28 @@ class PreAuthenticatedAuthenticationProvider implements AuthenticationProviderIn $this->providerKey = $providerKey; } - /** - * {@inheritdoc} - */ - public function authenticate(TokenInterface $token) - { - if (!$this->supports($token)) { - return; - } + /** + * {@inheritdoc} + */ + public function authenticate(TokenInterface $token) + { + if (!$this->supports($token)) { + return; + } - if (!$user = $token->getUser()) { - throw new BadCredentialsException('No pre-authenticated principal found in request.'); - } + if (!$user = $token->getUser()) { + throw new BadCredentialsException('No pre-authenticated principal found in request.'); + } - $user = $this->userProvider->loadUserByUsername($user); + $user = $this->userProvider->loadUserByUsername($user); - $this->userChecker->checkPostAuth($user); + $this->userChecker->checkPostAuth($user); - $authenticatedToken = new PreAuthenticatedToken($user, $token->getCredentials(), $this->providerKey, $user->getRoles()); - $authenticatedToken->setAttributes($token->getAttributes()); + $authenticatedToken = new PreAuthenticatedToken($user, $token->getCredentials(), $this->providerKey, $user->getRoles()); + $authenticatedToken->setAttributes($token->getAttributes()); - return $authenticatedToken; - } + return $authenticatedToken; + } /** * {@inheritdoc} diff --git a/Core/Authentication/Provider/SimpleAuthenticationProvider.php b/Core/Authentication/Provider/SimpleAuthenticationProvider.php new file mode 100644 index 0000000..ffbc72c --- /dev/null +++ b/Core/Authentication/Provider/SimpleAuthenticationProvider.php @@ -0,0 +1,50 @@ +<?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\Authentication\Provider; + +use Symfony\Component\Security\Core\User\UserProviderInterface; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authentication\SimpleAuthenticatorInterface; +use Symfony\Component\Security\Core\Exception\AuthenticationException; + +/** + * @author Jordi Boggiano <j.boggiano@seld.be> + */ +class SimpleAuthenticationProvider implements AuthenticationProviderInterface +{ + private $simpleAuthenticator; + private $userProvider; + private $providerKey; + + public function __construct(SimpleAuthenticatorInterface $simpleAuthenticator, UserProviderInterface $userProvider, $providerKey) + { + $this->simpleAuthenticator = $simpleAuthenticator; + $this->userProvider = $userProvider; + $this->providerKey = $providerKey; + } + + public function authenticate(TokenInterface $token) + { + $authToken = $this->simpleAuthenticator->authenticateToken($token, $this->userProvider, $this->providerKey); + + if ($authToken instanceof TokenInterface) { + return $authToken; + } + + throw new AuthenticationException('Simple authenticator failed to return an authenticated token.'); + } + + public function supports(TokenInterface $token) + { + return $this->simpleAuthenticator->supportsToken($token, $this->providerKey); + } +} diff --git a/Core/Authentication/Provider/UserAuthenticationProvider.php b/Core/Authentication/Provider/UserAuthenticationProvider.php index a624ccf..2674088 100644 --- a/Core/Authentication/Provider/UserAuthenticationProvider.php +++ b/Core/Authentication/Provider/UserAuthenticationProvider.php @@ -70,7 +70,7 @@ abstract class UserAuthenticationProvider implements AuthenticationProviderInter $user = $this->retrieveUser($username, $token); } catch (UsernameNotFoundException $e) { if ($this->hideUserNotFoundExceptions) { - throw new BadCredentialsException('Bad credentials', 0, $e); + throw new BadCredentialsException('Bad credentials.', 0, $e); } $e->setUsername($username); @@ -87,7 +87,7 @@ abstract class UserAuthenticationProvider implements AuthenticationProviderInter $this->userChecker->checkPostAuth($user); } catch (BadCredentialsException $e) { if ($this->hideUserNotFoundExceptions) { - throw new BadCredentialsException('Bad credentials', 0, $e); + throw new BadCredentialsException('Bad credentials.', 0, $e); } throw $e; diff --git a/Core/Authentication/SimpleAuthenticatorInterface.php b/Core/Authentication/SimpleAuthenticatorInterface.php new file mode 100644 index 0000000..868d072 --- /dev/null +++ b/Core/Authentication/SimpleAuthenticatorInterface.php @@ -0,0 +1,25 @@ +<?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\Authentication; + +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\User\UserProviderInterface; + +/** + * @author Jordi Boggiano <j.boggiano@seld.be> + */ +interface SimpleAuthenticatorInterface +{ + public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey); + + public function supportsToken(TokenInterface $token, $providerKey); +} diff --git a/Core/Authentication/SimpleFormAuthenticatorInterface.php b/Core/Authentication/SimpleFormAuthenticatorInterface.php new file mode 100644 index 0000000..95ee881 --- /dev/null +++ b/Core/Authentication/SimpleFormAuthenticatorInterface.php @@ -0,0 +1,22 @@ +<?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\Authentication; + +use Symfony\Component\HttpFoundation\Request; + +/** + * @author Jordi Boggiano <j.boggiano@seld.be> + */ +interface SimpleFormAuthenticatorInterface extends SimpleAuthenticatorInterface +{ + public function createToken(Request $request, $username, $password, $providerKey); +} diff --git a/Core/Authentication/SimplePreAuthenticatorInterface.php b/Core/Authentication/SimplePreAuthenticatorInterface.php new file mode 100644 index 0000000..6164e7d --- /dev/null +++ b/Core/Authentication/SimplePreAuthenticatorInterface.php @@ -0,0 +1,22 @@ +<?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\Authentication; + +use Symfony\Component\HttpFoundation\Request; + +/** + * @author Jordi Boggiano <j.boggiano@seld.be> + */ +interface SimplePreAuthenticatorInterface extends SimpleAuthenticatorInterface +{ + public function createToken(Request $request, $providerKey); +} diff --git a/Core/Authentication/Token/AbstractToken.php b/Core/Authentication/Token/AbstractToken.php index b07312f..7538648 100644 --- a/Core/Authentication/Token/AbstractToken.php +++ b/Core/Authentication/Token/AbstractToken.php @@ -26,9 +26,9 @@ use Symfony\Component\Security\Core\User\EquatableInterface; abstract class AbstractToken implements TokenInterface { private $user; - private $roles; - private $authenticated; - private $attributes; + private $roles = array(); + private $authenticated = false; + private $attributes = array(); /** * Constructor. @@ -39,10 +39,6 @@ abstract class AbstractToken implements TokenInterface */ public function __construct(array $roles = array()) { - $this->authenticated = false; - $this->attributes = array(); - - $this->roles = array(); foreach ($roles as $role) { if (is_string($role)) { $role = new Role($role); @@ -219,7 +215,7 @@ abstract class AbstractToken implements TokenInterface } /** - * Sets a attribute. + * Sets an attribute. * * @param string $name The attribute name * @param mixed $value The attribute value diff --git a/Core/Authentication/Token/Storage/TokenStorage.php b/Core/Authentication/Token/Storage/TokenStorage.php new file mode 100644 index 0000000..b493081 --- /dev/null +++ b/Core/Authentication/Token/Storage/TokenStorage.php @@ -0,0 +1,43 @@ +<?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\Authentication\Token\Storage; + +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; + +/** + * TokenStorage contains a TokenInterface. + * + * It gives access to the token representing the current user authentication. + * + * @author Fabien Potencier <fabien@symfony.com> + * @author Johannes M. Schmitt <schmittjoh@gmail.com> + */ +class TokenStorage implements TokenStorageInterface +{ + private $token; + + /** + * {@inheritdoc} + */ + public function getToken() + { + return $this->token; + } + + /** + * {@inheritdoc} + */ + public function setToken(TokenInterface $token = null) + { + $this->token = $token; + } +} diff --git a/Core/Authentication/Token/Storage/TokenStorageInterface.php b/Core/Authentication/Token/Storage/TokenStorageInterface.php new file mode 100644 index 0000000..218d750 --- /dev/null +++ b/Core/Authentication/Token/Storage/TokenStorageInterface.php @@ -0,0 +1,36 @@ +<?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\Authentication\Token\Storage; + +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; + +/** + * The TokenStorageInterface. + * + * @author Johannes M. Schmitt <schmittjoh@gmail.com> + */ +interface TokenStorageInterface +{ + /** + * Returns the current security token. + * + * @return TokenInterface|null A TokenInterface instance or null if no authentication information is available + */ + public function getToken(); + + /** + * Sets the authentication token. + * + * @param TokenInterface $token A TokenInterface token, or null if no further authentication information should be stored + */ + public function setToken(TokenInterface $token = null); +} diff --git a/Core/Authorization/AccessDecisionManager.php b/Core/Authorization/AccessDecisionManager.php index 6e5effb..b8b6a77 100644 --- a/Core/Authorization/AccessDecisionManager.php +++ b/Core/Authorization/AccessDecisionManager.php @@ -22,6 +22,10 @@ use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; */ class AccessDecisionManager implements AccessDecisionManagerInterface { + const STRATEGY_AFFIRMATIVE = 'affirmative'; + const STRATEGY_CONSENSUS = 'consensus'; + const STRATEGY_UNANIMOUS = 'unanimous'; + private $voters; private $strategy; private $allowIfAllAbstainDecisions; @@ -37,14 +41,19 @@ class AccessDecisionManager implements AccessDecisionManagerInterface * * @throws \InvalidArgumentException */ - public function __construct(array $voters, $strategy = 'affirmative', $allowIfAllAbstainDecisions = false, $allowIfEqualGrantedDeniedDecisions = true) + public function __construct(array $voters, $strategy = self::STRATEGY_AFFIRMATIVE, $allowIfAllAbstainDecisions = false, $allowIfEqualGrantedDeniedDecisions = true) { if (!$voters) { throw new \InvalidArgumentException('You must at least add one voter.'); } + $strategyMethod = 'decide'.ucfirst($strategy); + if (!is_callable(array($this, $strategyMethod))) { + throw new \InvalidArgumentException(sprintf('The strategy "%s" is not supported.', $strategy)); + } + $this->voters = $voters; - $this->strategy = 'decide'.ucfirst($strategy); + $this->strategy = $strategyMethod; $this->allowIfAllAbstainDecisions = (bool) $allowIfAllAbstainDecisions; $this->allowIfEqualGrantedDeniedDecisions = (bool) $allowIfEqualGrantedDeniedDecisions; } diff --git a/Core/Authorization/AuthorizationChecker.php b/Core/Authorization/AuthorizationChecker.php new file mode 100644 index 0000000..23c190c --- /dev/null +++ b/Core/Authorization/AuthorizationChecker.php @@ -0,0 +1,70 @@ +<?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\Authorization; + +use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException; + +/** + * AuthorizationChecker is the main authorization point of the Security component. + * + * It gives access to the token representing the current user authentication. + * + * @author Fabien Potencier <fabien@symfony.com> + * @author Johannes M. Schmitt <schmittjoh@gmail.com> + */ +class AuthorizationChecker implements AuthorizationCheckerInterface +{ + private $tokenStorage; + private $accessDecisionManager; + private $authenticationManager; + private $alwaysAuthenticate; + + /** + * Constructor. + * + * @param TokenStorageInterface $tokenStorage + * @param AuthenticationManagerInterface $authenticationManager An AuthenticationManager instance + * @param AccessDecisionManagerInterface $accessDecisionManager An AccessDecisionManager instance + * @param bool $alwaysAuthenticate + */ + public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, AccessDecisionManagerInterface $accessDecisionManager, $alwaysAuthenticate = false) + { + $this->tokenStorage = $tokenStorage; + $this->authenticationManager = $authenticationManager; + $this->accessDecisionManager = $accessDecisionManager; + $this->alwaysAuthenticate = $alwaysAuthenticate; + } + + /** + * {@inheritdoc} + * + * @throws AuthenticationCredentialsNotFoundException when the token storage has no authentication token. + */ + final public function isGranted($attributes, $object = null) + { + if (null === ($token = $this->tokenStorage->getToken())) { + throw new AuthenticationCredentialsNotFoundException('The token storage contains no authentication token. One possible reason may be that there is no firewall configured for this URL.'); + } + + if ($this->alwaysAuthenticate || !$token->isAuthenticated()) { + $this->tokenStorage->setToken($token = $this->authenticationManager->authenticate($token)); + } + + if (!is_array($attributes)) { + $attributes = array($attributes); + } + + return $this->accessDecisionManager->decide($token, $attributes, $object); + } +} diff --git a/Core/Authorization/AuthorizationCheckerInterface.php b/Core/Authorization/AuthorizationCheckerInterface.php new file mode 100644 index 0000000..bd24d6f --- /dev/null +++ b/Core/Authorization/AuthorizationCheckerInterface.php @@ -0,0 +1,30 @@ +<?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\Authorization; + +/** + * The AuthorizationCheckerInterface. + * + * @author Johannes M. Schmitt <schmittjoh@gmail.com> + */ +interface AuthorizationCheckerInterface +{ + /** + * Checks if the attributes are granted against the current authentication token and optionally supplied object. + * + * @param mixed $attributes + * @param mixed $object + * + * @return bool + */ + public function isGranted($attributes, $object = null); +} diff --git a/Core/Authorization/ExpressionLanguage.php b/Core/Authorization/ExpressionLanguage.php new file mode 100644 index 0000000..c2925af --- /dev/null +++ b/Core/Authorization/ExpressionLanguage.php @@ -0,0 +1,33 @@ +<?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\Authorization; + +use Symfony\Component\ExpressionLanguage\ExpressionLanguage as BaseExpressionLanguage; +use Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface; + +/** + * Adds some function to the default ExpressionLanguage. + * + * @author Fabien Potencier <fabien@symfony.com> + * + * @see ExpressionLanguageProvider + */ +class ExpressionLanguage extends BaseExpressionLanguage +{ + public function __construct(ParserCacheInterface $cache = null, array $providers = array()) + { + // prepend the default provider to let users override it easily + array_unshift($providers, new ExpressionLanguageProvider()); + + parent::__construct($cache, $providers); + } +} diff --git a/Core/Authorization/ExpressionLanguageProvider.php b/Core/Authorization/ExpressionLanguageProvider.php new file mode 100644 index 0000000..9293ba7 --- /dev/null +++ b/Core/Authorization/ExpressionLanguageProvider.php @@ -0,0 +1,58 @@ +<?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\Authorization; + +use Symfony\Component\ExpressionLanguage\ExpressionFunction; +use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface; + +/** + * Define some ExpressionLanguage functions. + * + * @author Fabien Potencier <fabien@symfony.com> + */ +class ExpressionLanguageProvider implements ExpressionFunctionProviderInterface +{ + public function getFunctions() + { + return array( + new ExpressionFunction('is_anonymous', function () { + return '$trust_resolver->isAnonymous($token)'; + }, function (array $variables) { + return $variables['trust_resolver']->isAnonymous($variables['token']); + }), + + new ExpressionFunction('is_authenticated', function () { + return '$token && !$trust_resolver->isAnonymous($token)'; + }, function (array $variables) { + return $variables['token'] && !$variables['trust_resolver']->isAnonymous($variables['token']); + }), + + new ExpressionFunction('is_fully_authenticated', function () { + return '$trust_resolver->isFullFledged($token)'; + }, function (array $variables) { + return $variables['trust_resolver']->isFullFledged($variables['token']); + }), + + new ExpressionFunction('is_remember_me', function () { + return '$trust_resolver->isRememberMe($token)'; + }, function (array $variables) { + return $variables['trust_resolver']->isRememberMe($variables['token']); + }), + + new ExpressionFunction('has_role', function ($role) { + return sprintf('in_array(%s, $roles)', $role); + }, function (array $variables, $role) { + return in_array($role, $variables['roles']); + }), + ); + } +} diff --git a/Core/Authorization/Voter/AbstractVoter.php b/Core/Authorization/Voter/AbstractVoter.php new file mode 100644 index 0000000..efa1562 --- /dev/null +++ b/Core/Authorization/Voter/AbstractVoter.php @@ -0,0 +1,113 @@ +<?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\Authorization\Voter; + +use Symfony\Component\Security\Core\User\UserInterface; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; + +/** + * Abstract Voter implementation that reduces boilerplate code required to create a custom Voter. + * + * @author Roman Marintšenko <inoryy@gmail.com> + */ +abstract class AbstractVoter implements VoterInterface +{ + /** + * {@inheritdoc} + */ + public function supportsAttribute($attribute) + { + return in_array($attribute, $this->getSupportedAttributes()); + } + + /** + * {@inheritdoc} + */ + public function supportsClass($class) + { + foreach ($this->getSupportedClasses() as $supportedClass) { + if ($supportedClass === $class || is_subclass_of($class, $supportedClass)) { + return true; + } + } + + return false; + } + + /** + * Iteratively check all given attributes by calling isGranted. + * + * This method terminates as soon as it is able to return ACCESS_GRANTED + * If at least one attribute is supported, but access not granted, then ACCESS_DENIED is returned + * Otherwise it will return ACCESS_ABSTAIN + * + * @param TokenInterface $token A TokenInterface instance + * @param object $object The object to secure + * @param array $attributes An array of attributes associated with the method being invoked + * + * @return int either ACCESS_GRANTED, ACCESS_ABSTAIN, or ACCESS_DENIED + */ + public function vote(TokenInterface $token, $object, array $attributes) + { + if (!$object || !$this->supportsClass(get_class($object))) { + return self::ACCESS_ABSTAIN; + } + + // abstain vote by default in case none of the attributes are supported + $vote = self::ACCESS_ABSTAIN; + + foreach ($attributes as $attribute) { + if (!$this->supportsAttribute($attribute)) { + continue; + } + + // as soon as at least one attribute is supported, default is to deny access + $vote = self::ACCESS_DENIED; + + if ($this->isGranted($attribute, $object, $token->getUser())) { + // grant access as soon as at least one voter returns a positive response + return self::ACCESS_GRANTED; + } + } + + return $vote; + } + + /** + * Return an array of supported classes. This will be called by supportsClass. + * + * @return array an array of supported classes, i.e. array('Acme\DemoBundle\Model\Product') + */ + abstract protected function getSupportedClasses(); + + /** + * Return an array of supported attributes. This will be called by supportsAttribute. + * + * @return array an array of supported attributes, i.e. array('CREATE', 'READ') + */ + abstract protected function getSupportedAttributes(); + + /** + * Perform a single access check operation on a given attribute, object and (optionally) user + * It is safe to assume that $attribute and $object's class pass supportsAttribute/supportsClass + * $user can be one of the following: + * a UserInterface object (fully authenticated user) + * a string (anonymously authenticated user). + * + * @param string $attribute + * @param object $object + * @param UserInterface|string $user + * + * @return bool + */ + abstract protected function isGranted($attribute, $object, $user = null); +} diff --git a/Core/Authorization/Voter/ExpressionVoter.php b/Core/Authorization/Voter/ExpressionVoter.php new file mode 100644 index 0000000..98b8f50 --- /dev/null +++ b/Core/Authorization/Voter/ExpressionVoter.php @@ -0,0 +1,118 @@ +<?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\Authorization\Voter; + +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface; +use Symfony\Component\Security\Core\Authorization\ExpressionLanguage; +use Symfony\Component\Security\Core\Role\RoleHierarchyInterface; +use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface; +use Symfony\Component\ExpressionLanguage\Expression; +use Symfony\Component\HttpFoundation\Request; + +/** + * ExpressionVoter votes based on the evaluation of an expression. + * + * @author Fabien Potencier <fabien@symfony.com> + */ +class ExpressionVoter implements VoterInterface +{ + private $expressionLanguage; + private $trustResolver; + private $roleHierarchy; + + /** + * Constructor. + * + * @param ExpressionLanguage $expressionLanguage + * @param AuthenticationTrustResolverInterface $trustResolver + * @param RoleHierarchyInterface|null $roleHierarchy + */ + public function __construct(ExpressionLanguage $expressionLanguage, AuthenticationTrustResolverInterface $trustResolver, RoleHierarchyInterface $roleHierarchy = null) + { + $this->expressionLanguage = $expressionLanguage; + $this->trustResolver = $trustResolver; + $this->roleHierarchy = $roleHierarchy; + } + + public function addExpressionLanguageProvider(ExpressionFunctionProviderInterface $provider) + { + $this->expressionLanguage->registerProvider($provider); + } + + /** + * {@inheritdoc} + */ + public function supportsAttribute($attribute) + { + return $attribute instanceof Expression; + } + + /** + * {@inheritdoc} + */ + public function supportsClass($class) + { + return true; + } + + /** + * {@inheritdoc} + */ + public function vote(TokenInterface $token, $object, array $attributes) + { + $result = VoterInterface::ACCESS_ABSTAIN; + $variables = null; + foreach ($attributes as $attribute) { + if (!$this->supportsAttribute($attribute)) { + continue; + } + + if (null === $variables) { + $variables = $this->getVariables($token, $object); + } + + $result = VoterInterface::ACCESS_DENIED; + if ($this->expressionLanguage->evaluate($attribute, $variables)) { + return VoterInterface::ACCESS_GRANTED; + } + } + + return $result; + } + + private function getVariables(TokenInterface $token, $object) + { + if (null !== $this->roleHierarchy) { + $roles = $this->roleHierarchy->getReachableRoles($token->getRoles()); + } else { + $roles = $token->getRoles(); + } + + $variables = array( + 'token' => $token, + 'user' => $token->getUser(), + 'object' => $object, + 'roles' => array_map(function ($role) { return $role->getRole(); }, $roles), + 'trust_resolver' => $this->trustResolver, + ); + + // this is mainly to propose a better experience when the expression is used + // in an access control rule, as the developer does not know that it's going + // to be handled by this voter + if ($object instanceof Request) { + $variables['request'] = $object; + } + + return $variables; + } +} diff --git a/Core/Encoder/EncoderAwareInterface.php b/Core/Encoder/EncoderAwareInterface.php new file mode 100644 index 0000000..22ae820 --- /dev/null +++ b/Core/Encoder/EncoderAwareInterface.php @@ -0,0 +1,28 @@ +<?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\Encoder; + +/** + * @author Christophe Coevoet <stof@notk.org> + */ +interface EncoderAwareInterface +{ + /** + * Gets the name of the encoder used to encode the password. + * + * If the method returns null, the standard way to retrieve the encoder + * will be used instead. + * + * @return string + */ + public function getEncoderName(); +} diff --git a/Core/Encoder/EncoderFactory.php b/Core/Encoder/EncoderFactory.php index 5f6c20c..0568d41 100644 --- a/Core/Encoder/EncoderFactory.php +++ b/Core/Encoder/EncoderFactory.php @@ -30,19 +30,32 @@ class EncoderFactory implements EncoderFactoryInterface */ public function getEncoder($user) { - foreach ($this->encoders as $class => $encoder) { - if ((is_object($user) && !$user instanceof $class) || (!is_object($user) && !is_subclass_of($user, $class) && $user != $class)) { - continue; + $encoderKey = null; + + if ($user instanceof EncoderAwareInterface && (null !== $encoderName = $user->getEncoderName())) { + if (!array_key_exists($encoderName, $this->encoders)) { + throw new \RuntimeException(sprintf('The encoder "%s" was not configured.', $encoderName)); } - if (!$encoder instanceof PasswordEncoderInterface) { - return $this->encoders[$class] = $this->createEncoder($encoder); + $encoderKey = $encoderName; + } else { + foreach ($this->encoders as $class => $encoder) { + if ((is_object($user) && $user instanceof $class) || (!is_object($user) && (is_subclass_of($user, $class) || $user == $class))) { + $encoderKey = $class; + break; + } } + } + + if (null === $encoderKey) { + throw new \RuntimeException(sprintf('No encoder has been configured for account "%s".', is_object($user) ? get_class($user) : $user)); + } - return $this->encoders[$class]; + if (!$this->encoders[$encoderKey] instanceof PasswordEncoderInterface) { + $this->encoders[$encoderKey] = $this->createEncoder($this->encoders[$encoderKey]); } - throw new \RuntimeException(sprintf('No encoder has been configured for account "%s".', is_object($user) ? get_class($user) : $user)); + return $this->encoders[$encoderKey]; } /** diff --git a/Core/Encoder/UserPasswordEncoder.php b/Core/Encoder/UserPasswordEncoder.php new file mode 100644 index 0000000..b096049 --- /dev/null +++ b/Core/Encoder/UserPasswordEncoder.php @@ -0,0 +1,55 @@ +<?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\Encoder; + +use Symfony\Component\Security\Core\User\UserInterface; + +/** + * A generic password encoder. + * + * @author Ariel Ferrandini <arielferrandini@gmail.com> + */ +class UserPasswordEncoder implements UserPasswordEncoderInterface +{ + /** + * @var EncoderFactoryInterface + */ + private $encoderFactory; + + /** + * @param EncoderFactoryInterface $encoderFactory The encoder factory + */ + public function __construct(EncoderFactoryInterface $encoderFactory) + { + $this->encoderFactory = $encoderFactory; + } + + /** + * {@inheritdoc} + */ + public function encodePassword(UserInterface $user, $plainPassword) + { + $encoder = $this->encoderFactory->getEncoder($user); + + return $encoder->encodePassword($plainPassword, $user->getSalt()); + } + + /** + * {@inheritdoc} + */ + public function isPasswordValid(UserInterface $user, $raw) + { + $encoder = $this->encoderFactory->getEncoder($user); + + return $encoder->isPasswordValid($user->getPassword(), $raw, $user->getSalt()); + } +} diff --git a/Core/Encoder/UserPasswordEncoderInterface.php b/Core/Encoder/UserPasswordEncoderInterface.php new file mode 100644 index 0000000..7861caa --- /dev/null +++ b/Core/Encoder/UserPasswordEncoderInterface.php @@ -0,0 +1,40 @@ +<?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\Encoder; + +use Symfony\Component\Security\Core\User\UserInterface; + +/** + * UserPasswordEncoderInterface is the interface for the password encoder service. + * + * @author Ariel Ferrandini <arielferrandini@gmail.com> + */ +interface UserPasswordEncoderInterface +{ + /** + * Encodes the plain password. + * + * @param UserInterface $user The user + * @param string $plainPassword The password to encode + * + * @return string The encoded password + */ + public function encodePassword(UserInterface $user, $plainPassword); + + /** + * @param UserInterface $user The user + * @param string $raw A raw password + * + * @return bool true if the password is valid, false otherwise + */ + public function isPasswordValid(UserInterface $user, $raw); +} diff --git a/Core/Exception/AccessDeniedException.php b/Core/Exception/AccessDeniedException.php index 7c16afb..736a36b 100644 --- a/Core/Exception/AccessDeniedException.php +++ b/Core/Exception/AccessDeniedException.php @@ -18,7 +18,7 @@ namespace Symfony\Component\Security\Core\Exception; */ class AccessDeniedException extends \RuntimeException { - public function __construct($message = 'Access Denied', \Exception $previous = null) + public function __construct($message = 'Access Denied.', \Exception $previous = null) { parent::__construct($message, 403, $previous); } diff --git a/Core/Exception/ExceptionInterface.php b/Core/Exception/ExceptionInterface.php new file mode 100644 index 0000000..5000d02 --- /dev/null +++ b/Core/Exception/ExceptionInterface.php @@ -0,0 +1,21 @@ +<?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; + +/** + * Base ExceptionInterface for the Security component. + * + * @author Bernhard Schussek <bschussek@gmail.com> + */ +interface ExceptionInterface +{ +} diff --git a/Core/Exception/InvalidArgumentException.php b/Core/Exception/InvalidArgumentException.php new file mode 100644 index 0000000..6f85e95 --- /dev/null +++ b/Core/Exception/InvalidArgumentException.php @@ -0,0 +1,21 @@ +<?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; + +/** + * Base InvalidArgumentException for the Security component. + * + * @author Bernhard Schussek <bschussek@gmail.com> + */ +class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/Core/Exception/RuntimeException.php b/Core/Exception/RuntimeException.php new file mode 100644 index 0000000..95edec8 --- /dev/null +++ b/Core/Exception/RuntimeException.php @@ -0,0 +1,21 @@ +<?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; + +/** + * Base RuntimeException for the Security component. + * + * @author Bernhard Schussek <bschussek@gmail.com> + */ +class RuntimeException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/Core/Exception/UsernameNotFoundException.php b/Core/Exception/UsernameNotFoundException.php index 11607d3..6979389 100644 --- a/Core/Exception/UsernameNotFoundException.php +++ b/Core/Exception/UsernameNotFoundException.php @@ -69,4 +69,12 @@ class UsernameNotFoundException extends AuthenticationException parent::unserialize($parentData); } + + /** + * {@inheritdoc} + */ + public function getMessageData() + { + return array('{{ username }}' => $this->username); + } } diff --git a/Core/LICENSE b/Core/LICENSE new file mode 100644 index 0000000..12a7453 --- /dev/null +++ b/Core/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2004-2016 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Core/README.md b/Core/README.md new file mode 100644 index 0000000..ede185b --- /dev/null +++ b/Core/README.md @@ -0,0 +1,16 @@ +Security Component - Core +========================= + +Security provides an infrastructure for sophisticated authorization systems, +which makes it possible to easily separate the actual authorization logic from +so called user providers that hold the users credentials. It is inspired by +the Java Spring framework. + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/components/security/index.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/Core/Resources/translations/security.ar.xlf b/Core/Resources/translations/security.ar.xlf new file mode 100644 index 0000000..fd18ee6 --- /dev/null +++ b/Core/Resources/translations/security.ar.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>حدث خطأ اثناء الدخول.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>لم استطع العثور على معلومات الدخول.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>لم يكتمل طلب الدخول نتيجه عطل فى النظام.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>معلومات الدخول خاطئة.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>ملفات تعريف الارتباط(cookies) تم استخدامها من قبل شخص اخر.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>ليست لديك الصلاحيات الكافية لهذا الطلب.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>رمز الموقع غير صحيح.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>انتهت صلاحية(digest nonce).</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>لا يوجد معرف للدخول يدعم الرمز المستخدم للدخول.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>لا يوجد صلة بينك و بين الموقع اما انها انتهت او ان متصفحك لا يدعم خاصية ملفات تعريف الارتباط (cookies).</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>لم استطع العثور على الرمز.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>لم استطع العثور على اسم الدخول.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>انتهت صلاحية الحساب.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>انتهت صلاحية معلومات الدخول.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>الحساب موقوف.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>الحساب مغلق.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.az.xlf b/Core/Resources/translations/security.az.xlf new file mode 100644 index 0000000..a974ed0 --- /dev/null +++ b/Core/Resources/translations/security.az.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>Doğrulama istisnası baş verdi.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>Doğrulama məlumatları tapılmadı.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>Sistem xətası səbəbilə doğrulama istəyi emal edilə bilmədi.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Yanlış məlumat.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Kuki başqası tərəfindən istifadə edilib.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Resurs istəyi üçün imtiyaz yoxdur.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Yanlış CSRF nişanı.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Dərləmə istifadə müddəti bitib.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>Doğrulama nişanını dəstəkləyəcək provayder tapılmadı.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>Uyğun seans yoxdur, vaxtı keçib və ya kuki aktiv deyil.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>Nişan tapılmadı.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>İstifadəçi adı tapılmadı.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>Hesabın istifadə müddəti bitib.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>Məlumatların istifadə müddəti bitib.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>Hesab qeyri-aktiv edilib.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>Hesab kilitlənib.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.bg.xlf b/Core/Resources/translations/security.bg.xlf new file mode 100644 index 0000000..06692ea --- /dev/null +++ b/Core/Resources/translations/security.bg.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>Грешка при автентикация.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>Удостоверението за автентикация не е открито.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>Заявката за автентикация не може да бъде обработената поради системна грешка.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Невалидно удостоверение за автентикация.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Това cookie вече се ползва от някой друг.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Нямате права за достъп до този ресурс.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Невалиден CSRF токен.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Digest nonce е изтекъл.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>Не е открит провайдър, който да поддържа този токен за автентикация.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>Сесията не е достъпна, или времето за достъп е изтекло, или кукитата не са разрешени.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>Токена не е открит.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>Потребителското име не е открито.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>Акаунта е изтекъл.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>Удостоверението за автентикация е изтекло.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>Акаунта е деактивиран.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>Акаунта е заключен.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.ca.xlf b/Core/Resources/translations/security.ca.xlf new file mode 100644 index 0000000..7ece260 --- /dev/null +++ b/Core/Resources/translations/security.ca.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>Ha succeït un error d'autenticació.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>No s'han trobat les credencials d'autenticació.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>La solicitud d'autenticació no s'ha pogut processar per un problema del sistema.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Credencials no vàlides.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>La cookie ja ha estat utilitzada per una altra persona.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>No té privilegis per solicitar el recurs.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Token CSRF no vàlid.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>El vector d'inicialització (digest nonce) ha expirat.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>No s'ha trobat un proveïdor d'autenticació que suporti el token d'autenticació.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>No hi ha sessió disponible, ha expirat o les cookies no estan habilitades.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>No s'ha trobat cap token.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>No s'ha trobat el nom d'usuari.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>El compte ha expirat.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>Les credencials han expirat.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>El compte està deshabilitat.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>El compte està bloquejat.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.cs.xlf b/Core/Resources/translations/security.cs.xlf new file mode 100644 index 0000000..bd146c6 --- /dev/null +++ b/Core/Resources/translations/security.cs.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>Při ověřování došlo k chybě.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>Ověřovací údaje nebyly nalezeny.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>Požadavek na ověření nemohl být zpracován kvůli systémové chybě.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Neplatné přihlašovací údaje.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Cookie již bylo použité někým jiným.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Nemáte oprávnění přistupovat k prostředku.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Neplatný CSRF token.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Platnost inicializačního vektoru (digest nonce) vypršela.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>Poskytovatel pro ověřovací token nebyl nalezen.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>Session není k dispozici, vypršela její platnost, nebo jsou zakázané cookies.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>Token nebyl nalezen.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>Přihlašovací jméno nebylo nalezeno.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>Platnost účtu vypršela.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>Platnost přihlašovacích údajů vypršela.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>Účet je zakázaný.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>Účet je zablokovaný.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.da.xlf b/Core/Resources/translations/security.da.xlf new file mode 100644 index 0000000..2ac4150 --- /dev/null +++ b/Core/Resources/translations/security.da.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>En fejl indtraf ved godkendelse.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>Loginoplysninger kan findes.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>Godkendelsesanmodning kan ikke behandles på grund af et systemfejl.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Ugyldige loginoplysninger.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Cookie er allerede brugt af en anden.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Ingen tilladselese at anvende kilden.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Ugyldigt CSRF token.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Digest nonce er udløbet.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>Ingen godkendelsesudbyder er fundet til understøttelsen af godkendelsestoken.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>Ingen session tilgængelig, sessionen er enten udløbet eller cookies er ikke aktiveret.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>Ingen token kan findes.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>Brugernavn kan ikke findes.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>Brugerkonto er udløbet.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>Loginoplysninger er udløbet.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>Brugerkonto er deaktiveret.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>Brugerkonto er låst.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.de.xlf b/Core/Resources/translations/security.de.xlf new file mode 100644 index 0000000..e5946ed --- /dev/null +++ b/Core/Resources/translations/security.de.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>Es ist ein Fehler bei der Authentifikation aufgetreten.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>Es konnten keine Zugangsdaten gefunden werden.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>Die Authentifikation konnte wegen eines Systemproblems nicht bearbeitet werden.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Fehlerhafte Zugangsdaten.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Cookie wurde bereits von jemand anderem verwendet.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Keine Rechte, um die Ressource anzufragen.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Ungültiges CSRF-Token.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Digest nonce ist abgelaufen.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>Es wurde kein Authentifizierungs-Provider gefunden, der das Authentifizierungs-Token unterstützt.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>Keine Session verfügbar, entweder ist diese abgelaufen oder Cookies sind nicht aktiviert.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>Es wurde kein Token gefunden.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>Der Benutzername wurde nicht gefunden.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>Der Account ist abgelaufen.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>Die Zugangsdaten sind abgelaufen.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>Der Account ist deaktiviert.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>Der Account ist gesperrt.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.el.xlf b/Core/Resources/translations/security.el.xlf new file mode 100644 index 0000000..07eabe7 --- /dev/null +++ b/Core/Resources/translations/security.el.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>Συνέβη ένα σφάλμα πιστοποίησης.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>Τα στοιχεία πιστοποίησης δε βρέθηκαν.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>Το αίτημα πιστοποίησης δε μπορεί να επεξεργαστεί λόγω σφάλματος του συστήματος.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Λανθασμένα στοιχεία σύνδεσης.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Το Cookie έχει ήδη χρησιμοποιηθεί από κάποιον άλλο.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Δεν είστε εξουσιοδοτημένος για πρόσβαση στο συγκεκριμένο περιεχόμενο.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Μη έγκυρο CSRF token.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Το digest nonce έχει λήξει.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>Δε βρέθηκε κάποιος πάροχος πιστοποίησης που να υποστηρίζει το token πιστοποίησης.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>Δεν υπάρχει ενεργή σύνοδος (session), είτε έχει λήξει ή τα cookies δεν είναι ενεργοποιημένα.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>Δεν ήταν δυνατόν να βρεθεί κάποιο token.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>Το Username δε βρέθηκε.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>Ο λογαριασμός έχει λήξει.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>Τα στοιχεία σύνδεσης έχουν λήξει.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>Ο λογαριασμός είναι απενεργοποιημένος.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>Ο λογαριασμός είναι κλειδωμένος.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.en.xlf b/Core/Resources/translations/security.en.xlf new file mode 100644 index 0000000..3640698 --- /dev/null +++ b/Core/Resources/translations/security.en.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>An authentication exception occurred.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>Authentication credentials could not be found.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>Authentication request could not be processed due to a system problem.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Invalid credentials.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Cookie has already been used by someone else.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Not privileged to request the resource.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Invalid CSRF token.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Digest nonce has expired.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>No authentication provider found to support the authentication token.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>No session available, it either timed out or cookies are not enabled.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>No token could be found.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>Username could not be found.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>Account has expired.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>Credentials have expired.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>Account is disabled.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>Account is locked.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.es.xlf b/Core/Resources/translations/security.es.xlf new file mode 100644 index 0000000..00cefbb --- /dev/null +++ b/Core/Resources/translations/security.es.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>Ocurrió un error de autenticación.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>No se encontraron las credenciales de autenticación.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>La solicitud de autenticación no se pudo procesar debido a un problema del sistema.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Credenciales no válidas.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>La cookie ya ha sido usada por otra persona.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>No tiene privilegios para solicitar el recurso.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Token CSRF no válido.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>El vector de inicialización (digest nonce) ha expirado.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>No se encontró un proveedor de autenticación que soporte el token de autenticación.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>No hay ninguna sesión disponible, ha expirado o las cookies no están habilitados.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>No se encontró ningún token.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>No se encontró el nombre de usuario.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>La cuenta ha expirado.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>Las credenciales han expirado.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>La cuenta está deshabilitada.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>La cuenta está bloqueada.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.fa.xlf b/Core/Resources/translations/security.fa.xlf new file mode 100644 index 0000000..0b76290 --- /dev/null +++ b/Core/Resources/translations/security.fa.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>خطایی هنگام تعیین اعتبار اتفاق افتاد.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>شرایط تعیین اعتبار پیدا نشد.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>درخواست تعیین اعتبار به دلیل مشکل سیستم قابل بررسی نیست.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>شرایط نامعتبر.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>کوکی قبلا برای شخص دیگری استفاده شده است.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>دسترسی لازم برای درخواست این منبع را ندارید.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>توکن CSRF معتبر نیست.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Digest nonce منقضی شده است.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>هیچ ارایه کننده تعیین اعتباری برای ساپورت توکن تعیین اعتبار پیدا نشد.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>جلسهای در دسترس نیست. این میتواند یا به دلیل پایان یافتن زمان باشد یا اینکه کوکی ها فعال نیستند.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>هیچ توکنی پیدا نشد.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>نام کاربری پیدا نشد.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>حساب کاربری منقضی شده است.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>پارامترهای تعیین اعتبار منقضی شدهاند.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>حساب کاربری غیرفعال است.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>حساب کاربری قفل شده است.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.fr.xlf b/Core/Resources/translations/security.fr.xlf new file mode 100644 index 0000000..5a77c6e --- /dev/null +++ b/Core/Resources/translations/security.fr.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>Une exception d'authentification s'est produite.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>Les identifiants d'authentification n'ont pas pu être trouvés.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>La requête d'authentification n'a pas pu être executée à cause d'un problème système.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Identifiants invalides.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Le cookie a déjà été utilisé par quelqu'un d'autre.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Privilèges insuffisants pour accéder à la ressource.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Jeton CSRF invalide.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Le digest nonce a expiré.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>Aucun fournisseur d'authentification n'a été trouvé pour supporter le jeton d'authentification.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>Aucune session disponible, celle-ci a expiré ou les cookies ne sont pas activés.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>Aucun jeton n'a pu être trouvé.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>Le nom d'utilisateur n'a pas pu être trouvé.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>Le compte a expiré.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>Les identifiants ont expiré.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>Le compte est désactivé.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>Le compte est bloqué.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.gl.xlf b/Core/Resources/translations/security.gl.xlf new file mode 100644 index 0000000..ed6491f --- /dev/null +++ b/Core/Resources/translations/security.gl.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>Ocorreu un erro de autenticación.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>Non se atoparon as credenciais de autenticación.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>A solicitude de autenticación no puido ser procesada debido a un problema do sistema.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Credenciais non válidas.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>A cookie xa foi empregado por outro usuario.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Non ten privilexios para solicitar o recurso.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Token CSRF non válido.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>O vector de inicialización (digest nonce) expirou.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>Non se atopou un provedor de autenticación que soporte o token de autenticación.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>Non hai ningunha sesión dispoñible, expirou ou as cookies non están habilitadas.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>Non se atopou ningún token.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>Non se atopou o nome de usuario.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>A conta expirou.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>As credenciais expiraron.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>A conta está deshabilitada.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>A conta está bloqueada.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.he.xlf b/Core/Resources/translations/security.he.xlf new file mode 100644 index 0000000..3640698 --- /dev/null +++ b/Core/Resources/translations/security.he.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>An authentication exception occurred.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>Authentication credentials could not be found.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>Authentication request could not be processed due to a system problem.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Invalid credentials.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Cookie has already been used by someone else.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Not privileged to request the resource.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Invalid CSRF token.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Digest nonce has expired.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>No authentication provider found to support the authentication token.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>No session available, it either timed out or cookies are not enabled.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>No token could be found.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>Username could not be found.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>Account has expired.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>Credentials have expired.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>Account is disabled.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>Account is locked.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.hr.xlf b/Core/Resources/translations/security.hr.xlf new file mode 100644 index 0000000..147b6e3 --- /dev/null +++ b/Core/Resources/translations/security.hr.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>Dogodila se autentifikacijske iznimka.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>Autentifikacijski podaci nisu pronađeni.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>Autentifikacijski zahtjev nije moguće provesti uslijed sistemskog problema.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Neispravni akreditacijski podaci.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Cookie je već netko drugi iskoristio.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Nemate privilegije zahtijevati resurs.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Neispravan CSRF token.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Digest nonce je isteko.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>Nije pronađen autentifikacijski provider koji bi podržao autentifikacijski token.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>Sesija nije dostupna, ili je istekla ili cookies nisu omogućeni.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>Token nije pronađen.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>Korisničko ime nije pronađeno.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>Račun je isteko.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>Akreditacijski podaci su istekli.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>Račun je onemogućen.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>Račun je zaključan.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.hu.xlf b/Core/Resources/translations/security.hu.xlf new file mode 100644 index 0000000..7243970 --- /dev/null +++ b/Core/Resources/translations/security.hu.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>Hitelesítési hiba lépett fel.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>Nem találhatók hitelesítési információk.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>A hitelesítési kérést rendszerhiba miatt nem lehet feldolgozni.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Érvénytelen hitelesítési információk.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Ezt a sütit valaki más már felhasználta.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Nem rendelkezik az erőforrás eléréséhez szükséges jogosultsággal.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Érvénytelen CSRF token.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>A kivonat bélyege (nonce) lejárt.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>Nem található a hitelesítési tokent támogató hitelesítési szolgáltatás.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>Munkamenet nem áll rendelkezésre, túllépte az időkeretet vagy a sütik le vannak tiltva.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>Nem található token.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>A felhasználónév nem található.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>A fiók lejárt.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>A hitelesítési információk lejártak.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>Felfüggesztett fiók.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>Zárolt fiók.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.id.xlf b/Core/Resources/translations/security.id.xlf new file mode 100644 index 0000000..ab1153b --- /dev/null +++ b/Core/Resources/translations/security.id.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>Terjadi sebuah pengecualian otentikasi.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>Kredensial otentikasi tidak bisa ditemukan.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>Permintaan otentikasi tidak bisa diproses karena masalah sistem.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Kredensial salah.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Cookie sudah digunakan oleh orang lain.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Tidak berhak untuk meminta sumber daya.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Token CSRF salah.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Digest nonce telah berakhir.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>Tidak ditemukan penyedia otentikasi untuk mendukung token otentikasi.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>Tidak ada sesi yang tersedia, mungkin waktu sudah habis atau cookie tidak diaktifkan</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>Tidak ada token yang bisa ditemukan.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>Username tidak bisa ditemukan.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>Akun telah berakhir.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>Kredensial telah berakhir.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>Akun dinonaktifkan.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>Akun terkunci.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.it.xlf b/Core/Resources/translations/security.it.xlf new file mode 100644 index 0000000..75d81cc --- /dev/null +++ b/Core/Resources/translations/security.it.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>Si è verificato un errore di autenticazione.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>Impossibile trovare le credenziali di autenticazione.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>La richiesta di autenticazione non può essere processata a causa di un errore di sistema.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Credenziali non valide.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Il cookie è già stato usato da qualcun altro.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Non hai i privilegi per richiedere questa risorsa.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>CSRF token non valido.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Il numero di autenticazione è scaduto.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>Non è stato trovato un valido fornitore di autenticazione per supportare il token.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>Nessuna sessione disponibile, può essere scaduta o i cookie non sono abilitati.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>Nessun token trovato.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>Username non trovato.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>Account scaduto.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>Credenziali scadute.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>L'account è disabilitato.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>L'account è bloccato.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.ja.xlf b/Core/Resources/translations/security.ja.xlf new file mode 100644 index 0000000..6a6b062 --- /dev/null +++ b/Core/Resources/translations/security.ja.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>認証エラーが発生しました。</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>認証資格がありません。</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>システムの問題により認証要求を処理できませんでした。</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>資格が無効です。</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Cookie が別のユーザーで使用されています。</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>リソースをリクエストする権限がありません。</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>CSRF トークンが無効です。</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Digest の nonce 値が期限切れです。</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>認証トークンをサポートする認証プロバイダーが見つかりません。</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>利用可能なセッションがありません。タイムアウトしたか、Cookie が無効になっています。</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>トークンが見つかりません。</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>ユーザー名が見つかりません。</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>アカウントが有効期限切れです。</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>資格が有効期限切れです。</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>アカウントが無効です。</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>アカウントはロックされています。</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.lb.xlf b/Core/Resources/translations/security.lb.xlf new file mode 100644 index 0000000..3dc76d5 --- /dev/null +++ b/Core/Resources/translations/security.lb.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" target-language="lb" datatype="plaintext" original="security.en.xlf"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>Bei der Authentifikatioun ass e Feeler opgetrueden.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>Et konnte keng Zouganksdate fonnt ginn.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>D'Ufro fir eng Authentifikatioun konnt wéinst engem Problem vum System net beaarbecht ginn.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Ongëlteg Zouganksdaten.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>De Cookie gouf scho vun engem anere benotzt.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Keng Rechter fir d'Ressource unzefroen.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Ongëltegen CSRF-Token.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Den eemolege Schlëssel ass ofgelaf.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>Et gouf keen Authentifizéierungs-Provider fonnt deen den Authentifizéierungs-Token ënnerstëtzt.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>Keng Sëtzung disponibel. Entweder ass se ofgelaf oder Cookies sinn net aktivéiert.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>Et konnt keen Token fonnt ginn.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>De Benotzernumm konnt net fonnt ginn.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>Den Account ass ofgelaf.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>D'Zouganksdate sinn ofgelaf.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>De Konto ass deaktivéiert.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>De Konto ass gespaart.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.lt.xlf b/Core/Resources/translations/security.lt.xlf new file mode 100644 index 0000000..da6c332 --- /dev/null +++ b/Core/Resources/translations/security.lt.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>Įvyko autentifikacijos klaida.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>Nepavyko rasti autentifikacijos duomneų.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>Autentifikacijos užklausos nepavyko įvykdyti dėl sistemos klaidų.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Klaidingi duomenys.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Slapukas buvo panaudotas kažkam kitam.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Neturite teisių pasiektį resursą.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Neteisingas CSRF raktas.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Prieigos kodas yra pasibaigęs.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>Nerastas autentifikacijos tiekėjas, kuris palaikytų autentifikacijos raktą.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>Sesija yra nepasiekiama, pasibaigė galiojimo laikas arba slapukai yra išjungti.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>Nepavyko rasti rakto.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>Tokio naudotojo vardo nepavyko rasti.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>Paskyros galiojimo laikas baigėsi.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>Autentifikacijos duomenų galiojimo laikas baigėsi.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>Paskyra yra išjungta.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>Paskyra yra užblokuota.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.nl.xlf b/Core/Resources/translations/security.nl.xlf new file mode 100644 index 0000000..8969e9e --- /dev/null +++ b/Core/Resources/translations/security.nl.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>Er heeft zich een authenticatieprobleem voorgedaan.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>Authenticatiegegevens konden niet worden gevonden.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>Authenticatieaanvraag kon niet worden verwerkt door een technisch probleem.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Ongeldige inloggegevens.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Cookie is al door een ander persoon gebruikt.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Onvoldoende rechten om de aanvraag te verwerken.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>CSRF-code is ongeldig.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Serverauthenticatiesleutel (digest nonce) is verlopen.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>Geen authenticatieprovider gevonden die de authenticatietoken ondersteunt.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>Geen sessie beschikbaar, mogelijk is deze verlopen of cookies zijn uitgeschakeld.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>Er kon geen authenticatietoken worden gevonden.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>Gebruikersnaam kon niet worden gevonden.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>Account is verlopen.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>Authenticatiegegevens zijn verlopen.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>Account is gedeactiveerd.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>Account is geblokkeerd.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.no.xlf b/Core/Resources/translations/security.no.xlf new file mode 100644 index 0000000..3635916 --- /dev/null +++ b/Core/Resources/translations/security.no.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>En autentiseringsfeil har skjedd.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>Påloggingsinformasjonen kunne ikke bli funnet.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>Autentiserings forespørselen kunne ikke bli prosessert grunnet en system feil.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Ugyldig påloggingsinformasjonen.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Cookie har allerede blitt brukt av noen andre.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Ingen tilgang til å be om gitt ressurs.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Ugyldig CSRF token.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Digest nonce er utløpt.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>Ingen autentiserings tilbyder funnet som støtter gitt autentiserings token.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>Ingen sesjon tilgjengelig, sesjonen er enten utløpt eller cookies ikke skrudd på.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>Ingen token kunne bli funnet.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>Brukernavn kunne ikke bli funnet.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>Brukerkonto har utgått.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>Påloggingsinformasjon har utløpt.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>Brukerkonto er deaktivert.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>Brukerkonto er sperret.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.pl.xlf b/Core/Resources/translations/security.pl.xlf new file mode 100644 index 0000000..8d563d2 --- /dev/null +++ b/Core/Resources/translations/security.pl.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>Wystąpił błąd uwierzytelniania.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>Dane uwierzytelniania nie zostały znalezione.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>Żądanie uwierzytelniania nie mogło zostać pomyślnie zakończone z powodu problemu z systemem.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Nieprawidłowe dane.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>To ciasteczko jest używane przez kogoś innego.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Brak uprawnień dla żądania wskazanego zasobu.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Nieprawidłowy token CSRF.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Kod dostępu wygasł.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>Nie znaleziono mechanizmu uwierzytelniania zdolnego do obsługi przesłanego tokenu.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>Brak danych sesji, sesja wygasła lub ciasteczka nie są włączone.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>Nie znaleziono tokenu.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>Użytkownik o podanej nazwie nie istnieje.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>Konto wygasło.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>Dane uwierzytelniania wygasły.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>Konto jest wyłączone.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>Konto jest zablokowane.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.pt_BR.xlf b/Core/Resources/translations/security.pt_BR.xlf new file mode 100644 index 0000000..61685d9 --- /dev/null +++ b/Core/Resources/translations/security.pt_BR.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>Uma exceção ocorreu durante a autenticação.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>As credenciais de autenticação não foram encontradas.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>A autenticação não pôde ser concluída devido a um problema no sistema.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Credenciais inválidas.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Este cookie já está em uso.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Não possui privilégios o bastante para requisitar este recurso.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Token CSRF inválido.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Digest nonce expirado.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>Nenhum provedor de autenticação encontrado para suportar o token de autenticação.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>Nenhuma sessão disponível, ela expirou ou os cookies estão desativados.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>Nenhum token foi encontrado.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>Nome de usuário não encontrado.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>A conta está expirada.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>As credenciais estão expiradas.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>Conta desativada.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>A conta está travada.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.pt_PT.xlf b/Core/Resources/translations/security.pt_PT.xlf new file mode 100644 index 0000000..f2af13e --- /dev/null +++ b/Core/Resources/translations/security.pt_PT.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>Ocorreu uma excepção durante a autenticação.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>As credenciais de autenticação não foram encontradas.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>O pedido de autenticação não foi concluído devido a um problema no sistema.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Credenciais inválidas.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Este cookie já está em uso.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Não possui privilégios para aceder a este recurso.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Token CSRF inválido.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Digest nonce expirado.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>Nenhum fornecedor de autenticação encontrado para suportar o token de autenticação.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>Não existe sessão disponível, esta expirou ou os cookies estão desativados.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>O token não foi encontrado.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>Nome de utilizador não encontrado.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>A conta expirou.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>As credenciais expiraram.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>Conta desativada.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>A conta está trancada.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.ro.xlf b/Core/Resources/translations/security.ro.xlf new file mode 100644 index 0000000..440f110 --- /dev/null +++ b/Core/Resources/translations/security.ro.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>A apărut o eroare de autentificare.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>Informațiile de autentificare nu au fost găsite.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>Sistemul nu a putut procesa cererea de autentificare din cauza unei erori.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Date de autentificare invalide.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Cookieul este folosit deja de altcineva.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Permisiuni insuficiente pentru resursa cerută.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Tokenul CSRF este invalid.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Tokenul temporar a expirat.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>Nu a fost găsit nici un agent de autentificare pentru tokenul specificat.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>Sesiunea nu mai este disponibilă, a expirat sau suportul pentru cookieuri nu este activat.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>Tokenul nu a putut fi găsit.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>Numele de utilizator nu a fost găsit.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>Contul a expirat.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>Datele de autentificare au expirat.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>Contul este dezactivat.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>Contul este blocat.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.ru.xlf b/Core/Resources/translations/security.ru.xlf new file mode 100644 index 0000000..1964f95 --- /dev/null +++ b/Core/Resources/translations/security.ru.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>Ошибка аутентификации.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>Аутентификационные данные не найдены.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>Запрос аутентификации не может быть обработан в связи с проблемой в системе.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Недействительные аутентификационные данные.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Cookie уже был использован кем-то другим.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Отсутствуют права на запрос этого ресурса.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Недействительный токен CSRF.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Время действия одноразового ключа дайджеста истекло.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>Не найден провайдер аутентификации, поддерживающий токен аутентификации.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>Сессия не найдена, ее время истекло, либо cookies не включены.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>Токен не найден.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>Имя пользователя не найдено.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>Время действия учетной записи истекло.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>Время действия аутентификационных данных истекло.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>Учетная запись отключена.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>Учетная запись заблокирована.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.sk.xlf b/Core/Resources/translations/security.sk.xlf new file mode 100644 index 0000000..e6552a6 --- /dev/null +++ b/Core/Resources/translations/security.sk.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>Pri overovaní došlo k chybe.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>Overovacie údaje neboli nájdené.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>Požiadavok na overenie nemohol byť spracovaný kvôli systémovej chybe.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Neplatné prihlasovacie údaje.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Cookie už bolo použité niekým iným.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Nemáte oprávnenie pristupovať k prostriedku.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Neplatný CSRF token.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Platnosť inicializačného vektoru (digest nonce) skončila.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>Poskytovateľ pre overovací token nebol nájdený.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>Session nie je k dispozíci, vypršala jej platnosť, alebo sú zakázané cookies.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>Token nebol nájdený.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>Prihlasovacie meno nebolo nájdené.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>Platnosť účtu skončila.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>Platnosť prihlasovacích údajov skončila.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>Účet je zakázaný.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>Účet je zablokovaný.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.sl.xlf b/Core/Resources/translations/security.sl.xlf new file mode 100644 index 0000000..ee70c9a --- /dev/null +++ b/Core/Resources/translations/security.sl.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>Prišlo je do izjeme pri preverjanju avtentikacije.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>Poverilnic za avtentikacijo ni bilo mogoče najti.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>Zahteve za avtentikacijo ni bilo mogoče izvesti zaradi sistemske težave.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Neveljavne pravice.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Piškotek je uporabil že nekdo drug.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Nimate privilegijev za zahtevani vir.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Neveljaven CSRF žeton.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Začasni žeton je potekel.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>Ponudnika avtentikacije za podporo prijavnega žetona ni bilo mogoče najti.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>Seja ni na voljo, ali je potekla ali pa piškotki niso omogočeni.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>Žetona ni bilo mogoče najti.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>Uporabniškega imena ni bilo mogoče najti.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>Račun je potekel.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>Poverilnice so potekle.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>Račun je onemogočen.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>Račun je zaklenjen.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.sr_Cyrl.xlf b/Core/Resources/translations/security.sr_Cyrl.xlf new file mode 100644 index 0000000..35e4ddf --- /dev/null +++ b/Core/Resources/translations/security.sr_Cyrl.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>Изузетак при аутентификацији.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>Аутентификациони подаци нису пронађени.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>Захтев за аутентификацију не може бити обрађен због системских проблема.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Невалидни подаци за аутентификацију.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Колачић је већ искоришћен од стране неког другог.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Немате права приступа овом ресурсу.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Невалидан CSRF токен.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Време криптографског кључа је истекло.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>Аутентификациони провајдер за подршку токена није пронађен.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>Сесија није доступна, истекла је или су колачићи искључени.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>Токен не може бити пронађен.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>Корисничко име не може бити пронађено.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>Налог је истекао.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>Подаци за аутентификацију су истекли.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>Налог је онемогућен.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>Налог је закључан.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.sr_Latn.xlf b/Core/Resources/translations/security.sr_Latn.xlf new file mode 100644 index 0000000..ddc4807 --- /dev/null +++ b/Core/Resources/translations/security.sr_Latn.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>Izuzetak pri autentifikaciji.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>Autentifikacioni podaci nisu pronađeni.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>Zahtev za autentifikaciju ne može biti obrađen zbog sistemskih problema.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Nevalidni podaci za autentifikaciju.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Kolačić je već iskorišćen od strane nekog drugog.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Nemate prava pristupa ovom resursu.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Nevalidan CSRF token.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Vreme kriptografskog ključa je isteklo.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>Autentifikacioni provajder za podršku tokena nije pronađen.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>Sesija nije dostupna, istekla je ili su kolačići isključeni.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>Token ne može biti pronađen.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>Korisničko ime ne može biti pronađeno.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>Nalog je istekao.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>Podaci za autentifikaciju su istekli.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>Nalog je onemogućen.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>Nalog je zaključan.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.sv.xlf b/Core/Resources/translations/security.sv.xlf new file mode 100644 index 0000000..b5f6209 --- /dev/null +++ b/Core/Resources/translations/security.sv.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>Ett autentiseringsfel har inträffat.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>Uppgifterna för autentisering kunde inte hittas.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>Autentiseringen kunde inte genomföras på grund av systemfel.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Felaktiga uppgifter.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Cookien har redan använts av någon annan.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Saknar rättigheter för resursen.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Ogiltig CSRF-token.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Förfallen digest nonce.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>Ingen leverantör för autentisering hittades för angiven autentiseringstoken.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>Ingen session finns tillgänglig, antingen har den förfallit eller är cookies inte aktiverat.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>Ingen token kunde hittas.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>Användarnamnet kunde inte hittas.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>Kontot har förfallit.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>Uppgifterna har förfallit.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>Kontot är inaktiverat.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>Kontot är låst.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.th.xlf b/Core/Resources/translations/security.th.xlf new file mode 100644 index 0000000..a8cb8d5 --- /dev/null +++ b/Core/Resources/translations/security.th.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>พบความผิดพลาดในการรับรองตัวตน</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>ไม่พบข้อมูลในการรับรองตัวตน (credentials) </target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>คำร้องในการรับรองตัวตนไม่สามารถดำเนินการได้ เนื่องมาจากปัญหาของระบบ</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>ข้อมูลการรับรองตัวตนไม่ถูกต้อง</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Cookie ถูกใช้งานไปแล้วด้วยผู้อื่น</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>ไม่ได้รับสิทธิ์ให้ใช้งานส่วนนี้ได้</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>CSRF token ไม่ถูกต้อง</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Digest nonce หมดอายุ</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>ไม่พบ authentication provider ที่รองรับสำหรับ authentication token</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>ไม่มี session ที่พร้อมใช้งาน, Session หมดอายุไปแล้วหรือ cookies ไม่ถูกเปิดใช้งาน</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>ไม่พบ token</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>ไม่พบ Username</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>บัญชีหมดอายุไปแล้ว</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>ข้อมูลการระบุตัวตนหมดอายุแล้ว</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>บัญชีถูกระงับแล้ว</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>บัญชีถูกล็อกแล้ว</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.tr.xlf b/Core/Resources/translations/security.tr.xlf new file mode 100644 index 0000000..68c4421 --- /dev/null +++ b/Core/Resources/translations/security.tr.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>Bir yetkilendirme istisnası oluştu.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>Kimlik bilgileri bulunamadı.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>Bir sistem hatası nedeniyle yetkilendirme isteği işleme alınamıyor.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Geçersiz kimlik bilgileri.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Çerez bir başkası tarafından zaten kullanılmıştı.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Kaynak talebi için imtiyaz bulunamadı.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Geçersiz CSRF fişi.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Derleme zaman aşımına uğradı.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>Yetkilendirme fişini destekleyecek yetkilendirme sağlayıcısı bulunamadı.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>Oturum bulunamadı, zaman aşımına uğradı veya çerezler etkin değil.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>Fiş bulunamadı.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>Kullanıcı adı bulunamadı.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>Hesap zaman aşımına uğradı.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>Kimlik bilgileri zaman aşımına uğradı.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>Hesap engellenmiş.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>Hesap kilitlenmiş.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.ua.xlf b/Core/Resources/translations/security.ua.xlf new file mode 100644 index 0000000..7972121 --- /dev/null +++ b/Core/Resources/translations/security.ua.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>Помилка автентифікації.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>Автентифікаційні дані не знайдено.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>Запит на автентифікацію не може бути опрацьовано у зв’язку з проблемою в системі.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Невірні автентифікаційні дані.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Хтось інший вже використав цей сookie.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Відсутні права на запит цього ресурсу.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Невірний токен CSRF.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Закінчився термін дії одноразового ключа дайджесту.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>Не знайдено провайдера автентифікації, що підтримує токен автентифікаціії.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>Сесія недоступна, її час вийшов, або cookies вимкнено.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>Токен не знайдено.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>Ім’я користувача не знайдено.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>Термін дії облікового запису вичерпано.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>Термін дії автентифікаційних даних вичерпано.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>Обліковий запис відключено.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>Обліковий запис заблоковано.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.vi.xlf b/Core/Resources/translations/security.vi.xlf new file mode 100644 index 0000000..b85a439 --- /dev/null +++ b/Core/Resources/translations/security.vi.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>Có lỗi trong quá trình xác thực.</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>Thông tin dùng để xác thực không tìm thấy.</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>Yêu cầu xác thực không thể thực hiện do lỗi của hệ thống.</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>Thông tin dùng để xác thực không hợp lệ.</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Cookie đã được dùng bởi người dùng khác.</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>Không được phép yêu cầu tài nguyên.</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>Mã CSRF không hợp lệ.</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>Mã dùng một lần đã hết hạn.</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>Không tìm thấy nhà cung cấp dịch vụ xác thực nào cho mã xác thực mà bạn sử dụng.</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>Không tìm thấy phiên làm việc. Phiên làm việc hoặc cookie có thể bị tắt.</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>Không tìm thấy mã token.</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>Không tìm thấy tên người dùng username.</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>Tài khoản đã hết hạn.</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>Thông tin xác thực đã hết hạn.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>Tài khoản bị tạm ngừng.</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>Tài khoản bị khóa.</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Resources/translations/security.zh_CN.xlf b/Core/Resources/translations/security.zh_CN.xlf new file mode 100644 index 0000000..2d6affe --- /dev/null +++ b/Core/Resources/translations/security.zh_CN.xlf @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>身份验证发生异常。</target> + </trans-unit> + <trans-unit id="2"> + <source>Authentication credentials could not be found.</source> + <target>没有找到身份验证的凭证。</target> + </trans-unit> + <trans-unit id="3"> + <source>Authentication request could not be processed due to a system problem.</source> + <target>由于系统故障,身份验证的请求无法被处理。</target> + </trans-unit> + <trans-unit id="4"> + <source>Invalid credentials.</source> + <target>无效的凭证。</target> + </trans-unit> + <trans-unit id="5"> + <source>Cookie has already been used by someone else.</source> + <target>Cookie 已经被其他人使用。</target> + </trans-unit> + <trans-unit id="6"> + <source>Not privileged to request the resource.</source> + <target>没有权限请求此资源。</target> + </trans-unit> + <trans-unit id="7"> + <source>Invalid CSRF token.</source> + <target>无效的 CSRF token 。</target> + </trans-unit> + <trans-unit id="8"> + <source>Digest nonce has expired.</source> + <target>摘要随机串(digest nonce)已过期。</target> + </trans-unit> + <trans-unit id="9"> + <source>No authentication provider found to support the authentication token.</source> + <target>没有找到支持此 token 的身份验证服务提供方。</target> + </trans-unit> + <trans-unit id="10"> + <source>No session available, it either timed out or cookies are not enabled.</source> + <target>Session 不可用。会话超时或没有启用 cookies 。</target> + </trans-unit> + <trans-unit id="11"> + <source>No token could be found.</source> + <target>找不到 token 。</target> + </trans-unit> + <trans-unit id="12"> + <source>Username could not be found.</source> + <target>找不到用户名。</target> + </trans-unit> + <trans-unit id="13"> + <source>Account has expired.</source> + <target>帐号已过期。</target> + </trans-unit> + <trans-unit id="14"> + <source>Credentials have expired.</source> + <target>凭证已过期。</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>帐号已被禁用。</target> + </trans-unit> + <trans-unit id="16"> + <source>Account is locked.</source> + <target>帐号已被锁定。</target> + </trans-unit> + </body> + </file> +</xliff> diff --git a/Core/Role/RoleHierarchy.php b/Core/Role/RoleHierarchy.php index 2e7df0e..793007e 100644 --- a/Core/Role/RoleHierarchy.php +++ b/Core/Role/RoleHierarchy.php @@ -19,7 +19,7 @@ namespace Symfony\Component\Security\Core\Role; class RoleHierarchy implements RoleHierarchyInterface { private $hierarchy; - private $map; + protected $map; /** * Constructor. @@ -52,7 +52,7 @@ class RoleHierarchy implements RoleHierarchyInterface return $reachableRoles; } - private function buildRoleMap() + protected function buildRoleMap() { $this->map = array(); foreach ($this->hierarchy as $main => $roles) { diff --git a/Core/Security.php b/Core/Security.php new file mode 100644 index 0000000..84cc77d --- /dev/null +++ b/Core/Security.php @@ -0,0 +1,25 @@ +<?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; + +/** + * This class holds security information. + * + * @author Johannes M. Schmitt <schmittjoh@gmail.com> + */ +final class Security +{ + const ACCESS_DENIED_ERROR = '_security.403_error'; + const AUTHENTICATION_ERROR = '_security.last_error'; + const LAST_USERNAME = '_security.last_username'; + const MAX_USERNAME_LENGTH = 4096; +} diff --git a/Core/SecurityContext.php b/Core/SecurityContext.php index 0326f1d..027ff49 100644 --- a/Core/SecurityContext.php +++ b/Core/SecurityContext.php @@ -11,10 +11,15 @@ namespace Symfony\Component\Security\Core; -use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException; -use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface; +@trigger_error('The '.__NAMESPACE__.'\SecurityContext class is deprecated since version 2.6 and will be removed in 3.0. Use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage or Symfony\Component\Security\Core\Authorization\AuthorizationChecker instead.', E_USER_DEPRECATED); + use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface; +use Symfony\Component\Security\Core\Authorization\AuthorizationChecker; +use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; /** * SecurityContext is the main entry point of the Security component. @@ -23,63 +28,77 @@ use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; * * @author Fabien Potencier <fabien@symfony.com> * @author Johannes M. Schmitt <schmittjoh@gmail.com> + * + * @deprecated since version 2.6, to be removed in 3.0. */ class SecurityContext implements SecurityContextInterface { - private $token; - private $accessDecisionManager; - private $authenticationManager; - private $alwaysAuthenticate; + /** + * @var TokenStorageInterface + */ + private $tokenStorage; /** - * Constructor. - * - * @param AuthenticationManagerInterface $authenticationManager An AuthenticationManager instance - * @param AccessDecisionManagerInterface|null $accessDecisionManager An AccessDecisionManager instance - * @param bool $alwaysAuthenticate + * @var AuthorizationCheckerInterface */ - public function __construct(AuthenticationManagerInterface $authenticationManager, AccessDecisionManagerInterface $accessDecisionManager, $alwaysAuthenticate = false) - { - $this->authenticationManager = $authenticationManager; - $this->accessDecisionManager = $accessDecisionManager; - $this->alwaysAuthenticate = $alwaysAuthenticate; - } + private $authorizationChecker; /** - * {@inheritdoc} + * For backwards compatibility, the signature of sf <2.6 still works. * - * @throws AuthenticationCredentialsNotFoundException when the security context has no authentication token. + * @param TokenStorageInterface|AuthenticationManagerInterface $tokenStorage + * @param AuthorizationCheckerInterface|AccessDecisionManagerInterface $authorizationChecker + * @param bool $alwaysAuthenticate only applicable with old signature */ - final public function isGranted($attributes, $object = null) + public function __construct($tokenStorage, $authorizationChecker, $alwaysAuthenticate = false) { - if (null === $this->token) { - throw new AuthenticationCredentialsNotFoundException('The security context contains no authentication token. One possible reason may be that there is no firewall configured for this URL.'); - } + $oldSignature = $tokenStorage instanceof AuthenticationManagerInterface && $authorizationChecker instanceof AccessDecisionManagerInterface; + $newSignature = $tokenStorage instanceof TokenStorageInterface && $authorizationChecker instanceof AuthorizationCheckerInterface; - if ($this->alwaysAuthenticate || !$this->token->isAuthenticated()) { - $this->token = $this->authenticationManager->authenticate($this->token); + // confirm possible signatures + if (!$oldSignature && !$newSignature) { + throw new \BadMethodCallException('Unable to construct SecurityContext, please provide the correct arguments'); } - if (!is_array($attributes)) { - $attributes = array($attributes); + if ($oldSignature) { + // renamed for clarity + $authenticationManager = $tokenStorage; + $accessDecisionManager = $authorizationChecker; + $tokenStorage = new TokenStorage(); + $authorizationChecker = new AuthorizationChecker($tokenStorage, $authenticationManager, $accessDecisionManager, $alwaysAuthenticate); } - return $this->accessDecisionManager->decide($this->token, $attributes, $object); + $this->tokenStorage = $tokenStorage; + $this->authorizationChecker = $authorizationChecker; } /** + * @deprecated since version 2.6, to be removed in 3.0. Use TokenStorageInterface::getToken() instead. + * * {@inheritdoc} */ public function getToken() { - return $this->token; + return $this->tokenStorage->getToken(); } /** + * @deprecated since version 2.6, to be removed in 3.0. Use TokenStorageInterface::setToken() instead. + * * {@inheritdoc} */ public function setToken(TokenInterface $token = null) { - $this->token = $token; + return $this->tokenStorage->setToken($token); + } + + /** + * @deprecated since version 2.6, to be removed in 3.0. Use AuthorizationCheckerInterface::isGranted() instead. + * + * {@inheritdoc} + */ + public function isGranted($attributes, $object = null) + { + return $this->authorizationChecker->isGranted($attributes, $object); } } diff --git a/Core/SecurityContextInterface.php b/Core/SecurityContextInterface.php index 0253a6a..73edd23 100644 --- a/Core/SecurityContextInterface.php +++ b/Core/SecurityContextInterface.php @@ -11,41 +11,20 @@ namespace Symfony\Component\Security\Core; -use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; /** * The SecurityContextInterface. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> + * + * @deprecated since version 2.6, to be removed in 3.0. */ -interface SecurityContextInterface +interface SecurityContextInterface extends TokenStorageInterface, AuthorizationCheckerInterface { - const ACCESS_DENIED_ERROR = '_security.403_error'; - const AUTHENTICATION_ERROR = '_security.last_error'; - const LAST_USERNAME = '_security.last_username'; - const MAX_USERNAME_LENGTH = 4096; - - /** - * Returns the current security token. - * - * @return TokenInterface|null A TokenInterface instance or null if no authentication information is available - */ - public function getToken(); - - /** - * Sets the authentication token. - * - * @param TokenInterface $token A TokenInterface token, or null if no further authentication information should be stored - */ - public function setToken(TokenInterface $token = null); - - /** - * Checks if the attributes are granted against the current authentication token and optionally supplied object. - * - * @param mixed $attributes - * @param mixed $object - * - * @return bool - */ - public function isGranted($attributes, $object = null); + const ACCESS_DENIED_ERROR = Security::ACCESS_DENIED_ERROR; + const AUTHENTICATION_ERROR = Security::AUTHENTICATION_ERROR; + const LAST_USERNAME = Security::LAST_USERNAME; + const MAX_USERNAME_LENGTH = Security::MAX_USERNAME_LENGTH; } diff --git a/Tests/Core/Authentication/AuthenticationProviderManagerTest.php b/Core/Tests/Authentication/AuthenticationProviderManagerTest.php index 32e6cf7..cc8b7c0 100644 --- a/Tests/Core/Authentication/AuthenticationProviderManagerTest.php +++ b/Core/Tests/Authentication/AuthenticationProviderManagerTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\Authentication; +namespace Symfony\Component\Security\Core\Tests\Authentication; use Symfony\Component\Security\Core\Authentication\AuthenticationProviderManager; use Symfony\Component\Security\Core\Exception\ProviderNotFoundException; @@ -27,6 +27,16 @@ class AuthenticationProviderManagerTest extends \PHPUnit_Framework_TestCase new AuthenticationProviderManager(array()); } + /** + * @expectedException \InvalidArgumentException + */ + public function testAuthenticateWithProvidersWithIncorrectInterface() + { + new AuthenticationProviderManager(array( + new \stdClass(), + )); + } + public function testAuthenticateWhenNoProviderSupportsToken() { $manager = new AuthenticationProviderManager(array( @@ -129,7 +139,7 @@ class AuthenticationProviderManagerTest extends \PHPUnit_Framework_TestCase } elseif (null !== $exception) { $provider->expects($this->once()) ->method('authenticate') - ->will($this->throwException($this->getMock($exception, null, array(), '', true))) + ->will($this->throwException($this->getMock($exception, null, array(), ''))) ; } diff --git a/Tests/Core/Authentication/AuthenticationTrustResolverTest.php b/Core/Tests/Authentication/AuthenticationTrustResolverTest.php index e2fc593..3640981 100644 --- a/Tests/Core/Authentication/AuthenticationTrustResolverTest.php +++ b/Core/Tests/Authentication/AuthenticationTrustResolverTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\Authentication; +namespace Symfony\Component\Security\Core\Tests\Authentication; use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolver; diff --git a/Tests/Core/Authentication/Provider/AnonymousAuthenticationProviderTest.php b/Core/Tests/Authentication/Provider/AnonymousAuthenticationProviderTest.php index d0da147..5a189b0 100644 --- a/Tests/Core/Authentication/Provider/AnonymousAuthenticationProviderTest.php +++ b/Core/Tests/Authentication/Provider/AnonymousAuthenticationProviderTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\Authentication\Provider; +namespace Symfony\Component\Security\Core\Tests\Authentication\Provider; use Symfony\Component\Security\Core\Authentication\Provider\AnonymousAuthenticationProvider; diff --git a/Tests/Core/Authentication/Provider/DaoAuthenticationProviderTest.php b/Core/Tests/Authentication/Provider/DaoAuthenticationProviderTest.php index 18e9669..3eedb8e 100644 --- a/Tests/Core/Authentication/Provider/DaoAuthenticationProviderTest.php +++ b/Core/Tests/Authentication/Provider/DaoAuthenticationProviderTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\Authentication\Provider; +namespace Symfony\Component\Security\Core\Tests\Authentication\Provider; use Symfony\Component\Security\Core\Encoder\PlaintextPasswordEncoder; use Symfony\Component\Security\Core\Authentication\Provider\DaoAuthenticationProvider; diff --git a/Tests/Core/Authentication/Provider/PreAuthenticatedAuthenticationProviderTest.php b/Core/Tests/Authentication/Provider/PreAuthenticatedAuthenticationProviderTest.php index 17234b6..5fd7b05 100644 --- a/Tests/Core/Authentication/Provider/PreAuthenticatedAuthenticationProviderTest.php +++ b/Core/Tests/Authentication/Provider/PreAuthenticatedAuthenticationProviderTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\Authentication\Provider; +namespace Symfony\Component\Security\Core\Tests\Authentication\Provider; use Symfony\Component\Security\Core\Authentication\Provider\PreAuthenticatedAuthenticationProvider; use Symfony\Component\Security\Core\Exception\LockedException; diff --git a/Tests/Core/Authentication/Provider/RememberMeAuthenticationProviderTest.php b/Core/Tests/Authentication/Provider/RememberMeAuthenticationProviderTest.php index 54fb4ea..a6fff4b 100644 --- a/Tests/Core/Authentication/Provider/RememberMeAuthenticationProviderTest.php +++ b/Core/Tests/Authentication/Provider/RememberMeAuthenticationProviderTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\Authentication\Provider; +namespace Symfony\Component\Security\Core\Tests\Authentication\Provider; use Symfony\Component\Security\Core\Authentication\Provider\RememberMeAuthenticationProvider; use Symfony\Component\Security\Core\Exception\DisabledException; diff --git a/Tests/Core/Authentication/Provider/UserAuthenticationProviderTest.php b/Core/Tests/Authentication/Provider/UserAuthenticationProviderTest.php index 32f5b10..0503054 100644 --- a/Tests/Core/Authentication/Provider/UserAuthenticationProviderTest.php +++ b/Core/Tests/Authentication/Provider/UserAuthenticationProviderTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\Authentication\Provider; +namespace Symfony\Component\Security\Core\Tests\Authentication\Provider; use Symfony\Component\Security\Core\Exception\AccountExpiredException; use Symfony\Component\Security\Core\Exception\BadCredentialsException; diff --git a/Tests/Core/Authentication/RememberMe/InMemoryTokenProviderTest.php b/Core/Tests/Authentication/RememberMe/InMemoryTokenProviderTest.php index 1739714..3bdf38c 100644 --- a/Tests/Core/Authentication/RememberMe/InMemoryTokenProviderTest.php +++ b/Core/Tests/Authentication/RememberMe/InMemoryTokenProviderTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\Authentication\RememberMe; +namespace Symfony\Component\Security\Core\Tests\Authentication\RememberMe; use Symfony\Component\Security\Core\Authentication\RememberMe\PersistentToken; use Symfony\Component\Security\Core\Authentication\RememberMe\InMemoryTokenProvider; diff --git a/Tests/Core/Authentication/RememberMe/PersistentTokenTest.php b/Core/Tests/Authentication/RememberMe/PersistentTokenTest.php index 3903591..903c030 100644 --- a/Tests/Core/Authentication/RememberMe/PersistentTokenTest.php +++ b/Core/Tests/Authentication/RememberMe/PersistentTokenTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\Authentication\RememberMe; +namespace Symfony\Component\Security\Core\Tests\Authentication\RememberMe; use Symfony\Component\Security\Core\Authentication\RememberMe\PersistentToken; diff --git a/Tests/Core/Authentication/Token/AbstractTokenTest.php b/Core/Tests/Authentication/Token/AbstractTokenTest.php index efdad4c..1a786d7 100644 --- a/Tests/Core/Authentication/Token/AbstractTokenTest.php +++ b/Core/Tests/Authentication/Token/AbstractTokenTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\Authentication\Token; +namespace Symfony\Component\Security\Core\Tests\Authentication\Token; use Symfony\Component\Security\Core\Authentication\Token\AbstractToken; use Symfony\Component\Security\Core\Role\Role; diff --git a/Tests/Core/Authentication/Token/AnonymousTokenTest.php b/Core/Tests/Authentication/Token/AnonymousTokenTest.php index 135397b..b5cf006 100644 --- a/Tests/Core/Authentication/Token/AnonymousTokenTest.php +++ b/Core/Tests/Authentication/Token/AnonymousTokenTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\Authentication\Token; +namespace Symfony\Component\Security\Core\Tests\Authentication\Token; use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken; use Symfony\Component\Security\Core\Role\Role; diff --git a/Tests/Core/Authentication/Token/PreAuthenticatedTokenTest.php b/Core/Tests/Authentication/Token/PreAuthenticatedTokenTest.php index 59a533a..77d2608 100644 --- a/Tests/Core/Authentication/Token/PreAuthenticatedTokenTest.php +++ b/Core/Tests/Authentication/Token/PreAuthenticatedTokenTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\Authentication\Token; +namespace Symfony\Component\Security\Core\Tests\Authentication\Token; use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken; use Symfony\Component\Security\Core\Role\Role; diff --git a/Tests/Core/Authentication/Token/RememberMeTokenTest.php b/Core/Tests/Authentication/Token/RememberMeTokenTest.php index 438c1d9..7449204 100644 --- a/Tests/Core/Authentication/Token/RememberMeTokenTest.php +++ b/Core/Tests/Authentication/Token/RememberMeTokenTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\Authentication\Token; +namespace Symfony\Component\Security\Core\Tests\Authentication\Token; use Symfony\Component\Security\Core\Authentication\Token\RememberMeToken; use Symfony\Component\Security\Core\Role\Role; diff --git a/Core/Tests/Authentication/Token/Storage/TokenStorageTest.php b/Core/Tests/Authentication/Token/Storage/TokenStorageTest.php new file mode 100644 index 0000000..d06e3f0 --- /dev/null +++ b/Core/Tests/Authentication/Token/Storage/TokenStorageTest.php @@ -0,0 +1,26 @@ +<?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\Tests\Authentication\Token\Storage; + +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; + +class TokenStorageTest extends \PHPUnit_Framework_TestCase +{ + public function testGetSetToken() + { + $tokenStorage = new TokenStorage(); + $this->assertNull($tokenStorage->getToken()); + $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); + $tokenStorage->setToken($token); + $this->assertSame($token, $tokenStorage->getToken()); + } +} diff --git a/Tests/Core/Authentication/Token/UsernamePasswordTokenTest.php b/Core/Tests/Authentication/Token/UsernamePasswordTokenTest.php index 67f431f..0297eff 100644 --- a/Tests/Core/Authentication/Token/UsernamePasswordTokenTest.php +++ b/Core/Tests/Authentication/Token/UsernamePasswordTokenTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\Authentication\Token; +namespace Symfony\Component\Security\Core\Tests\Authentication\Token; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\Role\Role; diff --git a/Tests/Core/Authorization/AccessDecisionManagerTest.php b/Core/Tests/Authorization/AccessDecisionManagerTest.php index 5341baf..7a9ab08 100644 --- a/Tests/Core/Authorization/AccessDecisionManagerTest.php +++ b/Core/Tests/Authorization/AccessDecisionManagerTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\Authorization; +namespace Symfony\Component\Security\Core\Tests\Authorization; use Symfony\Component\Security\Core\Authorization\AccessDecisionManager; use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; @@ -55,6 +55,14 @@ class AccessDecisionManagerTest extends \PHPUnit_Framework_TestCase } /** + * @expectedException \InvalidArgumentException + */ + public function testSetUnsupportedStrategy() + { + new AccessDecisionManager(array($this->getVoter(VoterInterface::ACCESS_GRANTED)), 'fooBar'); + } + + /** * @dataProvider getStrategyTests */ public function testStrategies($strategy, $voters, $allowIfAllAbstainDecisions, $allowIfEqualGrantedDeniedDecisions, $expected) @@ -111,34 +119,34 @@ class AccessDecisionManagerTest extends \PHPUnit_Framework_TestCase { return array( // affirmative - array('affirmative', $this->getVoters(1, 0, 0), false, true, true), - array('affirmative', $this->getVoters(1, 2, 0), false, true, true), - array('affirmative', $this->getVoters(0, 1, 0), false, true, false), - array('affirmative', $this->getVoters(0, 0, 1), false, true, false), - array('affirmative', $this->getVoters(0, 0, 1), true, true, true), + array(AccessDecisionManager::STRATEGY_AFFIRMATIVE, $this->getVoters(1, 0, 0), false, true, true), + array(AccessDecisionManager::STRATEGY_AFFIRMATIVE, $this->getVoters(1, 2, 0), false, true, true), + array(AccessDecisionManager::STRATEGY_AFFIRMATIVE, $this->getVoters(0, 1, 0), false, true, false), + array(AccessDecisionManager::STRATEGY_AFFIRMATIVE, $this->getVoters(0, 0, 1), false, true, false), + array(AccessDecisionManager::STRATEGY_AFFIRMATIVE, $this->getVoters(0, 0, 1), true, true, true), // consensus - array('consensus', $this->getVoters(1, 0, 0), false, true, true), - array('consensus', $this->getVoters(1, 2, 0), false, true, false), - array('consensus', $this->getVoters(2, 1, 0), false, true, true), + array(AccessDecisionManager::STRATEGY_CONSENSUS, $this->getVoters(1, 0, 0), false, true, true), + array(AccessDecisionManager::STRATEGY_CONSENSUS, $this->getVoters(1, 2, 0), false, true, false), + array(AccessDecisionManager::STRATEGY_CONSENSUS, $this->getVoters(2, 1, 0), false, true, true), - array('consensus', $this->getVoters(0, 0, 1), false, true, false), + array(AccessDecisionManager::STRATEGY_CONSENSUS, $this->getVoters(0, 0, 1), false, true, false), - array('consensus', $this->getVoters(0, 0, 1), true, true, true), + array(AccessDecisionManager::STRATEGY_CONSENSUS, $this->getVoters(0, 0, 1), true, true, true), - array('consensus', $this->getVoters(2, 2, 0), false, true, true), - array('consensus', $this->getVoters(2, 2, 1), false, true, true), + array(AccessDecisionManager::STRATEGY_CONSENSUS, $this->getVoters(2, 2, 0), false, true, true), + array(AccessDecisionManager::STRATEGY_CONSENSUS, $this->getVoters(2, 2, 1), false, true, true), - array('consensus', $this->getVoters(2, 2, 0), false, false, false), - array('consensus', $this->getVoters(2, 2, 1), false, false, false), + array(AccessDecisionManager::STRATEGY_CONSENSUS, $this->getVoters(2, 2, 0), false, false, false), + array(AccessDecisionManager::STRATEGY_CONSENSUS, $this->getVoters(2, 2, 1), false, false, false), // unanimous - array('unanimous', $this->getVoters(1, 0, 0), false, true, true), - array('unanimous', $this->getVoters(1, 0, 1), false, true, true), - array('unanimous', $this->getVoters(1, 1, 0), false, true, false), + array(AccessDecisionManager::STRATEGY_UNANIMOUS, $this->getVoters(1, 0, 0), false, true, true), + array(AccessDecisionManager::STRATEGY_UNANIMOUS, $this->getVoters(1, 0, 1), false, true, true), + array(AccessDecisionManager::STRATEGY_UNANIMOUS, $this->getVoters(1, 1, 0), false, true, false), - array('unanimous', $this->getVoters(0, 0, 2), false, true, false), - array('unanimous', $this->getVoters(0, 0, 2), true, true, true), + array(AccessDecisionManager::STRATEGY_UNANIMOUS, $this->getVoters(0, 0, 2), false, true, false), + array(AccessDecisionManager::STRATEGY_UNANIMOUS, $this->getVoters(0, 0, 2), true, true, true), ); } diff --git a/Core/Tests/Authorization/AuthorizationCheckerTest.php b/Core/Tests/Authorization/AuthorizationCheckerTest.php new file mode 100644 index 0000000..aafc12f --- /dev/null +++ b/Core/Tests/Authorization/AuthorizationCheckerTest.php @@ -0,0 +1,99 @@ +<?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\Tests\Authorization; + +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; +use Symfony\Component\Security\Core\Authorization\AuthorizationChecker; + +class AuthorizationCheckerTest extends \PHPUnit_Framework_TestCase +{ + private $authenticationManager; + private $accessDecisionManager; + private $authorizationChecker; + private $tokenStorage; + + protected function setUp() + { + $this->authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'); + $this->accessDecisionManager = $this->getMock('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface'); + $this->tokenStorage = new TokenStorage(); + + $this->authorizationChecker = new AuthorizationChecker( + $this->tokenStorage, + $this->authenticationManager, + $this->accessDecisionManager + ); + } + + public function testVoteAuthenticatesTokenIfNecessary() + { + $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); + $this->tokenStorage->setToken($token); + + $newToken = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); + + $this->authenticationManager + ->expects($this->once()) + ->method('authenticate') + ->with($this->equalTo($token)) + ->will($this->returnValue($newToken)); + + // default with() isn't a strict check + $tokenComparison = function ($value) use ($newToken) { + // make sure that the new token is used in "decide()" and not the old one + return $value === $newToken; + }; + + $this->accessDecisionManager + ->expects($this->once()) + ->method('decide') + ->with($this->callback($tokenComparison)) + ->will($this->returnValue(true)); + + // first run the token has not been re-authenticated yet, after isGranted is called, it should be equal + $this->assertFalse($newToken === $this->tokenStorage->getToken()); + $this->assertTrue($this->authorizationChecker->isGranted('foo')); + $this->assertTrue($newToken === $this->tokenStorage->getToken()); + } + + /** + * @expectedException \Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException + */ + public function testVoteWithoutAuthenticationToken() + { + $this->authorizationChecker->isGranted('ROLE_FOO'); + } + + /** + * @dataProvider isGrantedProvider + */ + public function testIsGranted($decide) + { + $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); + $token + ->expects($this->once()) + ->method('isAuthenticated') + ->will($this->returnValue(true)); + + $this->accessDecisionManager + ->expects($this->once()) + ->method('decide') + ->will($this->returnValue($decide)); + $this->tokenStorage->setToken($token); + $this->assertTrue($decide === $this->authorizationChecker->isGranted('ROLE_FOO')); + } + + public function isGrantedProvider() + { + return array(array(true), array(false)); + } +} diff --git a/Core/Tests/Authorization/ExpressionLanguageTest.php b/Core/Tests/Authorization/ExpressionLanguageTest.php new file mode 100644 index 0000000..5b4aca6 --- /dev/null +++ b/Core/Tests/Authorization/ExpressionLanguageTest.php @@ -0,0 +1,79 @@ +<?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\Tests\Authorization; + +use Symfony\Component\Security\Core\Authorization\ExpressionLanguage; +use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolver; +use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken; +use Symfony\Component\Security\Core\Authentication\Token\RememberMeToken; +use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; +use Symfony\Component\Security\Core\User\User; + +class ExpressionLanguageTest extends \PHPUnit_Framework_TestCase +{ + /** + * @dataProvider provider + */ + public function testIsAuthenticated($token, $expression, $result, array $roles = array()) + { + $anonymousTokenClass = 'Symfony\\Component\\Security\\Core\\Authentication\\Token\\AnonymousToken'; + $rememberMeTokenClass = 'Symfony\\Component\\Security\\Core\\Authentication\\Token\\RememberMeToken'; + $expressionLanguage = new ExpressionLanguage(); + $trustResolver = new AuthenticationTrustResolver($anonymousTokenClass, $rememberMeTokenClass); + + $context = array(); + $context['trust_resolver'] = $trustResolver; + $context['token'] = $token; + $context['roles'] = $roles; + + $this->assertEquals($result, $expressionLanguage->evaluate($expression, $context)); + } + + public function provider() + { + $roles = array('ROLE_USER', 'ROLE_ADMIN'); + $user = new User('username', 'password', $roles); + + $noToken = null; + $anonymousToken = new AnonymousToken('firewall', 'anon.'); + $rememberMeToken = new RememberMeToken($user, 'providerkey', 'firewall'); + $usernamePasswordToken = new UsernamePasswordToken('username', 'password', 'providerkey', $roles); + + return array( + array($noToken, 'is_anonymous()', false), + array($noToken, 'is_authenticated()', false), + array($noToken, 'is_fully_authenticated()', false), + array($noToken, 'is_remember_me()', false), + array($noToken, "has_role('ROLE_USER')", false), + + array($anonymousToken, 'is_anonymous()', true), + array($anonymousToken, 'is_authenticated()', false), + array($anonymousToken, 'is_fully_authenticated()', false), + array($anonymousToken, 'is_remember_me()', false), + array($anonymousToken, "has_role('ROLE_USER')", false), + + array($rememberMeToken, 'is_anonymous()', false), + array($rememberMeToken, 'is_authenticated()', true), + array($rememberMeToken, 'is_fully_authenticated()', false), + array($rememberMeToken, 'is_remember_me()', true), + array($rememberMeToken, "has_role('ROLE_FOO')", false, $roles), + array($rememberMeToken, "has_role('ROLE_USER')", true, $roles), + + array($usernamePasswordToken, 'is_anonymous()', false), + array($usernamePasswordToken, 'is_authenticated()', true), + array($usernamePasswordToken, 'is_fully_authenticated()', true), + array($usernamePasswordToken, 'is_remember_me()', false), + array($usernamePasswordToken, "has_role('ROLE_FOO')", false, $roles), + array($usernamePasswordToken, "has_role('ROLE_USER')", true, $roles), + ); + } +} diff --git a/Core/Tests/Authorization/Voter/AbstractVoterTest.php b/Core/Tests/Authorization/Voter/AbstractVoterTest.php new file mode 100644 index 0000000..2ab943b --- /dev/null +++ b/Core/Tests/Authorization/Voter/AbstractVoterTest.php @@ -0,0 +1,74 @@ +<?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\Tests\Authorization\Voter; + +use Symfony\Component\Security\Core\Authorization\Voter\AbstractVoter; +use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; + +class AbstractVoterTest extends \PHPUnit_Framework_TestCase +{ + protected $token; + + protected function setUp() + { + $this->token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); + } + + public function getTests() + { + return array( + array(array('EDIT'), VoterInterface::ACCESS_GRANTED, new \stdClass(), 'ACCESS_GRANTED if attribute and class are supported and attribute grants access'), + array(array('CREATE'), VoterInterface::ACCESS_DENIED, new \stdClass(), 'ACCESS_DENIED if attribute and class are supported and attribute does not grant access'), + + array(array('DELETE', 'EDIT'), VoterInterface::ACCESS_GRANTED, new \stdClass(), 'ACCESS_GRANTED if one attribute is supported and grants access'), + array(array('DELETE', 'CREATE'), VoterInterface::ACCESS_DENIED, new \stdClass(), 'ACCESS_DENIED if one attribute is supported and denies access'), + + array(array('CREATE', 'EDIT'), VoterInterface::ACCESS_GRANTED, new \stdClass(), 'ACCESS_GRANTED if one attribute grants access'), + + array(array('DELETE'), VoterInterface::ACCESS_ABSTAIN, new \stdClass(), 'ACCESS_ABSTAIN if no attribute is supported'), + + array(array('EDIT'), VoterInterface::ACCESS_ABSTAIN, $this, 'ACCESS_ABSTAIN if class is not supported'), + + array(array('EDIT'), VoterInterface::ACCESS_ABSTAIN, null, 'ACCESS_ABSTAIN if object is null'), + + array(array(), VoterInterface::ACCESS_ABSTAIN, new \stdClass(), 'ACCESS_ABSTAIN if no attributes were provided'), + ); + } + + /** + * @dataProvider getTests + */ + public function testVote(array $attributes, $expectedVote, $object, $message) + { + $voter = new AbstractVoterTest_Voter(); + + $this->assertEquals($expectedVote, $voter->vote($this->token, $object, $attributes), $message); + } +} + +class AbstractVoterTest_Voter extends AbstractVoter +{ + protected function getSupportedClasses() + { + return array('stdClass'); + } + + protected function getSupportedAttributes() + { + return array('EDIT', 'CREATE'); + } + + protected function isGranted($attribute, $object, $user = null) + { + return 'EDIT' === $attribute; + } +} diff --git a/Tests/Core/Authorization/Voter/AuthenticatedVoterTest.php b/Core/Tests/Authorization/Voter/AuthenticatedVoterTest.php index b077712..4679c0f 100644 --- a/Tests/Core/Authorization/Voter/AuthenticatedVoterTest.php +++ b/Core/Tests/Authorization/Voter/AuthenticatedVoterTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\Authorization\Voter; +namespace Symfony\Component\Security\Core\Tests\Authorization\Voter; use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolver; use Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter; diff --git a/Core/Tests/Authorization/Voter/ExpressionVoterTest.php b/Core/Tests/Authorization/Voter/ExpressionVoterTest.php new file mode 100644 index 0000000..dc8ea79 --- /dev/null +++ b/Core/Tests/Authorization/Voter/ExpressionVoterTest.php @@ -0,0 +1,97 @@ +<?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\Tests\Authorization\Voter; + +use Symfony\Component\Security\Core\Authorization\Voter\ExpressionVoter; +use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; +use Symfony\Component\Security\Core\Role\Role; + +class ExpressionVoterTest extends \PHPUnit_Framework_TestCase +{ + public function testSupportsAttribute() + { + $expression = $this->createExpression(); + $expressionLanguage = $this->getMock('Symfony\Component\Security\Core\Authorization\ExpressionLanguage'); + $voter = new ExpressionVoter($expressionLanguage, $this->createTrustResolver(), $this->createRoleHierarchy()); + + $this->assertTrue($voter->supportsAttribute($expression)); + } + + /** + * @dataProvider getVoteTests + */ + public function testVote($roles, $attributes, $expected, $tokenExpectsGetRoles = true, $expressionLanguageExpectsEvaluate = true) + { + $voter = new ExpressionVoter($this->createExpressionLanguage($expressionLanguageExpectsEvaluate), $this->createTrustResolver()); + + $this->assertSame($expected, $voter->vote($this->getToken($roles, $tokenExpectsGetRoles), null, $attributes)); + } + + public function getVoteTests() + { + return array( + array(array(), array(), VoterInterface::ACCESS_ABSTAIN, false, false), + array(array(), array('FOO'), VoterInterface::ACCESS_ABSTAIN, false, false), + + array(array(), array($this->createExpression()), VoterInterface::ACCESS_DENIED, true, false), + + array(array('ROLE_FOO'), array($this->createExpression(), $this->createExpression()), VoterInterface::ACCESS_GRANTED), + array(array('ROLE_BAR', 'ROLE_FOO'), array($this->createExpression()), VoterInterface::ACCESS_GRANTED), + ); + } + + protected function getToken(array $roles, $tokenExpectsGetRoles = true) + { + foreach ($roles as $i => $role) { + $roles[$i] = new Role($role); + } + $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); + + if ($tokenExpectsGetRoles) { + $token->expects($this->once()) + ->method('getRoles') + ->will($this->returnValue($roles)); + } + + return $token; + } + + protected function createExpressionLanguage($expressionLanguageExpectsEvaluate = true) + { + $mock = $this->getMock('Symfony\Component\Security\Core\Authorization\ExpressionLanguage'); + + if ($expressionLanguageExpectsEvaluate) { + $mock->expects($this->once()) + ->method('evaluate') + ->will($this->returnValue(true)); + } + + return $mock; + } + + protected function createTrustResolver() + { + return $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface'); + } + + protected function createRoleHierarchy() + { + return $this->getMock('Symfony\Component\Security\Core\Role\RoleHierarchyInterface'); + } + + protected function createExpression() + { + return $this->getMockBuilder('Symfony\Component\ExpressionLanguage\Expression') + ->disableOriginalConstructor() + ->getMock(); + } +} diff --git a/Tests/Core/Authorization/Voter/RoleHierarchyVoterTest.php b/Core/Tests/Authorization/Voter/RoleHierarchyVoterTest.php index a50fa79..c50ecf3 100644 --- a/Tests/Core/Authorization/Voter/RoleHierarchyVoterTest.php +++ b/Core/Tests/Authorization/Voter/RoleHierarchyVoterTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\Authorization\Voter; +namespace Symfony\Component\Security\Core\Tests\Authorization\Voter; use Symfony\Component\Security\Core\Authorization\Voter\RoleHierarchyVoter; use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; diff --git a/Tests/Core/Authorization/Voter/RoleVoterTest.php b/Core/Tests/Authorization/Voter/RoleVoterTest.php index 8a5cdc5..03ab2da 100644 --- a/Tests/Core/Authorization/Voter/RoleVoterTest.php +++ b/Core/Tests/Authorization/Voter/RoleVoterTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\Authorization\Voter; +namespace Symfony\Component\Security\Core\Tests\Authorization\Voter; use Symfony\Component\Security\Core\Authorization\Voter\RoleVoter; use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; diff --git a/Tests/Core/Encoder/BCryptPasswordEncoderTest.php b/Core/Tests/Encoder/BCryptPasswordEncoderTest.php index 9894c6f..40de8af 100644 --- a/Tests/Core/Encoder/BCryptPasswordEncoderTest.php +++ b/Core/Tests/Encoder/BCryptPasswordEncoderTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\Encoder; +namespace Symfony\Component\Security\Core\Tests\Encoder; use Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder; @@ -45,9 +45,6 @@ class BCryptPasswordEncoderTest extends \PHPUnit_Framework_TestCase } } - /** - * @requires PHP 5.3.7 - */ public function testResultLength() { $encoder = new BCryptPasswordEncoder(self::VALID_COST); @@ -55,9 +52,6 @@ class BCryptPasswordEncoderTest extends \PHPUnit_Framework_TestCase $this->assertEquals(60, strlen($result)); } - /** - * @requires PHP 5.3.7 - */ public function testValidation() { $encoder = new BCryptPasswordEncoder(self::VALID_COST); @@ -76,9 +70,6 @@ class BCryptPasswordEncoderTest extends \PHPUnit_Framework_TestCase $encoder->encodePassword(str_repeat('a', 73), 'salt'); } - /** - * @requires PHP 5.3.7 - */ public function testCheckPasswordLength() { $encoder = new BCryptPasswordEncoder(self::VALID_COST); diff --git a/Tests/Core/Encoder/BasePasswordEncoderTest.php b/Core/Tests/Encoder/BasePasswordEncoderTest.php index 702efb0..14c488b 100644 --- a/Tests/Core/Encoder/BasePasswordEncoderTest.php +++ b/Core/Tests/Encoder/BasePasswordEncoderTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\Encoder; +namespace Symfony\Component\Security\Core\Tests\Encoder; use Symfony\Component\Security\Core\Encoder\BasePasswordEncoder; diff --git a/Tests/Core/Encoder/EncoderFactoryTest.php b/Core/Tests/Encoder/EncoderFactoryTest.php index 4fe60ad..21aaae4 100644 --- a/Tests/Core/Encoder/EncoderFactoryTest.php +++ b/Core/Tests/Encoder/EncoderFactoryTest.php @@ -9,10 +9,11 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\Encoder; +namespace Symfony\Component\Security\Core\Tests\Encoder; use Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder; use Symfony\Component\Security\Core\Encoder\EncoderFactory; +use Symfony\Component\Security\Core\Encoder\EncoderAwareInterface; use Symfony\Component\Security\Core\User\User; use Symfony\Component\Security\Core\User\UserInterface; @@ -52,7 +53,7 @@ class EncoderFactoryTest extends \PHPUnit_Framework_TestCase 'Symfony\Component\Security\Core\User\UserInterface' => new MessageDigestPasswordEncoder('sha1'), )); - $encoder = $factory->getEncoder('Symfony\Component\Security\Tests\Core\Encoder\SomeChildUser'); + $encoder = $factory->getEncoder('Symfony\Component\Security\Core\Tests\Encoder\SomeChildUser'); $expectedEncoder = new MessageDigestPasswordEncoder('sha1'); $this->assertEquals($expectedEncoder->encodePassword('foo', ''), $encoder->encodePassword('foo', '')); } @@ -71,10 +72,63 @@ class EncoderFactoryTest extends \PHPUnit_Framework_TestCase public function testGetEncoderConfiguredForConcreteClassWithClassName() { $factory = new EncoderFactory(array( - 'Symfony\Component\Security\Tests\Core\Encoder\SomeUser' => new MessageDigestPasswordEncoder('sha1'), + 'Symfony\Component\Security\Core\Tests\Encoder\SomeUser' => new MessageDigestPasswordEncoder('sha1'), )); - $encoder = $factory->getEncoder('Symfony\Component\Security\Tests\Core\Encoder\SomeChildUser'); + $encoder = $factory->getEncoder('Symfony\Component\Security\Core\Tests\Encoder\SomeChildUser'); + $expectedEncoder = new MessageDigestPasswordEncoder('sha1'); + $this->assertEquals($expectedEncoder->encodePassword('foo', ''), $encoder->encodePassword('foo', '')); + } + + public function testGetNamedEncoderForEncoderAware() + { + $factory = new EncoderFactory(array( + 'Symfony\Component\Security\Core\Tests\Encoder\EncAwareUser' => new MessageDigestPasswordEncoder('sha256'), + 'encoder_name' => new MessageDigestPasswordEncoder('sha1'), + )); + + $encoder = $factory->getEncoder(new EncAwareUser('user', 'pass')); + $expectedEncoder = new MessageDigestPasswordEncoder('sha1'); + $this->assertEquals($expectedEncoder->encodePassword('foo', ''), $encoder->encodePassword('foo', '')); + } + + public function testGetNullNamedEncoderForEncoderAware() + { + $factory = new EncoderFactory(array( + 'Symfony\Component\Security\Core\Tests\Encoder\EncAwareUser' => new MessageDigestPasswordEncoder('sha1'), + 'encoder_name' => new MessageDigestPasswordEncoder('sha256'), + )); + + $user = new EncAwareUser('user', 'pass'); + $user->encoderName = null; + $encoder = $factory->getEncoder($user); + $expectedEncoder = new MessageDigestPasswordEncoder('sha1'); + $this->assertEquals($expectedEncoder->encodePassword('foo', ''), $encoder->encodePassword('foo', '')); + } + + /** + * @expectedException \RuntimeException + */ + public function testGetInvalidNamedEncoderForEncoderAware() + { + $factory = new EncoderFactory(array( + 'Symfony\Component\Security\Core\Tests\Encoder\EncAwareUser' => new MessageDigestPasswordEncoder('sha1'), + 'encoder_name' => new MessageDigestPasswordEncoder('sha256'), + )); + + $user = new EncAwareUser('user', 'pass'); + $user->encoderName = 'invalid_encoder_name'; + $encoder = $factory->getEncoder($user); + } + + public function testGetEncoderForEncoderAwareWithClassName() + { + $factory = new EncoderFactory(array( + 'Symfony\Component\Security\Core\Tests\Encoder\EncAwareUser' => new MessageDigestPasswordEncoder('sha1'), + 'encoder_name' => new MessageDigestPasswordEncoder('sha256'), + )); + + $encoder = $factory->getEncoder('Symfony\Component\Security\Core\Tests\Encoder\EncAwareUser'); $expectedEncoder = new MessageDigestPasswordEncoder('sha1'); $this->assertEquals($expectedEncoder->encodePassword('foo', ''), $encoder->encodePassword('foo', '')); } @@ -106,3 +160,13 @@ class SomeUser implements UserInterface class SomeChildUser extends SomeUser { } + +class EncAwareUser extends SomeUser implements EncoderAwareInterface +{ + public $encoderName = 'encoder_name'; + + public function getEncoderName() + { + return $this->encoderName; + } +} diff --git a/Tests/Core/Encoder/MessageDigestPasswordEncoderTest.php b/Core/Tests/Encoder/MessageDigestPasswordEncoderTest.php index f37d3bc..5189fff 100644 --- a/Tests/Core/Encoder/MessageDigestPasswordEncoderTest.php +++ b/Core/Tests/Encoder/MessageDigestPasswordEncoderTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\Encoder; +namespace Symfony\Component\Security\Core\Tests\Encoder; use Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder; diff --git a/Tests/Core/Encoder/Pbkdf2PasswordEncoderTest.php b/Core/Tests/Encoder/Pbkdf2PasswordEncoderTest.php index ca16f02..3e9452b 100644 --- a/Tests/Core/Encoder/Pbkdf2PasswordEncoderTest.php +++ b/Core/Tests/Encoder/Pbkdf2PasswordEncoderTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\Encoder; +namespace Symfony\Component\Security\Core\Tests\Encoder; use Symfony\Component\Security\Core\Encoder\Pbkdf2PasswordEncoder; diff --git a/Tests/Core/Encoder/PlaintextPasswordEncoderTest.php b/Core/Tests/Encoder/PlaintextPasswordEncoderTest.php index 8b1b888..c7e0d2a 100644 --- a/Tests/Core/Encoder/PlaintextPasswordEncoderTest.php +++ b/Core/Tests/Encoder/PlaintextPasswordEncoderTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\Encoder; +namespace Symfony\Component\Security\Core\Tests\Encoder; use Symfony\Component\Security\Core\Encoder\PlaintextPasswordEncoder; diff --git a/Core/Tests/Encoder/UserPasswordEncoderTest.php b/Core/Tests/Encoder/UserPasswordEncoderTest.php new file mode 100644 index 0000000..590652d --- /dev/null +++ b/Core/Tests/Encoder/UserPasswordEncoderTest.php @@ -0,0 +1,70 @@ +<?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\Tests\Encoder; + +use Symfony\Component\Security\Core\Encoder\UserPasswordEncoder; + +class UserPasswordEncoderTest extends \PHPUnit_Framework_TestCase +{ + public function testEncodePassword() + { + $userMock = $this->getMock('Symfony\Component\Security\Core\User\UserInterface'); + $userMock->expects($this->any()) + ->method('getSalt') + ->will($this->returnValue('userSalt')); + + $mockEncoder = $this->getMock('Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface'); + $mockEncoder->expects($this->any()) + ->method('encodePassword') + ->with($this->equalTo('plainPassword'), $this->equalTo('userSalt')) + ->will($this->returnValue('encodedPassword')); + + $mockEncoderFactory = $this->getMock('Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface'); + $mockEncoderFactory->expects($this->any()) + ->method('getEncoder') + ->with($this->equalTo($userMock)) + ->will($this->returnValue($mockEncoder)); + + $passwordEncoder = new UserPasswordEncoder($mockEncoderFactory); + + $encoded = $passwordEncoder->encodePassword($userMock, 'plainPassword'); + $this->assertEquals('encodedPassword', $encoded); + } + + public function testIsPasswordValid() + { + $userMock = $this->getMock('Symfony\Component\Security\Core\User\UserInterface'); + $userMock->expects($this->any()) + ->method('getSalt') + ->will($this->returnValue('userSalt')); + $userMock->expects($this->any()) + ->method('getPassword') + ->will($this->returnValue('encodedPassword')); + + $mockEncoder = $this->getMock('Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface'); + $mockEncoder->expects($this->any()) + ->method('isPasswordValid') + ->with($this->equalTo('encodedPassword'), $this->equalTo('plainPassword'), $this->equalTo('userSalt')) + ->will($this->returnValue(true)); + + $mockEncoderFactory = $this->getMock('Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface'); + $mockEncoderFactory->expects($this->any()) + ->method('getEncoder') + ->with($this->equalTo($userMock)) + ->will($this->returnValue($mockEncoder)); + + $passwordEncoder = new UserPasswordEncoder($mockEncoderFactory); + + $isValid = $passwordEncoder->isPasswordValid($userMock, 'plainPassword'); + $this->assertTrue($isValid); + } +} diff --git a/Core/Tests/Exception/UsernameNotFoundExceptionTest.php b/Core/Tests/Exception/UsernameNotFoundExceptionTest.php new file mode 100644 index 0000000..98ea374 --- /dev/null +++ b/Core/Tests/Exception/UsernameNotFoundExceptionTest.php @@ -0,0 +1,25 @@ +<?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\Tests\Exception; + +use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; + +class UsernameNotFoundExceptionTest extends \PHPUnit_Framework_TestCase +{ + public function testGetMessageData() + { + $exception = new UsernameNotFoundException('Username could not be found.'); + $this->assertEquals(array('{{ username }}' => null), $exception->getMessageData()); + $exception->setUsername('username'); + $this->assertEquals(array('{{ username }}' => 'username'), $exception->getMessageData()); + } +} diff --git a/Core/Tests/LegacySecurityContextInterfaceTest.php b/Core/Tests/LegacySecurityContextInterfaceTest.php new file mode 100644 index 0000000..a45ecf9 --- /dev/null +++ b/Core/Tests/LegacySecurityContextInterfaceTest.php @@ -0,0 +1,31 @@ +<?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\Tests; + +use Symfony\Component\Security\Core\SecurityContextInterface; +use Symfony\Component\Security\Core\Security; + +/** + * @group legacy + */ +class LegacySecurityContextInterfaceTest extends \PHPUnit_Framework_TestCase +{ + /** + * Test if the BC Layer is working as intended. + */ + public function testConstantSync() + { + $this->assertSame(Security::ACCESS_DENIED_ERROR, SecurityContextInterface::ACCESS_DENIED_ERROR); + $this->assertSame(Security::AUTHENTICATION_ERROR, SecurityContextInterface::AUTHENTICATION_ERROR); + $this->assertSame(Security::LAST_USERNAME, SecurityContextInterface::LAST_USERNAME); + } +} diff --git a/Core/Tests/LegacySecurityContextTest.php b/Core/Tests/LegacySecurityContextTest.php new file mode 100644 index 0000000..92d7c16 --- /dev/null +++ b/Core/Tests/LegacySecurityContextTest.php @@ -0,0 +1,122 @@ +<?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\Tests; + +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; +use Symfony\Component\Security\Core\Authorization\AuthorizationChecker; +use Symfony\Component\Security\Core\SecurityContext; + +/** + * @group legacy + */ +class LegacySecurityContextTest extends \PHPUnit_Framework_TestCase +{ + private $tokenStorage; + private $authorizationChecker; + private $securityContext; + + protected function setUp() + { + $this->tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); + $this->authorizationChecker = $this->getMock('Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface'); + $this->securityContext = new SecurityContext($this->tokenStorage, $this->authorizationChecker); + } + + public function testGetTokenDelegation() + { + $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); + + $this->tokenStorage + ->expects($this->once()) + ->method('getToken') + ->will($this->returnValue($token)); + + $this->assertTrue($token === $this->securityContext->getToken()); + } + + public function testSetTokenDelegation() + { + $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); + + $this->tokenStorage + ->expects($this->once()) + ->method('setToken') + ->with($token); + + $this->securityContext->setToken($token); + } + + /** + * @dataProvider isGrantedDelegationProvider + */ + public function testIsGrantedDelegation($attributes, $object, $return) + { + $this->authorizationChecker + ->expects($this->once()) + ->method('isGranted') + ->with($attributes, $object) + ->will($this->returnValue($return)); + + $this->assertEquals($return, $this->securityContext->isGranted($attributes, $object)); + } + + public function isGrantedDelegationProvider() + { + return array( + array(array(), new \stdClass(), true), + array(array('henk'), new \stdClass(), false), + array(null, new \stdClass(), false), + array('henk', null, true), + array(array(1), 'henk', true), + ); + } + + /** + * Test dedicated to check if the backwards compatibility is still working. + */ + public function testOldConstructorSignature() + { + $authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'); + $accessDecisionManager = $this->getMock('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface'); + new SecurityContext($authenticationManager, $accessDecisionManager); + } + + /** + * @dataProvider oldConstructorSignatureFailuresProvider + * @expectedException \BadMethodCallException + */ + public function testOldConstructorSignatureFailures($first, $second) + { + new SecurityContext($first, $second); + } + + public function oldConstructorSignatureFailuresProvider() + { + $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); + $authorizationChecker = $this->getMock('Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface'); + $authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'); + $accessDecisionManager = $this->getMock('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface'); + + return array( + array(new \stdClass(), new \stdClass()), + array($tokenStorage, $accessDecisionManager), + array($accessDecisionManager, $tokenStorage), + array($authorizationChecker, $accessDecisionManager), + array($accessDecisionManager, $authorizationChecker), + array($tokenStorage, $accessDecisionManager), + array($authenticationManager, $authorizationChecker), + array('henk', 'hans'), + array(null, false), + array(true, null), + ); + } +} diff --git a/Core/Tests/Resources/TranslationFilesTest.php b/Core/Tests/Resources/TranslationFilesTest.php new file mode 100644 index 0000000..dc38e4a --- /dev/null +++ b/Core/Tests/Resources/TranslationFilesTest.php @@ -0,0 +1,31 @@ +<?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\Tests\Resources; + +class TranslationFilesTest extends \PHPUnit_Framework_TestCase +{ + /** + * @dataProvider provideTranslationFiles + */ + public function testTranslationFileIsValid($filePath) + { + \PHPUnit_Util_XML::loadfile($filePath, false, false, true); + } + + public function provideTranslationFiles() + { + return array_map( + function ($filePath) { return (array) $filePath; }, + glob(dirname(dirname(__DIR__)).'/Resources/translations/*.xlf') + ); + } +} diff --git a/Tests/Core/Role/RoleHierarchyTest.php b/Core/Tests/Role/RoleHierarchyTest.php index a98aed6..df1b6a3 100644 --- a/Tests/Core/Role/RoleHierarchyTest.php +++ b/Core/Tests/Role/RoleHierarchyTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\Role; +namespace Symfony\Component\Security\Core\Tests\Role; use Symfony\Component\Security\Core\Role\RoleHierarchy; use Symfony\Component\Security\Core\Role\Role; diff --git a/Tests/Core/Role/RoleTest.php b/Core/Tests/Role/RoleTest.php index e2e7ca8..02be07b 100644 --- a/Tests/Core/Role/RoleTest.php +++ b/Core/Tests/Role/RoleTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\Role; +namespace Symfony\Component\Security\Core\Tests\Role; use Symfony\Component\Security\Core\Role\Role; diff --git a/Tests/Core/Role/SwitchUserRoleTest.php b/Core/Tests/Role/SwitchUserRoleTest.php index bf9b173..f0ce468 100644 --- a/Tests/Core/Role/SwitchUserRoleTest.php +++ b/Core/Tests/Role/SwitchUserRoleTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\Role; +namespace Symfony\Component\Security\Core\Tests\Role; use Symfony\Component\Security\Core\Role\SwitchUserRole; diff --git a/Tests/Core/User/ChainUserProviderTest.php b/Core/Tests/User/ChainUserProviderTest.php index 9d38a4c..ab01f47 100644 --- a/Tests/Core/User/ChainUserProviderTest.php +++ b/Core/Tests/User/ChainUserProviderTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\User; +namespace Symfony\Component\Security\Core\Tests\User; use Symfony\Component\Security\Core\Exception\UnsupportedUserException; use Symfony\Component\Security\Core\User\ChainUserProvider; diff --git a/Tests/Core/User/InMemoryUserProviderTest.php b/Core/Tests/User/InMemoryUserProviderTest.php index 266d397..0a1815f 100644 --- a/Tests/Core/User/InMemoryUserProviderTest.php +++ b/Core/Tests/User/InMemoryUserProviderTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\User; +namespace Symfony\Component\Security\Core\Tests\User; use Symfony\Component\Security\Core\User\InMemoryUserProvider; use Symfony\Component\Security\Core\User\User; diff --git a/Tests/Core/User/UserCheckerTest.php b/Core/Tests/User/UserCheckerTest.php index dca6311..ac21781 100644 --- a/Tests/Core/User/UserCheckerTest.php +++ b/Core/Tests/User/UserCheckerTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\User; +namespace Symfony\Component\Security\Core\Tests\User; use Symfony\Component\Security\Core\User\UserChecker; diff --git a/Tests/Core/User/UserTest.php b/Core/Tests/User/UserTest.php index eb21503..b589b4a 100644 --- a/Tests/Core/User/UserTest.php +++ b/Core/Tests/User/UserTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\User; +namespace Symfony\Component\Security\Core\Tests\User; use Symfony\Component\Security\Core\User\User; @@ -92,4 +92,10 @@ class UserTest extends \PHPUnit_Framework_TestCase $user->eraseCredentials(); $this->assertEquals('superpass', $user->getPassword()); } + + public function testToString() + { + $user = new User('fabien', 'superpass'); + $this->assertEquals('fabien', (string) $user); + } } diff --git a/Tests/Core/Util/ClassUtilsTest.php b/Core/Tests/Util/ClassUtilsTest.php index 8359236..e8f0143 100644 --- a/Tests/Core/Util/ClassUtilsTest.php +++ b/Core/Tests/Util/ClassUtilsTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\Util +namespace Symfony\Component\Security\Core\Tests\Util { use Symfony\Component\Security\Core\Util\ClassUtils; @@ -22,9 +22,9 @@ namespace Symfony\Component\Security\Tests\Core\Util array('Symfony\Component\Security\Core\Util\ClassUtils', 'Symfony\Component\Security\Core\Util\ClassUtils'), array('MyProject\Proxies\__CG__\stdClass', 'stdClass'), array('MyProject\Proxies\__CG__\OtherProject\Proxies\__CG__\stdClass', 'stdClass'), - array('MyProject\Proxies\__CG__\Symfony\Component\Security\Tests\Core\Util\ChildObject', 'Symfony\Component\Security\Tests\Core\Util\ChildObject'), - array(new TestObject(), 'Symfony\Component\Security\Tests\Core\Util\TestObject'), - array(new \Acme\DemoBundle\Proxy\__CG__\Symfony\Component\Security\Tests\Core\Util\TestObject(), 'Symfony\Component\Security\Tests\Core\Util\TestObject'), + array('MyProject\Proxies\__CG__\Symfony\Component\Security\Core\Tests\Util\ChildObject', 'Symfony\Component\Security\Core\Tests\Util\ChildObject'), + array(new TestObject(), 'Symfony\Component\Security\Core\Tests\Util\TestObject'), + array(new \Acme\DemoBundle\Proxy\__CG__\Symfony\Component\Security\Core\Tests\Util\TestObject(), 'Symfony\Component\Security\Core\Tests\Util\TestObject'), ); } @@ -42,9 +42,9 @@ namespace Symfony\Component\Security\Tests\Core\Util } } -namespace Acme\DemoBundle\Proxy\__CG__\Symfony\Component\Security\Tests\Core\Util +namespace Acme\DemoBundle\Proxy\__CG__\Symfony\Component\Security\Core\Tests\Util { - class TestObject extends \Symfony\Component\Security\Tests\Core\Util\TestObject + class TestObject extends \Symfony\Component\Security\Core\Tests\Util\TestObject { } } diff --git a/Tests/Core/Util/StringUtilsTest.php b/Core/Tests/Util/StringUtilsTest.php index 3b18d48..faeaf25 100644 --- a/Tests/Core/Util/StringUtilsTest.php +++ b/Core/Tests/Util/StringUtilsTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core\Util; +namespace Symfony\Component\Security\Core\Tests\Util; use Symfony\Component\Security\Core\Util\StringUtils; diff --git a/Core/Tests/Validator/Constraints/LegacyUserPasswordValidatorTest.php b/Core/Tests/Validator/Constraints/LegacyUserPasswordValidatorTest.php new file mode 100644 index 0000000..8053732 --- /dev/null +++ b/Core/Tests/Validator/Constraints/LegacyUserPasswordValidatorTest.php @@ -0,0 +1,28 @@ +<?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\Tests\Validator\Constraints; + +use Symfony\Component\Validator\Validation; + +/** + * @since 2.5.4 + * + * @author Bernhard Schussek <bschussek@gmail.com> + * @group legacy + */ +class LegacyUserPasswordValidatorTest extends UserPasswordValidatorTest +{ + protected function getApiVersion() + { + return Validation::API_VERSION_2_5_BC; + } +} diff --git a/Core/Tests/Validator/Constraints/UserPasswordValidatorTest.php b/Core/Tests/Validator/Constraints/UserPasswordValidatorTest.php new file mode 100644 index 0000000..047c929 --- /dev/null +++ b/Core/Tests/Validator/Constraints/UserPasswordValidatorTest.php @@ -0,0 +1,169 @@ +<?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\Tests\Validator\Constraints; + +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface; +use Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface; +use Symfony\Component\Security\Core\Validator\Constraints\UserPassword; +use Symfony\Component\Security\Core\Validator\Constraints\UserPasswordValidator; +use Symfony\Component\Validator\Tests\Constraints\AbstractConstraintValidatorTest; + +/** + * @author Bernhard Schussek <bschussek@gmail.com> + */ +abstract class UserPasswordValidatorTest extends AbstractConstraintValidatorTest +{ + const PASSWORD = 's3Cr3t'; + + const SALT = '^S4lt$'; + + /** + * @var TokenStorageInterface + */ + protected $tokenStorage; + + /** + * @var PasswordEncoderInterface + */ + protected $encoder; + + /** + * @var EncoderFactoryInterface + */ + protected $encoderFactory; + + protected function createValidator() + { + return new UserPasswordValidator($this->tokenStorage, $this->encoderFactory); + } + + protected function setUp() + { + $user = $this->createUser(); + $this->tokenStorage = $this->createTokenStorage($user); + $this->encoder = $this->createPasswordEncoder(); + $this->encoderFactory = $this->createEncoderFactory($this->encoder); + + parent::setUp(); + } + + public function testPasswordIsValid() + { + $constraint = new UserPassword(array( + 'message' => 'myMessage', + )); + + $this->encoder->expects($this->once()) + ->method('isPasswordValid') + ->with(static::PASSWORD, 'secret', static::SALT) + ->will($this->returnValue(true)); + + $this->validator->validate('secret', $constraint); + + $this->assertNoViolation(); + } + + public function testPasswordIsNotValid() + { + $constraint = new UserPassword(array( + 'message' => 'myMessage', + )); + + $this->encoder->expects($this->once()) + ->method('isPasswordValid') + ->with(static::PASSWORD, 'secret', static::SALT) + ->will($this->returnValue(false)); + + $this->validator->validate('secret', $constraint); + + $this->buildViolation('myMessage') + ->assertRaised(); + } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + */ + public function testUserIsNotValid() + { + $user = $this->getMock('Foo\Bar\User'); + + $this->tokenStorage = $this->createTokenStorage($user); + $this->validator = $this->createValidator(); + $this->validator->initialize($this->context); + + $this->validator->validate('secret', new UserPassword()); + } + + protected function createUser() + { + $mock = $this->getMock('Symfony\Component\Security\Core\User\UserInterface'); + + $mock + ->expects($this->any()) + ->method('getPassword') + ->will($this->returnValue(static::PASSWORD)) + ; + + $mock + ->expects($this->any()) + ->method('getSalt') + ->will($this->returnValue(static::SALT)) + ; + + return $mock; + } + + protected function createPasswordEncoder($isPasswordValid = true) + { + return $this->getMock('Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface'); + } + + protected function createEncoderFactory($encoder = null) + { + $mock = $this->getMock('Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface'); + + $mock + ->expects($this->any()) + ->method('getEncoder') + ->will($this->returnValue($encoder)) + ; + + return $mock; + } + + protected function createTokenStorage($user = null) + { + $token = $this->createAuthenticationToken($user); + + $mock = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); + $mock + ->expects($this->any()) + ->method('getToken') + ->will($this->returnValue($token)) + ; + + return $mock; + } + + protected function createAuthenticationToken($user = null) + { + $mock = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); + $mock + ->expects($this->any()) + ->method('getUser') + ->will($this->returnValue($user)) + ; + + return $mock; + } +} diff --git a/Core/User/User.php b/Core/User/User.php index 86f1acd..bc81f7f 100644 --- a/Core/User/User.php +++ b/Core/User/User.php @@ -43,6 +43,11 @@ final class User implements AdvancedUserInterface $this->roles = $roles; } + public function __toString() + { + return $this->getUsername(); + } + /** * {@inheritdoc} */ diff --git a/Core/Validator/Constraints/UserPassword.php b/Core/Validator/Constraints/UserPassword.php index aee4cda..35537b3 100644 --- a/Core/Validator/Constraints/UserPassword.php +++ b/Core/Validator/Constraints/UserPassword.php @@ -19,7 +19,7 @@ use Symfony\Component\Validator\Constraint; */ class UserPassword extends Constraint { - public $message = 'This value should be the user current password.'; + public $message = 'This value should be the user\'s current password.'; public $service = 'security.validator.user_password'; /** diff --git a/Core/Validator/Constraints/UserPasswordValidator.php b/Core/Validator/Constraints/UserPasswordValidator.php index ab455f3..2dc7fee 100644 --- a/Core/Validator/Constraints/UserPasswordValidator.php +++ b/Core/Validator/Constraints/UserPasswordValidator.php @@ -12,20 +12,21 @@ namespace Symfony\Component\Security\Core\Validator\Constraints; use Symfony\Component\Security\Core\User\UserInterface; -use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; use Symfony\Component\Validator\Exception\ConstraintDefinitionException; +use Symfony\Component\Validator\Exception\UnexpectedTypeException; class UserPasswordValidator extends ConstraintValidator { - private $securityContext; + private $tokenStorage; private $encoderFactory; - public function __construct(SecurityContextInterface $securityContext, EncoderFactoryInterface $encoderFactory) + public function __construct(TokenStorageInterface $tokenStorage, EncoderFactoryInterface $encoderFactory) { - $this->securityContext = $securityContext; + $this->tokenStorage = $tokenStorage; $this->encoderFactory = $encoderFactory; } @@ -34,7 +35,11 @@ class UserPasswordValidator extends ConstraintValidator */ public function validate($password, Constraint $constraint) { - $user = $this->securityContext->getToken()->getUser(); + if (!$constraint instanceof UserPassword) { + throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\UserPassword'); + } + + $user = $this->tokenStorage->getToken()->getUser(); if (!$user instanceof UserInterface) { throw new ConstraintDefinitionException('The User object must implement the UserInterface interface.'); diff --git a/Core/composer.json b/Core/composer.json new file mode 100644 index 0000000..354c55e --- /dev/null +++ b/Core/composer.json @@ -0,0 +1,49 @@ +{ + "name": "symfony/security-core", + "type": "library", + "description": "Symfony Security Component - Core Library", + "keywords": [], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=5.3.9", + "paragonie/random_compat": "~1.0" + }, + "require-dev": { + "symfony/event-dispatcher": "~2.1", + "symfony/expression-language": "~2.6", + "symfony/http-foundation": "~2.4", + "symfony/validator": "~2.5,>=2.5.9", + "psr/log": "~1.0", + "ircmaxell/password-compat": "1.0.*" + }, + "suggest": { + "symfony/event-dispatcher": "", + "symfony/http-foundation": "", + "symfony/validator": "For using the user password constraint", + "symfony/expression-language": "For using the expression voter", + "ircmaxell/password-compat": "For using the BCrypt password encoder in PHP <5.5" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\Security\\Core\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + } +} diff --git a/Core/phpunit.xml.dist b/Core/phpunit.xml.dist new file mode 100644 index 0000000..2dc341a --- /dev/null +++ b/Core/phpunit.xml.dist @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<phpunit backupGlobals="false" + backupStaticAttributes="false" + colors="true" + convertErrorsToExceptions="true" + convertNoticesToExceptions="true" + convertWarningsToExceptions="true" + processIsolation="false" + stopOnFailure="false" + syntaxCheck="false" + bootstrap="vendor/autoload.php" +> + <php> + <ini name="error_reporting" value="-1" /> + </php> + + <testsuites> + <testsuite name="Symfony Security Component Core Test Suite"> + <directory>./Tests/</directory> + </testsuite> + </testsuites> + + <filter> + <whitelist> + <directory>./</directory> + <exclude> + <directory>./Resources</directory> + <directory>./Tests</directory> + <directory>./vendor</directory> + </exclude> + </whitelist> + </filter> +</phpunit> diff --git a/Csrf/.gitignore b/Csrf/.gitignore new file mode 100644 index 0000000..c49a5d8 --- /dev/null +++ b/Csrf/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/Csrf/CsrfToken.php b/Csrf/CsrfToken.php new file mode 100644 index 0000000..9ccaaeb --- /dev/null +++ b/Csrf/CsrfToken.php @@ -0,0 +1,72 @@ +<?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\Csrf; + +/** + * A CSRF token. + * + * @author Bernhard Schussek <bschussek@gmail.com> + */ +class CsrfToken +{ + /** + * @var string + */ + private $id; + + /** + * @var string + */ + private $value; + + /** + * Constructor. + * + * @param string $id The token ID + * @param string $value The actual token value + */ + public function __construct($id, $value) + { + $this->id = (string) $id; + $this->value = (string) $value; + } + + /** + * Returns the ID of the CSRF token. + * + * @return string The token ID + */ + public function getId() + { + return $this->id; + } + + /** + * Returns the value of the CSRF token. + * + * @return string The token value + */ + public function getValue() + { + return $this->value; + } + + /** + * Returns the value of the CSRF token. + * + * @return string The token value + */ + public function __toString() + { + return $this->value; + } +} diff --git a/Csrf/CsrfTokenManager.php b/Csrf/CsrfTokenManager.php new file mode 100644 index 0000000..e129502 --- /dev/null +++ b/Csrf/CsrfTokenManager.php @@ -0,0 +1,97 @@ +<?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\Csrf; + +use Symfony\Component\Security\Core\Util\StringUtils; +use Symfony\Component\Security\Csrf\TokenGenerator\UriSafeTokenGenerator; +use Symfony\Component\Security\Csrf\TokenGenerator\TokenGeneratorInterface; +use Symfony\Component\Security\Csrf\TokenStorage\NativeSessionTokenStorage; +use Symfony\Component\Security\Csrf\TokenStorage\TokenStorageInterface; + +/** + * Default implementation of {@link CsrfTokenManagerInterface}. + * + * @author Bernhard Schussek <bschussek@gmail.com> + */ +class CsrfTokenManager implements CsrfTokenManagerInterface +{ + /** + * @var TokenGeneratorInterface + */ + private $generator; + + /** + * @var TokenStorageInterface + */ + private $storage; + + /** + * Creates a new CSRF provider using PHP's native session storage. + * + * @param TokenGeneratorInterface|null $generator The token generator + * @param TokenStorageInterface|null $storage The storage for storing + * generated CSRF tokens + */ + public function __construct(TokenGeneratorInterface $generator = null, TokenStorageInterface $storage = null) + { + $this->generator = $generator ?: new UriSafeTokenGenerator(); + $this->storage = $storage ?: new NativeSessionTokenStorage(); + } + + /** + * {@inheritdoc} + */ + public function getToken($tokenId) + { + if ($this->storage->hasToken($tokenId)) { + $value = $this->storage->getToken($tokenId); + } else { + $value = $this->generator->generateToken(); + + $this->storage->setToken($tokenId, $value); + } + + return new CsrfToken($tokenId, $value); + } + + /** + * {@inheritdoc} + */ + public function refreshToken($tokenId) + { + $value = $this->generator->generateToken(); + + $this->storage->setToken($tokenId, $value); + + return new CsrfToken($tokenId, $value); + } + + /** + * {@inheritdoc} + */ + public function removeToken($tokenId) + { + return $this->storage->removeToken($tokenId); + } + + /** + * {@inheritdoc} + */ + public function isTokenValid(CsrfToken $token) + { + if (!$this->storage->hasToken($token->getId())) { + return false; + } + + return StringUtils::equals($this->storage->getToken($token->getId()), $token->getValue()); + } +} diff --git a/Csrf/CsrfTokenManagerInterface.php b/Csrf/CsrfTokenManagerInterface.php new file mode 100644 index 0000000..bccabe6 --- /dev/null +++ b/Csrf/CsrfTokenManagerInterface.php @@ -0,0 +1,69 @@ +<?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\Csrf; + +/** + * Manages CSRF tokens. + * + * @since 2.4 + * + * @author Bernhard Schussek <bschussek@gmail.com> + */ +interface CsrfTokenManagerInterface +{ + /** + * Returns a CSRF token for the given ID. + * + * If previously no token existed for the given ID, a new token is + * generated. Otherwise the existing token is returned (with the same value, + * not the same instance). + * + * @param string $tokenId The token ID. You may choose an arbitrary value + * for the ID + * + * @return CsrfToken The CSRF token + */ + public function getToken($tokenId); + + /** + * Generates a new token value for the given ID. + * + * This method will generate a new token for the given token ID, independent + * of whether a token value previously existed or not. It can be used to + * enforce once-only tokens in environments with high security needs. + * + * @param string $tokenId The token ID. You may choose an arbitrary value + * for the ID + * + * @return CsrfToken The CSRF token + */ + public function refreshToken($tokenId); + + /** + * Invalidates the CSRF token with the given ID, if one exists. + * + * @param string $tokenId The token ID + * + * @return string|null Returns the removed token value if one existed, NULL + * otherwise + */ + public function removeToken($tokenId); + + /** + * Returns whether the given CSRF token is valid. + * + * @param CsrfToken $token A CSRF token + * + * @return bool Returns true if the token is valid, false otherwise + */ + public function isTokenValid(CsrfToken $token); +} diff --git a/Csrf/Exception/TokenNotFoundException.php b/Csrf/Exception/TokenNotFoundException.php new file mode 100644 index 0000000..936afde --- /dev/null +++ b/Csrf/Exception/TokenNotFoundException.php @@ -0,0 +1,21 @@ +<?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\Csrf\Exception; + +use Symfony\Component\Security\Core\Exception\RuntimeException; + +/** + * @author Bernhard Schussek <bschussek@gmail.com> + */ +class TokenNotFoundException extends RuntimeException +{ +} diff --git a/Csrf/LICENSE b/Csrf/LICENSE new file mode 100644 index 0000000..12a7453 --- /dev/null +++ b/Csrf/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2004-2016 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Csrf/README.md b/Csrf/README.md new file mode 100644 index 0000000..aff72a0 --- /dev/null +++ b/Csrf/README.md @@ -0,0 +1,14 @@ +Security Component - CSRF +========================= + +The Security CSRF (cross-site request forgery) component provides a class +`CsrfTokenManager` for generating and validating CSRF tokens. + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/components/security/index.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/Csrf/Tests/CsrfTokenManagerTest.php b/Csrf/Tests/CsrfTokenManagerTest.php new file mode 100644 index 0000000..3112038 --- /dev/null +++ b/Csrf/Tests/CsrfTokenManagerTest.php @@ -0,0 +1,164 @@ +<?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\Csrf\Tests; + +use Symfony\Component\Security\Csrf\CsrfToken; +use Symfony\Component\Security\Csrf\CsrfTokenManager; + +/** + * @author Bernhard Schussek <bschussek@gmail.com> + */ +class CsrfTokenManagerTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $generator; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $storage; + + /** + * @var CsrfTokenManager + */ + private $manager; + + protected function setUp() + { + $this->generator = $this->getMock('Symfony\Component\Security\Csrf\TokenGenerator\TokenGeneratorInterface'); + $this->storage = $this->getMock('Symfony\Component\Security\Csrf\TokenStorage\TokenStorageInterface'); + $this->manager = new CsrfTokenManager($this->generator, $this->storage); + } + + protected function tearDown() + { + $this->generator = null; + $this->storage = null; + $this->manager = null; + } + + public function testGetNonExistingToken() + { + $this->storage->expects($this->once()) + ->method('hasToken') + ->with('token_id') + ->will($this->returnValue(false)); + + $this->generator->expects($this->once()) + ->method('generateToken') + ->will($this->returnValue('TOKEN')); + + $this->storage->expects($this->once()) + ->method('setToken') + ->with('token_id', 'TOKEN'); + + $token = $this->manager->getToken('token_id'); + + $this->assertInstanceOf('Symfony\Component\Security\Csrf\CsrfToken', $token); + $this->assertSame('token_id', $token->getId()); + $this->assertSame('TOKEN', $token->getValue()); + } + + public function testUseExistingTokenIfAvailable() + { + $this->storage->expects($this->once()) + ->method('hasToken') + ->with('token_id') + ->will($this->returnValue(true)); + + $this->storage->expects($this->once()) + ->method('getToken') + ->with('token_id') + ->will($this->returnValue('TOKEN')); + + $token = $this->manager->getToken('token_id'); + + $this->assertInstanceOf('Symfony\Component\Security\Csrf\CsrfToken', $token); + $this->assertSame('token_id', $token->getId()); + $this->assertSame('TOKEN', $token->getValue()); + } + + public function testRefreshTokenAlwaysReturnsNewToken() + { + $this->storage->expects($this->never()) + ->method('hasToken'); + + $this->generator->expects($this->once()) + ->method('generateToken') + ->will($this->returnValue('TOKEN')); + + $this->storage->expects($this->once()) + ->method('setToken') + ->with('token_id', 'TOKEN'); + + $token = $this->manager->refreshToken('token_id'); + + $this->assertInstanceOf('Symfony\Component\Security\Csrf\CsrfToken', $token); + $this->assertSame('token_id', $token->getId()); + $this->assertSame('TOKEN', $token->getValue()); + } + + public function testMatchingTokenIsValid() + { + $this->storage->expects($this->once()) + ->method('hasToken') + ->with('token_id') + ->will($this->returnValue(true)); + + $this->storage->expects($this->once()) + ->method('getToken') + ->with('token_id') + ->will($this->returnValue('TOKEN')); + + $this->assertTrue($this->manager->isTokenValid(new CsrfToken('token_id', 'TOKEN'))); + } + + public function testNonMatchingTokenIsNotValid() + { + $this->storage->expects($this->once()) + ->method('hasToken') + ->with('token_id') + ->will($this->returnValue(true)); + + $this->storage->expects($this->once()) + ->method('getToken') + ->with('token_id') + ->will($this->returnValue('TOKEN')); + + $this->assertFalse($this->manager->isTokenValid(new CsrfToken('token_id', 'FOOBAR'))); + } + + public function testNonExistingTokenIsNotValid() + { + $this->storage->expects($this->once()) + ->method('hasToken') + ->with('token_id') + ->will($this->returnValue(false)); + + $this->storage->expects($this->never()) + ->method('getToken'); + + $this->assertFalse($this->manager->isTokenValid(new CsrfToken('token_id', 'FOOBAR'))); + } + + public function testRemoveToken() + { + $this->storage->expects($this->once()) + ->method('removeToken') + ->with('token_id') + ->will($this->returnValue('REMOVED_TOKEN')); + + $this->assertSame('REMOVED_TOKEN', $this->manager->removeToken('token_id')); + } +} diff --git a/Csrf/Tests/TokenGenerator/UriSafeTokenGeneratorTest.php b/Csrf/Tests/TokenGenerator/UriSafeTokenGeneratorTest.php new file mode 100644 index 0000000..1b325e5 --- /dev/null +++ b/Csrf/Tests/TokenGenerator/UriSafeTokenGeneratorTest.php @@ -0,0 +1,71 @@ +<?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\Csrf\Tests\TokenGenerator; + +use Symfony\Component\Security\Csrf\TokenGenerator\UriSafeTokenGenerator; + +/** + * @author Bernhard Schussek <bschussek@gmail.com> + */ +class UriSafeTokenGeneratorTest extends \PHPUnit_Framework_TestCase +{ + const ENTROPY = 1000; + + /** + * A non alpha-numeric byte string. + * + * @var string + */ + private static $bytes; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $random; + + /** + * @var UriSafeTokenGenerator + */ + private $generator; + + public static function setUpBeforeClass() + { + self::$bytes = base64_decode('aMf+Tct/RLn2WQ=='); + } + + protected function setUp() + { + $this->random = $this->getMock('Symfony\Component\Security\Core\Util\SecureRandomInterface'); + $this->generator = new UriSafeTokenGenerator($this->random, self::ENTROPY); + } + + protected function tearDown() + { + $this->random = null; + $this->generator = null; + } + + public function testGenerateToken() + { + $this->random->expects($this->once()) + ->method('nextBytes') + ->with(self::ENTROPY / 8) + ->will($this->returnValue(self::$bytes)); + + $token = $this->generator->generateToken(); + + $this->assertTrue(ctype_print($token), 'is printable'); + $this->assertStringNotMatchesFormat('%S+%S', $token, 'is URI safe'); + $this->assertStringNotMatchesFormat('%S/%S', $token, 'is URI safe'); + $this->assertStringNotMatchesFormat('%S=%S', $token, 'is URI safe'); + } +} diff --git a/Csrf/Tests/TokenStorage/NativeSessionTokenStorageTest.php b/Csrf/Tests/TokenStorage/NativeSessionTokenStorageTest.php new file mode 100644 index 0000000..7d3a537 --- /dev/null +++ b/Csrf/Tests/TokenStorage/NativeSessionTokenStorageTest.php @@ -0,0 +1,126 @@ +<?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\Csrf\Tests\TokenStorage; + +use Symfony\Component\Security\Csrf\TokenStorage\NativeSessionTokenStorage; + +/** + * @author Bernhard Schussek <bschussek@gmail.com> + * + * @runTestsInSeparateProcesses + * @preserveGlobalState disabled + */ +class NativeSessionTokenStorageTest extends \PHPUnit_Framework_TestCase +{ + const SESSION_NAMESPACE = 'foobar'; + + /** + * @var NativeSessionTokenStorage + */ + private $storage; + + public static function setUpBeforeClass() + { + ini_set('session.save_handler', 'files'); + ini_set('session.save_path', sys_get_temp_dir()); + + parent::setUpBeforeClass(); + } + + protected function setUp() + { + $_SESSION = array(); + + $this->storage = new NativeSessionTokenStorage(self::SESSION_NAMESPACE); + } + + public function testStoreTokenInClosedSession() + { + $this->storage->setToken('token_id', 'TOKEN'); + + $this->assertSame(array(self::SESSION_NAMESPACE => array('token_id' => 'TOKEN')), $_SESSION); + } + + /** + * @requires PHP 5.4 + */ + public function testStoreTokenInClosedSessionWithExistingSessionId() + { + session_id('foobar'); + + $this->assertSame(PHP_SESSION_NONE, session_status()); + + $this->storage->setToken('token_id', 'TOKEN'); + + $this->assertSame(PHP_SESSION_ACTIVE, session_status()); + $this->assertSame(array(self::SESSION_NAMESPACE => array('token_id' => 'TOKEN')), $_SESSION); + } + + public function testStoreTokenInActiveSession() + { + session_start(); + + $this->storage->setToken('token_id', 'TOKEN'); + + $this->assertSame(array(self::SESSION_NAMESPACE => array('token_id' => 'TOKEN')), $_SESSION); + } + + /** + * @depends testStoreTokenInClosedSession + */ + public function testCheckToken() + { + $this->assertFalse($this->storage->hasToken('token_id')); + + $this->storage->setToken('token_id', 'TOKEN'); + + $this->assertTrue($this->storage->hasToken('token_id')); + } + + /** + * @depends testStoreTokenInClosedSession + */ + public function testGetExistingToken() + { + $this->storage->setToken('token_id', 'TOKEN'); + + $this->assertSame('TOKEN', $this->storage->getToken('token_id')); + } + + /** + * @expectedException \Symfony\Component\Security\Csrf\Exception\TokenNotFoundException + */ + public function testGetNonExistingToken() + { + $this->storage->getToken('token_id'); + } + + /** + * @depends testCheckToken + */ + public function testRemoveNonExistingToken() + { + $this->assertNull($this->storage->removeToken('token_id')); + $this->assertFalse($this->storage->hasToken('token_id')); + } + + /** + * @depends testCheckToken + */ + public function testRemoveExistingToken() + { + $this->storage->setToken('token_id', 'TOKEN'); + + $this->assertSame('TOKEN', $this->storage->removeToken('token_id')); + $this->assertFalse($this->storage->hasToken('token_id')); + } +} diff --git a/Csrf/Tests/TokenStorage/SessionTokenStorageTest.php b/Csrf/Tests/TokenStorage/SessionTokenStorageTest.php new file mode 100644 index 0000000..0eac0a8 --- /dev/null +++ b/Csrf/Tests/TokenStorage/SessionTokenStorageTest.php @@ -0,0 +1,258 @@ +<?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\Csrf\Tests\TokenStorage; + +use Symfony\Component\Security\Csrf\TokenStorage\SessionTokenStorage; + +/** + * @author Bernhard Schussek <bschussek@gmail.com> + */ +class SessionTokenStorageTest extends \PHPUnit_Framework_TestCase +{ + const SESSION_NAMESPACE = 'foobar'; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $session; + + /** + * @var SessionTokenStorage + */ + private $storage; + + protected function setUp() + { + $this->session = $this->getMockBuilder('Symfony\Component\HttpFoundation\Session\SessionInterface') + ->disableOriginalConstructor() + ->getMock(); + $this->storage = new SessionTokenStorage($this->session, self::SESSION_NAMESPACE); + } + + public function testStoreTokenInClosedSession() + { + $this->session->expects($this->any()) + ->method('isStarted') + ->will($this->returnValue(false)); + + $this->session->expects($this->once()) + ->method('start'); + + $this->session->expects($this->once()) + ->method('set') + ->with(self::SESSION_NAMESPACE.'/token_id', 'TOKEN'); + + $this->storage->setToken('token_id', 'TOKEN'); + } + + public function testStoreTokenInActiveSession() + { + $this->session->expects($this->any()) + ->method('isStarted') + ->will($this->returnValue(true)); + + $this->session->expects($this->never()) + ->method('start'); + + $this->session->expects($this->once()) + ->method('set') + ->with(self::SESSION_NAMESPACE.'/token_id', 'TOKEN'); + + $this->storage->setToken('token_id', 'TOKEN'); + } + + public function testCheckTokenInClosedSession() + { + $this->session->expects($this->any()) + ->method('isStarted') + ->will($this->returnValue(false)); + + $this->session->expects($this->once()) + ->method('start'); + + $this->session->expects($this->once()) + ->method('has') + ->with(self::SESSION_NAMESPACE.'/token_id') + ->will($this->returnValue('RESULT')); + + $this->assertSame('RESULT', $this->storage->hasToken('token_id')); + } + + public function testCheckTokenInActiveSession() + { + $this->session->expects($this->any()) + ->method('isStarted') + ->will($this->returnValue(true)); + + $this->session->expects($this->never()) + ->method('start'); + + $this->session->expects($this->once()) + ->method('has') + ->with(self::SESSION_NAMESPACE.'/token_id') + ->will($this->returnValue('RESULT')); + + $this->assertSame('RESULT', $this->storage->hasToken('token_id')); + } + + public function testGetExistingTokenFromClosedSession() + { + $this->session->expects($this->any()) + ->method('isStarted') + ->will($this->returnValue(false)); + + $this->session->expects($this->once()) + ->method('start'); + + $this->session->expects($this->once()) + ->method('has') + ->with(self::SESSION_NAMESPACE.'/token_id') + ->will($this->returnValue(true)); + + $this->session->expects($this->once()) + ->method('get') + ->with(self::SESSION_NAMESPACE.'/token_id') + ->will($this->returnValue('RESULT')); + + $this->assertSame('RESULT', $this->storage->getToken('token_id')); + } + + public function testGetExistingTokenFromActiveSession() + { + $this->session->expects($this->any()) + ->method('isStarted') + ->will($this->returnValue(true)); + + $this->session->expects($this->never()) + ->method('start'); + + $this->session->expects($this->once()) + ->method('has') + ->with(self::SESSION_NAMESPACE.'/token_id') + ->will($this->returnValue(true)); + + $this->session->expects($this->once()) + ->method('get') + ->with(self::SESSION_NAMESPACE.'/token_id') + ->will($this->returnValue('RESULT')); + + $this->assertSame('RESULT', $this->storage->getToken('token_id')); + } + + /** + * @expectedException \Symfony\Component\Security\Csrf\Exception\TokenNotFoundException + */ + public function testGetNonExistingTokenFromClosedSession() + { + $this->session->expects($this->any()) + ->method('isStarted') + ->will($this->returnValue(false)); + + $this->session->expects($this->once()) + ->method('start'); + + $this->session->expects($this->once()) + ->method('has') + ->with(self::SESSION_NAMESPACE.'/token_id') + ->will($this->returnValue(false)); + + $this->storage->getToken('token_id'); + } + + /** + * @expectedException \Symfony\Component\Security\Csrf\Exception\TokenNotFoundException + */ + public function testGetNonExistingTokenFromActiveSession() + { + $this->session->expects($this->any()) + ->method('isStarted') + ->will($this->returnValue(true)); + + $this->session->expects($this->never()) + ->method('start'); + + $this->session->expects($this->once()) + ->method('has') + ->with(self::SESSION_NAMESPACE.'/token_id') + ->will($this->returnValue(false)); + + $this->storage->getToken('token_id'); + } + + public function testRemoveNonExistingTokenFromClosedSession() + { + $this->session->expects($this->any()) + ->method('isStarted') + ->will($this->returnValue(false)); + + $this->session->expects($this->once()) + ->method('start'); + + $this->session->expects($this->once()) + ->method('remove') + ->with(self::SESSION_NAMESPACE.'/token_id') + ->will($this->returnValue(null)); + + $this->assertNull($this->storage->removeToken('token_id')); + } + + public function testRemoveNonExistingTokenFromActiveSession() + { + $this->session->expects($this->any()) + ->method('isStarted') + ->will($this->returnValue(true)); + + $this->session->expects($this->never()) + ->method('start'); + + $this->session->expects($this->once()) + ->method('remove') + ->with(self::SESSION_NAMESPACE.'/token_id') + ->will($this->returnValue(null)); + + $this->assertNull($this->storage->removeToken('token_id')); + } + + public function testRemoveExistingTokenFromClosedSession() + { + $this->session->expects($this->any()) + ->method('isStarted') + ->will($this->returnValue(false)); + + $this->session->expects($this->once()) + ->method('start'); + + $this->session->expects($this->once()) + ->method('remove') + ->with(self::SESSION_NAMESPACE.'/token_id') + ->will($this->returnValue('TOKEN')); + + $this->assertSame('TOKEN', $this->storage->removeToken('token_id')); + } + + public function testRemoveExistingTokenFromActiveSession() + { + $this->session->expects($this->any()) + ->method('isStarted') + ->will($this->returnValue(true)); + + $this->session->expects($this->never()) + ->method('start'); + + $this->session->expects($this->once()) + ->method('remove') + ->with(self::SESSION_NAMESPACE.'/token_id') + ->will($this->returnValue('TOKEN')); + + $this->assertSame('TOKEN', $this->storage->removeToken('token_id')); + } +} diff --git a/Csrf/TokenGenerator/TokenGeneratorInterface.php b/Csrf/TokenGenerator/TokenGeneratorInterface.php new file mode 100644 index 0000000..1405b84 --- /dev/null +++ b/Csrf/TokenGenerator/TokenGeneratorInterface.php @@ -0,0 +1,29 @@ +<?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\Csrf\TokenGenerator; + +/** + * Generates CSRF tokens. + * + * @since 2.4 + * + * @author Bernhard Schussek <bschussek@gmail.com> + */ +interface TokenGeneratorInterface +{ + /** + * Generates a CSRF token. + * + * @return string The generated CSRF token + */ + public function generateToken(); +} diff --git a/Csrf/TokenGenerator/UriSafeTokenGenerator.php b/Csrf/TokenGenerator/UriSafeTokenGenerator.php new file mode 100644 index 0000000..edeb435 --- /dev/null +++ b/Csrf/TokenGenerator/UriSafeTokenGenerator.php @@ -0,0 +1,66 @@ +<?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\Csrf\TokenGenerator; + +use Symfony\Component\Security\Core\Util\SecureRandomInterface; +use Symfony\Component\Security\Core\Util\SecureRandom; + +/** + * Generates CSRF tokens. + * + * @since 2.4 + * + * @author Bernhard Schussek <bernhard.schussek@symfony.com> + */ +class UriSafeTokenGenerator implements TokenGeneratorInterface +{ + /** + * The generator for random values. + * + * @var SecureRandomInterface + */ + private $random; + + /** + * The amount of entropy collected for each token (in bits). + * + * @var int + */ + private $entropy; + + /** + * Generates URI-safe CSRF tokens. + * + * @param SecureRandomInterface|null $random The random value generator used for + * generating entropy + * @param int $entropy The amount of entropy collected for + * each token (in bits) + */ + public function __construct(SecureRandomInterface $random = null, $entropy = 256) + { + $this->random = $random ?: new SecureRandom(); + $this->entropy = $entropy; + } + + /** + * {@inheritdoc} + */ + public function generateToken() + { + // Generate an URI safe base64 encoded string that does not contain "+", + // "/" or "=" which need to be URL encoded and make URLs unnecessarily + // longer. + $bytes = $this->random->nextBytes($this->entropy / 8); + + return rtrim(strtr(base64_encode($bytes), '+/', '-_'), '='); + } +} diff --git a/Csrf/TokenStorage/NativeSessionTokenStorage.php b/Csrf/TokenStorage/NativeSessionTokenStorage.php new file mode 100644 index 0000000..2620156 --- /dev/null +++ b/Csrf/TokenStorage/NativeSessionTokenStorage.php @@ -0,0 +1,123 @@ +<?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\Csrf\TokenStorage; + +use Symfony\Component\Security\Csrf\Exception\TokenNotFoundException; + +/** + * Token storage that uses PHP's native session handling. + * + * @since 2.4 + * + * @author Bernhard Schussek <bschussek@gmail.com> + */ +class NativeSessionTokenStorage implements TokenStorageInterface +{ + /** + * The namespace used to store values in the session. + * + * @var string + */ + const SESSION_NAMESPACE = '_csrf'; + + /** + * @var bool + */ + private $sessionStarted = false; + + /** + * @var string + */ + private $namespace; + + /** + * Initializes the storage with a session namespace. + * + * @param string $namespace The namespace under which the token is stored + * in the session + */ + public function __construct($namespace = self::SESSION_NAMESPACE) + { + $this->namespace = $namespace; + } + + /** + * {@inheritdoc} + */ + public function getToken($tokenId) + { + if (!$this->sessionStarted) { + $this->startSession(); + } + + if (!isset($_SESSION[$this->namespace][$tokenId])) { + throw new TokenNotFoundException('The CSRF token with ID '.$tokenId.' does not exist.'); + } + + return (string) $_SESSION[$this->namespace][$tokenId]; + } + + /** + * {@inheritdoc} + */ + public function setToken($tokenId, $token) + { + if (!$this->sessionStarted) { + $this->startSession(); + } + + $_SESSION[$this->namespace][$tokenId] = (string) $token; + } + + /** + * {@inheritdoc} + */ + public function hasToken($tokenId) + { + if (!$this->sessionStarted) { + $this->startSession(); + } + + return isset($_SESSION[$this->namespace][$tokenId]); + } + + /** + * {@inheritdoc} + */ + public function removeToken($tokenId) + { + if (!$this->sessionStarted) { + $this->startSession(); + } + + $token = isset($_SESSION[$this->namespace][$tokenId]) + ? (string) $_SESSION[$this->namespace][$tokenId] + : null; + + unset($_SESSION[$this->namespace][$tokenId]); + + return $token; + } + + private function startSession() + { + if (PHP_VERSION_ID >= 50400) { + if (PHP_SESSION_NONE === session_status()) { + session_start(); + } + } elseif (!session_id()) { + session_start(); + } + + $this->sessionStarted = true; + } +} diff --git a/Csrf/TokenStorage/SessionTokenStorage.php b/Csrf/TokenStorage/SessionTokenStorage.php new file mode 100644 index 0000000..a6a6ea3 --- /dev/null +++ b/Csrf/TokenStorage/SessionTokenStorage.php @@ -0,0 +1,109 @@ +<?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\Csrf\TokenStorage; + +use Symfony\Component\HttpFoundation\Session\SessionInterface; +use Symfony\Component\Security\Csrf\Exception\TokenNotFoundException; + +/** + * Token storage that uses a Symfony2 Session object. + * + * @since 2.4 + * + * @author Bernhard Schussek <bschussek@gmail.com> + */ +class SessionTokenStorage implements TokenStorageInterface +{ + /** + * The namespace used to store values in the session. + * + * @var string + */ + const SESSION_NAMESPACE = '_csrf'; + + /** + * The user session from which the session ID is returned. + * + * @var SessionInterface + */ + private $session; + + /** + * @var string + */ + private $namespace; + + /** + * Initializes the storage with a Session object and a session namespace. + * + * @param SessionInterface $session The user session + * @param string $namespace The namespace under which the token + * is stored in the session + */ + public function __construct(SessionInterface $session, $namespace = self::SESSION_NAMESPACE) + { + $this->session = $session; + $this->namespace = $namespace; + } + + /** + * {@inheritdoc} + */ + public function getToken($tokenId) + { + if (!$this->session->isStarted()) { + $this->session->start(); + } + + if (!$this->session->has($this->namespace.'/'.$tokenId)) { + throw new TokenNotFoundException('The CSRF token with ID '.$tokenId.' does not exist.'); + } + + return (string) $this->session->get($this->namespace.'/'.$tokenId); + } + + /** + * {@inheritdoc} + */ + public function setToken($tokenId, $token) + { + if (!$this->session->isStarted()) { + $this->session->start(); + } + + $this->session->set($this->namespace.'/'.$tokenId, (string) $token); + } + + /** + * {@inheritdoc} + */ + public function hasToken($tokenId) + { + if (!$this->session->isStarted()) { + $this->session->start(); + } + + return $this->session->has($this->namespace.'/'.$tokenId); + } + + /** + * {@inheritdoc} + */ + public function removeToken($tokenId) + { + if (!$this->session->isStarted()) { + $this->session->start(); + } + + return $this->session->remove($this->namespace.'/'.$tokenId); + } +} diff --git a/Csrf/TokenStorage/TokenStorageInterface.php b/Csrf/TokenStorage/TokenStorageInterface.php new file mode 100644 index 0000000..5efe72f --- /dev/null +++ b/Csrf/TokenStorage/TokenStorageInterface.php @@ -0,0 +1,60 @@ +<?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\Csrf\TokenStorage; + +/** + * Stores CSRF tokens. + * + * @since 2.4 + * + * @author Bernhard Schussek <bschussek@gmail.com> + */ +interface TokenStorageInterface +{ + /** + * Reads a stored CSRF token. + * + * @param string $tokenId The token ID + * + * @return string The stored token + * + * @throws \Symfony\Component\Security\Csrf\Exception\TokenNotFoundException If the token ID does not exist + */ + public function getToken($tokenId); + + /** + * Stores a CSRF token. + * + * @param string $tokenId The token ID + * @param string $token The CSRF token + */ + public function setToken($tokenId, $token); + + /** + * Removes a CSRF token. + * + * @param string $tokenId The token ID + * + * @return string|null Returns the removed token if one existed, NULL + * otherwise + */ + public function removeToken($tokenId); + + /** + * Checks whether a token with the given token ID exists. + * + * @param string $tokenId The token ID + * + * @return bool Whether a token exists with the given ID + */ + public function hasToken($tokenId); +} diff --git a/Csrf/composer.json b/Csrf/composer.json new file mode 100644 index 0000000..2930e32 --- /dev/null +++ b/Csrf/composer.json @@ -0,0 +1,40 @@ +{ + "name": "symfony/security-csrf", + "type": "library", + "description": "Symfony Security Component - CSRF Library", + "keywords": [], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=5.3.9", + "symfony/security-core": "~2.4" + }, + "require-dev": { + "symfony/http-foundation": "~2.1" + }, + "suggest": { + "symfony/http-foundation": "For using the class SessionTokenStorage." + }, + "autoload": { + "psr-4": { "Symfony\\Component\\Security\\Csrf\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + } +} diff --git a/Csrf/phpunit.xml.dist b/Csrf/phpunit.xml.dist new file mode 100644 index 0000000..f5b1e65 --- /dev/null +++ b/Csrf/phpunit.xml.dist @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<phpunit backupGlobals="false" + backupStaticAttributes="false" + colors="true" + convertErrorsToExceptions="true" + convertNoticesToExceptions="true" + convertWarningsToExceptions="true" + processIsolation="false" + stopOnFailure="false" + syntaxCheck="false" + bootstrap="vendor/autoload.php" +> + <php> + <ini name="error_reporting" value="-1" /> + </php> + + <testsuites> + <testsuite name="Symfony Security Component CSRF Test Suite"> + <directory>./Tests/</directory> + </testsuite> + </testsuites> + + <filter> + <whitelist> + <directory>./</directory> + <exclude> + <directory>./Tests</directory> + <directory>./vendor</directory> + </exclude> + </whitelist> + </filter> +</phpunit> diff --git a/Http/.gitignore b/Http/.gitignore new file mode 100644 index 0000000..c49a5d8 --- /dev/null +++ b/Http/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/Http/AccessMap.php b/Http/AccessMap.php index 14fcbe1..116874a 100644 --- a/Http/AccessMap.php +++ b/Http/AccessMap.php @@ -28,12 +28,12 @@ class AccessMap implements AccessMapInterface * Constructor. * * @param RequestMatcherInterface $requestMatcher A RequestMatcherInterface instance - * @param array $roles An array of roles needed to access the resource + * @param array $attributes An array of attributes to pass to the access decision manager (like roles) * @param string|null $channel The channel to enforce (http, https, or null) */ - public function add(RequestMatcherInterface $requestMatcher, array $roles = array(), $channel = null) + public function add(RequestMatcherInterface $requestMatcher, array $attributes = array(), $channel = null) { - $this->map[] = array($requestMatcher, $roles, $channel); + $this->map[] = array($requestMatcher, $attributes, $channel); } /** diff --git a/Http/Authentication/AuthenticationUtils.php b/Http/Authentication/AuthenticationUtils.php new file mode 100644 index 0000000..4d5c71a --- /dev/null +++ b/Http/Authentication/AuthenticationUtils.php @@ -0,0 +1,88 @@ +<?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\Authentication; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\Security\Core\Exception\AuthenticationException; +use Symfony\Component\Security\Core\Security; + +/** + * Extracts Security Errors from Request. + * + * @author Boris Vujicic <boris.vujicic@gmail.com> + */ +class AuthenticationUtils +{ + /** + * @var RequestStack + */ + private $requestStack; + + /** + * @param RequestStack $requestStack + */ + public function __construct(RequestStack $requestStack) + { + $this->requestStack = $requestStack; + } + + /** + * @param bool $clearSession + * + * @return AuthenticationException|null + */ + public function getLastAuthenticationError($clearSession = true) + { + $request = $this->getRequest(); + $session = $request->getSession(); + $authenticationException = null; + + if ($request->attributes->has(Security::AUTHENTICATION_ERROR)) { + $authenticationException = $request->attributes->get(Security::AUTHENTICATION_ERROR); + } elseif ($session !== null && $session->has(Security::AUTHENTICATION_ERROR)) { + $authenticationException = $session->get(Security::AUTHENTICATION_ERROR); + + if ($clearSession) { + $session->remove(Security::AUTHENTICATION_ERROR); + } + } + + return $authenticationException; + } + + /** + * @return string + */ + public function getLastUsername() + { + $session = $this->getRequest()->getSession(); + + return null === $session ? '' : $session->get(Security::LAST_USERNAME); + } + + /** + * @return Request + * + * @throws \LogicException + */ + private function getRequest() + { + $request = $this->requestStack->getCurrentRequest(); + + if (null === $request) { + throw new \LogicException('Request should exist so it can be processed for error.'); + } + + return $request; + } +} diff --git a/Http/Authentication/CustomAuthenticationFailureHandler.php b/Http/Authentication/CustomAuthenticationFailureHandler.php new file mode 100644 index 0000000..36d4a78 --- /dev/null +++ b/Http/Authentication/CustomAuthenticationFailureHandler.php @@ -0,0 +1,45 @@ +<?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\Authentication; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Security\Core\Exception\AuthenticationException; + +/** + * @author Fabien Potencier <fabien@symfony.com> + */ +class CustomAuthenticationFailureHandler implements AuthenticationFailureHandlerInterface +{ + private $handler; + + /** + * Constructor. + * + * @param AuthenticationFailureHandlerInterface $handler An AuthenticationFailureHandlerInterface instance + * @param array $options Options for processing a successful authentication attempt + */ + public function __construct(AuthenticationFailureHandlerInterface $handler, array $options) + { + $this->handler = $handler; + if (method_exists($handler, 'setOptions')) { + $this->handler->setOptions($options); + } + } + + /** + * {@inheritdoc} + */ + public function onAuthenticationFailure(Request $request, AuthenticationException $exception) + { + return $this->handler->onAuthenticationFailure($request, $exception); + } +} diff --git a/Http/Authentication/CustomAuthenticationSuccessHandler.php b/Http/Authentication/CustomAuthenticationSuccessHandler.php new file mode 100644 index 0000000..2d1b26e --- /dev/null +++ b/Http/Authentication/CustomAuthenticationSuccessHandler.php @@ -0,0 +1,49 @@ +<?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\Authentication; + +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\HttpFoundation\Request; + +/** + * @author Fabien Potencier <fabien@symfony.com> + */ +class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandlerInterface +{ + private $handler; + + /** + * Constructor. + * + * @param AuthenticationSuccessHandlerInterface $handler An AuthenticationSuccessHandlerInterface instance + * @param array $options Options for processing a successful authentication attempt + * @param string $providerKey The provider key + */ + public function __construct(AuthenticationSuccessHandlerInterface $handler, array $options, $providerKey) + { + $this->handler = $handler; + if (method_exists($handler, 'setOptions')) { + $this->handler->setOptions($options); + } + if (method_exists($handler, 'setProviderKey')) { + $this->handler->setProviderKey($providerKey); + } + } + + /** + * {@inheritdoc} + */ + public function onAuthenticationSuccess(Request $request, TokenInterface $token) + { + return $this->handler->onAuthenticationSuccess($request, $token); + } +} diff --git a/Http/Authentication/DefaultAuthenticationFailureHandler.php b/Http/Authentication/DefaultAuthenticationFailureHandler.php index b3c5c4d..f8004d6 100644 --- a/Http/Authentication/DefaultAuthenticationFailureHandler.php +++ b/Http/Authentication/DefaultAuthenticationFailureHandler.php @@ -15,7 +15,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\HttpKernelInterface; use Psr\Log\LoggerInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; -use Symfony\Component\Security\Core\SecurityContextInterface; +use Symfony\Component\Security\Core\Security; use Symfony\Component\Security\Http\HttpUtils; /** @@ -34,6 +34,12 @@ class DefaultAuthenticationFailureHandler implements AuthenticationFailureHandle protected $httpUtils; protected $logger; protected $options; + protected $defaultOptions = array( + 'failure_path' => null, + 'failure_forward' => false, + 'login_path' => '/login', + 'failure_path_parameter' => '_failure_path', + ); /** * Constructor. @@ -43,18 +49,32 @@ class DefaultAuthenticationFailureHandler implements AuthenticationFailureHandle * @param array $options Options for processing a failed authentication attempt. * @param LoggerInterface $logger Optional logger */ - public function __construct(HttpKernelInterface $httpKernel, HttpUtils $httpUtils, array $options, LoggerInterface $logger = null) + public function __construct(HttpKernelInterface $httpKernel, HttpUtils $httpUtils, array $options = array(), LoggerInterface $logger = null) { $this->httpKernel = $httpKernel; $this->httpUtils = $httpUtils; $this->logger = $logger; + $this->setOptions($options); + } - $this->options = array_merge(array( - 'failure_path' => null, - 'failure_forward' => false, - 'login_path' => '/login', - 'failure_path_parameter' => '_failure_path', - ), $options); + /** + * Gets the options. + * + * @return array An array of options + */ + public function getOptions() + { + return $this->options; + } + + /** + * Sets the options. + * + * @param array $options An array of options + */ + public function setOptions(array $options) + { + $this->options = array_merge($this->defaultOptions, $options); } /** @@ -72,20 +92,20 @@ class DefaultAuthenticationFailureHandler implements AuthenticationFailureHandle if ($this->options['failure_forward']) { if (null !== $this->logger) { - $this->logger->debug(sprintf('Forwarding to %s', $this->options['failure_path'])); + $this->logger->debug('Authentication failure, forward triggered.', array('failure_path' => $this->options['failure_path'])); } $subRequest = $this->httpUtils->createRequest($request, $this->options['failure_path']); - $subRequest->attributes->set(SecurityContextInterface::AUTHENTICATION_ERROR, $exception); + $subRequest->attributes->set(Security::AUTHENTICATION_ERROR, $exception); return $this->httpKernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST); } if (null !== $this->logger) { - $this->logger->debug(sprintf('Redirecting to %s', $this->options['failure_path'])); + $this->logger->debug('Authentication failure, redirect triggered.', array('failure_path' => $this->options['failure_path'])); } - $request->getSession()->set(SecurityContextInterface::AUTHENTICATION_ERROR, $exception); + $request->getSession()->set(Security::AUTHENTICATION_ERROR, $exception); return $this->httpUtils->createRedirectResponse($request, $this->options['failure_path']); } diff --git a/Http/Authentication/DefaultAuthenticationSuccessHandler.php b/Http/Authentication/DefaultAuthenticationSuccessHandler.php index 591a28d..5fa7071 100644 --- a/Http/Authentication/DefaultAuthenticationSuccessHandler.php +++ b/Http/Authentication/DefaultAuthenticationSuccessHandler.php @@ -27,6 +27,13 @@ class DefaultAuthenticationSuccessHandler implements AuthenticationSuccessHandle protected $httpUtils; protected $options; protected $providerKey; + protected $defaultOptions = array( + 'always_use_default_target_path' => false, + 'default_target_path' => '/', + 'login_path' => '/login', + 'target_path_parameter' => '_target_path', + 'use_referer' => false, + ); /** * Constructor. @@ -34,17 +41,10 @@ class DefaultAuthenticationSuccessHandler implements AuthenticationSuccessHandle * @param HttpUtils $httpUtils * @param array $options Options for processing a successful authentication attempt. */ - public function __construct(HttpUtils $httpUtils, array $options) + public function __construct(HttpUtils $httpUtils, array $options = array()) { $this->httpUtils = $httpUtils; - - $this->options = array_merge(array( - 'always_use_default_target_path' => false, - 'default_target_path' => '/', - 'login_path' => '/login', - 'target_path_parameter' => '_target_path', - 'use_referer' => false, - ), $options); + $this->setOptions($options); } /** @@ -56,6 +56,26 @@ class DefaultAuthenticationSuccessHandler implements AuthenticationSuccessHandle } /** + * Gets the options. + * + * @return array An array of options + */ + public function getOptions() + { + return $this->options; + } + + /** + * Sets the options. + * + * @param array $options An array of options + */ + public function setOptions(array $options) + { + $this->options = array_merge($this->defaultOptions, $options); + } + + /** * Get the provider key. * * @return string diff --git a/Http/Authentication/SimpleAuthenticationHandler.php b/Http/Authentication/SimpleAuthenticationHandler.php new file mode 100644 index 0000000..c5c43f2 --- /dev/null +++ b/Http/Authentication/SimpleAuthenticationHandler.php @@ -0,0 +1,106 @@ +<?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\Authentication; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Psr\Log\LoggerInterface; +use Symfony\Component\Security\Core\Exception\AuthenticationException; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Core\Authentication\SimpleAuthenticatorInterface; + +/** + * Class to proxy authentication success/failure handlers. + * + * Events are sent to the SimpleAuthenticatorInterface if it implements + * the right interface, otherwise (or if it fails to return a Response) + * the default handlers are triggered. + * + * @author Jordi Boggiano <j.boggiano@seld.be> + */ +class SimpleAuthenticationHandler implements AuthenticationFailureHandlerInterface, AuthenticationSuccessHandlerInterface +{ + protected $successHandler; + protected $failureHandler; + protected $simpleAuthenticator; + protected $logger; + + /** + * Constructor. + * + * @param SimpleAuthenticatorInterface $authenticator SimpleAuthenticatorInterface instance + * @param AuthenticationSuccessHandlerInterface $successHandler Default success handler + * @param AuthenticationFailureHandlerInterface $failureHandler Default failure handler + * @param LoggerInterface $logger Optional logger + */ + public function __construct(SimpleAuthenticatorInterface $authenticator, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, LoggerInterface $logger = null) + { + $this->simpleAuthenticator = $authenticator; + $this->successHandler = $successHandler; + $this->failureHandler = $failureHandler; + $this->logger = $logger; + } + + /** + * {@inheritdoc} + */ + public function onAuthenticationSuccess(Request $request, TokenInterface $token) + { + if ($this->simpleAuthenticator instanceof AuthenticationSuccessHandlerInterface) { + if ($this->logger) { + $this->logger->debug('Selected an authentication success handler.', array('handler' => get_class($this->simpleAuthenticator))); + } + + $response = $this->simpleAuthenticator->onAuthenticationSuccess($request, $token); + if ($response instanceof Response) { + return $response; + } + + if (null !== $response) { + throw new \UnexpectedValueException(sprintf('The %s::onAuthenticationSuccess method must return null to use the default success handler, or a Response object', get_class($this->simpleAuthenticator))); + } + } + + if ($this->logger) { + $this->logger->debug('Fallback to the default authentication success handler.'); + } + + return $this->successHandler->onAuthenticationSuccess($request, $token); + } + + /** + * {@inheritdoc} + */ + public function onAuthenticationFailure(Request $request, AuthenticationException $exception) + { + if ($this->simpleAuthenticator instanceof AuthenticationFailureHandlerInterface) { + if ($this->logger) { + $this->logger->debug('Selected an authentication failure handler.', array('handler' => get_class($this->simpleAuthenticator))); + } + + $response = $this->simpleAuthenticator->onAuthenticationFailure($request, $exception); + if ($response instanceof Response) { + return $response; + } + + if (null !== $response) { + throw new \UnexpectedValueException(sprintf('The %s::onAuthenticationFailure method must return null to use the default failure handler, or a Response object', get_class($this->simpleAuthenticator))); + } + } + + if ($this->logger) { + $this->logger->debug('Fallback to the default authentication failure handler.'); + } + + return $this->failureHandler->onAuthenticationFailure($request, $exception); + } +} diff --git a/Http/EntryPoint/DigestAuthenticationEntryPoint.php b/Http/EntryPoint/DigestAuthenticationEntryPoint.php index 5a7aa1a..89f80ad 100644 --- a/Http/EntryPoint/DigestAuthenticationEntryPoint.php +++ b/Http/EntryPoint/DigestAuthenticationEntryPoint.php @@ -54,7 +54,7 @@ class DigestAuthenticationEntryPoint implements AuthenticationEntryPointInterfac } if (null !== $this->logger) { - $this->logger->debug(sprintf('WWW-Authenticate header sent to user agent: "%s"', $authenticateHeader)); + $this->logger->debug('WWW-Authenticate header sent.', array('header' => $authenticateHeader)); } $response = new Response(); diff --git a/Http/Firewall.php b/Http/Firewall.php index 7499c6f..7bad47a 100644 --- a/Http/Firewall.php +++ b/Http/Firewall.php @@ -11,9 +11,9 @@ namespace Symfony\Component\Security\Http; -use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpKernel\Event\FinishRequestEvent; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; @@ -31,6 +31,7 @@ class Firewall implements EventSubscriberInterface { private $map; private $dispatcher; + private $exceptionListeners; /** * Constructor. @@ -42,6 +43,7 @@ class Firewall implements EventSubscriberInterface { $this->map = $map; $this->dispatcher = $dispatcher; + $this->exceptionListeners = new \SplObjectStorage(); } /** @@ -51,14 +53,15 @@ class Firewall implements EventSubscriberInterface */ public function onKernelRequest(GetResponseEvent $event) { - if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) { + if (!$event->isMasterRequest()) { return; } // register listeners for this firewall - list($listeners, $exception) = $this->map->getListeners($event->getRequest()); - if (null !== $exception) { - $exception->register($this->dispatcher); + list($listeners, $exceptionListener) = $this->map->getListeners($event->getRequest()); + if (null !== $exceptionListener) { + $this->exceptionListeners[$event->getRequest()] = $exceptionListener; + $exceptionListener->register($this->dispatcher); } // initiate the listener chain @@ -71,11 +74,24 @@ class Firewall implements EventSubscriberInterface } } + public function onKernelFinishRequest(FinishRequestEvent $event) + { + $request = $event->getRequest(); + + if (isset($this->exceptionListeners[$request])) { + $this->exceptionListeners[$request]->unregister($this->dispatcher); + unset($this->exceptionListeners[$request]); + } + } + /** * {@inheritdoc} */ public static function getSubscribedEvents() { - return array(KernelEvents::REQUEST => array('onKernelRequest', 8)); + return array( + KernelEvents::REQUEST => array('onKernelRequest', 8), + KernelEvents::FINISH_REQUEST => 'onKernelFinishRequest', + ); } } diff --git a/Http/Firewall/AbstractAuthenticationListener.php b/Http/Firewall/AbstractAuthenticationListener.php index f71089f..09a4f55 100644 --- a/Http/Firewall/AbstractAuthenticationListener.php +++ b/Http/Firewall/AbstractAuthenticationListener.php @@ -15,8 +15,9 @@ use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterfa use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface; use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface; use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface; -use Symfony\Component\Security\Core\SecurityContextInterface; +use Symfony\Component\Security\Core\Security; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\Exception\SessionUnavailableException; @@ -55,7 +56,7 @@ abstract class AbstractAuthenticationListener implements ListenerInterface protected $providerKey; protected $httpUtils; - private $securityContext; + private $tokenStorage; private $sessionStrategy; private $dispatcher; private $successHandler; @@ -65,7 +66,7 @@ abstract class AbstractAuthenticationListener implements ListenerInterface /** * Constructor. * - * @param SecurityContextInterface $securityContext A SecurityContext instance + * @param TokenStorageInterface $tokenStorage A TokenStorageInterface instance * @param AuthenticationManagerInterface $authenticationManager An AuthenticationManagerInterface instance * @param SessionAuthenticationStrategyInterface $sessionStrategy * @param HttpUtils $httpUtils An HttpUtilsInterface instance @@ -79,13 +80,13 @@ abstract class AbstractAuthenticationListener implements ListenerInterface * * @throws \InvalidArgumentException */ - public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null) + public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null) { if (empty($providerKey)) { throw new \InvalidArgumentException('$providerKey must not be empty.'); } - $this->securityContext = $securityContext; + $this->tokenStorage = $tokenStorage; $this->authenticationManager = $authenticationManager; $this->sessionStrategy = $sessionStrategy; $this->providerKey = $providerKey; @@ -149,14 +150,14 @@ abstract class AbstractAuthenticationListener implements ListenerInterface if ($returnValue instanceof TokenInterface) { $this->sessionStrategy->onAuthentication($request, $returnValue); - $response = $this->onSuccess($event, $request, $returnValue); + $response = $this->onSuccess($request, $returnValue); } elseif ($returnValue instanceof Response) { $response = $returnValue; } else { throw new \RuntimeException('attemptAuthentication() must either return a Response, an implementation of TokenInterface, or null.'); } } catch (AuthenticationException $e) { - $response = $this->onFailure($event, $request, $e); + $response = $this->onFailure($request, $e); } $event->setResponse($response); @@ -189,15 +190,15 @@ abstract class AbstractAuthenticationListener implements ListenerInterface */ abstract protected function attemptAuthentication(Request $request); - private function onFailure(GetResponseEvent $event, Request $request, AuthenticationException $failed) + private function onFailure(Request $request, AuthenticationException $failed) { if (null !== $this->logger) { - $this->logger->info(sprintf('Authentication request failed: %s', $failed->getMessage())); + $this->logger->info('Authentication request failed.', array('exception' => $failed)); } - $token = $this->securityContext->getToken(); + $token = $this->tokenStorage->getToken(); if ($token instanceof UsernamePasswordToken && $this->providerKey === $token->getProviderKey()) { - $this->securityContext->setToken(null); + $this->tokenStorage->setToken(null); } $response = $this->failureHandler->onAuthenticationFailure($request, $failed); @@ -209,17 +210,17 @@ abstract class AbstractAuthenticationListener implements ListenerInterface return $response; } - private function onSuccess(GetResponseEvent $event, Request $request, TokenInterface $token) + private function onSuccess(Request $request, TokenInterface $token) { if (null !== $this->logger) { - $this->logger->info(sprintf('User "%s" has been authenticated successfully', $token->getUsername())); + $this->logger->info('User has been authenticated successfully.', array('username' => $token->getUsername())); } - $this->securityContext->setToken($token); + $this->tokenStorage->setToken($token); $session = $request->getSession(); - $session->remove(SecurityContextInterface::AUTHENTICATION_ERROR); - $session->remove(SecurityContextInterface::LAST_USERNAME); + $session->remove(Security::AUTHENTICATION_ERROR); + $session->remove(Security::LAST_USERNAME); if (null !== $this->dispatcher) { $loginEvent = new InteractiveLoginEvent($request, $token); diff --git a/Http/Firewall/AbstractPreAuthenticatedListener.php b/Http/Firewall/AbstractPreAuthenticatedListener.php index 9973683..b793310 100644 --- a/Http/Firewall/AbstractPreAuthenticatedListener.php +++ b/Http/Firewall/AbstractPreAuthenticatedListener.php @@ -11,9 +11,9 @@ namespace Symfony\Component\Security\Http\Firewall; -use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Http\Event\InteractiveLoginEvent; use Symfony\Component\Security\Http\SecurityEvents; @@ -33,14 +33,14 @@ use Symfony\Component\Security\Core\Exception\BadCredentialsException; abstract class AbstractPreAuthenticatedListener implements ListenerInterface { protected $logger; - private $securityContext; + private $tokenStorage; private $authenticationManager; private $providerKey; private $dispatcher; - public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, $providerKey, LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null) + public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, $providerKey, LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null) { - $this->securityContext = $securityContext; + $this->tokenStorage = $tokenStorage; $this->authenticationManager = $authenticationManager; $this->providerKey = $providerKey; $this->logger = $logger; @@ -56,10 +56,6 @@ abstract class AbstractPreAuthenticatedListener implements ListenerInterface { $request = $event->getRequest(); - if (null !== $this->logger) { - $this->logger->debug(sprintf('Checking secure context token: %s', $this->securityContext->getToken())); - } - try { list($user, $credentials) = $this->getPreAuthenticatedData($request); } catch (BadCredentialsException $e) { @@ -68,23 +64,27 @@ abstract class AbstractPreAuthenticatedListener implements ListenerInterface return; } - if (null !== $token = $this->securityContext->getToken()) { + if (null !== $this->logger) { + $this->logger->debug('Checking current security token.', array('token' => (string) $this->tokenStorage->getToken())); + } + + if (null !== $token = $this->tokenStorage->getToken()) { if ($token instanceof PreAuthenticatedToken && $this->providerKey == $token->getProviderKey() && $token->isAuthenticated() && $token->getUsername() === $user) { return; } } if (null !== $this->logger) { - $this->logger->debug(sprintf('Trying to pre-authenticate user "%s"', $user)); + $this->logger->debug('Trying to pre-authenticate user.', array('username' => (string) $user)); } try { $token = $this->authenticationManager->authenticate(new PreAuthenticatedToken($user, $credentials, $this->providerKey)); if (null !== $this->logger) { - $this->logger->info(sprintf('Authentication success: %s', $token)); + $this->logger->info('Pre-authentication successful.', array('token' => (string) $token)); } - $this->securityContext->setToken($token); + $this->tokenStorage->setToken($token); if (null !== $this->dispatcher) { $loginEvent = new InteractiveLoginEvent($request, $token); @@ -102,12 +102,12 @@ abstract class AbstractPreAuthenticatedListener implements ListenerInterface */ private function clearToken(AuthenticationException $exception) { - $token = $this->securityContext->getToken(); + $token = $this->tokenStorage->getToken(); if ($token instanceof PreAuthenticatedToken && $this->providerKey === $token->getProviderKey()) { - $this->securityContext->setToken(null); + $this->tokenStorage->setToken(null); if (null !== $this->logger) { - $this->logger->info(sprintf('Cleared security context due to exception: %s', $exception->getMessage())); + $this->logger->info('Cleared security token due to an exception.', array('exception' => $exception)); } } } diff --git a/Http/Firewall/AccessListener.php b/Http/Firewall/AccessListener.php index ecb6a09..c234317 100644 --- a/Http/Firewall/AccessListener.php +++ b/Http/Firewall/AccessListener.php @@ -11,10 +11,10 @@ namespace Symfony\Component\Security\Http\Firewall; -use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface; use Symfony\Component\Security\Http\AccessMapInterface; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException; use Symfony\Component\Security\Core\Exception\AccessDeniedException; @@ -26,14 +26,14 @@ use Symfony\Component\Security\Core\Exception\AccessDeniedException; */ class AccessListener implements ListenerInterface { - private $context; + private $tokenStorage; private $accessDecisionManager; private $map; private $authManager; - public function __construct(SecurityContextInterface $context, AccessDecisionManagerInterface $accessDecisionManager, AccessMapInterface $map, AuthenticationManagerInterface $authManager) + public function __construct(TokenStorageInterface $tokenStorage, AccessDecisionManagerInterface $accessDecisionManager, AccessMapInterface $map, AuthenticationManagerInterface $authManager) { - $this->context = $context; + $this->tokenStorage = $tokenStorage; $this->accessDecisionManager = $accessDecisionManager; $this->map = $map; $this->authManager = $authManager; @@ -49,8 +49,8 @@ class AccessListener implements ListenerInterface */ public function handle(GetResponseEvent $event) { - if (null === $token = $this->context->getToken()) { - throw new AuthenticationCredentialsNotFoundException('A Token was not found in the SecurityContext.'); + if (null === $token = $this->tokenStorage->getToken()) { + throw new AuthenticationCredentialsNotFoundException('A Token was not found in the TokenStorage.'); } $request = $event->getRequest(); @@ -63,7 +63,7 @@ class AccessListener implements ListenerInterface if (!$token->isAuthenticated()) { $token = $this->authManager->authenticate($token); - $this->context->setToken($token); + $this->tokenStorage->setToken($token); } if (!$this->accessDecisionManager->decide($token, $attributes, $request)) { diff --git a/Http/Firewall/AnonymousAuthenticationListener.php b/Http/Firewall/AnonymousAuthenticationListener.php index 446dfec..f7feee8 100644 --- a/Http/Firewall/AnonymousAuthenticationListener.php +++ b/Http/Firewall/AnonymousAuthenticationListener.php @@ -11,7 +11,9 @@ namespace Symfony\Component\Security\Http\Firewall; -use Symfony\Component\Security\Core\SecurityContextInterface; +use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Security\Core\Exception\AuthenticationException; use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken; @@ -24,14 +26,16 @@ use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken; */ class AnonymousAuthenticationListener implements ListenerInterface { - private $context; + private $tokenStorage; private $key; + private $authenticationManager; private $logger; - public function __construct(SecurityContextInterface $context, $key, LoggerInterface $logger = null) + public function __construct(TokenStorageInterface $tokenStorage, $key, LoggerInterface $logger = null, AuthenticationManagerInterface $authenticationManager = null) { - $this->context = $context; + $this->tokenStorage = $tokenStorage; $this->key = $key; + $this->authenticationManager = $authenticationManager; $this->logger = $logger; } @@ -42,14 +46,25 @@ class AnonymousAuthenticationListener implements ListenerInterface */ public function handle(GetResponseEvent $event) { - if (null !== $this->context->getToken()) { + if (null !== $this->tokenStorage->getToken()) { return; } - $this->context->setToken(new AnonymousToken($this->key, 'anon.', array())); + try { + $token = new AnonymousToken($this->key, 'anon.', array()); + if (null !== $this->authenticationManager) { + $token = $this->authenticationManager->authenticate($token); + } - if (null !== $this->logger) { - $this->logger->info('Populated SecurityContext with an anonymous Token'); + $this->tokenStorage->setToken($token); + + if (null !== $this->logger) { + $this->logger->info('Populated the TokenStorage with an anonymous Token.'); + } + } catch (AuthenticationException $failed) { + if (null !== $this->logger) { + $this->logger->info('Anonymous authentication failed.', array('exception' => $failed)); + } } } } diff --git a/Http/Firewall/BasicAuthenticationListener.php b/Http/Firewall/BasicAuthenticationListener.php index eed9838..ebe96ea 100644 --- a/Http/Firewall/BasicAuthenticationListener.php +++ b/Http/Firewall/BasicAuthenticationListener.php @@ -11,8 +11,8 @@ namespace Symfony\Component\Security\Http\Firewall; -use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; @@ -26,20 +26,20 @@ use Symfony\Component\Security\Core\Exception\AuthenticationException; */ class BasicAuthenticationListener implements ListenerInterface { - private $securityContext; + private $tokenStorage; private $authenticationManager; private $providerKey; private $authenticationEntryPoint; private $logger; private $ignoreFailure; - public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, $providerKey, AuthenticationEntryPointInterface $authenticationEntryPoint, LoggerInterface $logger = null) + public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, $providerKey, AuthenticationEntryPointInterface $authenticationEntryPoint, LoggerInterface $logger = null) { if (empty($providerKey)) { throw new \InvalidArgumentException('$providerKey must not be empty.'); } - $this->securityContext = $securityContext; + $this->tokenStorage = $tokenStorage; $this->authenticationManager = $authenticationManager; $this->providerKey = $providerKey; $this->authenticationEntryPoint = $authenticationEntryPoint; @@ -60,27 +60,27 @@ class BasicAuthenticationListener implements ListenerInterface return; } - if (null !== $token = $this->securityContext->getToken()) { + if (null !== $token = $this->tokenStorage->getToken()) { if ($token instanceof UsernamePasswordToken && $token->isAuthenticated() && $token->getUsername() === $username) { return; } } if (null !== $this->logger) { - $this->logger->info(sprintf('Basic Authentication Authorization header found for user "%s"', $username)); + $this->logger->info('Basic authentication Authorization header found for user.', array('username' => $username)); } try { $token = $this->authenticationManager->authenticate(new UsernamePasswordToken($username, $request->headers->get('PHP_AUTH_PW'), $this->providerKey)); - $this->securityContext->setToken($token); + $this->tokenStorage->setToken($token); } catch (AuthenticationException $e) { - $token = $this->securityContext->getToken(); + $token = $this->tokenStorage->getToken(); if ($token instanceof UsernamePasswordToken && $this->providerKey === $token->getProviderKey()) { - $this->securityContext->setToken(null); + $this->tokenStorage->setToken(null); } if (null !== $this->logger) { - $this->logger->info(sprintf('Authentication request failed for user "%s": %s', $username, $e->getMessage())); + $this->logger->info('Basic authentication failed for user.', array('username' => $username, 'exception' => $e)); } if ($this->ignoreFailure) { diff --git a/Http/Firewall/ChannelListener.php b/Http/Firewall/ChannelListener.php index 9e4a6ee..637a7f5 100644 --- a/Http/Firewall/ChannelListener.php +++ b/Http/Firewall/ChannelListener.php @@ -44,11 +44,11 @@ class ChannelListener implements ListenerInterface { $request = $event->getRequest(); - list($attributes, $channel) = $this->map->getPatterns($request); + list(, $channel) = $this->map->getPatterns($request); if ('https' === $channel && !$request->isSecure()) { if (null !== $this->logger) { - $this->logger->info('Redirecting to HTTPS'); + $this->logger->info('Redirecting to HTTPS.'); } $response = $this->authenticationEntryPoint->start($request); @@ -60,7 +60,7 @@ class ChannelListener implements ListenerInterface if ('http' === $channel && $request->isSecure()) { if (null !== $this->logger) { - $this->logger->info('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 43ad31d..9ac37cd 100644 --- a/Http/Firewall/ContextListener.php +++ b/Http/Firewall/ContextListener.php @@ -11,16 +11,15 @@ namespace Symfony\Component\Security\Http\Firewall; -use Symfony\Component\HttpKernel\HttpKernelInterface; use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\Event\FilterResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; use Symfony\Component\Security\Core\Exception\UnsupportedUserException; -use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; @@ -33,14 +32,15 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface; */ class ContextListener implements ListenerInterface { - private $context; + private $tokenStorage; private $contextKey; + private $sessionKey; private $logger; private $userProviders; private $dispatcher; private $registered; - public function __construct(SecurityContextInterface $context, array $userProviders, $contextKey, LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null) + public function __construct(TokenStorageInterface $tokenStorage, array $userProviders, $contextKey, LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null) { if (empty($contextKey)) { throw new \InvalidArgumentException('$contextKey must not be empty.'); @@ -52,21 +52,22 @@ class ContextListener implements ListenerInterface } } - $this->context = $context; + $this->tokenStorage = $tokenStorage; $this->userProviders = $userProviders; $this->contextKey = $contextKey; + $this->sessionKey = '_security_'.$contextKey; $this->logger = $logger; $this->dispatcher = $dispatcher; } /** - * Reads the SecurityContext from the session. + * Reads the Security Token from the session. * * @param GetResponseEvent $event A GetResponseEvent instance */ public function handle(GetResponseEvent $event) { - if (!$this->registered && null !== $this->dispatcher && HttpKernelInterface::MASTER_REQUEST === $event->getRequestType()) { + if (!$this->registered && null !== $this->dispatcher && $event->isMasterRequest()) { $this->dispatcher->addListener(KernelEvents::RESPONSE, array($this, 'onKernelResponse')); $this->registered = true; } @@ -74,8 +75,8 @@ class ContextListener implements ListenerInterface $request = $event->getRequest(); $session = $request->hasPreviousSession() ? $request->getSession() : null; - if (null === $session || null === $token = $session->get('_security_'.$this->contextKey)) { - $this->context->setToken(null); + if (null === $session || null === $token = $session->get($this->sessionKey)) { + $this->tokenStorage->setToken(null); return; } @@ -83,30 +84,30 @@ class ContextListener implements ListenerInterface $token = unserialize($token); if (null !== $this->logger) { - $this->logger->debug('Read SecurityContext from the session'); + $this->logger->debug('Read existing security token from the session.', array('key' => $this->sessionKey)); } if ($token instanceof TokenInterface) { $token = $this->refreshUser($token); } elseif (null !== $token) { if (null !== $this->logger) { - $this->logger->warning(sprintf('Session includes a "%s" where a security token is expected', is_object($token) ? get_class($token) : gettype($token))); + $this->logger->warning('Expected a security token from the session, got something else.', array('key' => $this->sessionKey, 'received' => $token)); } $token = null; } - $this->context->setToken($token); + $this->tokenStorage->setToken($token); } /** - * Writes the SecurityContext to the session. + * Writes the security token into the session. * * @param FilterResponseEvent $event A FilterResponseEvent instance */ public function onKernelResponse(FilterResponseEvent $event) { - if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) { + if (!$event->isMasterRequest()) { return; } @@ -117,23 +118,19 @@ class ContextListener implements ListenerInterface $this->dispatcher->removeListener(KernelEvents::RESPONSE, array($this, 'onKernelResponse')); $this->registered = false; - if (null !== $this->logger) { - $this->logger->debug('Write SecurityContext in the session'); - } - $request = $event->getRequest(); $session = $request->getSession(); - if (null === $session) { - return; - } - - if ((null === $token = $this->context->getToken()) || ($token instanceof AnonymousToken)) { + if ((null === $token = $this->tokenStorage->getToken()) || ($token instanceof AnonymousToken)) { if ($request->hasPreviousSession()) { - $session->remove('_security_'.$this->contextKey); + $session->remove($this->sessionKey); } } else { - $session->set('_security_'.$this->contextKey, serialize($token)); + $session->set($this->sessionKey, serialize($token)); + + if (null !== $this->logger) { + $this->logger->debug('Stored the security token in the session.', array('key' => $this->sessionKey)); + } } } @@ -146,24 +143,20 @@ class ContextListener implements ListenerInterface * * @throws \RuntimeException */ - private function refreshUser(TokenInterface $token) + protected function refreshUser(TokenInterface $token) { $user = $token->getUser(); if (!$user instanceof UserInterface) { return $token; } - if (null !== $this->logger) { - $this->logger->debug(sprintf('Reloading user from user provider.')); - } - foreach ($this->userProviders as $provider) { try { $refreshedUser = $provider->refreshUser($user); $token->setUser($refreshedUser); if (null !== $this->logger) { - $this->logger->debug(sprintf('Username "%s" was reloaded from user provider.', $refreshedUser->getUsername())); + $this->logger->debug('User was reloaded from a user provider.', array('username' => $refreshedUser->getUsername(), 'provider' => get_class($provider))); } return $token; @@ -171,7 +164,7 @@ class ContextListener implements ListenerInterface // let's try the next user provider } catch (UsernameNotFoundException $e) { if (null !== $this->logger) { - $this->logger->warning(sprintf('Username "%s" could not be found.', $e->getUsername())); + $this->logger->warning('Username could not be found in the selected user provider.', array('username' => $e->getUsername(), 'provider' => get_class($provider))); } return; diff --git a/Http/Firewall/DigestAuthenticationListener.php b/Http/Firewall/DigestAuthenticationListener.php index 4e57667..702cf33 100644 --- a/Http/Firewall/DigestAuthenticationListener.php +++ b/Http/Firewall/DigestAuthenticationListener.php @@ -11,13 +11,13 @@ namespace Symfony\Component\Security\Http\Firewall; -use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\Security\Core\Util\StringUtils; use Symfony\Component\Security\Http\EntryPoint\DigestAuthenticationEntryPoint; use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Exception\BadCredentialsException; use Symfony\Component\Security\Core\Exception\AuthenticationServiceException; use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; @@ -32,19 +32,19 @@ use Symfony\Component\Security\Core\Exception\AuthenticationException; */ class DigestAuthenticationListener implements ListenerInterface { - private $securityContext; + private $tokenStorage; private $provider; private $providerKey; private $authenticationEntryPoint; private $logger; - public function __construct(SecurityContextInterface $securityContext, UserProviderInterface $provider, $providerKey, DigestAuthenticationEntryPoint $authenticationEntryPoint, LoggerInterface $logger = null) + public function __construct(TokenStorageInterface $tokenStorage, UserProviderInterface $provider, $providerKey, DigestAuthenticationEntryPoint $authenticationEntryPoint, LoggerInterface $logger = null) { if (empty($providerKey)) { throw new \InvalidArgumentException('$providerKey must not be empty.'); } - $this->securityContext = $securityContext; + $this->tokenStorage = $tokenStorage; $this->provider = $provider; $this->providerKey = $providerKey; $this->authenticationEntryPoint = $authenticationEntryPoint; @@ -68,14 +68,14 @@ class DigestAuthenticationListener implements ListenerInterface $digestAuth = new DigestData($header); - if (null !== $token = $this->securityContext->getToken()) { + if (null !== $token = $this->tokenStorage->getToken()) { if ($token instanceof UsernamePasswordToken && $token->isAuthenticated() && $token->getUsername() === $digestAuth->getUsername()) { return; } } if (null !== $this->logger) { - $this->logger->debug(sprintf('Digest Authorization header received from user agent: %s', $header)); + $this->logger->debug('Digest Authorization header received from user agent.', array('header' => $header)); } try { @@ -90,7 +90,7 @@ class DigestAuthenticationListener implements ListenerInterface $user = $this->provider->loadUserByUsername($digestAuth->getUsername()); if (null === $user) { - throw new AuthenticationServiceException('AuthenticationDao returned null, which is an interface contract violation'); + throw new AuthenticationServiceException('Digest User provider returned null, which is an interface contract violation'); } $serverDigestMd5 = $digestAuth->calculateServerDigest($user->getPassword(), $request->getMethod()); @@ -102,7 +102,7 @@ class DigestAuthenticationListener implements ListenerInterface if (!StringUtils::equals($serverDigestMd5, $digestAuth->getResponse())) { if (null !== $this->logger) { - $this->logger->debug(sprintf('Expected response: "%s" but received: "%s"; is AuthenticationDao returning clear text passwords?', $serverDigestMd5, $digestAuth->getResponse())); + $this->logger->debug('Unexpected response from the DigestAuth received; is the header returning a clear text passwords?', array('expected' => $serverDigestMd5, 'received' => $digestAuth->getResponse())); } $this->fail($event, $request, new BadCredentialsException('Incorrect response')); @@ -117,21 +117,21 @@ class DigestAuthenticationListener implements ListenerInterface } if (null !== $this->logger) { - $this->logger->info(sprintf('Authentication success for user "%s" with response "%s"', $digestAuth->getUsername(), $digestAuth->getResponse())); + $this->logger->info('Digest authentication successful.', array('username' => $digestAuth->getUsername(), 'received' => $digestAuth->getResponse())); } - $this->securityContext->setToken(new UsernamePasswordToken($user, $user->getPassword(), $this->providerKey)); + $this->tokenStorage->setToken(new UsernamePasswordToken($user, $user->getPassword(), $this->providerKey)); } private function fail(GetResponseEvent $event, Request $request, AuthenticationException $authException) { - $token = $this->securityContext->getToken(); + $token = $this->tokenStorage->getToken(); if ($token instanceof UsernamePasswordToken && $this->providerKey === $token->getProviderKey()) { - $this->securityContext->setToken(null); + $this->tokenStorage->setToken(null); } if (null !== $this->logger) { - $this->logger->info($authException); + $this->logger->info('Digest authentication failed.', array('exception' => $authException)); } $event->setResponse($this->authenticationEntryPoint->start($request, $authException)); @@ -140,7 +140,7 @@ class DigestAuthenticationListener implements ListenerInterface class DigestData { - private $elements; + private $elements = array(); private $header; private $nonceExpiryTime; @@ -148,7 +148,6 @@ class DigestData { $this->header = $header; preg_match_all('/(\w+)=("((?:[^"\\\\]|\\\\.)+)"|([^\s,$]+))/', $header, $matches, PREG_SET_ORDER); - $this->elements = array(); foreach ($matches as $match) { if (isset($match[1]) && isset($match[3])) { $this->elements[$match[1]] = isset($match[4]) ? $match[4] : $match[3]; diff --git a/Http/Firewall/ExceptionListener.php b/Http/Firewall/ExceptionListener.php index 8553c75..a1cae2a 100644 --- a/Http/Firewall/ExceptionListener.php +++ b/Http/Firewall/ExceptionListener.php @@ -13,8 +13,9 @@ namespace Symfony\Component\Security\Http\Firewall; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Security\Http\Authorization\AccessDeniedHandlerInterface; -use Symfony\Component\Security\Core\SecurityContextInterface; +use Symfony\Component\Security\Core\Security; use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; use Symfony\Component\Security\Core\Exception\AccountStatusException; use Symfony\Component\Security\Core\Exception\AuthenticationException; @@ -38,7 +39,7 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface; */ class ExceptionListener { - private $context; + private $tokenStorage; private $providerKey; private $accessDeniedHandler; private $authenticationEntryPoint; @@ -48,9 +49,9 @@ class ExceptionListener private $httpUtils; private $stateless; - public function __construct(SecurityContextInterface $context, AuthenticationTrustResolverInterface $trustResolver, HttpUtils $httpUtils, $providerKey, AuthenticationEntryPointInterface $authenticationEntryPoint = null, $errorPage = null, AccessDeniedHandlerInterface $accessDeniedHandler = null, LoggerInterface $logger = null, $stateless = false) + public function __construct(TokenStorageInterface $tokenStorage, AuthenticationTrustResolverInterface $trustResolver, HttpUtils $httpUtils, $providerKey, AuthenticationEntryPointInterface $authenticationEntryPoint = null, $errorPage = null, AccessDeniedHandlerInterface $accessDeniedHandler = null, LoggerInterface $logger = null, $stateless = false) { - $this->context = $context; + $this->tokenStorage = $tokenStorage; $this->accessDeniedHandler = $accessDeniedHandler; $this->httpUtils = $httpUtils; $this->providerKey = $providerKey; @@ -72,16 +73,22 @@ class ExceptionListener } /** + * Unregisters the dispatcher. + * + * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance + */ + public function unregister(EventDispatcherInterface $dispatcher) + { + $dispatcher->removeListener(KernelEvents::EXCEPTION, array($this, 'onKernelException')); + } + + /** * Handles security related exceptions. * * @param GetResponseForExceptionEvent $event An GetResponseForExceptionEvent instance */ public function onKernelException(GetResponseForExceptionEvent $event) { - // we need to remove ourselves as the exception listener can be - // different depending on the Request - $event->getDispatcher()->removeListener(KernelEvents::EXCEPTION, array($this, 'onKernelException')); - $exception = $event->getException(); do { if ($exception instanceof AuthenticationException) { @@ -97,7 +104,7 @@ class ExceptionListener private function handleAuthenticationException(GetResponseForExceptionEvent $event, AuthenticationException $exception) { if (null !== $this->logger) { - $this->logger->info(sprintf('Authentication exception occurred; redirecting to authentication entry point (%s)', $exception->getMessage())); + $this->logger->info('An AuthenticationException was thrown; redirecting to authentication entry point.', array('exception' => $exception)); } try { @@ -111,10 +118,10 @@ class ExceptionListener { $event->setException(new AccessDeniedHttpException($exception->getMessage(), $exception)); - $token = $this->context->getToken(); + $token = $this->tokenStorage->getToken(); if (!$this->authenticationTrustResolver->isFullFledged($token)) { if (null !== $this->logger) { - $this->logger->debug(sprintf('Access is denied (user is not fully authenticated) by "%s" at line %s; redirecting to authentication entry point', $exception->getFile(), $exception->getLine())); + $this->logger->debug('Access denied, the user is not fully authenticated; redirecting to authentication entry point.', array('exception' => $exception)); } try { @@ -130,7 +137,7 @@ class ExceptionListener } if (null !== $this->logger) { - $this->logger->debug(sprintf('Access is denied (and user is neither anonymous, nor remember-me) by "%s" at line %s', $exception->getFile(), $exception->getLine())); + $this->logger->debug('Access denied, the user is neither anonymous, nor remember-me.', array('exception' => $exception)); } try { @@ -142,13 +149,13 @@ class ExceptionListener } } elseif (null !== $this->errorPage) { $subRequest = $this->httpUtils->createRequest($event->getRequest(), $this->errorPage); - $subRequest->attributes->set(SecurityContextInterface::ACCESS_DENIED_ERROR, $exception); + $subRequest->attributes->set(Security::ACCESS_DENIED_ERROR, $exception); $event->setResponse($event->getKernel()->handle($subRequest, HttpKernelInterface::SUB_REQUEST, true)); } } catch (\Exception $e) { if (null !== $this->logger) { - $this->logger->error(sprintf('Exception thrown when handling an exception (%s: %s)', get_class($e), $e->getMessage())); + $this->logger->error('An exception was thrown when handling an AccessDeniedException.', array('exception' => $e)); } $event->setException(new \RuntimeException('Exception thrown when handling an exception.', 0, $e)); @@ -158,7 +165,7 @@ class ExceptionListener private function handleLogoutException(LogoutException $exception) { if (null !== $this->logger) { - $this->logger->info(sprintf('Logout exception occurred; wrapping with AccessDeniedHttpException (%s)', $exception->getMessage())); + $this->logger->info('A LogoutException was thrown.', array('exception' => $exception)); } } @@ -177,7 +184,7 @@ class ExceptionListener } if (null !== $this->logger) { - $this->logger->debug('Calling Authentication entry point'); + $this->logger->debug('Calling Authentication entry point.'); } if (!$this->stateless) { @@ -186,7 +193,11 @@ class ExceptionListener if ($authException instanceof AccountStatusException) { // remove the security token to prevent infinite redirect loops - $this->context->setToken(null); + $this->tokenStorage->setToken(null); + + if (null !== $this->logger) { + $this->logger->info('The security token was removed due to an AccountStatusException.', array('exception' => $authException)); + } } return $this->authenticationEntryPoint->start($request, $authException); diff --git a/Http/Firewall/LogoutListener.php b/Http/Firewall/LogoutListener.php index 5a68670..96f5685 100644 --- a/Http/Firewall/LogoutListener.php +++ b/Http/Firewall/LogoutListener.php @@ -11,12 +11,16 @@ namespace Symfony\Component\Security\Http\Firewall; +use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderAdapter; use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\GetResponseEvent; -use Symfony\Component\Security\Core\SecurityContextInterface; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Security\Core\Exception\InvalidArgumentException; use Symfony\Component\Security\Core\Exception\LogoutException; +use Symfony\Component\Security\Csrf\CsrfToken; +use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; use Symfony\Component\Security\Http\HttpUtils; use Symfony\Component\Security\Http\Logout\LogoutHandlerInterface; use Symfony\Component\Security\Http\Logout\LogoutSuccessHandlerInterface; @@ -28,25 +32,31 @@ use Symfony\Component\Security\Http\Logout\LogoutSuccessHandlerInterface; */ class LogoutListener implements ListenerInterface { - private $securityContext; + private $tokenStorage; private $options; private $handlers; private $successHandler; private $httpUtils; - private $csrfProvider; + private $csrfTokenManager; /** * Constructor. * - * @param SecurityContextInterface $securityContext - * @param HttpUtils $httpUtils An HttpUtilsInterface instance - * @param LogoutSuccessHandlerInterface $successHandler A LogoutSuccessHandlerInterface instance - * @param array $options An array of options to process a logout attempt - * @param CsrfProviderInterface $csrfProvider A CsrfProviderInterface instance + * @param TokenStorageInterface $tokenStorage + * @param HttpUtils $httpUtils An HttpUtilsInterface instance + * @param LogoutSuccessHandlerInterface $successHandler A LogoutSuccessHandlerInterface instance + * @param array $options An array of options to process a logout attempt + * @param CsrfTokenManagerInterface $csrfTokenManager A CsrfTokenManagerInterface instance */ - public function __construct(SecurityContextInterface $securityContext, HttpUtils $httpUtils, LogoutSuccessHandlerInterface $successHandler, array $options = array(), CsrfProviderInterface $csrfProvider = null) + public function __construct(TokenStorageInterface $tokenStorage, HttpUtils $httpUtils, LogoutSuccessHandlerInterface $successHandler, array $options = array(), $csrfTokenManager = null) { - $this->securityContext = $securityContext; + if ($csrfTokenManager instanceof CsrfProviderInterface) { + $csrfTokenManager = new CsrfProviderAdapter($csrfTokenManager); + } elseif (null !== $csrfTokenManager && !$csrfTokenManager instanceof CsrfTokenManagerInterface) { + throw new InvalidArgumentException('The CSRF token manager should be an instance of CsrfProviderInterface or CsrfTokenManagerInterface.'); + } + + $this->tokenStorage = $tokenStorage; $this->httpUtils = $httpUtils; $this->options = array_merge(array( 'csrf_parameter' => '_csrf_token', @@ -54,7 +64,7 @@ class LogoutListener implements ListenerInterface 'logout_path' => '/logout', ), $options); $this->successHandler = $successHandler; - $this->csrfProvider = $csrfProvider; + $this->csrfTokenManager = $csrfTokenManager; $this->handlers = array(); } @@ -71,7 +81,7 @@ class LogoutListener implements ListenerInterface /** * Performs the logout if requested. * - * If a CsrfProviderInterface instance is available, it will be used to + * If a CsrfTokenManagerInterface instance is available, it will be used to * validate the request. * * @param GetResponseEvent $event A GetResponseEvent instance @@ -87,10 +97,10 @@ class LogoutListener implements ListenerInterface return; } - if (null !== $this->csrfProvider) { + if (null !== $this->csrfTokenManager) { $csrfToken = $request->get($this->options['csrf_parameter'], null, true); - if (false === $this->csrfProvider->isCsrfTokenValid($this->options['intention'], $csrfToken)) { + if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['intention'], $csrfToken))) { throw new LogoutException('Invalid CSRF token.'); } } @@ -101,13 +111,13 @@ class LogoutListener implements ListenerInterface } // handle multiple logout attempts gracefully - if ($token = $this->securityContext->getToken()) { + if ($token = $this->tokenStorage->getToken()) { foreach ($this->handlers as $handler) { $handler->logout($request, $response, $token); } } - $this->securityContext->setToken(null); + $this->tokenStorage->setToken(null); $event->setResponse($response); } diff --git a/Http/Firewall/RememberMeListener.php b/Http/Firewall/RememberMeListener.php index 52a231c..4186430 100644 --- a/Http/Firewall/RememberMeListener.php +++ b/Http/Firewall/RememberMeListener.php @@ -14,12 +14,13 @@ namespace Symfony\Component\Security\Http\Firewall; use Psr\Log\LoggerInterface; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; -use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface; use Symfony\Component\Security\Http\Event\InteractiveLoginEvent; use Symfony\Component\Security\Http\SecurityEvents; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface; use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategy; /** @@ -29,30 +30,34 @@ use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategy; */ class RememberMeListener implements ListenerInterface { - private $securityContext; + private $tokenStorage; private $rememberMeServices; private $authenticationManager; private $logger; private $dispatcher; + private $catchExceptions = true; private $sessionStrategy; /** * Constructor. * - * @param SecurityContextInterface $securityContext - * @param RememberMeServicesInterface $rememberMeServices - * @param AuthenticationManagerInterface $authenticationManager - * @param LoggerInterface $logger - * @param EventDispatcherInterface $dispatcher + * @param TokenStorageInterface $tokenStorage + * @param RememberMeServicesInterface $rememberMeServices + * @param AuthenticationManagerInterface $authenticationManager + * @param LoggerInterface $logger + * @param EventDispatcherInterface $dispatcher + * @param bool $catchExceptions + * @param SessionAuthenticationStrategyInterface $sessionStrategy */ - public function __construct(SecurityContextInterface $securityContext, RememberMeServicesInterface $rememberMeServices, AuthenticationManagerInterface $authenticationManager, LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null) + public function __construct(TokenStorageInterface $tokenStorage, RememberMeServicesInterface $rememberMeServices, AuthenticationManagerInterface $authenticationManager, LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, $catchExceptions = true, SessionAuthenticationStrategyInterface $sessionStrategy = null) { - $this->securityContext = $securityContext; + $this->tokenStorage = $tokenStorage; $this->rememberMeServices = $rememberMeServices; $this->authenticationManager = $authenticationManager; $this->logger = $logger; $this->dispatcher = $dispatcher; - $this->sessionStrategy = new SessionAuthenticationStrategy(SessionAuthenticationStrategy::MIGRATE); + $this->catchExceptions = $catchExceptions; + $this->sessionStrategy = null === $sessionStrategy ? new SessionAuthenticationStrategy(SessionAuthenticationStrategy::MIGRATE) : $sessionStrategy; } /** @@ -62,7 +67,7 @@ class RememberMeListener implements ListenerInterface */ public function handle(GetResponseEvent $event) { - if (null !== $this->securityContext->getToken()) { + if (null !== $this->tokenStorage->getToken()) { return; } @@ -73,12 +78,10 @@ class RememberMeListener implements ListenerInterface try { $token = $this->authenticationManager->authenticate($token); - if ($request->hasSession() && $request->getSession()->isStarted()) { $this->sessionStrategy->onAuthentication($request, $token); } - - $this->securityContext->setToken($token); + $this->tokenStorage->setToken($token); if (null !== $this->dispatcher) { $loginEvent = new InteractiveLoginEvent($request, $token); @@ -86,18 +89,22 @@ class RememberMeListener implements ListenerInterface } if (null !== $this->logger) { - $this->logger->debug('SecurityContext populated with remember-me token.'); + $this->logger->debug('Populated the token storage with a remember-me token.'); } } catch (AuthenticationException $e) { if (null !== $this->logger) { $this->logger->warning( - 'SecurityContext not populated with remember-me token as the' + 'The token storage was not populated with remember-me token as the' .' AuthenticationManager rejected the AuthenticationToken returned' - .' by the RememberMeServices: '.$e->getMessage() + .' by the RememberMeServices.', array('exception' => $e) ); } $this->rememberMeServices->loginFail($request); + + if (!$this->catchExceptions) { + throw $e; + } } } } diff --git a/Http/Firewall/RemoteUserAuthenticationListener.php b/Http/Firewall/RemoteUserAuthenticationListener.php new file mode 100644 index 0000000..c42badf --- /dev/null +++ b/Http/Firewall/RemoteUserAuthenticationListener.php @@ -0,0 +1,49 @@ +<?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\Firewall; + +use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Security\Core\Exception\BadCredentialsException; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; + +/** + * REMOTE_USER authentication listener. + * + * @author Fabien Potencier <fabien@symfony.com> + * @author Maxime Douailin <maxime.douailin@gmail.com> + */ +class RemoteUserAuthenticationListener extends AbstractPreAuthenticatedListener +{ + private $userKey; + + public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, $providerKey, $userKey = 'REMOTE_USER', LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null) + { + parent::__construct($tokenStorage, $authenticationManager, $providerKey, $logger, $dispatcher); + + $this->userKey = $userKey; + } + + /** + * {@inheritdoc} + */ + protected function getPreAuthenticatedData(Request $request) + { + if (!$request->server->has($this->userKey)) { + throw new BadCredentialsException(sprintf('User key was not found: %s', $this->userKey)); + } + + return array($request->server->get($this->userKey), null); + } +} diff --git a/Http/Firewall/SimpleFormAuthenticationListener.php b/Http/Firewall/SimpleFormAuthenticationListener.php new file mode 100644 index 0000000..8123e0e --- /dev/null +++ b/Http/Firewall/SimpleFormAuthenticationListener.php @@ -0,0 +1,130 @@ +<?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\Firewall; + +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderAdapter; +use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Security\Core\Exception\InvalidArgumentException; +use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException; +use Symfony\Component\Security\Csrf\CsrfToken; +use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; +use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface; +use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface; +use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; +use Symfony\Component\Security\Core\Authentication\SimpleFormAuthenticatorInterface; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Security\Core\Exception\BadCredentialsException; +use Symfony\Component\Security\Core\Security; +use Symfony\Component\Security\Http\HttpUtils; +use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface; +use Psr\Log\LoggerInterface; + +/** + * @author Jordi Boggiano <j.boggiano@seld.be> + */ +class SimpleFormAuthenticationListener extends AbstractAuthenticationListener +{ + private $simpleAuthenticator; + private $csrfTokenManager; + + /** + * Constructor. + * + * @param TokenStorageInterface $tokenStorage A TokenStorageInterface instance + * @param AuthenticationManagerInterface $authenticationManager An AuthenticationManagerInterface instance + * @param SessionAuthenticationStrategyInterface $sessionStrategy + * @param HttpUtils $httpUtils An HttpUtilsInterface instance + * @param string $providerKey + * @param AuthenticationSuccessHandlerInterface $successHandler + * @param AuthenticationFailureHandlerInterface $failureHandler + * @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 CsrfTokenManagerInterface $csrfTokenManager A CsrfTokenManagerInterface instance + * @param SimpleFormAuthenticatorInterface $simpleAuthenticator A SimpleFormAuthenticatorInterface instance + * + * @throws \InvalidArgumentException In case no simple authenticator is provided + * @throws InvalidArgumentException In case an invalid CSRF token manager is passed + */ + public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, $csrfTokenManager = null, SimpleFormAuthenticatorInterface $simpleAuthenticator = null) + { + if (!$simpleAuthenticator) { + throw new \InvalidArgumentException('Missing simple authenticator'); + } + + if ($csrfTokenManager instanceof CsrfProviderInterface) { + $csrfTokenManager = new CsrfProviderAdapter($csrfTokenManager); + } elseif (null !== $csrfTokenManager && !$csrfTokenManager instanceof CsrfTokenManagerInterface) { + throw new InvalidArgumentException('The CSRF token manager should be an instance of CsrfProviderInterface or CsrfTokenManagerInterface.'); + } + + $this->simpleAuthenticator = $simpleAuthenticator; + $this->csrfTokenManager = $csrfTokenManager; + + $options = array_merge(array( + 'username_parameter' => '_username', + 'password_parameter' => '_password', + 'csrf_parameter' => '_csrf_token', + 'intention' => 'authenticate', + 'post_only' => true, + ), $options); + + parent::__construct($tokenStorage, $authenticationManager, $sessionStrategy, $httpUtils, $providerKey, $successHandler, $failureHandler, $options, $logger, $dispatcher); + } + + /** + * {@inheritdoc} + */ + protected function requiresAuthentication(Request $request) + { + if ($this->options['post_only'] && !$request->isMethod('POST')) { + return false; + } + + return parent::requiresAuthentication($request); + } + + /** + * {@inheritdoc} + */ + protected function attemptAuthentication(Request $request) + { + if (null !== $this->csrfTokenManager) { + $csrfToken = $request->get($this->options['csrf_parameter'], null, true); + + if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['intention'], $csrfToken))) { + throw new InvalidCsrfTokenException('Invalid CSRF token.'); + } + } + + if ($this->options['post_only']) { + $username = trim($request->request->get($this->options['username_parameter'], null, true)); + $password = $request->request->get($this->options['password_parameter'], null, true); + } else { + $username = trim($request->get($this->options['username_parameter'], null, true)); + $password = $request->get($this->options['password_parameter'], null, true); + } + + if (strlen($username) > Security::MAX_USERNAME_LENGTH) { + throw new BadCredentialsException('Invalid username.'); + } + + $request->getSession()->set(Security::LAST_USERNAME, $username); + + $token = $this->simpleAuthenticator->createToken($request, $username, $password, $this->providerKey); + + return $this->authenticationManager->authenticate($token); + } +} diff --git a/Http/Firewall/SimplePreAuthenticationListener.php b/Http/Firewall/SimplePreAuthenticationListener.php new file mode 100644 index 0000000..8f1f6fd --- /dev/null +++ b/Http/Firewall/SimplePreAuthenticationListener.php @@ -0,0 +1,126 @@ +<?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\Firewall; + +use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; +use Psr\Log\LoggerInterface; +use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Security\Core\Authentication\SimplePreAuthenticatorInterface; +use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Security\Core\Exception\AuthenticationException; +use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface; +use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface; +use Symfony\Component\Security\Http\Event\InteractiveLoginEvent; +use Symfony\Component\Security\Http\SecurityEvents; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; + +/** + * SimplePreAuthenticationListener implements simple proxying to an authenticator. + * + * @author Jordi Boggiano <j.boggiano@seld.be> + */ +class SimplePreAuthenticationListener implements ListenerInterface +{ + private $tokenStorage; + private $authenticationManager; + private $providerKey; + private $simpleAuthenticator; + private $logger; + private $dispatcher; + + /** + * Constructor. + * + * @param TokenStorageInterface $tokenStorage A TokenStorageInterface instance + * @param AuthenticationManagerInterface $authenticationManager An AuthenticationManagerInterface instance + * @param string $providerKey + * @param SimplePreAuthenticatorInterface $simpleAuthenticator A SimplePreAuthenticatorInterface instance + * @param LoggerInterface $logger A LoggerInterface instance + * @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance + */ + public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, $providerKey, SimplePreAuthenticatorInterface $simpleAuthenticator, LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null) + { + if (empty($providerKey)) { + throw new \InvalidArgumentException('$providerKey must not be empty.'); + } + + $this->tokenStorage = $tokenStorage; + $this->authenticationManager = $authenticationManager; + $this->providerKey = $providerKey; + $this->simpleAuthenticator = $simpleAuthenticator; + $this->logger = $logger; + $this->dispatcher = $dispatcher; + } + + /** + * Handles basic authentication. + * + * @param GetResponseEvent $event A GetResponseEvent instance + */ + public function handle(GetResponseEvent $event) + { + $request = $event->getRequest(); + + if (null !== $this->logger) { + $this->logger->info('Attempting SimplePreAuthentication.', array('key' => $this->providerKey, 'authenticator' => get_class($this->simpleAuthenticator))); + } + + if (null !== $this->tokenStorage->getToken() && !$this->tokenStorage->getToken() instanceof AnonymousToken) { + return; + } + + try { + $token = $this->simpleAuthenticator->createToken($request, $this->providerKey); + + // allow null to be returned to skip authentication + if (null === $token) { + return; + } + + $token = $this->authenticationManager->authenticate($token); + $this->tokenStorage->setToken($token); + + if (null !== $this->dispatcher) { + $loginEvent = new InteractiveLoginEvent($request, $token); + $this->dispatcher->dispatch(SecurityEvents::INTERACTIVE_LOGIN, $loginEvent); + } + } catch (AuthenticationException $e) { + $this->tokenStorage->setToken(null); + + if (null !== $this->logger) { + $this->logger->info('SimplePreAuthentication request failed.', array('exception' => $e, 'authenticator' => get_class($this->simpleAuthenticator))); + } + + if ($this->simpleAuthenticator instanceof AuthenticationFailureHandlerInterface) { + $response = $this->simpleAuthenticator->onAuthenticationFailure($request, $e); + if ($response instanceof Response) { + $event->setResponse($response); + } elseif (null !== $response) { + throw new \UnexpectedValueException(sprintf('The %s::onAuthenticationFailure method must return null or a Response object', get_class($this->simpleAuthenticator))); + } + } + + return; + } + + if ($this->simpleAuthenticator instanceof AuthenticationSuccessHandlerInterface) { + $response = $this->simpleAuthenticator->onAuthenticationSuccess($request, $token); + if ($response instanceof Response) { + $event->setResponse($response); + } elseif (null !== $response) { + throw new \UnexpectedValueException(sprintf('The %s::onAuthenticationSuccess method must return null or a Response object', get_class($this->simpleAuthenticator))); + } + } + } +} diff --git a/Http/Firewall/SwitchUserListener.php b/Http/Firewall/SwitchUserListener.php index b983b68..7de83d2 100644 --- a/Http/Firewall/SwitchUserListener.php +++ b/Http/Firewall/SwitchUserListener.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Security\Http\Firewall; use Symfony\Component\Security\Core\Exception\AccessDeniedException; -use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\Security\Core\User\UserCheckerInterface; @@ -24,6 +23,7 @@ use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Security\Core\Role\SwitchUserRole; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Http\Event\SwitchUserEvent; @@ -38,7 +38,7 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface; */ class SwitchUserListener implements ListenerInterface { - private $securityContext; + private $tokenStorage; private $provider; private $userChecker; private $providerKey; @@ -48,16 +48,13 @@ class SwitchUserListener implements ListenerInterface private $logger; private $dispatcher; - /** - * Constructor. - */ - public function __construct(SecurityContextInterface $securityContext, UserProviderInterface $provider, UserCheckerInterface $userChecker, $providerKey, AccessDecisionManagerInterface $accessDecisionManager, LoggerInterface $logger = null, $usernameParameter = '_switch_user', $role = 'ROLE_ALLOWED_TO_SWITCH', EventDispatcherInterface $dispatcher = null) + public function __construct(TokenStorageInterface $tokenStorage, UserProviderInterface $provider, UserCheckerInterface $userChecker, $providerKey, AccessDecisionManagerInterface $accessDecisionManager, LoggerInterface $logger = null, $usernameParameter = '_switch_user', $role = 'ROLE_ALLOWED_TO_SWITCH', EventDispatcherInterface $dispatcher = null) { if (empty($providerKey)) { throw new \InvalidArgumentException('$providerKey must not be empty.'); } - $this->securityContext = $securityContext; + $this->tokenStorage = $tokenStorage; $this->provider = $provider; $this->userChecker = $userChecker; $this->providerKey = $providerKey; @@ -84,16 +81,18 @@ class SwitchUserListener implements ListenerInterface } if ('_exit' === $request->get($this->usernameParameter)) { - $this->securityContext->setToken($this->attemptExitUser($request)); + $this->tokenStorage->setToken($this->attemptExitUser($request)); } else { try { - $this->securityContext->setToken($this->attemptSwitchUser($request)); + $this->tokenStorage->setToken($this->attemptSwitchUser($request)); } catch (AuthenticationException $e) { throw new \LogicException(sprintf('Switch User failed: "%s"', $e->getMessage())); } } - $request->server->set('QUERY_STRING', ''); + $request->query->remove($this->usernameParameter); + $request->server->set('QUERY_STRING', http_build_query($request->query->all())); + $response = new RedirectResponse($request->getUri(), 302); $event->setResponse($response); @@ -111,7 +110,7 @@ class SwitchUserListener implements ListenerInterface */ private function attemptSwitchUser(Request $request) { - $token = $this->securityContext->getToken(); + $token = $this->tokenStorage->getToken(); $originalToken = $this->getOriginalToken($token); if (false !== $originalToken) { @@ -129,14 +128,14 @@ class SwitchUserListener implements ListenerInterface $username = $request->get($this->usernameParameter); if (null !== $this->logger) { - $this->logger->info(sprintf('Attempt to switch to user "%s"', $username)); + $this->logger->info('Attempting to switch to user.', array('username' => $username)); } $user = $this->provider->loadUserByUsername($username); $this->userChecker->checkPostAuth($user); $roles = $user->getRoles(); - $roles[] = new SwitchUserRole('ROLE_PREVIOUS_ADMIN', $this->securityContext->getToken()); + $roles[] = new SwitchUserRole('ROLE_PREVIOUS_ADMIN', $this->tokenStorage->getToken()); $token = new UsernamePasswordToken($user, $user->getPassword(), $this->providerKey, $roles); @@ -159,7 +158,7 @@ class SwitchUserListener implements ListenerInterface */ private function attemptExitUser(Request $request) { - if (false === $original = $this->getOriginalToken($this->securityContext->getToken())) { + if (false === $original = $this->getOriginalToken($this->tokenStorage->getToken())) { throw new AuthenticationCredentialsNotFoundException('Could not find original Token object.'); } diff --git a/Http/Firewall/UsernamePasswordFormAuthenticationListener.php b/Http/Firewall/UsernamePasswordFormAuthenticationListener.php index 26aeb67..ba4329b 100644 --- a/Http/Firewall/UsernamePasswordFormAuthenticationListener.php +++ b/Http/Firewall/UsernamePasswordFormAuthenticationListener.php @@ -11,18 +11,23 @@ namespace Symfony\Component\Security\Http\Firewall; +use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderAdapter; use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface; use Symfony\Component\HttpFoundation\Request; use Psr\Log\LoggerInterface; +use Symfony\Component\Security\Csrf\CsrfToken; +use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; 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\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\Exception\BadCredentialsException; +use Symfony\Component\Security\Core\Exception\InvalidArgumentException; use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException; -use Symfony\Component\Security\Core\SecurityContextInterface; +use Symfony\Component\Security\Core\Security; use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** @@ -33,14 +38,17 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface; */ class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationListener { - private $csrfProvider; + private $csrfTokenManager; - /** - * {@inheritdoc} - */ - public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfProviderInterface $csrfProvider = null) + public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, $csrfTokenManager = null) { - parent::__construct($securityContext, $authenticationManager, $sessionStrategy, $httpUtils, $providerKey, $successHandler, $failureHandler, array_merge(array( + if ($csrfTokenManager instanceof CsrfProviderInterface) { + $csrfTokenManager = new CsrfProviderAdapter($csrfTokenManager); + } elseif (null !== $csrfTokenManager && !$csrfTokenManager instanceof CsrfTokenManagerInterface) { + throw new InvalidArgumentException('The CSRF token manager should be an instance of CsrfProviderInterface or CsrfTokenManagerInterface.'); + } + + parent::__construct($tokenStorage, $authenticationManager, $sessionStrategy, $httpUtils, $providerKey, $successHandler, $failureHandler, array_merge(array( 'username_parameter' => '_username', 'password_parameter' => '_password', 'csrf_parameter' => '_csrf_token', @@ -48,7 +56,7 @@ class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationL 'post_only' => true, ), $options), $logger, $dispatcher); - $this->csrfProvider = $csrfProvider; + $this->csrfTokenManager = $csrfTokenManager; } /** @@ -68,10 +76,10 @@ class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationL */ protected function attemptAuthentication(Request $request) { - if (null !== $this->csrfProvider) { + if (null !== $this->csrfTokenManager) { $csrfToken = $request->get($this->options['csrf_parameter'], null, true); - if (false === $this->csrfProvider->isCsrfTokenValid($this->options['intention'], $csrfToken)) { + if (false === $this->csrfTokenManager->isTokenValid(new CsrfToken($this->options['intention'], $csrfToken))) { throw new InvalidCsrfTokenException('Invalid CSRF token.'); } } @@ -84,11 +92,11 @@ class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationL $password = $request->get($this->options['password_parameter'], null, true); } - if (strlen($username) > SecurityContextInterface::MAX_USERNAME_LENGTH) { + if (strlen($username) > Security::MAX_USERNAME_LENGTH) { throw new BadCredentialsException('Invalid username.'); } - $request->getSession()->set(SecurityContextInterface::LAST_USERNAME, $username); + $request->getSession()->set(Security::LAST_USERNAME, $username); return $this->authenticationManager->authenticate(new UsernamePasswordToken($username, $password, $this->providerKey)); } diff --git a/Http/Firewall/X509AuthenticationListener.php b/Http/Firewall/X509AuthenticationListener.php index 9c07be1..326c9af 100644 --- a/Http/Firewall/X509AuthenticationListener.php +++ b/Http/Firewall/X509AuthenticationListener.php @@ -11,8 +11,8 @@ namespace Symfony\Component\Security\Http\Firewall; -use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Psr\Log\LoggerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Security\Core\Exception\BadCredentialsException; @@ -28,9 +28,9 @@ class X509AuthenticationListener extends AbstractPreAuthenticatedListener private $userKey; private $credentialKey; - public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, $providerKey, $userKey = 'SSL_CLIENT_S_DN_Email', $credentialKey = 'SSL_CLIENT_S_DN', LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null) + public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, $providerKey, $userKey = 'SSL_CLIENT_S_DN_Email', $credentialKey = 'SSL_CLIENT_S_DN', LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null) { - parent::__construct($securityContext, $authenticationManager, $providerKey, $logger, $dispatcher); + parent::__construct($tokenStorage, $authenticationManager, $providerKey, $logger, $dispatcher); $this->userKey = $userKey; $this->credentialKey = $credentialKey; diff --git a/Http/HttpUtils.php b/Http/HttpUtils.php index 0f47809..ed737a2 100644 --- a/Http/HttpUtils.php +++ b/Http/HttpUtils.php @@ -11,7 +11,6 @@ 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\Matcher\UrlMatcherInterface; @@ -19,6 +18,7 @@ use Symfony\Component\Routing\Matcher\RequestMatcherInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Routing\Exception\MethodNotAllowedException; use Symfony\Component\Routing\Exception\ResourceNotFoundException; +use Symfony\Component\Security\Core\Security; /** * Encapsulates the logic needed to create sub-requests, redirect the user, and match URLs. @@ -71,19 +71,19 @@ class HttpUtils */ public function createRequest(Request $request, $path) { - $newRequest = $request::create($this->generateUri($request, $path), 'get', array(), $request->cookies->all(), array(), $request->server->all()); + $newRequest = Request::create($this->generateUri($request, $path), 'get', array(), $request->cookies->all(), array(), $request->server->all()); if ($request->hasSession()) { $newRequest->setSession($request->getSession()); } - if ($request->attributes->has(SecurityContextInterface::AUTHENTICATION_ERROR)) { - $newRequest->attributes->set(SecurityContextInterface::AUTHENTICATION_ERROR, $request->attributes->get(SecurityContextInterface::AUTHENTICATION_ERROR)); + if ($request->attributes->has(Security::AUTHENTICATION_ERROR)) { + $newRequest->attributes->set(Security::AUTHENTICATION_ERROR, $request->attributes->get(Security::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(Security::ACCESS_DENIED_ERROR)) { + $newRequest->attributes->set(Security::ACCESS_DENIED_ERROR, $request->attributes->get(Security::ACCESS_DENIED_ERROR)); } - if ($request->attributes->has(SecurityContextInterface::LAST_USERNAME)) { - $newRequest->attributes->set(SecurityContextInterface::LAST_USERNAME, $request->attributes->get(SecurityContextInterface::LAST_USERNAME)); + if ($request->attributes->has(Security::LAST_USERNAME)) { + $newRequest->attributes->set(Security::LAST_USERNAME, $request->attributes->get(Security::LAST_USERNAME)); } return $newRequest; diff --git a/Http/LICENSE b/Http/LICENSE new file mode 100644 index 0000000..12a7453 --- /dev/null +++ b/Http/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2004-2016 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Http/Logout/LogoutUrlGenerator.php b/Http/Logout/LogoutUrlGenerator.php new file mode 100644 index 0000000..4ad63cc --- /dev/null +++ b/Http/Logout/LogoutUrlGenerator.php @@ -0,0 +1,139 @@ +<?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\Logout; + +use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderAdapter; +use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; + +/** + * Provides generator functions for the logout URL. + * + * @author Fabien Potencier <fabien@symfony.com> + * @author Jeremy Mikola <jmikola@gmail.com> + */ +class LogoutUrlGenerator +{ + private $requestStack; + private $router; + private $tokenStorage; + private $listeners = array(); + + public function __construct(RequestStack $requestStack = null, UrlGeneratorInterface $router = null, TokenStorageInterface $tokenStorage = null) + { + $this->requestStack = $requestStack; + $this->router = $router; + $this->tokenStorage = $tokenStorage; + } + + /** + * Registers a firewall's LogoutListener, allowing its URL to be generated. + * + * @param string $key The firewall key + * @param string $logoutPath The path that starts the logout process + * @param string $csrfTokenId The ID of the CSRF token + * @param string $csrfParameter The CSRF token parameter name + * @param CsrfTokenManagerInterface $csrfTokenManager A CsrfTokenManagerInterface instance + */ + public function registerListener($key, $logoutPath, $csrfTokenId, $csrfParameter, $csrfTokenManager = null) + { + if ($csrfTokenManager instanceof CsrfProviderInterface) { + $csrfTokenManager = new CsrfProviderAdapter($csrfTokenManager); + } elseif (null !== $csrfTokenManager && !$csrfTokenManager instanceof CsrfTokenManagerInterface) { + throw new \InvalidArgumentException('The CSRF token manager should be an instance of CsrfProviderInterface or CsrfTokenManagerInterface.'); + } + + $this->listeners[$key] = array($logoutPath, $csrfTokenId, $csrfParameter, $csrfTokenManager); + } + + /** + * Generates the absolute logout path for the firewall. + * + * @param string|null $key The firewall key or null to use the current firewall key + * + * @return string The logout path + */ + public function getLogoutPath($key = null) + { + return $this->generateLogoutUrl($key, UrlGeneratorInterface::ABSOLUTE_PATH); + } + + /** + * Generates the absolute logout URL for the firewall. + * + * @param string|null $key The firewall key or null to use the current firewall key + * + * @return string The logout URL + */ + public function getLogoutUrl($key = null) + { + return $this->generateLogoutUrl($key, UrlGeneratorInterface::ABSOLUTE_URL); + } + + /** + * Generates the logout URL for the firewall. + * + * @param string|null $key The firewall key or null to use the current firewall key + * @param bool|string $referenceType The type of reference (one of the constants in UrlGeneratorInterface) + * + * @return string The logout URL + * + * @throws \InvalidArgumentException if no LogoutListener is registered for the key or the key could not be found automatically. + */ + private function generateLogoutUrl($key, $referenceType) + { + // Fetch the current provider key from token, if possible + if (null === $key && null !== $this->tokenStorage) { + $token = $this->tokenStorage->getToken(); + if (null !== $token && method_exists($token, 'getProviderKey')) { + $key = $token->getProviderKey(); + } + } + + if (null === $key) { + throw new \InvalidArgumentException('Unable to find the current firewall LogoutListener, please provide the provider key manually.'); + } + + if (!array_key_exists($key, $this->listeners)) { + throw new \InvalidArgumentException(sprintf('No LogoutListener found for firewall key "%s".', $key)); + } + + list($logoutPath, $csrfTokenId, $csrfParameter, $csrfTokenManager) = $this->listeners[$key]; + + $parameters = null !== $csrfTokenManager ? array($csrfParameter => (string) $csrfTokenManager->getToken($csrfTokenId)) : array(); + + if ('/' === $logoutPath[0]) { + if (!$this->requestStack) { + throw new \LogicException('Unable to generate the logout URL without a RequestStack.'); + } + + $request = $this->requestStack->getCurrentRequest(); + + $url = UrlGeneratorInterface::ABSOLUTE_URL === $referenceType ? $request->getUriForPath($logoutPath) : $request->getBaseUrl().$logoutPath; + + if (!empty($parameters)) { + $url .= '?'.http_build_query($parameters); + } + } else { + if (!$this->router) { + throw new \LogicException('Unable to generate the logout URL without a Router.'); + } + + $url = $this->router->generate($logoutPath, $parameters, $referenceType); + } + + return $url; + } +} diff --git a/Http/README.md b/Http/README.md new file mode 100644 index 0000000..5be2111 --- /dev/null +++ b/Http/README.md @@ -0,0 +1,16 @@ +Security Component - HTTP Integration +===================================== + +Security provides an infrastructure for sophisticated authorization systems, +which makes it possible to easily separate the actual authorization logic from +so called user providers that hold the users credentials. It is inspired by +the Java Spring framework. + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/components/security/index.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/Http/RememberMe/AbstractRememberMeServices.php b/Http/RememberMe/AbstractRememberMeServices.php index be22a1d..cd8640d 100644 --- a/Http/RememberMe/AbstractRememberMeServices.php +++ b/Http/RememberMe/AbstractRememberMeServices.php @@ -140,7 +140,7 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface } } catch (AuthenticationException $e) { if (null !== $this->logger) { - $this->logger->debug('Remember-Me authentication failed: '.$e->getMessage()); + $this->logger->debug('Remember-Me authentication failed.', array('exception' => $e)); } } @@ -293,7 +293,7 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface protected function cancelCookie(Request $request) { if (null !== $this->logger) { - $this->logger->debug(sprintf('Clearing remember-me cookie "%s"', $this->options['name'])); + $this->logger->debug('Clearing remember-me cookie.', array('name' => $this->options['name'])); } $request->attributes->set(self::COOKIE_ATTR_NAME, new Cookie($this->options['name'], null, 1, $this->options['path'], $this->options['domain'], $this->options['secure'], $this->options['httponly'])); @@ -315,7 +315,7 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface $parameter = $request->get($this->options['remember_me_parameter'], null, true); if (null === $parameter && 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'])); + $this->logger->debug('Did not send remember-me cookie.', array('parameter' => $this->options['remember_me_parameter'])); } return $parameter === 'true' || $parameter === 'on' || $parameter === '1' || $parameter === 'yes'; diff --git a/Http/RememberMe/PersistentTokenBasedRememberMeServices.php b/Http/RememberMe/PersistentTokenBasedRememberMeServices.php index 0fffbfe..cbbbb23 100644 --- a/Http/RememberMe/PersistentTokenBasedRememberMeServices.php +++ b/Http/RememberMe/PersistentTokenBasedRememberMeServices.php @@ -45,7 +45,7 @@ class PersistentTokenBasedRememberMeServices extends AbstractRememberMeServices * @param LoggerInterface $logger * @param SecureRandomInterface $secureRandom */ - public function __construct(array $userProviders, $key, $providerKey, array $options = array(), LoggerInterface $logger = null, SecureRandomInterface $secureRandom) + public function __construct(array $userProviders, $key, $providerKey, array $options, LoggerInterface $logger = null, SecureRandomInterface $secureRandom) { parent::__construct($userProviders, $key, $providerKey, $options, $logger); @@ -99,7 +99,6 @@ class PersistentTokenBasedRememberMeServices extends AbstractRememberMeServices throw new AuthenticationException('The cookie has expired.'); } - $series = $persistentToken->getSeries(); $tokenValue = base64_encode($this->secureRandom->nextBytes(64)); $this->tokenProvider->updateToken($series, $tokenValue, new \DateTime()); $request->attributes->set(self::COOKIE_ATTR_NAME, diff --git a/Http/RememberMe/RememberMeServicesInterface.php b/Http/RememberMe/RememberMeServicesInterface.php index 7adb827..5750a8c 100644 --- a/Http/RememberMe/RememberMeServicesInterface.php +++ b/Http/RememberMe/RememberMeServicesInterface.php @@ -36,8 +36,8 @@ interface RememberMeServicesInterface const COOKIE_ATTR_NAME = '_security_remember_me_cookie'; /** - * This method will be called whenever the SecurityContext does not contain - * an TokenInterface object and the framework wishes to provide an implementation + * This method will be called whenever the TokenStorage does not contain + * a TokenInterface object and the framework wishes to provide an implementation * with an opportunity to authenticate the request using remember-me capabilities. * * No attempt whatsoever is made to determine whether the browser has requested diff --git a/Http/RememberMe/ResponseListener.php b/Http/RememberMe/ResponseListener.php index ec5f006..4149fb6 100644 --- a/Http/RememberMe/ResponseListener.php +++ b/Http/RememberMe/ResponseListener.php @@ -13,7 +13,6 @@ namespace Symfony\Component\Security\Http\RememberMe; use Symfony\Component\HttpKernel\Event\FilterResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; -use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; /** @@ -28,7 +27,7 @@ class ResponseListener implements EventSubscriberInterface */ public function onKernelResponse(FilterResponseEvent $event) { - if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) { + if (!$event->isMasterRequest()) { return; } diff --git a/Http/RememberMe/TokenBasedRememberMeServices.php b/Http/RememberMe/TokenBasedRememberMeServices.php index 1aea5fd..d68ada5 100644 --- a/Http/RememberMe/TokenBasedRememberMeServices.php +++ b/Http/RememberMe/TokenBasedRememberMeServices.php @@ -54,7 +54,7 @@ class TokenBasedRememberMeServices extends AbstractRememberMeServices throw new \RuntimeException(sprintf('The UserProviderInterface implementation must return an instance of UserInterface, but returned "%s".', get_class($user))); } - if (!StringUtils::equals($this->generateCookieHash($class, $username, $expires, $user->getPassword()), $hash)) { + if (true !== StringUtils::equals($this->generateCookieHash($class, $username, $expires, $user->getPassword()), $hash)) { throw new AuthenticationException('The cookie\'s hash is invalid.'); } @@ -121,6 +121,6 @@ class TokenBasedRememberMeServices extends AbstractRememberMeServices */ protected function generateCookieHash($class, $username, $expires, $password) { - return hash('sha256', $class.$username.$expires.$password.$this->getKey()); + return hash_hmac('sha256', $class.$username.$expires.$password, $this->getKey()); } } diff --git a/Http/Session/SessionAuthenticationStrategyInterface.php b/Http/Session/SessionAuthenticationStrategyInterface.php index 9cb95d8..dd0c381 100644 --- a/Http/Session/SessionAuthenticationStrategyInterface.php +++ b/Http/Session/SessionAuthenticationStrategyInterface.php @@ -27,7 +27,7 @@ interface SessionAuthenticationStrategyInterface /** * This performs any necessary changes to the session. * - * This method is called before the SecurityContext is populated with a + * This method is called before the TokenStorage is populated with a * Token, and only by classes inheriting from AbstractAuthenticationListener. * * @param Request $request diff --git a/Tests/Http/AccessMapTest.php b/Http/Tests/AccessMapTest.php index c2d9b7f..d8ab7aa 100644 --- a/Tests/Http/AccessMapTest.php +++ b/Http/Tests/AccessMapTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Http; +namespace Symfony\Component\Security\Http\Tests; use Symfony\Component\Security\Http\AccessMap; diff --git a/Tests/Http/Authentication/DefaultAuthenticationFailureHandlerTest.php b/Http/Tests/Authentication/DefaultAuthenticationFailureHandlerTest.php index 38072d6..82b5533 100644 --- a/Tests/Http/Authentication/DefaultAuthenticationFailureHandlerTest.php +++ b/Http/Tests/Authentication/DefaultAuthenticationFailureHandlerTest.php @@ -9,10 +9,10 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Http\Authentication; +namespace Symfony\Component\Security\Http\Tests\Authentication; use Symfony\Component\Security\Http\Authentication\DefaultAuthenticationFailureHandler; -use Symfony\Component\Security\Core\SecurityContextInterface; +use Symfony\Component\Security\Core\Security; use Symfony\Component\HttpKernel\HttpKernelInterface; class DefaultAuthenticationFailureHandlerTest extends \PHPUnit_Framework_TestCase @@ -47,7 +47,7 @@ class DefaultAuthenticationFailureHandlerTest extends \PHPUnit_Framework_TestCas $subRequest = $this->getRequest(); $subRequest->attributes->expects($this->once()) - ->method('set')->with(SecurityContextInterface::AUTHENTICATION_ERROR, $this->exception); + ->method('set')->with(Security::AUTHENTICATION_ERROR, $this->exception); $this->httpUtils->expects($this->once()) ->method('createRequest')->with($this->request, '/login') ->will($this->returnValue($subRequest)); @@ -79,7 +79,7 @@ class DefaultAuthenticationFailureHandlerTest extends \PHPUnit_Framework_TestCas public function testExceptionIsPersistedInSession() { $this->session->expects($this->once()) - ->method('set')->with(SecurityContextInterface::AUTHENTICATION_ERROR, $this->exception); + ->method('set')->with(Security::AUTHENTICATION_ERROR, $this->exception); $handler = new DefaultAuthenticationFailureHandler($this->httpKernel, $this->httpUtils, array(), $this->logger); $handler->onAuthenticationFailure($this->request, $this->exception); @@ -91,7 +91,7 @@ class DefaultAuthenticationFailureHandlerTest extends \PHPUnit_Framework_TestCas $subRequest = $this->getRequest(); $subRequest->attributes->expects($this->once()) - ->method('set')->with(SecurityContextInterface::AUTHENTICATION_ERROR, $this->exception); + ->method('set')->with(Security::AUTHENTICATION_ERROR, $this->exception); $this->httpUtils->expects($this->once()) ->method('createRequest')->with($this->request, '/login') @@ -105,7 +105,10 @@ class DefaultAuthenticationFailureHandlerTest extends \PHPUnit_Framework_TestCas public function testRedirectIsLogged() { - $this->logger->expects($this->once())->method('debug')->with('Redirecting to /login'); + $this->logger + ->expects($this->once()) + ->method('debug') + ->with('Authentication failure, redirect triggered.', array('failure_path' => '/login')); $handler = new DefaultAuthenticationFailureHandler($this->httpKernel, $this->httpUtils, array(), $this->logger); $handler->onAuthenticationFailure($this->request, $this->exception); @@ -119,7 +122,10 @@ class DefaultAuthenticationFailureHandlerTest extends \PHPUnit_Framework_TestCas ->method('createRequest')->with($this->request, '/login') ->will($this->returnValue($this->getRequest())); - $this->logger->expects($this->once())->method('debug')->with('Forwarding to /login'); + $this->logger + ->expects($this->once()) + ->method('debug') + ->with('Authentication failure, forward triggered.', array('failure_path' => '/login')); $handler = new DefaultAuthenticationFailureHandler($this->httpKernel, $this->httpUtils, $options, $this->logger); $handler->onAuthenticationFailure($this->request, $this->exception); diff --git a/Tests/Http/Authentication/DefaultAuthenticationSuccessHandlerTest.php b/Http/Tests/Authentication/DefaultAuthenticationSuccessHandlerTest.php index 3d8ebf3..4d1847d 100644 --- a/Tests/Http/Authentication/DefaultAuthenticationSuccessHandlerTest.php +++ b/Http/Tests/Authentication/DefaultAuthenticationSuccessHandlerTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Http\Authentication; +namespace Symfony\Component\Security\Http\Tests\Authentication; use Symfony\Component\Security\Http\Authentication\DefaultAuthenticationSuccessHandler; diff --git a/Http/Tests/Authentication/SimpleAuthenticationHandlerTest.php b/Http/Tests/Authentication/SimpleAuthenticationHandlerTest.php new file mode 100644 index 0000000..6e79b07 --- /dev/null +++ b/Http/Tests/Authentication/SimpleAuthenticationHandlerTest.php @@ -0,0 +1,194 @@ +<?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\Tests; + +use Symfony\Component\Security\Core\Authentication\SimpleAuthenticatorInterface; +use Symfony\Component\Security\Core\Exception\AuthenticationException; +use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface; +use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface; +use Symfony\Component\Security\Http\Authentication\SimpleAuthenticationHandler; + +class SimpleAuthenticationHandlerTest extends \PHPUnit_Framework_TestCase +{ + private $successHandler; + + private $failureHandler; + + private $request; + + private $token; + + private $authenticationException; + + private $response; + + protected function setUp() + { + $this->successHandler = $this->getMock('Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface'); + $this->failureHandler = $this->getMock('Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface'); + + $this->request = $this->getMock('Symfony\Component\HttpFoundation\Request'); + $this->token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); + // No methods are invoked on the exception; we just assert on its class + $this->authenticationException = new AuthenticationException(); + + $this->response = $this->getMock('Symfony\Component\HttpFoundation\Response'); + } + + public function testOnAuthenticationSuccessFallsBackToDefaultHandlerIfSimpleIsNotASuccessHandler() + { + $authenticator = $this->getMock('Symfony\Component\Security\Core\Authentication\SimpleAuthenticatorInterface'); + + $this->successHandler->expects($this->once()) + ->method('onAuthenticationSuccess') + ->with($this->request, $this->token) + ->will($this->returnValue($this->response)); + + $handler = new SimpleAuthenticationHandler($authenticator, $this->successHandler, $this->failureHandler); + $result = $handler->onAuthenticationSuccess($this->request, $this->token); + + $this->assertSame($this->response, $result); + } + + public function testOnAuthenticationSuccessCallsSimpleAuthenticator() + { + $this->successHandler->expects($this->never()) + ->method('onAuthenticationSuccess'); + + $authenticator = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Tests\TestSuccessHandlerInterface'); + $authenticator->expects($this->once()) + ->method('onAuthenticationSuccess') + ->with($this->request, $this->token) + ->will($this->returnValue($this->response)); + + $handler = new SimpleAuthenticationHandler($authenticator, $this->successHandler, $this->failureHandler); + $result = $handler->onAuthenticationSuccess($this->request, $this->token); + + $this->assertSame($this->response, $result); + } + + /** + * @expectedException \UnexpectedValueException + * @expectedExceptionMessage onAuthenticationSuccess method must return null to use the default success handler, or a Response object + */ + public function testOnAuthenticationSuccessThrowsAnExceptionIfNonResponseIsReturned() + { + $this->successHandler->expects($this->never()) + ->method('onAuthenticationSuccess'); + + $authenticator = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Tests\TestSuccessHandlerInterface'); + $authenticator->expects($this->once()) + ->method('onAuthenticationSuccess') + ->with($this->request, $this->token) + ->will($this->returnValue(new \stdClass())); + + $handler = new SimpleAuthenticationHandler($authenticator, $this->successHandler, $this->failureHandler); + $handler->onAuthenticationSuccess($this->request, $this->token); + } + + public function testOnAuthenticationSuccessFallsBackToDefaultHandlerIfNullIsReturned() + { + $this->successHandler->expects($this->once()) + ->method('onAuthenticationSuccess') + ->with($this->request, $this->token) + ->will($this->returnValue($this->response)); + + $authenticator = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Tests\TestSuccessHandlerInterface'); + $authenticator->expects($this->once()) + ->method('onAuthenticationSuccess') + ->with($this->request, $this->token) + ->will($this->returnValue(null)); + + $handler = new SimpleAuthenticationHandler($authenticator, $this->successHandler, $this->failureHandler); + $result = $handler->onAuthenticationSuccess($this->request, $this->token); + + $this->assertSame($this->response, $result); + } + + public function testOnAuthenticationFailureFallsBackToDefaultHandlerIfSimpleIsNotAFailureHandler() + { + $authenticator = $this->getMock('Symfony\Component\Security\Core\Authentication\SimpleAuthenticatorInterface'); + + $this->failureHandler->expects($this->once()) + ->method('onAuthenticationFailure') + ->with($this->request, $this->authenticationException) + ->will($this->returnValue($this->response)); + + $handler = new SimpleAuthenticationHandler($authenticator, $this->successHandler, $this->failureHandler); + $result = $handler->onAuthenticationFailure($this->request, $this->authenticationException); + + $this->assertSame($this->response, $result); + } + + public function testOnAuthenticationFailureCallsSimpleAuthenticator() + { + $this->failureHandler->expects($this->never()) + ->method('onAuthenticationFailure'); + + $authenticator = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Tests\TestFailureHandlerInterface'); + $authenticator->expects($this->once()) + ->method('onAuthenticationFailure') + ->with($this->request, $this->authenticationException) + ->will($this->returnValue($this->response)); + + $handler = new SimpleAuthenticationHandler($authenticator, $this->successHandler, $this->failureHandler); + $result = $handler->onAuthenticationFailure($this->request, $this->authenticationException); + + $this->assertSame($this->response, $result); + } + + /** + * @expectedException \UnexpectedValueException + * @expectedExceptionMessage onAuthenticationFailure method must return null to use the default failure handler, or a Response object + */ + public function testOnAuthenticationFailureThrowsAnExceptionIfNonResponseIsReturned() + { + $this->failureHandler->expects($this->never()) + ->method('onAuthenticationFailure'); + + $authenticator = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Tests\TestFailureHandlerInterface'); + $authenticator->expects($this->once()) + ->method('onAuthenticationFailure') + ->with($this->request, $this->authenticationException) + ->will($this->returnValue(new \stdClass())); + + $handler = new SimpleAuthenticationHandler($authenticator, $this->successHandler, $this->failureHandler); + $handler->onAuthenticationFailure($this->request, $this->authenticationException); + } + + public function testOnAuthenticationFailureFallsBackToDefaultHandlerIfNullIsReturned() + { + $this->failureHandler->expects($this->once()) + ->method('onAuthenticationFailure') + ->with($this->request, $this->authenticationException) + ->will($this->returnValue($this->response)); + + $authenticator = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Tests\TestFailureHandlerInterface'); + $authenticator->expects($this->once()) + ->method('onAuthenticationFailure') + ->with($this->request, $this->authenticationException) + ->will($this->returnValue(null)); + + $handler = new SimpleAuthenticationHandler($authenticator, $this->successHandler, $this->failureHandler); + $result = $handler->onAuthenticationFailure($this->request, $this->authenticationException); + + $this->assertSame($this->response, $result); + } +} + +interface TestSuccessHandlerInterface extends AuthenticationSuccessHandlerInterface, SimpleAuthenticatorInterface +{ +} + +interface TestFailureHandlerInterface extends AuthenticationFailureHandlerInterface, SimpleAuthenticatorInterface +{ +} diff --git a/Tests/Http/EntryPoint/BasicAuthenticationEntryPointTest.php b/Http/Tests/EntryPoint/BasicAuthenticationEntryPointTest.php index 5640789..ca5922c 100644 --- a/Tests/Http/EntryPoint/BasicAuthenticationEntryPointTest.php +++ b/Http/Tests/EntryPoint/BasicAuthenticationEntryPointTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Http\EntryPoint; +namespace Symfony\Component\Security\Http\Tests\EntryPoint; use Symfony\Component\Security\Http\EntryPoint\BasicAuthenticationEntryPoint; use Symfony\Component\Security\Core\Exception\AuthenticationException; diff --git a/Tests/Http/EntryPoint/DigestAuthenticationEntryPointTest.php b/Http/Tests/EntryPoint/DigestAuthenticationEntryPointTest.php index 5c6eccc..181e340 100644 --- a/Tests/Http/EntryPoint/DigestAuthenticationEntryPointTest.php +++ b/Http/Tests/EntryPoint/DigestAuthenticationEntryPointTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Http\EntryPoint; +namespace Symfony\Component\Security\Http\Tests\EntryPoint; use Symfony\Component\Security\Http\EntryPoint\DigestAuthenticationEntryPoint; use Symfony\Component\Security\Core\Exception\AuthenticationException; diff --git a/Tests/Http/EntryPoint/FormAuthenticationEntryPointTest.php b/Http/Tests/EntryPoint/FormAuthenticationEntryPointTest.php index 097912d..3acb9c2 100644 --- a/Tests/Http/EntryPoint/FormAuthenticationEntryPointTest.php +++ b/Http/Tests/EntryPoint/FormAuthenticationEntryPointTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Http\EntryPoint; +namespace Symfony\Component\Security\Http\Tests\EntryPoint; use Symfony\Component\Security\Http\EntryPoint\FormAuthenticationEntryPoint; use Symfony\Component\HttpKernel\HttpKernelInterface; diff --git a/Tests/Http/EntryPoint/RetryAuthenticationEntryPointTest.php b/Http/Tests/EntryPoint/RetryAuthenticationEntryPointTest.php index 59ec912..ff5fbc2 100644 --- a/Tests/Http/EntryPoint/RetryAuthenticationEntryPointTest.php +++ b/Http/Tests/EntryPoint/RetryAuthenticationEntryPointTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Http\EntryPoint; +namespace Symfony\Component\Security\Http\Tests\EntryPoint; use Symfony\Component\Security\Http\EntryPoint\RetryAuthenticationEntryPoint; use Symfony\Component\HttpFoundation\Request; diff --git a/Tests/Http/Firewall/AbstractPreAuthenticatedListenerTest.php b/Http/Tests/Firewall/AbstractPreAuthenticatedListenerTest.php index d6373b3..61f086a 100644 --- a/Tests/Http/Firewall/AbstractPreAuthenticatedListenerTest.php +++ b/Http/Tests/Firewall/AbstractPreAuthenticatedListenerTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Http\Firewall; +namespace Symfony\Component\Security\Http\Tests\Firewall; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken; @@ -26,13 +26,13 @@ class AbstractPreAuthenticatedListenerTest extends \PHPUnit_Framework_TestCase $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); - $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'); - $context + $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); + $tokenStorage ->expects($this->any()) ->method('getToken') ->will($this->returnValue(null)) ; - $context + $tokenStorage ->expects($this->once()) ->method('setToken') ->with($this->equalTo($token)) @@ -47,7 +47,7 @@ class AbstractPreAuthenticatedListenerTest extends \PHPUnit_Framework_TestCase ; $listener = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Firewall\AbstractPreAuthenticatedListener', array( - $context, + $tokenStorage, $authenticationManager, 'TheProviderKey', )); @@ -72,13 +72,13 @@ class AbstractPreAuthenticatedListenerTest extends \PHPUnit_Framework_TestCase $request = new Request(array(), array(), array(), array(), array(), array()); - $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'); - $context + $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); + $tokenStorage ->expects($this->any()) ->method('getToken') ->will($this->returnValue(null)) ; - $context + $tokenStorage ->expects($this->never()) ->method('setToken') ; @@ -93,7 +93,7 @@ class AbstractPreAuthenticatedListenerTest extends \PHPUnit_Framework_TestCase ; $listener = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Firewall\AbstractPreAuthenticatedListener', array( - $context, + $tokenStorage, $authenticationManager, 'TheProviderKey', )); @@ -120,13 +120,13 @@ class AbstractPreAuthenticatedListenerTest extends \PHPUnit_Framework_TestCase $request = new Request(array(), array(), array(), array(), array(), array()); - $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'); - $context + $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); + $tokenStorage ->expects($this->any()) ->method('getToken') ->will($this->returnValue($token)) ; - $context + $tokenStorage ->expects($this->never()) ->method('setToken') ; @@ -141,7 +141,7 @@ class AbstractPreAuthenticatedListenerTest extends \PHPUnit_Framework_TestCase ; $listener = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Firewall\AbstractPreAuthenticatedListener', array( - $context, + $tokenStorage, $authenticationManager, 'TheProviderKey', )); @@ -168,8 +168,8 @@ class AbstractPreAuthenticatedListenerTest extends \PHPUnit_Framework_TestCase $token = new PreAuthenticatedToken('TheUser', 'TheCredentials', 'TheProviderKey', array('ROLE_FOO')); - $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'); - $context + $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); + $tokenStorage ->expects($this->any()) ->method('getToken') ->will($this->returnValue($token)) @@ -182,7 +182,7 @@ class AbstractPreAuthenticatedListenerTest extends \PHPUnit_Framework_TestCase ; $listener = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Firewall\AbstractPreAuthenticatedListener', array( - $context, + $tokenStorage, $authenticationManager, 'TheProviderKey', )); @@ -209,13 +209,13 @@ class AbstractPreAuthenticatedListenerTest extends \PHPUnit_Framework_TestCase $token = new PreAuthenticatedToken('AnotherUser', 'TheCredentials', 'TheProviderKey', array('ROLE_FOO')); - $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'); - $context + $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); + $tokenStorage ->expects($this->any()) ->method('getToken') ->will($this->returnValue($token)) ; - $context + $tokenStorage ->expects($this->once()) ->method('setToken') ->with($this->equalTo(null)) @@ -231,7 +231,7 @@ class AbstractPreAuthenticatedListenerTest extends \PHPUnit_Framework_TestCase ; $listener = $this->getMockForAbstractClass('Symfony\Component\Security\Http\Firewall\AbstractPreAuthenticatedListener', array( - $context, + $tokenStorage, $authenticationManager, 'TheProviderKey', )); diff --git a/Tests/Http/Firewall/AccessListenerTest.php b/Http/Tests/Firewall/AccessListenerTest.php index 961c792..af9d565 100644 --- a/Tests/Http/Firewall/AccessListenerTest.php +++ b/Http/Tests/Firewall/AccessListenerTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Http\Firewall; +namespace Symfony\Component\Security\Http\Tests\Firewall; use Symfony\Component\Security\Http\Firewall\AccessListener; @@ -37,8 +37,8 @@ class AccessListenerTest extends \PHPUnit_Framework_TestCase ->will($this->returnValue(true)) ; - $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'); - $context + $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); + $tokenStorage ->expects($this->any()) ->method('getToken') ->will($this->returnValue($token)) @@ -53,7 +53,7 @@ class AccessListenerTest extends \PHPUnit_Framework_TestCase ; $listener = new AccessListener( - $context, + $tokenStorage, $accessDecisionManager, $accessMap, $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface') @@ -103,13 +103,13 @@ class AccessListenerTest extends \PHPUnit_Framework_TestCase ->will($this->returnValue($authenticatedToken)) ; - $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'); - $context + $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); + $tokenStorage ->expects($this->any()) ->method('getToken') ->will($this->returnValue($notAuthenticatedToken)) ; - $context + $tokenStorage ->expects($this->once()) ->method('setToken') ->with($this->equalTo($authenticatedToken)) @@ -124,7 +124,7 @@ class AccessListenerTest extends \PHPUnit_Framework_TestCase ; $listener = new AccessListener( - $context, + $tokenStorage, $accessDecisionManager, $accessMap, $authManager @@ -158,15 +158,15 @@ class AccessListenerTest extends \PHPUnit_Framework_TestCase ->method('isAuthenticated') ; - $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'); - $context + $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); + $tokenStorage ->expects($this->any()) ->method('getToken') ->will($this->returnValue($token)) ; $listener = new AccessListener( - $context, + $tokenStorage, $this->getMock('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface'), $accessMap, $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface') @@ -185,17 +185,17 @@ class AccessListenerTest extends \PHPUnit_Framework_TestCase /** * @expectedException \Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException */ - public function testHandleWhenTheSecurityContextHasNoToken() + public function testHandleWhenTheSecurityTokenStorageHasNoToken() { - $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'); - $context + $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); + $tokenStorage ->expects($this->any()) ->method('getToken') ->will($this->returnValue(null)) ; $listener = new AccessListener( - $context, + $tokenStorage, $this->getMock('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface'), $this->getMock('Symfony\Component\Security\Http\AccessMapInterface'), $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface') diff --git a/Http/Tests/Firewall/AnonymousAuthenticationListenerTest.php b/Http/Tests/Firewall/AnonymousAuthenticationListenerTest.php new file mode 100644 index 0000000..3450c1e --- /dev/null +++ b/Http/Tests/Firewall/AnonymousAuthenticationListenerTest.php @@ -0,0 +1,87 @@ +<?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\Tests\Firewall; + +use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken; +use Symfony\Component\Security\Http\Firewall\AnonymousAuthenticationListener; + +class AnonymousAuthenticationListenerTest extends \PHPUnit_Framework_TestCase +{ + public function testHandleWithTokenStorageHavingAToken() + { + $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); + $tokenStorage + ->expects($this->any()) + ->method('getToken') + ->will($this->returnValue($this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'))) + ; + $tokenStorage + ->expects($this->never()) + ->method('setToken') + ; + + $authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'); + $authenticationManager + ->expects($this->never()) + ->method('authenticate') + ; + + $listener = new AnonymousAuthenticationListener($tokenStorage, 'TheKey', null, $authenticationManager); + $listener->handle($this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false)); + } + + public function testHandleWithTokenStorageHavingNoToken() + { + $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); + $tokenStorage + ->expects($this->any()) + ->method('getToken') + ->will($this->returnValue(null)) + ; + + $anonymousToken = new AnonymousToken('TheKey', 'anon.', array()); + + $authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'); + $authenticationManager + ->expects($this->once()) + ->method('authenticate') + ->with($this->callback(function ($token) { + return 'TheKey' === $token->getKey(); + })) + ->will($this->returnValue($anonymousToken)) + ; + + $tokenStorage + ->expects($this->once()) + ->method('setToken') + ->with($anonymousToken) + ; + + $listener = new AnonymousAuthenticationListener($tokenStorage, 'TheKey', null, $authenticationManager); + $listener->handle($this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false)); + } + + public function testHandledEventIsLogged() + { + $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); + $logger = $this->getMock('Psr\Log\LoggerInterface'); + $logger->expects($this->once()) + ->method('info') + ->with('Populated the TokenStorage with an anonymous Token.') + ; + + $authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'); + + $listener = new AnonymousAuthenticationListener($tokenStorage, 'TheKey', $logger, $authenticationManager); + $listener->handle($this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false)); + } +} diff --git a/Tests/Http/Firewall/BasicAuthenticationListenerTest.php b/Http/Tests/Firewall/BasicAuthenticationListenerTest.php index 65dc185..8901cb2 100644 --- a/Tests/Http/Firewall/BasicAuthenticationListenerTest.php +++ b/Http/Tests/Firewall/BasicAuthenticationListenerTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Http\Firewall; +namespace Symfony\Component\Security\Http\Tests\Firewall; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Security\Core\Authentication\Token\PreAuthenticatedToken; @@ -29,13 +29,13 @@ class BasicAuthenticationListenerTest extends \PHPUnit_Framework_TestCase $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); - $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'); - $context + $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); + $tokenStorage ->expects($this->any()) ->method('getToken') ->will($this->returnValue(null)) ; - $context + $tokenStorage ->expects($this->once()) ->method('setToken') ->with($this->equalTo($token)) @@ -50,7 +50,7 @@ class BasicAuthenticationListenerTest extends \PHPUnit_Framework_TestCase ; $listener = new BasicAuthenticationListener( - $context, + $tokenStorage, $authenticationManager, 'TheProviderKey', $this->getMock('Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface') @@ -75,13 +75,13 @@ class BasicAuthenticationListenerTest extends \PHPUnit_Framework_TestCase $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); - $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'); - $context + $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); + $tokenStorage ->expects($this->any()) ->method('getToken') ->will($this->returnValue(null)) ; - $context + $tokenStorage ->expects($this->never()) ->method('setToken') ; @@ -97,7 +97,7 @@ class BasicAuthenticationListenerTest extends \PHPUnit_Framework_TestCase ; $listener = new BasicAuthenticationListener( - $context, + $tokenStorage, new AuthenticationProviderManager(array($this->getMock('Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface'))), 'TheProviderKey', $authenticationEntryPoint @@ -122,14 +122,14 @@ class BasicAuthenticationListenerTest extends \PHPUnit_Framework_TestCase { $request = new Request(); - $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'); - $context + $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); + $tokenStorage ->expects($this->never()) ->method('getToken') ; $listener = new BasicAuthenticationListener( - $context, + $tokenStorage, $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'), 'TheProviderKey', $this->getMock('Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface') @@ -151,8 +151,8 @@ class BasicAuthenticationListenerTest extends \PHPUnit_Framework_TestCase $token = new UsernamePasswordToken('TheUsername', 'ThePassword', 'TheProviderKey', array('ROLE_FOO')); - $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'); - $context + $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); + $tokenStorage ->expects($this->any()) ->method('getToken') ->will($this->returnValue($token)) @@ -165,7 +165,7 @@ class BasicAuthenticationListenerTest extends \PHPUnit_Framework_TestCase ; $listener = new BasicAuthenticationListener( - $context, + $tokenStorage, $authenticationManager, 'TheProviderKey', $this->getMock('Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface') @@ -188,7 +188,7 @@ class BasicAuthenticationListenerTest extends \PHPUnit_Framework_TestCase public function testItRequiresProviderKey() { new BasicAuthenticationListener( - $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'), + $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'), $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'), '', $this->getMock('Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface') @@ -204,13 +204,13 @@ class BasicAuthenticationListenerTest extends \PHPUnit_Framework_TestCase $token = new PreAuthenticatedToken('TheUser', 'TheCredentials', 'TheProviderKey', array('ROLE_FOO')); - $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'); - $context + $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); + $tokenStorage ->expects($this->any()) ->method('getToken') ->will($this->returnValue($token)) ; - $context + $tokenStorage ->expects($this->never()) ->method('setToken') ; @@ -226,7 +226,7 @@ class BasicAuthenticationListenerTest extends \PHPUnit_Framework_TestCase ; $listener = new BasicAuthenticationListener( - $context, + $tokenStorage, new AuthenticationProviderManager(array($this->getMock('Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface'))), 'TheProviderKey', $authenticationEntryPoint diff --git a/Tests/Http/Firewall/ChannelListenerTest.php b/Http/Tests/Firewall/ChannelListenerTest.php index 5e583e0..1465224 100644 --- a/Tests/Http/Firewall/ChannelListenerTest.php +++ b/Http/Tests/Firewall/ChannelListenerTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Http\Firewall; +namespace Symfony\Component\Security\Http\Tests\Firewall; use Symfony\Component\Security\Http\Firewall\ChannelListener; use Symfony\Component\HttpFoundation\Response; diff --git a/Tests/Http/Firewall/ContextListenerTest.php b/Http/Tests/Firewall/ContextListenerTest.php index 6b4ef73..ae1199a 100644 --- a/Tests/Http/Firewall/ContextListenerTest.php +++ b/Http/Tests/Firewall/ContextListenerTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Http\Firewall; +namespace Symfony\Component\Security\Http\Tests\Firewall; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -18,26 +18,13 @@ use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage; use Symfony\Component\HttpKernel\Event\FilterResponseEvent; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\KernelEvents; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; -use Symfony\Component\Security\Core\SecurityContext; use Symfony\Component\Security\Http\Firewall\ContextListener; use Symfony\Component\EventDispatcher\EventDispatcher; class ContextListenerTest extends \PHPUnit_Framework_TestCase { - protected function setUp() - { - $this->securityContext = new SecurityContext( - $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'), - $this->getMock('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface') - ); - } - - protected function tearDown() - { - unset($this->securityContext); - } - /** * @expectedException \InvalidArgumentException * @expectedExceptionMessage $contextKey must not be empty @@ -45,7 +32,7 @@ class ContextListenerTest extends \PHPUnit_Framework_TestCase public function testItRequiresContextKey() { new ContextListener( - $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'), + $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'), array(), '' ); @@ -58,7 +45,7 @@ class ContextListenerTest extends \PHPUnit_Framework_TestCase public function testUserProvidersNeedToImplementAnInterface() { new ContextListener( - $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'), + $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'), array(new \stdClass()), 'key123' ); @@ -100,7 +87,8 @@ class ContextListenerTest extends \PHPUnit_Framework_TestCase public function testOnKernelResponseWithoutSession() { - $this->securityContext->setToken(new UsernamePasswordToken('test1', 'pass1', 'phpunit')); + $tokenStorage = new TokenStorage(); + $tokenStorage->setToken(new UsernamePasswordToken('test1', 'pass1', 'phpunit')); $request = new Request(); $session = new Session(new MockArraySessionStorage()); $request->setSession($session); @@ -112,7 +100,7 @@ class ContextListenerTest extends \PHPUnit_Framework_TestCase new Response() ); - $listener = new ContextListener($this->securityContext, array(), 'session', null, new EventDispatcher()); + $listener = new ContextListener($tokenStorage, array(), 'session', null, new EventDispatcher()); $listener->onKernelResponse($event); $this->assertTrue($session->isStarted()); @@ -131,7 +119,7 @@ class ContextListenerTest extends \PHPUnit_Framework_TestCase new Response() ); - $listener = new ContextListener($this->securityContext, array(), 'session', null, new EventDispatcher()); + $listener = new ContextListener(new TokenStorage(), array(), 'session', null, new EventDispatcher()); $listener->onKernelResponse($event); $this->assertFalse($session->isStarted()); @@ -142,7 +130,7 @@ class ContextListenerTest extends \PHPUnit_Framework_TestCase */ public function testInvalidTokenInSession($token) { - $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'); + $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); $event = $this->getMockBuilder('Symfony\Component\HttpKernel\Event\GetResponseEvent') ->disableOriginalConstructor() ->getMock(); @@ -162,11 +150,11 @@ class ContextListenerTest extends \PHPUnit_Framework_TestCase ->method('get') ->with('_security_key123') ->will($this->returnValue($token)); - $context->expects($this->once()) + $tokenStorage->expects($this->once()) ->method('setToken') ->with(null); - $listener = new ContextListener($context, array(), 'key123'); + $listener = new ContextListener($tokenStorage, array(), 'key123'); $listener->handle($event); } @@ -181,17 +169,17 @@ class ContextListenerTest extends \PHPUnit_Framework_TestCase public function testHandleAddsKernelResponseListener() { - $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'); + $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'); $event = $this->getMockBuilder('Symfony\Component\HttpKernel\Event\GetResponseEvent') ->disableOriginalConstructor() ->getMock(); - $listener = new ContextListener($context, array(), 'key123', null, $dispatcher); + $listener = new ContextListener($tokenStorage, array(), 'key123', null, $dispatcher); $event->expects($this->any()) - ->method('getRequestType') - ->will($this->returnValue(HttpKernelInterface::MASTER_REQUEST)); + ->method('isMasterRequest') + ->will($this->returnValue(true)); $event->expects($this->any()) ->method('getRequest') ->will($this->returnValue($this->getMock('Symfony\Component\HttpFoundation\Request'))); @@ -205,13 +193,13 @@ class ContextListenerTest extends \PHPUnit_Framework_TestCase public function testOnKernelResponseListenerRemovesItself() { - $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'); + $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'); $event = $this->getMockBuilder('Symfony\Component\HttpKernel\Event\FilterResponseEvent') ->disableOriginalConstructor() ->getMock(); - $listener = new ContextListener($context, array(), 'key123', null, $dispatcher); + $listener = new ContextListener($tokenStorage, array(), 'key123', null, $dispatcher); $request = $this->getMock('Symfony\Component\HttpFoundation\Request'); $request->expects($this->any()) @@ -219,8 +207,8 @@ class ContextListenerTest extends \PHPUnit_Framework_TestCase ->will($this->returnValue(true)); $event->expects($this->any()) - ->method('getRequestType') - ->will($this->returnValue(HttpKernelInterface::MASTER_REQUEST)); + ->method('isMasterRequest') + ->will($this->returnValue(true)); $event->expects($this->any()) ->method('getRequest') ->will($this->returnValue($request)); @@ -242,10 +230,10 @@ class ContextListenerTest extends \PHPUnit_Framework_TestCase ->getMock(); $event->expects($this->any())->method('getRequest')->will($this->returnValue($request)); - $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'); - $context->expects($this->once())->method('setToken')->with(null); + $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); + $tokenStorage->expects($this->once())->method('setToken')->with(null); - $listener = new ContextListener($context, array(), 'key123'); + $listener = new ContextListener($tokenStorage, array(), 'key123'); $listener->handle($event); } @@ -257,7 +245,8 @@ class ContextListenerTest extends \PHPUnit_Framework_TestCase $session->set('_security_session', $original); } - $this->securityContext->setToken($newToken); + $tokenStorage = new TokenStorage(); + $tokenStorage->setToken($newToken); $request = new Request(); $request->setSession($session); @@ -270,7 +259,7 @@ class ContextListenerTest extends \PHPUnit_Framework_TestCase new Response() ); - $listener = new ContextListener($this->securityContext, array(), 'session', null, new EventDispatcher()); + $listener = new ContextListener($tokenStorage, array(), 'session', null, new EventDispatcher()); $listener->onKernelResponse($event); return $session; diff --git a/Tests/Http/Firewall/DigestDataTest.php b/Http/Tests/Firewall/DigestDataTest.php index e5be6f8..a7c8d49 100644 --- a/Tests/Http/Firewall/DigestDataTest.php +++ b/Http/Tests/Firewall/DigestDataTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Http\Firewall; +namespace Symfony\Component\Security\Http\Tests\Firewall; use Symfony\Component\Security\Http\Firewall\DigestData; diff --git a/Tests/Http/Firewall/ExceptionListenerTest.php b/Http/Tests/Firewall/ExceptionListenerTest.php index 12f18a6..3d409e5 100644 --- a/Tests/Http/Firewall/ExceptionListenerTest.php +++ b/Http/Tests/Firewall/ExceptionListenerTest.php @@ -9,16 +9,16 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Http\Firewall; +namespace Symfony\Component\Security\Http\Tests\Firewall; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Symfony\Component\Security\Core\Exception\AuthenticationException; -use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Http\Authorization\AccessDeniedHandlerInterface; use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; use Symfony\Component\Security\Http\Firewall\ExceptionListener; @@ -123,10 +123,10 @@ class ExceptionListenerTest extends \PHPUnit_Framework_TestCase { $event = $this->createEvent($exception); - $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'); - $context->expects($this->once())->method('getToken')->will($this->returnValue($this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'))); + $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); + $tokenStorage->expects($this->once())->method('getToken')->will($this->returnValue($this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'))); - $listener = $this->createExceptionListener($context, $this->createTrustResolver(false), null, $this->createEntryPoint()); + $listener = $this->createExceptionListener($tokenStorage, $this->createTrustResolver(false), null, $this->createEntryPoint()); $listener->onKernelException($event); $this->assertEquals('OK', $event->getResponse()->getContent()); @@ -166,18 +166,13 @@ class ExceptionListenerTest extends \PHPUnit_Framework_TestCase $kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface'); } - $event = new GetResponseForExceptionEvent($kernel, Request::create('/'), HttpKernelInterface::MASTER_REQUEST, $exception); - - $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'); - $event->setDispatcher($dispatcher); - - return $event; + return new GetResponseForExceptionEvent($kernel, Request::create('/'), HttpKernelInterface::MASTER_REQUEST, $exception); } - private function createExceptionListener(SecurityContextInterface $context = null, AuthenticationTrustResolverInterface $trustResolver = null, HttpUtils $httpUtils = null, AuthenticationEntryPointInterface $authenticationEntryPoint = null, $errorPage = null, AccessDeniedHandlerInterface $accessDeniedHandler = null) + private function createExceptionListener(TokenStorageInterface $tokenStorage = null, AuthenticationTrustResolverInterface $trustResolver = null, HttpUtils $httpUtils = null, AuthenticationEntryPointInterface $authenticationEntryPoint = null, $errorPage = null, AccessDeniedHandlerInterface $accessDeniedHandler = null) { return new ExceptionListener( - $context ?: $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'), + $tokenStorage ?: $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'), $trustResolver ?: $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface'), $httpUtils ?: $this->getMock('Symfony\Component\Security\Http\HttpUtils'), 'key', diff --git a/Tests/Http/Firewall/LogoutListenerTest.php b/Http/Tests/Firewall/LogoutListenerTest.php index 9301086..15c996e 100644 --- a/Tests/Http/Firewall/LogoutListenerTest.php +++ b/Http/Tests/Firewall/LogoutListenerTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Http\Firewall; +namespace Symfony\Component\Security\Http\Tests\Firewall; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -19,7 +19,7 @@ class LogoutListenerTest extends \PHPUnit_Framework_TestCase { public function testHandleUnmatchedPath() { - list($listener, $context, $httpUtils, $options) = $this->getListener(); + list($listener, $tokenStorage, $httpUtils, $options) = $this->getListener(); list($event, $request) = $this->getGetResponseEvent(); @@ -37,22 +37,21 @@ class LogoutListenerTest extends \PHPUnit_Framework_TestCase public function testHandleMatchedPathWithSuccessHandlerAndCsrfValidation() { $successHandler = $this->getSuccessHandler(); - $csrfProvider = $this->getCsrfProvider(); + $tokenManager = $this->getTokenManager(); - list($listener, $context, $httpUtils, $options) = $this->getListener($successHandler, $csrfProvider); + list($listener, $tokenStorage, $httpUtils, $options) = $this->getListener($successHandler, $tokenManager); list($event, $request) = $this->getGetResponseEvent(); - $request->query->set('_csrf_token', $csrfToken = 'token'); + $request->query->set('_csrf_token', 'token'); $httpUtils->expects($this->once()) ->method('checkRequestPath') ->with($request, $options['logout_path']) ->will($this->returnValue(true)); - $csrfProvider->expects($this->once()) - ->method('isCsrfTokenValid') - ->with('logout', $csrfToken) + $tokenManager->expects($this->once()) + ->method('isTokenValid') ->will($this->returnValue(true)); $successHandler->expects($this->once()) @@ -60,7 +59,7 @@ class LogoutListenerTest extends \PHPUnit_Framework_TestCase ->with($request) ->will($this->returnValue($response = new Response())); - $context->expects($this->once()) + $tokenStorage->expects($this->once()) ->method('getToken') ->will($this->returnValue($token = $this->getToken())); @@ -69,7 +68,7 @@ class LogoutListenerTest extends \PHPUnit_Framework_TestCase ->method('logout') ->with($request, $response, $token); - $context->expects($this->once()) + $tokenStorage->expects($this->once()) ->method('setToken') ->with(null); @@ -86,7 +85,7 @@ class LogoutListenerTest extends \PHPUnit_Framework_TestCase { $successHandler = $this->getSuccessHandler(); - list($listener, $context, $httpUtils, $options) = $this->getListener($successHandler); + list($listener, $tokenStorage, $httpUtils, $options) = $this->getListener($successHandler); list($event, $request) = $this->getGetResponseEvent(); @@ -100,7 +99,7 @@ class LogoutListenerTest extends \PHPUnit_Framework_TestCase ->with($request) ->will($this->returnValue($response = new Response())); - $context->expects($this->once()) + $tokenStorage->expects($this->once()) ->method('getToken') ->will($this->returnValue($token = $this->getToken())); @@ -109,7 +108,7 @@ class LogoutListenerTest extends \PHPUnit_Framework_TestCase ->method('logout') ->with($request, $response, $token); - $context->expects($this->once()) + $tokenStorage->expects($this->once()) ->method('setToken') ->with(null); @@ -129,7 +128,7 @@ class LogoutListenerTest extends \PHPUnit_Framework_TestCase { $successHandler = $this->getSuccessHandler(); - list($listener, $context, $httpUtils, $options) = $this->getListener($successHandler); + list($listener, $tokenStorage, $httpUtils, $options) = $this->getListener($successHandler); list($event, $request) = $this->getGetResponseEvent(); @@ -151,37 +150,34 @@ class LogoutListenerTest extends \PHPUnit_Framework_TestCase */ public function testCsrfValidationFails() { - $csrfProvider = $this->getCsrfProvider(); + $tokenManager = $this->getTokenManager(); - list($listener, $context, $httpUtils, $options) = $this->getListener(null, $csrfProvider); + list($listener, $tokenStorage, $httpUtils, $options) = $this->getListener(null, $tokenManager); list($event, $request) = $this->getGetResponseEvent(); - $request->query->set('_csrf_token', $csrfToken = 'token'); + $request->query->set('_csrf_token', 'token'); $httpUtils->expects($this->once()) ->method('checkRequestPath') ->with($request, $options['logout_path']) ->will($this->returnValue(true)); - $csrfProvider->expects($this->once()) - ->method('isCsrfTokenValid') - ->with('logout', $csrfToken) + $tokenManager->expects($this->once()) + ->method('isTokenValid') ->will($this->returnValue(false)); $listener->handle($event); } - private function getCsrfProvider() + private function getTokenManager() { - return $this->getMock('Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface'); + return $this->getMock('Symfony\Component\Security\Csrf\CsrfTokenManagerInterface'); } - private function getContext() + private function getTokenStorage() { - return $this->getMockBuilder('Symfony\Component\Security\Core\SecurityContext') - ->disableOriginalConstructor() - ->getMock(); + return $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); } private function getGetResponseEvent() @@ -209,10 +205,10 @@ class LogoutListenerTest extends \PHPUnit_Framework_TestCase ->getMock(); } - private function getListener($successHandler = null, $csrfProvider = null) + private function getListener($successHandler = null, $tokenManager = null) { $listener = new LogoutListener( - $context = $this->getContext(), + $tokenStorage = $this->getTokenStorage(), $httpUtils = $this->getHttpUtils(), $successHandler ?: $this->getSuccessHandler(), $options = array( @@ -221,10 +217,10 @@ class LogoutListenerTest extends \PHPUnit_Framework_TestCase 'logout_path' => '/logout', 'target_url' => '/', ), - $csrfProvider + $tokenManager ); - return array($listener, $context, $httpUtils, $options); + return array($listener, $tokenStorage, $httpUtils, $options); } private function getSuccessHandler() diff --git a/Http/Tests/Firewall/RememberMeListenerTest.php b/Http/Tests/Firewall/RememberMeListenerTest.php new file mode 100644 index 0000000..7309042 --- /dev/null +++ b/Http/Tests/Firewall/RememberMeListenerTest.php @@ -0,0 +1,415 @@ +<?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\Tests\Firewall; + +use Symfony\Component\Security\Core\Exception\AuthenticationException; +use Symfony\Component\Security\Http\Firewall\RememberMeListener; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Security\Http\SecurityEvents; + +class RememberMeListenerTest extends \PHPUnit_Framework_TestCase +{ + public function testOnCoreSecurityDoesNotTryToPopulateNonEmptyTokenStorage() + { + list($listener, $tokenStorage) = $this->getListener(); + + $tokenStorage + ->expects($this->once()) + ->method('getToken') + ->will($this->returnValue($this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'))) + ; + + $tokenStorage + ->expects($this->never()) + ->method('setToken') + ; + + $this->assertNull($listener->handle($this->getGetResponseEvent())); + } + + public function testOnCoreSecurityDoesNothingWhenNoCookieIsSet() + { + list($listener, $tokenStorage, $service) = $this->getListener(); + + $tokenStorage + ->expects($this->once()) + ->method('getToken') + ->will($this->returnValue(null)) + ; + + $service + ->expects($this->once()) + ->method('autoLogin') + ->will($this->returnValue(null)) + ; + + $event = $this->getGetResponseEvent(); + $event + ->expects($this->once()) + ->method('getRequest') + ->will($this->returnValue(new Request())) + ; + + $this->assertNull($listener->handle($event)); + } + + public function testOnCoreSecurityIgnoresAuthenticationExceptionThrownByAuthenticationManagerImplementation() + { + list($listener, $tokenStorage, $service, $manager) = $this->getListener(); + + $tokenStorage + ->expects($this->once()) + ->method('getToken') + ->will($this->returnValue(null)) + ; + + $service + ->expects($this->once()) + ->method('autoLogin') + ->will($this->returnValue($this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'))) + ; + + $service + ->expects($this->once()) + ->method('loginFail') + ; + + $exception = new AuthenticationException('Authentication failed.'); + $manager + ->expects($this->once()) + ->method('authenticate') + ->will($this->throwException($exception)) + ; + + $event = $this->getGetResponseEvent(); + $event + ->expects($this->once()) + ->method('getRequest') + ->will($this->returnValue(new Request())) + ; + + $listener->handle($event); + } + + /** + * @expectedException Symfony\Component\Security\Core\Exception\AuthenticationException + * @expectedExceptionMessage Authentication failed. + */ + public function testOnCoreSecurityIgnoresAuthenticationOptionallyRethrowsExceptionThrownAuthenticationManagerImplementation() + { + list($listener, $tokenStorage, $service, $manager) = $this->getListener(false, false); + + $tokenStorage + ->expects($this->once()) + ->method('getToken') + ->will($this->returnValue(null)) + ; + + $service + ->expects($this->once()) + ->method('autoLogin') + ->will($this->returnValue($this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'))) + ; + + $service + ->expects($this->once()) + ->method('loginFail') + ; + + $exception = new AuthenticationException('Authentication failed.'); + $manager + ->expects($this->once()) + ->method('authenticate') + ->will($this->throwException($exception)) + ; + + $event = $this->getGetResponseEvent(); + $event + ->expects($this->once()) + ->method('getRequest') + ->will($this->returnValue(new Request())) + ; + + $listener->handle($event); + } + + public function testOnCoreSecurity() + { + list($listener, $tokenStorage, $service, $manager) = $this->getListener(); + + $tokenStorage + ->expects($this->once()) + ->method('getToken') + ->will($this->returnValue(null)) + ; + + $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); + $service + ->expects($this->once()) + ->method('autoLogin') + ->will($this->returnValue($token)) + ; + + $tokenStorage + ->expects($this->once()) + ->method('setToken') + ->with($this->equalTo($token)) + ; + + $manager + ->expects($this->once()) + ->method('authenticate') + ->will($this->returnValue($token)) + ; + + $event = $this->getGetResponseEvent(); + $event + ->expects($this->once()) + ->method('getRequest') + ->will($this->returnValue(new Request())) + ; + + $listener->handle($event); + } + + public function testSessionStrategy() + { + list($listener, $tokenStorage, $service, $manager, , $dispatcher, $sessionStrategy) = $this->getListener(false, true, true); + + $tokenStorage + ->expects($this->once()) + ->method('getToken') + ->will($this->returnValue(null)) + ; + + $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); + $service + ->expects($this->once()) + ->method('autoLogin') + ->will($this->returnValue($token)) + ; + + $tokenStorage + ->expects($this->once()) + ->method('setToken') + ->with($this->equalTo($token)) + ; + + $manager + ->expects($this->once()) + ->method('authenticate') + ->will($this->returnValue($token)) + ; + + $session = $this->getMock('\Symfony\Component\HttpFoundation\Session\SessionInterface'); + $session + ->expects($this->once()) + ->method('isStarted') + ->will($this->returnValue(true)) + ; + + $request = $this->getMock('\Symfony\Component\HttpFoundation\Request'); + $request + ->expects($this->once()) + ->method('hasSession') + ->will($this->returnValue(true)) + ; + + $request + ->expects($this->once()) + ->method('getSession') + ->will($this->returnValue($session)) + ; + + $event = $this->getGetResponseEvent(); + $event + ->expects($this->once()) + ->method('getRequest') + ->will($this->returnValue($request)) + ; + + $sessionStrategy + ->expects($this->once()) + ->method('onAuthentication') + ->will($this->returnValue(null)) + ; + + $listener->handle($event); + } + + public function testSessionIsMigratedByDefault() + { + list($listener, $tokenStorage, $service, $manager, , $dispatcher, $sessionStrategy) = $this->getListener(false, true, false); + + $tokenStorage + ->expects($this->once()) + ->method('getToken') + ->will($this->returnValue(null)) + ; + + $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); + $service + ->expects($this->once()) + ->method('autoLogin') + ->will($this->returnValue($token)) + ; + + $tokenStorage + ->expects($this->once()) + ->method('setToken') + ->with($this->equalTo($token)) + ; + + $manager + ->expects($this->once()) + ->method('authenticate') + ->will($this->returnValue($token)) + ; + + $session = $this->getMock('\Symfony\Component\HttpFoundation\Session\SessionInterface'); + $session + ->expects($this->once()) + ->method('isStarted') + ->will($this->returnValue(true)) + ; + $session + ->expects($this->once()) + ->method('migrate') + ; + + $request = $this->getMock('\Symfony\Component\HttpFoundation\Request'); + $request + ->expects($this->any()) + ->method('hasSession') + ->will($this->returnValue(true)) + ; + + $request + ->expects($this->any()) + ->method('getSession') + ->will($this->returnValue($session)) + ; + + $event = $this->getGetResponseEvent(); + $event + ->expects($this->once()) + ->method('getRequest') + ->will($this->returnValue($request)) + ; + + $listener->handle($event); + } + + public function testOnCoreSecurityInteractiveLoginEventIsDispatchedIfDispatcherIsPresent() + { + list($listener, $tokenStorage, $service, $manager, , $dispatcher) = $this->getListener(true); + + $tokenStorage + ->expects($this->once()) + ->method('getToken') + ->will($this->returnValue(null)) + ; + + $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); + $service + ->expects($this->once()) + ->method('autoLogin') + ->will($this->returnValue($token)) + ; + + $tokenStorage + ->expects($this->once()) + ->method('setToken') + ->with($this->equalTo($token)) + ; + + $manager + ->expects($this->once()) + ->method('authenticate') + ->will($this->returnValue($token)) + ; + + $event = $this->getGetResponseEvent(); + $request = new Request(); + $event + ->expects($this->once()) + ->method('getRequest') + ->will($this->returnValue($request)) + ; + + $dispatcher + ->expects($this->once()) + ->method('dispatch') + ->with( + SecurityEvents::INTERACTIVE_LOGIN, + $this->isInstanceOf('Symfony\Component\Security\Http\Event\InteractiveLoginEvent') + ) + ; + + $listener->handle($event); + } + + protected function getGetResponseEvent() + { + return $this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false); + } + + protected function getFilterResponseEvent() + { + return $this->getMock('Symfony\Component\HttpKernel\Event\FilterResponseEvent', array(), array(), '', false); + } + + protected function getListener($withDispatcher = false, $catchExceptions = true, $withSessionStrategy = false) + { + $listener = new RememberMeListener( + $tokenStorage = $this->getTokenStorage(), + $service = $this->getService(), + $manager = $this->getManager(), + $logger = $this->getLogger(), + $dispatcher = ($withDispatcher ? $this->getDispatcher() : null), + $catchExceptions, + $sessionStrategy = ($withSessionStrategy ? $this->getSessionStrategy() : null) + ); + + return array($listener, $tokenStorage, $service, $manager, $logger, $dispatcher, $sessionStrategy); + } + + protected function getLogger() + { + return $this->getMock('Psr\Log\LoggerInterface'); + } + + protected function getManager() + { + return $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'); + } + + protected function getService() + { + return $this->getMock('Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface'); + } + + protected function getTokenStorage() + { + return $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); + } + + protected function getDispatcher() + { + return $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'); + } + + private function getSessionStrategy() + { + return $this->getMock('\Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface'); + } +} diff --git a/Http/Tests/Firewall/RemoteUserAuthenticationListenerTest.php b/Http/Tests/Firewall/RemoteUserAuthenticationListenerTest.php new file mode 100644 index 0000000..dad7aad --- /dev/null +++ b/Http/Tests/Firewall/RemoteUserAuthenticationListenerTest.php @@ -0,0 +1,91 @@ +<?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\Tests\Firewall; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Security\Http\Firewall\RemoteUserAuthenticationListener; + +class RemoteUserAuthenticationListenerTest extends \PHPUnit_Framework_TestCase +{ + public function testGetPreAuthenticatedData() + { + $serverVars = array( + 'REMOTE_USER' => 'TheUser', + ); + + $request = new Request(array(), array(), array(), array(), array(), $serverVars); + + $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); + + $authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'); + + $listener = new RemoteUserAuthenticationListener( + $tokenStorage, + $authenticationManager, + 'TheProviderKey' + ); + + $method = new \ReflectionMethod($listener, 'getPreAuthenticatedData'); + $method->setAccessible(true); + + $result = $method->invokeArgs($listener, array($request)); + $this->assertSame($result, array('TheUser', null)); + } + + /** + * @expectedException \Symfony\Component\Security\Core\Exception\BadCredentialsException + */ + public function testGetPreAuthenticatedDataNoUser() + { + $request = new Request(array(), array(), array(), array(), array(), array()); + + $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); + + $authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'); + + $listener = new RemoteUserAuthenticationListener( + $tokenStorage, + $authenticationManager, + 'TheProviderKey' + ); + + $method = new \ReflectionMethod($listener, 'getPreAuthenticatedData'); + $method->setAccessible(true); + + $result = $method->invokeArgs($listener, array($request)); + } + + public function testGetPreAuthenticatedDataWithDifferentKeys() + { + $userCredentials = array('TheUser', null); + + $request = new Request(array(), array(), array(), array(), array(), array( + 'TheUserKey' => 'TheUser', + )); + $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); + + $authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'); + + $listener = new RemoteUserAuthenticationListener( + $tokenStorage, + $authenticationManager, + 'TheProviderKey', + 'TheUserKey' + ); + + $method = new \ReflectionMethod($listener, 'getPreAuthenticatedData'); + $method->setAccessible(true); + + $result = $method->invokeArgs($listener, array($request)); + $this->assertSame($result, $userCredentials); + } +} diff --git a/Http/Tests/Firewall/SimplePreAuthenticationListenerTest.php b/Http/Tests/Firewall/SimplePreAuthenticationListenerTest.php new file mode 100644 index 0000000..0a1286c --- /dev/null +++ b/Http/Tests/Firewall/SimplePreAuthenticationListenerTest.php @@ -0,0 +1,128 @@ +<?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\Tests\Firewall; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Security\Core\Exception\AuthenticationException; +use Symfony\Component\Security\Http\Event\InteractiveLoginEvent; +use Symfony\Component\Security\Http\Firewall\SimplePreAuthenticationListener; +use Symfony\Component\Security\Http\SecurityEvents; + +class SimplePreAuthenticationListenerTest extends \PHPUnit_Framework_TestCase +{ + private $authenticationManager; + private $dispatcher; + private $event; + private $logger; + private $request; + private $tokenStorage; + private $token; + + public function testHandle() + { + $this->tokenStorage + ->expects($this->once()) + ->method('setToken') + ->with($this->equalTo($this->token)) + ; + + $this->authenticationManager + ->expects($this->once()) + ->method('authenticate') + ->with($this->equalTo($this->token)) + ->will($this->returnValue($this->token)) + ; + + $simpleAuthenticator = $this->getMock('Symfony\Component\Security\Core\Authentication\SimplePreAuthenticatorInterface'); + $simpleAuthenticator + ->expects($this->once()) + ->method('createToken') + ->with($this->equalTo($this->request), $this->equalTo('secured_area')) + ->will($this->returnValue($this->token)) + ; + + $loginEvent = new InteractiveLoginEvent($this->request, $this->token); + + $this->dispatcher + ->expects($this->once()) + ->method('dispatch') + ->with($this->equalTo(SecurityEvents::INTERACTIVE_LOGIN), $this->equalTo($loginEvent)) + ; + + $listener = new SimplePreAuthenticationListener($this->tokenStorage, $this->authenticationManager, 'secured_area', $simpleAuthenticator, $this->logger, $this->dispatcher); + + $listener->handle($this->event); + } + + public function testHandlecatchAuthenticationException() + { + $exception = new AuthenticationException('Authentication failed.'); + + $this->authenticationManager + ->expects($this->once()) + ->method('authenticate') + ->with($this->equalTo($this->token)) + ->will($this->throwException($exception)) + ; + + $this->tokenStorage->expects($this->once()) + ->method('setToken') + ->with($this->equalTo(null)) + ; + + $simpleAuthenticator = $this->getMock('Symfony\Component\Security\Core\Authentication\SimplePreAuthenticatorInterface'); + $simpleAuthenticator + ->expects($this->once()) + ->method('createToken') + ->with($this->equalTo($this->request), $this->equalTo('secured_area')) + ->will($this->returnValue($this->token)) + ; + + $listener = new SimplePreAuthenticationListener($this->tokenStorage, $this->authenticationManager, 'secured_area', $simpleAuthenticator, $this->logger, $this->dispatcher); + + $listener->handle($this->event); + } + + protected function setUp() + { + $this->authenticationManager = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\AuthenticationProviderManager') + ->disableOriginalConstructor() + ->getMock() + ; + + $this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'); + + $this->request = new Request(array(), array(), array(), array(), array(), array()); + + $this->event = $this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false); + $this->event + ->expects($this->any()) + ->method('getRequest') + ->will($this->returnValue($this->request)) + ; + + $this->logger = $this->getMock('Psr\Log\LoggerInterface'); + $this->tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); + $this->token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); + } + + protected function tearDown() + { + $this->authenticationManager = null; + $this->dispatcher = null; + $this->event = null; + $this->logger = null; + $this->request = null; + $this->tokenStorage = null; + $this->token = null; + } +} diff --git a/Tests/Http/Firewall/SwitchUserListenerTest.php b/Http/Tests/Firewall/SwitchUserListenerTest.php index 4e795c8..28d73e0 100644 --- a/Tests/Http/Firewall/SwitchUserListenerTest.php +++ b/Http/Tests/Firewall/SwitchUserListenerTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Http\Firewall; +namespace Symfony\Component\Security\Http\Tests\Firewall; use Symfony\Component\Security\Http\Event\SwitchUserEvent; use Symfony\Component\Security\Http\Firewall\SwitchUserListener; @@ -17,7 +17,7 @@ use Symfony\Component\Security\Http\SecurityEvents; class SwitchUserListenerTest extends \PHPUnit_Framework_TestCase { - private $securityContext; + private $tokenStorage; private $userProvider; @@ -31,11 +31,12 @@ class SwitchUserListenerTest extends \PHPUnit_Framework_TestCase protected function setUp() { - $this->securityContext = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'); + $this->tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); $this->userProvider = $this->getMock('Symfony\Component\Security\Core\User\UserProviderInterface'); $this->userChecker = $this->getMock('Symfony\Component\Security\Core\User\UserCheckerInterface'); $this->accessDecisionManager = $this->getMock('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface'); $this->request = $this->getMock('Symfony\Component\HttpFoundation\Request'); + $this->request->query = $this->getMock('Symfony\Component\HttpFoundation\ParameterBag'); $this->request->server = $this->getMock('Symfony\Component\HttpFoundation\ServerBag'); $this->event = $this->getEvent($this->request); } @@ -46,7 +47,7 @@ class SwitchUserListenerTest extends \PHPUnit_Framework_TestCase */ public function testProviderKeyIsRequired() { - new SwitchUserListener($this->securityContext, $this->userProvider, $this->userChecker, '', $this->accessDecisionManager); + new SwitchUserListener($this->tokenStorage, $this->userProvider, $this->userChecker, '', $this->accessDecisionManager); } public function testEventIsIgnoredIfUsernameIsNotPassedWithTheRequest() @@ -54,9 +55,9 @@ class SwitchUserListenerTest extends \PHPUnit_Framework_TestCase $this->request->expects($this->any())->method('get')->with('_switch_user')->will($this->returnValue(null)); $this->event->expects($this->never())->method('setResponse'); - $this->securityContext->expects($this->never())->method('setToken'); + $this->tokenStorage->expects($this->never())->method('setToken'); - $listener = new SwitchUserListener($this->securityContext, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager); + $listener = new SwitchUserListener($this->tokenStorage, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager); $listener->handle($this->event); } @@ -67,10 +68,10 @@ class SwitchUserListenerTest extends \PHPUnit_Framework_TestCase { $token = $this->getToken(array($this->getMock('Symfony\Component\Security\Core\Role\RoleInterface'))); - $this->securityContext->expects($this->any())->method('getToken')->will($this->returnValue($token)); + $this->tokenStorage->expects($this->any())->method('getToken')->will($this->returnValue($token)); $this->request->expects($this->any())->method('get')->with('_switch_user')->will($this->returnValue('_exit')); - $listener = new SwitchUserListener($this->securityContext, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager); + $listener = new SwitchUserListener($this->tokenStorage, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager); $listener->handle($this->event); } @@ -82,20 +83,22 @@ class SwitchUserListenerTest extends \PHPUnit_Framework_TestCase ->getMock(); $role->expects($this->any())->method('getSource')->will($this->returnValue($originalToken)); - $this->securityContext->expects($this->any()) + $this->tokenStorage->expects($this->any()) ->method('getToken') ->will($this->returnValue($this->getToken(array($role)))); $this->request->expects($this->any())->method('get')->with('_switch_user')->will($this->returnValue('_exit')); $this->request->expects($this->any())->method('getUri')->will($this->returnValue('/')); + $this->request->query->expects($this->once())->method('remove', '_switch_user'); + $this->request->query->expects($this->any())->method('all')->will($this->returnValue(array())); $this->request->server->expects($this->once())->method('set')->with('QUERY_STRING', ''); - $this->securityContext->expects($this->once()) + $this->tokenStorage->expects($this->once()) ->method('setToken')->with($originalToken); $this->event->expects($this->once()) ->method('setResponse')->with($this->isInstanceOf('Symfony\Component\HttpFoundation\RedirectResponse')); - $listener = new SwitchUserListener($this->securityContext, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager); + $listener = new SwitchUserListener($this->tokenStorage, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager); $listener->handle($this->event); } @@ -120,7 +123,7 @@ class SwitchUserListenerTest extends \PHPUnit_Framework_TestCase ->getMock(); $role->expects($this->any())->method('getSource')->willReturn($originalToken); $this - ->securityContext + ->tokenStorage ->expects($this->any()) ->method('getToken') ->willReturn($this->getToken(array($role))); @@ -135,6 +138,12 @@ class SwitchUserListenerTest extends \PHPUnit_Framework_TestCase ->expects($this->any()) ->method('getUri') ->willReturn('/'); + $this + ->request + ->query + ->expects($this->any()) + ->method('all') + ->will($this->returnValue(array())); $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'); $dispatcher @@ -145,7 +154,7 @@ class SwitchUserListenerTest extends \PHPUnit_Framework_TestCase })) ; - $listener = new SwitchUserListener($this->securityContext, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager, null, '_switch_user', 'ROLE_ALLOWED_TO_SWITCH', $dispatcher); + $listener = new SwitchUserListener($this->tokenStorage, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager, null, '_switch_user', 'ROLE_ALLOWED_TO_SWITCH', $dispatcher); $listener->handle($this->event); } @@ -170,7 +179,7 @@ class SwitchUserListenerTest extends \PHPUnit_Framework_TestCase ->method('getSource') ->willReturn($originalToken); $this - ->securityContext + ->tokenStorage ->expects($this->any()) ->method('getToken') ->willReturn($this->getToken(array($role))); @@ -182,6 +191,12 @@ class SwitchUserListenerTest extends \PHPUnit_Framework_TestCase ->willReturn('_exit'); $this ->request + ->query + ->expects($this->any()) + ->method('all') + ->will($this->returnValue(array())); + $this + ->request ->expects($this->any()) ->method('getUri') ->willReturn('/'); @@ -192,25 +207,25 @@ class SwitchUserListenerTest extends \PHPUnit_Framework_TestCase ->method('dispatch') ; - $listener = new SwitchUserListener($this->securityContext, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager, null, '_switch_user', 'ROLE_ALLOWED_TO_SWITCH', $dispatcher); + $listener = new SwitchUserListener($this->tokenStorage, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager, null, '_switch_user', 'ROLE_ALLOWED_TO_SWITCH', $dispatcher); $listener->handle($this->event); } /** * @expectedException \Symfony\Component\Security\Core\Exception\AccessDeniedException */ - public function testSwitchUserIsDissallowed() + public function testSwitchUserIsDisallowed() { $token = $this->getToken(array($this->getMock('Symfony\Component\Security\Core\Role\RoleInterface'))); - $this->securityContext->expects($this->any())->method('getToken')->will($this->returnValue($token)); + $this->tokenStorage->expects($this->any())->method('getToken')->will($this->returnValue($token)); $this->request->expects($this->any())->method('get')->with('_switch_user')->will($this->returnValue('kuba')); $this->accessDecisionManager->expects($this->once()) ->method('decide')->with($token, array('ROLE_ALLOWED_TO_SWITCH')) ->will($this->returnValue(false)); - $listener = new SwitchUserListener($this->securityContext, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager); + $listener = new SwitchUserListener($this->tokenStorage, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager); $listener->handle($this->event); } @@ -220,8 +235,11 @@ class SwitchUserListenerTest extends \PHPUnit_Framework_TestCase $user = $this->getMock('Symfony\Component\Security\Core\User\UserInterface'); $user->expects($this->any())->method('getRoles')->will($this->returnValue(array())); - $this->securityContext->expects($this->any())->method('getToken')->will($this->returnValue($token)); + $this->tokenStorage->expects($this->any())->method('getToken')->will($this->returnValue($token)); $this->request->expects($this->any())->method('get')->with('_switch_user')->will($this->returnValue('kuba')); + $this->request->query->expects($this->once())->method('remove', '_switch_user'); + $this->request->query->expects($this->any())->method('all')->will($this->returnValue(array())); + $this->request->expects($this->any())->method('getUri')->will($this->returnValue('/')); $this->request->server->expects($this->once())->method('set')->with('QUERY_STRING', ''); @@ -234,10 +252,39 @@ class SwitchUserListenerTest extends \PHPUnit_Framework_TestCase ->will($this->returnValue($user)); $this->userChecker->expects($this->once()) ->method('checkPostAuth')->with($user); - $this->securityContext->expects($this->once()) + $this->tokenStorage->expects($this->once()) + ->method('setToken')->with($this->isInstanceOf('Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken')); + + $listener = new SwitchUserListener($this->tokenStorage, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager); + $listener->handle($this->event); + } + + public function testSwitchUserKeepsOtherQueryStringParameters() + { + $token = $this->getToken(array($this->getMock('Symfony\Component\Security\Core\Role\RoleInterface'))); + $user = $this->getMock('Symfony\Component\Security\Core\User\UserInterface'); + $user->expects($this->any())->method('getRoles')->will($this->returnValue(array())); + + $this->tokenStorage->expects($this->any())->method('getToken')->will($this->returnValue($token)); + $this->request->expects($this->any())->method('get')->with('_switch_user')->will($this->returnValue('kuba')); + $this->request->query->expects($this->once())->method('remove', '_switch_user'); + $this->request->query->expects($this->any())->method('all')->will($this->returnValue(array('page' => 3, 'section' => 2))); + $this->request->expects($this->any())->method('getUri')->will($this->returnValue('/')); + $this->request->server->expects($this->once())->method('set')->with('QUERY_STRING', 'page=3§ion=2'); + + $this->accessDecisionManager->expects($this->once()) + ->method('decide')->with($token, array('ROLE_ALLOWED_TO_SWITCH')) + ->will($this->returnValue(true)); + + $this->userProvider->expects($this->once()) + ->method('loadUserByUsername')->with('kuba') + ->will($this->returnValue($user)); + $this->userChecker->expects($this->once()) + ->method('checkPostAuth')->with($user); + $this->tokenStorage->expects($this->once()) ->method('setToken')->with($this->isInstanceOf('Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken')); - $listener = new SwitchUserListener($this->securityContext, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager); + $listener = new SwitchUserListener($this->tokenStorage, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager); $listener->handle($this->event); } diff --git a/Tests/Http/Firewall/X509AuthenticationListenerTest.php b/Http/Tests/Firewall/X509AuthenticationListenerTest.php index b28c0ac..66690d9 100644 --- a/Tests/Http/Firewall/X509AuthenticationListenerTest.php +++ b/Http/Tests/Firewall/X509AuthenticationListenerTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Http\Firewall; +namespace Symfony\Component\Security\Http\Tests\Firewall; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Security\Http\Firewall\X509AuthenticationListener; @@ -31,11 +31,11 @@ class X509AuthenticationListenerTest extends \PHPUnit_Framework_TestCase $request = new Request(array(), array(), array(), array(), array(), $serverVars); - $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'); + $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); $authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'); - $listener = new X509AuthenticationListener($context, $authenticationManager, 'TheProviderKey'); + $listener = new X509AuthenticationListener($tokenStorage, $authenticationManager, 'TheProviderKey'); $method = new \ReflectionMethod($listener, 'getPreAuthenticatedData'); $method->setAccessible(true); @@ -60,11 +60,11 @@ class X509AuthenticationListenerTest extends \PHPUnit_Framework_TestCase $credentials = 'CN=Sample certificate DN/emailAddress='.$emailAddress; $request = new Request(array(), array(), array(), array(), array(), array('SSL_CLIENT_S_DN' => $credentials)); - $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'); + $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); $authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'); - $listener = new X509AuthenticationListener($context, $authenticationManager, 'TheProviderKey'); + $listener = new X509AuthenticationListener($tokenStorage, $authenticationManager, 'TheProviderKey'); $method = new \ReflectionMethod($listener, 'getPreAuthenticatedData'); $method->setAccessible(true); @@ -88,11 +88,11 @@ class X509AuthenticationListenerTest extends \PHPUnit_Framework_TestCase { $request = new Request(array(), array(), array(), array(), array(), array()); - $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'); + $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); $authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'); - $listener = new X509AuthenticationListener($context, $authenticationManager, 'TheProviderKey'); + $listener = new X509AuthenticationListener($tokenStorage, $authenticationManager, 'TheProviderKey'); $method = new \ReflectionMethod($listener, 'getPreAuthenticatedData'); $method->setAccessible(true); @@ -108,11 +108,11 @@ class X509AuthenticationListenerTest extends \PHPUnit_Framework_TestCase 'TheUserKey' => 'TheUser', 'TheCredentialsKey' => 'TheCredentials', )); - $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'); + $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); $authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'); - $listener = new X509AuthenticationListener($context, $authenticationManager, 'TheProviderKey', 'TheUserKey', 'TheCredentialsKey'); + $listener = new X509AuthenticationListener($tokenStorage, $authenticationManager, 'TheProviderKey', 'TheUserKey', 'TheCredentialsKey'); $method = new \ReflectionMethod($listener, 'getPreAuthenticatedData'); $method->setAccessible(true); diff --git a/Tests/Http/FirewallMapTest.php b/Http/Tests/FirewallMapTest.php index 5d3a72a..85a57ab 100644 --- a/Tests/Http/FirewallMapTest.php +++ b/Http/Tests/FirewallMapTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Http; +namespace Symfony\Component\Security\Http\Tests; use Symfony\Component\Security\Http\FirewallMap; use Symfony\Component\HttpFoundation\Request; diff --git a/Tests/Http/FirewallTest.php b/Http/Tests/FirewallTest.php index 7fd2cda..9994737 100644 --- a/Tests/Http/FirewallTest.php +++ b/Http/Tests/FirewallTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Http; +namespace Symfony\Component\Security\Http\Tests; use Symfony\Component\Security\Http\Firewall; use Symfony\Component\HttpKernel\Event\GetResponseEvent; diff --git a/Tests/Http/HttpUtilsTest.php b/Http/Tests/HttpUtilsTest.php index 4a69242..45a0281 100644 --- a/Tests/Http/HttpUtilsTest.php +++ b/Http/Tests/HttpUtilsTest.php @@ -9,13 +9,13 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Http; +namespace Symfony\Component\Security\Http\Tests; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Exception\MethodNotAllowedException; use Symfony\Component\Routing\Exception\ResourceNotFoundException; +use Symfony\Component\Security\Core\Security; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; -use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\Security\Http\HttpUtils; class HttpUtilsTest extends \PHPUnit_Framework_TestCase @@ -127,9 +127,9 @@ class HttpUtilsTest extends \PHPUnit_Framework_TestCase public function provideSecurityContextAttributes() { return array( - array(SecurityContextInterface::AUTHENTICATION_ERROR), - array(SecurityContextInterface::ACCESS_DENIED_ERROR), - array(SecurityContextInterface::LAST_USERNAME), + array(Security::AUTHENTICATION_ERROR), + array(Security::ACCESS_DENIED_ERROR), + array(Security::LAST_USERNAME), ); } diff --git a/Tests/Http/Logout/CookieClearingLogoutHandlerTest.php b/Http/Tests/Logout/CookieClearingLogoutHandlerTest.php index c443d8d..8474504 100644 --- a/Tests/Http/Logout/CookieClearingLogoutHandlerTest.php +++ b/Http/Tests/Logout/CookieClearingLogoutHandlerTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Http\Logout; +namespace Symfony\Component\Security\Http\Tests\Logout; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\ResponseHeaderBag; diff --git a/Tests/Http/Logout/DefaultLogoutSuccessHandlerTest.php b/Http/Tests/Logout/DefaultLogoutSuccessHandlerTest.php index f18604d..381a48e 100644 --- a/Tests/Http/Logout/DefaultLogoutSuccessHandlerTest.php +++ b/Http/Tests/Logout/DefaultLogoutSuccessHandlerTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Http\Logout; +namespace Symfony\Component\Security\Http\Tests\Logout; use Symfony\Component\Security\Http\Logout\DefaultLogoutSuccessHandler; diff --git a/Tests/Http/Logout/SessionLogoutHandlerTest.php b/Http/Tests/Logout/SessionLogoutHandlerTest.php index f89a423..c342995 100644 --- a/Tests/Http/Logout/SessionLogoutHandlerTest.php +++ b/Http/Tests/Logout/SessionLogoutHandlerTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Http\Logout; +namespace Symfony\Component\Security\Http\Tests\Logout; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Security\Http\Logout\SessionLogoutHandler; diff --git a/Tests/Http/RememberMe/AbstractRememberMeServicesTest.php b/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php index c98b6b4..ddfaaeb 100644 --- a/Tests/Http/RememberMe/AbstractRememberMeServicesTest.php +++ b/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Http\RememberMe; +namespace Symfony\Component\Security\Http\Tests\RememberMe; use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface; use Symfony\Component\HttpFoundation\Request; @@ -266,7 +266,7 @@ class AbstractRememberMeServicesTest extends \PHPUnit_Framework_TestCase } /** - * @expectedException InvalidArgumentException + * @expectedException \InvalidArgumentException * @expectedExceptionMessage cookie delimiter */ public function testThereShouldBeNoCookieDelimiterInCookieParts() diff --git a/Tests/Http/RememberMe/PersistentTokenBasedRememberMeServicesTest.php b/Http/Tests/RememberMe/PersistentTokenBasedRememberMeServicesTest.php index 3ba8f99..f43963e 100644 --- a/Tests/Http/RememberMe/PersistentTokenBasedRememberMeServicesTest.php +++ b/Http/Tests/RememberMe/PersistentTokenBasedRememberMeServicesTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Http\RememberMe; +namespace Symfony\Component\Security\Http\Tests\RememberMe; use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface; use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; diff --git a/Tests/Http/RememberMe/ResponseListenerTest.php b/Http/Tests/RememberMe/ResponseListenerTest.php index bca2c43..78de8e4 100644 --- a/Tests/Http/RememberMe/ResponseListenerTest.php +++ b/Http/Tests/RememberMe/ResponseListenerTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Http\RememberMe; +namespace Symfony\Component\Security\Http\Tests\RememberMe; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\Security\Http\RememberMe\ResponseListener; @@ -94,7 +94,7 @@ class ResponseListenerTest extends \PHPUnit_Framework_TestCase ->getMock(); $event->expects($this->any())->method('getRequest')->will($this->returnValue($request)); - $event->expects($this->any())->method('getRequestType')->will($this->returnValue($type)); + $event->expects($this->any())->method('isMasterRequest')->will($this->returnValue($type === HttpKernelInterface::MASTER_REQUEST)); $event->expects($this->any())->method('getResponse')->will($this->returnValue($response)); return $event; diff --git a/Tests/Http/RememberMe/TokenBasedRememberMeServicesTest.php b/Http/Tests/RememberMe/TokenBasedRememberMeServicesTest.php index d1ec9b2..e3b58e9 100644 --- a/Tests/Http/RememberMe/TokenBasedRememberMeServicesTest.php +++ b/Http/Tests/RememberMe/TokenBasedRememberMeServicesTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Http\RememberMe; +namespace Symfony\Component\Security\Http\Tests\RememberMe; use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface; use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; diff --git a/Tests/Http/Session/SessionAuthenticationStrategyTest.php b/Http/Tests/Session/SessionAuthenticationStrategyTest.php index 7296afd..4aef4b2 100644 --- a/Tests/Http/Session/SessionAuthenticationStrategyTest.php +++ b/Http/Tests/Session/SessionAuthenticationStrategyTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Http\Session; +namespace Symfony\Component\Security\Http\Tests\Session; use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategy; diff --git a/Http/composer.json b/Http/composer.json new file mode 100644 index 0000000..1b36428 --- /dev/null +++ b/Http/composer.json @@ -0,0 +1,46 @@ +{ + "name": "symfony/security-http", + "type": "library", + "description": "Symfony Security Component - HTTP Integration", + "keywords": [], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=5.3.9", + "symfony/security-core": "~2.6", + "symfony/event-dispatcher": "~2.1", + "symfony/http-foundation": "~2.4", + "symfony/http-kernel": "~2.4" + }, + "require-dev": { + "symfony/routing": "~2.2", + "symfony/security-csrf": "~2.4", + "psr/log": "~1.0" + }, + "suggest": { + "symfony/security-csrf": "For using tokens to protect authentication/logout attempts", + "symfony/routing": "For using the HttpUtils class to create sub-requests, redirect the user, and match URLs" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\Security\\Http\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + } +} diff --git a/Http/phpunit.xml.dist b/Http/phpunit.xml.dist new file mode 100644 index 0000000..8d636e9 --- /dev/null +++ b/Http/phpunit.xml.dist @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<phpunit backupGlobals="false" + backupStaticAttributes="false" + colors="true" + convertErrorsToExceptions="true" + convertNoticesToExceptions="true" + convertWarningsToExceptions="true" + processIsolation="false" + stopOnFailure="false" + syntaxCheck="false" + bootstrap="vendor/autoload.php" +> + <php> + <ini name="error_reporting" value="-1" /> + </php> + + <testsuites> + <testsuite name="Symfony Security Component HTTP Test Suite"> + <directory>./Tests/</directory> + </testsuite> + </testsuites> + + <filter> + <whitelist> + <directory>./</directory> + <exclude> + <directory>./Tests</directory> + <directory>./vendor</directory> + </exclude> + </whitelist> + </filter> +</phpunit> diff --git a/Tests/Core/SecurityContextTest.php b/Tests/Core/SecurityContextTest.php deleted file mode 100644 index 3fba8d9..0000000 --- a/Tests/Core/SecurityContextTest.php +++ /dev/null @@ -1,97 +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\Tests\Core; - -use Symfony\Component\Security\Core\SecurityContext; - -class SecurityContextTest extends \PHPUnit_Framework_TestCase -{ - public function testVoteAuthenticatesTokenIfNecessary() - { - $authManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'); - $decisionManager = $this->getMock('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface'); - - $context = new SecurityContext($authManager, $decisionManager); - $context->setToken($token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')); - - $authManager - ->expects($this->once()) - ->method('authenticate') - ->with($this->equalTo($token)) - ->will($this->returnValue($newToken = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'))) - ; - - $decisionManager - ->expects($this->once()) - ->method('decide') - ->will($this->returnValue(true)) - ; - - $this->assertTrue($context->isGranted('foo')); - $this->assertSame($newToken, $context->getToken()); - } - - /** - * @expectedException \Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException - */ - public function testVoteWithoutAuthenticationToken() - { - $context = new SecurityContext( - $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'), - $this->getMock('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface') - ); - - $context->isGranted('ROLE_FOO'); - } - - public function testIsGranted() - { - $manager = $this->getMock('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface'); - $manager->expects($this->once())->method('decide')->will($this->returnValue(false)); - $context = new SecurityContext($this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'), $manager); - $context->setToken($token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')); - $token - ->expects($this->once()) - ->method('isAuthenticated') - ->will($this->returnValue(true)) - ; - $this->assertFalse($context->isGranted('ROLE_FOO')); - - $manager = $this->getMock('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface'); - $manager->expects($this->once())->method('decide')->will($this->returnValue(true)); - $context = new SecurityContext($this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'), $manager); - $context->setToken($token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')); - $token - ->expects($this->once()) - ->method('isAuthenticated') - ->will($this->returnValue(true)) - ; - $this->assertTrue($context->isGranted('ROLE_FOO')); - } - - public function testGetSetToken() - { - $context = new SecurityContext( - $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'), - $this->getMock('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface') - ); - $this->assertNull($context->getToken()); - - $context->setToken($token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')); - $this->assertSame($token, $context->getToken()); - } - - public function testTranslationsAreNotInCore() - { - $this->assertFileNotExists(__DIR__.'/../../Core/Resources/translations/'); - } -} diff --git a/Tests/Core/Validator/Constraints/UserPasswordValidatorTest.php b/Tests/Core/Validator/Constraints/UserPasswordValidatorTest.php deleted file mode 100644 index 4c420c7..0000000 --- a/Tests/Core/Validator/Constraints/UserPasswordValidatorTest.php +++ /dev/null @@ -1,157 +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\Tests\Core\Validator\Constraints; - -use Symfony\Component\Security\Core\Validator\Constraints\UserPassword; -use Symfony\Component\Security\Core\Validator\Constraints\UserPasswordValidator; - -class UserPasswordValidatorTest extends \PHPUnit_Framework_TestCase -{ - const PASSWORD_VALID = true; - const PASSWORD_INVALID = false; - - protected $context; - - protected function setUp() - { - $this->context = $this->getMock('Symfony\Component\Validator\ExecutionContext', array(), array(), '', false); - } - - protected function tearDown() - { - $this->context = null; - } - - public function testPasswordIsValid() - { - $user = $this->createUser(); - $securityContext = $this->createSecurityContext($user); - - $encoder = $this->createPasswordEncoder(static::PASSWORD_VALID); - $encoderFactory = $this->createEncoderFactory($encoder); - - $validator = new UserPasswordValidator($securityContext, $encoderFactory); - $validator->initialize($this->context); - - $this - ->context - ->expects($this->never()) - ->method('addViolation') - ; - - $validator->validate('secret', new UserPassword()); - } - - public function testPasswordIsNotValid() - { - $user = $this->createUser(); - $securityContext = $this->createSecurityContext($user); - - $encoder = $this->createPasswordEncoder(static::PASSWORD_INVALID); - $encoderFactory = $this->createEncoderFactory($encoder); - - $validator = new UserPasswordValidator($securityContext, $encoderFactory); - $validator->initialize($this->context); - - $this - ->context - ->expects($this->once()) - ->method('addViolation') - ; - - $validator->validate('secret', new UserPassword()); - } - - public function testUserIsNotValid() - { - $this->setExpectedException('Symfony\Component\Validator\Exception\ConstraintDefinitionException'); - - $user = $this->getMock('Foo\Bar\User'); - $encoderFactory = $this->getMock('Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface'); - $securityContext = $this->createSecurityContext($user); - - $validator = new UserPasswordValidator($securityContext, $encoderFactory); - $validator->initialize($this->context); - $validator->validate('secret', new UserPassword()); - } - - protected function createUser() - { - $mock = $this->getMock('Symfony\Component\Security\Core\User\UserInterface'); - - $mock - ->expects($this->once()) - ->method('getPassword') - ->will($this->returnValue('s3Cr3t')) - ; - - $mock - ->expects($this->once()) - ->method('getSalt') - ->will($this->returnValue('^S4lt$')) - ; - - return $mock; - } - - protected function createPasswordEncoder($isPasswordValid = true) - { - $mock = $this->getMock('Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface'); - - $mock - ->expects($this->once()) - ->method('isPasswordValid') - ->will($this->returnValue($isPasswordValid)) - ; - - return $mock; - } - - protected function createEncoderFactory($encoder = null) - { - $mock = $this->getMock('Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface'); - - $mock - ->expects($this->once()) - ->method('getEncoder') - ->will($this->returnValue($encoder)) - ; - - return $mock; - } - - protected function createSecurityContext($user = null) - { - $token = $this->createAuthenticationToken($user); - - $mock = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'); - $mock - ->expects($this->once()) - ->method('getToken') - ->will($this->returnValue($token)) - ; - - return $mock; - } - - protected function createAuthenticationToken($user = null) - { - $mock = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); - $mock - ->expects($this->once()) - ->method('getUser') - ->will($this->returnValue($user)) - ; - - return $mock; - } -} diff --git a/Tests/Http/Firewall/AnonymousAuthenticationListenerTest.php b/Tests/Http/Firewall/AnonymousAuthenticationListenerTest.php deleted file mode 100644 index 0666ef3..0000000 --- a/Tests/Http/Firewall/AnonymousAuthenticationListenerTest.php +++ /dev/null @@ -1,68 +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\Tests\Http\Firewall; - -use Symfony\Component\Security\Http\Firewall\AnonymousAuthenticationListener; - -class AnonymousAuthenticationListenerTest extends \PHPUnit_Framework_TestCase -{ - public function testHandleWithContextHavingAToken() - { - $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'); - $context - ->expects($this->any()) - ->method('getToken') - ->will($this->returnValue($this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'))) - ; - $context - ->expects($this->never()) - ->method('setToken') - ; - - $listener = new AnonymousAuthenticationListener($context, 'TheKey'); - $listener->handle($this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false)); - } - - public function testHandleWithContextHavingNoToken() - { - $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'); - $context - ->expects($this->any()) - ->method('getToken') - ->will($this->returnValue(null)) - ; - $context - ->expects($this->once()) - ->method('setToken') - ->with(self::logicalAnd( - $this->isInstanceOf('Symfony\Component\Security\Core\Authentication\Token\AnonymousToken'), - $this->attributeEqualTo('key', 'TheKey') - )) - ; - - $listener = new AnonymousAuthenticationListener($context, 'TheKey'); - $listener->handle($this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false)); - } - - public function testHandledEventIsLogged() - { - $context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'); - $logger = $this->getMock('Psr\Log\LoggerInterface'); - $logger->expects($this->once()) - ->method('info') - ->with('Populated SecurityContext with an anonymous Token') - ; - - $listener = new AnonymousAuthenticationListener($context, 'TheKey', $logger); - $listener->handle($this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false)); - } -} diff --git a/Tests/Http/Firewall/RememberMeListenerTest.php b/Tests/Http/Firewall/RememberMeListenerTest.php deleted file mode 100644 index 8316a8c..0000000 --- a/Tests/Http/Firewall/RememberMeListenerTest.php +++ /dev/null @@ -1,247 +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\Tests\Http\Firewall; - -use Symfony\Component\Security\Core\Exception\AuthenticationException; -use Symfony\Component\Security\Http\Firewall\RememberMeListener; -use Symfony\Component\HttpFoundation\Request; - -class RememberMeListenerTest extends \PHPUnit_Framework_TestCase -{ - public function testOnCoreSecurityDoesNotTryToPopulateNonEmptySecurityContext() - { - list($listener, $context, $service) = $this->getListener(); - - $context - ->expects($this->once()) - ->method('getToken') - ->will($this->returnValue($this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'))) - ; - - $context - ->expects($this->never()) - ->method('setToken') - ; - - $this->assertNull($listener->handle($this->getGetResponseEvent())); - } - - public function testOnCoreSecurityDoesNothingWhenNoCookieIsSet() - { - list($listener, $context, $service) = $this->getListener(); - - $context - ->expects($this->once()) - ->method('getToken') - ->will($this->returnValue(null)) - ; - - $service - ->expects($this->once()) - ->method('autoLogin') - ->will($this->returnValue(null)) - ; - - $event = $this->getGetResponseEvent(); - $event - ->expects($this->once()) - ->method('getRequest') - ->will($this->returnValue(new Request())) - ; - - $this->assertNull($listener->handle($event)); - } - - public function testOnCoreSecurityIgnoresAuthenticationExceptionThrownByAuthenticationManagerImplementation() - { - list($listener, $context, $service, $manager) = $this->getListener(); - - $context - ->expects($this->once()) - ->method('getToken') - ->will($this->returnValue(null)) - ; - - $service - ->expects($this->once()) - ->method('autoLogin') - ->will($this->returnValue($this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'))) - ; - - $service - ->expects($this->once()) - ->method('loginFail') - ; - - $exception = new AuthenticationException('Authentication failed.'); - $manager - ->expects($this->once()) - ->method('authenticate') - ->will($this->throwException($exception)) - ; - - $event = $this->getGetResponseEvent(); - $event - ->expects($this->once()) - ->method('getRequest') - ->will($this->returnValue(new Request())) - ; - - $listener->handle($event); - } - - public function testOnCoreSecurity() - { - list($listener, $context, $service, $manager) = $this->getListener(); - - $context - ->expects($this->once()) - ->method('getToken') - ->will($this->returnValue(null)) - ; - - $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); - $service - ->expects($this->once()) - ->method('autoLogin') - ->will($this->returnValue($token)) - ; - - $context - ->expects($this->once()) - ->method('setToken') - ->with($this->equalTo($token)) - ; - - $manager - ->expects($this->once()) - ->method('authenticate') - ->will($this->returnValue($token)) - ; - - $event = $this->getGetResponseEvent(); - $event - ->expects($this->once()) - ->method('getRequest') - ->will($this->returnValue(new Request())) - ; - - $listener->handle($event); - } - - public function testSessionStrategy() - { - list($listener, $tokenStorage, $service, $manager) = $this->getListener(); - - $tokenStorage - ->expects($this->once()) - ->method('getToken') - ->will($this->returnValue(null)) - ; - - $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'); - $service - ->expects($this->once()) - ->method('autoLogin') - ->will($this->returnValue($token)) - ; - - $tokenStorage - ->expects($this->once()) - ->method('setToken') - ->with($this->equalTo($token)) - ; - - $manager - ->expects($this->once()) - ->method('authenticate') - ->will($this->returnValue($token)) - ; - - $session = $this->getMock('\Symfony\Component\HttpFoundation\Session\SessionInterface'); - $session - ->expects($this->once()) - ->method('isStarted') - ->will($this->returnValue(true)) - ; - $session - ->expects($this->once()) - ->method('migrate') - ; - - $request = $this->getMock('\Symfony\Component\HttpFoundation\Request'); - $request - ->expects($this->any()) - ->method('hasSession') - ->will($this->returnValue(true)) - ; - - $request - ->expects($this->any()) - ->method('getSession') - ->will($this->returnValue($session)) - ; - - $event = $this->getGetResponseEvent(); - $event - ->expects($this->once()) - ->method('getRequest') - ->will($this->returnValue($request)) - ; - - $listener->handle($event); - } - - protected function getGetResponseEvent() - { - return $this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false); - } - - protected function getFilterResponseEvent() - { - return $this->getMock('Symfony\Component\HttpKernel\Event\FilterResponseEvent', array(), array(), '', false); - } - - protected function getListener() - { - $listener = new RememberMeListener( - $context = $this->getContext(), - $service = $this->getService(), - $manager = $this->getManager(), - $logger = $this->getLogger() - ); - - return array($listener, $context, $service, $manager, $logger); - } - - protected function getLogger() - { - return $this->getMock('Psr\Log\LoggerInterface'); - } - - protected function getManager() - { - return $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'); - } - - protected function getService() - { - return $this->getMock('Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface'); - } - - protected function getContext() - { - return $this->getMockBuilder('Symfony\Component\Security\Core\SecurityContext') - ->disableOriginalConstructor() - ->getMock(); - } -} diff --git a/Tests/TranslationSyncStatusTest.php b/Tests/TranslationSyncStatusTest.php new file mode 100644 index 0000000..4b72d41 --- /dev/null +++ b/Tests/TranslationSyncStatusTest.php @@ -0,0 +1,63 @@ +<?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\Tests; + +use Symfony\Component\Finder\Finder; + +class TranslationSyncStatusTest extends \PHPUnit_Framework_TestCase +{ + /** + * @dataProvider getTranslationDirectoriesData + */ + public function testTranslationFileIsNotMissingInCore($dir1, $dir2) + { + $finder = new Finder(); + $files = $finder->in($dir1)->files(); + + foreach ($files as $file) { + $this->assertFileExists($dir2.'/'.$file->getFilename(), 'Missing file '.$file->getFilename().' in directory '.$dir2); + } + } + + public function getTranslationDirectoriesData() + { + $legacyTranslationsDir = $this->getLegacyTranslationsDirectory(); + $coreTranslationsDir = $this->getCoreTranslationsDirectory(); + + return array( + 'file-not-missing-in-core' => array($legacyTranslationsDir, $coreTranslationsDir), + 'file-not-added-in-core' => array($coreTranslationsDir, $legacyTranslationsDir), + ); + } + + public function testFileContentsAreEqual() + { + $finder = new Finder(); + $files = $finder->in($this->getLegacyTranslationsDirectory())->files(); + + foreach ($files as $file) { + $coreFile = $this->getCoreTranslationsDirectory().'/'.$file->getFilename(); + + $this->assertFileEquals($file->getRealPath(), $coreFile, $file.' and '.$coreFile.' have equal content.'); + } + } + + private function getLegacyTranslationsDirectory() + { + return __DIR__.'/../Resources/translations'; + } + + private function getCoreTranslationsDirectory() + { + return __DIR__.'/../Core/Resources/translations'; + } +} diff --git a/composer.json b/composer.json index 4f265fe..b64e1b8 100644 --- a/composer.json +++ b/composer.json @@ -16,47 +16,49 @@ } ], "require": { - "php": ">=5.3.3", + "php": ">=5.3.9", "paragonie/random_compat": "~1.0", "symfony/event-dispatcher": "~2.2", "symfony/http-foundation": "~2.1", - "symfony/http-kernel": "~2.1" + "symfony/http-kernel": "~2.4" + }, + "replace": { + "symfony/security-acl": "self.version", + "symfony/security-core": "self.version", + "symfony/security-csrf": "self.version", + "symfony/security-http": "self.version" }, "require-dev": { - "symfony/form": "~2.0,>=2.0.5", + "symfony/finder": "~2.3", "symfony/intl": "~2.3", "symfony/routing": "~2.2", - "symfony/validator": "~2.2", + "symfony/validator": "~2.5,>=2.5.9", "doctrine/common": "~2.2", "doctrine/dbal": "~2.2", "psr/log": "~1.0", - "ircmaxell/password-compat": "~1.0" - }, - "replace": { - "symfony/security-acl": "self.version", - "symfony/security-core": "self.version", - "symfony/security-http": "self.version" + "ircmaxell/password-compat": "~1.0", + "symfony/expression-language": "~2.6" }, "suggest": { - "symfony/class-loader": "", - "symfony/finder": "", + "symfony/class-loader": "For using the ACL generateSql script", + "symfony/finder": "For using the ACL generateSql script", "symfony/form": "", - "symfony/validator": "", - "symfony/routing": "", - "doctrine/dbal": "to use the built-in ACL implementation", - "ircmaxell/password-compat": "" + "symfony/validator": "For using the user password constraint", + "symfony/routing": "For using the HttpUtils class to create sub-requests, redirect the user, and match URLs", + "doctrine/dbal": "For using the built-in ACL implementation", + "symfony/expression-language": "For using the expression voter", + "ircmaxell/password-compat": "For using the BCrypt password encoder in PHP <5.5" }, "autoload": { - "psr-0": { "Symfony\\Component\\Security\\": "" }, + "psr-4": { "Symfony\\Component\\Security\\": "" }, "exclude-from-classmap": [ "/Tests/" ] }, - "target-dir": "Symfony/Component/Security", "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "2.3-dev" + "dev-master": "2.7-dev" } } } diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 9d3cf4a..6b56bf2 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -13,6 +13,7 @@ <testsuites> <testsuite name="Symfony Security Component Test Suite"> <directory>./Tests/</directory> + <directory>./*/Tests/</directory> </testsuite> </testsuites> @@ -20,10 +21,12 @@ <whitelist> <directory>./</directory> <exclude> - <directory>./Acl/Resources</directory> <directory>./Resources</directory> <directory>./Tests</directory> <directory>./vendor</directory> + <directory>./*/Resources</directory> + <directory>./*/Tests</directory> + <directory>./*/vendor</directory> </exclude> </whitelist> </filter> |