Completed
Push — bugfix/enforce_raa ( 1a8a7b...35dd82 )
by
unknown
02:31
created

IdentityAuthorizationService   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 161
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 10

Importance

Changes 0
Metric Value
wmc 20
lcom 1
cbo 10
dl 0
loc 161
rs 10
c 0
b 0
f 0

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 11 1
A assertInstitutionIsWhitelisted() 0 23 4
A assertCommandMayBeExecutedOnBehalfOf() 0 5 1
B assertSelfServiceCommandMayBeExecutedOnBehalfOf() 0 31 6
A assertRaCommandMayBeExecutedOnBehalfOf() 0 30 5
A isSraa() 0 13 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\StepupMiddleware\ApiBundle\Authorization\Service;
19
20
21
use Psr\Log\LoggerInterface;
22
use Surfnet\Stepup\Configuration\Value\InstitutionRole;
23
use Surfnet\Stepup\Identity\Value\IdentityId;
24
use Surfnet\Stepup\Identity\Value\Institution;
25
use Surfnet\StepupMiddleware\ApiBundle\Identity\Service\IdentityService;
26
use Surfnet\StepupMiddleware\ApiBundle\Identity\Service\WhitelistService;
27
use Surfnet\StepupMiddleware\CommandHandlingBundle\Command\Command;
28
use Surfnet\StepupMiddleware\CommandHandlingBundle\Command\RaExecutable;
29
use Surfnet\StepupMiddleware\CommandHandlingBundle\Command\SelfServiceExecutable;
30
use Surfnet\StepupMiddleware\CommandHandlingBundle\Identity\Command\CreateIdentityCommand;
31
use Surfnet\StepupMiddleware\CommandHandlingBundle\Identity\Command\UpdateIdentityCommand;
32
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
33
34
class IdentityAuthorizationService
35
{
36
37
    /**
38
     * @var WhitelistService
39
     */
40
    private $whitelistService;
41
    /**
42
     * @var IdentityService
43
     */
44
    private $identityService;
45
    /**
46
     * @var InstitutionAuthorizationService
47
     */
48
    private $institutionAuthorizationService;
49
    /**
50
     * @var LoggerInterface
51
     */
52
    private $logger;
53
54
    public function __construct(
55
        WhitelistService $whitelistService,
56
        IdentityService $identityService,
57
        LoggerInterface $logger,
58
        InstitutionAuthorizationService $institutionAuthorizationService
59
    ) {
60
        $this->logger = $logger;
61
        $this->institutionAuthorizationService = $institutionAuthorizationService;
62
        $this->whitelistService = $whitelistService;
63
        $this->identityService = $identityService;
64
    }
65
66
    /**
67
     * @param Institution      $institution
68
     * @param IdentityId $actorId
69
     */
70
    public function assertInstitutionIsWhitelisted(Institution $institution, IdentityId $actorId)
71
    {
72
        if ($this->whitelistService->isWhitelisted($institution)) {
73
            return;
74
        }
75
76
        if (!$actorId) {
77
            throw new AccessDeniedHttpException(sprintf(
78
                'Institution "%s" is not on the whitelist and no actor is found, processing of command denied',
79
                $institution
80
            ));
81
        }
82
83
        if ($this->isSraa($actorId)) {
84
            return;
85
        }
86
87
        throw new AccessDeniedHttpException(sprintf(
88
            'Institution "%s" is not on the whitelist and actor "%s" is not an SRAA, processing of command denied',
89
            $institution,
90
            $actorId
91
        ));
92
    }
93
94
    /**
95
     * @param IdentityId $actorId
96
     * @param Institution $actorInstitution
97
     * @param Command $command
98
     */
99
    public function assertCommandMayBeExecutedOnBehalfOf(IdentityId $actorId, Institution $actorInstitution, Command $command)
100
    {
101
        $this->assertSelfServiceCommandMayBeExecutedOnBehalfOf($actorId, $command);
102
        $this->assertRaCommandMayBeExecutedOnBehalfOf($actorId, $actorInstitution, $command);
103
    }
104
105
    /**
106
     * @param string $actorId
0 ignored issues
show
Documentation introduced by
Should the type for parameter $actorId not be IdentityId?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
107
     * @param Command $command
108
     */
109
    private function assertSelfServiceCommandMayBeExecutedOnBehalfOf(IdentityId $actorId, Command $command)
110
    {
111
        // Assert self service command could be executed
112
        if ($command instanceof SelfServiceExecutable) {
113
            $this->logger->notice('Asserting a SelfService command');
114
115
            // the createIdentityCommand is used to create an Identity for a new user,
116
            // the updateIdentityCommand is used to update name or email of an identity
117
            // Both are only sent by the SS when the Identity is not logged in yet,
118
            // thus there is not Metadata::actorInstitution,
119
            if ($command instanceof CreateIdentityCommand || $command instanceof UpdateIdentityCommand) {
120
                return;
121
            }
122
123
            // If the actor is SRAA all actions should be allowed
124
            if ($this->isSraa($actorId)) {
125
                return;
126
            }
127
128
            // Validate if the actor is the user
129
            if ($command->getIdentityId() !== $actorId) {
130
                throw new AccessDeniedHttpException(sprintf(
131
                    'The actor "%s" is not allowed to act on behalf of identity "%s" processing of command denied',
132
                    $actorId,
133
                    $command->getIdentityId()
134
                ));
135
            }
136
137
            return;
138
        }
139
    }
140
141
    /**
142
     * @param string $actorId
0 ignored issues
show
Documentation introduced by
Should the type for parameter $actorId not be IdentityId?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
143
     * @param string $actorInstitution
0 ignored issues
show
Documentation introduced by
Should the type for parameter $actorInstitution not be Institution?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
144
     * @param Command $command
145
     */
146
    private function assertRaCommandMayBeExecutedOnBehalfOf(IdentityId $actorId, Institution $actorInstitution, Command $command)
147
    {
148
        // Assert RAA specific authorizations
149
        if ($command instanceof RaExecutable) {
150
            $this->logger->notice('Asserting a RA command');
151
152
            // If the actor is SRAA all actions should be allowed
153
            if ($this->isSraa($actorId)) {
154
                return;
155
            }
156
157
            $raInstitution = $command->getRaInstitution();
158
            if (is_null($raInstitution)) {
159
                $raInstitution = $actorInstitution;
160
            }
161
162
            $authorizationContext = $this->institutionAuthorizationService->buildInstitutionAuthorizationContext(
163
                new IdentityId($actorId),
164
                InstitutionRole::useRaa()
165
            );
166
167
            if (!$authorizationContext->getInstitutions()->contains(new Institution($raInstitution))) {
168
                throw new AccessDeniedHttpException(sprintf(
169
                    'The actor "%s" is not allowed to act on behalf of institution  "%s" processing of command denied',
170
                    $actorId,
171
                    $raInstitution
172
                ));
173
            }
174
        }
175
    }
176
177
    /**
178
     * @param string $actorId
179
     * @return bool
180
     */
181
    private function isSraa($actorId)
182
    {
183
        $registrationAuthorityCredentials = $this->identityService->findRegistrationAuthorityCredentialsOf($actorId);
184
        if (!$registrationAuthorityCredentials) {
185
            return false;
186
        }
187
188
        if (!$registrationAuthorityCredentials->isSraa()) {
0 ignored issues
show
Unused Code introduced by
This if statement, and the following return statement can be replaced with return $registrationAuth...yCredentials->isSraa();.
Loading history...
189
            return false;
190
        }
191
192
        return true;
193
    }
194
}