LogoutReceiveResponse::manage()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
c 4
b 0
f 0
dl 0
loc 12
rs 9.4286
cc 2
eloc 7
nc 2
nop 1
1
<?php
2
3
namespace AerialShip\SamlSPBundle\Bridge;
4
5
use AerialShip\LightSaml\Model\Protocol\LogoutResponse;
6
use AerialShip\SamlSPBundle\Config\ServiceInfoCollection;
7
use AerialShip\SamlSPBundle\RelyingParty\RelyingPartyInterface;
8
use AerialShip\SamlSPBundle\Security\Core\Authentication\Token\SamlSpToken;
9
use AerialShip\SamlSPBundle\State\Request\RequestStateStoreInterface;
10
use AerialShip\SamlSPBundle\State\SSO\SSOStateStoreInterface;
11
use Symfony\Component\HttpFoundation\Request;
12
use Symfony\Component\Security\Core\SecurityContextInterface;
13
use Symfony\Component\Security\Http\HttpUtils;
14
15
class LogoutReceiveResponse extends LogoutBase implements RelyingPartyInterface
16
{
17
    /** @var BindingManager */
18
    protected $bindingManager;
19
20
    /** @var RequestStateStoreInterface  */
21
    protected $requestStore;
22
23
    /** @var ServiceInfoCollection  */
24
    protected $serviceInfoCollection;
25
26
    /** @var \Symfony\Component\Security\Core\SecurityContextInterface  */
27
    protected $securityContext;
28
29
30
    /**
31
     * @param BindingManager $bindingManager
32
     * @param RequestStateStoreInterface $requestStore
33
     * @param \AerialShip\SamlSPBundle\Config\ServiceInfoCollection $serviceInfoCollection
34
     * @param \AerialShip\SamlSPBundle\State\SSO\SSOStateStoreInterface $ssoStore
35
     * @param \Symfony\Component\Security\Core\SecurityContextInterface $securityContext
36
     * @param \Symfony\Component\Security\Http\HttpUtils $httpUtils
37
     */
38
    public function __construct(
39
        BindingManager $bindingManager,
40
        RequestStateStoreInterface $requestStore,
41
        ServiceInfoCollection $serviceInfoCollection,
42
        SSOStateStoreInterface $ssoStore,
43
        SecurityContextInterface $securityContext,
44
        HttpUtils $httpUtils
45
    ) {
46
        parent::__construct($ssoStore, $httpUtils);
47
        $this->bindingManager = $bindingManager;
48
        $this->requestStore = $requestStore;
49
        $this->serviceInfoCollection = $serviceInfoCollection;
50
        $this->securityContext = $securityContext;
51
    }
52
53
54
    /**
55
     * @param \Symfony\Component\HttpFoundation\Request $request
56
     * @return bool
57
     */
58
    public function supports(Request $request)
59
    {
60
        if ($request->attributes->get('logout_path') != $request->getPathInfo()) {
61
            return false;
62
        }
63
        if (!$request->get('SAMLResponse')) {
64
            return false;
65
        }
66
        return true;
67
    }
68
69
    /**
70
     * @param \Symfony\Component\HttpFoundation\Request $request
71
     * @throws \RuntimeException
72
     * @throws \InvalidArgumentException if cannot manage the Request
73
     * @return \Symfony\Component\HttpFoundation\Response|SamlSpInfo|null
74
     */
75
    public function manage(Request $request)
76
    {
77
        if (!$this->supports($request)) {
78
            throw new \InvalidArgumentException('Unsupported request');
79
        }
80
81
        $logoutResponse = $this->getLogoutResponse($request);
82
        $this->validateRequestState($logoutResponse);
83
        $this->deleteSSOSession($logoutResponse);
84
85
        return $this->httpUtils->createRedirectResponse($request, $request->attributes->get('local_logout_path'));
86
    }
87
88
89
    /**
90
     * @param Request $request
91
     * @return LogoutResponse
92
     * @throws \InvalidArgumentException
93
     */
94
    protected function getLogoutResponse(Request $request)
95
    {
96
        /** @var  $logoutResponse LogoutResponse */
97
        $logoutResponse = $this->bindingManager->receive($request);
98
        if (!$logoutResponse || !$logoutResponse instanceof LogoutResponse) {
99
            throw new \InvalidArgumentException('Did not receive logout response');
100
        }
101
102
        return $logoutResponse;
103
    }
104
105
    /**
106
     * @param LogoutResponse $logoutResponse
107
     * @throws \RuntimeException
108
     */
109
    protected function validateRequestState(LogoutResponse $logoutResponse)
110
    {
111
        $state = $this->requestStore->get($logoutResponse->getInResponseTo());
112
        if (!$state) {
113
            throw new \RuntimeException('Got response to a request that was not made');
114
        }
115
        if ($state->getDestination() != $logoutResponse->getIssuer()) {
116
            throw new \RuntimeException('Got response from different issuer');
117
        }
118
        $this->requestStore->remove($state);
119
    }
120
121
122
    protected function deleteSSOSession(LogoutResponse $logoutResponse)
123
    {
124
        $serviceInfo = $this->serviceInfoCollection->findByIDPEntityID($logoutResponse->getIssuer());
125
        /** @var $token SamlSpToken */
126
        $token = $this->securityContext->getToken();
127
        if ($token && $token instanceof SamlSpToken) {
128
            $samlInfo = $token->getSamlSpInfo();
129
            if ($samlInfo) {
130
                $arrStates = $this->getSSOState($serviceInfo, $samlInfo->getNameID()->getValue(), $samlInfo->getAuthnStatement()->getSessionIndex());
0 ignored issues
show
Bug introduced by
It seems like $serviceInfo defined by $this->serviceInfoCollec...tResponse->getIssuer()) on line 124 can be null; however, AerialShip\SamlSPBundle\...goutBase::getSSOState() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
131
                $this->deleteSSOState($arrStates);
132
            }
133
        }
134
    }
135
}
136