Passed
Pull Request — main (#308)
by Paul
24:50 queued 14:16
created

RegistrationController::displayVettingTypes()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 60
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 36
c 1
b 0
f 0
nc 4
nop 2
dl 0
loc 60
rs 8.7217

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