Skip to content

Commit f5358c6

Browse files
author
Axel Vankrunkelsven
committed
Add support for single sign-off
1 parent c32db2e commit f5358c6

File tree

3 files changed

+74
-0
lines changed

3 files changed

+74
-0
lines changed

src/LightSaml/SpBundle/Resources/config/security.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ services:
55
abstract: true
66
calls:
77
- [setProfile, ["@ligthsaml.profile.acs"]]
8+
- [setBindingFactory, ["@lightsaml.service.binding_factory"]]
89

910
security.authentication.provider.lightsaml_sp:
1011
class: LightSaml\SpBundle\Security\Authentication\Provider\LightsSamlSpAuthenticationProvider

src/LightSaml/SpBundle/Security/Firewall/LightSamlSpListener.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,13 @@
1111

1212
namespace LightSaml\SpBundle\Security\Firewall;
1313

14+
use LightSaml\Binding\AbstractBinding;
15+
use LightSaml\Binding\BindingFactory;
1416
use LightSaml\Builder\Profile\ProfileBuilderInterface;
17+
use LightSaml\Context\Profile\MessageContext;
18+
use LightSaml\Model\Protocol\LogoutResponse;
1519
use LightSaml\Model\Protocol\Response;
20+
use LightSaml\SamlConstants;
1621
use LightSaml\SpBundle\Security\Authentication\Token\SamlSpResponseToken;
1722
use Symfony\Component\HttpFoundation\Request;
1823
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
@@ -24,6 +29,9 @@ class LightSamlSpListener extends AbstractAuthenticationListener
2429
/** @var ProfileBuilderInterface */
2530
private $profile;
2631

32+
/** @var BindingFactory */
33+
private $bindingFactory;
34+
2735
/**
2836
* @param ProfileBuilderInterface $profile
2937
*
@@ -36,6 +44,18 @@ public function setProfile(ProfileBuilderInterface $profile)
3644
return $this;
3745
}
3846

47+
/**
48+
* @param BindingFactory $bindingFactory
49+
*
50+
* @return LightSamlSpListener
51+
*/
52+
public function setBindingFactory(BindingFactory $bindingFactory)
53+
{
54+
$this->bindingFactory = $bindingFactory;
55+
56+
return $this;
57+
}
58+
3959
/**
4060
* Performs authentication.
4161
*
@@ -47,6 +67,29 @@ public function setProfile(ProfileBuilderInterface $profile)
4767
*/
4868
protected function attemptAuthentication(Request $request)
4969
{
70+
$bindingType = $this->bindingFactory->detectBindingType($request);
71+
72+
if (null === $bindingType) {
73+
throw new \LogicException('No SAML response.');
74+
}
75+
76+
$binding = $this->bindingFactory->create($bindingType);
77+
$messageContext = new MessageContext();
78+
/* @var $binding AbstractBinding */
79+
$binding->receive($request, $messageContext);
80+
$samlRequest = $messageContext->getMessage();
81+
82+
if ($samlRequest instanceof LogoutResponse) {
83+
$status = $samlRequest->getStatus();
84+
$code = $status->getStatusCode() ? $status->getStatusCode()->getValue() : null;
85+
86+
if (SamlConstants::STATUS_PARTIAL_LOGOUT === $code || SamlConstants::STATUS_SUCCESS === $code) {
87+
$request->getSession()->invalidate();
88+
}
89+
90+
throw new AuthenticationException('This is a logout response');
91+
}
92+
5093
$samlResponse = $this->receiveSamlResponse();
5194

5295
$token = new SamlSpResponseToken($samlResponse, $this->providerKey);

tests/LightSaml/SpBundle/Tests/Security/Firewall/LightSamlSpListenerTest.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,20 @@ public function test_calls_profile_to_receive_response_and_authentication_manage
4848
->method('buildAction')
4949
->willReturn($actionMock);
5050

51+
$redirectBindingMock = $this->getHttpRedirectBindingMock();
52+
53+
$bindingFactoryMock = $this->getBindingFactoryMock();
54+
$bindingFactoryMock->expects($this->once())
55+
->method('detectBindingType')
56+
->willReturn(\LightSaml\SamlConstants::BINDING_SAML2_HTTP_REDIRECT);
57+
$bindingFactoryMock->expects($this->once())
58+
->method('create')
59+
->willReturn($redirectBindingMock);
60+
$redirectBindingMock->expects($this->once())
61+
->method('receive');
62+
63+
$listener->setBindingFactory($bindingFactoryMock);
64+
5165
$samlResponse = new Response();
5266

5367
$contextMock->expects($this->any())
@@ -120,6 +134,22 @@ private function getProfileBuilderMock()
120134
return $this->getMock(\LightSaml\Builder\Profile\ProfileBuilderInterface::class);
121135
}
122136

137+
/**
138+
* @return \PHPUnit_Framework_MockObject_MockObject|\LightSaml\Binding\BindingFactory
139+
*/
140+
private function getBindingFactoryMock()
141+
{
142+
return $this->getMock(\LightSaml\Binding\BindingFactory::class);
143+
}
144+
145+
/**
146+
* @return \PHPUnit_Framework_MockObject_MockObject|\LightSaml\Binding\HttpRedirectBinding
147+
*/
148+
private function getHttpRedirectBindingMock()
149+
{
150+
return $this->getMock(\LightSaml\Binding\HttpRedirectBinding::class);
151+
}
152+
123153
/**
124154
* @return \PHPUnit_Framework_MockObject_MockObject|\Symfony\Component\HttpFoundation\Request
125155
*/

0 commit comments

Comments
 (0)