Completed
Push — develop ( 35eb4c...a68f85 )
by Daan van
8s
created

assertCommandMayBeProcessedOnBehalfOf()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 28
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 1
Metric Value
dl 0
loc 28
rs 8.5806
c 1
b 1
f 1
cc 4
eloc 16
nc 4
nop 2
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
 */
18
19
namespace Surfnet\StepupMiddleware\ApiBundle\Controller;
20
21
use Surfnet\StepupMiddleware\CommandHandlingBundle\Command\Command;
22
use Surfnet\StepupMiddleware\CommandHandlingBundle\Command\Metadata;
23
use Surfnet\StepupMiddleware\CommandHandlingBundle\EventSourcing\MetadataEnricher;
24
use Surfnet\StepupMiddleware\CommandHandlingBundle\Exception\ForbiddenException;
25
use Surfnet\StepupMiddleware\CommandHandlingBundle\Identity\Command\CreateIdentityCommand;
26
use Surfnet\StepupMiddleware\CommandHandlingBundle\Identity\Command\UpdateIdentityCommand;
27
use Surfnet\StepupMiddleware\CommandHandlingBundle\Pipeline\Pipeline;
28
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
29
use Symfony\Component\HttpFoundation\JsonResponse;
30
use Symfony\Component\HttpFoundation\Request;
31
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
32
33
class CommandController extends Controller
34
{
35
    public function handleAction(Command $command, Metadata $metadata, Request $request)
36
    {
37
        $this->denyAccessUnlessGranted(['ROLE_RA', 'ROLE_SS']);
38
39
        /** @var \Monolog\Logger $logger */
40
        $logger = $this->get('logger');
41
        $logger->notice(sprintf('Received request to process Command "%s"', $command));
42
43
        /** @var MetadataEnricher $metadataEnricher */
44
        $metadataEnricher = $this->get('surfnet_stepup_middleware_command_handling.metadata_enricher.actor');
45
        $metadataEnricher->setMetadata($metadata);
46
47
        if ($this->get('security.authorization_checker')->isGranted('ROLE_MANAGEMENT')) {
48
            $logger->notice('Command sent through Management API, not enforcing Whitelist');
49
        } else {
50
            $logger->notice('Ensuring that the actor institution is on the whitelist, or the actor is SRAA');
51
52
            $institution = $this->resolveInstitution($command, $metadata);
53
            $this->assertCommandMayBeProcessedOnBehalfOf($institution, $metadata->actorId);
54
        }
55
56
        /** @var Pipeline $pipeline */
57
        $pipeline = $this->get('pipeline');
58
59
        try {
60
            $command = $pipeline->process($command);
61
        } catch (ForbiddenException $e) {
62
            throw new AccessDeniedHttpException(
63
                sprintf('Processing of command "%s" is forbidden for this client', $command),
64
                $e
65
            );
66
        }
67
68
        $serverName = $request->server->get('SERVER_NAME') ?: $request->server->get('SERVER_ADDR');
69
        $response = new JsonResponse(['command' => $command->UUID, 'processed_by' => $serverName]);
0 ignored issues
show
Bug introduced by
Accessing UUID on the interface Surfnet\StepupMiddleware...gBundle\Command\Command suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
70
71
        $logger->notice(sprintf('Command "%s" has been successfully processed', $command));
72
73
        return $response;
74
    }
75
76
    /**
77
     * @param Command  $command
78
     * @param Metadata $metadata
79
     * @return string
80
     */
81
    private function resolveInstitution(Command $command, Metadata $metadata)
82
    {
83
        if ($metadata->actorInstitution) {
84
            return $metadata->actorInstitution;
85
        }
86
87
        // the createIdentityCommand is used to create an Identity for a new user,
88
        // the updateIdentityCommand is used to update name or email of an identity
89
        // Both are only sent by the SS when the Identity is not logged in yet,
90
        // thus there is not Metadata::actorInstitution,
91
        if ($command instanceof CreateIdentityCommand || $command instanceof UpdateIdentityCommand) {
92
            return $command->institution;
93
        }
94
95
        // conservative, if we cannot determine an institution, deny processing.
96
        throw new AccessDeniedHttpException(
97
            'Cannot reliably determine the institution of the actor, denying processing of command'
98
        );
99
    }
100
101
    /**
102
     * @param string      $institution
103
     * @param string|null $actorId
104
     */
105
    private function assertCommandMayBeProcessedOnBehalfOf($institution, $actorId)
106
    {
107
        $whitelistService = $this->get('surfnet_stepup_middleware_api.service.whitelist_entry');
108
109
        if ($whitelistService->isWhitelisted($institution)) {
110
            return;
111
        }
112
113
        if (!$actorId) {
114
            throw new AccessDeniedHttpException(sprintf(
115
                'Institution "%s" is not on the whitelist and no actor is found, processing of command denied',
116
                $institution
117
            ));
118
        }
119
120
        $identityService = $this->get('surfnet_stepup_middleware_api.service.identity');
121
        $registrationAuthorityCredentials = $identityService->findRegistrationAuthorityCredentialsOf($actorId);
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $registrationAuthorityCredentials exceeds the maximum configured length of 30.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
122
123
        if ($registrationAuthorityCredentials->isSraa()) {
124
            return;
125
        }
126
127
        throw new AccessDeniedHttpException(sprintf(
128
            'Institution "%s" is not on the whitelist and actor "%s" is not an SRAA, processing of command denied',
129
            $institution,
130
            $actorId
131
        ));
132
    }
133
}
134