From d7e429709e6fc5b8005f9a5163ae0ce38bd1dfe3 Mon Sep 17 00:00:00 2001 From: Daniel Seifert Date: Tue, 25 Oct 2022 01:01:10 +0200 Subject: [PATCH] refactor to show existing registrations in admin --- .../Controller/Admin/d3user_webauthn.php | 19 +-- .../Controller/d3_account_webauthn.php | 12 +- .../Model/Credential/PublicKeyCredential.php | 140 ++++++++++++++++ .../Credential/PublicKeyCredentialList.php | 131 +++++++++++++++ .../d3MetadataStatementRepository.php | 29 ---- .../Credential/d3PublicKeyCredential.php | 153 ------------------ .../Credential/d3PublicKeyCredentialList.php | 53 ------ .../Webauthn/d3PublicKeyCredentialSource.php | 6 +- .../d3PublicKeyCredentialSourceRepository.php | 10 +- .../views/admin/tpl/d3user_webauthn.tpl | 7 +- .../d3_StartController_Webauthn.php | 13 +- src/Setup/Events.php | 2 +- src/metadata.php | 6 +- 13 files changed, 303 insertions(+), 278 deletions(-) create mode 100755 src/Application/Model/Credential/PublicKeyCredential.php create mode 100755 src/Application/Model/Credential/PublicKeyCredentialList.php delete mode 100755 src/Application/Model/Credential/d3MetadataStatementRepository.php delete mode 100755 src/Application/Model/Credential/d3PublicKeyCredential.php delete mode 100755 src/Application/Model/Credential/d3PublicKeyCredentialList.php diff --git a/src/Application/Controller/Admin/d3user_webauthn.php b/src/Application/Controller/Admin/d3user_webauthn.php index e604ac2..44b9388 100755 --- a/src/Application/Controller/Admin/d3user_webauthn.php +++ b/src/Application/Controller/Admin/d3user_webauthn.php @@ -15,9 +15,8 @@ namespace D3\Webauthn\Application\Controller\Admin; -use D3\Webauthn\Application\Model\Credential\d3PublicKeyCredentialList; +use D3\Webauthn\Application\Model\Credential\PublicKeyCredentialList; use D3\Webauthn\Application\Model\d3webauthn; -use D3\Webauthn\Application\Model\Webauthn\d3PublicKeyCredentialUserEntity; use D3\Webauthn\Modules\Application\Model\d3_User_Webauthn; use Exception; use OxidEsales\Eshop\Application\Controller\Admin\AdminDetailsController; @@ -59,7 +58,7 @@ class d3user_webauthn extends AdminDetailsController $this->addTplParam("sSaveError", $this->_sSaveError); } - $this->setAuthnRegister(); +// $this->setAuthnRegister(); return $this->_sThisTemplate; } @@ -79,23 +78,15 @@ class d3user_webauthn extends AdminDetailsController /** * @param $userId - * @return d3PublicKeyCredentialList|object - * @throws DatabaseConnectionException - * @throws DatabaseErrorException + * @return array */ public function getCredentialList($userId) { - $credentialList = oxNew(d3PublicKeyCredentialList::class); - $oUser = $this->getUserObject(); $oUser->load($userId); - if ($oUser && $oUser->getId()) { - /** @var d3PublicKeyCredentialUserEntity $userEntity */ - $userEntity = oxNew(d3PublicKeyCredentialUserEntity::class, $oUser); - $credentialList->loadAllForUserEntity($userEntity); - } - return $credentialList; + $publicKeyCrendetials = oxNew(PublicKeyCredentialList::class); + return $publicKeyCrendetials->getAllFromUser($oUser)->getArray(); } /** diff --git a/src/Application/Controller/d3_account_webauthn.php b/src/Application/Controller/d3_account_webauthn.php index 9ba9a9d..3c9d5d5 100755 --- a/src/Application/Controller/d3_account_webauthn.php +++ b/src/Application/Controller/d3_account_webauthn.php @@ -15,8 +15,8 @@ namespace D3\Webauthn\Application\Controller; -use D3\Webauthn\Application\Model\Credential\d3PublicKeyCredential; -use D3\Webauthn\Application\Model\Credential\d3PublicKeyCredentialList; +use D3\Webauthn\Application\Model\Credential\PublicKeyCredential; +use D3\Webauthn\Application\Model\Credential\PublicKeyCredentialList; use D3\Webauthn\Application\Model\d3webauthn; use D3\Webauthn\Application\Model\Webauthn\d3PublicKeyCredentialUserEntity; use OxidEsales\Eshop\Application\Controller\AccountController; @@ -50,19 +50,19 @@ dumpvar(Registry::getRequest()->getRequestEscapedParameter('error')); $this->addTplParam('user', $this->getUser()); - $this->setAuthnRegister(); + // $this->setAuthnRegister(); return $sRet; } /** - * @return d3PublicKeyCredentialList|object + * @return publicKeyCredentialList|object * @throws DatabaseConnectionException * @throws DatabaseErrorException */ public function getCredentialList() { - $credentialList = oxNew(d3PublicKeyCredentialList::class); + $credentialList = oxNew(PublicKeyCredentialList::class); $oUser = $this->getUser(); if ($oUser) { @@ -98,7 +98,7 @@ dumpvar(Registry::getRequest()->getRequestEscapedParameter('error')); public function deleteKey() { if (Registry::getRequest()->getRequestEscapedParameter('oxid')) { - $credential = oxNew(d3PublicKeyCredential::class); + $credential = oxNew(publicKeyCredential::class); $credential->delete(Registry::getRequest()->getRequestEscapedParameter('oxid')); } } diff --git a/src/Application/Model/Credential/PublicKeyCredential.php b/src/Application/Model/Credential/PublicKeyCredential.php new file mode 100755 index 0000000..5b89ade --- /dev/null +++ b/src/Application/Model/Credential/PublicKeyCredential.php @@ -0,0 +1,140 @@ + + * @link http://www.oxidmodule.com + */ + +namespace D3\Webauthn\Application\Model\Credential; + +use Doctrine\DBAL\Query\QueryBuilder; +use OxidEsales\Eshop\Core\Model\BaseModel; +use OxidEsales\Eshop\Core\Registry; +use OxidEsales\EshopCommunity\Internal\Container\ContainerFactory; +use OxidEsales\EshopCommunity\Internal\Framework\Database\QueryBuilderFactoryInterface; +use Webauthn\PublicKeyCredentialSource; + +class PublicKeyCredential extends BaseModel +{ + protected $_sCoreTable = 'd3wa_usercredentials'; + + public function __construct() + { + $this->init($this->getCoreTableName()); + + parent::__construct(); + } + +/* + public function setName($name) + { + $this->assign(['name' => $name]); + } + + public function getName() + { + return $this->getFieldData('name'); + } +*/ + public function setCredentialId($credentialId) + { + $this->assign([ + 'credentialid' => bin2hex($credentialId) + ]); + } + + public function getCredentialId() + { + return hex2bin($this->__get($this->_getFieldLongName('credentialid'))->rawValue); + } + + public function setUserId($userId) + { + $this->assign([ + 'oxuserid' => $userId + ]); + } + + public function getUserId() + { + return $this->__get($this->_getFieldLongName('oxuserid'))->rawValue; + } + + public function setCredential($credential) + { + $this->assign([ + 'credential' => bin2hex(serialize($credential)) + ]); + } + + public function getCredential() + { + return unserialize(hex2bin($this->__get($this->_getFieldLongName('credential'))->rawValue)); + } +/* + public function setPublicKey($publicKey) + { + $this->assign(['PublicKey' => $publicKey]); + } + + public function getPublicKey() + { + return $this->__get($this->_getFieldLongName('PublicKey'))->rawValue; + } + + /** + * @param PublicKeyCredentialSource $publicKeyCredentialSource + * @return void + * @throws \Exception + */ + public function saveCredentialSource(PublicKeyCredentialSource $publicKeyCredentialSource): void + { + // will save on every successfully assertion, set id to prevent duplicated database entries + $id = $this->getIdByCredentialId($publicKeyCredentialSource->getPublicKeyCredentialId()); + $this->setId($id); + + $this->setShopId(Registry::getConfig()->getShopId()); + $this->setUserId($publicKeyCredentialSource->getUserHandle()); + $this->setCredentialId($publicKeyCredentialSource->getPublicKeyCredentialId()); + $this->setCredential($publicKeyCredentialSource); + +// ToDo: required?? + $this->assign([ + 'pubkey_hex' => bin2hex($publicKeyCredentialSource->getCredentialPublicKey()), + ]); + $this->save(); + } + + public function getIdByCredentialId(string $publicKeyCredentialId): ?string + { + /** @var QueryBuilder $qb */ + $qb = ContainerFactory::getInstance()->getContainer()->get(QueryBuilderFactoryInterface::class)->create(); + $qb->select('oxid') + ->from($this->getViewName()) + ->where( + $qb->expr()->and( + $qb->expr()->eq( + 'credid_hex', + $qb->createNamedParameter(bin2hex($publicKeyCredentialId)) + ), + $qb->expr()->eq( + 'oxshopid', + $qb->createNamedParameter(Registry::getConfig()->getShopId()) + ) + ) + ); + $oxid = $qb->execute()->fetchOne(); + + return strlen($oxid) ? $oxid : null; + } +} \ No newline at end of file diff --git a/src/Application/Model/Credential/PublicKeyCredentialList.php b/src/Application/Model/Credential/PublicKeyCredentialList.php new file mode 100755 index 0000000..f967546 --- /dev/null +++ b/src/Application/Model/Credential/PublicKeyCredentialList.php @@ -0,0 +1,131 @@ + + * @link http://www.oxidmodule.com + */ + +namespace D3\Webauthn\Application\Model\Credential; + +use Doctrine\DBAL\Query\QueryBuilder; +use OxidEsales\Eshop\Application\Model\User; +use OxidEsales\Eshop\Core\Model\ListModel; +use OxidEsales\Eshop\Core\Registry; +use OxidEsales\EshopCommunity\Internal\Container\ContainerFactory; +use OxidEsales\EshopCommunity\Internal\Framework\Database\QueryBuilderFactoryInterface; +use phpDocumentor\Reflection\Types\This; +use Webauthn\PublicKeyCredentialSource; +use Webauthn\PublicKeyCredentialSourceRepository; +use Webauthn\PublicKeyCredentialUserEntity; + +class PublicKeyCredentialList extends ListModel implements PublicKeyCredentialSourceRepository +{ + protected $_sObjectsInListName = PublicKeyCredential::class; + + public function __construct() + { + parent::__construct(PublicKeyCredential::class); + } + + public function findOneByCredentialId(string $publicKeyCredentialId): ?PublicKeyCredentialSource + { + /** @var QueryBuilder $qb */ + $qb = ContainerFactory::getInstance()->getContainer()->get(QueryBuilderFactoryInterface::class)->create(); + $qb->select('credential') + ->from($this->getBaseObject()->getViewName()) + ->where( + $qb->expr()->and( + $qb->expr()->eq( + 'credid_hex', + $qb->createNamedParameter(bin2hex($publicKeyCredentialId)) + ), + $qb->expr()->eq( + 'oxshopid', + $qb->createNamedParameter(Registry::getConfig()->getShopId()) + ) + ) + ); + $credential = $qb->execute()->fetchOne(); + + if (!strlen($credential)) { + return null; + } + + $credential = unserialize(hex2bin($credential)); + + return $credential instanceof PublicKeyCredentialSource ? $credential : null; + } + + public function findAllForUserEntity(PublicKeyCredentialUserEntity $publicKeyCredentialUserEntity): array + { + /** @var QueryBuilder $qb */ + $qb = ContainerFactory::getInstance()->getContainer()->get(QueryBuilderFactoryInterface::class)->create(); + $qb->select('credential') + ->from($this->getBaseObject()->getViewName()) + ->where( + $qb->expr()->and( + $qb->expr()->eq( + 'oxuserid', + $qb->createNamedParameter($publicKeyCredentialUserEntity->getId()) + ), + $qb->expr()->eq( + 'oxshopid', + $qb->createNamedParameter(Registry::getConfig()->getShopId()) + ) + ) + ); + + // generate decoded credentials list + return array_map(function (array $fields) { + return unserialize(hex2bin($fields['credential'])); + }, $qb->execute()->fetchAllAssociative()); + } + + public function getAllFromUser(User $user) + { + if (!$user->isLoaded()) { + return $this; + } + + /** @var QueryBuilder $qb */ + $qb = ContainerFactory::getInstance()->getContainer()->get(QueryBuilderFactoryInterface::class)->create(); + $qb->select('oxid') + ->from($this->getBaseObject()->getViewName()) + ->where( + $qb->expr()->and( + $qb->expr()->eq( + 'oxuserid', + $qb->createNamedParameter($user->getId()) + ), + $qb->expr()->eq( + 'oxshopid', + $qb->createNamedParameter(Registry::getConfig()->getShopId()) + ) + ) + ); + + foreach ($qb->execute()->fetchAllAssociative() as $fields) { + $id = $fields['oxid']; + $credential = clone $this->getBaseObject(); + $credential->load($id); + $this->offsetSet($id, $credential); + } + + return $this; + } + + public function saveCredentialSource(PublicKeyCredentialSource $publicKeyCredentialSource): void + { + $this->getBaseObject()->saveCredentialSource($publicKeyCredentialSource); + } +} \ No newline at end of file diff --git a/src/Application/Model/Credential/d3MetadataStatementRepository.php b/src/Application/Model/Credential/d3MetadataStatementRepository.php deleted file mode 100755 index 68c12f4..0000000 --- a/src/Application/Model/Credential/d3MetadataStatementRepository.php +++ /dev/null @@ -1,29 +0,0 @@ - - * @link http://www.oxidmodule.com - */ - -namespace D3\Webauthn\Application\Model\Credential; - -use Webauthn\MetadataService\MetadataStatement; -use Webauthn\MetadataService\MetadataStatementRepository; - -class d3MetadataStatementRepository implements MetadataStatementRepository -{ - public function findOneByAAGUID(string $aaguid): ?MetadataStatement - { - return new MetadataStatement(); - } -} \ No newline at end of file diff --git a/src/Application/Model/Credential/d3PublicKeyCredential.php b/src/Application/Model/Credential/d3PublicKeyCredential.php deleted file mode 100755 index e715034..0000000 --- a/src/Application/Model/Credential/d3PublicKeyCredential.php +++ /dev/null @@ -1,153 +0,0 @@ - - * @link http://www.oxidmodule.com - */ - -namespace D3\Webauthn\Application\Model\Credential; - -use OxidEsales\Eshop\Core\DatabaseProvider; -use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException; -use OxidEsales\Eshop\Core\Model\BaseModel; -use OxidEsales\Eshop\Core\Registry; - -class d3PublicKeyCredential extends BaseModel -{ - protected $_sCoreTable = 'd3PublicKeyCredential'; - - public function __construct() - { - $this->init($this->getCoreTableName()); - - parent::__construct(); - } - - public function d3SetName($name) - { - $this->assign(['name' => $name]); - } - - public function d3GetName() - { - return $this->getFieldData('name'); - } - - public function d3SetCredentialId($credentialId) - { - $this->assign(['credentialid' => $credentialId]); - } - - public function d3GetCredentialId() - { - return $this->__get($this->_getFieldLongName('credentialid'))->rawValue; - } - - public function d3SetType($type) - { - $this->assign(['Type' => $type]); - } - - public function d3GetType() - { - return $this->getFieldData('Type'); - } - - public function d3SetTransports($transports) - { - $this->assign(['Transports' => base64_encode(serialize($transports))]); - } - - public function d3GetTransports() - { - return unserialize(base64_decode($this->getFieldData('Transports'))); - } - - public function d3SetAttestationType($attestationType) - { - $this->assign(['AttestationType' => $attestationType]); - } - - public function d3GetAttestationType() - { - return $this->getFieldData('AttestationType'); - } - - public function d3SetTrustPath($trustPath) - { - $this->assign(['TrustPath' => base64_encode(serialize($trustPath))]); - } - - public function d3GetTrustPath() - { - return unserialize(base64_decode($this->getFieldData('TrustPath'))); - } - - public function d3SetAaguid($aaguid) - { - $this->assign(['Aaguid' => base64_encode(serialize($aaguid))]); - } - - public function d3GetAaguid() - { - return unserialize(base64_decode($this->getFieldData('Aaguid'))); - } - - public function d3SetPublicKey($publicKey) - { - $this->assign(['PublicKey' => $publicKey]); - } - - public function d3GetPublicKey() - { - return $this->__get($this->_getFieldLongName('PublicKey'))->rawValue; - } - - public function d3SetUserHandle($userHandle) - { - $this->assign(['UserHandle' => $userHandle]); - } - - public function d3GetUserHandle() - { - return $this->getFieldData('UserHandle'); - } - - public function d3SetCounter($count) - { - $this->assign(['Counter' => $count]); - } - - public function d3GetCounter() - { - return $this->getFieldData('Counter'); - } - - /** - * @param string $publicKeyCredentialId - * @return |null - * @throws DatabaseConnectionException - */ - public function loadByCredentialId(string $publicKeyCredentialId) - { - if (Registry::getRequest()->getRequestEscapedParameter('fnc') == 'checkregister') { - return null; - } - - $oDb = DatabaseProvider::getDb(DatabaseProvider::FETCH_MODE_ASSOC); - $q = "SELECT oxid FROM ".$this->getViewName()." WHERE CredentialId = ".$oDb->quote($publicKeyCredentialId); - $id = $oDb->getOne($q); - $this->load($id); - } - -} \ No newline at end of file diff --git a/src/Application/Model/Credential/d3PublicKeyCredentialList.php b/src/Application/Model/Credential/d3PublicKeyCredentialList.php deleted file mode 100755 index cccfa09..0000000 --- a/src/Application/Model/Credential/d3PublicKeyCredentialList.php +++ /dev/null @@ -1,53 +0,0 @@ - - * @link http://www.oxidmodule.com - */ - -namespace D3\Webauthn\Application\Model\Credential; - -use OxidEsales\Eshop\Core\DatabaseProvider; -use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException; -use OxidEsales\Eshop\Core\Exception\DatabaseErrorException; -use OxidEsales\Eshop\Core\Model\ListModel; -use Webauthn\PublicKeyCredentialUserEntity; - -class d3PublicKeyCredentialList extends ListModel -{ - protected $_sObjectsInListName = d3PublicKeyCredential::class; - - public function __construct() - { - parent::__construct(d3PublicKeyCredential::class); - } - - /** - * @param PublicKeyCredentialUserEntity $publicKeyCredentialUserEntity - * @throws DatabaseConnectionException - * @throws DatabaseErrorException - */ - public function loadAllForUserEntity(PublicKeyCredentialUserEntity $publicKeyCredentialUserEntity) - { - $q = "SELECT oxid FROM ".$this->getBaseObject()->getViewName()." WHERE UserHandle = ".DatabaseProvider::getDb(DatabaseProvider::FETCH_MODE_ASSOC)->quote($publicKeyCredentialUserEntity->getId()); - $idList = DatabaseProvider::getDb(DatabaseProvider::FETCH_MODE_ASSOC)->getAll($q); - - if ($idList && is_iterable($idList)) { - foreach ($idList as $id) { - $credential = oxNew($this->_sObjectsInListName); - $credential->load($id['oxid']); - $this->offsetSet($credential->getId(), $credential); - } - } - } -} \ No newline at end of file diff --git a/src/Application/Model/Webauthn/d3PublicKeyCredentialSource.php b/src/Application/Model/Webauthn/d3PublicKeyCredentialSource.php index bb90f21..0569c94 100755 --- a/src/Application/Model/Webauthn/d3PublicKeyCredentialSource.php +++ b/src/Application/Model/Webauthn/d3PublicKeyCredentialSource.php @@ -17,7 +17,7 @@ namespace D3\Webauthn\Application\Model\Webauthn; -use D3\Webauthn\Application\Model\Credential\d3PublicKeyCredential; +use D3\Webauthn\Application\Model\Credential\publicKeyCredential; use Webauthn\PublicKeyCredentialSource; class d3PublicKeyCredentialSource extends PublicKeyCredentialSource @@ -27,7 +27,7 @@ class d3PublicKeyCredentialSource extends PublicKeyCredentialSource */ public function saveCredential() { - $credential = oxNew(d3PublicKeyCredential::class); + $credential = oxNew(publicKeyCredential::class); $credential->d3SetName(date('Y-m-d H:i:s')); $credential->d3SetCredentialId($this->getPublicKeyCredentialId()); $credential->d3SetType($this->getType()); @@ -42,7 +42,7 @@ class d3PublicKeyCredentialSource extends PublicKeyCredentialSource $credential->save(); } - public static function createFromd3PublicKeyCredential(d3PublicKeyCredential $publicKeyCredential): self + public static function createFromd3PublicKeyCredential(publicKeyCredential $publicKeyCredential): self { return new self( $publicKeyCredential->d3GetCredentialId(), diff --git a/src/Application/Model/Webauthn/d3PublicKeyCredentialSourceRepository.php b/src/Application/Model/Webauthn/d3PublicKeyCredentialSourceRepository.php index e6c572d..1abd6b3 100755 --- a/src/Application/Model/Webauthn/d3PublicKeyCredentialSourceRepository.php +++ b/src/Application/Model/Webauthn/d3PublicKeyCredentialSourceRepository.php @@ -19,8 +19,8 @@ declare(strict_types=1); namespace D3\Webauthn\Application\Model\Webauthn; -use D3\Webauthn\Application\Model\Credential\d3PublicKeyCredential; -use D3\Webauthn\Application\Model\Credential\d3PublicKeyCredentialList; +use D3\Webauthn\Application\Model\Credential\PublicKeyCredential; +use D3\Webauthn\Application\Model\Credential\PublicKeyCredentialList; use Exception; use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException; use OxidEsales\Eshop\Core\Exception\DatabaseErrorException; @@ -42,7 +42,7 @@ class d3PublicKeyCredentialSourceRepository implements PublicKeyCredentialSource return null; } - $credential = oxNew(d3PublicKeyCredential::class); + $credential = oxNew(publicKeyCredential::class); $credential->loadByCredentialId($publicKeyCredentialId); return $credential->getId() ? @@ -60,10 +60,10 @@ class d3PublicKeyCredentialSourceRepository implements PublicKeyCredentialSource { $sourceList = []; - $credentialList = oxNew(d3PublicKeyCredentialList::class); + $credentialList = oxNew(PublicKeyCredentialList::class); $credentialList->loadAllForUserEntity($publicKeyCredentialUserEntity); - /** @var d3PublicKeyCredential $credential */ + /** @var publicKeyCredential $credential */ foreach ($credentialList->getArray() as $credential) { $sourceList[$credential->getId()] = d3PublicKeyCredentialSource::createFromd3PublicKeyCredential($credential); }; diff --git a/src/Application/views/admin/tpl/d3user_webauthn.tpl b/src/Application/views/admin/tpl/d3user_webauthn.tpl index af64e9b..d31dcf8 100755 --- a/src/Application/views/admin/tpl/d3user_webauthn.tpl +++ b/src/Application/views/admin/tpl/d3user_webauthn.tpl @@ -10,7 +10,7 @@ [{assign var="readonly" value=""}] [{/if}] -