diff --git a/src/LightSaml/SpBundle/Resources/config/security.yml b/src/LightSaml/SpBundle/Resources/config/security.yml index a6ac436..c75f407 100644 --- a/src/LightSaml/SpBundle/Resources/config/security.yml +++ b/src/LightSaml/SpBundle/Resources/config/security.yml @@ -5,6 +5,7 @@ services: abstract: true calls: - [setProfile, ["@ligthsaml.profile.acs"]] + - [setBindingFactory, ["@lightsaml.service.binding_factory"]] security.authentication.provider.lightsaml_sp: class: LightSaml\SpBundle\Security\Authentication\Provider\LightsSamlSpAuthenticationProvider diff --git a/src/LightSaml/SpBundle/Security/Firewall/LightSamlSpListener.php b/src/LightSaml/SpBundle/Security/Firewall/LightSamlSpListener.php index c9e9cfc..cefa641 100644 --- a/src/LightSaml/SpBundle/Security/Firewall/LightSamlSpListener.php +++ b/src/LightSaml/SpBundle/Security/Firewall/LightSamlSpListener.php @@ -11,8 +11,13 @@ namespace LightSaml\SpBundle\Security\Firewall; +use LightSaml\Binding\AbstractBinding; +use LightSaml\Binding\BindingFactory; use LightSaml\Builder\Profile\ProfileBuilderInterface; +use LightSaml\Context\Profile\MessageContext; +use LightSaml\Model\Protocol\LogoutResponse; use LightSaml\Model\Protocol\Response; +use LightSaml\SamlConstants; use LightSaml\SpBundle\Security\Authentication\Token\SamlSpResponseToken; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; @@ -24,6 +29,9 @@ class LightSamlSpListener extends AbstractAuthenticationListener /** @var ProfileBuilderInterface */ private $profile; + /** @var BindingFactory */ + private $bindingFactory; + /** * @param ProfileBuilderInterface $profile * @@ -36,6 +44,18 @@ public function setProfile(ProfileBuilderInterface $profile) return $this; } + /** + * @param BindingFactory $bindingFactory + * + * @return LightSamlSpListener + */ + public function setBindingFactory(BindingFactory $bindingFactory) + { + $this->bindingFactory = $bindingFactory; + + return $this; + } + /** * Performs authentication. * @@ -47,6 +67,29 @@ public function setProfile(ProfileBuilderInterface $profile) */ protected function attemptAuthentication(Request $request) { + $bindingType = $this->bindingFactory->detectBindingType($request); + + if (null === $bindingType) { + throw new \LogicException('No SAML response.'); + } + + $binding = $this->bindingFactory->create($bindingType); + $messageContext = new MessageContext(); + /* @var $binding AbstractBinding */ + $binding->receive($request, $messageContext); + $samlRequest = $messageContext->getMessage(); + + if ($samlRequest instanceof LogoutResponse) { + $status = $samlRequest->getStatus(); + $code = $status->getStatusCode() ? $status->getStatusCode()->getValue() : null; + + if (SamlConstants::STATUS_PARTIAL_LOGOUT === $code || SamlConstants::STATUS_SUCCESS === $code) { + $request->getSession()->invalidate(); + } + + throw new AuthenticationException('This is a logout response'); + } + $samlResponse = $this->receiveSamlResponse(); $token = new SamlSpResponseToken($samlResponse, $this->providerKey); diff --git a/tests/LightSaml/SpBundle/Tests/Security/Firewall/LightSamlSpListenerTest.php b/tests/LightSaml/SpBundle/Tests/Security/Firewall/LightSamlSpListenerTest.php index 6c4586a..bd71b13 100644 --- a/tests/LightSaml/SpBundle/Tests/Security/Firewall/LightSamlSpListenerTest.php +++ b/tests/LightSaml/SpBundle/Tests/Security/Firewall/LightSamlSpListenerTest.php @@ -48,6 +48,20 @@ public function test_calls_profile_to_receive_response_and_authentication_manage ->method('buildAction') ->willReturn($actionMock); + $redirectBindingMock = $this->getHttpRedirectBindingMock(); + + $bindingFactoryMock = $this->getBindingFactoryMock(); + $bindingFactoryMock->expects($this->once()) + ->method('detectBindingType') + ->willReturn(\LightSaml\SamlConstants::BINDING_SAML2_HTTP_REDIRECT); + $bindingFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($redirectBindingMock); + $redirectBindingMock->expects($this->once()) + ->method('receive'); + + $listener->setBindingFactory($bindingFactoryMock); + $samlResponse = new Response(); $contextMock->expects($this->any()) @@ -120,6 +134,22 @@ private function getProfileBuilderMock() return $this->getMock(\LightSaml\Builder\Profile\ProfileBuilderInterface::class); } + /** + * @return \PHPUnit_Framework_MockObject_MockObject|\LightSaml\Binding\BindingFactory + */ + private function getBindingFactoryMock() + { + return $this->getMock(\LightSaml\Binding\BindingFactory::class); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject|\LightSaml\Binding\HttpRedirectBinding + */ + private function getHttpRedirectBindingMock() + { + return $this->getMock(\LightSaml\Binding\HttpRedirectBinding::class); + } + /** * @return \PHPUnit_Framework_MockObject_MockObject|\Symfony\Component\HttpFoundation\Request */