Passed
Push — master ( c4afc2...9cde23 )
by Pieter van der
27:49 queued 12:42
created

SelfVetMarshaller::isAllowed()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 36
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 22
nc 7
nop 2
dl 0
loc 36
rs 8.6346
c 1
b 0
f 0
1
<?php
2
3
/**
4
 * Copyright 2021 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\StepupSelfService\SelfServiceBundle\Service;
20
21
use Psr\Log\LoggerInterface;
22
use Surfnet\StepupBundle\Service\SecondFactorTypeService;
23
use Surfnet\StepupBundle\Value\SecondFactorType;
24
use Surfnet\StepupBundle\Value\VettingType;
25
use Surfnet\StepupMiddlewareClientBundle\Identity\Dto\Identity;
26
use Surfnet\StepupMiddlewareClientBundle\Identity\Dto\VettedSecondFactor;
27
use function sprintf;
28
29
class SelfVetMarshaller implements VettingMarshaller
30
{
31
    /**
32
     * @var SecondFactorService
33
     */
34
    private $secondFactorService;
35
36
    /**
37
     * @var SecondFactorTypeService
38
     */
39
    private $secondFactorTypeService;
40
41
    /**
42
     * @var InstitutionConfigurationOptionsService
43
     */
44
    private $institutionConfigurationService;
45
46
    private $authorizationService;
47
48
    /**
49
     * @var LoggerInterface
50
     */
51
    private $logger;
52
53
    public function __construct(
54
        SecondFactorService $secondFactorService,
55
        SecondFactorTypeService $secondFactorTypeService,
56
        InstitutionConfigurationOptionsService $institutionConfigurationOptionsService,
57
        AuthorizationService $authorizationService,
58
        LoggerInterface $logger
59
    ) {
60
        $this->secondFactorService = $secondFactorService;
61
        $this->secondFactorTypeService = $secondFactorTypeService;
62
        $this->institutionConfigurationService = $institutionConfigurationOptionsService;
63
        $this->authorizationService = $authorizationService;
64
        $this->logger = $logger;
65
    }
66
67
    /**
68
     * You are allowed to self vet when:
69
     * 1. You already have a vetted token
70
     * 2. The vetted token has higher LoA (or equal) to the one being vetted
71
     *
72
     * Or
73
     *
74
     * When you have a self asserted token, you are allowed to self-vet any
75
     * token with the self-vetted token. Resulting in tokens that are of the
76
     * self-asserted token type.
77
     */
78
    public function isAllowed(Identity $identity, string $secondFactorId): bool
79
    {
80
        if (!$this->isSelfVettingEnabledFor($identity)) {
81
            return false;
82
        }
83
        $vettedSecondFactors = $this->secondFactorService->findVettedByIdentity($identity->id);
84
        if ($vettedSecondFactors->getTotalItems() === 0) {
85
            $this->logger->info('Self vetting is not allowed, no vetted tokens are available');
86
            return false;
87
        }
88
        $candidateToken = $this->secondFactorService->findOneVerified($secondFactorId);
89
        if ($candidateToken) {
90
            /** @var VettedSecondFactor $authoringSecondFactor */
91
            foreach ($vettedSecondFactors->getElements() as $authoringSecondFactor) {
92
                $hasSuitableToken = $this->secondFactorTypeService->hasEqualOrLowerLoaComparedTo(
93
                    new SecondFactorType($candidateToken->type),
94
                    new VettingType(VettingType::TYPE_SELF_VET),
95
                    new SecondFactorType($authoringSecondFactor->type),
96
                    new VettingType($authoringSecondFactor->vettingType)
97
                );
98
                if ($hasSuitableToken) {
99
                    $this->logger->info('Self vetting is allowed, a suitable token was found');
100
                    return true;
101
                }
102
            }
103
        }
104
105
        // Finally, we allow vetting with self-asserted tokens. Using the SAT authorization service
106
        // we ascertain if the user is allowed to use SAT.
107
        if ($this->authorizationService->maySelfVetSelfAssertedTokens($identity)) {
108
            $this->logger->info('Self vetting is allowed, by utilizing self-asserted tokens');
109
            return true;
110
        }
111
112
        $this->logger->info('Self vetting is not allowed, no suitable tokens are available');
113
        return false;
114
    }
115
116
    /**
117
     * Does the institution allow for self vetting?
118
     */
119
120
    private function isSelfVettingEnabledFor(Identity $identity):bool
121
    {
122
        $this->logger->info('Determine if self vetting is allowed');
123
        $configurationOptions = $this->institutionConfigurationService->getInstitutionConfigurationOptionsFor(
124
            $identity->institution
125
        );
126
        if ($configurationOptions->selfVet === false) {
127
            $this->logger->info(
128
                sprintf(
129
                    'Self vetting is not allowed, as the option is not enabled for institution %s',
130
                    $identity->institution
131
                )
132
            );
133
            return false;
134
        }
135
        $this->logger->info(sprintf('Self vetting is allowed for %s', $identity->institution));
136
        return true;
137
    }
138
}
139