Passed
Push — 1.0 ( 18b7ea...393954 )
by Pol
10:11 queued 08:27
created

CasGuardAuthenticator::getCredentials()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

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