Add tests for minimal configuration
parent
21653bc7e3
commit
6d6162f26c
|
@ -22,6 +22,7 @@ addons:
|
|||
- mx2.mail.example.com
|
||||
- public.example.com
|
||||
- authelia.example.com
|
||||
- admin.example.com
|
||||
|
||||
before_install:
|
||||
- npm install -g npm@'>=2.13.5'
|
||||
|
|
|
@ -12,8 +12,7 @@ RUN apk --update add --no-cache --virtual \
|
|||
COPY dist/server /usr/src/server
|
||||
COPY dist/shared /usr/src/shared
|
||||
|
||||
ENV PORT=80
|
||||
EXPOSE 80
|
||||
EXPOSE 8080
|
||||
|
||||
VOLUME /etc/authelia
|
||||
VOLUME /var/lib/authelia
|
||||
|
|
|
@ -41,10 +41,14 @@ module.exports = function (grunt) {
|
|||
cmd: "./node_modules/.bin/mocha",
|
||||
args: ['--colors', '--require', 'ts-node/register', 'client/test/**/*.test.ts']
|
||||
},
|
||||
"test-int": {
|
||||
"test-cucumber": {
|
||||
cmd: "./scripts/run-cucumber.sh",
|
||||
args: ["./test/features"]
|
||||
},
|
||||
"test-minimal-config": {
|
||||
cmd: "./node_modules/.bin/mocha",
|
||||
args: ['--colors', '--require', 'ts-node/register', 'test/minimal-config/**/*.ts']
|
||||
},
|
||||
"docker-build": {
|
||||
cmd: "docker",
|
||||
args: ['build', '-t', 'clems4ever/authelia', '.']
|
||||
|
@ -183,7 +187,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-int']);
|
||||
grunt.registerTask('test-int', ['run:test-cucumber', 'run:test-minimal-config']);
|
||||
|
||||
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']);
|
||||
|
|
|
@ -15,10 +15,9 @@ ldap:
|
|||
password: password
|
||||
|
||||
session:
|
||||
# The secret to encrypt the session cookies.
|
||||
# The secret to encrypt the session cookies with.
|
||||
secret: unsecure_session_secret
|
||||
|
||||
# The domain to protect.
|
||||
# Note: the authenticator must also be in that domain. If empty, the cookie
|
||||
# is restricted to the subdomain of the issuer.
|
||||
# Note: Authelia must also be served by that domain.
|
||||
domain: example.com
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
###############################################################
|
||||
|
||||
# The port to listen on
|
||||
port: 80
|
||||
port: 8080
|
||||
|
||||
# Log level
|
||||
#
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
version: '2'
|
||||
services:
|
||||
authelia:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
restart: always
|
||||
volumes:
|
||||
- ./server:/usr/src/server
|
||||
- ./dist/server/src/public_html:/usr/src/server/src/public_html
|
||||
- ./client:/usr/src/client
|
||||
- ./shared:/usr/src/shared
|
||||
- ./node_modules:/usr/src/node_modules
|
||||
- ./config.minimal.yml:/etc/authelia/config.yml:ro
|
||||
- /tmp/authelia:/tmp/authelia
|
||||
environment:
|
||||
- NODE_TLS_REJECT_UNAUTHORIZED=0
|
||||
depends_on:
|
||||
- redis
|
||||
networks:
|
||||
- example-network
|
||||
command:
|
||||
- "./node_modules/.bin/ts-node"
|
||||
- "-P"
|
||||
- "server/tsconfig.json"
|
||||
- "server/src/index.ts"
|
||||
- "/etc/authelia/config.yml"
|
|
@ -10,4 +10,4 @@ services:
|
|||
depends_on:
|
||||
- redis
|
||||
networks:
|
||||
- example-network
|
||||
- example-network
|
|
@ -0,0 +1,12 @@
|
|||
version: '2'
|
||||
services:
|
||||
authelia:
|
||||
build: .
|
||||
restart: always
|
||||
volumes:
|
||||
- ./config.minimal.yml:/etc/authelia/config.yml:ro
|
||||
- /tmp/authelia:/tmp/authelia
|
||||
environment:
|
||||
- NODE_TLS_REJECT_UNAUTHORIZED=0
|
||||
networks:
|
||||
- example-network
|
|
@ -9,5 +9,6 @@ services:
|
|||
- NODE_TLS_REJECT_UNAUTHORIZED=0
|
||||
depends_on:
|
||||
- redis
|
||||
- mongo
|
||||
networks:
|
||||
- example-network
|
||||
- example-network
|
|
@ -1,8 +0,0 @@
|
|||
version: '2'
|
||||
services:
|
||||
authelia:
|
||||
volumes:
|
||||
- ./dist/server:/usr/src/server
|
||||
- ./dist/shared:/usr/src/shared
|
||||
networks:
|
||||
- example-network
|
|
@ -1,8 +0,0 @@
|
|||
version: '2'
|
||||
services:
|
||||
nginx-authelia:
|
||||
image: nginx:alpine
|
||||
volumes:
|
||||
- ./example/compose/nginx/authelia/nginx.conf:/etc/nginx/nginx.conf
|
||||
networks:
|
||||
- example-network
|
|
@ -1,22 +0,0 @@
|
|||
worker_processes 1;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
|
||||
http {
|
||||
server {
|
||||
listen 80;
|
||||
|
||||
resolver 127.0.0.11 ipv6=off;
|
||||
set $upstream_endpoint http://authelia;
|
||||
|
||||
location / {
|
||||
proxy_set_header Host $http_host;
|
||||
|
||||
proxy_pass $upstream_endpoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
version: '2'
|
||||
services:
|
||||
nginx-portal:
|
||||
image: nginx:alpine
|
||||
volumes:
|
||||
- ./example/compose/nginx/minimal/nginx.conf:/etc/nginx/nginx.conf
|
||||
- ./example/compose/nginx/minimal/html:/usr/share/nginx/html
|
||||
- ./example/compose/nginx/minimal/ssl:/etc/ssl
|
||||
ports:
|
||||
- "8080:443"
|
||||
networks:
|
||||
- example-network
|
|
@ -0,0 +1,11 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Secret</title>
|
||||
<link rel="icon" href="/icon.png" type="image/png" />
|
||||
</head>
|
||||
<body>
|
||||
<h1>Secret</h1>
|
||||
This is a very important secret!<br/>
|
||||
Go back to <a href="https://home.example.com:8080/">home page</a>.
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,32 @@
|
|||
<!DOCTYPE>
|
||||
<html>
|
||||
<head>
|
||||
<title>Home page</title>
|
||||
<link rel="icon" href="/icon.png" type="image/png" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Access the secret</h1>
|
||||
<span style="font-size: 1.2em; color: red">You need to log in to access the secret!</span><br/><br/> Try to access it using
|
||||
the following links to test Authelia.<br/>
|
||||
<ul>
|
||||
<li>
|
||||
admin.example.com <a href="https://admin.example.com:8080/secret.html"> / secret.html</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
You can also log off by visiting the following <a href="https://login.example.com:8080/logout?rd=https://home.example.com:8080/">link</a>.
|
||||
|
||||
<h1>List of users</h1>
|
||||
Here is the list of credentials you can log in with.<br/>
|
||||
<br/> Once first factor is passed, you will need to follow the links to register a secret for the second factor.<br/> Authelia
|
||||
will send you a fictituous email stored in a <strong>local file</strong> called <strong>/tmp/authelia/notification.txt</strong>.<br/>
|
||||
It will provide you with the link to complete the registration allowing you to authenticate with 2-factor.
|
||||
|
||||
<ul>
|
||||
<li><strong>john / password</strong>: belongs to <em>admin</em> and <em>dev</em> groups.</li>
|
||||
<li><strong>bob / password</strong>: belongs to <em>dev</em> group only.</li>
|
||||
<li><strong>harry / password</strong>: does not belong to any group.</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,99 @@
|
|||
worker_processes 1;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name login.example.com;
|
||||
|
||||
resolver 127.0.0.11 ipv6=off;
|
||||
set $upstream_endpoint http://authelia:8080;
|
||||
|
||||
ssl on;
|
||||
ssl_certificate /etc/ssl/server.crt;
|
||||
ssl_certificate_key /etc/ssl/server.key;
|
||||
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header X-Frame-Options "SAMEORIGIN";
|
||||
|
||||
location / {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Original-URI $request_uri;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_intercept_errors on;
|
||||
|
||||
proxy_pass $upstream_endpoint;
|
||||
|
||||
if ($request_method !~ ^(POST)$){
|
||||
error_page 401 = /error/401;
|
||||
error_page 403 = /error/403;
|
||||
error_page 404 = /error/404;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name home.example.com;
|
||||
|
||||
resolver 127.0.0.11 ipv6=off;
|
||||
set $upstream_endpoint http://nginx-backend;
|
||||
|
||||
root /usr/share/nginx/html/home;
|
||||
|
||||
ssl on;
|
||||
ssl_certificate /etc/ssl/server.crt;
|
||||
ssl_certificate_key /etc/ssl/server.key;
|
||||
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header X-Frame-Options "SAMEORIGIN";
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name admin.example.com;
|
||||
|
||||
root /usr/share/nginx/html/admin;
|
||||
|
||||
resolver 127.0.0.11 ipv6=off;
|
||||
set $upstream_verify http://authelia:8080/api/verify;
|
||||
|
||||
ssl on;
|
||||
ssl_certificate /etc/ssl/server.crt;
|
||||
ssl_certificate_key /etc/ssl/server.key;
|
||||
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
add_header X-Frame-Options "SAMEORIGIN";
|
||||
|
||||
location /auth_verify {
|
||||
internal;
|
||||
proxy_set_header Host $http_host;
|
||||
|
||||
proxy_set_header X-Original-URI $request_uri;
|
||||
proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
proxy_pass_request_body off;
|
||||
proxy_set_header Content-Length "";
|
||||
|
||||
proxy_pass $upstream_verify;
|
||||
}
|
||||
|
||||
location / {
|
||||
auth_request /auth_verify;
|
||||
|
||||
auth_request_set $redirect $upstream_http_redirect;
|
||||
auth_request_set $user $upstream_http_remote_user;
|
||||
auth_request_set $groups $upstream_http_remote_groups;
|
||||
|
||||
error_page 401 =302 https://login.example.com:8080?rd=$redirect;
|
||||
error_page 403 = https://login.example.com:8080/error/403;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIICATCCAWoCCQCvH2RvyOshNzANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB
|
||||
VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0
|
||||
cyBQdHkgTHRkMB4XDTE3MDExNzIzMTc0M1oXDTE4MDExNzIzMTc0M1owRTELMAkG
|
||||
A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0
|
||||
IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAzZaE
|
||||
4XE1QyFNbrHBHRhSA53anAsJ5mBeG7Om6SdQcZAYahlDWEbtdoY4hy0gPNGcITcW
|
||||
eE+WA+PvNRr7PczKEhneIyUUgV+nrz010fM5JnECPxLTe1oFzl4U8dyYiBpTziNz
|
||||
hiUfq733PRYjcd9BQtcKcN4LdmQvjUHnnQ73TysCAwEAATANBgkqhkiG9w0BAQsF
|
||||
AAOBgQAUFICtbuqXgL4HBRAg7yGbwokoH8Ar1QKZGe+F2WTR8vaDLOYUL7VsltLE
|
||||
EJIGrcfs31nItHOBcLJuflrS8y0CQqes5puRw33LL2usSvO8z2q7JhCx+DSBi6yN
|
||||
RbhcrGOllIdjsrbmd/zAMBVTUyxSisq3Nmk1cZayDvKg+GSAEA==
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,11 @@
|
|||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIBhDCB7gIBADBFMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEh
|
||||
MB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEB
|
||||
AQUAA4GNADCBiQKBgQDNloThcTVDIU1uscEdGFIDndqcCwnmYF4bs6bpJ1BxkBhq
|
||||
GUNYRu12hjiHLSA80ZwhNxZ4T5YD4+81Gvs9zMoSGd4jJRSBX6evPTXR8zkmcQI/
|
||||
EtN7WgXOXhTx3JiIGlPOI3OGJR+rvfc9FiNx30FC1wpw3gt2ZC+NQeedDvdPKwID
|
||||
AQABoAAwDQYJKoZIhvcNAQELBQADgYEAmCX60kspIw1Zfb79AQOarFW5Q2K2h5Vx
|
||||
/cRbDyHlKtbmG77EtICccULyqf76B1gNRw5Zq3lSotSUcLzsWcdesXCFDC7k87Qf
|
||||
mpQKPj6GdTYJvdWf8aDwt32tAqWuBIRoAbdx5WbFPPWVfDcm7zDJefBrhNUDH0Qd
|
||||
vcnxjvPMmOM=
|
||||
-----END CERTIFICATE REQUEST-----
|
|
@ -0,0 +1,15 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICXQIBAAKBgQDNloThcTVDIU1uscEdGFIDndqcCwnmYF4bs6bpJ1BxkBhqGUNY
|
||||
Ru12hjiHLSA80ZwhNxZ4T5YD4+81Gvs9zMoSGd4jJRSBX6evPTXR8zkmcQI/EtN7
|
||||
WgXOXhTx3JiIGlPOI3OGJR+rvfc9FiNx30FC1wpw3gt2ZC+NQeedDvdPKwIDAQAB
|
||||
AoGBAIwGcfkO30UawJ+daDeF4g5ejI/toM+NYWuiwBNbWJoQl+Bj1o+gt4obvxKq
|
||||
tKNX7OxelepZ4oZB0CIuf2LHQfU6cVGdu//or7nfS2FLBYStopZyL6KorZbkqsj1
|
||||
ikQN4GosJQqaYkexnwjItMFaHaRRX6YnIXp42Jl1glitO3+5AkEA+thn/vwFo24I
|
||||
fC+7ORpmLi+BVAkTuhMm+C6TIV6s64B+A5oQ82OBCYK9YCOWmS6JHHFDrxJla+3M
|
||||
2U9KXky63wJBANHQCFCirfuT6esSjbqpCeqtmZG5LWHtL12V9DF7yjHPjmHL9uRu
|
||||
e9W+Uz33IJbqd82gtZ/ARfpYEjD0JEieQTUCQFo872xzDTQ1qSfDo/5u2MNUo5mv
|
||||
ikEuEp7FYnhmrp4poyt4iRCFgy4Ask+bfdmtO/XXaRnZ7FJfQYoLVB2ITNECQQCN
|
||||
gOiauZztl4yj5heAVJFDnWF9To61BOp1C7VtyjdL8NfuTUluNrV+KqapnAp2vhue
|
||||
q0zTOTH47X0XVxFBiLohAkBuQzPey5I3Ui8inE4sDt/fqX8r/GMhBTxIb9KlV/H6
|
||||
jKZNs/83n5/ohaX36er8svW9PB4pcqENZ+kBpvDtKVwS
|
||||
-----END RSA PRIVATE KEY-----
|
|
@ -10,7 +10,7 @@ http {
|
|||
server_name login.example.com;
|
||||
|
||||
resolver 127.0.0.11 ipv6=off;
|
||||
set $upstream_endpoint http://nginx-authelia;
|
||||
set $upstream_endpoint http://authelia:8080;
|
||||
|
||||
ssl on;
|
||||
ssl_certificate /etc/ssl/server.crt;
|
||||
|
@ -61,7 +61,7 @@ http {
|
|||
server_name public.example.com;
|
||||
|
||||
resolver 127.0.0.11 ipv6=off;
|
||||
set $upstream_verify http://nginx-authelia/api/verify;
|
||||
set $upstream_verify http://authelia:8080/api/verify;
|
||||
set $upstream_endpoint http://nginx-backend;
|
||||
set $upstream_headers http://httpbin:8000/headers;
|
||||
|
||||
|
@ -129,7 +129,7 @@ http {
|
|||
server_name admin.example.com;
|
||||
|
||||
resolver 127.0.0.11 ipv6=off;
|
||||
set $upstream_verify http://nginx-authelia/api/verify;
|
||||
set $upstream_verify http://authelia:8080/api/verify;
|
||||
set $upstream_endpoint http://nginx-backend;
|
||||
|
||||
ssl on;
|
||||
|
@ -179,7 +179,7 @@ http {
|
|||
server_name dev.example.com;
|
||||
|
||||
resolver 127.0.0.11 ipv6=off;
|
||||
set $upstream_verify http://nginx-authelia/api/verify;
|
||||
set $upstream_verify http://authelia:8080/api/verify;
|
||||
set $upstream_endpoint http://nginx-backend;
|
||||
|
||||
ssl on;
|
||||
|
@ -229,7 +229,7 @@ http {
|
|||
server_name mx1.mail.example.com mx2.mail.example.com;
|
||||
|
||||
resolver 127.0.0.11 ipv6=off;
|
||||
set $upstream_verify http://nginx-authelia/api/verify;
|
||||
set $upstream_verify http://authelia:8080/api/verify;
|
||||
set $upstream_endpoint http://nginx-backend;
|
||||
|
||||
ssl on;
|
||||
|
@ -279,7 +279,7 @@ http {
|
|||
server_name single_factor.example.com;
|
||||
|
||||
resolver 127.0.0.11 ipv6=off;
|
||||
set $upstream_verify http://nginx-authelia/api/verify;
|
||||
set $upstream_verify http://authelia:8080/api/verify;
|
||||
set $upstream_endpoint http://nginx-backend;
|
||||
set $upstream_headers http://httpbin:8000/headers;
|
||||
|
||||
|
@ -350,7 +350,7 @@ http {
|
|||
server_name authelia.example.com;
|
||||
|
||||
resolver 127.0.0.11 ipv6=off;
|
||||
set $upstream_endpoint http://authelia;
|
||||
set $upstream_endpoint http://authelia:8080;
|
||||
|
||||
ssl on;
|
||||
ssl_certificate /etc/ssl/server.crt;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
npm i
|
||||
grunt schema
|
||||
grunt build
|
|
@ -3,12 +3,10 @@
|
|||
set -e
|
||||
|
||||
docker-compose \
|
||||
-f docker-compose.yml \
|
||||
-f docker-compose.dev.yml \
|
||||
-f example/compose/docker-compose.base.yml \
|
||||
-f example/compose/authelia/docker-compose.dev.yml \
|
||||
-f example/compose/mongo/docker-compose.yml \
|
||||
-f example/compose/redis/docker-compose.yml \
|
||||
-f example/compose/nginx/authelia/docker-compose.yml \
|
||||
-f example/compose/nginx/backend/docker-compose.yml \
|
||||
-f example/compose/nginx/portal/docker-compose.yml \
|
||||
-f example/compose/smtp/docker-compose.yml \
|
||||
|
|
|
@ -7,7 +7,6 @@ docker-compose \
|
|||
-f example/compose/docker-compose.base.yml \
|
||||
-f example/compose/mongo/docker-compose.yml \
|
||||
-f example/compose/redis/docker-compose.yml \
|
||||
-f example/compose/nginx/authelia/docker-compose.yml \
|
||||
-f example/compose/nginx/backend/docker-compose.yml \
|
||||
-f example/compose/nginx/portal/docker-compose.yml \
|
||||
-f example/compose/smtp/docker-compose.yml \
|
||||
|
|
|
@ -3,4 +3,4 @@
|
|||
DC_SCRIPT=./scripts/example-commit/dc-example.sh
|
||||
|
||||
$DC_SCRIPT build
|
||||
$DC_SCRIPT up -d httpbin mongo redis openldap authelia smtp nginx-authelia nginx-portal nginx-backend
|
||||
$DC_SCRIPT up -d httpbin mongo redis openldap authelia smtp nginx-portal nginx-backend
|
||||
|
|
|
@ -7,7 +7,6 @@ docker-compose \
|
|||
-f example/compose/docker-compose.base.yml \
|
||||
-f example/compose/mongo/docker-compose.yml \
|
||||
-f example/compose/redis/docker-compose.yml \
|
||||
-f example/compose/nginx/authelia/docker-compose.yml \
|
||||
-f example/compose/nginx/backend/docker-compose.yml \
|
||||
-f example/compose/nginx/portal/docker-compose.yml \
|
||||
-f example/compose/smtp/docker-compose.yml \
|
||||
|
|
|
@ -3,4 +3,4 @@
|
|||
DC_SCRIPT=./scripts/example-dockerhub/dc-example.sh
|
||||
|
||||
#$DC_SCRIPT build
|
||||
$DC_SCRIPT up -d httpbin mongo redis openldap authelia smtp nginx-authelia nginx-portal nginx-backend
|
||||
$DC_SCRIPT up -d httpbin mongo redis openldap authelia smtp nginx-portal nginx-backend
|
||||
|
|
|
@ -1,25 +1,12 @@
|
|||
#!/bin/bash
|
||||
|
||||
DC_SCRIPT=./scripts/example-commit/dc-example.sh
|
||||
EXPECTED_SERVICES_COUNT=9
|
||||
EXPECTED_SERVICES_COUNT=8
|
||||
|
||||
build_services() {
|
||||
$DC_SCRIPT build authelia
|
||||
}
|
||||
|
||||
start_services() {
|
||||
$DC_SCRIPT up -d httpbin mongo redis openldap authelia smtp nginx-authelia nginx-portal nginx-backend
|
||||
sleep 3
|
||||
}
|
||||
|
||||
shut_services() {
|
||||
containers_exist=`docker ps -aq | wc -l`
|
||||
if [ "$containers_exist" -ne "0" ]
|
||||
then
|
||||
docker rm -f $(docker ps -aq)
|
||||
fi
|
||||
}
|
||||
|
||||
expect_services_count() {
|
||||
EXPECTED_COUNT=$1
|
||||
service_count=`docker ps -a | grep "Up " | wc -l`
|
||||
|
@ -35,19 +22,11 @@ expect_services_count() {
|
|||
}
|
||||
|
||||
run_integration_tests() {
|
||||
echo "Start services..."
|
||||
start_services
|
||||
expect_services_count $EXPECTED_SERVICES_COUNT
|
||||
|
||||
sleep 5
|
||||
./node_modules/.bin/grunt run:test-int
|
||||
shut_services
|
||||
./node_modules/.bin/grunt test-int
|
||||
}
|
||||
|
||||
run_other_tests() {
|
||||
echo "Test dev environment deployment (commands in README)"
|
||||
# rm -rf node_modules
|
||||
# ./scripts/build-dev.sh
|
||||
./scripts/example-commit/deploy-example.sh
|
||||
expect_services_count $EXPECTED_SERVICES_COUNT
|
||||
./scripts/example-commit/undeploy-example.sh
|
||||
|
@ -60,18 +39,14 @@ run_other_tests_docker() {
|
|||
./scripts/example-dockerhub/undeploy-example.sh
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
set -e
|
||||
|
||||
echo "Make sure services are not already running"
|
||||
shut_services
|
||||
|
||||
# Build the container
|
||||
build_services
|
||||
|
||||
# Pull all images
|
||||
$DC_SCRIPT pull
|
||||
|
||||
# Prepare & test example from end user perspective
|
||||
run_integration_tests
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ set -e
|
|||
|
||||
docker --version
|
||||
docker-compose --version
|
||||
echo "node `node -v`"
|
||||
echo "npm `npm -v`"
|
||||
|
||||
# Generate configuration schema
|
||||
grunt schema
|
||||
|
|
|
@ -22,23 +22,36 @@ export interface Configuration {
|
|||
totp?: TotpConfiguration;
|
||||
}
|
||||
|
||||
export function complete(configuration: Configuration): [Configuration, string[]] {
|
||||
const newConfiguration: Configuration = JSON.parse(JSON.stringify(configuration));
|
||||
export function complete(
|
||||
configuration: Configuration):
|
||||
[Configuration, string[]] {
|
||||
|
||||
const newConfiguration: Configuration = JSON.parse(
|
||||
JSON.stringify(configuration));
|
||||
const errors: string[] = [];
|
||||
|
||||
newConfiguration.access_control = AclConfigurationComplete(newConfiguration.access_control);
|
||||
newConfiguration.ldap = LdapConfigurationComplete(newConfiguration.ldap);
|
||||
newConfiguration.access_control = AclConfigurationComplete(
|
||||
newConfiguration.access_control);
|
||||
newConfiguration.ldap = LdapConfigurationComplete(
|
||||
newConfiguration.ldap);
|
||||
|
||||
newConfiguration.authentication_methods = AuthenticationMethodsConfigurationComplete(newConfiguration.authentication_methods);
|
||||
newConfiguration.authentication_methods =
|
||||
AuthenticationMethodsConfigurationComplete(
|
||||
newConfiguration.authentication_methods);
|
||||
|
||||
if (!newConfiguration.logs_level) {
|
||||
newConfiguration.logs_level = "info";
|
||||
}
|
||||
|
||||
// In single factor mode, notifier section is optional.
|
||||
if (!MethodCalculator.isSingleFactorOnlyMode(newConfiguration.authentication_methods)) {
|
||||
const [notifier, error] = NotifierConfigurationComplete(newConfiguration.notifier);
|
||||
if (!MethodCalculator.isSingleFactorOnlyMode(
|
||||
newConfiguration.authentication_methods) ||
|
||||
newConfiguration.notifier) {
|
||||
|
||||
const [notifier, error] = NotifierConfigurationComplete(
|
||||
newConfiguration.notifier);
|
||||
newConfiguration.notifier = notifier;
|
||||
|
||||
if (error) errors.push(error);
|
||||
}
|
||||
|
||||
|
@ -46,10 +59,14 @@ export function complete(configuration: Configuration): [Configuration, string[]
|
|||
newConfiguration.port = 8080;
|
||||
}
|
||||
|
||||
newConfiguration.regulation = RegulationConfigurationComplete(newConfiguration.regulation);
|
||||
newConfiguration.session = SessionConfigurationComplete(newConfiguration.session);
|
||||
newConfiguration.storage = StorageConfigurationComplete(newConfiguration.storage);
|
||||
newConfiguration.totp = TotpConfigurationComplete(newConfiguration.totp);
|
||||
newConfiguration.regulation = RegulationConfigurationComplete(
|
||||
newConfiguration.regulation);
|
||||
newConfiguration.session = SessionConfigurationComplete(
|
||||
newConfiguration.session);
|
||||
newConfiguration.storage = StorageConfigurationComplete(
|
||||
newConfiguration.storage);
|
||||
newConfiguration.totp = TotpConfigurationComplete(
|
||||
newConfiguration.totp);
|
||||
|
||||
return [newConfiguration, errors];
|
||||
}
|
|
@ -2,10 +2,19 @@ import Assert = require("assert");
|
|||
import { NotifierConfiguration, complete } from "./NotifierConfiguration";
|
||||
|
||||
describe("configuration/schema/NotifierConfiguration", function() {
|
||||
it("should ensure at least one key is provided", function() {
|
||||
it("should use a default notifier when none is provided", function() {
|
||||
const configuration: NotifierConfiguration = {};
|
||||
const [newConfiguration, error] = complete(configuration);
|
||||
|
||||
Assert.deepEqual(newConfiguration.filesystem, {filename: "/tmp/authelia/notification.txt"})
|
||||
});
|
||||
|
||||
it("should ensure correct key is provided", function() {
|
||||
const configuration = {
|
||||
abc: 'badvalue'
|
||||
};
|
||||
const [newConfiguration, error] = complete(configuration as any);
|
||||
|
||||
Assert.equal(error, "Notifier must have one of the following keys: 'filesystem', 'email' or 'smtp'");
|
||||
});
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ export function complete(configuration: NotifierConfiguration): [NotifierConfigu
|
|||
const newConfiguration: NotifierConfiguration = (configuration) ? JSON.parse(JSON.stringify(configuration)) : {};
|
||||
|
||||
if (Object.keys(newConfiguration).length == 0)
|
||||
newConfiguration.filesystem = { filename: '/tmp/authelia-notification.txt' };
|
||||
newConfiguration.filesystem = { filename: "/tmp/authelia/notification.txt" };
|
||||
|
||||
const ERROR = "Notifier must have one of the following keys: 'filesystem', 'email' or 'smtp'";
|
||||
|
||||
|
@ -42,4 +42,4 @@ export function complete(configuration: NotifierConfiguration): [NotifierConfigu
|
|||
return [newConfiguration, ERROR];
|
||||
|
||||
return [newConfiguration, undefined];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
const { exec } = require('child_process');
|
||||
import Bluebird = require("bluebird");
|
||||
|
||||
function docker_compose(includes: string[]) {
|
||||
const compose_args = includes.map((dc: string) => `-f ${dc}`).join(' ');
|
||||
return `docker-compose ${compose_args}`;
|
||||
}
|
||||
|
||||
export function setup(includes: string[], setupTime: number = 2000): Bluebird<void> {
|
||||
const command = docker_compose(includes) + ' up -d'
|
||||
console.log('Starting up environment.');
|
||||
console.log('Running: %s', command);
|
||||
|
||||
return new Bluebird<void>(function(resolve, reject) {
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
if(err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
setTimeout(function() {
|
||||
resolve();
|
||||
}, setupTime);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function cleanup(includes: string[]): Bluebird<void> {
|
||||
const command = docker_compose(includes) + ' down';
|
||||
console.log('Shutting down environment.');
|
||||
console.log('Running: %s', command);
|
||||
|
||||
return new Bluebird<void>(function(resolve, reject) {
|
||||
exec(command, function(err, stdout, stderr) {
|
||||
if(err) {
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
|
@ -10,6 +10,7 @@ Feature: User is correctly redirected
|
|||
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"
|
||||
|
|
|
@ -8,7 +8,6 @@ When("I query {string}", function (url: string) {
|
|||
const that = this;
|
||||
return Request(url, { followRedirect: false })
|
||||
.then(function(response) {
|
||||
console.log(response);
|
||||
that.response = response;
|
||||
})
|
||||
.catch(function(err: Error) {
|
||||
|
@ -26,7 +25,7 @@ Then("I get error code 401", function() {
|
|||
if(that.response)
|
||||
reject(new Error("No error thrown"));
|
||||
else if(that.error.statusCode != 401)
|
||||
reject(new Error("Error code != 401"));
|
||||
reject(new Error(`Error code (${that.error.statusCode}) != 401`));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {setDefaultTimeout, After, Before} from "cucumber";
|
||||
import {setDefaultTimeout, After, Before, BeforeAll, AfterAll} from "cucumber";
|
||||
import fs = require("fs");
|
||||
import BluebirdPromise = require("bluebird");
|
||||
import ChildProcess = require("child_process");
|
||||
|
@ -10,11 +10,32 @@ import { TotpHandler } from "../../../server/src/lib/authentication/totp/TotpHan
|
|||
import Speakeasy = require("speakeasy");
|
||||
import Request = require("request-promise");
|
||||
import { TOTPSecret } from "../../../server/types/TOTPSecret";
|
||||
import Environment = require("../../environment");
|
||||
|
||||
setDefaultTimeout(20 * 1000);
|
||||
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"
|
||||
]
|
||||
|
||||
BeforeAll(function() {
|
||||
return Environment.setup(includes, 10000);
|
||||
});
|
||||
|
||||
AfterAll(function() {
|
||||
return Environment.cleanup(includes)
|
||||
});
|
||||
|
||||
Before(function () {
|
||||
this.jar = Request.jar();
|
||||
})
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
import SeleniumWebdriver = require("selenium-webdriver");
|
||||
import Bluebird = require("bluebird");
|
||||
|
||||
export default function(driver: any) {
|
||||
return driver.findElement(
|
||||
SeleniumWebdriver.By.tagName('h1')).getText()
|
||||
.then(function(content: string) {
|
||||
return (content.indexOf('Secret') > -1)
|
||||
? Bluebird.resolve()
|
||||
: Bluebird.reject(new Error("Secret is not accessible."));
|
||||
})
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import SeleniumWebdriver = require("selenium-webdriver");
|
||||
|
||||
export default function(driver: any, buttonText: string) {
|
||||
return driver.wait(
|
||||
SeleniumWebdriver.until.elementLocated(
|
||||
SeleniumWebdriver.By.tagName("button")), 5000)
|
||||
.then(function () {
|
||||
return driver
|
||||
.findElement(SeleniumWebdriver.By.tagName("button"))
|
||||
.findElement(SeleniumWebdriver.By.xpath("//button[contains(.,'" + buttonText + "')]"))
|
||||
.click();
|
||||
});
|
||||
};
|
|
@ -0,0 +1,17 @@
|
|||
import SeleniumWebdriver = require("selenium-webdriver");
|
||||
|
||||
export default function(driver: any, username: string, password: string) {
|
||||
return driver.wait(SeleniumWebdriver.until.elementLocated(SeleniumWebdriver.By.id("username")), 5000)
|
||||
.then(function () {
|
||||
return driver.findElement(SeleniumWebdriver.By.id("username"))
|
||||
.sendKeys(username);
|
||||
})
|
||||
.then(function () {
|
||||
return driver.findElement(SeleniumWebdriver.By.id("password"))
|
||||
.sendKeys(password);
|
||||
})
|
||||
.then(function () {
|
||||
return driver.findElement(SeleniumWebdriver.By.tagName("button"))
|
||||
.click();
|
||||
});
|
||||
};
|
|
@ -0,0 +1,11 @@
|
|||
import VisitPage from "./visit-page";
|
||||
import FillLoginPageAndClick from './fill-login-page-and-click';
|
||||
import RegisterTotp from './register-totp';
|
||||
import WaitRedirected from './wait-redirected';
|
||||
|
||||
export default function(driver: any, user: string) {
|
||||
return VisitPage(driver, "https://login.example.com:8080/")
|
||||
.then(() => FillLoginPageAndClick(driver, user, "password"))
|
||||
.then(() => WaitRedirected(driver, "https://login.example.com:8080/secondfactor"))
|
||||
.then(() => RegisterTotp(driver));
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
import Bluebird = require("bluebird");
|
||||
import SeleniumWebdriver = require("selenium-webdriver");
|
||||
import Fs = require("fs");
|
||||
|
||||
function retrieveValidationLinkFromNotificationFile(): Bluebird<string> {
|
||||
return Bluebird.promisify(Fs.readFile)("/tmp/authelia/notification.txt")
|
||||
.then(function (data: any) {
|
||||
const regexp = new RegExp(/Link: (.+)/);
|
||||
const match = regexp.exec(data);
|
||||
const link = match[1];
|
||||
return Bluebird.resolve(link);
|
||||
});
|
||||
};
|
||||
|
||||
export default function(driver: any): Bluebird<string> {
|
||||
return driver.wait(SeleniumWebdriver.until.elementLocated(SeleniumWebdriver.By.className("register-totp")), 5000)
|
||||
.then(function () {
|
||||
return driver.findElement(SeleniumWebdriver.By.className("register-totp")).click();
|
||||
})
|
||||
.then(function () {
|
||||
return retrieveValidationLinkFromNotificationFile();
|
||||
})
|
||||
.then(function (link: string) {
|
||||
return driver.get(link);
|
||||
})
|
||||
.then(function () {
|
||||
return driver.wait(SeleniumWebdriver.until.elementLocated(SeleniumWebdriver.By.id("secret")), 5000);
|
||||
})
|
||||
.then(function () {
|
||||
return driver.findElement(SeleniumWebdriver.By.id("secret")).getText();
|
||||
});
|
||||
};
|
|
@ -0,0 +1,18 @@
|
|||
import SeleniumWebdriver = require("selenium-webdriver");
|
||||
import Assert = require("assert");
|
||||
|
||||
export default function(driver: any, type: string, message: string) {
|
||||
const notificationEl = driver.findElement(SeleniumWebdriver.By.className("notification"));
|
||||
return driver.wait(SeleniumWebdriver.until.elementIsVisible(notificationEl), 5000)
|
||||
.then(function () {
|
||||
return notificationEl.getText();
|
||||
})
|
||||
.then(function (txt: string) {
|
||||
Assert.equal(message, txt);
|
||||
return notificationEl.getAttribute("class");
|
||||
})
|
||||
.then(function (classes: string) {
|
||||
Assert(classes.indexOf(type) > -1, "Class '" + type + "' not found in notification element.");
|
||||
return driver.sleep(500);
|
||||
});
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
import Speakeasy = require("speakeasy");
|
||||
import SeleniumWebdriver = require("selenium-webdriver");
|
||||
import ClickOnButton from "./click-on-button";
|
||||
|
||||
export default function(driver: any, secret: string) {
|
||||
const token = Speakeasy.totp({
|
||||
secret: secret,
|
||||
encoding: "base32"
|
||||
});
|
||||
return driver.wait(
|
||||
SeleniumWebdriver.until.elementLocated(
|
||||
SeleniumWebdriver.By.id("token")), 5000)
|
||||
.then(function () {
|
||||
return driver.findElement(SeleniumWebdriver.By.id("token"))
|
||||
.sendKeys(token);
|
||||
})
|
||||
.then(function () {
|
||||
return ClickOnButton(driver, "Sign in");
|
||||
});
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
import SeleniumWebdriver = require("selenium-webdriver");
|
||||
|
||||
export default function(driver: any, url: string, timeout: number = 5000) {
|
||||
return driver.get(url)
|
||||
.then(function () {
|
||||
return driver.wait(SeleniumWebdriver.until.urlIs(url), timeout);
|
||||
});
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
import SeleniumWebdriver = require("selenium-webdriver");
|
||||
|
||||
export default function(driver: any, url: string, timeout: number = 5000) {
|
||||
return driver.wait(SeleniumWebdriver.until.urlIs(url), timeout);
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import SeleniumWebdriver = require("selenium-webdriver");
|
||||
|
||||
export default function() {
|
||||
before(function() {
|
||||
this.driver = new SeleniumWebdriver.Builder()
|
||||
.forBrowser("chrome")
|
||||
.build();
|
||||
})
|
||||
|
||||
after(function() {
|
||||
this.driver.quit();
|
||||
});
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
require("chromedriver");
|
||||
import Environment = require('../environment');
|
||||
|
||||
const includes = [
|
||||
"docker-compose.minimal.yml",
|
||||
"example/compose/docker-compose.base.yml",
|
||||
"example/compose/nginx/minimal/docker-compose.yml",
|
||||
"example/compose/ldap/docker-compose.yml"
|
||||
]
|
||||
|
||||
|
||||
before(function() {
|
||||
this.timeout(20000);
|
||||
return Environment.setup(includes);
|
||||
});
|
||||
|
||||
after(function() {
|
||||
this.timeout(30000);
|
||||
return Environment.cleanup(includes);
|
||||
});
|
|
@ -0,0 +1,34 @@
|
|||
import Bluebird = require("bluebird");
|
||||
import SeleniumWebdriver = require("selenium-webdriver");
|
||||
import Fs = require("fs");
|
||||
import Speakeasy = require("speakeasy");
|
||||
import WithDriver from '../helpers/with-driver';
|
||||
import FillLoginPageWithUserAndPasswordAndClick from '../helpers/fill-login-page-and-click';
|
||||
import WaitRedirected from '../helpers/wait-redirected';
|
||||
import VisitPage from '../helpers/visit-page';
|
||||
import SeeNotification from '../helpers/see-notification';
|
||||
|
||||
/**
|
||||
* When user provides bad password,
|
||||
* Then he gets a notification message.
|
||||
*/
|
||||
describe("Provide bad password", function() {
|
||||
WithDriver();
|
||||
|
||||
describe('failed login as john', function() {
|
||||
before(function() {
|
||||
this.timeout(10000);
|
||||
|
||||
const driver = this.driver;
|
||||
return VisitPage(driver, "https://login.example.com:8080/")
|
||||
.then(function() {
|
||||
return FillLoginPageWithUserAndPasswordAndClick(driver, 'john', 'bad_password');
|
||||
});
|
||||
});
|
||||
|
||||
it('should get a notification message', function() {
|
||||
this.timeout(10000);
|
||||
return SeeNotification(this.driver, "error", "Authentication failed. Please check your credentials.");
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,46 @@
|
|||
require("chromedriver");
|
||||
import Bluebird = require("bluebird");
|
||||
import SeleniumWebdriver = require("selenium-webdriver");
|
||||
import Fs = require("fs");
|
||||
import Speakeasy = require("speakeasy");
|
||||
import WithDriver from '../helpers/with-driver';
|
||||
import FillLoginPageWithUserAndPasswordAndClick from '../helpers/fill-login-page-and-click';
|
||||
import WaitRedirected from '../helpers/wait-redirected';
|
||||
import VisitPage from '../helpers/visit-page';
|
||||
import RegisterTotp from '../helpers/register-totp';
|
||||
import ValidateTotp from '../helpers/validate-totp';
|
||||
import AccessSecret from "../helpers/access-secret";
|
||||
import LoginAndRegisterTotp from '../helpers/login-and-register-totp';
|
||||
import seeNotification from "../helpers/see-notification";
|
||||
|
||||
/**
|
||||
* Given john has registered a TOTP secret,
|
||||
* When he fails the TOTP challenge,
|
||||
* Then he gets a notification message.
|
||||
*/
|
||||
describe('Fail TOTP challenge', function() {
|
||||
this.timeout(10000);
|
||||
WithDriver();
|
||||
|
||||
describe('successfully login as john', function() {
|
||||
before(function() {
|
||||
const that = this;
|
||||
return LoginAndRegisterTotp(this.driver, "john");
|
||||
});
|
||||
|
||||
describe('fail second factor', function() {
|
||||
before(function() {
|
||||
const BAD_TOKEN = "125478";
|
||||
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'))
|
||||
.then(() => ValidateTotp(driver, BAD_TOKEN));
|
||||
});
|
||||
|
||||
it("get a notification message", function() {
|
||||
return seeNotification(this.driver, "error", "Authentication failed. Have you already registered your secret?");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,32 @@
|
|||
import SeleniumWebdriver = require("selenium-webdriver");
|
||||
import WithDriver from '../helpers/with-driver';
|
||||
import LoginAndRegisterTotp from '../helpers/login-and-register-totp';
|
||||
|
||||
/**
|
||||
* Given the user logs in as john,
|
||||
* When he register a TOTP token,
|
||||
* Then he reach a page containing the secret as string an qrcode
|
||||
*/
|
||||
describe('Registering TOTP', function() {
|
||||
this.timeout(10000);
|
||||
WithDriver();
|
||||
|
||||
describe('successfully login as john', function() {
|
||||
before('register successfully', function() {
|
||||
this.timeout(10000);
|
||||
return LoginAndRegisterTotp(this.driver, "john");
|
||||
})
|
||||
|
||||
it("should see generated qrcode", function() {
|
||||
this.driver.findElement(
|
||||
SeleniumWebdriver.By.id("qrcode"),
|
||||
5000);
|
||||
});
|
||||
|
||||
it("should see generated secret", function() {
|
||||
this.driver.findElement(
|
||||
SeleniumWebdriver.By.id("secret"),
|
||||
5000);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,56 @@
|
|||
require("chromedriver");
|
||||
import Bluebird = require("bluebird");
|
||||
import SeleniumWebdriver = require("selenium-webdriver");
|
||||
import Fs = require("fs");
|
||||
import Speakeasy = require("speakeasy");
|
||||
import WithDriver from '../helpers/with-driver';
|
||||
import FillLoginPageWithUserAndPasswordAndClick from '../helpers/fill-login-page-and-click';
|
||||
import WaitRedirected from '../helpers/wait-redirected';
|
||||
import VisitPage from '../helpers/visit-page';
|
||||
import RegisterTotp from '../helpers/register-totp';
|
||||
import ValidateTotp from '../helpers/validate-totp';
|
||||
import AccessSecret from "../helpers/access-secret";
|
||||
import LoginAndRegisterTotp from '../helpers/login-and-register-totp';
|
||||
|
||||
/**
|
||||
* Given john has registered a TOTP secret,
|
||||
* When he validates the TOTP second factor,
|
||||
* Then he has access to secret page.
|
||||
*/
|
||||
describe('Validate TOTP factor', function() {
|
||||
this.timeout(10000);
|
||||
WithDriver();
|
||||
|
||||
describe('successfully login as john', function() {
|
||||
before(function() {
|
||||
const that = this;
|
||||
return LoginAndRegisterTotp(this.driver, "john")
|
||||
.then(function(secret: string) {
|
||||
that.secret = secret;
|
||||
})
|
||||
});
|
||||
|
||||
describe('validate second factor', function() {
|
||||
before(function() {
|
||||
const secret = this.secret;
|
||||
if(!secret) return Bluebird.reject(new Error("No secret!"));
|
||||
const driver = this.driver;
|
||||
|
||||
return VisitPage(driver, "https://login.example.com:8080/?rd=https://admin.example.com:8080/secret.html")
|
||||
.then(function() {
|
||||
return FillLoginPageWithUserAndPasswordAndClick(driver, 'john', 'password');
|
||||
})
|
||||
.then(function () {
|
||||
return ValidateTotp(driver, secret);
|
||||
})
|
||||
.then(function() {
|
||||
return WaitRedirected(driver, "https://admin.example.com:8080/secret.html")
|
||||
});
|
||||
});
|
||||
|
||||
it("should access the secret", function() {
|
||||
return AccessSecret(this.driver);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue