ServiceValidator::checkServiceURL()   B
last analyzed

Complexity

Conditions 11
Paths 33

Size

Total Lines 70
Code Lines 42

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 42
dl 0
loc 70
rs 7.3166
c 0
b 0
f 0
cc 11
nc 33
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\Module\casserver\Cas;
6
7
use SimpleSAML\Configuration;
8
use SimpleSAML\Logger;
9
use SimpleSAML\Module\casserver\Codebooks\OverrideConfigPropertiesEnum;
10
11
/**
12
 * Validates if a CAS service can use server
13
 * @package SimpleSAML\Module\casserver\Cas
14
 */
15
class ServiceValidator
16
{
17
    /**
18
     * @var \SimpleSAML\Configuration
19
     */
20
    private Configuration $mainConfig;
21
22
    /**
23
     * ServiceValidator constructor.
24
     * @param Configuration $mainConfig
25
     */
26
    public function __construct(Configuration $mainConfig)
27
    {
28
        $this->mainConfig = $mainConfig;
29
    }
30
31
    /**
32
     * Check that the $service is allowed, and if so return the configuration to use.
33
     *
34
     * @param   string  $service  The service url. Assume to already be url decoded
35
     *
36
     * @return Configuration|null Return the configuration to use for this service, or null if service is not allowed
37
     * @throws \ErrorException
38
     */
39
    public function checkServiceURL(string $service): ?Configuration
40
    {
41
        $isValidService = false;
42
        $legalUrl = 'undefined';
43
        $configOverride = null;
44
        $legalServiceUrlsConfig = $this->mainConfig->getOptionalArray('legal_service_urls', []);
45
46
        foreach ($legalServiceUrlsConfig as $index => $value) {
47
            // Support two styles:  0 => 'https://example' and 'https://example' => [ extra config ]
48
            $legalUrl = \is_int($index) ? $value : $index;
49
            if (empty($legalUrl)) {
50
                Logger::warning("Ignoring empty CAS legal service url '$legalUrl'.");
51
                continue;
52
            }
53
54
            $configOverride = \is_int($index) ? null : $value;
55
56
            // URL String
57
            if (str_starts_with($service, $legalUrl)) {
58
                $isValidService = true;
59
                break;
60
            }
61
62
            // Regex
63
            // Since "If the regex pattern passed does not compile to a valid regex, an E_WARNING is emitted. "
64
            // we will throw an exception if the warning is emitted and use try-catch to handle it
65
            set_error_handler(static function ($severity, $message, $file, $line) {
66
                throw new \ErrorException($message, $severity, $severity, $file, $line);
67
            }, E_WARNING);
68
69
            try {
70
                $result = preg_match($legalUrl, $service);
71
                if ($result !== 1) {
72
                    throw new \RuntimeException('Service URL does not match legal service URL.');
73
                }
74
                $isValidService = true;
75
                break;
76
            } catch (\RuntimeException $e) {
77
                // do nothing
78
                Logger::warning($e->getMessage());
79
            } catch (\Exception $e) {
80
                // do nothing
81
                Logger::warning("Invalid CAS legal service url '$legalUrl'. Error " . preg_last_error());
82
            } finally {
83
                restore_error_handler();
84
            }
85
        }
86
87
        if (!$isValidService) {
88
            return null;
89
        }
90
91
        $serviceConfig = $this->mainConfig->toArray();
92
        // Return contextual information about which url rule triggered the validation
93
        $serviceConfig['casService'] = [
94
            'matchingUrl' => $legalUrl,
95
            'serviceUrl'  => $service,
96
        ];
97
        if ($configOverride !== null) {
98
            // We need to remove all the unsupported configuration keys
99
            $supportedProperties = array_column(OverrideConfigPropertiesEnum::cases(), 'value');
100
            $configOverride = array_filter(
101
                $configOverride,
102
                static fn($property) => \in_array($property, $supportedProperties, true),
103
                ARRAY_FILTER_USE_KEY,
104
            );
105
            // Merge the configurations
106
            $serviceConfig = array_merge($serviceConfig, $configOverride);
107
        }
108
        return Configuration::loadFromArray($serviceConfig);
109
    }
110
}
111