Skip to content

Commit

Permalink
Include SelfService SAT tests
Browse files Browse the repository at this point in the history
  • Loading branch information
MKodde committed Feb 8, 2024
1 parent d1527f5 commit 3436e87
Show file tree
Hide file tree
Showing 6 changed files with 260 additions and 49 deletions.
2 changes: 1 addition & 1 deletion stepup/tests/behat/behat
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
# For now the only feature is that it pipes on any argument provided
# to the script, into the behat command

./vendor/bin/behat --config config/behat.yml --strict $1
./vendor/bin/behat --config config/behat.yml --tags=~SKIP $1
2 changes: 2 additions & 0 deletions stepup/tests/behat/config/behat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ default:
paths: false
suites:
default:
filters:
tags: "~@wip&&~@skip"
paths:
- '%paths.base%/../features'
contexts:
Expand Down
29 changes: 10 additions & 19 deletions stepup/tests/behat/features/bootstrap/RaContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,30 +49,21 @@ public function gatherContexts(BeforeScenarioScope $scope)
}

/**
* @Given I vet my :tokenType second factor :vettingType
* @Given I vet my :tokenType second factor at the information desk
*/
public function iVetMySecondFactor(string $tokenType, string $vettingType)
public function iVetMySecondFactorAtTheInformationDesk(string $tokenType)
{
switch ($vettingType) {
case "at the information desk":
// We visit the RA location url
$this->minkContext->visit($this->raUrl);
// We visit the RA location url
$this->minkContext->visit($this->raUrl);
$this->iAmLoggedInIntoTheRaPortalAs('admin', 'yubikey');

$this->iAmLoggedInIntoTheRaPortalAs('admin', 'yubikey');
$this->iVetASpecificSecondFactor(
$tokenType,
$this->selfServiceContext->getVerifiedSecondFactorId(),
$this->selfServiceContext->getActivationCode()
);
break;
case "using self asserted token registration":
break;
default:
throw new Exception(sprintf('The %s vettingType type is not supported', $vettingType));
}
$this->iVetASpecificSecondFactor(
$tokenType,
$this->selfServiceContext->getVerifiedSecondFactorId(),
$this->selfServiceContext->getActivationCode()
);
}


/**
* @Given /^I vet the last added second factor$/
*/
Expand Down
227 changes: 206 additions & 21 deletions stepup/tests/behat/features/bootstrap/SelfServiceContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,12 @@ public function registerNewToken(string $tokenType)
$this->minkContext->getSession()
->getPage()
->find('css', '[href="/registration/sms/send-challenge"]')->click();

$this->minkContext->assertPageAddress('/registration/sms/send-challenge');
// Start registration
$this->minkContext->assertPageContainsText('Send SMS code');
$this->minkContext->assertPageContainsText('Send code');
$this->minkContext->fillField('ss_send_sms_challenge_subscriber', '612345678');
$this->minkContext->pressButton('Send code');

// Now we should be on the prove possession page where we enter our OTP
$this->minkContext->assertPageAddress('/registration/sms/prove-possession');
$this->minkContext->assertPageContainsText('Enter SMS code');
Expand Down Expand Up @@ -141,10 +141,6 @@ public function registerNewToken(string $tokenType)
default:
throw new Exception(sprintf('The %s token type is not supported', $tokenType));
}

## And we should now be on the mail verification page
$this->minkContext->assertPageContainsText('Verify your e-mail');
$this->minkContext->assertPageContainsText('Check your inbox');
}

/**
Expand Down Expand Up @@ -225,43 +221,232 @@ public function iTryToSelfVetANewYubikeyTokenWithMySMSToken()
}

/**
* @When I verify my e-mail address
* @When I verify my e-mail address and choose the :vettingType vetting type
*/
public function verifyEmailAddress()
public function verifyEmailAddress(string $vettingType)
{
## And we should now be on the mail verification page
$this->minkContext->assertPageContainsText('Verify your e-mail');
$this->minkContext->assertPageContainsText('Check your inbox');

$this->minkContext->visit(
$this->getEmailVerificationUrl()
);
$this->iChooseToActivateMyTokenUsingServiceDeskVetting();
$this->minkContext->printCurrentUrl();
$this->minkContext->assertPageContainsText('Thank you for registering your token.');

$page = $this->minkContext->getSession()->getPage();
$activationCodeCell = $page->find('xpath', '//th[text()="Activation code"]/../td');
if (!$activationCodeCell) {
throw new Exception('Could not find a activation code table on the page');
switch ($vettingType) {
case "RA vetting":
$this->iChooseToActivateMyTokenUsingServiceDeskVetting();
$this->minkContext->assertPageContainsText('Thank you for registering your token.');

$page = $this->minkContext->getSession()->getPage();
$activationCodeCell = $page->find('xpath', '//th[text()="Activation code"]/../td');
if (!$activationCodeCell) {
throw new Exception('Could not find a activation code table on the page');
}

$url = $this->minkContext->getSession()->getCurrentUrl();
$matches = [];
preg_match('#[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}#', $url, $matches);
if (empty($matches)) {
throw new Exception('Could not find a valid second factor verification id in the url');
}
$this->activationCode = $activationCodeCell->getText();
$this->verifiedSecondFactorId = reset($matches);

if (!preg_match('#[A-Z0-9]{8}#', $this->activationCode)) {
throw new Exception('Could not find a valid activation code');
}
break;
case "Self Asserted Token registration":
$this->iChooseToActivateMyTokenUsingSat();
break;
default:
throw new Exception(sprintf('Vetting type "%s" is not supported', $vettingType));
}
}

/**
* @When I choose the :vettingType vetting type
*/
public function chooseVettingType(string $vettingType)
{
switch ($vettingType) {
case "RA vetting":
$this->iChooseToActivateMyTokenUsingServiceDeskVetting();
$this->minkContext->assertPageContainsText('Thank you for registering your token.');

$page = $this->minkContext->getSession()->getPage();
$activationCodeCell = $page->find('xpath', '//th[text()="Activation code"]/../td');
if (!$activationCodeCell) {
throw new Exception('Could not find a activation code table on the page');
}

$url = $this->minkContext->getSession()->getCurrentUrl();
$matches = [];
preg_match('#[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}#', $url, $matches);
if (empty($matches)) {
throw new Exception('Could not find a valid second factor verification id in the url');
}
$this->activationCode = $activationCodeCell->getText();
$this->verifiedSecondFactorId = reset($matches);

if (!preg_match('#[A-Z0-9]{8}#', $this->activationCode)) {
throw new Exception('Could not find a valid activation code');
}
break;
case "Self Asserted Token registration":
$this->iChooseToActivateMyTokenUsingSat();
break;
default:
throw new Exception(sprintf('Vetting type "%s" is not supported', $vettingType));
}
}

$url = $this->minkContext->getSession()->getCurrentUrl();
/**
* @Given I vet my :tokenType second factor in selfservice
*/
public function iVetMySecondFactorInSelfService(string $tokenType)
{
$url = $this->minkContext->getSession()->getCurrentUrl();
$matches = [];
preg_match('#[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}#', $url, $matches);
if (empty($matches)) {
throw new Exception('Could not find a valid second factor verification id in the url');
}
$this->activationCode = $activationCodeCell->getText();
$this->verifiedSecondFactorId = reset($matches);
$secondFactorId = reset($matches);
$this->minkContext->assertPageAddress(sprintf('/second-factor/%s/new-recovery-token', $secondFactorId));

if (!preg_match('#[A-Z0-9]{8}#', $this->activationCode)) {
throw new Exception('Could not find a valid activation code');
$page = $this->minkContext->getSession()->getPage();
$form = $page->find('css', 'form[name="safe-store"]');
$form->submit();
// Todo store the safe store password for later use?
$this->minkContext->assertPageAddress(sprintf('/second-factor/%s/safe-store', $secondFactorId));
// Promise we safely stored the secret
$this->minkContext->checkOption('ss_promise_recovery_token_possession_promisedPossession');
preg_match('#[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}#', $url, $matches);
if (empty($matches)) {
throw new Exception('Could not find a valid second factor verification id in the url');
}
// Update the SF id, it now refers to the vetted second factor id
$secondFactorId = reset($matches);
$this->minkContext->pressButton('Continue');
// We are back on the overview page. The revoke button is on the page (indicating the token was vetted)
$this->minkContext->assertPageAddress('/overview');
echo $secondFactorId;
$this->minkContext->assertResponseContains(sprintf('/second-factor/vetted/%s/revoke', $secondFactorId));
// The recovery token should also be present
$this->minkContext->assertPageContainsText('Recovery methods');
$this->minkContext->assertPageContainsText('Recovery code');
$this->minkContext->assertResponseContains('/recovery-token/delete/');
}

public function iChooseToActivateMyTokenUsingServiceDeskVetting()
{
$this->minkContext->assertPageContainsText('Activate your token');
$this->minkContext->pressButton('ra-vetting-button');
}
public function iChooseToActivateMyTokenUsingSAT()
{
$this->minkContext->assertPageContainsText('Activate your token yourself');
$this->minkContext->pressButton('sat-button');
}

/**
* @Then I can add an :recoveryTokenType recovery token using :tokenType
*/
public function iCanAddAnRecoveryToken(string $recoveryTokenType, string $tokenType)
{
$this->minkContext->assertPageContainsText('Add recovery method');
$this->minkContext->clickLink('Add recovery method');
switch ($recoveryTokenType){
case 'SMS':
$this->minkContext->assertPageContainsText('You\'ll receive a text message with a verification code');
$page = $this->minkContext->getSession()->getPage();
$form = $page->find('css', 'form[name="sms"]');
$form->submit();
$this->provePossession($tokenType);
// Now you need to register your SMS recovery token
$this->minkContext->assertPageContainsText('Register an SMS recovery token');
$this->minkContext->fillField('ss_send_sms_challenge_subscriber', '615056898');
$this->minkContext->pressButton('Send code');

$this->minkContext->assertPageAddress('/recovery-token/prove-sms-possession');
$this->minkContext->assertPageContainsText('Enter the code that was sent to your phone');
$this->minkContext->fillField('ss_verify_sms_challenge_challenge', '123456');
$this->minkContext->pressButton('Verify');
break;
default:
throw new Exception(sprintf('Recovery token type %s is not supported', $recoveryTokenType));
}
}

private function provePossession(string $tokenType)
{
switch ($tokenType) {
case "Demo GSSP":
// We first need to prove we are in possession of our 2nd factor
$this->minkContext->pressButton('Yes, continue');
// Press the Authenticate button on the Demo authentication page
$this->minkContext->assertPageAddress('https://demogssp.dev.openconext.local/authentication');
$this->minkContext->pressButton('button_authenticate');
// Pass through the Demo Gssp redirection page.
$this->minkContext->assertPageAddress('https://demogssp.dev.openconext.local/saml/sso_return');
$this->minkContext->pressButton('Submit');
// Pass through the 'return to sp' redirection page.
$this->minkContext->assertPageAddress('https://gateway.dev.openconext.local/gssp/demo_gssp/consume-assertion');
$this->minkContext->pressButton('Submit');

break;
case "Yubikey":
$this->minkContext->pressButton('Yes, continue');
$this->performYubikeyAuthentication();
break;

default:
throw new Exception(sprintf('Prove possession is not yet supported for token type %s', $tokenType));
}
}

/**
* @Then I can not add a :recoveryTokenType recovery token
*/
public function iCanNotAddARecoveryToken($recoveryTokenType)
{
$this->minkContext->visit('/overview');
$this->minkContext->assertPageNotContainsText('Add recovery method');
}

/**
* @Then :nofRecoveryTokens recovery tokens are activated
*/
public function numberOfTokensRegistered(int $nofRecoveryTokens)
{
$page = $this->minkContext->getMink()->getSession()->getPage();
$tokenTypes = $page->findAll('css', 'tr[data-test_tokentype]');

if (empty($tokenTypes)) {
throw new Exception('No active recovery tokens found on the page');
}

if (count($tokenTypes) != $nofRecoveryTokens) {
throw new Exception(
sprintf(
'Excpected to find %d recovery tokens on the page, actually found %d tokens',
$nofRecoveryTokens,
count($tokenTypes)
)
);
}
}

private function performYubikeyAuthentication()
{
$this->minkContext->fillField('gateway_verify_yubikey_otp_otp', 'ccccccdhgrbtfddefpkffhkkukbgfcdilhiltrrncmig');
$page = $this->minkContext->getSession()->getPage();
$form = $page->find('css', 'form[name="gateway_verify_yubikey_otp"]');
$form->submit();
$this->minkContext->pressButton('Submit');
}

/**
* @Given /^I visit the "([^"]*)" page in the selfservice portal$/
Expand Down
16 changes: 8 additions & 8 deletions stepup/tests/behat/features/selfservice.feature
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,26 @@ Feature: A user manages his tokens in the SelfService portal
Scenario: A user registers a SMS token in selfservice using RA vetting
Given I am logged in into the selfservice portal as "joe-a1"
When I register a new "SMS" token
And I verify my e-mail address
And I verify my e-mail address and choose the "RA vetting" vetting type
And I vet my "SMS" second factor at the information desk

Scenario: A user registers a Yubikey token in selfservice using RA vetting
Given I am logged in into the selfservice portal as "joe-a2"
When I register a new "Yubikey" token
And I verify my e-mail address
And I verify my e-mail address and choose the "RA vetting" vetting type
And I vet my "Yubikey" second factor at the information desk

Scenario: A user registers a Demo GSSP token in selfservice using RA vetting
Given I am logged in into the selfservice portal as "joe-a3"
When I register a new "Demo GSSP" token
And I verify my e-mail address
And I verify my e-mail address and choose the "RA vetting" vetting type
And I vet my "Demo GSSP" second factor at the information desk

Scenario: A user registers a Demo GSSP token in selfservice using RA vetting
Given I am logged in into the selfservice portal as "joe-a3"
When I register a new "Demo GSSP" token
And I verify my e-mail address
And I vet my "Demo GSSP" second factor at the information desk
Scenario: A user registers a SMS token in selfservice using RA vetting without mail verification
Given I am logged in into the selfservice portal as "joe-b1"
When I register a new "Yubikey" token
And I choose the "RA vetting" vetting type
And I vet my "Yubikey" second factor at the information desk

Scenario: After token registration, the token can be viewed on the token overview page
Given I am logged in into the selfservice portal as "joe-a1"
Expand Down
33 changes: 33 additions & 0 deletions stepup/tests/behat/features/selfservice_sat.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
Feature: A user manages his tokens in the SelfService portal
In order to SAT register a second factor token
As a user
I must be able to manage my second factor tokens

Scenario: A user registers a SMS token in selfservice using SAT
Given I am logged in into the selfservice portal as "user-a1"
When I register a new "SMS" token
And I verify my e-mail address and choose the "Self Asserted Token registration" vetting type
And I vet my "SMS" second factor in selfservice
And "1" recovery tokens are activated

Scenario: A user registers a Yubikey token in selfservice using SAT
Given I am logged in into the selfservice portal as "user-a2"
When I register a new "Yubikey" token
And I verify my e-mail address and choose the "Self Asserted Token registration" vetting type
And I vet my "Yubikey" second factor in selfservice
And "1" recovery tokens are activated

Scenario: A user registers a Demo GSSP token in selfservice using SAT
Given I am logged in into the selfservice portal as "user-a3"
When I register a new "Demo GSSP" token
And I verify my e-mail address and choose the "Self Asserted Token registration" vetting type
And I vet my "Demo GSSP" second factor in selfservice
And "1" recovery tokens are activated

Scenario: A user can register an additional recovery token
Given I am logged in into the selfservice portal as "user-a4"
When I register a new "Yubikey" token
And I verify my e-mail address and choose the "Self Asserted Token registration" vetting type
And I vet my "Yubikey" second factor in selfservice
Then I can add an "SMS" recovery token using "Yubikey"
And "2" recovery tokens are activated

0 comments on commit 3436e87

Please sign in to comment.