diff --git a/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php b/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php
index 0fff7552e858d..fc798989dec78 100644
--- a/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php
+++ b/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php
@@ -18,6 +18,8 @@
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
use Symfony\Component\Security\Core\Role\RoleInterface;
use Symfony\Component\Security\Http\Logout\LogoutUrlGenerator;
+use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
+use Symfony\Component\Security\Core\Authorization\DebugAccessDecisionManager;
/**
* SecurityDataCollector.
@@ -29,19 +31,22 @@ class SecurityDataCollector extends DataCollector
private $tokenStorage;
private $roleHierarchy;
private $logoutUrlGenerator;
+ private $accessDecisionManager;
/**
* Constructor.
*
- * @param TokenStorageInterface|null $tokenStorage
- * @param RoleHierarchyInterface|null $roleHierarchy
- * @param LogoutUrlGenerator|null $logoutUrlGenerator
+ * @param TokenStorageInterface|null $tokenStorage
+ * @param RoleHierarchyInterface|null $roleHierarchy
+ * @param LogoutUrlGenerator|null $logoutUrlGenerator
+ * @param AccessDecisionManagerInterface|null $accessDecisionManager
*/
- public function __construct(TokenStorageInterface $tokenStorage = null, RoleHierarchyInterface $roleHierarchy = null, LogoutUrlGenerator $logoutUrlGenerator = null)
+ public function __construct(TokenStorageInterface $tokenStorage = null, RoleHierarchyInterface $roleHierarchy = null, LogoutUrlGenerator $logoutUrlGenerator = null, AccessDecisionManagerInterface $accessDecisionManager = null)
{
$this->tokenStorage = $tokenStorage;
$this->roleHierarchy = $roleHierarchy;
$this->logoutUrlGenerator = $logoutUrlGenerator;
+ $this->accessDecisionManager = $accessDecisionManager;
}
/**
@@ -104,6 +109,20 @@ public function collect(Request $request, Response $response, \Exception $except
'supports_role_hierarchy' => null !== $this->roleHierarchy,
);
}
+
+ // collect voters and access decision manager information
+ if ($this->accessDecisionManager instanceof DebugAccessDecisionManager) {
+ $this->data['access_decision_log'] = $this->accessDecisionManager->getDecisionLog();
+ $this->data['voter_strategy'] = $this->accessDecisionManager->getStrategy();
+
+ foreach ($this->accessDecisionManager->getVoters() as $voter) {
+ $this->data['voters'][] = get_class($voter);
+ }
+ } else {
+ $this->data['access_decision_log'] = array();
+ $this->data['voter_strategy'] = 'unknown';
+ $this->data['voters'] = array();
+ }
}
/**
@@ -187,6 +206,36 @@ public function getLogoutUrl()
return $this->data['logout_url'];
}
+ /**
+ * Returns the FQCN of the security voters enabled in the application.
+ *
+ * @return string[]
+ */
+ public function getVoters()
+ {
+ return $this->data['voters'];
+ }
+
+ /**
+ * Returns the strategy configured for the security voters.
+ *
+ * @return string
+ */
+ public function getVoterStrategy()
+ {
+ return $this->data['voter_strategy'];
+ }
+
+ /**
+ * Returns the log of the security decisions made by the access decision manager.
+ *
+ * @return array
+ */
+ public function getAccessDecisionLog()
+ {
+ return $this->data['access_decision_log'];
+ }
+
/**
* {@inheritdoc}
*/
diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Compiler/AddSecurityVotersPass.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Compiler/AddSecurityVotersPass.php
index 992d5a5f7c6f5..e2f8b3c645b61 100644
--- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Compiler/AddSecurityVotersPass.php
+++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Compiler/AddSecurityVotersPass.php
@@ -46,5 +46,9 @@ public function process(ContainerBuilder $container)
}
$container->getDefinition('security.access.decision_manager')->addMethodCall('setVoters', array(array_values($voters)));
+
+ if ($container->hasDefinition('debug.security.access.decision_manager')) {
+ $container->getDefinition('debug.security.access.decision_manager')->addMethodCall('setVoters', array(array_values($voters)));
+ }
}
}
diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php
index 6043ed6292089..8427068727035 100644
--- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php
+++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php
@@ -97,6 +97,13 @@ public function load(array $configs, ContainerBuilder $container)
$this->aclLoad($config['acl'], $container);
}
+ if ($container->hasParameter('kernel.debug') && $container->getParameter('kernel.debug')) {
+ $loader->load('security_debug.xml');
+
+ $definition = $container->findDefinition('security.authorization_checker');
+ $definition->replaceArgument(2, new Reference('debug.security.access.decision_manager'));
+ }
+
// add some required classes for compilation
$this->addClassesToCompile(array(
'Symfony\Component\Security\Http\Firewall',
diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/collectors.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/collectors.xml
index 329815fd608a1..738455358b0dd 100644
--- a/src/Symfony/Bundle/SecurityBundle/Resources/config/collectors.xml
+++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/collectors.xml
@@ -10,6 +10,7 @@
The security component is disabled.
{% endif %} + + {% if collector.voters|default([]) is not empty %} +# | +Voter class | +
---|---|
{{ loop.index }} | +{{ voter }} | +
# | +Result | +Attributes | +Object | +
---|---|---|---|
{{ loop.index }} | ++ {{ decision.result + ? 'GRANTED' + : 'DENIED' + }} + | +{{ decision.attributes|length == 1 ? decision.attributes|first : profiler_dump(decision.attributes) }} | +{{ profiler_dump(decision.object) }} | +