<?php
declare(strict_types=1);
namespace AppBundle\EventListener;
use CustomerManagementFrameworkBundle\CustomerProvider\CustomerProviderInterface;
use CustomerManagementFrameworkBundle\Model\CustomerInterface;
use CustomerManagementFrameworkBundle\CustomerSaveValidator\Exception\DuplicateCustomerException;
use CustomerManagementFrameworkBundle\Security\Authentication\LoginManagerInterface;
use CustomerManagementFrameworkBundle\Security\OAuth\OAuthRegistrationHandler;
use HWI\Bundle\OAuthBundle\Security\Core\Exception\AccountNotLinkedException;
use Pimcore\Logger;
use Pimcore\Model\DataObject\Customer;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Event\AuthenticationSuccessEvent;
use Symfony\Component\Security\Core\Exception\UserNotFoundException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Http\Event\LoginFailureEvent;
use Symfony\Contracts\EventDispatcher\Event;
class MyLorchAuthenticationListener
{
public function __construct(
protected OAuthRegistrationHandler $oAuthHandler,
protected CustomerProviderInterface $customerProvider,
protected LoginManagerInterface $loginManager,
protected RouterInterface $router
) {
}
public function onSuccess(Event $event): void
{
if ($event instanceof AuthenticationSuccessEvent) {
$user = $event->getAuthenticationToken()->getUser();
try {
if ($user !== null) {
$this->loginManager->login($user);
}
} catch (\Exception $e) {
Logger::error($e->getMessage());
}
}
}
public function onError(Event $event): void
{
if ($event instanceof LoginFailureEvent) {
$error = $event->getException();
$user = $event->getRequest()->getUser();
// OAuth handling - the OAuth authenticator is configured to return to the login page on errors
// (see failure_path configuration) - therefore we can fetch the last authentication error
// here. If the error is an AccountNotLinkedException (as thrown by our user provider) save the
// OAuth token to the session and redirect to registration with a special key which can be used
// to load the token to prepopulate the registration form with account data.
if ($error instanceof AccountNotLinkedException) {
$oAuthToken = $error->getToken();
$oAuthUserInfo = $this->oAuthHandler->loadUserInformation($oAuthToken);
if ($oAuthUserInfo !== null) {
$userData = $oAuthUserInfo->getData();
$customFields = !(empty($userData['customFields'])) ? $userData['customFields'] : [];
/** @var CustomerInterface|Customer $customer */
$customer = $this->customerProvider->create();
$customer->setCompany(!(empty($customFields['company'])) ? $customFields['company'] : null);
$customer->setLastname(!(empty($userData['family_name'])) ? $userData['family_name'] : null);
$customer->setFirstname(!(empty($userData['given_name'])) ? $userData['given_name'] : null);
$customer->setEmail(!(empty($userData['email'])) ? $userData['email'] : null);
$customer->setCity(!(empty($customFields['locality'])) ? $customFields['locality'] : null);
$customer->setStreet(!(empty($customFields['street_address'])) ? $customFields['street_address'] . (!(empty($customFields['house_number'])) ? ' ' . $customFields['house_number'] : null) : null);
$customer->setZip(!(empty($customFields['postal_code'])) ? $customFields['postal_code'] : null);
$customer->setCountryCode(!(empty($customFields['country'])) ? $customFields['country'] : null);
$customer->setActive(true);
$customer->save();
$this->oAuthHandler->connectSsoIdentity($customer, $oAuthUserInfo);
$response = $this->buildUserRedirect($user);
try {
$response = $this->buildUserRedirect($customer);
$this->loginManager->login($customer, $event->getRequest(), $event->getResponse());
} catch (DuplicateCustomerException $e) {
$errors[] = 'Customer already exists';
} catch (\Exception $e) {
$errors[] = $e->getMessage();
}
$event->setResponse($response);
}
}
}
}
private function buildUserRedirect(UserInterface $user = null): RedirectResponse
{
/** @var Customer $user */
if ($user !== null) {
$dateTime = new \Carbon\Carbon();
$user->setLastLogin($dateTime);
$user->save();
return $this->redirectToRoute('app_mylorch_index');
}
return $this->redirectToRoute('app_auth_login');
}
protected function redirectToRoute(string $route, array $parameters = [], int $status = 302): RedirectResponse
{
return $this->redirect($this->generateUrl($route, $parameters), $status);
}
protected function redirect(string $url, int $status = 302): RedirectResponse
{
return new RedirectResponse($url, $status);
}
protected function generateUrl(string $route, array $parameters = [], int $referenceType = UrlGeneratorInterface::ABSOLUTE_PATH): string
{
return $this->router->generate($route, $parameters, $referenceType);
}
}