Add integration test for keep me logged in feature.
parent
4c3b5cfbb3
commit
05c423c6f8
|
@ -53,6 +53,10 @@ module.exports = function (grunt) {
|
||||||
cmd: "./node_modules/.bin/mocha",
|
cmd: "./node_modules/.bin/mocha",
|
||||||
args: ['--colors', '--require', 'ts-node/register', 'test/minimal-config/**/*.ts']
|
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": {
|
"docker-build": {
|
||||||
cmd: "docker",
|
cmd: "docker",
|
||||||
args: ['build', '-t', 'clems4ever/authelia', '.']
|
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-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-client', ['env:env-test-client-unit', 'run:test-client-unit'])
|
||||||
grunt.registerTask('test-unit', ['test-server', 'test-client']);
|
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('copy-resources', ['copy:resources', 'copy:views', 'copy:images', 'copy:thirdparties', 'concat:css']);
|
||||||
grunt.registerTask('generate-config-schema', ['run:generate-config-schema', 'copy:schema']);
|
grunt.registerTask('generate-config-schema', ['run:generate-config-schema', 'copy:schema']);
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
# Authelia minimal configuration #
|
# Authelia minimal configuration #
|
||||||
###############################################################
|
###############################################################
|
||||||
|
|
||||||
logs_level: debug
|
|
||||||
|
|
||||||
authentication_backend:
|
authentication_backend:
|
||||||
file:
|
file:
|
||||||
path: /etc/authelia/users_database.yml
|
path: /etc/authelia/users_database.yml
|
||||||
|
@ -11,7 +9,6 @@ authentication_backend:
|
||||||
session:
|
session:
|
||||||
secret: unsecure_session_secret
|
secret: unsecure_session_secret
|
||||||
domain: example.com
|
domain: example.com
|
||||||
inactivity: 30000
|
|
||||||
|
|
||||||
# Configuration of the storage backend used to store data and secrets. i.e. totp data
|
# Configuration of the storage backend used to store data and secrets. i.e. totp data
|
||||||
storage:
|
storage:
|
||||||
|
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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}`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,9 +13,9 @@ export class Environment {
|
||||||
}
|
}
|
||||||
|
|
||||||
private runCommand(command: string, timeout?: number): Bluebird<void> {
|
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);
|
console.log('[ENVIRONMENT] Running: %s', command);
|
||||||
exec(command, function(err, stdout, stderr) {
|
exec(command, (err, stdout, stderr) => {
|
||||||
if(err) {
|
if(err) {
|
||||||
reject(err);
|
reject(err);
|
||||||
return;
|
return;
|
||||||
|
@ -34,9 +34,12 @@ export class Environment {
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup(): Bluebird<void> {
|
cleanup(): Bluebird<void> {
|
||||||
const command = docker_compose(this.includes) + ' down'
|
if(process.env.KEEP_ENV != "true") {
|
||||||
console.log('[ENVIRONMENT] Cleaning up...');
|
const command = docker_compose(this.includes) + ' down'
|
||||||
return this.runCommand(command);
|
console.log('[ENVIRONMENT] Cleaning up...');
|
||||||
|
return this.runCommand(command);
|
||||||
|
}
|
||||||
|
return Bluebird.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
stop_service(serviceName: string): Bluebird<void> {
|
stop_service(serviceName: string): Bluebird<void> {
|
||||||
|
|
|
@ -1,16 +1,28 @@
|
||||||
|
import Bluebird = require("bluebird");
|
||||||
import SeleniumWebdriver = require("selenium-webdriver");
|
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)
|
return driver.wait(SeleniumWebdriver.until.elementLocated(SeleniumWebdriver.By.id("username")), 5000)
|
||||||
.then(function () {
|
.then(() => {
|
||||||
return driver.findElement(SeleniumWebdriver.By.id("username"))
|
return driver.findElement(SeleniumWebdriver.By.id("username"))
|
||||||
.sendKeys(username);
|
.sendKeys(username);
|
||||||
})
|
})
|
||||||
.then(function () {
|
.then(() => {
|
||||||
return driver.findElement(SeleniumWebdriver.By.id("password"))
|
return driver.findElement(SeleniumWebdriver.By.id("password"))
|
||||||
.sendKeys(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"))
|
return driver.findElement(SeleniumWebdriver.By.tagName("button"))
|
||||||
.click();
|
.click();
|
||||||
});
|
});
|
||||||
|
|
|
@ -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());
|
||||||
|
});
|
|
@ -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"))
|
||||||
|
});
|
||||||
|
});
|
|
@ -37,13 +37,13 @@ describe('Validate TOTP factor', function() {
|
||||||
const driver = this.driver;
|
const driver = this.driver;
|
||||||
|
|
||||||
return VisitPage(driver, "https://login.example.com:8080/?rd=https://admin.example.com:8080/secret.html")
|
return VisitPage(driver, "https://login.example.com:8080/?rd=https://admin.example.com:8080/secret.html")
|
||||||
.then(function() {
|
.then(() => {
|
||||||
return FillLoginPageWithUserAndPasswordAndClick(driver, 'john', 'password');
|
return FillLoginPageWithUserAndPasswordAndClick(driver, 'john', 'password');
|
||||||
})
|
})
|
||||||
.then(function () {
|
.then(() => {
|
||||||
return ValidateTotp(driver, secret);
|
return ValidateTotp(driver, secret);
|
||||||
})
|
})
|
||||||
.then(function() {
|
.then(() => {
|
||||||
return WaitRedirected(driver, "https://admin.example.com:8080/secret.html")
|
return WaitRedirected(driver, "https://admin.example.com:8080/secret.html")
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue