getInstitutionsForSelectRaaRole()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 31
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 20
nc 2
nop 1
dl 0
loc 31
rs 9.6
c 0
b 0
f 0
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
Missing @link tag in file comment
Loading history...
18
19
namespace Surfnet\StepupMiddleware\ApiBundle\Identity\Repository;
20
21
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
22
use Doctrine\ORM\Query\Expr\Join;
23
use Doctrine\Persistence\ManagerRegistry;
24
use Psr\Log\LoggerInterface;
25
use Surfnet\Stepup\Configuration\Value\InstitutionRole;
26
use Surfnet\Stepup\Identity\Collection\InstitutionCollection;
27
use Surfnet\Stepup\Identity\Value\IdentityId;
28
use Surfnet\Stepup\Identity\Value\Institution;
29
use Surfnet\Stepup\Identity\Value\RegistrationAuthorityRole;
0 ignored issues
show
Bug introduced by
The type Surfnet\Stepup\Identity\...gistrationAuthorityRole was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
30
use Surfnet\StepupMiddleware\ApiBundle\Configuration\Entity\ConfiguredInstitution;
31
use Surfnet\StepupMiddleware\ApiBundle\Configuration\Entity\InstitutionAuthorization;
32
use Surfnet\StepupMiddleware\ApiBundle\Exception\RuntimeException;
33
use Surfnet\StepupMiddleware\ApiBundle\Identity\Entity\AuditLogEntry;
34
use Surfnet\StepupMiddleware\ApiBundle\Identity\Entity\Identity;
35
use Surfnet\StepupMiddleware\ApiBundle\Identity\Entity\RaListing;
36
use Surfnet\StepupMiddleware\ApiBundle\Identity\Value\AuthorityRole;
37
38
/**
39
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
40
 * @extends ServiceEntityRepository<InstitutionCollection>
0 ignored issues
show
Coding Style introduced by
Tag value for @extends tag indented incorrectly; expected 40 spaces but found 1
Loading history...
41
 */
0 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @package tag in class comment
Loading history...
Coding Style introduced by
Missing @author tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
42
class AuthorizationRepository extends ServiceEntityRepository
43
{
44
    public function __construct(
45
        ManagerRegistry $registry,
46
        private readonly LoggerInterface $logger,
47
    ) {
48
        parent::__construct($registry, AuditLogEntry::class);
49
    }
50
51
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $role should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $actorId should have a doc-comment as per coding-style.
Loading history...
52
     * Return all institutions were the actor has the specified role for
53
     * The returned institutions are used to filter query results on
54
     *
55
     * @return InstitutionCollection
56
     */
57
    public function getInstitutionsForRole(RegistrationAuthorityRole $role, IdentityId $actorId): InstitutionCollection
58
    {
59
        $result = new InstitutionCollection();
60
        $qb = $this->getEntityManager()->createQueryBuilder()
61
            ->select("a.institution")
62
            ->from(ConfiguredInstitution::class, 'i')
63
            ->innerJoin(RaListing::class, 'r', Join::WITH, "i.institution = r.raInstitution")
64
            ->innerJoin(
65
                InstitutionAuthorization::class,
66
                'a',
67
                Join::WITH,
68
                "i.institution = a.institutionRelation AND a.institutionRole IN (:authorizationRoles)",
69
            )
70
            ->where("r.identityId = :identityId AND r.role IN(:roles)")
71
            ->groupBy("a.institution");
72
73
        $qb->setParameter('identityId', (string)$actorId);
74
        $qb->setParameter(
75
            'authorizationRoles',
76
            $this->getAllowedInstitutionRoles($role),
77
        );
78
        $identityRoles = $this->getAllowedIdentityRoles($role);
79
        $qb->setParameter(
80
            'roles',
81
            $identityRoles,
82
        );
83
84
        $institutions = $qb->getQuery()->getArrayResult();
85
        foreach ($institutions as $institution) {
86
            $this->logger->notice(
87
                sprintf('Adding %s to authorized institutions', $institution['institution']),
88
            );
89
            $result->add(new Institution((string)$institution['institution']));
90
        }
91
92
        // Also get the institutions that are linked to the user via the 'institution_relation' field.
93
        // Effectively getting the use_raa relation.
94
        // See https://www.pivotaltracker.com/story/show/181537313
95
        $qb = $this->getEntityManager()->createQueryBuilder()
96
            ->select('ia.institution')
97
            ->from(InstitutionAuthorization::class, 'ia')
98
            // Filter the RA listing on the authorizations that apply for the RA(A) listed there
99
            // For example, when testing a USE_RA institution authorization, the listed RA should have
100
            // at least a RA or RAA role
101
            ->join(
102
                RaListing::class,
103
                'r',
104
                Join::WITH,
105
                'r.raInstitution = ia.institutionRelation AND r.role IN (:identityRoles)',
106
            )
107
            ->where('r.identityId = :identityId')
108
            ->andWhere("ia.institutionRole = :role") // Only filter on use_ra and use_raa roles here.
109
            ->groupBy('ia.institution');
110
111
        $qb->setParameter('identityId', (string)$actorId);
112
        $qb->setParameter('role', $this->getInstitutionRoleByRaRole($role));
113
        $qb->setParameter('identityRoles', $identityRoles);
114
115
        $institutions = $qb->getQuery()->getArrayResult();
116
        foreach ($institutions as $institution) {
117
            $institutionVo = new Institution((string)$institution['institution']);
118
            if (!$result->contains($institutionVo)) {
119
                $result->add($institutionVo);
120
                $this->logger->notice(
121
                    sprintf(
122
                        'Adding %s to authorized institutions from %s',
123
                        $role,
124
                        $institution['institution'],
125
                    ),
126
                );
127
            }
128
        }
129
130
        return $result;
131
    }
132
133
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $actorId should have a doc-comment as per coding-style.
Loading history...
134
     * Finds the institutions that have the Select RAA authorization based on
135
     * the institution of the specified identity.
136
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
137
    public function getInstitutionsForSelectRaaRole(IdentityId $actorId): InstitutionCollection
138
    {
139
        $qb = $this->getEntityManager()->createQueryBuilder()
140
            ->select("ci.institution")
141
            ->from(InstitutionAuthorization::class, 'ia')
142
            ->innerJoin(ConfiguredInstitution::class, 'ci', Join::WITH, 'ia.institutionRelation = ci.institution')
143
            ->innerJoin(Identity::class, 'i', Join::WITH, 'ia.institution = i.institution AND i.id = :identityId')
144
            ->innerJoin(RaListing::class, 'ra', Join::WITH, 'i.id = ra.identityId AND ra.role = :authorizationRole')
145
            ->where('ia.institutionRole = :institutionRole AND ra.role = :authorizationRole')
146
            ->groupBy("ci.institution");
147
148
        $qb->setParameter('identityId', (string)$actorId);
149
        // The identity requires RAA role to perform this search
150
        $qb->setParameter(
151
            'authorizationRole',
152
            AuthorityRole::ROLE_RAA,
153
        );
154
        // Filter on the SELECT_RAA authorization in the institution authorization projection
155
        $qb->setParameter(
156
            'institutionRole',
157
            InstitutionRole::ROLE_SELECT_RAA,
158
        );
159
160
        $institutions = $qb->getQuery()->getArrayResult();
161
162
        $result = new InstitutionCollection();
163
        foreach ($institutions as $institution) {
164
            $result->add(new Institution((string)$institution['institution']));
165
        }
166
167
        return $result;
168
    }
169
170
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $role should have a doc-comment as per coding-style.
Loading history...
171
     * This is the mapping to look up allowed institution roles
172
     * - if the required role is RA we should look if the configured institution has USE_RA role
173
     * - if the required role is RAA we should look if the configured institution has USE_RAA role
174
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
175
    private function getAllowedInstitutionRoles(RegistrationAuthorityRole $role): array
0 ignored issues
show
Coding Style introduced by
Private method name "AuthorizationRepository::getAllowedInstitutionRoles" must be prefixed with an underscore
Loading history...
176
    {
177
        return match (true) {
178
            $role->equals(RegistrationAuthorityRole::ra()) => [InstitutionRole::ROLE_USE_RA],
179
            $role->equals(RegistrationAuthorityRole::raa()) => [InstitutionRole::ROLE_USE_RAA],
180
            default => [],
181
        };
182
    }
183
184
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $role should have a doc-comment as per coding-style.
Loading history...
185
     * This is the mapping to look up allowed identity roles for a specific institution role
186
     * - if the required role is RA we should look if the identity has a RA or RAA role
187
     * - if the required role is RAA we should look if the identity has a RAA role
188
     *
189
     */
0 ignored issues
show
Coding Style introduced by
Additional blank lines found at end of doc comment
Loading history...
Coding Style introduced by
Missing @return tag in function comment
Loading history...
190
    private function getAllowedIdentityRoles(RegistrationAuthorityRole $role): array
0 ignored issues
show
Coding Style introduced by
Private method name "AuthorizationRepository::getAllowedIdentityRoles" must be prefixed with an underscore
Loading history...
191
    {
192
        return match (true) {
193
            $role->equals(RegistrationAuthorityRole::ra()) => [AuthorityRole::ROLE_RA, AuthorityRole::ROLE_RAA],
194
            $role->equals(RegistrationAuthorityRole::raa()) => [AuthorityRole::ROLE_RAA],
195
            default => [],
196
        };
197
    }
198
199
    private function getInstitutionRoleByRaRole(RegistrationAuthorityRole $role): string
0 ignored issues
show
Coding Style introduced by
Private method name "AuthorizationRepository::getInstitutionRoleByRaRole" must be prefixed with an underscore
Loading history...
200
    {
201
        if ($role->equals(RegistrationAuthorityRole::ra())) {
202
            return AuthorityRole::ROLE_RA;
203
        }
204
        if ($role->equals(RegistrationAuthorityRole::raa())) {
205
            return AuthorityRole::ROLE_RAA;
206
        }
207
208
        throw new RuntimeException(
209
            sprintf(
210
                'The role "%s did not match any of our supported AuthorityRoles (ra, raa)',
211
                $role->jsonSerialize()
212
            )
213
        );
214
    }
215
}
216