Files
monica/tests/Browser/Settings/MultiFAControllerTest.php
T
2020-03-20 08:17:59 +01:00

351 lines
12 KiB
PHP

<?php
namespace Tests\Browser\Settings;
use Zxing\QrReader;
use Tests\DuskTestCase;
use Laravel\Dusk\Browser;
use Illuminate\Console\Application;
use Tests\Browser\Pages\SettingsSecurity;
use Tests\Browser\Pages\DashboardValidate2fa;
class MultiFAControllerTest extends DuskTestCase
{
/**
* Cleanup.
*/
public function cleanup()
{
exec(Application::formatCommandString('2fa:deactivate --force --email=admin@admin.com'), $output);
}
/**
* Test if the user has 2fa Enable Link in Security Page.
* @group multifa
*/
public function testHasSettings2faEnableLink()
{
$this->browse(function (Browser $browser) {
$browser->login()
->visit(new SettingsSecurity)
->assertSeeLink('Enable Two Factor Authentication');
});
}
/**
* Test if the user has WebAuthn Enable Link in Security Page.
* @group multifa
*/
public function testHasSettingsWebAuthnEnableLink()
{
$this->browse(function (Browser $browser) {
$browser->login()
->visit(new SettingsSecurity)
->assertSeeLink('Add a new security key');
});
}
/**
* Test U2F modal.
* @group multifa
*/
public function testU2fModal()
{
$this->markTestIncomplete('Ignore 2fa tests for now.');
$this->browse(function (Browser $browser) {
$browser->login()
->visit(new SettingsSecurity)
->scrollTo('two_factor_link')
->clickLink('Add a new U2F security key')
->waitFor('registerModal')
->assertSee('Insert your security key.');
});
}
/**
* Test the barcode generated in 2fa Enable Page.
* @group multifa
*/
public function testHas2faEnableBarCode()
{
$this->markTestIncomplete('Ignore 2fa tests for now.');
$this->browse(function (Browser $browser) {
$browser->login()
->visit(new SettingsSecurity)
->scrollTo('two_factor_link')
->clickLink('Enable Two Factor Authentication')
->waitFor('enableModal')
->assertVisible('barcode')
->assertVisible('secretkey');
});
}
/**
* Test the barcode generated in 2fa Enable Page.
* @group multifa
* @group multifabarcode
*/
public function testBarCodeContent()
{
$this->markTestIncomplete('Ignore 2fa tests for now.');
$this->browse(function (Browser $browser) {
$browser =
$browser->login()
->visit(new SettingsSecurity)
->scrollTo('two_factor_link')
->clickLink('Enable Two Factor Authentication')
->waitFor('enableModal');
// \Facebook\WebDriver\Remote\RemoteWebElement
$barcode = $browser->element('barcode');
$imgsrc = $barcode->getAttribute('src');
$key = $this->unparseBarcode($imgsrc);
$this->assertEquals(32, strlen($key));
$this->assertEquals($browser->text('secretkey'), $key);
});
}
private function unparseBarcode($imgsrc)
{
$this->assertStringStartsWith('data:image/png', $imgsrc);
$imgcode = str_replace('data:image/png;base64,', '', $imgsrc);
$qrcode = new QrReader(base64_decode($imgcode), QrReader::SOURCE_TYPE_BLOB);
$text = $qrcode->text();
$this->assertStringStartsWith('otpauth://totp/', $text);
// unparse $text
// See PragmaRX\Google2FA\Support\QRCode getQRCodeUrl
// example :
//otpauth://totp/monicalocal.test:admin%40admin.com?secret=H25L7JLI7I57KYE7U53BIIOUELWXMRE6&issuer=monicalocal.test
$ret = preg_match('@^otpauth://totp/([^:]+):([^?]+)\?secret=([^&]+)&issuer=(.+)@i', $text, $matches);
$this->assertEquals(1, $ret, 'otp content does not match format');
$this->assertCount(5, $matches);
return $matches[3];
}
/**
* Test the 2fa Enable Page with wrong code.
* @group multifa
*/
public function testEnable2faWrongCode()
{
$this->markTestIncomplete('Ignore 2fa tests for now.');
$this->browse(function (Browser $browser) {
$browser =
$browser->login()
->visit(new SettingsSecurity)
->scrollTo('two_factor_link')
->clickLink('Enable Two Factor Authentication')
->waitFor('enableModal')
->type('otpenable', '000000')
->scrollTo('enableVerify')
->press('enableVerify')
->waitUntilMissing('enableModal');
$this->assertTrue($this->hasNotification($browser));
$notification = $this->getNotification($browser);
$this->assertStringContainsString('error', $notification->getAttribute('class'));
$this->assertStringContainsString('Two Factor Authentication', $notification->getText());
});
}
/**
* Test the 2fa Enable Page.
* @group multifa
*/
public function testEnable2fa()
{
$this->markTestIncomplete('Ignore 2fa tests for now.');
$this->browse(function (Browser $browser) {
$browser =
$browser->login()
->visit(new SettingsSecurity)
->scrollTo('two_factor_link')
->clickLink('Enable Two Factor Authentication')
->waitFor('enableModal');
$this->enable2fa($browser);
});
}
private function enable2fa(Browser $browser)
{
$secretkey = $browser->waitFor('enableModal')
->text('secretkey');
$google2fa = new \PragmaRX\Google2FA\Google2FA();
$one_time_password = $google2fa->getCurrentOtp($secretkey);
$browser->type('otpenable', $one_time_password);
$browser = $browser->scrollTo('enableVerify')
->press('enableVerify')
->waitUntilMissing('enableModal');
$this->assertTrue($this->hasNotification($browser));
$notification = $this->getNotification($browser);
$this->assertStringContainsString('success', $notification->getAttribute('class'));
$this->assertStringContainsString('Two Factor Authentication', $notification->getText());
// TODO: test if user has 2fa enabled actually
// TODO: test if session token auth is right
$browser->assertSeeLink('Disable Two Factor Authentication');
return $secretkey;
}
/**
* Test the 2fa Enable Page.
* @group multifa
*/
public function testEnable2faLoginWrongCode()
{
$this->markTestIncomplete('Ignore 2fa tests for now.');
$user = call_user_func(Browser::$userResolver);
$this->browse(function (Browser $browser) use ($user) {
$browser =
$browser->loginAs($user)
->visit(new SettingsSecurity)
->scrollTo('two_factor_link')
->clickLink('Enable Two Factor Authentication')
->waitFor('enableModal');
$secretkey = $this->enable2fa($browser);
$browser =
$browser->clickLink('Logout')
->loginAs($user)
->visit(new DashboardValidate2fa)
->assertVisible('otp')
->type('otp', '000000')
->press('verify');
$this->assertTrue($this->hasDivAlert($browser));
$notification = $this->getDivAlert($browser);
$this->assertStringContainsString('alert-danger', $notification->getAttribute('class'));
$this->assertStringContainsString('The two factor authentication has failed.', $notification->getText());
});
}
/**
* Test the 2fa Enable Page.
* @group multifa
*/
public function testEnable2faLogin()
{
$this->markTestIncomplete('Ignore 2fa tests for now.');
$user = call_user_func(Browser::$userResolver);
$this->browse(function (Browser $browser) use ($user) {
$browser =
$browser->loginAs($user)
->visit(new SettingsSecurity)
->scrollTo('two_factor_link')
->clickLink('Enable Two Factor Authentication')
->waitFor('enableModal');
$secretkey = $this->enable2fa($browser);
$google2fa = new \PragmaRX\Google2FA\Google2FA();
$one_time_password = $google2fa->getCurrentOtp($secretkey);
$browser =
$browser->clickLink('Logout')
->loginAs($user)
->visit(new DashboardValidate2fa)
->assertVisible('otp')
->type('otp', $one_time_password)
->press('verify');
$this->assertFalse($this->hasDivAlert($browser));
$browser->assertPathIs('/dashboard');
});
}
/**
* Test 2fa Enable Page and Disable Page.
* @group multifa
*/
public function testEnable2faDisable2fa()
{
$this->markTestIncomplete('Ignore 2fa tests for now.');
$this->browse(function (Browser $browser) {
$browser =
$browser->login()
->visit(new SettingsSecurity)
->scrollTo('two_factor_link')
->clickLink('Enable Two Factor Authentication')
->waitFor('enableModal');
$secretkey = $this->enable2fa($browser);
$google2fa = new \PragmaRX\Google2FA\Google2FA();
$one_time_password = $google2fa->getCurrentOtp($secretkey);
$browser =
$browser->clickLink('Disable Two Factor Authentication')
->waitFor('disableModal')
->assertVisible('otpdisable')
->type('otpdisable', $one_time_password)
->scrollTo('disableVerify')
->press('disableVerify')
->waitUntilMissing('enableModal');
$this->assertTrue($this->hasNotification($browser));
$notification = $this->getNotification($browser);
$this->assertStringContainsString('success', $notification->getAttribute('class'));
$this->assertStringContainsString('Two Factor Authentication', $notification->getText());
});
}
/**
* Test 2fa Enable Page and Disable Page.
* @group multifa
*/
public function testEnable2faDisable2faWrongCode()
{
$this->markTestIncomplete('Ignore 2fa tests for now.');
$this->browse(function (Browser $browser) {
$browser =
$browser->login()
->visit(new SettingsSecurity)
->scrollTo('two_factor_link')
->clickLink('Enable Two Factor Authentication')
->waitFor('enableModal');
$this->enable2fa($browser);
$browser =
$browser->clickLink('Disable Two Factor Authentication')
->waitFor('disableModal')
->assertVisible('otpdisable')
->type('otpdisable', '000000')
->scrollTo('disableVerify')
->press('disableVerify')
->waitUntilMissing('disableModal');
$this->assertTrue($this->hasNotification($browser));
$res = $browser->elements('.notification');
$notification = $res[1];
$this->assertStringContainsString('error', $notification->getAttribute('class'));
$this->assertStringContainsString('Two Factor Authentication', $notification->getText());
});
}
}