summaryrefslogtreecommitdiffstats
path: root/Core/Authorization
diff options
context:
space:
mode:
Diffstat (limited to 'Core/Authorization')
-rw-r--r--Core/Authorization/AccessDecisionManager.php53
-rw-r--r--Core/Authorization/AccessDecisionManagerInterface.php20
-rw-r--r--Core/Authorization/AuthorizationChecker.php70
-rw-r--r--Core/Authorization/AuthorizationCheckerInterface.php30
-rw-r--r--Core/Authorization/DebugAccessDecisionManager.php121
-rw-r--r--Core/Authorization/ExpressionLanguage.php33
-rw-r--r--Core/Authorization/ExpressionLanguageProvider.php58
-rw-r--r--Core/Authorization/Voter/AuthenticatedVoter.php22
-rw-r--r--Core/Authorization/Voter/ExpressionVoter.php103
-rw-r--r--Core/Authorization/Voter/RoleVoter.php20
-rw-r--r--Core/Authorization/Voter/Voter.php69
-rw-r--r--Core/Authorization/Voter/VoterInterface.php26
12 files changed, 512 insertions, 113 deletions
diff --git a/Core/Authorization/AccessDecisionManager.php b/Core/Authorization/AccessDecisionManager.php
index 6e5effb..e40d906 100644
--- a/Core/Authorization/AccessDecisionManager.php
+++ b/Core/Authorization/AccessDecisionManager.php
@@ -22,6 +22,10 @@ use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
*/
class AccessDecisionManager implements AccessDecisionManagerInterface
{
+ const STRATEGY_AFFIRMATIVE = 'affirmative';
+ const STRATEGY_CONSENSUS = 'consensus';
+ const STRATEGY_UNANIMOUS = 'unanimous';
+
private $voters;
private $strategy;
private $allowIfAllAbstainDecisions;
@@ -37,52 +41,35 @@ class AccessDecisionManager implements AccessDecisionManagerInterface
*
* @throws \InvalidArgumentException
*/
- public function __construct(array $voters, $strategy = 'affirmative', $allowIfAllAbstainDecisions = false, $allowIfEqualGrantedDeniedDecisions = true)
+ public function __construct(array $voters = array(), $strategy = self::STRATEGY_AFFIRMATIVE, $allowIfAllAbstainDecisions = false, $allowIfEqualGrantedDeniedDecisions = true)
{
- if (!$voters) {
- throw new \InvalidArgumentException('You must at least add one voter.');
+ $strategyMethod = 'decide'.ucfirst($strategy);
+ if (!is_callable(array($this, $strategyMethod))) {
+ throw new \InvalidArgumentException(sprintf('The strategy "%s" is not supported.', $strategy));
}
$this->voters = $voters;
- $this->strategy = 'decide'.ucfirst($strategy);
+ $this->strategy = $strategyMethod;
$this->allowIfAllAbstainDecisions = (bool) $allowIfAllAbstainDecisions;
$this->allowIfEqualGrantedDeniedDecisions = (bool) $allowIfEqualGrantedDeniedDecisions;
}
/**
- * {@inheritdoc}
- */
- public function decide(TokenInterface $token, array $attributes, $object = null)
- {
- return $this->{$this->strategy}($token, $attributes, $object);
- }
-
- /**
- * {@inheritdoc}
+ * Configures the voters.
+ *
+ * @param VoterInterface[] $voters An array of VoterInterface instances
*/
- public function supportsAttribute($attribute)
+ public function setVoters(array $voters)
{
- foreach ($this->voters as $voter) {
- if ($voter->supportsAttribute($attribute)) {
- return true;
- }
- }
-
- return false;
+ $this->voters = $voters;
}
/**
* {@inheritdoc}
*/
- public function supportsClass($class)
+ public function decide(TokenInterface $token, array $attributes, $object = null)
{
- foreach ($this->voters as $voter) {
- if ($voter->supportsClass($class)) {
- return true;
- }
- }
-
- return false;
+ return $this->{$this->strategy}($token, $attributes, $object);
}
/**
@@ -135,7 +122,6 @@ class AccessDecisionManager implements AccessDecisionManagerInterface
{
$grant = 0;
$deny = 0;
- $abstain = 0;
foreach ($this->voters as $voter) {
$result = $voter->vote($token, $object, $attributes);
@@ -149,11 +135,6 @@ class AccessDecisionManager implements AccessDecisionManagerInterface
++$deny;
break;
-
- default:
- ++$abstain;
-
- break;
}
}
@@ -165,7 +146,7 @@ class AccessDecisionManager implements AccessDecisionManagerInterface
return false;
}
- if ($grant == $deny && $grant != 0) {
+ if ($grant > 0) {
return $this->allowIfEqualGrantedDeniedDecisions;
}
diff --git a/Core/Authorization/AccessDecisionManagerInterface.php b/Core/Authorization/AccessDecisionManagerInterface.php
index ec82800..723ef19 100644
--- a/Core/Authorization/AccessDecisionManagerInterface.php
+++ b/Core/Authorization/AccessDecisionManagerInterface.php
@@ -27,25 +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 bool 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);
-
- /**
- * Checks if the access decision manager supports the given attribute.
- *
- * @param string $attribute An attribute
- *
- * @return bool true if this decision manager supports the attribute, false otherwise
- */
- public function supportsAttribute($attribute);
-
- /**
- * Checks if the access decision manager supports the given class.
- *
- * @param string $class A class name
- *
- * @return true if this decision manager can process the class
- */
- public function supportsClass($class);
}
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/DebugAccessDecisionManager.php b/Core/Authorization/DebugAccessDecisionManager.php
new file mode 100644
index 0000000..7c0cfc9
--- /dev/null
+++ b/Core/Authorization/DebugAccessDecisionManager.php
@@ -0,0 +1,121 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Core\Authorization;
+
+use Doctrine\Common\Util\ClassUtils;
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+
+/**
+ * Decorates the original AccessDecisionManager class to log information
+ * about the security voters and the decisions made by them.
+ *
+ * @author Javier Eguiluz <javier.eguiluz@gmail.com>
+ *
+ * @internal
+ */
+class DebugAccessDecisionManager implements AccessDecisionManagerInterface
+{
+ private $manager;
+ private $strategy;
+ private $voters;
+ private $decisionLog = array();
+
+ public function __construct(AccessDecisionManager $manager)
+ {
+ $this->manager = $manager;
+
+ // The strategy is stored in a private property of the decorated service
+ $reflection = new \ReflectionProperty($manager, 'strategy');
+ $reflection->setAccessible(true);
+ $this->strategy = $reflection->getValue($manager);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function decide(TokenInterface $token, array $attributes, $object = null)
+ {
+ $result = $this->manager->decide($token, $attributes, $object);
+
+ $this->decisionLog[] = array(
+ 'attributes' => $attributes,
+ 'object' => $this->getStringRepresentation($object),
+ 'result' => $result,
+ );
+
+ return $result;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setVoters(array $voters)
+ {
+ $this->voters = $voters;
+ $this->manager->setVoters($voters);
+ }
+
+ /**
+ * @return string
+ */
+ public function getStrategy()
+ {
+ // The $strategy property is misleading because it stores the name of its
+ // method (e.g. 'decideAffirmative') instead of the original strategy name
+ // (e.g. 'affirmative')
+ return strtolower(substr($this->strategy, 6));
+ }
+
+ /**
+ * @return array
+ */
+ public function getVoters()
+ {
+ return $this->voters;
+ }
+
+ /**
+ * @return array
+ */
+ public function getDecisionLog()
+ {
+ return $this->decisionLog;
+ }
+
+ /**
+ * @param mixed $object
+ *
+ * @return string
+ */
+ private function getStringRepresentation($object)
+ {
+ if (null === $object) {
+ return 'NULL';
+ }
+
+ if (!is_object($object)) {
+ return sprintf('%s (%s)', gettype($object), $object);
+ }
+
+ $objectClass = class_exists('Doctrine\Common\Util\ClassUtils') ? ClassUtils::getClass($object) : get_class($object);
+
+ if (method_exists($object, 'getId')) {
+ $objectAsString = sprintf('ID: %s', $object->getId());
+ } elseif (method_exists($object, '__toString')) {
+ $objectAsString = (string) $object;
+ } else {
+ $objectAsString = sprintf('object hash: %s', spl_object_hash($object));
+ }
+
+ return sprintf('%s (%s)', $objectClass, $objectAsString);
+ }
+}
diff --git a/Core/Authorization/ExpressionLanguage.php b/Core/Authorization/ExpressionLanguage.php
new file mode 100644
index 0000000..c2925af
--- /dev/null
+++ b/Core/Authorization/ExpressionLanguage.php
@@ -0,0 +1,33 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Core\Authorization;
+
+use Symfony\Component\ExpressionLanguage\ExpressionLanguage as BaseExpressionLanguage;
+use Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface;
+
+/**
+ * Adds some function to the default ExpressionLanguage.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @see ExpressionLanguageProvider
+ */
+class ExpressionLanguage extends BaseExpressionLanguage
+{
+ public function __construct(ParserCacheInterface $cache = null, array $providers = array())
+ {
+ // prepend the default provider to let users override it easily
+ array_unshift($providers, new ExpressionLanguageProvider());
+
+ parent::__construct($cache, $providers);
+ }
+}
diff --git a/Core/Authorization/ExpressionLanguageProvider.php b/Core/Authorization/ExpressionLanguageProvider.php
new file mode 100644
index 0000000..9293ba7
--- /dev/null
+++ b/Core/Authorization/ExpressionLanguageProvider.php
@@ -0,0 +1,58 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Core\Authorization;
+
+use Symfony\Component\ExpressionLanguage\ExpressionFunction;
+use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
+
+/**
+ * Define some ExpressionLanguage functions.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class ExpressionLanguageProvider implements ExpressionFunctionProviderInterface
+{
+ public function getFunctions()
+ {
+ return array(
+ new ExpressionFunction('is_anonymous', function () {
+ return '$trust_resolver->isAnonymous($token)';
+ }, function (array $variables) {
+ return $variables['trust_resolver']->isAnonymous($variables['token']);
+ }),
+
+ new ExpressionFunction('is_authenticated', function () {
+ return '$token && !$trust_resolver->isAnonymous($token)';
+ }, function (array $variables) {
+ return $variables['token'] && !$variables['trust_resolver']->isAnonymous($variables['token']);
+ }),
+
+ new ExpressionFunction('is_fully_authenticated', function () {
+ return '$trust_resolver->isFullFledged($token)';
+ }, function (array $variables) {
+ return $variables['trust_resolver']->isFullFledged($variables['token']);
+ }),
+
+ new ExpressionFunction('is_remember_me', function () {
+ return '$trust_resolver->isRememberMe($token)';
+ }, function (array $variables) {
+ return $variables['trust_resolver']->isRememberMe($variables['token']);
+ }),
+
+ new ExpressionFunction('has_role', function ($role) {
+ return sprintf('in_array(%s, $roles)', $role);
+ }, function (array $variables, $role) {
+ return in_array($role, $variables['roles']);
+ }),
+ );
+ }
+}
diff --git a/Core/Authorization/Voter/AuthenticatedVoter.php b/Core/Authorization/Voter/AuthenticatedVoter.php
index 5847e0d..dc1407b 100644
--- a/Core/Authorization/Voter/AuthenticatedVoter.php
+++ b/Core/Authorization/Voter/AuthenticatedVoter.php
@@ -44,27 +44,13 @@ class AuthenticatedVoter implements VoterInterface
/**
* {@inheritdoc}
*/
- public function supportsAttribute($attribute)
- {
- return null !== $attribute && (self::IS_AUTHENTICATED_FULLY === $attribute || self::IS_AUTHENTICATED_REMEMBERED === $attribute || self::IS_AUTHENTICATED_ANONYMOUSLY === $attribute);
- }
-
- /**
- * {@inheritdoc}
- */
- public function supportsClass($class)
- {
- return true;
- }
-
- /**
- * {@inheritdoc}
- */
- public function vote(TokenInterface $token, $object, array $attributes)
+ public function vote(TokenInterface $token, $subject, array $attributes)
{
$result = VoterInterface::ACCESS_ABSTAIN;
foreach ($attributes as $attribute) {
- if (!$this->supportsAttribute($attribute)) {
+ if (null === $attribute || (self::IS_AUTHENTICATED_FULLY !== $attribute
+ && self::IS_AUTHENTICATED_REMEMBERED !== $attribute
+ && self::IS_AUTHENTICATED_ANONYMOUSLY !== $attribute)) {
continue;
}
diff --git a/Core/Authorization/Voter/ExpressionVoter.php b/Core/Authorization/Voter/ExpressionVoter.php
new file mode 100644
index 0000000..5fd8b83
--- /dev/null
+++ b/Core/Authorization/Voter/ExpressionVoter.php
@@ -0,0 +1,103 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Core\Authorization\Voter;
+
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
+use Symfony\Component\Security\Core\Authorization\ExpressionLanguage;
+use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
+use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
+use Symfony\Component\ExpressionLanguage\Expression;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * ExpressionVoter votes based on the evaluation of an expression.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class ExpressionVoter implements VoterInterface
+{
+ private $expressionLanguage;
+ private $trustResolver;
+ private $roleHierarchy;
+
+ /**
+ * Constructor.
+ *
+ * @param ExpressionLanguage $expressionLanguage
+ * @param AuthenticationTrustResolverInterface $trustResolver
+ * @param RoleHierarchyInterface|null $roleHierarchy
+ */
+ public function __construct(ExpressionLanguage $expressionLanguage, AuthenticationTrustResolverInterface $trustResolver, RoleHierarchyInterface $roleHierarchy = null)
+ {
+ $this->expressionLanguage = $expressionLanguage;
+ $this->trustResolver = $trustResolver;
+ $this->roleHierarchy = $roleHierarchy;
+ }
+
+ public function addExpressionLanguageProvider(ExpressionFunctionProviderInterface $provider)
+ {
+ $this->expressionLanguage->registerProvider($provider);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function vote(TokenInterface $token, $subject, array $attributes)
+ {
+ $result = VoterInterface::ACCESS_ABSTAIN;
+ $variables = null;
+ foreach ($attributes as $attribute) {
+ if (!$attribute instanceof Expression) {
+ continue;
+ }
+
+ if (null === $variables) {
+ $variables = $this->getVariables($token, $subject);
+ }
+
+ $result = VoterInterface::ACCESS_DENIED;
+ if ($this->expressionLanguage->evaluate($attribute, $variables)) {
+ return VoterInterface::ACCESS_GRANTED;
+ }
+ }
+
+ return $result;
+ }
+
+ private function getVariables(TokenInterface $token, $subject)
+ {
+ if (null !== $this->roleHierarchy) {
+ $roles = $this->roleHierarchy->getReachableRoles($token->getRoles());
+ } else {
+ $roles = $token->getRoles();
+ }
+
+ $variables = array(
+ 'token' => $token,
+ 'user' => $token->getUser(),
+ 'object' => $subject,
+ 'subject' => $subject,
+ 'roles' => array_map(function ($role) { return $role->getRole(); }, $roles),
+ 'trust_resolver' => $this->trustResolver,
+ );
+
+ // this is mainly to propose a better experience when the expression is used
+ // in an access control rule, as the developer does not know that it's going
+ // to be handled by this voter
+ if ($subject instanceof Request) {
+ $variables['request'] = $subject;
+ }
+
+ return $variables;
+ }
+}
diff --git a/Core/Authorization/Voter/RoleVoter.php b/Core/Authorization/Voter/RoleVoter.php
index 722675d..b017c81 100644
--- a/Core/Authorization/Voter/RoleVoter.php
+++ b/Core/Authorization/Voter/RoleVoter.php
@@ -35,29 +35,13 @@ class RoleVoter implements VoterInterface
/**
* {@inheritdoc}
*/
- public function supportsAttribute($attribute)
- {
- return 0 === strpos($attribute, $this->prefix);
- }
-
- /**
- * {@inheritdoc}
- */
- public function supportsClass($class)
- {
- return true;
- }
-
- /**
- * {@inheritdoc}
- */
- public function vote(TokenInterface $token, $object, array $attributes)
+ public function vote(TokenInterface $token, $subject, array $attributes)
{
$result = VoterInterface::ACCESS_ABSTAIN;
$roles = $this->extractRoles($token);
foreach ($attributes as $attribute) {
- if (!$this->supportsAttribute($attribute)) {
+ if (0 !== strpos($attribute, $this->prefix)) {
continue;
}
diff --git a/Core/Authorization/Voter/Voter.php b/Core/Authorization/Voter/Voter.php
new file mode 100644
index 0000000..ba4d6af
--- /dev/null
+++ b/Core/Authorization/Voter/Voter.php
@@ -0,0 +1,69 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Core\Authorization\Voter;
+
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+
+/**
+ * Voter is an abstract default implementation of a voter.
+ *
+ * @author Roman Marintšenko <inoryy@gmail.com>
+ * @author Grégoire Pineau <lyrixx@lyrixx.info>
+ */
+abstract class Voter implements VoterInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function vote(TokenInterface $token, $subject, array $attributes)
+ {
+ // abstain vote by default in case none of the attributes are supported
+ $vote = self::ACCESS_ABSTAIN;
+
+ foreach ($attributes as $attribute) {
+ if (!$this->supports($attribute, $subject)) {
+ continue;
+ }
+
+ // as soon as at least one attribute is supported, default is to deny access
+ $vote = self::ACCESS_DENIED;
+
+ if ($this->voteOnAttribute($attribute, $subject, $token)) {
+ // grant access as soon as at least one attribute returns a positive response
+ return self::ACCESS_GRANTED;
+ }
+ }
+
+ return $vote;
+ }
+
+ /**
+ * Determines if the attribute and subject are supported by this voter.
+ *
+ * @param string $attribute An attribute
+ * @param mixed $subject The subject to secure, e.g. an object the user wants to access or any other PHP type
+ *
+ * @return bool True if the attribute and subject are supported, false otherwise
+ */
+ abstract protected function supports($attribute, $subject);
+
+ /**
+ * Perform a single access check operation on a given attribute, subject and token.
+ *
+ * @param string $attribute
+ * @param mixed $subject
+ * @param TokenInterface $token
+ *
+ * @return bool
+ */
+ abstract protected function voteOnAttribute($attribute, $subject, TokenInterface $token);
+}
diff --git a/Core/Authorization/Voter/VoterInterface.php b/Core/Authorization/Voter/VoterInterface.php
index abc18b4..4bb7367 100644
--- a/Core/Authorization/Voter/VoterInterface.php
+++ b/Core/Authorization/Voter/VoterInterface.php
@@ -22,25 +22,7 @@ interface VoterInterface
{
const ACCESS_GRANTED = 1;
const ACCESS_ABSTAIN = 0;
- const ACCESS_DENIED = -1;
-
- /**
- * Checks if the voter supports the given attribute.
- *
- * @param string $attribute An attribute
- *
- * @return bool true if this Voter supports the attribute, false otherwise
- */
- public function supportsAttribute($attribute);
-
- /**
- * Checks if the voter supports the given class.
- *
- * @param string $class A class name
- *
- * @return bool true if this Voter can process the class
- */
- public function supportsClass($class);
+ const ACCESS_DENIED = -1;
/**
* Returns the vote for the given parameters.
@@ -49,10 +31,10 @@ interface VoterInterface
* ACCESS_GRANTED, ACCESS_DENIED, or ACCESS_ABSTAIN.
*
* @param TokenInterface $token A TokenInterface instance
- * @param object $object The object to secure
+ * @param mixed $subject The subject 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
+ * @return int either ACCESS_GRANTED, ACCESS_ABSTAIN, or ACCESS_DENIED
*/
- public function vote(TokenInterface $token, $object, array $attributes);
+ public function vote(TokenInterface $token, $subject, array $attributes);
}