diff options
189 files changed, 5627 insertions, 474 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 b53dc75..705b4ff 100644 --- a/Acl/Dbal/AclProvider.php +++ b/Acl/Dbal/AclProvider.php @@ -176,13 +176,13 @@ class AclProvider implements AclProviderInterface if ((self::MAX_BATCH_SIZE === count($currentBatch) || ($i + 1) === $c) && count($currentBatch) > 0) { try { $loadedBatch = $this->lookupObjectIdentities($currentBatch, $sids, $oidLookup); - } catch (AclNotFoundException $aclNotFoundexception) { + } catch (AclNotFoundException $aclNotFoundException) { if ($result->count()) { $partialResultException = new NotAllAclsFoundException('The provider could not find ACLs for all object identities.'); $partialResultException->setPartialResult($result); throw $partialResultException; } else { - throw $aclNotFoundexception; + throw $aclNotFoundException; } } foreach ($loadedBatch as $loadedOid) { @@ -205,7 +205,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.'); @@ -295,7 +296,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( @@ -338,17 +340,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; } @@ -377,8 +379,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()) ); } @@ -434,8 +436,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; @@ -541,7 +543,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 f1b8aff..1a5ea0a 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()) @@ -253,7 +267,7 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf } // check properties for deleted, and created ACEs, and perform deletions - // we need to perfom deletions before updating existing ACEs, in order to + // we need to perform deletions before updating existing ACEs, in order to // preserve uniqueness of the order field if (isset($propertyChanges['classAces'])) { $this->updateOldAceProperty('classAces', $propertyChanges['classAces']); @@ -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 0366ccf..328f754 100644 --- a/Acl/Domain/Acl.php +++ b/Acl/Domain/Acl.php @@ -37,14 +37,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. @@ -62,12 +62,6 @@ class Acl implements AuditableAclInterface, NotifyPropertyChanged $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/LICENSE b/Acl/LICENSE new file mode 100644 index 0000000..43028bc --- /dev/null +++ b/Acl/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2004-2015 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/MaskBuilder.php b/Acl/Permission/MaskBuilder.php index 39fe4e7..5364c9b 100644 --- a/Acl/Permission/MaskBuilder.php +++ b/Acl/Permission/MaskBuilder.php @@ -96,13 +96,7 @@ class MaskBuilder */ 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; + $this->mask |= $this->getMask($mask); return $this; } @@ -152,13 +146,7 @@ class MaskBuilder */ 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; + $this->mask &= ~$this->getMask($mask); return $this; } @@ -193,19 +181,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 + */ + private function getMask($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/README.md b/Acl/README.md new file mode 100644 index 0000000..6c009a3 --- /dev/null +++ b/Acl/README.md @@ -0,0 +1,23 @@ +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: + +http://symfony.com/doc/2.5/book/security.html + +Tests +----- + +You can run the unit tests with the following command: + + $ cd path/to/Symfony/Component/Security/Acl/ + $ composer.phar install --dev + $ phpunit diff --git a/Tests/Acl/Dbal/AclProviderBenchmarkTest.php b/Acl/Tests/Dbal/AclProviderBenchmarkTest.php index c25a697..dab90d4 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 d701e22..717a258 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 faa9261..5ec23d3 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; @@ -410,6 +410,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 93c87c1..128f2c8 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 55c8f0a..6a2aac0 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 9281fd5..4eab7b2 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; @@ -26,10 +26,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() @@ -54,14 +54,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()); } /** @@ -101,9 +101,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 4935bff..c7675ea 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 57f9d1b..c4c0b4e 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/composer.json b/Acl/composer.json new file mode 100644 index 0000000..5f5787f --- /dev/null +++ b/Acl/composer.json @@ -0,0 +1,42 @@ +{ + "name": "symfony/security-acl", + "type": "library", + "description": "Symfony Security Component - ACL (Access Control List)", + "keywords": [], + "homepage": "http://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "require": { + "php": ">=5.3.3", + "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-0": { "Symfony\\Component\\Security\\Acl\\": "" } + }, + "target-dir": "Symfony/Component/Security/Acl", + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "2.5-dev" + } + } +} diff --git a/Acl/phpunit.xml.dist b/Acl/phpunit.xml.dist new file mode 100644 index 0000000..50d0448 --- /dev/null +++ b/Acl/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> + <!-- Silence E_USER_DEPRECATED (-16385 == -1 & ~E_USER_DEPRECATED) --> + <ini name="error_reporting" value="-16385"/> + </php> + <testsuites> + <testsuite name="Symfony Security Component ACL Test Suite"> + <directory>./Tests/</directory> + </testsuite> + </testsuites> + + <filter> + <whitelist> + <directory>./</directory> + <exclude> + <directory>./vendor</directory> + <directory>./Tests</directory> + </exclude> + </whitelist> + </filter> +</phpunit> diff --git a/CHANGELOG.md b/CHANGELOG.md index 92f8073..9ab61d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,16 @@ CHANGELOG ========= +2.4.0 +----- + + * 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/Provider/PreAuthenticatedAuthenticationProvider.php b/Core/Authentication/Provider/PreAuthenticatedAuthenticationProvider.php index a73c244..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); - $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/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 c239f8c..c6bf09f 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/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/ExpressionLanguage.php b/Core/Authorization/ExpressionLanguage.php new file mode 100644 index 0000000..f9012b7 --- /dev/null +++ b/Core/Authorization/ExpressionLanguage.php @@ -0,0 +1,57 @@ +<?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; + +/** + * Adds some function to the default ExpressionLanguage. + * + * @author Fabien Potencier <fabien@symfony.com> + */ +class ExpressionLanguage extends BaseExpressionLanguage +{ + protected function registerFunctions() + { + parent::registerFunctions(); + + $this->register('is_anonymous', function () { + return '$trust_resolver->isAnonymous($token)'; + }, function (array $variables) { + return $variables['trust_resolver']->isAnonymous($variables['token']); + }); + + $this->register('is_authenticated', function () { + return '$token && !$trust_resolver->isAnonymous($token)'; + }, function (array $variables) { + return $variables['token'] && !$variables['trust_resolver']->isAnonymous($variables['token']); + }); + + $this->register('is_fully_authenticated', function () { + return '$trust_resolver->isFullFledged($token)'; + }, function (array $variables) { + return $variables['trust_resolver']->isFullFledged($variables['token']); + }); + + $this->register('is_remember_me', function () { + return '$trust_resolver->isRememberMe($token)'; + }, function (array $variables) { + return $variables['trust_resolver']->isRememberMe($variables['token']); + }); + + $this->register('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/ExpressionVoter.php b/Core/Authorization/Voter/ExpressionVoter.php new file mode 100644 index 0000000..3263803 --- /dev/null +++ b/Core/Authorization/Voter/ExpressionVoter.php @@ -0,0 +1,112 @@ +<?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\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; + } + + /** + * {@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/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/LICENSE b/Core/LICENSE new file mode 100644 index 0000000..43028bc --- /dev/null +++ b/Core/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2004-2015 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..4585a5d --- /dev/null +++ b/Core/README.md @@ -0,0 +1,23 @@ +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: + +http://symfony.com/doc/2.5/book/security.html + +Tests +----- + +You can run the unit tests with the following command: + + $ cd path/to/Symfony/Component/Security/Core/ + $ composer.phar install --dev + $ phpunit 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.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..9c7b886 --- /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="no" 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..f3965d3 --- /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 droits 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>Droits 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>Pas de privilèges 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>Pas de 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 ne peut pas ê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 droits ont expirés.</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.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.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.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.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..3857ab4 --- /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="no" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>An authentication exception occurred.</source> + <target>En autentiserings feil 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 kilde.</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..846fd49 --- /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á esta 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 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 esta 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 esta 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..e661000 --- /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 um 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á esta 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 esta 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.tr.xlf b/Core/Resources/translations/security.tr.xlf new file mode 100644 index 0000000..fbf9b26 --- /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>Yetkilendirme girdileri 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 girdiler.</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ı gerçekleşti.</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>Bilet 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>Girdiler zaman aşımına uğradı.</target> + </trans-unit> + <trans-unit id="15"> + <source>Account is disabled.</source> + <target>Hesap devre dışı bırakılmış.</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/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/Tests/Core/Authentication/AuthenticationProviderManagerTest.php b/Core/Tests/Authentication/AuthenticationProviderManagerTest.php index 32e6cf7..df25874 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; @@ -129,7 +129,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 b8be628..6f2b6ed 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 cef3d28..691f54c 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/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 74e790a..ae5894d 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/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/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 61e2afe..2f7b845 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; 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 85d4e91..a8ca2f0 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', '')); } @@ -102,3 +156,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/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/SecurityContextTest.php b/Core/Tests/SecurityContextTest.php index 124ebf9..dd0e2e3 100644 --- a/Tests/Core/SecurityContextTest.php +++ b/Core/Tests/SecurityContextTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Security\Tests\Core; +namespace Symfony\Component\Security\Core\Tests; use Symfony\Component\Security\Core\SecurityContext; 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 826e390..dfc4237 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 d05f491..2fe6daa 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; 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/SecureRandomTest.php b/Core/Tests/Util/SecureRandomTest.php index bd9fec5..6e12ef2 100644 --- a/Tests/Core/Util/SecureRandomTest.php +++ b/Core/Tests/Util/SecureRandomTest.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\SecureRandom; 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/LegacyUserPasswordValidator2Dot4ApiTest.php b/Core/Tests/Validator/Constraints/LegacyUserPasswordValidator2Dot4ApiTest.php new file mode 100644 index 0000000..4cba363 --- /dev/null +++ b/Core/Tests/Validator/Constraints/LegacyUserPasswordValidator2Dot4ApiTest.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\Validator\Constraints; + +use Symfony\Component\Validator\Validation; + +/** + * @since 2.5.4 + * @author Bernhard Schussek <bschussek@gmail.com> + */ +class LegacyUserPasswordValidator2Dot4ApiTest extends UserPasswordValidatorTest +{ + protected function getApiVersion() + { + return Validation::API_VERSION_2_4; + } +} diff --git a/Core/Tests/Validator/Constraints/LegacyUserPasswordValidatorTest.php b/Core/Tests/Validator/Constraints/LegacyUserPasswordValidatorTest.php new file mode 100644 index 0000000..5cfe444 --- /dev/null +++ b/Core/Tests/Validator/Constraints/LegacyUserPasswordValidatorTest.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\Validator\Constraints; + +use Symfony\Component\Validator\Validation; + +/** + * @since 2.5.4 + * @author Bernhard Schussek <bschussek@gmail.com> + */ +class LegacyUserPasswordValidatorApiTest 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..7792913 --- /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\Encoder\EncoderFactoryInterface; +use Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface; +use Symfony\Component\Security\Core\SecurityContextInterface; +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 SecurityContextInterface + */ + protected $securityContext; + + /** + * @var PasswordEncoderInterface + */ + protected $encoder; + + /** + * @var EncoderFactoryInterface + */ + protected $encoderFactory; + + protected function createValidator() + { + return new UserPasswordValidator($this->securityContext, $this->encoderFactory); + } + + protected function setUp() + { + $user = $this->createUser(); + $this->securityContext = $this->createSecurityContext($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->securityContext = $this->createSecurityContext($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 createSecurityContext($user = null) + { + $token = $this->createAuthenticationToken($user); + + $mock = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface'); + $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/Validator/Constraints/UserPasswordValidator.php b/Core/Validator/Constraints/UserPasswordValidator.php index ab455f3..5f9ad2a 100644 --- a/Core/Validator/Constraints/UserPasswordValidator.php +++ b/Core/Validator/Constraints/UserPasswordValidator.php @@ -17,6 +17,7 @@ use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface; 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 { @@ -34,6 +35,10 @@ class UserPasswordValidator extends ConstraintValidator */ public function validate($password, Constraint $constraint) { + if (!$constraint instanceof UserPassword) { + throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\UserPassword'); + } + $user = $this->securityContext->getToken()->getUser(); if (!$user instanceof UserInterface) { diff --git a/Core/composer.json b/Core/composer.json new file mode 100644 index 0000000..16288c8 --- /dev/null +++ b/Core/composer.json @@ -0,0 +1,47 @@ +{ + "name": "symfony/security-core", + "type": "library", + "description": "Symfony Security Component - Core Library", + "keywords": [], + "homepage": "http://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "symfony/event-dispatcher": "~2.1", + "symfony/expression-language": "~2.4", + "symfony/http-foundation": "~2.4", + "symfony/translation": "~2.0,>=2.0.5", + "symfony/validator": "~2.5,>=2.5.5", + "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-0": { "Symfony\\Component\\Security\\Core\\": "" } + }, + "target-dir": "Symfony/Component/Security/Core", + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "2.5-dev" + } + } +} diff --git a/Core/phpunit.xml.dist b/Core/phpunit.xml.dist new file mode 100644 index 0000000..7bdf5cb --- /dev/null +++ b/Core/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> + <!-- Silence E_USER_DEPRECATED (-16385 == -1 & ~E_USER_DEPRECATED) --> + <ini name="error_reporting" value="-16385"/> + </php> + <testsuites> + <testsuite name="Symfony Security Component Core Test Suite"> + <directory>./Tests/</directory> + </testsuite> + </testsuites> + + <filter> + <whitelist> + <directory>./</directory> + <exclude> + <directory>./vendor</directory> + <directory>./Tests</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..5abe47c --- /dev/null +++ b/Csrf/CsrfTokenManagerInterface.php @@ -0,0 +1,68 @@ +<?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..43028bc --- /dev/null +++ b/Csrf/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2004-2015 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..95a1062 --- /dev/null +++ b/Csrf/README.md @@ -0,0 +1,21 @@ +Security Component - CSRF +========================= + +The Security CSRF (cross-site request forgery) component provides a class +`CsrfTokenManager` for generating and validating CSRF tokens. + +Resources +--------- + +Documentation: + +http://symfony.com/doc/2.5/book/security.html + +Tests +----- + +You can run the unit tests with the following command: + + $ cd path/to/Symfony/Component/Security/Csrf/ + $ composer.phar install --dev + $ phpunit 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..4fb0c99 --- /dev/null +++ b/Csrf/Tests/TokenGenerator/UriSafeTokenGeneratorTest.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\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..0039deb --- /dev/null +++ b/Csrf/Tests/TokenStorage/NativeSessionTokenStorageTest.php @@ -0,0 +1,127 @@ +<?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); + } + + public function testStoreTokenInClosedSessionWithExistingSessionId() + { + if (PHP_VERSION_ID < 50400) { + $this->markTestSkipped('This test requires PHP 5.4 or later.'); + } + + 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..4166c1e --- /dev/null +++ b/Csrf/Tests/TokenStorage/SessionTokenStorageTest.php @@ -0,0 +1,262 @@ +<?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() + { + if (!interface_exists('Symfony\Component\HttpFoundation\Session\SessionInterface')) { + $this->markTestSkipped('The "HttpFoundation" component is not available'); + } + + $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..e02ac66 --- /dev/null +++ b/Csrf/TokenGenerator/TokenGeneratorInterface.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\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..122bc02 --- /dev/null +++ b/Csrf/TokenGenerator/UriSafeTokenGenerator.php @@ -0,0 +1,65 @@ +<?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..60145c6 --- /dev/null +++ b/Csrf/TokenStorage/NativeSessionTokenStorage.php @@ -0,0 +1,121 @@ +<?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..f08eb96 --- /dev/null +++ b/Csrf/TokenStorage/SessionTokenStorage.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\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..0fadfa3 --- /dev/null +++ b/Csrf/TokenStorage/TokenStorageInterface.php @@ -0,0 +1,59 @@ +<?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..398a2d3 --- /dev/null +++ b/Csrf/composer.json @@ -0,0 +1,38 @@ +{ + "name": "symfony/security-csrf", + "type": "library", + "description": "Symfony Security Component - CSRF Library", + "keywords": [], + "homepage": "http://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "require": { + "php": ">=5.3.3", + "symfony/security-core": "~2.4" + }, + "require-dev": { + "symfony/http-foundation": "~2.1" + }, + "suggest": { + "symfony/http-foundation": "For using the class SessionTokenStorage." + }, + "autoload": { + "psr-0": { "Symfony\\Component\\Security\\Csrf\\": "" } + }, + "target-dir": "Symfony/Component/Security/Csrf", + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "2.5-dev" + } + } +} diff --git a/Csrf/phpunit.xml.dist b/Csrf/phpunit.xml.dist new file mode 100644 index 0000000..0606071 --- /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> + <!-- Silence E_USER_DEPRECATED (-16385 == -1 & ~E_USER_DEPRECATED) --> + <ini name="error_reporting" value="-16385"/> + </php> + <testsuites> + <testsuite name="Symfony Security Component CSRF Test Suite"> + <directory>./Tests/</directory> + </testsuite> + </testsuites> + + <filter> + <whitelist> + <directory>./</directory> + <exclude> + <directory>./vendor</directory> + <directory>./Tests</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/SimpleAuthenticationHandler.php b/Http/Authentication/SimpleAuthenticationHandler.php new file mode 100644 index 0000000..09a55ef --- /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(sprintf('Using the %s object as authentication success 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(sprintf('Using the %s object as authentication failure 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/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..f1be39e 100644 --- a/Http/Firewall/AbstractAuthenticationListener.php +++ b/Http/Firewall/AbstractAuthenticationListener.php @@ -149,14 +149,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,7 +189,7 @@ 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())); @@ -209,7 +209,7 @@ 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())); diff --git a/Http/Firewall/ContextListener.php b/Http/Firewall/ContextListener.php index 3ea6512..1c97df6 100644 --- a/Http/Firewall/ContextListener.php +++ b/Http/Firewall/ContextListener.php @@ -11,7 +11,6 @@ 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; @@ -66,7 +65,7 @@ class ContextListener implements ListenerInterface */ 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; } @@ -106,7 +105,7 @@ class ContextListener implements ListenerInterface */ public function onKernelResponse(FilterResponseEvent $event) { - if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) { + if (!$event->isMasterRequest()) { return; } diff --git a/Http/Firewall/DigestAuthenticationListener.php b/Http/Firewall/DigestAuthenticationListener.php index ea85e77..a5e0222 100644 --- a/Http/Firewall/DigestAuthenticationListener.php +++ b/Http/Firewall/DigestAuthenticationListener.php @@ -139,7 +139,7 @@ class DigestAuthenticationListener implements ListenerInterface class DigestData { - private $elements; + private $elements = array(); private $header; private $nonceExpiryTime; @@ -147,7 +147,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 fac5dc1..8f54f8d 100644 --- a/Http/Firewall/ExceptionListener.php +++ b/Http/Firewall/ExceptionListener.php @@ -70,16 +70,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) { diff --git a/Http/Firewall/LogoutListener.php b/Http/Firewall/LogoutListener.php index 5a68670..3a45e37 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\Exception\InvalidArgumentException; use Symfony\Component\Security\Core\SecurityContextInterface; 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; @@ -33,19 +37,25 @@ class LogoutListener implements ListenerInterface 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 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(SecurityContextInterface $securityContext, HttpUtils $httpUtils, LogoutSuccessHandlerInterface $successHandler, array $options = array(), $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->securityContext = $securityContext; $this->httpUtils = $httpUtils; $this->options = array_merge(array( @@ -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.'); } } diff --git a/Http/Firewall/SimpleFormAuthenticationListener.php b/Http/Firewall/SimpleFormAuthenticationListener.php new file mode 100644 index 0000000..5b905df --- /dev/null +++ b/Http/Firewall/SimpleFormAuthenticationListener.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\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\SecurityContextInterface; +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 SecurityContextInterface $securityContext A SecurityContext 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(SecurityContextInterface $securityContext, 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($securityContext, $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); + } + + $request->getSession()->set(SecurityContextInterface::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..e80cc98 --- /dev/null +++ b/Http/Firewall/SimplePreAuthenticationListener.php @@ -0,0 +1,115 @@ +<?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\SecurityContextInterface; +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\Exception\AuthenticationException; +use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface; +use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface; + +/** + * SimplePreAuthenticationListener implements simple proxying to an authenticator. + * + * @author Jordi Boggiano <j.boggiano@seld.be> + */ +class SimplePreAuthenticationListener implements ListenerInterface +{ + private $securityContext; + private $authenticationManager; + private $providerKey; + private $simpleAuthenticator; + private $logger; + + /** + * Constructor. + * + * @param SecurityContextInterface $securityContext A SecurityContext instance + * @param AuthenticationManagerInterface $authenticationManager An AuthenticationManagerInterface instance + * @param string $providerKey + * @param SimplePreAuthenticatorInterface $simpleAuthenticator A SimplePreAuthenticatorInterface instance + * @param LoggerInterface $logger A LoggerInterface instance + */ + public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, $providerKey, SimplePreAuthenticatorInterface $simpleAuthenticator, LoggerInterface $logger = null) + { + if (empty($providerKey)) { + throw new \InvalidArgumentException('$providerKey must not be empty.'); + } + + $this->securityContext = $securityContext; + $this->authenticationManager = $authenticationManager; + $this->providerKey = $providerKey; + $this->simpleAuthenticator = $simpleAuthenticator; + $this->logger = $logger; + } + + /** + * Handles basic authentication. + * + * @param GetResponseEvent $event A GetResponseEvent instance + */ + public function handle(GetResponseEvent $event) + { + $request = $event->getRequest(); + + if (null !== $this->logger) { + $this->logger->info(sprintf('Attempting simple pre-authorization %s', $this->providerKey)); + } + + if (null !== $this->securityContext->getToken() && !$this->securityContext->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->securityContext->setToken($token); + } catch (AuthenticationException $e) { + $this->securityContext->setToken(null); + + if (null !== $this->logger) { + $this->logger->info(sprintf('Authentication request failed: %s', $e->getMessage())); + } + + 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 7700096..b46b1bc 100644 --- a/Http/Firewall/SwitchUserListener.php +++ b/Http/Firewall/SwitchUserListener.php @@ -92,7 +92,9 @@ class SwitchUserListener implements ListenerInterface } } - $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); diff --git a/Http/Firewall/UsernamePasswordFormAuthenticationListener.php b/Http/Firewall/UsernamePasswordFormAuthenticationListener.php index 2147817..36ff758 100644 --- a/Http/Firewall/UsernamePasswordFormAuthenticationListener.php +++ b/Http/Firewall/UsernamePasswordFormAuthenticationListener.php @@ -11,15 +11,19 @@ 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\UsernamePasswordToken; +use Symfony\Component\Security\Core\Exception\InvalidArgumentException; use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException; use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; @@ -32,13 +36,19 @@ 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(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, $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.'); + } + parent::__construct($securityContext, $authenticationManager, $sessionStrategy, $httpUtils, $providerKey, $successHandler, $failureHandler, array_merge(array( 'username_parameter' => '_username', 'password_parameter' => '_password', @@ -47,7 +57,7 @@ class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationL 'post_only' => true, ), $options), $logger, $dispatcher); - $this->csrfProvider = $csrfProvider; + $this->csrfTokenManager = $csrfTokenManager; } /** @@ -67,10 +77,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.'); } } diff --git a/Http/HttpUtils.php b/Http/HttpUtils.php index 0f47809..a447a44 100644 --- a/Http/HttpUtils.php +++ b/Http/HttpUtils.php @@ -71,7 +71,7 @@ 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()); } diff --git a/Http/LICENSE b/Http/LICENSE new file mode 100644 index 0000000..43028bc --- /dev/null +++ b/Http/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2004-2015 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/README.md b/Http/README.md new file mode 100644 index 0000000..c0760d4 --- /dev/null +++ b/Http/README.md @@ -0,0 +1,23 @@ +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: + +http://symfony.com/doc/2.5/book/security.html + +Tests +----- + +You can run the unit tests with the following command: + + $ cd path/to/Symfony/Component/Security/Http/ + $ composer.phar install --dev + $ phpunit 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 8283a7c..9042963 100644 --- a/Http/RememberMe/TokenBasedRememberMeServices.php +++ b/Http/RememberMe/TokenBasedRememberMeServices.php @@ -17,6 +17,7 @@ use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\User\UserInterface; +use Symfony\Component\Security\Core\Util\StringUtils; /** * Concrete implementation of the RememberMeServicesInterface providing @@ -53,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 (true !== $this->compareHashes($hash, $this->generateCookieHash($class, $username, $expires, $user->getPassword()))) { + if (true !== StringUtils::equals($hash, $this->generateCookieHash($class, $username, $expires, $user->getPassword()))) { throw new AuthenticationException('The cookie\'s hash is invalid.'); } @@ -65,31 +66,6 @@ class TokenBasedRememberMeServices extends AbstractRememberMeServices } /** - * Compares two hashes using a constant-time algorithm to avoid (remote) - * timing attacks. - * - * This is the same implementation as used in the BasePasswordEncoder. - * - * @param string $hash1 The first hash - * @param string $hash2 The second hash - * - * @return bool true if the two hashes are the same, false otherwise - */ - private function compareHashes($hash1, $hash2) - { - if (strlen($hash1) !== $c = strlen($hash2)) { - return false; - } - - $result = 0; - for ($i = 0; $i < $c; $i++) { - $result |= ord($hash1[$i]) ^ ord($hash2[$i]); - } - - return 0 === $result; - } - - /** * {@inheritdoc} */ protected function onLoginSuccess(Request $request, Response $response, TokenInterface $token) @@ -147,6 +123,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/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 accc45d..15adcdf 100644 --- a/Tests/Http/Authentication/DefaultAuthenticationFailureHandlerTest.php +++ b/Http/Tests/Authentication/DefaultAuthenticationFailureHandlerTest.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\DefaultAuthenticationFailureHandler; use Symfony\Component\Security\Core\SecurityContextInterface; 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..97167c9 --- /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; + + public 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..6e34532 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; diff --git a/Tests/Http/Firewall/AccessListenerTest.php b/Http/Tests/Firewall/AccessListenerTest.php index 961c792..f9b0f3c 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; diff --git a/Tests/Http/Firewall/AnonymousAuthenticationListenerTest.php b/Http/Tests/Firewall/AnonymousAuthenticationListenerTest.php index 0666ef3..7b24e61 100644 --- a/Tests/Http/Firewall/AnonymousAuthenticationListenerTest.php +++ b/Http/Tests/Firewall/AnonymousAuthenticationListenerTest.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\AnonymousAuthenticationListener; diff --git a/Tests/Http/Firewall/BasicAuthenticationListenerTest.php b/Http/Tests/Firewall/BasicAuthenticationListenerTest.php index 65dc185..0ef993f 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; 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 f44c60a..d6bc5b4 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; @@ -189,8 +189,8 @@ class ContextListenerTest extends \PHPUnit_Framework_TestCase $listener = new ContextListener($context, 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'))); 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 b1c7622..f1409e4 100644 --- a/Tests/Http/Firewall/ExceptionListenerTest.php +++ b/Http/Tests/Firewall/ExceptionListenerTest.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; @@ -166,12 +166,7 @@ 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) diff --git a/Tests/Http/Firewall/LogoutListenerTest.php b/Http/Tests/Firewall/LogoutListenerTest.php index 9301086..041febc 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; @@ -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, $context, $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()) @@ -151,30 +150,29 @@ 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, $context, $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() @@ -209,7 +207,7 @@ 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(), @@ -221,7 +219,7 @@ class LogoutListenerTest extends \PHPUnit_Framework_TestCase 'logout_path' => '/logout', 'target_url' => '/', ), - $csrfProvider + $tokenManager ); return array($listener, $context, $httpUtils, $options); diff --git a/Tests/Http/Firewall/RememberMeListenerTest.php b/Http/Tests/Firewall/RememberMeListenerTest.php index 3624f11..99d7fcc 100644 --- a/Tests/Http/Firewall/RememberMeListenerTest.php +++ b/Http/Tests/Firewall/RememberMeListenerTest.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\Core\Exception\AuthenticationException; use Symfony\Component\Security\Http\Firewall\RememberMeListener; diff --git a/Tests/Http/Firewall/SwitchUserListenerTest.php b/Http/Tests/Firewall/SwitchUserListenerTest.php index e86ee83..9fb4e50 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\Firewall\SwitchUserListener; @@ -34,6 +34,7 @@ class SwitchUserListenerTest extends \PHPUnit_Framework_TestCase $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); } @@ -51,7 +52,7 @@ 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('setResopnse'); + $this->event->expects($this->never())->method('setResponse'); $this->securityContext->expects($this->never())->method('setToken'); $listener = new SwitchUserListener($this->securityContext, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager); @@ -86,6 +87,8 @@ class SwitchUserListenerTest extends \PHPUnit_Framework_TestCase $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()) @@ -100,7 +103,7 @@ class SwitchUserListenerTest extends \PHPUnit_Framework_TestCase /** * @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'))); @@ -123,6 +126,9 @@ class SwitchUserListenerTest extends \PHPUnit_Framework_TestCase $this->securityContext->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', ''); @@ -142,6 +148,35 @@ class SwitchUserListenerTest extends \PHPUnit_Framework_TestCase $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->securityContext->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->securityContext->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->handle($this->event); + } + private function getEvent($request) { $event = $this->getMockBuilder('Symfony\Component\HttpKernel\Event\GetResponseEvent') diff --git a/Tests/Http/Firewall/X509AuthenticationListenerTest.php b/Http/Tests/Firewall/X509AuthenticationListenerTest.php index b28c0ac..7f2da3e 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; 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 019af19..5cac504 100644 --- a/Tests/Http/HttpUtilsTest.php +++ b/Http/Tests/HttpUtilsTest.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\HttpFoundation\Request; use Symfony\Component\Routing\Exception\MethodNotAllowedException; 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 0f64730..c3d9260 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; diff --git a/Tests/Http/RememberMe/PersistentTokenBasedRememberMeServicesTest.php b/Http/Tests/RememberMe/PersistentTokenBasedRememberMeServicesTest.php index 19f6984..6aee1b1 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 7947753..8c215e2 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..c544ad1 --- /dev/null +++ b/Http/composer.json @@ -0,0 +1,44 @@ +{ + "name": "symfony/security-http", + "type": "library", + "description": "Symfony Security Component - HTTP Integration", + "keywords": [], + "homepage": "http://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "require": { + "php": ">=5.3.3", + "symfony/security-core": "~2.4", + "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-0": { "Symfony\\Component\\Security\\Http\\": "" } + }, + "target-dir": "Symfony/Component/Security/Http", + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "2.5-dev" + } + } +} diff --git a/Http/phpunit.xml.dist b/Http/phpunit.xml.dist new file mode 100644 index 0000000..a152839 --- /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> + <!-- Silence E_USER_DEPRECATED (-16385 == -1 & ~E_USER_DEPRECATED) --> + <ini name="error_reporting" value="-16385"/> + </php> + <testsuites> + <testsuite name="Symfony Security Component HTTP Test Suite"> + <directory>./Tests/</directory> + </testsuite> + </testsuites> + + <filter> + <whitelist> + <directory>./</directory> + <exclude> + <directory>./vendor</directory> + <directory>./Tests</directory> + </exclude> + </whitelist> + </filter> +</phpunit> @@ -11,10 +11,10 @@ Resources Documentation: -http://symfony.com/doc/2.3/book/security.html +http://symfony.com/doc/2.5/book/security.html -Resources ---------- +Tests +----- You can run the unit tests with the following command: 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/composer.json b/composer.json index 15919a4..bd323fa 100644 --- a/composer.json +++ b/composer.json @@ -19,26 +19,33 @@ "php": ">=5.3.3", "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/intl": "~2.3", "symfony/routing": "~2.2", - "symfony/validator": "~2.2", + "symfony/translation": "~2.0,>=2.0.5", + "symfony/validator": "~2.5,>=2.5.5", "doctrine/common": "~2.2", "doctrine/dbal": "~2.2", "psr/log": "~1.0", - "ircmaxell/password-compat": "~1.0" + "ircmaxell/password-compat": "~1.0", + "symfony/expression-language": "~2.4" }, "suggest": { - "symfony/class-loader": "", - "symfony/finder": "", - "symfony/form": "", - "symfony/validator": "", - "symfony/routing": "", - "doctrine/dbal": "to use the built-in ACL implementation", - "ircmaxell/password-compat": "" + "symfony/class-loader": "For using the ACL generateSql script", + "symfony/finder": "For using the ACL generateSql script", + "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\\": "" } @@ -47,7 +54,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "2.3-dev" + "dev-master": "2.5-dev" } } } diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 1f1ff85..f11fabe 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -12,7 +12,9 @@ </php> <testsuites> <testsuite name="Symfony Security Component Test Suite"> - <directory>./Tests/</directory> + <directory>./Acl/Tests/</directory> + <directory>./Core/Tests/</directory> + <directory>./Http/Tests/</directory> </testsuite> </testsuites> @@ -21,7 +23,9 @@ <directory>./</directory> <exclude> <directory>./vendor</directory> - <directory>./Tests</directory> + <directory>./Acl/Tests</directory> + <directory>./Core/Tests</directory> + <directory>./Http/Tests</directory> </exclude> </whitelist> </filter> |