From 2539da5e6a05851be9bbc7ad1b4eb7906185b4db Mon Sep 17 00:00:00 2001 From: Lukas Kahwe Smith Date: Fri, 28 Jan 2011 16:35:16 +0100 Subject: [PATCH] [Security] added AbstractFactory --- .../Security/Factory/AbstractFactory.php | 171 ++++++++++++++++++ .../Security/Factory/FormLoginFactory.php | 97 ++++------ .../SecurityExtensionTest.php | 5 +- 3 files changed, 210 insertions(+), 63 deletions(-) create mode 100644 src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AbstractFactory.php diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AbstractFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AbstractFactory.php new file mode 100644 index 0000000000..342371f0d8 --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AbstractFactory.php @@ -0,0 +1,171 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory; + +use Symfony\Component\DependencyInjection\DefinitionDecorator; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; + +/** + * AbstractFactory is the base class for all classes inheriting from + * AbstractAuthenticationListener + * + * @author Lukas Kahwe Smith + * @author Johannes M. Schmitt + */ +abstract class AbstractFactory implements SecurityFactoryInterface +{ + protected $options = array( + 'check_path' => '/login_check', + 'login_path' => '/login', + 'use_forward' => false, + 'always_use_default_target_path' => false, + 'default_target_path' => '/', + 'target_path_parameter' => '_target_path', + 'use_referer' => false, + 'failure_path' => null, + 'failure_forward' => false, + ); + + public function create(ContainerBuilder $container, $id, $config, $userProviderId, $defaultEntryPointId) + { + if (!is_array($config)) { + $config = array(); + } + + // merge set options with default options + $options = $this->getOptionsFromConfig($config); + + // authentication provider + $authProviderId = $this->createAuthProvider($container, $id, $options, $userProviderId); + $container + ->getDefinition($authProviderId) + ->addTag('security.authentication_provider') + ; + + // authentication listener + $listenerId = $this->createListener($container, $id, $options, $userProviderId); + + // add remember-me aware tag if requested + if ($this->isRememberMeAware($config)) { + $container + ->getDefinition($listenerId) + ->addTag('security.remember_me_aware', array('id' => $id, 'provider' => $userProviderId)) + ; + } + + // create entry point if applicable (optional) + $entryPointId = $this->createEntryPoint($container, $id, $options, $defaultEntryPointId); + + return array($authProviderId, $listenerId, $entryPointId); + } + + public final function addOption($name, $default = null) + { + $this->options[$name] = $default; + } + + /** + * Subclasses must return the id of a service which implements the + * AuthenticationProviderInterface. + * + * @param ContainerBuilder $container + * @param string $id The unique id of the firewall + * @param array $options The options array for this listener + * @param string $userProviderId The id of the user provider + * + * @return string never null, the id of the authentication provider + */ + abstract protected function createAuthProvider(ContainerBuilder $container, $id, $options, $userProviderId); + + /** + * Subclasses must return the id of the abstract listener template. + * + * Listener definitions should inherit from the AbstractAuthenticationListener + * like this: + * + * + * + * In the above case, this method would return "my.listener.id". + * + * @return string + */ + abstract protected function getListenerId(); + + /** + * Subclasses may create an entry point of their as they see fit. The + * default implementation does not change the default entry point. + * + * @param ContainerBuilder $container + * @param string $id + * @param array $options + * @param string $defaultEntryPointId + * + * @return string the entry point id + */ + protected function createEntryPoint($container, $id, $options, $defaultEntryPointId) + { + return $defaultEntryPointId; + } + + /** + * Subclasses may disable remember-me features for the listener, by + * always returning false from this method. + * + * @param array $config + * + * @return Boolean Whether a possibly configured RememberMeServices should be set for this listener + */ + protected function isRememberMeAware($config) + { + return !isset($config['remember_me']) || (Boolean) $config['remember_me']; + } + + protected function createListener($container, $id, $options, $userProvider) + { + $listenerId = $this->getListenerId(); + $listener = new DefinitionDecorator($listenerId); + $listener->setArgument(3, $id); + $listener->setArgument(4, $options); + + // success handler + if (isset($config['success_handler'])) { + $listener->setArgument(5, new Reference($config['success_handler'])); + } + + // failure handler + if (isset($config['failure_handler'])) { + $listener->setArgument(6, new Reference($config['failure_handler'])); + } + + $listenerId .= '.'.$id; + $container->setDefinition($listenerId, $listener); + + return $listenerId; + } + + protected final function getOptionsFromConfig($config) + { + $options = $this->options; + + foreach (array_keys($options) as $key) { + if (array_key_exists($key, $config)) { + $options[$key] = $config[$key]; + } + } + + return $options; + } +} diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginFactory.php index 9da067799e..59427ea2dd 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/FormLoginFactory.php @@ -19,71 +19,15 @@ use Symfony\Component\DependencyInjection\Reference; * FormLoginFactory creates services for form login authentication. * * @author Fabien Potencier + * @author Johannes M. Schmitt */ -class FormLoginFactory implements SecurityFactoryInterface +class FormLoginFactory extends AbstractFactory { - public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint) + public function __construct() { - $provider = 'security.authentication.provider.dao.'.$id; - $container - ->setDefinition($provider, new DefinitionDecorator('security.authentication.provider.dao')) - ->setArgument(0, new Reference($userProvider)) - ->setArgument(2, $id) - ->addTag('security.authentication_provider') - ; - - // listener - $listenerId = 'security.authentication.listener.form.'.$id; - $listener = $container->setDefinition($listenerId, new DefinitionDecorator('security.authentication.listener.form')); - $listener->setArgument(3, $id); - - // add remember-me tag - $rememberMe = true; - if (isset($config['remember_me']) && false === $config['remember_me']) { - $rememberMe = false; - } - if ($rememberMe) { - $listener->addTag('security.remember_me_aware', array('id' => $id, 'provider' => $userProvider)); - } - - // generate options - $options = array( - 'check_path' => '/login_check', - 'login_path' => '/login', - 'use_forward' => false, - 'always_use_default_target_path' => false, - 'default_target_path' => '/', - 'target_path_parameter' => '_target_path', - 'use_referer' => false, - 'failure_path' => null, - 'failure_forward' => false, - ); - foreach (array_keys($options) as $key) { - if (array_key_exists($key, $config)) { - $options[$key] = $config[$key]; - } - } - $listener->setArgument(4, $options); - - // success handler - if (isset($config['success_handler'])) { - $listener->setArgument(5, new Reference($config['success_handler'])); - } - - // failure handler - if (isset($config['failure_handler'])) { - $listener->setArgument(6, new Reference($config['failure_handler'])); - } - - // form entry point - $entryPointId = 'security.authentication.form_entry_point.'.$id; - $container - ->setDefinition($entryPointId, new DefinitionDecorator('security.authentication.form_entry_point')) - ->addArgument($options['login_path']) - ->addArgument($options['use_forward']) - ; - - return array($provider, $listenerId, $entryPointId); + $this->addOption('username_parameter', '_username'); + $this->addOption('password_parameter', '_password'); + $this->addOption('post_only', true); } public function getPosition() @@ -95,4 +39,33 @@ class FormLoginFactory implements SecurityFactoryInterface { return 'form-login'; } + + protected function getListenerId() + { + return 'security.authentication.listener.form'; + } + + protected function createAuthProvider(ContainerBuilder $container, $id, $options, $userProviderId) + { + $provider = 'security.authentication.provider.dao.'.$id; + $container + ->setDefinition($provider, new DefinitionDecorator('security.authentication.provider.dao')) + ->setArgument(0, new Reference($userProviderId)) + ->setArgument(2, $id) + ; + + return $provider; + } + + protected function createEntryPoint($container, $id, $options, $defaultEntryPoint) + { + $entryPointId = 'security.authentication.form_entry_point.'.$id; + $container + ->setDefinition($entryPointId, new DefinitionDecorator('security.authentication.form_entry_point')) + ->addArgument($options['login_path']) + ->addArgument($options['use_forward']) + ; + + return $entryPointId; + } } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php index d83b3b975f..733d06c776 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php @@ -43,6 +43,9 @@ abstract class SecurityExtensionTest extends \PHPUnit_Framework_TestCase 'security.authentication.provider.doctrine', 'security.authentication.provider.service', 'security.authentication.provider.anonymous', + 'security.authentication.provider.dao', + 'security.authentication.provider.pre_authenticated', + 'security.authentication.provider.rememberme', ); $this->assertEquals(array(), array_diff($expectedProviders, $providers)); @@ -58,7 +61,7 @@ abstract class SecurityExtensionTest extends \PHPUnit_Framework_TestCase foreach (array_keys($arguments[1]) as $contextId) { $contextDef = $container->getDefinition($contextId); $arguments = $contextDef->getArguments(); - $listeners[] = array_map(function ($ref) { return preg_replace('/\.[a-f0-9]+$/', '', (string) $ref); }, $arguments[0]); + $listeners[] = array_map(function ($ref) { return preg_replace('/\.[a-f0-9]+$/', '', (string) $ref); }, $arguments['index_0']); } $this->assertEquals(array(