Fix integration test and package Travis scripts
parent
0414d28e2b
commit
e56c2492ed
|
@ -13,9 +13,7 @@ src/.baseDir.ts
|
|||
|
||||
*.swp
|
||||
|
||||
*.sh
|
||||
|
||||
config.yml
|
||||
/config.yml
|
||||
|
||||
npm-debug.log
|
||||
|
||||
|
|
|
@ -19,14 +19,7 @@ addons:
|
|||
|
||||
before_install: npm install -g npm@'>=2.13.5'
|
||||
script:
|
||||
- grunt build-dist
|
||||
- grunt docker-build
|
||||
- docker-compose build
|
||||
- docker-compose up -d
|
||||
- sleep 5
|
||||
- ./scripts/check-services.sh
|
||||
- npm run int-test
|
||||
- ./scripts/npm-deployment-test.sh
|
||||
- ./scripts/travis.sh
|
||||
|
||||
after_success:
|
||||
- ./scripts/docker-publish.sh
|
||||
|
|
|
@ -10,7 +10,7 @@ COPY dist/src/server /usr/src
|
|||
ENV PORT=80
|
||||
EXPOSE 80
|
||||
|
||||
VOLUME /etc/auth-server
|
||||
VOLUME /var/lib/auth-server
|
||||
VOLUME /etc/authelia
|
||||
VOLUME /var/lib/authelia
|
||||
|
||||
CMD ["node", "index.js", "/etc/auth-server/config.yml"]
|
||||
CMD ["node", "index.js", "/etc/authelia/config.yml"]
|
||||
|
|
|
@ -5,12 +5,12 @@ module.exports = function (grunt) {
|
|||
run: {
|
||||
options: {},
|
||||
"build": {
|
||||
cmd: "npm",
|
||||
args: ['run', 'build']
|
||||
cmd: "./node_modules/.bin/tsc",
|
||||
args: ['-p', 'tsconfig.json']
|
||||
},
|
||||
"tslint": {
|
||||
cmd: "npm",
|
||||
args: ['run', 'tslint']
|
||||
cmd: "./node_modules/.bin/tslint",
|
||||
args: ['-c', 'tslint.json', '-p', 'tsconfig.json']
|
||||
},
|
||||
"test": {
|
||||
cmd: "npm",
|
||||
|
|
|
@ -12,7 +12,7 @@ logs_level: info
|
|||
# Example: for user john, the DN will be cn=john,ou=users,dc=example,dc=com
|
||||
ldap:
|
||||
# The url of the ldap server
|
||||
url: ldap://ldap
|
||||
url: ldap://openldap-restriction
|
||||
|
||||
# The base dn for every entries
|
||||
base_dn: dc=example,dc=com
|
||||
|
@ -85,7 +85,7 @@ store_directory: /var/lib/authelia/store
|
|||
notifier:
|
||||
# For testing purpose, notifications can be sent in a file
|
||||
filesystem:
|
||||
filename: /var/lib/auth-server/notifications/notification.txt
|
||||
filename: /var/lib/authelia/notifications/notification.txt
|
||||
|
||||
# Use your gmail account to send the notifications. You can use an app password.
|
||||
# gmail:
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
version: '2'
|
||||
|
||||
networks:
|
||||
example-network:
|
||||
driver: bridge
|
|
@ -1,10 +1,10 @@
|
|||
|
||||
version: '2'
|
||||
services:
|
||||
auth:
|
||||
authelia:
|
||||
volumes:
|
||||
- ./test:/usr/src/test
|
||||
- ./dist/src/server:/usr/src
|
||||
- ./node_modules:/usr/src/node_modules
|
||||
- ./config.yml:/etc/auth-server/config.yml:ro
|
||||
|
||||
- ./config.yml:/etc/authelia/config.yml:ro
|
||||
networks:
|
||||
- example-network
|
||||
|
|
|
@ -1,43 +1,11 @@
|
|||
version: '2'
|
||||
services:
|
||||
auth:
|
||||
authelia:
|
||||
build: .
|
||||
restart: always
|
||||
volumes:
|
||||
- ./config.template.yml:/etc/auth-server/config.yml:ro
|
||||
- ./notifications:/var/lib/auth-server/notifications
|
||||
- ./config.template.yml:/etc/authelia/config.yml:ro
|
||||
- ./notifications:/var/lib/authelia/notifications
|
||||
networks:
|
||||
- example-network
|
||||
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
volumes:
|
||||
- ./example/nginx_conf/nginx.conf:/etc/nginx/nginx.conf
|
||||
- ./example/nginx_conf/index.html:/usr/share/nginx/html/index.html
|
||||
- ./example/nginx_conf/secret.html:/usr/share/nginx/html/secret.html
|
||||
- ./example/nginx_conf/ssl:/etc/ssl
|
||||
depends_on:
|
||||
- auth
|
||||
ports:
|
||||
- "8080:443"
|
||||
|
||||
openldap:
|
||||
image: clems4ever/openldap
|
||||
ports:
|
||||
- "389:389"
|
||||
environment:
|
||||
- SLAPD_ORGANISATION=MyCompany
|
||||
- SLAPD_DOMAIN=example.com
|
||||
- SLAPD_PASSWORD=password
|
||||
- SLAPD_CONFIG_PASSWORD=password
|
||||
- SLAPD_ADDITIONAL_MODULES=memberof
|
||||
- SLAPD_ADDITIONAL_SCHEMAS=openldap
|
||||
- SLAPD_FORCE_RECONFIGURE=true
|
||||
volumes:
|
||||
- ./example/ldap:/etc/ldap.dist/prepopulate
|
||||
|
||||
openldap-admin:
|
||||
image: osixia/phpldapadmin:0.6.11
|
||||
ports:
|
||||
- 9090:80
|
||||
environment:
|
||||
- PHPLDAPADMIN_LDAP_HOSTS=openldap
|
||||
- PHPLDAPADMIN_HTTPS=false
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
FROM clems4ever/openldap
|
||||
|
||||
ENV SLAPD_ORGANISATION=MyCompany
|
||||
ENV SLAPD_DOMAIN=example.com
|
||||
ENV SLAPD_PASSWORD=password
|
||||
ENV SLAPD_CONFIG_PASSWORD=password
|
||||
ENV SLAPD_ADDITIONAL_MODULES=memberof
|
||||
ENV SLAPD_ADDITIONAL_SCHEMAS=openldap
|
||||
ENV SLAPD_FORCE_RECONFIGURE=true
|
|
@ -25,7 +25,7 @@ dn: cn=john,ou=users,dc=example,dc=com
|
|||
cn: john
|
||||
objectclass: inetOrgPerson
|
||||
objectclass: top
|
||||
mail: clement.michaud34@gmail.com
|
||||
mail: john.doe@example.com
|
||||
sn: John Doe
|
||||
userpassword: {SHA}W6ph5Mm5Pz8GgiULbPgzG37mj9g=
|
||||
|
||||
|
@ -45,18 +45,3 @@ mail: bob.dylan@example.com
|
|||
sn: Bob Dylan
|
||||
userpassword: {SHA}W6ph5Mm5Pz8GgiULbPgzG37mj9g=
|
||||
|
||||
# dn: uid=jack,ou=users,dc=example,dc=com
|
||||
# cn: jack
|
||||
# gidnumber: 501
|
||||
# givenname: Jack
|
||||
# homedirectory: /home/jack
|
||||
# loginshell: /bin/sh
|
||||
# objectclass: inetOrgPerson
|
||||
# objectclass: posixAccount
|
||||
# objectclass: top
|
||||
# mail: jack.daniels@example.com
|
||||
# sn: Jack Daniels
|
||||
# uid: jack
|
||||
# uidnumber: 1001
|
||||
# userpassword: {SHA}W6ph5Mm5Pz8GgiULbPgzG37mj9g=
|
||||
#
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
version: '2'
|
||||
services:
|
||||
openldap-admin:
|
||||
image: osixia/phpldapadmin:0.6.11
|
||||
ports:
|
||||
- 9090:80
|
||||
environment:
|
||||
- PHPLDAPADMIN_LDAP_HOSTS=openldap
|
||||
- PHPLDAPADMIN_HTTPS=false
|
||||
networks:
|
||||
- example-network
|
|
@ -0,0 +1,10 @@
|
|||
version: '2'
|
||||
services:
|
||||
openldap:
|
||||
build: ./example/ldap
|
||||
volumes:
|
||||
- ./example/ldap/base.ldif:/etc/ldap.dist/prepopulate/base.ldif
|
||||
- ./example/ldap/access.rules:/etc/ldap.dist/prepopulate/access.rules
|
||||
networks:
|
||||
- example-network
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
version: '2'
|
||||
services:
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
volumes:
|
||||
- ./example/nginx/index.html:/usr/share/nginx/html/index.html
|
||||
- ./example/nginx/secret.html:/usr/share/nginx/html/secret.html
|
||||
- ./example/nginx/ssl:/etc/ssl
|
||||
- ./example/nginx/nginx.conf:/etc/nginx/nginx.conf
|
||||
ports:
|
||||
- "8080:443"
|
||||
depends_on:
|
||||
- authelia
|
||||
networks:
|
||||
example-network:
|
||||
aliases:
|
||||
- home.test.local
|
||||
- secret.test.local
|
||||
- secret1.test.local
|
||||
- secret2.test.local
|
||||
- mx1.mail.test.local
|
||||
- mx2.mail.test.local
|
||||
- auth.test.local
|
||||
|
|
@ -36,7 +36,7 @@ http {
|
|||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
|
||||
proxy_pass http://auth/;
|
||||
proxy_pass http://authelia/;
|
||||
|
||||
proxy_intercept_errors on;
|
||||
|
||||
|
@ -68,7 +68,7 @@ http {
|
|||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header Host $http_host;
|
||||
|
||||
proxy_pass http://auth/verify;
|
||||
proxy_pass http://authelia/verify;
|
||||
}
|
||||
|
||||
location = /secret.html {
|
|
@ -4,6 +4,6 @@
|
|||
</head>
|
||||
<body>
|
||||
This is a very important secret!<br/>
|
||||
Go back to <a href="https://home.test.local:8080/">home page</a>.
|
||||
Go back to <a href="https://home.test.local/">home page</a>.
|
||||
</body>
|
||||
</html>
|
|
@ -8,10 +8,7 @@
|
|||
},
|
||||
"scripts": {
|
||||
"test": "./node_modules/.bin/mocha --compilers ts:ts-node/register --recursive test/client test/server",
|
||||
"int-test": "./node_modules/.bin/mocha --compilers ts:ts-node/register --recursive test/integration",
|
||||
"cover": "NODE_ENV=test nyc npm t",
|
||||
"build": "tsc",
|
||||
"tslint": "tslint -c tslint.json -p tsconfig.json",
|
||||
"serve": "node dist/server/index.js"
|
||||
},
|
||||
"repository": {
|
||||
|
@ -63,7 +60,7 @@
|
|||
"@types/proxyquire": "^1.3.27",
|
||||
"@types/query-string": "^4.3.1",
|
||||
"@types/randomstring": "^1.1.5",
|
||||
"@types/request": "0.0.43",
|
||||
"@types/request": "0.0.45",
|
||||
"@types/sinon": "^2.2.1",
|
||||
"@types/speakeasy": "^2.0.1",
|
||||
"@types/tmp": "0.0.33",
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
docker-compose -f docker-compose.base.yml -f docker-compose.yml -f example/nginx/docker-compose.yml -f example/ldap/docker-compose.yml $*
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
docker-compose -f docker-compose.base.yml -f example/ldap/docker-compose.yml -f test/integration/docker-compose.yml $*
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
|
||||
./scripts/dc-example.sh build
|
||||
./scripts/dc-example.sh up -d
|
|
@ -16,6 +16,7 @@ function deploy_on_dockerhub {
|
|||
docker login -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD";
|
||||
|
||||
echo "Docker image $IMAGE_WITH_TAG will be deployed on Dockerhub."
|
||||
docker build -t $IMAGE_NAME .
|
||||
docker tag $IMAGE_NAME $IMAGE_WITH_TAG;
|
||||
docker push $IMAGE_WITH_TAG;
|
||||
echo "Docker image deployed successfully."
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
NPM_UNPACK_DIR=/tmp/npm-unpack
|
||||
|
||||
echo "--- Packing npm package into a tarball"
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
echo "Build services images..."
|
||||
./scripts/dc-test.sh build
|
||||
|
||||
echo "Start services..."
|
||||
./scripts/dc-test.sh up -d authelia nginx openldap
|
||||
sleep 3
|
||||
docker ps -a
|
||||
|
||||
echo "Display services logs..."
|
||||
./scripts/dc-test.sh logs authelia
|
||||
./scripts/dc-test.sh logs nginx
|
||||
./scripts/dc-test.sh logs openldap
|
||||
|
||||
echo "Run integration tests..."
|
||||
./scripts/dc-test.sh run --rm --name int-test int-test
|
||||
|
||||
echo "Shutdown services..."
|
||||
./scripts/dc-test.sh down
|
|
@ -0,0 +1,15 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
# Build production environment and set it up
|
||||
./scripts/dc-example.sh build
|
||||
./scripts/dc-example.sh up -d
|
||||
|
||||
# Wait for services to be running
|
||||
sleep 5
|
||||
|
||||
# Check if services are correctly running
|
||||
./scripts/check-services.sh
|
||||
|
||||
./scripts/dc-example.sh down
|
|
@ -0,0 +1,21 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
docker --version
|
||||
docker-compose --version
|
||||
|
||||
# Run unit tests
|
||||
grunt test
|
||||
|
||||
# Build the app from Typescript and package
|
||||
grunt build-dist
|
||||
|
||||
# Run integration tests
|
||||
./scripts/run-int-test.sh
|
||||
|
||||
# Test staging environment
|
||||
./scripts/run-staging.sh
|
||||
|
||||
# Test npm deployment before actual deployment
|
||||
./scripts/npm-deployment-test.sh
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
./scripts/dc-example.sh down
|
|
@ -2,6 +2,8 @@
|
|||
import * as ObjectPath from "object-path";
|
||||
import { AppConfiguration, UserConfiguration, NotifierConfiguration, ACLConfiguration, LdapConfiguration } from "./../../types/Configuration";
|
||||
|
||||
const LDAP_URL_ENV_VARIABLE = "LDAP_URL";
|
||||
|
||||
|
||||
function get_optional<T>(config: object, path: string, default_value: T): T {
|
||||
let entry = default_value;
|
||||
|
@ -17,26 +19,36 @@ function ensure_key_existence(config: object, path: string): void {
|
|||
}
|
||||
}
|
||||
|
||||
function adaptFromUserConfiguration(userConfiguration: UserConfiguration): AppConfiguration {
|
||||
ensure_key_existence(userConfiguration, "ldap");
|
||||
ensure_key_existence(userConfiguration, "session.secret");
|
||||
|
||||
const port = ObjectPath.get(userConfiguration, "port", 8080);
|
||||
|
||||
return {
|
||||
port: port,
|
||||
ldap: ObjectPath.get<object, LdapConfiguration>(userConfiguration, "ldap"),
|
||||
session: {
|
||||
domain: ObjectPath.get<object, string>(userConfiguration, "session.domain"),
|
||||
secret: ObjectPath.get<object, string>(userConfiguration, "session.secret"),
|
||||
expiration: get_optional<number>(userConfiguration, "session.expiration", 3600000), // in ms
|
||||
},
|
||||
store_directory: get_optional<string>(userConfiguration, "store_directory", undefined),
|
||||
logs_level: get_optional<string>(userConfiguration, "logs_level", "info"),
|
||||
notifier: ObjectPath.get<object, NotifierConfiguration>(userConfiguration, "notifier"),
|
||||
access_control: ObjectPath.get<object, ACLConfiguration>(userConfiguration, "access_control")
|
||||
};
|
||||
}
|
||||
|
||||
export default class ConfigurationAdapter {
|
||||
static adapt(yaml_config: UserConfiguration): AppConfiguration {
|
||||
ensure_key_existence(yaml_config, "ldap");
|
||||
ensure_key_existence(yaml_config, "session.secret");
|
||||
static adapt(userConfiguration: UserConfiguration): AppConfiguration {
|
||||
const appConfiguration = adaptFromUserConfiguration(userConfiguration);
|
||||
|
||||
const port = ObjectPath.get(yaml_config, "port", 8080);
|
||||
const ldapUrl = process.env[LDAP_URL_ENV_VARIABLE];
|
||||
if (ldapUrl)
|
||||
appConfiguration.ldap.url = ldapUrl;
|
||||
|
||||
return {
|
||||
port: port,
|
||||
ldap: ObjectPath.get<object, LdapConfiguration>(yaml_config, "ldap"),
|
||||
session: {
|
||||
domain: ObjectPath.get<object, string>(yaml_config, "session.domain"),
|
||||
secret: ObjectPath.get<object, string>(yaml_config, "session.secret"),
|
||||
expiration: get_optional<number>(yaml_config, "session.expiration", 3600000), // in ms
|
||||
},
|
||||
store_directory: get_optional<string>(yaml_config, "store_directory", undefined),
|
||||
logs_level: get_optional<string>(yaml_config, "logs_level", "info"),
|
||||
notifier: ObjectPath.get<object, NotifierConfiguration>(yaml_config, "notifier"),
|
||||
access_control: ObjectPath.get<object, ACLConfiguration>(yaml_config, "access_control")
|
||||
};
|
||||
return appConfiguration;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -68,9 +68,10 @@ export class LdapClient {
|
|||
const that = this;
|
||||
const ldapClient = this.createClient();
|
||||
|
||||
this.logger.debug("LDAP: Check password for user '%s'", userDN);
|
||||
this.logger.debug("LDAP: Check password by binding user '%s'", userDN);
|
||||
return ldapClient.bindAsync(userDN, password)
|
||||
.then(function () {
|
||||
that.logger.debug("LDAP: Unbind user '%s'", userDN);
|
||||
return ldapClient.unbindAsync();
|
||||
})
|
||||
.error(function (err: Error) {
|
||||
|
|
|
@ -50,6 +50,7 @@ export default class Server {
|
|||
// by default the level of logs is info
|
||||
deps.winston.level = config.logs_level;
|
||||
console.log("Log level = ", deps.winston.level);
|
||||
deps.winston.debug("Authelia configuration is %s", JSON.stringify(config, undefined, 2));
|
||||
|
||||
ServerVariables.fill(app, config, deps);
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ export class GMailNotifier extends INotifier {
|
|||
};
|
||||
|
||||
const mailOptions = {
|
||||
from: "auth-server@open-intent.io",
|
||||
from: "authelia@authelia.com",
|
||||
to: identity.email,
|
||||
subject: subject,
|
||||
html: ejs.render(email_template, d)
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
FROM node:7-alpine
|
||||
|
||||
WORKDIR /usr/src
|
||||
|
||||
CMD ["./node_modules/.bin/mocha", "--compilers", "ts:ts-node/register", "--recursive", "test/integration"]
|
|
@ -0,0 +1,164 @@
|
|||
|
||||
import Request = require("request");
|
||||
import Assert = require("assert");
|
||||
import Speakeasy = require("speakeasy");
|
||||
import BluebirdPromise = require("bluebird");
|
||||
import Util = require("util");
|
||||
import Sinon = require("sinon");
|
||||
import Endpoints = require("../../src/server/endpoints");
|
||||
|
||||
const EXEC_PATH = "./dist/src/server/index.js";
|
||||
const CONFIG_PATH = "./test/integration/config.yml";
|
||||
const j = Request.jar();
|
||||
const request: typeof Request = <typeof Request>BluebirdPromise.promisifyAll(Request.defaults({ jar: j }));
|
||||
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
||||
|
||||
const DOMAIN = "test.local";
|
||||
const PORT = 8080;
|
||||
|
||||
const HOME_URL = Util.format("https://%s.%s:%d", "home", DOMAIN, PORT);
|
||||
const SECRET_URL = Util.format("https://%s.%s:%d", "secret", DOMAIN, PORT);
|
||||
const SECRET1_URL = Util.format("https://%s.%s:%d", "secret1", DOMAIN, PORT);
|
||||
const SECRET2_URL = Util.format("https://%s.%s:%d", "secret2", DOMAIN, PORT);
|
||||
const MX1_URL = Util.format("https://%s.%s:%d", "mx1.mail", DOMAIN, PORT);
|
||||
const MX2_URL = Util.format("https://%s.%s:%d", "mx2.mail", DOMAIN, PORT);
|
||||
const BASE_AUTH_URL = Util.format("https://%s.%s:%d", "auth", DOMAIN, PORT);
|
||||
|
||||
function waitFor(ms: number): BluebirdPromise<{}> {
|
||||
return new BluebirdPromise(function (resolve, reject) {
|
||||
setTimeout(function () {
|
||||
resolve();
|
||||
}, ms);
|
||||
});
|
||||
}
|
||||
|
||||
describe("test the server", function () {
|
||||
let home_page: string;
|
||||
let login_page: string;
|
||||
|
||||
before(function () {
|
||||
const home_page_promise = getHomePage()
|
||||
.then(function (data) {
|
||||
home_page = data.body;
|
||||
});
|
||||
const login_page_promise = getLoginPage()
|
||||
.then(function (data) {
|
||||
login_page = data.body;
|
||||
});
|
||||
|
||||
return BluebirdPromise.all([home_page_promise,
|
||||
login_page_promise]);
|
||||
});
|
||||
|
||||
after(function () {
|
||||
});
|
||||
|
||||
function str_contains(str: string, pattern: string) {
|
||||
return str.indexOf(pattern) != -1;
|
||||
}
|
||||
|
||||
function home_page_contains(pattern: string) {
|
||||
return str_contains(home_page, pattern);
|
||||
}
|
||||
|
||||
it("should serve a correct home page", function () {
|
||||
Assert(home_page_contains(BASE_AUTH_URL + Endpoints.LOGOUT_GET + "?redirect=" + HOME_URL + "/"));
|
||||
Assert(home_page_contains(HOME_URL + "/secret.html"));
|
||||
Assert(home_page_contains(SECRET_URL + "/secret.html"));
|
||||
Assert(home_page_contains(SECRET1_URL + "/secret.html"));
|
||||
Assert(home_page_contains(SECRET2_URL + "/secret.html"));
|
||||
Assert(home_page_contains(MX1_URL + "/secret.html"));
|
||||
Assert(home_page_contains(MX2_URL + "/secret.html"));
|
||||
});
|
||||
|
||||
it("should serve the login page", function () {
|
||||
return getPromised(BASE_AUTH_URL + Endpoints.FIRST_FACTOR_GET)
|
||||
.then(function (data: Request.RequestResponse) {
|
||||
Assert.equal(data.statusCode, 200);
|
||||
});
|
||||
});
|
||||
|
||||
it("should serve the homepage", function () {
|
||||
return getPromised(HOME_URL + "/")
|
||||
.then(function (data: Request.RequestResponse) {
|
||||
Assert.equal(data.statusCode, 200);
|
||||
});
|
||||
});
|
||||
|
||||
it("should redirect when logout", function () {
|
||||
return getPromised(BASE_AUTH_URL + Endpoints.LOGOUT_GET + "?redirect=" + HOME_URL)
|
||||
.then(function (data: Request.RequestResponse) {
|
||||
Assert.equal(data.statusCode, 200);
|
||||
Assert.equal(data.body, home_page);
|
||||
});
|
||||
});
|
||||
|
||||
it("should be redirected to the login page when accessing secret while not authenticated", function () {
|
||||
return getPromised(HOME_URL + "/secret.html")
|
||||
.then(function (data: Request.RequestResponse) {
|
||||
Assert.equal(data.statusCode, 200);
|
||||
Assert.equal(data.body, login_page);
|
||||
});
|
||||
});
|
||||
|
||||
it.skip("should fail the first factor", function () {
|
||||
return postPromised(BASE_AUTH_URL + Endpoints.FIRST_FACTOR_POST, {
|
||||
form: {
|
||||
username: "admin",
|
||||
password: "password",
|
||||
}
|
||||
})
|
||||
.then(function (data: Request.RequestResponse) {
|
||||
Assert.equal(data.body, "Bad credentials");
|
||||
});
|
||||
});
|
||||
|
||||
function login_as(username: string, password: string) {
|
||||
return postPromised(BASE_AUTH_URL + Endpoints.FIRST_FACTOR_POST, {
|
||||
form: {
|
||||
username: "john",
|
||||
password: "password",
|
||||
}
|
||||
})
|
||||
.then(function (data: Request.RequestResponse) {
|
||||
Assert.equal(data.statusCode, 302);
|
||||
return BluebirdPromise.resolve();
|
||||
});
|
||||
}
|
||||
|
||||
it("should succeed the first factor", function () {
|
||||
return login_as("john", "password");
|
||||
});
|
||||
|
||||
describe("test ldap connection", function () {
|
||||
it("should not fail after inactivity", function () {
|
||||
const clock = Sinon.useFakeTimers();
|
||||
return login_as("john", "password")
|
||||
.then(function () {
|
||||
clock.tick(3600000 * 24); // 24 hour
|
||||
return login_as("john", "password");
|
||||
})
|
||||
.then(function () {
|
||||
clock.restore();
|
||||
return BluebirdPromise.resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function getPromised(url: string) {
|
||||
return request.getAsync(url);
|
||||
}
|
||||
|
||||
function postPromised(url: string, body: Object) {
|
||||
return request.postAsync(url, body);
|
||||
}
|
||||
|
||||
function getHomePage(): BluebirdPromise<Request.RequestResponse> {
|
||||
return getPromised(HOME_URL + "/");
|
||||
}
|
||||
|
||||
function getLoginPage(): BluebirdPromise<Request.RequestResponse> {
|
||||
return getPromised(BASE_AUTH_URL + Endpoints.FIRST_FACTOR_GET);
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
|
||||
# The port to listen on
|
||||
port: 80
|
||||
|
||||
# Log level
|
||||
#
|
||||
# Level of verbosity for logs
|
||||
logs_level: debug
|
||||
|
||||
# LDAP configuration
|
||||
#
|
||||
# Example: for user john, the DN will be cn=john,ou=users,dc=example,dc=com
|
||||
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_user_dn: ou=users
|
||||
|
||||
# The user name attribute of users. Might uid for FreeIPA. 'cn' by default.
|
||||
user_name_attribute: cn
|
||||
|
||||
# An additional dn to define the scope of groups
|
||||
additional_group_dn: ou=groups
|
||||
|
||||
# The group name attribute of group. 'cn' by default.
|
||||
group_name_attribute: cn
|
||||
|
||||
# The username and password of the admin user.
|
||||
user: cn=admin,dc=example,dc=com
|
||||
password: password
|
||||
|
||||
|
||||
# Access Control
|
||||
#
|
||||
# Access control is a set of rules you can use to restrict the user access.
|
||||
# Default (anyone), per-user or per-group rules can be defined.
|
||||
#
|
||||
# If 'access_control' is not defined, ACL rules are disabled and default policy
|
||||
# is applied, i.e., access is allowed to anyone. Otherwise restrictions follow
|
||||
# the rules defined below.
|
||||
# If no rule is provided, all domains are denied.
|
||||
#
|
||||
# '*' means 'any' subdomains and matches any string. It must stand at the
|
||||
# beginning of the pattern.
|
||||
access_control:
|
||||
default:
|
||||
- home.test.local
|
||||
groups:
|
||||
admin:
|
||||
- '*.test.local'
|
||||
dev:
|
||||
- secret.test.local
|
||||
- secret2.test.local
|
||||
users:
|
||||
harry:
|
||||
- secret1.test.local
|
||||
bob:
|
||||
- '*.mail.test.local'
|
||||
|
||||
|
||||
# Configuration of session cookies
|
||||
#
|
||||
# _secret_ the secret to encrypt session cookies
|
||||
# _expiration_ the time before cookies expire
|
||||
# _domain_ 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.
|
||||
session:
|
||||
secret: unsecure_secret
|
||||
expiration: 3600000
|
||||
domain: test.local
|
||||
|
||||
|
||||
# The directory where the DB files will be saved
|
||||
store_directory: /var/lib/authelia/store
|
||||
|
||||
|
||||
# Notifications are sent to users when they require a password reset, a u2f
|
||||
# registration or a TOTP registration.
|
||||
# Use only one available configuration: filesystem, gmail
|
||||
notifier:
|
||||
# For testing purpose, notifications can be sent in a file
|
||||
filesystem:
|
||||
filename: /var/lib/authelia/notifications/notification.txt
|
||||
|
||||
# Use your gmail account to send the notifications. You can use an app password.
|
||||
# gmail:
|
||||
# username: user
|
||||
# password: password
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
version: '2'
|
||||
services:
|
||||
authelia:
|
||||
image: node:7-alpine
|
||||
command: node /usr/src/dist/src/server/index.js /etc/authelia/config.yml
|
||||
volumes:
|
||||
- ./:/usr/src
|
||||
- ./test/integration/config.yml:/etc/authelia/config.yml:ro
|
||||
networks:
|
||||
- example-network
|
||||
|
||||
int-test:
|
||||
build: ./test/integration
|
||||
volumes:
|
||||
- ./:/usr/src
|
||||
networks:
|
||||
- example-network
|
||||
|
||||
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
volumes:
|
||||
- ./example/nginx/index.html:/usr/share/nginx/html/index.html
|
||||
- ./example/nginx/secret.html:/usr/share/nginx/html/secret.html
|
||||
- ./example/nginx/ssl:/etc/ssl
|
||||
- ./test/integration/nginx.conf:/etc/nginx/nginx.conf
|
||||
expose:
|
||||
- "8080"
|
||||
depends_on:
|
||||
- authelia
|
||||
networks:
|
||||
example-network:
|
||||
aliases:
|
||||
- home.test.local
|
||||
- secret.test.local
|
||||
- secret1.test.local
|
||||
- secret2.test.local
|
||||
- mx1.mail.test.local
|
||||
- mx2.mail.test.local
|
||||
- auth.test.local
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
# nginx-sso - example nginx config
|
||||
#
|
||||
# (c) 2015 by Johannes Gilger <heipei@hackvalue.de>
|
||||
#
|
||||
# This is an example config for using nginx with the nginx-sso cookie system.
|
||||
# For simplicity, this config sets up two fictional vhosts that you can use to
|
||||
# test against both components of the nginx-sso system: ssoauth & ssologin.
|
||||
# In a real deployment, these vhosts would be separate hosts.
|
||||
|
||||
#user nobody;
|
||||
worker_processes 1;
|
||||
|
||||
#error_log logs/error.log;
|
||||
#error_log logs/error.log notice;
|
||||
#error_log logs/error.log info;
|
||||
|
||||
#pid logs/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
|
||||
http {
|
||||
server {
|
||||
listen 8080 ssl;
|
||||
server_name auth.test.local localhost;
|
||||
|
||||
ssl on;
|
||||
ssl_certificate /etc/ssl/server.crt;
|
||||
ssl_certificate_key /etc/ssl/server.key;
|
||||
|
||||
|
||||
location / {
|
||||
proxy_set_header X-Original-URI $request_uri;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
|
||||
proxy_pass http://authelia/;
|
||||
|
||||
proxy_intercept_errors on;
|
||||
|
||||
error_page 401 = /error/401;
|
||||
error_page 403 = /error/403;
|
||||
error_page 404 = /error/404;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 8080 ssl;
|
||||
root /usr/share/nginx/html;
|
||||
|
||||
server_name secret1.test.local secret2.test.local secret.test.local
|
||||
home.test.local mx1.mail.test.local mx2.mail.test.local;
|
||||
|
||||
ssl on;
|
||||
ssl_certificate /etc/ssl/server.crt;
|
||||
ssl_certificate_key /etc/ssl/server.key;
|
||||
|
||||
error_page 401 = @error401;
|
||||
location @error401 {
|
||||
return 302 https://auth.test.local:8080;
|
||||
}
|
||||
|
||||
location /auth_verify {
|
||||
internal;
|
||||
proxy_set_header X-Original-URI $request_uri;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header Host $http_host;
|
||||
|
||||
proxy_pass http://authelia/verify;
|
||||
}
|
||||
|
||||
location = /secret.html {
|
||||
auth_request /auth_verify;
|
||||
|
||||
auth_request_set $user $upstream_http_x_remote_user;
|
||||
proxy_set_header X-Forwarded-User $user;
|
||||
auth_request_set $groups $upstream_http_remote_groups;
|
||||
proxy_set_header Remote-Groups $groups;
|
||||
auth_request_set $expiry $upstream_http_remote_expiry;
|
||||
proxy_set_header Remote-Expiry $expiry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,157 +0,0 @@
|
|||
|
||||
import request_ = require("request");
|
||||
import assert = require("assert");
|
||||
import speakeasy = require("speakeasy");
|
||||
import BluebirdPromise = require("bluebird");
|
||||
import util = require("util");
|
||||
import sinon = require("sinon");
|
||||
import Endpoints = require("../../src/server/endpoints");
|
||||
|
||||
const j = request_.jar();
|
||||
const request: typeof request_ = <typeof request_>BluebirdPromise.promisifyAll(request_.defaults({ jar: j }));
|
||||
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
||||
|
||||
const AUTHELIA_HOST = "nginx";
|
||||
const DOMAIN = "test.local";
|
||||
const PORT = 8080;
|
||||
|
||||
const HOME_URL = util.format("https://%s.%s:%d", "home", DOMAIN, PORT);
|
||||
const SECRET_URL = util.format("https://%s.%s:%d", "secret", DOMAIN, PORT);
|
||||
const SECRET1_URL = util.format("https://%s.%s:%d", "secret1", DOMAIN, PORT);
|
||||
const SECRET2_URL = util.format("https://%s.%s:%d", "secret2", DOMAIN, PORT);
|
||||
const MX1_URL = util.format("https://%s.%s:%d", "mx1.mail", DOMAIN, PORT);
|
||||
const MX2_URL = util.format("https://%s.%s:%d", "mx2.mail", DOMAIN, PORT);
|
||||
const BASE_AUTH_URL = util.format("https://%s.%s:%d", "auth", DOMAIN, PORT);
|
||||
|
||||
describe("test the server", function () {
|
||||
let home_page: string;
|
||||
let login_page: string;
|
||||
|
||||
before(function () {
|
||||
const home_page_promise = getHomePage()
|
||||
.then(function (data) {
|
||||
home_page = data.body;
|
||||
});
|
||||
const login_page_promise = getLoginPage()
|
||||
.then(function (data) {
|
||||
login_page = data.body;
|
||||
});
|
||||
return BluebirdPromise.all([home_page_promise,
|
||||
login_page_promise]);
|
||||
});
|
||||
|
||||
function str_contains(str: string, pattern: string) {
|
||||
return str.indexOf(pattern) != -1;
|
||||
}
|
||||
|
||||
function home_page_contains(pattern: string) {
|
||||
return str_contains(home_page, pattern);
|
||||
}
|
||||
|
||||
it("should serve a correct home page", function () {
|
||||
assert(home_page_contains(BASE_AUTH_URL + Endpoints.LOGOUT_GET + "?redirect=" + HOME_URL + "/"));
|
||||
assert(home_page_contains(HOME_URL + "/secret.html"));
|
||||
assert(home_page_contains(SECRET_URL + "/secret.html"));
|
||||
assert(home_page_contains(SECRET1_URL + "/secret.html"));
|
||||
assert(home_page_contains(SECRET2_URL + "/secret.html"));
|
||||
assert(home_page_contains(MX1_URL + "/secret.html"));
|
||||
assert(home_page_contains(MX2_URL + "/secret.html"));
|
||||
});
|
||||
|
||||
it("should serve the login page", function (done) {
|
||||
getPromised(BASE_AUTH_URL + Endpoints.FIRST_FACTOR_GET + "?redirect=/")
|
||||
.then(function (data: request_.RequestResponse) {
|
||||
assert.equal(data.statusCode, 200);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("should serve the homepage", function (done) {
|
||||
getPromised(HOME_URL + "/")
|
||||
.then(function (data: request_.RequestResponse) {
|
||||
assert.equal(data.statusCode, 200);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("should redirect when logout", function (done) {
|
||||
getPromised(BASE_AUTH_URL + Endpoints.LOGOUT_GET + "?redirect=" + HOME_URL)
|
||||
.then(function (data: request_.RequestResponse) {
|
||||
assert.equal(data.statusCode, 200);
|
||||
assert.equal(data.body, home_page);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("should be redirected to the login page when accessing secret while not authenticated", function (done) {
|
||||
const url = HOME_URL + "/secret.html";
|
||||
getPromised(url)
|
||||
.then(function (data: request_.RequestResponse) {
|
||||
assert.equal(data.statusCode, 200);
|
||||
assert.equal(data.body, login_page);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it.skip("should fail the first factor", function (done) {
|
||||
postPromised(BASE_AUTH_URL + Endpoints.FIRST_FACTOR_POST, {
|
||||
form: {
|
||||
username: "admin",
|
||||
password: "password",
|
||||
}
|
||||
})
|
||||
.then(function (data: request_.RequestResponse) {
|
||||
assert.equal(data.body, "Bad credentials");
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
function login_as(username: string, password: string) {
|
||||
return postPromised(BASE_AUTH_URL + Endpoints.FIRST_FACTOR_POST, {
|
||||
form: {
|
||||
username: "john",
|
||||
password: "password",
|
||||
}
|
||||
})
|
||||
.then(function (data: request_.RequestResponse) {
|
||||
assert.equal(data.statusCode, 302);
|
||||
return BluebirdPromise.resolve();
|
||||
});
|
||||
}
|
||||
|
||||
it("should succeed the first factor", function () {
|
||||
return login_as("john", "password");
|
||||
});
|
||||
|
||||
describe("test ldap connection", function () {
|
||||
it("should not fail after inactivity", function () {
|
||||
const clock = sinon.useFakeTimers();
|
||||
return login_as("john", "password")
|
||||
.then(function () {
|
||||
clock.tick(3600000 * 24); // 24 hour
|
||||
return login_as("john", "password");
|
||||
})
|
||||
.then(function () {
|
||||
clock.restore();
|
||||
return BluebirdPromise.resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function getPromised(url: string) {
|
||||
return request.getAsync(url);
|
||||
}
|
||||
|
||||
function postPromised(url: string, body: Object) {
|
||||
return request.postAsync(url, body);
|
||||
}
|
||||
|
||||
function getHomePage(): BluebirdPromise<request_.RequestResponse> {
|
||||
return getPromised(HOME_URL + "/");
|
||||
}
|
||||
|
||||
function getLoginPage(): BluebirdPromise<request_.RequestResponse> {
|
||||
return getPromised(BASE_AUTH_URL + Endpoints.FIRST_FACTOR_GET);
|
||||
}
|
Loading…
Reference in New Issue