Passed
Pull Request — master (#45)
by
unknown
14:02
created

Cas10Controller::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 9
c 1
b 0
f 0
dl 0
loc 15
rs 9.9666
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\Module\casserver\Controller;
6
7
use Exception;
8
use Module\casserver\Cas\Factories;
0 ignored issues
show
Bug introduced by
The type Module\casserver\Cas\Factories was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

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

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