Skip to content

Commit

Permalink
added real logout support & tests
Browse files Browse the repository at this point in the history
  • Loading branch information
jfsimon committed Jul 14, 2011
1 parent 68424c6 commit bf68af6
Show file tree
Hide file tree
Showing 17 changed files with 212 additions and 25 deletions.
23 changes: 23 additions & 0 deletions Controller/Controller.php
@@ -0,0 +1,23 @@
<?php

namespace BeSimple\SsoAuthBundle\Controller;

use Symfony\Component\DependencyInjection\ContainerAware;
use Symfony\Component\DependencyInjection\ContainerInterface;

class Controller extends ContainerAware
{
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}

protected function render($view, array $parameters)
{
return $this
->container
->get('templating')
->renderResponse($view, $parameters)
;
}
}
9 changes: 7 additions & 2 deletions Controller/OpenSsoController.php
Expand Up @@ -4,10 +4,15 @@

use Symfony\Component\HttpKernel\Exception\HttpException;

class OpenSsoController
class OpenSsoController extends Controller
{
public function loginAction()
{
throw new HttpException(500, 'Method not implemented.');
throw new HttpException(500, 'Not implemented.');
}

public function logoutAction()
{
throw new HttpException(500, 'Not implemented.');
}
}
19 changes: 13 additions & 6 deletions Controller/TrustedSsoController.php
Expand Up @@ -2,18 +2,25 @@

namespace BeSimple\SsoAuthBundle\Controller;

use Symfony\Component\DependencyInjection\ContainerAware;
use BeSimple\SsoAuthBundle\Sso\SsoProviderInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use BeSimple\SsoAuthBundle\Sso\SsoProviderInterface;

class TrustedSsoController extends ContainerAware
class TrustedSsoController extends Controller
{
public function loginAction(SsoProviderInterface $provider, Request $request, AuthenticationException $exception = null)
{
$view = 'BeSimpleSsoAuthBundle:TrustedSso:login.html.twig';
$parameters = array('provider' => $provider, 'request' => $request, 'exception' => $exception);
return $this->render(
'BeSimpleSsoAuthBundle:TrustedSso:login.html.twig',
array('provider' => $provider, 'request' => $request, 'exception' => $exception)
);
}

return $this->container->get('templating')->renderResponse($view, $parameters);
public function logoutAction(SsoProviderInterface $provider, Request $request)
{
return $this->render(
'BeSimpleSsoAuthBundle:TrustedSso:logout.html.twig',
array('provider' => $provider, 'request' => $request)
);
}
}
20 changes: 19 additions & 1 deletion DependencyInjection/Security/Factory/AbstractSsoFactory.php
Expand Up @@ -9,6 +9,13 @@

abstract class AbstractSsoFactory extends AbstractFactory
{
public function create(ContainerBuilder $container, $id, $config, $userProviderId, $defaultEntryPointId)
{
$this->createLogoutSuccessHandler($container, $config);

return parent::create($container, $id, $config, $userProviderId, $defaultEntryPointId);
}

public function getPosition()
{
return 'form';
Expand All @@ -21,9 +28,20 @@ protected function createAuthProvider(ContainerBuilder $container, $id, $config,
$container
->setDefinition($provider, new DefinitionDecorator('security.authentication.provider.sso'))
->replaceArgument(0, new Reference($userProviderId))
// ->replaceArgument(2, $id) // dont need provider id
;

return $provider;
}

protected function createLogoutSuccessHandler(ContainerBuilder $container, $config)
{
$templateHandler = 'security.logout.sso.success_handler';
$realHandler = 'security.logout.success_handler';

// dont know if this is the right way, but it works
$container
->setDefinition($realHandler, new DefinitionDecorator($templateHandler))
->addArgument($config)
;
}
}
3 changes: 2 additions & 1 deletion DependencyInjection/Security/Factory/OpenSsoFactory.php
Expand Up @@ -12,7 +12,8 @@ class OpenSsoFactory extends AbstractSsoFactory
{
public function __construct()
{
$this->addOption('login_controller', 'BeSimpleSsoAuthBundle:OpenSso:login');
$this->addOption('login_action', 'BeSimpleSsoAuthBundle:TrustedSso:login');
$this->addOption('logout_action', 'BeSimpleSsoAuthBundle:TrustedSso:logout');
}

public function getKey()
Expand Down
4 changes: 3 additions & 1 deletion DependencyInjection/Security/Factory/TrustedSsoFactory.php
Expand Up @@ -14,6 +14,7 @@ public function __construct()
{
$this->addOption('server');
$this->addOption('login_action', 'BeSimpleSsoAuthBundle:TrustedSso:login');
$this->addOption('logout_action', 'BeSimpleSsoAuthBundle:TrustedSso:logout');
}

public function getKey()
Expand Down Expand Up @@ -41,7 +42,8 @@ protected function createEntryPoint($container, $id, $config, $defaultEntryPoint
protected function createListener($container, $id, $config, $userProvider)
{
$listenerId = $this->getListenerId();
$listener = new DefinitionDecorator($listenerId);
$listener = new DefinitionDecorator($listenerId);

$listener->replaceArgument(4, $id);
$listener->replaceArgument(6, array_intersect_key($config, $this->options));

Expand Down
10 changes: 10 additions & 0 deletions Resources/config/security_listeners.xml
Expand Up @@ -8,6 +8,8 @@
<parameter key="security.authentication.trusted_sso_entry_point.class">BeSimple\SsoAuthBundle\Security\Http\EntryPoint\TrustedSsoAuthenticationEntryPoint</parameter>
<parameter key="security.authentication.provider.sso.class">BeSimple\SsoAuthBundle\Security\Core\Authentication\Provider\SsoAuthenticationProvider</parameter>
<parameter key="security.authentication.listener.trusted_sso.class">BeSimple\SsoAuthBundle\Security\Http\Firewall\TrustedSsoAuthenticationListener</parameter>
<parameter key="security.logout.handler.sso.class">BeSimple\SsoAuthBundle\Security\Http\Logout\SsoLogoutHandler</parameter>
<parameter key="security.logout.sso_success_handler.class">BeSimple\SsoAuthBundle\Security\Http\Logout\SsoLogoutSuccessHandler</parameter>
</parameters>

<services>
Expand All @@ -24,6 +26,14 @@
<!-- $hideUserNotFoundExceptions = true -->
</service>

<service id="security.logout.handler.sso" class="%security.logout.handler.sso.class%" public="false" />

<service id="security.logout.sso.success_handler" class="%security.logout.sso_success_handler.class%">
<argument type="service" id="http_kernel" />
<argument type="service" id="be_simple_sso_auth.sso_factory" />
<!-- $ssoProviderFactoryConfig -->
</service>

<service id="security.authentication.listener.trusted_sso" class="%security.authentication.listener.trusted_sso.class%" public="false">
<argument type="service" id="security.context" />
<argument type="service" id="security.authentication.manager" />
Expand Down
13 changes: 13 additions & 0 deletions Resources/views/TrustedSso/logout.html.twig
@@ -0,0 +1,13 @@
{% extends "::base.html.twig" %}

{% block body %}

<h1>You're about to logout</h1>

<p class="notice">
Follow this link to logout from external
<strong>{{ provider.protocolName | upper }}</strong> server :
<a href="{{ provider.server.logoutUrl }}">{{ provider.server.logoutUrl }}</a>.
</p>

{% endblock body %}
2 changes: 0 additions & 2 deletions Security/Http/Firewall/TrustedSsoAuthenticationListener.php
Expand Up @@ -34,8 +34,6 @@ protected function attemptAuthentication(Request $request)
return null;
}

//$request->getSession()->set(SecurityContextInterface::LAST_USERNAME, $username);

return $this->authenticationManager->authenticate($ssoProvider->createToken($request));
}
}
1 change: 1 addition & 0 deletions Security/Http/Logout/SsoLogoutHandler.php
Expand Up @@ -6,6 +6,7 @@
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use BeSimple\SsoAuthBundle\Security\Core\Authentication\Token\SsoToken;

class SsoLogoutHandler implements LogoutHandlerInterface
{
Expand Down
59 changes: 59 additions & 0 deletions Security/Http/Logout/SsoLogoutSuccessHandler.php
@@ -0,0 +1,59 @@
<?php

namespace BeSimple\SsoAuthBundle\Security\Http\Logout;

use Symfony\Component\Security\Http\Logout\LogoutSuccessHandlerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Bundle\FrameworkBundle\HttpKernel;
use BeSimple\SsoAuthBundle\Sso\SsoFactory;

class SsoLogoutSuccessHandler implements LogoutSuccessHandlerInterface
{
/**
* @var HttpKernel
*/
protected $httpKernel;

/**
* @var SsoFactory
*/
protected $ssoFactory;

/**
* @var array
*/
protected $config;

/**
* @param HttpKernel $httpKernel
* @param SsoProviderFactory $ssoFactory
* @param array $ssoConfig
*/
public function __construct(HttpKernel $httpKernel, SsoFactory $ssoFactory, array $config)
{
$this->httpKernel = $httpKernel;
$this->ssoFactory = $ssoFactory;
$this->config = $config;
}

/**
* @param Request $request
* @param null|AuthenticationException $authException
* @return Response
*/
public function onLogoutSuccess(Request $request)
{
$action = $this->config['logout_action'];
$provider = $this->ssoFactory->createProvider($this->config['server'], $this->config['check_path']);

if ($action) {
return $this->httpKernel->forward($action, array(
'provider' => $provider,
'request' => $request,
));
}

return new RedirectResponse($provider->getServer()->getLogoutUrl());
}
}
15 changes: 13 additions & 2 deletions Tests/Controller/Server/CasController.php
Expand Up @@ -8,7 +8,6 @@
class CasController extends Controller
{
/**
* @abstract
* @param \Symfony\Component\HttpFoundation\Request $request
* @param string $credentials
* @return string
Expand All @@ -20,13 +19,25 @@ protected function getLoginRedirectUrl(Request $request, Login $login)
return sprintf('%s?ticket=%s', $url, $login->getCredentials());
}

/**
* @param \Symfony\Component\HttpFoundation\Request $request
* @return string
*/
protected function getLogoutRedirectUrl(Request $request)
{
return urldecode($request->query->get('service'));
}

/**
* @param \Symfony\Component\HttpFoundation\Request $request
* @return string
*/
protected function getCredentials(Request $request)
{
return $request->query->get('ticket');
}

/**
* @abstract
* @param \Symfony\Component\HttpFoundation\Request $request
* @param string $view
* @return string
Expand Down
17 changes: 17 additions & 0 deletions Tests/Controller/Server/Controller.php
Expand Up @@ -11,6 +11,8 @@

abstract class Controller extends BaseController
{
const LOGOUT_MESSAGE = 'you are logged out';

/**
* @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
*/
Expand Down Expand Up @@ -44,6 +46,14 @@ public function validationAction()
return $this->render($view, array('username' => $credentials));
}

public function logoutAction()
{
return $this->render('common/link.html.twig', array(
'message' => self::LOGOUT_MESSAGE,
'url' => $this->getLogoutRedirectUrl($this->getRequest()),
));
}

/**
* @return \Symfony\Component\Form\Form
*/
Expand All @@ -69,6 +79,13 @@ protected function isValidCredentials($credentials)
*/
abstract protected function getLoginRedirectUrl(Request $request, Login $login);

/**
* @abstract
* @param \Symfony\Component\HttpFoundation\Request $request
* @return string
*/
abstract protected function getLogoutRedirectUrl(Request $request);

/**
* @abstract
* @param \Symfony\Component\HttpFoundation\Request $request
Expand Down
13 changes: 11 additions & 2 deletions Tests/Controller/TrustedSsoController.php
Expand Up @@ -8,13 +8,22 @@

class TrustedSsoController extends Controller
{
const LOGIN_REQUIRED_MESSAGE = 'login required';
const LOGIN_REQUIRED_MESSAGE = 'login required';
const LOGOUT_REDIRECT_MESSAGE = 'logout redirection';

public function loginAction(SsoProviderInterface $provider, Request $request, AuthenticationException $exception = null)
{
return $this->render('common/trusted_login.html.twig', array(
return $this->render('common/link.html.twig', array(
'message' => self::LOGIN_REQUIRED_MESSAGE,
'url' => $provider->getServer()->getLoginUrl()
));
}

public function logoutAction(SsoProviderInterface $provider, Request $request)
{
return $this->render('common/link.html.twig', array(
'message' => self::LOGOUT_REDIRECT_MESSAGE,
'url' => $provider->getServer()->getLogoutUrl()
));
}
}
14 changes: 11 additions & 3 deletions Tests/Functional/LoginTest.php
Expand Up @@ -5,6 +5,7 @@
use Symfony\Bundle\FrameworkBundle\Client;
use BeSimple\SsoAuthBundle\Tests\Controller\TestController;
use BeSimple\SsoAuthBundle\Tests\Controller\TrustedSsoController;
use BeSimple\SsoAuthBundle\Tests\Controller\Server\Controller as ServerController;

class LoginTest extends WebTestCase
{
Expand All @@ -29,8 +30,16 @@ public function testLogin(Client $client, $securedUrl, $login, $expectedMessage)
$crawler = $client->submit($form, array('login[username]' => $login, 'login[password]' => $login));
$this->assertEquals($expectedMessage, $crawler->filter('#message')->text());

// logout
// logout -> got logout redirect
$crawler = $client->request('GET', '/secured/logout');
$this->assertEquals(TrustedSsoController::LOGOUT_REDIRECT_MESSAGE, $crawler->filter('#message')->text());

// click link -> got logout done
$crawler = $client->click($crawler->filter('#url')->link());
$this->assertEquals(ServerController::LOGOUT_MESSAGE, $crawler->filter('#message')->text());

// click link -> return to secured page anonymously
$crawler = $client->click($crawler->filter('#url')->link());
$this->assertEquals(TrustedSsoController::LOGIN_REQUIRED_MESSAGE, $crawler->filter('#message')->text());
}

Expand All @@ -53,8 +62,7 @@ private function provideCases()
array('/secured', self::LOGIN_INVALID, TrustedSsoController::LOGIN_REQUIRED_MESSAGE),
array('/secured/user', self::LOGIN_USER, TestController::USER_MESSAGE),
array('/secured/admin', self::LOGIN_ADMIN, TestController::ADMIN_MESSAGE),
// array('/secured/admin', self::LOGIN_USER, TrustedSsoController::LOGIN_REQUIRED_MESSAGE),
// get 500 AccessDenied ...
// got 500 AccessDenied with array('/secured/admin', self::LOGIN_USER, TrustedSsoController::LOGIN_REQUIRED_MESSAGE)
);
}
}

0 comments on commit bf68af6

Please sign in to comment.