-
Notifications
You must be signed in to change notification settings - Fork 39
/
Copy pathSaml2Authenticator.php
107 lines (90 loc) · 3.9 KB
/
Saml2Authenticator.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
<?php
declare(strict_types=1);
namespace App\Authenticator;
use App\Exception\SsoConsumerException;
use OneLogin\Saml2\Auth;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
use Symfony\Component\Security\Http\HttpUtils;
class Saml2Authenticator extends AbstractAuthenticator implements AuthenticationEntryPointInterface
{
public function __construct(
private readonly UserProviderInterface $userProvider,
private readonly HttpUtils $httpUtils,
private readonly string $checkPath,
private readonly Auth $auth,
private readonly string $returnTo,
private readonly \Psr\Log\LoggerInterface $logger,
) {
}
/**
* Called on every request to decide if this authenticator should be
* used for the request. Returning `false` will cause this authenticator
* to be skipped.
*/
public function supports(Request $request): bool|null
{
return $this->httpUtils->checkRequestPath($request, $this->checkPath);
}
public function authenticate(Request $request): Passport
{
$session = $request->getSession();
$authNRequestId = $session->get('AuthNRequestID', null);
$auth = $this->auth;
$auth->setStrict(false);
$auth->processResponse($authNRequestId);
$errors = $auth->getErrors();
if (! empty($errors)) {
throw new SsoConsumerException($auth);
}
$email = $auth->getNameId();
$emails = $auth->getAttribute('email');
if ($emails) {
$email = $emails[0];
}
$this->userProvider->loadUserByIdentifier($email); // Check user existence
return new SelfValidatingPassport(new UserBadge($email));
}
/** This is kept as example */
public function basicAuthenticate(Request $request): Passport
{
$data = \json_decode((string) $request->getContent(), true, 512, JSON_THROW_ON_ERROR);
$username = $data['username'];
$this->userProvider->loadUserByIdentifier($username);
return new SelfValidatingPassport(new UserBadge($username));
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): Response|null
{
// on success, let the request continue
return null;
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): Response|null
{
$data = [
// you may want to customize or obfuscate the message first
'message' => strtr($exception->getMessageKey(), $exception->getMessageData()),
];
return new JsonResponse($data, Response::HTTP_UNAUTHORIZED);
}
/** @inheritDoc */
public function start(Request $request, AuthenticationException|null $authException = null)
{
$session = $request->getSession();
$this->logger->debug('Starting auth');
$auth = $this->auth;
$url = $auth->login($this->returnTo, [], false, false, true);
$authNRequestId = $auth->getLastRequestID();
$session->set('AuthNRequestID', $authNRequestId);
$this->logger->debug("Need redirect to $url");
return new JsonResponse(['url' => $url], Response::HTTP_UNAUTHORIZED);
}
}