Skip to content

Commit

Permalink
Add acceptance test for TOTP verification through webUI
Browse files Browse the repository at this point in the history
  • Loading branch information
skshetry authored and individual-it committed Feb 11, 2019
1 parent 02894ef commit 9400b95
Show file tree
Hide file tree
Showing 5 changed files with 225 additions and 3 deletions.
27 changes: 26 additions & 1 deletion .drone.yml
Original file line number Diff line number Diff line change
Expand Up @@ -309,4 +309,29 @@ matrix:
NEED_CORE: true
NEED_INSTALL_APP: true
NEED_SERVER: true
USE_EMAIL: true
USE_EMAIL: true

- PHP_VERSION: 7.1
DB_TYPE: mysql
OC_VERSION: daily-master-qa
TEST_SUITE: web-acceptance
BEHAT_SUITE: webUITwoFactorTOTP
DB_NAME: oc_db
DB_USERNAME: admin
DB_PASSWORD: secret
NEED_CORE: true
NEED_INSTALL_APP: true
NEED_SERVER: true

- PHP_VERSION: 7.0
DB_TYPE: mysql
OC_VERSION: daily-stable10-qa
TEST_SUITE: web-acceptance
BEHAT_SUITE: webUITwoFactorTOTP
DB_NAME: oc_db
DB_USERNAME: admin
DB_PASSWORD: secret
NEED_CORE: true
NEED_INSTALL_APP: true
NEED_SERVER: true
USE_EMAIL: true
11 changes: 11 additions & 0 deletions tests/acceptance/config/behat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,17 @@ default:
- WebUIPersonalSecuritySettingsContext:
- WebUILoginContext:

webUITwoFactorTOTP:
paths:
- '%paths.base%/../features/webUITwoFactorTOTP'
contexts:
- TwoFactorTOTPContext:
- FeatureContext: *common_feature_context_params
- OccContext:
- WebUIGeneralContext:
- WebUIPersonalSecuritySettingsContext:
- WebUILoginContext:

extensions:
jarnaiz\JUnitFormatter\JUnitFormatterExtension:
filename: report.xml
Expand Down
94 changes: 93 additions & 1 deletion tests/acceptance/features/bootstrap/TwoFactorTOTPContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@
*/

use Behat\Behat\Context\Context;
use Behat\MinkExtension\Context\RawMinkContext;
use Page\PersonalSecuritySettingsPageWithTOTPEnabled;
use Otp\Otp;
use Base32\Base32;

require_once 'bootstrap.php';

Expand All @@ -35,6 +36,34 @@ class TwoFactorTOTPContext implements Context {
*/
private $personalSecuritySettingsPage;

/**
* @var bool
*/
private $totpUsed = false;

/**
* @var string
*/
private $totpSecret;

/**
* Returns secret key
*
* @return string
*/
private function getSecret() {
return $this->totpSecret;
}

/**
* Generate One time key for login from secret
*
* @return string
*/
private function generateTOTPKey() {
$otp = new Otp();
return $otp->totp(Base32::decode($this->getSecret()));
}
/**
* WebUIPersonalSecuritySettingsTOTPEnabledContext constructor.
*
Expand All @@ -49,10 +78,73 @@ public function __construct(

/**
* @Given /^the user has activated TOTP Second\-factor auth but not verified$/
* @When /^the user activates TOTP Second\-factor auth but does not verify$/
*
* @return void
*/
public function theUserHasActivatedTOTPSecondFactorAuthButNotVerified() {
$this->personalSecuritySettingsPage->activateTOTP();
$this->totpSecret = $this->personalSecuritySettingsPage->getSecretCode();
}

/**
* Returns secret code extracted from QRCode
*
* @return string
*/
public function getSecretCodeFromQRCode() {
$path = \tempnam(\sys_get_temp_dir(), 'totp_qrcode');
$data = \explode(',', $this->personalSecuritySettingsPage->getQRCode());
$file = \fopen($path, 'wb');
\fwrite($file, \base64_decode($data[1]));
$qrCode = new QrReader($path);
\preg_match('/secret=(?P<secret>[A-Z0-9]{16})/', $qrCode->text(), $matches);
return $matches['secret'];
}

/**
* @When the user adds one-time key generated from the secret key using the webUI
*
* @throws \Exception
*
* @return void
*/
public function theUserAddsVerficationKeyFromSecretKeyToVerifyUsingWebUI() {
if (!$this->totpUsed) {
$this->personalSecuritySettingsPage->addVerificationKey(
$this->generateTOTPKey()
);
$this->totpUsed = true;
} else {
throw new \Exception(
'TOTP Already used.' .
'Key generation multiple times is not supported ' .
'due to the possibility of same key generation.'
);
}
}

/**
* @Then the TOTP secret key should be verified on the webUI
*
* @return void
*/
public function totpSecretKeyShouldBeVerifiecOnTheWebUI() {
PHPUnit_Framework_Assert::assertTrue(
$this->personalSecuritySettingsPage->isKeyVerified(),
'The key could not be verified'
);
}

/**
* @Then /^the secret code from QR code should match with the one displayed on the webUI$/
*
* @return void
*/
public function theSecretCodeFromQRCodeShouldMatchWithTheOneDisplayedOnTheWebUI() {
PHPUnit_Framework_Assert::assertEquals(
$this->getSecretCodeFromQRCode(),
$this->personalSecuritySettingsPage->getSecretCode()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
class PersonalSecuritySettingsPageWithTOTPEnabled extends PersonalSecuritySettingsPage {
private $activateTOTPLabelXpath = '//label[@for="totp-enabled"]';
private $qrCodeImageXpath = '//div[@id="twofactor-totp-settings"]//img';
private $secretCodeXpath = '//div[@id="twofactor-totp-settings"]//div/span';
private $verificationFieldXpath = '//input[@id="totp-challenge"]';
private $totpVerifyMsgXpath = '//span[@id="totp-verify-msg"]';
private $verifySubmissionBtnXpath = '//button[@id="totp-verify-secret"]';

/**
* Activate TOTP for the user
Expand All @@ -43,7 +47,74 @@ public function activateTOTP() {
__METHOD__ . " Label not found to activate TOTP"
);
$label->click();
}

$this->waitTillElementIsNotNull($this->qrCodeImageXpath);
/**
* Returns QR Code image in base64
*
* @return string
*/
public function getQRCode() {
$image = $this->waitTillElementIsNotNull($this->qrCodeImageXpath);
$this->assertElementNotNull(
$image,
__METHOD__ . ' QR code not found on the webUI'
);
return $image->getAttribute("src");
}

/**
* Returns secret code from the activity page
*
* @return string
*/
public function getSecretCode() {
$secret = $this->waitTillElementIsNotNull($this->secretCodeXpath);
$this->assertElementNotNull(
$secret,
__METHOD__ . ' Secret code not found on the webUI'
);
$parts = \explode(':', $secret->getText());
return \trim($parts[1]);
}

/**
* Verifies 2fa by filling the $key
*
* @param string $key
*
* @return void
*/
public function addVerificationKey($key) {
$field = $this->waitTillElementIsNotNull($this->verificationFieldXpath);
$this->assertElementNotNull(
$field,
__METHOD__ . ' Field for adding verification code could not be found'
);
$field->setValue($key);

$submit_btn = $this->find("xpath", $this->verifySubmissionBtnXpath);
$this->assertElementNotNull(
$submit_btn,
__METHOD__ . ' Button for code submission could not be found'
);
$submit_btn->click();
}

/**
* Returns true if verified
*
* The message remains visible for a few seconds only. So, we need to call
* this just after calling addVerificationKey method.
*
* @return bool
*/
public function isKeyVerified() {
$verificationMsg = $this->waitTillElementIsNotNull($this->totpVerifyMsgXpath);
$this->assertElementNotNull(
$verificationMsg,
__METHOD__ . ' The verification msg could not be found'
);
return ($verificationMsg->getText() === 'Verified');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
@webUI @insulated
Feature: Testing Two factor TOTP
As a admin
I want to be able to verify secrets from webUI
So that the users can use two factor auth from TOTP key

Background:
Given user "newly-created-user" has been created with default attributes
And using OCS API version "2"

Scenario: Verify using the key generated from the secret
Given user "newly-created-user" has logged in using the webUI
And the user has browsed to the personal security settings page
And the user has activated TOTP Second-factor auth but not verified
When the user adds one-time key generated from the secret key using the webUI
Then the TOTP secret key should be verified on the webUI
And user "newly-created-user" using password "%regularuser%" should not be able to download file "textfile0.txt"

Scenario: The secret code from qr code should match with the one displayed in the page
Given user "newly-created-user" has logged in using the webUI
And the user has browsed to the personal security settings page
When the user activates TOTP Second-factor auth but does not verify
Then the secret code from QR code should match with the one displayed on the webUI

0 comments on commit 9400b95

Please sign in to comment.