[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.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.listener.anonymous.class">Symfony\Component\Security\Http\Firewall\AnonymousAuthenticationListener</parameter>
|
||||||
|
|
||||||
<parameter key="security.authentication.switchuser_listener.class">Symfony\Component\Security\Http\Firewall\SwitchUserListener</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"/>
|
<argument type="service" id="event_dispatcher" on-invalid="null"/>
|
||||||
</service>
|
</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">
|
<service id="security.authentication.listener.basic" class="%security.authentication.listener.basic.class%" public="false" abstract="true">
|
||||||
<tag name="monolog.logger" channel="security" />
|
<tag name="monolog.logger" channel="security" />
|
||||||
<argument type="service" id="security.context" />
|
<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\HttpDigestFactory;
|
||||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\RememberMeFactory;
|
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\RememberMeFactory;
|
||||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\X509Factory;
|
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\SimplePreAuthenticationFactory;
|
||||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SimpleFormFactory;
|
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SimpleFormFactory;
|
||||||
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\UserProvider\InMemoryFactory;
|
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\UserProvider\InMemoryFactory;
|
||||||
@ -40,6 +41,7 @@ class SecurityBundle extends Bundle
|
|||||||
$extension->addSecurityListenerFactory(new HttpDigestFactory());
|
$extension->addSecurityListenerFactory(new HttpDigestFactory());
|
||||||
$extension->addSecurityListenerFactory(new RememberMeFactory());
|
$extension->addSecurityListenerFactory(new RememberMeFactory());
|
||||||
$extension->addSecurityListenerFactory(new X509Factory());
|
$extension->addSecurityListenerFactory(new X509Factory());
|
||||||
|
$extension->addSecurityListenerFactory(new RemoteUserFactory());
|
||||||
$extension->addSecurityListenerFactory(new SimplePreAuthenticationFactory());
|
$extension->addSecurityListenerFactory(new SimplePreAuthenticationFactory());
|
||||||
$extension->addSecurityListenerFactory(new SimpleFormFactory());
|
$extension->addSecurityListenerFactory(new SimpleFormFactory());
|
||||||
|
|
||||||
|
@ -79,6 +79,7 @@ abstract class CompleteConfigurationTest extends \PHPUnit_Framework_TestCase
|
|||||||
'security.channel_listener',
|
'security.channel_listener',
|
||||||
'security.logout_listener.secure',
|
'security.logout_listener.secure',
|
||||||
'security.authentication.listener.x509.secure',
|
'security.authentication.listener.x509.secure',
|
||||||
|
'security.authentication.listener.remote_user.secure',
|
||||||
'security.authentication.listener.form.secure',
|
'security.authentication.listener.form.secure',
|
||||||
'security.authentication.listener.basic.secure',
|
'security.authentication.listener.basic.secure',
|
||||||
'security.authentication.listener.digest.secure',
|
'security.authentication.listener.digest.secure',
|
||||||
|
@ -69,6 +69,7 @@ $container->loadFromExtension('security', array(
|
|||||||
'anonymous' => true,
|
'anonymous' => true,
|
||||||
'switch_user' => true,
|
'switch_user' => true,
|
||||||
'x509' => true,
|
'x509' => true,
|
||||||
|
'remote_user' => true,
|
||||||
'logout' => true,
|
'logout' => true,
|
||||||
),
|
),
|
||||||
'host' => array(
|
'host' => array(
|
||||||
|
@ -54,6 +54,7 @@
|
|||||||
<anonymous />
|
<anonymous />
|
||||||
<switch-user />
|
<switch-user />
|
||||||
<x509 />
|
<x509 />
|
||||||
|
<remote-user />
|
||||||
<logout />
|
<logout />
|
||||||
</firewall>
|
</firewall>
|
||||||
|
|
||||||
|
@ -52,6 +52,7 @@ security:
|
|||||||
anonymous: true
|
anonymous: true
|
||||||
switch_user: true
|
switch_user: true
|
||||||
x509: true
|
x509: true
|
||||||
|
remote_user: true
|
||||||
logout: true
|
logout: true
|
||||||
host:
|
host:
|
||||||
pattern: /test
|
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