Completed
Push — master ( d5bbb9...ab4758 )
by Milos
04:50 queued 02:32
created

SamlSPBundle/Bridge/LogoutReceiveResponse.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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
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