LogoutController::getSession()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
rs 10
nc 1
nop 0
cc 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace SimpleSAML\Module\casserver\Controller;
6
7
use RuntimeException;
8
use SimpleSAML\Auth\Simple;
9
use SimpleSAML\Configuration;
10
use SimpleSAML\HTTP\RunnableResponse;
11
use SimpleSAML\Logger;
12
use SimpleSAML\Module;
13
use SimpleSAML\Module\casserver\Cas\Factories\TicketFactory;
14
use SimpleSAML\Module\casserver\Cas\Ticket\TicketStore;
15
use SimpleSAML\Module\casserver\Controller\Traits\UrlTrait;
16
use SimpleSAML\Session;
17
use SimpleSAML\Utils;
18
use Symfony\Component\HttpFoundation\Request;
19
use Symfony\Component\HttpKernel\Attribute\AsController;
20
use Symfony\Component\HttpKernel\Attribute\MapQueryParameter;
21
22
#[AsController]
23
class LogoutController
24
{
25
    use UrlTrait;
26
27
    /** @var \SimpleSAML\Logger */
28
    protected Logger $logger;
29
30
    /** @var \SimpleSAML\Configuration */
31
    protected Configuration $casConfig;
32
33
    /** @var \SimpleSAML\Module\casserver\Cas\Factories\TicketFactory */
34
    protected TicketFactory $ticketFactory;
35
36
    /** @var \SimpleSAML\Auth\Simple */
37
    protected Simple $authSource;
38
39
    /** @var \SimpleSAML\Utils\HTTP */
40
    protected Utils\HTTP $httpUtils;
41
42
    /** @var \SimpleSAML\Module\casserver\Cas\Ticket\TicketStore */
43
    protected TicketStore $ticketStore;
44
45
46
    /**
47
     * @param \SimpleSAML\Configuration $sspConfig
48
     * @param \SimpleSAML\Configuration|null $casConfig
49
     * @param \SimpleSAML\Auth\Simple|null $source
50
     * @param \SimpleSAML\Utils\HTTP|null $httpUtils
51
     *
52
     * @throws \Exception
53
     */
54
    public function __construct(
55
        private readonly Configuration $sspConfig,
56
        // Facilitate testing
57
        ?Configuration $casConfig = null,
58
        ?Simple $source = null,
59
        ?Utils\HTTP $httpUtils = null,
60
    ) {
61
        // We are using this work around in order to bypass Symfony's autowiring for cas configuration. Since
62
        // the configuration class is the same, it loads the ssp configuration twice. Still, we need the constructor
63
        // argument in order to facilitate testin.
64
        $this->casConfig = ($casConfig === null || $casConfig === $sspConfig)
65
            ? Configuration::getConfig('module_casserver.php') : $casConfig;
66
        $this->authSource = $source ?? new Simple($this->casConfig->getValue('authsource'));
67
        $this->httpUtils = $httpUtils ?? new Utils\HTTP();
68
69
        /* Instantiate ticket factory */
70
        $this->ticketFactory = new TicketFactory($this->casConfig);
71
72
        /* Instantiate ticket store */
73
        $ticketStoreConfig = $this->casConfig->getOptionalValue(
74
            'ticketstore',
75
            ['class' => 'casserver:FileSystemTicketStore'],
76
        );
77
        $ticketStoreClass = Module::resolveClass($ticketStoreConfig['class'], 'Cas\Ticket');
78
        $this->ticketStore = new $ticketStoreClass($this->casConfig);
79
    }
80
81
    /**
82
     * @param \Symfony\Component\HttpFoundation\Request $request
83
     * @param string|null $url
84
     *
85
     * @return \SimpleSAML\HTTP\RunnableResponse
86
     */
87
    public function logout(
88
        Request $request,
89
        #[MapQueryParameter] ?string $url = null,
90
    ): RunnableResponse {
91
        if (!$this->casConfig->getOptionalValue('enable_logout', false)) {
92
            $this->handleExceptionThrown('Logout not allowed');
93
        }
94
95
        // Skip Logout Page configuration
96
        $skipLogoutPage = $this->casConfig->getOptionalValue('skip_logout_page', false);
97
98
        if ($skipLogoutPage && $url === null) {
99
            $this->handleExceptionThrown('Required URL query parameter [url] not provided. (CAS Server)');
100
        }
101
102
        // Construct the logout redirect url
103
        if ($skipLogoutPage) {
104
            $logoutRedirectUrl = $url;
105
            $params = [];
106
        } else {
107
            $logoutRedirectUrl = Module::getModuleURL('casserver/loggedOut');
108
            $params =  $url === null ? []
109
                : ['url' => $url];
110
        }
111
112
        // Delete the ticket from the session
113
        $session = $this->getSession();
114
        if ($session !== null) {
115
            $this->ticketStore->deleteTicket($session->getSessionId());
0 ignored issues
show
Bug introduced by
It seems like $session->getSessionId() can also be of type null; however, parameter $ticketId of SimpleSAML\Module\casser...etStore::deleteTicket() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

115
            $this->ticketStore->deleteTicket(/** @scrutinizer ignore-type */ $session->getSessionId());
Loading history...
116
        }
117
118
        // Redirect
119
        if (!$this->authSource->isAuthenticated()) {
120
            return new RunnableResponse([$this->httpUtils, 'redirectTrustedURL'], [$logoutRedirectUrl, $params]);
121
        }
122
123
        // Logout and redirect
124
        return new RunnableResponse(
125
            [$this->authSource, 'logout'],
126
            [$logoutRedirectUrl],
127
        );
128
    }
129
130
    /**
131
     * @return \SimpleSAML\Module\casserver\Cas\Ticket\TicketStore
132
     */
133
    public function getTicketStore(): TicketStore
134
    {
135
        return $this->ticketStore;
136
    }
137
138
    /**
139
     * @param string $message
140
     *
141
     * @return void
142
     */
143
    protected function handleExceptionThrown(string $message): void
144
    {
145
        Logger::debug('casserver:' . $message);
146
        throw new RuntimeException($message);
147
    }
148
149
    /**
150
     * Get the Session
151
     *
152
     * @return \SimpleSAML\Session|null
153
     */
154
    protected function getSession(): ?Session
155
    {
156
        return Session::getSession();
157
    }
158
}
159