Passed
Pull Request — master (#8)
by Pol
08:41 queued 06:22
created

CasGuardAuthenticator::start()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 20
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3.009

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 12
c 1
b 0
f 0
nc 3
nop 2
dl 0
loc 20
ccs 9
cts 10
cp 0.9
crap 3.009
rs 9.8666
1
<?php
2
3
declare(strict_types=1);
4
5
namespace EcPhp\CasBundle\Security;
6
7
use EcPhp\CasBundle\Security\Core\User\CasUserProviderInterface;
8
use EcPhp\CasLib\CasInterface;
9
use EcPhp\CasLib\Introspection\Contract\ServiceValidate;
10
use EcPhp\CasLib\Introspection\Introspector;
11
use EcPhp\CasLib\Utils\Uri;
12
use InvalidArgumentException;
13
use Psr\Http\Message\ResponseInterface;
14
use Psr\Http\Message\ServerRequestInterface;
15
use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface;
16
use Symfony\Component\HttpFoundation\JsonResponse;
17
use Symfony\Component\HttpFoundation\RedirectResponse;
18
use Symfony\Component\HttpFoundation\Request;
19
use Symfony\Component\HttpFoundation\Response;
20
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
21
use Symfony\Component\Security\Core\Exception\AuthenticationException;
22
use Symfony\Component\Security\Core\User\UserInterface;
23
use Symfony\Component\Security\Core\User\UserProviderInterface;
24
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
25
use Symfony\Component\Security\Http\Logout\LogoutSuccessHandlerInterface;
26
27
class CasGuardAuthenticator extends AbstractGuardAuthenticator implements LogoutSuccessHandlerInterface
0 ignored issues
show
Deprecated Code introduced by
The interface Symfony\Component\Securi...SuccessHandlerInterface has been deprecated: since Symfony 5.1 ( Ignorable by Annotation )

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

27
class CasGuardAuthenticator extends AbstractGuardAuthenticator implements /** @scrutinizer ignore-deprecated */ LogoutSuccessHandlerInterface

This interface has been deprecated. The supplier of the interface has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the interface will be removed and what other interface to use instead.

Loading history...
28
{
29
    /**
30
     * The ecphp/cas-lib library.
31
     *
32
     * @var \EcPhp\CasLib\CasInterface
33
     */
34
    private $cas;
35
36
    /**
37
     * @var \Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface
38
     */
39
    private $httpMessageFactory;
40 11
41
    public function __construct(
42
        CasInterface $cas,
43
        HttpMessageFactoryInterface $httpMessageFactory
44 11
    ) {
45 11
        $this->cas = $cas;
46 11
        $this->httpMessageFactory = $httpMessageFactory;
47
    }
48
49
    /**
50
     * {@inheritdoc}
51 1
     */
52
    public function checkCredentials($credentials, UserInterface $user): bool
53
    {
54 1
        try {
55 1
            $introspect = Introspector::detect($credentials);
56 1
        } catch (InvalidArgumentException $exception) {
57
            throw new AuthenticationException($exception->getMessage());
58
        }
59 1
60 1
        if (false === ($introspect instanceof ServiceValidate)) {
61 1
            throw new AuthenticationException(
62
                'Failure in the returned response'
63
            );
64
        }
65 1
66
        return true;
67
    }
68
69
    /**
70
     * {@inheritdoc}
71
     */
72
    public function getCredentials(Request $request): ?ResponseInterface
73
    {
74
        $response = $this
75
            ->cas->withServerRequest($this->toPsr($request))
76
            ->requestTicketValidation();
77
78
        if (null === $response) {
79
            throw new AuthenticationException('Unable to authenticate the user with such service ticket.');
80
        }
81
82
        return $response;
83
    }
84
85
    /**
86
     * {@inheritdoc}
87 1
     */
88
    public function getUser($credentials, UserProviderInterface $userProvider): ?UserInterface
89 1
    {
90 1
        if (false === ($userProvider instanceof CasUserProviderInterface)) {
91
            throw new AuthenticationException('Unable to load the user through the given User Provider.');
92
        }
93
94 1
        try {
95 1
            $user = $userProvider->loadUserByResponse($credentials);
96 1
        } catch (AuthenticationException $exception) {
97
            throw $exception;
98
        }
99 1
100
        return $user;
101
    }
102
103
    /**
104
     * {@inheritdoc}
105 1
     */
106
    public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
107 1
    {
108
        $uri = $this->toPsr($request)->getUri();
109 1
110
        if (true === Uri::hasParams($uri, 'ticket')) {
111 1
            // Remove the ticket parameter.
112 1
            $uri = Uri::removeParams(
113 1
                $uri,
114
                'ticket'
115
            );
116
117 1
            // Add the renew parameter to force login again.
118
            $uri = Uri::withParam($uri, 'renew', 'true');
119 1
120
            return new RedirectResponse((string) $uri);
121
        }
122 1
123
        return null;
124
    }
125
126
    /**
127
     * {@inheritdoc}
128 1
     */
129
    public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $providerKey): Response
130 1
    {
131 1
        return new RedirectResponse(
132 1
            (string) Uri::removeParams(
133 1
                $this->toPsr($request)->getUri(),
134 1
                'ticket',
135
                'renew'
136
            )
137
        );
138
    }
139
140
    /**
141
     * {@inheritdoc}
142 1
     */
143
    public function onLogoutSuccess(Request $request): Response
144
    {
145 1
        $response = $this
146 1
            ->cas
147
            ->logout();
148 1
149
        if (null === $response) {
150
            throw new AuthenticationException('Unable to trigger the logout procedure');
151
        }
152 1
153
        return new RedirectResponse(
154 1
            $response
155
                ->getHeaderLine('location')
156
        );
157
    }
158
159
    /**
160
     * {@inheritdoc}
161 2
     */
162
    public function start(Request $request, ?AuthenticationException $authException = null): Response
163 2
    {
164 1
        if (true === $request->isXmlHttpRequest()) {
165 1
            return new JsonResponse(
166 1
                ['message' => 'Authentication required'],
167
                Response::HTTP_UNAUTHORIZED
168
            );
169
        }
170
171 1
        $response = $this
172 1
            ->cas
173
            ->login();
174 1
175
        if (null === $response) {
176
            throw new AuthenticationException('Unable to trigger the login procedure');
177
        }
178 1
179
        return new RedirectResponse(
180 1
            $response
181
                ->getHeaderLine('location')
182
        );
183
    }
184
185
    /**
186
     * {@inheritdoc}
187 2
     */
188
    public function supports(Request $request): bool
189
    {
190 2
        return $this
191 2
            ->cas
192 2
            ->withServerRequest($this->toPsr($request))
193
            ->supportAuthentication();
194
    }
195
196
    /**
197
     * {@inheritdoc}
198 1
     */
199
    public function supportsRememberMe(): bool
200 1
    {
201
        return false;
202
    }
203
204
    /**
205
     * Convert a Symfony request into a PSR Request.
206
     *
207
     * @param \Symfony\Component\HttpFoundation\Request $request
208
     *   The Symfony request.
209
     *
210
     * @return \Psr\Http\Message\ServerRequestInterface
211
     *   The PSR request.
212 4
     */
213
    private function toPsr(Request $request): ServerRequestInterface
214
    {
215
        // As we cannot decorate the Symfony Request object, we convert it into
216
        // a PSR Request so we can override the PSR HTTP Message factory if
217
        // needed.
218 4
        // See the reasons at https://github.com/ecphp/cas-lib/issues/5
219
        return $this->httpMessageFactory->createRequest($request);
220
    }
221
}
222