Passed
Pull Request — master (#45)
by
unknown
15:47 queued 02:06
created

Cas10Controller::validate()   C

Complexity

Conditions 14
Paths 42

Size

Total Lines 84
Code Lines 53

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 53
c 2
b 0
f 0
dl 0
loc 84
rs 6.2666
cc 14
nc 42
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 SimpleSAML\Configuration;
8
use SimpleSAML\Logger;
9
use SimpleSAML\Module\casserver\Cas\Factories\TicketFactory;
10
use SimpleSAML\Module\casserver\Cas\Protocol\Cas10;
11
use SimpleSAML\Module\casserver\Controller\Traits\UrlTrait;
12
use Symfony\Component\HttpFoundation\Request;
13
use Symfony\Component\HttpFoundation\Response;
14
15
/**
16
 * Controller class for the casserver module.
17
 *
18
 * This class serves the different views available in the module.
19
 *
20
 * @package SimpleSAML\Module\casserver
21
 */
22
class Cas10Controller
23
{
24
    use UrlTrait;
1 ignored issue
show
introduced by
The trait SimpleSAML\Module\casser...troller\Traits\UrlTrait requires some properties which are not provided by SimpleSAML\Module\casser...troller\Cas10Controller: $query, $request
Loading history...
25
26
    /** @var Logger */
27
    protected Logger $logger;
28
29
    /** @var Configuration */
30
    protected Configuration $casConfig;
31
32
    /** @var Cas10 */
33
    protected Cas10 $cas10Protocol;
34
35
    /** @var TicketFactory */
36
    protected TicketFactory $ticketFactory;
37
38
    // this could be any configured ticket store
39
    protected mixed $ticketStore;
40
41
    /**
42
     * Controller constructor.
43
     *
44
     * It initializes the global configuration for the controllers implemented here.
45
     *
46
     * @throws Exception
47
     */
48
    public function __construct()
49
    {
50
        $this->casConfig = Configuration::getConfig('module_casserver.php');
51
        $this->cas10Protocol = new Cas10($this->casConfig);
52
        /* Instantiate ticket factory */
53
        $this->ticketFactory = new TicketFactory($this->casConfig);
54
        /* Instantiate ticket store */
55
        $ticketStoreConfig = $this->casConfig->getOptionalValue(
56
            'ticketstore',
57
            ['class' => 'casserver:FileSystemTicketStore'],
58
        );
59
        $ticketStoreClass = 'SimpleSAML\\Module\\casserver\\Cas\\Ticket\\'
60
            . explode(':', $ticketStoreConfig['class'])[1];
61
        /** @psalm-suppress InvalidStringClass */
62
        $this->ticketStore = new $ticketStoreClass($this->casConfig);
63
    }
64
65
    /**
66
     * @param   Request  $request
67
     *
68
     * @return Response
69
     */
70
    public function validate(Request $request): Response
71
    {
72
        // Check if any of the required query parameters are missing
73
        if (!$request->query->has('service')) {
74
            Logger::debug('casserver: Missing service parameter: [service]');
75
            return new Response(
76
                $this->cas10Protocol->getValidateFailureResponse(),
77
                Response::HTTP_BAD_REQUEST,
78
            );
79
        } elseif (!$request->query->has('ticket')) {
80
            Logger::debug('casserver: Missing service parameter: [ticket]');
81
            return new Response(
82
                $this->cas10Protocol->getValidateFailureResponse(),
83
                Response::HTTP_BAD_REQUEST,
84
            );
85
        }
86
87
        // Check if we are required to force an authentication
88
        $forceAuthn = $request->query->has('renew') && $request->query->get('renew');
89
        // Get the ticket
90
        $ticket = $request->query->get('ticket');
91
        // Get the service
92
        $service = $request->query->get('service');
93
94
        try {
95
            // Get the service ticket
96
            $serviceTicket = $this->ticketStore->getTicket($ticket);
97
            // Delete the ticket
98
            $this->ticketStore->deleteTicket($ticket);
99
        } catch (\Exception $e) {
100
            Logger::error('casserver:validate: internal server error. ' . var_export($e->getMessage(), true));
101
            return new Response(
102
                $this->cas10Protocol->getValidateFailureResponse(),
103
                Response::HTTP_INTERNAL_SERVER_ERROR,
104
            );
105
        }
106
107
        $failed = false;
108
        $message = '';
109
        // No ticket
110
        if ($serviceTicket === null) {
111
            $message = 'ticket: ' . var_export($ticket, true) . ' not recognized';
112
            $failed = true;
113
            // This is not a service ticket
114
        } elseif (!$this->ticketFactory->isServiceTicket($serviceTicket)) {
115
            $message = 'ticket: ' . var_export($ticket, true) . ' is not a service ticket';
116
            $failed = true;
117
            // the ticket has expired
118
        } elseif ($this->ticketFactory->isExpired($serviceTicket)) {
119
            $message = 'Ticket has ' . var_export($ticket, true) . ' expired';
120
            $failed = true;
121
        } elseif ($this->sanitize($serviceTicket['service']) === $this->sanitize($service)) {
122
            $message = 'Mismatching service parameters: expected ' .
123
                var_export($serviceTicket['service'], true) .
124
                ' but was: ' . var_export($service, true);
125
            $failed = true;
126
        } elseif ($forceAuthn && isset($serviceTicket['forceAuthn']) && $serviceTicket['forceAuthn']) {
127
            $message = 'Ticket was issued from single sign on session';
128
            $failed = true;
129
        }
130
131
        if ($failed) {
132
            Logger::error('casserver:validate: ' . $message, true);
0 ignored issues
show
Unused Code introduced by
The call to SimpleSAML\Logger::error() has too many arguments starting with true. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

132
            Logger::/** @scrutinizer ignore-call */ 
133
                    error('casserver:validate: ' . $message, true);

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
133
            return new Response(
134
                $this->cas10Protocol->getValidateFailureResponse(),
135
                Response::HTTP_BAD_REQUEST,
136
            );
137
        }
138
139
        // Get the username field
140
        $usernameField = $this->casConfig->getOptionalValue('attrname', 'eduPersonPrincipalName');
141
142
        // Fail if the username field is not present in the attribute list
143
        if (!\array_key_exists($usernameField, $serviceTicket['attributes'])) {
144
            Logger::error(
145
                'casserver:validate: internal server error. Missing user name attribute: '
146
                . var_export($usernameField, true),
147
            );
148
        }
149
150
        // Successful validation
151
        return new Response(
152
            $this->cas10Protocol->getValidateSuccessResponse($serviceTicket['attributes'][$usernameField][0]),
153
            Response::HTTP_OK,
154
        );
155
    }
156
}
157