Commit 204a2491 authored by Bertrand Gauthier's avatar Bertrand Gauthier
Browse files

Adapteurs d'authentification Cas : tests unitaires ; refactorisation pour tests.

parent ae0273fb
<?php
namespace UnicaenAuth\Authentication\Adapter;
use phpCAS;
use UnicaenApp\Exception;
use UnicaenAuth\Options\ModuleOptions;
use Zend\Authentication\Exception\UnexpectedValueException;
use Zend\Authentication\Result as AuthenticationResult;
use Zend\EventManager\EventManager;
use Zend\EventManager\EventManagerAwareInterface;
use Zend\EventManager\EventManagerInterface;
use Zend\Mvc\Router\Http\TreeRouteStack;
use Zend\ServiceManager\ServiceManager;
use Zend\ServiceManager\ServiceManagerAwareInterface;
use ZfcUser\Authentication\Adapter\AbstractAdapter;
......@@ -34,8 +37,19 @@ class Cas extends AbstractAdapter implements ServiceManagerAwareInterface, Event
* @var ModuleOptions
*/
protected $options;
/**
* @var array
*/
protected $casOptions;
/**
* @var phpCAS
*/
protected $casClient;
/**
* Réalise l'authentification.
*
* @param AuthEvent $e
* @return boolean
......@@ -51,20 +65,14 @@ class Cas extends AbstractAdapter implements ServiceManagerAwareInterface, Event
error_reporting($oldErrorReporting = error_reporting() & ~E_NOTICE);
$this->initCasClient();
\phpCAS::forceAuthentication();
$this->getCasClient()->forceAuthentication();
// at this step, the user has been authenticated by the CAS server
// and the user's login name can be read with phpCAS::getUser().
$identity = \phpCAS::getUser();
$identity = $this->getCasClient(false)->getUser();
error_reporting($oldErrorReporting);
// // nécessaire pour que le "base DN" de l'objet \Zend\Ldap\Ldap soit bien initialisé
// $this->getLdapAdapter()->setUsername($identity)
// ->setPassword('xxx') // peu importe mais pas null
// ->authenticate();
$e->setIdentity($identity);
$this->setSatisfied(true);
......@@ -92,36 +100,64 @@ class Cas extends AbstractAdapter implements ServiceManagerAwareInterface, Event
return; // NB: l'authentification CAS est désactivée ssi le tableau des options est vide
}
$this->initCasClient();
if (\phpCAS::isAuthenticated()) {
$urlHelper = $this->getServiceManager()->get('Router'); /* @var $urlHelper \Zend\Mvc\Router\Http\TreeRouteStack */
$returnUrl = $urlHelper->getRequestUri()->setPath($urlHelper->getBaseUrl())->toString();
\phpCAS::logoutWithRedirectService($returnUrl);
if ($this->getCasClient()->isAuthenticated()) {
$router = $this->getServiceManager()->get('router'); /* @var $router TreeRouteStack */
$returnUrl = $router->getRequestUri()->setPath($router->getBaseUrl())->toString();
$this->getCasClient(false)->logoutWithRedirectService($returnUrl);
}
}
/**
* Retourne le client CAS.
*
* @throws \UnicaenApp\Exception
* @param boolean $initClient
* @return phpCAS
* @throws Exception
*/
protected function initCasClient()
protected function getCasClient($initClient = true)
{
require_once __VENDOR_DIR__ . '/gorg/phpcas/CAS.php';
$config = $this->getOptions()->getCas();
if (!isset($config['connection']['default']['params'])) {
throw new \UnicaenApp\Exception("Les paramètres de connexion au serveur CAS sont invalides.");
if (null === $this->casClient) {
$this->casClient = new phpCAS();
}
$options = $config['connection']['default']['params'];
if (!$initClient) {
return $this->casClient;
}
if (null === $this->casOptions) {
$config = $this->getOptions()->getCas();
if (!isset($config['connection']['default']['params']) || !$config['connection']['default']['params']) {
throw new Exception("Les paramètres de connexion au serveur CAS sont invalides.");
}
$this->casOptions = $config['connection']['default']['params'];
}
$options = $this->casOptions;
if (array_key_exists('debug', $options) && (bool) $options['debug']) {
\phpCAS::setDebug();
$this->casClient->setDebug();
}
// initialize phpCAS
\phpCAS::client($options['version'], $options['hostname'], $options['port'], $options['uri'], true);
$this->casClient->client($options['version'], $options['hostname'], $options['port'], $options['uri'], true);
// no SSL validation for the CAS server
\phpCAS::setNoCasServerValidation();
$this->casClient->setNoCasServerValidation();
return $this->casClient;
}
/**
* Spécifie le client CAS.
*
* @param phpCAS $casClient
* @return self
*/
public function setCasClient(phpCAS $casClient)
{
$this->casClient = $casClient;
return $this;
}
/**
......@@ -160,7 +196,7 @@ class Cas extends AbstractAdapter implements ServiceManagerAwareInterface, Event
* Set service manager
*
* @param ServiceManager $serviceManager
* @return Ldap
* @return self
*/
public function setServiceManager(ServiceManager $serviceManager)
{
......@@ -182,7 +218,7 @@ class Cas extends AbstractAdapter implements ServiceManagerAwareInterface, Event
* Inject an EventManager instance
*
* @param EventManagerInterface $eventManager
* @return Ldap
* @return self
*/
public function setEventManager(EventManagerInterface $eventManager)
{
......
<?php
namespace UnicaenAuthTest\Authentication\Adapter;
use CAS_GracefullTerminationException;
use PHPUnit_Framework_TestCase;
use UnicaenApp\Exception;
use UnicaenAuth\Authentication\Adapter\Cas;
use Zend\EventManager\EventManager;
use ZfcUser\Authentication\Adapter\AdapterChainEvent;
define ('__VENDOR_DIR__', __DIR__ . '/../../../../vendor');
require_once __VENDOR_DIR__ . '/gorg/phpcas/CAS.php';
/**
* Description of CasTest
*
* @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr>
*/
class CasTest extends PHPUnit_Framework_TestCase
{
protected $adapter;
protected $moduleOptions;
/**
* Sets up the fixture, for example, open a network connection.
* This method is called before a test is executed.
*/
protected function setUp()
{
$this->moduleOptions = $moduleOptions = new \UnicaenAuth\Options\ModuleOptions(array(
'cas' => array(
'connection' => array(
'default' => array(
'params' => array(
'hostname' => 'cas.unicaen.fr',
'port' => 443,
'version' => "2.0",
'uri' => "",
'debug' => false,
),
),
),
),
));
$serviceManager = $this->getMock('Zend\ServiceManager\ServiceManager', array('get'));
$serviceManager->expects($this->any())
->method('get')
->will($this->returnCallback(function($serviceName) use ($moduleOptions) {
if ('zfcuser_module_options' === $serviceName) {
return new \ZfcUser\Options\ModuleOptions();
}
if ('unicaen-auth_module_options' === $serviceName) {
return $moduleOptions;
}
if ('router' === $serviceName) {
$router = new \Zend\Mvc\Router\Http\TreeRouteStack();
$router->setBaseUrl('/appli')->setRequestUri(new \Zend\Uri\Http('/request'));
return $router;
}
return null;
}));
$this->adapter = new Cas();
$this->adapter->setServiceManager($serviceManager)
->setEventManager(new EventManager());
}
public function getInvalidCasOptions()
{
return array(
array(array('other' => array())),
array(array('connection' => array())),
array(array('connection' => array('default'=> array()))),
array(array('connection' => array('default'=> array('params' => array())))),
);
}
/**
* @dataProvider getInvalidCasOptions
* @expectedException Exception
*/
public function testThrowsExceptionIfNoCasParamSpecified($config)
{
$this->moduleOptions->setCas($config);
$this->adapter->authenticate(new AdapterChainEvent());
}
public function testAuthenticateReturnsNullIfNoCasConfigSpecified()
{
$this->moduleOptions->setCas(array());
$result = $this->adapter->authenticate(new AdapterChainEvent());
$this->assertNull($result);
}
public function testCanRedirectToCasIfNotAuthenticated()
{
CAS_GracefullTerminationException::throwInsteadOfExiting();
ob_start();
try {
$result = $this->adapter->authenticate(new AdapterChainEvent());
$this->fail("Exception CAS_GracefullTerminationException non levée.");
}
catch (CAS_GracefullTerminationException $e) {
}
$result = ob_get_clean();
$expected = <<<EOS
<html><head><title>CAS Authentication wanted!</title></head><body><h1>CAS Authentication wanted!</h1><p>You should already have been redirected to the CAS server. Click <a href="https://cas.unicaen.fr/login?service=http%3A%2F%2F%3A">here</a> to continue.</p><hr><address>phpCAS 1.3.1+ using server <a href="https://cas.unicaen.fr/">https://cas.unicaen.fr/</a> (CAS 2.0)</a></address></body></html>
EOS;
$this->assertEquals($expected, $result);
}
public function testAuthenticateReturnsTrueWhenAuthenticationSucceeds()
{
$casClient = $this->getMock('phpCAS', array('client', 'forceAuthentication', 'getUser'));
$casClient->staticExpects($this->once())
->method('getUser')
->will($this->returnValue($username = 'username'));
$this->adapter->setCasClient($casClient);
$event = new AdapterChainEvent();
$result = $this->adapter->authenticate($event);
$this->assertTrue($result);
$this->assertTrue($this->adapter->isSatisfied());
$this->assertEquals(array('is_satisfied' => true, 'identity' => $username), $this->adapter->getStorage()->read());
$this->assertEquals("userAuthenticated", $event->getName());
$this->assertTrue($event->propagationIsStopped());
$this->assertEquals($username, $event->getParam('identity'));
}
public function testLogoutReturnsNullIfNoCasConfigSpecified()
{
$this->moduleOptions->setCas(array());
$result = $this->adapter->logout(new AdapterChainEvent());
$this->assertNull($result);
}
public function testCanLogoutFromCasWithRedirectService()
{
$casClient = $this->getMock('phpCAS', array('client', 'isAuthenticated', 'logoutWithRedirectService'));
$casClient->staticExpects($this->once())
->method('isAuthenticated')
->will($this->returnValue(true));
$casClient->staticExpects($this->once())
->method('logoutWithRedirectService');
$this->adapter->setCasClient($casClient);
$this->adapter->logout(new AdapterChainEvent());
}
}
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment