[Security] Added a REMOTE_USER based listener to security firewalls
This commit is contained in:
parent
2aea588ceb
commit
a2872f21b9
@ -0,0 +1,65 @@
|
||||
<?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\Bundle\SecurityBundle\DependencyInjection\Security\Factory;
|
||||
|
||||
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
|
||||
|
||||
use Symfony\Component\DependencyInjection\DefinitionDecorator;
|
||||
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* RemoteUserFactory creates services for REMOTE_USER based authentication.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Maxime Douailin <maxime.douailin@gmail.com>
|
||||
*/
|
||||
class RemoteUserFactory implements SecurityFactoryInterface
|
||||
{
|
||||
public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint)
|
||||
{
|
||||
$providerId = 'security.authentication.provider.pre_authenticated.'.$id;
|
||||
$container
|
||||
->setDefinition($providerId, new DefinitionDecorator('security.authentication.provider.pre_authenticated'))
|
||||
->replaceArgument(0, new Reference($userProvider))
|
||||
->addArgument($id)
|
||||
;
|
||||
|
||||
$listenerId = 'security.authentication.listener.remote_user.'.$id;
|
||||
$listener = $container->setDefinition($listenerId, new DefinitionDecorator('security.authentication.listener.remote_user'));
|
||||
$listener->replaceArgument(2, $id);
|
||||
$listener->replaceArgument(3, $config['user']);
|
||||
|
||||
return array($providerId, $listenerId, $defaultEntryPoint);
|
||||
}
|
||||
|
||||
public function getPosition()
|
||||
{
|
||||
return 'pre_auth';
|
||||
}
|
||||
|
||||
public function getKey()
|
||||
{
|
||||
return 'remote-user';
|
||||
}
|
||||
|
||||
public function addConfiguration(NodeDefinition $node)
|
||||
{
|
||||
$node
|
||||
->children()
|
||||
->scalarNode('provider')->end()
|
||||
->scalarNode('user')->defaultValue('REMOTE_USER')->end()
|
||||
->end()
|
||||
;
|
||||
}
|
||||
}
|
@ -24,6 +24,8 @@
|
||||
|
||||
<parameter key="security.authentication.listener.x509.class">Symfony\Component\Security\Http\Firewall\X509AuthenticationListener</parameter>
|
||||
|
||||
<parameter key="security.authentication.listener.remote_user.class">Symfony\Component\Security\Http\Firewall\RemoteUserAuthenticationListener</parameter>
|
||||
|
||||
<parameter key="security.authentication.listener.anonymous.class">Symfony\Component\Security\Http\Firewall\AnonymousAuthenticationListener</parameter>
|
||||
|
||||
<parameter key="security.authentication.switchuser_listener.class">Symfony\Component\Security\Http\Firewall\SwitchUserListener</parameter>
|
||||
@ -173,6 +175,16 @@
|
||||
<argument type="service" id="event_dispatcher" on-invalid="null"/>
|
||||
</service>
|
||||
|
||||
<service id="security.authentication.listener.remote_user" class="%security.authentication.listener.remote_user.class%" public="false" abstract="true">
|
||||
<tag name="monolog.logger" channel="security" />
|
||||
<argument type="service" id="security.context" />
|
||||
<argument type="service" id="security.authentication.manager" />
|
||||
<argument /> <!-- Provider-shared Key -->
|
||||
<argument /> <!-- REMOTE_USER server env var -->
|
||||
<argument type="service" id="logger" on-invalid="null" />
|
||||
<argument type="service" id="event_dispatcher" on-invalid="null"/>
|
||||
</service>
|
||||
|
||||
<service id="security.authentication.listener.basic" class="%security.authentication.listener.basic.class%" public="false" abstract="true">
|
||||
<tag name="monolog.logger" channel="security" />
|
||||
<argument type="service" id="security.context" />
|
||||
|
@ -19,6 +19,7 @@ use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\HttpBasic
|
||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\HttpDigestFactory;
|
||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\RememberMeFactory;
|
||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\X509Factory;
|
||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\RemoteUserFactory;
|
||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SimplePreAuthenticationFactory;
|
||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SimpleFormFactory;
|
||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\UserProvider\InMemoryFactory;
|
||||
@ -40,6 +41,7 @@ class SecurityBundle extends Bundle
|
||||
$extension->addSecurityListenerFactory(new HttpDigestFactory());
|
||||
$extension->addSecurityListenerFactory(new RememberMeFactory());
|
||||
$extension->addSecurityListenerFactory(new X509Factory());
|
||||
$extension->addSecurityListenerFactory(new RemoteUserFactory());
|
||||
$extension->addSecurityListenerFactory(new SimplePreAuthenticationFactory());
|
||||
$extension->addSecurityListenerFactory(new SimpleFormFactory());
|
||||
|
||||
|
@ -79,6 +79,7 @@ abstract class CompleteConfigurationTest extends \PHPUnit_Framework_TestCase
|
||||
'security.channel_listener',
|
||||
'security.logout_listener.secure',
|
||||
'security.authentication.listener.x509.secure',
|
||||
'security.authentication.listener.remote_user.secure',
|
||||
'security.authentication.listener.form.secure',
|
||||
'security.authentication.listener.basic.secure',
|
||||
'security.authentication.listener.digest.secure',
|
||||
|
@ -69,6 +69,7 @@ $container->loadFromExtension('security', array(
|
||||
'anonymous' => true,
|
||||
'switch_user' => true,
|
||||
'x509' => true,
|
||||
'remote_user' => true,
|
||||
'logout' => true,
|
||||
),
|
||||
'host' => array(
|
||||
|
@ -54,6 +54,7 @@
|
||||
<anonymous />
|
||||
<switch-user />
|
||||
<x509 />
|
||||
<remote-user />
|
||||
<logout />
|
||||
</firewall>
|
||||
|
||||
|
@ -52,6 +52,7 @@ security:
|
||||
anonymous: true
|
||||
switch_user: true
|
||||
x509: true
|
||||
remote_user: true
|
||||
logout: true
|
||||
host:
|
||||
pattern: /test
|
||||
|
@ -0,0 +1,49 @@
|
||||
<?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\Http\Firewall;
|
||||
|
||||
use Symfony\Component\Security\Core\SecurityContextInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
/**
|
||||
* REMOTE_USER authentication listener.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Maxime Douailin <maxime.douailin@gmail.com>
|
||||
*/
|
||||
class RemoteUserAuthenticationListener extends AbstractPreAuthenticatedListener
|
||||
{
|
||||
private $userKey;
|
||||
|
||||
public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, $providerKey, $userKey = 'REMOTE_USER', LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null)
|
||||
{
|
||||
parent::__construct($securityContext, $authenticationManager, $providerKey, $logger, $dispatcher);
|
||||
|
||||
$this->userKey = $userKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getPreAuthenticatedData(Request $request)
|
||||
{
|
||||
if (!$request->server->has($this->userKey)) {
|
||||
throw new BadCredentialsException(sprintf('User key was not found: %s', $this->userKey));
|
||||
}
|
||||
|
||||
return array($request->server->get($this->userKey), null);
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
<?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\Http\Tests\Firewall;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Security\Http\Firewall\RemoteUserAuthenticationListener;
|
||||
|
||||
class RemoteUserAuthenticationListenerTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testGetPreAuthenticatedData()
|
||||
{
|
||||
$serverVars = array(
|
||||
'REMOTE_USER' => 'TheUser'
|
||||
);
|
||||
|
||||
$request = new Request(array(), array(), array(), array(), array(), $serverVars);
|
||||
|
||||
$context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
|
||||
|
||||
$authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface');
|
||||
|
||||
$listener = new RemoteUserAuthenticationListener(
|
||||
$context,
|
||||
$authenticationManager,
|
||||
'TheProviderKey'
|
||||
);
|
||||
|
||||
$method = new \ReflectionMethod($listener, 'getPreAuthenticatedData');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$result = $method->invokeArgs($listener, array($request));
|
||||
$this->assertSame($result, array('TheUser', null));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Security\Core\Exception\BadCredentialsException
|
||||
*/
|
||||
public function testGetPreAuthenticatedDataNoUser()
|
||||
{
|
||||
$request = new Request(array(), array(), array(), array(), array(), array());
|
||||
|
||||
$context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
|
||||
|
||||
$authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface');
|
||||
|
||||
$listener = new RemoteUserAuthenticationListener(
|
||||
$context,
|
||||
$authenticationManager,
|
||||
'TheProviderKey'
|
||||
);
|
||||
|
||||
$method = new \ReflectionMethod($listener, 'getPreAuthenticatedData');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$result = $method->invokeArgs($listener, array($request));
|
||||
}
|
||||
|
||||
public function testGetPreAuthenticatedDataWithDifferentKeys()
|
||||
{
|
||||
$userCredentials = array('TheUser', null);
|
||||
|
||||
$request = new Request(array(), array(), array(), array(), array(), array(
|
||||
'TheUserKey' => 'TheUser'
|
||||
));
|
||||
$context = $this->getMock('Symfony\Component\Security\Core\SecurityContextInterface');
|
||||
|
||||
$authenticationManager = $this->getMock('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface');
|
||||
|
||||
$listener = new RemoteUserAuthenticationListener(
|
||||
$context,
|
||||
$authenticationManager,
|
||||
'TheProviderKey',
|
||||
'TheUserKey'
|
||||
);
|
||||
|
||||
$method = new \ReflectionMethod($listener, 'getPreAuthenticatedData');
|
||||
$method->setAccessible(true);
|
||||
|
||||
$result = $method->invokeArgs($listener, array($request));
|
||||
$this->assertSame($result, $userCredentials);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user