diff --git a/src/Application/Model/Credential/PublicKeyCredentialList.php b/src/Application/Model/Credential/PublicKeyCredentialList.php index 052958e..60e7929 100755 --- a/src/Application/Model/Credential/PublicKeyCredentialList.php +++ b/src/Application/Model/Credential/PublicKeyCredentialList.php @@ -15,10 +15,12 @@ declare(strict_types=1); namespace D3\Webauthn\Application\Model\Credential; +use D3\TestingTools\Production\IsMockable; use Doctrine\DBAL\Driver\Exception as DoctrineDriverException; use Doctrine\DBAL\Exception as DoctrineException; use Doctrine\DBAL\Query\QueryBuilder; use OxidEsales\Eshop\Application\Model\User; +use OxidEsales\Eshop\Core\Config as Config; use OxidEsales\Eshop\Core\Model\ListModel; use OxidEsales\Eshop\Core\Registry; use OxidEsales\EshopCommunity\Internal\Container\ContainerFactory; @@ -31,11 +33,13 @@ use Webauthn\PublicKeyCredentialUserEntity; class PublicKeyCredentialList extends ListModel implements PublicKeyCredentialSourceRepository { + use IsMockable; + protected $_sObjectsInListName = PublicKeyCredential::class; public function __construct() { - parent::__construct(PublicKeyCredential::class); + $this->d3CallMockableParent('__construct', [PublicKeyCredential::class]); } /** @@ -60,7 +64,7 @@ class PublicKeyCredentialList extends ListModel implements PublicKeyCredentialSo ), $qb->expr()->eq( 'oxshopid', - $qb->createNamedParameter(Registry::getConfig()->getShopId()) + $qb->createNamedParameter($this->getConfigObject()->getShopId()) ) ) ); @@ -97,7 +101,7 @@ class PublicKeyCredentialList extends ListModel implements PublicKeyCredentialSo ), $qb->expr()->eq( 'oxshopid', - $qb->createNamedParameter(Registry::getConfig()->getShopId()) + $qb->createNamedParameter($this->getConfigObject()->getShopId()) ) ) ); @@ -134,7 +138,7 @@ class PublicKeyCredentialList extends ListModel implements PublicKeyCredentialSo ), $qb->expr()->eq( 'oxshopid', - $qb->createNamedParameter(Registry::getConfig()->getShopId()) + $qb->createNamedParameter($this->getConfigObject()->getShopId()) ) ) ); @@ -157,4 +161,12 @@ class PublicKeyCredentialList extends ListModel implements PublicKeyCredentialSo { $this->getBaseObject()->saveCredentialSource($publicKeyCredentialSource); } + + /** + * @return Config + */ + public function getConfigObject(): Config + { + return Registry::getConfig(); + } } \ 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 a6439ae..cb65fa5 100755 --- a/src/Modules/Application/Controller/Admin/d3_LoginController_Webauthn.php +++ b/src/Modules/Application/Controller/Admin/d3_LoginController_Webauthn.php @@ -15,6 +15,7 @@ declare(strict_types=1); namespace D3\Webauthn\Modules\Application\Controller\Admin; +use D3\TestingTools\Production\IsMockable; use D3\Webauthn\Application\Model\Webauthn; use D3\Webauthn\Application\Model\WebauthnConf; use D3\Webauthn\Modules\Application\Model\d3_User_Webauthn; @@ -23,11 +24,14 @@ use Doctrine\DBAL\Exception; use OxidEsales\Eshop\Application\Model\User; use OxidEsales\Eshop\Core\Registry; use OxidEsales\Eshop\Core\Request; +use OxidEsales\Eshop\Core\Session; use Psr\Container\ContainerExceptionInterface; use Psr\Container\NotFoundExceptionInterface; class d3_LoginController_Webauthn extends d3_LoginController_Webauthn_parent { + use IsMockable; + /** * @return mixed|string * @throws ContainerExceptionInterface @@ -38,36 +42,32 @@ class d3_LoginController_Webauthn extends d3_LoginController_Webauthn_parent public function checklogin() { $lgn_user = $this->d3WebauthnGetRequestObject()->getRequestParameter( 'user') ?: - Registry::getSession()->getVariable(WebauthnConf::WEBAUTHN_ADMIN_SESSION_LOGINUSER); + $this->d3WebauthnGetSessionObject()->getVariable(WebauthnConf::WEBAUTHN_ADMIN_SESSION_LOGINUSER); /** @var d3_User_Webauthn $user */ $user = $this->d3WebauthnGetUserObject(); $userId = $user->d3GetLoginUserId($lgn_user, 'malladmin'); if ( $this->d3CanUseWebauthn( $lgn_user, $userId)) { - Registry::getSession()->setVariable( + $this->d3WebauthnGetSessionObject()->setVariable( WebauthnConf::WEBAUTHN_ADMIN_PROFILE, $this->d3WebauthnGetRequestObject()->getRequestEscapedParameter( 'profile') ); - Registry::getSession()->setVariable( + $this->d3WebauthnGetSessionObject()->setVariable( WebauthnConf::WEBAUTHN_ADMIN_CHLANGUAGE, $this->d3WebauthnGetRequestObject()->getRequestEscapedParameter( 'chlanguage') ); - $webauthn = $this->d3GetWebauthnObject(); - - if ($webauthn->isActive($userId) - && !Registry::getSession()->getVariable(WebauthnConf::WEBAUTHN_ADMIN_SESSION_AUTH) - ) { - Registry::getSession()->setVariable( + if ($this->hasWebauthnButNotLoggedin($userId)) { + $this->d3WebauthnGetSessionObject()->setVariable( WebauthnConf::WEBAUTHN_ADMIN_SESSION_CURRENTCLASS, $this->getClassKey() != 'd3webauthnadminlogin' ? $this->getClassKey() : 'admin_start' ); - Registry::getSession()->setVariable( + $this->d3WebauthnGetSessionObject()->setVariable( WebauthnConf::WEBAUTHN_ADMIN_SESSION_CURRENTUSER, $userId ); - Registry::getSession()->setVariable( + $this->d3WebauthnGetSessionObject()->setVariable( WebauthnConf::WEBAUTHN_ADMIN_SESSION_LOGINUSER, $lgn_user ); @@ -76,7 +76,7 @@ class d3_LoginController_Webauthn extends d3_LoginController_Webauthn_parent } } - return parent::checklogin(); + return $this->d3CallMockableParent('checklogin'); } /** @@ -112,6 +112,14 @@ class d3_LoginController_Webauthn extends d3_LoginController_Webauthn_parent return Registry::getRequest(); } + /** + * @return Session + */ + public function d3WebauthnGetSessionObject(): Session + { + return Registry::getSession(); + } + /** * @param $lgn_user * @param string|null $userId @@ -124,7 +132,21 @@ class d3_LoginController_Webauthn extends d3_LoginController_Webauthn_parent return $lgn_user && $userId && - false === Registry::getSession()->hasVariable( WebauthnConf::WEBAUTHN_ADMIN_SESSION_AUTH ) && + false === $this->d3WebauthnGetSessionObject()->hasVariable( WebauthnConf::WEBAUTHN_ADMIN_SESSION_AUTH ) && ( ! strlen( trim( (string) $password ) ) ); } + + /** + * @param $userId + * @return bool + * @throws DoctrineException + * @throws Exception + */ + protected function hasWebauthnButNotLoggedin($userId): bool + { + $webauthn = $this->d3GetWebauthnObject(); + + return $webauthn->isActive($userId) + && !$this->d3WebauthnGetSessionObject()->getVariable(WebauthnConf::WEBAUTHN_ADMIN_SESSION_AUTH); + } } \ No newline at end of file diff --git a/src/tests/unit/Application/Model/Credential/PublicKeyCredentialListTest.php b/src/tests/unit/Application/Model/Credential/PublicKeyCredentialListTest.php new file mode 100644 index 0000000..598068d --- /dev/null +++ b/src/tests/unit/Application/Model/Credential/PublicKeyCredentialListTest.php @@ -0,0 +1,331 @@ + + * @link https://www.oxidmodule.com + */ + +declare(strict_types=1); + +namespace D3\Webauthn\tests\unit\Application\Model\Credential; + +use D3\TestingTools\Development\CanAccessRestricted; +use D3\Webauthn\Application\Model\Credential\PublicKeyCredential; +use D3\Webauthn\Application\Model\Credential\PublicKeyCredentialList; +use D3\Webauthn\Application\Model\UserEntity; +use OxidEsales\Eshop\Application\Model\User; +use OxidEsales\Eshop\Core\Config; +use OxidEsales\TestingLibrary\UnitTestCase; +use PHPUnit\Framework\MockObject\MockObject; +use ReflectionException; +use Webauthn\PublicKeyCredentialSource; +use Webauthn\PublicKeyCredentialUserEntity; + +class PublicKeyCredentialListTest extends UnitTestCase +{ + use CanAccessRestricted; + + /** + * @test + * @return void + * @throws ReflectionException + * @covers \D3\Webauthn\Application\Model\Credential\PublicKeyCredentialList::__construct + */ + public function canConstruct() + { + /** @var PublicKeyCredentialList|MockObject $sut */ + $sut = $this->getMockBuilder(PublicKeyCredentialList::class) + ->disableOriginalConstructor() + ->onlyMethods(['d3CallMockableParent']) + ->getMock(); + $sut->expects($this->once())->method('d3CallMockableParent')->with( + $this->anything(), + $this->containsIdentical(PublicKeyCredential::class) + ); + + $this->callMethod( + $sut, + '__construct' + ); + } + + /** + * @test + * @param $doCreate + * @param $expected + * @return void + * @throws ReflectionException + * @dataProvider canFindOneByCredentialIdDataProvider + * @covers \D3\Webauthn\Application\Model\Credential\PublicKeyCredentialList::findOneByCredentialId + */ + public function canFindOneByCredentialId($doCreate, $expected) + { + $oxid = 'idFixture'; + + /** @var Config|MockObject $configMock */ + $configMock = $this->getMockBuilder(Config::class) + ->onlyMethods(['getShopId']) + ->getMock(); + $configMock->method('getShopId')->willReturn(55); + + /** @var PublicKeyCredentialList|MockObject $sut */ + $sut = $this->getMockBuilder(PublicKeyCredentialList::class) + ->disableOriginalConstructor() + ->onlyMethods(['getConfigObject']) + ->getMock(); + $sut->method('getConfigObject')->willReturn($configMock); + + if ($doCreate) { + $pkcsMock = $this->getMockBuilder(PublicKeyCredentialSource::class) + ->disableOriginalConstructor() + ->getMock(); + $pkc = $this->getMockBuilder(PublicKeyCredential::class) + ->onlyMethods(['allowDerivedDelete']) + ->getMock(); + $pkc->method('allowDerivedDelete')->willReturn(true); + $pkc->setId($oxid); + $pkc->assign([ + 'credentialid' => base64_encode('myCredentialId'), + 'oxshopid' => 55 + ]); + $pkc->setCredential($pkcsMock); + $pkc->save(); + } + + $this->assertEquals( + $expected === 'pkcsource' ? $pkcsMock : $expected, + $this->callMethod( + $sut, + 'findOneByCredentialId', + ['myCredentialId'] + ) + ); + + if ($doCreate) { + $pkc->delete($oxid); + } + } + + /** + * @return array + */ + public function canFindOneByCredentialIdDataProvider(): array + { + return [ + 'existing' => [true, 'pkcsource'], + 'not existing' => [false, null] + ]; + } + + /** + * @test + * @param $doCreate + * @param $expected + * @return void + * @throws ReflectionException + * @dataProvider canFindOneByCredentialIdDataProvider + * @covers \D3\Webauthn\Application\Model\Credential\PublicKeyCredentialList::findAllForUserEntity() + */ + public function canFindAllForUserEntity($doCreate, $expected) + { + $oxids = ['idFixture1','idFixture2']; + + /** @var Config|MockObject $configMock */ + $configMock = $this->getMockBuilder(Config::class) + ->onlyMethods(['getShopId']) + ->getMock(); + $configMock->method('getShopId')->willReturn(55); + + /** @var PublicKeyCredentialList|MockObject $sut */ + $sut = $this->getMockBuilder(PublicKeyCredentialList::class) + ->disableOriginalConstructor() + ->onlyMethods(['getConfigObject']) + ->getMock(); + $sut->method('getConfigObject')->willReturn($configMock); + + if ($doCreate) { + $pkcsMock = $this->getMockBuilder(PublicKeyCredentialSource::class) + ->disableOriginalConstructor() + ->getMock(); + foreach ($oxids as $oxid) { + $pkc = $this->getMockBuilder(PublicKeyCredential::class) + ->onlyMethods(['allowDerivedDelete']) + ->getMock(); + $pkc->method('allowDerivedDelete')->willReturn(true); + $pkc->setId($oxid); + $pkc->assign([ + 'oxuserid' => 'userid', + 'oxshopid' => 55 + ]); + $pkc->setCredential($pkcsMock); + $pkc->save(); + } + } + + /** @var UserEntity|MockObject $pkcUserEntity */ + $pkcUserEntity = $this->getMockBuilder(UserEntity::class) + ->disableOriginalConstructor() + ->onlyMethods(['getId']) + ->getMock(); + $pkcUserEntity->method('getId')->willReturn('userid'); + + $this->assertEquals( + $expected === 'pkcsource' ? [$pkcsMock, $pkcsMock] : [], + $this->callMethod( + $sut, + 'findAllForUserEntity', + [$pkcUserEntity] + ) + ); + + if ($doCreate) { + foreach ($oxids as $oxid) { + $pkc->delete($oxid); + } + } + } + + /** + * @test + * @param $userLoaded + * @param $doCreate + * @param $expectedCount + * @return void + * @throws ReflectionException + * @dataProvider canGetAllFromUserDataProvider + * @covers \D3\Webauthn\Application\Model\Credential\PublicKeyCredentialList::getAllFromUser() + */ + public function canGetAllFromUser($userLoaded, $doCreate, $expectedCount) + { + $oxids = ['idFixture1','idFixture2']; + + /** @var Config|MockObject $configMock */ + $configMock = $this->getMockBuilder(Config::class) + ->onlyMethods(['getShopId']) + ->getMock(); + $configMock->method('getShopId')->willReturn(55); + + /** @var PublicKeyCredentialList|MockObject $sut */ + $sut = $this->getMockBuilder(PublicKeyCredentialList::class) + ->disableOriginalConstructor() + ->onlyMethods(['getConfigObject']) + ->getMock(); + $sut->method('getConfigObject')->willReturn($configMock); + + /** @var User|MockObject $userMock */ + $userMock = $this->getMockBuilder(User::class) + ->onlyMethods(['isLoaded', 'getId']) + ->getMock(); + $userMock->method('isLoaded')->willReturn($userLoaded); + $userMock->method('getId')->willReturn('userid'); + + if ($doCreate) { + $pkcsMock = $this->getMockBuilder(PublicKeyCredentialSource::class) + ->disableOriginalConstructor() + ->getMock(); + foreach ($oxids as $oxid) { + $pkc = $this->getMockBuilder(PublicKeyCredential::class) + ->onlyMethods(['allowDerivedDelete']) + ->getMock(); + $pkc->method('allowDerivedDelete')->willReturn(true); + $pkc->setId($oxid); + $pkc->assign([ + 'oxuserid' => 'userid', + 'oxshopid' => 55 + ]); + $pkc->setCredential($pkcsMock); + $pkc->save(); + } + } + + $return = $this->callMethod( + $sut, + 'getAllFromUser', + [$userMock] + ); + + if ($doCreate) { + foreach ($oxids as $oxid) { + $pkc->delete($oxid); + } + } + + $this->assertInstanceOf(PublicKeyCredentialList::class, $return); + $this->assertCount($expectedCount, $return); + } + + /** + * @return array + */ + public function canGetAllFromUserDataProvider(): array + { + return [ + 'no user loaded' => [false, false, 0], + 'empty list' => [true, false, 0], + 'filled list' => [true, true, 2], + ]; + } + + /** + * @test + * @return void + * @throws ReflectionException + * @covers \D3\Webauthn\Application\Model\Credential\PublicKeyCredentialList::saveCredentialSource() + */ + public function canSaveCredentialSource() + { + /** @var PublicKeyCredentialSource|MockObject $pkcsMock */ + $pkcsMock = $this->getMockBuilder(PublicKeyCredentialSource::class) + ->disableOriginalConstructor() + ->getMock(); + + /** @var PublicKeyCredential|MockObject $baseObjectMock */ + $baseObjectMock = $this->getMockBuilder(PublicKeyCredential::class) + ->onlyMethods(['saveCredentialSource']) + ->getMock(); + $baseObjectMock->expects($this->once())->method('saveCredentialSource') + ->with($this->identicalTo($pkcsMock)); + + /** @var PublicKeyCredentialList|MockObject $sut */ + $sut = $this->getMockBuilder(PublicKeyCredentialList::class) + ->onlyMethods(['getBaseObject']) + ->getMock(); + $sut->method('getBaseObject')->willReturn($baseObjectMock); + + $this->callMethod( + $sut, + 'saveCredentialSource', + [$pkcsMock] + ); + } + + /** + * @test + * @return void + * @throws ReflectionException + * @covers \D3\Webauthn\Application\Model\Credential\PublicKeyCredentialList::getConfigObject() + */ + public function canGetConfigObject() + { + /** @var PublicKeyCredentialList|MockObject $sut */ + $sut = $this->getMockBuilder(PublicKeyCredentialList::class) + ->disableOriginalConstructor() + ->onlyMethods(['saveCredentialSource']) // required for code coverage + ->getMock(); + $sut->method('saveCredentialSource'); + + $this->assertInstanceOf( + Config::class, + $this->callMethod( + $sut, + 'getConfigObject' + ) + ); + } +} \ No newline at end of file diff --git a/src/tests/unit/Application/Model/Credential/PublicKeyCredentialTest.php b/src/tests/unit/Application/Model/Credential/PublicKeyCredentialTest.php index b166e12..b6e3499 100644 --- a/src/tests/unit/Application/Model/Credential/PublicKeyCredentialTest.php +++ b/src/tests/unit/Application/Model/Credential/PublicKeyCredentialTest.php @@ -222,7 +222,7 @@ class PublicKeyCredentialTest extends UnitTestCase ->disableOriginalConstructor() ->getMock(); - /** @var PublicKeyCredentialList|MockObject $pkcListObjectMock */ + /** @var PublicKeyCredentialListTest|MockObject $pkcListObjectMock */ $pkcListObjectMock = $this->getMockBuilder(PublicKeyCredentialList::class) ->onlyMethods(['findOneByCredentialId']) ->getMock(); diff --git a/src/tests/unit/Application/Model/RelyingPartyEntityTest.php b/src/tests/unit/Application/Model/RelyingPartyEntityTest.php index d093985..77f0377 100644 --- a/src/tests/unit/Application/Model/RelyingPartyEntityTest.php +++ b/src/tests/unit/Application/Model/RelyingPartyEntityTest.php @@ -21,9 +21,10 @@ use OxidEsales\Eshop\Application\Model\Shop; use OxidEsales\Eshop\Core\Config; use OxidEsales\TestingLibrary\UnitTestCase; use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase; use ReflectionException; -class RelyingPartyEntityTest extends UnitTestCase +class RelyingPartyEntityTest extends TestCase { use CanAccessRestricted; @@ -223,11 +224,12 @@ class RelyingPartyEntityTest extends UnitTestCase */ public function canGetConfig() { - /** @var RelyingPartyEntity $sut */ - //$sut = oxNew(RelyingPartyEntity::class); + /** @var RelyingPartyEntity|MockObject $sut */ $sut = $this->getMockBuilder(RelyingPartyEntity::class) ->disableOriginalConstructor() + ->onlyMethods(['hasConfiguredShopUrl']) // required for code coverage ->getMock(); + $sut->method('hasConfiguredShopUrl')->willReturn(true); $this->assertInstanceOf( Config::class, @@ -246,11 +248,12 @@ class RelyingPartyEntityTest extends UnitTestCase */ public function canGetActiveShop() { - /** @var RelyingPartyEntity $sut */ - //$sut = oxNew(RelyingPartyEntity::class); + /** @var RelyingPartyEntity|MockObject $sut */ $sut = $this->getMockBuilder(RelyingPartyEntity::class) ->disableOriginalConstructor() + ->onlyMethods(['hasConfiguredShopUrl']) // required for code coverage ->getMock(); + $sut->method('hasConfiguredShopUrl')->willReturn(true); $this->assertInstanceOf( Shop::class, diff --git a/src/tests/unit/Modules/Application/Controller/Admin/LoginControllerWebauthnTest.php b/src/tests/unit/Modules/Application/Controller/Admin/LoginControllerWebauthnTest.php index 5b66cdc..6be4f38 100644 --- a/src/tests/unit/Modules/Application/Controller/Admin/LoginControllerWebauthnTest.php +++ b/src/tests/unit/Modules/Application/Controller/Admin/LoginControllerWebauthnTest.php @@ -17,9 +17,11 @@ namespace D3\Webauthn\tests\unit\Modules\Application\Controller\Admin; use D3\TestingTools\Development\CanAccessRestricted; use D3\Webauthn\Application\Model\Webauthn; +use D3\Webauthn\Application\Model\WebauthnConf; use OxidEsales\Eshop\Application\Controller\Admin\LoginController; use OxidEsales\Eshop\Application\Model\User; use OxidEsales\Eshop\Core\Request; +use OxidEsales\Eshop\Core\Session; use OxidEsales\TestingLibrary\UnitTestCase; use PHPUnit\Framework\MockObject\MockObject; use ReflectionException; @@ -108,4 +110,205 @@ class LoginControllerWebauthnTest extends UnitTestCase ) ); } + + /** + * @test + * @throws ReflectionException + * @covers \D3\Webauthn\Modules\Application\Controller\Admin\d3_LoginController_Webauthn::d3WebauthnGetSessionObject + */ + public function canGetSessionObject() + { + /** @var LoginController $sut */ + $sut = oxNew(LoginController::class); + + $this->assertInstanceOf( + Session::class, + $this->callMethod( + $sut, + 'd3WebauthnGetSessionObject' + ) + ); + } + + /** + * @test + * @param $username + * @param $userId + * @param $hasWebauthnLogin + * @param $usedPassword + * @param $expected + * @return void + * @throws ReflectionException + * @dataProvider canUseWebauthnDataProvider + * @covers \D3\Webauthn\Modules\Application\Controller\Admin\d3_LoginController_Webauthn::d3CanUseWebauthn + */ + public function canUseWebauthn($username, $userId, $hasWebauthnLogin, $usedPassword, $expected) + { + /** @var Session|MockObject $sessionMock */ + $sessionMock = $this->getMockBuilder(Session::class) + ->onlyMethods(['hasVariable']) + ->getMock(); + $sessionMock->method('hasVariable')->with(WebauthnConf::WEBAUTHN_ADMIN_SESSION_AUTH) + ->willReturn($hasWebauthnLogin); + + /** @var Request|MockObject $requestMock */ + $requestMock = $this->getMockBuilder(Request::class) + ->onlyMethods(['getRequestParameter']) + ->getMock(); + $requestMock->method('getRequestParameter')->with('pwd')->willReturn($usedPassword); + + /** @var LoginController|MockObject $sut */ + $sut = $this->getMockBuilder(LoginController::class) + ->onlyMethods(['d3WebauthnGetRequestObject', 'd3WebauthnGetSessionObject']) + ->getMock(); + $sut->method('d3WebauthnGetRequestObject')->willReturn($requestMock); + $sut->method('d3WebauthnGetSessionObject')->willReturn($sessionMock); + + $this->assertSame( + $expected, + $this->callMethod( + $sut, + 'd3CanUseWebauthn', + [$username, $userId] + ) + ); + } + + /** + * @return array + */ + public function canUseWebauthnDataProvider(): array + { + return [ + 'no username' => [null, 'myUserId', false, null, false], + 'no userid' => ['username', null, false, null, false], + 'existing webauthn login' => ['username', 'myUserId', true, null, false], + 'used password' => ['username', 'myUserId', false, 'myPassword', false], + 'passed' => ['username', 'myUserId', false, null, true], + ]; + } + + /** + * @test + * @param $webauthnActive + * @param $hasAuth + * @param $expected + * @return void + * @throws ReflectionException + * @covers \D3\Webauthn\Modules\Application\Controller\Admin\d3_LoginController_Webauthn::hasWebauthnButNotLoggedin + * @dataProvider canHasWebauthnButNotLoggedinDataProvider + */ + public function canHasWebauthnButNotLoggedin($webauthnActive, $hasAuth, $expected) + { + /** @var Session|MockObject $sessionMock */ + $sessionMock = $this->getMockBuilder(Session::class) + ->onlyMethods(['getVariable']) + ->getMock(); + $sessionMock->method('getVariable')->with(WebauthnConf::WEBAUTHN_ADMIN_SESSION_AUTH) + ->willReturn($hasAuth); + + /** @var Webauthn|MockObject $webauthnMock */ + $webauthnMock = $this->getMockBuilder(Webauthn::class) + ->onlyMethods(['isActive']) + ->getMock(); + $webauthnMock->method('isActive')->willReturn($webauthnActive); + + /** @var LoginController|MockObject $sut */ + $sut = $this->getMockBuilder(LoginController::class) + ->onlyMethods(['d3GetWebauthnObject', 'd3WebauthnGetSessionObject']) + ->getMock(); + $sut->method('d3GetWebauthnObject')->willReturn($webauthnMock); + $sut->method('d3WebauthnGetSessionObject')->willReturn($sessionMock); + + $this->assertSame( + $expected, + $this->callMethod( + $sut, + 'hasWebauthnButNotLoggedin', + ['userId'] + ) + ); + } + + /** + * @return array + */ + public function canHasWebauthnButNotLoggedinDataProvider(): array + { + return [ + 'webauthn not active' => [false, false, false], + 'has webauthn auth' => [true, true, false], + 'passed' => [true, false, true], + ]; + } + + /** + * @test + * @param $canUseWebauthn + * @param $loggedin + * @param $setVariableCount + * @param $expected + * @return void + * @throws ReflectionException + * @dataProvider canCheckloginDataProvider + * @covers \D3\Webauthn\Modules\Application\Controller\Admin\d3_LoginController_Webauthn::checklogin + */ + public function canChecklogin($canUseWebauthn, $loggedin, $setVariableCount, $expected) + { + /** @var Request|MockObject $requestMock */ + $requestMock = $this->getMockBuilder(Request::class) + ->onlyMethods(['getRequestParameter']) + ->getMock(); + $requestMock->method('getRequestParameter')->willReturnMap([ + ['user', 'myUserName'], + ['profile', 'myProfile'] + ]); + + /** @var User|MockObject $userMock */ + $userMock = $this->getMockBuilder(User::class) + ->onlyMethods(['d3GetLoginUserId']) + ->getMock(); + $userMock->method('d3GetLoginUserId')->willReturn('myUserId'); + + /** @var Session|MockObject $sessionMock */ + $sessionMock = $this->getMockBuilder(Session::class) + ->onlyMethods(['setVariable', 'getVariable']) + ->getMock(); + $sessionMock->expects($this->exactly($setVariableCount))->method('setVariable'); + $sessionMock->method('getVariable')->with(WebauthnConf::WEBAUTHN_ADMIN_SESSION_LOGINUSER) + ->willReturn('myUserName'); + + /** @var LoginController|MockObject $sut */ + $sut = $this->getMockBuilder(LoginController::class) + ->onlyMethods(['d3CanUseWebauthn', 'd3CallMockableParent', 'hasWebauthnButNotLoggedin', + 'd3WebauthnGetSessionObject', 'd3WebauthnGetUserObject', 'd3WebauthnGetRequestObject' + ]) + ->getMock(); + $sut->method('d3CanUseWebauthn')->willReturn($canUseWebauthn); + $sut->method('d3CallMockableParent')->willReturn('parentReturn'); + $sut->method('hasWebauthnButNotLoggedin')->willReturn($loggedin); + $sut->method('d3WebauthnGetSessionObject')->willReturn($sessionMock); + $sut->method('d3WebauthnGetUserObject')->willReturn($userMock); + $sut->method('d3WebauthnGetRequestObject')->willReturn($requestMock); + + $this->assertSame( + $expected, + $this->callMethod( + $sut, + 'checklogin' + ) + ); + } + + /** + * @return array + */ + public function canCheckloginDataProvider(): array + { + return [ + 'can not use webauthn' => [false, false, 0, 'parentReturn'], + 'already logged in' => [true, false, 2, 'parentReturn'], + 'passed' => [true, true, 5, 'd3webauthnadminlogin'], + ]; + } } \ No newline at end of file