Add integration test for keep me logged in feature.

pull/287/head
Clement Michaud 2018-10-22 09:35:06 +02:00
parent 4c3b5cfbb3
commit 05c423c6f8
10 changed files with 844 additions and 374 deletions

View File

@ -53,6 +53,10 @@ module.exports = function (grunt) {
cmd: "./node_modules/.bin/mocha",
args: ['--colors', '--require', 'ts-node/register', 'test/minimal-config/**/*.ts']
},
"test-inactivity": {
cmd: "./node_modules/.bin/mocha",
args: ['--colors', '--require', 'ts-node/register', 'test/inactivity/**/*.ts']
},
"docker-build": {
cmd: "docker",
args: ['build', '-t', 'clems4ever/authelia', '.']
@ -191,7 +195,7 @@ module.exports = function (grunt) {
grunt.registerTask('test-server', ['env:env-test-server-unit', 'run:test-server-unit'])
grunt.registerTask('test-client', ['env:env-test-client-unit', 'run:test-client-unit'])
grunt.registerTask('test-unit', ['test-server', 'test-client']);
grunt.registerTask('test-int', ['run:test-cucumber', 'run:test-minimal-config', 'run:test-complete-config']);
grunt.registerTask('test-int', ['run:test-cucumber', 'run:test-minimal-config', 'run:test-complete-config', 'run:test-inactivity']);
grunt.registerTask('copy-resources', ['copy:resources', 'copy:views', 'copy:images', 'copy:thirdparties', 'concat:css']);
grunt.registerTask('generate-config-schema', ['run:generate-config-schema', 'copy:schema']);

View File

@ -2,8 +2,6 @@
# Authelia minimal configuration #
###############################################################
logs_level: debug
authentication_backend:
file:
path: /etc/authelia/users_database.yml
@ -11,7 +9,6 @@ authentication_backend:
session:
secret: unsecure_session_secret
domain: example.com
inactivity: 30000
# Configuration of the storage backend used to store data and secrets. i.e. totp data
storage:

View File

@ -0,0 +1,13 @@
version: '2'
services:
authelia:
build: .
restart: always
volumes:
- ./config.test.yml:/etc/authelia/config.yml:ro
- ./users_database.test.yml:/etc/authelia/users_database.yml:rw
- /tmp/authelia:/tmp/authelia
environment:
- NODE_TLS_REJECT_UNAUTHORIZED=0
networks:
- example-network

1041
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,32 @@
import Bluebird = require("bluebird");
import YamlJS = require("yamljs");
import Fs = require("fs");
import ChildProcess = require("child_process");
const execAsync = Bluebird.promisify(ChildProcess.exec);
export class Configuration {
private outputPath: string;
setup(
inputPath: string,
outputPath: string,
updateFn: (configuration: any) => void)
: Bluebird<void> {
console.log("[CONFIGURATION] setup");
this.outputPath = outputPath;
return new Bluebird((resolve, reject) => {
const configuration = YamlJS.load(inputPath);
updateFn(configuration);
const configurationStr = YamlJS.stringify(configuration);
Fs.writeFileSync(outputPath, configurationStr);
resolve();
});
}
cleanup(): Bluebird<{}> {
console.log("[CONFIGURATION] cleanup");
return execAsync(`rm ${this.outputPath}`);
}
}

View File

@ -13,9 +13,9 @@ export class Environment {
}
private runCommand(command: string, timeout?: number): Bluebird<void> {
return new Bluebird<void>(function(resolve, reject) {
return new Bluebird<void>((resolve, reject) => {
console.log('[ENVIRONMENT] Running: %s', command);
exec(command, function(err, stdout, stderr) {
exec(command, (err, stdout, stderr) => {
if(err) {
reject(err);
return;
@ -34,10 +34,13 @@ export class Environment {
}
cleanup(): Bluebird<void> {
if(process.env.KEEP_ENV != "true") {
const command = docker_compose(this.includes) + ' down'
console.log('[ENVIRONMENT] Cleaning up...');
return this.runCommand(command);
}
return Bluebird.resolve();
}
stop_service(serviceName: string): Bluebird<void> {
const command = docker_compose(this.includes) + ' stop ' + serviceName;

View File

@ -1,16 +1,28 @@
import Bluebird = require("bluebird");
import SeleniumWebdriver = require("selenium-webdriver");
export default function(driver: any, username: string, password: string) {
export default function(
driver: any,
username: string,
password: string,
keepMeLoggedIn: boolean = false) {
return driver.wait(SeleniumWebdriver.until.elementLocated(SeleniumWebdriver.By.id("username")), 5000)
.then(function () {
.then(() => {
return driver.findElement(SeleniumWebdriver.By.id("username"))
.sendKeys(username);
})
.then(function () {
.then(() => {
return driver.findElement(SeleniumWebdriver.By.id("password"))
.sendKeys(password);
})
.then(function () {
.then(() => {
if (keepMeLoggedIn) {
return driver.findElement(SeleniumWebdriver.By.id("keep_me_logged_in"))
.click();
}
return Bluebird.resolve();
})
.then(() => {
return driver.findElement(SeleniumWebdriver.By.tagName("button"))
.click();
});

View File

@ -0,0 +1,36 @@
require("chromedriver");
import Bluebird = require("bluebird");
import Configuration = require("../configuration");
import Environment = require("../environment");
import ChildProcess = require('child_process');
const execAsync = Bluebird.promisify(ChildProcess.exec);
const includes = [
"docker-compose.test.yml",
"example/compose/docker-compose.base.yml",
"example/compose/nginx/minimal/docker-compose.yml",
]
before(function() {
this.timeout(20000);
this.environment = new Environment.Environment(includes);
this.configuration = new Configuration.Configuration();
return this.configuration.setup(
"config.minimal.yml",
"config.test.yml",
conf => {
conf.session.inactivity = 2000;
})
.then(() => execAsync("cp users_database.yml users_database.test.yml"))
.then(() => this.environment.setup(2000));
});
after(function() {
this.timeout(30000);
return this.configuration.cleanup()
.then(() => execAsync("rm users_database.test.yml"))
.then(() => this.environment.cleanup());
});

View File

@ -0,0 +1,48 @@
import Bluebird = require("bluebird");
import loginAndRegisterTotp from "../helpers/login-and-register-totp";
import VisitPage from "../helpers/visit-page";
import FillLoginPageWithUserAndPasswordAndClick from "../helpers/fill-login-page-and-click";
import WithDriver from "../helpers/with-driver";
import ValidateTotp from "../helpers/validate-totp";
import WaitRedirected from "../helpers/wait-redirected";
describe("Keep me logged in", function() {
this.timeout(15000);
WithDriver();
before(function() {
const that = this;
return loginAndRegisterTotp(this.driver, "john")
.then(function(secret: string) {
that.secret = secret;
if(!secret) return Bluebird.reject(new Error("No secret!"));
return Bluebird.resolve();
});
});
it("should disconnect user after inactivity period", function() {
const that = this;
const driver = this.driver;
return VisitPage(driver, "https://login.example.com:8080/?rd=https://admin.example.com:8080/secret.html")
.then(() => FillLoginPageWithUserAndPasswordAndClick(driver, 'john', 'password', false))
.then(() => ValidateTotp(driver, that.secret))
.then(() => WaitRedirected(driver, "https://admin.example.com:8080/secret.html"))
.then(() => VisitPage(driver, "https://home.example.com:8080/"))
.then(() => driver.sleep(3000))
.then(() => driver.get("https://admin.example.com:8080/secret.html"))
.then(() => WaitRedirected(driver, "https://login.example.com:8080/?rd=https://admin.example.com:8080/secret.html"))
});
it.only("should keep user logged in after inactivity period", function() {
const that = this;
const driver = this.driver;
return VisitPage(driver, "https://login.example.com:8080/?rd=https://admin.example.com:8080/secret.html")
.then(() => FillLoginPageWithUserAndPasswordAndClick(driver, 'john', 'password', true))
.then(() => ValidateTotp(driver, that.secret))
.then(() => WaitRedirected(driver, "https://admin.example.com:8080/secret.html"))
.then(() => VisitPage(driver, "https://home.example.com:8080/"))
.then(() => driver.sleep(5000))
.then(() => driver.get("https://admin.example.com:8080/secret.html"))
.then(() => WaitRedirected(driver, "https://admin.example.com:8080/secret.html"))
});
});

View File

@ -37,13 +37,13 @@ describe('Validate TOTP factor', function() {
const driver = this.driver;
return VisitPage(driver, "https://login.example.com:8080/?rd=https://admin.example.com:8080/secret.html")
.then(function() {
.then(() => {
return FillLoginPageWithUserAndPasswordAndClick(driver, 'john', 'password');
})
.then(function () {
.then(() => {
return ValidateTotp(driver, secret);
})
.then(function() {
.then(() => {
return WaitRedirected(driver, "https://admin.example.com:8080/secret.html")
});
});