Skip to content

Commit

Permalink
Add acceptance tests for the new totp key confirmation
Browse files Browse the repository at this point in the history
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
  • Loading branch information
ChristophWurst committed Mar 14, 2017
1 parent 3b4e1c0 commit 2a85bdf
Showing 1 changed file with 51 additions and 7 deletions.
58 changes: 51 additions & 7 deletions tests/Acceptance/TOTPAcceptanceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,20 @@

namespace OCA\TwoFactorTOTP\Tests\Acceptance;

use Base32\Base32;
use Facebook\WebDriver\Exception\ElementNotSelectableException;
use Facebook\WebDriver\WebDriver;
use Facebook\WebDriver\WebDriverBy;
use Facebook\WebDriver\WebDriverExpectedCondition;
use OC;
use OCA\TwoFactorTOTP\Db\TotpSecret;
use OCA\TwoFactorTOTP\Db\TotpSecretMapper;
use OCA\TwoFactorTOTP\Service\ITotp;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\IUser;
use Otp\GoogleAuthenticator;
use Otp\Otp;
use PHPUnit_Framework_AssertionFailedError;

/**
* @group Acceptance
Expand Down Expand Up @@ -80,17 +84,17 @@ public function testEnableTOTP() {
$this->webDriver->findElement(WebDriverBy::cssSelector('form[name=login] input[type=submit]'))->click();

// Go to personal settings
$this->webDriver->wait(20, 1000)->until(WebDriverExpectedCondition::elementToBeClickable(WebDriverBy::id('expandDisplayName')));
$this->webDriver->wait(20, 200)->until(WebDriverExpectedCondition::elementToBeClickable(WebDriverBy::id('expandDisplayName')));
$this->webDriver->findElement(WebDriverBy::id('expandDisplayName'))->click();
$this->webDriver->findElement(WebDriverBy::linkText('Personal'))->click();

// Go to TOTP settings
$this->webDriver->wait(20, 1000)->until(WebDriverExpectedCondition::elementToBeClickable(WebDriverBy::linkText('TOTP second-factor auth')));
$this->webDriver->wait(20, 200)->until(WebDriverExpectedCondition::elementToBeClickable(WebDriverBy::linkText('TOTP second-factor auth')));
$this->webDriver->findElement(WebDriverBy::linkText('TOTP second-factor auth'))->click();

// Enable TOTP
usleep(15 * 1000 * 1000); // Hard-coded sleep because the scripts need some time load the page
$this->webDriver->wait(20, 1000)->until(function(WebDriver $driver) {
// Wait for state being loaded from the server
$this->webDriver->wait(20, 200)->until(function(WebDriver $driver) {
try {
return count($driver->findElements(WebDriverBy::id('totp-enabled'))) > 0;
} catch (ElementNotSelectableException $ex) {
Expand All @@ -100,7 +104,47 @@ public function testEnableTOTP() {
$this->webDriver->executeScript('arguments[0].click(); console.log(arguments[0]);', [
$this->webDriver->findElement(WebDriverBy::id('totp-enabled')),
]);
$this->webDriver->wait(20, 1000)->until(WebDriverExpectedCondition::elementTextContains(WebDriverBy::id('twofactor-totp-settings'), 'This is your new TOTP secret:'));
$this->webDriver->wait(15, 200)->until(WebDriverExpectedCondition::elementTextContains(WebDriverBy::id('twofactor-totp-settings'), 'This is your new TOTP secret:'));
$this->assertHasSecret(ITotp::STATE_CREATED);

// Enter a wrong OTP
$this->webDriver->findElement(WebDriverBy::id('totp-confirmation'))->sendKeys('000000');
$this->webDriver->findElement(WebDriverBy::id('totp-confirmation-submit'))->click();

// Wait for the notification
$this->webDriver->wait(15, 200)->until(WebDriverExpectedCondition::elementTextContains(WebDriverBy::id('notification'), 'Could not verify your key. Please try again'));

// Enter a correct OTP
$this->webDriver->findElement(WebDriverBy::id('totp-confirmation'))->sendKeys($this->getValidTOTP());
$this->webDriver->findElement(WebDriverBy::id('totp-confirmation-submit'))->click();

// Try to locate checked checkbox
$this->webDriver->wait(20, 200)->until(function(WebDriver $driver) {
try {
return $driver->findElement(WebDriverBy::id('totp-enabled'))->getAttribute('checked') === 'true';
} catch (ElementNotSelectableException $ex) {
return false;
}
});
$this->assertHasSecret(ITotp::STATE_ENABLED);
}

private function assertHasSecret($state) {
try {
$secret = $this->secretMapper->getSecret($this->user);
if ($state !== (int) $secret->getState()) {
throw new PHPUnit_Framework_AssertionFailedError('TOTP secret has wrong state');
}
} catch (DoesNotExistException $ex) {
throw new PHPUnit_Framework_AssertionFailedError('User does not have a totp secret');
}
}

private function getValidTOTP() {
$dbSecret = $this->secretMapper->getSecret($this->user);
$secret = OC::$server->getCrypto()->decrypt($dbSecret->getSecret());
$otp = new Otp();
return $otp->totp(Base32::decode($secret));
}

private function createSecret() {
Expand All @@ -123,7 +167,7 @@ public function testLoginShouldFailWithWrongOTP() {
$this->webDriver->findElement(WebDriverBy::id('password'))->sendKeys('admin');
$this->webDriver->findElement(WebDriverBy::cssSelector('form[name=login] input[type=submit]'))->click();

$this->webDriver->wait(20, 1000)->until(function(WebDriver $driver) {
$this->webDriver->wait(20, 200)->until(function(WebDriver $driver) {
try {
return $driver->findElements(WebDriverBy::className('totp-form'));
} catch (ElementNotSelectableException $ex) {
Expand All @@ -135,7 +179,7 @@ public function testLoginShouldFailWithWrongOTP() {
$this->webDriver->findElement(WebDriverBy::name('challenge'))->sendKeys('000000');
$this->webDriver->findElement(WebDriverBy::cssSelector('button[type="submit"]'))->submit();

$this->webDriver->wait(20, 1000)->until(WebDriverExpectedCondition::elementTextContains(WebDriverBy::className('warning'), 'Error while validating your second factor'));
$this->webDriver->wait(20, 200)->until(WebDriverExpectedCondition::elementTextContains(WebDriverBy::className('warning'), 'Error while validating your second factor'));

$this->assertEquals('http://localhost:8080/index.php/login/challenge/totp', $this->webDriver->getCurrentURL());
}
Expand Down

0 comments on commit 2a85bdf

Please sign in to comment.