139 lines
4.9 KiB
PHP
139 lines
4.9 KiB
PHP
<?php
|
|
|
|
namespace App\Security;
|
|
|
|
use App\BusProNet\ApiClient;
|
|
use App\BusProNet\Exception\ApiClientException;
|
|
use App\BusProNet\Model\CrmAttributes;
|
|
use App\BusProNet\Model\PersonalData;
|
|
use App\Entity\User;
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
use Psr\Log\LoggerInterface;
|
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
|
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
|
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
|
|
use Symfony\Component\Security\Http\Authenticator\AbstractLoginFormAuthenticator;
|
|
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge;
|
|
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\RememberMeBadge;
|
|
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\Util\TargetPathTrait;
|
|
|
|
class BpnAuthenticator extends AbstractLoginFormAuthenticator implements AuthenticationEntryPointInterface
|
|
{
|
|
use TargetPathTrait;
|
|
|
|
public function __construct(
|
|
private readonly UrlGeneratorInterface $urlGenerator,
|
|
private readonly ApiClient $apiClient,
|
|
private readonly EntityManagerInterface $entityManager,
|
|
private readonly Crypt $crypt,
|
|
private readonly LoggerInterface $authLogger,
|
|
) {
|
|
}
|
|
|
|
protected function getLoginUrl(Request $request): string
|
|
{
|
|
return $this->urlGenerator->generate('app_login');
|
|
}
|
|
|
|
public function authenticate(Request $request): Passport
|
|
{
|
|
$email = trim($request->request->getString('_username'));
|
|
$passwordPlain = trim($request->request->getString('_password'));
|
|
|
|
// Very lame hashing applied here as required by BPN
|
|
$password = md5($passwordPlain);
|
|
|
|
try {
|
|
$response = $this->apiClient->getPersonalData($email, $password);
|
|
} catch (ApiClientException $e) {
|
|
throw new CustomUserMessageAuthenticationException($e->getMessage());
|
|
}
|
|
|
|
if (false === $response instanceof PersonalData) {
|
|
throw new CustomUserMessageAuthenticationException('Der Login ist fehlgeschlagen :(');
|
|
}
|
|
|
|
$csrfToken = $request->request->getString('_csrf_token');
|
|
|
|
return new SelfValidatingPassport(
|
|
new UserBadge($email, function () use ($email, $password, $response) {
|
|
return $this->createOrUpdateLocalUser($email, $password, $response->personId, $response->addressId);
|
|
}),
|
|
[
|
|
new CsrfTokenBadge('authenticate', $csrfToken),
|
|
]
|
|
);
|
|
}
|
|
|
|
private function createOrUpdateLocalUser(string $email, string $password, ?int $personId, ?int $addressId): User
|
|
{
|
|
try {
|
|
$crmAttributes = $this->apiClient->getCrmAttributes($email, $password);
|
|
} catch (ApiClientException $e) {
|
|
throw new CustomUserMessageAuthenticationException($e->getMessage());
|
|
}
|
|
|
|
$roles = $this->collectRoles($crmAttributes);
|
|
$encryptedPassword = $this->crypt->encrypt($password);
|
|
|
|
$userRepository = $this->entityManager->getRepository(User::class);
|
|
|
|
if (null === $user = $userRepository->findOneBy(['email' => $email])) {
|
|
$user = new User($email);
|
|
$this->entityManager->persist($user);
|
|
}
|
|
|
|
$user
|
|
->setPassword($encryptedPassword)
|
|
->setPersonId($personId)
|
|
->setAddressId($addressId)
|
|
->setRoles($roles)
|
|
->setLastLoginAt(new \DateTimeImmutable())
|
|
;
|
|
|
|
$this->entityManager->flush();
|
|
|
|
return $user;
|
|
}
|
|
|
|
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
|
|
{
|
|
$this->authLogger->info('Login', [
|
|
'email' => $token->getUserIdentifier(),
|
|
]);
|
|
|
|
if ($targetPath = $this->getTargetPath($request->getSession(), $firewallName)) {
|
|
return new RedirectResponse($targetPath);
|
|
}
|
|
|
|
return new RedirectResponse($this->urlGenerator->generate('app_personal_data'));
|
|
}
|
|
|
|
private function collectRoles(CrmAttributes $crmAttributes): array
|
|
{
|
|
// Collect user's roles from CRM attributes
|
|
$roles = [];
|
|
|
|
if ($crmAttributes->admin) {
|
|
$roles[] = 'ROLE_ADMIN';
|
|
} elseif ($crmAttributes->manager) {
|
|
$roles[] = 'ROLE_MANAGER';
|
|
} elseif ($crmAttributes->houseManager) {
|
|
$roles[] = 'ROLE_HOUSE_MANAGER';
|
|
}
|
|
|
|
if ($crmAttributes->teamer) {
|
|
$roles[] = 'ROLE_TEAMER';
|
|
}
|
|
|
|
return $roles;
|
|
}
|
|
}
|