Completed
Push — master ( 511440...d2e337 )
by
unknown
26s
created

TicketValidator::validateAndDeleteTicket()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 36
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 21
c 1
b 0
f 0
nc 6
nop 2
dl 0
loc 36
rs 8.9617
1
<?php
2
3
namespace SimpleSAML\Module\casserver\Cas;
4
5
use SimpleSAML\Configuration;
6
use SimpleSAML\Error\BadRequest;
7
use SimpleSAML\Logger;
8
use SimpleSAML\Module;
9
use SimpleSAML\Module\casserver\Cas\Ticket\TicketFactory;
10
use SimpleSAML\Module\casserver\Cas\Ticket\TicketStore;
11
12
class TicketValidator
13
{
14
    /** @var  Configuration */
15
    private $casconfig;
16
17
    /** @var TicketStore */
18
    private $ticketStore;
19
20
    /** @var  TicketFactory */
21
    private $ticketFactory;
22
23
    /**
24
     * The ticket id doesn't match a ticket
25
     */
26
    const INVALID_TICKET = 'INVALID_TICKET';
27
28
    /**
29
     * TicketValidator constructor.
30
     * @param Configuration $casconfig
31
     */
32
    public function __construct(Configuration $casconfig)
33
    {
34
        $this->casconfig = $casconfig;
35
        $ticketStoreConfig = $casconfig->getValue('ticketstore', ['class' => 'casserver:FileSystemTicketStore']);
36
        $ticketStoreClass = Module::resolveClass($ticketStoreConfig['class'], 'Cas_Ticket');
37
        /** @var TicketStore $ticketStore */
38
        /** @psalm-suppress InvalidStringClass */
39
        $this->ticketStore = new $ticketStoreClass($casconfig);
40
        $ticketFactoryClass = Module::resolveClass('casserver:TicketFactory', 'Cas_Ticket');
41
        /** @var $ticketFactory TicketFactory */
42
        /** @psalm-suppress InvalidStringClass */
43
        $this->ticketFactory = new $ticketFactoryClass($casconfig);
44
    }
45
46
    /**
47
     * @param string $ticket the ticket id to load validate
48
     * @param string $service the service that the ticket was issued to
49
     * @return string|array|null
50
     * @throws CasException Thrown if ticket doesn't exist, expired, service mismatch
51
     * @throws \InvalidArgumentException thrown if $ticket or $service parameter is missing
52
     */
53
    public function validateAndDeleteTicket($ticket, $service)
54
    {
55
        if (empty($ticket)) {
56
            throw new \InvalidArgumentException('Missing ticket parameter: [ticket]');
57
        }
58
        if (empty($service)) {
59
            throw new \InvalidArgumentException('Missing service parameter: [service]');
60
        }
61
62
        $serviceTicket = $this->ticketStore->getTicket($ticket);
63
        if ($serviceTicket == null) {
64
            $message = 'Ticket '.var_export($ticket, true).' not recognized';
65
            Logger::debug('casserver:'.$message);
66
            throw new CasException(CasException::INVALID_TICKET, $message);
67
        }
68
69
        // TODO: do proxy vs non proxy ticket check
70
        $this->ticketStore->deleteTicket($ticket);
71
72
        if ($this->ticketFactory->isExpired($serviceTicket)) {
73
            $message = 'Ticket '.var_export($ticket, true).' has expired';
74
            Logger::debug('casserver:'.$message);
75
            throw new CasException(CasException::INVALID_TICKET, $message);
76
        }
77
78
        if (self::sanitize($serviceTicket['service']) !== self::sanitize($service)) {
79
            $message = 'Mismatching service parameters: expected '.
80
                var_export($serviceTicket['service'], true).
81
                ' but was: '.var_export($service, true);
82
83
            Logger::debug('casserver:'.$message);
84
            throw new CasException(CasException::INVALID_SERVICE, $message);
85
        }
86
87
88
        return $serviceTicket;
89
    }
90
91
    public static function sanitize($parameter)
92
    {
93
        return preg_replace(
94
            '/;jsessionid=.*[^?].*$/',
95
            '',
96
            preg_replace('/;jsessionid=.*[?]/', '?', urldecode($parameter))
97
        );
98
    }
99
}
100