ExplicitSessionTimeoutHandler   A
last analyzed

Complexity

Total Complexity 9

Size/Duplication

Total Lines 112
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 41
dl 0
loc 112
rs 10
c 2
b 0
f 0
wmc 9

3 Methods

Rating   Name   Duplication   Size   Complexity  
A setNext() 0 3 1
A __construct() 0 16 1
B process() 0 47 7
1
<?php
2
3
/**
4
 * Copyright 2016 SURFnet bv
5
 *
6
 * Licensed under the Apache License, Version 2.0 (the "License");
7
 * you may not use this file except in compliance with the License.
8
 * You may obtain a copy of the License at
9
 *
10
 *     http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing, software
13
 * distributed under the License is distributed on an "AS IS" BASIS,
14
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 * See the License for the specific language governing permissions and
16
 * limitations under the License.
17
 */
18
19
namespace Surfnet\StepupSelfService\SelfServiceBundle\Security\Authentication\Handler;
20
21
use Psr\Log\LoggerInterface;
22
use Surfnet\StepupSelfService\SelfServiceBundle\Security\Authentication\AuthenticatedSessionStateHandler;
23
use Surfnet\StepupSelfService\SelfServiceBundle\Security\Authentication\Session\SessionLifetimeGuard;
24
use Symfony\Component\HttpFoundation\RedirectResponse;
25
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
26
use Symfony\Component\Routing\RouterInterface;
27
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
28
use Symfony\Component\Security\Http\Logout\CookieClearingLogoutHandler;
29
use Symfony\Component\Security\Http\Logout\SessionLogoutHandler;
30
31
/**
32
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
33
 */
34
class ExplicitSessionTimeoutHandler implements AuthenticationHandler
35
{
36
    /**
37
     * @var AuthenticationHandler|null
38
     */
39
    private $nextHandler;
40
41
    /**
42
     * @var TokenStorageInterface
43
     */
44
    private $tokenStorage;
45
46
    /**
47
     * @var SessionLifetimeGuard
48
     */
49
    private $sessionLifetimeGuard;
50
51
    /**
52
     * @var AuthenticatedSessionStateHandler
53
     */
54
    private $authenticatedSession;
55
56
    /**
57
     * @var SessionLogoutHandler
58
     */
59
    private $sessionLogoutHandler;
60
61
    /**
62
     * @var CookieClearingLogoutHandler
63
     */
64
    private $cookieClearingLogoutHandler;
65
66
    /**
67
     * @var RouterInterface
68
     */
69
    private $router;
70
    /**
71
     * @var LoggerInterface
72
     */
73
    private $logger;
74
75
    public function __construct(
76
        TokenStorageInterface $tokenStorageInterface,
77
        AuthenticatedSessionStateHandler $authenticatedSessionStateHandler,
78
        SessionLifetimeGuard $sessionLifetimeGuard,
79
        SessionLogoutHandler $sessionLogoutHandler,
80
        CookieClearingLogoutHandler $cookieClearingLogoutHandler,
81
        RouterInterface $router,
82
        LoggerInterface $logger
83
    ) {
84
        $this->tokenStorage                = $tokenStorageInterface;
85
        $this->authenticatedSession        = $authenticatedSessionStateHandler;
86
        $this->sessionLifetimeGuard        = $sessionLifetimeGuard;
87
        $this->sessionLogoutHandler        = $sessionLogoutHandler;
88
        $this->cookieClearingLogoutHandler = $cookieClearingLogoutHandler;
89
        $this->router                      = $router;
90
        $this->logger                      = $logger;
91
    }
92
93
    public function process(GetResponseEvent $event)
94
    {
95
        if ($this->tokenStorage->getToken() !== null
96
            && !$this->sessionLifetimeGuard->sessionLifetimeWithinLimits($this->authenticatedSession)
97
        ) {
98
            $invalidatedBy = [];
99
            if (!$this->sessionLifetimeGuard->sessionLifetimeWithinAbsoluteLimit($this->authenticatedSession)) {
100
                $invalidatedBy[] = 'absolute';
101
            }
102
103
            if (!$this->sessionLifetimeGuard->sessionLifetimeWithinRelativeLimit($this->authenticatedSession)) {
104
                $invalidatedBy[] = 'relative';
105
            }
106
107
            $this->logger->notice(sprintf(
108
                'Authenticated user found, but session was determined to be outside of the "%s" time limit. User will '
109
                . 'be logged out and redirected to session-expired page to attempt new login.',
110
                implode(' and ', $invalidatedBy)
111
            ));
112
113
114
            $token   = $this->tokenStorage->getToken();
115
            $request = $event->getRequest();
116
117
            // if the current request was not a GET request we cannot safely redirect to that page after login as it
118
            // may require a form resubmit for instance. Therefor, we redirect to the last GET request (either current
119
            // or previous).
120
            $afterLoginRedirectTo = $this->authenticatedSession->getCurrentRequestUri();
121
            if ($event->getRequest()->getMethod() === 'GET') {
122
                $afterLoginRedirectTo = $event->getRequest()->getRequestUri();
123
            }
124
125
            // log the user out using Symfony methodology, see the LogoutListener
126
            $event->setResponse(new RedirectResponse($this->router->generate('selfservice_security_session_expired')));
127
128
            $this->sessionLogoutHandler->logout($request, $event->getResponse(), $token);
129
            $this->cookieClearingLogoutHandler->logout($request, $event->getResponse(), $token);
130
            $this->tokenStorage->setToken(null);
131
132
            // the session is restarted after invalidation during the logout, so we can (re)store the last GET request
133
            $this->authenticatedSession->setCurrentRequestUri($afterLoginRedirectTo);
134
135
            return;
136
        }
137
138
        if ($this->nextHandler !== null) {
139
            $this->nextHandler->process($event);
140
        }
141
    }
142
143
    public function setNext(AuthenticationHandler $handler)
144
    {
145
        $this->nextHandler = $handler;
146
    }
147
}
148