305 lines
10 KiB
PHP
305 lines
10 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace External\HannahBundle\SAP\Security;
|
|
|
|
use External\HannahBundle\SAP\Exception\SAPManyException;
|
|
use External\HannahBundle\SAP\MappingType;
|
|
use External\HannahBundle\SAP\Util\SAPClient;
|
|
use External\HannahBundle\SAP\Util\SAPUtil;
|
|
use External\HannahBundle\Util\Configuration;
|
|
use KupShop\KupShopBundle\Util\StringUtil;
|
|
use KupShop\UserBundle\Security\CustomAuthenticator;
|
|
use KupShop\UserBundle\Security\LegacyPasswordEncoder;
|
|
use Query\Operator;
|
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
|
use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException;
|
|
use Symfony\Component\Security\Core\Exception\AuthenticationException;
|
|
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
|
|
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\SecurityRequestAttributes;
|
|
use Symfony\Component\Security\Http\Util\TargetPathTrait;
|
|
use Symfony\Contracts\Service\Attribute\Required;
|
|
|
|
class SAPAuthenticator extends CustomAuthenticator
|
|
{
|
|
use TargetPathTrait;
|
|
|
|
#[Required]
|
|
public Configuration $configuration;
|
|
|
|
private SAPClient $client;
|
|
private SAPUtil $sapUtil;
|
|
private LegacyPasswordEncoder $passwordEncoder;
|
|
|
|
#[Required]
|
|
final public function setSAPClient(SAPClient $client): void
|
|
{
|
|
$this->client = $client;
|
|
}
|
|
|
|
#[Required]
|
|
final public function setSAPUtil(SAPUtil $sapUtil): void
|
|
{
|
|
$this->sapUtil = $sapUtil;
|
|
}
|
|
|
|
#[Required]
|
|
final public function setPasswordEncoder(LegacyPasswordEncoder $passwordEncoder): void
|
|
{
|
|
$this->passwordEncoder = $passwordEncoder;
|
|
}
|
|
|
|
public function authenticate(Request $request): Passport
|
|
{
|
|
$email = $request->get('login');
|
|
$password = $request->get('password');
|
|
if (($url = $request->get('url')) && $request->getSession()) {
|
|
$this->saveTargetPath($request->getSession(), 'main', $url);
|
|
}
|
|
|
|
if (empty($email) || empty($password)) {
|
|
throw new AuthenticationCredentialsNotFoundException();
|
|
}
|
|
|
|
try {
|
|
$email = mb_strtolower($email);
|
|
|
|
// nevalidni email ani nezkousim
|
|
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
|
throw new AuthenticationCredentialsNotFoundException();
|
|
}
|
|
|
|
$user = \User::createFromLogin($email);
|
|
$process = $user ? $this->configuration->getProcessByUser($user) : null;
|
|
|
|
$result = $this->client->customerValidate(
|
|
$email,
|
|
$this->passwordEncoder->encodePassword($password, ''),
|
|
$process
|
|
);
|
|
} catch (SAPManyException $e) {
|
|
if ($e->hasExceptionWithCode(['005', '020', '095', '148', '318'])) {
|
|
throw new AuthenticationCredentialsNotFoundException();
|
|
}
|
|
|
|
$this->sapUtil->getLogger()->log(
|
|
$e,
|
|
sprintf('Při příhlašování uživatele "%s" vznikla chyba: %s', $email, $e->getMessage())
|
|
);
|
|
|
|
// Nalezen více než jeden BP ... - chyba, kterou si musi OC opravit v SAPu
|
|
if ($e->hasExceptionWithCode(['018'])) {
|
|
throw new CustomUserMessageAuthenticationException(
|
|
translate('error_login_generic', 'oc')
|
|
);
|
|
}
|
|
|
|
throw $e;
|
|
}
|
|
|
|
$customer = $result->CustomerData;
|
|
if (empty($customer)) {
|
|
throw new AuthenticationCredentialsNotFoundException();
|
|
}
|
|
|
|
// check that user exists, or create new one
|
|
/** @var \User $user */
|
|
$user = sqlGetConnection()->transactional(function () use ($customer) {
|
|
if (!($userId = $this->sapUtil->getMapping(MappingType::USERS, $customer->CustomerId))) {
|
|
$userId = $this->createUser($customer);
|
|
$this->sapUtil->createMapping(MappingType::USERS, $customer->CustomerId, $userId);
|
|
}
|
|
|
|
return \User::createFromId($userId);
|
|
});
|
|
|
|
$this->sapUtil->updateUser($user, $customer);
|
|
|
|
if (!$this->passwordEncoder->isPasswordValid(trim($customer->PaswdData->PaswdHash ?? ''), $password, '')) {
|
|
throw new AuthenticationCredentialsNotFoundException();
|
|
}
|
|
|
|
return new SelfValidatingPassport(
|
|
new UserBadge($email),
|
|
[new RememberMeBadge()]
|
|
);
|
|
}
|
|
|
|
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
|
|
{
|
|
if ($request->getSession() && ($url = $this->getTargetPath($request->getSession(), 'main'))) {
|
|
$this->removeTargetPath($request->getSession(), 'main');
|
|
|
|
return new RedirectResponse($url);
|
|
}
|
|
|
|
return new RedirectResponse(
|
|
$request->headers->get('referer', '/')
|
|
);
|
|
}
|
|
|
|
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
|
|
{
|
|
// pass to next authenticator
|
|
if ($exception instanceof AuthenticationCredentialsNotFoundException) {
|
|
return null;
|
|
}
|
|
|
|
if ($request->hasSession()) {
|
|
$request->getSession()->set(SecurityRequestAttributes::AUTHENTICATION_ERROR, $exception);
|
|
}
|
|
|
|
$url = $this->getLoginUrl($request);
|
|
|
|
return new RedirectResponse($url);
|
|
}
|
|
|
|
public function supports(Request $request): bool
|
|
{
|
|
return $request->isMethod('POST')
|
|
&& StringUtil::startsWith($request->getPathInfo(), path('kupshop_user_login_login'));
|
|
}
|
|
|
|
private function createUser(\stdClass $data): int
|
|
{
|
|
// check if user exists
|
|
$userId = sqlQueryBuilder()
|
|
->select('id')
|
|
->from('users')
|
|
->where(Operator::equals(
|
|
[
|
|
'email' => $data->PersonalData->Email,
|
|
]
|
|
))->execute()->fetchColumn();
|
|
|
|
if ($userId) {
|
|
return (int) $userId;
|
|
}
|
|
|
|
$addressData = [
|
|
'name' => '',
|
|
'surname' => '',
|
|
'firm' => '',
|
|
'ico' => '',
|
|
'dic' => '',
|
|
'street' => '',
|
|
'city' => '',
|
|
'zip' => '',
|
|
'country' => '',
|
|
|
|
'delivery_name' => '',
|
|
'delivery_surname' => '',
|
|
'delivery_street' => '',
|
|
'delivery_city' => '',
|
|
'delivery_zip' => '',
|
|
'delivery_country' => '',
|
|
];
|
|
|
|
$addresses = $this->sapUtil->prepareSAPItems($data->AddressData);
|
|
foreach ($addresses as $address) {
|
|
foreach ($address as $key => $value) {
|
|
if ($address->AddressType === 'COMPANY') {
|
|
if (!in_array($key, ['Company', 'VatIdentNumber', 'CompRegNumber'])) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if ($field = $this->getAddressField($key)) {
|
|
$addressData[$this->getAddressPrefix($address->AddressType).$field] = $value;
|
|
}
|
|
}
|
|
}
|
|
|
|
return sqlGetConnection()->transactional(function () use ($data, $addressData) {
|
|
sqlQueryBuilder()
|
|
->insert('users')
|
|
->directValues(
|
|
array_merge(
|
|
[
|
|
'email' => $data->PersonalData->Email,
|
|
'phone' => $data->PersonalData->TelNo ?? '',
|
|
'passw' => $data->PaswdData->PaswdHash ?? '',
|
|
'date_reg' => (new \DateTime())->format('Y-m-d H:i:s'),
|
|
'custom_data' => json_encode(
|
|
[
|
|
'passwordInSap' => $data->PaswdData->PaswdHash ?? '',
|
|
'sap' => [
|
|
'discountIndex' => $data->PersonalData->DiscountIndex,
|
|
'cards' => [],
|
|
],
|
|
]
|
|
),
|
|
],
|
|
$addressData
|
|
)
|
|
)->execute();
|
|
|
|
return (int) sqlInsertId();
|
|
});
|
|
}
|
|
|
|
private function updatePriceLevelByDiscountIndex(\User $user, string $discountIndex): void
|
|
{
|
|
$priceLevelId = sqlQueryBuilder()
|
|
->select('id')
|
|
->from('price_levels')
|
|
->where(Operator::equals(['descr' => $discountIndex]))
|
|
->execute()->fetchColumn();
|
|
|
|
sqlGetConnection()->transactional(function () use ($user, $priceLevelId) {
|
|
sqlQueryBuilder()
|
|
->delete('users_dealer_price_level')
|
|
->where(Operator::equals(
|
|
[
|
|
'id_user' => $user->id,
|
|
]
|
|
))->execute();
|
|
|
|
if ($priceLevelId) {
|
|
sqlQueryBuilder()
|
|
->insert('users_dealer_price_level')
|
|
->directValues(
|
|
[
|
|
'id_user' => $user->id,
|
|
'id_price_level' => $priceLevelId,
|
|
]
|
|
)->execute();
|
|
}
|
|
});
|
|
}
|
|
|
|
private function getAddressPrefix(string $type): string
|
|
{
|
|
if ($type === 'SHIPPING') {
|
|
return 'delivery_';
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
private function getAddressField(string $key): ?string
|
|
{
|
|
$map = [
|
|
'FirstName' => 'name',
|
|
'LastName' => 'surname',
|
|
'Street' => 'street',
|
|
'City' => 'city',
|
|
'PostlCod' => 'zip',
|
|
'Country' => 'country',
|
|
'Company' => 'firm',
|
|
'VatIdentNumber' => 'ico',
|
|
'CompRegNumber' => 'dic',
|
|
];
|
|
|
|
return $map[$key] ?? null;
|
|
}
|
|
}
|