add backup code generation

This commit is contained in:
Daniel Seifert 2019-07-27 00:03:22 +02:00
parent 28ad88b734
commit c3ba0c28b1
7 changed files with 191 additions and 1 deletions

View File

@ -34,7 +34,8 @@
"php": ">=5.6",
"oxid-esales/oxideshop-metapackage-ce": "~6.0.3 || ~6.1.0",
"spomky-labs/otphp": "^8.3",
"bacon/bacon-qr-code": "^1.0"
"bacon/bacon-qr-code": "^1.0",
"ircmaxell/random-lib": "^1.2"
},
"autoload": {
"psr-4": {

View File

@ -17,8 +17,10 @@ namespace D3\Totp\Application\Controller\Admin;
use D3\Totp\Application\Model\d3totp;
use D3\Totp\Modules\Application\Model\d3_totp_user;
use Doctrine\DBAL\DBALException;
use OxidEsales\Eshop\Application\Controller\Admin\AdminDetailsController;
use OxidEsales\Eshop\Application\Model\User;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
use OxidEsales\Eshop\Core\Exception\StandardException;
use OxidEsales\Eshop\Core\Registry;
@ -30,6 +32,8 @@ class d3user_totp extends AdminDetailsController
/**
* @return string
* @throws DBALException
* @throws DatabaseConnectionException
*/
public function render()
{
@ -87,6 +91,7 @@ class d3user_totp extends AdminDetailsController
$oTotp->saveSecret($seed);
$oTotp->assign($aParams);
$oTotp->verify($otp, $seed);
$this->addTplParam('aBackupCodes', $oTotp->generateBackupCodes());
$oTotp->setId();
}
$oTotp->save();

View File

@ -26,6 +26,8 @@ use OxidEsales\Eshop\Core\DatabaseProvider;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
use OxidEsales\Eshop\Core\Model\BaseModel;
use OxidEsales\Eshop\Core\Registry;
use RandomLib\Factory;
use RandomLib\Generator;
class d3totp extends BaseModel
{
@ -35,6 +37,7 @@ class d3totp extends BaseModel
public $userId;
public $totp;
protected $timeWindow = 2;
protected $_backupCodes = array();
/**
* d3totp constructor.
@ -116,6 +119,21 @@ class d3totp extends BaseModel
return null;
}
/**
* @return array
*/
public function generateBackupCodes()
{
$factory = new Factory();
$generator = $factory->getLowStrengthGenerator();
for ($i = 0; $i < 10; $i++) {
$this->_backupCodes[] = $generator->generateString(6, Generator::CHAR_DIGITS);
}
return $this->_backupCodes;
}
/**
* @param $seed
* @return TOTP
@ -181,6 +199,40 @@ class d3totp extends BaseModel
);
}
/**
* @param $code
* @return false|string
* @throws DatabaseConnectionException
*/
public function d3EncodeBC($code)
{
$oDb = DatabaseProvider::getDb();
$salt = $this->getUser()->getFieldData('oxpasssalt');
$sSelect = "SELECT BINARY MD5( CONCAT( " . $oDb->quote($code) . ", UNHEX( ".$oDb->quote($salt)." ) ) )";
return $oDb->getOne($sSelect);
}
public function save()
{
$this->assign(
array(
'bc1' => $this->d3EncodeBC($this->_backupCodes[0]),
'bc2' => $this->d3EncodeBC($this->_backupCodes[1]),
'bc3' => $this->d3EncodeBC($this->_backupCodes[2]),
'bc4' => $this->d3EncodeBC($this->_backupCodes[3]),
'bc5' => $this->d3EncodeBC($this->_backupCodes[4]),
'bc6' => $this->d3EncodeBC($this->_backupCodes[5]),
'bc7' => $this->d3EncodeBC($this->_backupCodes[6]),
'bc8' => $this->d3EncodeBC($this->_backupCodes[7]),
'bc9' => $this->d3EncodeBC($this->_backupCodes[8]),
'bc10' => $this->d3EncodeBC($this->_backupCodes[9]),
)
);
return parent::save();
}
/**
* @param $totp
* @param $seed

View File

@ -40,6 +40,9 @@ $aLang = [
'D3_TOTP_REGISTERDELETE' => 'Registrierung löschen',
'D3_TOTP_REGISTERDELETE_DESC' => 'Um die Registrierung zu ändern, löschen Sie diese bitte vorerst. Sie können sofort im Anschluss eine neue Registrierung anlegen.<br>Wenn Sie die Registrierung löschen, ist das Konto nicht mehr durch die Zweifaktorauthentisierung geschützt.',
'D3_TOTP_BACKUPCODES' => 'Backup-Codes',
'D3_TOTP_BACKUPCODES_DESC' => 'Mit diesen Backup-Codes können Sie sich anmelden, wenn die Generierung des Einmalpasswortes nicht möglich ist (z.B. Gerät verloren oder neu installiert). Sie können dann die Einstellungen zur Verwendung der 2-Faktor-Autetizierung aändern oder einen neuen Zugang erstellen. Speichern Sie sich diese Codes bitte in diesem Moment sicher ab. Nach Verlassen dieser Seite können diese Codes nicht erneut angezeigt werden.',
'D3_TOTP_SAVE' => 'Speichern',
'D3_TOTP_ERROR_UNVALID' => 'Das Einmalpasswort ist ungültig.',

View File

@ -40,6 +40,9 @@ $aLang = [
'D3_TOTP_REGISTERDELETE' => 'Delete registration',
'D3_TOTP_REGISTERDELETE_DESC' => 'To change the registration, please delete it. You can then immediately create a new registration. <br> If you delete the registration, the account is no longer protected by the two-factor authentication.',
'D3_TOTP_BACKUPCODES' => 'backup codes',
'D3_TOTP_BACKUPCODES_DESC' => 'You can use these backup codes to log on if it is not possible to generate the one-time password (e.g. device lost or newly installed). You can then change the settings to use 2-factor authentication or create a new 2FA login. Please save these codes safely at this moment. After leaving this page, these codes cannot be displayed again.',
'D3_TOTP_SAVE' => 'Save',
'D3_TOTP_ERROR_UNVALID' => 'The one-time password is invalid.',

View File

@ -8,6 +8,12 @@
[{assign var="readonly" value=""}]
[{/if}]
<style type="text/css">
td.edittext {
white-space: normal;
}
</style>
<form name="transfer" id="transfer" action="[{$oViewConf->getSelfLink()}]" method="post">
[{$oViewConf->getHiddenSid()}]
<input type="hidden" name="oxid" value="[{$oxid}]">
@ -117,6 +123,26 @@
<input type="submit" class="edittext" id="oLockButton" name="save" value="[{oxmultilang ident="D3_TOTP_SAVE"}]" onClick="document.myedit.fnc.value='save'" [{$readonly}]>
</td>
</tr>
[{else}]
[{if $aBackupCodes}]
<tr>
<td class="edittext" colspan="2">
<h4>[{oxmultilang ident="D3_TOTP_BACKUPCODES"}]</h4>
</td>
</tr>
<tr>
<td>
<label for="backupcodes">[{oxmultilang ident="D3_TOTP_BACKUPCODES_DESC"}]</label>
<br>
<br>
<textarea id="backupcodes" rows="10" cols="20">[{strip}]
[{'
'|implode:$aBackupCodes}]
[{/strip}]</textarea>
</td>
</tr>
[{/if}]
[{/if}]
[{/block}]

View File

@ -75,6 +75,106 @@ class Installation extends d3install_updatebase
'sComment' => '',
'sExtra' => '',
'blMultilang' => false,
),
'BC1' => array(
'sTableName' => 'd3totp',
'sFieldName' => 'BC1',
'sType' => 'VARCHAR(64)',
'blNull' => false,
'sDefault' => false,
'sComment' => 'BackupCode #1',
'sExtra' => '',
'blMultilang' => false,
),
'BC2' => array(
'sTableName' => 'd3totp',
'sFieldName' => 'BC2',
'sType' => 'VARCHAR(64)',
'blNull' => false,
'sDefault' => false,
'sComment' => 'BackupCode #2',
'sExtra' => '',
'blMultilang' => false,
),
'BC3' => array(
'sTableName' => 'd3totp',
'sFieldName' => 'BC3',
'sType' => 'VARCHAR(64)',
'blNull' => false,
'sDefault' => false,
'sComment' => 'BackupCode #3',
'sExtra' => '',
'blMultilang' => false,
),
'BC4' => array(
'sTableName' => 'd3totp',
'sFieldName' => 'BC4',
'sType' => 'VARCHAR(64)',
'blNull' => false,
'sDefault' => false,
'sComment' => 'BackupCode #4',
'sExtra' => '',
'blMultilang' => false,
),
'BC5' => array(
'sTableName' => 'd3totp',
'sFieldName' => 'BC5',
'sType' => 'VARCHAR(64)',
'blNull' => false,
'sDefault' => false,
'sComment' => 'BackupCode #5',
'sExtra' => '',
'blMultilang' => false,
),
'BC6' => array(
'sTableName' => 'd3totp',
'sFieldName' => 'BC6',
'sType' => 'VARCHAR(64)',
'blNull' => false,
'sDefault' => false,
'sComment' => 'BackupCode #6',
'sExtra' => '',
'blMultilang' => false,
),
'BC7' => array(
'sTableName' => 'd3totp',
'sFieldName' => 'BC7',
'sType' => 'VARCHAR(64)',
'blNull' => false,
'sDefault' => false,
'sComment' => 'BackupCode #7',
'sExtra' => '',
'blMultilang' => false,
),
'BC8' => array(
'sTableName' => 'd3totp',
'sFieldName' => 'BC8',
'sType' => 'VARCHAR(64)',
'blNull' => false,
'sDefault' => false,
'sComment' => 'BackupCode #8',
'sExtra' => '',
'blMultilang' => false,
),
'BC9' => array(
'sTableName' => 'd3totp',
'sFieldName' => 'BC9',
'sType' => 'VARCHAR(64)',
'blNull' => false,
'sDefault' => false,
'sComment' => 'BackupCode #9',
'sExtra' => '',
'blMultilang' => false,
),
'BC10' => array(
'sTableName' => 'd3totp',
'sFieldName' => 'BC10',
'sType' => 'VARCHAR(64)',
'blNull' => false,
'sDefault' => false,
'sComment' => 'BackupCode #10',
'sExtra' => '',
'blMultilang' => false,
)
);