implement OTP check, add exception

This commit is contained in:
2018-10-18 15:33:59 +02:00
parent ed3eee4e67
commit 0a528f993b
8 changed files with 372 additions and 27 deletions
src
Application
Modules

@ -15,9 +15,36 @@
namespace D3\Totp\Application\Controller\Admin;
use D3\Totp\Application\Model\d3totp;
use Doctrine\DBAL\DBALException;
use OxidEsales\Eshop\Application\Controller\Admin\AdminDetailsController;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
class d3user_totp extends AdminDetailsController
{
protected $_sThisTemplate = 'd3user_totp.tpl';
/**
* @return string
* @throws DBALException
* @throws DatabaseConnectionException
*/
public function render()
{
parent::render();
$soxId = $this->_aViewData["oxid"] = $this->getEditObjectId();
if (isset($soxId) && $soxId != "-1") {
/** @var d3totp $oTotp */
$oTotp = oxNew(d3totp::class);
$oTotp->loadByUserId($soxId);
$this->_aViewData["edit"] = $oTotp;
}
if (!$this->_allowAdminEdit($soxId)) {
$this->_aViewData['readonly'] = true;
}
return $this->_sThisTemplate;
}
}

@ -0,0 +1,32 @@
<?php
/**
* This Software is the property of Data Development and is protected
* by copyright law - it is NOT Freeware.
*
* Any unauthorized use of this software without a valid license
* is a violation of the license agreement and will be prosecuted by
* civil and criminal law.
*
* http://www.shopmodule.com
*
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
* @link http://www.oxidmodule.com
*/
namespace D3\Totp\Application\Model\Exceptions;
use D3\ModCfg\Application\Model\DependencyInjectionContainer\d3DicHandler;
use D3\ModCfg\Application\Model\Exception\d3_cfg_mod_exception;
use D3\ModCfg\Application\Model\Exception\d3ShopCompatibilityAdapterException;
use D3\ModCfg\Application\Model\Log\d3log;
use Doctrine\DBAL\DBALException;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
use OxidEsales\Eshop\Core\Exception\DatabaseErrorException;
use OxidEsales\Eshop\Core\Exception\StandardException;
class d3totp_wrongOtpException extends StandardException
{
}

@ -0,0 +1,150 @@
<?php
/**
* This Software is the property of Data Development and is protected
* by copyright law - it is NOT Freeware.
* Any unauthorized use of this software without a valid license
* is a violation of the license agreement and will be prosecuted by
* civil and criminal law.
* http://www.shopmodule.com
*
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
* @link http://www.oxidmodule.com
*/
namespace D3\Totp\Application\Model;
use D3\ModCfg\Application\Model\d3database;
use D3\Totp\Application\Model\Exceptions\d3totp_wrongOtpException;
use Doctrine\DBAL\DBALException;
use OTPHP\TOTP;
use OxidEsales\Eshop\Application\Model\User;
use OxidEsales\Eshop\Core\DatabaseProvider;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
use OxidEsales\Eshop\Core\Model\BaseModel;
use OxidEsales\Eshop\Core\Registry;
class d3totp extends BaseModel
{
public $tableName = 'd3totp';
public $userId;
public $totp;
/**
* d3totp constructor.
*/
public function __construct()
{
$this->init($this->tableName);
return parent::__construct();
}
/**
* @param $userId
* @return bool
* @throws DBALException
* @throws DatabaseConnectionException
*/
public function loadByUserId($userId)
{
$this->userId = $userId;
$oQB = d3database::getInstance()->getQueryBuilder();
$oQB->select('oxid')
->from($this->getViewName())
->where("oxuserid = ".$oQB->createNamedParameter($userId))
->setMaxResults(1);
return $this->load(DatabaseProvider::getDb(DatabaseProvider::FETCH_MODE_ASSOC)->getOne($oQB->getSQL(), $oQB->getParameters()));
}
/**
* @return User
*/
public function getUser()
{
$userId = $this->userId ? $this->userId : $this->getFieldData('oxuserid');
$user = oxNew(User::class);
$user->load($userId);
return $user;
}
/**
* @param $userId
* @return bool
*/
public function UserUseTotp()
{
return $this->getFieldData('usetotp');
}
/**
* @param $userId
* @return string
*/
public function getSavedSecret()
{
$secret = $this->getFieldData('seed');
if ($secret) {
return $secret;
}
return null;
}
/**
* @return TOTP
*/
public function getTotp()
{
if (false == $this->totp) {
$this->totp = oxNew(
TOTP::class,
$this->getUser()->getFieldData('oxusername')
? $this->getUser()->getFieldData('oxusername')
: null,
$this->getSavedSecret()
);
$this->totp->setIssuer(Registry::getConfig()->getActiveShop()->getFieldData('oxname'));
}
return $this->totp;
}
/**
* @return string
*/
public function getQrCodeUri()
{
return $this->getTotp()->getQrCodeUri();
}
/**
* @return string
*/
public function getSecret()
{
return $this->getTotp()->getSecret();
}
/**
* @param $totp
* @return string
* @throws d3totp_wrongOtpException
*/
public function verify($totp)
{
$blVerify = $this->getTotp()->verify($totp, null, 2);
if (false == $blVerify) {
$oException = oxNew(d3totp_wrongOtpException::class, 'unvalid TOTP');
throw $oException;
}
return $blVerify;
}
}

@ -24,4 +24,10 @@ $aLang = [
'TOTP_INPUT_HELP' => 'Den Authentisierungscode erhalten Sie von der Zweifaktorauthentisierung-App auf Ihrem Gerät.',
'd3mxuser_totp' => '2-Faktor-Authentisierung',
'D3_TOTP_ACTIVE' => 'Benutzer verwendet 2-Faktor-Authentisierung',
'D3_TOTP_ACTIVE_HELP' => 'Benutzer verwendet 2-Faktor-Authentisierung',
'D3_TOTP_QRCODE' => 'QR-Code',
'D3_TOTP_SECRET' => 'QR-Code kann nicht gescannt werden?',
'D3_TOTP_CURROTP' => 'Bestätigung mit Einmalpasswort',
];

@ -1,6 +1,97 @@
[{include file="headitem.tpl" title="GENERAL_ADMIN_TITLE"|oxmultilangassign}]
foo
[{if $readonly}]
[{assign var="readonly" value="readonly disabled"}]
[{else}]
[{assign var="readonly" value=""}]
[{/if}]
<form name="transfer" id="transfer" action="[{$oViewConf->getSelfLink()}]" method="post">
[{$oViewConf->getHiddenSid()}]
<input type="hidden" name="oxid" value="[{$oxid}]">
<input type="hidden" name="cl" value="[{$oViewConf->getActiveClassName()}]">
</form>
<form name="myedit" id="myedit" action="[{$oViewConf->getSelfLink()}]" method="post" style="padding: 0;margin: 0;height:0;">
[{$oViewConf->getHiddenSid()}]
<input type="hidden" name="cl" value="[{$oViewConf->getActiveClassName()}]">
<input type="hidden" name="fnc" value="">
<input type="hidden" name="oxid" value="[{$oxid}]">
<input type="hidden" name="editval[d3totp__oxuserid]" value="[{$oxid}]">
<table cellspacing="0" cellpadding="0" border="0" style="width:98%;">
<tr>
<td valign="top" class="edittext" style="padding-top:10px;padding-left:10px; width: 50%;">
<table cellspacing="0" cellpadding="0" border="0">
[{block name="user_d3user_totp_form1"}]
<tr>
<td class="edittext" width="120">
[{oxmultilang ident="D3_TOTP_ACTIVE"}]
</td>
<td class="edittext">
<input type="hidden" name="editval[d3totp__usetoptp]" value="0">
<input class="edittext" type="checkbox" name="editval[d3totp__usetotp]" value='1' [{if $edit->getFieldData('usetotp') == 1}]checked[{/if}] [{$readonly}]>
[{oxinputhelp ident="D3_TOTP_ACTIVE_HELP"}]
</td>
</tr>
[{/block}]
<tr>
<td class="edittext" colspan="2"><br><br>
<input type="submit" class="edittext" id="oLockButton" name="saveArticle" value="[{oxmultilang ident="ARTICLE_MAIN_SAVE"}]" onClick="Javascript:document.myedit.fnc.value='save'" [{if !$edit->oxarticles__oxtitle->value && !$oxparentid}]disabled[{/if}] [{$readonly}]>
[{if $oxid!=-1 && !$readonly}]
<input type="submit" class="edittext" name="save" value="[{oxmultilang ident="ARTICLE_MAIN_ARTCOPY"}]" onClick="Javascript:document.myedit.fnc.value='copyArticle';" [{$readonly}]>&nbsp;&nbsp;&nbsp;
[{/if}]
</td>
</tr>
</table>
</td>
<!-- Anfang rechte Seite -->
<td valign="top" class="edittext" align="left" style="height:99%;padding-left:5px;padding-bottom:30px;padding-top:10px; width: 50%;">
<table cellspacing="0" cellpadding="0" border="0">
[{block name="user_d3user_totp_form2"}]
<tr>
<td class="edittext">
[{oxmultilang ident="D3_TOTP_QRCODE"}]&nbsp;
</td>
<td class="edittext">
<img src="[{$edit->getQrCodeUri()}]">
[{*
<input type="text" class="editinput" size="32" maxlength="[{$edit->oxarticles__oxtitle->fldmax_length}]" id="oLockTarget" name="editval[oxarticles__oxtitle]" value="[{$edit->oxarticles__oxtitle->value}]">
[{oxinputhelp ident="HELP_ARTICLE_MAIN_TITLE"}]
*}]
</td>
</tr>
<tr>
<td class="edittext">
[{oxmultilang ident="D3_TOTP_SECRET"}]&nbsp;
</td>
<td class="edittext">
[{$edit->getSecret()}]
[{*
<input type="text" class="editinput" size="32" maxlength="[{$edit->oxarticles__oxartnum->fldmax_length}]" name="editval[oxarticles__oxartnum]" value="[{$edit->oxarticles__oxartnum->value}]" [{$readonly}]>
[{oxinputhelp ident="HELP_ARTICLE_MAIN_ARTNUM"}]
*}]
</td>
</tr>
<tr>
<td class="edittext">
[{oxmultilang ident="D3_TOTP_CURROTP"}]&nbsp;
</td>
<td class="edittext">
<input type="text" class="editinput" size="6" maxlength="6" name="otp" value="">
[{oxinputhelp ident="D3_TOTP_CURROTP_HELP"}]
</td>
</tr>
[{/block}]
</table>
</td>
<!-- Ende rechte Seite -->
</tr>
</table>
</form>
[{include file="bottomnaviitem.tpl"}]
[{include file="bottomitem.tpl"}]