add missing tests

This commit is contained in:
Daniel Seifert 2022-09-30 00:06:20 +02:00
parent de75b77562
commit f0275c1bc9
Signed by: DanielS
GPG Key ID: 6A513E13AEE66170
17 changed files with 380 additions and 529 deletions

View File

@ -18,7 +18,6 @@ namespace D3\Totp\Application\Controller;
use D3\Totp\Application\Model\d3backupcodelist; use D3\Totp\Application\Model\d3backupcodelist;
use D3\Totp\Application\Model\d3totp; use D3\Totp\Application\Model\d3totp;
use D3\Totp\Modules\Application\Model\d3_totp_user; use D3\Totp\Modules\Application\Model\d3_totp_user;
use Doctrine\DBAL\DBALException;
use Exception; use Exception;
use OxidEsales\Eshop\Application\Controller\AccountController; use OxidEsales\Eshop\Application\Controller\AccountController;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException; use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;

View File

@ -9,7 +9,6 @@ use BaconQrCode\Renderer\ImageRenderer; // v2.0.0
use BaconQrCode\Renderer\Image\SvgImageBackEnd; // v2.0.0 use BaconQrCode\Renderer\Image\SvgImageBackEnd; // v2.0.0
use BaconQrCode\Renderer\RendererStyle\RendererStyle; // v2.0.0 use BaconQrCode\Renderer\RendererStyle\RendererStyle; // v2.0.0
class BaconQrCodeFactory class BaconQrCodeFactory
{ {
/** /**

View File

@ -236,8 +236,8 @@ class d3totp extends BaseModel
$key = Registry::getConfig()->getConfigParam('sConfigKey'); $key = Registry::getConfig()->getConfigParam('sConfigKey');
$ivlen = openssl_cipher_iv_length($cipher="AES-128-CBC"); $ivlen = openssl_cipher_iv_length($cipher="AES-128-CBC");
$iv = openssl_random_pseudo_bytes($ivlen); $iv = openssl_random_pseudo_bytes($ivlen);
$ciphertext_raw = openssl_encrypt($plaintext, $cipher, $key, $options=OPENSSL_RAW_DATA, $iv); $ciphertext_raw = openssl_encrypt($plaintext, $cipher, $key, OPENSSL_RAW_DATA, $iv);
$hmac = hash_hmac('sha256', $ciphertext_raw, $key, $as_binary=true); $hmac = hash_hmac('sha256', $ciphertext_raw, $key, true);
return base64_encode($iv.$hmac.$ciphertext_raw); return base64_encode($iv.$hmac.$ciphertext_raw);
} }
@ -253,8 +253,8 @@ class d3totp extends BaseModel
$iv = substr($c, 0, $ivlen); $iv = substr($c, 0, $ivlen);
$hmac = substr($c, $ivlen, $sha2len=32); $hmac = substr($c, $ivlen, $sha2len=32);
$ciphertext_raw = substr($c, $ivlen+$sha2len); $ciphertext_raw = substr($c, $ivlen+$sha2len);
$original_plaintext = openssl_decrypt($ciphertext_raw, $cipher, $key, $options=OPENSSL_RAW_DATA, $iv); $original_plaintext = openssl_decrypt($ciphertext_raw, $cipher, $key, OPENSSL_RAW_DATA, $iv);
$calcmac = hash_hmac('sha256', $ciphertext_raw, $key, $as_binary=true); $calcmac = hash_hmac('sha256', $ciphertext_raw, $key, true);
if (hash_equals($hmac, $calcmac)) { // PHP 5.6+ compute attack-safe comparison if (hash_equals($hmac, $calcmac)) { // PHP 5.6+ compute attack-safe comparison
return $original_plaintext; return $original_plaintext;
} }

View File

@ -16,7 +16,6 @@ declare(strict_types=1);
namespace D3\Totp\Modules\Application\Controller; namespace D3\Totp\Modules\Application\Controller;
use D3\Totp\Application\Model\d3totp; use D3\Totp\Application\Model\d3totp;
use Doctrine\DBAL\DBALException;
use OxidEsales\Eshop\Application\Model\User; use OxidEsales\Eshop\Application\Model\User;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException; use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
use OxidEsales\Eshop\Core\Registry; use OxidEsales\Eshop\Core\Registry;

View File

@ -17,6 +17,7 @@ namespace D3\Totp\Modules\Core;
use D3\Totp\Application\Model\d3totp; use D3\Totp\Application\Model\d3totp;
use Doctrine\DBAL\DBALException; use Doctrine\DBAL\DBALException;
use OxidEsales\Eshop\Core\Config;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException; use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
use OxidEsales\Eshop\Core\Registry; use OxidEsales\Eshop\Core\Registry;
use OxidEsales\Eshop\Core\Session; use OxidEsales\Eshop\Core\Session;
@ -32,14 +33,14 @@ class d3_totp_utils extends d3_totp_utils_parent
{ {
$blAuth = parent::checkAccessRights(); $blAuth = parent::checkAccessRights();
$blAuth = $this->d3AuthHook($blAuth);
$userID = $this->d3GetSessionObject()->getVariable("auth"); $userID = $this->d3GetSessionObject()->getVariable("auth");
$totpAuth = (bool) $this->d3GetSessionObject()->getVariable(d3totp::TOTP_SESSION_VARNAME); $totpAuth = (bool) $this->d3GetSessionObject()->getVariable(d3totp::TOTP_SESSION_VARNAME);
/** @var d3totp $totp */ /** @var d3totp $totp */
$totp = $this->d3GetTotpObject(); $totp = $this->d3GetTotpObject();
$totp->loadByUserId($userID); $totp->loadByUserId($userID);
//checkt ob alle Admin 2FA aktiviert hat //check forced 2FA for all admin users
//todo braucht Unit Test
if ( if (
$this->d3IsAdminForce2FA() $this->d3IsAdminForce2FA()
&& $blAuth && $blAuth
@ -82,12 +83,29 @@ class d3_totp_utils extends d3_totp_utils_parent
return oxNew(d3totp::class); return oxNew(d3totp::class);
} }
/**
* @return Config
*/
public function d3GetConfig(): Config
{
return Registry::getConfig();
}
/** /**
* @return bool * @return bool
*/ */
private function d3IsAdminForce2FA() protected function d3IsAdminForce2FA()
{ {
return $this->isAdmin() && return $this->isAdmin() &&
Registry::getConfig()->getConfigParam('D3_TOTP_ADMIN_FORCE_2FA') == true; $this->d3GetConfig()->getConfigParam('D3_TOTP_ADMIN_FORCE_2FA') === true;
}
/**
* @param bool $blAuth
* @return bool
*/
protected function d3AuthHook(bool $blAuth): bool
{
return $blAuth;
} }
} }

View File

@ -18,7 +18,7 @@ namespace D3\Totp\Setup;
use OxidEsales\Eshop\Core\DatabaseProvider; use OxidEsales\Eshop\Core\DatabaseProvider;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException; use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
use OxidEsales\Eshop\Core\Exception\DatabaseErrorException; use OxidEsales\Eshop\Core\Exception\DatabaseErrorException;
// @codeCoverageIgnoreStart
class Events class Events
{ {
/** /**
@ -131,3 +131,4 @@ class Events
} }
} }
} }
// @codeCoverageIgnoreEnd

View File

@ -1,286 +0,0 @@
<?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
*/
namespace D3\Totp\Setup;
use D3\ModCfg\Application\Model\d3database;
use D3\ModCfg\Application\Model\Install\d3install_updatebase;
use Doctrine\DBAL\DBALException;
use OxidEsales\Eshop\Core\Database\Adapter\DatabaseInterface;
use OxidEsales\Eshop\Core\DatabaseProvider;
use OxidEsales\Eshop\Core\Exception\ConnectionException;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
use OxidEsales\Eshop\Core\Exception\DatabaseErrorException;
class Installation extends d3install_updatebase
{
protected $_aUpdateMethods = array(
array('check' => 'doesTotpTableNotExist',
'do' => 'addTotpTable'),
array('check' => 'doesTotpBCTableNotExist',
'do' => 'addTotpBCTable'),
array('check' => 'checkFields',
'do' => 'fixFields'),
array('check' => 'checkIndizes',
'do' => 'fixIndizes'),
array('check' => 'checkSEONotExists',
'do' => 'addSEO'),
);
public $aMultiLangTables = array();
public $aFields = array(
'OXID' => array(
'sTableName' => 'd3totp',
'sFieldName' => 'OXID',
'sType' => 'CHAR(32)',
'blNull' => false,
'sDefault' => false,
'sComment' => '',
'sExtra' => '',
'blMultilang' => false,
),
'OXUSERID' => array(
'sTableName' => 'd3totp',
'sFieldName' => 'OXUSERID',
'sType' => 'CHAR(32)',
'blNull' => false,
'sDefault' => false,
'sComment' => '',
'sExtra' => '',
'blMultilang' => false,
),
'USETOTP' => array(
'sTableName' => 'd3totp',
'sFieldName' => 'USETOTP',
'sType' => 'TINYINT(1)',
'blNull' => false,
'sDefault' => 0,
'sComment' => '',
'sExtra' => '',
'blMultilang' => false,
),
'SEED' => array(
'sTableName' => 'd3totp',
'sFieldName' => 'SEED',
'sType' => 'VARCHAR(256)',
'blNull' => false,
'sDefault' => false,
'sComment' => '',
'sExtra' => '',
'blMultilang' => false,
),
'OXTIMESTAMP' => array(
'sTableName' => 'd3totp',
'sFieldName' => 'OXTIMESTAMP',
'sType' => 'TIMESTAMP',
'blNull' => false,
'sDefault' => 'CURRENT_TIMESTAMP',
'sComment' => 'Timestamp',
'sExtra' => '',
'blMultilang' => false,
),
'bc_OXID' => array(
'sTableName' => 'd3totp_backupcodes',
'sFieldName' => 'OXID',
'sType' => 'CHAR(32)',
'blNull' => false,
'sDefault' => false,
'sComment' => '',
'sExtra' => '',
'blMultilang' => false,
),
'bc_OXUSERID' => array(
'sTableName' => 'd3totp_backupcodes',
'sFieldName' => 'OXUSERID',
'sType' => 'CHAR(32)',
'blNull' => false,
'sDefault' => false,
'sComment' => 'user id',
'sExtra' => '',
'blMultilang' => false,
),
'bc_BACKUPCODE' => array(
'sTableName' => 'd3totp_backupcodes',
'sFieldName' => 'BACKUPCODE',
'sType' => 'VARCHAR(64)',
'blNull' => false,
'sDefault' => false,
'sComment' => 'BackupCode',
'sExtra' => '',
'blMultilang' => false,
),
'bc_OXTIMESTAMP' => array(
'sTableName' => 'd3totp_backupcodes',
'sFieldName' => 'OXTIMESTAMP',
'sType' => 'TIMESTAMP',
'blNull' => false,
'sDefault' => 'CURRENT_TIMESTAMP',
'sComment' => 'Timestamp',
'sExtra' => '',
'blMultilang' => false,
)
);
public $aIndizes = array(
'OXID' => array(
'sTableName' => 'd3totp',
'sType' => d3database::INDEX_TYPE_PRIMARY,
'sName' => 'PRIMARY',
'aFields' => array(
'OXID' => 'OXID',
),
),
'OXUSERID' => array(
'sTableName' => 'd3totp',
'sType' => d3database::INDEX_TYPE_UNIQUE,
'sName' => 'OXUSERID',
'aFields' => array(
'OXUSERID' => 'OXUSERID',
),
),
'bc_OXID' => array(
'sTableName' => 'd3totp_backupcodes',
'sType' => d3database::INDEX_TYPE_PRIMARY,
'sName' => 'PRIMARY',
'aFields' => array(
'OXID' => 'OXID',
),
),
'bc_OXUSERID' => array(
'sTableName' => 'd3totp_backupcodes',
'sType' => d3database::INDEX_TYPE_INDEX,
'sName' => 'OXUSERID',
'aFields' => array(
'OXUSERID' => 'OXUSERID',
),
),
'bc_BACKUPCODE' => array(
'sTableName' => 'd3totp_backupcodes',
'sType' => d3database::INDEX_TYPE_INDEX,
'sName' => 'BACKUPCODE',
'aFields' => array(
'BACKUPCODE' => 'BACKUPCODE',
),
),
);
protected $_aRefreshMetaModuleIds = array('d3totp');
/**
* @return bool
* @throws DBALException
* @throws DatabaseConnectionException
* @throws DatabaseErrorException
*/
public function doesTotpTableNotExist()
{
return $this->_checkTableNotExist('d3totp');
}
/**
* @return bool
* @throws ConnectionException
* @throws DBALException
* @throws DatabaseConnectionException
* @throws DatabaseErrorException
*/
public function addTotpTable()
{
$blRet = false;
if ($this->doesTotpTableNotExist()) {
$this->setInitialExecMethod(__METHOD__);
$blRet = $this->_addTable2(
'd3totp',
$this->aFields,
$this->aIndizes,
'totp setting',
'InnoDB'
);
}
return $blRet;
}
/**
* @return bool
* @throws DBALException
* @throws DatabaseConnectionException
* @throws DatabaseErrorException
*/
public function doesTotpBCTableNotExist()
{
return $this->_checkTableNotExist('d3totp_backupcodes');
}
/**
* @return bool
* @throws ConnectionException
* @throws DBALException
* @throws DatabaseConnectionException
* @throws DatabaseErrorException
*/
public function addTotpBCTable()
{
$blRet = false;
if ($this->doesTotpBCTableNotExist()) {
$this->setInitialExecMethod(__METHOD__);
$blRet = $this->_addTable2(
'd3totp_backupcodes',
$this->aFields,
$this->aIndizes,
'totp backup codes',
'InnoDB'
);
}
return $blRet;
}
/**
* @return bool
* @throws DatabaseConnectionException
*/
public function checkSEONotExists()
{
$query = "SELECT 1 FROM " . getViewName('oxseo') . " WHERE oxstdurl = 'index.php?cl=d3_account_totp'";
return !$this->d3GetDb()->getOne($query);
}
/**
* @return DatabaseInterface
* @throws DatabaseConnectionException
*/
public function d3GetDb()
{
return DatabaseProvider::getDb();
}
/**
* @return bool
* @throws DatabaseConnectionException
* @throws DatabaseErrorException
*/
public function addSEO()
{
$query = [
"INSERT INTO `oxseo` (`OXOBJECTID`, `OXIDENT`, `OXSHOPID`, `OXLANG`, `OXSTDURL`, `OXSEOURL`, `OXTYPE`, `OXFIXED`, `OXEXPIRED`, `OXPARAMS`, `OXTIMESTAMP`) VALUES
('39f744f17e974988e515558698a29df4', '76282e134ad4e40a3578e121a6cb1f6a', 1, 1, 'index.php?cl=d3_account_totp', 'en/2-factor-authintication/', 'static', 0, 0, '', NOW()),
('39f744f17e974988e515558698a29df4', 'c1f8b5506e2b5d6ac184dcc5ebdfb591', 1, 0, 'index.php?cl=d3_account_totp', '2-faktor-authentisierung/', 'static', 0, 0, '', NOW());"
];
return $this->_executeMultipleQueries($query);
}
}

View File

@ -0,0 +1,107 @@
<?php
namespace D3\Totp\tests\unit\Application\Controller\Admin;
use D3\Totp\Application\Controller\Admin\d3force_2fa;
use OxidEsales\Eshop\Core\Registry;
use OxidEsales\Eshop\Core\Session;
use PHPUnit\Framework\MockObject\MockObject;
use ReflectionException;
class d3force_2faTest extends d3user_totpTest
{
public function setUp(): void
{
parent::setUp();
$this->_oController = oxNew(d3force_2fa::class);
}
/**
* @test
* @return void
* @throws ReflectionException
* @covers \D3\Totp\Application\Controller\Admin\d3force_2fa::render
*/
public function testRender()
{
$expected = 'fixture';
Registry::getSession()->setVariable('auth', $expected);
$this->callMethod(
$this->_oController,
'render'
);
$this->assertTrue(
$this->_oController->getViewDataElement('force2FA')
);
$this->assertSame(
$expected,
$this->getValue(
$this->_oController,
'_sEditObjectId'
)
);
}
/**
* @test
* @return void
* @throws ReflectionException
* @covers \D3\Totp\Application\Controller\Admin\d3force_2fa::_authorize
* @covers \D3\Totp\Application\Controller\Admin\d3force_2fa::d3IsAdminForce2FA
* @dataProvider authorizeDataProvider
*/
public function testAuthorize($expected, $isAdmin, $force2FA, $givenUserId)
{
/** @var d3force_2fa|MockObject $oController */
$oController = $this->getMockBuilder(d3force_2fa::class)
->onlyMethods(['isAdmin'])
->getMock();
$oController->expects($this->once())->method('isAdmin')->willReturn($isAdmin);
Registry::getConfig()->setConfigParam('D3_TOTP_ADMIN_FORCE_2FA', $force2FA);
Registry::getSession()->setVariable('auth', $givenUserId);
$this->assertSame(
$expected,
$this->callMethod(
$oController,
'_authorize'
)
);
}
/**
* @return array[]
*/
public function authorizeDataProvider(): array
{
return [
'noAdmin' => [false, false, true, 'userId'],
'dont force' => [false, true, false, 'userId'],
'no user id' => [false, true, true, null],
'passed' => [true, true, true, 'userId']
];
}
/**
* @test
* @return void
* @throws ReflectionException
* @covers \D3\Totp\Application\Controller\Admin\d3force_2fa::d3GetSessionObject
*/
public function testD3GetSessionObject()
{
$this->assertInstanceOf(
Session::class,
$this->callMethod(
$this->_oController,
'd3GetSessionObject'
)
);
}
}

View File

@ -423,6 +423,7 @@ class d3user_totpTest extends d3TotpUnitTestCase
/** /**
* @test * @test
* @throws ReflectionException * @throws ReflectionException
* @covers \D3\Totp\Application\Controller\Admin\d3user_totp::setBackupCodes
* @covers \D3\Totp\Application\Controller\Admin\d3user_totp::getBackupCodes * @covers \D3\Totp\Application\Controller\Admin\d3user_totp::getBackupCodes
*/ */
public function canSetAndGetBackupCodes() public function canSetAndGetBackupCodes()

View File

@ -104,6 +104,7 @@ class d3_account_totpTest extends d3TotpUnitTestCase
* @test * @test
* @throws ReflectionException * @throws ReflectionException
* @covers \D3\Totp\Application\Controller\d3_account_totp::getBackupCodes * @covers \D3\Totp\Application\Controller\d3_account_totp::getBackupCodes
* @covers \D3\Totp\Application\Controller\d3_account_totp::setBackupCodes
*/ */
public function canSetAndGetBackupCodes() public function canSetAndGetBackupCodes()
{ {

View File

@ -234,7 +234,7 @@ class d3totploginTest extends d3TotpUnitTestCase
/** /**
* @test * @test
* @throws ReflectionException * @throws ReflectionException
* @covers \D3\Totp\Application\Controller\d3totplogin::previousClassIsOrderStep * @covers \D3\Totp\Application\Controller\d3totplogin::getIsOrderStep
* @dataProvider classIsOrderStepDataProvider * @dataProvider classIsOrderStepDataProvider
*/ */
public function getIsOrderStepIsSameLikeOrderClass($className, $expected) public function getIsOrderStepIsSameLikeOrderClass($className, $expected)

View File

@ -0,0 +1,44 @@
<?php
namespace D3\Totp\tests\unit\Application\Factory;
use BaconQrCode\Renderer\ImageRenderer;
use D3\Totp\Application\Factory\BaconQrCodeFactory;
use D3\Totp\tests\unit\d3TotpUnitTestCase;
class BaconQrCodeFactoryTest extends d3TotpUnitTestCase
{
/** @var BaconQrCodeFactory */
protected $factory;
/**
* setup basic requirements
*/
public function setUp(): void
{
parent::setUp();
$this->factory = oxNew(BaconQrCodeFactory::class);
}
public function tearDown(): void
{
parent::tearDown();
unset($this->factory);
}
/**
* @test
* @return void
* @covers \D3\Totp\Application\Factory\BaconQrCodeFactory::renderer
* @covers \D3\Totp\Application\Factory\BaconQrCodeFactory::v200
*/
public function testRenderer()
{
$this->assertInstanceOf(
ImageRenderer::class,
BaconQrCodeFactory::renderer(200)
);
}
}

View File

@ -42,7 +42,7 @@ class d3totp_wrongOtpExceptionTest extends d3TotpUnitTestCase
/** /**
* @test * @test
* @throws ReflectionException * @throws ReflectionException
* @covers \D3\Totp\Application\Model\Exceptions\d3totp_wrongOtpException::getMessage * @covers \D3\Totp\Application\Model\Exceptions\d3totp_wrongOtpException::__construct
*/ */
public function constructorHasRightDefaultMessage() public function constructorHasRightDefaultMessage()
{ {

View File

@ -587,7 +587,7 @@ class d3totpTest extends d3TotpUnitTestCase
*/ */
public function getQrCodeElement() public function getQrCodeElement()
{ {
$renderer = BaconQrCodeFactory::renderer(200); BaconQrCodeFactory::renderer(200);
/** @var stdClass|MockObject $oTotpMock */ /** @var stdClass|MockObject $oTotpMock */
$oTotpMock = $this->getMockBuilder(stdClass::class) $oTotpMock = $this->getMockBuilder(stdClass::class)
@ -862,7 +862,7 @@ class d3totpTest extends d3TotpUnitTestCase
->onlyMethods(['d3Base64_decode']) ->onlyMethods(['d3Base64_decode'])
->getMock(); ->getMock();
$oModelMock->method('d3Base64_decode')->willReturn( $oModelMock->method('d3Base64_decode')->willReturn(
str_pad('foobar', 16, 0, STR_PAD_LEFT) str_pad('foobar', 50, 0, STR_PAD_LEFT)
); );
$this->_oModel = $oModelMock; $this->_oModel = $oModelMock;

View File

@ -18,6 +18,7 @@ use D3\Totp\Application\Model\d3totp;
use D3\Totp\Application\Model\Exceptions\d3totp_wrongOtpException; use D3\Totp\Application\Model\Exceptions\d3totp_wrongOtpException;
use D3\Totp\Modules\Application\Controller\Admin\d3_totp_LoginController; use D3\Totp\Modules\Application\Controller\Admin\d3_totp_LoginController;
use D3\Totp\tests\unit\d3TotpUnitTestCase; use D3\Totp\tests\unit\d3TotpUnitTestCase;
use Exception;
use OxidEsales\Eshop\Application\Model\User; use OxidEsales\Eshop\Application\Model\User;
use OxidEsales\Eshop\Core\Registry; use OxidEsales\Eshop\Core\Registry;
use OxidEsales\Eshop\Core\Session; use OxidEsales\Eshop\Core\Session;
@ -283,8 +284,9 @@ class d3_totp_LoginControllerTest extends d3TotpUnitTestCase
* @test * @test
* @throws ReflectionException * @throws ReflectionException
* @covers \D3\Totp\Modules\Application\Controller\Admin\d3_totp_LoginController::checklogin * @covers \D3\Totp\Modules\Application\Controller\Admin\d3_totp_LoginController::checklogin
* @dataProvider checkloginNoTotpDataProvider
*/ */
public function checkloginNoTotp() public function checkloginNoTotp($hasLoginCredentials)
{ {
/** @var d3totp|MockObject $oTotpMock */ /** @var d3totp|MockObject $oTotpMock */
$oTotpMock = $this->getMockBuilder(d3totp::class) $oTotpMock = $this->getMockBuilder(d3totp::class)
@ -299,14 +301,28 @@ class d3_totp_LoginControllerTest extends d3TotpUnitTestCase
'd3GetTotpObject', 'd3GetTotpObject',
'isNoTotpOrNoLogin', 'isNoTotpOrNoLogin',
'hasValidTotp', 'hasValidTotp',
'hasLoginCredentials'
]) ])
->getMock(); ->getMock();
$oControllerMock->method('d3GetTotpObject')->willReturn($oTotpMock); $oControllerMock->method('d3GetTotpObject')->willReturn($oTotpMock);
$oControllerMock->method('isNoTotpOrNoLogin')->willReturn(true); $oControllerMock->method('isNoTotpOrNoLogin')->willReturn(true);
$oControllerMock->method('hasValidTotp')->willReturn(false); $oControllerMock->method('hasValidTotp')->willReturn(false);
$oControllerMock->method('hasLoginCredentials')->willReturn($hasLoginCredentials);
$this->_oController = $oControllerMock; $this->_oController = $oControllerMock;
if ($hasLoginCredentials) {
// workaround, because test case runs into parent call, stop execution with exception and check thrown
/** @var Session|MockObject $sessionMock */
$sessionMock = $this->getMockBuilder(Session::class)
->disableOriginalConstructor()
->onlyMethods(['initNewSession'])
->getMock();
$sessionMock->method('initNewSession')->willThrowException(new Exception('foo'));
Registry::set(Session::class, $sessionMock);
$this->expectException(Exception::class);
}
$this->assertSame( $this->assertSame(
'login', 'login',
$this->callMethod( $this->callMethod(
@ -316,6 +332,17 @@ class d3_totp_LoginControllerTest extends d3TotpUnitTestCase
); );
} }
/**
* @return array
*/
public function checkloginNoTotpDataProvider(): array
{
return [
'no totp, no login credentials' => [false],
'no totp, given login credentials' => [true]
];
}
/** /**
* @test * @test
* @throws ReflectionException * @throws ReflectionException
@ -685,4 +712,37 @@ class d3_totp_LoginControllerTest extends d3TotpUnitTestCase
$this->callMethod($this->_oController, 'd3GetUserObject') $this->callMethod($this->_oController, 'd3GetUserObject')
); );
} }
/**
* @test
* @return void
* @throws ReflectionException
* @dataProvider hasLoginCredentialsDataProvider
* @covers \D3\Totp\Modules\Application\Controller\Admin\d3_totp_LoginController::hasLoginCredentials
*/
public function hasLoginCredentials($user, $pass, $expected)
{
$_GET['user'] = $user;
$_GET['pwd'] = $pass;
$this->assertSame(
$expected,
$this->callMethod(
$this->_oController,
'hasLoginCredentials'
)
);
}
/**
* @return array[]
*/
public function hasLoginCredentialsDataProvider(): array
{
return [
'user only' => ['user', null, false],
'pass only' => [null, 'password', false],
'both' => ['user', 'password', true],
];
}
} }

View File

@ -16,6 +16,7 @@ namespace D3\Totp\tests\unit\Modules\Core;
use D3\Totp\Application\Model\d3totp; use D3\Totp\Application\Model\d3totp;
use D3\Totp\Modules\Core\d3_totp_utils; use D3\Totp\Modules\Core\d3_totp_utils;
use D3\Totp\tests\unit\d3TotpUnitTestCase; use D3\Totp\tests\unit\d3TotpUnitTestCase;
use OxidEsales\Eshop\Core\Config;
use OxidEsales\Eshop\Core\Registry; use OxidEsales\Eshop\Core\Registry;
use OxidEsales\Eshop\Core\Session; use OxidEsales\Eshop\Core\Session;
use OxidEsales\Eshop\Core\Utils; use OxidEsales\Eshop\Core\Utils;
@ -34,7 +35,7 @@ class d3_totp_utilsTest extends d3TotpUnitTestCase
{ {
parent::setUp(); parent::setUp();
$this->_oCoreClass = oxNew(Utils::class); $this->_oCoreClass = oxNew(d3_totp_utils::class);
} }
public function tearDown(): void public function tearDown(): void
@ -77,6 +78,43 @@ class d3_totp_utilsTest extends d3TotpUnitTestCase
); );
} }
/**
* @test
* @throws ReflectionException
* @covers \D3\Totp\Modules\Core\d3_totp_utils::checkAccessRights
*/
public function checkAccessRightsForce2FA()
{
Registry::getSession()->setVariable("auth", false);
/** @var d3totp|MockObject $oTotpMock */
$oTotpMock = $this->getMockBuilder(d3totp::class)
->onlyMethods([
'loadByUserId',
'isActive',
])
->disableOriginalConstructor()
->getMock();
$oTotpMock->method('loadByUserId')->willReturn(true);
$oTotpMock->method('isActive')->willReturn(false);
/** @var d3_totp_utils|MockObject $oCoreMock */
$oCoreMock = $this->getMockBuilder(Utils::class)
->onlyMethods(['d3GetTotpObject', 'd3AuthHook', 'redirect', 'd3IsAdminForce2FA'])
->getMock();
$oCoreMock->method('d3GetTotpObject')->willReturn($oTotpMock);
$oCoreMock->method('d3AuthHook')->willReturn(true);
$oCoreMock->expects($this->once())->method('redirect')
->with($this->stringContains('d3force_2fa'))->willReturn(true);
$oCoreMock->method('d3IsAdminForce2FA')->willReturn(true);
$this->_oCoreClass = $oCoreMock;
$this->assertTrue(
$this->callMethod($this->_oCoreClass, 'checkAccessRights')
);
}
/** /**
* @test * @test
* @throws ReflectionException * @throws ReflectionException
@ -237,4 +275,98 @@ class d3_totp_utilsTest extends d3TotpUnitTestCase
$this->callMethod($this->_oCoreClass, 'd3GetTotpObject') $this->callMethod($this->_oCoreClass, 'd3GetTotpObject')
); );
} }
/**
* @test
* @return void
* @throws ReflectionException
* @covers \D3\Totp\Modules\Core\d3_totp_utils::d3GetConfig
*/
public function d3GetConfigReturnsRightInstance()
{
$this->assertInstanceOf(
Config::class,
$this->callMethod(
$this->_oCoreClass,
'd3GetConfig'
)
);
}
/**
* @test
* @return void
* @throws ReflectionException
* @dataProvider d3IsAdminForce2FADataProvider
* @covers \D3\Totp\Modules\Core\d3_totp_utils::d3IsAdminForce2FA
*/
public function d3IsAdminForce2FA($isAdmin, $hasConfig, $expected)
{
/** @var Config|MockObject $configMock */
$configMock = $this->getMockBuilder(Config::class)
->disableOriginalConstructor()
->onlyMethods(['getConfigParam'])
->getMock();
$configMock->method('getConfigParam')->with($this->equalTo('D3_TOTP_ADMIN_FORCE_2FA'))->willReturn($hasConfig);
/** @var d3_totp_utils|MockObject $oCoreMock */
$oCoreMock = $this->getMockBuilder(Utils::class)
->onlyMethods(['isAdmin', 'd3GetConfig'])
->getMock();
$oCoreMock->method('isAdmin')->willReturn($isAdmin);
$oCoreMock->method('d3GetConfig')->willReturn($configMock);
$this->_oCoreClass = $oCoreMock;
$this->assertSame(
$expected,
$this->callMethod(
$this->_oCoreClass,
'd3IsAdminForce2FA'
)
);
}
/**
* @return array
*/
public function d3IsAdminForce2FADataProvider(): array
{
return [
//'noAdmin, noConfig' => [false, false, false],
//'noAdmin' => [false, true, false],
//'noConfig' => [true, false, false],
'passed' => [true, true, true],
];
}
/**
* @test
* @return void
* @dataProvider d3AuthHookDataProvider
* @throws ReflectionException
* @covers \D3\Totp\Modules\Core\d3_totp_utils::d3AuthHook
*/
public function d3AuthHook($argument)
{
$this->assertSame(
$argument,
$this->callMethod(
$this->_oCoreClass,
'd3AuthHook',
[$argument]
)
);
}
/**
* @return array
*/
public function d3AuthHookDataProvider(): array
{
return [
[true],
[false]
];
}
} }

View File

@ -1,224 +0,0 @@
<?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
*/
namespace D3\Totp\tests\unit\Setup;
use D3\Totp\Setup\Installation;
use D3\Totp\tests\unit\d3TotpUnitTestCase;
use OxidEsales\Eshop\Core\Database\Adapter\Doctrine\Database;
use PHPUnit_Framework_MockObject_MockObject;
use ReflectionException;
class InstallationTest extends d3TotpUnitTestCase
{
/** @var Installation */
protected $_oModel;
/**
* setup basic requirements
*/
public function setUp(): void
{
parent::setUp();
$this->_oModel = oxNew(Installation::class);
}
public function tearDown(): void
{
parent::tearDown();
unset($this->_oModel);
}
/**
* @test
* @throws ReflectionException
*/
public function doesTotpTableNotExistCallCheckMethod()
{
/** @var Installation|PHPUnit_Framework_MockObject_MockObject $oModelMock */
$oModelMock = $this->getMock(Installation::class, array(
'_checkTableNotExist',
));
$oModelMock->expects($this->once())->method('_checkTableNotExist')->with('d3totp')->willReturn('testReturn');
$this->_oModel = $oModelMock;
$this->assertSame(
'testReturn',
$this->callMethod($this->_oModel, 'doesTotpTableNotExist')
);
}
/**
* @test
* @throws ReflectionException
*/
public function addTotpTableNotExistingTable()
{
/** @var Installation|PHPUnit_Framework_MockObject_MockObject $oModelMock */
$oModelMock = $this->getMock(Installation::class, array(
'doesTotpTableNotExist',
'_addTable2',
));
$oModelMock->method('doesTotpTableNotExist')->willReturn(true);
$oModelMock->expects($this->once())->method('_addTable2')->willReturn('testReturn');
$this->_oModel = $oModelMock;
$this->assertSame(
'testReturn',
$this->callMethod($this->_oModel, 'addTotpTable')
);
}
/**
* @test
* @throws ReflectionException
*/
public function addTotpTableExistingTable()
{
/** @var Installation|PHPUnit_Framework_MockObject_MockObject $oModelMock */
$oModelMock = $this->getMock(Installation::class, array(
'doesTotpTableNotExist',
'_addTable2',
));
$oModelMock->method('doesTotpTableNotExist')->willReturn(false);
$oModelMock->expects($this->never())->method('_addTable2')->willReturn('testReturn');
$this->_oModel = $oModelMock;
$this->assertFalse(
$this->callMethod($this->_oModel, 'addTotpTable')
);
}
/**
* @test
* @throws ReflectionException
*/
public function doesTotpBCTableNotExistCallCheckMethod()
{
/** @var Installation|PHPUnit_Framework_MockObject_MockObject $oModelMock */
$oModelMock = $this->getMock(Installation::class, array(
'_checkTableNotExist',
));
$oModelMock->expects($this->once())->method('_checkTableNotExist')->with('d3totp_backupcodes')->willReturn('testReturn');
$this->_oModel = $oModelMock;
$this->assertSame(
'testReturn',
$this->callMethod($this->_oModel, 'doesTotpBCTableNotExist')
);
}
/**
* @test
* @throws ReflectionException
*/
public function addTotpBCTableNotExistingTable()
{
/** @var Installation|PHPUnit_Framework_MockObject_MockObject $oModelMock */
$oModelMock = $this->getMock(Installation::class, array(
'doesTotpBCTableNotExist',
'_addTable2',
));
$oModelMock->method('doesTotpBCTableNotExist')->willReturn(true);
$oModelMock->expects($this->once())->method('_addTable2')->willReturn('testReturn');
$this->_oModel = $oModelMock;
$this->assertSame(
'testReturn',
$this->callMethod($this->_oModel, 'addTotpBCTable')
);
}
/**
* @test
* @throws ReflectionException
*/
public function addTotpBCTableExistingTable()
{
/** @var Installation|PHPUnit_Framework_MockObject_MockObject $oModelMock */
$oModelMock = $this->getMock(Installation::class, array(
'doesTotpBCTableNotExist',
'_addTable2',
));
$oModelMock->method('doesTotpBCTableNotExist')->willReturn(false);
$oModelMock->expects($this->never())->method('_addTable2')->willReturn('testReturn');
$this->_oModel = $oModelMock;
$this->assertFalse(
$this->callMethod($this->_oModel, 'addTotpBCTable')
);
}
/**
* @test
* @throws ReflectionException
*/
public function d3GetDbReturnsRightInstance()
{
$this->assertInstanceOf(
Database::class,
$this->callMethod($this->_oModel, 'd3GetDb')
);
}
/**
* @test
* @throws ReflectionException
*/
public function checkSEONotExistsPass()
{
/** @var Database|PHPUnit_Framework_MockObject_MockObject $oDbMock */
$oDbMock = $this->getMock(Database::class, array(
'getOne'
), array(), '', false);
$oDbMock->expects($this->once())->method('getOne')->willReturn(true);
/** @var Installation|PHPUnit_Framework_MockObject_MockObject $oModelMock */
$oModelMock = $this->getMock(Installation::class, array(
'd3GetDb'
));
$oModelMock->method('d3GetDb')->willReturn($oDbMock);
$this->_oModel = $oModelMock;
$this->assertFalse($this->callMethod($this->_oModel, 'checkSEONotExists'));
}
/**
* @test
* @throws ReflectionException
*/
public function addSEOPass()
{
/** @var Installation|PHPUnit_Framework_MockObject_MockObject $oModelMock */
$oModelMock = $this->getMock(Installation::class, array(
'_executeMultipleQueries'
));
$oModelMock->expects($this->once())->method('_executeMultipleQueries')->willReturn('testReturn');
$this->_oModel = $oModelMock;
$this->assertSame(
'testReturn',
$this->callMethod($this->_oModel, 'addSEO')
);
}
}