diff --git a/src/Application/Controller/Admin/d3webauthnadminlogin.php b/src/Application/Controller/Admin/d3webauthnadminlogin.php
new file mode 100755
index 0000000..f7b3096
--- /dev/null
+++ b/src/Application/Controller/Admin/d3webauthnadminlogin.php
@@ -0,0 +1,167 @@
+
+ * @link http://www.oxidmodule.com
+ */
+
+namespace D3\Webauthn\Application\Controller\Admin;
+
+use D3\Webauthn\Application\Model\Webauthn;
+use D3\Webauthn\Application\Model\WebauthnConf;
+use D3\Webauthn\Application\Model\WebauthnErrors;
+use D3\Webauthn\Modules\Application\Component\d3_webauthn_UserComponent;
+use D3\Webauthn\Modules\Application\Model\d3_User_Webauthn;
+use Exception;
+use OxidEsales\Eshop\Application\Controller\Admin\AdminController;
+use OxidEsales\Eshop\Application\Controller\Admin\LoginController;
+use OxidEsales\Eshop\Application\Controller\FrontendController;
+use OxidEsales\Eshop\Application\Model\User;
+use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
+use OxidEsales\Eshop\Core\Exception\DatabaseErrorException;
+use OxidEsales\Eshop\Core\Exception\StandardException;
+use OxidEsales\Eshop\Core\Registry;
+use OxidEsales\Eshop\Core\Utils;
+
+class d3webauthnadminlogin extends AdminController
+{
+ protected $_sThisTemplate = 'd3webauthnadminlogin.tpl';
+
+ protected function _authorize() // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore
+ {
+ return true;
+ }
+
+ /**
+ * @return null
+ * @throws DatabaseConnectionException
+ * @throws DatabaseErrorException
+ */
+ public function render()
+ {
+ if (Registry::getSession()->hasVariable(WebauthnConf::WEBAUTHN_SESSION_AUTH) ||
+ false == Registry::getSession()->hasVariable(WebauthnConf::WEBAUTHN_SESSION_CURRENTUSER)
+ ) {
+ $this->getUtils()->redirect('index.php?cl=admin_start');
+ if (false == defined('OXID_PHP_UNIT')) {
+ // @codeCoverageIgnoreStart
+ exit;
+ // @codeCoverageIgnoreEnd
+ }
+ }
+
+ $this->generateCredentialRequest();
+
+ //$this->addTplParam('navFormParams', Registry::getSession()->getVariable(WebauthnConf::WEBAUTHN_SESSION_NAVFORMPARAMS));
+
+ return parent::render();
+ }
+
+ /**
+ * @throws DatabaseConnectionException
+ * @throws DatabaseErrorException
+ */
+ public function generateCredentialRequest()
+ {
+ /** @var Webauthn $webauthn */
+ $webauthn = oxNew(Webauthn::class);
+ $publicKeyCredentialRequestOptions = $webauthn->getRequestOptions();
+ Registry::getSession()->setVariable(WebauthnConf::WEBAUTHN_LOGIN_OBJECT, $publicKeyCredentialRequestOptions);
+ $this->addTplParam('webauthn_publickey_login', $publicKeyCredentialRequestOptions);
+ $this->addTplParam('isAdmin', isAdmin());
+ }
+
+ public function assertAuthn()
+ {
+ /** @var d3_User_Webauthn $user */
+ $user = oxNew(User::class);
+
+ try {
+ if (strlen(Registry::getRequest()->getRequestEscapedParameter('error'))) {
+ $errors = oxNew(WebauthnErrors::class);
+ throw oxNew(
+ StandardException::class,
+ $errors->translateError(Registry::getRequest()->getRequestEscapedParameter('error'))
+ );
+ }
+
+ if (strlen(Registry::getRequest()->getRequestEscapedParameter('credential'))) {
+ $credential = Registry::getRequest()->getRequestEscapedParameter('credential');
+ $webAuthn = oxNew(Webauthn::class);
+ $webAuthn->assertAuthn($credential);
+ $user->load(Registry::getSession()->getVariable(WebauthnConf::WEBAUTHN_SESSION_CURRENTUSER));
+ Registry::getSession()->setVariable(WebauthnConf::WEBAUTHN_SESSION_AUTH, true);
+
+ /** @var d3_webauthn_UserComponent $userCmp */
+ $loginController = oxNew(LoginController::class);
+ return $loginController->checklogin();
+
+ //Registry::getSession()->setVariable(WebauthnConf::WEBAUTHN_SESSION_AUTH, true);
+ }
+
+ } catch (Exception $e) {
+ Registry::getUtilsView()->addErrorToDisplay($e->getMessage());
+
+ $user->logout();
+ $this->getUtils()->redirect('index.php?cl=login');
+ }
+ }
+
+ /**
+ * @return Utils
+ */
+ public function getUtils()
+ {
+ return Registry::getUtils();
+ }
+
+ public function getPreviousClass()
+ {
+ return Registry::getSession()->getVariable(WebauthnConf::WEBAUTHN_SESSION_CURRENTCLASS);
+ }
+
+ public function previousClassIsOrderStep()
+ {
+ $sClassKey = Registry::getSession()->getVariable(WebauthnConf::WEBAUTHN_SESSION_CURRENTCLASS);
+ $resolvedClass = Registry::getControllerClassNameResolver()->getClassNameById($sClassKey);
+ $resolvedClass = $resolvedClass ? $resolvedClass : 'start';
+
+ /** @var FrontendController $oController */
+ $oController = oxNew($resolvedClass);
+ return $oController->getIsOrderStep();
+ }
+
+ /**
+ * @return bool
+ */
+ public function getIsOrderStep()
+ {
+ return $this->previousClassIsOrderStep();
+ }
+
+ /**
+ * Returns Bread Crumb - you are here page1/page2/page3...
+ *
+ * @return array
+ */
+ public function getBreadCrumb()
+ {
+ $aPaths = [];
+ $aPath = [];
+ $iBaseLanguage = Registry::getLang()->getBaseLanguage();
+ $aPath['title'] = Registry::getLang()->translateString('D3_WEBAUTHN_BREADCRUMB', $iBaseLanguage, false);
+ $aPath['link'] = $this->getLink();
+
+ $aPaths[] = $aPath;
+
+ return $aPaths;
+ }
+}
\ No newline at end of file
diff --git a/src/Application/Controller/d3webauthnlogin.php b/src/Application/Controller/d3webauthnlogin.php
index 0cec098..06e8767 100755
--- a/src/Application/Controller/d3webauthnlogin.php
+++ b/src/Application/Controller/d3webauthnlogin.php
@@ -64,7 +64,6 @@ class d3webauthnlogin extends FrontendController
*/
public function generateCredentialRequest()
{
- $auth = Registry::getSession()->getSession()->getVariable(WebauthnConf::WEBAUTHN_SESSION_CURRENTUSER);
/** @var Webauthn $webauthn */
$webauthn = oxNew(Webauthn::class);
$publicKeyCredentialRequestOptions = $webauthn->getRequestOptions();
diff --git a/src/Application/Model/WebauthnConf.php b/src/Application/Model/WebauthnConf.php
index ced8ff3..4d6235a 100755
--- a/src/Application/Model/WebauthnConf.php
+++ b/src/Application/Model/WebauthnConf.php
@@ -20,6 +20,7 @@ class WebauthnConf
const WEBAUTHN_SESSION_AUTH = 'webauthn_auth'; // has valid webauthn, user is logged in completly
const WEBAUTHN_LOGIN_OBJECT = 'authnloginobject'; // webauthn register options, required for credential check
const WEBAUTHN_SESSION_CURRENTUSER = 'd3webauthnCurrentUser'; // oxid assigned to user from entered username
+ const WEBAUTHN_SESSION_LOGINUSER = 'd3webauthnLoginUser'; // username entered in login form
const WEBAUTHN_SESSION_CURRENTCLASS = 'd3webauthnCurrentClass'; // no usage
const WEBAUTHN_SESSION_NAVFORMPARAMS = 'd3webauthnNavFormParams'; // no usage
}
\ No newline at end of file
diff --git a/src/Application/views/admin/de/d3webauthn_lang.php b/src/Application/views/admin/de/d3webauthn_lang.php
index a2320ff..384a90d 100755
--- a/src/Application/views/admin/de/d3webauthn_lang.php
+++ b/src/Application/views/admin/de/d3webauthn_lang.php
@@ -32,7 +32,7 @@ $aLang = [
'D3_WEBAUTHN_REGISTEREDKEYS' => 'registrierte Schlüssel',
- 'D3_WEBAUTHN_ERR_UNSECURECONNECTION' => 'Die Verwendung von Sicherheitsschlüsseln ist nur bei gesicherten Verbindungen (https) möglich.',
+ 'D3_WEBAUTHN_ERR_UNSECURECONNECTION' => 'Die Verwendung von Sicherheitsschlüsseln ist nur bei gesicherten oder lokalen Verbindungen (https) möglich.',
'D3_WEBAUTHN_ERR_INVALIDSTATE' => 'Der Schlüssel vom Token kann nicht oder nicht mehr verwendet werden. Möglicherweise wurde dieser in Ihrem Konto schon einmal gespeichert.',
'D3_WEBAUTHN_ERR_NOTALLOWED' => 'Die Anfrage wurde vom Browser oder der Plattform nicht zugelassen. Möglicherweise fehlen Berechtigungen oder die Zeit ist abgelaufen.',
'D3_WEBAUTHN_ERR_ABORT' => 'Die Aktion wurde vom Browser oder der Plattform abgebrochen.',
diff --git a/src/Application/views/admin/en/d3webauthn_lang.php b/src/Application/views/admin/en/d3webauthn_lang.php
index e48ee59..0158e2f 100755
--- a/src/Application/views/admin/en/d3webauthn_lang.php
+++ b/src/Application/views/admin/en/d3webauthn_lang.php
@@ -32,7 +32,7 @@ $aLang = [
'D3_WEBAUTHN_REGISTEREDKEYS' => 'registered keys',
- 'D3_WEBAUTHN_ERR_UNSECURECONNECTION' => 'The use of security keys is only possible with secured connections (https).',
+ 'D3_WEBAUTHN_ERR_UNSECURECONNECTION' => 'The use of security keys is only possible with secured or local connections (https).',
'D3_WEBAUTHN_ERR_INVALIDSTATE' => 'The key from the token cannot be used or can no longer be used. It may have been stored in your account before.',
'D3_WEBAUTHN_ERR_NOTALLOWED' => 'The request was not allowed by the browser or the platform. Possibly permissions are missing or the time has expired.',
'D3_WEBAUTHN_ERR_ABORT' => 'The action was aborted by the browser or the platform.',
diff --git a/src/Application/views/admin/tpl/d3webauthnlogin.tpl b/src/Application/views/admin/tpl/d3webauthnlogin.tpl
new file mode 100644
index 0000000..cdc7d3d
--- /dev/null
+++ b/src/Application/views/admin/tpl/d3webauthnlogin.tpl
@@ -0,0 +1,56 @@
+
+
+
+ [{oxmultilang ident="LOGIN_TITLE"}]
+
+
+
+
+
+
+
+
+
+
+
+
+ [{include file="js_login.tpl"}]
+
+
+
+
+[{oxscript}]
+
+
+
+
diff --git a/src/Modules/Application/Component/d3_webauthn_UserComponent.php b/src/Modules/Application/Component/d3_webauthn_UserComponent.php
index 2874cb0..d00cd45 100755
--- a/src/Modules/Application/Component/d3_webauthn_UserComponent.php
+++ b/src/Modules/Application/Component/d3_webauthn_UserComponent.php
@@ -22,6 +22,7 @@ use D3\Webauthn\Application\Model\Exceptions\d3webauthnWrongAuthException;
use D3\Webauthn\Application\Model\Webauthn;
use D3\Webauthn\Modules\Application\Model\d3_User_Webauthn;
use Doctrine\DBAL\DBALException;
+use Doctrine\DBAL\Exception;
use Doctrine\DBAL\Query\QueryBuilder;
use OxidEsales\Eshop\Application\Model\User;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
@@ -30,6 +31,8 @@ use OxidEsales\Eshop\Core\Session;
use OxidEsales\Eshop\Core\UtilsView;
use OxidEsales\EshopCommunity\Internal\Container\ContainerFactory;
use OxidEsales\EshopCommunity\Internal\Framework\Database\QueryBuilderFactoryInterface;
+use Psr\Container\ContainerExceptionInterface;
+use Psr\Container\NotFoundExceptionInterface;
class d3_webauthn_UserComponent extends d3_webauthn_UserComponent_parent
{
@@ -41,26 +44,7 @@ class d3_webauthn_UserComponent extends d3_webauthn_UserComponent_parent
public function login_noredirect()
{
$lgn_user = Registry::getRequest()->getRequestParameter('lgn_usr');
- $user = oxNew(User::class);
-
- /** @var QueryBuilder $qb */
- $qb = ContainerFactory::getInstance()->getContainer()->get(QueryBuilderFactoryInterface::class)->create();
- $qb->select('oxid')
- ->from($user->getViewName())
- ->where(
- $qb->expr()->and(
- $qb->expr()->eq(
- 'oxusername',
- $qb->createNamedParameter($lgn_user)
- ),
- $qb->expr()->eq(
- 'oxshopid',
- $qb->createNamedParameter(Registry::getConfig()->getShopId())
- )
- )
- )->setMaxResults(1);
-
- $userId = $qb->execute()->fetchOne();
+ $userId = $this->d3GetLoginUserId($lgn_user);
if ($lgn_user && $userId) {
$webauthn = $this->d3GetWebauthnObject();
@@ -218,4 +202,39 @@ class d3_webauthn_UserComponent extends d3_webauthn_UserComponent_parent
{
return Registry::getSession();
}
+
+ /**
+ * @return string|null
+ * @throws \Doctrine\DBAL\Driver\Exception
+ * @throws Exception
+ * @throws ContainerExceptionInterface
+ * @throws NotFoundExceptionInterface
+ */
+ public function d3GetLoginUserId($username): ?string
+ {
+ if (empty($username)) {
+ return null;
+ }
+
+ $user = oxNew(User::class);
+
+ /** @var QueryBuilder $qb */
+ $qb = ContainerFactory::getInstance()->getContainer()->get(QueryBuilderFactoryInterface::class)->create();
+ $qb->select('oxid')
+ ->from($user->getViewName())
+ ->where(
+ $qb->expr()->and(
+ $qb->expr()->eq(
+ 'oxusername',
+ $qb->createNamedParameter($username)
+ ),
+ $qb->expr()->eq(
+ 'oxshopid',
+ $qb->createNamedParameter(Registry::getConfig()->getShopId())
+ )
+ )
+ )->setMaxResults(1);
+
+ return $qb->execute()->fetchOne();
+ }
}
\ No newline at end of file
diff --git a/src/Modules/Application/Controller/Admin/d3_LoginController_Webauthn.php b/src/Modules/Application/Controller/Admin/d3_LoginController_Webauthn.php
index 5e1b569..f09fe96 100755
--- a/src/Modules/Application/Controller/Admin/d3_LoginController_Webauthn.php
+++ b/src/Modules/Application/Controller/Admin/d3_LoginController_Webauthn.php
@@ -16,16 +16,24 @@
namespace D3\Webauthn\Modules\Application\Controller\Admin;
use D3\Webauthn\Application\Model\d3webauthn;
+use D3\Webauthn\Application\Model\Webauthn;
use D3\Webauthn\Application\Model\WebauthnConf;
use D3\Webauthn\Application\Model\Exceptions\d3WebauthnExceptionAbstract;
use D3\Webauthn\Application\Model\Exceptions\d3webauthnMissingPublicKeyCredentialRequestOptions;
use D3\Webauthn\Application\Model\Exceptions\d3webauthnWrongAuthException;
+use Doctrine\DBAL\Driver\Exception as DoctrineException;
+use Doctrine\DBAL\Exception;
+use Doctrine\DBAL\Query\QueryBuilder;
use OxidEsales\Eshop\Application\Model\User;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
use OxidEsales\Eshop\Core\Exception\DatabaseErrorException;
use OxidEsales\Eshop\Core\Registry;
use OxidEsales\Eshop\Core\Session;
use OxidEsales\Eshop\Core\UtilsView;
+use OxidEsales\EshopCommunity\Internal\Container\ContainerFactory;
+use OxidEsales\EshopCommunity\Internal\Framework\Database\QueryBuilderFactoryInterface;
+use Psr\Container\ContainerExceptionInterface;
+use Psr\Container\NotFoundExceptionInterface;
class d3_LoginController_Webauthn extends d3_LoginController_Webauthn_parent
{
@@ -56,11 +64,11 @@ class d3_LoginController_Webauthn extends d3_LoginController_Webauthn_parent
}
/**
- * @return d3webauthn
+ * @return Webauthn
*/
- public function d3GetWebauthnObject()
+ public function d3GetWebauthnObject(): Webauthn
{
- return oxNew(d3webauthn::class);
+ return oxNew(Webauthn::class);
}
/**
@@ -85,33 +93,81 @@ class d3_LoginController_Webauthn extends d3_LoginController_Webauthn_parent
*/
public function checklogin()
{
- //$sWebauth = Registry::getRequest()->getRequestEscapedParameter('keyauth');
- $sWebauth = base64_decode(Registry::getRequest()->getRequestParameter('keyauth'));
+ $lgn_user = Registry::getRequest()->getRequestParameter('user');
+ $userId = $this->d3GetLoginUserId($lgn_user);
- $webauthn = $this->d3GetWebauthnObject();
- $webauthn->loadByUserId(Registry::getSession()->getVariable("auth"));
+ if ($lgn_user && $userId && false === Registry::getSession()->hasVariable(WebauthnConf::WEBAUTHN_SESSION_AUTH)) {
+ $webauthn = $this->d3GetWebauthnObject();
- $return = 'login';
+ if ($webauthn->isActive($userId)
+ && false == Registry::getSession()->getVariable(WebauthnConf::WEBAUTHN_SESSION_AUTH)
+ ) {
+ Registry::getSession()->setVariable(
+ WebauthnConf::WEBAUTHN_SESSION_CURRENTCLASS,
+ $this->getClassKey() != 'd3webauthnadminlogin' ? $this->getClassKey() : 'admin_start');
+ Registry::getSession()->setVariable(WebauthnConf::WEBAUTHN_SESSION_CURRENTUSER, $userId);
+ Registry::getSession()->setVariable(WebauthnConf::WEBAUTHN_SESSION_LOGINUSER, $lgn_user);
- try {
- if ($this->isNoWebauthnOrNoLogin($webauthn)) {
- $return = parent::checklogin();
- } elseif ($this->hasValidWebauthn($sWebauth, $webauthn)) {
- $this->d3GetSession()->setVariable(WebauthnConf::WEBAUTHN_SESSION_AUTH, $sWebauth);
- $return = "admin_start";
+/*
+ Registry::getSession()->setVariable(
+ WebauthnConf::WEBAUTHN_SESSION_NAVFORMPARAMS,
+ $this->getViewConfig()->getNavFormParams()
+ );
+*/
+ //$oUser->d3templogout();
+
+ return "d3webauthnadminlogin";
}
- } catch (d3webauthnExceptionAbstract $oEx) {
- $this->d3GetUtilsView()->addErrorToDisplay($oEx);
}
- return $return;
+ return parent::checklogin();
+ }
+
+ /**
+ * @param $username
+ * @return string|null
+ * @throws DoctrineException
+ * @throws Exception
+ * @throws ContainerExceptionInterface
+ * @throws NotFoundExceptionInterface
+ */
+ protected function d3GetLoginUserId($username): ?string
+ {
+ if (empty($username)) {
+ return null;
+ }
+
+ $user = oxNew(User::class);
+
+ /** @var QueryBuilder $qb */
+ $qb = ContainerFactory::getInstance()->getContainer()->get(QueryBuilderFactoryInterface::class)->create();
+ $qb->select('oxid')
+ ->from($user->getViewName())
+ ->where(
+ $qb->expr()->and(
+ $qb->expr()->eq(
+ 'oxusername',
+ $qb->createNamedParameter($username)
+ ),
+ $qb->expr()->eq(
+ 'oxshopid',
+ $qb->createNamedParameter(Registry::getConfig()->getShopId())
+ ),
+ $qb->expr()->eq(
+ 'oxrights',
+ $qb->createNamedParameter('malladmin')
+ )
+ )
+ )->setMaxResults(1);
+
+ return $qb->execute()->fetchOne();
}
/**
* @param d3webauthn $webauthn
* @return bool
*/
- public function isNoWebauthnOrNoLogin($webauthn)
+ public function d3IsNoWebauthnOrNoLogin($webauthn)
{
return false == $this->d3GetSession()->getVariable("auth")
|| false == $webauthn->isActive();
diff --git a/src/Modules/Application/Model/d3_User_Webauthn.php b/src/Modules/Application/Model/d3_User_Webauthn.php
index 34ea7dc..0e942da 100755
--- a/src/Modules/Application/Model/d3_User_Webauthn.php
+++ b/src/Modules/Application/Model/d3_User_Webauthn.php
@@ -19,6 +19,7 @@ use D3\Webauthn\Application\Model\d3webauthn;
use D3\Webauthn\Application\Model\WebauthnConf;
use OxidEsales\Eshop\Core\Exception\StandardException;
use OxidEsales\Eshop\Core\Registry;
+use ReflectionClass;
use Webauthn\PublicKeyCredentialUserEntity;
class d3_User_Webauthn extends d3_User_Webauthn_parent
@@ -78,4 +79,27 @@ class d3_User_Webauthn extends d3_User_Webauthn_parent
throw oxNew(StandardException::class, 'can not create webauthn user entity from not loaded user');
}
+
+ public function login($userName, $password, $setSessionCookie = false)
+ {
+ if (Registry::getSession()->getVariable(WebauthnConf::WEBAUTHN_SESSION_AUTH)) {
+ $userName = $userName ?: Registry::getSession()->getVariable(WebauthnConf::WEBAUTHN_SESSION_LOGINUSER);
+ $config = Registry::getConfig();
+ $shopId = $config->getShopId();
+
+ /** private method is out of scope */
+ $class = new ReflectionClass($this);
+ $method = $class->getMethod('loadAuthenticatedUser');
+ $method->setAccessible(true);
+ $method->invokeArgs(
+ $this,
+ [
+ Registry::getSession()->getVariable(WebauthnConf::WEBAUTHN_SESSION_LOGINUSER),
+ $shopId
+ ]
+ );
+ }
+
+ return parent::login($userName, $password, $setSessionCookie);
+ }
}
\ No newline at end of file
diff --git a/src/metadata.php b/src/metadata.php
index 2940562..3baa2c1 100755
--- a/src/metadata.php
+++ b/src/metadata.php
@@ -20,6 +20,7 @@
// https://docs.solokeys.io/solo/
use D3\Webauthn\Application\Controller\Admin\d3user_webauthn;
+use D3\Webauthn\Application\Controller\Admin\d3webauthnadminlogin;
use D3\Webauthn\Application\Controller\d3_account_webauthn;
use D3\Webauthn\Application\Controller\d3webauthnlogin;
use D3\Webauthn\Modules\Application\Component\d3_webauthn_UserComponent;
@@ -66,7 +67,7 @@ $aModule = array(
'extend' => [
UserController::class => d3_webauthn_UserController::class,
PaymentController::class => d3_webauthn_PaymentController::class,
- OrderController::class => d3_webauthn_OrderController::class,
+ OrderController::class => d3_webauthn_OrderController::class,
OxidModel\User::class => d3_User_Webauthn::class,
StartController::class => d3_StartController_Webauthn::class,
LoginController::class => d3_LoginController_Webauthn::class,
@@ -76,11 +77,13 @@ $aModule = array(
'controllers' => [
'd3user_webauthn' => d3user_webauthn::class,
'd3webauthnlogin' => d3webauthnlogin::class,
+ 'd3webauthnadminlogin' => d3webauthnadminlogin::class,
'd3_account_webauthn' => d3_account_webauthn::class
],
'templates' => [
'd3user_webauthn.tpl' => 'd3/oxwebauthn/Application/views/admin/tpl/d3user_webauthn.tpl',
'd3webauthnlogin.tpl' => 'd3/oxwebauthn/Application/views/tpl/d3webauthnlogin.tpl',
+ 'd3webauthnadminlogin.tpl' => 'd3/oxwebauthn/Application/views/admin/tpl/d3webauthnlogin.tpl',
'd3_account_webauthn.tpl' => 'd3/oxwebauthn/Application/views/tpl/d3_account_webauthn.tpl',
'js_create.tpl' => 'd3/oxwebauthn/Application/views/tpl/inc/js_create.tpl',