diff --git a/1 b/1 deleted file mode 100644 index 7541d799..00000000 --- a/1 +++ /dev/null @@ -1,3 +0,0 @@ -Error: No such container: authelia-test -Error: No such container: 2 -Error: No such container: dev/null diff --git a/docker-compose.dockerhub.yml b/example/compose/authelia/docker-compose.dockerhub.yml similarity index 76% rename from docker-compose.dockerhub.yml rename to example/compose/authelia/docker-compose.dockerhub.yml index 5d660957..a78db496 100644 --- a/docker-compose.dockerhub.yml +++ b/example/compose/authelia/docker-compose.dockerhub.yml @@ -4,7 +4,7 @@ services: image: clems4ever/authelia:latest restart: always volumes: - - ./config.template.yml:/etc/authelia/config.yml:ro + - ./test/suites/dockerhub/config.yml:/etc/authelia/config.yml:ro environment: - NODE_TLS_REJECT_UNAUTHORIZED=0 depends_on: diff --git a/example/compose/authelia/docker-compose.test.yml b/example/compose/authelia/docker-compose.test.yml deleted file mode 100644 index ed5f9083..00000000 --- a/example/compose/authelia/docker-compose.test.yml +++ /dev/null @@ -1,9 +0,0 @@ -version: '2' -services: - authelia: - volumes: - - ./config.test.yml:/etc/authelia/config.yml:ro - - ./dist/server:/usr/src/server - - ./dist/shared:/usr/src/shared - networks: - - authelianet diff --git a/example/compose/nginx/portal/nginx.conf.ejs b/example/compose/nginx/portal/nginx.conf.ejs index f513c1e8..8ecb9c7f 100644 --- a/example/compose/nginx/portal/nginx.conf.ejs +++ b/example/compose/nginx/portal/nginx.conf.ejs @@ -21,7 +21,7 @@ http { server_name login.example.com; resolver 127.0.0.11 ipv6=off; - set $backend_endpoint http://192.168.240.1:9091; + set $backend_endpoint <%= authelia_backend %>; ssl_certificate /etc/ssl/server.crt; ssl_certificate_key /etc/ssl/server.key; @@ -56,7 +56,7 @@ http { resolver 127.0.0.11 ipv6=off; set $frontend_endpoint http://192.168.240.1:3000; - set $backend_endpoint http://192.168.240.1:9091; + set $backend_endpoint <%= authelia_backend %>; ssl_certificate /etc/ssl/server.crt; ssl_certificate_key /etc/ssl/server.key; @@ -111,7 +111,7 @@ http { server_name public.example.com; resolver 127.0.0.11 ipv6=off; - set $upstream_verify http://192.168.240.1:9091/api/verify; + set $upstream_verify <%= authelia_backend %>/api/verify; set $upstream_endpoint http://nginx-backend; set $upstream_headers http://httpbin:8000/headers; @@ -179,7 +179,7 @@ http { server_name admin.example.com; resolver 127.0.0.11 ipv6=off; - set $upstream_verify http://192.168.240.1:9091/api/verify; + set $upstream_verify <%= authelia_backend %>/api/verify; set $upstream_endpoint http://nginx-backend; ssl_certificate /etc/ssl/server.crt; @@ -229,7 +229,7 @@ http { server_name dev.example.com; resolver 127.0.0.11 ipv6=off; - set $upstream_verify http://192.168.240.1:9091/api/verify; + set $upstream_verify <%= authelia_backend %>/api/verify; set $upstream_endpoint http://nginx-backend; ssl_certificate /etc/ssl/server.crt; @@ -279,7 +279,7 @@ http { server_name mx1.mail.example.com mx2.mail.example.com; resolver 127.0.0.11 ipv6=off; - set $upstream_verify http://192.168.240.1:9091/api/verify; + set $upstream_verify <%= authelia_backend %>/api/verify; set $upstream_endpoint http://nginx-backend; ssl_certificate /etc/ssl/server.crt; @@ -329,7 +329,7 @@ http { server_name single_factor.example.com; resolver 127.0.0.11 ipv6=off; - set $upstream_verify http://192.168.240.1:9091/api/verify; + set $upstream_verify <%= authelia_backend %>/api/verify; set $upstream_endpoint http://nginx-backend; set $upstream_headers http://httpbin:8000/headers; @@ -400,7 +400,7 @@ http { server_name authelia.example.com; resolver 127.0.0.11 ipv6=off; - set $upstream_endpoint http://192.168.240.1:9091; + set $upstream_endpoint <%= authelia_backend %>; ssl_certificate /etc/ssl/server.crt; ssl_certificate_key /etc/ssl/server.key; diff --git a/example/compose/nginx/portal/render.js b/example/compose/nginx/portal/render.js index 38125fd6..607ff70d 100755 --- a/example/compose/nginx/portal/render.js +++ b/example/compose/nginx/portal/render.js @@ -4,19 +4,29 @@ const ejs = require('ejs'); const fs = require('fs'); const program = require('commander'); +let backend; + program .version('0.1.0') .option('-p, --production', 'Render template for production.') + .arguments('[backend]') + .action((backendArg) => backend = backendArg) .parse(process.argv) const options = { production: false, } +if (!backend) { + backend = 'http://192.168.240.1:9091' +} + if (program.production) { options['production'] = true; } +options['authelia_backend'] = backend; + const templatePath = __dirname + '/nginx.conf.ejs'; const outputPath = __dirname + '/nginx.conf'; diff --git a/scripts/example-dockerhub/dc-example.sh b/scripts/example-dockerhub/dc-example.sh deleted file mode 100755 index cda6064e..00000000 --- a/scripts/example-dockerhub/dc-example.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -set -e - -docker-compose \ - -f docker-compose.yml \ - -f docker-compose.dockerhub.yml \ - -f example/compose/mongo/docker-compose.yml \ - -f example/compose/redis/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 \ - -f example/compose/httpbin/docker-compose.yml \ - -f example/compose/ldap/docker-compose.yml $* diff --git a/scripts/example-dockerhub/deploy-example.sh b/scripts/example-dockerhub/deploy-example.sh deleted file mode 100755 index 84492065..00000000 --- a/scripts/example-dockerhub/deploy-example.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -DC_SCRIPT=./scripts/example-dockerhub/dc-example.sh - -#$DC_SCRIPT build -$DC_SCRIPT up -d httpbin mongo redis openldap authelia smtp nginx-portal nginx-backend diff --git a/scripts/example-dockerhub/undeploy-example.sh b/scripts/example-dockerhub/undeploy-example.sh deleted file mode 100755 index 1b943f39..00000000 --- a/scripts/example-dockerhub/undeploy-example.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -DC_SCRIPT=./scripts/example-dockerhub/dc-example.sh - -$DC_SCRIPT down diff --git a/test/helpers/context/DockerCompose.ts b/test/helpers/context/DockerCompose.ts index 742fe41b..ddf6c963 100644 --- a/test/helpers/context/DockerCompose.ts +++ b/test/helpers/context/DockerCompose.ts @@ -1,4 +1,5 @@ import { exec } from '../../helpers/utils/exec'; +import { execSync } from 'child_process'; class DockerCompose { private commandPrefix: string; @@ -8,15 +9,19 @@ class DockerCompose { } async up() { - await exec(this.commandPrefix + ' up -d'); + return await exec(this.commandPrefix + ' up -d'); } async down() { - await exec(this.commandPrefix + ' down'); + return await exec(this.commandPrefix + ' down'); } async restart(service: string) { - await exec(this.commandPrefix + ' restart ' + service); + return await exec(this.commandPrefix + ' restart ' + service); + } + + async ps() { + return Promise.resolve(execSync(this.commandPrefix + ' ps').toString('utf-8')); } } diff --git a/test/helpers/context/WithEnvironment.ts b/test/helpers/context/WithEnvironment.ts index c6fd9bdc..5019ba5f 100644 --- a/test/helpers/context/WithEnvironment.ts +++ b/test/helpers/context/WithEnvironment.ts @@ -13,7 +13,7 @@ export default function WithAutheliaRunning(suitePath: string, waitTimeout: numb }); after(async function() { - this.timeout(10000); + this.timeout(30000); console.log('Stopping environment...'); await teardown(); diff --git a/test/suites/dockerhub/config.yml b/test/suites/dockerhub/config.yml new file mode 100644 index 00000000..f88b207f --- /dev/null +++ b/test/suites/dockerhub/config.yml @@ -0,0 +1,262 @@ +############################################################### +# Authelia configuration # +############################################################### + +# The port to listen on +port: 9091 + +# Log level +# +# Level of verbosity for logs +logs_level: debug + +# Default redirection URL +# +# If user tries to authenticate without any referer, Authelia +# does not know where to redirect the user to at the end of the +# authentication process. +# This parameter allows you to specify the default redirection +# URL Authelia will use in such a case. +# +# Note: this parameter is optional. If not provided, user won't +# be redirected upon successful authentication. +default_redirection_url: https://home.example.com:8080/ + +# TOTP Issuer Name +# +# This will be the issuer name displayed in Google Authenticator +# See: https://github.com/google/google-authenticator/wiki/Key-Uri-Format for more info on issuer names +totp: + issuer: authelia.com + +# The authentication backend to use for verifying user passwords +# and retrieve information such as email address and groups +# users belong to. +# +# There are two supported backends: `ldap` and `file`. +authentication_backend: + # LDAP backend configuration. + # + # This backend allows Authelia to be scaled to more + # than one instance and therefore is recommended for + # production. + ldap: + # The url of the ldap server + url: ldap://openldap + + # The base dn for every entries + base_dn: dc=example,dc=com + + # An additional dn to define the scope to all users + additional_users_dn: ou=users + + # The users filter used to find the user DN + # {0} is a matcher replaced by username. + # 'cn={0}' by default. + users_filter: cn={0} + + # An additional dn to define the scope of groups + additional_groups_dn: ou=groups + + # The groups filter used for retrieving groups of a given user. + # {0} is a matcher replaced by username. + # {dn} is a matcher replaced by user DN. + # 'member={dn}' by default. + groups_filter: (&(member={dn})(objectclass=groupOfNames)) + + # The attribute holding the name of the group + group_name_attribute: cn + + # The attribute holding the mail address of the user + mail_attribute: mail + + # The username and password of the admin user. + user: cn=admin,dc=example,dc=com + password: password + + # File backend configuration. + # + # With this backend, the users database is stored in a file + # which is updated when users reset their passwords. + # Therefore, this backend is meant to be used in a dev environment + # and not in production since it prevents Authelia to be scaled to + # more than one instance. + # + ## file: + ## path: ./users_database.yml + + +# Access Control +# +# Access control is a list of rules defining the authorizations applied for one +# resource to users or group of users. +# +# If 'access_control' is not defined, ACL rules are disabled and the `bypass` +# rule is applied, i.e., access is allowed to anyone. Otherwise restrictions follow +# the rules defined. +# +# Note: One can use the wildcard * to match any subdomain. +# It must stand at the beginning of the pattern. (example: *.mydomain.com) +# +# Note: You must put patterns containing wildcards between simple quotes for the YAML +# to be syntaxically correct. +# +# Definition: A `rule` is an object with the following keys: `domain`, `subject`, +# `policy` and `resources`. +# +# - `domain` defines which domain or set of domains the rule applies to. +# +# - `subject` defines the subject to apply authorizations to. This parameter is +# optional and matching any user if not provided. If provided, the parameter +# represents either a user or a group. It should be of the form 'user:' +# or 'group:'. +# +# - `policy` is the policy to apply to resources. It must be either `bypass`, +# `one_factor`, `two_factor` or `deny`. +# +# - `resources` is a list of regular expressions that matches a set of resources to +# apply the policy to. This parameter is optional and matches any resource if not +# provided. +# +# Note: the order of the rules is important. The first policy matching +# (domain, resource, subject) applies. +access_control: + # Default policy can either be `bypass`, `one_factor`, `two_factor` or `deny`. + # It is the policy applied to any resource if there is no policy to be applied + # to the user. + default_policy: deny + + rules: + # Rules applied to everyone + - domain: public.example.com + policy: two_factor + - domain: single_factor.example.com + policy: one_factor + + # Rules applied to 'admin' group + - domain: 'mx2.mail.example.com' + subject: 'group:admin' + policy: deny + - domain: '*.example.com' + subject: 'group:admin' + policy: two_factor + + # Rules applied to 'dev' group + - domain: dev.example.com + resources: + - '^/groups/dev/.*$' + subject: 'group:dev' + policy: two_factor + + # Rules applied to user 'john' + - domain: dev.example.com + resources: + - '^/users/john/.*$' + subject: 'user:john' + policy: two_factor + + + # Rules applied to user 'harry' + - domain: dev.example.com + resources: + - '^/users/harry/.*$' + subject: 'user:harry' + policy: two_factor + + # Rules applied to user 'bob' + - domain: '*.mail.example.com' + subject: 'user:bob' + policy: two_factor + - domain: 'dev.example.com' + resources: + - '^/users/bob/.*$' + subject: 'user:bob' + policy: two_factor + + +# Configuration of session cookies +# +# The session cookies identify the user once logged in. +session: + # The name of the session cookie. (default: authelia_session). + name: authelia_session + + # The secret to encrypt the session cookie. + secret: unsecure_session_secret + + # The time in ms before the cookie expires and session is reset. + expiration: 3600000 # 1 hour + + # The inactivity time in ms before the session is reset. + inactivity: 300000 # 5 minutes + + # 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. + domain: example.com + + # The redis connection details + redis: + host: redis + port: 6379 + password: authelia + +# Configuration of the authentication regulation mechanism. +# +# This mechanism prevents attackers from brute forcing the first factor. +# It bans the user if too many attempts are done in a short period of +# time. +regulation: + # The number of failed login attempts before user is banned. + # Set it to 0 to disable regulation. + max_retries: 3 + + # The time range during which the user can attempt login before being banned. + # The user is banned if the authenticaction failed `max_retries` times in a `find_time` seconds window. + find_time: 15 + + # The length of time before a banned user can login again. + ban_time: 5 + +# Configuration of the storage backend used to store data and secrets. +# +# You must use only an available configuration: local, mongo +storage: + # The directory where the DB files will be saved + ## local: + ## path: /var/lib/authelia/store + + # Settings to connect to mongo server + mongo: + url: mongodb://mongo + database: authelia + auth: + username: authelia + password: authelia + +# Configuration of the notification system. +# +# Notifications are sent to users when they require a password reset, a u2f +# registration or a TOTP registration. +# Use only an available configuration: filesystem, gmail +notifier: + # For testing purpose, notifications can be sent in a file + ## filesystem: + ## filename: /tmp/authelia/notification.txt + + # Use your email account to send the notifications. You can use an app password. + # List of valid services can be found here: https://nodemailer.com/smtp/well-known/ + ## email: + ## username: user@example.com + ## password: yourpassword + ## sender: admin@example.com + ## service: gmail + + # Use a SMTP server for sending notifications + smtp: + username: test + password: password + secure: false + host: smtp + port: 1025 + sender: admin@example.com diff --git a/test/suites/dockerhub/environment.ts b/test/suites/dockerhub/environment.ts new file mode 100644 index 00000000..b8213ef3 --- /dev/null +++ b/test/suites/dockerhub/environment.ts @@ -0,0 +1,28 @@ +import DockerEnvironment from "../../helpers/context/DockerEnvironment"; +import { exec } from "../../helpers/utils/exec"; + +const composeFiles = [ + 'docker-compose.yml', + 'example/compose/authelia/docker-compose.dockerhub.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.admin.yml', // This is just used for administration, not for testing. + 'example/compose/ldap/docker-compose.yml' +] + +const dockerEnv = new DockerEnvironment(composeFiles); + +async function setup() { + await exec('./example/compose/nginx/portal/render.js --production http://authelia:9091'); + await dockerEnv.start(); +} + +async function teardown() { + await dockerEnv.stop(); +} + +export { setup, teardown, composeFiles }; \ No newline at end of file diff --git a/test/suites/dockerhub/scenarii/SimpleAuthentication.ts b/test/suites/dockerhub/scenarii/SimpleAuthentication.ts new file mode 100644 index 00000000..7d42298a --- /dev/null +++ b/test/suites/dockerhub/scenarii/SimpleAuthentication.ts @@ -0,0 +1,20 @@ +import { StartDriver, StopDriver } from "../../../helpers/context/WithDriver"; +import RegisterAndLoginTwoFactor from "../../../helpers/behaviors/RegisterAndLoginTwoFactor"; +import VerifyUrlIs from "../../../helpers/assertions/VerifyUrlIs"; + +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'); + }); + }); +} \ No newline at end of file diff --git a/test/suites/dockerhub/test.ts b/test/suites/dockerhub/test.ts new file mode 100644 index 00000000..efc3931a --- /dev/null +++ b/test/suites/dockerhub/test.ts @@ -0,0 +1,25 @@ +import AutheliaSuite from '../../helpers/context/AutheliaSuite'; +import DockerCompose from '../../helpers/context/DockerCompose'; +import { composeFiles } from './environment'; +import Assert from 'assert'; +import SimpleAuthentication from './scenarii/SimpleAuthentication'; + +AutheliaSuite('Dockerhub', __dirname, function() { + this.timeout(15000); + const dockerCompose = new DockerCompose(composeFiles); + + describe('Check the container', function() { + it('should be running', async function() { + const stdout = await dockerCompose.ps(); + const lines = stdout.split("\n"); + const autheliaLine = lines.filter(l => l.indexOf('authelia_1') > -1); + if (autheliaLine.length != 1) { + throw new Error('Authelia container not found...'); + } + // check if the container is up. + Assert(autheliaLine[0].indexOf(' Up ') > -1); + }); + }); + + describe.only('Simple authentication', SimpleAuthentication); +}); \ No newline at end of file diff --git a/test/suites/simple/scenarii/SimpleAuthentication.ts b/test/suites/simple/scenarii/SimpleAuthentication.ts index d88ea9d0..78331b8d 100644 --- a/test/suites/simple/scenarii/SimpleAuthentication.ts +++ b/test/suites/simple/scenarii/SimpleAuthentication.ts @@ -2,7 +2,6 @@ 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() {