summaryrefslogtreecommitdiffstats
path: root/Core
diff options
context:
space:
mode:
Diffstat (limited to 'Core')
-rw-r--r--Core/Authentication/AuthenticationProviderManager.php6
-rw-r--r--Core/Authentication/Provider/DaoAuthenticationProvider.php5
-rw-r--r--Core/Authentication/Provider/UserAuthenticationProvider.php3
-rw-r--r--Core/Authentication/RememberMe/PersistentToken.php2
-rw-r--r--Core/Authentication/Token/AbstractToken.php4
-rw-r--r--Core/Authentication/Token/AnonymousToken.php10
-rw-r--r--Core/Authentication/Token/RememberMeToken.php2
-rw-r--r--Core/Authentication/Token/TokenInterface.php4
-rw-r--r--Core/Authentication/Token/UsernamePasswordToken.php18
-rw-r--r--Core/Authorization/AccessDecisionManager.php2
-rw-r--r--Core/Encoder/BCryptPasswordEncoder.php148
-rw-r--r--Core/Encoder/BasePasswordEncoder.php15
-rw-r--r--Core/Encoder/EncoderFactory.php2
-rw-r--r--Core/Encoder/Pbkdf2PasswordEncoder.php97
-rw-r--r--Core/Exception/AccountExpiredException.php8
-rw-r--r--Core/Exception/AccountStatusException.php45
-rw-r--r--Core/Exception/AuthenticationCredentialsNotFoundException.php8
-rw-r--r--Core/Exception/AuthenticationException.php54
-rw-r--r--Core/Exception/AuthenticationServiceException.php8
-rw-r--r--Core/Exception/BadCredentialsException.php8
-rw-r--r--Core/Exception/CookieTheftException.php8
-rw-r--r--Core/Exception/CredentialsExpiredException.php8
-rw-r--r--Core/Exception/DisabledException.php8
-rw-r--r--Core/Exception/InsufficientAuthenticationException.php8
-rw-r--r--Core/Exception/InvalidCsrfTokenException.php8
-rw-r--r--Core/Exception/LockedException.php8
-rw-r--r--Core/Exception/NonceExpiredException.php8
-rw-r--r--Core/Exception/ProviderNotFoundException.php8
-rw-r--r--Core/Exception/SessionUnavailableException.php8
-rw-r--r--Core/Exception/TokenNotFoundException.php11
-rw-r--r--Core/Exception/UsernameNotFoundException.php51
-rw-r--r--Core/Role/RoleHierarchyInterface.php4
-rw-r--r--Core/Role/RoleInterface.php2
-rw-r--r--Core/User/ChainUserProvider.php8
-rw-r--r--Core/User/InMemoryUserProvider.php7
-rw-r--r--Core/User/UserChecker.php16
-rw-r--r--Core/Util/ClassUtils.php5
-rw-r--r--Core/Util/SecureRandom.php114
-rw-r--r--Core/Util/SecureRandomInterface.php29
-rw-r--r--Core/Util/StringUtils.php60
-rw-r--r--Core/Validator/Constraint/UserPassword.php14
-rw-r--r--Core/Validator/Constraint/UserPasswordValidator.php31
-rw-r--r--Core/Validator/Constraints/UserPassword.php28
-rw-r--r--Core/Validator/Constraints/UserPasswordValidator.php46
44 files changed, 864 insertions, 83 deletions
diff --git a/Core/Authentication/AuthenticationProviderManager.php b/Core/Authentication/AuthenticationProviderManager.php
index 7ca46c0..8b7474b 100644
--- a/Core/Authentication/AuthenticationProviderManager.php
+++ b/Core/Authentication/AuthenticationProviderManager.php
@@ -39,6 +39,8 @@ class AuthenticationProviderManager implements AuthenticationManagerInterface
*
* @param AuthenticationProviderInterface[] $providers An array of AuthenticationProviderInterface instances
* @param Boolean $eraseCredentials Whether to erase credentials after authentication or not
+ *
+ * @throws \InvalidArgumentException
*/
public function __construct(array $providers, $eraseCredentials = true)
{
@@ -75,7 +77,7 @@ class AuthenticationProviderManager implements AuthenticationManagerInterface
break;
}
} catch (AccountStatusException $e) {
- $e->setExtraInformation($token);
+ $e->setToken($token);
throw $e;
} catch (AuthenticationException $e) {
@@ -103,7 +105,7 @@ class AuthenticationProviderManager implements AuthenticationManagerInterface
$this->eventDispatcher->dispatch(AuthenticationEvents::AUTHENTICATION_FAILURE, new AuthenticationFailureEvent($token, $lastException));
}
- $lastException->setExtraInformation($token);
+ $lastException->setToken($token);
throw $lastException;
}
diff --git a/Core/Authentication/Provider/DaoAuthenticationProvider.php b/Core/Authentication/Provider/DaoAuthenticationProvider.php
index f22045f..a9a2205 100644
--- a/Core/Authentication/Provider/DaoAuthenticationProvider.php
+++ b/Core/Authentication/Provider/DaoAuthenticationProvider.php
@@ -88,9 +88,12 @@ class DaoAuthenticationProvider extends UserAuthenticationProvider
return $user;
} catch (UsernameNotFoundException $notFound) {
+ $notFound->setUsername($username);
throw $notFound;
} catch (\Exception $repositoryProblem) {
- throw new AuthenticationServiceException($repositoryProblem->getMessage(), $token, 0, $repositoryProblem);
+ $ex = new AuthenticationServiceException($repositoryProblem->getMessage(), 0, $repositoryProblem);
+ $ex->setToken($token);
+ throw $ex;
}
}
}
diff --git a/Core/Authentication/Provider/UserAuthenticationProvider.php b/Core/Authentication/Provider/UserAuthenticationProvider.php
index 32d7971..626f50b 100644
--- a/Core/Authentication/Provider/UserAuthenticationProvider.php
+++ b/Core/Authentication/Provider/UserAuthenticationProvider.php
@@ -37,6 +37,8 @@ abstract class UserAuthenticationProvider implements AuthenticationProviderInter
* @param UserCheckerInterface $userChecker An UserCheckerInterface interface
* @param string $providerKey A provider key
* @param Boolean $hideUserNotFoundExceptions Whether to hide user not found exception or not
+ *
+ * @throws \InvalidArgumentException
*/
public function __construct(UserCheckerInterface $userChecker, $providerKey, $hideUserNotFoundExceptions = true)
{
@@ -69,6 +71,7 @@ abstract class UserAuthenticationProvider implements AuthenticationProviderInter
if ($this->hideUserNotFoundExceptions) {
throw new BadCredentialsException('Bad credentials', 0, $notFound);
}
+ $notFound->setUsername($username);
throw $notFound;
}
diff --git a/Core/Authentication/RememberMe/PersistentToken.php b/Core/Authentication/RememberMe/PersistentToken.php
index 88b0413..f3f6858 100644
--- a/Core/Authentication/RememberMe/PersistentToken.php
+++ b/Core/Authentication/RememberMe/PersistentToken.php
@@ -32,6 +32,8 @@ final class PersistentToken implements PersistentTokenInterface
* @param string $series
* @param string $tokenValue
* @param \DateTime $lastUsed
+ *
+ * @throws \InvalidArgumentException
*/
public function __construct($class, $username, $series, $tokenValue, \DateTime $lastUsed)
{
diff --git a/Core/Authentication/Token/AbstractToken.php b/Core/Authentication/Token/AbstractToken.php
index ed6e8de..f21aa76 100644
--- a/Core/Authentication/Token/AbstractToken.php
+++ b/Core/Authentication/Token/AbstractToken.php
@@ -33,7 +33,9 @@ abstract class AbstractToken implements TokenInterface
/**
* Constructor.
*
- * @param Role[] $roles An array of roles
+ * @param RoleInterface[] $roles An array of roles
+ *
+ * @throws \InvalidArgumentException
*/
public function __construct(array $roles = array())
{
diff --git a/Core/Authentication/Token/AnonymousToken.php b/Core/Authentication/Token/AnonymousToken.php
index ecdd4cc..9b0a084 100644
--- a/Core/Authentication/Token/AnonymousToken.php
+++ b/Core/Authentication/Token/AnonymousToken.php
@@ -24,9 +24,9 @@ class AnonymousToken extends AbstractToken
/**
* Constructor.
*
- * @param string $key The key shared with the authentication provider
- * @param string $user The user
- * @param Role[] $roles An array of roles
+ * @param string $key The key shared with the authentication provider
+ * @param string $user The user
+ * @param RoleInterface[] $roles An array of roles
*/
public function __construct($key, $user, array $roles = array())
{
@@ -66,9 +66,9 @@ class AnonymousToken extends AbstractToken
/**
* {@inheritDoc}
*/
- public function unserialize($str)
+ public function unserialize($serialized)
{
- list($this->key, $parentStr) = unserialize($str);
+ list($this->key, $parentStr) = unserialize($serialized);
parent::unserialize($parentStr);
}
}
diff --git a/Core/Authentication/Token/RememberMeToken.php b/Core/Authentication/Token/RememberMeToken.php
index de50e5c..6f3d821 100644
--- a/Core/Authentication/Token/RememberMeToken.php
+++ b/Core/Authentication/Token/RememberMeToken.php
@@ -29,6 +29,8 @@ class RememberMeToken extends AbstractToken
* @param UserInterface $user
* @param string $providerKey
* @param string $key
+ *
+ * @throws \InvalidArgumentException
*/
public function __construct(UserInterface $user, $providerKey, $key)
{
diff --git a/Core/Authentication/Token/TokenInterface.php b/Core/Authentication/Token/TokenInterface.php
index dec31d5..11f69da 100644
--- a/Core/Authentication/Token/TokenInterface.php
+++ b/Core/Authentication/Token/TokenInterface.php
@@ -11,6 +11,8 @@
namespace Symfony\Component\Security\Core\Authentication\Token;
+use Symfony\Component\Security\Core\Role\RoleInterface;
+
/**
* TokenInterface is the interface for the user authentication information.
*
@@ -31,7 +33,7 @@ interface TokenInterface extends \Serializable
/**
* Returns the user roles.
*
- * @return Role[] An array of Role instances.
+ * @return RoleInterface[] An array of RoleInterface instances.
*/
public function getRoles();
diff --git a/Core/Authentication/Token/UsernamePasswordToken.php b/Core/Authentication/Token/UsernamePasswordToken.php
index 95eec54..d6e3998 100644
--- a/Core/Authentication/Token/UsernamePasswordToken.php
+++ b/Core/Authentication/Token/UsernamePasswordToken.php
@@ -24,10 +24,10 @@ class UsernamePasswordToken extends AbstractToken
/**
* Constructor.
*
- * @param string $user The username (like a nickname, email address, etc.), or a UserInterface instance or an object implementing a __toString method.
- * @param string $credentials This usually is the password of the user
- * @param string $providerKey The provider key
- * @param array $roles An array of roles
+ * @param string $user The username (like a nickname, email address, etc.), or a UserInterface instance or an object implementing a __toString method.
+ * @param string $credentials This usually is the password of the user
+ * @param string $providerKey The provider key
+ * @param RoleInterface[] $roles An array of roles
*
* @throws \InvalidArgumentException
*/
@@ -78,14 +78,20 @@ class UsernamePasswordToken extends AbstractToken
$this->credentials = null;
}
+ /**
+ * {@inheritdoc}
+ */
public function serialize()
{
return serialize(array($this->credentials, $this->providerKey, parent::serialize()));
}
- public function unserialize($str)
+ /**
+ * {@inheritdoc}
+ */
+ public function unserialize($serialized)
{
- list($this->credentials, $this->providerKey, $parentStr) = unserialize($str);
+ list($this->credentials, $this->providerKey, $parentStr) = unserialize($serialized);
parent::unserialize($parentStr);
}
}
diff --git a/Core/Authorization/AccessDecisionManager.php b/Core/Authorization/AccessDecisionManager.php
index a8bb5cf..6028c42 100644
--- a/Core/Authorization/AccessDecisionManager.php
+++ b/Core/Authorization/AccessDecisionManager.php
@@ -34,6 +34,8 @@ class AccessDecisionManager implements AccessDecisionManagerInterface
* @param string $strategy The vote strategy
* @param Boolean $allowIfAllAbstainDecisions Whether to grant access if all voters abstained or not
* @param Boolean $allowIfEqualGrantedDeniedDecisions Whether to grant access if result are equals
+ *
+ * @throws \InvalidArgumentException
*/
public function __construct(array $voters, $strategy = 'affirmative', $allowIfAllAbstainDecisions = false, $allowIfEqualGrantedDeniedDecisions = true)
{
diff --git a/Core/Encoder/BCryptPasswordEncoder.php b/Core/Encoder/BCryptPasswordEncoder.php
new file mode 100644
index 0000000..1b7572d
--- /dev/null
+++ b/Core/Encoder/BCryptPasswordEncoder.php
@@ -0,0 +1,148 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Core\Encoder;
+
+use Symfony\Component\Security\Core\Encoder\BasePasswordEncoder;
+use Symfony\Component\Security\Core\Util\SecureRandomInterface;
+
+/**
+ * @author Elnur Abdurrakhimov <elnur@elnur.pro>
+ * @author Terje BrĂ¥ten <terje@braten.be>
+ */
+class BCryptPasswordEncoder extends BasePasswordEncoder
+{
+ /**
+ * @var SecureRandomInterface
+ */
+ private $secureRandom;
+
+ /**
+ * @var string
+ */
+ private $cost;
+
+ private static $prefix = null;
+
+ /**
+ * Constructor.
+ *
+ * @param SecureRandomInterface $secureRandom A SecureRandomInterface instance
+ * @param integer $cost The algorithmic cost that should be used
+ *
+ * @throws \InvalidArgumentException if cost is out of range
+ */
+ public function __construct(SecureRandomInterface $secureRandom, $cost)
+ {
+ $this->secureRandom = $secureRandom;
+
+ $cost = (int) $cost;
+ if ($cost < 4 || $cost > 31) {
+ throw new \InvalidArgumentException('Cost must be in the range of 4-31.');
+ }
+ $this->cost = sprintf('%02d', $cost);
+
+ if (!self::$prefix) {
+ self::$prefix = '$'.(version_compare(phpversion(), '5.3.7', '>=') ? '2y' : '2a').'$';
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function encodePassword($raw, $salt)
+ {
+ if (function_exists('password_hash')) {
+ return password_hash($raw, PASSWORD_BCRYPT, array('cost' => $this->cost));
+ }
+
+ $salt = self::$prefix.$this->cost.'$'.$this->encodeSalt($this->getRawSalt());
+ $encoded = crypt($raw, $salt);
+ if (!is_string($encoded) || strlen($encoded) <= 13) {
+ return false;
+ }
+
+ return $encoded;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isPasswordValid($encoded, $raw, $salt)
+ {
+ if (function_exists('password_verify')) {
+ return password_verify($raw, $encoded);
+ }
+
+ $crypted = crypt($raw, $encoded);
+ if (strlen($crypted) <= 13) {
+ return false;
+ }
+
+ return $this->comparePasswords($encoded, $crypted);
+ }
+
+ /**
+ * Encodes the salt to be used by Bcrypt.
+ *
+ * The blowfish/bcrypt algorithm used by PHP crypt expects a different
+ * set and order of characters than the usual base64_encode function.
+ * Regular b64: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
+ * Bcrypt b64: ./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ * We care because the last character in our encoded string will
+ * only represent 2 bits. While two known implementations of
+ * bcrypt will happily accept and correct a salt string which
+ * has the 4 unused bits set to non-zero, we do not want to take
+ * chances and we also do not want to waste an additional byte
+ * of entropy.
+ *
+ * @param bytes $random a string of 16 random bytes
+ *
+ * @return string Properly encoded salt to use with php crypt function
+ *
+ * @throws \InvalidArgumentException if string of random bytes is too short
+ */
+ protected function encodeSalt($random)
+ {
+ $len = strlen($random);
+ if ($len < 16) {
+ throw new \InvalidArgumentException('The bcrypt salt needs 16 random bytes.');
+ }
+ if ($len > 16) {
+ $random = substr($random, 0, 16);
+ }
+
+ $base64raw = str_replace('+', '.', base64_encode($random));
+ $salt128bit = substr($base64raw, 0, 21);
+ $lastchar = substr($base64raw, 21, 1);
+ $lastchar = strtr($lastchar, 'AQgw', '.Oeu');
+ $salt128bit .= $lastchar;
+
+ return $salt128bit;
+ }
+
+ /**
+ * @return bytes 16 random bytes to be used in the salt
+ */
+ protected function getRawSalt()
+ {
+ $rawSalt = false;
+ $numBytes = 16;
+ if (function_exists('mcrypt_create_iv')) {
+ $rawSalt = mcrypt_create_iv($numBytes, MCRYPT_DEV_URANDOM);
+ }
+ if (!$rawSalt) {
+ $rawSalt = $this->secureRandom->nextBytes($numBytes);
+ }
+
+ return $rawSalt;
+ }
+}
diff --git a/Core/Encoder/BasePasswordEncoder.php b/Core/Encoder/BasePasswordEncoder.php
index ae1c7d4..c26c9ce 100644
--- a/Core/Encoder/BasePasswordEncoder.php
+++ b/Core/Encoder/BasePasswordEncoder.php
@@ -11,6 +11,8 @@
namespace Symfony\Component\Security\Core\Encoder;
+use Symfony\Component\Security\Core\Util\StringUtils;
+
/**
* BasePasswordEncoder is the base class for all password encoders.
*
@@ -50,6 +52,8 @@ abstract class BasePasswordEncoder implements PasswordEncoderInterface
* @param string $salt the salt to be used
*
* @return string a merged password and salt
+ *
+ * @throws \InvalidArgumentException
*/
protected function mergePasswordAndSalt($password, $salt)
{
@@ -77,15 +81,6 @@ abstract class BasePasswordEncoder implements PasswordEncoderInterface
*/
protected function comparePasswords($password1, $password2)
{
- if (strlen($password1) !== strlen($password2)) {
- return false;
- }
-
- $result = 0;
- for ($i = 0; $i < strlen($password1); $i++) {
- $result |= ord($password1[$i]) ^ ord($password2[$i]);
- }
-
- return 0 === $result;
+ return StringUtils::equals($password1, $password2);
}
}
diff --git a/Core/Encoder/EncoderFactory.php b/Core/Encoder/EncoderFactory.php
index 9429441..8bad61f 100644
--- a/Core/Encoder/EncoderFactory.php
+++ b/Core/Encoder/EncoderFactory.php
@@ -51,6 +51,8 @@ class EncoderFactory implements EncoderFactoryInterface
* @param array $config
*
* @return PasswordEncoderInterface
+ *
+ * @throws \InvalidArgumentException
*/
private function createEncoder(array $config)
{
diff --git a/Core/Encoder/Pbkdf2PasswordEncoder.php b/Core/Encoder/Pbkdf2PasswordEncoder.php
new file mode 100644
index 0000000..656545f
--- /dev/null
+++ b/Core/Encoder/Pbkdf2PasswordEncoder.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\Encoder;
+
+/**
+ * Pbkdf2PasswordEncoder uses the PBKDF2 (Password-Based Key Derivation Function 2).
+ *
+ * Providing a high level of Cryptographic security,
+ * PBKDF2 is recommended by the National Institute of Standards and Technology (NIST).
+ *
+ * But also warrants a warning, using PBKDF2 (with a high number of iterations) slows down the process.
+ * PBKDF2 should be used with caution and care.
+ *
+ * @author Sebastiaan Stok <s.stok@rollerscapes.net>
+ * @author Andrew Johnson
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class Pbkdf2PasswordEncoder extends BasePasswordEncoder
+{
+ private $algorithm;
+ private $encodeHashAsBase64;
+ private $iterations;
+ private $length;
+
+ /**
+ * Constructor.
+ *
+ * @param string $algorithm The digest algorithm to use
+ * @param Boolean $encodeHashAsBase64 Whether to base64 encode the password hash
+ * @param integer $iterations The number of iterations to use to stretch the password hash
+ * @param integer $length Length of derived key to create
+ */
+ public function __construct($algorithm = 'sha512', $encodeHashAsBase64 = true, $iterations = 1000, $length = 40)
+ {
+ $this->algorithm = $algorithm;
+ $this->encodeHashAsBase64 = $encodeHashAsBase64;
+ $this->iterations = $iterations;
+ $this->length = $length;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @throws \LogicException when the algorithm is not supported
+ */
+ public function encodePassword($raw, $salt)
+ {
+ if (!in_array($this->algorithm, hash_algos(), true)) {
+ throw new \LogicException(sprintf('The algorithm "%s" is not supported.', $this->algorithm));
+ }
+
+ if (function_exists('hash_pbkdf2')) {
+ $digest = hash_pbkdf2($this->algorithm, $raw, $salt, $this->iterations, $this->length, true);
+ } else {
+ $digest = $this->hashPbkdf2($this->algorithm, $raw, $salt, $this->iterations, $this->length);
+ }
+
+ return $this->encodeHashAsBase64 ? base64_encode($digest) : bin2hex($digest);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isPasswordValid($encoded, $raw, $salt)
+ {
+ return $this->comparePasswords($encoded, $this->encodePassword($raw, $salt));
+ }
+
+ private function hashPbkdf2($algorithm, $password, $salt, $iterations, $length = 0)
+ {
+ // Number of blocks needed to create the derived key
+ $blocks = ceil($length / strlen(hash($algorithm, null, true)));
+ $digest = '';
+
+ for ($i = 1; $i <= $blocks; $i++) {
+ $ib = $block = hash_hmac($algorithm, $salt . pack('N', $i), $password, true);
+
+ // Iterations
+ for ($j = 1; $j < $iterations; $j++) {
+ $ib ^= ($block = hash_hmac($algorithm, $block, $password, true));
+ }
+
+ $digest .= $ib;
+ }
+
+ return substr($digest, 0, $this->length);
+ }
+}
diff --git a/Core/Exception/AccountExpiredException.php b/Core/Exception/AccountExpiredException.php
index f899b1b..a5618ce 100644
--- a/Core/Exception/AccountExpiredException.php
+++ b/Core/Exception/AccountExpiredException.php
@@ -15,7 +15,15 @@ namespace Symfony\Component\Security\Core\Exception;
* AccountExpiredException is thrown when the user account has expired.
*
* @author Fabien Potencier <fabien@symfony.com>
+ * @author Alexander <iam.asm89@gmail.com>
*/
class AccountExpiredException extends AccountStatusException
{
+ /**
+ * {@inheritDoc}
+ */
+ public function getMessageKey()
+ {
+ return 'Account has expired.';
+ }
}
diff --git a/Core/Exception/AccountStatusException.php b/Core/Exception/AccountStatusException.php
index 958f584..7819e4d 100644
--- a/Core/Exception/AccountStatusException.php
+++ b/Core/Exception/AccountStatusException.php
@@ -11,12 +11,57 @@
namespace Symfony\Component\Security\Core\Exception;
+use Symfony\Component\Security\Core\User\UserInterface;
+
/**
* AccountStatusException is the base class for authentication exceptions
* caused by the user account status.
*
* @author Fabien Potencier <fabien@symfony.com>
+ * @author Alexander <iam.asm89@gmail.com>
*/
abstract class AccountStatusException extends AuthenticationException
{
+ private $user;
+
+ /**
+ * Get the user.
+ *
+ * @return UserInterface
+ */
+ public function getUser()
+ {
+ return $this->user;
+ }
+
+ /**
+ * Set the user.
+ *
+ * @param UserInterface $user
+ */
+ public function setUser(UserInterface $user)
+ {
+ $this->user = $user;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function serialize()
+ {
+ return serialize(array(
+ $this->user,
+ parent::serialize(),
+ ));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function unserialize($str)
+ {
+ list($this->user, $parentData) = unserialize($str);
+
+ parent::unserialize($parentData);
+ }
}
diff --git a/Core/Exception/AuthenticationCredentialsNotFoundException.php b/Core/Exception/AuthenticationCredentialsNotFoundException.php
index 16686ad..633b2be 100644
--- a/Core/Exception/AuthenticationCredentialsNotFoundException.php
+++ b/Core/Exception/AuthenticationCredentialsNotFoundException.php
@@ -16,7 +16,15 @@ namespace Symfony\Component\Security\Core\Exception;
* because no Token is available.
*
* @author Fabien Potencier <fabien@symfony.com>
+ * @author Alexander <iam.asm89@gmail.com>
*/
class AuthenticationCredentialsNotFoundException extends AuthenticationException
{
+ /**
+ * {@inheritDoc}
+ */
+ public function getMessageKey()
+ {
+ return 'Authentication credentials could not be found.';
+ }
}
diff --git a/Core/Exception/AuthenticationException.php b/Core/Exception/AuthenticationException.php
index 074dad0..2b897c2 100644
--- a/Core/Exception/AuthenticationException.php
+++ b/Core/Exception/AuthenticationException.php
@@ -11,36 +11,42 @@
namespace Symfony\Component\Security\Core\Exception;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+
/**
* AuthenticationException is the base class for all authentication exceptions.
*
* @author Fabien Potencier <fabien@symfony.com>
+ * @author Alexander <iam.asm89@gmail.com>
*/
class AuthenticationException extends \RuntimeException implements \Serializable
{
- private $extraInformation;
-
- public function __construct($message, $extraInformation = null, $code = 0, \Exception $previous = null)
- {
- parent::__construct($message, $code, $previous);
+ private $token;
- $this->extraInformation = $extraInformation;
- }
-
- public function getExtraInformation()
+ /**
+ * Get the token.
+ *
+ * @return TokenInterface
+ */
+ public function getToken()
{
- return $this->extraInformation;
+ return $this->token;
}
- public function setExtraInformation($extraInformation)
+ /**
+ * Set the token.
+ *
+ * @param TokenInterface $token
+ */
+ public function setToken(TokenInterface $token)
{
- $this->extraInformation = $extraInformation;
+ $this->token = $token;
}
public function serialize()
{
return serialize(array(
- $this->extraInformation,
+ $this->token,
$this->code,
$this->message,
$this->file,
@@ -51,11 +57,31 @@ class AuthenticationException extends \RuntimeException implements \Serializable
public function unserialize($str)
{
list(
- $this->extraInformation,
+ $this->token,
$this->code,
$this->message,
$this->file,
$this->line
) = unserialize($str);
}
+
+ /**
+ * Message key to be used by the translation component.
+ *
+ * @return string
+ */
+ public function getMessageKey()
+ {
+ return 'An authentication exception occurred.';
+ }
+
+ /**
+ * Message data to be used by the translation component.
+ *
+ * @return array
+ */
+ public function getMessageData()
+ {
+ return array();
+ }
}
diff --git a/Core/Exception/AuthenticationServiceException.php b/Core/Exception/AuthenticationServiceException.php
index 5b32d81..758a4f0 100644
--- a/Core/Exception/AuthenticationServiceException.php
+++ b/Core/Exception/AuthenticationServiceException.php
@@ -15,7 +15,15 @@ namespace Symfony\Component\Security\Core\Exception;
* AuthenticationServiceException is thrown when an authentication request could not be processed due to a system problem.
*
* @author Fabien Potencier <fabien@symfony.com>
+ * @author Alexander <iam.asm89@gmail.com>
*/
class AuthenticationServiceException extends AuthenticationException
{
+ /**
+ * {@inheritDoc}
+ */
+ public function getMessageKey()
+ {
+ return 'Authentication request could not be processed due to a system problem.';
+ }
}
diff --git a/Core/Exception/BadCredentialsException.php b/Core/Exception/BadCredentialsException.php
index 2eae5b8..5deecca 100644
--- a/Core/Exception/BadCredentialsException.php
+++ b/Core/Exception/BadCredentialsException.php
@@ -15,11 +15,15 @@ namespace Symfony\Component\Security\Core\Exception;
* BadCredentialsException is thrown when the user credentials are invalid.
*
* @author Fabien Potencier <fabien@symfony.com>
+ * @author Alexander <iam.asm89@gmail.com>
*/
class BadCredentialsException extends AuthenticationException
{
- public function __construct($message, $code = 0, \Exception $previous = null)
+ /**
+ * {@inheritDoc}
+ */
+ public function getMessageKey()
{
- parent::__construct($message, null, $code, $previous);
+ return 'Invalid credentials.';
}
}
diff --git a/Core/Exception/CookieTheftException.php b/Core/Exception/CookieTheftException.php
index 2ada78d..8d9e154 100644
--- a/Core/Exception/CookieTheftException.php
+++ b/Core/Exception/CookieTheftException.php
@@ -16,7 +16,15 @@ namespace Symfony\Component\Security\Core\Exception;
* detects that a presented cookie has already been used by someone else.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ * @author Alexander <iam.asm89@gmail.com>
*/
class CookieTheftException extends AuthenticationException
{
+ /**
+ * {@inheritDoc}
+ */
+ public function getMessageKey()
+ {
+ return 'Cookie has already been used by someone else.';
+ }
}
diff --git a/Core/Exception/CredentialsExpiredException.php b/Core/Exception/CredentialsExpiredException.php
index a4d42c8..b9bf2d1 100644
--- a/Core/Exception/CredentialsExpiredException.php
+++ b/Core/Exception/CredentialsExpiredException.php
@@ -15,7 +15,15 @@ namespace Symfony\Component\Security\Core\Exception;
* CredentialsExpiredException is thrown when the user account credentials have expired.
*
* @author Fabien Potencier <fabien@symfony.com>
+ * @author Alexander <iam.asm89@gmail.com>
*/
class CredentialsExpiredException extends AccountStatusException
{
+ /**
+ * {@inheritDoc}
+ */
+ public function getMessageKey()
+ {
+ return 'Credentials have expired.';
+ }
}
diff --git a/Core/Exception/DisabledException.php b/Core/Exception/DisabledException.php
index fd26221..5571ab1 100644
--- a/Core/Exception/DisabledException.php
+++ b/Core/Exception/DisabledException.php
@@ -15,7 +15,15 @@ namespace Symfony\Component\Security\Core\Exception;
* DisabledException is thrown when the user account is disabled.
*
* @author Fabien Potencier <fabien@symfony.com>
+ * @author Alexander <iam.asm89@gmail.com>
*/
class DisabledException extends AccountStatusException
{
+ /**
+ * {@inheritDoc}
+ */
+ public function getMessageKey()
+ {
+ return 'Account is disabled.';
+ }
}
diff --git a/Core/Exception/InsufficientAuthenticationException.php b/Core/Exception/InsufficientAuthenticationException.php
index bbf5517..74fc2b9 100644
--- a/Core/Exception/InsufficientAuthenticationException.php
+++ b/Core/Exception/InsufficientAuthenticationException.php
@@ -17,7 +17,15 @@ namespace Symfony\Component\Security\Core\Exception;
* This is the case when a user is anonymous and the resource to be displayed has an access role.
*
* @author Fabien Potencier <fabien@symfony.com>
+ * @author Alexander <iam.asm89@gmail.com>
*/
class InsufficientAuthenticationException extends AuthenticationException
{
+ /**
+ * {@inheritDoc}
+ */
+ public function getMessageKey()
+ {
+ return 'Not privileged to request the resource.';
+ }
}
diff --git a/Core/Exception/InvalidCsrfTokenException.php b/Core/Exception/InvalidCsrfTokenException.php
index 4181bac..ce0e1f4 100644
--- a/Core/Exception/InvalidCsrfTokenException.php
+++ b/Core/Exception/InvalidCsrfTokenException.php
@@ -15,7 +15,15 @@ namespace Symfony\Component\Security\Core\Exception;
* This exception is thrown when the csrf token is invalid.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ * @author Alexander <iam.asm89@gmail.com>
*/
class InvalidCsrfTokenException extends AuthenticationException
{
+ /**
+ * {@inheritDoc}
+ */
+ public function getMessageKey()
+ {
+ return 'Invalid CSRF token.';
+ }
}
diff --git a/Core/Exception/LockedException.php b/Core/Exception/LockedException.php
index 6fa0b77..6532f70 100644
--- a/Core/Exception/LockedException.php
+++ b/Core/Exception/LockedException.php
@@ -15,7 +15,15 @@ namespace Symfony\Component\Security\Core\Exception;
* LockedException is thrown if the user account is locked.
*
* @author Fabien Potencier <fabien@symfony.com>
+ * @author Alexander <iam.asm89@gmail.com>
*/
class LockedException extends AccountStatusException
{
+ /**
+ * {@inheritDoc}
+ */
+ public function getMessageKey()
+ {
+ return 'Account is locked.';
+ }
}
diff --git a/Core/Exception/NonceExpiredException.php b/Core/Exception/NonceExpiredException.php
index 6a6a781..da6fba8 100644
--- a/Core/Exception/NonceExpiredException.php
+++ b/Core/Exception/NonceExpiredException.php
@@ -18,7 +18,15 @@ use Symfony\Component\Security\Core\Exception\AuthenticationException;
* the digest nonce has expired.
*
* @author Fabien Potencier <fabien@symfony.com>
+ * @author Alexander <iam.asm89@gmail.com>
*/
class NonceExpiredException extends AuthenticationException
{
+ /**
+ * {@inheritDoc}
+ */
+ public function getMessageKey()
+ {
+ return 'Digest nonce has expired.';
+ }
}
diff --git a/Core/Exception/ProviderNotFoundException.php b/Core/Exception/ProviderNotFoundException.php
index e11c8aa..ea2b1fd 100644
--- a/Core/Exception/ProviderNotFoundException.php
+++ b/Core/Exception/ProviderNotFoundException.php
@@ -16,7 +16,15 @@ namespace Symfony\Component\Security\Core\Exception;
* supports an authentication Token.
*
* @author Fabien Potencier <fabien@symfony.com>
+ * @author Alexander <iam.asm89@gmail.com>
*/
class ProviderNotFoundException extends AuthenticationException
{
+ /**
+ * {@inheritDoc}
+ */
+ public function getMessageKey()
+ {
+ return 'No authentication provider found to support the authentication token.';
+ }
}
diff --git a/Core/Exception/SessionUnavailableException.php b/Core/Exception/SessionUnavailableException.php
index 519164a..4b47b18 100644
--- a/Core/Exception/SessionUnavailableException.php
+++ b/Core/Exception/SessionUnavailableException.php
@@ -21,7 +21,15 @@ namespace Symfony\Component\Security\Core\Exception;
* request.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ * @author Alexander <iam.asm89@gmail.com>
*/
class SessionUnavailableException extends AuthenticationException
{
+ /**
+ * {@inheritDoc}
+ */
+ public function getMessageKey()
+ {
+ return 'No session available, it either timed out or cookies are not enabled.';
+ }
}
diff --git a/Core/Exception/TokenNotFoundException.php b/Core/Exception/TokenNotFoundException.php
index 593f3ad..fb85abf 100644
--- a/Core/Exception/TokenNotFoundException.php
+++ b/Core/Exception/TokenNotFoundException.php
@@ -1,5 +1,4 @@
<?php
-namespace Symfony\Component\Security\Core\Exception;
/*
* This file is part of the Symfony package.
@@ -10,11 +9,21 @@ namespace Symfony\Component\Security\Core\Exception;
* file that was distributed with this source code.
*/
+namespace Symfony\Component\Security\Core\Exception;
+
/**
* TokenNotFoundException is thrown if a Token cannot be found.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ * @author Alexander <iam.asm89@gmail.com>
*/
class TokenNotFoundException extends AuthenticationException
{
+ /**
+ * {@inheritDoc}
+ */
+ public function getMessageKey()
+ {
+ return 'No token could be found.';
+ }
}
diff --git a/Core/Exception/UsernameNotFoundException.php b/Core/Exception/UsernameNotFoundException.php
index 38533e7..f656bac 100644
--- a/Core/Exception/UsernameNotFoundException.php
+++ b/Core/Exception/UsernameNotFoundException.php
@@ -15,7 +15,58 @@ namespace Symfony\Component\Security\Core\Exception;
* UsernameNotFoundException is thrown if a User cannot be found by its username.
*
* @author Fabien Potencier <fabien@symfony.com>
+ * @author Alexander <iam.asm89@gmail.com>
*/
class UsernameNotFoundException extends AuthenticationException
{
+ private $username;
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getMessageKey()
+ {
+ return 'Username could not be found.';
+ }
+
+ /**
+ * Get the username.
+ *
+ * @return string
+ */
+ public function getUsername()
+ {
+ return $this->username;
+ }
+
+ /**
+ * Set the username.
+ *
+ * @param string $username
+ */
+ public function setUsername($username)
+ {
+ $this->username = $username;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function serialize()
+ {
+ return serialize(array(
+ $this->username,
+ parent::serialize(),
+ ));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function unserialize($str)
+ {
+ list($this->username, $parentData) = unserialize($str);
+
+ parent::unserialize($parentData);
+ }
}
diff --git a/Core/Role/RoleHierarchyInterface.php b/Core/Role/RoleHierarchyInterface.php
index c495a7f..2ea6ca3 100644
--- a/Core/Role/RoleHierarchyInterface.php
+++ b/Core/Role/RoleHierarchyInterface.php
@@ -24,9 +24,9 @@ interface RoleHierarchyInterface
* Reachable roles are the roles directly assigned but also all roles that
* are transitively reachable from them in the role hierarchy.
*
- * @param array $roles An array of directly assigned roles
+ * @param RoleInterface[] $roles An array of directly assigned roles
*
- * @return array An array of all reachable roles
+ * @return RoleInterface[] An array of all reachable roles
*/
public function getReachableRoles(array $roles);
}
diff --git a/Core/Role/RoleInterface.php b/Core/Role/RoleInterface.php
index a3cb266..3d4cbea 100644
--- a/Core/Role/RoleInterface.php
+++ b/Core/Role/RoleInterface.php
@@ -15,7 +15,7 @@ namespace Symfony\Component\Security\Core\Role;
* RoleInterface represents a role granted to a user.
*
* A role must either have a string representation or it needs to be explicitly
- * supported by an at least one AccessDecisionManager.
+ * supported by at least one AccessDecisionManager.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
diff --git a/Core/User/ChainUserProvider.php b/Core/User/ChainUserProvider.php
index 376ba1c..3ff1ea9 100644
--- a/Core/User/ChainUserProvider.php
+++ b/Core/User/ChainUserProvider.php
@@ -44,7 +44,9 @@ class ChainUserProvider implements UserProviderInterface
}
}
- throw new UsernameNotFoundException(sprintf('There is no user with name "%s".', $username));
+ $ex = new UsernameNotFoundException(sprintf('There is no user with name "%s".', $username));
+ $ex->setUsername($username);
+ throw $ex;
}
/**
@@ -66,7 +68,9 @@ class ChainUserProvider implements UserProviderInterface
}
if ($supportedUserFound) {
- throw new UsernameNotFoundException(sprintf('There is no user with name "%s".', $user->getUsername()));
+ $ex = new UsernameNotFoundException(sprintf('There is no user with name "%s".', $user->getUsername()));
+ $ex->setUsername($user->getUsername());
+ throw $ex;
} else {
throw new UnsupportedUserException(sprintf('The account "%s" is not supported.', get_class($user)));
}
diff --git a/Core/User/InMemoryUserProvider.php b/Core/User/InMemoryUserProvider.php
index eae2083..e87f80c 100644
--- a/Core/User/InMemoryUserProvider.php
+++ b/Core/User/InMemoryUserProvider.php
@@ -50,6 +50,8 @@ class InMemoryUserProvider implements UserProviderInterface
* Adds a new User to the provider.
*
* @param UserInterface $user A UserInterface instance
+ *
+ * @throws \LogicException
*/
public function createUser(UserInterface $user)
{
@@ -66,7 +68,10 @@ class InMemoryUserProvider implements UserProviderInterface
public function loadUserByUsername($username)
{
if (!isset($this->users[strtolower($username)])) {
- throw new UsernameNotFoundException(sprintf('Username "%s" does not exist.', $username));
+ $ex = new UsernameNotFoundException(sprintf('Username "%s" does not exist.', $username));
+ $ex->setUsername($username);
+
+ throw $ex;
}
$user = $this->users[strtolower($username)];
diff --git a/Core/User/UserChecker.php b/Core/User/UserChecker.php
index 93897a1..8dde3a6 100644
--- a/Core/User/UserChecker.php
+++ b/Core/User/UserChecker.php
@@ -33,7 +33,9 @@ class UserChecker implements UserCheckerInterface
}
if (!$user->isCredentialsNonExpired()) {
- throw new CredentialsExpiredException('User credentials have expired.', $user);
+ $ex = new CredentialsExpiredException('User credentials have expired.');
+ $ex->setUser($user);
+ throw $ex;
}
}
@@ -47,15 +49,21 @@ class UserChecker implements UserCheckerInterface
}
if (!$user->isAccountNonLocked()) {
- throw new LockedException('User account is locked.', $user);
+ $ex = new LockedException('User account is locked.');
+ $ex->setUser($user);
+ throw $ex;
}
if (!$user->isEnabled()) {
- throw new DisabledException('User account is disabled.', $user);
+ $ex = new DisabledException('User account is disabled.');
+ $ex->setUser($user);
+ throw $ex;
}
if (!$user->isAccountNonExpired()) {
- throw new AccountExpiredException('User account has expired.', $user);
+ $ex = new AccountExpiredException('User account has expired.');
+ $ex->setUser($user);
+ throw $ex;
}
}
}
diff --git a/Core/Util/ClassUtils.php b/Core/Util/ClassUtils.php
index 7b583a3..26bf1a1 100644
--- a/Core/Util/ClassUtils.php
+++ b/Core/Util/ClassUtils.php
@@ -37,6 +37,11 @@ class ClassUtils
const MARKER_LENGTH = 6;
/**
+ * This class should not be instantiated
+ */
+ private function __construct() {}
+
+ /**
* Gets the real class name of a class name that could be a proxy.
*
* @param string|object
diff --git a/Core/Util/SecureRandom.php b/Core/Util/SecureRandom.php
new file mode 100644
index 0000000..841b9af
--- /dev/null
+++ b/Core/Util/SecureRandom.php
@@ -0,0 +1,114 @@
+<?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\Util;
+
+use Psr\Log\LoggerInterface;
+
+/**
+ * A secure random number generator implementation.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+final class SecureRandom implements SecureRandomInterface
+{
+ private $logger;
+ private $useOpenSsl;
+ private $seed;
+ private $seedUpdated;
+ private $seedLastUpdatedAt;
+ private $seedFile;
+
+ /**
+ * Constructor.
+ *
+ * Be aware that a guessable seed will severely compromise the PRNG
+ * algorithm that is employed.
+ *
+ * @param string $seedFile
+ * @param LoggerInterface $logger
+ */
+ public function __construct($seedFile = null, LoggerInterface $logger = null)
+ {
+ $this->seedFile = $seedFile;
+ $this->logger = $logger;
+
+ // determine whether to use OpenSSL
+ if (defined('PHP_WINDOWS_VERSION_BUILD') && version_compare(PHP_VERSION, '5.3.4', '<')) {
+ $this->useOpenSsl = false;
+ } elseif (!function_exists('openssl_random_pseudo_bytes')) {
+ if (null !== $this->logger) {
+ $this->logger->notice('It is recommended that you enable the "openssl" extension for random number generation.');
+ }
+ $this->useOpenSsl = false;
+ } else {
+ $this->useOpenSsl = true;
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function nextBytes($nbBytes)
+ {
+ // try OpenSSL
+ if ($this->useOpenSsl) {
+ $bytes = openssl_random_pseudo_bytes($nbBytes, $strong);
+
+ if (false !== $bytes && true === $strong) {
+ return $bytes;
+ }
+
+ if (null !== $this->logger) {
+ $this->logger->info('OpenSSL did not produce a secure random number.');
+ }
+ }
+
+ // initialize seed
+ if (null === $this->seed) {
+ if (null === $this->seedFile) {
+ throw new \RuntimeException('You need to specify a file path to store the seed.');
+ }
+
+ if (is_file($this->seedFile)) {
+ list($this->seed, $this->seedLastUpdatedAt) = $this->readSeed();
+ } else {
+ $this->seed = uniqid(mt_rand(), true);
+ $this->updateSeed();
+ }
+ }
+
+ $bytes = '';
+ while (strlen($bytes) < $nbBytes) {
+ static $incr = 1;
+ $bytes .= hash('sha512', $incr++.$this->seed.uniqid(mt_rand(), true).$nbBytes, true);
+ $this->seed = base64_encode(hash('sha512', $this->seed.$bytes.$nbBytes, true));
+ $this->updateSeed();
+ }
+
+ return substr($bytes, 0, $nbBytes);
+ }
+
+ private function readSeed()
+ {
+ return json_decode(file_get_contents($this->seedFile));
+ }
+
+ private function updateSeed()
+ {
+ if (!$this->seedUpdated && $this->seedLastUpdatedAt < time() - mt_rand(1, 10)) {
+ file_put_contents($this->seedFile, json_encode(array($this->seed, microtime(true))));
+ }
+
+ $this->seedUpdated = true;
+ }
+}
diff --git a/Core/Util/SecureRandomInterface.php b/Core/Util/SecureRandomInterface.php
new file mode 100644
index 0000000..2c35a72
--- /dev/null
+++ b/Core/Util/SecureRandomInterface.php
@@ -0,0 +1,29 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Core\Util;
+
+/**
+ * Interface that needs to be implemented by all secure random number generators.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+interface SecureRandomInterface
+{
+ /**
+ * Generates the specified number of secure random bytes.
+ *
+ * @param integer $nbBytes
+ *
+ * @return string
+ */
+ public function nextBytes($nbBytes);
+}
diff --git a/Core/Util/StringUtils.php b/Core/Util/StringUtils.php
new file mode 100644
index 0000000..2e8925d
--- /dev/null
+++ b/Core/Util/StringUtils.php
@@ -0,0 +1,60 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Core\Util;
+
+/**
+ * String utility functions.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class StringUtils
+{
+ /**
+ * This class should not be instantiated
+ */
+ private function __construct() {}
+
+ /**
+ * Compares two strings.
+ *
+ * This method implements a constant-time algorithm to compare strings.
+ *
+ * @param string $knownString The string of known length to compare against
+ * @param string $userInput The string that the user can control
+ *
+ * @return Boolean true if the two strings are the same, false otherwise
+ */
+ public static function equals($knownString, $userInput)
+ {
+ // Prevent issues if string length is 0
+ $knownString .= chr(0);
+ $userInput .= chr(0);
+
+ $knownLen = strlen($knownString);
+ $userLen = strlen($userInput);
+
+ // Set the result to the difference between the lengths
+ $result = $knownLen - $userLen;
+
+ // Note that we ALWAYS iterate over the user-supplied length
+ // This is to prevent leaking length information
+ for ($i = 0; $i < $userLen; $i++) {
+ // Using % here is a trick to prevent notices
+ // It's safe, since if the lengths are different
+ // $result is already non-0
+ $result |= (ord($knownString[$i % $knownLen]) ^ ord($userInput[$i]));
+ }
+
+ // They are only identical strings if $result is exactly 0...
+ return 0 === $result;
+ }
+}
diff --git a/Core/Validator/Constraint/UserPassword.php b/Core/Validator/Constraint/UserPassword.php
index 3279e02..93ca24d 100644
--- a/Core/Validator/Constraint/UserPassword.php
+++ b/Core/Validator/Constraint/UserPassword.php
@@ -11,17 +11,19 @@
namespace Symfony\Component\Security\Core\Validator\Constraint;
-use Symfony\Component\Validator\Constraint;
+use Symfony\Component\Security\Core\Validator\Constraints\UserPassword as BaseUserPassword;
/**
* @Annotation
+ *
+ * @deprecated Deprecated since version 2.2, to be removed in 2.3.
*/
-class UserPassword extends Constraint
+class UserPassword extends BaseUserPassword
{
- public $message = 'This value should be the user current password.';
-
- public function validatedBy()
+ public function __construct($options = null)
{
- return 'security.validator.user_password';
+ trigger_error('UserPassword class in Symfony\Component\Security\Core\Validator\Constraint namespace is deprecated since version 2.2 and will be removed in 2.3. Use the Symfony\Component\Security\Core\Validator\Constraints\UserPassword class instead.', E_USER_DEPRECATED);
+
+ parent::__construct($options);
}
}
diff --git a/Core/Validator/Constraint/UserPasswordValidator.php b/Core/Validator/Constraint/UserPasswordValidator.php
index a54906b..0195fe5 100644
--- a/Core/Validator/Constraint/UserPasswordValidator.php
+++ b/Core/Validator/Constraint/UserPasswordValidator.php
@@ -11,36 +11,19 @@
namespace Symfony\Component\Security\Core\Validator\Constraint;
-use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\SecurityContextInterface;
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\Security\Core\Validator\Constraints\UserPasswordValidator as BaseUserPasswordValidator;
-class UserPasswordValidator extends ConstraintValidator
+/**
+ * @deprecated Deprecated since version 2.2, to be removed in 2.3.
+ */
+class UserPasswordValidator extends BaseUserPasswordValidator
{
- private $securityContext;
- private $encoderFactory;
-
public function __construct(SecurityContextInterface $securityContext, EncoderFactoryInterface $encoderFactory)
{
- $this->securityContext = $securityContext;
- $this->encoderFactory = $encoderFactory;
- }
-
- public function validate($password, Constraint $constraint)
- {
- $user = $this->securityContext->getToken()->getUser();
-
- if (!$user instanceof UserInterface) {
- throw new ConstraintDefinitionException('The User must extend UserInterface');
- }
-
- $encoder = $this->encoderFactory->getEncoder($user);
+ trigger_error('UserPasswordValidator class in Symfony\Component\Security\Core\Validator\Constraint namespace is deprecated since version 2.2 and will be removed in 2.3. Use the Symfony\Component\Security\Core\Validator\Constraints\UserPasswordValidator class instead.', E_USER_DEPRECATED);
- if (!$encoder->isPasswordValid($user->getPassword(), $password, $user->getSalt())) {
- $this->context->addViolation($constraint->message);
- }
+ parent::__construct($securityContext, $encoderFactory);
}
}
diff --git a/Core/Validator/Constraints/UserPassword.php b/Core/Validator/Constraints/UserPassword.php
new file mode 100644
index 0000000..ed29b0c
--- /dev/null
+++ b/Core/Validator/Constraints/UserPassword.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\Validator\Constraints;
+
+use Symfony\Component\Validator\Constraint;
+
+/**
+ * @Annotation
+ */
+class UserPassword extends Constraint
+{
+ public $message = 'This value should be the user current password.';
+ public $service = 'security.validator.user_password';
+
+ public function validatedBy()
+ {
+ return $this->service;
+ }
+}
diff --git a/Core/Validator/Constraints/UserPasswordValidator.php b/Core/Validator/Constraints/UserPasswordValidator.php
new file mode 100644
index 0000000..a4e0f90
--- /dev/null
+++ b/Core/Validator/Constraints/UserPasswordValidator.php
@@ -0,0 +1,46 @@
+<?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\Validator\Constraints;
+
+use Symfony\Component\Security\Core\User\UserInterface;
+use Symfony\Component\Security\Core\SecurityContextInterface;
+use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
+use Symfony\Component\Validator\Constraint;
+use Symfony\Component\Validator\ConstraintValidator;
+use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
+
+class UserPasswordValidator extends ConstraintValidator
+{
+ private $securityContext;
+ private $encoderFactory;
+
+ public function __construct(SecurityContextInterface $securityContext, EncoderFactoryInterface $encoderFactory)
+ {
+ $this->securityContext = $securityContext;
+ $this->encoderFactory = $encoderFactory;
+ }
+
+ public function validate($password, Constraint $constraint)
+ {
+ $user = $this->securityContext->getToken()->getUser();
+
+ if (!$user instanceof UserInterface) {
+ throw new ConstraintDefinitionException('The User object must implement the UserInterface interface.');
+ }
+
+ $encoder = $this->encoderFactory->getEncoder($user);
+
+ if (!$encoder->isPasswordValid($user->getPassword(), $password, $user->getSalt())) {
+ $this->context->addViolation($constraint->message);
+ }
+ }
+}