Finish migrating integration tests to mocha.
parent
85d3adc3e3
commit
50d4ab1368
|
@ -1,34 +0,0 @@
|
|||
Feature: User is redirected when factors are already validated
|
||||
|
||||
@need-registered-user-john
|
||||
Scenario: User has validated first factor and tries to access service protected by second factor. He is then redirect to second factor step.
|
||||
When I visit "https://single_factor.example.com:8080/secret.html"
|
||||
And I'm redirected to "https://login.example.com:8080/?rd=https://single_factor.example.com:8080/secret.html"
|
||||
And I login with user "john" and password "password"
|
||||
And I'm redirected to "https://single_factor.example.com:8080/secret.html"
|
||||
And I visit "https://public.example.com:8080/secret.html"
|
||||
Then I'm redirected to "https://login.example.com:8080/secondfactor?rd=https://public.example.com:8080/secret.html"
|
||||
|
||||
@need-registered-user-john
|
||||
Scenario: User who has validated second factor and access auth portal should be redirected to "Already logged in page" and redirected to default URL declared in configuration
|
||||
When I visit "https://public.example.com:8080/secret.html"
|
||||
And I'm redirected to "https://login.example.com:8080/?rd=https://public.example.com:8080/secret.html"
|
||||
And I login with user "john" and password "password"
|
||||
And I use "REGISTERED" as TOTP token handle
|
||||
And I click on "Sign in"
|
||||
And I'm redirected to "https://public.example.com:8080/secret.html"
|
||||
And I visit "https://login.example.com:8080"
|
||||
Then I'm redirected to "https://login.example.com:8080/loggedin"
|
||||
And I sleep for 5 seconds
|
||||
And I'm redirected to "https://home.example.com:8080/"
|
||||
|
||||
@need-registered-user-john
|
||||
Scenario: User who has validated second factor and access auth portal with rediction param should be redirected to that URL
|
||||
When I visit "https://public.example.com:8080/secret.html"
|
||||
And I'm redirected to "https://login.example.com:8080/?rd=https://public.example.com:8080/secret.html"
|
||||
And I login with user "john" and password "password"
|
||||
And I use "REGISTERED" as TOTP token handle
|
||||
And I click on "Sign in"
|
||||
And I'm redirected to "https://public.example.com:8080/secret.html"
|
||||
And I visit "https://login.example.com:8080?rd=https://public.example.com:8080/secret.html"
|
||||
Then I'm redirected to "https://public.example.com:8080/secret.html"
|
|
@ -1,5 +0,0 @@
|
|||
Feature: Authentication scenarii
|
||||
|
||||
Scenario: Logout redirects user to redirect URL given in parameter
|
||||
When I visit "https://login.example.com:8080/logout?rd=https://home.example.com:8080/"
|
||||
Then I'm redirected to "https://home.example.com:8080/"
|
|
@ -1,71 +0,0 @@
|
|||
Feature: User is correctly redirected
|
||||
|
||||
Scenario: User is redirected to authelia when he is not authenticated
|
||||
When I visit "https://public.example.com:8080"
|
||||
Then I'm redirected to "https://login.example.com:8080/?rd=https://public.example.com:8080/"
|
||||
|
||||
@need-registered-user-john
|
||||
Scenario: User is redirected to home page after several authentication tries
|
||||
When I visit "https://public.example.com:8080/secret.html"
|
||||
And I login with user "john" and password "badpassword"
|
||||
And I wait for notification to disappear
|
||||
And I clear field "username"
|
||||
And I clear field "password"
|
||||
And I login with user "john" and password "password"
|
||||
And I use "REGISTERED" as TOTP token handle
|
||||
And I click on "Sign in"
|
||||
Then I'm redirected to "https://public.example.com:8080/secret.html"
|
||||
|
||||
Scenario: User Harry does not have access to admin domain and thus he must get an error 403
|
||||
When I register TOTP and login with user "harry" and password "password"
|
||||
And I visit "https://admin.example.com:8080/secret.html"
|
||||
Then I get an error 403
|
||||
|
||||
Scenario: Redirection URL is propagated from restricted page to first factor
|
||||
When I visit "https://public.example.com:8080/secret.html"
|
||||
Then I'm redirected to "https://login.example.com:8080/?rd=https://public.example.com:8080/secret.html"
|
||||
|
||||
Scenario: Redirection URL is propagated from first factor to second factor
|
||||
Given I visit "https://login.example.com:8080/"
|
||||
And I login with user "john" and password "password"
|
||||
And I register a TOTP secret called "Sec0"
|
||||
When I visit "https://public.example.com:8080/secret.html"
|
||||
And I login with user "john" and password "password"
|
||||
Then I'm redirected to "https://login.example.com:8080/secondfactor?rd=https://public.example.com:8080/secret.html"
|
||||
|
||||
Scenario: Redirection URL is used to send user from second factor to target page
|
||||
Given I visit "https://login.example.com:8080/"
|
||||
And I login with user "john" and password "password"
|
||||
And I register a TOTP secret called "Sec0"
|
||||
When I visit "https://public.example.com:8080/secret.html"
|
||||
And I login with user "john" and password "password"
|
||||
And I use "Sec0" as TOTP token handle
|
||||
And I click on "Sign in"
|
||||
Then I'm redirected to "https://public.example.com:8080/secret.html"
|
||||
|
||||
@need-registered-user-john
|
||||
Scenario: User is redirected to default URL defined in configuration when authentication is successful
|
||||
When I visit "https://login.example.com:8080"
|
||||
And I login with user "john" and password "password"
|
||||
And I use "REGISTERED" as TOTP token handle
|
||||
And I click on "Sign in"
|
||||
Then I'm redirected to "https://home.example.com:8080/"
|
||||
|
||||
|
||||
Scenario: User is redirected when hitting an error 401
|
||||
When I visit "https://login.example.com:8080/secondfactor/u2f/identity/finish"
|
||||
Then I'm redirected to "https://login.example.com:8080/error/401"
|
||||
And I sleep for 5 seconds
|
||||
And I'm redirected to "https://home.example.com:8080/"
|
||||
|
||||
@need-registered-user-harry
|
||||
Scenario: User is redirected when hitting an error 403
|
||||
When I visit "https://login.example.com:8080"
|
||||
And I login with user "harry" and password "password"
|
||||
And I use "REGISTERED" as TOTP token handle
|
||||
And I click on "Sign in"
|
||||
And I'm redirected to "https://home.example.com:8080/"
|
||||
When I visit "https://admin.example.com:8080/secret.html"
|
||||
Then I'm redirected to "https://login.example.com:8080/error/403"
|
||||
And I sleep for 5 seconds
|
||||
And I'm redirected to "https://home.example.com:8080/"
|
|
@ -1,17 +0,0 @@
|
|||
import {Then} from "cucumber";
|
||||
|
||||
Then("I have access to {string}", function(url: string) {
|
||||
const that = this;
|
||||
return this.driver.get(url)
|
||||
.then(function () {
|
||||
return that.waitUntilUrlContains(url);
|
||||
});
|
||||
});
|
||||
|
||||
Then("I have no access to {string}", function(url: string) {
|
||||
const that = this;
|
||||
return this.driver.get(url)
|
||||
.then(function () {
|
||||
return that.getErrorPage(403);
|
||||
});
|
||||
});
|
|
@ -1,44 +0,0 @@
|
|||
import {Before, When, Then} from "cucumber";
|
||||
import seleniumWebdriver = require("selenium-webdriver");
|
||||
import Assert = require("assert");
|
||||
import Request = require("request-promise");
|
||||
import Bluebird = require("bluebird");
|
||||
|
||||
When("I query {string}", function (url: string) {
|
||||
const that = this;
|
||||
return Request(url, { followRedirect: false })
|
||||
.then(function(response) {
|
||||
that.response = response;
|
||||
})
|
||||
.catch(function(err: Error) {
|
||||
that.error = err;
|
||||
})
|
||||
});
|
||||
|
||||
Then("I get error code 401", function() {
|
||||
const that = this;
|
||||
return new Bluebird(function(resolve, reject) {
|
||||
if(that.error && that.error.statusCode == 401) {
|
||||
resolve();
|
||||
}
|
||||
else {
|
||||
if(that.response)
|
||||
reject(new Error("No error thrown"));
|
||||
else if(that.error.statusCode != 401)
|
||||
reject(new Error(`Error code (${that.error.statusCode}) != 401`));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Then("I get redirected to {string}", function(url: string) {
|
||||
const that = this;
|
||||
return new Bluebird(function(resolve, reject) {
|
||||
if(that.error && that.error.statusCode == 302
|
||||
&& that.error.message.indexOf(url) > -1) {
|
||||
resolve();
|
||||
}
|
||||
else {
|
||||
reject(new Error("Not redirected"));
|
||||
}
|
||||
});
|
||||
});
|
|
@ -1,99 +0,0 @@
|
|||
import {Given, When, Then, TableDefinition} from "cucumber";
|
||||
import seleniumWebdriver = require("selenium-webdriver");
|
||||
import Assert = require("assert");
|
||||
import Fs = require("fs");
|
||||
import Speakeasy = require("speakeasy");
|
||||
import CustomWorld = require("../support/world");
|
||||
import BluebirdPromise = require("bluebird");
|
||||
import Request = require("request-promise");
|
||||
|
||||
When(/^I visit "(https:\/\/[a-zA-Z0-9:%&._\/=?-]+)"$/, function (link: string) {
|
||||
return this.visit(link);
|
||||
});
|
||||
|
||||
When("I wait for notification to disappear", function () {
|
||||
const that = this;
|
||||
const notificationEl = this.driver.findElement(seleniumWebdriver.By.className("notification"));
|
||||
return this.driver.wait(seleniumWebdriver.until.elementIsVisible(notificationEl), 15000)
|
||||
.then(function () {
|
||||
return that.driver.wait(seleniumWebdriver.until.elementIsNotVisible(notificationEl), 15000);
|
||||
})
|
||||
})
|
||||
|
||||
When("I set field {string} to {string}", function (fieldName: string, content: string) {
|
||||
return this.setFieldTo(fieldName, content);
|
||||
});
|
||||
|
||||
When("I clear field {string}", function (fieldName: string) {
|
||||
return this.clearField(fieldName);
|
||||
});
|
||||
|
||||
When("I click on {string}", function (text: string) {
|
||||
return this.clickOnButton(text);
|
||||
});
|
||||
|
||||
Given("I login with user {string} and password {string}",
|
||||
function (username: string, password: string) {
|
||||
return this.loginWithUserPassword(username, password);
|
||||
});
|
||||
|
||||
Given("I login with user {string} and password {string} \
|
||||
and I use TOTP token handle {string}",
|
||||
function (username: string, password: string, totpTokenHandle: string) {
|
||||
const that = this;
|
||||
return this.loginWithUserPassword(username, password)
|
||||
.then(function () {
|
||||
return that.useTotpTokenHandle(totpTokenHandle);
|
||||
});
|
||||
});
|
||||
|
||||
Given("I register a TOTP secret called {string}", function (handle: string) {
|
||||
return this.registerTotpSecret(handle);
|
||||
});
|
||||
|
||||
Given("I use {string} as TOTP token", function (token: string) {
|
||||
return this.useTotpToken(token);
|
||||
});
|
||||
|
||||
Given("I use {string} as TOTP token handle", function (handle) {
|
||||
return this.useTotpTokenHandle(handle);
|
||||
});
|
||||
|
||||
When("I visit {string} and get redirected {string}",
|
||||
function (url: string, redirectUrl: string) {
|
||||
const that = this;
|
||||
return this.driver.get(url)
|
||||
.then(function () {
|
||||
return that.driver.wait(seleniumWebdriver.until.urlIs(redirectUrl), 5000);
|
||||
});
|
||||
});
|
||||
|
||||
Given("I register TOTP and login with user {string} and password {string}",
|
||||
function (username: string, password: string) {
|
||||
return this.registerTotpAndSignin(username, password);
|
||||
});
|
||||
|
||||
function endpointReplyWith(context: any, link: string, method: string,
|
||||
returnCode: number) {
|
||||
return Request(link, {
|
||||
method: method
|
||||
})
|
||||
.then(function (response: string) {
|
||||
Assert(response.indexOf("Error " + returnCode) >= 0);
|
||||
return BluebirdPromise.resolve();
|
||||
}, function (response: any) {
|
||||
Assert.equal(response.statusCode, returnCode);
|
||||
return BluebirdPromise.resolve();
|
||||
});
|
||||
}
|
||||
|
||||
Then("the following endpoints reply with:", function (dataTable: TableDefinition) {
|
||||
const promises = [];
|
||||
for (let i = 0; i < dataTable.rows().length; i++) {
|
||||
const url: string = (dataTable.hashes() as any)[i].url;
|
||||
const method: string = (dataTable.hashes() as any)[i].method;
|
||||
const code: number = (dataTable.hashes() as any)[i].code;
|
||||
promises.push(endpointReplyWith(this, url, method, code));
|
||||
}
|
||||
return BluebirdPromise.all(promises);
|
||||
});
|
|
@ -1,19 +0,0 @@
|
|||
import {Then} from "cucumber";
|
||||
import seleniumWebdriver = require("selenium-webdriver");
|
||||
import CustomWorld = require("../support/world");
|
||||
import Util = require("util");
|
||||
import Bluebird = require("bluebird");
|
||||
import Request = require("request-promise");
|
||||
|
||||
Then("I see header {string} set to {string}",
|
||||
{ timeout: 5000 },
|
||||
function (expectedHeaderName: string, expectedValue: string) {
|
||||
return this.driver.findElement(seleniumWebdriver.By.tagName("body")).getText()
|
||||
.then(function (txt: string) {
|
||||
const expectedLine = Util.format("\"%s\": \"%s\"", expectedHeaderName, expectedValue);
|
||||
if (txt.indexOf(expectedLine) > 0)
|
||||
return Bluebird.resolve();
|
||||
else
|
||||
return Bluebird.reject(new Error(Util.format("No such header or with unexpected value.")));
|
||||
});
|
||||
})
|
|
@ -1,173 +0,0 @@
|
|||
import {setDefaultTimeout, After, Before, BeforeAll, AfterAll} from "cucumber";
|
||||
import fs = require("fs");
|
||||
import BluebirdPromise = require("bluebird");
|
||||
import ChildProcess = require("child_process");
|
||||
import { UserDataStore } from "../../../server/src/lib/storage/UserDataStore";
|
||||
import { CollectionFactoryFactory } from "../../../server/src/lib/storage/CollectionFactoryFactory";
|
||||
import { IMongoClient } from "../../../server/src/lib/connectors/mongo/IMongoClient";
|
||||
import { TotpHandler } from "../../../server/src/lib/authentication/totp/TotpHandler";
|
||||
import Speakeasy = require("speakeasy");
|
||||
import Request = require("request-promise");
|
||||
import { TOTPSecret } from "../../../server/types/TOTPSecret";
|
||||
import Environment = require("../../environment");
|
||||
import { MongoClient } from "../../../server/src/lib/connectors/mongo/MongoClient";
|
||||
import { GlobalLogger } from "../../../server/src/lib/logging/GlobalLogger";
|
||||
import { GlobalLoggerStub } from "../../../server/src/lib/logging/GlobalLoggerStub.spec";
|
||||
|
||||
setDefaultTimeout(30 * 1000);
|
||||
|
||||
const exec = BluebirdPromise.promisify<any, any>(ChildProcess.exec);
|
||||
|
||||
const includes = [
|
||||
"docker-compose.yml",
|
||||
"example/compose/docker-compose.base.yml",
|
||||
"example/compose/mongo/docker-compose.yml",
|
||||
"example/compose/redis/docker-compose.yml",
|
||||
"example/compose/nginx/backend/docker-compose.yml",
|
||||
"example/compose/nginx/portal/docker-compose.yml",
|
||||
"example/compose/smtp/docker-compose.yml",
|
||||
"example/compose/httpbin/docker-compose.yml",
|
||||
"example/compose/ldap/docker-compose.yml"
|
||||
]
|
||||
|
||||
const environment = new Environment.Environment(includes);
|
||||
|
||||
BeforeAll(function() {
|
||||
return environment.setup(10000);
|
||||
});
|
||||
|
||||
AfterAll(function() {
|
||||
return environment.cleanup()
|
||||
});
|
||||
|
||||
Before(function () {
|
||||
this.jar = Request.jar();
|
||||
})
|
||||
|
||||
After(function () {
|
||||
return this.driver.quit();
|
||||
});
|
||||
|
||||
function createRegulationConfiguration(): BluebirdPromise<void> {
|
||||
return exec("\
|
||||
cat config.template.yml | \
|
||||
sed 's/find_time: [0-9]\\+/find_time: 15/' | \
|
||||
sed 's/ban_time: [0-9]\\+/ban_time: 4/' > config.test.yml \
|
||||
");
|
||||
}
|
||||
|
||||
function createInactivityConfiguration(): BluebirdPromise<void> {
|
||||
return exec("\
|
||||
cat config.template.yml | \
|
||||
sed 's/expiration: [0-9]\\+/expiration: 10000/' | \
|
||||
sed 's/inactivity: [0-9]\\+/inactivity: 5000/' > config.test.yml \
|
||||
");
|
||||
}
|
||||
|
||||
function createSingleFactorConfiguration(): BluebirdPromise<void> {
|
||||
return exec("\
|
||||
cat config.template.yml | \
|
||||
sed 's/default_method: two_factor/default_method: single_factor/' > config.test.yml \
|
||||
");
|
||||
}
|
||||
|
||||
function createCustomTotpIssuerConfiguration(): BluebirdPromise<void> {
|
||||
return exec("\
|
||||
cat config.template.yml | \
|
||||
sed 's/issuer: authelia.com/issuer: custom.com/' > config.test.yml \
|
||||
");
|
||||
}
|
||||
|
||||
function declareNeedsConfiguration(tag: string, cb: () => BluebirdPromise<void>) {
|
||||
Before({ tags: "@needs-" + tag + "-config", timeout: 20 * 1000 }, function () {
|
||||
return cb()
|
||||
.then(function () {
|
||||
return exec("./scripts/example-commit/dc-example.sh -f " +
|
||||
"./example/compose/authelia/docker-compose.test.yml up -d authelia &&" +
|
||||
" sleep 3");
|
||||
})
|
||||
});
|
||||
|
||||
After({ tags: "@needs-" + tag + "-config", timeout: 20 * 1000 }, function () {
|
||||
return exec("rm config.test.yml")
|
||||
.then(function () {
|
||||
return exec("./scripts/example-commit/dc-example.sh up -d authelia && sleep 3");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
declareNeedsConfiguration("regulation", createRegulationConfiguration);
|
||||
declareNeedsConfiguration("inactivity", createInactivityConfiguration);
|
||||
declareNeedsConfiguration("single_factor", createSingleFactorConfiguration);
|
||||
declareNeedsConfiguration("totp_issuer", createCustomTotpIssuerConfiguration);
|
||||
|
||||
function registerUser(context: any, username: string) {
|
||||
let secret: TOTPSecret;
|
||||
const mongoClient = new MongoClient({
|
||||
url: "mongodb://localhost:27017",
|
||||
database: "authelia",
|
||||
auth: {
|
||||
username: "authelia",
|
||||
password: "authelia"
|
||||
}
|
||||
}, new GlobalLoggerStub());
|
||||
const collectionFactory = CollectionFactoryFactory.createMongo(mongoClient);
|
||||
const userDataStore = new UserDataStore(collectionFactory);
|
||||
|
||||
const generator = new TotpHandler(Speakeasy);
|
||||
secret = generator.generate("user", "authelia.com");
|
||||
return userDataStore.saveTOTPSecret(username, secret)
|
||||
.then(function () {
|
||||
context.totpSecrets["REGISTERED"] = secret.base32;
|
||||
return mongoClient.close();
|
||||
});
|
||||
}
|
||||
|
||||
function declareNeedRegisteredUserHooks(username: string) {
|
||||
Before({ tags: "@need-registered-user-" + username, timeout: 15 * 1000 }, function () {
|
||||
return registerUser(this, username);
|
||||
});
|
||||
|
||||
After({ tags: "@need-registered-user-" + username, timeout: 15 * 1000 }, function () {
|
||||
this.totpSecrets["REGISTERED"] = undefined;
|
||||
return BluebirdPromise.resolve();
|
||||
});
|
||||
}
|
||||
|
||||
function needAuthenticatedUser(context: any, username: string): BluebirdPromise<void> {
|
||||
return context.visit("https://login.example.com:8080/logout")
|
||||
.then(function () {
|
||||
return context.visit("https://login.example.com:8080/");
|
||||
})
|
||||
.then(function () {
|
||||
return registerUser(context, username);
|
||||
})
|
||||
.then(function () {
|
||||
return context.loginWithUserPassword(username, "password");
|
||||
})
|
||||
.then(function () {
|
||||
return context.useTotpTokenHandle("REGISTERED");
|
||||
})
|
||||
.then(function () {
|
||||
return context.clickOnButton("Sign in");
|
||||
});
|
||||
}
|
||||
|
||||
function declareNeedAuthenticatedUserHooks(username: string) {
|
||||
Before({ tags: "@need-authenticated-user-" + username, timeout: 15 * 1000 }, function () {
|
||||
return needAuthenticatedUser(this, username);
|
||||
});
|
||||
|
||||
After({ tags: "@need-authenticated-user-" + username, timeout: 15 * 1000 }, function () {
|
||||
this.totpSecrets["REGISTERED"] = undefined;
|
||||
return BluebirdPromise.resolve();
|
||||
});
|
||||
}
|
||||
|
||||
function declareHooksForUser(username: string) {
|
||||
declareNeedRegisteredUserHooks(username);
|
||||
declareNeedAuthenticatedUserHooks(username);
|
||||
}
|
||||
|
||||
const users = ["harry", "john", "bob", "blackhat"];
|
||||
users.forEach(declareHooksForUser);
|
|
@ -1,23 +0,0 @@
|
|||
import {Then} from "cucumber";
|
||||
import seleniumWebdriver = require("selenium-webdriver");
|
||||
import Assert = require("assert");
|
||||
import Fs = require("fs");
|
||||
import CustomWorld = require("../support/world");
|
||||
|
||||
Then("I get a notification of type {string} with message {string}", { timeout: 10 * 1000 },
|
||||
function (notificationType: string, notificationMessage: string) {
|
||||
const that = this;
|
||||
const notificationEl = this.driver.findElement(seleniumWebdriver.By.className("notification"));
|
||||
return this.driver.wait(seleniumWebdriver.until.elementIsVisible(notificationEl), 5000)
|
||||
.then(function () {
|
||||
return notificationEl.getText();
|
||||
})
|
||||
.then(function (txt: string) {
|
||||
Assert.equal(notificationMessage, txt);
|
||||
return notificationEl.getAttribute("class");
|
||||
})
|
||||
.then(function (classes: string) {
|
||||
Assert(classes.indexOf(notificationType) > -1, "Class '" + notificationType + "' not found in notification element.");
|
||||
return that.driver.sleep(500);
|
||||
});
|
||||
});
|
|
@ -1,15 +0,0 @@
|
|||
import {Given, When, Then} from "cucumber";
|
||||
import seleniumWebdriver = require("selenium-webdriver");
|
||||
import Assert = require("assert");
|
||||
|
||||
Given("I'm on {string}", function (link: string) {
|
||||
return this.driver.get(link);
|
||||
});
|
||||
|
||||
When("I click on the link to {string}", function (link: string) {
|
||||
return this.driver.findElement(seleniumWebdriver.By.linkText(link)).click();
|
||||
});
|
||||
|
||||
Then("I'm redirected to {string}", function (link: string) {
|
||||
return this.waitUntilUrlContains(link);
|
||||
});
|
|
@ -1,13 +0,0 @@
|
|||
import {When} from "cucumber";
|
||||
import seleniumWebdriver = require("selenium-webdriver");
|
||||
import Assert = require("assert");
|
||||
|
||||
When("the otpauth url has label {string} and issuer \
|
||||
{string}", function (label: string, issuer: string) {
|
||||
return this.driver.findElement(seleniumWebdriver.By.id("qrcode"))
|
||||
.getAttribute("title")
|
||||
.then(function (title: string) {
|
||||
const re = `^otpauth://totp/${label}\\?secret=[A-Z0-9]+&issuer=${issuer}$`;
|
||||
Assert(new RegExp(re).test(title));
|
||||
})
|
||||
});
|
|
@ -1,9 +0,0 @@
|
|||
import {When} from "cucumber";
|
||||
import seleniumWebdriver = require("selenium-webdriver");
|
||||
import Assert = require("assert");
|
||||
import Fs = require("fs");
|
||||
import CustomWorld = require("../support/world");
|
||||
|
||||
When("I wait {int} seconds", { timeout: 10 * 1000 }, function (seconds: number) {
|
||||
return this.driver.sleep(seconds * 1000);
|
||||
});
|
|
@ -1,16 +0,0 @@
|
|||
import {When} from "cucumber";
|
||||
import seleniumWebdriver = require("selenium-webdriver");
|
||||
import Assert = require("assert");
|
||||
import Fs = require("fs");
|
||||
|
||||
When("I click on the link {string}", function (text: string) {
|
||||
return this.driver.findElement(seleniumWebdriver.By.linkText(text)).click();
|
||||
});
|
||||
|
||||
When("I click on the link of the email", function () {
|
||||
const that = this;
|
||||
return this.retrieveLatestMail()
|
||||
.then(function (link: string) {
|
||||
return that.driver.get(link);
|
||||
});
|
||||
});
|
|
@ -1,10 +0,0 @@
|
|||
import {When} from "cucumber";
|
||||
import seleniumWebdriver = require("selenium-webdriver");
|
||||
import Assert = require("assert");
|
||||
import ChildProcess = require("child_process");
|
||||
import BluebirdPromise = require("bluebird");
|
||||
|
||||
When(/^the application restarts$/, {timeout: 15 * 1000}, function () {
|
||||
const exec = BluebirdPromise.promisify(ChildProcess.exec);
|
||||
return exec("./scripts/example-commit/dc-example.sh restart authelia && sleep 3");
|
||||
});
|
|
@ -1,63 +0,0 @@
|
|||
import {Before, When, Then, TableDefinition} from "cucumber";
|
||||
import seleniumWebdriver = require("selenium-webdriver");
|
||||
import Assert = require("assert");
|
||||
import Request = require("request-promise");
|
||||
import Bluebird = require("bluebird");
|
||||
|
||||
Before(function () {
|
||||
this.jar = Request.jar();
|
||||
});
|
||||
|
||||
Then("I get an error {int}", function (code: number) {
|
||||
return this.getErrorPage(code);
|
||||
});
|
||||
|
||||
function requestAndExpectStatusCode(ctx: any, url: string, method: string,
|
||||
expectedStatusCode: number) {
|
||||
return Request(url, {
|
||||
method: method,
|
||||
jar: ctx.jar
|
||||
})
|
||||
.then(function (body: string) {
|
||||
return Bluebird.resolve(parseInt(body.match(/Error ([0-9]{3})/)[1]));
|
||||
}, function (response: any) {
|
||||
return Bluebird.resolve(response.statusCode)
|
||||
})
|
||||
.then(function (statusCode: number) {
|
||||
try {
|
||||
Assert.equal(statusCode, expectedStatusCode);
|
||||
}
|
||||
catch (e) {
|
||||
console.log("%s (actual) != %s (expected)", statusCode,
|
||||
expectedStatusCode);
|
||||
throw e;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Then("I get the following status code when requesting:",
|
||||
function (dataTable: TableDefinition) {
|
||||
const promises: Bluebird<void>[] = [];
|
||||
for (let i = 0; i < dataTable.rows().length; i++) {
|
||||
const url: string = (dataTable.hashes() as any)[i].url;
|
||||
const method: string = (dataTable.hashes() as any)[i].method;
|
||||
const code: number = (dataTable.hashes() as any)[i].code;
|
||||
promises.push(requestAndExpectStatusCode(this, url, method, code));
|
||||
}
|
||||
return Bluebird.all(promises);
|
||||
})
|
||||
|
||||
When("I post {string} with body:", function (url: string,
|
||||
dataTable: TableDefinition) {
|
||||
const body = {};
|
||||
for (let i = 0; i < dataTable.rows().length; i++) {
|
||||
const key = (dataTable.hashes() as any)[i].key;
|
||||
const value = (dataTable.hashes() as any)[i].value;
|
||||
body[key] = value;
|
||||
}
|
||||
return Request.post(url, {
|
||||
body: body,
|
||||
jar: this.jar,
|
||||
json: true
|
||||
});
|
||||
});
|
|
@ -1,6 +0,0 @@
|
|||
import {When} from "cucumber";
|
||||
import seleniumWebdriver = require("selenium-webdriver");
|
||||
|
||||
When("I sleep for {int} seconds", function (seconds: number) {
|
||||
return this.driver.sleep(seconds * 1000);
|
||||
});
|
|
@ -1,37 +0,0 @@
|
|||
import {When, Then} from "cucumber";
|
||||
import seleniumWebdriver = require("selenium-webdriver");
|
||||
import Request = require("request-promise");
|
||||
import BluebirdPromise = require("bluebird");
|
||||
import Util = require("util");
|
||||
|
||||
When("I request {string} with username {string}" +
|
||||
" and password {string} using basic authentication",
|
||||
function (url: string, username: string, password: string) {
|
||||
const that = this;
|
||||
return Request(url, {
|
||||
auth: {
|
||||
username: username,
|
||||
password: password
|
||||
},
|
||||
resolveWithFullResponse: true
|
||||
})
|
||||
.then(function (response: any) {
|
||||
that.response = response;
|
||||
});
|
||||
});
|
||||
|
||||
Then("I receive the secret page", function () {
|
||||
if (this.response.body.match("This is a very important secret!"))
|
||||
return BluebirdPromise.resolve();
|
||||
return BluebirdPromise.reject(new Error("Secret page not received."));
|
||||
});
|
||||
|
||||
Then("I received header {string} set to {string}",
|
||||
function (expectedHeaderName: string, expectedValue: string) {
|
||||
const expectedLine = Util.format("\"%s\": \"%s\"", expectedHeaderName,
|
||||
expectedValue);
|
||||
if (this.response.body.indexOf(expectedLine) > 0)
|
||||
return BluebirdPromise.resolve();
|
||||
return BluebirdPromise.reject(new Error(
|
||||
Util.format("No such header or with unexpected value.")));
|
||||
});
|
|
@ -1,183 +0,0 @@
|
|||
require("chromedriver");
|
||||
import seleniumWebdriver = require("selenium-webdriver");
|
||||
import {setWorldConstructor, After} from "cucumber";
|
||||
import Fs = require("fs");
|
||||
import Speakeasy = require("speakeasy");
|
||||
import Assert = require("assert");
|
||||
import Request = require("request-promise");
|
||||
import BluebirdPromise = require("bluebird");
|
||||
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"
|
||||
|
||||
function CustomWorld() {
|
||||
const that = this;
|
||||
this.driver = new seleniumWebdriver.Builder()
|
||||
.forBrowser("chrome")
|
||||
.build();
|
||||
|
||||
this.totpSecrets = {};
|
||||
this.configuration = {};
|
||||
|
||||
this.visit = function (link: string) {
|
||||
return this.driver.get(link);
|
||||
};
|
||||
|
||||
this.setFieldTo = function (fieldName: string, content: string) {
|
||||
const that = this;
|
||||
return this.driver.findElement(seleniumWebdriver.By.id(fieldName))
|
||||
.sendKeys(content);
|
||||
};
|
||||
|
||||
this.clearField = function (fieldName: string) {
|
||||
return this.driver.findElement(seleniumWebdriver.By.id(fieldName)).clear();
|
||||
};
|
||||
|
||||
this.getErrorPage = function (code: number) {
|
||||
const that = this;
|
||||
return this.driver.wait(seleniumWebdriver.until.elementLocated(seleniumWebdriver.By.tagName("h1")), 5000)
|
||||
.then(function () {
|
||||
return that.driver
|
||||
.findElement(seleniumWebdriver.By.tagName("h1")).getText();
|
||||
})
|
||||
.then(function (txt: string) {
|
||||
try {
|
||||
Assert.equal(txt, "Error " + code);
|
||||
} catch (e) {
|
||||
console.log(txt);
|
||||
throw e;
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
this.clickOnButton = function (buttonText: string) {
|
||||
const that = this;
|
||||
return this.driver.wait(seleniumWebdriver.until.elementLocated(seleniumWebdriver.By.tagName("button")), 5000)
|
||||
.then(function () {
|
||||
return that.driver
|
||||
.findElement(seleniumWebdriver.By.tagName("button"))
|
||||
.findElement(seleniumWebdriver.By.xpath("//button[contains(.,'" + buttonText + "')]"))
|
||||
.click();
|
||||
});
|
||||
};
|
||||
|
||||
this.waitUntilUrlContains = function (url: string) {
|
||||
const that = this;
|
||||
return this.driver.wait(seleniumWebdriver.until.urlIs(url), 15000)
|
||||
.then(function () {return BluebirdPromise.resolve(); }, function (err: Error) {
|
||||
that.driver.getCurrentUrl()
|
||||
.then(function (current: string) {
|
||||
console.error("====> Error due to: %s (current) != %s (expected)", current, url);
|
||||
});
|
||||
return BluebirdPromise.reject(err);
|
||||
});
|
||||
};
|
||||
|
||||
this.loginWithUserPassword = function (username: string, password: string) {
|
||||
return that.driver.wait(seleniumWebdriver.until.elementLocated(seleniumWebdriver.By.id("username")), 5000)
|
||||
.then(function () {
|
||||
return that.driver.findElement(seleniumWebdriver.By.id("username"))
|
||||
.sendKeys(username);
|
||||
})
|
||||
.then(function () {
|
||||
return that.driver.findElement(seleniumWebdriver.By.id("password"))
|
||||
.clear();
|
||||
})
|
||||
.then(function () {
|
||||
return that.driver.findElement(seleniumWebdriver.By.id("password"))
|
||||
.sendKeys(password);
|
||||
})
|
||||
.then(function () {
|
||||
return that.driver.findElement(seleniumWebdriver.By.tagName("button"))
|
||||
.click();
|
||||
});
|
||||
};
|
||||
|
||||
this.retrieveLatestMail = function () {
|
||||
return Request({
|
||||
method: "GET",
|
||||
uri: "http://localhost:8085/messages",
|
||||
json: true
|
||||
})
|
||||
.then(function (data: any) {
|
||||
const messageId = data[data.length - 1].id;
|
||||
return Request({
|
||||
method: "GET",
|
||||
uri: `http://localhost:8085/messages/${messageId}.html`
|
||||
});
|
||||
})
|
||||
.then(function (data: any) {
|
||||
const regexp = new RegExp(/<a href="(.+)" class="button">Continue<\/a>/);
|
||||
const match = regexp.exec(data);
|
||||
const link = match[1];
|
||||
return BluebirdPromise.resolve(link);
|
||||
});
|
||||
};
|
||||
|
||||
this.registerTotpSecret = function (totpSecretHandle: string) {
|
||||
return that.driver.wait(seleniumWebdriver.until.elementLocated(seleniumWebdriver.By.className("register-totp")), 5000)
|
||||
.then(function () {
|
||||
return that.driver.findElement(seleniumWebdriver.By.className("register-totp")).click();
|
||||
})
|
||||
.then(function () {
|
||||
return that.retrieveLatestMail();
|
||||
})
|
||||
.then(function (url: string) {
|
||||
return that.driver.get(url);
|
||||
})
|
||||
.then(function () {
|
||||
return that.driver.wait(seleniumWebdriver.until.elementLocated(seleniumWebdriver.By.id("secret")), 5000);
|
||||
})
|
||||
.then(function () {
|
||||
return that.driver.findElement(seleniumWebdriver.By.id("secret")).getText();
|
||||
})
|
||||
.then(function (secret: string) {
|
||||
that.totpSecrets[totpSecretHandle] = secret;
|
||||
});
|
||||
};
|
||||
|
||||
this.useTotpTokenHandle = function (totpSecretHandle: string) {
|
||||
if (!this.totpSecrets[totpSecretHandle])
|
||||
throw new Error("No available TOTP token handle " + totpSecretHandle);
|
||||
|
||||
const token = Speakeasy.totp({
|
||||
secret: this.totpSecrets[totpSecretHandle],
|
||||
encoding: "base32"
|
||||
});
|
||||
return this.useTotpToken(token);
|
||||
};
|
||||
|
||||
this.useTotpToken = function (totpSecret: string) {
|
||||
return that.driver.wait(seleniumWebdriver.until.elementLocated(seleniumWebdriver.By.id("token")), 5000)
|
||||
.then(function () {
|
||||
return that.driver.findElement(seleniumWebdriver.By.id("token"))
|
||||
.sendKeys(totpSecret);
|
||||
});
|
||||
};
|
||||
|
||||
this.registerTotpAndSignin = function (username: string, password: string) {
|
||||
const totpHandle = "HANDLE";
|
||||
const authUrl = "https://login.example.com:8080/";
|
||||
const that = this;
|
||||
return this.visit(authUrl)
|
||||
.then(function () {
|
||||
return that.loginWithUserPassword(username, password);
|
||||
})
|
||||
.then(function () {
|
||||
return that.registerTotpSecret(totpHandle);
|
||||
})
|
||||
.then(function () {
|
||||
return that.visit(authUrl);
|
||||
})
|
||||
.then(function () {
|
||||
return that.loginWithUserPassword(username, password);
|
||||
})
|
||||
.then(function () {
|
||||
return that.useTotpTokenHandle(totpHandle);
|
||||
})
|
||||
.then(function () {
|
||||
return that.clickOnButton("Sign in");
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
setWorldConstructor(CustomWorld);
|
|
@ -1,6 +1,5 @@
|
|||
import FillLoginPageAndClick from "./FillLoginPageAndClick";
|
||||
import ValidateTotp from "./ValidateTotp";
|
||||
import VerifyUrlIs from "./assertions/VerifyUrlIs";
|
||||
import { WebDriver } from "selenium-webdriver";
|
||||
import VisitPageAndWaitUrlIs from "./behaviors/VisitPageAndWaitUrlIs";
|
||||
|
||||
|
@ -9,5 +8,4 @@ export default async function(driver: WebDriver, user: string, secret: string, u
|
|||
await VisitPageAndWaitUrlIs(driver, `https://login.example.com:8080/?rd=${url}`);
|
||||
await FillLoginPageAndClick(driver, user, 'password');
|
||||
await ValidateTotp(driver, secret);
|
||||
await VerifyUrlIs(driver, url);
|
||||
}
|
|
@ -3,8 +3,8 @@ import LoginAs from './LoginAs';
|
|||
import { WebDriver } from 'selenium-webdriver';
|
||||
import VerifyIsSecondFactorStage from './assertions/VerifyIsSecondFactorStage';
|
||||
|
||||
export default async function(driver: WebDriver, user: string, email: boolean = false) {
|
||||
await LoginAs(driver, user);
|
||||
export default async function(driver: WebDriver, user: string, password: string, email: boolean = false) {
|
||||
await LoginAs(driver, user, password);
|
||||
await VerifyIsSecondFactorStage(driver);
|
||||
return await RegisterTotp(driver, email);
|
||||
}
|
|
@ -2,7 +2,8 @@ import FillLoginPageAndClick from './FillLoginPageAndClick';
|
|||
import { WebDriver } from "selenium-webdriver";
|
||||
import VisitPageAndWaitUrlIs from "./behaviors/VisitPageAndWaitUrlIs";
|
||||
|
||||
export default async function(driver: WebDriver, user: string, password: string = "password") {
|
||||
await VisitPageAndWaitUrlIs(driver, "https://login.example.com:8080/");
|
||||
export default async function(driver: WebDriver, user: string, password: string, targetUrl?: string) {
|
||||
const urlExt = (targetUrl) ? ('rd=' + targetUrl) : '';
|
||||
await VisitPageAndWaitUrlIs(driver, "https://login.example.com:8080/" + urlExt);
|
||||
await FillLoginPageAndClick(driver, user, password);
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import SeleniumWebdriver, { WebDriver } from "selenium-webdriver";
|
||||
import { WebDriver } from "selenium-webdriver";
|
||||
|
||||
export default async function(driver: WebDriver, url: string, timeout: number = 5000) {
|
||||
await driver.get(url);
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import SeleniumWebDriver, { WebDriver } from "selenium-webdriver";
|
||||
import Util from "util";
|
||||
|
||||
export default async function(driver: WebDriver, header: string, expectedValue: string) {
|
||||
const el = await driver.wait(SeleniumWebDriver.until.elementLocated(SeleniumWebDriver.By.tagName("body")), 5000);
|
||||
export default async function(driver: WebDriver, header: string, expectedValue: string, timeout: number = 5000) {
|
||||
const el = await driver.wait(SeleniumWebDriver.until.elementLocated(
|
||||
SeleniumWebDriver.By.tagName("body")), timeout);
|
||||
const text = await el.getText();
|
||||
|
||||
const expectedLine = Util.format("\"%s\": \"%s\"", header, expectedValue);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import SeleniumWebDriver, { WebDriver } from "selenium-webdriver";
|
||||
|
||||
export default async function(driver: WebDriver) {
|
||||
await driver.wait(SeleniumWebDriver.until.elementLocated(SeleniumWebDriver.By.className('already-authenticated-step')));
|
||||
export default async function(driver: WebDriver, timeout: number = 5000) {
|
||||
await driver.wait(SeleniumWebDriver.until.elementLocated(
|
||||
SeleniumWebDriver.By.className('already-authenticated-step')), timeout);
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
import SeleniumWebDriver, { WebDriver } from "selenium-webdriver";
|
||||
|
||||
export default async function(driver: WebDriver) {
|
||||
await driver.wait(SeleniumWebDriver.until.elementLocated(SeleniumWebDriver.By.className('second-factor-step')));
|
||||
export default async function(driver: WebDriver, timeout: number = 5000) {
|
||||
await driver.wait(SeleniumWebDriver.until.elementLocated(
|
||||
SeleniumWebDriver.By.className('second-factor-step')), timeout);
|
||||
}
|
|
@ -1,8 +1,9 @@
|
|||
import SeleniumWebdriver, { WebDriver } from "selenium-webdriver";
|
||||
import Assert = require("assert");
|
||||
|
||||
export default async function(driver: WebDriver, message: string) {
|
||||
await driver.wait(SeleniumWebdriver.until.elementLocated(SeleniumWebdriver.By.className("notification")), 5000)
|
||||
export default async function(driver: WebDriver, message: string, timeout: number = 5000) {
|
||||
await driver.wait(SeleniumWebdriver.until.elementLocated(
|
||||
SeleniumWebdriver.By.className("notification")), timeout)
|
||||
const notificationEl = driver.findElement(SeleniumWebdriver.By.className("notification"));
|
||||
const txt = await notificationEl.getText();
|
||||
Assert.equal(message, txt);
|
||||
|
|
|
@ -5,9 +5,11 @@ import FullLogin from "../FullLogin";
|
|||
export default async function(
|
||||
driver: WebDriver,
|
||||
username: string,
|
||||
password: string,
|
||||
email: boolean = false,
|
||||
targetUrl: string = "https://login.example.com:8080/") {
|
||||
|
||||
const secret = await LoginAndRegisterTotp(driver, username, email);
|
||||
const secret = await LoginAndRegisterTotp(driver, username, password, email);
|
||||
await FullLogin(driver, username, secret, targetUrl);
|
||||
return secret;
|
||||
};
|
|
@ -34,7 +34,7 @@ export default function() {
|
|||
WithDriver();
|
||||
|
||||
before(async function() {
|
||||
const secret = await LoginAndRegisterTotp(this.driver, "john", true);
|
||||
const secret = await LoginAndRegisterTotp(this.driver, "john", "password", true);
|
||||
await VisitPageAndWaitUrlIs(this.driver, 'https://login.example.com:8080/');
|
||||
await FillLoginPageAndClick(this.driver, 'john', 'password', false);
|
||||
await ValidateTotp(this.driver, secret);
|
||||
|
@ -61,7 +61,7 @@ export default function() {
|
|||
WithDriver();
|
||||
|
||||
before(async function() {
|
||||
const secret = await LoginAndRegisterTotp(this.driver, "bob", true);
|
||||
const secret = await LoginAndRegisterTotp(this.driver, "bob", "password", true);
|
||||
await VisitPageAndWaitUrlIs(this.driver, 'https://login.example.com:8080/');
|
||||
await FillLoginPageAndClick(this.driver, 'bob', 'password', false);
|
||||
await ValidateTotp(this.driver, secret);
|
||||
|
@ -88,7 +88,7 @@ export default function() {
|
|||
WithDriver();
|
||||
|
||||
before(async function() {
|
||||
const secret = await LoginAndRegisterTotp(this.driver, "harry", true);
|
||||
const secret = await LoginAndRegisterTotp(this.driver, "harry", "password", true);
|
||||
await VisitPageAndWaitUrlIs(this.driver, 'https://login.example.com:8080/');
|
||||
await FillLoginPageAndClick(this.driver, 'harry', 'password', false);
|
||||
await ValidateTotp(this.driver, secret);
|
||||
|
|
|
@ -15,7 +15,7 @@ export default function() {
|
|||
ChildProcess.execSync('rm -f .authelia-interrupt');
|
||||
|
||||
this.driver = await StartDriver();
|
||||
await RegisterAndLoginTwoFactor(this.driver, 'john', true, 'https://admin.example.com:8080/secret.html');
|
||||
await RegisterAndLoginTwoFactor(this.driver, 'john', "password", true, 'https://admin.example.com:8080/secret.html');
|
||||
await VisitPageAndWaitUrlIs(this.driver, 'https://home.example.com:8080/');
|
||||
});
|
||||
|
||||
|
@ -46,7 +46,7 @@ export default function() {
|
|||
ChildProcess.execSync('rm -f .authelia-interrupt');
|
||||
|
||||
this.driver = await StartDriver();
|
||||
this.secret = await LoginAndRegisterTotp(this.driver, 'john', true);
|
||||
this.secret = await LoginAndRegisterTotp(this.driver, 'john', "password", true);
|
||||
await Logout(this.driver);
|
||||
});
|
||||
|
||||
|
|
|
@ -3,31 +3,14 @@ import LoginAs from "../../../helpers/LoginAs";
|
|||
import VerifyNotificationDisplayed from "../../../helpers/assertions/VerifyNotificationDisplayed";
|
||||
import VerifyIsSecondFactorStage from "../../../helpers/assertions/VerifyIsSecondFactorStage";
|
||||
|
||||
/*
|
||||
Given I visit "https://login.example.com:8080/"
|
||||
And I set field "username" to "blackhat"
|
||||
And I set field "password" to "bad-password"
|
||||
And I click on "Sign in"
|
||||
And I get a notification of type "error" with message "Authentication failed. Please check your credentials."
|
||||
And I set field "password" to "bad-password"
|
||||
And I click on "Sign in"
|
||||
And I get a notification of type "error" with message "Authentication failed. Please check your credentials."
|
||||
And I set field "password" to "bad-password"
|
||||
And I click on "Sign in"
|
||||
And I get a notification of type "error" with message "Authentication failed. Please check your credentials."
|
||||
When I set field "password" to "password"
|
||||
And I click on "Sign in"
|
||||
Then I get a notification of type "error" with message "Authentication failed. Please check your credentials."
|
||||
*/
|
||||
|
||||
export default function() {
|
||||
describe('Authelia regulates authentications when a hacker is brute forcing', function() {
|
||||
this.timeout(15000);
|
||||
before(async function() {
|
||||
beforeEach(async function() {
|
||||
this.driver = await StartDriver();
|
||||
});
|
||||
|
||||
after(async function() {
|
||||
afterEach(async function() {
|
||||
await StopDriver(this.driver);
|
||||
});
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ export default function() {
|
|||
describe("With two factors", function() {
|
||||
before(async function() {
|
||||
this.driver = await StartDriver();
|
||||
await RegisterAndLoginWith2FA(this.driver, "john", true, "https://public.example.com:8080/headers");
|
||||
await RegisterAndLoginWith2FA(this.driver, "john", "password", true, "https://public.example.com:8080/headers");
|
||||
});
|
||||
|
||||
after(async function() {
|
||||
|
|
|
@ -21,7 +21,7 @@ export default function() {
|
|||
|
||||
beforeEach(async function() {
|
||||
this.driver = await StartDriver();
|
||||
secret = await LoginAndRegisterTotp(this.driver, "john", true)
|
||||
secret = await LoginAndRegisterTotp(this.driver, "john", "password", true)
|
||||
});
|
||||
|
||||
afterEach(async function() {
|
||||
|
|
|
@ -9,6 +9,9 @@ import TOTPValidation from './scenarii/TOTPValidation';
|
|||
import Inactivity from './scenarii/Inactivity';
|
||||
import BackendProtection from './scenarii/BackendProtection';
|
||||
import VerifyEndpoint from './scenarii/VerifyEndpoint';
|
||||
import RequiredTwoFactor from './scenarii/RequiredTwoFactor';
|
||||
import LogoutRedirectToAlreadyLoggedIn from './scenarii/LogoutRedirectToAlreadyLoggedIn';
|
||||
import SimpleAuthentication from './scenarii/SimpleAuthentication';
|
||||
|
||||
const execAsync = Bluebird.promisify(ChildProcess.exec);
|
||||
|
||||
|
@ -18,14 +21,14 @@ AutheliaSuite('Minimal configuration', __dirname + '/config.yml', function() {
|
|||
return execAsync("cp users_database.example.yml users_database.yml");
|
||||
});
|
||||
|
||||
describe('Simple authentication', SimpleAuthentication);
|
||||
describe('Backend protection', BackendProtection);
|
||||
describe('Verify API endpoint', VerifyEndpoint);
|
||||
|
||||
describe('Bad password', BadPassword);
|
||||
describe('Reset password', ResetPassword);
|
||||
|
||||
describe('TOTP Registration', RegisterTotp);
|
||||
describe('TOTP Validation', TOTPValidation);
|
||||
|
||||
describe('Inactivity period', Inactivity);
|
||||
describe('Required two factor', RequiredTwoFactor);
|
||||
describe('Logout endpoint redirect to already logged in page', LogoutRedirectToAlreadyLoggedIn);
|
||||
});
|
|
@ -12,7 +12,7 @@ export default function(this: Mocha.ISuiteCallbackContext) {
|
|||
|
||||
beforeEach(async function() {
|
||||
this.driver = await StartDriver();
|
||||
this.secret = await LoginAndRegisterTotp(this.driver, "john", true);
|
||||
this.secret = await LoginAndRegisterTotp(this.driver, "john", "password", true);
|
||||
});
|
||||
|
||||
afterEach(async function() {
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
import { StartDriver, StopDriver } from "../../../helpers/context/WithDriver";
|
||||
import VisitPage from "../../../helpers/VisitPage";
|
||||
import VerifyIsAlreadyAuthenticatedStage from "../../../helpers/assertions/VerifyIsAlreadyAuthenticatedStage";
|
||||
import RegisterAndLoginTwoFactor from "../../../helpers/behaviors/RegisterAndLoginTwoFactor";
|
||||
|
||||
|
||||
export default function() {
|
||||
describe('When visiting /logout the user is redirected to already logged in page to log out', function() {
|
||||
before(async function() {
|
||||
this.driver = await StartDriver();
|
||||
await RegisterAndLoginTwoFactor(this.driver, 'john', "password", true);
|
||||
});
|
||||
|
||||
after(async function() {
|
||||
await StopDriver(this.driver);
|
||||
});
|
||||
|
||||
it('should redirect the user', async function() {
|
||||
await VisitPage(this.driver, 'https://login.example.com:8080/logout');
|
||||
await VerifyIsAlreadyAuthenticatedStage(this.driver);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -14,7 +14,7 @@ export default function() {
|
|||
|
||||
beforeEach(async function() {
|
||||
this.driver = await StartDriver();
|
||||
await LoginAndRegisterTotp(this.driver, "john", true);
|
||||
await LoginAndRegisterTotp(this.driver, "john", "password", true);
|
||||
});
|
||||
|
||||
afterEach(async function() {
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
import LoginAndRegisterTotp from '../../../helpers/LoginAndRegisterTotp';
|
||||
import VerifyUrlIs from '../../../helpers/assertions/VerifyUrlIs';
|
||||
import { StartDriver, StopDriver } from '../../../helpers/context/WithDriver';
|
||||
import VerifyIsSecondFactorStage from '../../../helpers/assertions/VerifyIsSecondFactorStage';
|
||||
import VisitPage from '../../../helpers/VisitPage';
|
||||
import FillLoginPageAndClick from '../../../helpers/FillLoginPageAndClick';
|
||||
|
||||
export default function() {
|
||||
describe('User tries to access a page protected by second factor while he only passed first factor', function() {
|
||||
before(async function() {
|
||||
this.driver = await StartDriver();
|
||||
const secret = await LoginAndRegisterTotp(this.driver, "john", "password", true);
|
||||
if (!secret) throw new Error('No secret!');
|
||||
|
||||
await VisitPage(this.driver, "https://admin.example.com:8080/secret.html");
|
||||
await VerifyUrlIs(this.driver, "https://login.example.com:8080/?rd=https://admin.example.com:8080/secret.html");
|
||||
await FillLoginPageAndClick(this.driver, "john", "password");
|
||||
await VerifyIsSecondFactorStage(this.driver);
|
||||
});
|
||||
|
||||
after(async function() {
|
||||
await StopDriver(this.driver);
|
||||
});
|
||||
|
||||
it("should reach second factor page of login portal", async function() {
|
||||
await VisitPage(this.driver, "https://admin.example.com:8080/secret.html");
|
||||
await VerifyIsSecondFactorStage(this.driver);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
import { StartDriver, StopDriver } from "../../../helpers/context/WithDriver";
|
||||
import RegisterAndLoginTwoFactor from "../../../helpers/behaviors/RegisterAndLoginTwoFactor";
|
||||
import VerifyUrlIs from "../../../helpers/assertions/VerifyUrlIs";
|
||||
import VisitPage from "../../../helpers/VisitPage";
|
||||
import VisitPageAndWaitUrlIs from "../../../helpers/behaviors/VisitPageAndWaitUrlIs";
|
||||
|
||||
|
||||
export default function() {
|
||||
describe('The user is redirected to target url upon successful authentication', function() {
|
||||
before(async function() {
|
||||
this.driver = await StartDriver();
|
||||
await RegisterAndLoginTwoFactor(this.driver, 'john', "password", true, 'https://admin.example.com:8080/secret.html');
|
||||
});
|
||||
|
||||
after(async function() {
|
||||
await StopDriver(this.driver);
|
||||
});
|
||||
|
||||
it('should redirect the user', async function() {
|
||||
await VerifyUrlIs(this.driver, 'https://admin.example.com:8080/secret.html');
|
||||
});
|
||||
});
|
||||
|
||||
describe('The target url is in "rd" parameter of the portal URL', function() {
|
||||
before(async function() {
|
||||
this.driver = await StartDriver();
|
||||
await VisitPage(this.driver, 'https://admin.example.com:8080/secret.html');
|
||||
});
|
||||
|
||||
after(async function() {
|
||||
await StopDriver(this.driver);
|
||||
});
|
||||
|
||||
it('should redirect the user', async function() {
|
||||
await VerifyUrlIs(this.driver, 'https://login.example.com:8080/?rd=https://admin.example.com:8080/secret.html');
|
||||
});
|
||||
})
|
||||
}
|
|
@ -17,7 +17,7 @@ export default function() {
|
|||
describe('Successfully pass second factor with TOTP', function() {
|
||||
before(async function() {
|
||||
this.driver = await StartDriver();
|
||||
const secret = await LoginAndRegisterTotp(this.driver, "john", true);
|
||||
const secret = await LoginAndRegisterTotp(this.driver, "john", "password", true);
|
||||
if (!secret) throw new Error('No secret!');
|
||||
|
||||
await VisitPageAndWaitUrlIs(this.driver, "https://login.example.com:8080/?rd=https://admin.example.com:8080/secret.html");
|
||||
|
@ -46,7 +46,7 @@ export default function() {
|
|||
describe('Fail validation of second factor with TOTP', function() {
|
||||
before(async function() {
|
||||
this.driver = await StartDriver();
|
||||
await LoginAndRegisterTotp(this.driver, "john", true);
|
||||
await LoginAndRegisterTotp(this.driver, "john", "password", true);
|
||||
const BAD_TOKEN = "125478";
|
||||
|
||||
await VisitPageAndWaitUrlIs(this.driver, "https://login.example.com:8080/?rd=https://admin.example.com:8080/secret.html");
|
||||
|
|
Loading…
Reference in New Issue