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

SamlSPBundle/Bridge/LogoutSendRequest.php (2 issues)

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\Meta\LogoutRequestBuilder;
6
use AerialShip\LightSaml\Model\Protocol\LogoutRequest;
7
use AerialShip\SamlSPBundle\Config\ServiceInfo;
8
use AerialShip\SamlSPBundle\Config\ServiceInfoCollection;
9
use AerialShip\SamlSPBundle\RelyingParty\RelyingPartyInterface;
10
use AerialShip\SamlSPBundle\Security\Core\Authentication\Token\SamlSpToken;
11
use AerialShip\SamlSPBundle\State\Request\RequestState;
12
use AerialShip\SamlSPBundle\State\Request\RequestStateStoreInterface;
13
use Symfony\Component\HttpFoundation\RedirectResponse;
14
use Symfony\Component\HttpFoundation\Request;
15
use Symfony\Component\HttpFoundation\Response;
16
use Symfony\Component\Security\Core\SecurityContextInterface;
17
18
class LogoutSendRequest implements RelyingPartyInterface
19
{
20
    /** @var \Symfony\Component\Security\Core\SecurityContextInterface  */
21
    protected $securityContext;
22
23
    /** @var  ServiceInfoCollection */
24
    protected $serviceInfoCollection;
25
26
    /** @var RequestStateStoreInterface */
27
    protected $requestStateStore;
28
29
30
31
    /**
32
     * @param SecurityContextInterface $securityContext
33
     * @param ServiceInfoCollection $serviceInfoCollection
34
     * @param \AerialShip\SamlSPBundle\State\Request\RequestStateStoreInterface $requestStateStore
35
     */
36
    public function __construct(
37
        SecurityContextInterface $securityContext,
38
        ServiceInfoCollection $serviceInfoCollection,
39
        RequestStateStoreInterface $requestStateStore
40
    ) {
41
        $this->securityContext = $securityContext;
42
        $this->serviceInfoCollection = $serviceInfoCollection;
43
        $this->requestStateStore = $requestStateStore;
44
    }
45
46
47
48
    /**
49
     * @param \Symfony\Component\HttpFoundation\Request $request
50
     * @return bool
51
     */
52
    function supports(Request $request)
0 ignored issues
show
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
53
    {
54
        if ($request->attributes->get('logout_path') != $request->getPathInfo()) {
55
            return false;
56
        }
57
        /** @var $token SamlSpToken */
58
        $token = $this->securityContext->getToken();
59
        if (!$token || !$token instanceof SamlSpToken) {
60
            return false;
61
        }
62
        if (!$token->getSamlSpInfo()) {
63
            return false;
64
        }
65
        return true;
66
    }
67
68
    /**
69
     * @param \Symfony\Component\HttpFoundation\Request $request
70
     * @throws \RuntimeException  if no signing provider set
71
     * @throws \InvalidArgumentException if cannot manage the Request
72
     * @return \Symfony\Component\HttpFoundation\Response|SamlSpInfo
73
     */
74
    function manage(Request $request)
0 ignored issues
show
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
75
    {
76
        if (!$this->supports($request)) {
77
            throw new \InvalidArgumentException('Unsupported request');
78
        }
79
80
        $samlInfo = $this->getSamlInfo();
81
        $serviceInfo = $this->getServiceInfo($samlInfo, $request);
82
83
        $builder = $this->createLogoutRequestBuilder($serviceInfo);
84
        $logoutRequest = $this->createLogoutRequest($builder, $serviceInfo, $samlInfo);
85
        $bindingResponse = $builder->send($logoutRequest);
86
87
        $this->createRequestState($logoutRequest, $serviceInfo);
88
89
        if ($bindingResponse instanceof \AerialShip\LightSaml\Binding\PostResponse) {
90
            return new Response($bindingResponse->render());
91
        } else if ($bindingResponse instanceof \AerialShip\LightSaml\Binding\RedirectResponse) {
92
            return new RedirectResponse($bindingResponse->getDestination());
93
        }
94
95
        throw new \RuntimeException('Unknown binding response '.get_class($bindingResponse));
96
    }
97
98
99
    /**
100
     * @return SamlSpInfo
101
     */
102
    protected function getSamlInfo()
103
    {
104
        /** @var $token SamlSpToken */
105
        $token = $this->securityContext->getToken();
106
        $samlInfo = $token->getSamlSpInfo();
107
        return $samlInfo;
108
    }
109
110
111
    /**
112
     * @param SamlSpInfo $samlInfo
113
     * @param Request $request
114
     * @return ServiceInfo
115
     * @throws \RuntimeException
116
     */
117
    protected function getServiceInfo(SamlSpInfo $samlInfo, Request $request)
118
    {
119
        $serviceInfo = $this->serviceInfoCollection->get($samlInfo->getAuthenticationServiceID());
120
        if (!$serviceInfo) {
121
            throw new \RuntimeException("redirect to discovery");
122
        }
123
        if (!$serviceInfo->getSpSigningProvider()->isEnabled()) {
124
            throw new \RuntimeException('Signing is required for Logout');
125
        }
126
        $serviceInfo->getSpProvider()->setRequest($request);
127
128
        return $serviceInfo;
129
    }
130
131
    /**
132
     * @param ServiceInfo $serviceInfo
133
     * @return LogoutRequestBuilder
134
     */
135
    protected function createLogoutRequestBuilder(ServiceInfo $serviceInfo)
136
    {
137
        $builder = new LogoutRequestBuilder(
138
            $serviceInfo->getSpProvider()->getEntityDescriptor(),
139
            $serviceInfo->getIdpProvider()->getEntityDescriptor(),
140
            $serviceInfo->getSpMetaProvider()->getSpMeta()
141
        );
142
143
        return $builder;
144
    }
145
146
    /**
147
     * @param LogoutRequestBuilder $builder
148
     * @param ServiceInfo $serviceInfo
149
     * @param SamlSpInfo $samlInfo
150
     * @return LogoutRequest
151
     */
152
    protected function createLogoutRequest(LogoutRequestBuilder $builder, ServiceInfo $serviceInfo, SamlSpInfo $samlInfo)
153
    {
154
        $logoutRequest = $builder->build(
155
            $samlInfo->getNameID()->getValue(),
156
            $samlInfo->getNameID()->getFormat(),
157
            $samlInfo->getAuthnStatement()->getSessionIndex()
158
        );
159
        $logoutRequest->sign($serviceInfo->getSpSigningProvider()->getCertificate(), $serviceInfo->getSpSigningProvider()->getPrivateKey());
160
161
        return $logoutRequest;
162
    }
163
164
    /**
165
     * @param LogoutRequest $request
166
     * @param ServiceInfo $serviceInfo
167
     * @return RequestState
168
     */
169
    protected function createRequestState(LogoutRequest $request, ServiceInfo $serviceInfo)
170
    {
171
        $state = new RequestState();
172
        $state->setId($request->getID());
173
        $state->setDestination($serviceInfo->getIdpProvider()->getEntityDescriptor()->getEntityID());
174
        $this->requestStateStore->set($state);
175
176
        return $state;
177
    }
178
}
179