Skip to content

Commit 512289b

Browse files
committed
receive logout response and session termination
1 parent e7b047d commit 512289b

File tree

11 files changed

+277
-10
lines changed

11 files changed

+277
-10
lines changed

.php_cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ EOT;
1616
Symfony\CS\Fixer\Contrib\HeaderCommentFixer::setHeader($header);
1717

1818
return Symfony\CS\Config\Config::create()
19-
->setUsingCache(true)
19+
->setUsingCache(false)
2020
->level(Symfony\CS\FixerInterface::SYMFONY_LEVEL)
2121
->fixers(array('-empty_return', '-phpdoc_no_empty_return', 'header_comment'))
2222
->finder($finder)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the LightSAML-Logout package.
5+
*
6+
* (c) Milos Tomic <[email protected]>
7+
*
8+
* This source file is subject to the GPL-3 license that is bundled
9+
* with this source code in the file LICENSE.
10+
*/
11+
12+
namespace LightSaml\Logout\Action\Profile\Inbound\LogoutResponse;
13+
14+
use LightSaml\Action\Profile\AbstractProfileAction;
15+
use LightSaml\Context\Profile\Helper\LogHelper;
16+
use LightSaml\Context\Profile\Helper\MessageContextHelper;
17+
use LightSaml\Context\Profile\ProfileContext;
18+
use LightSaml\Error\LightSamlContextException;
19+
use LightSaml\Logout\Resolver\Logout\LogoutSessionResolverInterface;
20+
use LightSaml\State\Request\RequestStateParameters;
21+
use LightSaml\Store\Request\RequestStateStoreInterface;
22+
use Psr\Log\LoggerInterface;
23+
24+
class RemoveSsoSessionFromStoreAction extends AbstractProfileAction
25+
{
26+
/** @var RequestStateStoreInterface */
27+
private $requestStore;
28+
29+
/** @var LogoutSessionResolverInterface */
30+
private $logoutResolver;
31+
32+
/**
33+
* @param LoggerInterface $logger
34+
* @param RequestStateStoreInterface $requestStore
35+
* @param LogoutSessionResolverInterface $logoutResolver
36+
*/
37+
public function __construct(LoggerInterface $logger, RequestStateStoreInterface $requestStore, LogoutSessionResolverInterface $logoutResolver)
38+
{
39+
parent::__construct($logger);
40+
41+
$this->requestStore = $requestStore;
42+
$this->logoutResolver = $logoutResolver;
43+
}
44+
45+
protected function doExecute(ProfileContext $context)
46+
{
47+
$logoutResponse = MessageContextHelper::asLogoutResponse($context->getInboundContext());
48+
$id = $logoutResponse->getInResponseTo();
49+
$requestState = $this->requestStore->get($id);
50+
$partyEntityId = $requestState->getParameters()->get(RequestStateParameters::PARTY);
51+
if ($partyEntityId && $logoutResponse->getIssuer() && $partyEntityId != $logoutResponse->getIssuer()->getValue()) {
52+
$message = sprintf(
53+
'LogoutRequest sent to %s but LogoutResponse for that request was issued by %s',
54+
$partyEntityId,
55+
$logoutResponse->getIssuer()->getValue()
56+
);
57+
$this->logger->critical($message, LogHelper::getActionErrorContext($context, $this, [
58+
'sent_to' => $partyEntityId,
59+
'received_from' => $logoutResponse->getIssuer()->getValue(),
60+
]));
61+
throw new LightSamlContextException($context, $message);
62+
}
63+
64+
$nameId = $requestState->getParameters()->get(RequestStateParameters::NAME_ID);
65+
$nameIdFormat = $requestState->getParameters()->get(RequestStateParameters::NAME_ID_FORMAT);
66+
$sessionIndex = $requestState->getParameters()->get(RequestStateParameters::SESSION_INDEX);
67+
68+
$numberOfTerminatedSessions = $this->logoutResolver->terminateSession(
69+
$logoutResponse->getIssuer()->getValue(),
70+
$nameId,
71+
$nameIdFormat,
72+
$sessionIndex
73+
);
74+
75+
$this->logger->debug(
76+
sprintf(
77+
'Processing LogoutResponse from %s for %s in format %s and session index %s resulted in termination of %s sso session from the store',
78+
$partyEntityId,
79+
$nameId,
80+
$nameIdFormat,
81+
$sessionIndex,
82+
$numberOfTerminatedSessions
83+
),
84+
LogHelper::getActionContext($context, $this)
85+
);
86+
}
87+
}

src/LightSaml/Logout/Action/Profile/Outbound/LogoutRequest/LogoutResolveAction.php

+29-3
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,17 @@
1313

1414
use LightSaml\Action\ActionInterface;
1515
use LightSaml\Action\Profile\AbstractProfileAction;
16+
use LightSaml\Context\Profile\Helper\LogHelper;
1617
use LightSaml\Context\Profile\ProfileContext;
1718
use LightSaml\Logout\Resolver\Logout\LogoutSessionResolverInterface;
1819
use Psr\Log\LoggerInterface;
1920

2021
class LogoutResolveAction extends AbstractProfileAction
2122
{
22-
/** @var LogoutSessionResolverInterface */
23+
/** @var LogoutSessionResolverInterface */
2324
protected $logoutSessionResolver;
2425

25-
/** @var ActionInterface */
26+
/** @var ActionInterface */
2627
protected $logoutProceedAction;
2728

2829
/**
@@ -46,12 +47,37 @@ public function __construct(
4647
*/
4748
protected function doExecute(ProfileContext $context)
4849
{
49-
$ssoSessionState = $this->logoutSessionResolver->resolve($context->getOwnEntityDescriptor()->getEntityID());
5050
$logoutContext = $context->getLogoutContext();
51+
$ssoSessionState = $logoutContext->getSsoSessionState();
5152
if ($ssoSessionState) {
53+
$this->logger->debug(
54+
'SSO session already set',
55+
LogHelper::getActionContext($context, $this, array(
56+
'sso_session' => $ssoSessionState,
57+
))
58+
);
59+
} else {
60+
$this->logger->debug(
61+
'SSO session not defined, about to resolve it',
62+
LogHelper::getActionContext($context, $this, array())
63+
);
64+
$ssoSessionState = $this->logoutSessionResolver->resolve($context->getOwnEntityDescriptor()->getEntityID());
65+
}
66+
67+
if ($ssoSessionState) {
68+
$this->logger->debug(
69+
'SSO session resolved and being used for logout profile',
70+
LogHelper::getActionContext($context, $this, array(
71+
'sso_session' => $ssoSessionState,
72+
))
73+
);
5274
$logoutContext->setSsoSessionState($ssoSessionState);
5375
$this->logoutProceedAction->execute($context);
5476
} else {
77+
$this->logger->debug(
78+
'There is no SSO session for logout',
79+
LogHelper::getActionContext($context, $this, array())
80+
);
5581
$logoutContext->setAllSsoSessionsTerminated(true);
5682
}
5783
}

src/LightSaml/Logout/Action/Profile/Outbound/LogoutRequest/ResolveLogoutPartyAction.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class ResolveLogoutPartyAction extends AbstractProfileAction
2626
/** @var EntityDescriptorStoreInterface */
2727
private $spEntityDescriptorStore;
2828

29-
/** @var TrustOptionsStoreInterface */
29+
/** @var TrustOptionsStoreInterface */
3030
protected $trustOptionsProvider;
3131

3232
/**

src/LightSaml/Logout/Action/Profile/Outbound/LogoutRequest/SetNotOnOrAfterAction.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@
2222
*/
2323
class SetNotOnOrAfterAction extends AbstractProfileAction
2424
{
25-
/** @var TimeProviderInterface */
25+
/** @var TimeProviderInterface */
2626
protected $timeProvider;
2727

28-
/** @var int */
28+
/** @var int */
2929
protected $secondsSkew;
3030

3131
/**

src/LightSaml/Logout/Builder/Action/Profile/SingleLogout/SloRequestActionBuilder.php

+6-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use LightSaml\Action\Profile\Outbound\Message\CreateMessageIssuerAction;
1515
use LightSaml\Action\Profile\Outbound\Message\DestinationAction;
1616
use LightSaml\Action\Profile\Outbound\Message\ResolveEndpointSloAction;
17+
use LightSaml\Action\Profile\Outbound\Message\SaveRequestStateAction;
1718
use LightSaml\Logout\Action\Profile\Outbound\LogoutRequest\CreateLogoutRequestAction;
1819
use LightSaml\Logout\Action\Profile\Outbound\LogoutRequest\LogoutResolveAction;
1920
use LightSaml\Logout\Action\Profile\Outbound\LogoutRequest\ResolveLogoutPartyAction;
@@ -31,8 +32,6 @@
3132

3233
class SloRequestActionBuilder extends AbstractProfileActionBuilder
3334
{
34-
/**
35-
*/
3635
protected function doInitialize()
3736
{
3837
$proceedActionBuilder = new CompositeActionBuilder();
@@ -77,6 +76,11 @@ protected function doInitialize()
7776
$this->buildContainer->getSystemContainer()->getTimeProvider(),
7877
120
7978
));
79+
$proceedActionBuilder->add(new SaveRequestStateAction(
80+
$this->buildContainer->getSystemContainer()->getLogger(),
81+
$this->buildContainer->getStoreContainer()->getRequestStateStore()
82+
));
83+
8084
$proceedActionBuilder->add(new SignMessageAction(
8185
$this->buildContainer->getSystemContainer()->getLogger(),
8286
$this->buildContainer->getServiceContainer()->getSignatureResolver()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the LightSAML-Logout package.
5+
*
6+
* (c) Milos Tomic <[email protected]>
7+
*
8+
* This source file is subject to the GPL-3 license that is bundled
9+
* with this source code in the file LICENSE.
10+
*/
11+
12+
namespace LightSaml\Logout\Builder\Action\Profile\SingleLogout;
13+
14+
use LightSaml\Action\Profile\FlushRequestStatesAction;
15+
use LightSaml\Action\Profile\Inbound\Message\EntityIdFromMessageIssuerAction;
16+
use LightSaml\Action\Profile\Inbound\Message\IssuerValidatorAction;
17+
use LightSaml\Action\Profile\Inbound\Message\MessageSignatureValidatorAction;
18+
use LightSaml\Action\Profile\Inbound\Message\ReceiveMessageAction;
19+
use LightSaml\Action\Profile\Inbound\Message\ResolvePartyEntityIdAction;
20+
use LightSaml\Action\Profile\Inbound\StatusResponse\InResponseToValidatorAction;
21+
use LightSaml\Action\Profile\Inbound\StatusResponse\StatusAction;
22+
use LightSaml\Builder\Action\Profile\AbstractProfileActionBuilder;
23+
use LightSaml\Logout\Action\Profile\Inbound\LogoutResponse\RemoveSsoSessionFromStoreAction;
24+
use LightSaml\SamlConstants;
25+
26+
class SloResponseActionBuilder extends AbstractProfileActionBuilder
27+
{
28+
protected function doInitialize()
29+
{
30+
$this->add(new ReceiveMessageAction(
31+
$this->buildContainer->getSystemContainer()->getLogger(),
32+
$this->buildContainer->getServiceContainer()->getBindingFactory()
33+
), 100);
34+
35+
// Response validation
36+
$this->add(new IssuerValidatorAction(
37+
$this->buildContainer->getSystemContainer()->getLogger(),
38+
$this->buildContainer->getServiceContainer()->getNameIdValidator(),
39+
SamlConstants::NAME_ID_FORMAT_ENTITY
40+
), 200);
41+
$this->add(new EntityIdFromMessageIssuerAction(
42+
$this->buildContainer->getSystemContainer()->getLogger()
43+
));
44+
$this->add(new ResolvePartyEntityIdAction(
45+
$this->buildContainer->getSystemContainer()->getLogger(),
46+
$this->buildContainer->getPartyContainer()->getSpEntityDescriptorStore(),
47+
$this->buildContainer->getPartyContainer()->getIdpEntityDescriptorStore(),
48+
$this->buildContainer->getPartyContainer()->getTrustOptionsStore()
49+
));
50+
$this->add(new InResponseToValidatorAction(
51+
$this->buildContainer->getSystemContainer()->getLogger(),
52+
$this->buildContainer->getStoreContainer()->getRequestStateStore()
53+
));
54+
$this->add(new StatusAction(
55+
$this->buildContainer->getSystemContainer()->getLogger()
56+
));
57+
$this->add(new MessageSignatureValidatorAction(
58+
$this->buildContainer->getSystemContainer()->getLogger(),
59+
$this->buildContainer->getServiceContainer()->getSignatureValidator()
60+
));
61+
$this->add(new RemoveSsoSessionFromStoreAction(
62+
$this->buildContainer->getSystemContainer()->getLogger(),
63+
$this->buildContainer->getStoreContainer()->getRequestStateStore(),
64+
$this->buildContainer->getServiceContainer()->getLogoutSessionResolver()
65+
));
66+
$this->add(new FlushRequestStatesAction(
67+
$this->buildContainer->getSystemContainer()->getLogger(),
68+
$this->buildContainer->getStoreContainer()->getRequestStateStore()
69+
));
70+
}
71+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the LightSAML-Logout package.
5+
*
6+
* (c) Milos Tomic <[email protected]>
7+
*
8+
* This source file is subject to the GPL-3 license that is bundled
9+
* with this source code in the file LICENSE.
10+
*/
11+
12+
namespace LightSaml\Logout\Builder\Profile\WebBrowserSlo;
13+
14+
use LightSaml\Builder\Profile\AbstractProfileBuilder;
15+
use LightSaml\Context\Profile\ProfileContext;
16+
use LightSaml\Logout\Builder\Action\Profile\SingleLogout\SloResponseActionBuilder;
17+
use LightSaml\Logout\Profile\Profiles;
18+
19+
class SloResponseProfileBuilder extends AbstractProfileBuilder
20+
{
21+
/**
22+
* @return string
23+
*/
24+
protected function getProfileId()
25+
{
26+
return Profiles::SLO_RECEIVE_LOGOUT_RESPONSE;
27+
}
28+
29+
/**
30+
* @return string
31+
*/
32+
protected function getProfileRole()
33+
{
34+
return ProfileContext::ROLE_NONE;
35+
}
36+
37+
/**
38+
* @return \LightSaml\Builder\Action\ActionBuilderInterface
39+
*/
40+
protected function getActionBuilder()
41+
{
42+
return new SloResponseActionBuilder($this->container);
43+
}
44+
}

src/LightSaml/Logout/Profile/Profiles.php

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
class Profiles
1515
{
1616
const SLO_SEND_LOGOUT_REQUEST = 'slo_send_logout_request';
17+
const SLO_RECEIVE_LOGOUT_RESPONSE = 'slo_receive_logout_response';
1718

1819
private function __construct()
1920
{

src/LightSaml/Logout/Resolver/Logout/LogoutSessionResolver.php

+25-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
class LogoutSessionResolver implements LogoutSessionResolverInterface
1919
{
20-
/** @var SsoStateStoreInterface */
20+
/** @var SsoStateStoreInterface */
2121
protected $ssoStateStore;
2222

2323
/**
@@ -47,6 +47,30 @@ public function resolve($ownEntityId)
4747
return $result;
4848
}
4949

50+
public function terminateSession($entityId, $nameId, $nameIdFormat, $sessionIndex = null)
51+
{
52+
$ssoState = $this->ssoStateStore->get();
53+
54+
$count = 0;
55+
56+
$ssoState->modify(function (SsoSessionState $session) use ($entityId, $nameId, $nameIdFormat, &$count) {
57+
if (($session->getIdpEntityId() == $entityId || $session->getSpEntityId() == $entityId) &&
58+
$session->getNameId() == $nameId &&
59+
$session->getNameIdFormat() == $nameIdFormat
60+
) {
61+
++$count;
62+
63+
return false;
64+
}
65+
66+
return true;
67+
});
68+
69+
$this->ssoStateStore->set($ssoState);
70+
71+
return $count;
72+
}
73+
5074
/**
5175
* @param SsoState $ssoState
5276
* @param string $ownEntityId

src/LightSaml/Logout/Resolver/Logout/LogoutSessionResolverInterface.php

+10
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,14 @@ interface LogoutSessionResolverInterface
2121
* @return SsoSessionState|null
2222
*/
2323
public function resolve($ownEntityId);
24+
25+
/**
26+
* @param string $entityId
27+
* @param string $nameId
28+
* @param string $nameIdFormat
29+
* @param string $sessionIndex
30+
*
31+
* @return int Number of sso sessions terminated for given arguments
32+
*/
33+
public function terminateSession($entityId, $nameId, $nameIdFormat, $sessionIndex = null);
2434
}

0 commit comments

Comments
 (0)