summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Core/Authorization/ExpressionLanguage.php57
-rw-r--r--Core/Authorization/Voter/ExpressionVoter.php100
-rw-r--r--Http/AccessMap.php6
-rw-r--r--composer.json3
4 files changed, 162 insertions, 4 deletions
diff --git a/Core/Authorization/ExpressionLanguage.php b/Core/Authorization/ExpressionLanguage.php
new file mode 100644
index 0000000..bdb3371
--- /dev/null
+++ b/Core/Authorization/ExpressionLanguage.php
@@ -0,0 +1,57 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Core\Authorization;
+
+use Symfony\Component\ExpressionLanguage\ExpressionLanguage as BaseExpressionLanguage;
+
+/**
+ * Adds some function to the default ExpressionLanguage.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class ExpressionLanguage extends BaseExpressionLanguage
+{
+ protected function registerFunctions()
+ {
+ parent::registerFunctions();
+
+ $this->addFunction('is_anonymous', function () {
+ return '$trust_resolver->isAnonymous($token)';
+ }, function (array $variables) {
+ return $variables['trust_resolver']->isAnonymous($variables['token']);
+ });
+
+ $this->addFunction('is_authenticated', function () {
+ return '!$trust_resolver->isAnonymous($token)';
+ }, function (array $variables) {
+ return !$variables['trust_resolver']->isAnonymous($variables['token']);
+ });
+
+ $this->addFunction('is_fully_authenticated', function () {
+ return '!$trust_resolver->isFullFledge($token)';
+ }, function (array $variables) {
+ return !$variables['trust_resolver']->isFullFledge($variables['token']);
+ });
+
+ $this->addFunction('is_remember_me', function () {
+ return '!$trust_resolver->isRememberMe($token)';
+ }, function (array $variables) {
+ return !$variables['trust_resolver']->isRememberMe($variables['token']);
+ });
+
+ $this->addFunction('has_role', function ($role) {
+ return sprintf('in_array(%s, $roles)', $role);
+ }, function (array $variables, $role) {
+ return in_array($role, $variables['roles']);
+ });
+ }
+}
diff --git a/Core/Authorization/Voter/ExpressionVoter.php b/Core/Authorization/Voter/ExpressionVoter.php
new file mode 100644
index 0000000..50c8d5c
--- /dev/null
+++ b/Core/Authorization/Voter/ExpressionVoter.php
@@ -0,0 +1,100 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Core\Authorization\Voter;
+
+use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
+use Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface;
+use Symfony\Component\Security\Core\Authorization\ExpressionLanguage;
+use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
+use Symfony\Component\ExpressionLanguage\Expression;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * ExpressionVoter votes based on the evaluation of an expression.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ */
+class ExpressionVoter implements VoterInterface
+{
+ private $expressionLanguage;
+ private $trustResolver;
+ private $roleHierarchy;
+
+ /**
+ * Constructor.
+ *
+ * @param ExpressionLanguage $expressionLanguage
+ */
+ public function __construct(ExpressionLanguage $expressionLanguage, AuthenticationTrustResolverInterface $trustResolver, RoleHierarchyInterface $roleHierarchy = null)
+ {
+ $this->expressionLanguage = $expressionLanguage;
+ $this->trustResolver = $trustResolver;
+ $this->roleHierarchy = $roleHierarchy;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function supportsAttribute($attribute)
+ {
+ return $attribute instanceof Expression;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function supportsClass($class)
+ {
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function vote(TokenInterface $token, $object, array $attributes)
+ {
+ if (null !== $this->roleHierarchy) {
+ $roles = $this->roleHierarchy->getReachableRoles($token->getRoles());
+ } else {
+ $roles = $token->getRoles();
+ }
+
+ $variables = array(
+ 'token' => $token,
+ 'user' => $token->getUser(),
+ 'object' => $object,
+ 'roles' => array_map(function ($role) { return $role->getRole(); }, $roles),
+ 'trust_resolver' => $this->trustResolver,
+ );
+
+ // this is mainly to propose a better experience when the expression is used
+ // in an access control rule, as the developer does not know that it's going
+ // to be handled by this voter
+ if ($object instanceof Request) {
+ $variables['request'] = $object;
+ }
+
+ $result = VoterInterface::ACCESS_ABSTAIN;
+ foreach ($attributes as $attribute) {
+ if (!$this->supportsAttribute($attribute)) {
+ continue;
+ }
+
+ $result = VoterInterface::ACCESS_DENIED;
+ if ($this->expressionLanguage->evaluate($attribute, $variables)) {
+ return VoterInterface::ACCESS_GRANTED;
+ }
+ }
+
+ return $result;
+ }
+}
diff --git a/Http/AccessMap.php b/Http/AccessMap.php
index de78e15..bf1d540 100644
--- a/Http/AccessMap.php
+++ b/Http/AccessMap.php
@@ -28,12 +28,12 @@ class AccessMap implements AccessMapInterface
* Constructor.
*
* @param RequestMatcherInterface $requestMatcher A RequestMatcherInterface instance
- * @param array $roles An array of roles needed to access the resource
+ * @param array $attributes An array of attributes to pass to the access decision manager (like roles)
* @param string|null $channel The channel to enforce (http, https, or null)
*/
- public function add(RequestMatcherInterface $requestMatcher, array $roles = array(), $channel = null)
+ public function add(RequestMatcherInterface $requestMatcher, array $attributes = array(), $channel = null)
{
- $this->map[] = array($requestMatcher, $roles, $channel);
+ $this->map[] = array($requestMatcher, $attributes, $channel);
}
public function getPatterns(Request $request)
diff --git a/composer.json b/composer.json
index c66e967..164deb3 100644
--- a/composer.json
+++ b/composer.json
@@ -33,7 +33,8 @@
"doctrine/common": "~2.2",
"doctrine/dbal": "~2.2",
"psr/log": "~1.0",
- "ircmaxell/password-compat": "1.0.*"
+ "ircmaxell/password-compat": "1.0.*",
+ "symfony/expression-language": "~2.4"
},
"suggest": {
"symfony/class-loader": "",