Completed
Pull Request — develop (#239)
by Michiel
05:22 queued 02:10
created

InstitutionConfigurationController::showAction()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 35
rs 9.36
c 0
b 0
f 0
cc 2
nc 2
nop 0
1
<?php
2
3
/**
4
 * Copyright 2016 SURFnet B.V.
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\StepupMiddleware\ManagementBundle\Controller;
20
21
use DateTime;
22
use Exception;
23
use Liip\FunctionalTestBundle\Validator\DataCollectingValidator;
24
use Psr\Log\LoggerInterface;
25
use Rhumsaa\Uuid\Uuid;
26
use Surfnet\Stepup\Configuration\Value\Institution;
27
use Surfnet\Stepup\Configuration\Value\InstitutionRole;
28
use Surfnet\Stepup\Helper\JsonHelper;
29
use Surfnet\StepupMiddleware\ApiBundle\Configuration\Service\AllowedSecondFactorListService;
30
use Surfnet\StepupMiddleware\ApiBundle\Configuration\Service\InstitutionAuthorizationService;
31
use Surfnet\StepupMiddleware\ApiBundle\Configuration\Service\InstitutionConfigurationOptionsService;
32
use Surfnet\StepupMiddleware\ApiBundle\Exception\BadCommandRequestException;
33
use Surfnet\StepupMiddleware\CommandHandlingBundle\Command\Command;
34
use Surfnet\StepupMiddleware\CommandHandlingBundle\Configuration\Command\ReconfigureInstitutionConfigurationOptionsCommand;
35
use Surfnet\StepupMiddleware\CommandHandlingBundle\Exception\ForbiddenException;
36
use Surfnet\StepupMiddleware\CommandHandlingBundle\Pipeline\TransactionAwarePipeline;
37
use Surfnet\StepupMiddleware\ManagementBundle\Service\DBALConnectionHelper;
38
use Surfnet\StepupMiddleware\ManagementBundle\Validator\Constraints\ValidReconfigureInstitutionsRequest;
39
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
40
use Symfony\Component\HttpFoundation\JsonResponse;
41
use Symfony\Component\HttpFoundation\Request;
42
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
43
44
/**
45
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
46
 */
47
final class InstitutionConfigurationController extends Controller
48
{
49
    /**
50
     * @return InstitutionConfigurationOptionsService
51
     */
52
    private $institutionConfigurationOptionsService;
53
54
    /**
55
     * @return InstitutionAuthorizationService
56
     */
57
    private $institutionAuthorizationService;
58
59
    /**
60
     * @return DataCollectingValidator
61
     */
62
    private $validator;
63
64
    /**
65
     * @return AllowedSecondFactorListService
66
     */
67
    private $allowedSecondFactorListService;
68
69
    /**
70
     * @return LoggerInterface
71
     */
72
    private $logger;
73
74
    /**
75
     * @return TransactionAwarePipeline
76
     */
77
    private $pipeline;
78
79
    /**
80
     * @var DBALConnectionHelper
81
     */
82
    private $connectionHelper;
83
84
    public function __construct(
85
        InstitutionConfigurationOptionsService $institutionConfigurationOptionsService,
86
        InstitutionAuthorizationService $institutionAuthorizationService,
87
        DataCollectingValidator $dataCollectingValidator,
88
        AllowedSecondFactorListService $allowedSecondFactorListService,
89
        LoggerInterface $logger,
90
        TransactionAwarePipeline $pipeline,
91
        DBALConnectionHelper $dbalConnectionHelper
92
    ) {
93
        $this->institutionConfigurationOptionsService = $institutionConfigurationOptionsService;
94
        $this->institutionAuthorizationService = $institutionAuthorizationService;
95
        $this->validator = $dataCollectingValidator;
96
        $this->allowedSecondFactorListService = $allowedSecondFactorListService;
97
        $this->logger = $logger;
98
        $this->pipeline = $pipeline;
99
        $this->connectionHelper = $dbalConnectionHelper;
100
    }
101
102
    public function showAction()
103
    {
104
        $this->denyAccessUnlessGranted(['ROLE_MANAGEMENT']);
105
106
        $institutionConfigurationOptions = $this->institutionConfigurationOptionsService
107
            ->findAllInstitutionConfigurationOptions();
108
109
        $allowedSecondFactorMap = $this->allowedSecondFactorListService->getAllowedSecondFactorMap();
110
111
        $overview = [];
112
        foreach ($institutionConfigurationOptions as $options) {
113
            // Load the numberOfTokensPerIdentity from the institution config options service
114
            $numberOfTokensPerIdentity = $this->institutionConfigurationOptionsService
115
                ->getMaxNumberOfTokensFor(new Institution($options->institution->getInstitution()));
116
117
            // Get the authorization options for this institution
118
            $institutionConfigurationOptionsMap = $this->institutionAuthorizationService
119
                ->findAuthorizationsFor($options->institution);
120
121
            $overview[$options->institution->getInstitution()] = [
122
                'use_ra_locations' => $options->useRaLocationsOption,
123
                'show_raa_contact_information' => $options->showRaaContactInformationOption,
124
                'verify_email' => $options->verifyEmailOption,
125
                'number_of_tokens_per_identity' => $numberOfTokensPerIdentity,
126
                'allowed_second_factors' => $allowedSecondFactorMap->getAllowedSecondFactorListFor(
127
                    $options->institution
128
                ),
129
                'use_ra' => $institutionConfigurationOptionsMap->getAuthorizationOptionsByRole(InstitutionRole::useRa())->jsonSerialize(),
130
                'use_raa' => $institutionConfigurationOptionsMap->getAuthorizationOptionsByRole(InstitutionRole::useRaa())->jsonSerialize(),
131
                'select_raa' => $institutionConfigurationOptionsMap->getAuthorizationOptionsByRole(InstitutionRole::selectRaa())->jsonSerialize(),
132
            ];
133
        }
134
135
        return new JsonResponse($overview);
136
    }
137
138
    public function reconfigureAction(Request $request)
139
    {
140
        $this->denyAccessUnlessGranted(['ROLE_MANAGEMENT']);
141
142
        $configuration = JsonHelper::decode($request->getContent());
143
144
        $violations = $this->validator->validate($configuration, new ValidReconfigureInstitutionsRequest());
145
        if ($violations->count() > 0) {
146
            throw BadCommandRequestException::withViolations('Invalid reconfigure institutions request', $violations);
147
        }
148
149
        if (empty($configuration)) {
150
            $this->logger->notice(sprintf('No institutions to reconfigure: empty configuration received'));
151
152
            return new JsonResponse([
153
                'status'       => 'OK',
154
                'processed_by' =>  $request->server->get('SERVER_NAME') ?: $request->server->get('SERVER_ADDR'),
155
                'applied_at'   => (new DateTime())->format(DateTime::ISO8601),
156
            ]);
157
        }
158
159
        $commands = [];
160
        foreach ($configuration as $institution => $options) {
161
            $command                                  = new ReconfigureInstitutionConfigurationOptionsCommand();
162
            $command->UUID                            = (string) Uuid::uuid4();
163
            $command->institution                     = $institution;
0 ignored issues
show
Documentation Bug introduced by
It seems like $institution can also be of type integer. However, the property $institution is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
164
            $command->useRaLocationsOption            = $options['use_ra_locations'];
165
            $command->showRaaContactInformationOption = $options['show_raa_contact_information'];
166
            $command->verifyEmailOption               = $options['verify_email'];
167
            $command->numberOfTokensPerIdentityOption = $options['number_of_tokens_per_identity'];
168
            $command->allowedSecondFactors            = $options['allowed_second_factors'];
169
170
            // The useRa, useRaa and selectRaa options are optional
171
            $command->useRaOption = isset($options['use_ra']) ? $options['use_ra'] : null;
172
            $command->useRaaOption = isset($options['use_raa']) ? $options['use_raa'] : null;
173
            $command->selectRaaOption = isset($options['select_raa']) ? $options['select_raa'] : null;
174
175
            $commands[] = $command;
176
        }
177
178
        $this->logger->notice(
179
            sprintf('Executing %s reconfigure institution configuration options commands', count($commands))
180
        );
181
182
        $this->handleCommands($commands);
183
184
        return new JsonResponse([
185
            'status'       => 'OK',
186
            'processed_by' =>  $request->server->get('SERVER_NAME') ?: $request->server->get('SERVER_ADDR'),
187
            'applied_at'   => (new DateTime())->format(DateTime::ISO8601),
188
        ]);
189
    }
190
191
    /**
192
     * @param Command[] $commands
193
     * @throws Exception
194
     */
195
    private function handleCommands(array $commands)
196
    {
197
        $connectionHelper = $this->connectionHelper;
198
199
        $connectionHelper->beginTransaction();
200
201
        foreach ($commands as $command) {
202
            try {
203
                $this->pipeline->process($command);
204
            } catch (ForbiddenException $e) {
205
                $connectionHelper->rollBack();
206
207
                throw new AccessDeniedHttpException(
208
                    sprintf('Processing of command "%s" is forbidden for this client', $command),
209
                    $e
210
                );
211
            } catch (Exception $exception) {
212
                $connectionHelper->rollBack();
213
214
                throw $exception;
215
            }
216
        }
217
218
        $connectionHelper->commit();
219
    }
220
}
221