Passed
Push — master ( 3edc20...833dc1 )
by Pol
11:24
created

CasGuardAuthenticator::supports()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 4
c 2
b 0
f 0
nc 1
nop 1
dl 0
loc 6
rs 10
1
<?php
2
3
/**
4
 * For the full copyright and license information, please view
5
 * the LICENSE file that was distributed with this source code.
6
 *
7
 * @see https://github.com/ecphp
8
 */
9
10
declare(strict_types=1);
11
12
namespace EcPhp\CasBundle\Security;
13
14
use EcPhp\CasBundle\Security\Core\User\CasUserProviderInterface;
15
use EcPhp\CasLib\CasInterface;
16
use EcPhp\CasLib\Introspection\Contract\ServiceValidate;
17
use EcPhp\CasLib\Utils\Uri;
18
use InvalidArgumentException;
19
use Psr\Http\Message\ResponseInterface;
20
use Psr\Http\Message\ServerRequestInterface;
21
use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface;
22
use Symfony\Component\HttpFoundation\JsonResponse;
23
use Symfony\Component\HttpFoundation\RedirectResponse;
24
use Symfony\Component\HttpFoundation\Request;
25
use Symfony\Component\HttpFoundation\Response;
26
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
27
use Symfony\Component\Security\Core\Exception\AuthenticationException;
28
use Symfony\Component\Security\Core\User\UserInterface;
29
use Symfony\Component\Security\Core\User\UserProviderInterface;
30
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
0 ignored issues
show
Bug introduced by
The type Symfony\Component\Securi...tractGuardAuthenticator was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

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