summaryrefslogtreecommitdiffstats
path: root/Core
diff options
context:
space:
mode:
Diffstat (limited to 'Core')
-rw-r--r--Core/Authentication/AuthenticationProviderManager.php4
-rw-r--r--Core/Authentication/AuthenticationTrustResolver.php6
-rw-r--r--Core/Authentication/AuthenticationTrustResolverInterface.php6
-rw-r--r--Core/Authentication/Provider/AnonymousAuthenticationProvider.php2
-rw-r--r--Core/Authentication/Provider/AuthenticationProviderInterface.php2
-rw-r--r--Core/Authentication/Provider/DaoAuthenticationProvider.php2
-rw-r--r--Core/Authentication/Provider/PreAuthenticatedAuthenticationProvider.php3
-rw-r--r--Core/Authentication/Provider/UserAuthenticationProvider.php8
-rw-r--r--Core/Authentication/Token/AbstractToken.php10
-rw-r--r--Core/Authentication/Token/AnonymousToken.php4
-rw-r--r--Core/Authentication/Token/Storage/TokenStorage.php43
-rw-r--r--Core/Authentication/Token/Storage/TokenStorageInterface.php36
-rw-r--r--Core/Authentication/Token/TokenInterface.php6
-rw-r--r--Core/Authorization/AccessDecisionManager.php8
-rw-r--r--Core/Authorization/AccessDecisionManagerInterface.php4
-rw-r--r--Core/Authorization/AuthorizationChecker.php70
-rw-r--r--Core/Authorization/AuthorizationCheckerInterface.php30
-rw-r--r--Core/Authorization/Voter/AbstractVoter.php113
-rw-r--r--Core/Authorization/Voter/ExpressionVoter.php2
-rw-r--r--Core/Authorization/Voter/VoterInterface.php8
-rw-r--r--Core/Encoder/BCryptPasswordEncoder.php4
-rw-r--r--Core/Encoder/BasePasswordEncoder.php6
-rw-r--r--Core/Encoder/EncoderFactory.php2
-rw-r--r--Core/Encoder/MessageDigestPasswordEncoder.php4
-rw-r--r--Core/Encoder/PasswordEncoderInterface.php2
-rw-r--r--Core/Encoder/Pbkdf2PasswordEncoder.php6
-rw-r--r--Core/Encoder/PlaintextPasswordEncoder.php2
-rw-r--r--Core/Encoder/UserPasswordEncoder.php55
-rw-r--r--Core/Encoder/UserPasswordEncoderInterface.php41
-rw-r--r--Core/Exception/AccountExpiredException.php2
-rw-r--r--Core/Exception/AccountStatusException.php4
-rw-r--r--Core/Exception/AuthenticationCredentialsNotFoundException.php2
-rw-r--r--Core/Exception/AuthenticationServiceException.php2
-rw-r--r--Core/Exception/BadCredentialsException.php2
-rw-r--r--Core/Exception/CookieTheftException.php2
-rw-r--r--Core/Exception/CredentialsExpiredException.php2
-rw-r--r--Core/Exception/DisabledException.php2
-rw-r--r--Core/Exception/InsufficientAuthenticationException.php2
-rw-r--r--Core/Exception/InvalidCsrfTokenException.php2
-rw-r--r--Core/Exception/LockedException.php2
-rw-r--r--Core/Exception/NonceExpiredException.php2
-rw-r--r--Core/Exception/ProviderNotFoundException.php2
-rw-r--r--Core/Exception/SessionUnavailableException.php2
-rw-r--r--Core/Exception/TokenNotFoundException.php2
-rw-r--r--Core/Exception/UsernameNotFoundException.php14
-rw-r--r--Core/README.md2
-rw-r--r--Core/SecurityContext.php76
-rw-r--r--Core/SecurityContextInterface.php33
-rw-r--r--Core/SecuritySessionStorageInterface.php24
-rw-r--r--Core/Tests/Authentication/AuthenticationProviderManagerTest.php2
-rw-r--r--Core/Tests/Authentication/Token/AbstractTokenTest.php14
-rw-r--r--Core/Tests/Authentication/Token/Storage/TokenStorageTest.php26
-rw-r--r--Core/Tests/Authorization/AccessDecisionManagerTest.php45
-rw-r--r--Core/Tests/Authorization/AuthorizationCheckerTest.php99
-rw-r--r--Core/Tests/Authorization/Voter/RoleVoterTest.php1
-rw-r--r--Core/Tests/Encoder/EncoderFactoryTest.php28
-rw-r--r--Core/Tests/Encoder/UserPasswordEncoderTest.php70
-rw-r--r--Core/Tests/Exception/UsernameNotFoundExceptionTest.php25
-rw-r--r--Core/Tests/SecurityContextTest.php131
-rw-r--r--Core/Tests/Util/StringUtilsTest.php44
-rw-r--r--Core/Tests/Validator/Constraints/LegacyUserPasswordValidator2Dot4ApiTest.php26
-rw-r--r--Core/Tests/Validator/Constraints/LegacyUserPasswordValidatorLegacyApiTest.php26
-rw-r--r--Core/Tests/Validator/Constraints/UserPasswordValidatorTest.php129
-rw-r--r--Core/User/AdvancedUserInterface.php8
-rw-r--r--Core/User/ChainUserProvider.php6
-rw-r--r--Core/User/EquatableInterface.php2
-rw-r--r--Core/User/InMemoryUserProvider.php4
-rw-r--r--Core/User/User.php1
-rw-r--r--Core/User/UserProviderInterface.php2
-rw-r--r--Core/Util/ClassUtils.php4
-rw-r--r--Core/Util/SecureRandomInterface.php2
-rw-r--r--Core/Util/StringUtils.php26
-rw-r--r--Core/Validator/Constraints/UserPassword.php3
-rw-r--r--Core/composer.json2
74 files changed, 1111 insertions, 285 deletions
diff --git a/Core/Authentication/AuthenticationProviderManager.php b/Core/Authentication/AuthenticationProviderManager.php
index 8b7474b..f713e8f 100644
--- a/Core/Authentication/AuthenticationProviderManager.php
+++ b/Core/Authentication/AuthenticationProviderManager.php
@@ -38,7 +38,7 @@ class AuthenticationProviderManager implements AuthenticationManagerInterface
* Constructor.
*
* @param AuthenticationProviderInterface[] $providers An array of AuthenticationProviderInterface instances
- * @param Boolean $eraseCredentials Whether to erase credentials after authentication or not
+ * @param bool $eraseCredentials Whether to erase credentials after authentication or not
*
* @throws \InvalidArgumentException
*/
@@ -49,7 +49,7 @@ class AuthenticationProviderManager implements AuthenticationManagerInterface
}
$this->providers = $providers;
- $this->eraseCredentials = (Boolean) $eraseCredentials;
+ $this->eraseCredentials = (bool) $eraseCredentials;
}
public function setEventDispatcher(EventDispatcherInterface $dispatcher)
diff --git a/Core/Authentication/AuthenticationTrustResolver.php b/Core/Authentication/AuthenticationTrustResolver.php
index 9b3ff3d..d030459 100644
--- a/Core/Authentication/AuthenticationTrustResolver.php
+++ b/Core/Authentication/AuthenticationTrustResolver.php
@@ -36,7 +36,7 @@ class AuthenticationTrustResolver implements AuthenticationTrustResolverInterfac
}
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function isAnonymous(TokenInterface $token = null)
{
@@ -48,7 +48,7 @@ class AuthenticationTrustResolver implements AuthenticationTrustResolverInterfac
}
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function isRememberMe(TokenInterface $token = null)
{
@@ -60,7 +60,7 @@ class AuthenticationTrustResolver implements AuthenticationTrustResolverInterfac
}
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function isFullFledged(TokenInterface $token = null)
{
diff --git a/Core/Authentication/AuthenticationTrustResolverInterface.php b/Core/Authentication/AuthenticationTrustResolverInterface.php
index ac07db0..03b48e9 100644
--- a/Core/Authentication/AuthenticationTrustResolverInterface.php
+++ b/Core/Authentication/AuthenticationTrustResolverInterface.php
@@ -28,7 +28,7 @@ interface AuthenticationTrustResolverInterface
*
* @param TokenInterface $token
*
- * @return Boolean
+ * @return bool
*/
public function isAnonymous(TokenInterface $token = null);
@@ -38,7 +38,7 @@ interface AuthenticationTrustResolverInterface
*
* @param TokenInterface $token
*
- * @return Boolean
+ * @return bool
*/
public function isRememberMe(TokenInterface $token = null);
@@ -47,7 +47,7 @@ interface AuthenticationTrustResolverInterface
*
* @param TokenInterface $token
*
- * @return Boolean
+ * @return bool
*/
public function isFullFledged(TokenInterface $token = null);
}
diff --git a/Core/Authentication/Provider/AnonymousAuthenticationProvider.php b/Core/Authentication/Provider/AnonymousAuthenticationProvider.php
index ea91075..7fbbf85 100644
--- a/Core/Authentication/Provider/AnonymousAuthenticationProvider.php
+++ b/Core/Authentication/Provider/AnonymousAuthenticationProvider.php
@@ -40,7 +40,7 @@ class AnonymousAuthenticationProvider implements AuthenticationProviderInterface
public function authenticate(TokenInterface $token)
{
if (!$this->supports($token)) {
- return null;
+ return;
}
if ($this->key !== $token->getKey()) {
diff --git a/Core/Authentication/Provider/AuthenticationProviderInterface.php b/Core/Authentication/Provider/AuthenticationProviderInterface.php
index f63a924..23724db 100644
--- a/Core/Authentication/Provider/AuthenticationProviderInterface.php
+++ b/Core/Authentication/Provider/AuthenticationProviderInterface.php
@@ -29,7 +29,7 @@ interface AuthenticationProviderInterface extends AuthenticationManagerInterface
*
* @param TokenInterface $token A TokenInterface instance
*
- * @return Boolean true if the implementation supports the Token, false otherwise
+ * @return bool true if the implementation supports the Token, false otherwise
*/
public function supports(TokenInterface $token);
}
diff --git a/Core/Authentication/Provider/DaoAuthenticationProvider.php b/Core/Authentication/Provider/DaoAuthenticationProvider.php
index a9a2205..4913be8 100644
--- a/Core/Authentication/Provider/DaoAuthenticationProvider.php
+++ b/Core/Authentication/Provider/DaoAuthenticationProvider.php
@@ -38,7 +38,7 @@ class DaoAuthenticationProvider extends UserAuthenticationProvider
* @param UserCheckerInterface $userChecker An UserCheckerInterface instance
* @param string $providerKey The provider key
* @param EncoderFactoryInterface $encoderFactory An EncoderFactoryInterface instance
- * @param Boolean $hideUserNotFoundExceptions Whether to hide user not found exception or not
+ * @param bool $hideUserNotFoundExceptions Whether to hide user not found exception or not
*/
public function __construct(UserProviderInterface $userProvider, UserCheckerInterface $userChecker, $providerKey, EncoderFactoryInterface $encoderFactory, $hideUserNotFoundExceptions = true)
{
diff --git a/Core/Authentication/Provider/PreAuthenticatedAuthenticationProvider.php b/Core/Authentication/Provider/PreAuthenticatedAuthenticationProvider.php
index f4d0959..11c3cda 100644
--- a/Core/Authentication/Provider/PreAuthenticatedAuthenticationProvider.php
+++ b/Core/Authentication/Provider/PreAuthenticatedAuthenticationProvider.php
@@ -53,8 +53,9 @@ class PreAuthenticatedAuthenticationProvider implements AuthenticationProviderIn
public function authenticate(TokenInterface $token)
{
if (!$this->supports($token)) {
- return null;
+ return;
}
+
if (!$user = $token->getUser()) {
throw new BadCredentialsException('No pre-authenticated principal found in request.');
}
diff --git a/Core/Authentication/Provider/UserAuthenticationProvider.php b/Core/Authentication/Provider/UserAuthenticationProvider.php
index 18c3e70..4371abf 100644
--- a/Core/Authentication/Provider/UserAuthenticationProvider.php
+++ b/Core/Authentication/Provider/UserAuthenticationProvider.php
@@ -37,7 +37,7 @@ 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
+ * @param bool $hideUserNotFoundExceptions Whether to hide user not found exception or not
*
* @throws \InvalidArgumentException
*/
@@ -58,7 +58,7 @@ abstract class UserAuthenticationProvider implements AuthenticationProviderInter
public function authenticate(TokenInterface $token)
{
if (!$this->supports($token)) {
- return null;
+ return;
}
$username = $token->getUsername();
@@ -70,7 +70,7 @@ abstract class UserAuthenticationProvider implements AuthenticationProviderInter
$user = $this->retrieveUser($username, $token);
} catch (UsernameNotFoundException $notFound) {
if ($this->hideUserNotFoundExceptions) {
- throw new BadCredentialsException('Bad credentials', 0, $notFound);
+ throw new BadCredentialsException('Bad credentials.', 0, $notFound);
}
$notFound->setUsername($username);
@@ -87,7 +87,7 @@ abstract class UserAuthenticationProvider implements AuthenticationProviderInter
$this->userChecker->checkPostAuth($user);
} catch (BadCredentialsException $e) {
if ($this->hideUserNotFoundExceptions) {
- throw new BadCredentialsException('Bad credentials', 0, $e);
+ throw new BadCredentialsException('Bad credentials.', 0, $e);
}
throw $e;
diff --git a/Core/Authentication/Token/AbstractToken.php b/Core/Authentication/Token/AbstractToken.php
index 5160fc5..b54d25e 100644
--- a/Core/Authentication/Token/AbstractToken.php
+++ b/Core/Authentication/Token/AbstractToken.php
@@ -127,7 +127,7 @@ abstract class AbstractToken implements TokenInterface
*/
public function setAuthenticated($authenticated)
{
- $this->authenticated = (Boolean) $authenticated;
+ $this->authenticated = (bool) $authenticated;
}
/**
@@ -150,7 +150,7 @@ abstract class AbstractToken implements TokenInterface
is_object($this->user) ? clone $this->user : $this->user,
$this->authenticated,
$this->roles,
- $this->attributes
+ $this->attributes,
)
);
}
@@ -188,7 +188,7 @@ abstract class AbstractToken implements TokenInterface
*
* @param string $name The attribute name
*
- * @return Boolean true if the attribute exists, false otherwise
+ * @return bool true if the attribute exists, false otherwise
*/
public function hasAttribute($name)
{
@@ -225,7 +225,7 @@ abstract class AbstractToken implements TokenInterface
}
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function __toString()
{
@@ -247,7 +247,7 @@ abstract class AbstractToken implements TokenInterface
}
if ($this->user instanceof EquatableInterface) {
- return ! (Boolean) $this->user->isEqualTo($user);
+ return ! (bool) $this->user->isEqualTo($user);
}
if ($this->user->getPassword() !== $user->getPassword()) {
diff --git a/Core/Authentication/Token/AnonymousToken.php b/Core/Authentication/Token/AnonymousToken.php
index d39fec8..571816c 100644
--- a/Core/Authentication/Token/AnonymousToken.php
+++ b/Core/Authentication/Token/AnonymousToken.php
@@ -57,7 +57,7 @@ class AnonymousToken extends AbstractToken
}
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function serialize()
{
@@ -65,7 +65,7 @@ class AnonymousToken extends AbstractToken
}
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function unserialize($serialized)
{
diff --git a/Core/Authentication/Token/Storage/TokenStorage.php b/Core/Authentication/Token/Storage/TokenStorage.php
new file mode 100644
index 0000000..4b6c11f
--- /dev/null
+++ b/Core/Authentication/Token/Storage/TokenStorage.php
@@ -0,0 +1,43 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Core\Authentication\Token\Storage;
+
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+
+/**
+ * TokenStorage contains a TokenInterface
+ *
+ * It gives access to the token representing the current user authentication.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class TokenStorage implements TokenStorageInterface
+{
+ private $token;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getToken()
+ {
+ return $this->token;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setToken(TokenInterface $token = null)
+ {
+ $this->token = $token;
+ }
+}
diff --git a/Core/Authentication/Token/Storage/TokenStorageInterface.php b/Core/Authentication/Token/Storage/TokenStorageInterface.php
new file mode 100644
index 0000000..218d750
--- /dev/null
+++ b/Core/Authentication/Token/Storage/TokenStorageInterface.php
@@ -0,0 +1,36 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Core\Authentication\Token\Storage;
+
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+
+/**
+ * The TokenStorageInterface.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+interface TokenStorageInterface
+{
+ /**
+ * Returns the current security token.
+ *
+ * @return TokenInterface|null A TokenInterface instance or null if no authentication information is available
+ */
+ public function getToken();
+
+ /**
+ * Sets the authentication token.
+ *
+ * @param TokenInterface $token A TokenInterface token, or null if no further authentication information should be stored
+ */
+ public function setToken(TokenInterface $token = null);
+}
diff --git a/Core/Authentication/Token/TokenInterface.php b/Core/Authentication/Token/TokenInterface.php
index 11f69da..8f7d03f 100644
--- a/Core/Authentication/Token/TokenInterface.php
+++ b/Core/Authentication/Token/TokenInterface.php
@@ -69,14 +69,14 @@ interface TokenInterface extends \Serializable
/**
* Returns whether the user is authenticated or not.
*
- * @return Boolean true if the token has been authenticated, false otherwise
+ * @return bool true if the token has been authenticated, false otherwise
*/
public function isAuthenticated();
/**
* Sets the authenticated flag.
*
- * @param Boolean $isAuthenticated The authenticated flag
+ * @param bool $isAuthenticated The authenticated flag
*/
public function setAuthenticated($isAuthenticated);
@@ -104,7 +104,7 @@ interface TokenInterface extends \Serializable
*
* @param string $name The attribute name
*
- * @return Boolean true if the attribute exists, false otherwise
+ * @return bool true if the attribute exists, false otherwise
*/
public function hasAttribute($name);
diff --git a/Core/Authorization/AccessDecisionManager.php b/Core/Authorization/AccessDecisionManager.php
index 9445440..84856f6 100644
--- a/Core/Authorization/AccessDecisionManager.php
+++ b/Core/Authorization/AccessDecisionManager.php
@@ -36,8 +36,8 @@ class AccessDecisionManager implements AccessDecisionManagerInterface
*
* @param VoterInterface[] $voters An array of VoterInterface instances
* @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
+ * @param bool $allowIfAllAbstainDecisions Whether to grant access if all voters abstained or not
+ * @param bool $allowIfEqualGrantedDeniedDecisions Whether to grant access if result are equals
*
* @throws \InvalidArgumentException
*/
@@ -54,8 +54,8 @@ class AccessDecisionManager implements AccessDecisionManagerInterface
$this->voters = $voters;
$this->strategy = $strategyMethod;
- $this->allowIfAllAbstainDecisions = (Boolean) $allowIfAllAbstainDecisions;
- $this->allowIfEqualGrantedDeniedDecisions = (Boolean) $allowIfEqualGrantedDeniedDecisions;
+ $this->allowIfAllAbstainDecisions = (bool) $allowIfAllAbstainDecisions;
+ $this->allowIfEqualGrantedDeniedDecisions = (bool) $allowIfEqualGrantedDeniedDecisions;
}
/**
diff --git a/Core/Authorization/AccessDecisionManagerInterface.php b/Core/Authorization/AccessDecisionManagerInterface.php
index 742ea74..ec82800 100644
--- a/Core/Authorization/AccessDecisionManagerInterface.php
+++ b/Core/Authorization/AccessDecisionManagerInterface.php
@@ -27,7 +27,7 @@ interface AccessDecisionManagerInterface
* @param array $attributes An array of attributes associated with the method being invoked
* @param object $object The object to secure
*
- * @return Boolean true if the access is granted, false otherwise
+ * @return bool true if the access is granted, false otherwise
*/
public function decide(TokenInterface $token, array $attributes, $object = null);
@@ -36,7 +36,7 @@ interface AccessDecisionManagerInterface
*
* @param string $attribute An attribute
*
- * @return Boolean true if this decision manager supports the attribute, false otherwise
+ * @return bool true if this decision manager supports the attribute, false otherwise
*/
public function supportsAttribute($attribute);
diff --git a/Core/Authorization/AuthorizationChecker.php b/Core/Authorization/AuthorizationChecker.php
new file mode 100644
index 0000000..23c190c
--- /dev/null
+++ b/Core/Authorization/AuthorizationChecker.php
@@ -0,0 +1,70 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Core\Authorization;
+
+use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
+use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
+use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException;
+
+/**
+ * AuthorizationChecker is the main authorization point of the Security component.
+ *
+ * It gives access to the token representing the current user authentication.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+class AuthorizationChecker implements AuthorizationCheckerInterface
+{
+ private $tokenStorage;
+ private $accessDecisionManager;
+ private $authenticationManager;
+ private $alwaysAuthenticate;
+
+ /**
+ * Constructor.
+ *
+ * @param TokenStorageInterface $tokenStorage
+ * @param AuthenticationManagerInterface $authenticationManager An AuthenticationManager instance
+ * @param AccessDecisionManagerInterface $accessDecisionManager An AccessDecisionManager instance
+ * @param bool $alwaysAuthenticate
+ */
+ public function __construct(TokenStorageInterface $tokenStorage, AuthenticationManagerInterface $authenticationManager, AccessDecisionManagerInterface $accessDecisionManager, $alwaysAuthenticate = false)
+ {
+ $this->tokenStorage = $tokenStorage;
+ $this->authenticationManager = $authenticationManager;
+ $this->accessDecisionManager = $accessDecisionManager;
+ $this->alwaysAuthenticate = $alwaysAuthenticate;
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @throws AuthenticationCredentialsNotFoundException when the token storage has no authentication token.
+ */
+ final public function isGranted($attributes, $object = null)
+ {
+ if (null === ($token = $this->tokenStorage->getToken())) {
+ throw new AuthenticationCredentialsNotFoundException('The token storage contains no authentication token. One possible reason may be that there is no firewall configured for this URL.');
+ }
+
+ if ($this->alwaysAuthenticate || !$token->isAuthenticated()) {
+ $this->tokenStorage->setToken($token = $this->authenticationManager->authenticate($token));
+ }
+
+ if (!is_array($attributes)) {
+ $attributes = array($attributes);
+ }
+
+ return $this->accessDecisionManager->decide($token, $attributes, $object);
+ }
+}
diff --git a/Core/Authorization/AuthorizationCheckerInterface.php b/Core/Authorization/AuthorizationCheckerInterface.php
new file mode 100644
index 0000000..bd24d6f
--- /dev/null
+++ b/Core/Authorization/AuthorizationCheckerInterface.php
@@ -0,0 +1,30 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Core\Authorization;
+
+/**
+ * The AuthorizationCheckerInterface.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+interface AuthorizationCheckerInterface
+{
+ /**
+ * Checks if the attributes are granted against the current authentication token and optionally supplied object.
+ *
+ * @param mixed $attributes
+ * @param mixed $object
+ *
+ * @return bool
+ */
+ public function isGranted($attributes, $object = null);
+}
diff --git a/Core/Authorization/Voter/AbstractVoter.php b/Core/Authorization/Voter/AbstractVoter.php
new file mode 100644
index 0000000..61c928e
--- /dev/null
+++ b/Core/Authorization/Voter/AbstractVoter.php
@@ -0,0 +1,113 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Core\Authorization\Voter;
+
+use Symfony\Component\Security\Core\User\UserInterface;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+
+/**
+ * Abstract Voter implementation that reduces boilerplate code required to create a custom Voter
+ *
+ * @author Roman Marintšenko <inoryy@gmail.com>
+ */
+abstract class AbstractVoter implements VoterInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function supportsAttribute($attribute)
+ {
+ return in_array($attribute, $this->getSupportedAttributes());
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function supportsClass($class)
+ {
+ foreach ($this->getSupportedClasses() as $supportedClass) {
+ if ($supportedClass === $class || is_subclass_of($class, $supportedClass)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Iteratively check all given attributes by calling isGranted
+ *
+ * This method terminates as soon as it is able to return ACCESS_GRANTED
+ * If at least one attribute is supported, but access not granted, then ACCESS_DENIED is returned
+ * Otherwise it will return ACCESS_ABSTAIN
+ *
+ * @param TokenInterface $token A TokenInterface instance
+ * @param object $object The object to secure
+ * @param array $attributes An array of attributes associated with the method being invoked
+ *
+ * @return int either ACCESS_GRANTED, ACCESS_ABSTAIN, or ACCESS_DENIED
+ */
+ public function vote(TokenInterface $token, $object, array $attributes)
+ {
+ if (!$object || !$this->supportsClass(get_class($object))) {
+ return self::ACCESS_ABSTAIN;
+ }
+
+ // abstain vote by default in case none of the attributes are supported
+ $vote = self::ACCESS_ABSTAIN;
+
+ foreach ($attributes as $attribute) {
+ if (!$this->supportsAttribute($attribute)) {
+ continue;
+ }
+
+ // as soon as at least one attribute is supported, default is to deny access
+ $vote = self::ACCESS_DENIED;
+
+ if ($this->isGranted($attribute, $object, $token->getUser())) {
+ // grant access as soon as at least one voter returns a positive response
+ return self::ACCESS_GRANTED;
+ }
+ }
+
+ return $vote;
+ }
+
+ /**
+ * Return an array of supported classes. This will be called by supportsClass
+ *
+ * @return array an array of supported classes, i.e. ['\Acme\DemoBundle\Model\Product']
+ */
+ abstract protected function getSupportedClasses();
+
+ /**
+ * Return an array of supported attributes. This will be called by supportsAttribute
+ *
+ * @return array an array of supported attributes, i.e. ['CREATE', 'READ']
+ */
+ abstract protected function getSupportedAttributes();
+
+ /**
+ * Perform a single access check operation on a given attribute, object and (optionally) user
+ * It is safe to assume that $attribute and $object's class pass supportsAttribute/supportsClass
+ * $user can be one of the following:
+ * a UserInterface object (fully authenticated user)
+ * a string (anonymously authenticated user)
+ *
+ * @param string $attribute
+ * @param object $object
+ * @param UserInterface|string $user
+ *
+ * @return bool
+ */
+ abstract protected function isGranted($attribute, $object, $user = null);
+}
diff --git a/Core/Authorization/Voter/ExpressionVoter.php b/Core/Authorization/Voter/ExpressionVoter.php
index bf6683d..3263803 100644
--- a/Core/Authorization/Voter/ExpressionVoter.php
+++ b/Core/Authorization/Voter/ExpressionVoter.php
@@ -34,7 +34,7 @@ class ExpressionVoter implements VoterInterface
*
* @param ExpressionLanguage $expressionLanguage
* @param AuthenticationTrustResolverInterface $trustResolver
- * @param RoleHierarchyInterface $roleHierarchy
+ * @param RoleHierarchyInterface|null $roleHierarchy
*/
public function __construct(ExpressionLanguage $expressionLanguage, AuthenticationTrustResolverInterface $trustResolver, RoleHierarchyInterface $roleHierarchy = null)
{
diff --git a/Core/Authorization/Voter/VoterInterface.php b/Core/Authorization/Voter/VoterInterface.php
index 0840c1c..79fa69f 100644
--- a/Core/Authorization/Voter/VoterInterface.php
+++ b/Core/Authorization/Voter/VoterInterface.php
@@ -29,7 +29,7 @@ interface VoterInterface
*
* @param string $attribute An attribute
*
- * @return Boolean true if this Voter supports the attribute, false otherwise
+ * @return bool true if this Voter supports the attribute, false otherwise
*/
public function supportsAttribute($attribute);
@@ -38,7 +38,7 @@ interface VoterInterface
*
* @param string $class A class name
*
- * @return Boolean true if this Voter can process the class
+ * @return bool true if this Voter can process the class
*/
public function supportsClass($class);
@@ -49,10 +49,10 @@ interface VoterInterface
* ACCESS_GRANTED, ACCESS_DENIED, or ACCESS_ABSTAIN.
*
* @param TokenInterface $token A TokenInterface instance
- * @param object $object The object to secure
+ * @param object|null $object The object to secure
* @param array $attributes An array of attributes associated with the method being invoked
*
- * @return integer either ACCESS_GRANTED, ACCESS_ABSTAIN, or ACCESS_DENIED
+ * @return int either ACCESS_GRANTED, ACCESS_ABSTAIN, or ACCESS_DENIED
*/
public function vote(TokenInterface $token, $object, array $attributes);
}
diff --git a/Core/Encoder/BCryptPasswordEncoder.php b/Core/Encoder/BCryptPasswordEncoder.php
index 5a0f122..27a7334 100644
--- a/Core/Encoder/BCryptPasswordEncoder.php
+++ b/Core/Encoder/BCryptPasswordEncoder.php
@@ -27,7 +27,7 @@ class BCryptPasswordEncoder extends BasePasswordEncoder
/**
* Constructor.
*
- * @param integer $cost The algorithmic cost that should be used
+ * @param int $cost The algorithmic cost that should be used
*
* @throws \RuntimeException When no BCrypt encoder is available
* @throws \InvalidArgumentException if cost is out of range
@@ -61,6 +61,8 @@ class BCryptPasswordEncoder extends BasePasswordEncoder
*
* @return string The encoded password
*
+ * @throws BadCredentialsException when the given password is too long
+ *
* @link http://lxr.php.net/xref/PHP_5_5/ext/standard/password.c#111
*/
public function encodePassword($raw, $salt)
diff --git a/Core/Encoder/BasePasswordEncoder.php b/Core/Encoder/BasePasswordEncoder.php
index aa29876..0d29631 100644
--- a/Core/Encoder/BasePasswordEncoder.php
+++ b/Core/Encoder/BasePasswordEncoder.php
@@ -79,7 +79,7 @@ abstract class BasePasswordEncoder implements PasswordEncoderInterface
* @param string $password1 The first password
* @param string $password2 The second password
*
- * @return Boolean true if the two passwords are the same, false otherwise
+ * @return bool true if the two passwords are the same, false otherwise
*/
protected function comparePasswords($password1, $password2)
{
@@ -89,9 +89,9 @@ abstract class BasePasswordEncoder implements PasswordEncoderInterface
/**
* Checks if the password is too long.
*
- * @param string $password The password
+ * @param string $password The password to check
*
- * @return Boolean true if the password is too long, false otherwise
+ * @return bool true if the password is too long, false otherwise
*/
protected function isPasswordTooLong($password)
{
diff --git a/Core/Encoder/EncoderFactory.php b/Core/Encoder/EncoderFactory.php
index bb5ba91..77021ec 100644
--- a/Core/Encoder/EncoderFactory.php
+++ b/Core/Encoder/EncoderFactory.php
@@ -26,7 +26,7 @@ class EncoderFactory implements EncoderFactoryInterface
}
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function getEncoder($user)
{
diff --git a/Core/Encoder/MessageDigestPasswordEncoder.php b/Core/Encoder/MessageDigestPasswordEncoder.php
index a7e5546..9aa240a 100644
--- a/Core/Encoder/MessageDigestPasswordEncoder.php
+++ b/Core/Encoder/MessageDigestPasswordEncoder.php
@@ -28,8 +28,8 @@ class MessageDigestPasswordEncoder extends BasePasswordEncoder
* 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 bool $encodeHashAsBase64 Whether to base64 encode the password hash
+ * @param int $iterations The number of iterations to use to stretch the password hash
*/
public function __construct($algorithm = 'sha512', $encodeHashAsBase64 = true, $iterations = 5000)
{
diff --git a/Core/Encoder/PasswordEncoderInterface.php b/Core/Encoder/PasswordEncoderInterface.php
index 78b4e42..23acaf3 100644
--- a/Core/Encoder/PasswordEncoderInterface.php
+++ b/Core/Encoder/PasswordEncoderInterface.php
@@ -35,7 +35,7 @@ interface PasswordEncoderInterface
* @param string $raw A raw password
* @param string $salt The salt
*
- * @return Boolean true if the password is valid, false otherwise
+ * @return bool true if the password is valid, false otherwise
*/
public function isPasswordValid($encoded, $raw, $salt);
}
diff --git a/Core/Encoder/Pbkdf2PasswordEncoder.php b/Core/Encoder/Pbkdf2PasswordEncoder.php
index 8a5a958..55b5261 100644
--- a/Core/Encoder/Pbkdf2PasswordEncoder.php
+++ b/Core/Encoder/Pbkdf2PasswordEncoder.php
@@ -37,9 +37,9 @@ class Pbkdf2PasswordEncoder extends BasePasswordEncoder
* 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
+ * @param bool $encodeHashAsBase64 Whether to base64 encode the password hash
+ * @param int $iterations The number of iterations to use to stretch the password hash
+ * @param int $length Length of derived key to create
*/
public function __construct($algorithm = 'sha512', $encodeHashAsBase64 = true, $iterations = 1000, $length = 40)
{
diff --git a/Core/Encoder/PlaintextPasswordEncoder.php b/Core/Encoder/PlaintextPasswordEncoder.php
index 22f3da4..bdb058a 100644
--- a/Core/Encoder/PlaintextPasswordEncoder.php
+++ b/Core/Encoder/PlaintextPasswordEncoder.php
@@ -25,7 +25,7 @@ class PlaintextPasswordEncoder extends BasePasswordEncoder
/**
* Constructor.
*
- * @param Boolean $ignorePasswordCase Compare password case-insensitive
+ * @param bool $ignorePasswordCase Compare password case-insensitive
*/
public function __construct($ignorePasswordCase = false)
{
diff --git a/Core/Encoder/UserPasswordEncoder.php b/Core/Encoder/UserPasswordEncoder.php
new file mode 100644
index 0000000..13ee835
--- /dev/null
+++ b/Core/Encoder/UserPasswordEncoder.php
@@ -0,0 +1,55 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Core\Encoder;
+
+use Symfony\Component\Security\Core\User\UserInterface;
+
+/**
+ * A generic password encoder
+ *
+ * @author Ariel Ferrandini <arielferrandini@gmail.com>
+ */
+class UserPasswordEncoder implements UserPasswordEncoderInterface
+{
+ /**
+ * @var EncoderFactoryInterface
+ */
+ private $encoderFactory;
+
+ /**
+ * @param EncoderFactoryInterface $encoderFactory The encoder factory
+ */
+ public function __construct(EncoderFactoryInterface $encoderFactory)
+ {
+ $this->encoderFactory = $encoderFactory;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function encodePassword(UserInterface $user, $plainPassword)
+ {
+ $encoder = $this->encoderFactory->getEncoder($user);
+
+ return $encoder->encodePassword($plainPassword, $user->getSalt());
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isPasswordValid(UserInterface $user, $raw)
+ {
+ $encoder = $this->encoderFactory->getEncoder($user);
+
+ return $encoder->isPasswordValid($user->getPassword(), $raw, $user->getSalt());
+ }
+}
diff --git a/Core/Encoder/UserPasswordEncoderInterface.php b/Core/Encoder/UserPasswordEncoderInterface.php
new file mode 100644
index 0000000..39e906a
--- /dev/null
+++ b/Core/Encoder/UserPasswordEncoderInterface.php
@@ -0,0 +1,41 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Core\Encoder;
+
+use Symfony\Component\Security\Core\User\UserInterface;
+
+/**
+ * UserPasswordEncoderInterface is the interface for the password encoder service.
+ *
+ * @author Ariel Ferrandini <arielferrandini@gmail.com>
+ */
+interface UserPasswordEncoderInterface
+{
+ /**
+ *
+ * Encodes the plain password.
+ *
+ * @param UserInterface $user The user
+ * @param string $plainPassword The password to encode
+ *
+ * @return string The encoded password
+ */
+ public function encodePassword(UserInterface $user, $plainPassword);
+
+ /**
+ * @param UserInterface $user The user
+ * @param string $raw A raw password
+ *
+ * @return bool true if the password is valid, false otherwise
+ */
+ public function isPasswordValid(UserInterface $user, $raw);
+}
diff --git a/Core/Exception/AccountExpiredException.php b/Core/Exception/AccountExpiredException.php
index a5618ce..4a71263 100644
--- a/Core/Exception/AccountExpiredException.php
+++ b/Core/Exception/AccountExpiredException.php
@@ -20,7 +20,7 @@ namespace Symfony\Component\Security\Core\Exception;
class AccountExpiredException extends AccountStatusException
{
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function getMessageKey()
{
diff --git a/Core/Exception/AccountStatusException.php b/Core/Exception/AccountStatusException.php
index 7819e4d..9b29f63 100644
--- a/Core/Exception/AccountStatusException.php
+++ b/Core/Exception/AccountStatusException.php
@@ -45,7 +45,7 @@ abstract class AccountStatusException extends AuthenticationException
}
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function serialize()
{
@@ -56,7 +56,7 @@ abstract class AccountStatusException extends AuthenticationException
}
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function unserialize($str)
{
diff --git a/Core/Exception/AuthenticationCredentialsNotFoundException.php b/Core/Exception/AuthenticationCredentialsNotFoundException.php
index 633b2be..8595bed 100644
--- a/Core/Exception/AuthenticationCredentialsNotFoundException.php
+++ b/Core/Exception/AuthenticationCredentialsNotFoundException.php
@@ -21,7 +21,7 @@ namespace Symfony\Component\Security\Core\Exception;
class AuthenticationCredentialsNotFoundException extends AuthenticationException
{
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function getMessageKey()
{
diff --git a/Core/Exception/AuthenticationServiceException.php b/Core/Exception/AuthenticationServiceException.php
index 758a4f0..66f051d 100644
--- a/Core/Exception/AuthenticationServiceException.php
+++ b/Core/Exception/AuthenticationServiceException.php
@@ -20,7 +20,7 @@ namespace Symfony\Component\Security\Core\Exception;
class AuthenticationServiceException extends AuthenticationException
{
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function getMessageKey()
{
diff --git a/Core/Exception/BadCredentialsException.php b/Core/Exception/BadCredentialsException.php
index 5deecca..be061c7 100644
--- a/Core/Exception/BadCredentialsException.php
+++ b/Core/Exception/BadCredentialsException.php
@@ -20,7 +20,7 @@ namespace Symfony\Component\Security\Core\Exception;
class BadCredentialsException extends AuthenticationException
{
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function getMessageKey()
{
diff --git a/Core/Exception/CookieTheftException.php b/Core/Exception/CookieTheftException.php
index 8d9e154..af97168 100644
--- a/Core/Exception/CookieTheftException.php
+++ b/Core/Exception/CookieTheftException.php
@@ -21,7 +21,7 @@ namespace Symfony\Component\Security\Core\Exception;
class CookieTheftException extends AuthenticationException
{
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function getMessageKey()
{
diff --git a/Core/Exception/CredentialsExpiredException.php b/Core/Exception/CredentialsExpiredException.php
index b9bf2d1..bcc1267 100644
--- a/Core/Exception/CredentialsExpiredException.php
+++ b/Core/Exception/CredentialsExpiredException.php
@@ -20,7 +20,7 @@ namespace Symfony\Component\Security\Core\Exception;
class CredentialsExpiredException extends AccountStatusException
{
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function getMessageKey()
{
diff --git a/Core/Exception/DisabledException.php b/Core/Exception/DisabledException.php
index 5571ab1..e9b784f 100644
--- a/Core/Exception/DisabledException.php
+++ b/Core/Exception/DisabledException.php
@@ -20,7 +20,7 @@ namespace Symfony\Component\Security\Core\Exception;
class DisabledException extends AccountStatusException
{
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function getMessageKey()
{
diff --git a/Core/Exception/InsufficientAuthenticationException.php b/Core/Exception/InsufficientAuthenticationException.php
index 74fc2b9..e33ef6a 100644
--- a/Core/Exception/InsufficientAuthenticationException.php
+++ b/Core/Exception/InsufficientAuthenticationException.php
@@ -22,7 +22,7 @@ namespace Symfony\Component\Security\Core\Exception;
class InsufficientAuthenticationException extends AuthenticationException
{
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function getMessageKey()
{
diff --git a/Core/Exception/InvalidCsrfTokenException.php b/Core/Exception/InvalidCsrfTokenException.php
index ce0e1f4..84be855 100644
--- a/Core/Exception/InvalidCsrfTokenException.php
+++ b/Core/Exception/InvalidCsrfTokenException.php
@@ -20,7 +20,7 @@ namespace Symfony\Component\Security\Core\Exception;
class InvalidCsrfTokenException extends AuthenticationException
{
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function getMessageKey()
{
diff --git a/Core/Exception/LockedException.php b/Core/Exception/LockedException.php
index 6532f70..fffae74 100644
--- a/Core/Exception/LockedException.php
+++ b/Core/Exception/LockedException.php
@@ -20,7 +20,7 @@ namespace Symfony\Component\Security\Core\Exception;
class LockedException extends AccountStatusException
{
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function getMessageKey()
{
diff --git a/Core/Exception/NonceExpiredException.php b/Core/Exception/NonceExpiredException.php
index 2f6681f..998e987 100644
--- a/Core/Exception/NonceExpiredException.php
+++ b/Core/Exception/NonceExpiredException.php
@@ -21,7 +21,7 @@ namespace Symfony\Component\Security\Core\Exception;
class NonceExpiredException extends AuthenticationException
{
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function getMessageKey()
{
diff --git a/Core/Exception/ProviderNotFoundException.php b/Core/Exception/ProviderNotFoundException.php
index ea2b1fd..af2e1b5 100644
--- a/Core/Exception/ProviderNotFoundException.php
+++ b/Core/Exception/ProviderNotFoundException.php
@@ -21,7 +21,7 @@ namespace Symfony\Component\Security\Core\Exception;
class ProviderNotFoundException extends AuthenticationException
{
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function getMessageKey()
{
diff --git a/Core/Exception/SessionUnavailableException.php b/Core/Exception/SessionUnavailableException.php
index 4b47b18..90b858a 100644
--- a/Core/Exception/SessionUnavailableException.php
+++ b/Core/Exception/SessionUnavailableException.php
@@ -26,7 +26,7 @@ namespace Symfony\Component\Security\Core\Exception;
class SessionUnavailableException extends AuthenticationException
{
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function getMessageKey()
{
diff --git a/Core/Exception/TokenNotFoundException.php b/Core/Exception/TokenNotFoundException.php
index fb85abf..b050302 100644
--- a/Core/Exception/TokenNotFoundException.php
+++ b/Core/Exception/TokenNotFoundException.php
@@ -20,7 +20,7 @@ namespace Symfony\Component\Security\Core\Exception;
class TokenNotFoundException extends AuthenticationException
{
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function getMessageKey()
{
diff --git a/Core/Exception/UsernameNotFoundException.php b/Core/Exception/UsernameNotFoundException.php
index f656bac..6979389 100644
--- a/Core/Exception/UsernameNotFoundException.php
+++ b/Core/Exception/UsernameNotFoundException.php
@@ -22,7 +22,7 @@ class UsernameNotFoundException extends AuthenticationException
private $username;
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function getMessageKey()
{
@@ -50,7 +50,7 @@ class UsernameNotFoundException extends AuthenticationException
}
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function serialize()
{
@@ -61,7 +61,7 @@ class UsernameNotFoundException extends AuthenticationException
}
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function unserialize($str)
{
@@ -69,4 +69,12 @@ class UsernameNotFoundException extends AuthenticationException
parent::unserialize($parentData);
}
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getMessageData()
+ {
+ return array('{{ username }}' => $this->username);
+ }
}
diff --git a/Core/README.md b/Core/README.md
index 4585a5d..66c323e 100644
--- a/Core/README.md
+++ b/Core/README.md
@@ -11,7 +11,7 @@ Resources
Documentation:
-http://symfony.com/doc/2.5/book/security.html
+http://symfony.com/doc/2.6/book/security.html
Tests
-----
diff --git a/Core/SecurityContext.php b/Core/SecurityContext.php
index c55cecf..1f46cd6 100644
--- a/Core/SecurityContext.php
+++ b/Core/SecurityContext.php
@@ -11,10 +11,13 @@
namespace Symfony\Component\Security\Core;
-use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException;
-use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
+use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
+use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
+use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;
+use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
/**
* SecurityContext is the main entry point of the Security component.
@@ -23,63 +26,76 @@ use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ * @deprecated Deprecated since version 2.6, to be removed in 3.0.
*/
class SecurityContext implements SecurityContextInterface
{
- private $token;
- private $accessDecisionManager;
- private $authenticationManager;
- private $alwaysAuthenticate;
+ /**
+ * @var TokenStorageInterface
+ */
+ private $tokenStorage;
/**
- * Constructor.
- *
- * @param AuthenticationManagerInterface $authenticationManager An AuthenticationManager instance
- * @param AccessDecisionManagerInterface|null $accessDecisionManager An AccessDecisionManager instance
- * @param Boolean $alwaysAuthenticate
+ * @var AuthorizationCheckerInterface
*/
- public function __construct(AuthenticationManagerInterface $authenticationManager, AccessDecisionManagerInterface $accessDecisionManager, $alwaysAuthenticate = false)
- {
- $this->authenticationManager = $authenticationManager;
- $this->accessDecisionManager = $accessDecisionManager;
- $this->alwaysAuthenticate = $alwaysAuthenticate;
- }
+ private $authorizationChecker;
/**
- * {@inheritdoc}
+ * For backwords compatibility, the signature of sf <2.6 still works
*
- * @throws AuthenticationCredentialsNotFoundException when the security context has no authentication token.
+ * @param TokenStorageInterface|AuthenticationManagerInterface $tokenStorage
+ * @param AuthorizationCheckerInterface|AccessDecisionManagerInterface $authorizationChecker
+ * @param bool $alwaysAuthenticate only applicable with old signature
*/
- final public function isGranted($attributes, $object = null)
+ public function __construct($tokenStorage, $authorizationChecker, $alwaysAuthenticate = false)
{
- if (null === $this->token) {
- throw new AuthenticationCredentialsNotFoundException('The security context contains no authentication token. One possible reason may be that there is no firewall configured for this URL.');
- }
+ $oldSignature = $tokenStorage instanceof AuthenticationManagerInterface && $authorizationChecker instanceof AccessDecisionManagerInterface;
+ $newSignature = $tokenStorage instanceof TokenStorageInterface && $authorizationChecker instanceof AuthorizationCheckerInterface;
- if ($this->alwaysAuthenticate || !$this->token->isAuthenticated()) {
- $this->token = $this->authenticationManager->authenticate($this->token);
+ // confirm possible signatures
+ if (!$oldSignature && !$newSignature) {
+ throw new \BadMethodCallException('Unable to construct SecurityContext, please provide the correct arguments');
}
- if (!is_array($attributes)) {
- $attributes = array($attributes);
+ if ($oldSignature) {
+ // renamed for clearity
+ $authenticationManager = $tokenStorage;
+ $accessDecisionManager = $authorizationChecker;
+ $tokenStorage = new TokenStorage();
+ $authorizationChecker = new AuthorizationChecker($tokenStorage, $authenticationManager, $accessDecisionManager, $alwaysAuthenticate);
}
- return $this->accessDecisionManager->decide($this->token, $attributes, $object);
+ $this->tokenStorage = $tokenStorage;
+ $this->authorizationChecker = $authorizationChecker;
}
/**
+ * @deprecated Deprecated since version 2.6, to be removed in 3.0. Use TokenStorageInterface::getToken() instead.
+ *
* {@inheritdoc}
*/
public function getToken()
{
- return $this->token;
+ return $this->tokenStorage->getToken();
}
/**
+ * @deprecated Deprecated since version 2.6, to be removed in 3.0. Use TokenStorageInterface::setToken() instead.
+ *
* {@inheritdoc}
*/
public function setToken(TokenInterface $token = null)
{
- $this->token = $token;
+ return $this->tokenStorage->setToken($token);
+ }
+
+ /**
+ * @deprecated Deprecated since version 2.6, to be removed in 3.0. Use AuthorizationCheckerInterface::isGranted() instead.
+ *
+ * {@inheritdoc}
+ */
+ public function isGranted($attributes, $object = null)
+ {
+ return $this->authorizationChecker->isGranted($attributes, $object);
}
}
diff --git a/Core/SecurityContextInterface.php b/Core/SecurityContextInterface.php
index 434f9a5..844482b 100644
--- a/Core/SecurityContextInterface.php
+++ b/Core/SecurityContextInterface.php
@@ -11,40 +11,15 @@
namespace Symfony\Component\Security\Core;
-use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
+use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
/**
* The SecurityContextInterface.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ * @deprecated Deprecated since version 2.6, to be removed in 3.0.
*/
-interface SecurityContextInterface
+interface SecurityContextInterface extends TokenStorageInterface, AuthorizationCheckerInterface, SecuritySessionStorageInterface
{
- const ACCESS_DENIED_ERROR = '_security.403_error';
- const AUTHENTICATION_ERROR = '_security.last_error';
- const LAST_USERNAME = '_security.last_username';
-
- /**
- * Returns the current security token.
- *
- * @return TokenInterface|null A TokenInterface instance or null if no authentication information is available
- */
- public function getToken();
-
- /**
- * Sets the authentication token.
- *
- * @param TokenInterface $token A TokenInterface token, or null if no further authentication information should be stored
- */
- public function setToken(TokenInterface $token = null);
-
- /**
- * Checks if the attributes are granted against the current authentication token and optionally supplied object.
- *
- * @param mixed $attributes
- * @param mixed $object
- *
- * @return Boolean
- */
- public function isGranted($attributes, $object = null);
}
diff --git a/Core/SecuritySessionStorageInterface.php b/Core/SecuritySessionStorageInterface.php
new file mode 100644
index 0000000..47c0bbe
--- /dev/null
+++ b/Core/SecuritySessionStorageInterface.php
@@ -0,0 +1,24 @@
+<?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;
+
+/**
+ * The SecuritySessionStorageInterface.
+ *
+ * @author Johannes M. Schmitt <schmittjoh@gmail.com>
+ */
+interface SecuritySessionStorageInterface
+{
+ const ACCESS_DENIED_ERROR = '_security.403_error';
+ const AUTHENTICATION_ERROR = '_security.last_error';
+ const LAST_USERNAME = '_security.last_username';
+}
diff --git a/Core/Tests/Authentication/AuthenticationProviderManagerTest.php b/Core/Tests/Authentication/AuthenticationProviderManagerTest.php
index f63ef79..df25874 100644
--- a/Core/Tests/Authentication/AuthenticationProviderManagerTest.php
+++ b/Core/Tests/Authentication/AuthenticationProviderManagerTest.php
@@ -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/Core/Tests/Authentication/Token/AbstractTokenTest.php b/Core/Tests/Authentication/Token/AbstractTokenTest.php
index 098017e..6f2b6ed 100644
--- a/Core/Tests/Authentication/Token/AbstractTokenTest.php
+++ b/Core/Tests/Authentication/Token/AbstractTokenTest.php
@@ -52,7 +52,9 @@ class ConcreteToken extends AbstractToken
parent::unserialize($parentStr);
}
- public function getCredentials() {}
+ public function getCredentials()
+ {
+ }
}
class AbstractTokenTest extends \PHPUnit_Framework_TestCase
@@ -227,13 +229,13 @@ class AbstractTokenTest extends \PHPUnit_Framework_TestCase
'foo', $user,
),
array(
- 'foo', $advancedUser
+ 'foo', $advancedUser,
),
array(
- $user, 'foo'
+ $user, 'foo',
),
array(
- $advancedUser, 'foo'
+ $advancedUser, 'foo',
),
array(
$user, new TestUser('foo'),
@@ -254,10 +256,10 @@ class AbstractTokenTest extends \PHPUnit_Framework_TestCase
new TestUser('foo'), $advancedUser,
),
array(
- $user, $advancedUser
+ $user, $advancedUser,
),
array(
- $advancedUser, $user
+ $advancedUser, $user,
),
);
}
diff --git a/Core/Tests/Authentication/Token/Storage/TokenStorageTest.php b/Core/Tests/Authentication/Token/Storage/TokenStorageTest.php
new file mode 100644
index 0000000..d06e3f0
--- /dev/null
+++ b/Core/Tests/Authentication/Token/Storage/TokenStorageTest.php
@@ -0,0 +1,26 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Core\Tests\Authentication\Token\Storage;
+
+use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
+
+class TokenStorageTest extends \PHPUnit_Framework_TestCase
+{
+ public function testGetSetToken()
+ {
+ $tokenStorage = new TokenStorage();
+ $this->assertNull($tokenStorage->getToken());
+ $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+ $tokenStorage->setToken($token);
+ $this->assertSame($token, $tokenStorage->getToken());
+ }
+}
diff --git a/Core/Tests/Authorization/AccessDecisionManagerTest.php b/Core/Tests/Authorization/AccessDecisionManagerTest.php
index e182838..bf0ad11 100644
--- a/Core/Tests/Authorization/AccessDecisionManagerTest.php
+++ b/Core/Tests/Authorization/AccessDecisionManagerTest.php
@@ -73,6 +73,48 @@ class AccessDecisionManagerTest extends \PHPUnit_Framework_TestCase
$this->assertSame($expected, $manager->decide($token, array('ROLE_FOO')));
}
+ /**
+ * @dataProvider getStrategiesWith2RolesTests
+ */
+ public function testStrategiesWith2Roles($token, $strategy, $voter, $expected)
+ {
+ $manager = new AccessDecisionManager(array($voter), $strategy);
+
+ $this->assertSame($expected, $manager->decide($token, array('ROLE_FOO', 'ROLE_BAR')));
+ }
+
+ public function getStrategiesWith2RolesTests()
+ {
+ $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+
+ return array(
+ array($token, 'affirmative', $this->getVoter(VoterInterface::ACCESS_DENIED), false),
+ array($token, 'affirmative', $this->getVoter(VoterInterface::ACCESS_GRANTED), true),
+
+ array($token, 'consensus', $this->getVoter(VoterInterface::ACCESS_DENIED), false),
+ array($token, 'consensus', $this->getVoter(VoterInterface::ACCESS_GRANTED), true),
+
+ array($token, 'unanimous', $this->getVoterFor2Roles($token, VoterInterface::ACCESS_DENIED, VoterInterface::ACCESS_DENIED), false),
+ array($token, 'unanimous', $this->getVoterFor2Roles($token, VoterInterface::ACCESS_DENIED, VoterInterface::ACCESS_GRANTED), false),
+ array($token, 'unanimous', $this->getVoterFor2Roles($token, VoterInterface::ACCESS_GRANTED, VoterInterface::ACCESS_DENIED), false),
+ array($token, 'unanimous', $this->getVoterFor2Roles($token, VoterInterface::ACCESS_GRANTED, VoterInterface::ACCESS_GRANTED), true),
+ );
+ }
+
+ protected function getVoterFor2Roles($token, $vote1, $vote2)
+ {
+ $voter = $this->getMock('Symfony\Component\Security\Core\Authorization\Voter\VoterInterface');
+ $voter->expects($this->exactly(2))
+ ->method('vote')
+ ->will($this->returnValueMap(array(
+ array($token, null, array("ROLE_FOO"),$vote1),
+ array($token, null, array("ROLE_BAR"),$vote2),
+ )))
+ ;
+
+ return $voter;
+ }
+
public function getStrategyTests()
{
return array(
@@ -130,7 +172,6 @@ class AccessDecisionManagerTest extends \PHPUnit_Framework_TestCase
$voter->expects($this->any())
->method('vote')
->will($this->returnValue($vote));
- ;
return $voter;
}
@@ -141,7 +182,6 @@ class AccessDecisionManagerTest extends \PHPUnit_Framework_TestCase
$voter->expects($this->any())
->method('supportsClass')
->will($this->returnValue($ret));
- ;
return $voter;
}
@@ -152,7 +192,6 @@ class AccessDecisionManagerTest extends \PHPUnit_Framework_TestCase
$voter->expects($this->any())
->method('supportsAttribute')
->will($this->returnValue($ret));
- ;
return $voter;
}
diff --git a/Core/Tests/Authorization/AuthorizationCheckerTest.php b/Core/Tests/Authorization/AuthorizationCheckerTest.php
new file mode 100644
index 0000000..64de6ef
--- /dev/null
+++ b/Core/Tests/Authorization/AuthorizationCheckerTest.php
@@ -0,0 +1,99 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Core\Tests\Authorization;
+
+use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
+use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;
+
+class AuthorizationCheckerTest extends \PHPUnit_Framework_TestCase
+{
+ private $authenticationManager;
+ private $accessDecisionManager;
+ private $authorizationChecker;
+ private $tokenStorage;
+
+ public function setUp()
+ {
+ $this->authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface');
+ $this->accessDecisionManager = $this->getMock('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface');
+ $this->tokenStorage = new TokenStorage();
+
+ $this->authorizationChecker = new AuthorizationChecker(
+ $this->tokenStorage,
+ $this->authenticationManager,
+ $this->accessDecisionManager
+ );
+ }
+
+ public function testVoteAuthenticatesTokenIfNecessary()
+ {
+ $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+ $this->tokenStorage->setToken($token);
+
+ $newToken = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+
+ $this->authenticationManager
+ ->expects($this->once())
+ ->method('authenticate')
+ ->with($this->equalTo($token))
+ ->will($this->returnValue($newToken));
+
+ // default with() isn't a strict check
+ $tokenComparison = function ($value) use ($newToken) {
+ // make sure that the new token is used in "decide()" and not the old one
+ return $value === $newToken;
+ };
+
+ $this->accessDecisionManager
+ ->expects($this->once())
+ ->method('decide')
+ ->with($this->callback($tokenComparison))
+ ->will($this->returnValue(true));
+
+ // first run the token has not been re-authenticated yet, after isGranted is called, it should be equal
+ $this->assertFalse($newToken === $this->tokenStorage->getToken());
+ $this->assertTrue($this->authorizationChecker->isGranted('foo'));
+ $this->assertTrue($newToken === $this->tokenStorage->getToken());
+ }
+
+ /**
+ * @expectedException \Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException
+ */
+ public function testVoteWithoutAuthenticationToken()
+ {
+ $this->authorizationChecker->isGranted('ROLE_FOO');
+ }
+
+ /**
+ * @dataProvider isGrantedProvider
+ */
+ public function testIsGranted($decide)
+ {
+ $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+ $token
+ ->expects($this->once())
+ ->method('isAuthenticated')
+ ->will($this->returnValue(true));
+
+ $this->accessDecisionManager
+ ->expects($this->once())
+ ->method('decide')
+ ->will($this->returnValue($decide));
+ $this->tokenStorage->setToken($token);
+ $this->assertTrue($decide === $this->authorizationChecker->isGranted('ROLE_FOO'));
+ }
+
+ public function isGrantedProvider()
+ {
+ return array(array(true), array(false));
+ }
+}
diff --git a/Core/Tests/Authorization/Voter/RoleVoterTest.php b/Core/Tests/Authorization/Voter/RoleVoterTest.php
index 62e3013..03ab2da 100644
--- a/Core/Tests/Authorization/Voter/RoleVoterTest.php
+++ b/Core/Tests/Authorization/Voter/RoleVoterTest.php
@@ -55,7 +55,6 @@ class RoleVoterTest extends \PHPUnit_Framework_TestCase
$token->expects($this->once())
->method('getRoles')
->will($this->returnValue($roles));
- ;
return $token;
}
diff --git a/Core/Tests/Encoder/EncoderFactoryTest.php b/Core/Tests/Encoder/EncoderFactoryTest.php
index 3d34d04..a8ca2f0 100644
--- a/Core/Tests/Encoder/EncoderFactoryTest.php
+++ b/Core/Tests/Encoder/EncoderFactoryTest.php
@@ -84,7 +84,7 @@ class EncoderFactoryTest extends \PHPUnit_Framework_TestCase
{
$factory = new EncoderFactory(array(
'Symfony\Component\Security\Core\Tests\Encoder\EncAwareUser' => new MessageDigestPasswordEncoder('sha256'),
- 'encoder_name' => new MessageDigestPasswordEncoder('sha1')
+ 'encoder_name' => new MessageDigestPasswordEncoder('sha1'),
));
$encoder = $factory->getEncoder(new EncAwareUser('user', 'pass'));
@@ -96,7 +96,7 @@ class EncoderFactoryTest extends \PHPUnit_Framework_TestCase
{
$factory = new EncoderFactory(array(
'Symfony\Component\Security\Core\Tests\Encoder\EncAwareUser' => new MessageDigestPasswordEncoder('sha1'),
- 'encoder_name' => new MessageDigestPasswordEncoder('sha256')
+ 'encoder_name' => new MessageDigestPasswordEncoder('sha256'),
));
$user = new EncAwareUser('user', 'pass');
@@ -113,7 +113,7 @@ class EncoderFactoryTest extends \PHPUnit_Framework_TestCase
{
$factory = new EncoderFactory(array(
'Symfony\Component\Security\Core\Tests\Encoder\EncAwareUser' => new MessageDigestPasswordEncoder('sha1'),
- 'encoder_name' => new MessageDigestPasswordEncoder('sha256')
+ 'encoder_name' => new MessageDigestPasswordEncoder('sha256'),
));
$user = new EncAwareUser('user', 'pass');
@@ -125,7 +125,7 @@ class EncoderFactoryTest extends \PHPUnit_Framework_TestCase
{
$factory = new EncoderFactory(array(
'Symfony\Component\Security\Core\Tests\Encoder\EncAwareUser' => new MessageDigestPasswordEncoder('sha1'),
- 'encoder_name' => new MessageDigestPasswordEncoder('sha256')
+ 'encoder_name' => new MessageDigestPasswordEncoder('sha256'),
));
$encoder = $factory->getEncoder('Symfony\Component\Security\Core\Tests\Encoder\EncAwareUser');
@@ -136,11 +136,21 @@ class EncoderFactoryTest extends \PHPUnit_Framework_TestCase
class SomeUser implements UserInterface
{
- public function getRoles() {}
- public function getPassword() {}
- public function getSalt() {}
- public function getUsername() {}
- public function eraseCredentials() {}
+ public function getRoles()
+ {
+ }
+ public function getPassword()
+ {
+ }
+ public function getSalt()
+ {
+ }
+ public function getUsername()
+ {
+ }
+ public function eraseCredentials()
+ {
+ }
}
class SomeChildUser extends SomeUser
diff --git a/Core/Tests/Encoder/UserPasswordEncoderTest.php b/Core/Tests/Encoder/UserPasswordEncoderTest.php
new file mode 100644
index 0000000..590652d
--- /dev/null
+++ b/Core/Tests/Encoder/UserPasswordEncoderTest.php
@@ -0,0 +1,70 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Core\Tests\Encoder;
+
+use Symfony\Component\Security\Core\Encoder\UserPasswordEncoder;
+
+class UserPasswordEncoderTest extends \PHPUnit_Framework_TestCase
+{
+ public function testEncodePassword()
+ {
+ $userMock = $this->getMock('Symfony\Component\Security\Core\User\UserInterface');
+ $userMock->expects($this->any())
+ ->method('getSalt')
+ ->will($this->returnValue('userSalt'));
+
+ $mockEncoder = $this->getMock('Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface');
+ $mockEncoder->expects($this->any())
+ ->method('encodePassword')
+ ->with($this->equalTo('plainPassword'), $this->equalTo('userSalt'))
+ ->will($this->returnValue('encodedPassword'));
+
+ $mockEncoderFactory = $this->getMock('Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface');
+ $mockEncoderFactory->expects($this->any())
+ ->method('getEncoder')
+ ->with($this->equalTo($userMock))
+ ->will($this->returnValue($mockEncoder));
+
+ $passwordEncoder = new UserPasswordEncoder($mockEncoderFactory);
+
+ $encoded = $passwordEncoder->encodePassword($userMock, 'plainPassword');
+ $this->assertEquals('encodedPassword', $encoded);
+ }
+
+ public function testIsPasswordValid()
+ {
+ $userMock = $this->getMock('Symfony\Component\Security\Core\User\UserInterface');
+ $userMock->expects($this->any())
+ ->method('getSalt')
+ ->will($this->returnValue('userSalt'));
+ $userMock->expects($this->any())
+ ->method('getPassword')
+ ->will($this->returnValue('encodedPassword'));
+
+ $mockEncoder = $this->getMock('Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface');
+ $mockEncoder->expects($this->any())
+ ->method('isPasswordValid')
+ ->with($this->equalTo('encodedPassword'), $this->equalTo('plainPassword'), $this->equalTo('userSalt'))
+ ->will($this->returnValue(true));
+
+ $mockEncoderFactory = $this->getMock('Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface');
+ $mockEncoderFactory->expects($this->any())
+ ->method('getEncoder')
+ ->with($this->equalTo($userMock))
+ ->will($this->returnValue($mockEncoder));
+
+ $passwordEncoder = new UserPasswordEncoder($mockEncoderFactory);
+
+ $isValid = $passwordEncoder->isPasswordValid($userMock, 'plainPassword');
+ $this->assertTrue($isValid);
+ }
+}
diff --git a/Core/Tests/Exception/UsernameNotFoundExceptionTest.php b/Core/Tests/Exception/UsernameNotFoundExceptionTest.php
new file mode 100644
index 0000000..98ea374
--- /dev/null
+++ b/Core/Tests/Exception/UsernameNotFoundExceptionTest.php
@@ -0,0 +1,25 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Core\Tests\Exception;
+
+use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
+
+class UsernameNotFoundExceptionTest extends \PHPUnit_Framework_TestCase
+{
+ public function testGetMessageData()
+ {
+ $exception = new UsernameNotFoundException('Username could not be found.');
+ $this->assertEquals(array('{{ username }}' => null), $exception->getMessageData());
+ $exception->setUsername('username');
+ $this->assertEquals(array('{{ username }}' => 'username'), $exception->getMessageData());
+ }
+}
diff --git a/Core/Tests/SecurityContextTest.php b/Core/Tests/SecurityContextTest.php
index dd0e2e3..886c596 100644
--- a/Core/Tests/SecurityContextTest.php
+++ b/Core/Tests/SecurityContextTest.php
@@ -11,82 +11,109 @@
namespace Symfony\Component\Security\Core\Tests;
+use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
+use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;
use Symfony\Component\Security\Core\SecurityContext;
class SecurityContextTest extends \PHPUnit_Framework_TestCase
{
- public function testVoteAuthenticatesTokenIfNecessary()
+ private $tokenStorage;
+ private $authorizationChecker;
+ private $securityContext;
+
+ public function setUp()
{
- $authManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface');
- $decisionManager = $this->getMock('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface');
+ $this->tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface');
+ $this->authorizationChecker = $this->getMock('Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface');
+ $this->securityContext = new SecurityContext($this->tokenStorage, $this->authorizationChecker);
+ }
- $context = new SecurityContext($authManager, $decisionManager);
- $context->setToken($token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'));
+ public function testGetTokenDelegation()
+ {
+ $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
- $authManager
+ $this->tokenStorage
->expects($this->once())
- ->method('authenticate')
- ->with($this->equalTo($token))
- ->will($this->returnValue($newToken = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')))
- ;
+ ->method('getToken')
+ ->will($this->returnValue($token));
- $decisionManager
+ $this->assertTrue($token === $this->securityContext->getToken());
+ }
+
+ public function testSetTokenDelegation()
+ {
+ $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
+
+ $this->tokenStorage
->expects($this->once())
- ->method('decide')
- ->will($this->returnValue(true))
- ;
+ ->method('setToken')
+ ->with($token);
- $this->assertTrue($context->isGranted('foo'));
- $this->assertSame($newToken, $context->getToken());
+ $this->securityContext->setToken($token);
}
/**
- * @expectedException \Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException
+ * @dataProvider isGrantedDelegationProvider
*/
- public function testVoteWithoutAuthenticationToken()
+ public function testIsGrantedDelegation($attributes, $object, $return)
+ {
+ $this->authorizationChecker
+ ->expects($this->once())
+ ->method('isGranted')
+ ->with($attributes, $object)
+ ->will($this->returnValue($return));
+
+ $this->assertEquals($return, $this->securityContext->isGranted($attributes, $object));
+ }
+
+ public function isGrantedDelegationProvider()
{
- $context = new SecurityContext(
- $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'),
- $this->getMock('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface')
+ return array(
+ array(array(), new \stdClass(), true),
+ array(array('henk'), new \stdClass(), false),
+ array(null, new \stdClass(), false),
+ array('henk', null, true),
+ array(array(1), 'henk', true),
);
+ }
- $context->isGranted('ROLE_FOO');
+ /**
+ * Test dedicated to check if the backwards compatibility is still working
+ */
+ public function testOldConstructorSignature()
+ {
+ $authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface');
+ $accessDecisionManager = $this->getMock('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface');
+ new SecurityContext($authenticationManager, $accessDecisionManager);
}
- public function testIsGranted()
+ /**
+ * @dataProvider oldConstructorSignatureFailuresProvider
+ * @expectedException \BadMethodCallException
+ */
+ public function testOldConstructorSignatureFailures($first, $second)
{
- $manager = $this->getMock('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface');
- $manager->expects($this->once())->method('decide')->will($this->returnValue(false));
- $context = new SecurityContext($this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'), $manager);
- $context->setToken($token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'));
- $token
- ->expects($this->once())
- ->method('isAuthenticated')
- ->will($this->returnValue(true))
- ;
- $this->assertFalse($context->isGranted('ROLE_FOO'));
-
- $manager = $this->getMock('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface');
- $manager->expects($this->once())->method('decide')->will($this->returnValue(true));
- $context = new SecurityContext($this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'), $manager);
- $context->setToken($token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'));
- $token
- ->expects($this->once())
- ->method('isAuthenticated')
- ->will($this->returnValue(true))
- ;
- $this->assertTrue($context->isGranted('ROLE_FOO'));
+ new SecurityContext($first, $second);
}
- public function testGetSetToken()
+ public function oldConstructorSignatureFailuresProvider()
{
- $context = new SecurityContext(
- $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface'),
- $this->getMock('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface')
- );
- $this->assertNull($context->getToken());
+ $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface');
+ $authorizationChecker = $this->getMock('Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface');
+ $authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface');
+ $accessDecisionManager = $this->getMock('Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface');
- $context->setToken($token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface'));
- $this->assertSame($token, $context->getToken());
+ return array(
+ array(new \stdClass(), new \stdClass()),
+ array($tokenStorage, $accessDecisionManager),
+ array($accessDecisionManager, $tokenStorage),
+ array($authorizationChecker, $accessDecisionManager),
+ array($accessDecisionManager, $authorizationChecker),
+ array($tokenStorage, $accessDecisionManager),
+ array($authenticationManager, $authorizationChecker),
+ array('henk', 'hans'),
+ array(null, false),
+ array(true, null),
+ );
}
}
diff --git a/Core/Tests/Util/StringUtilsTest.php b/Core/Tests/Util/StringUtilsTest.php
index 89da98d..e0366a5 100644
--- a/Core/Tests/Util/StringUtilsTest.php
+++ b/Core/Tests/Util/StringUtilsTest.php
@@ -13,11 +13,49 @@ namespace Symfony\Component\Security\Core\Tests\Util;
use Symfony\Component\Security\Core\Util\StringUtils;
+/**
+ * Data from PHP.net's hash_equals tests
+ */
class StringUtilsTest extends \PHPUnit_Framework_TestCase
{
- public function testEquals()
+ public function dataProviderTrue()
+ {
+ return array(
+ array('same', 'same'),
+ array('', ''),
+ array(123, 123),
+ array(null, ''),
+ array(null, null),
+ );
+ }
+
+ public function dataProviderFalse()
+ {
+ return array(
+ array('not1same', 'not2same'),
+ array('short', 'longer'),
+ array('longer', 'short'),
+ array('', 'notempty'),
+ array('notempty', ''),
+ array(123, 'NaN'),
+ array('NaN', 123),
+ array(null, 123),
+ );
+ }
+
+ /**
+ * @dataProvider dataProviderTrue
+ */
+ public function testEqualsTrue($known, $user)
+ {
+ $this->assertTrue(StringUtils::equals($known, $user));
+ }
+
+ /**
+ * @dataProvider dataProviderFalse
+ */
+ public function testEqualsFalse($known, $user)
{
- $this->assertTrue(StringUtils::equals('password', 'password'));
- $this->assertFalse(StringUtils::equals('password', 'foo'));
+ $this->assertFalse(StringUtils::equals($known, $user));
}
}
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/LegacyUserPasswordValidatorLegacyApiTest.php b/Core/Tests/Validator/Constraints/LegacyUserPasswordValidatorLegacyApiTest.php
new file mode 100644
index 0000000..5092a79
--- /dev/null
+++ b/Core/Tests/Validator/Constraints/LegacyUserPasswordValidatorLegacyApiTest.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 LegacyUserPasswordValidatorLegacyApiTest 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
index 53eeb5f..10f692c 100644
--- a/Core/Tests/Validator/Constraints/UserPasswordValidatorTest.php
+++ b/Core/Tests/Validator/Constraints/UserPasswordValidatorTest.php
@@ -11,77 +11,102 @@
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;
+use Symfony\Component\Validator\Validation;
-class UserPasswordValidatorTest extends \PHPUnit_Framework_TestCase
+/**
+ * @author Bernhard Schussek <bschussek@gmail.com>
+ */
+class UserPasswordValidatorTest extends AbstractConstraintValidatorTest
{
- const PASSWORD_VALID = true;
- const PASSWORD_INVALID = false;
+ const PASSWORD = 's3Cr3t';
- protected $context;
+ const SALT = '^S4lt$';
- protected function setUp()
+ /**
+ * @var SecurityContextInterface
+ */
+ protected $securityContext;
+
+ /**
+ * @var PasswordEncoderInterface
+ */
+ protected $encoder;
+
+ /**
+ * @var EncoderFactoryInterface
+ */
+ protected $encoderFactory;
+
+ protected function getApiVersion()
{
- $this->context = $this->getMock('Symfony\Component\Validator\ExecutionContext', array(), array(), '', false);
+ return Validation::API_VERSION_2_5;
}
- protected function tearDown()
+ protected function createValidator()
{
- $this->context = null;
+ return new UserPasswordValidator($this->securityContext, $this->encoderFactory);
}
- public function testPasswordIsValid()
+ protected function setUp()
{
$user = $this->createUser();
- $securityContext = $this->createSecurityContext($user);
+ $this->securityContext = $this->createSecurityContext($user);
+ $this->encoder = $this->createPasswordEncoder();
+ $this->encoderFactory = $this->createEncoderFactory($this->encoder);
- $encoder = $this->createPasswordEncoder(static::PASSWORD_VALID);
- $encoderFactory = $this->createEncoderFactory($encoder);
+ parent::setUp();
+ }
+
+ public function testPasswordIsValid()
+ {
+ $constraint = new UserPassword(array(
+ 'message' => 'myMessage',
+ ));
- $validator = new UserPasswordValidator($securityContext, $encoderFactory);
- $validator->initialize($this->context);
+ $this->encoder->expects($this->once())
+ ->method('isPasswordValid')
+ ->with(static::PASSWORD, 'secret', static::SALT)
+ ->will($this->returnValue(true));
- $this
- ->context
- ->expects($this->never())
- ->method('addViolation')
- ;
+ $this->validator->validate('secret', $constraint);
- $validator->validate('secret', new UserPassword());
+ $this->assertNoViolation();
}
public function testPasswordIsNotValid()
{
- $user = $this->createUser();
- $securityContext = $this->createSecurityContext($user);
-
- $encoder = $this->createPasswordEncoder(static::PASSWORD_INVALID);
- $encoderFactory = $this->createEncoderFactory($encoder);
+ $constraint = new UserPassword(array(
+ 'message' => 'myMessage',
+ ));
- $validator = new UserPasswordValidator($securityContext, $encoderFactory);
- $validator->initialize($this->context);
+ $this->encoder->expects($this->once())
+ ->method('isPasswordValid')
+ ->with(static::PASSWORD, 'secret', static::SALT)
+ ->will($this->returnValue(false));
- $this
- ->context
- ->expects($this->once())
- ->method('addViolation')
- ;
+ $this->validator->validate('secret', $constraint);
- $validator->validate('secret', new UserPassword());
+ $this->assertViolation('myMessage');
}
+ /**
+ * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException
+ */
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());
+ $this->securityContext = $this->createSecurityContext($user);
+ $this->validator = $this->createValidator();
+ $this->validator->initialize($this->context);
+
+ $this->validator->validate('secret', new UserPassword());
}
protected function createUser()
@@ -89,15 +114,15 @@ class UserPasswordValidatorTest extends \PHPUnit_Framework_TestCase
$mock = $this->getMock('Symfony\Component\Security\Core\User\UserInterface');
$mock
- ->expects($this->once())
+ ->expects($this->any())
->method('getPassword')
- ->will($this->returnValue('s3Cr3t'))
+ ->will($this->returnValue(static::PASSWORD))
;
$mock
- ->expects($this->once())
+ ->expects($this->any())
->method('getSalt')
- ->will($this->returnValue('^S4lt$'))
+ ->will($this->returnValue(static::SALT))
;
return $mock;
@@ -105,15 +130,7 @@ class UserPasswordValidatorTest extends \PHPUnit_Framework_TestCase
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;
+ return $this->getMock('Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface');
}
protected function createEncoderFactory($encoder = null)
@@ -121,7 +138,7 @@ class UserPasswordValidatorTest extends \PHPUnit_Framework_TestCase
$mock = $this->getMock('Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface');
$mock
- ->expects($this->once())
+ ->expects($this->any())
->method('getEncoder')
->will($this->returnValue($encoder))
;
@@ -135,7 +152,7 @@ class UserPasswordValidatorTest extends \PHPUnit_Framework_TestCase
$mock = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
$mock
- ->expects($this->once())
+ ->expects($this->any())
->method('getToken')
->will($this->returnValue($token))
;
@@ -147,7 +164,7 @@ class UserPasswordValidatorTest extends \PHPUnit_Framework_TestCase
{
$mock = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
$mock
- ->expects($this->once())
+ ->expects($this->any())
->method('getUser')
->will($this->returnValue($user))
;
diff --git a/Core/User/AdvancedUserInterface.php b/Core/User/AdvancedUserInterface.php
index 5b3a51a..19775c0 100644
--- a/Core/User/AdvancedUserInterface.php
+++ b/Core/User/AdvancedUserInterface.php
@@ -43,7 +43,7 @@ interface AdvancedUserInterface extends UserInterface
* Internally, if this method returns false, the authentication system
* will throw an AccountExpiredException and prevent login.
*
- * @return Boolean true if the user's account is non expired, false otherwise
+ * @return bool true if the user's account is non expired, false otherwise
*
* @see AccountExpiredException
*/
@@ -55,7 +55,7 @@ interface AdvancedUserInterface extends UserInterface
* Internally, if this method returns false, the authentication system
* will throw a LockedException and prevent login.
*
- * @return Boolean true if the user is not locked, false otherwise
+ * @return bool true if the user is not locked, false otherwise
*
* @see LockedException
*/
@@ -67,7 +67,7 @@ interface AdvancedUserInterface extends UserInterface
* Internally, if this method returns false, the authentication system
* will throw a CredentialsExpiredException and prevent login.
*
- * @return Boolean true if the user's credentials are non expired, false otherwise
+ * @return bool true if the user's credentials are non expired, false otherwise
*
* @see CredentialsExpiredException
*/
@@ -79,7 +79,7 @@ interface AdvancedUserInterface extends UserInterface
* Internally, if this method returns false, the authentication system
* will throw a DisabledException and prevent login.
*
- * @return Boolean true if the user is enabled, false otherwise
+ * @return bool true if the user is enabled, false otherwise
*
* @see DisabledException
*/
diff --git a/Core/User/ChainUserProvider.php b/Core/User/ChainUserProvider.php
index fc72074..6e14a4f 100644
--- a/Core/User/ChainUserProvider.php
+++ b/Core/User/ChainUserProvider.php
@@ -40,7 +40,7 @@ class ChainUserProvider implements UserProviderInterface
}
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function loadUserByUsername($username)
{
@@ -58,7 +58,7 @@ class ChainUserProvider implements UserProviderInterface
}
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function refreshUser(UserInterface $user)
{
@@ -85,7 +85,7 @@ class ChainUserProvider implements UserProviderInterface
}
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function supportsClass($class)
{
diff --git a/Core/User/EquatableInterface.php b/Core/User/EquatableInterface.php
index 645b77c..c6082ce 100644
--- a/Core/User/EquatableInterface.php
+++ b/Core/User/EquatableInterface.php
@@ -31,7 +31,7 @@ interface EquatableInterface
*
* @param UserInterface $user
*
- * @return Boolean
+ * @return bool
*/
public function isEqualTo(UserInterface $user);
}
diff --git a/Core/User/InMemoryUserProvider.php b/Core/User/InMemoryUserProvider.php
index 074c21e..624eb3d 100644
--- a/Core/User/InMemoryUserProvider.php
+++ b/Core/User/InMemoryUserProvider.php
@@ -81,7 +81,7 @@ class InMemoryUserProvider implements UserProviderInterface
}
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function refreshUser(UserInterface $user)
{
@@ -93,7 +93,7 @@ class InMemoryUserProvider implements UserProviderInterface
}
/**
- * {@inheritDoc}
+ * {@inheritdoc}
*/
public function supportsClass($class)
{
diff --git a/Core/User/User.php b/Core/User/User.php
index b378e1b..ea2c6a4 100644
--- a/Core/User/User.php
+++ b/Core/User/User.php
@@ -64,7 +64,6 @@ final class User implements AdvancedUserInterface
*/
public function getSalt()
{
- return null;
}
/**
diff --git a/Core/User/UserProviderInterface.php b/Core/User/UserProviderInterface.php
index 6669c43..6b7895c 100644
--- a/Core/User/UserProviderInterface.php
+++ b/Core/User/UserProviderInterface.php
@@ -70,7 +70,7 @@ interface UserProviderInterface
*
* @param string $class
*
- * @return Boolean
+ * @return bool
*/
public function supportsClass($class);
}
diff --git a/Core/Util/ClassUtils.php b/Core/Util/ClassUtils.php
index 26bf1a1..1d40c8d 100644
--- a/Core/Util/ClassUtils.php
+++ b/Core/Util/ClassUtils.php
@@ -39,7 +39,9 @@ class ClassUtils
/**
* This class should not be instantiated
*/
- private function __construct() {}
+ private function __construct()
+ {
+ }
/**
* Gets the real class name of a class name that could be a proxy.
diff --git a/Core/Util/SecureRandomInterface.php b/Core/Util/SecureRandomInterface.php
index 2c35a72..2cf7779 100644
--- a/Core/Util/SecureRandomInterface.php
+++ b/Core/Util/SecureRandomInterface.php
@@ -21,7 +21,7 @@ interface SecureRandomInterface
/**
* Generates the specified number of secure random bytes.
*
- * @param integer $nbBytes
+ * @param int $nbBytes
*
* @return string
*/
diff --git a/Core/Util/StringUtils.php b/Core/Util/StringUtils.php
index 2e8925d..01441cb 100644
--- a/Core/Util/StringUtils.php
+++ b/Core/Util/StringUtils.php
@@ -21,37 +21,43 @@ class StringUtils
/**
* This class should not be instantiated
*/
- private function __construct() {}
+ private function __construct()
+ {
+ }
/**
* Compares two strings.
*
* This method implements a constant-time algorithm to compare strings.
+ * Regardless of the used implementation, it will leak length information.
*
* @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
+ * @return bool 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);
+ $knownString = (string) $knownString;
+ $userInput = (string) $userInput;
+
+ if (function_exists('hash_equals')) {
+ return hash_equals($knownString, $userInput);
+ }
$knownLen = strlen($knownString);
$userLen = strlen($userInput);
+ // Extend the known string to avoid uninitialized string offsets
+ $knownString .= $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
+ // This is to mitigate 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]));
+ $result |= (ord($knownString[$i]) ^ ord($userInput[$i]));
}
// They are only identical strings if $result is exactly 0...
diff --git a/Core/Validator/Constraints/UserPassword.php b/Core/Validator/Constraints/UserPassword.php
index 76c4b3b..35537b3 100644
--- a/Core/Validator/Constraints/UserPassword.php
+++ b/Core/Validator/Constraints/UserPassword.php
@@ -15,10 +15,11 @@ use Symfony\Component\Validator\Constraint;
/**
* @Annotation
+ * @Target({"PROPERTY", "METHOD", "ANNOTATION"})
*/
class UserPassword extends Constraint
{
- public $message = 'This value should be the user current password.';
+ public $message = 'This value should be the user\'s current password.';
public $service = 'security.validator.user_password';
/**
diff --git a/Core/composer.json b/Core/composer.json
index 249d4c1..54a76dc 100644
--- a/Core/composer.json
+++ b/Core/composer.json
@@ -40,7 +40,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
- "dev-master": "2.5-dev"
+ "dev-master": "2.6-dev"
}
}
}