Completed
Push — main ( a2ea13...6eca10 )
by
unknown
37s queued 33s
created

ActivationFlowService::process()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 39
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 4
eloc 26
c 2
b 0
f 0
nc 6
nop 1
dl 0
loc 39
rs 9.504

1 Method

Rating   Name   Duplication   Size   Complexity  
A ActivationFlowService::processPreferenceFromUri() 0 9 2
1
<?php
2
3
declare(strict_types = 1);
4
5
/**
6
 * Copyright 2022 SURFnet bv
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *     http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
0 ignored issues
show
Coding Style introduced by
PHP version not specified
Loading history...
Coding Style introduced by
Missing @category tag in file comment
Loading history...
Coding Style introduced by
Missing @package tag in file comment
Loading history...
Coding Style introduced by
Missing @author tag in file comment
Loading history...
Coding Style introduced by
Missing @license tag in file comment
Loading history...
Coding Style introduced by
Missing @link tag in file comment
Loading history...
20
21
namespace Surfnet\StepupSelfService\SelfServiceBundle\Service;
22
23
use Psr\Log\LoggerInterface;
24
use Surfnet\StepupSelfService\SelfServiceBundle\Exception\InvalidArgumentException;
25
use Surfnet\StepupSelfService\SelfServiceBundle\Exception\LogicException;
26
use Surfnet\StepupSelfService\SelfServiceBundle\Security\Authentication\AuthenticatedSessionStateHandler;
27
use Surfnet\StepupSelfService\SelfServiceBundle\Value\ActivationFlowPreference;
28
use Surfnet\StepupSelfService\SelfServiceBundle\Value\ActivationFlowPreferenceInterface;
29
use Surfnet\StepupSelfService\SelfServiceBundle\Value\ActivationFlowPreferenceNotExpressed;
30
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
31
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
32
33
class ActivationFlowService
0 ignored issues
show
Coding Style introduced by
Missing doc comment for class ActivationFlowService
Loading history...
34
{
35
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $logger should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $fieldName should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $sessionState should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $tokenStorage should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $attributeName should have a doc-comment as per coding-style.
Loading history...
36
     * Handle preferred activation flow logic
37
     *
38
     * 1. On the / path, the preferred activation flow can be set using the configured
39
     *    query string field. This field can have an option indicating the preferred flow.
40
     *    This is stored in session.
41
     * 2. If this preference was set, the list of available options is limited to just that
42
     *    option.
43
     * 3. The option can be reset by the Identity, removing it from session.
44
     *
45
     * Note that:
46
     * - fieldName and options are configured in the SelfServiceExtension
47
     *
48
     * @param string[] $options
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Expected 14 spaces after parameter type; 1 found
Loading history...
Coding Style introduced by
Doc comment for parameter $options does not match actual variable name $sessionState
Loading history...
49
     * @param array<string, string> $attributes
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Doc comment for parameter $attributes does not match actual variable name $tokenStorage
Loading history...
50
     */
51
    public function __construct(
52
        private readonly AuthenticatedSessionStateHandler $sessionState,
53
        private readonly TokenStorageInterface $tokenStorage,
54
        private readonly LoggerInterface $logger,
55
        private readonly string $fieldName,
56
        private readonly array $options,
57
        private readonly string $attributeName,
58
        private readonly array $attributes
59
    ) {
60
    }
61
62
    public function processPreferenceFromUri(string $uri): void
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function processPreferenceFromUri()
Loading history...
63
    {
64
        $requestedActivationPreference = $this->getFlowPreferenceFromUri($uri);
65
        if ($requestedActivationPreference instanceof ActivationFlowPreferenceNotExpressed) {
66
            return;
67
        }
68
69
        $this->logger->info('Storing the preference in session');
70
        $this->sessionState->setRequestedActivationFlowPreference($requestedActivationPreference);
71
    }
72
73
    public function getPreference(): ActivationFlowPreferenceInterface
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function getPreference()
Loading history...
74
    {
75
        $requestedActivationPreference = $this->sessionState->getRequestedActivationFlowPreference();
76
        $availableActivationPreferences = $this->getFlowPreferencesFromSamlAttributes();
77
78
        if (count($availableActivationPreferences) == 0) {
79
            $this->logger->info('No entitlement attributes found to determine the allowed flow, allowing all flows');
80
            $availableActivationPreferences = [
81
                ActivationFlowPreference::createSelf(),
82
                ActivationFlowPreference::createRa(),
83
            ];
84
        }
85
86
        if (in_array($requestedActivationPreference, $availableActivationPreferences)) {
87
            $this->logger->info('Found allowed activation flow');
88
            return $requestedActivationPreference;
89
        }
90
91
        $this->logger->info('Not found allowed activation flow');
92
93
        return new ActivationFlowPreferenceNotExpressed();
94
    }
95
96
    private function getFlowPreferenceFromUri(string $uri): ActivationFlowPreferenceInterface
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function getFlowPreferenceFromUri()
Loading history...
Coding Style introduced by
Private method name "ActivationFlowService::getFlowPreferenceFromUri" must be prefixed with an underscore
Loading history...
97
    {
98
        $this->logger->info(sprintf('Analysing uri "%s" for activation flow query parameter', $uri));
99
100
        $parts = parse_url($uri);
101
102
        $parameters = [];
103
        if (array_key_exists('query', $parts)) {
104
            $this->logger->debug('Found a query string in the uri');
105
            parse_str($parts['query'], $parameters);
106
        }
107
108
        // Is the configured field name in the querystring?
109
        if (!array_key_exists($this->fieldName, $parameters)) {
110
            $this->logger->notice(
111
                sprintf(
112
                    'The configured query string field name "%s" was not found in the uri "%s"',
113
                    $this->fieldName,
114
                    $uri
115
                )
116
            );
117
            return new ActivationFlowPreferenceNotExpressed();
118
        }
119
120
        try {
121
            $option = $parameters[$this->fieldName];
122
            $option = is_string($option) ? $option : "";
123
            return ActivationFlowPreference::fromString($option);
124
        } catch (InvalidArgumentException $e) {
125
            $this->logger->notice(
126
                sprintf(
127
                    'Field "%s" contained an invalid option "%s", must be one of: %s',
128
                    $this->fieldName,
129
                    $parameters[$this->fieldName],
130
                    implode(', ', $this->options)
131
                )
132
            );
133
            return new ActivationFlowPreferenceNotExpressed();
134
        }
135
    }
136
137
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
138
     * @return ActivationFlowPreferenceInterface[]
139
     */
140
    private function getFlowPreferencesFromSamlAttributes(): array
0 ignored issues
show
Coding Style introduced by
Private method name "ActivationFlowService::getFlowPreferencesFromSamlAttributes" must be prefixed with an underscore
Loading history...
141
    {
142
        $this->logger->info('Analysing saml entitlement attributes for allowed activation flows');
143
144
        $token = $this->tokenStorage->getToken();
145
        if (!$token instanceof TokenInterface) {
146
            throw new LogicException("A authentication token should be set at this point");
147
        }
148
149
        $activationFlows = [];
150
        $attributes = $token->getAttributes();
151
        if (array_key_exists($this->attributeName, $attributes)) {
152
            $this->logger->debug('Found entitlement saml attributes');
153
            if (in_array($this->attributes['ra'], $attributes[$this->attributeName])) {
154
                $activationFlows[] = ActivationFlowPreference::createRa();
155
            }
156
            if (in_array($this->attributes['self'], $attributes[$this->attributeName])) {
157
                $activationFlows[] = ActivationFlowPreference::createSelf();
158
            }
159
        }
160
        return $activationFlows;
161
    }
162
}
163