InitiateSamlAuthenticationHandler::process()   B
last analyzed

Complexity

Conditions 8
Paths 6

Size

Total Lines 40
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
eloc 21
nc 6
nop 1
dl 0
loc 40
rs 8.4444
c 1
b 0
f 0
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\SamlBundle\Monolog\SamlAuthenticationLogger;
23
use Surfnet\StepupSelfService\SelfServiceBundle\Security\Authentication\AuthenticatedSessionStateHandler;
24
use Surfnet\StepupSelfService\SelfServiceBundle\Security\Authentication\SamlAuthenticationStateHandler;
25
use Surfnet\StepupSelfService\SelfServiceBundle\Security\Authentication\SamlInteractionProvider;
26
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
27
use Symfony\Component\Routing\RouterInterface;
28
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
29
30
class InitiateSamlAuthenticationHandler implements AuthenticationHandler
31
{
32
    /**
33
     * @var AuthenticationHandler|null
34
     */
35
    private $nextHandler;
36
37
    /**
38
     * @var TokenStorageInterface
39
     */
40
    private $tokenStorage;
41
42
    /**
43
     * @var AuthenticatedSessionStateHandler
44
     */
45
    private $authenticatedSession;
46
47
    /**
48
     * @var SamlAuthenticationStateHandler
49
     */
50
    private $samlAuthenticationStateHandler;
51
52
    /**
53
     * @var SamlInteractionProvider
54
     */
55
    private $samlInteractionProvider;
56
57
    /**
58
     * @var RouterInterface
59
     */
60
    private $router;
61
62
    /**
63
     * @var SamlAuthenticationLogger
64
     */
65
    private $authenticationLogger;
66
67
    /**
68
     * @var LoggerInterface
69
     */
70
    private $logger;
71
72
    public function __construct(
73
        TokenStorageInterface $tokenStorageInterface,
74
        AuthenticatedSessionStateHandler $authenticatedSession,
75
        SamlAuthenticationStateHandler $samlAuthenticationStateHandler,
76
        SamlInteractionProvider $samlInteractionProvider,
77
        RouterInterface $router,
78
        SamlAuthenticationLogger $authenticationLogger,
79
        LoggerInterface $logger
80
    ) {
81
        $this->tokenStorage                   = $tokenStorageInterface;
82
        $this->authenticatedSession           = $authenticatedSession;
83
        $this->samlAuthenticationStateHandler = $samlAuthenticationStateHandler;
84
        $this->samlInteractionProvider        = $samlInteractionProvider;
85
        $this->router                         = $router;
86
        $this->authenticationLogger           = $authenticationLogger;
87
        $this->logger                         = $logger;
88
    }
89
90
    public function process(GetResponseEvent $event)
91
    {
92
        $acsUri = $this->router->generate('selfservice_serviceprovider_consume_assertion');
93
94
        // we have no logged in user, and have sent an authentication request, but do not receive a response POSTed
95
        // back to our ACS. This means that a user may have inadvertedly triggered the sending of an AuthnRequest
96
        // one of the common causes of this is the prefetching of pages by browsers to give users the illusion of speed.
97
        // In any case, we reset the login and send a new AuthnRequest.
98
        if ($this->tokenStorage->getToken() === null
99
            && $this->samlInteractionProvider->isSamlAuthenticationInitiated()
100
            && $event->getRequest()->getMethod() !== 'POST'
101
            && $event->getRequest()->getRequestUri() !== $acsUri
102
        ) {
103
            $this->logger->notice(
104
                'No authenticated user, a AuthnRequest was sent, but the current request is not a POST to our ACS '
105
                . 'thus we assume the user attempts to access the application again (possibly after a browser '
106
                . 'prefetch). Resetting the login state so that a new AuthnRequest can be sent.'
107
            );
108
109
            $this->samlInteractionProvider->reset();
110
        }
111
112
        if ($this->tokenStorage->getToken() === null
113
            && !$this->samlInteractionProvider->isSamlAuthenticationInitiated()
114
        ) {
115
            $this->logger->notice('No authenticated user, no saml AuthnRequest pending, sending new AuthnRequest');
116
117
            $this->authenticatedSession->setCurrentRequestUri($event->getRequest()->getUri());
118
            $event->setResponse($this->samlInteractionProvider->initiateSamlRequest());
119
120
            $logger = $this->authenticationLogger->forAuthentication(
121
                $this->samlAuthenticationStateHandler->getRequestId()
122
            );
123
            $logger->notice('Sending AuthnRequest');
124
125
            return;
126
        }
127
128
        if ($this->nextHandler) {
129
            $this->nextHandler->process($event);
130
        }
131
    }
132
133
    public function setNext(AuthenticationHandler $handler)
134
    {
135
        $this->nextHandler = $handler;
136
    }
137
}
138