2022-11-30 01:27:05 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/**
|
|
|
|
* For the full copyright and license information, please view the LICENSE
|
|
|
|
* file that was distributed with this source code.
|
|
|
|
*
|
|
|
|
* https://www.d3data.de
|
|
|
|
*
|
|
|
|
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
|
|
|
* @author D3 Data Development - Daniel Seifert <info@shopmodule.com>
|
|
|
|
* @link https://www.oxidmodule.com
|
|
|
|
*/
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
namespace D3\Webauthn\Application\Model;
|
|
|
|
|
2022-12-04 00:24:28 +01:00
|
|
|
use D3\TestingTools\Production\IsMockable;
|
2022-11-30 01:27:05 +01:00
|
|
|
use D3\Webauthn\Application\Model\Exceptions\WebauthnException;
|
|
|
|
use D3\Webauthn\Application\Model\Exceptions\WebauthnGetException;
|
|
|
|
use D3\Webauthn\Application\Model\Exceptions\WebauthnLoginErrorException;
|
|
|
|
use D3\Webauthn\Modules\Application\Model\d3_User_Webauthn;
|
|
|
|
use OxidEsales\Eshop\Application\Model\User;
|
|
|
|
use OxidEsales\Eshop\Core\Config;
|
|
|
|
use OxidEsales\Eshop\Core\Exception\CookieException;
|
|
|
|
use OxidEsales\Eshop\Core\Exception\UserException;
|
|
|
|
use OxidEsales\Eshop\Core\Session;
|
|
|
|
use OxidEsales\Eshop\Core\Str;
|
|
|
|
use OxidEsales\Eshop\Core\SystemEventHandler;
|
2022-12-04 00:24:28 +01:00
|
|
|
use OxidEsales\Eshop\Core\Utils;
|
2022-11-30 01:27:05 +01:00
|
|
|
use OxidEsales\Eshop\Core\UtilsServer;
|
2022-12-04 00:24:28 +01:00
|
|
|
use OxidEsales\Eshop\Core\UtilsView;
|
2022-11-30 01:27:05 +01:00
|
|
|
use OxidEsales\EshopCommunity\Application\Component\UserComponent;
|
|
|
|
|
|
|
|
class WebauthnLogin
|
|
|
|
{
|
2022-12-04 00:24:28 +01:00
|
|
|
use IsMockable;
|
2022-11-30 01:27:05 +01:00
|
|
|
|
|
|
|
public $credential;
|
|
|
|
|
|
|
|
public $errorMsg;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $credential
|
|
|
|
* @param string|null $error
|
|
|
|
* @throws WebauthnGetException
|
|
|
|
*/
|
|
|
|
public function __construct(string $credential, string $error = null)
|
|
|
|
{
|
|
|
|
$this->setCredential($credential);
|
|
|
|
$this->setErrorMsg($error);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return string
|
|
|
|
* @throws WebauthnGetException
|
|
|
|
*/
|
|
|
|
public function getCredential(): string
|
|
|
|
{
|
|
|
|
if (!strlen(trim((string) $this->credential))) {
|
|
|
|
/** @var WebauthnGetException $e */
|
|
|
|
$e = oxNew(WebauthnGetException::class, 'missing credential data');
|
|
|
|
throw $e;
|
|
|
|
}
|
|
|
|
|
|
|
|
return trim($this->credential);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $credential
|
|
|
|
* @throws WebauthnGetException
|
|
|
|
*/
|
|
|
|
public function setCredential(string $credential): void
|
|
|
|
{
|
|
|
|
if (!strlen(trim($credential))) {
|
|
|
|
/** @var WebauthnGetException $e */
|
|
|
|
$e = oxNew(WebauthnGetException::class, 'missing credential data');
|
|
|
|
throw $e;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->credential = trim($credential);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return ?string
|
|
|
|
*/
|
|
|
|
public function getErrorMsg(): ?string
|
|
|
|
{
|
|
|
|
return $this->errorMsg;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string|null $errorMsg
|
|
|
|
*/
|
|
|
|
public function setErrorMsg(?string $errorMsg): void
|
|
|
|
{
|
|
|
|
$this->errorMsg = $errorMsg;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param UserComponent $usrCmp
|
|
|
|
* @param bool $setSessionCookie
|
|
|
|
* @return void
|
|
|
|
* @throws WebauthnLoginErrorException
|
|
|
|
*/
|
|
|
|
public function frontendLogin(UserComponent $usrCmp, bool $setSessionCookie = false)
|
|
|
|
{
|
2022-12-04 00:24:28 +01:00
|
|
|
$myUtilsView = $this->d3GetMockableRegistryObject(UtilsView::class);
|
2022-11-30 01:27:05 +01:00
|
|
|
/** @var d3_User_Webauthn $user */
|
2022-12-04 00:24:28 +01:00
|
|
|
$user = $this->d3GetMockableOxNewObject(User::class);
|
2022-11-30 01:27:05 +01:00
|
|
|
$userId = $this->getUserId();
|
|
|
|
|
|
|
|
try {
|
|
|
|
$this->handleErrorMessage();
|
|
|
|
|
|
|
|
$user = $this->assertUser($userId);
|
|
|
|
$this->assertAuthn();
|
|
|
|
|
|
|
|
// relogin, don't extract from this try block
|
2022-12-04 00:24:28 +01:00
|
|
|
$usrCmp->setUser($this->d3GetMockableOxNewObject(User::class));
|
2022-11-30 01:27:05 +01:00
|
|
|
$this->setFrontendSession($user);
|
|
|
|
$usrCmp->setLoginStatus(USER_LOGIN_SUCCESS);
|
|
|
|
|
|
|
|
if ($setSessionCookie) {
|
|
|
|
$this->setSessionCookie($user);
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->regenerateSessionId();
|
|
|
|
|
|
|
|
$usrCmp->setUser($user);
|
|
|
|
|
|
|
|
return;
|
|
|
|
} catch (UserException $oEx) {
|
|
|
|
// for login component send exception text to a custom component (if defined)
|
|
|
|
$myUtilsView->addErrorToDisplay($oEx, false, true, '', false);
|
|
|
|
|
|
|
|
//return 'user';
|
2022-12-04 00:24:28 +01:00
|
|
|
} catch (CookieException $oEx) {
|
2022-11-30 01:27:05 +01:00
|
|
|
$myUtilsView->addErrorToDisplay($oEx);
|
|
|
|
|
|
|
|
//return 'user';
|
|
|
|
} catch (WebauthnException $e) {
|
|
|
|
$myUtilsView->addErrorToDisplay($e);
|
2022-12-04 00:24:28 +01:00
|
|
|
$this->d3GetMockableLogger()->error($e->getDetailedErrorMessage(), ['UserId' => $userId]);
|
|
|
|
$this->d3GetMockableLogger()->debug($e->getTraceAsString());
|
2022-11-30 01:27:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
$user->logout();
|
|
|
|
$exc = oxNew(WebauthnLoginErrorException::class);
|
|
|
|
throw $exc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $selectedProfile
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function adminLogin(string $selectedProfile): string
|
|
|
|
{
|
2022-12-04 00:24:28 +01:00
|
|
|
$myUtilsView = $this->d3GetMockableRegistryObject(UtilsView::class);
|
2022-11-30 01:27:05 +01:00
|
|
|
/** @var d3_User_Webauthn $user */
|
2022-12-04 00:24:28 +01:00
|
|
|
$user = $this->d3GetMockableOxNewObject(User::class);
|
2022-11-30 01:27:05 +01:00
|
|
|
$userId = $this->getUserId();
|
|
|
|
|
|
|
|
try {
|
|
|
|
$this->handleErrorMessage();
|
|
|
|
$this->assertUser($userId, true);
|
|
|
|
$this->handleBlockedUser($user);
|
|
|
|
$this->assertAuthn();
|
|
|
|
$session = $this->setAdminSession($userId);
|
|
|
|
$this->handleBackendCookie();
|
|
|
|
$this->handleBackendSubshopRights($user, $session);
|
|
|
|
|
2022-12-04 00:24:28 +01:00
|
|
|
$oEventHandler = $this->d3GetMockableOxNewObject(SystemEventHandler::class);
|
|
|
|
$oEventHandler->onAdminLogin();
|
2022-11-30 01:27:05 +01:00
|
|
|
|
2022-12-04 00:24:28 +01:00
|
|
|
$afterLogin = $this->d3GetMockableOxNewObject(WebauthnAfterLogin::class);
|
2022-11-30 01:27:05 +01:00
|
|
|
$afterLogin->setDisplayProfile();
|
|
|
|
$afterLogin->changeLanguage();
|
|
|
|
|
|
|
|
$this->regenerateSessionId();
|
|
|
|
$this->updateBasket();
|
|
|
|
|
|
|
|
return "admin_start";
|
|
|
|
} catch (UserException $oEx) {
|
|
|
|
$myUtilsView->addErrorToDisplay('LOGIN_ERROR');
|
|
|
|
} catch (CookieException $oEx) {
|
|
|
|
$myUtilsView->addErrorToDisplay('LOGIN_NO_COOKIE_SUPPORT');
|
|
|
|
} catch (WebauthnException $e) {
|
|
|
|
$myUtilsView->addErrorToDisplay($e);
|
2022-12-04 00:24:28 +01:00
|
|
|
$this->d3GetMockableLogger()->error($e->getDetailedErrorMessage(), ['UserId' => $userId]);
|
|
|
|
$this->d3GetMockableLogger()->debug($e->getTraceAsString());
|
2022-11-30 01:27:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
$user->logout();
|
|
|
|
$oStr = Str::getStr();
|
2022-12-04 00:24:28 +01:00
|
|
|
$this->d3GetMockableRegistryObject(Config::class)->getActiveView()
|
|
|
|
->addTplParam('user', $oStr->htmlspecialchars($userId));
|
|
|
|
$this->d3GetMockableRegistryObject(Config::class)->getActiveView()
|
|
|
|
->addTplParam('profile', $oStr->htmlspecialchars($selectedProfile));
|
2022-11-30 01:27:05 +01:00
|
|
|
|
|
|
|
return 'login';
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @throws WebauthnGetException
|
|
|
|
*/
|
|
|
|
public function handleErrorMessage()
|
|
|
|
{
|
|
|
|
$error = $this->getErrorMsg();
|
|
|
|
|
|
|
|
if (strlen((string)$error)) {
|
|
|
|
/** @var WebauthnGetException $e */
|
|
|
|
$e = oxNew(WebauthnGetException::class, $error);
|
|
|
|
throw $e;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @throws WebauthnGetException|WebauthnException
|
|
|
|
*/
|
|
|
|
public function assertAuthn(): void
|
|
|
|
{
|
|
|
|
$credential = $this->getCredential();
|
2022-12-04 00:24:28 +01:00
|
|
|
$webAuthn = $this->d3GetMockableOxNewObject(Webauthn::class);
|
2022-11-30 01:27:05 +01:00
|
|
|
$webAuthn->assertAuthn($credential);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param $userId
|
|
|
|
* @return Session
|
|
|
|
*/
|
|
|
|
public function setAdminSession($userId): Session
|
|
|
|
{
|
2022-12-04 00:24:28 +01:00
|
|
|
$session = $this->d3GetMockableRegistryObject(Session::class);
|
2022-11-30 01:27:05 +01:00
|
|
|
$adminProfiles = $session->getVariable("aAdminProfiles");
|
|
|
|
$session->initNewSession();
|
|
|
|
$session->setVariable("aAdminProfiles", $adminProfiles);
|
|
|
|
$session->setVariable(WebauthnConf::OXID_ADMIN_AUTH, $userId);
|
|
|
|
return $session;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param User $user
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function setSessionCookie(User $user)
|
|
|
|
{
|
2022-12-04 00:24:28 +01:00
|
|
|
if ($this->d3GetMockableRegistryObject(Config::class)->getConfigParam('blShowRememberMe')) {
|
|
|
|
$this->d3GetMockableRegistryObject(UtilsServer::class)->setUserCookie(
|
2022-11-30 01:27:05 +01:00
|
|
|
$user->getFieldData('oxusername'),
|
|
|
|
$user->getFieldData('oxpassword'),
|
2022-12-04 00:24:28 +01:00
|
|
|
$this->d3GetMockableRegistryObject(Config::class)->getShopId()
|
2022-11-30 01:27:05 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param $userId
|
|
|
|
* @param bool $isBackend
|
|
|
|
* @return User
|
|
|
|
* @throws UserException
|
|
|
|
*/
|
|
|
|
public function assertUser($userId, bool $isBackend = false): User
|
|
|
|
{
|
2022-12-04 00:24:28 +01:00
|
|
|
$user = $this->d3GetMockableOxNewObject(User::class);
|
2022-11-30 01:27:05 +01:00
|
|
|
$user->load($userId);
|
|
|
|
if (!$user->isLoaded() ||
|
|
|
|
($isBackend && $user->getFieldData('oxrights') === 'user')
|
|
|
|
) {
|
|
|
|
/** @var UserException $exc */
|
|
|
|
$exc = oxNew(UserException::class, 'ERROR_MESSAGE_USER_NOVALIDLOGIN');
|
|
|
|
throw $exc;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $user;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return void
|
|
|
|
* @throws CookieException
|
|
|
|
*/
|
|
|
|
public function handleBackendCookie(): void
|
|
|
|
{
|
2022-12-04 00:24:28 +01:00
|
|
|
$cookie = $this->d3GetMockableRegistryObject(UtilsServer::class)->getOxCookie();
|
2022-11-30 01:27:05 +01:00
|
|
|
if ($cookie === null) {
|
|
|
|
/** @var CookieException $exc */
|
|
|
|
$exc = oxNew(CookieException::class, 'ERROR_MESSAGE_COOKIE_NOCOOKIE');
|
|
|
|
throw $exc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param User $user
|
|
|
|
* @param Session $session
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function handleBackendSubshopRights(User $user, Session $session): void
|
|
|
|
{
|
|
|
|
$iSubshop = (int)$user->getFieldData('oxrights');
|
|
|
|
|
|
|
|
if ($iSubshop) {
|
|
|
|
$session->setVariable("shp", $iSubshop);
|
|
|
|
$session->setVariable('currentadminshop', $iSubshop);
|
2022-12-04 00:24:28 +01:00
|
|
|
$this->d3GetMockableRegistryObject(Config::class)->setShopId($iSubshop);
|
2022-11-30 01:27:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function regenerateSessionId(): void
|
|
|
|
{
|
2022-12-04 00:24:28 +01:00
|
|
|
$oSession = $this->d3GetMockableRegistryObject(Session::class);
|
2022-11-30 01:27:05 +01:00
|
|
|
if ($oSession->isSessionStarted()) {
|
|
|
|
$oSession->regenerateSessionId();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public function handleBlockedUser(User $user)
|
|
|
|
{
|
|
|
|
// this user is blocked, deny him
|
|
|
|
if ($user->inGroup('oxidblocked')) {
|
2022-12-04 00:24:28 +01:00
|
|
|
$sUrl = $this->d3GetMockableRegistryObject(Config::class)->getShopHomeUrl() .
|
|
|
|
'cl=content&tpl=user_blocked.tpl';
|
|
|
|
$this->d3GetMockableRegistryObject(Utils::class)->redirect($sUrl);
|
2022-11-30 01:27:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function updateBasket(): void
|
|
|
|
{
|
2022-12-04 00:24:28 +01:00
|
|
|
if ($oBasket = $this->d3GetMockableRegistryObject(Session::class)->getBasket()) {
|
2022-11-30 01:27:05 +01:00
|
|
|
$oBasket->onUpdate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
public function isAdmin(): bool
|
|
|
|
{
|
|
|
|
return isAdmin();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function getUserId(): string
|
|
|
|
{
|
|
|
|
return $this->isAdmin() ?
|
2022-12-04 00:24:28 +01:00
|
|
|
$this->d3GetMockableRegistryObject(Session::class)
|
|
|
|
->getVariable(WebauthnConf::WEBAUTHN_ADMIN_SESSION_CURRENTUSER) :
|
|
|
|
$this->d3GetMockableRegistryObject(Session::class)
|
|
|
|
->getVariable(WebauthnConf::WEBAUTHN_SESSION_CURRENTUSER);
|
2022-11-30 01:27:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param User $user
|
|
|
|
* @return void
|
|
|
|
* @throws WebauthnGetException
|
|
|
|
*/
|
|
|
|
public function setFrontendSession(User $user): void
|
|
|
|
{
|
2022-12-04 00:24:28 +01:00
|
|
|
$session = $this->d3GetMockableRegistryObject(Session::class);
|
|
|
|
$session->setVariable(WebauthnConf::WEBAUTHN_SESSION_AUTH, $this->getCredential());
|
|
|
|
$session->setVariable(WebauthnConf::OXID_FRONTEND_AUTH, $user->getId());
|
2022-11-30 01:27:05 +01:00
|
|
|
}
|
|
|
|
}
|