Passed
Push — feature/symfony6-upgrade ( 166417...86e2b9 )
by Paul
06:45
created

RegistrationController::displayVettingTypes()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 61
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 36
nc 4
nop 2
dl 0
loc 61
rs 8.7217
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
 */
0 ignored issues
show
Coding Style introduced by
PHP version not specified
Loading history...
Coding Style introduced by
Missing @category tag in file comment
Loading history...
Coding Style introduced by
Missing @package tag in file comment
Loading history...
Coding Style introduced by
Missing @author tag in file comment
Loading history...
Coding Style introduced by
Missing @license tag in file comment
Loading history...
Coding Style introduced by
Missing @link tag in file comment
Loading history...
18
19
namespace Surfnet\StepupSelfService\SelfServiceBundle\Controller;
20
21
use DateInterval;
22
use Mpdf\Mpdf;
23
use Mpdf\Output\Destination as MpdfDestination;
24
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
25
use Surfnet\StepupSelfService\SamlStepupProviderBundle\Provider\ViewConfig;
26
use Surfnet\StepupSelfService\SelfServiceBundle\Service\RaLocationService;
27
use Surfnet\StepupSelfService\SelfServiceBundle\Service\RaService;
28
use Surfnet\StepupSelfService\SelfServiceBundle\Service\SecondFactorService;
29
use Surfnet\StepupSelfService\SelfServiceBundle\Service\VettingTypeService;
30
use Surfnet\StepupSelfService\SelfServiceBundle\Value\AvailableTokenCollection;
31
use Surfnet\StepupSelfService\SelfServiceBundle\Value\VettingType\VettingTypeInterface;
32
use Symfony\Component\HttpFoundation\Request;
33
use Symfony\Component\HttpFoundation\Response;
34
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
35
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
36
use Symfony\Component\Routing\Annotation\Route;
37
38
class RegistrationController extends Controller
0 ignored issues
show
Coding Style introduced by
Missing doc comment for class RegistrationController
Loading history...
39
{
40
    public function __construct(private \Surfnet\StepupSelfService\SelfServiceBundle\Service\VettingTypeService $vettingTypeService)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __construct()
Loading history...
41
    {
42
    }
43
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
44
     * @Template
45
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
46
    #[Route(
47
        path: '/registration/select-token',
48
        name: 'ss_registration_display_types',
49
        methods: ['GET'],
50
    )]
51
    public function displaySecondFactorTypes(): \Symfony\Component\HttpFoundation\Response|array
52
    {
53
        $institution = $this->getIdentity()->institution;
54
        $institutionConfigurationOptions = $this->get('self_service.service.institution_configuration_options')
55
            ->getInstitutionConfigurationOptionsFor($institution);
56
57
        $identity = $this->getIdentity();
58
59
        /** @var SecondFactorService $service */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
60
        $service = $this->get('surfnet_stepup_self_service_self_service.service.second_factor');
61
62
        // Get all available second factors from the config.
63
        $allSecondFactors = $this->getParameter('ss.enabled_second_factors');
64
65
        $secondFactors = $service->getSecondFactorsForIdentity(
66
            $identity,
67
            $allSecondFactors,
68
            $institutionConfigurationOptions->allowedSecondFactors,
69
            $institutionConfigurationOptions->numberOfTokensPerIdentity
70
        );
71
72
        if ($secondFactors->getRegistrationsLeft() <= 0) {
73
            $this->get('logger')->notice(
74
                'User tried to register a new token but maximum number of tokens is reached. Redirecting to overview'
75
            );
76
            return $this->forward('SurfnetStepupSelfServiceSelfServiceBundle:SecondFactor:list');
77
        }
78
79
80
        $availableGsspSecondFactors = [];
81
        foreach ($secondFactors->available as $index => $secondFactor) {
82
            if ($this->has("gssp.view_config.{$secondFactor}")) {
83
                /** @var ViewConfig $secondFactorConfig */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
84
                $secondFactorConfig = $this->get("gssp.view_config.{$secondFactor}");
85
                $availableGsspSecondFactors[$index] = $secondFactorConfig;
86
                // Remove the gssp second factors from the regular second factors.
87
                unset($secondFactors->available[$index]);
88
            }
89
        }
90
91
        $availableTokens = AvailableTokenCollection::from($secondFactors->available, $availableGsspSecondFactors);
92
93
        return [
94
            'commonName' => $this->getIdentity()->commonName,
95
            'availableSecondFactors' => $availableTokens,
96
            'verifyEmail' => $this->emailVerificationIsRequired(),
97
        ];
98
    }
99
100
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
Parameter $request should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $secondFactorId should have a doc-comment as per coding-style.
Loading history...
101
     * @Template
102
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
103
    #[Route(
104
        path: '/second-factor/{secondFactorId}/vetting-types',
105
        name: 'ss_second_factor_vetting_types',
106
        methods:  ['GET'],
107
    )]
108
    public function displayVettingTypes(Request $request, string $secondFactorId): array|Response
109
    {
110
        /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
111
         * @var VettingTypeService
112
         */
113
        $vettingTypeService = $this->vettingTypeService;
114
        $vettingTypeCollection = $vettingTypeService->vettingTypes($this->getIdentity(), $secondFactorId);
115
116
        $logger = $this->get('logger');
117
118
        $nudgeSelfAssertedTokens = $vettingTypeCollection->isPreferred(VettingTypeInterface::SELF_ASSERTED_TOKENS);
119
        $nudgeRaVetting = $vettingTypeCollection->isPreferred(VettingTypeInterface::ON_PREMISE);
120
121
        // Nudging section: helping the Identity into choosing the right vetting type:
122
123
        // Option 1: A self-asserted token registration nudge was requested via query string (?activate=self)
124
        if ($nudgeSelfAssertedTokens && $vettingTypeCollection->allowSelfAssertedTokens()) {
125
            $logger->notice('Nudging (forcing) self-asserted token registration');
126
            return $this->forward(
127
                'SurfnetStepupSelfServiceSelfServiceBundle:SelfAssertedTokens:selfAssertedTokenRegistration',
128
                ['secondFactorId' => $secondFactorId]
129
            );
130
        }
131
132
        // Option 2: A ra-vetting nudge was requested via query string (?activate=ra)
133
        if ($nudgeRaVetting) {
134
            $logger->notice('Nudging (forcing) RA vetting');
135
            return $this->forward(
136
                'SurfnetStepupSelfServiceSelfServiceBundle:Registration:sendRegistrationEmail',
137
                ['secondFactorId' => $secondFactorId]
138
            );
139
        }
140
141
        // Option 3: non-formal nudge, skip over selection screen. As only ra vetting is available.
142
        if (!$vettingTypeCollection->allowSelfVetting() && !$vettingTypeCollection->allowSelfAssertedTokens()) {
143
            $logger
144
                ->notice(
145
                    'Skipping ahead to the RA vetting option as self vetting or self-asserted tokens are not allowed'
146
                );
147
            return $this->forward(
148
                'SurfnetStepupSelfServiceSelfServiceBundle:Registration:sendRegistrationEmail',
149
                ['secondFactorId' => $secondFactorId]
150
            );
151
        }
152
153
        $institution = $this->getIdentity()->institution;
154
        $currentLocale = $request->getLocale();
155
        $vettingTypeHint = $vettingTypeService->vettingTypeHint($institution, $currentLocale);
156
157
        return [
158
            'allowSelfVetting' => $vettingTypeCollection->allowSelfVetting(),
159
            'allowSelfAssertedTokens' => $vettingTypeCollection->allowSelfAssertedTokens(),
160
            'hasVettingTypeHint' => !is_null($vettingTypeHint),
161
            'vettingTypeHint' => $vettingTypeHint,
162
            'verifyEmail' => $this->emailVerificationIsRequired(),
163
            'secondFactorId' => $secondFactorId,
164
        ];
165
    }
166
167
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
168
     * @Template
169
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
170
    #[Route(
171
        path: '/registration/{secondFactorId}/email-verification-email-sent',
172
        name: 'ss_registration_email_verification_email_sent',
173
        methods: ['GET'],
174
    )]
175
    public function emailVerificationEmailSent(): array
176
    {
177
        return ['email' => $this->getIdentity()->email];
178
    }
179
180
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
Parameter $request should have a doc-comment as per coding-style.
Loading history...
181
     * @Template
182
     *
183
     * @return array|\Symfony\Component\HttpFoundation\RedirectResponse
184
     */
185
    #[Route(
186
        path: '/verify-email',
187
        name: 'ss_registration_verify_email',
188
        methods: ['GET'],
189
    )]
190
    public function verifyEmail(Request $request): \Symfony\Component\HttpFoundation\RedirectResponse|array
191
    {
192
        $nonce = $request->query->get('n', '');
193
        $identityId = $this->getIdentity()->id;
194
195
        /** @var SecondFactorService $service */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
196
        $service = $this->get('surfnet_stepup_self_service_self_service.service.second_factor');
197
198
        $secondFactor = $service->findUnverifiedByVerificationNonce($identityId, $nonce);
199
200
        if ($secondFactor === null) {
201
            throw new NotFoundHttpException('No second factor can be verified using this URL.');
202
        }
203
204
        if ($service->verifyEmail($identityId, $nonce)) {
205
            return $this->redirectToRoute(
206
                'ss_second_factor_vetting_types',
207
                ['secondFactorId' => $secondFactor->id]
208
            );
209
        }
210
211
        return [];
212
    }
213
214
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $secondFactorId should have a doc-comment as per coding-style.
Loading history...
215
     * Intermediate action where the registration mail is sent. After which the
216
     * email-sent page is displayed. Preventing the mail message from being sent
217
     * over and over again when the user performs a page reload.
218
     */
0 ignored issues
show
Coding Style introduced by
There must be no blank lines after the function comment
Loading history...
Coding Style introduced by
Missing @return tag in function comment
Loading history...
219
    #[Route(
220
        path: '/registration/{secondFactorId}/send-registration-email',
221
        name: 'ss_registration_send_registration_email',
222
        methods: ['GET'],
223
    )]
224
225
    public function sendRegistrationEmail(string $secondFactorId): \Symfony\Component\HttpFoundation\RedirectResponse
226
    {
227
        // Send the registration email
228
        $this->get('self_service.service.ra')
229
            ->sendRegistrationMailMessage($this->getIdentity()->id, $secondFactorId);
230
        return $this->redirectToRoute(
231
            'ss_registration_registration_email_sent',
232
            ['secondFactorId' => $secondFactorId]
233
        );
234
    }
235
236
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
237
     * @param $secondFactorId
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
238
     * @return Response
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
239
     */
240
    #[Route(
241
        path: '/registration/{secondFactorId}/registration-email-sent',
242
        name: 'ss_registration_registration_email_sent',
243
        methods: ['GET'],
244
    )]
245
    public function registrationEmailSent($secondFactorId): \Symfony\Component\HttpFoundation\Response
246
    {
247
        $parameters = $this->buildRegistrationActionParameters($secondFactorId);
248
        // Report that it was sent
249
        return $this->render(
250
            'SurfnetStepupSelfServiceSelfServiceBundle:registration:registration_email_sent.html.twig',
251
            $parameters
252
        );
253
    }
254
255
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
256
     * @param $secondFactorId
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
257
     * @return Response
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
258
     */
259
    #[Route(
260
        path: '/registration/{secondFactorId}/registration-pdf',
261
        name: 'ss_registration_registration_pdf',
262
        methods: ['GET'],
263
    )]
264
    public function registrationPdf($secondFactorId): \Symfony\Component\HttpFoundation\Response
265
    {
266
        $parameters = $this->buildRegistrationActionParameters($secondFactorId);
267
268
        $response = $this->render(
269
            'SurfnetStepupSelfServiceSelfServiceBundle:registration:registration_email_sent_pdf.html.twig',
270
            $parameters
271
        );
272
        $content = $response->getContent();
273
274
275
        $mpdf = new Mpdf(
276
            ['tempDir' => sys_get_temp_dir()]
277
        );
278
        $mpdf->setLogger($this->get('logger'));
279
280
        $mpdf->WriteHTML($content);
281
        $output = $mpdf->Output('registration-code.pdf', MpdfDestination::STRING_RETURN);
282
283
        $response = new Response($output);
284
        $disposition = $response->headers->makeDisposition(
285
            ResponseHeaderBag::DISPOSITION_ATTACHMENT,
286
            'registration-code.pdf'
287
        );
288
289
        $response->headers->set('Content-Disposition', $disposition);
290
        $response->headers->set('Content-Description', 'File Transfer');
291
        $response->headers->set('Content-Transfer-Encoding', 'binary');
292
        $response->headers->set('Cache-Control', 'public, must-revalidate, max-age=0');
293
        $response->headers->set('Pragma', 'public');
294
        $response->headers->set('Expires', 'Sat, 26 Jul 1997 05:00:00 GMT');
295
        $response->headers->set('Last-Modified', '' . gmdate('D, d M Y H:i:s') . ' GMT');
296
        $response->headers->set('Content-Type', 'application/pdf');
297
298
        return $response;
299
    }
300
301
302
    private function buildRegistrationActionParameters($secondFactorId): array
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function buildRegistrationActionParameters()
Loading history...
Coding Style introduced by
Private method name "RegistrationController::buildRegistrationActionParameters" must be prefixed with an underscore
Loading history...
303
    {
304
        $identity = $this->getIdentity();
305
306
        /** @var \Surfnet\StepupMiddlewareClientBundle\Identity\Dto\VerifiedSecondFactor $secondFactor */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
307
        $secondFactor = $this->get('surfnet_stepup_self_service_self_service.service.second_factor')
308
            ->findOneVerified($secondFactorId);
309
310
        $parameters = [
311
            'email'            => $identity->email,
312
            'secondFactorId'   => $secondFactor->id,
313
            'registrationCode' => $secondFactor->registrationCode,
314
            'expirationDate'   => $secondFactor->registrationRequestedAt->add(
315
                new DateInterval('P14D')
316
            ),
317
            'locale'           => $identity->preferredLocale,
318
            'verifyEmail'      => $this->emailVerificationIsRequired(),
319
        ];
320
321
        /** @var RaService $raService */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
322
        $raService         = $this->get('self_service.service.ra');
323
        /** @var RaLocationService $raLocationService */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
324
        $raLocationService = $this->get('self_service.service.ra_location');
325
326
        $institutionConfigurationOptions = $this->get('self_service.service.institution_configuration_options')
327
            ->getInstitutionConfigurationOptionsFor($identity->institution);
328
329
        if ($institutionConfigurationOptions->useRaLocations) {
330
            $parameters['raLocations'] = $raLocationService->listRaLocationsFor($identity->institution);
331
        } elseif (!$institutionConfigurationOptions->showRaaContactInformation) {
332
            $parameters['ras'] = $raService->listRasWithoutRaas($identity->institution);
333
        } else {
334
            $parameters['ras'] = $raService->listRas($identity->institution);
335
        }
336
337
        return $parameters;
338
    }
339
}
340