Completed
Push — feature/refactor-gateway-contr... ( 236313...33303a )
by
unknown
02:26
created

createRequesterFailureResponse()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 14
rs 9.7998
c 0
b 0
f 0
cc 1
nc 1
nop 0

1 Method

Rating   Name   Duplication   Size   Complexity  
A GatewayController::getGatewayConsumeAssertionService() 0 4 1
1
<?php
2
3
/**
4
 * Copyright 2014 SURFnet bv
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 *     http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
namespace Surfnet\StepupGateway\GatewayBundle\Controller;
20
21
use SAML2\Response as SAMLResponse;
22
use Surfnet\StepupGateway\GatewayBundle\Exception\RequesterFailureException;
23
use Surfnet\StepupGateway\GatewayBundle\Exception\ResponseFailureException;
24
use Surfnet\StepupGateway\GatewayBundle\Service\Gateway\ConsumeAssertionService;
25
use Surfnet\StepupGateway\GatewayBundle\Service\Gateway\FailedResponseService;
26
use Surfnet\StepupGateway\GatewayBundle\Service\Gateway\LoginService;
27
use Surfnet\StepupGateway\GatewayBundle\Service\Gateway\RespondService;
28
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
29
use Symfony\Component\HttpFoundation\Request;
30
use Symfony\Component\HttpFoundation\Response;
31
use Symfony\Component\HttpKernel\Exception\HttpException;
32
33
/**
34
 * Entry point for the Stepup login flow.
35
 *
36
 * See docs/GatewayState.md for a high-level diagram on how this controller
37
 * interacts with outside actors and other parts of Stepup.
38
 */
39
class GatewayController extends Controller
40
{
41
    const RESPONSE_CONTEXT_SERVICE_ID = 'gateway.proxy.response_context';
42
43
    /**
44
     * Receive an AuthnRequest from a service provider.
45
     *
46
     * The service provider is either a Stepup component (SelfService, RA) or
47
     * an external service provider.
48
     *
49
     * This single sign-on action will start a new SAML request to the remote
50
     * IDP configured in Stepup (most likely to be an instance of OpenConext
51
     * EngineBlock).
52
     *
53
     * @param Request $httpRequest
54
     * @return \Symfony\Component\HttpFoundation\RedirectResponse|Response
55
     */
56
    public function ssoAction(Request $httpRequest)
57
    {
58
        /** @var \Psr\Log\LoggerInterface $logger */
59
        $logger = $this->get('logger');
60
61
        $redirectBinding = $this->get('surfnet_saml.http.redirect_binding');
62
        $gatewayLoginService = $this->getGatewayLoginService();
63
64
        $logger->notice('Received AuthnRequest, started processing');
65
66
        /** @var \Surfnet\SamlBundle\Http\RedirectBinding $redirectBinding */
67
        $originalRequest = $redirectBinding->receiveSignedAuthnRequestFrom($httpRequest);
68
69
        try {
70
            $proxyRequest = $gatewayLoginService->singleSignOn($httpRequest, $originalRequest);
71
        } catch (RequesterFailureException $e) {
72
            $response = $this->getGatewayFailedResponseService()->createRequesterFailureResponse();
73
74
            return $this->renderSamlResponse('consumeAssertion', $response);
75
        }
76
77
        return $redirectBinding->createResponseFor($proxyRequest);
78
    }
79
80
    /**
81
     *
82
     */
83
    public function proxySsoAction()
84
    {
85
        throw new HttpException(418, 'Not Yet Implemented');
86
    }
87
88
    /**
89
     * Receive an AuthnResponse from an identity provider.
90
     *
91
     * The AuthnRequest started in ssoAction() resulted in an AuthnResponse
92
     * from the IDP. This method handles the assertion and forwards the user
93
     * using an internal redirect to the SecondFactorController to start the
94
     * actual second factor verification.
95
     *
96
     * @param Request $request
97
     * @return \Symfony\Component\HttpFoundation\Response
98
     */
99
    public function consumeAssertionAction(Request $request)
100
    {
101
        $responseContext = $this->getResponseContext();
102
        $gatewayLoginService = $this->getGatewayConsumeAssertionService();
103
104
        try {
105
            $gatewayLoginService->consumeAssertion($request, $responseContext);
106
        } catch (ResponseFailureException $e) {
107
            $response = $this->getGatewayFailedResponseService()->createResponseFailureResponse($responseContext);
108
109
            return $this->renderSamlResponse('unprocessableResponse', $response);
110
        }
111
112
        return $this->forward('SurfnetStepupGatewayGatewayBundle:SecondFactor:selectSecondFactorForVerification');
113
    }
114
115
    /**
116
     * Send a SAML response back to the service provider.
117
     *
118
     * Second factor verification handled by SecondFactorController is
119
     * finished. The user was forwarded back to this action with an internal
120
     * redirect. This method sends a AuthnResponse back to the service
121
     * provider in response to the AuthnRequest received in ssoAction().
122
     */
123
    public function respondAction()
124
    {
125
        $responseContext = $this->getResponseContext();
126
        $gatewayLoginService = $this->getGatewayRespondService();
127
128
        $response = $gatewayLoginService->respond($responseContext);
129
130
        return $this->renderSamlResponse('consumeAssertion', $response);
131
    }
132
133
    /**
134
     * @return Response
135
     */
136 View Code Duplication
    public function sendLoaCannotBeGivenAction()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
137
    {
138
        $responseContext = $this->getResponseContext();
139
        $gatewayLoginService = $this->getGatewayFailedResponseService();
140
141
        $response = $gatewayLoginService->sendLoaCannotBeGiven($responseContext);
142
143
        return $this->renderSamlResponse('consumeAssertion', $response);
144
    }
145
146
    /**
147
     * @return Response
148
     */
149 View Code Duplication
    public function sendAuthenticationCancelledByUserAction()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
150
    {
151
        $responseContext = $this->getResponseContext();
152
        $gatewayLoginService = $this->getGatewayFailedResponseService();
153
154
        $response = $gatewayLoginService->sendAuthenticationCancelledByUser($responseContext);
155
156
        return $this->renderSamlResponse('consumeAssertion', $response);
157
    }
158
159
    /**
160
     * @param string         $view
161
     * @param SAMLResponse $response
162
     * @return Response
163
     */
164 View Code Duplication
    public function renderSamlResponse($view, SAMLResponse $response)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
165
    {
166
        $responseContext = $this->getResponseContext();
167
168
        return $this->render($view, [
169
            'acu'        => $responseContext->getDestination(),
170
            'response'   => $this->getResponseAsXML($response),
171
            'relayState' => $responseContext->getRelayState()
172
        ]);
173
    }
174
175
    /**
176
     * @param string   $view
177
     * @param array    $parameters
178
     * @param Response $response
0 ignored issues
show
Documentation introduced by
Should the type for parameter $response not be null|Response?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
179
     * @return Response
180
     */
181
    public function render($view, array $parameters = array(), Response $response = null)
182
    {
183
        return parent::render(
184
            'SurfnetStepupGatewayGatewayBundle:Gateway:' . $view . '.html.twig',
185
            $parameters,
186
            $response
187
        );
188
    }
189
190
    /**
191
     * @return \Surfnet\StepupGateway\GatewayBundle\Saml\ResponseContext
192
     */
193
    public function getResponseContext()
194
    {
195
        $stateHandler = $this->get('gateway.proxy.state_handler');
196
197
        $responseContextServiceId = $stateHandler->getResponseContextServiceId();
198
199
        if (!$responseContextServiceId) {
200
            return $this->get(static::RESPONSE_CONTEXT_SERVICE_ID);
201
        }
202
203
        return $this->get($responseContextServiceId);
204
    }
205
206
    /**
207
     * @param SAMLResponse $response
208
     * @return string
209
     */
210
    private function getResponseAsXML(SAMLResponse $response)
211
    {
212
        return base64_encode($response->toUnsignedXML()->ownerDocument->saveXML());
213
    }
214
215
    /**
216
     * @return LoginService
217
     */
218
    private function getGatewayLoginService()
219
    {
220
        return $this->get('gateway.service.gateway.login');
221
    }
222
223
    /**
224
     * @return ConsumeAssertionService
225
     */
226
    private function getGatewayConsumeAssertionService()
227
    {
228
        return $this->get('gateway.service.gateway.consume_assertion');
229
    }
230
231
    /**
232
     * @return RespondService
233
     */
234
    private function getGatewayRespondService()
235
    {
236
        return $this->get('gateway.service.gateway.respond');
237
    }
238
239
    /**
240
     * @return FailedResponseService
241
     */
242
    private function getGatewayFailedResponseService()
243
    {
244
        return $this->get('gateway.service.gateway.failed_response');
245
    }
246
247
}
248