2010-10-19 12:06:43 +01:00
|
|
|
<?php
|
|
|
|
|
2011-01-15 13:29:43 +00:00
|
|
|
/*
|
|
|
|
* This file is part of the Symfony package.
|
|
|
|
*
|
|
|
|
* (c) Fabien Potencier <fabien.potencier@symfony-project.com>
|
|
|
|
*
|
|
|
|
* For the full copyright and license information, please view the LICENSE
|
|
|
|
* file that was distributed with this source code.
|
|
|
|
*/
|
|
|
|
|
2011-01-26 16:28:43 +00:00
|
|
|
namespace Symfony\Bundle\SecurityBundle\DependencyInjection;
|
2010-10-19 12:06:43 +01:00
|
|
|
|
2011-01-07 14:44:29 +00:00
|
|
|
use Symfony\Component\DependencyInjection\Alias;
|
2011-01-19 17:10:46 +00:00
|
|
|
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
2010-10-19 12:06:43 +01:00
|
|
|
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
|
|
|
|
use Symfony\Component\DependencyInjection\Resource\FileResource;
|
|
|
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
|
|
|
use Symfony\Component\DependencyInjection\Reference;
|
2011-01-25 19:28:26 +00:00
|
|
|
use Symfony\Component\DependencyInjection\Parameter;
|
2010-10-19 12:06:43 +01:00
|
|
|
use Symfony\Component\DependencyInjection\Definition;
|
2010-12-02 09:56:25 +00:00
|
|
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
2010-10-19 12:06:43 +01:00
|
|
|
use Symfony\Component\HttpFoundation\RequestMatcher;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* SecurityExtension.
|
|
|
|
*
|
|
|
|
* @author Fabien Potencier <fabien.potencier@symfony-project.com>
|
2011-01-25 19:28:26 +00:00
|
|
|
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
2010-10-19 12:06:43 +01:00
|
|
|
*/
|
|
|
|
class SecurityExtension extends Extension
|
|
|
|
{
|
2011-01-21 10:00:52 +00:00
|
|
|
protected $requestMatchers = array();
|
2011-01-25 19:28:26 +00:00
|
|
|
protected $contextListeners = array();
|
2011-01-21 10:00:52 +00:00
|
|
|
|
2011-01-14 13:49:00 +00:00
|
|
|
public function configLoad(array $configs, ContainerBuilder $container)
|
|
|
|
{
|
|
|
|
foreach ($configs as $config) {
|
|
|
|
$this->doConfigLoad($config, $container);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public function aclLoad(array $configs, ContainerBuilder $container)
|
|
|
|
{
|
|
|
|
foreach ($configs as $config) {
|
|
|
|
$this->doAclLoad($config, $container);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-19 12:06:43 +01:00
|
|
|
/**
|
|
|
|
* Loads the web configuration.
|
|
|
|
*
|
|
|
|
* @param array $config An array of configuration settings
|
|
|
|
* @param ContainerBuilder $container A ContainerBuilder instance
|
|
|
|
*/
|
2011-01-14 13:49:00 +00:00
|
|
|
protected function doConfigLoad($config, ContainerBuilder $container)
|
2010-10-19 12:06:43 +01:00
|
|
|
{
|
|
|
|
if (!$container->hasDefinition('security.context')) {
|
|
|
|
$loader = new XmlFileLoader($container, array(__DIR__.'/../Resources/config', __DIR__.'/Resources/config'));
|
|
|
|
$loader->load('security.xml');
|
2011-01-26 19:44:22 +00:00
|
|
|
$loader->load('templating_php.xml');
|
|
|
|
$loader->load('templating_twig.xml');
|
2011-01-28 23:22:25 +00:00
|
|
|
$loader->load('collectors.xml');
|
2010-10-19 12:06:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (isset($config['access-denied-url'])) {
|
2011-01-25 19:28:26 +00:00
|
|
|
$container->setParameter('security.access.denied_url', $config['access-denied-url']);
|
|
|
|
}
|
|
|
|
|
|
|
|
// session fixation protection
|
|
|
|
if (isset($config['session_fixation_protection'])) {
|
|
|
|
$config['session-fixation-protection'] = $config['session_fixation_protection'];
|
|
|
|
}
|
|
|
|
if (isset($config['session-fixation-protection'])) {
|
|
|
|
$container->setParameter('security.authentication.session_strategy.strategy', $config['session-fixation-protection']);
|
2010-10-19 12:06:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
$this->createFirewalls($config, $container);
|
|
|
|
$this->createAuthorization($config, $container);
|
|
|
|
$this->createRoleHierarchy($config, $container);
|
|
|
|
|
|
|
|
return $container;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function createRoleHierarchy($config, ContainerBuilder $container)
|
|
|
|
{
|
|
|
|
$roles = array();
|
|
|
|
if (isset($config['role_hierarchy'])) {
|
|
|
|
$roles = $config['role_hierarchy'];
|
|
|
|
} elseif (isset($config['role-hierarchy'])) {
|
|
|
|
$roles = $config['role-hierarchy'];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isset($roles['role']) && is_int(key($roles['role']))) {
|
|
|
|
$roles = $roles['role'];
|
|
|
|
}
|
|
|
|
|
|
|
|
$hierarchy = array();
|
|
|
|
foreach ($roles as $id => $role) {
|
|
|
|
if (is_array($role) && isset($role['id'])) {
|
|
|
|
$id = $role['id'];
|
|
|
|
}
|
|
|
|
|
|
|
|
$value = $role;
|
|
|
|
if (is_array($role) && isset($role['value'])) {
|
|
|
|
$value = $role['value'];
|
|
|
|
}
|
|
|
|
|
|
|
|
$hierarchy[$id] = is_array($value) ? $value : preg_split('/\s*,\s*/', $value);
|
|
|
|
}
|
|
|
|
|
|
|
|
$container->setParameter('security.role_hierarchy.roles', $hierarchy);
|
|
|
|
$container->remove('security.access.simple_role_voter');
|
|
|
|
$container->getDefinition('security.access.role_hierarchy_voter')->addTag('security.voter');
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function createAuthorization($config, ContainerBuilder $container)
|
|
|
|
{
|
|
|
|
$rules = array();
|
|
|
|
if (isset($config['access_control'])) {
|
|
|
|
$rules = $config['access_control'];
|
|
|
|
} elseif (isset($config['access-control'])) {
|
|
|
|
$rules = $config['access-control'];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isset($rules['rule']) && is_array($rules['rule'])) {
|
|
|
|
$rules = $rules['rule'];
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ($rules as $i => $access) {
|
|
|
|
$roles = isset($access['role']) ? (is_array($access['role']) ? $access['role'] : preg_split('/\s*,\s*/', $access['role'])) : array();
|
|
|
|
$channel = null;
|
|
|
|
if (isset($access['requires-channel'])) {
|
|
|
|
$channel = $access['requires-channel'];
|
|
|
|
} elseif (isset($access['requires_channel'])) {
|
|
|
|
$channel = $access['requires_channel'];
|
|
|
|
}
|
|
|
|
|
|
|
|
// matcher
|
2011-01-21 10:00:52 +00:00
|
|
|
$path = $host = $methods = $ip = null;
|
2010-10-19 12:06:43 +01:00
|
|
|
if (isset($access['path'])) {
|
2011-01-21 10:00:52 +00:00
|
|
|
$path = $access['path'];
|
|
|
|
}
|
|
|
|
if (isset($access['host'])) {
|
|
|
|
$host = $access['host'];
|
|
|
|
}
|
2011-01-21 16:44:30 +00:00
|
|
|
if (count($tMethods = $this->normalizeConfig($access, 'method')) > 0) {
|
2011-01-21 10:00:52 +00:00
|
|
|
$methods = $tMethods;
|
|
|
|
}
|
|
|
|
if (isset($access['ip'])) {
|
|
|
|
$ip = $access['ip'];
|
2010-10-19 12:06:43 +01:00
|
|
|
}
|
|
|
|
|
2011-01-21 10:00:52 +00:00
|
|
|
$matchAttributes = array();
|
2011-01-21 16:44:30 +00:00
|
|
|
$attributes = $this->normalizeConfig($access, 'attribute');
|
2010-10-19 12:06:43 +01:00
|
|
|
foreach ($attributes as $key => $attribute) {
|
|
|
|
if (isset($attribute['key'])) {
|
|
|
|
$key = $attribute['key'];
|
|
|
|
}
|
2011-01-21 10:00:52 +00:00
|
|
|
$matchAttributes[$key] = $attribute['pattern'];
|
2010-10-19 12:06:43 +01:00
|
|
|
}
|
2011-01-21 10:00:52 +00:00
|
|
|
$matcher = $this->createRequestMatcher($container, $path, $host, $methods, $ip, $matchAttributes);
|
2010-10-19 12:06:43 +01:00
|
|
|
|
2011-01-21 10:00:52 +00:00
|
|
|
$container->getDefinition('security.access_map')->addMethodCall('add', array($matcher, $roles, $channel));
|
2010-10-19 12:06:43 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function createFirewalls($config, ContainerBuilder $container)
|
|
|
|
{
|
2010-12-08 12:51:26 +00:00
|
|
|
$providerIds = $this->createUserProviders($config, $container);
|
2010-10-19 12:06:43 +01:00
|
|
|
|
2011-01-18 10:31:05 +00:00
|
|
|
$this->createEncoders($config, $container);
|
2010-12-21 15:10:53 +00:00
|
|
|
|
2011-01-21 16:44:30 +00:00
|
|
|
if (!$firewalls = $this->normalizeConfig($config, 'firewall')) {
|
2010-10-19 12:06:43 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-12-08 12:51:26 +00:00
|
|
|
// make the ContextListener aware of the configured user providers
|
|
|
|
$definition = $container->getDefinition('security.context_listener');
|
|
|
|
$arguments = $definition->getArguments();
|
|
|
|
$userProviders = array();
|
2010-12-21 15:10:53 +00:00
|
|
|
foreach ($providerIds as $userProviderId) {
|
2010-12-08 12:51:26 +00:00
|
|
|
$userProviders[] = new Reference($userProviderId);
|
|
|
|
}
|
|
|
|
$arguments[1] = $userProviders;
|
|
|
|
$definition->setArguments($arguments);
|
|
|
|
|
2010-10-19 12:06:43 +01:00
|
|
|
// load service templates
|
2010-12-02 10:04:31 +00:00
|
|
|
$c = new ContainerBuilder($container->getParameterBag());
|
2010-12-02 09:56:25 +00:00
|
|
|
$loader = new XmlFileLoader($c, array(__DIR__.'/../Resources/config', __DIR__.'/Resources/config'));
|
2010-10-19 12:06:43 +01:00
|
|
|
$loader->load('security_templates.xml');
|
|
|
|
|
2011-01-21 16:44:30 +00:00
|
|
|
foreach ($this->normalizeConfig($config, 'template') as $template) {
|
2010-12-02 10:04:57 +00:00
|
|
|
$loader->load($c->getParameterBag()->resolveValue($template));
|
2010-12-02 09:56:25 +00:00
|
|
|
}
|
|
|
|
$container->merge($c);
|
|
|
|
|
2010-10-19 12:06:43 +01:00
|
|
|
// load firewall map
|
2011-01-21 10:00:52 +00:00
|
|
|
$mapDef = $container->getDefinition('security.firewall.map');
|
|
|
|
$map = array();
|
2010-10-19 12:06:43 +01:00
|
|
|
foreach ($firewalls as $firewall) {
|
|
|
|
list($matcher, $listeners, $exceptionListener) = $this->createFirewall($container, $firewall, $providerIds);
|
|
|
|
|
2011-01-21 10:00:52 +00:00
|
|
|
$contextId = 'security.firewall.map.context.'.count($map);
|
|
|
|
$context = $container->setDefinition($contextId, clone $container->getDefinition('security.firewall.context'));
|
|
|
|
$context
|
|
|
|
->setPublic(true)
|
|
|
|
->setArgument(0, $listeners)
|
|
|
|
->setArgument(1, $exceptionListener)
|
|
|
|
;
|
|
|
|
$map[$contextId] = $matcher;
|
2010-10-19 12:06:43 +01:00
|
|
|
}
|
2011-01-21 10:00:52 +00:00
|
|
|
$mapDef->setArgument(1, $map);
|
2010-10-19 12:06:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
protected function createFirewall(ContainerBuilder $container, $firewall, $providerIds)
|
|
|
|
{
|
|
|
|
// unique id for this firewall
|
|
|
|
$id = md5(serialize($firewall));
|
|
|
|
|
|
|
|
// Matcher
|
|
|
|
$i = 0;
|
|
|
|
$matcher = null;
|
2011-01-25 19:28:26 +00:00
|
|
|
if (isset($firewall['request_matcher'])) {
|
|
|
|
$firewall['request-matcher'] = $firewall['request_matcher'];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isset($firewall['request-matcher'])) {
|
|
|
|
$matcher = new Reference($firewall['request-matcher']);
|
|
|
|
} else if (isset($firewall['pattern'])) {
|
2011-01-21 10:00:52 +00:00
|
|
|
$matcher = $this->createRequestMatcher($container, $firewall['pattern']);
|
2010-10-19 12:06:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Security disabled?
|
2010-10-20 08:49:00 +01:00
|
|
|
if (isset($firewall['security']) && !$firewall['security']) {
|
2010-10-19 12:06:43 +01:00
|
|
|
return array($matcher, array(), null);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Provider id (take the first registered provider if none defined)
|
|
|
|
if (isset($firewall['provider'])) {
|
|
|
|
$defaultProvider = $this->getUserProviderId($firewall['provider']);
|
|
|
|
} else {
|
|
|
|
if (!$providerIds) {
|
|
|
|
throw new \InvalidArgumentException('You must provide at least one authentication provider.');
|
|
|
|
}
|
2010-12-21 15:10:53 +00:00
|
|
|
$defaultProvider = reset($providerIds);
|
2010-10-19 12:06:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Register listeners
|
|
|
|
$listeners = array();
|
|
|
|
$providers = array();
|
|
|
|
|
|
|
|
// Channel listener
|
|
|
|
$listeners[] = new Reference('security.channel_listener');
|
|
|
|
|
|
|
|
// Context serializer listener
|
|
|
|
if (!isset($firewall['stateless']) || !$firewall['stateless']) {
|
2011-01-25 19:28:26 +00:00
|
|
|
$contextKey = $id;
|
|
|
|
if (isset($firewall['context'])) {
|
|
|
|
$contextKey = $firewall['context'];
|
|
|
|
}
|
|
|
|
|
|
|
|
$listeners[] = new Reference($this->createContextListener($container, $contextKey));
|
2010-10-19 12:06:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Logout listener
|
|
|
|
if (array_key_exists('logout', $firewall)) {
|
2010-12-03 10:52:17 +00:00
|
|
|
$listenerId = 'security.logout_listener.'.$id;
|
2010-12-08 12:51:26 +00:00
|
|
|
$listener = $container->setDefinition($listenerId, clone $container->getDefinition('security.logout_listener'));
|
|
|
|
|
2010-12-03 10:52:17 +00:00
|
|
|
$listeners[] = new Reference($listenerId);
|
2010-10-20 09:48:05 +01:00
|
|
|
|
2011-01-25 19:28:26 +00:00
|
|
|
if (!is_array($firewall['logout'])) {
|
|
|
|
$firewall['logout'] = array();
|
|
|
|
}
|
|
|
|
|
2010-12-03 10:52:17 +00:00
|
|
|
$arguments = $listener->getArguments();
|
2010-10-20 09:48:05 +01:00
|
|
|
if (isset($firewall['logout']['path'])) {
|
2010-12-03 10:52:17 +00:00
|
|
|
$arguments[1] = $firewall['logout']['path'];
|
2010-10-20 09:48:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (isset($firewall['logout']['target'])) {
|
2010-12-03 10:52:17 +00:00
|
|
|
$arguments[2] = $firewall['logout']['target'];
|
|
|
|
}
|
|
|
|
$listener->setArguments($arguments);
|
2010-12-08 12:51:26 +00:00
|
|
|
|
2011-01-25 19:28:26 +00:00
|
|
|
// add session logout handler
|
|
|
|
$invalidateSession = true;
|
|
|
|
if (array_key_exists('invalidate_session', $firewall['logout'])) {
|
|
|
|
$firewall['logout']['invalidate-session'] = $firewall['logout']['invalidate_session'];
|
|
|
|
}
|
|
|
|
if (array_key_exists('invalidate-session', $firewall['logout'])) {
|
|
|
|
$invalidateSession = (Boolean) $invalidateSession;
|
|
|
|
}
|
|
|
|
if (true === $invalidateSession && (!isset($firewall['stateless']) || !$firewall['stateless'])) {
|
2010-12-03 10:52:17 +00:00
|
|
|
$listener->addMethodCall('addHandler', array(new Reference('security.logout.handler.session')));
|
|
|
|
}
|
2010-12-08 12:51:26 +00:00
|
|
|
|
2011-01-25 19:28:26 +00:00
|
|
|
// add cookie logout handler
|
2011-01-21 16:44:30 +00:00
|
|
|
if (count($cookies = $this->normalizeConfig($firewall['logout'], 'cookie')) > 0) {
|
2010-12-03 10:52:17 +00:00
|
|
|
$cookieHandlerId = 'security.logout.handler.cookie_clearing.'.$id;
|
|
|
|
$cookieHandler = $container->setDefinition($cookieHandlerId, clone $container->getDefinition('security.logout.handler.cookie_clearing'));
|
|
|
|
$cookieHandler->setArguments(array($cookies));
|
|
|
|
|
|
|
|
$listener->addMethodCall('addHandler', array(new Reference($cookieHandlerId)));
|
2010-10-20 09:48:05 +01:00
|
|
|
}
|
2010-10-19 12:06:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Authentication listeners
|
2010-12-21 15:10:53 +00:00
|
|
|
list($authListeners, $providers, $defaultEntryPoint) = $this->createAuthenticationListeners($container, $id, $firewall, $defaultProvider);
|
2010-10-19 12:06:43 +01:00
|
|
|
|
|
|
|
$listeners = array_merge($listeners, $authListeners);
|
|
|
|
|
|
|
|
// Access listener
|
2011-01-25 19:28:26 +00:00
|
|
|
$listeners[] = new Reference('security.access_listener');
|
2010-10-19 12:06:43 +01:00
|
|
|
|
|
|
|
// Switch user listener
|
|
|
|
if (array_key_exists('switch_user', $firewall)) {
|
|
|
|
$firewall['switch-user'] = $firewall['switch_user'];
|
|
|
|
}
|
|
|
|
if (array_key_exists('switch-user', $firewall)) {
|
|
|
|
$listeners[] = new Reference($this->createSwitchUserListener($container, $id, $firewall['switch-user'], $defaultProvider));
|
|
|
|
}
|
|
|
|
|
2011-01-25 19:28:26 +00:00
|
|
|
// Determine default entry point
|
|
|
|
if (isset($firewall['entry_point'])) {
|
|
|
|
$firewall['entry-point'] = $firewall['entry_point'];
|
|
|
|
}
|
|
|
|
if (isset($firewall['entry-point'])) {
|
|
|
|
$defaultEntryPoint = $firewall['entry-point'];
|
|
|
|
}
|
|
|
|
|
2010-10-19 12:06:43 +01:00
|
|
|
// Exception listener
|
2011-01-25 19:28:26 +00:00
|
|
|
$exceptionListener = new Reference($this->createExceptionListener($container, $firewall, $id, $defaultEntryPoint));
|
2010-10-19 12:06:43 +01:00
|
|
|
|
|
|
|
return array($matcher, $listeners, $exceptionListener);
|
|
|
|
}
|
|
|
|
|
2011-01-25 19:28:26 +00:00
|
|
|
protected function createContextListener($container, $contextKey)
|
|
|
|
{
|
|
|
|
if (isset($this->contextListeners[$contextKey])) {
|
|
|
|
return $this->contextListeners[$contextKey];
|
|
|
|
}
|
|
|
|
|
|
|
|
$listenerId = 'security.context_listener.'.count($this->contextListeners);
|
|
|
|
$listener = $container->setDefinition($listenerId, clone $container->getDefinition('security.context_listener'));
|
|
|
|
$arguments = $listener->getArguments();
|
|
|
|
$arguments[2] = $contextKey;
|
|
|
|
$listener->setArguments($arguments);
|
|
|
|
|
|
|
|
return $this->contextListeners[$contextKey] = $listenerId;
|
|
|
|
}
|
|
|
|
|
2010-12-21 15:10:53 +00:00
|
|
|
protected function createAuthenticationListeners($container, $id, $firewall, $defaultProvider)
|
2010-10-19 12:06:43 +01:00
|
|
|
{
|
|
|
|
$listeners = array();
|
|
|
|
$providers = array();
|
|
|
|
$hasListeners = false;
|
|
|
|
$defaultEntryPoint = null;
|
|
|
|
|
2011-01-25 19:28:26 +00:00
|
|
|
$positions = array('pre_auth', 'form', 'http', 'remember_me');
|
2010-10-19 12:06:43 +01:00
|
|
|
|
2010-12-02 09:09:54 +00:00
|
|
|
$tags = $container->findTaggedServiceIds('security.listener.factory');
|
|
|
|
$factories = array();
|
|
|
|
foreach ($positions as $position) {
|
|
|
|
$factories[$position] = array();
|
2010-10-19 12:06:43 +01:00
|
|
|
}
|
|
|
|
|
2010-12-02 09:09:54 +00:00
|
|
|
foreach (array_keys($tags) as $tag) {
|
|
|
|
$factory = $container->get($tag);
|
2010-10-19 12:06:43 +01:00
|
|
|
|
2010-12-02 09:09:54 +00:00
|
|
|
$factories[$factory->getPosition()][] = $factory;
|
2010-10-19 12:06:43 +01:00
|
|
|
}
|
|
|
|
|
2010-12-02 09:09:54 +00:00
|
|
|
foreach ($positions as $position) {
|
|
|
|
foreach ($factories[$position] as $factory) {
|
|
|
|
$key = $factory->getKey();
|
|
|
|
$keybis = str_replace('-', '_', $key);
|
2010-10-19 12:06:43 +01:00
|
|
|
|
2010-12-02 09:09:54 +00:00
|
|
|
if (array_key_exists($keybis, $firewall)) {
|
|
|
|
$firewall[$key] = $firewall[$keybis];
|
|
|
|
}
|
2011-01-18 10:31:05 +00:00
|
|
|
if (array_key_exists($key, $firewall) && $firewall[$key] !== false) {
|
2010-12-02 09:09:54 +00:00
|
|
|
$userProvider = isset($firewall[$key]['provider']) ? $this->getUserProviderId($firewall[$key]['provider']) : $defaultProvider;
|
2010-10-19 12:06:43 +01:00
|
|
|
|
2011-01-25 19:28:26 +00:00
|
|
|
list($provider, $listenerId, $defaultEntryPoint) = $factory->create($container, $id, $firewall[$key], $userProvider, $defaultEntryPoint);
|
2010-10-19 12:06:43 +01:00
|
|
|
|
2011-01-25 19:28:26 +00:00
|
|
|
$listeners[] = new Reference($listenerId);
|
2010-12-02 09:09:54 +00:00
|
|
|
$providers[] = new Reference($provider);
|
|
|
|
$hasListeners = true;
|
|
|
|
}
|
2010-10-19 12:06:43 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Anonymous
|
|
|
|
if (array_key_exists('anonymous', $firewall)) {
|
|
|
|
$listeners[] = new Reference('security.authentication.listener.anonymous');
|
|
|
|
$hasListeners = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (false === $hasListeners) {
|
|
|
|
throw new \LogicException(sprintf('No authentication listener registered for pattern "%s".', isset($firewall['pattern']) ? $firewall['pattern'] : ''));
|
|
|
|
}
|
|
|
|
|
|
|
|
return array($listeners, $providers, $defaultEntryPoint);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parses user providers and returns an array of their ids
|
2010-12-08 12:51:26 +00:00
|
|
|
protected function createUserProviders($config, ContainerBuilder $container)
|
2010-10-19 12:06:43 +01:00
|
|
|
{
|
2011-01-21 16:44:30 +00:00
|
|
|
$providers = $this->normalizeConfig($config, 'provider');
|
2010-10-19 12:06:43 +01:00
|
|
|
if (!$providers) {
|
|
|
|
return array();
|
|
|
|
}
|
|
|
|
|
|
|
|
$providerIds = array();
|
|
|
|
foreach ($providers as $name => $provider) {
|
2010-12-21 15:10:53 +00:00
|
|
|
$id = $this->createUserDaoProvider($name, $provider, $container);
|
2010-12-08 12:51:26 +00:00
|
|
|
|
2010-12-21 15:10:53 +00:00
|
|
|
if (in_array($id, $providerIds, true)) {
|
2010-12-08 12:51:26 +00:00
|
|
|
throw new \RuntimeException(sprintf('Provider names must be unique. Duplicate entry for %s.', $id));
|
|
|
|
}
|
|
|
|
|
2010-12-21 15:10:53 +00:00
|
|
|
$providerIds[] = $id;
|
2010-10-19 12:06:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return $providerIds;
|
|
|
|
}
|
|
|
|
|
2010-12-21 15:10:53 +00:00
|
|
|
protected function createEncoders($config, ContainerBuilder $container)
|
2010-10-19 12:06:43 +01:00
|
|
|
{
|
2011-01-21 16:44:30 +00:00
|
|
|
$encoders = $this->normalizeConfig($config, 'encoder');
|
2010-12-21 15:10:53 +00:00
|
|
|
if (!$encoders) {
|
|
|
|
return array();
|
2010-10-19 12:06:43 +01:00
|
|
|
}
|
|
|
|
|
2010-12-21 15:10:53 +00:00
|
|
|
$encoderMap = array();
|
|
|
|
foreach ($encoders as $class => $encoder) {
|
|
|
|
$encoderMap = $this->createEncoder($encoderMap, $class, $encoder, $container);
|
|
|
|
}
|
|
|
|
|
|
|
|
$container
|
|
|
|
->getDefinition('security.encoder_factory.generic')
|
|
|
|
->setArguments(array($encoderMap))
|
|
|
|
;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function createEncoder(array $encoderMap, $accountClass, $config, ContainerBuilder $container)
|
|
|
|
{
|
|
|
|
if (is_array($config) && isset($config['class'])) {
|
|
|
|
$accountClass = $config['class'];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (empty($accountClass)) {
|
|
|
|
throw new \RuntimeException('Each encoder needs an account class.');
|
|
|
|
}
|
|
|
|
|
2011-01-06 18:12:47 +00:00
|
|
|
// a minimal message digest, or plaintext encoder
|
2010-12-21 15:10:53 +00:00
|
|
|
if (is_string($config)) {
|
2011-01-06 18:12:47 +00:00
|
|
|
$config = array(
|
|
|
|
'algorithm' => $config,
|
2010-12-21 15:10:53 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// a custom encoder service
|
|
|
|
if (isset($config['id'])) {
|
|
|
|
$container
|
|
|
|
->getDefinition('security.encoder_factory.generic')
|
|
|
|
->addMethodCall('addEncoder', array($accountClass, new Reference($config['id'])))
|
|
|
|
;
|
|
|
|
|
|
|
|
return $encoderMap;
|
|
|
|
}
|
|
|
|
|
2011-01-06 18:12:47 +00:00
|
|
|
// a lazy loaded, message digest or plaintext encoder
|
2010-12-21 15:10:53 +00:00
|
|
|
if (!isset($config['algorithm'])) {
|
2011-01-14 13:21:14 +00:00
|
|
|
throw new \RuntimeException('"algorithm" must be defined.');
|
2010-12-21 15:10:53 +00:00
|
|
|
}
|
|
|
|
|
2011-01-06 18:12:47 +00:00
|
|
|
// plaintext encoder
|
|
|
|
if ('plaintext' === $config['algorithm']) {
|
|
|
|
$arguments = array();
|
|
|
|
|
|
|
|
if (array_key_exists('ignore-case', $config)) {
|
|
|
|
$arguments[0] = (Boolean) $config['ignore-case'];
|
|
|
|
}
|
|
|
|
|
|
|
|
$encoderMap[$accountClass] = array(
|
|
|
|
'class' => new Parameter('security.encoder.plain.class'),
|
|
|
|
'arguments' => $arguments,
|
|
|
|
);
|
|
|
|
|
|
|
|
return $encoderMap;
|
|
|
|
}
|
|
|
|
|
|
|
|
// message digest encoder
|
2010-12-21 15:10:53 +00:00
|
|
|
$arguments = array($config['algorithm']);
|
|
|
|
|
|
|
|
// add optional arguments
|
|
|
|
if (isset($config['encode-as-base64'])) {
|
2011-01-06 18:12:47 +00:00
|
|
|
$arguments[1] = (Boolean) $config['encode-as-base64'];
|
2010-12-21 15:10:53 +00:00
|
|
|
} else {
|
|
|
|
$arguments[1] = false;
|
2010-10-19 12:06:43 +01:00
|
|
|
}
|
|
|
|
|
2010-12-21 15:10:53 +00:00
|
|
|
if (isset($config['iterations'])) {
|
|
|
|
$arguments[2] = $config['iterations'];
|
|
|
|
} else {
|
|
|
|
$arguments[2] = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
$encoderMap[$accountClass] = array(
|
|
|
|
'class' => new Parameter('security.encoder.digest.class'),
|
|
|
|
'arguments' => $arguments,
|
|
|
|
);
|
|
|
|
|
|
|
|
return $encoderMap;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parses a <provider> tag and returns the id for the related user provider service
|
|
|
|
protected function createUserDaoProvider($name, $provider, ContainerBuilder $container, $master = true)
|
|
|
|
{
|
2010-10-19 12:06:43 +01:00
|
|
|
if (isset($provider['name'])) {
|
|
|
|
$name = $provider['name'];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!$name) {
|
2010-12-08 12:51:26 +00:00
|
|
|
throw new \RuntimeException('You must define a name for each user provider.');
|
2010-10-19 12:06:43 +01:00
|
|
|
}
|
|
|
|
|
2010-12-08 12:51:26 +00:00
|
|
|
$name = $this->getUserProviderId(strtolower($name));
|
2010-10-19 12:06:43 +01:00
|
|
|
|
|
|
|
// Existing DAO service provider
|
|
|
|
if (isset($provider['id'])) {
|
2011-01-07 14:44:29 +00:00
|
|
|
$container->setAlias($name, new Alias($provider['id'], false));
|
2011-01-04 20:13:00 +00:00
|
|
|
|
2010-12-21 15:10:53 +00:00
|
|
|
return $provider['id'];
|
2010-10-19 12:06:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Chain provider
|
|
|
|
if (isset($provider['provider'])) {
|
|
|
|
// FIXME
|
|
|
|
throw new \RuntimeException('Not implemented yet.');
|
|
|
|
}
|
|
|
|
|
|
|
|
// Doctrine Entity DAO provider
|
|
|
|
if (isset($provider['entity'])) {
|
|
|
|
$container
|
|
|
|
->register($name, '%security.user.provider.entity.class%')
|
2011-01-05 11:38:41 +00:00
|
|
|
->setPublic(false)
|
2010-10-19 12:06:43 +01:00
|
|
|
->setArguments(array(
|
|
|
|
new Reference('security.user.entity_manager'),
|
|
|
|
$provider['entity']['class'],
|
|
|
|
isset($provider['entity']['property']) ? $provider['entity']['property'] : null,
|
|
|
|
));
|
|
|
|
|
2010-12-21 15:10:53 +00:00
|
|
|
return $name;
|
2010-10-19 12:06:43 +01:00
|
|
|
}
|
|
|
|
|
2010-10-28 14:04:25 +01:00
|
|
|
// Doctrine Document DAO provider
|
|
|
|
if (isset($provider['document'])) {
|
|
|
|
$container
|
|
|
|
->register($name, '%security.user.provider.document.class%')
|
2011-01-05 11:38:41 +00:00
|
|
|
->setPublic(false)
|
2010-10-28 14:04:25 +01:00
|
|
|
->setArguments(array(
|
|
|
|
new Reference('security.user.document_manager'),
|
|
|
|
$provider['document']['class'],
|
|
|
|
isset($provider['document']['property']) ? $provider['document']['property'] : null,
|
|
|
|
));
|
|
|
|
|
2010-12-21 15:10:53 +00:00
|
|
|
return $name;
|
2010-10-28 14:04:25 +01:00
|
|
|
}
|
|
|
|
|
2010-10-19 12:06:43 +01:00
|
|
|
// In-memory DAO provider
|
2010-12-16 21:27:16 +00:00
|
|
|
$definition = $container->register($name, '%security.user.provider.in_memory.class%');
|
2011-01-05 11:38:41 +00:00
|
|
|
$definition->setPublic(false);
|
2011-01-21 16:44:30 +00:00
|
|
|
foreach ($this->normalizeConfig($provider, 'user') as $username => $user) {
|
2010-10-19 12:06:43 +01:00
|
|
|
if (isset($user['name'])) {
|
|
|
|
$username = $user['name'];
|
|
|
|
}
|
|
|
|
|
2010-10-21 09:58:00 +01:00
|
|
|
if (!array_key_exists('password', $user)) {
|
|
|
|
// if no password is provided explicitly, it means that
|
|
|
|
// the user will be used with OpenID, X.509 certificates, ...
|
|
|
|
// Let's generate a random password just to be sure this
|
|
|
|
// won't be used accidentally with other authentication schemes.
|
|
|
|
// If you want an empty password, just say so explicitly
|
|
|
|
$user['password'] = uniqid();
|
2010-10-19 12:06:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!isset($user['roles'])) {
|
|
|
|
$user['roles'] = array();
|
|
|
|
} else {
|
|
|
|
$user['roles'] = is_array($user['roles']) ? $user['roles'] : preg_split('/\s*,\s*/', $user['roles']);
|
|
|
|
}
|
|
|
|
|
|
|
|
$userId = $name.'_'.md5(serialize(array($username, $user['password'], $user['roles'])));
|
|
|
|
|
|
|
|
$container
|
2011-01-26 20:34:11 +00:00
|
|
|
->register($userId, 'Symfony\Component\Security\Core\User\User')
|
2010-10-19 12:06:43 +01:00
|
|
|
->setArguments(array($username, $user['password'], $user['roles']))
|
2011-01-05 11:38:41 +00:00
|
|
|
->setPublic(false)
|
2010-10-19 12:06:43 +01:00
|
|
|
;
|
|
|
|
|
|
|
|
$definition->addMethodCall('createUser', array(new Reference($userId)));
|
|
|
|
}
|
|
|
|
|
2010-12-21 15:10:53 +00:00
|
|
|
return $name;
|
2010-10-19 12:06:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
protected function getUserProviderId($name)
|
|
|
|
{
|
|
|
|
return 'security.authentication.provider.'.$name;
|
|
|
|
}
|
|
|
|
|
2011-01-25 19:28:26 +00:00
|
|
|
protected function createExceptionListener($container, $config, $id, $defaultEntryPoint)
|
2010-10-19 12:06:43 +01:00
|
|
|
{
|
2011-01-25 19:28:26 +00:00
|
|
|
if (isset($config['access_denied_handler'])) {
|
|
|
|
$config['access-denied-handler'] = $config['access_denied_handler'];
|
|
|
|
}
|
|
|
|
if (isset($config['access_denied_url'])) {
|
|
|
|
$config['access-denied-url'] = $config['access_denied_url'];
|
|
|
|
}
|
2010-10-19 12:06:43 +01:00
|
|
|
|
|
|
|
$exceptionListenerId = 'security.exception_listener.'.$id;
|
|
|
|
$listener = $container->setDefinition($exceptionListenerId, clone $container->getDefinition('security.exception_listener'));
|
|
|
|
$arguments = $listener->getArguments();
|
2010-12-12 08:41:47 +00:00
|
|
|
$arguments[2] = null === $defaultEntryPoint ? null : new Reference($defaultEntryPoint);
|
2011-01-25 19:28:26 +00:00
|
|
|
|
|
|
|
// access denied handler setup
|
|
|
|
if (isset($config['access-denied-handler'])) {
|
|
|
|
$arguments[4] = new Reference($config['access-denied-handler']);
|
|
|
|
} else if (isset($config['access-denied-url'])) {
|
|
|
|
$arguments[3] = $config['access-denied-url'];
|
|
|
|
}
|
|
|
|
|
2010-10-19 12:06:43 +01:00
|
|
|
$listener->setArguments($arguments);
|
|
|
|
|
|
|
|
return $exceptionListenerId;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function createSwitchUserListener($container, $id, $config, $defaultProvider)
|
|
|
|
{
|
|
|
|
$userProvider = isset($config['provider']) ? $this->getUserProviderId($config['provider']) : $defaultProvider;
|
|
|
|
|
|
|
|
$switchUserListenerId = 'security.authentication.switchuser_listener.'.$id;
|
|
|
|
$listener = $container->setDefinition($switchUserListenerId, clone $container->getDefinition('security.authentication.switchuser_listener'));
|
|
|
|
$arguments = $listener->getArguments();
|
|
|
|
$arguments[1] = new Reference($userProvider);
|
|
|
|
$listener->setArguments($arguments);
|
|
|
|
|
2010-10-20 09:59:13 +01:00
|
|
|
if (isset($config['role'])) {
|
|
|
|
$container->setParameter('security.authentication.switchuser.role', $config['role']);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isset($config['parameter'])) {
|
|
|
|
$container->setParameter('security.authentication.switchuser.parameter', $config['parameter']);
|
|
|
|
}
|
|
|
|
|
2010-10-19 12:06:43 +01:00
|
|
|
return $switchUserListenerId;
|
|
|
|
}
|
|
|
|
|
2011-01-21 10:00:52 +00:00
|
|
|
protected function createRequestMatcher($container, $path = null, $host = null, $methods = null, $ip = null, array $attributes = array())
|
|
|
|
{
|
|
|
|
$serialized = serialize(array($path, $host, $methods, $ip, $attributes));
|
|
|
|
$id = 'security.request_matcher.'.md5($serialized).sha1($serialized);
|
|
|
|
|
|
|
|
if (isset($this->requestMatchers[$id])) {
|
|
|
|
return $this->requestMatchers[$id];
|
|
|
|
}
|
|
|
|
|
|
|
|
// only add arguments that are necessary
|
|
|
|
$arguments = array($path, $host, $methods, $ip, $attributes);
|
|
|
|
while (count($arguments) > 0 && !end($arguments)) {
|
|
|
|
array_pop($arguments);
|
|
|
|
}
|
|
|
|
|
|
|
|
$container
|
|
|
|
->register($id, '%security.matcher.class%')
|
|
|
|
->setPublic(false)
|
|
|
|
->setArguments($arguments)
|
|
|
|
;
|
|
|
|
|
|
|
|
return $this->requestMatchers[$id] = new Reference($id);
|
|
|
|
}
|
|
|
|
|
2011-01-14 13:49:00 +00:00
|
|
|
protected function doAclLoad(array $config, ContainerBuilder $container)
|
2010-12-14 15:43:40 +00:00
|
|
|
{
|
|
|
|
if (!$container->hasDefinition('security.acl')) {
|
|
|
|
$loader = new XmlFileLoader($container, array(__DIR__.'/../Resources/config', __DIR__.'/Resources/config'));
|
|
|
|
$loader->load('security_acl.xml');
|
|
|
|
}
|
2011-01-06 18:12:47 +00:00
|
|
|
|
2010-12-14 15:43:40 +00:00
|
|
|
if (isset($config['connection'])) {
|
2011-01-19 09:59:46 +00:00
|
|
|
$container->setAlias('security.acl.dbal.connection', sprintf('doctrine.dbal.%s_connection', $config['connection']));
|
2010-12-14 15:43:40 +00:00
|
|
|
}
|
2011-01-06 18:12:47 +00:00
|
|
|
|
2010-12-14 15:43:40 +00:00
|
|
|
if (isset($config['cache'])) {
|
|
|
|
$container->setAlias('security.acl.cache', sprintf('security.acl.cache.%s', $config['cache']));
|
|
|
|
} else {
|
|
|
|
$container->remove('security.acl.cache.doctrine');
|
|
|
|
$container->removeAlias('security.acl.cache.doctrine.cache_impl');
|
|
|
|
}
|
|
|
|
}
|
2010-10-19 12:06:43 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the base path for the XSD files.
|
|
|
|
*
|
|
|
|
* @return string The XSD base path
|
|
|
|
*/
|
|
|
|
public function getXsdValidationBasePath()
|
|
|
|
{
|
|
|
|
return __DIR__.'/../Resources/config/schema';
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getNamespace()
|
|
|
|
{
|
|
|
|
return 'http://www.symfony-project.org/schema/dic/security';
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getAlias()
|
|
|
|
{
|
|
|
|
return 'security';
|
|
|
|
}
|
|
|
|
}
|