Passed
Pull Request — main (#308)
by Paul
16:02 queued 07:12
created

RegistrationController::displayVettingTypes()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 60
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

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