extract assertAuth and login procedure to separate classes

This commit is contained in:
Daniel Seifert 2022-11-30 01:27:05 +01:00
parent dd9d9490b8
commit c7f48bf960
Signed by: DanielS
GPG Key ID: 6A513E13AEE66170
10 changed files with 1692 additions and 359 deletions

View File

@ -18,24 +18,20 @@ namespace D3\Webauthn\Application\Controller\Admin;
use D3\TestingTools\Production\IsMockable;
use D3\Webauthn\Application\Controller\Traits\helpersTrait;
use D3\Webauthn\Application\Model\Exceptions\WebauthnGetException;
use D3\Webauthn\Application\Model\Webauthn;
use D3\Webauthn\Application\Model\WebauthnAfterLogin;
use D3\Webauthn\Application\Model\WebauthnConf;
use D3\Webauthn\Application\Model\Exceptions\WebauthnException;
use D3\Webauthn\Modules\Application\Controller\Admin\d3_LoginController_Webauthn;
use D3\Webauthn\Modules\Application\Model\d3_User_Webauthn;
use D3\Webauthn\Application\Model\WebauthnLogin;
use Doctrine\DBAL\Driver\Exception as DoctrineDriverException;
use Doctrine\DBAL\Exception as DoctrineException;
use OxidEsales\Eshop\Application\Controller\Admin\AdminController;
use OxidEsales\Eshop\Application\Controller\Admin\LoginController;
use OxidEsales\Eshop\Application\Controller\FrontendController;
use OxidEsales\Eshop\Core\Exception\ConnectionException;
use OxidEsales\Eshop\Core\Exception\CookieException;
use OxidEsales\Eshop\Core\Exception\UserException;
use OxidEsales\Eshop\Core\Registry;
use OxidEsales\Eshop\Core\Request;
use OxidEsales\Eshop\Core\SystemEventHandler;
use OxidEsales\Eshop\Core\Utils;
use OxidEsales\Eshop\Core\UtilsServer;
use OxidEsales\Eshop\Core\UtilsView;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
@ -69,17 +65,15 @@ class d3webauthnadminlogin extends AdminController
$this->getUtils()->redirect('index.php?cl=login');
}
/** @var d3_LoginController_Webauthn $loginController */
$loginController = $this->d3WebauthnGetLoginController();
$loginController->d3WebauthnAfterLoginChangeLanguage();
$this->generateCredentialRequest();
$this->addTplParam('navFormParams', $this->d3GetSession()->getVariable(WebauthnConf::WEBAUTHN_SESSION_NAVFORMPARAMS));
$this->addTplParam('currentProfile', $this->d3GetSession()->getVariable(WebauthnConf::WEBAUTHN_ADMIN_PROFILE));
$this->d3GetSession()->deleteVariable(WebauthnConf::WEBAUTHN_ADMIN_PROFILE);
$this->addTplParam('currentChLanguage', $this->d3GetSession()->getVariable(WebauthnConf::WEBAUTHN_ADMIN_CHLANGUAGE));
$this->d3GetSession()->deleteVariable(WebauthnConf::WEBAUTHN_ADMIN_CHLANGUAGE);
$afterLogin = $this->d3WebauthnGetAfterLogin();
$afterLogin->changeLanguage();
return $this->d3CallMockableParent('render');
}
@ -95,7 +89,6 @@ class d3webauthnadminlogin extends AdminController
{
$userId = $this->d3GetSession()->getVariable(WebauthnConf::WEBAUTHN_ADMIN_SESSION_CURRENTUSER);
try {
/** @var Webauthn $webauthn */
$webauthn = $this->d3GetWebauthnObject();
$publicKeyCredentialRequestOptions = $webauthn->getRequestOptions($userId);
$this->d3GetSession()->setVariable(WebauthnConf::WEBAUTHN_ADMIN_LOGIN_OBJECT, $publicKeyCredentialRequestOptions);
@ -103,95 +96,41 @@ class d3webauthnadminlogin extends AdminController
$this->addTplParam('isAdmin', isAdmin());
} catch (WebauthnException $e) {
$this->d3GetSession()->setVariable(WebauthnConf::GLOBAL_SWITCH, true);
Registry::getUtilsView()->addErrorToDisplay($e);
$this->d3GetUtilsViewObject()->addErrorToDisplay($e);
$this->d3GetLoggerObject()->error($e->getDetailedErrorMessage(), ['UserId' => $userId]);
$this->d3GetLoggerObject()->debug($e->getTraceAsString());
$this->getUtils()->redirect('index.php?cl=login');
}
}
/**
* @param string $credential
* @param string|null $error
* @throws WebauthnGetException
* @return WebauthnLogin
*/
public function getWebauthnLoginObject(string $credential, ?string $error): WebauthnLogin
{
return oxNew(WebauthnLogin::class, $credential, $error);
}
/**
* @return string|null
*/
public function d3AssertAuthn(): ?string
{
$myUtilsView = $this->d3GetUtilsViewObject();
/** @var d3_User_Webauthn $user */
$user = $this->d3GetUserObject();
$userId = $this->d3GetSession()->getVariable(WebauthnConf::WEBAUTHN_ADMIN_SESSION_CURRENTUSER);
$selectedProfile = $this->d3WebAuthnGetRequest()->getRequestEscapedParameter('profile');
try {
$error = $this->d3WebAuthnGetRequest()->getRequestEscapedParameter('error');
if (strlen((string) $error)) {
/** @var WebauthnGetException $e */
$e = oxNew(WebauthnGetException::class, $error);
throw $e;
}
$credential = $this->d3WebAuthnGetRequest()->getRequestEscapedParameter('credential');
if (!strlen((string) $credential)) {
/** @var WebauthnGetException $e */
$e = oxNew(WebauthnGetException::class, 'missing credential data');
throw $e;
}
$webAuthn = $this->d3GetWebauthnObject();
$webAuthn->assertAuthn($credential);
$user->load($userId);
$session = $this->d3GetSession();
$adminProfiles = $session->getVariable("aAdminProfiles");
$session->initNewSession();
$session->setVariable("aAdminProfiles", $adminProfiles);
$session->setVariable(WebauthnConf::OXID_ADMIN_AUTH, $userId);
$cookie = $this->d3WebauthnGetUtilsServer()->getOxCookie();
if ($cookie === null) {
/** @var CookieException $exc */
$exc = oxNew(CookieException::class, 'ERROR_MESSAGE_COOKIE_NOCOOKIE');
throw $exc;
}
if ($user->getFieldData('oxrights') === 'user') {
/** @var UserException $exc */
$exc = oxNew(UserException::class, 'ERROR_MESSAGE_USER_NOVALIDLOGIN');
throw $exc;
}
$iSubshop = (int) $user->getFieldData('oxrights');
if ($iSubshop) {
$session->setVariable("shp", $iSubshop);
$session->setVariable('currentadminshop', $iSubshop);
Registry::getConfig()->setShopId($iSubshop);
}
//execute onAdminLogin() event
$oEvenHandler = $this->d3WebauthnGetEventHandler();
$oEvenHandler->onAdminLogin(Registry::getConfig()->getShopId());
/** @var d3_LoginController_Webauthn $loginController */
$loginController = $this->d3WebauthnGetLoginController();
$loginController->d3webauthnAfterLogin();
return "admin_start";
} catch (UserException $oEx) {
$myUtilsView->addErrorToDisplay('LOGIN_ERROR');
$oStr = getStr();
$this->addTplParam('user', $oStr->htmlspecialchars($userId));
$this->addTplParam('profile', $oStr->htmlspecialchars($selectedProfile));
} catch (CookieException $oEx) {
$myUtilsView->addErrorToDisplay('LOGIN_NO_COOKIE_SUPPORT');
$oStr = getStr();
$this->addTplParam('user', $oStr->htmlspecialchars($userId));
$this->addTplParam('profile', $oStr->htmlspecialchars($selectedProfile));
} catch (WebauthnException $e) {
$myUtilsView->addErrorToDisplay($e);
$this->d3GetLoggerObject()->error($e->getDetailedErrorMessage(), ['UserId' => $userId]);
$this->d3GetLoggerObject()->debug($e->getTraceAsString());
$user->logout();
$login = $this->getWebauthnLoginObject(
$this->d3WebAuthnGetRequest()->getRequestEscapedParameter('credential'),
$this->d3WebAuthnGetRequest()->getRequestEscapedParameter('error')
);
return $login->adminLogin(
$this->d3WebAuthnGetRequest()->getRequestEscapedParameter('profile')
);
} catch (WebauthnGetException $e) {
$this->d3GetUtilsViewObject()->addErrorToDisplay($e);
return 'login';
}
return 'login';
}
/**
@ -233,11 +172,11 @@ class d3webauthnadminlogin extends AdminController
}
/**
* @return mixed|LoginController
* @return WebauthnAfterLogin
*/
public function d3WebauthnGetLoginController()
public function d3WebauthnGetAfterLogin(): WebauthnAfterLogin
{
return oxNew(LoginController::class);
return oxNew(WebauthnAfterLogin::class);
}
/**

View File

@ -0,0 +1,22 @@
<?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\Exceptions;
use OxidEsales\Eshop\Core\Exception\StandardException;
class WebauthnLoginErrorException extends StandardException
{
}

View File

@ -0,0 +1,64 @@
<?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;
use OxidEsales\Eshop\Core\Registry;
class WebauthnAfterLogin
{
public function setDisplayProfile()
{
$sProfile = Registry::getRequest()->getRequestEscapedParameter('profile') ?:
Registry::getSession()->getVariable(WebauthnConf::WEBAUTHN_ADMIN_PROFILE);
Registry::getSession()->deleteVariable(WebauthnConf::WEBAUTHN_ADMIN_PROFILE);
$myUtilsServer = Registry::getUtilsServer();
if (isset($sProfile)) {
$aProfiles = Registry::getSession()->getVariable("aAdminProfiles");
if ($aProfiles && isset($aProfiles[$sProfile])) {
// setting cookie to store last locally used profile
$myUtilsServer->setOxCookie("oxidadminprofile", $sProfile . "@" . implode("@", $aProfiles[$sProfile]), time() + 31536000);
Registry::getSession()->setVariable("profile", $aProfiles[$sProfile]);
}
} else {
//deleting cookie info, as setting profile to default
$myUtilsServer->setOxCookie("oxidadminprofile", "", time() - 3600);
}
}
/**
* @return void
*/
public function changeLanguage()
{
$myUtilsServer = Registry::getUtilsServer();
// languages
$iLang = Registry::getRequest()->getRequestEscapedParameter('chlanguage') ?:
Registry::getSession()->getVariable(WebauthnConf::WEBAUTHN_ADMIN_CHLANGUAGE);
Registry::getSession()->deleteVariable(WebauthnConf::WEBAUTHN_ADMIN_CHLANGUAGE);
$aLanguages = Registry::getLang()->getAdminTplLanguageArray();
if (!isset($aLanguages[$iLang])) {
$iLang = key($aLanguages);
}
$myUtilsServer->setOxCookie("oxidadminlanguage", $aLanguages[$iLang]->abbr, time() + 31536000);
Registry::getLang()->setTplLanguage($iLang);
}
}

View File

@ -0,0 +1,395 @@
<?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;
use D3\Webauthn\Application\Controller\Traits\helpersTrait;
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\Registry;
use OxidEsales\Eshop\Core\Session;
use OxidEsales\Eshop\Core\Str;
use OxidEsales\Eshop\Core\SystemEventHandler;
use OxidEsales\Eshop\Core\UtilsServer;
use OxidEsales\EshopCommunity\Application\Component\UserComponent;
class WebauthnLogin
{
use helpersTrait;
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)
{
$myUtilsView = $this->d3GetUtilsViewObject();
/** @var d3_User_Webauthn $user */
$user = $this->d3GetUserObject();
$userId = $this->getUserId();
try {
$this->handleErrorMessage();
$user = $this->assertUser($userId);
$this->assertAuthn();
// relogin, don't extract from this try block
$usrCmp->setUser($this->d3GetUserObject());
$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';
} catch (\OxidEsales\Eshop\Core\Exception\CookieException $oEx) {
$myUtilsView->addErrorToDisplay($oEx);
//return 'user';
} catch (WebauthnException $e) {
$myUtilsView->addErrorToDisplay($e);
$this->d3GetLoggerObject()->error($e->getDetailedErrorMessage(), ['UserId' => $userId]);
$this->d3GetLoggerObject()->debug($e->getTraceAsString());
}
$user->logout();
$exc = oxNew(WebauthnLoginErrorException::class);
throw $exc;
}
/**
* @param string $selectedProfile
* @return string
*/
public function adminLogin(string $selectedProfile): string
{
$myUtilsView = $this->d3GetUtilsViewObject();
/** @var d3_User_Webauthn $user */
$user = $this->d3GetUserObject();
$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);
$oEvenHandler = $this->d3WebauthnGetEventHandler();
$oEvenHandler->onAdminLogin();
$afterLogin = $this->getAfterLogin();
$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);
$this->d3GetLoggerObject()->error($e->getDetailedErrorMessage(), ['UserId' => $userId]);
$this->d3GetLoggerObject()->debug($e->getTraceAsString());
}
$user->logout();
$oStr = Str::getStr();
$this->d3GetConfig()->getActiveView()->addTplParam('user', $oStr->htmlspecialchars($userId));
$this->d3GetConfig()->getActiveView()->addTplParam('profile', $oStr->htmlspecialchars($selectedProfile));
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();
$webAuthn = $this->d3GetWebauthnObject();
$webAuthn->assertAuthn($credential);
}
/**
* @param $userId
* @return Session
*/
public function setAdminSession($userId): Session
{
$session = $this->d3GetSession();
$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)
{
if ($this->d3GetConfig()->getConfigParam('blShowRememberMe')) {
$this->getUtilsServer()->setUserCookie(
$user->getFieldData('oxusername'),
$user->getFieldData('oxpassword'),
$this->d3GetConfig()->getShopId()
);
}
}
/**
* @param $userId
* @param bool $isBackend
* @return User
* @throws UserException
*/
public function assertUser($userId, bool $isBackend = false): User
{
$user = $this->d3GetUserObject();
$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
{
$cookie = $this->getUtilsServer()->getOxCookie();
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);
$this->d3GetConfig()->setShopId($iSubshop);
}
}
/**
* @return void
*/
public function regenerateSessionId(): void
{
$oSession = $this->d3GetSession();
if ($oSession->isSessionStarted()) {
$oSession->regenerateSessionId();
}
}
public function handleBlockedUser(User $user)
{
// this user is blocked, deny him
if ($user->inGroup('oxidblocked')) {
$sUrl = $this->d3GetConfig()->getShopHomeUrl() . 'cl=content&tpl=user_blocked.tpl';
$this->d3GetUtilsObject()->redirect($sUrl, true, 302);
}
}
/**
* @return void
*/
public function updateBasket(): void
{
if ($oBasket = $this->d3GetSession()->getBasket()) {
$oBasket->onUpdate();
}
}
/**
* @return SystemEventHandler
*/
public function d3WebauthnGetEventHandler(): SystemEventHandler
{
return oxNew(SystemEventHandler::class);
}
/**
* @return WebauthnAfterLogin
*/
public function getAfterLogin(): WebauthnAfterLogin
{
return oxNew(WebauthnAfterLogin::class);
}
/**
* @return bool
*/
public function isAdmin(): bool
{
return isAdmin();
}
/**
* @return string
*/
public function getUserId(): string
{
return $this->isAdmin() ?
$this->d3GetSession()->getVariable(WebauthnConf::WEBAUTHN_ADMIN_SESSION_CURRENTUSER) :
$this->d3GetSession()->getVariable(WebauthnConf::WEBAUTHN_SESSION_CURRENTUSER);
}
/**
* @return Config
*/
public function d3GetConfig(): Config
{
return Registry::getConfig();
}
/**
* @return UtilsServer
*/
public function getUtilsServer(): UtilsServer
{
return Registry::getUtilsServer();
}
/**
* @param User $user
* @return void
* @throws WebauthnGetException
*/
public function setFrontendSession(User $user): void
{
$this->d3GetSession()->setVariable(WebauthnConf::WEBAUTHN_SESSION_AUTH, $this->getCredential());
$this->d3GetSession()->setVariable(WebauthnConf::OXID_FRONTEND_AUTH, $user->getId());
}
}

View File

@ -25,7 +25,7 @@
[{$oViewConf->getHiddenSid()}]
<input type="hidden" name="fnc" value="d3CancelWebauthnlogin">
<input type="hidden" name="cl" value="[{$oView->getPreviousClass()}]">
<input type="hidden" name="cl" value="[{$oView->d3GetPreviousClass()}]">
[{$navFormParams}]
<button class="btn btn_cancel btn-outline-danger btn-sm" type="submit">

View File

@ -17,8 +17,10 @@ namespace D3\Webauthn\Modules\Application\Component;
use D3\Webauthn\Application\Model\Exceptions\WebauthnException;
use D3\Webauthn\Application\Model\Exceptions\WebauthnGetException;
use D3\Webauthn\Application\Model\Exceptions\WebauthnLoginErrorException;
use D3\Webauthn\Application\Model\WebauthnConf;
use D3\Webauthn\Application\Model\Webauthn;
use D3\Webauthn\Application\Model\WebauthnLogin;
use D3\Webauthn\Modules\Application\Model\d3_User_Webauthn;
use Doctrine\DBAL\Driver\Exception as DoctrineDriverException;
use Doctrine\DBAL\Exception;
@ -108,48 +110,27 @@ class d3_webauthn_UserComponent extends d3_webauthn_UserComponent_parent
*/
public function d3AssertAuthn(): void
{
/** @var d3_User_Webauthn $user */
$user = $this->d3WebauthnGetUserObject();
$userId = $this->d3WebauthnGetSession()->getVariable(WebauthnConf::WEBAUTHN_SESSION_CURRENTUSER);
try {
$error = $this->d3WebAuthnGetRequest()->getRequestEscapedParameter('error');
if (strlen((string) $error)) {
/** @var WebauthnGetException $e */
$e = oxNew(WebauthnGetException::class, $error);
throw $e;
}
$login = $this->getWebauthnLoginObject(
$this->d3WebAuthnGetRequest()->getRequestEscapedParameter('credential'),
$this->d3WebAuthnGetRequest()->getRequestEscapedParameter('error')
);
$login->frontendLogin($this, (bool)$this->d3WebAuthnGetRequest()->getRequestParameter('lgn_cook'));
$this->_afterLogin($this->getUser());
} catch (WebauthnGetException $e) {
Registry::getUtilsView()->addErrorToDisplay($e);
} catch (WebauthnLoginErrorException $e) {}
}
$credential = $this->d3WebAuthnGetRequest()->getRequestEscapedParameter('credential');
if (strlen((string) $credential)) {
$webAuthn = $this->d3GetWebauthnObject();
$webAuthn->assertAuthn($credential);
$user->load($userId);
// relogin, don't extract from this try block
$setSessionCookie = $this->d3WebAuthnGetRequest()->getRequestParameter('lgn_cook');
$this->d3WebauthnGetSession()->setVariable(WebauthnConf::WEBAUTHN_SESSION_AUTH, $credential);
$this->d3WebauthnGetSession()->setVariable(WebauthnConf::OXID_FRONTEND_AUTH, $user->getId());
$this->setUser(null);
$this->setLoginStatus(USER_LOGIN_SUCCESS);
// cookie must be set ?
if ($setSessionCookie && Registry::getConfig()->getConfigParam('blShowRememberMe')) {
Registry::getUtilsServer()->setUserCookie(
$user->oxuser__oxusername->value,
$user->oxuser__oxpassword->value,
Registry::getConfig()->getShopId()
);
}
$this->_afterLogin($user);
}
} catch (WebauthnException $e) {
$this->d3GetUtilsViewObject()->addErrorToDisplay($e);
$this->d3GetLoggerObject()->error($e->getDetailedErrorMessage(), ['UserId' => $userId]);
$this->d3GetLoggerObject()->debug($e->getTraceAsString());
$user->logout();
}
/**
* @param string $credential
* @param string|null $error
* @throws WebauthnGetException
* @return WebauthnLogin
*/
public function getWebauthnLoginObject(string $credential, ?string $error): WebauthnLogin
{
return oxNew(WebauthnLogin::class, $credential, $error);
}
/**

View File

@ -90,45 +90,6 @@ class d3_LoginController_Webauthn extends d3_LoginController_Webauthn_parent
return parent::checklogin();
}
public function d3webauthnAfterLogin()
{
$myUtilsServer = Registry::getUtilsServer();
$sProfile = Registry::getRequest()->getRequestEscapedParameter('profile');
// #533
if (isset($sProfile)) {
$aProfiles = Registry::getSession()->getVariable("aAdminProfiles");
if ($aProfiles && isset($aProfiles[$sProfile])) {
// setting cookie to store last locally used profile
$myUtilsServer->setOxCookie("oxidadminprofile", $sProfile . "@" . implode("@", $aProfiles[$sProfile]), time() + 31536000, "/");
Registry::getSession()->setVariable("profile", $aProfiles[$sProfile]);
Registry::getSession()->deleteVariable(WebauthnConf::WEBAUTHN_ADMIN_PROFILE);
}
} else {
//deleting cookie info, as setting profile to default
$myUtilsServer->setOxCookie("oxidadminprofile", "", time() - 3600, "/");
}
$this->d3WebauthnAfterLoginChangeLanguage();
Registry::getSession()->deleteVariable(WebauthnConf::WEBAUTHN_ADMIN_CHLANGUAGE);
}
public function d3WebauthnAfterLoginChangeLanguage()
{
$myUtilsServer = Registry::getUtilsServer();
// languages
$iLang = Registry::getRequest()->getRequestEscapedParameter('chlanguage') ?:
Registry::getSession()->getVariable(WebauthnConf::WEBAUTHN_ADMIN_CHLANGUAGE);
$aLanguages = Registry::getLang()->getAdminTplLanguageArray();
if (!isset($aLanguages[$iLang])) {
$iLang = key($aLanguages);
}
$myUtilsServer->setOxCookie("oxidadminlanguage", $aLanguages[$iLang]->abbr, time() + 31536000, "/");
Registry::getLang()->setTplLanguage($iLang);
}
/**
* @return void
*/

View File

@ -19,8 +19,11 @@ use D3\TestingTools\Development\CanAccessRestricted;
use D3\Webauthn\Application\Controller\Admin\d3webauthnadminlogin;
use D3\Webauthn\Application\Controller\d3webauthnlogin;
use D3\Webauthn\Application\Model\Exceptions\WebauthnException;
use D3\Webauthn\Application\Model\Exceptions\WebauthnGetException;
use D3\Webauthn\Application\Model\Webauthn;
use D3\Webauthn\Application\Model\WebauthnAfterLogin;
use D3\Webauthn\Application\Model\WebauthnConf;
use D3\Webauthn\Application\Model\WebauthnLogin;
use D3\Webauthn\tests\unit\Application\Controller\d3webauthnloginTest;
use OxidEsales\Eshop\Application\Controller\Admin\LoginController;
use OxidEsales\Eshop\Application\Model\User;
@ -73,12 +76,6 @@ class d3webauthnadminloginTest extends d3webauthnloginTest
*/
public function canRender($auth, $userFromLogin, $startRedirect, $redirectController)
{
/** @var LoginController|MockObject $loginControllerMock */
$loginControllerMock = $this->getMockBuilder(LoginController::class)
->onlyMethods(['d3WebauthnAfterLoginChangeLanguage'])
->getMock();
$loginControllerMock->expects($this->once())->method('d3WebauthnAfterLoginChangeLanguage')->willReturn(true);
/** @var Session|MockObject $sessionMock */
$sessionMock = $this->getMockBuilder(Session::class)
->onlyMethods(['hasVariable'])
@ -95,10 +92,16 @@ class d3webauthnadminloginTest extends d3webauthnloginTest
$utilsMock->expects($startRedirect ? $this->once() : $this->never())
->method('redirect')->with('index.php?cl='.$redirectController)->willReturn(true);
/** @var WebauthnAfterLogin|MockObject $afterLoginMock */
$afterLoginMock = $this->getMockBuilder(WebauthnAfterLogin::class)
->onlyMethods(['changeLanguage'])
->getMock();
$afterLoginMock->expects($this->once())->method('changeLanguage');
/** @var d3webauthnlogin|MockObject $sut */
$sut = $this->getMockBuilder($this->sutClassName)
->onlyMethods(['d3GetSession', 'getUtils', 'd3CallMockableParent',
'generateCredentialRequest', 'addTplParam', 'd3WebauthnGetLoginController'])
->onlyMethods(['d3GetSession', 'getUtils', 'd3CallMockableParent', 'd3WebauthnGetAfterLogin',
'generateCredentialRequest', 'addTplParam'])
->getMock();
$sut->method('d3GetSession')->willReturn($sessionMock);
$sut->method('getUtils')->willReturn($utilsMock);
@ -108,7 +111,7 @@ class d3webauthnadminloginTest extends d3webauthnloginTest
->method('generateCredentialRequest');
$sut->expects($startRedirect ? $this->any() : $this->atLeastOnce())
->method('addTplParam')->willReturn(true);
$sut->method('d3WebauthnGetLoginController')->willReturn($loginControllerMock);
$sut->method('d3WebauthnGetAfterLogin')->willReturn($afterLoginMock);
$this->assertSame(
'myTemplate.tpl',
@ -209,113 +212,32 @@ class d3webauthnadminloginTest extends d3webauthnloginTest
* @test
* @return void
* @throws ReflectionException
* @covers \D3\Webauthn\Application\Controller\Admin\d3webauthnadminlogin::d3WebauthnGetLoginController
*/
public function canGetLoginController()
{
$sut = oxNew(d3webauthnadminlogin::class);
$this->assertInstanceOf(
LoginController::class,
$this->callMethod(
$sut,
'd3WebauthnGetLoginController'
)
);
}
/**
* @test
* @param $error
* @param $credential
* @param $canAssert
* @param $return
* @param $showErrorMsg
* @return void
* @throws ReflectionException
* @dataProvider canAssertAuthnDataProvider
* @covers \D3\Webauthn\Application\Controller\Admin\d3webauthnadminlogin::d3AssertAuthn
*/
public function canAssertAuthn($error, $credential, $canAssert, $return, $showErrorMsg)
public function canAssertAuthn()
{
/** @var WebauthnLogin|MockObject $loginMock */
$loginMock = $this->getMockBuilder(WebauthnLogin::class)
->disableOriginalConstructor()
->onlyMethods(['adminLogin'])
->getMock();
$loginMock->expects($this->once())->method('adminLogin')->willReturn('expected');
/** @var Request|MockObject $requestMock */
$requestMock = $this->getMockBuilder(Request::class)
->onlyMethods(['getRequestEscapedParameter'])
->getMock();
$requestMock->method('getRequestEscapedParameter')->willReturnCallback(
function () use ($error, $credential) {
$args = func_get_args();
if ($args[0] === 'error')
return $error;
elseif ($args[0] === 'credential')
return $credential;
return null;
}
);
/** @var Webauthn|MockObject $webauthnMock */
$webauthnMock = $this->getMockBuilder(Webauthn::class)
->onlyMethods(['assertAuthn'])
->getMock();
if ($canAssert) {
$webauthnMock->expects($error || !$credential ? $this->never() : $this->once())->method('assertAuthn');
} else {
$webauthnMock->expects($error || !$credential ? $this->never() : $this->once())->method('assertAuthn')
->willThrowException(oxNew(WebauthnException::class));
}
/** @var Session|MockObject $sessionMock */
$sessionMock = $this->getMockBuilder(Session::class)
->onlyMethods(['initNewSession', 'setVariable'])
->getMock();
$sessionMock->expects($canAssert ? $this->once() : $this->never())->method('initNewSession');
$sessionMock->expects($canAssert ? $this->atLeast(2) : $this->never())->method('setVariable');
/** @var SystemEventHandler|MockObject $eventHandlerMock */
$eventHandlerMock = $this->getMockBuilder(SystemEventHandler::class)
->onlyMethods(['onAdminLogin'])
->getMock();
$eventHandlerMock->expects($canAssert ? $this->once() : $this->never())->method('onAdminLogin');
/** @var LoginController|MockObject $loginControllerMock */
$loginControllerMock = $this->getMockBuilder(LoginController::class)
->onlyMethods(['d3webauthnAfterLogin'])
->getMock();
$loginControllerMock->expects($canAssert ? $this->once() : $this->never())->method('d3webauthnAfterLogin');
/** @var UtilsView|MockObject $utilsViewMock */
$utilsViewMock = $this->getMockBuilder(UtilsView::class)
->onlyMethods(['addErrorToDisplay'])
->getMock();
$utilsViewMock->expects($showErrorMsg ? $this->once() : $this->never())->method('addErrorToDisplay');
/** @var UtilsServer|MockObject $utilsServerMock */
$utilsServerMock = $this->getMockBuilder(UtilsServer::class)
->onlyMethods(['getOxCookie'])
->getMock();
$utilsServerMock->method('getOxCookie')->willReturn('cookie');
/** @var LoggerInterface|MockObject $loggerMock */
$loggerMock = $this->getMockForAbstractClass(LoggerInterface::class, [], '', true, true, true, ['error', 'debug']);
$loggerMock->method('error')->willReturn(true);
$loggerMock->method('debug')->willReturn(true);
$requestMock->expects($this->exactly(3))->method('getRequestEscapedParameter')->willReturn('abc');
/** @var d3webauthnadminlogin|MockObject $sut */
$sut = $this->getMockBuilder(d3webauthnadminlogin::class)
->onlyMethods(['d3WebAuthnGetRequest', 'd3GetWebauthnObject', 'd3GetSession', 'd3WebauthnGetEventHandler',
'd3WebauthnGetLoginController', 'd3GetUtilsViewObject', 'd3GetLoggerObject', 'd3WebauthnGetUtilsServer'])
->onlyMethods(['getWebauthnLoginObject', 'd3WebAuthnGetRequest'])
->getMock();
$sut->method('getWebauthnLoginObject')->willReturn($loginMock);
$sut->method('d3WebAuthnGetRequest')->willReturn($requestMock);
$sut->method('d3GetWebauthnObject')->willReturn($webauthnMock);
$sut->method('d3GetSession')->willReturn($sessionMock);
$sut->method('d3WebauthnGetEventHandler')->willReturn($eventHandlerMock);
$sut->method('d3WebauthnGetLoginController')->willReturn($loginControllerMock);
$sut->method('d3GetUtilsViewObject')->willReturn($utilsViewMock);
$sut->method('d3GetLoggerObject')->willReturn($loggerMock);
$sut->method('d3WebauthnGetUtilsServer')->willReturn($utilsServerMock);
$this->assertSame(
$return,
'expected',
$this->callMethod(
$sut,
'd3AssertAuthn'
@ -323,112 +245,36 @@ class d3webauthnadminloginTest extends d3webauthnloginTest
);
}
/**
* @return array
*/
public function canAssertAuthnDataProvider(): array
{
return [
'has error' => ['errorFixture', null, false, 'login', true],
'missing credential' => [null, null, false, 'login', true],
'assertion failed' => [null, 'credential', false, 'login', true],
'assertion succ' => [null, 'credential', true, 'admin_start', false],
];
}
/**
* @test
* @param $return
* @param $showErrorMsg
* @param $cookie
* @return void
* @throws ReflectionException
* @dataProvider canAssertAuthnCookieSubshopDataProvider
* @covers \D3\Webauthn\Application\Controller\Admin\d3webauthnadminlogin::d3AssertAuthn
*/
public function canAssertAuthnCookieSubshop($return, $showErrorMsg, $cookie, $rights)
public function cannotAssertAuthn()
{
/** @var Request|MockObject $requestMock */
$requestMock = $this->getMockBuilder(Request::class)
->onlyMethods(['getRequestEscapedParameter'])
->getMock();
$requestMock->method('getRequestEscapedParameter')->willReturnCallback(
function () {
$args = func_get_args();
if ($args[0] === 'error')
return null;
elseif ($args[0] === 'credential')
return 'credential';
return null;
}
);
/** @var Webauthn|MockObject $webauthnMock */
$webauthnMock = $this->getMockBuilder(Webauthn::class)
->onlyMethods(['assertAuthn'])
->getMock();
$webauthnMock->expects($this->once())->method('assertAuthn');
/** @var Session|MockObject $sessionMock */
$sessionMock = $this->getMockBuilder(Session::class)
->onlyMethods(['initNewSession', 'setVariable'])
->getMock();
$sessionMock->expects($this->once())->method('initNewSession');
$sessionMock->expects($this->atLeast(is_int($rights) ? 4 : 2))->method('setVariable');
/** @var SystemEventHandler|MockObject $eventHandlerMock */
$eventHandlerMock = $this->getMockBuilder(SystemEventHandler::class)
->onlyMethods(['onAdminLogin'])
->getMock();
$eventHandlerMock->expects($cookie && $rights != 'user' ? $this->once() : $this->never())->method('onAdminLogin');
/** @var LoginController|MockObject $loginControllerMock */
$loginControllerMock = $this->getMockBuilder(LoginController::class)
->onlyMethods(['d3webauthnAfterLogin'])
->getMock();
$loginControllerMock->expects($cookie && $rights != 'user' ? $this->once() : $this->never())->method('d3webauthnAfterLogin');
/** @var UtilsView|MockObject $utilsViewMock */
$utilsViewMock = $this->getMockBuilder(UtilsView::class)
->onlyMethods(['addErrorToDisplay'])
->getMock();
$utilsViewMock->expects($showErrorMsg ? $this->once() : $this->never())->method('addErrorToDisplay');
$utilsViewMock->expects($this->once())->method('addErrorToDisplay');
/** @var UtilsServer|MockObject $utilsServerMock */
$utilsServerMock = $this->getMockBuilder(UtilsServer::class)
->onlyMethods(['getOxCookie'])
/** @var Request|MockObject $requestMock */
$requestMock = $this->getMockBuilder(Request::class)
->onlyMethods(['getRequestEscapedParameter'])
->getMock();
$utilsServerMock->method('getOxCookie')->willReturn($cookie);
/** @var LoggerInterface|MockObject $loggerMock */
$loggerMock = $this->getMockForAbstractClass(LoggerInterface::class, [], '', true, true, true, ['error', 'debug']);
$loggerMock->method('error')->willReturn(true);
$loggerMock->method('debug')->willReturn(true);
/** @var User|MockObject $userMock */
$userMock = $this->getMockBuilder(User::class)
->onlyMethods(['getFieldData'])
->getMock();
$userMock->method('getFieldData')->willReturn($rights);
$requestMock->expects($this->atLeast(2))->method('getRequestEscapedParameter')->willReturn('abc');
/** @var d3webauthnadminlogin|MockObject $sut */
$sut = $this->getMockBuilder(d3webauthnadminlogin::class)
->onlyMethods(['d3WebAuthnGetRequest', 'd3GetWebauthnObject', 'd3GetSession', 'd3WebauthnGetEventHandler',
'd3WebauthnGetLoginController', 'd3GetUtilsViewObject', 'd3GetLoggerObject', 'd3WebauthnGetUtilsServer',
'd3GetUserObject'])
->onlyMethods(['getWebauthnLoginObject', 'd3WebAuthnGetRequest', 'd3GetUtilsViewObject'])
->getMock();
$sut->method('getWebauthnLoginObject')->willThrowException(oxNew(WebauthnGetException::class));
$sut->method('d3WebAuthnGetRequest')->willReturn($requestMock);
$sut->method('d3GetWebauthnObject')->willReturn($webauthnMock);
$sut->method('d3GetSession')->willReturn($sessionMock);
$sut->method('d3WebauthnGetEventHandler')->willReturn($eventHandlerMock);
$sut->method('d3WebauthnGetLoginController')->willReturn($loginControllerMock);
$sut->method('d3GetUtilsViewObject')->willReturn($utilsViewMock);
$sut->method('d3GetLoggerObject')->willReturn($loggerMock);
$sut->method('d3WebauthnGetUtilsServer')->willReturn($utilsServerMock);
$sut->method('d3GetUserObject')->willReturn($userMock);
$this->assertSame(
$return,
'login',
$this->callMethod(
$sut,
'd3AssertAuthn'
@ -505,4 +351,43 @@ class d3webauthnadminloginTest extends d3webauthnloginTest
)
);
}
/**
* @test
* @return void
* @throws ReflectionException
* @covers \D3\Webauthn\Application\Controller\Admin\d3webauthnadminlogin::getWebauthnLoginObject
*/
public function canGetWebauthnLoginObject()
{
$sut = oxNew(d3webauthnadminlogin::class);
$this->assertInstanceOf(
WebauthnLogin::class,
$this->callMethod(
$sut,
'getWebauthnLoginObject',
['credential', 'error']
)
);
}
/**
* @test
* @return void
* @throws ReflectionException
* @covers \D3\Webauthn\Application\Controller\Admin\d3webauthnadminlogin::d3WebauthnGetAfterLogin
*/
public function canGetWebauthnAfterLoginObject()
{
$sut = oxNew(d3webauthnadminlogin::class);
$this->assertInstanceOf(
WebauthnAfterLogin::class,
$this->callMethod(
$sut,
'd3WebauthnGetAfterLogin'
)
);
}
}

View File

@ -11,6 +11,8 @@
* @link https://www.oxidmodule.com
*/
declare(strict_types=1);
namespace D3\Webauthn\tests\unit\Application\Controller;
use D3\TestingTools\Development\CanAccessRestricted;

File diff suppressed because it is too large Load Diff