Passed
Pull Request — master (#37)
by Tim
02:48
created

Cas10::validate()   C

Complexity

Conditions 17
Paths 82

Size

Total Lines 112
Code Lines 68

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 68
c 2
b 0
f 0
dl 0
loc 112
rs 5.2166
cc 17
nc 82
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\Controller;
6
7
use Exception;
8
use SimpleSAML\Configuration;
9
use SimpleSAML\Logger;
10
use SimpleSAML\Module;
11
use SimpleSAML\Module\casserver\Utils\Url as UrlUtils;
12
use Symfony\Component\HttpFoundation\Request;
13
use Symfony\Component\HttpFoundation\StreamedResponse;
14
15
use function array_key_exist;
16
use function is_null;
17
use function var_export;
18
19
/**
20
 * Controller class for the casserver module.
21
 *
22
 * This class serves the different views available in the module.
23
 *
24
 * @package SimpleSAML\Module\casserver
25
 */
26
class Cas10
27
{
28
    /** @var \SimpleSAML\Configuration */
29
    protected Configuration $config;
30
31
    /** @var \SimpleSAML\Module\casserver\Utils\Url */
32
    protected UrlUtils $urlUtils;
33
34
35
    /**
36
     * Controller constructor.
37
     *
38
     * It initializes the global configuration for the controllers implemented here.
39
     *
40
     * @param \SimpleSAML\Configuration $config The configuration to use by the controllers.
41
     */
42
    public function __construct(
43
        Configuration $config
44
    ) {
45
        $this->config = $config;
46
        $this->urlUtils = new UrlUtils();
47
    }
48
49
50
    /**
51
     * @param \Symfony\Component\HttpFoundation\Request $request
52
     * @return \Symfony\Component\HttpFoundation\StreamedResponse
53
     */
54
    public function validate(Request $request): StreamedResponse
55
    {
56
        /* Load simpleSAMLphp, configuration and metadata */
57
        $casconfig = Configuration::getConfig('module_casserver.php');
58
59
        /* Instantiate protocol handler */
60
        $protocolClass = Module::resolveClass('casserver:Cas10', 'Cas\Protocol');
61
62
        /** @psalm-suppress InvalidStringClass */
63
        $protocol = new $protocolClass($casconfig);
0 ignored issues
show
Unused Code introduced by
The assignment to $protocol is dead and can be removed.
Loading history...
64
65
        $response = new StreamedResponse();
66
        if ($request->query->has('service') && $request->query->has('ticket')) {
67
            $forceAuthn = $request->query->has('renew') && !!$request->query->get('renew');
68
69
            try {
70
                /* Instantiate ticket store */
71
                $ticketStoreConfig = $casconfig->getOptionalValue(
72
                    'ticketstore',
73
                    ['class' => 'casserver:FileSystemTicketStore']
74
                );
75
76
                $ticketStoreClass = Module::resolveClass($ticketStoreConfig['class'], 'Cas\Ticket');
77
78
                /** @psalm-suppress InvalidStringClass */
79
                $ticketStore = new $ticketStoreClass($casconfig);
80
81
                $ticketFactoryClass = Module::resolveClass('casserver:TicketFactory', 'Cas\Ticket');
82
83
                /** @psalm-suppress InvalidStringClass */
84
                $ticketFactory = new $ticketFactoryClass($casconfig);
85
86
                $ticket = $request->query->get('ticket');
87
                $serviceTicket = $ticketStore->getTicket($ticket);
88
89
                if (!is_null($serviceTicket) && $ticketFactory->isServiceTicket($serviceTicket)) {
90
                    $service = $request->query->get('service');
91
                    $ticketStore->deleteTicket($ticket);
92
                    $usernameField = $casconfig->getOptionalValue('attrname', 'eduPersonPrincipalName');
93
94
                    if (
95
                        !$ticketFactory->isExpired($serviceTicket) &&
96
                        $this->urlUtils->sanitize($serviceTicket['service']) === $this->urlUtils->sanitize($service) &&
97
                        (!$forceAuthn || $serviceTicket['forceAuthn']) &&
98
                        array_key_exists($usernameField, $serviceTicket['attributes'])
99
                    ) {
100
                        $response->setCallback(function($protocol, array $serviceTicket, string $usernameField) {
101
                            echo $protocol->getValidateSuccessResponse($serviceTicket['attributes'][$usernameField][0]);
102
                        });
103
                    } else {
104
                        if (!array_key_exists($usernameField, $serviceTicket['attributes'])) {
105
                            Logger::error(sprintf(
106
                                'casserver:validate: internal server error. Missing user name attribute: %s',
107
                                var_export($usernameField, true)
108
                            ));
109
110
                            $response->setCallback(function($protocol) {
111
                                echo $protocol->getValidateFailureResponse();
112
                            });
113
                        } else {
114
                            if ($ticketFactory->isExpired($serviceTicket)) {
115
                                $message = 'Ticket has ' . var_export($ticket, true) . ' expired';
116
                            } else {
117
                                if ($this->urlUtils->sanitize($serviceTicket['service']) === $this->urlUtils->sanitize($service)) {
118
                                    $message = 'Mismatching service parameters: expected ' .
119
                                    var_export($serviceTicket['service'], true) .
120
                                    ' but was: ' . var_export($service, true);
121
                                } else {
122
                                    $message = 'Ticket was issue from single sign on session';
123
                                }
124
                            }
125
                            Logger::debug('casserver:' . $message);
126
127
                            $response->setCallback(function($protocol) {
128
                                echo $protocol->getValidateFailureResponse();
129
                            });
130
                        }
131
                    }
132
                } else {
133
                    if (is_null($serviceTicket)) {
134
                        $message = 'ticket: ' . var_export($ticket, true) . ' not recognized';
135
                    } else {
136
                        $message = 'ticket: ' . var_export($ticket, true) . ' is not a service ticket';
137
                    }
138
139
                    Logger::debug('casserver:' . $message);
140
141
                    $response->setCallback(function($protocol) {
142
                        echo $protocol->getValidateFailureResponse();
143
                    });
144
                }
145
            } catch (Exception $e) {
146
                Logger::error('casserver:validate: internal server error. ' . var_export($e->getMessage(), true));
147
148
                $response->setCallback(function($protocol) {
149
                    echo $protocol->getValidateFailureResponse();
150
                });
151
            }
152
        } else {
153
            if (!$request->query->has('service')) {
154
                $message = 'Missing service parameter: [service]';
155
            } else {
156
                $message = 'Missing ticket parameter: [ticket]';
157
            }
158
159
            Logger::debug('casserver:' . $message);
160
            $response->setCallback(function($protocol) {
161
                echo $protocol->getValidateFailureResponse();
162
            });
163
        }
164
165
        return $response;
166
    }
167
}
168