GssfController::consumeAssertionAction()   B
last analyzed

Complexity

Conditions 6
Paths 6

Size

Total Lines 79
Code Lines 46

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 46
nc 6
nop 2
dl 0
loc 79
rs 8.5559
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\StepupSelfService\SelfServiceBundle\Controller\Registration;
20
21
use Exception;
22
use Surfnet\SamlBundle\Http\XMLResponse;
23
use Surfnet\SamlBundle\SAML2\AuthnRequestFactory;
24
use Surfnet\SamlBundle\SAML2\Response\Assertion\InResponseTo;
25
use Surfnet\StepupSelfService\SamlStepupProviderBundle\Provider\Provider;
26
use Surfnet\StepupSelfService\SamlStepupProviderBundle\Provider\ViewConfig;
27
use Surfnet\StepupSelfService\SelfServiceBundle\Controller\Controller;
28
use Surfnet\StepupSelfService\SelfServiceBundle\Form\Type\StatusGssfType;
29
use Symfony\Component\HttpFoundation\Request;
30
use Symfony\Component\HttpFoundation\Response;
31
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
32
33
/**
34
 * Controls registration with Generic SAML Stepup Providers (GSSPs), yielding Generic SAML Second Factors (GSSFs).
35
 */
36
final class GssfController extends Controller
37
{
38
    /**
39
     * Render the status form.
40
     *
41
     * This action has two parameters:
42
     *
43
     * - authenticationFailed (default false), will trigger an error message
44
     *   and is used when a SAML failure response was received, for example
45
     *   when the users cancelled the registration
46
     *
47
     * - proofOfPossessionFailed (default false), will trigger an error message
48
     *   when possession was not proven, but the SAML response was successful
49
     *
50
     * @param Request $request
51
     * @param string $provider
52
     * @return array|Response
53
     */
54
    public function statusAction(Request $request, $provider)
55
    {
56
        $this->assertSecondFactorEnabled($provider);
57
58
        return $this->renderStatusForm(
59
            $provider,
60
            [
61
                'authenticationFailed' => (bool) $request->query->get('authenticationFailed'),
62
                'proofOfPossessionFailed' => (bool) $request->query->get('proofOfPossessionFailed'),
63
            ]
64
        );
65
    }
66
67
    /**
68
     * @param string $provider
69
     * @return array|Response
70
     */
71
    public function authenticateAction($provider)
72
    {
73
        $this->assertSecondFactorEnabled($provider);
74
75
        $provider = $this->getProvider($provider);
76
77
        $authnRequest = AuthnRequestFactory::createNewRequest(
78
            $provider->getServiceProvider(),
79
            $provider->getRemoteIdentityProvider()
80
        );
81
82
        $attributeService = $this->get('surfnet_stepup_self_service_self_service.service.gsspuserattributes');
83
        $attributeService->addGsspUserAttributes(
84
            $authnRequest,
85
            $provider,
86
            $this->get('security.token_storage')->getToken()->getUser()
87
        );
88
        $stateHandler = $provider->getStateHandler();
89
        $stateHandler->setRequestId($authnRequest->getRequestId());
90
91
        /** @var \Surfnet\SamlBundle\Http\RedirectBinding $redirectBinding */
92
        $redirectBinding = $this->get('surfnet_saml.http.redirect_binding');
93
94
        $this->getLogger()->notice(sprintf(
95
            'Sending AuthnRequest with request ID: "%s" to GSSP "%s" at "%s"',
96
            $authnRequest->getRequestId(),
97
            $provider->getName(),
98
            $provider->getRemoteIdentityProvider()->getSsoUrl()
99
        ));
100
101
        return $redirectBinding->createRedirectResponseFor($authnRequest);
0 ignored issues
show
Deprecated Code introduced by
The function Surfnet\SamlBundle\Http\...teRedirectResponseFor() has been deprecated: Please use the `createResponseFor` method instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

101
        return /** @scrutinizer ignore-deprecated */ $redirectBinding->createRedirectResponseFor($authnRequest);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
102
    }
103
104
    /**
105
     * @param Request $httpRequest
106
     * @param string  $provider
107
     * @return array|Response
108
     */
109
    public function consumeAssertionAction(Request $httpRequest, $provider)
110
    {
111
        $this->assertSecondFactorEnabled($provider);
112
113
        $provider = $this->getProvider($provider);
114
115
        $this->get('logger')->notice(
116
            sprintf('Received GSSP "%s" SAMLResponse through Gateway, attempting to process', $provider->getName())
117
        );
118
119
        try {
120
            /** @var \Surfnet\SamlBundle\Http\PostBinding $postBinding */
121
            $postBinding = $this->get('surfnet_saml.http.post_binding');
122
            $assertion = $postBinding->processResponse(
123
                $httpRequest,
124
                $provider->getRemoteIdentityProvider(),
125
                $provider->getServiceProvider()
126
            );
127
        } catch (Exception $exception) {
128
            $provider->getStateHandler()->clear();
129
130
            $this->getLogger()->error(
131
                sprintf('Could not process received Response, error: "%s"', $exception->getMessage())
132
            );
133
134
            return $this->redirectToStatusReportForm(
135
                $provider,
136
                ['authenticationFailed' => true]
137
            );
138
        }
139
140
        $expectedResponseTo = $provider->getStateHandler()->getRequestId();
141
        $provider->getStateHandler()->clear();
142
143
        if (!InResponseTo::assertEquals($assertion, $expectedResponseTo)) {
144
            $this->getLogger()->critical(sprintf(
145
                'Received Response with unexpected InResponseTo, %s',
146
                ($expectedResponseTo ? 'expected "' . $expectedResponseTo . '"' : ' no response expected')
147
            ));
148
149
            return $this->redirectToStatusReportForm(
150
                $provider,
151
                ['authenticationFailed' => true]
152
            );
153
        }
154
155
        $this->get('logger')->notice(
156
            sprintf('Processed GSSP "%s" SAMLResponse received through Gateway successfully', $provider->getName())
157
        );
158
159
        /** @var \Surfnet\StepupSelfService\SelfServiceBundle\Service\GssfService $service */
160
        $service = $this->get('surfnet_stepup_self_service_self_service.service.gssf');
161
        /** @var \Surfnet\SamlBundle\SAML2\Attribute\AttributeDictionary $attributeDictionary */
162
        $attributeDictionary = $this->get('surfnet_saml.saml.attribute_dictionary');
163
        $gssfId = $attributeDictionary->translate($assertion)->getNameID();
164
165
        $secondFactorId = $service->provePossession($this->getIdentity()->id, $provider->getName(), $gssfId);
166
167
        if ($secondFactorId) {
168
            $this->getLogger()->notice('GSSF possession has been proven successfully');
169
170
            if ($this->emailVerificationIsRequired()) {
171
                return $this->redirectToRoute(
172
                    'ss_registration_email_verification_email_sent',
173
                    ['secondFactorId' => $secondFactorId]
174
                );
175
            } else {
176
                return $this->redirectToRoute(
177
                    'ss_second_factor_vetting_types',
178
                    ['secondFactorId' => $secondFactorId]
179
                );
180
            }
181
        }
182
183
        $this->getLogger()->error('Unable to prove GSSF possession');
184
185
        return $this->redirectToStatusReportForm(
186
            $provider,
187
            ['proofOfPossessionFailed' => true]
188
        );
189
    }
190
191
    private function redirectToStatusReportForm(Provider $provider, array $options)
192
    {
193
        return $this->redirectToRoute(
194
            'ss_registration_gssf_status_report',
195
            $options + [
196
                'provider' => $provider->getName(),
197
            ]
198
        );
199
    }
200
201
    /**
202
     * @param string $provider
203
     * @return \Symfony\Component\HttpFoundation\Response
204
     */
205
    public function metadataAction($provider)
206
    {
207
        $this->assertSecondFactorEnabled($provider);
208
209
        $provider = $this->getProvider($provider);
210
211
        /** @var \Surfnet\SamlBundle\Metadata\MetadataFactory $factory */
212
        $factory = $this->get('gssp.provider.' . $provider->getName() . '.metadata.factory');
213
214
        return new XMLResponse($factory->generate());
215
    }
216
217
    /**
218
     * @param string $provider
219
     * @return \Surfnet\StepupSelfService\SamlStepupProviderBundle\Provider\Provider
220
     * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
221
     */
222
    private function getProvider($provider)
223
    {
224
        /** @var \Surfnet\StepupSelfService\SamlStepupProviderBundle\Provider\ProviderRepository $providerRepository */
225
        $providerRepository = $this->get('gssp.provider_repository');
226
227
        if (!$providerRepository->has($provider)) {
228
            $this->get('logger')->info(sprintf('Requested GSSP "%s" does not exist or is not registered', $provider));
229
230
            throw new NotFoundHttpException('Requested provider does not exist');
231
        }
232
233
        return $providerRepository->get($provider);
234
    }
235
236
    /**
237
     * @return \Psr\Log\LoggerInterface
238
     */
239
    private function getLogger()
240
    {
241
        return $this->get('logger');
242
    }
243
244
    private function renderStatusForm(string $provider, array $parameters = []): Response
245
    {
246
        /** @var ViewConfig $secondFactorConfig */
247
        $secondFactorConfig = $this->get("gssp.view_config.{$provider}");
248
249
        $form = $this->createForm(
250
            StatusGssfType::class,
251
            null,
252
            [
253
                'provider' => $provider,
254
                /** @Ignore from translation message extraction */
255
                'label' => $secondFactorConfig->getInitiateButton()
256
            ]
257
        );
258
        /** @var ViewConfig $secondFactorConfig */
259
        $templateParameters = array_merge(
260
            $parameters,
261
            [
262
                'form' => $form->createView(),
263
                'provider' => $provider,
264
                'secondFactorConfig' => $secondFactorConfig,
265
                'verifyEmail' => $this->emailVerificationIsRequired(),
266
            ]
267
        );
268
        return $this->render(
269
            'SurfnetStepupSelfServiceSelfServiceBundle:registration/gssf:status.html.twig',
270
            $templateParameters
271
        );
272
    }
273
}
274