commit
19c846a366
|
@ -33,3 +33,5 @@ dist/
|
||||||
example/ldap/private.ldif
|
example/ldap/private.ldif
|
||||||
|
|
||||||
package-lock.json
|
package-lock.json
|
||||||
|
|
||||||
|
Configuration.schema.json
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
src/
|
client/
|
||||||
|
server/
|
||||||
test/
|
test/
|
||||||
doc/
|
doc/
|
||||||
scripts/
|
scripts/
|
||||||
images/
|
images/
|
||||||
example/
|
example/
|
||||||
dist/test/
|
|
||||||
|
|
||||||
.travis.yml
|
.travis.yml
|
||||||
config.test.yml
|
config.test.yml
|
||||||
|
|
34
README.md
34
README.md
|
@ -24,11 +24,12 @@ used in production to secure internal services in a small docker swarm cluster.
|
||||||
5. [Access control](#access-control)
|
5. [Access control](#access-control)
|
||||||
6. [Basic authentication](#basic-authentication)
|
6. [Basic authentication](#basic-authentication)
|
||||||
7. [Session management with Redis](#session-management-with-redis)
|
7. [Session management with Redis](#session-management-with-redis)
|
||||||
4. [Documentation](#documentation)
|
4. [Security](#security)
|
||||||
|
5. [Documentation](#documentation)
|
||||||
1. [Authelia configuration](#authelia-configuration)
|
1. [Authelia configuration](#authelia-configuration)
|
||||||
1. [API documentation](#api-documentation)
|
2. [API documentation](#api-documentation)
|
||||||
5. [Contributing to Authelia](#contributing-to-authelia)
|
6. [Contributing to Authelia](#contributing-to-authelia)
|
||||||
6. [License](#license)
|
7. [License](#license)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -197,6 +198,29 @@ Please see [config.template.yml] to see an example of configuration.
|
||||||
### Session management with Redis
|
### Session management with Redis
|
||||||
When your users authenticate against Authelia, sessions are stored in a Redis key/value store. You can specify your own Redis instance in [config.template.yml].
|
When your users authenticate against Authelia, sessions are stored in a Redis key/value store. You can specify your own Redis instance in [config.template.yml].
|
||||||
|
|
||||||
|
## Security
|
||||||
|
|
||||||
|
### Protection against cookie theft
|
||||||
|
|
||||||
|
Authelia uses two mechanism to protect against cookie theft:
|
||||||
|
1. session attribute `httpOnly` set to true make client-side code unable to
|
||||||
|
read the cookie.
|
||||||
|
2. session attribute `secure` ensure the cookie will never be sent over an
|
||||||
|
unsecure HTTP connections.
|
||||||
|
|
||||||
|
### Protection against multi-domain cookie attacks
|
||||||
|
|
||||||
|
Since Authelia uses multi-domain cookies to perform single sign-on, an
|
||||||
|
attacker who poisonned a user's DNS cache can easily retrieve the user's
|
||||||
|
cookies by making the user send a request to one of the attacker's IPs.
|
||||||
|
|
||||||
|
To mitigate this risk, it's advisable to only use HTTPS connections with valid
|
||||||
|
certificates and enforce it with HTTP Strict Transport Security ([HSTS]) so
|
||||||
|
that the attacker must also require the certificate to retrieve the cookies.
|
||||||
|
|
||||||
|
Note that using [HSTS] has consequences. That's why you should read the blog
|
||||||
|
post nginx has written on [HSTS].
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
### Authelia configuration
|
### Authelia configuration
|
||||||
The configuration of the server is defined in the file
|
The configuration of the server is defined in the file
|
||||||
|
@ -246,4 +270,4 @@ Follow [contributing](CONTRIBUTORS.md) file.
|
||||||
[auth_request]: http://nginx.org/en/docs/http/ngx_http_auth_request_module.html
|
[auth_request]: http://nginx.org/en/docs/http/ngx_http_auth_request_module.html
|
||||||
[Google Authenticator]: https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&hl=en
|
[Google Authenticator]: https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2&hl=en
|
||||||
[config.template.yml]: https://github.com/clems4ever/authelia/blob/master/config.template.yml
|
[config.template.yml]: https://github.com/clems4ever/authelia/blob/master/config.template.yml
|
||||||
|
[HSTS]: https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/
|
||||||
|
|
|
@ -55,8 +55,10 @@ ldap:
|
||||||
#
|
#
|
||||||
# Note: by default a domain uses "two_factor" method.
|
# Note: by default a domain uses "two_factor" method.
|
||||||
#
|
#
|
||||||
# Note: 'overriden_methods' is a dictionary where keys must be subdomains and
|
# Note: 'per_subdomain_methods' is a dictionary where keys must be subdomains and
|
||||||
# values must be one of the two possible methods.
|
# values must be one of the two possible methods.
|
||||||
|
#
|
||||||
|
# Note: 'per_subdomain_methods' is optional.
|
||||||
authentication_methods:
|
authentication_methods:
|
||||||
default_method: two_factor
|
default_method: two_factor
|
||||||
per_subdomain_methods:
|
per_subdomain_methods:
|
||||||
|
|
|
@ -47,6 +47,21 @@ ldap:
|
||||||
user: cn=admin,dc=example,dc=com
|
user: cn=admin,dc=example,dc=com
|
||||||
password: password
|
password: password
|
||||||
|
|
||||||
|
# Authentication methods
|
||||||
|
#
|
||||||
|
# Authentication methods can be defined per subdomain.
|
||||||
|
# There are currently two available methods: "basic_auth" and "two_factor"
|
||||||
|
#
|
||||||
|
# Note: by default a domain uses "two_factor" method.
|
||||||
|
#
|
||||||
|
# Note: 'per_subdomain_methods' is a dictionary where keys must be subdomains and
|
||||||
|
# values must be one of the two possible methods.
|
||||||
|
#
|
||||||
|
# Note: 'per_subdomain_methods' is optional.
|
||||||
|
authentication_methods:
|
||||||
|
default_method: two_factor
|
||||||
|
per_subdomain_methods:
|
||||||
|
basicauth.test.local: basic_auth
|
||||||
|
|
||||||
# Access Control
|
# Access Control
|
||||||
#
|
#
|
||||||
|
|
|
@ -5,6 +5,8 @@ services:
|
||||||
restart: always
|
restart: always
|
||||||
volumes:
|
volumes:
|
||||||
- ./config.template.yml:/etc/authelia/config.yml:ro
|
- ./config.template.yml:/etc/authelia/config.yml:ro
|
||||||
|
environment:
|
||||||
|
- NODE_TLS_REJECT_UNAUTHORIZED=0
|
||||||
depends_on:
|
depends_on:
|
||||||
- redis
|
- redis
|
||||||
networks:
|
networks:
|
||||||
|
|
|
@ -6,6 +6,8 @@ services:
|
||||||
volumes:
|
volumes:
|
||||||
- ./config.template.yml:/etc/authelia/config.yml:ro
|
- ./config.template.yml:/etc/authelia/config.yml:ro
|
||||||
- ./notifications:/var/lib/authelia/notifications
|
- ./notifications:/var/lib/authelia/notifications
|
||||||
|
environment:
|
||||||
|
- NODE_TLS_REJECT_UNAUTHORIZED=0
|
||||||
depends_on:
|
depends_on:
|
||||||
- redis
|
- redis
|
||||||
networks:
|
networks:
|
||||||
|
|
|
@ -30,11 +30,14 @@ http {
|
||||||
ssl_certificate /etc/ssl/server.crt;
|
ssl_certificate /etc/ssl/server.crt;
|
||||||
ssl_certificate_key /etc/ssl/server.key;
|
ssl_certificate_key /etc/ssl/server.key;
|
||||||
|
|
||||||
|
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||||
|
add_header X-Frame-Options "SAMEORIGIN";
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
proxy_set_header X-Original-URI $request_uri;
|
proxy_set_header X-Original-URI $request_uri;
|
||||||
proxy_set_header Host $http_host;
|
proxy_set_header Host $http_host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
|
||||||
proxy_pass http://authelia/;
|
proxy_pass http://authelia/;
|
||||||
|
|
||||||
|
@ -57,6 +60,9 @@ http {
|
||||||
ssl on;
|
ssl on;
|
||||||
ssl_certificate /etc/ssl/server.crt;
|
ssl_certificate /etc/ssl/server.crt;
|
||||||
ssl_certificate_key /etc/ssl/server.key;
|
ssl_certificate_key /etc/ssl/server.key;
|
||||||
|
|
||||||
|
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||||
|
add_header X-Frame-Options "SAMEORIGIN";
|
||||||
}
|
}
|
||||||
|
|
||||||
server {
|
server {
|
||||||
|
@ -69,10 +75,14 @@ http {
|
||||||
ssl_certificate /etc/ssl/server.crt;
|
ssl_certificate /etc/ssl/server.crt;
|
||||||
ssl_certificate_key /etc/ssl/server.key;
|
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 {
|
location /auth_verify {
|
||||||
internal;
|
internal;
|
||||||
proxy_set_header X-Original-URI $request_uri;
|
proxy_set_header X-Original-URI $request_uri;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
proxy_set_header Host $http_host;
|
proxy_set_header Host $http_host;
|
||||||
proxy_set_header Content-Length "";
|
proxy_set_header Content-Length "";
|
||||||
|
|
||||||
|
@ -122,10 +132,14 @@ http {
|
||||||
ssl_certificate /etc/ssl/server.crt;
|
ssl_certificate /etc/ssl/server.crt;
|
||||||
ssl_certificate_key /etc/ssl/server.key;
|
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 {
|
location /auth_verify {
|
||||||
internal;
|
internal;
|
||||||
proxy_set_header X-Original-URI $request_uri;
|
proxy_set_header X-Original-URI $request_uri;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
proxy_set_header Host $http_host;
|
proxy_set_header Host $http_host;
|
||||||
proxy_set_header Content-Length "";
|
proxy_set_header Content-Length "";
|
||||||
|
|
||||||
|
@ -158,10 +172,14 @@ http {
|
||||||
ssl_certificate /etc/ssl/server.crt;
|
ssl_certificate /etc/ssl/server.crt;
|
||||||
ssl_certificate_key /etc/ssl/server.key;
|
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 {
|
location /auth_verify {
|
||||||
internal;
|
internal;
|
||||||
proxy_set_header X-Original-URI $request_uri;
|
proxy_set_header X-Original-URI $request_uri;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
proxy_set_header Host $http_host;
|
proxy_set_header Host $http_host;
|
||||||
proxy_set_header Content-Length "";
|
proxy_set_header Content-Length "";
|
||||||
|
|
||||||
|
@ -194,10 +212,14 @@ http {
|
||||||
ssl_certificate /etc/ssl/server.crt;
|
ssl_certificate /etc/ssl/server.crt;
|
||||||
ssl_certificate_key /etc/ssl/server.key;
|
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 {
|
location /auth_verify {
|
||||||
internal;
|
internal;
|
||||||
proxy_set_header X-Original-URI $request_uri;
|
proxy_set_header X-Original-URI $request_uri;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
proxy_set_header Host $http_host;
|
proxy_set_header Host $http_host;
|
||||||
proxy_set_header Content-Length "";
|
proxy_set_header Content-Length "";
|
||||||
|
|
||||||
|
@ -230,10 +252,14 @@ http {
|
||||||
ssl_certificate /etc/ssl/server.crt;
|
ssl_certificate /etc/ssl/server.crt;
|
||||||
ssl_certificate_key /etc/ssl/server.key;
|
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 {
|
location /auth_verify {
|
||||||
internal;
|
internal;
|
||||||
proxy_set_header X-Original-URI $request_uri;
|
proxy_set_header X-Original-URI $request_uri;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
proxy_set_header Host $http_host;
|
proxy_set_header Host $http_host;
|
||||||
proxy_set_header Content-Length "";
|
proxy_set_header Content-Length "";
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,9 @@ function deploy_on_dockerhub {
|
||||||
if [ "$TRAVIS_BRANCH" == "master" ]; then
|
if [ "$TRAVIS_BRANCH" == "master" ]; then
|
||||||
login_to_dockerhub
|
login_to_dockerhub
|
||||||
deploy_on_dockerhub master
|
deploy_on_dockerhub master
|
||||||
|
elif [ "$TRAVIS_BRANCH" == "develop" ]; then
|
||||||
|
login_to_dockerhub
|
||||||
|
deploy_on_dockerhub develop
|
||||||
elif [ ! -z "$TRAVIS_TAG" ]; then
|
elif [ ! -z "$TRAVIS_TAG" ]; then
|
||||||
login_to_dockerhub
|
login_to_dockerhub
|
||||||
deploy_on_dockerhub $TRAVIS_TAG
|
deploy_on_dockerhub $TRAVIS_TAG
|
||||||
|
|
|
@ -5,6 +5,8 @@ set -e
|
||||||
docker --version
|
docker --version
|
||||||
docker-compose --version
|
docker-compose --version
|
||||||
|
|
||||||
|
grunt run:generate-config-schema
|
||||||
|
|
||||||
# Run unit tests
|
# Run unit tests
|
||||||
grunt test-unit
|
grunt test-unit
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
#! /usr/bin/env node
|
#! /usr/bin/env node
|
||||||
|
|
||||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
|
||||||
|
|
||||||
import Server from "./lib/Server";
|
import Server from "./lib/Server";
|
||||||
import { GlobalDependencies } from "../types/Dependencies";
|
import { GlobalDependencies } from "../types/Dependencies";
|
||||||
import YAML = require("yamljs");
|
import YAML = require("yamljs");
|
||||||
|
|
|
@ -23,8 +23,8 @@ import * as http from "http";
|
||||||
const addRequestId = require("express-request-id")();
|
const addRequestId = require("express-request-id")();
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
|
|
||||||
const TRUST_PROXY = "trust proxy";
|
const TRUST_PROXY = "trust proxy";
|
||||||
|
const X_POWERED_BY = "x-powered-by";
|
||||||
const VIEWS = "views";
|
const VIEWS = "views";
|
||||||
const VIEW_ENGINE = "view engine";
|
const VIEW_ENGINE = "view engine";
|
||||||
const PUG = "pug";
|
const PUG = "pug";
|
||||||
|
@ -54,9 +54,9 @@ export default class Server {
|
||||||
app.use(BodyParser.json());
|
app.use(BodyParser.json());
|
||||||
app.use(deps.session(expressSessionOptions));
|
app.use(deps.session(expressSessionOptions));
|
||||||
app.use(addRequestId);
|
app.use(addRequestId);
|
||||||
app.disable("x-powered-by");
|
app.disable(X_POWERED_BY);
|
||||||
|
app.enable(TRUST_PROXY);
|
||||||
|
|
||||||
app.set(TRUST_PROXY, 1);
|
|
||||||
app.set(VIEWS, viewsDirectory);
|
app.set(VIEWS, viewsDirectory);
|
||||||
app.set(VIEW_ENGINE, PUG);
|
app.set(VIEW_ENGINE, PUG);
|
||||||
|
|
||||||
|
|
|
@ -73,8 +73,8 @@ export interface GmailNotifierConfiguration {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SmtpNotifierConfiguration {
|
export interface SmtpNotifierConfiguration {
|
||||||
username: string;
|
username?: string;
|
||||||
password: string;
|
password?: string;
|
||||||
host: string;
|
host: string;
|
||||||
port: number;
|
port: number;
|
||||||
secure: boolean;
|
secure: boolean;
|
||||||
|
@ -116,7 +116,7 @@ declare type AuthenticationMethodPerSubdomain = { [subdomain: string]: Authentic
|
||||||
|
|
||||||
export interface AuthenticationMethodsConfiguration {
|
export interface AuthenticationMethodsConfiguration {
|
||||||
default_method: AuthenticationMethod;
|
default_method: AuthenticationMethod;
|
||||||
per_subdomain_methods: AuthenticationMethodPerSubdomain;
|
per_subdomain_methods?: AuthenticationMethodPerSubdomain;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UserConfiguration {
|
export interface UserConfiguration {
|
||||||
|
|
|
@ -1,368 +0,0 @@
|
||||||
{
|
|
||||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
|
||||||
"definitions": {
|
|
||||||
"ACLConfiguration": {
|
|
||||||
"properties": {
|
|
||||||
"any": {
|
|
||||||
"items": {
|
|
||||||
"properties": {
|
|
||||||
"domain": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"policy": {
|
|
||||||
"$ref": "#/definitions/ACLPolicy"
|
|
||||||
},
|
|
||||||
"resources": {
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"type": "array"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"domain",
|
|
||||||
"policy"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"type": "array"
|
|
||||||
},
|
|
||||||
"default_policy": {
|
|
||||||
"$ref": "#/definitions/ACLPolicy"
|
|
||||||
},
|
|
||||||
"groups": {
|
|
||||||
"additionalProperties": {
|
|
||||||
"items": {
|
|
||||||
"properties": {
|
|
||||||
"domain": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"policy": {
|
|
||||||
"$ref": "#/definitions/ACLPolicy"
|
|
||||||
},
|
|
||||||
"resources": {
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"type": "array"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"domain",
|
|
||||||
"policy"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"type": "array"
|
|
||||||
},
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"users": {
|
|
||||||
"additionalProperties": {
|
|
||||||
"items": {
|
|
||||||
"properties": {
|
|
||||||
"domain": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"policy": {
|
|
||||||
"$ref": "#/definitions/ACLPolicy"
|
|
||||||
},
|
|
||||||
"resources": {
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"type": "array"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"domain",
|
|
||||||
"policy"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"type": "array"
|
|
||||||
},
|
|
||||||
"type": "object"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"ACLPolicy": {
|
|
||||||
"enum": [
|
|
||||||
"allow",
|
|
||||||
"deny"
|
|
||||||
],
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"AuthenticationMethod": {
|
|
||||||
"enum": [
|
|
||||||
"basic_auth",
|
|
||||||
"two_factor"
|
|
||||||
],
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"AuthenticationMethodsConfiguration": {
|
|
||||||
"properties": {
|
|
||||||
"default_method": {
|
|
||||||
"$ref": "#/definitions/AuthenticationMethod"
|
|
||||||
},
|
|
||||||
"per_subdomain_methods": {
|
|
||||||
"additionalProperties": {
|
|
||||||
"enum": [
|
|
||||||
"basic_auth",
|
|
||||||
"two_factor"
|
|
||||||
],
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"type": "object"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"default_method",
|
|
||||||
"per_subdomain_methods"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"FileSystemNotifierConfiguration": {
|
|
||||||
"properties": {
|
|
||||||
"filename": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"filename"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"GmailNotifierConfiguration": {
|
|
||||||
"properties": {
|
|
||||||
"password": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"sender": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"username": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"password",
|
|
||||||
"sender",
|
|
||||||
"username"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"LocalStorageConfiguration": {
|
|
||||||
"properties": {
|
|
||||||
"in_memory": {
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"path": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"MongoStorageConfiguration": {
|
|
||||||
"properties": {
|
|
||||||
"url": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"url"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"NotifierConfiguration": {
|
|
||||||
"properties": {
|
|
||||||
"filesystem": {
|
|
||||||
"$ref": "#/definitions/FileSystemNotifierConfiguration"
|
|
||||||
},
|
|
||||||
"gmail": {
|
|
||||||
"$ref": "#/definitions/GmailNotifierConfiguration"
|
|
||||||
},
|
|
||||||
"smtp": {
|
|
||||||
"$ref": "#/definitions/SmtpNotifierConfiguration"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"RegulationConfiguration": {
|
|
||||||
"properties": {
|
|
||||||
"ban_time": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"find_time": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"max_retries": {
|
|
||||||
"type": "number"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"ban_time",
|
|
||||||
"find_time",
|
|
||||||
"max_retries"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"SessionCookieConfiguration": {
|
|
||||||
"properties": {
|
|
||||||
"domain": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"expiration": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"redis": {
|
|
||||||
"$ref": "#/definitions/SessionRedisOptions"
|
|
||||||
},
|
|
||||||
"secret": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"secret"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"SessionRedisOptions": {
|
|
||||||
"properties": {
|
|
||||||
"host": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"port": {
|
|
||||||
"type": "number"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"host",
|
|
||||||
"port"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"SmtpNotifierConfiguration": {
|
|
||||||
"properties": {
|
|
||||||
"host": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"password": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"port": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"secure": {
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"sender": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"username": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"host",
|
|
||||||
"password",
|
|
||||||
"port",
|
|
||||||
"secure",
|
|
||||||
"sender",
|
|
||||||
"username"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"StorageConfiguration": {
|
|
||||||
"properties": {
|
|
||||||
"local": {
|
|
||||||
"$ref": "#/definitions/LocalStorageConfiguration"
|
|
||||||
},
|
|
||||||
"mongo": {
|
|
||||||
"$ref": "#/definitions/MongoStorageConfiguration"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"UserLdapConfiguration": {
|
|
||||||
"properties": {
|
|
||||||
"additional_groups_dn": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"additional_users_dn": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"base_dn": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"group_name_attribute": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"groups_filter": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"mail_attribute": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"password": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"url": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"user": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"users_filter": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"base_dn",
|
|
||||||
"password",
|
|
||||||
"url",
|
|
||||||
"user"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"properties": {
|
|
||||||
"access_control": {
|
|
||||||
"$ref": "#/definitions/ACLConfiguration"
|
|
||||||
},
|
|
||||||
"authentication_methods": {
|
|
||||||
"$ref": "#/definitions/AuthenticationMethodsConfiguration"
|
|
||||||
},
|
|
||||||
"ldap": {
|
|
||||||
"$ref": "#/definitions/UserLdapConfiguration"
|
|
||||||
},
|
|
||||||
"logs_level": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"notifier": {
|
|
||||||
"$ref": "#/definitions/NotifierConfiguration"
|
|
||||||
},
|
|
||||||
"port": {
|
|
||||||
"type": "number"
|
|
||||||
},
|
|
||||||
"regulation": {
|
|
||||||
"$ref": "#/definitions/RegulationConfiguration"
|
|
||||||
},
|
|
||||||
"session": {
|
|
||||||
"$ref": "#/definitions/SessionCookieConfiguration"
|
|
||||||
},
|
|
||||||
"storage": {
|
|
||||||
"$ref": "#/definitions/StorageConfiguration"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"ldap",
|
|
||||||
"notifier",
|
|
||||||
"regulation",
|
|
||||||
"session",
|
|
||||||
"storage"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
}
|
|
||||||
|
|
|
@ -12,7 +12,8 @@ export class SessionConfigurationBuilder {
|
||||||
resave: false,
|
resave: false,
|
||||||
saveUninitialized: true,
|
saveUninitialized: true,
|
||||||
cookie: {
|
cookie: {
|
||||||
secure: false,
|
secure: true,
|
||||||
|
httpOnly: true,
|
||||||
maxAge: configuration.session.expiration,
|
maxAge: configuration.session.expiration,
|
||||||
domain: configuration.session.domain
|
domain: configuration.session.domain
|
||||||
},
|
},
|
||||||
|
|
|
@ -28,11 +28,15 @@ export class MailSenderBuilder implements IMailSenderBuilder {
|
||||||
host: options.host,
|
host: options.host,
|
||||||
port: options.port,
|
port: options.port,
|
||||||
secure: options.secure, // upgrade later with STARTTLS
|
secure: options.secure, // upgrade later with STARTTLS
|
||||||
auth: {
|
};
|
||||||
|
|
||||||
|
if (options.username && options.password) {
|
||||||
|
smtpOptions.auth = {
|
||||||
user: options.username,
|
user: options.username,
|
||||||
pass: options.password
|
pass: options.password
|
||||||
}
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
return new MailSender(smtpOptions, this.nodemailer);
|
return new MailSender(smtpOptions, this.nodemailer);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,8 +1,17 @@
|
||||||
import Express = require("express");
|
import Express = require("express");
|
||||||
import Endpoints = require("../../../../../shared/api");
|
import Endpoints = require("../../../../../shared/api");
|
||||||
|
import FirstFactorBlocker from "../FirstFactorBlocker";
|
||||||
|
import BluebirdPromise = require("bluebird");
|
||||||
|
import AuthenticationSession = require("../../AuthenticationSession");
|
||||||
|
|
||||||
export default function(req: Express.Request, res: Express.Response) {
|
export default FirstFactorBlocker(handler);
|
||||||
res.render("already-logged-in", {
|
|
||||||
logout_endpoint: Endpoints.LOGOUT_GET
|
function handler(req: Express.Request, res: Express.Response): BluebirdPromise<void> {
|
||||||
});
|
return AuthenticationSession.get(req)
|
||||||
|
.then(function (authSession) {
|
||||||
|
res.render("already-logged-in", {
|
||||||
|
logout_endpoint: Endpoints.LOGOUT_GET,
|
||||||
|
username: authSession.userid
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
|
@ -5,5 +5,5 @@ block form-header
|
||||||
<img class="header-img" src="/img/success.png" alt="">
|
<img class="header-img" src="/img/success.png" alt="">
|
||||||
|
|
||||||
block content
|
block content
|
||||||
<p>You are already logged in.<br/>
|
<p>You are already logged in as <b>#{ username }</b>.<br/>
|
||||||
| Click <a href="#{ logout_endpoint }">here</a> to log off.<p>
|
| Click <a href="#{ logout_endpoint }">here</a> to log off.<p>
|
||||||
|
|
|
@ -73,7 +73,8 @@ describe("test session configuration builder", function () {
|
||||||
resave: false,
|
resave: false,
|
||||||
saveUninitialized: true,
|
saveUninitialized: true,
|
||||||
cookie: {
|
cookie: {
|
||||||
secure: false,
|
secure: true,
|
||||||
|
httpOnly: true,
|
||||||
maxAge: 3600,
|
maxAge: 3600,
|
||||||
domain: "example.com"
|
domain: "example.com"
|
||||||
}
|
}
|
||||||
|
@ -153,7 +154,8 @@ describe("test session configuration builder", function () {
|
||||||
resave: false,
|
resave: false,
|
||||||
saveUninitialized: true,
|
saveUninitialized: true,
|
||||||
cookie: {
|
cookie: {
|
||||||
secure: false,
|
secure: true,
|
||||||
|
httpOnly: true,
|
||||||
maxAge: 3600,
|
maxAge: 3600,
|
||||||
domain: "example.com"
|
domain: "example.com"
|
||||||
},
|
},
|
||||||
|
|
|
@ -25,24 +25,41 @@ describe("test MailSenderBuilder", function() {
|
||||||
Assert.equal(createTransportStub.getCall(0).args[0].auth.pass, "pass_gmail");
|
Assert.equal(createTransportStub.getCall(0).args[0].auth.pass, "pass_gmail");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should create a smtp mail sender", function() {
|
describe("build smtp mail sender", function() {
|
||||||
const mailSenderBuilder = new MailSenderBuilder(Nodemailer);
|
it("should create a smtp mail sender with authenticated user", function() {
|
||||||
mailSenderBuilder.buildSmtp({
|
const mailSenderBuilder = new MailSenderBuilder(Nodemailer);
|
||||||
host: "mail.example.com",
|
mailSenderBuilder.buildSmtp({
|
||||||
password: "password",
|
host: "mail.example.com",
|
||||||
port: 25,
|
password: "password",
|
||||||
secure: true,
|
port: 25,
|
||||||
username: "user",
|
secure: true,
|
||||||
sender: "admin@example.com"
|
username: "user",
|
||||||
|
sender: "admin@example.com"
|
||||||
|
});
|
||||||
|
Assert.deepStrictEqual(createTransportStub.getCall(0).args[0], {
|
||||||
|
host: "mail.example.com",
|
||||||
|
auth: {
|
||||||
|
pass: "password",
|
||||||
|
user: "user"
|
||||||
|
},
|
||||||
|
port: 25,
|
||||||
|
secure: true,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
Assert.deepStrictEqual(createTransportStub.getCall(0).args[0], {
|
|
||||||
host: "mail.example.com",
|
it("should create a smtp mail sender with anonymous user", function() {
|
||||||
auth: {
|
const mailSenderBuilder = new MailSenderBuilder(Nodemailer);
|
||||||
pass: "password",
|
mailSenderBuilder.buildSmtp({
|
||||||
user: "user"
|
host: "mail.example.com",
|
||||||
},
|
port: 25,
|
||||||
port: 25,
|
secure: true,
|
||||||
secure: true,
|
sender: "admin@example.com"
|
||||||
|
});
|
||||||
|
Assert.deepStrictEqual(createTransportStub.getCall(0).args[0], {
|
||||||
|
host: "mail.example.com",
|
||||||
|
port: 25,
|
||||||
|
secure: true,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -173,6 +173,10 @@ describe("Private pages of the server must not be accessible without session", f
|
||||||
it("should block " + Endpoints.SECOND_FACTOR_TOTP_POST, function () {
|
it("should block " + Endpoints.SECOND_FACTOR_TOTP_POST, function () {
|
||||||
return should_post_and_reply_with_401(BASE_URL + Endpoints.SECOND_FACTOR_TOTP_POST);
|
return should_post_and_reply_with_401(BASE_URL + Endpoints.SECOND_FACTOR_TOTP_POST);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should block " + Endpoints.LOGGED_IN, function () {
|
||||||
|
return should_get_and_reply_with_401(BASE_URL + Endpoints.LOGGED_IN);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue