Completed
Push — feature/upgrade-remote-vetting ( 883904 )
by
unknown
65:35
created

RemoteVettingController::remoteVetAction()   B

Complexity

Conditions 6
Paths 3

Size

Total Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 37
rs 8.7057
c 0
b 0
f 0
cc 6
nc 3
nop 3
1
<?php
2
/**
3
 * Copyright 2010 SURFnet B.V.
4
 *
5
 * Licensed under the Apache License, Version 2.0 (the "License");
6
 * you may not use this file except in compliance with the License.
7
 * You may obtain a copy of the License at
8
 *
9
 *     http://www.apache.org/licenses/LICENSE-2.0
10
 *
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
16
 */
17
18
namespace Surfnet\StepupSelfService\SelfServiceBundle\Controller;
19
20
use Psr\Log\LoggerInterface;
21
use SAML2\Response\Exception\PreconditionNotMetException;
22
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
23
use Surfnet\StepupBundle\DateTime\RegistrationExpirationHelper;
24
use Surfnet\StepupSelfService\SelfServiceBundle\Command\RemoteVetCommand;
25
use Surfnet\StepupSelfService\SelfServiceBundle\Command\RemoteVetValidationCommand;
26
use Surfnet\StepupSelfService\SelfServiceBundle\Exception\InvalidRemoteVettingContextException;
27
use Surfnet\StepupSelfService\SelfServiceBundle\Exception\InvalidRemoteVettingStateException;
28
use Surfnet\StepupSelfService\SelfServiceBundle\Form\Type\RemoteVetSecondFactorType;
29
use Surfnet\StepupSelfService\SelfServiceBundle\Form\Type\RemoteVetValidationType;
30
use Surfnet\StepupSelfService\SelfServiceBundle\Security\Authentication\Token\SamlToken;
31
use Surfnet\StepupSelfService\SelfServiceBundle\Service\RemoteVetting\Dto\AttributeListDto;
32
use Surfnet\StepupSelfService\SelfServiceBundle\Service\RemoteVetting\Dto\RemoteVettingTokenDto;
33
use Surfnet\StepupSelfService\SelfServiceBundle\Service\RemoteVetting\SamlCalloutHelper;
34
use Surfnet\StepupSelfService\SelfServiceBundle\Service\RemoteVetting\Value\ProcessId;
35
use Surfnet\StepupSelfService\SelfServiceBundle\Service\RemoteVettingService;
36
use Surfnet\StepupSelfService\SelfServiceBundle\Service\SecondFactorService;
37
use Symfony\Component\HttpFoundation\RedirectResponse;
38
use Symfony\Component\HttpFoundation\Request;
39
use Symfony\Component\HttpFoundation\Response;
40
use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
41
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
42
43
/**
44
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects) Too much coupling dus to glue code nature of this controller.
45
 *                                                 Could be refactored later on
46
 */
47
class RemoteVettingController extends Controller
48
{
49
    /**
50
     * @var RemoteVettingService
51
     */
52
    private $remoteVettingService;
53
    /**
54
     * @var SamlCalloutHelper
55
     */
56
    private $samlCalloutHelper;
57
    /**
58
     * @var LoggerInterface
59
     */
60
    private $logger;
61
    /**
62
     * @var RegistrationExpirationHelper
63
     */
64
    private $expirationHelper;
65
    /**
66
     * @var SecondFactorService
67
     */
68
    private $secondFactorService;
69
70
    public function __construct(
71
        RemoteVettingService $remoteVettingService,
72
        SecondFactorService $secondFactorService,
73
        SamlCalloutHelper $samlCalloutHelper,
74
        RegistrationExpirationHelper $expirationHelper,
75
        LoggerInterface $logger
76
    ) {
77
        $this->secondFactorService = $secondFactorService;
78
        $this->remoteVettingService = $remoteVettingService;
79
        $this->samlCalloutHelper = $samlCalloutHelper;
80
        $this->expirationHelper = $expirationHelper;
81
        $this->logger = $logger;
82
    }
83
84
    /**
85
     * @Template
86
     * @param Request $request
87
     * @param string $secondFactorId
88
     * @param string $identityProviderSlug
89
     * @return array|Response
0 ignored issues
show
Documentation introduced by
Should the return type not be RedirectResponse|array?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
90
     */
91
    public function remoteVetAction(Request $request, $secondFactorId, $identityProviderSlug)
92
    {
93
        $identity = $this->getIdentity();
94
95
        $secondFactor = $this->secondFactorService->findOneVerified($secondFactorId);
96
        if ($secondFactor === null ||
97
            $secondFactor->identityId != $identity->id ||
98
            $this->expirationHelper->hasExpired($secondFactor->registrationRequestedAt)
99
        ) {
100
            throw new NotFoundHttpException(
101
                sprintf("No %s second factor with id '%s' exists.", 'verified', $secondFactorId)
102
            );
103
        }
104
105
        $command = new RemoteVetCommand();
106
        $command->identity = $identity;
0 ignored issues
show
Documentation Bug introduced by
It seems like $identity of type object<Surfnet\StepupMid...\Identity\Dto\Identity> is incompatible with the declared type string of property $identity.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
107
        $command->secondFactor = $secondFactor;
0 ignored issues
show
Documentation Bug introduced by
It seems like $secondFactor of type object<Surfnet\StepupMid...o\VerifiedSecondFactor> is incompatible with the declared type string of property $secondFactor.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
108
109
        $form = $this->createForm(RemoteVetSecondFactorType::class, $command)->handleRequest($request);
110
111
        if ($form->isSubmitted() && $form->isValid()) {
112
            $token = RemoteVettingTokenDto::create(
113
                $command->identity->id,
114
                $command->secondFactor->id
115
            );
116
117
            $this->remoteVettingService->start($identityProviderSlug, $token);
118
119
            return new RedirectResponse($this->samlCalloutHelper->createAuthnRequest($identityProviderSlug));
120
        }
121
122
        return [
123
            'form' => $form->createView(),
124
            'identity' => $identity,
125
            'secondFactor' => $secondFactor,
126
        ];
127
    }
128
129
    /**
130
     * @param Request $request
131
     * @return mixed
132
     */
133
    public function acsAction(Request $request)
134
    {
135
        $this->logger->info('Receiving response from the remote IdP');
136
137
        /** @var FlashBagInterface $flashBag */
138
        $flashBag = $this->get('session')->getFlashBag();
139
140
        $this->logger->info('Load the attributes from the saml response');
141
142
        try {
143
            $processId = $this->samlCalloutHelper->handleResponse($request, $this->remoteVettingService->getActiveIdentityProviderSlug());
144
        } catch (InvalidRemoteVettingStateException $e) {
145
            $this->logger->error($e->getMessage());
146
            $flashBag->add('error', 'ss.second_factor.revoke.alert.remote_vetting_failed');
147
            return $this->redirectToRoute('ss_second_factor_list');
148
        } catch (PreconditionNotMetException $e) {
0 ignored issues
show
Bug introduced by
The class SAML2\Response\Exception...onditionNotMetException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
149
            $this->logger->error($e->getMessage());
150
            $flashBag->add('error', 'ss.second_factor.revoke.alert.remote_vetting_failed');
151
            return $this->redirectToRoute('ss_second_factor_list');
152
        } catch (InvalidRemoteVettingContextException $e) {
153
            $this->logger->error($e->getMessage());
154
            return $this->redirectToRoute('ss_second_factor_list');
155
        }
156
157
        return $this->redirectToRoute('ss_second_factor_remote_vet_match', [
158
            'processId' => $processId->getProcessId(),
159
        ]);
160
161
        return $this->redirectToRoute('ss_second_factor_list');
0 ignored issues
show
Unused Code introduced by
return $this->redirectTo...s_second_factor_list'); does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
162
    }
163
164
    /**
165
     * @param Request $request
166
     * @param $processId
167
     * @return Response
168
     */
169
    public function remoteVetMatchAction(Request $request, $processId)
170
    {
171
        /** @var FlashBagInterface $flashBag */
172
        $flashBag = $this->get('session')->getFlashBag();
173
174
        /** @var SamlToken $samlToken */
175
        $samlToken = $this->container->get('security.token_storage')->getToken();
176
177
        $localAttributes = AttributeListDto::fromAttributeSet($samlToken->getAttribute(SamlToken::ATTRIBUTE_SET));
178
179
        $command = new RemoteVetValidationCommand();
180
181
        try {
182
            $command->matches = $this->remoteVettingService->getAttributeMatchCollection($localAttributes);
183
184
            $form = $this->createForm(RemoteVetValidationType::class, $command)->handleRequest($request);
185
            if ($form->isSubmitted() && $form->isValid()) {
186
187
                /** @var RemoteVetValidationCommand $command */$command = $form->getData();
188
189
                $token =  $this->remoteVettingService->done(
190
                    ProcessId::create($processId),
191
                    $this->getIdentity(),
192
                    $localAttributes,
193
                    $command->matches,
194
                    (string)$command->remarks
195
                );
196
197
                $command = new RemoteVetCommand();
198
                $command->identity = $token->getIdentityId();
199
                $command->secondFactor = $token->getSecondFactorId();
200
201
                if ($this->secondFactorService->remoteVet($command)) {
202
                    $flashBag->add('success', 'ss.second_factor.revoke.alert.remote_vetting_successful');
203
                } else {
204
                    $flashBag->add('error', 'ss.second_factor.revoke.alert.remote_vetting_failed');
205
                }
206
207
                return $this->redirectToRoute('ss_second_factor_list');
208
            }
209
210
            return $this->render('SurfnetStepupSelfServiceSelfServiceBundle:RemoteVetting:validation.html.twig', [
211
                'form' => $form->createView(),
212
            ]);
213
        } catch (InvalidRemoteVettingStateException $e) {
214
            $this->logger->error($e->getMessage());
215
            $flashBag->add('error', 'ss.second_factor.revoke.alert.remote_vetting_failed');
216
            return $this->redirectToRoute('ss_second_factor_list');
217
        } catch (InvalidRemoteVettingContextException $e) {
218
            $this->logger->error($e->getMessage());
219
            return $this->redirectToRoute('ss_second_factor_list');
220
        }
221
    }
222
}
223