View source
<?php
namespace Drupal\Tests\cas\Unit\Controller;
use Drupal\cas\CasPropertyBag;
use Drupal\cas\Controller\ServiceController;
use Drupal\cas\Event\CasPreUserLoadRedirectEvent;
use Drupal\cas\Exception\CasLoginException;
use Drupal\cas\Exception\CasValidateException;
use Drupal\cas\Service\CasHelper;
use Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Logger\LoggerChannelFactory;
use Drupal\Core\Utility\Token;
use Drupal\externalauth\ExternalAuthInterface;
use Drupal\Tests\UnitTestCase;
use Prophecy\Argument;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\HttpFoundation\Request;
class ServiceControllerTest extends UnitTestCase {
protected $casHelper;
protected $requestStack;
protected $casValidator;
protected $casUserManager;
protected $casLogout;
protected $urlGenerator;
protected $configFactory;
protected $requestBag;
protected $queryBag;
protected $requestObject;
protected $messenger;
protected $eventDispatcher;
protected $externalAuth;
protected $token;
protected function setUp() : void {
parent::setUp();
$this->casValidator = $this
->getMockBuilder('\\Drupal\\cas\\Service\\CasValidator')
->disableOriginalConstructor()
->getMock();
$this->casUserManager = $this
->getMockBuilder('\\Drupal\\cas\\Service\\CasUserManager')
->disableOriginalConstructor()
->getMock();
$this->casLogout = $this
->getMockBuilder('\\Drupal\\cas\\Service\\CasLogout')
->disableOriginalConstructor()
->getMock();
$this->configFactory = $this
->getConfigFactoryStub([
'cas.settings' => [
'server.hostname' => 'example-server.com',
'server.port' => 443,
'server.path' => '/cas',
'error_handling.login_failure_page' => '/user/login',
'error_handling.message_validation_failure' => '/user/login',
'login_success_message' => '',
],
]);
$this->token = $this
->prophesize(Token::class);
$this->casHelper = new CasHelper($this->configFactory, new LoggerChannelFactory(), $this->token
->reveal());
$this->requestStack = $this
->createMock('\\Symfony\\Component\\HttpFoundation\\RequestStack');
$this->urlGenerator = $this
->createMock('\\Drupal\\Core\\Routing\\UrlGeneratorInterface');
$this->requestObject = new Request();
$request_bag = $this
->createMock('\\Symfony\\Component\\HttpFoundation\\ParameterBag');
$query_bag = $this
->createMock('\\Symfony\\Component\\HttpFoundation\\ParameterBag');
$this->requestObject->query = $query_bag;
$this->requestObject->request = $request_bag;
$storage = $this
->getMockBuilder('\\Symfony\\Component\\HttpFoundation\\Session\\Storage\\MockArraySessionStorage')
->setMethods(NULL)
->getMock();
$session = $this
->getMockBuilder('\\Symfony\\Component\\HttpFoundation\\Session\\Session')
->setConstructorArgs([
$storage,
])
->setMethods(NULL)
->getMock();
$session
->start();
$this->requestObject
->setSession($session);
$this->requestBag = $request_bag;
$this->queryBag = $query_bag;
$this->messenger = $this
->createMock('\\Drupal\\Core\\Messenger\\MessengerInterface');
$this->eventDispatcher = $this
->prophesize(ContainerAwareEventDispatcher::class);
$this->externalAuth = $this
->prophesize(ExternalAuthInterface::class);
}
public function testSingleLogout($returnto) {
$this
->setupRequestParameters($returnto, TRUE, FALSE);
$this->requestStack
->expects($this
->once())
->method('getCurrentRequest')
->will($this
->returnValue($this->requestObject));
$this->casLogout
->expects($this
->once())
->method('handleSlo')
->with($this
->equalTo('<foobar/>'));
$serviceController = new ServiceController($this->casHelper, $this->casValidator, $this->casUserManager, $this->casLogout, $this->requestStack, $this->urlGenerator, $this->configFactory, $this->messenger, $this->eventDispatcher
->reveal(), $this->externalAuth
->reveal());
$serviceController
->setStringTranslation($this
->getStringTranslationStub());
$response = $serviceController
->handle();
$this
->assertEquals(200, $response
->getStatusCode());
$this
->assertEquals('', $response
->getContent());
}
public function testMissingTicketRedirectsHome($returnto) {
$this
->setupRequestParameters($returnto, FALSE, FALSE);
$this->requestStack
->expects($this
->once())
->method('getCurrentRequest')
->will($this
->returnValue($this->requestObject));
if ($returnto) {
$this
->assertDestinationSetFromReturnTo();
}
$serviceController = new ServiceController($this->casHelper, $this->casValidator, $this->casUserManager, $this->casLogout, $this->requestStack, $this->urlGenerator, $this->configFactory, $this->messenger, $this->eventDispatcher
->reveal(), $this->externalAuth
->reveal());
$serviceController
->setStringTranslation($this
->getStringTranslationStub());
$this
->assertRedirectedToFrontPageOnHandle($serviceController);
}
public function testSuccessfulLogin($returnto) {
$this
->setupRequestParameters($returnto, FALSE, TRUE);
$this->requestStack
->expects($this
->once())
->method('getCurrentRequest')
->will($this
->returnValue($this->requestObject));
if ($returnto) {
$this
->assertDestinationSetFromReturnTo();
}
$validation_data = new CasPropertyBag('testuser');
$this
->assertSuccessfulValidation($returnto);
$this->casUserManager
->expects($this
->once())
->method('login')
->with($this
->equalTo($validation_data), $this
->equalTo('ST-foobar'));
$serviceController = new ServiceController($this->casHelper, $this->casValidator, $this->casUserManager, $this->casLogout, $this->requestStack, $this->urlGenerator, $this->configFactory, $this->messenger, $this->eventDispatcher
->reveal(), $this->externalAuth
->reveal());
$serviceController
->setStringTranslation($this
->getStringTranslationStub());
$this
->assertRedirectedToFrontPageOnHandle($serviceController);
}
public function testSuccessfulLoginProxyEnabled($returnto) {
$this
->setupRequestParameters($returnto, FALSE, TRUE);
$this->requestStack
->expects($this
->once())
->method('getCurrentRequest')
->will($this
->returnValue($this->requestObject));
if ($returnto) {
$this
->assertDestinationSetFromReturnTo();
}
$this
->assertSuccessfulValidation($returnto, TRUE);
$validation_data = new CasPropertyBag('testuser');
$validation_data
->setPgt('testpgt');
$this->casUserManager
->expects($this
->once())
->method('login')
->with($this
->equalTo($validation_data), $this
->equalTo('ST-foobar'));
$configFactory = $this
->getConfigFactoryStub([
'cas.settings' => [
'server.hostname' => 'example-server.com',
'server.port' => 443,
'server.path' => '/cas',
'proxy.initialize' => TRUE,
],
]);
$serviceController = new ServiceController($this->casHelper, $this->casValidator, $this->casUserManager, $this->casLogout, $this->requestStack, $this->urlGenerator, $configFactory, $this->messenger, $this->eventDispatcher
->reveal(), $this->externalAuth
->reveal());
$serviceController
->setStringTranslation($this
->getStringTranslationStub());
$this
->assertRedirectedToFrontPageOnHandle($serviceController);
}
public function testTicketValidationError($returnto) {
$this
->setupRequestParameters($returnto, FALSE, TRUE);
$this->requestStack
->expects($this
->once())
->method('getCurrentRequest')
->will($this
->returnValue($this->requestObject));
$this->casValidator
->expects($this
->once())
->method('validateTicket')
->will($this
->throwException(new CasValidateException()));
$this->casUserManager
->expects($this
->never())
->method('login');
$serviceController = new ServiceController($this->casHelper, $this->casValidator, $this->casUserManager, $this->casLogout, $this->requestStack, $this->urlGenerator, $this->configFactory, $this->messenger, $this->eventDispatcher
->reveal(), $this->externalAuth
->reveal());
$serviceController
->setStringTranslation($this
->getStringTranslationStub());
$this
->assertRedirectedToSpecialPageOnLoginFailure($serviceController);
}
public function testLoginError($returnto) {
$this
->setupRequestParameters($returnto, FALSE, TRUE);
$this->requestStack
->expects($this
->once())
->method('getCurrentRequest')
->will($this
->returnValue($this->requestObject));
$this
->assertSuccessfulValidation($returnto);
$this->casUserManager
->expects($this
->once())
->method('login')
->will($this
->throwException(new CasLoginException()));
$serviceController = new ServiceController($this->casHelper, $this->casValidator, $this->casUserManager, $this->casLogout, $this->requestStack, $this->urlGenerator, $this->configFactory, $this->messenger, $this->eventDispatcher
->reveal(), $this->externalAuth
->reveal());
$serviceController
->setStringTranslation($this
->getStringTranslationStub());
$this
->assertRedirectedToSpecialPageOnLoginFailure($serviceController);
}
public function testEventListenerChangesCasUsername($returnto) {
$this
->setupRequestParameters($returnto, FALSE, TRUE);
$this->requestStack
->expects($this
->once())
->method('getCurrentRequest')
->will($this
->returnValue($this->requestObject));
$this->eventDispatcher
->dispatch(Argument::type('string'), Argument::type(Event::class))
->will(function (array $args) {
if ($args[0] === CasHelper::EVENT_PRE_USER_LOAD_REDIRECT && $args[1] instanceof CasPreUserLoadRedirectEvent) {
$args[1]
->getPropertyBag()
->setUsername('foobar');
}
});
$expected_bag = new CasPropertyBag('foobar');
$this->casUserManager
->expects($this
->once())
->method('login')
->with($this
->equalTo($expected_bag), 'ST-foobar');
$this->casValidator
->expects($this
->once())
->method('validateTicket')
->with($this
->equalTo('ST-foobar'))
->will($this
->returnValue($expected_bag));
$this->urlGenerator
->expects($this
->once())
->method('generate')
->with('<front>')
->willReturn('/user/login');
$serviceController = new ServiceController($this->casHelper, $this->casValidator, $this->casUserManager, $this->casLogout, $this->requestStack, $this->urlGenerator, $this->configFactory, $this->messenger, $this->eventDispatcher
->reveal(), $this->externalAuth
->reveal());
$serviceController
->handle();
}
private function assertRedirectedToSpecialPageOnLoginFailure($serviceController) {
$path_validator = $this
->createMock('Drupal\\Core\\Path\\PathValidatorInterface');
$unrouted_url_assember = $this
->createMock('Drupal\\Core\\Utility\\UnroutedUrlAssemblerInterface');
$unrouted_url_assember
->expects($this
->atLeastOnce())
->method('assemble')
->will($this
->returnValue('/user/login'));
$container_builder = new ContainerBuilder();
$container_builder
->set('path.validator', $path_validator);
$container_builder
->set('unrouted_url_assembler', $unrouted_url_assember);
\Drupal::setContainer($container_builder);
$response = $serviceController
->handle();
$this
->assertTrue($response
->isRedirect('/user/login'));
}
public function parameterDataProvider() {
return [
[
FALSE,
],
[
TRUE,
],
];
}
private function assertRedirectedToFrontPageOnHandle($serviceController) {
$this->urlGenerator
->expects($this
->once())
->method('generate')
->with('<front>')
->will($this
->returnValue('http://example.com/front'));
$response = $serviceController
->handle();
$this
->assertTrue($response
->isRedirect('http://example.com/front'));
}
private function assertDestinationSetFromReturnTo() {
$this->queryBag
->expects($this
->once())
->method('set')
->with('destination')
->will($this
->returnValue('node/1'));
}
private function assertSuccessfulValidation($returnto, $for_proxy = FALSE) {
$service_params = [];
if ($returnto) {
$service_params['returnto'] = 'node/1';
}
$validation_data = new CasPropertyBag('testuser');
if ($for_proxy) {
$validation_data
->setPgt('testpgt');
}
$this->casValidator
->expects($this
->once())
->method('validateTicket')
->with($this
->equalTo('ST-foobar'), $this
->equalTo($service_params))
->will($this
->returnValue($validation_data));
}
private function setupRequestParameters($returnto, $logout_request, $ticket) {
$map = [
[
'logoutRequest',
$logout_request,
],
];
$this->requestBag
->expects($this
->any())
->method('has')
->will($this
->returnValueMap($map));
$map = [];
if ($logout_request === TRUE) {
$map[] = [
'logoutRequest',
NULL,
'<foobar/>',
];
}
if (!empty($map)) {
$this->requestBag
->expects($this
->any())
->method('get')
->will($this
->returnValueMap($map));
}
$map = [
[
'returnto',
$returnto,
],
[
'ticket',
$ticket,
],
];
$this->queryBag
->expects($this
->any())
->method('has')
->will($this
->returnValueMap($map));
$map = [];
if ($returnto === TRUE) {
$map[] = [
'returnto',
NULL,
'node/1',
];
}
if ($ticket === TRUE) {
$map[] = [
'ticket',
NULL,
'ST-foobar',
];
}
if (!empty($map)) {
$this->queryBag
->expects($this
->any())
->method('get')
->will($this
->returnValueMap($map));
}
$all = [];
if ($returnto) {
$all['returnto'] = 'node/1';
}
if ($ticket) {
$all['ticket'] = 'ST-foobar';
}
$this->queryBag
->method('all')
->will($this
->returnValue($all));
}
}