Fix and parallelize integration tests.
parent
be802cfc7b
commit
b89f63e9c1
74
.travis.yml
74
.travis.yml
|
@ -3,7 +3,7 @@ language: go
|
|||
required: sudo
|
||||
|
||||
go:
|
||||
- '1.13'
|
||||
- "1.13"
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
@ -19,25 +19,73 @@ addons:
|
|||
- libgif-dev
|
||||
- google-chrome-stable
|
||||
|
||||
install: # Install ChromeDriver (64bits; replace 64 with 32 for 32bits).
|
||||
- wget -N https://chromedriver.storage.googleapis.com/78.0.3904.70/chromedriver_linux64.zip -P ~/
|
||||
- unzip ~/chromedriver_linux64.zip -d ~/
|
||||
- rm ~/chromedriver_linux64.zip
|
||||
- sudo mv -f ~/chromedriver /usr/local/share/
|
||||
- sudo chmod +x /usr/local/share/chromedriver
|
||||
- sudo ln -s /usr/local/share/chromedriver /usr/bin/chromedriver
|
||||
install:
|
||||
- go mod download
|
||||
|
||||
before_script:
|
||||
- export PATH=./cmd/authelia-scripts/:/tmp:$PATH
|
||||
- curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash
|
||||
- nvm install v12 && nvm use v12 && npm i
|
||||
- source bootstrap.sh
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- stage: test
|
||||
- stage: build & test
|
||||
before_script:
|
||||
- curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash
|
||||
- nvm install v12 && nvm use v12
|
||||
script:
|
||||
- authelia-scripts --log-level debug ci
|
||||
|
||||
# Run all suites in a dedicated container
|
||||
- &e2e-test
|
||||
stage: end-to-end suite tests
|
||||
env:
|
||||
- SUITE_NAME=BypassAll
|
||||
before_script:
|
||||
# Install chrome driver
|
||||
- wget -N https://chromedriver.storage.googleapis.com/78.0.3904.70/chromedriver_linux64.zip -P ~/
|
||||
- unzip ~/chromedriver_linux64.zip -d ~/
|
||||
- rm ~/chromedriver_linux64.zip
|
||||
- sudo mv -f ~/chromedriver /usr/local/share/
|
||||
- sudo chmod +x /usr/local/share/chromedriver
|
||||
- sudo ln -s /usr/local/share/chromedriver /usr/bin/chromedriver
|
||||
script:
|
||||
# Run the suite
|
||||
- CI=true authelia-scripts --log-level debug suites test $SUITE_NAME --headless
|
||||
# TODO(c.michaud): check if all suites are listed based on `authelia-scripts suites list` command.
|
||||
- <<: *e2e-test
|
||||
env:
|
||||
- SUITE_NAME=Docker
|
||||
- <<: *e2e-test
|
||||
env:
|
||||
- SUITE_NAME=DuoPush
|
||||
- <<: *e2e-test
|
||||
env:
|
||||
- SUITE_NAME=HighAvailability
|
||||
- <<: *e2e-test
|
||||
env:
|
||||
- SUITE_NAME=Kubernetes
|
||||
- <<: *e2e-test
|
||||
env:
|
||||
- SUITE_NAME=LDAP
|
||||
- <<: *e2e-test
|
||||
env:
|
||||
- SUITE_NAME=Mariadb
|
||||
- <<: *e2e-test
|
||||
env:
|
||||
- SUITE_NAME=NetworkACL
|
||||
- <<: *e2e-test
|
||||
env:
|
||||
- SUITE_NAME=Postgres
|
||||
- <<: *e2e-test
|
||||
env:
|
||||
- SUITE_NAME=ShortTimeouts
|
||||
- <<: *e2e-test
|
||||
env:
|
||||
- SUITE_NAME=Standalone
|
||||
- <<: *e2e-test
|
||||
env:
|
||||
- SUITE_NAME=Traefik
|
||||
|
||||
- &build-images
|
||||
stage: build images
|
||||
env:
|
||||
|
@ -56,9 +104,9 @@ jobs:
|
|||
- tar -czf authelia-linux-$ARCH.tar.gz authelia-linux-$ARCH public_html
|
||||
deploy:
|
||||
provider: releases
|
||||
api_key: '$GITHUB_API_KEY'
|
||||
api_key: "$GITHUB_API_KEY"
|
||||
file_glob: true
|
||||
file: 'authelia-linux-$ARCH.tar.gz'
|
||||
file: "authelia-linux-$ARCH.tar.gz"
|
||||
skip_cleanup: true
|
||||
on:
|
||||
tags: true
|
||||
|
|
15
Dockerfile
15
Dockerfile
|
@ -7,7 +7,14 @@ FROM golang:1.13-alpine AS builder-backend
|
|||
RUN apk --no-cache add gcc musl-dev
|
||||
|
||||
WORKDIR /go/src/app
|
||||
COPY . .
|
||||
|
||||
COPY go.mod go.mod
|
||||
COPY go.sum go.sum
|
||||
|
||||
RUN go mod download
|
||||
|
||||
COPY cmd cmd
|
||||
COPY internal internal
|
||||
|
||||
# CGO_ENABLED=1 is mandatory for building go-sqlite3
|
||||
RUN cd cmd/authelia && GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -tags netgo -ldflags '-w' -o authelia
|
||||
|
@ -16,10 +23,10 @@ RUN cd cmd/authelia && GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -tags netg
|
|||
# ========================================
|
||||
# ===== Build image for the frontend =====
|
||||
# ========================================
|
||||
FROM node:11-alpine AS builder-frontend
|
||||
FROM node:12-alpine AS builder-frontend
|
||||
|
||||
WORKDIR /node/src/app
|
||||
COPY client .
|
||||
COPY web .
|
||||
|
||||
# Install the dependencies and build
|
||||
RUN npm ci && npm run build
|
||||
|
@ -41,4 +48,4 @@ EXPOSE 9091
|
|||
VOLUME /etc/authelia
|
||||
VOLUME /var/lib/authelia
|
||||
|
||||
CMD ["./authelia", "-config", "/etc/authelia/config.yml"]
|
||||
CMD ["./authelia", "-config", "/etc/authelia/configuration.yml"]
|
||||
|
|
|
@ -8,7 +8,14 @@ COPY ./qemu-arm-static /usr/bin/qemu-arm-static
|
|||
RUN apk --no-cache add gcc musl-dev
|
||||
|
||||
WORKDIR /go/src/app
|
||||
COPY . .
|
||||
|
||||
COPY go.mod go.mod
|
||||
COPY go.sum go.sum
|
||||
|
||||
RUN go mod download
|
||||
|
||||
COPY cmd cmd
|
||||
COPY internal internal
|
||||
|
||||
# CGO_ENABLED=1 is mandatory for building go-sqlite3
|
||||
RUN cd cmd/authelia && GOOS=linux GOARCH=arm CGO_ENABLED=1 go build -tags netgo -ldflags '-w' -o authelia
|
||||
|
@ -17,10 +24,10 @@ RUN cd cmd/authelia && GOOS=linux GOARCH=arm CGO_ENABLED=1 go build -tags netgo
|
|||
# ========================================
|
||||
# ===== Build image for the frontend =====
|
||||
# ========================================
|
||||
FROM node:11-alpine AS builder-frontend
|
||||
FROM node:12-alpine AS builder-frontend
|
||||
|
||||
WORKDIR /node/src/app
|
||||
COPY client .
|
||||
COPY web .
|
||||
|
||||
# Install the dependencies and build
|
||||
RUN npm ci && npm run build
|
||||
|
@ -45,4 +52,4 @@ EXPOSE 9091
|
|||
VOLUME /etc/authelia
|
||||
VOLUME /var/lib/authelia
|
||||
|
||||
CMD ["./authelia", "-config", "/etc/authelia/config.yml"]
|
||||
CMD ["./authelia", "-config", "/etc/authelia/configuration.yml"]
|
||||
|
|
|
@ -8,7 +8,14 @@ COPY ./qemu-aarch64-static /usr/bin/qemu-aarch64-static
|
|||
RUN apk --no-cache add gcc musl-dev
|
||||
|
||||
WORKDIR /go/src/app
|
||||
COPY . .
|
||||
|
||||
COPY go.mod go.mod
|
||||
COPY go.sum go.sum
|
||||
|
||||
RUN go mod download
|
||||
|
||||
COPY cmd cmd
|
||||
COPY internal internal
|
||||
|
||||
# CGO_ENABLED=1 is mandatory for building go-sqlite3
|
||||
RUN cd cmd/authelia && GOOS=linux GOARCH=arm64 CGO_ENABLED=1 go build -tags netgo -ldflags '-w' -o authelia
|
||||
|
@ -17,10 +24,10 @@ RUN cd cmd/authelia && GOOS=linux GOARCH=arm64 CGO_ENABLED=1 go build -tags netg
|
|||
# ========================================
|
||||
# ===== Build image for the frontend =====
|
||||
# ========================================
|
||||
FROM node:11-alpine AS builder-frontend
|
||||
FROM node:12-alpine AS builder-frontend
|
||||
|
||||
WORKDIR /node/src/app
|
||||
COPY client .
|
||||
COPY web .
|
||||
|
||||
# Install the dependencies and build
|
||||
RUN npm ci && npm run build
|
||||
|
@ -45,4 +52,4 @@ EXPOSE 9091
|
|||
VOLUME /etc/authelia
|
||||
VOLUME /var/lib/authelia
|
||||
|
||||
CMD ["./authelia", "-config", "/etc/authelia/config.yml"]
|
||||
CMD ["./authelia", "-config", "/etc/authelia/configuration.yml"]
|
||||
|
|
|
@ -7,6 +7,9 @@ if [ -z "$OLD_PS1" ]; then
|
|||
export PS1="(authelia) $PS1"
|
||||
fi
|
||||
|
||||
export USER_ID=$(id -u)
|
||||
export GROUP_ID=$(id -g)
|
||||
|
||||
|
||||
echo "[BOOTSTRAP] Checking if Go is installed..."
|
||||
if [ ! -x "$(command -v go)" ];
|
||||
|
|
|
@ -96,15 +96,6 @@ func shell(cmd string) {
|
|||
runCommand("bash", "-c", cmd)
|
||||
}
|
||||
|
||||
func buildHelperDockerImages() {
|
||||
shell("docker build -t authelia-example-backend example/compose/nginx/backend")
|
||||
shell("docker build -t authelia-duo-api example/compose/duo-api")
|
||||
|
||||
shell("docker-compose -f docker-compose.yml -f example/compose/kind/docker-compose.yml build")
|
||||
shell("docker-compose -f docker-compose.yml -f example/compose/authelia/docker-compose.backend.yml build --build-arg USER_ID=$(id -u) --build-arg GROUP_ID=$(id -g)")
|
||||
shell("docker-compose -f docker-compose.yml -f example/compose/authelia/docker-compose.frontend.yml build --build-arg USER_ID=$(id -u) --build-arg GROUP_ID=$(id -g)")
|
||||
}
|
||||
|
||||
func prepareHostsFile() {
|
||||
contentBytes, err := readHostsFile()
|
||||
|
||||
|
@ -209,9 +200,6 @@ func Bootstrap(cobraCmd *cobra.Command, args []string) {
|
|||
log.Fatal("GOPATH is not set")
|
||||
}
|
||||
|
||||
bootstrapPrintln("Building development Docker images...")
|
||||
buildHelperDockerImages()
|
||||
|
||||
createTemporaryDirectory()
|
||||
|
||||
bootstrapPrintln("Preparing /etc/hosts to serve subdomains of example.com...")
|
||||
|
|
|
@ -24,7 +24,7 @@ func buildAutheliaBinary() {
|
|||
func buildFrontend() {
|
||||
// Install npm dependencies
|
||||
cmd := utils.CommandWithStdout("npm", "ci")
|
||||
cmd.Dir = "client"
|
||||
cmd.Dir = "web"
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
log.Fatal(err)
|
||||
|
@ -32,13 +32,13 @@ func buildFrontend() {
|
|||
|
||||
// Then build the frontend
|
||||
cmd = utils.CommandWithStdout("npm", "run", "build")
|
||||
cmd.Dir = "client"
|
||||
cmd.Dir = "web"
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if err := os.Rename("client/build", OutputDir+"/public_html"); err != nil {
|
||||
if err := os.Rename("web/build", OutputDir+"/public_html"); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,18 +18,18 @@ const dockerPullCommandLine = "docker-compose -f docker-compose.yml " +
|
|||
|
||||
// RunCI run the CI scripts
|
||||
func RunCI(cmd *cobra.Command, args []string) {
|
||||
log.Info("=====> Build stage")
|
||||
log.Info("=====> Build stage <=====")
|
||||
if err := utils.CommandWithStdout("authelia-scripts", "--log-level", "debug", "build").Run(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Info("=====> Unit testing stage")
|
||||
log.Info("=====> Unit testing stage <=====")
|
||||
if err := utils.CommandWithStdout("authelia-scripts", "--log-level", "debug", "unittest").Run(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Info("=====> End-to-end testing stage")
|
||||
if err := utils.CommandWithStdout("authelia-scripts", "--log-level", "debug", "suites", "test", "--headless", "--only-forbidden").Run(); err != nil {
|
||||
log.Info("=====> Build Docker stage <=====")
|
||||
if err := utils.CommandWithStdout("authelia-scripts", "--log-level", "debug", "docker", "build").Run(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,11 +27,9 @@ var ErrNoRunningSuite = errors.New("no running suite")
|
|||
var runningSuiteFile = ".suite"
|
||||
|
||||
var headless bool
|
||||
var onlyForbidden bool
|
||||
|
||||
func init() {
|
||||
SuitesTestCmd.Flags().BoolVar(&headless, "headless", false, "Run tests in headless mode")
|
||||
SuitesTestCmd.Flags().BoolVar(&onlyForbidden, "only-forbidden", false, "Mocha 'only' filters are forbidden")
|
||||
}
|
||||
|
||||
// SuitesListCmd Command for listing the available suites
|
||||
|
@ -79,17 +77,17 @@ var SuitesTeardownCmd = &cobra.Command{
|
|||
runningSuite, err := getRunningSuite()
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if runningSuite == "" {
|
||||
panic(ErrNoRunningSuite)
|
||||
log.Fatal(ErrNoRunningSuite)
|
||||
}
|
||||
suiteName = runningSuite
|
||||
}
|
||||
|
||||
if err := teardownSuite(suiteName); err != nil {
|
||||
panic(err)
|
||||
log.Fatal(err)
|
||||
}
|
||||
},
|
||||
Args: cobra.MaximumNArgs(1),
|
||||
|
@ -143,6 +141,14 @@ func runSuiteSetupTeardown(command string, suite string) error {
|
|||
return utils.RunCommandWithTimeout(cmd, s.SetUpTimeout)
|
||||
}
|
||||
|
||||
func runOnSetupTimeout(suite string) error {
|
||||
cmd := utils.CommandWithStdout("go", "run", "cmd/authelia-suites/main.go", "timeout", suite)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Env = os.Environ()
|
||||
return utils.RunCommandWithTimeout(cmd, 15*time.Second)
|
||||
}
|
||||
|
||||
func setupSuite(suiteName string) error {
|
||||
log.Infof("Setup environment for suite %s...", suiteName)
|
||||
signalChannel := make(chan os.Signal)
|
||||
|
@ -156,10 +162,10 @@ func setupSuite(suiteName string) error {
|
|||
}()
|
||||
|
||||
if errSetup := runSuiteSetupTeardown("setup", suiteName); errSetup != nil || interrupted {
|
||||
err := teardownSuite(suiteName)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
if errSetup == utils.ErrTimeoutReached {
|
||||
runOnSetupTimeout(suiteName)
|
||||
}
|
||||
teardownSuite(suiteName)
|
||||
return errSetup
|
||||
}
|
||||
|
||||
|
@ -231,7 +237,7 @@ func runSuiteTests(suiteName string, withEnv bool) error {
|
|||
if suite.TestTimeout > 0 {
|
||||
timeout = fmt.Sprintf("%ds", int64(suite.TestTimeout/time.Second))
|
||||
}
|
||||
testCmdLine := fmt.Sprintf("go test ./internal/suites -timeout %s -run '^(Test%sSuite)$'", timeout, suiteName)
|
||||
testCmdLine := fmt.Sprintf("go test -v ./internal/suites -timeout %s -run '^(Test%sSuite)$'", timeout, suiteName)
|
||||
|
||||
log.Infof("Running tests of suite %s...", suiteName)
|
||||
log.Debugf("Running tests with command: %s", testCmdLine)
|
||||
|
|
|
@ -32,6 +32,12 @@ func main() {
|
|||
Run: setupSuite,
|
||||
}
|
||||
|
||||
setupTimeoutCmd := &cobra.Command{
|
||||
Use: "timeout [suite]",
|
||||
Short: "Run the OnSetupTimeout callback when setup times out",
|
||||
Run: setupTimeoutSuite,
|
||||
}
|
||||
|
||||
stopCmd := &cobra.Command{
|
||||
Use: "teardown [suite]",
|
||||
Short: "Teardown the suite environment",
|
||||
|
@ -39,6 +45,7 @@ func main() {
|
|||
}
|
||||
|
||||
rootCmd.AddCommand(startCmd)
|
||||
rootCmd.AddCommand(setupTimeoutCmd)
|
||||
rootCmd.AddCommand(stopCmd)
|
||||
rootCmd.Execute()
|
||||
}
|
||||
|
@ -101,6 +108,18 @@ func setupSuite(cmd *cobra.Command, args []string) {
|
|||
log.Info("Environment is ready!")
|
||||
}
|
||||
|
||||
func setupTimeoutSuite(cmd *cobra.Command, args []string) {
|
||||
suiteName := args[0]
|
||||
s := suites.GlobalRegistry.Get(suiteName)
|
||||
|
||||
if s.OnSetupTimeout == nil {
|
||||
return
|
||||
}
|
||||
if err := s.OnSetupTimeout(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func teardownSuite(cmd *cobra.Command, args []string) {
|
||||
if os.Getenv("SKIP_TEARDOWN") != "" {
|
||||
return
|
||||
|
|
|
@ -99,7 +99,6 @@ authentication_backend:
|
|||
## file:
|
||||
## path: ./users_database.yml
|
||||
|
||||
|
||||
# Access Control
|
||||
#
|
||||
# Access control is a list of rules defining the authorizations applied for one
|
||||
|
@ -156,47 +155,45 @@ access_control:
|
|||
- domain: singlefactor.example.com
|
||||
policy: one_factor
|
||||
|
||||
# Rules applied to 'admin' group
|
||||
- domain: 'mx2.mail.example.com'
|
||||
subject: 'group:admin'
|
||||
# Rules applied to 'admins' group
|
||||
- domain: "mx2.mail.example.com"
|
||||
subject: "groups:admins"
|
||||
policy: deny
|
||||
- domain: '*.example.com'
|
||||
subject: 'group:admin'
|
||||
- domain: "*.example.com"
|
||||
subject: "groups:admins"
|
||||
policy: two_factor
|
||||
|
||||
# Rules applied to 'dev' group
|
||||
- domain: dev.example.com
|
||||
resources:
|
||||
- '^/groups/dev/.*$'
|
||||
subject: 'group:dev'
|
||||
- "^/groups/dev/.*$"
|
||||
subject: "group:dev"
|
||||
policy: two_factor
|
||||
|
||||
# Rules applied to user 'john'
|
||||
- domain: dev.example.com
|
||||
resources:
|
||||
- '^/users/john/.*$'
|
||||
subject: 'user:john'
|
||||
- "^/users/john/.*$"
|
||||
subject: "user:john"
|
||||
policy: two_factor
|
||||
|
||||
|
||||
# Rules applied to user 'harry'
|
||||
- domain: dev.example.com
|
||||
resources:
|
||||
- '^/users/harry/.*$'
|
||||
subject: 'user:harry'
|
||||
- "^/users/harry/.*$"
|
||||
subject: "user:harry"
|
||||
policy: two_factor
|
||||
|
||||
# Rules applied to user 'bob'
|
||||
- domain: '*.mail.example.com'
|
||||
subject: 'user:bob'
|
||||
- domain: "*.mail.example.com"
|
||||
subject: "user:bob"
|
||||
policy: two_factor
|
||||
- domain: 'dev.example.com'
|
||||
- domain: "dev.example.com"
|
||||
resources:
|
||||
- '^/users/bob/.*$'
|
||||
subject: 'user:bob'
|
||||
- "^/users/bob/.*$"
|
||||
subject: "user:bob"
|
||||
policy: two_factor
|
||||
|
||||
|
||||
# Configuration of session cookies
|
||||
#
|
||||
# The session cookies identify the user once logged in.
|
||||
|
@ -283,7 +280,6 @@ notifier:
|
|||
host: 127.0.0.1
|
||||
port: 1025
|
||||
sender: admin@example.com
|
||||
|
||||
# Sending an email using a Gmail account is as simple as the next section.
|
||||
# You need to create an app password by following: https://support.google.com/accounts/answer/185833?hl=en
|
||||
## smtp:
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
FROM golang:1.13-stretch
|
||||
FROM golang:1.13-alpine
|
||||
|
||||
RUN apk --no-cache add gcc musl-dev
|
||||
|
||||
ARG USER_ID
|
||||
ARG GROUP_ID
|
||||
|
||||
RUN groupadd -g ${GROUP_ID} dev && \
|
||||
useradd -m -u $USER_ID -g $GROUP_ID dev
|
||||
RUN addgroup --gid ${GROUP_ID} dev && \
|
||||
adduser --uid ${USER_ID} -G dev -D dev
|
||||
USER dev
|
|
@ -1,9 +1,9 @@
|
|||
FROM node:11-stretch-slim
|
||||
FROM node:12-alpine
|
||||
|
||||
ARG USER_ID
|
||||
ARG GROUP_ID
|
||||
|
||||
RUN cat /etc/passwd && userdel -rf node && \
|
||||
groupadd -g ${GROUP_ID} dev && \
|
||||
useradd -m -u $USER_ID -g $GROUP_ID dev
|
||||
RUN deluser node && \
|
||||
addgroup --gid ${GROUP_ID} dev && \
|
||||
adduser --uid ${USER_ID} -G dev -D dev
|
||||
USER dev
|
|
@ -0,0 +1,14 @@
|
|||
version: "3"
|
||||
services:
|
||||
authelia-backend:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
volumes:
|
||||
- "/tmp/authelia:/tmp/authelia"
|
||||
environment:
|
||||
- ENVIRONMENT=dev
|
||||
restart: always
|
||||
networks:
|
||||
authelianet:
|
||||
ipv4_address: 192.168.240.50
|
|
@ -4,6 +4,9 @@ services:
|
|||
build:
|
||||
context: example/compose/authelia
|
||||
dockerfile: Dockerfile.backend
|
||||
args:
|
||||
USER_ID: ${USER_ID}
|
||||
GROUP_ID: ${GROUP_ID}
|
||||
command: /resources/entrypoint.sh
|
||||
working_dir: /app
|
||||
volumes:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
version: '3'
|
||||
version: "3"
|
||||
services:
|
||||
authelia-frontend:
|
||||
image: nginx:alpine
|
|
@ -1,10 +1,13 @@
|
|||
version: '3'
|
||||
version: "3"
|
||||
services:
|
||||
authelia-frontend:
|
||||
build:
|
||||
context: example/compose/authelia
|
||||
dockerfile: Dockerfile.frontend
|
||||
command: npm run start
|
||||
args:
|
||||
USER_ID: ${USER_ID}
|
||||
GROUP_ID: ${GROUP_ID}
|
||||
command: sh -c 'npm ci && npm run start'
|
||||
working_dir: /app
|
||||
volumes:
|
||||
- "./web:/app"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/bin/sh
|
||||
|
||||
set -x
|
||||
|
||||
|
|
|
@ -7,11 +7,11 @@ events {
|
|||
|
||||
http {
|
||||
server {
|
||||
listen 80;
|
||||
listen 3000;
|
||||
|
||||
location / {
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_pass http://authelia-backend;
|
||||
proxy_pass http://authelia-backend:9091;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,30 +1,12 @@
|
|||
#!/bin/bash
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
# Retries a command on failure.
|
||||
# $1 - the max number of attempts
|
||||
# $2... - the command to run
|
||||
|
||||
retry() {
|
||||
local -r -i max_attempts="$1"; shift
|
||||
local -r cmd="$@"
|
||||
local -i attempt_num=1
|
||||
until $cmd
|
||||
do
|
||||
if ((attempt_num==max_attempts))
|
||||
then
|
||||
echo "Attempt $attempt_num failed and there are no more attempts left!"
|
||||
return 1
|
||||
else
|
||||
echo "Attempt $attempt_num failed! Trying again in 10 seconds..."
|
||||
sleep 10
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
# Build the binary
|
||||
go build -o /tmp/authelia/authelia-tmp cmd/authelia/main.go
|
||||
|
||||
retry 3 /tmp/authelia/authelia-tmp -config /etc/authelia/configuration.yml
|
||||
while true;
|
||||
do
|
||||
/tmp/authelia/authelia-tmp -config /etc/authelia/configuration.yml
|
||||
sleep 10
|
||||
done
|
|
@ -1,4 +1,4 @@
|
|||
FROM node:8.7.0-alpine
|
||||
FROM node:12-alpine
|
||||
|
||||
WORKDIR /usr/app/src
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
version: '3'
|
||||
version: "3"
|
||||
services:
|
||||
duo-api:
|
||||
image: authelia-duo-api
|
||||
build:
|
||||
context: ./example/compose/duo-api
|
||||
networks:
|
||||
- authelianet
|
||||
|
|
|
@ -16,36 +16,40 @@ let permission = 'allow';
|
|||
|
||||
app.post('/allow', (req, res) => {
|
||||
permission = 'allow';
|
||||
console.log("set allowed!");
|
||||
res.send('ALLOWED');
|
||||
});
|
||||
|
||||
app.post('/deny', (req, res) => {
|
||||
permission = 'deny';
|
||||
console.log("set denied!");
|
||||
res.send('DENIED');
|
||||
});
|
||||
|
||||
app.post('/auth/v2/auth', (req, res) => {
|
||||
let response;
|
||||
if (permission == 'allow') {
|
||||
response = {
|
||||
response: {
|
||||
result: 'allow',
|
||||
status: 'allow',
|
||||
status_msg: 'The user allowed access.',
|
||||
},
|
||||
stat: 'OK',
|
||||
};
|
||||
} else {
|
||||
response = {
|
||||
response: {
|
||||
result: 'deny',
|
||||
status: 'deny',
|
||||
status_msg: 'The user denied access.',
|
||||
},
|
||||
stat: 'OK',
|
||||
};
|
||||
}
|
||||
setTimeout(() => res.json(response), 2000);
|
||||
setTimeout(() => {
|
||||
let response;
|
||||
if (permission == 'allow') {
|
||||
response = {
|
||||
response: {
|
||||
result: 'allow',
|
||||
status: 'allow',
|
||||
status_msg: 'The user allowed access.',
|
||||
},
|
||||
stat: 'OK',
|
||||
};
|
||||
} else {
|
||||
response = {
|
||||
response: {
|
||||
result: 'deny',
|
||||
status: 'deny',
|
||||
status_msg: 'The user denied access.',
|
||||
},
|
||||
stat: 'OK',
|
||||
};
|
||||
}
|
||||
res.json(response);
|
||||
}, 2000);
|
||||
});
|
||||
|
||||
app.listen(port, () => console.log(`Duo API listening on port ${port}!`));
|
||||
|
|
|
@ -15,8 +15,8 @@ member: cn=bob,ou=users,dc=example,dc=com
|
|||
objectclass: groupOfNames
|
||||
objectclass: top
|
||||
|
||||
dn: cn=admin,ou=groups,dc=example,dc=com
|
||||
cn: admin
|
||||
dn: cn=admins,ou=groups,dc=example,dc=com
|
||||
cn: admins
|
||||
member: cn=john,ou=users,dc=example,dc=com
|
||||
objectclass: groupOfNames
|
||||
objectclass: top
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
FROM nginx:alpine
|
||||
|
||||
ADD ./html /usr/share/nginx/html
|
||||
ADD ./nginx.conf /etc/nginx/nginx.conf
|
||||
ADD html /usr/share/nginx/html
|
||||
ADD nginx.conf /etc/nginx/nginx.conf
|
|
@ -1,10 +1,11 @@
|
|||
version: '3'
|
||||
version: "3"
|
||||
services:
|
||||
nginx-backend:
|
||||
image: authelia-example-backend
|
||||
build:
|
||||
context: example/compose/nginx/backend
|
||||
labels:
|
||||
- traefik.frontend.rule=Host:home.example.com,public.example.com,secure.example.com,admin.example.com,singlefactor.example.com
|
||||
- traefik.frontend.auth.forward.address=http://192.168.240.1:9091/api/verify?rd=https://login.example.com:8080/%23/
|
||||
- traefik.frontend.auth.forward.address=http://authelia-backend:9091/api/verify?rd=https://login.example.com:8080/
|
||||
- traefik.frontend.auth.forward.tls.insecureSkipVerify=true
|
||||
networks:
|
||||
- authelianet
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Secret</title>
|
||||
<link rel="icon" href="/icon.png" type="image/png" />
|
||||
</head>
|
||||
<body>
|
||||
This is a very important secret!<br/>
|
||||
|
||||
<head>
|
||||
<title>Secret</title>
|
||||
<link rel="icon" href="/icon.png" type="image/png" />
|
||||
</head>
|
||||
|
||||
<body id="secret">
|
||||
This is a very important secret!<br />
|
||||
Go back to <a href="https://home.example.com:8080/">home page</a>.
|
||||
</body>
|
||||
</html>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,10 +1,13 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Secret</title>
|
||||
<link rel="icon" href="/icon.png" type="image/png" />
|
||||
</head>
|
||||
<body>
|
||||
This is a very important secret!<br/>
|
||||
|
||||
<head>
|
||||
<title>Secret</title>
|
||||
<link rel="icon" href="/icon.png" type="image/png" />
|
||||
</head>
|
||||
|
||||
<body id="secret">
|
||||
This is a very important secret!<br />
|
||||
Go back to <a href="https://home.example.com:8080/">home page</a>.
|
||||
</body>
|
||||
</html>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,10 +1,13 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Secret</title>
|
||||
<link rel="icon" href="/icon.png" type="image/png" />
|
||||
</head>
|
||||
<body>
|
||||
This is a very important secret!<br/>
|
||||
|
||||
<head>
|
||||
<title>Secret</title>
|
||||
<link rel="icon" href="/icon.png" type="image/png" />
|
||||
</head>
|
||||
|
||||
<body id="secret">
|
||||
This is a very important secret!<br />
|
||||
Go back to <a href="https://home.example.com:8080/">home page</a>.
|
||||
</body>
|
||||
</html>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,10 +1,13 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Secret</title>
|
||||
<link rel="icon" href="/icon.png" type="image/png" />
|
||||
</head>
|
||||
<body>
|
||||
This is a very important secret!<br/>
|
||||
|
||||
<head>
|
||||
<title>Secret</title>
|
||||
<link rel="icon" href="/icon.png" type="image/png" />
|
||||
</head>
|
||||
|
||||
<body id="secret">
|
||||
This is a very important secret!<br />
|
||||
Go back to <a href="https://home.example.com:8080/">home page</a>.
|
||||
</body>
|
||||
</html>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,10 +1,13 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Secret</title>
|
||||
<link rel="icon" href="/icon.png" type="image/png" />
|
||||
</head>
|
||||
<body>
|
||||
This is a very important secret!<br/>
|
||||
|
||||
<head>
|
||||
<title>Secret</title>
|
||||
<link rel="icon" href="/icon.png" type="image/png" />
|
||||
</head>
|
||||
|
||||
<body id="secret">
|
||||
This is a very important secret!<br />
|
||||
Go back to <a href="https://home.example.com:8080/">home page</a>.
|
||||
</body>
|
||||
</html>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,10 +1,13 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Secret</title>
|
||||
<link rel="icon" href="/icon.png" type="image/png" />
|
||||
</head>
|
||||
<body>
|
||||
This is a very important secret!<br/>
|
||||
|
||||
<head>
|
||||
<title>Secret</title>
|
||||
<link rel="icon" href="/icon.png" type="image/png" />
|
||||
</head>
|
||||
|
||||
<body id="secret">
|
||||
This is a very important secret!<br />
|
||||
Go back to <a href="https://home.example.com:8080/">home page</a>.
|
||||
</body>
|
||||
</html>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -8,8 +8,9 @@
|
|||
|
||||
<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
|
||||
one of the following links to test access control powered by Authelia.<br/>
|
||||
<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
|
||||
one of the following links to test access control powered by Authelia.<br />
|
||||
<ul>
|
||||
<li>
|
||||
public.example.com <a href="https://public.example.com:8080/"> /</a>
|
||||
|
@ -59,12 +60,15 @@
|
|||
</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>.
|
||||
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 to test access control.<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 in a <strong>fake webmail</strong> at <a href="http://localhost:8085">http://localhost:8085</a>.<br/>
|
||||
Here is the list of credentials you can log in with to test access control.<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 in a <strong>fake webmail</strong> at <a
|
||||
href="http://localhost:8085">http://localhost:8085</a>.<br />
|
||||
It will provide you with the link to complete the registration allowing you to authenticate with 2-factor.
|
||||
|
||||
<ul>
|
||||
|
@ -86,12 +90,12 @@
|
|||
- domain: singlefactor.example.com
|
||||
policy: one_factor
|
||||
|
||||
# Rules applied to 'admin' group
|
||||
# Rules applied to 'admins' group
|
||||
- domain: 'mx2.mail.example.com'
|
||||
subject: 'group:admin'
|
||||
subject: 'groups:admins'
|
||||
policy: deny
|
||||
- domain: '*.example.com'
|
||||
subject: 'group:admin'
|
||||
subject: 'groups:admins'
|
||||
policy: two_factor
|
||||
|
||||
# Rules applied to 'dev' group
|
||||
|
@ -128,4 +132,4 @@
|
|||
</pre>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
|
@ -1,10 +1,13 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Secret</title>
|
||||
<link rel="icon" href="/icon.png" type="image/png" />
|
||||
</head>
|
||||
<body>
|
||||
This is a very important secret!<br/>
|
||||
|
||||
<head>
|
||||
<title>Secret</title>
|
||||
<link rel="icon" href="/icon.png" type="image/png" />
|
||||
</head>
|
||||
|
||||
<body id="secret">
|
||||
This is a very important secret!<br />
|
||||
Go back to <a href="https://home.example.com:8080/">home page</a>.
|
||||
</body>
|
||||
</html>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,10 +1,13 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Secret</title>
|
||||
<link rel="icon" href="/icon.png" type="image/png" />
|
||||
</head>
|
||||
<body>
|
||||
This is a very important secret!<br/>
|
||||
|
||||
<head>
|
||||
<title>Secret</title>
|
||||
<link rel="icon" href="/icon.png" type="image/png" />
|
||||
</head>
|
||||
|
||||
<body id="secret">
|
||||
This is a very important secret!<br />
|
||||
Go back to <a href="https://home.example.com:8080/">home page</a>.
|
||||
</body>
|
||||
</html>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,10 +1,13 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Secret</title>
|
||||
<link rel="icon" href="/icon.png" type="image/png" />
|
||||
</head>
|
||||
<body>
|
||||
This is a very important secret!<br/>
|
||||
|
||||
<head>
|
||||
<title>Secret</title>
|
||||
<link rel="icon" href="/icon.png" type="image/png" />
|
||||
</head>
|
||||
|
||||
<body id="secret">
|
||||
This is a very important secret!<br />
|
||||
Go back to <a href="https://home.example.com:8080/">home page</a>.
|
||||
</body>
|
||||
</html>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -1,10 +1,13 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Secret</title>
|
||||
<link rel="icon" href="/icon.png" type="image/png" />
|
||||
</head>
|
||||
<body>
|
||||
This is a very important secret!<br/>
|
||||
|
||||
<head>
|
||||
<title>Secret</title>
|
||||
<link rel="icon" href="/icon.png" type="image/png" />
|
||||
</head>
|
||||
|
||||
<body id="secret">
|
||||
This is a very important secret!<br />
|
||||
Go back to <a href="https://home.example.com:8080/">home page</a>.
|
||||
</body>
|
||||
</html>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -17,12 +17,11 @@ spec:
|
|||
app: test-app
|
||||
spec:
|
||||
containers:
|
||||
- name: test-app
|
||||
imagePullPolicy: Never
|
||||
image: authelia-example-backend
|
||||
ports:
|
||||
- containerPort: 80
|
||||
|
||||
- name: test-app
|
||||
imagePullPolicy: Never
|
||||
image: nginx-backend
|
||||
ports:
|
||||
- containerPort: 80
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
|
@ -53,17 +52,17 @@ metadata:
|
|||
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
|
||||
spec:
|
||||
tls:
|
||||
- secretName: test-app-tls
|
||||
hosts:
|
||||
- home.example.com
|
||||
- secretName: test-app-tls
|
||||
hosts:
|
||||
- home.example.com
|
||||
rules:
|
||||
- host: home.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
backend:
|
||||
serviceName: test-app-service
|
||||
servicePort: 80
|
||||
- host: home.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
backend:
|
||||
serviceName: test-app-service
|
||||
servicePort: 80
|
||||
|
||||
---
|
||||
apiVersion: extensions/v1beta1
|
||||
|
@ -79,55 +78,54 @@ metadata:
|
|||
nginx.ingress.kubernetes.io/auth-signin: "https://login.example.com:8080/#/"
|
||||
spec:
|
||||
tls:
|
||||
- secretName: test-app-tls
|
||||
hosts:
|
||||
- public.example.com
|
||||
- admin.example.com
|
||||
- dev.example.com
|
||||
- mx1.mail.example.com
|
||||
- mx2.mail.example.com
|
||||
- singlefactor.example.com
|
||||
- secretName: test-app-tls
|
||||
hosts:
|
||||
- public.example.com
|
||||
- admin.example.com
|
||||
- dev.example.com
|
||||
- mx1.mail.example.com
|
||||
- mx2.mail.example.com
|
||||
- singlefactor.example.com
|
||||
rules:
|
||||
- host: public.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
backend:
|
||||
serviceName: test-app-service
|
||||
servicePort: 80
|
||||
- host: admin.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
backend:
|
||||
serviceName: test-app-service
|
||||
servicePort: 80
|
||||
- host: dev.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
backend:
|
||||
serviceName: test-app-service
|
||||
servicePort: 80
|
||||
- host: mx1.mail.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
backend:
|
||||
serviceName: test-app-service
|
||||
servicePort: 80
|
||||
- host: mx2.mail.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
backend:
|
||||
serviceName: test-app-service
|
||||
servicePort: 80
|
||||
- host: singlefactor.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
backend:
|
||||
serviceName: test-app-service
|
||||
servicePort: 80
|
||||
|
||||
- host: public.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
backend:
|
||||
serviceName: test-app-service
|
||||
servicePort: 80
|
||||
- host: admin.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
backend:
|
||||
serviceName: test-app-service
|
||||
servicePort: 80
|
||||
- host: dev.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
backend:
|
||||
serviceName: test-app-service
|
||||
servicePort: 80
|
||||
- host: mx1.mail.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
backend:
|
||||
serviceName: test-app-service
|
||||
servicePort: 80
|
||||
- host: mx2.mail.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
backend:
|
||||
serviceName: test-app-service
|
||||
servicePort: 80
|
||||
- host: singlefactor.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
backend:
|
||||
serviceName: test-app-service
|
||||
servicePort: 80
|
||||
|
|
|
@ -10,7 +10,7 @@ default_redirection_url: https://home.example.com:8080
|
|||
|
||||
authentication_backend:
|
||||
ldap:
|
||||
url: ldap-service:389
|
||||
url: ldap-service:389
|
||||
base_dn: dc=example,dc=com
|
||||
additional_users_dn: ou=users
|
||||
users_filter: (cn={0})
|
||||
|
@ -33,47 +33,45 @@ access_control:
|
|||
- domain: singlefactor.example.com
|
||||
policy: one_factor
|
||||
|
||||
# Rules applied to 'admin' group
|
||||
- domain: 'mx2.mail.example.com'
|
||||
subject: 'group:admin'
|
||||
# Rules applied to 'admins' group
|
||||
- domain: "mx2.mail.example.com"
|
||||
subject: "group:admins"
|
||||
policy: deny
|
||||
- domain: '*.example.com'
|
||||
subject: 'group:admin'
|
||||
- domain: "*.example.com"
|
||||
subject: "group:admins"
|
||||
policy: two_factor
|
||||
|
||||
# Rules applied to 'dev' group
|
||||
- domain: dev.example.com
|
||||
resources:
|
||||
- '^/groups/dev/.*$'
|
||||
subject: 'group:dev'
|
||||
- "^/groups/dev/.*$"
|
||||
subject: "group:dev"
|
||||
policy: two_factor
|
||||
|
||||
# Rules applied to user 'john'
|
||||
- domain: dev.example.com
|
||||
resources:
|
||||
- '^/users/john/.*$'
|
||||
subject: 'user:john'
|
||||
- "^/users/john/.*$"
|
||||
subject: "user:john"
|
||||
policy: two_factor
|
||||
|
||||
|
||||
# Rules applied to user 'harry'
|
||||
- domain: dev.example.com
|
||||
resources:
|
||||
- '^/users/harry/.*$'
|
||||
subject: 'user:harry'
|
||||
- "^/users/harry/.*$"
|
||||
subject: "user:harry"
|
||||
policy: two_factor
|
||||
|
||||
# Rules applied to user 'bob'
|
||||
- domain: '*.mail.example.com'
|
||||
subject: 'user:bob'
|
||||
- domain: "*.mail.example.com"
|
||||
subject: "user:bob"
|
||||
policy: two_factor
|
||||
- domain: 'dev.example.com'
|
||||
- domain: "dev.example.com"
|
||||
resources:
|
||||
- '^/users/bob/.*$'
|
||||
subject: 'user:bob'
|
||||
- "^/users/bob/.*$"
|
||||
subject: "user:bob"
|
||||
policy: two_factor
|
||||
|
||||
|
||||
session:
|
||||
secret: unsecure_password
|
||||
expiration: 3600000 # 1 hour
|
||||
|
@ -98,6 +96,6 @@ storage:
|
|||
|
||||
notifier:
|
||||
smtp:
|
||||
host: 'mailcatcher-service'
|
||||
host: "mailcatcher-service"
|
||||
port: 1025
|
||||
sender: admin@example.com
|
|
@ -17,17 +17,17 @@ spec:
|
|||
app: authelia
|
||||
spec:
|
||||
containers:
|
||||
- name: authelia
|
||||
image: authelia:dist
|
||||
ports:
|
||||
- containerPort: 80
|
||||
volumeMounts:
|
||||
- name: config-volume
|
||||
mountPath: /etc/authelia
|
||||
- name: authelia
|
||||
image: authelia:dist
|
||||
ports:
|
||||
- containerPort: 80
|
||||
volumeMounts:
|
||||
- name: config-volume
|
||||
mountPath: /etc/authelia
|
||||
volumes:
|
||||
- name: config-volume
|
||||
configMap:
|
||||
name: authelia-config
|
||||
items:
|
||||
- key: config.yml
|
||||
path: config.yml
|
||||
- name: config-volume
|
||||
configMap:
|
||||
name: authelia-config
|
||||
items:
|
||||
- key: configuration.yml
|
||||
path: configuration.yml
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/bin/sh
|
||||
|
||||
start_authelia() {
|
||||
kubectl create configmap authelia-config --namespace=authelia --from-file=authelia/configs/config.yml
|
||||
kubectl create configmap authelia-config --namespace=authelia --from-file=authelia/configs/configuration.yml
|
||||
kubectl apply -f authelia
|
||||
}
|
||||
|
||||
|
|
|
@ -15,8 +15,8 @@ member: cn=bob,ou=users,dc=example,dc=com
|
|||
objectclass: groupOfNames
|
||||
objectclass: top
|
||||
|
||||
dn: cn=admin,ou=groups,dc=example,dc=com
|
||||
cn: admin
|
||||
dn: cn=admins,ou=groups,dc=example,dc=com
|
||||
cn: admins
|
||||
member: cn=john,ou=users,dc=example,dc=com
|
||||
objectclass: groupOfNames
|
||||
objectclass: top
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
version: '3.4'
|
||||
version: "3.4"
|
||||
services:
|
||||
authelia:
|
||||
image: clems4ever/authelia:latest
|
||||
# Used for Docker configs
|
||||
configs:
|
||||
- source: authelia
|
||||
target: /etc/authelia/config.yml
|
||||
uid: '0'
|
||||
gid: '0'
|
||||
target: /etc/authelia/configuration.yml
|
||||
uid: "0"
|
||||
gid: "0"
|
||||
mode: 0444
|
||||
environment:
|
||||
- NODE_TLS_REJECT_UNAUTHORIZED=0
|
||||
|
|
1
go.mod
1
go.mod
|
@ -7,6 +7,7 @@ require (
|
|||
github.com/Workiva/go-datastructures v1.0.50
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a
|
||||
github.com/cespare/reflex v0.2.0 // indirect
|
||||
github.com/deckarep/golang-set v1.7.1
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/duosecurity/duo_api_golang v0.0.0-20190308151101-6c680f768e74
|
||||
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect
|
||||
|
|
2
go.sum
2
go.sum
|
@ -33,6 +33,8 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do
|
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ=
|
||||
github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/duosecurity/duo_api_golang v0.0.0-20190308151101-6c680f768e74 h1:2MIhn2R6oXQbgW5yHfS+d6YqyMfXiu2L55rFZC4UD/M=
|
||||
|
|
|
@ -128,7 +128,7 @@ users
|
|||
john
|
||||
email: john.doe@authelia.com
|
||||
groups:
|
||||
- admin
|
||||
- admins
|
||||
- dev
|
||||
`)
|
||||
|
||||
|
|
|
@ -48,44 +48,43 @@ access_control:
|
|||
- domain: singlefactor.example.com
|
||||
policy: one_factor
|
||||
|
||||
# Rules applied to 'admin' group
|
||||
- domain: 'mx2.mail.example.com'
|
||||
subject: 'group:admin'
|
||||
# Rules applied to 'admins' group
|
||||
- domain: "mx2.mail.example.com"
|
||||
subject: "groups:admins"
|
||||
policy: deny
|
||||
- domain: '*.example.com'
|
||||
subject: 'group:admin'
|
||||
- domain: "*.example.com"
|
||||
subject: "groups:admins"
|
||||
policy: two_factor
|
||||
|
||||
# Rules applied to 'dev' group
|
||||
- domain: dev.example.com
|
||||
resources:
|
||||
- '^/groups/dev/.*$'
|
||||
subject: 'group:dev'
|
||||
- "^/groups/dev/.*$"
|
||||
subject: "group:dev"
|
||||
policy: two_factor
|
||||
|
||||
# Rules applied to user 'john'
|
||||
- domain: dev.example.com
|
||||
resources:
|
||||
- '^/users/john/.*$'
|
||||
subject: 'user:john'
|
||||
- "^/users/john/.*$"
|
||||
subject: "user:john"
|
||||
policy: two_factor
|
||||
|
||||
|
||||
# Rules applied to user 'harry'
|
||||
- domain: dev.example.com
|
||||
resources:
|
||||
- '^/users/harry/.*$'
|
||||
subject: 'user:harry'
|
||||
- "^/users/harry/.*$"
|
||||
subject: "user:harry"
|
||||
policy: two_factor
|
||||
|
||||
# Rules applied to user 'bob'
|
||||
- domain: '*.mail.example.com'
|
||||
subject: 'user:bob'
|
||||
- domain: "*.mail.example.com"
|
||||
subject: "user:bob"
|
||||
policy: two_factor
|
||||
- domain: 'dev.example.com'
|
||||
- domain: "dev.example.com"
|
||||
resources:
|
||||
- '^/users/bob/.*$'
|
||||
subject: 'user:bob'
|
||||
- "^/users/bob/.*$"
|
||||
subject: "user:bob"
|
||||
policy: two_factor
|
||||
|
||||
session:
|
||||
|
|
|
@ -24,10 +24,11 @@ func FirstFactorPost(ctx *middlewares.AutheliaCtx) {
|
|||
|
||||
bannedUntil, err := ctx.Providers.Regulator.Regulate(bodyJSON.Username)
|
||||
|
||||
if err == regulation.ErrUserIsBanned {
|
||||
ctx.Error(fmt.Errorf("User %s is banned until %s", bodyJSON.Username, bannedUntil), userBannedMessage)
|
||||
return
|
||||
} else if err != nil {
|
||||
if err != nil {
|
||||
if err == regulation.ErrUserIsBanned {
|
||||
ctx.Error(fmt.Errorf("User %s is banned until %s", bodyJSON.Username, bannedUntil), userBannedMessage)
|
||||
return
|
||||
}
|
||||
ctx.Error(fmt.Errorf("Unable to regulate authentication: %s", err), authenticationFailedMessage)
|
||||
return
|
||||
}
|
||||
|
@ -43,6 +44,9 @@ func FirstFactorPost(ctx *middlewares.AutheliaCtx) {
|
|||
}
|
||||
|
||||
if !userPasswordOk {
|
||||
ctx.Logger.Debugf("Mark authentication attempt made by user %s", bodyJSON.Username)
|
||||
ctx.Providers.Regulator.Mark(bodyJSON.Username, false)
|
||||
|
||||
ctx.ReplyError(fmt.Errorf("Credentials are wrong for user %s", bodyJSON.Username), authenticationFailedMessage)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -162,7 +162,7 @@ func (s *FirstFactorSuite) TestShouldAuthenticateUser() {
|
|||
GetDetails(gomock.Eq("test")).
|
||||
Return(&authentication.UserDetails{
|
||||
Emails: []string{"test@example.com"},
|
||||
Groups: []string{"dev", "admin"},
|
||||
Groups: []string{"dev", "admins"},
|
||||
}, nil)
|
||||
|
||||
s.mock.StorageProviderMock.
|
||||
|
@ -186,7 +186,7 @@ func (s *FirstFactorSuite) TestShouldAuthenticateUser() {
|
|||
assert.Equal(s.T(), "test", session.Username)
|
||||
assert.Equal(s.T(), authentication.OneFactor, session.AuthenticationLevel)
|
||||
assert.Equal(s.T(), []string{"test@example.com"}, session.Emails)
|
||||
assert.Equal(s.T(), []string{"dev", "admin"}, session.Groups)
|
||||
assert.Equal(s.T(), []string{"dev", "admins"}, session.Groups)
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -208,7 +208,7 @@ func (s *BasicAuthorizationSuite) TestShouldApplyDefaultPolicy() {
|
|||
GetDetails(gomock.Eq("john")).
|
||||
Return(&authentication.UserDetails{
|
||||
Emails: []string{"john@example.com"},
|
||||
Groups: []string{"dev", "admin"},
|
||||
Groups: []string{"dev", "admins"},
|
||||
}, nil)
|
||||
|
||||
VerifyGet(mock.Ctx)
|
||||
|
@ -231,7 +231,7 @@ func (s *BasicAuthorizationSuite) TestShouldApplyPolicyOfBypassDomain() {
|
|||
GetDetails(gomock.Eq("john")).
|
||||
Return(&authentication.UserDetails{
|
||||
Emails: []string{"john@example.com"},
|
||||
Groups: []string{"dev", "admin"},
|
||||
Groups: []string{"dev", "admins"},
|
||||
}, nil)
|
||||
|
||||
VerifyGet(mock.Ctx)
|
||||
|
@ -254,7 +254,7 @@ func (s *BasicAuthorizationSuite) TestShouldApplyPolicyOfOneFactorDomain() {
|
|||
GetDetails(gomock.Eq("john")).
|
||||
Return(&authentication.UserDetails{
|
||||
Emails: []string{"john@example.com"},
|
||||
Groups: []string{"dev", "admin"},
|
||||
Groups: []string{"dev", "admins"},
|
||||
}, nil)
|
||||
|
||||
VerifyGet(mock.Ctx)
|
||||
|
@ -277,7 +277,7 @@ func (s *BasicAuthorizationSuite) TestShouldApplyPolicyOfTwoFactorDomain() {
|
|||
GetDetails(gomock.Eq("john")).
|
||||
Return(&authentication.UserDetails{
|
||||
Emails: []string{"john@example.com"},
|
||||
Groups: []string{"dev", "admin"},
|
||||
Groups: []string{"dev", "admins"},
|
||||
}, nil)
|
||||
|
||||
VerifyGet(mock.Ctx)
|
||||
|
@ -300,7 +300,7 @@ func (s *BasicAuthorizationSuite) TestShouldApplyPolicyOfDenyDomain() {
|
|||
GetDetails(gomock.Eq("john")).
|
||||
Return(&authentication.UserDetails{
|
||||
Emails: []string{"john@example.com"},
|
||||
Groups: []string{"dev", "admin"},
|
||||
Groups: []string{"dev", "admins"},
|
||||
}, nil)
|
||||
|
||||
VerifyGet(mock.Ctx)
|
||||
|
|
|
@ -3,6 +3,7 @@ package server
|
|||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/clems4ever/authelia/internal/configuration/schema"
|
||||
"github.com/clems4ever/authelia/internal/duo"
|
||||
|
@ -27,7 +28,6 @@ func StartServer(configuration schema.Configuration, providers middlewares.Provi
|
|||
fmt.Println("Selected public_html directory is ", publicDir)
|
||||
|
||||
router.GET("/", fasthttp.FSHandler(publicDir, 0))
|
||||
router.NotFound = fasthttp.FSHandler(publicDir, 0)
|
||||
router.ServeFiles("/static/*filepath", publicDir+"/static")
|
||||
|
||||
router.GET("/api/state", autheliaMiddleware(handlers.StateGet))
|
||||
|
@ -95,6 +95,10 @@ func StartServer(configuration schema.Configuration, providers middlewares.Provi
|
|||
middlewares.RequireFirstFactor(handlers.SecondFactorDuoPost(duoAPI))))
|
||||
}
|
||||
|
||||
router.NotFound = func(ctx *fasthttp.RequestCtx) {
|
||||
ctx.SendFile(path.Join(publicDir, "index.html"))
|
||||
}
|
||||
|
||||
portPattern := fmt.Sprintf(":%d", configuration.Port)
|
||||
logging.Logger().Infof("Authelia is listening on %s", portPattern)
|
||||
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
###############################################################
|
||||
# Authelia minimal configuration #
|
||||
###############################################################
|
||||
|
||||
port: 9091
|
||||
|
||||
logs_level: debug
|
||||
|
||||
default_redirection_url: https://home.example.com:8080/
|
||||
|
||||
jwt_secret: very_important_secret
|
||||
|
||||
authentication_backend:
|
||||
file:
|
||||
path: /var/lib/authelia/users.yml
|
||||
|
||||
session:
|
||||
secret: unsecure_session_secret
|
||||
domain: example.com
|
||||
expiration: 3600 # 1 hour
|
||||
inactivity: 300 # 5 minutes
|
||||
|
||||
storage:
|
||||
local:
|
||||
path: /tmp/authelia/db.sqlite3
|
||||
|
||||
totp:
|
||||
issuer: example.com
|
||||
|
||||
access_control:
|
||||
default_policy: deny
|
||||
|
||||
rules:
|
||||
- domain: singlefactor.example.com
|
||||
policy: one_factor
|
||||
|
||||
- domain: public.example.com
|
||||
policy: bypass
|
||||
|
||||
- domain: secure.example.com
|
||||
policy: two_factor
|
||||
|
||||
- domain: "*.example.com"
|
||||
subject: "group:admins"
|
||||
policy: two_factor
|
||||
|
||||
- domain: dev.example.com
|
||||
resources:
|
||||
- "^/users/john/.*$"
|
||||
subject: "user:john"
|
||||
policy: two_factor
|
||||
|
||||
- domain: dev.example.com
|
||||
resources:
|
||||
- "^/users/harry/.*$"
|
||||
subject: "user:harry"
|
||||
policy: two_factor
|
||||
|
||||
- domain: "*.mail.example.com"
|
||||
subject: "user:bob"
|
||||
policy: two_factor
|
||||
|
||||
- domain: dev.example.com
|
||||
resources:
|
||||
- "^/users/bob/.*$"
|
||||
subject: "user:bob"
|
||||
policy: two_factor
|
||||
|
||||
regulation:
|
||||
# Set it to 0 to disable max_retries.
|
||||
max_retries: 3
|
||||
# The user is banned if the authenticaction failed `max_retries` times in a `find_time` seconds window.
|
||||
find_time: 300
|
||||
# The length of time before a banned user can login again.
|
||||
ban_time: 900
|
||||
|
||||
notifier:
|
||||
smtp:
|
||||
host: smtp
|
||||
port: 1025
|
||||
sender: admin@example.com
|
|
@ -0,0 +1,6 @@
|
|||
version: "3"
|
||||
services:
|
||||
authelia-backend:
|
||||
volumes:
|
||||
- "./internal/suites/Docker/configuration.yml:/etc/authelia/configuration.yml:ro"
|
||||
- "./internal/suites/Docker/users.yml:/var/lib/authelia/users.yml"
|
|
@ -0,0 +1,20 @@
|
|||
users:
|
||||
bob:
|
||||
password: "{CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/"
|
||||
email: bob.dylan@authelia.com
|
||||
groups:
|
||||
- dev
|
||||
harry:
|
||||
password: "{CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/"
|
||||
email: harry.potter@authelia.com
|
||||
groups: []
|
||||
james:
|
||||
password: "{CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/"
|
||||
email: james.dean@authelia.com
|
||||
groups: []
|
||||
john:
|
||||
password: "{CRYPT}$6$rounds=50000$LnfgDsc2WD8F2qNf$0gcCt8jlqAGZRv2ee3mCFsfAr1P4N7kESWEf36Xtw6OjkhAcQuGVOBHXp0lFuZbppa7YlgHk3VD28aSQu9U9S1"
|
||||
email: john.doe@authelia.com
|
||||
groups:
|
||||
- admins
|
||||
- dev
|
|
@ -136,9 +136,9 @@ access_control:
|
|||
- domain: singlefactor.example.com
|
||||
policy: one_factor
|
||||
|
||||
# Rules applied to 'admin' group
|
||||
# Rules applied to 'admins' group
|
||||
- domain: mx2.mail.example.com
|
||||
subject: "group:admin"
|
||||
subject: "group:admins"
|
||||
policy: deny
|
||||
|
||||
# Rules applied to user 'john'
|
||||
|
@ -147,7 +147,7 @@ access_control:
|
|||
policy: two_factor
|
||||
|
||||
- domain: "*.example.com"
|
||||
subject: "group:admin"
|
||||
subject: "group:admins"
|
||||
policy: two_factor
|
||||
|
||||
# Rules applied to 'dev' group
|
||||
|
@ -225,7 +225,7 @@ storage:
|
|||
# Settings to connect to mariadb server
|
||||
mysql:
|
||||
host: mariadb
|
||||
port: 3306
|
||||
port: 3306
|
||||
database: authelia
|
||||
username: admin
|
||||
password: password
|
||||
|
|
|
@ -3,3 +3,4 @@ services:
|
|||
authelia-backend:
|
||||
volumes:
|
||||
- "./internal/suites/Mariadb/configuration.yml:/etc/authelia/configuration.yml:ro"
|
||||
- "./internal/suites/Mariadb/users.yml:/var/lib/authelia/users.yml"
|
||||
|
|
|
@ -10,7 +10,7 @@ jwt_secret: unsecure_password
|
|||
|
||||
authentication_backend:
|
||||
file:
|
||||
path: users.yml
|
||||
path: /var/lib/authelia/users.yml
|
||||
|
||||
session:
|
||||
secret: unsecure_session_secret
|
||||
|
|
|
@ -4,27 +4,27 @@ import (
|
|||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func (wds *WebDriverSession) doFillLoginPageAndClick(ctx context.Context, t *testing.T, username, password string, keepMeLoggedIn bool) {
|
||||
usernameElement := wds.WaitElementLocatedByID(ctx, t, "username-textfield")
|
||||
err := usernameElement.SendKeys(username)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
passwordElement := wds.WaitElementLocatedByID(ctx, t, "password-textfield")
|
||||
err = passwordElement.SendKeys(password)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
if keepMeLoggedIn {
|
||||
keepMeLoggedInElement := wds.WaitElementLocatedByID(ctx, t, "remember-checkbox")
|
||||
err = keepMeLoggedInElement.Click()
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
buttonElement := wds.WaitElementLocatedByID(ctx, t, "sign-in-button")
|
||||
err = buttonElement.Click()
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
// Login 1FA
|
||||
|
|
|
@ -33,7 +33,7 @@ func (de *DockerEnvironment) createCommand(cmd string) *exec.Cmd {
|
|||
|
||||
// Up spawn a docker environment
|
||||
func (de *DockerEnvironment) Up() error {
|
||||
return de.createCommandWithStdout("up -d").Run()
|
||||
return de.createCommandWithStdout("up --build -d").Run()
|
||||
}
|
||||
|
||||
// Restart restarts a service
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// DuoPolicy a type of policy
|
||||
|
@ -26,10 +26,10 @@ func ConfigureDuo(t *testing.T, allowDeny DuoPolicy) {
|
|||
}
|
||||
|
||||
req, err := http.NewRequest("POST", url, nil)
|
||||
assert.NoError(t, err)
|
||||
require.NoError(t, err)
|
||||
|
||||
client := NewHTTPClient()
|
||||
res, err := client.Do(req)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 200, res.StatusCode)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 200, res.StatusCode)
|
||||
}
|
||||
|
|
|
@ -35,31 +35,34 @@ func waitUntilServiceLogDetected(
|
|||
return err
|
||||
}
|
||||
|
||||
func waitUntilAutheliaIsReady(dockerEnvironment *DockerEnvironment) error {
|
||||
log.Info("Waiting for Authelia to be ready...")
|
||||
|
||||
err := waitUntilServiceLogDetected(
|
||||
func waitUntilAutheliaBackendIsReady(dockerEnvironment *DockerEnvironment) error {
|
||||
return waitUntilServiceLogDetected(
|
||||
5*time.Second,
|
||||
90*time.Second,
|
||||
dockerEnvironment,
|
||||
"authelia-backend",
|
||||
[]string{"Authelia is listening on"})
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = waitUntilServiceLogDetected(
|
||||
func waitUntilAutheliaFrontendIsReady(dockerEnvironment *DockerEnvironment) error {
|
||||
return waitUntilServiceLogDetected(
|
||||
5*time.Second,
|
||||
90*time.Second,
|
||||
dockerEnvironment,
|
||||
"authelia-frontend",
|
||||
[]string{"You can now view web in the browser.", "Compiled with warnings", "Compiled successfully!"})
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
func waitUntilAutheliaIsReady(dockerEnvironment *DockerEnvironment) error {
|
||||
log.Info("Waiting for Authelia to be ready...")
|
||||
|
||||
if err := waitUntilAutheliaBackendIsReady(dockerEnvironment); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := waitUntilAutheliaFrontendIsReady(dockerEnvironment); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Info("Authelia is now ready!")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -9,9 +9,12 @@ import (
|
|||
|
||||
// Suite the definition of a suite
|
||||
type Suite struct {
|
||||
TestTimeout time.Duration
|
||||
SetUp func(tmpPath string) error
|
||||
SetUpTimeout time.Duration
|
||||
SetUp func(tmpPath string) error
|
||||
SetUpTimeout time.Duration
|
||||
OnSetupTimeout func() error
|
||||
|
||||
TestTimeout time.Duration
|
||||
|
||||
TearDown func(tmpPath string) error
|
||||
TearDownTimeout time.Duration
|
||||
|
||||
|
|
|
@ -2,11 +2,15 @@ package suites
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
mapset "github.com/deckarep/golang-set"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"github.com/tebeka/selenium"
|
||||
)
|
||||
|
@ -59,18 +63,55 @@ func (s *CustomHeadersScenario) TestShouldNotForwardCustomHeaderForUnauthenticat
|
|||
s.WaitElementTextContains(ctx, s.T(), body, "httpbin:8000")
|
||||
}
|
||||
|
||||
type Headers struct {
|
||||
ForwardedGroups string `json:"Custom-Forwarded-Groups"`
|
||||
ForwardedUser string `json:"Custom-Forwarded-User"`
|
||||
}
|
||||
|
||||
type HeadersPayload struct {
|
||||
Headers Headers `json:"headers"`
|
||||
}
|
||||
|
||||
func (s *CustomHeadersScenario) TestShouldForwardCustomHeaderForAuthenticatedUser() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
|
||||
defer cancel()
|
||||
|
||||
expectedGroups := mapset.NewSetWith("dev", "admins")
|
||||
|
||||
targetURL := fmt.Sprintf("%s/headers", PublicBaseURL)
|
||||
s.doLoginOneFactor(ctx, s.T(), "john", "password", false, targetURL)
|
||||
s.verifyURLIs(ctx, s.T(), targetURL)
|
||||
|
||||
body, err := s.WebDriver().FindElement(selenium.ByTagName, "body")
|
||||
s.Assert().NoError(err)
|
||||
s.WaitElementTextContains(ctx, s.T(), body, "\"Custom-Forwarded-User\": \"john\"")
|
||||
s.WaitElementTextContains(ctx, s.T(), body, "\"Custom-Forwarded-Groups\": \"admins,dev\"")
|
||||
err := s.Wait(ctx, func(d selenium.WebDriver) (bool, error) {
|
||||
body, err := s.WebDriver().FindElement(selenium.ByTagName, "body")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if body == nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
content, err := body.Text()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
payload := HeadersPayload{}
|
||||
if err := json.Unmarshal([]byte(content), &payload); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
groups := strings.Split(payload.Headers.ForwardedGroups, ",")
|
||||
actualGroups := mapset.NewSet()
|
||||
for _, group := range groups {
|
||||
actualGroups.Add(group)
|
||||
}
|
||||
|
||||
return strings.Contains(payload.Headers.ForwardedUser, "john") && expectedGroups.Equal(actualGroups), nil
|
||||
})
|
||||
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
|
||||
func TestCustomHeadersScenario(t *testing.T) {
|
||||
|
|
|
@ -57,7 +57,7 @@ func (s *RegulationScenario) TestShouldBanUserAfterTooManyAttempt() {
|
|||
|
||||
for i := 0; i < 3; i++ {
|
||||
s.WaitElementLocatedByID(ctx, s.T(), "sign-in-button").Click()
|
||||
time.Sleep(2 * time.Second)
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
|
||||
// Reset password field
|
||||
|
|
|
@ -47,7 +47,7 @@ func (s *UserPreferencesScenario) SetupTest() {
|
|||
}
|
||||
|
||||
func (s *UserPreferencesScenario) TestShouldRememberLastUsed2FAMethod() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
defer cancel()
|
||||
|
||||
// Authenticate
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package suites
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -24,7 +25,22 @@ func init() {
|
|||
return err
|
||||
}
|
||||
|
||||
return waitUntilAutheliaIsReady(dockerEnvironment)
|
||||
return waitUntilAutheliaBackendIsReady(dockerEnvironment)
|
||||
}
|
||||
|
||||
onSetupTimeout := func() error {
|
||||
backendLogs, err := dockerEnvironment.Logs("authelia-backend", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(backendLogs)
|
||||
|
||||
frontendLogs, err := dockerEnvironment.Logs("authelia-frontend", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(frontendLogs)
|
||||
return nil
|
||||
}
|
||||
|
||||
teardown := func(suitePath string) error {
|
||||
|
@ -34,6 +50,7 @@ func init() {
|
|||
GlobalRegistry.Register(bypassAllSuiteName, Suite{
|
||||
SetUp: setup,
|
||||
SetUpTimeout: 5 * time.Minute,
|
||||
OnSetupTimeout: onSetupTimeout,
|
||||
TestTimeout: 1 * time.Minute,
|
||||
TearDown: teardown,
|
||||
TearDownTimeout: 2 * time.Minute,
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
package suites
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
dockerEnvironment := NewDockerEnvironment([]string{
|
||||
"docker-compose.yml",
|
||||
"internal/suites/Docker/docker-compose.yml",
|
||||
"example/compose/authelia/docker-compose.backend-dist.yml",
|
||||
"example/compose/authelia/docker-compose.frontend-dist.yml",
|
||||
"example/compose/nginx/backend/docker-compose.yml",
|
||||
"example/compose/nginx/portal/docker-compose.yml",
|
||||
"example/compose/smtp/docker-compose.yml",
|
||||
})
|
||||
|
||||
setup := func(suitePath string) error {
|
||||
if err := dockerEnvironment.Up(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return waitUntilAutheliaBackendIsReady(dockerEnvironment)
|
||||
}
|
||||
|
||||
onSetupTimeout := func() error {
|
||||
backendLogs, err := dockerEnvironment.Logs("authelia-backend", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(backendLogs)
|
||||
|
||||
frontendLogs, err := dockerEnvironment.Logs("authelia-frontend", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(frontendLogs)
|
||||
return nil
|
||||
}
|
||||
|
||||
teardown := func(suitePath string) error {
|
||||
return dockerEnvironment.Down()
|
||||
}
|
||||
|
||||
GlobalRegistry.Register("Docker", Suite{
|
||||
SetUp: setup,
|
||||
SetUpTimeout: 5 * time.Minute,
|
||||
OnSetupTimeout: onSetupTimeout,
|
||||
TestTimeout: 1 * time.Minute,
|
||||
TearDown: teardown,
|
||||
TearDownTimeout: 2 * time.Minute,
|
||||
|
||||
Description: `This suite has been created to test the distributable version of Authelia
|
||||
It's often useful to test this one before the Kube one.`,
|
||||
})
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package suites
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
type DockerSuite struct {
|
||||
*SeleniumSuite
|
||||
}
|
||||
|
||||
func NewDockerSuite() *DockerSuite {
|
||||
return &DockerSuite{SeleniumSuite: new(SeleniumSuite)}
|
||||
}
|
||||
|
||||
func TestDockerSuite(t *testing.T) {
|
||||
suite.Run(t, NewOneFactorScenario())
|
||||
suite.Run(t, NewTwoFactorScenario())
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package suites
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -22,7 +23,22 @@ func init() {
|
|||
return err
|
||||
}
|
||||
|
||||
return waitUntilAutheliaIsReady(dockerEnvironment)
|
||||
return waitUntilAutheliaBackendIsReady(dockerEnvironment)
|
||||
}
|
||||
|
||||
onSetupTimeout := func() error {
|
||||
backendLogs, err := dockerEnvironment.Logs("authelia-backend", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(backendLogs)
|
||||
|
||||
frontendLogs, err := dockerEnvironment.Logs("authelia-frontend", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(frontendLogs)
|
||||
return nil
|
||||
}
|
||||
|
||||
teardown := func(suitePath string) error {
|
||||
|
@ -32,6 +48,7 @@ func init() {
|
|||
GlobalRegistry.Register(duoPushSuiteName, Suite{
|
||||
SetUp: setup,
|
||||
SetUpTimeout: 5 * time.Minute,
|
||||
OnSetupTimeout: onSetupTimeout,
|
||||
TestTimeout: 1 * time.Minute,
|
||||
TearDown: teardown,
|
||||
TearDownTimeout: 2 * time.Minute,
|
||||
|
|
|
@ -35,15 +35,23 @@ func (s *DuoPushSuite) TearDownSuite() {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *DuoPushSuite) SetupTest() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
s.doLogout(ctx, s.T())
|
||||
}
|
||||
|
||||
func (s *DuoPushSuite) TearDownTest() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
s.doChangeMethod(ctx, s.T(), "one-time-password")
|
||||
s.WaitElementLocatedByID(ctx, s.T(), "one-time-password-method")
|
||||
}
|
||||
|
||||
func (s *DuoPushSuite) TestShouldSucceedAuthentication() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||
defer cancel()
|
||||
|
||||
ConfigureDuo(s.T(), Allow)
|
||||
|
@ -54,7 +62,7 @@ func (s *DuoPushSuite) TestShouldSucceedAuthentication() {
|
|||
}
|
||||
|
||||
func (s *DuoPushSuite) TestShouldFailAuthentication() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||
defer cancel()
|
||||
|
||||
ConfigureDuo(s.T(), Deny)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package suites
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -27,7 +28,22 @@ func init() {
|
|||
return err
|
||||
}
|
||||
|
||||
return waitUntilAutheliaIsReady(haDockerEnvironment)
|
||||
return waitUntilAutheliaBackendIsReady(haDockerEnvironment)
|
||||
}
|
||||
|
||||
onSetupTimeout := func() error {
|
||||
backendLogs, err := haDockerEnvironment.Logs("authelia-backend", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(backendLogs)
|
||||
|
||||
frontendLogs, err := haDockerEnvironment.Logs("authelia-frontend", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(frontendLogs)
|
||||
return nil
|
||||
}
|
||||
|
||||
teardown := func(suitePath string) error {
|
||||
|
@ -37,7 +53,8 @@ func init() {
|
|||
GlobalRegistry.Register(highAvailabilitySuiteName, Suite{
|
||||
SetUp: setup,
|
||||
SetUpTimeout: 5 * time.Minute,
|
||||
TestTimeout: 1 * time.Minute,
|
||||
OnSetupTimeout: onSetupTimeout,
|
||||
TestTimeout: 5 * time.Minute,
|
||||
TearDown: teardown,
|
||||
TearDownTimeout: 2 * time.Minute,
|
||||
Description: `This suite is made to test Authelia in a *complete*
|
||||
|
|
|
@ -39,6 +39,15 @@ func (s *HighAvailabilityWebDriverSuite) TearDownSuite() {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *HighAvailabilityWebDriverSuite) SetupTest() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
s.doLogout(ctx, s.T())
|
||||
s.doVisit(s.T(), HomeBaseURL)
|
||||
s.verifyIsHome(ctx, s.T())
|
||||
}
|
||||
|
||||
func (s *HighAvailabilityWebDriverSuite) TestShouldKeepUserDataInDB() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
|
||||
defer cancel()
|
||||
|
@ -151,13 +160,15 @@ func (s *HighAvailabilityWebDriverSuite) TestShouldVerifyAccessControl() {
|
|||
|
||||
verifyAuthorization := func(username string) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
|
||||
defer cancel()
|
||||
|
||||
s.doRegisterAndLogin2FA(ctx, t, username, "password", false, "")
|
||||
|
||||
for url, authorizations := range expectedAuthorizations {
|
||||
verifyUserIsAuthorized(ctx, t, username, url, authorizations[username])
|
||||
t.Run(url, func(t *testing.T) {
|
||||
verifyUserIsAuthorized(ctx, t, username, url, authorizations[username])
|
||||
})
|
||||
}
|
||||
|
||||
s.doLogout(ctx, t)
|
||||
|
@ -165,7 +176,7 @@ func (s *HighAvailabilityWebDriverSuite) TestShouldVerifyAccessControl() {
|
|||
}
|
||||
|
||||
for _, user := range []string{UserJohn, UserBob, UserHarry} {
|
||||
s.T().Run(fmt.Sprintf("user %s", user), verifyAuthorization(user))
|
||||
s.T().Run(fmt.Sprintf("%s", user), verifyAuthorization(user))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,16 @@ func init() {
|
|||
kubectl := Kubectl{}
|
||||
|
||||
setup := func(suitePath string) error {
|
||||
cmd := utils.Shell("docker-compose -f docker-compose.yml -f example/compose/kind/docker-compose.yml build")
|
||||
if err := cmd.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd = utils.Shell("docker build -t nginx-backend example/compose/nginx/backend")
|
||||
if err := cmd.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
exists, err := kind.ClusterExists()
|
||||
|
||||
if err != nil {
|
||||
|
@ -74,23 +84,24 @@ func init() {
|
|||
}
|
||||
|
||||
teardown := func(suitePath string) error {
|
||||
kubectl.StopDashboard()
|
||||
kubectl.StopProxy()
|
||||
return kind.DeleteCluster()
|
||||
}
|
||||
|
||||
GlobalRegistry.Register(kubernetesSuiteName, Suite{
|
||||
TestTimeout: 60 * time.Second,
|
||||
SetUp: setup,
|
||||
SetUpTimeout: 10 * time.Minute,
|
||||
TestTimeout: 2 * time.Minute,
|
||||
TearDown: teardown,
|
||||
TearDownTimeout: 10 * time.Minute,
|
||||
TearDownTimeout: 2 * time.Minute,
|
||||
Description: "This suite has been created to test Authelia in a Kubernetes context and using nginx as the ingress controller.",
|
||||
})
|
||||
}
|
||||
|
||||
func loadDockerImages() error {
|
||||
kind := Kind{}
|
||||
images := []string{"authelia:dist", "authelia-example-backend"}
|
||||
images := []string{"authelia:dist", "nginx-backend"}
|
||||
|
||||
for _, image := range images {
|
||||
err := kind.LoadImage(image)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package suites
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -25,7 +26,22 @@ func init() {
|
|||
return err
|
||||
}
|
||||
|
||||
return waitUntilAutheliaIsReady(dockerEnvironment)
|
||||
return waitUntilAutheliaBackendIsReady(dockerEnvironment)
|
||||
}
|
||||
|
||||
onSetupTimeout := func() error {
|
||||
backendLogs, err := dockerEnvironment.Logs("authelia-backend", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(backendLogs)
|
||||
|
||||
frontendLogs, err := dockerEnvironment.Logs("authelia-frontend", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(frontendLogs)
|
||||
return nil
|
||||
}
|
||||
|
||||
teardown := func(suitePath string) error {
|
||||
|
@ -36,6 +52,7 @@ func init() {
|
|||
GlobalRegistry.Register(ldapSuiteName, Suite{
|
||||
SetUp: setup,
|
||||
SetUpTimeout: 5 * time.Minute,
|
||||
OnSetupTimeout: onSetupTimeout,
|
||||
TestTimeout: 1 * time.Minute,
|
||||
TearDown: teardown,
|
||||
TearDownTimeout: 2 * time.Minute,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package suites
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -24,7 +25,22 @@ func init() {
|
|||
return err
|
||||
}
|
||||
|
||||
return waitUntilAutheliaIsReady(dockerEnvironment)
|
||||
return waitUntilAutheliaBackendIsReady(dockerEnvironment)
|
||||
}
|
||||
|
||||
onSetupTimeout := func() error {
|
||||
backendLogs, err := dockerEnvironment.Logs("authelia-backend", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(backendLogs)
|
||||
|
||||
frontendLogs, err := dockerEnvironment.Logs("authelia-frontend", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(frontendLogs)
|
||||
return nil
|
||||
}
|
||||
|
||||
teardown := func(suitePath string) error {
|
||||
|
@ -34,7 +50,8 @@ func init() {
|
|||
|
||||
GlobalRegistry.Register(mariadbSuiteName, Suite{
|
||||
SetUp: setup,
|
||||
SetUpTimeout: 3 * time.Minute,
|
||||
SetUpTimeout: 5 * time.Minute,
|
||||
OnSetupTimeout: onSetupTimeout,
|
||||
TearDown: teardown,
|
||||
TearDownTimeout: 2 * time.Minute,
|
||||
})
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package suites
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -25,7 +26,22 @@ func init() {
|
|||
return err
|
||||
}
|
||||
|
||||
return waitUntilAutheliaIsReady(dockerEnvironment)
|
||||
return waitUntilAutheliaBackendIsReady(dockerEnvironment)
|
||||
}
|
||||
|
||||
onSetupTimeout := func() error {
|
||||
backendLogs, err := dockerEnvironment.Logs("authelia-backend", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(backendLogs)
|
||||
|
||||
frontendLogs, err := dockerEnvironment.Logs("authelia-frontend", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(frontendLogs)
|
||||
return nil
|
||||
}
|
||||
|
||||
teardown := func(suitePath string) error {
|
||||
|
@ -35,6 +51,7 @@ func init() {
|
|||
GlobalRegistry.Register(networkACLSuiteName, Suite{
|
||||
SetUp: setup,
|
||||
SetUpTimeout: 5 * time.Minute,
|
||||
OnSetupTimeout: onSetupTimeout,
|
||||
TestTimeout: 1 * time.Minute,
|
||||
TearDown: teardown,
|
||||
TearDownTimeout: 2 * time.Minute,
|
||||
|
|
|
@ -3,7 +3,6 @@ package suites
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -12,66 +11,26 @@ import (
|
|||
|
||||
type NetworkACLSuite struct {
|
||||
suite.Suite
|
||||
|
||||
clients []*WebDriverSession
|
||||
}
|
||||
|
||||
func NewNetworkACLSuite() *NetworkACLSuite {
|
||||
return &NetworkACLSuite{clients: make([]*WebDriverSession, 3)}
|
||||
}
|
||||
|
||||
func (s *NetworkACLSuite) createClient(idx int) {
|
||||
wds, err := StartWebDriverWithProxy(fmt.Sprintf("http://proxy-client%d.example.com:3128", idx), 4444+idx)
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
s.clients[idx] = wds
|
||||
}
|
||||
|
||||
func (s *NetworkACLSuite) teardownClient(idx int) {
|
||||
if err := s.clients[idx].Stop(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *NetworkACLSuite) SetupSuite() {
|
||||
wds, err := StartWebDriver()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
s.clients[0] = wds
|
||||
|
||||
for i := 1; i <= 2; i++ {
|
||||
s.createClient(i)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *NetworkACLSuite) TearDownSuite() {
|
||||
if err := s.clients[0].Stop(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
for i := 1; i <= 2; i++ {
|
||||
s.teardownClient(i)
|
||||
}
|
||||
return &NetworkACLSuite{}
|
||||
}
|
||||
|
||||
func (s *NetworkACLSuite) TestShouldAccessSecretUpon2FA() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
wds, err := StartWebDriver()
|
||||
s.Require().NoError(err)
|
||||
defer wds.Stop()
|
||||
|
||||
targetURL := fmt.Sprintf("%s/secret.html", SecureBaseURL)
|
||||
secret := s.clients[0].doRegisterThenLogout(ctx, s.T(), "john", "password")
|
||||
wds.doVisit(s.T(), targetURL)
|
||||
wds.verifyIsFirstFactorPage(ctx, s.T())
|
||||
|
||||
s.clients[0].doVisit(s.T(), targetURL)
|
||||
s.clients[0].verifyIsFirstFactorPage(ctx, s.T())
|
||||
|
||||
s.clients[0].doLoginOneFactor(ctx, s.T(), "john", "password", false, targetURL)
|
||||
s.clients[0].verifyIsSecondFactorPage(ctx, s.T())
|
||||
s.clients[0].doValidateTOTP(ctx, s.T(), secret)
|
||||
|
||||
s.clients[0].verifySecretAuthorized(ctx, s.T())
|
||||
wds.doRegisterAndLogin2FA(ctx, s.T(), "john", "password", false, targetURL)
|
||||
wds.verifySecretAuthorized(ctx, s.T())
|
||||
}
|
||||
|
||||
// from network 192.168.240.201/32
|
||||
|
@ -79,13 +38,17 @@ func (s *NetworkACLSuite) TestShouldAccessSecretUpon1FA() {
|
|||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
targetURL := fmt.Sprintf("%s/secret.html", SecureBaseURL)
|
||||
s.clients[1].doVisit(s.T(), targetURL)
|
||||
s.clients[1].verifyIsFirstFactorPage(ctx, s.T())
|
||||
wds, err := StartWebDriverWithProxy("http://proxy-client1.example.com:3128", 4444)
|
||||
s.Require().NoError(err)
|
||||
defer wds.Stop()
|
||||
|
||||
s.clients[1].doLoginOneFactor(ctx, s.T(), "john", "password",
|
||||
targetURL := fmt.Sprintf("%s/secret.html", SecureBaseURL)
|
||||
wds.doVisit(s.T(), targetURL)
|
||||
wds.verifyIsFirstFactorPage(ctx, s.T())
|
||||
|
||||
wds.doLoginOneFactor(ctx, s.T(), "john", "password",
|
||||
false, fmt.Sprintf("%s/secret.html", SecureBaseURL))
|
||||
s.clients[1].verifySecretAuthorized(ctx, s.T())
|
||||
wds.verifySecretAuthorized(ctx, s.T())
|
||||
}
|
||||
|
||||
// from network 192.168.240.202/32
|
||||
|
@ -93,8 +56,12 @@ func (s *NetworkACLSuite) TestShouldAccessSecretUpon0FA() {
|
|||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
s.clients[2].doVisit(s.T(), fmt.Sprintf("%s/secret.html", SecureBaseURL))
|
||||
s.clients[2].verifySecretAuthorized(ctx, s.T())
|
||||
wds, err := StartWebDriverWithProxy("http://proxy-client2.example.com:3128", 4444)
|
||||
s.Require().NoError(err)
|
||||
defer wds.Stop()
|
||||
|
||||
wds.doVisit(s.T(), fmt.Sprintf("%s/secret.html", SecureBaseURL))
|
||||
wds.verifySecretAuthorized(ctx, s.T())
|
||||
}
|
||||
|
||||
func TestNetworkACLSuite(t *testing.T) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package suites
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -24,7 +25,22 @@ func init() {
|
|||
return err
|
||||
}
|
||||
|
||||
return waitUntilAutheliaIsReady(dockerEnvironment)
|
||||
return waitUntilAutheliaBackendIsReady(dockerEnvironment)
|
||||
}
|
||||
|
||||
onSetupTimeout := func() error {
|
||||
backendLogs, err := dockerEnvironment.Logs("authelia-backend", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(backendLogs)
|
||||
|
||||
frontendLogs, err := dockerEnvironment.Logs("authelia-frontend", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(frontendLogs)
|
||||
return nil
|
||||
}
|
||||
|
||||
teardown := func(suitePath string) error {
|
||||
|
@ -34,7 +50,8 @@ func init() {
|
|||
|
||||
GlobalRegistry.Register(postgresSuiteName, Suite{
|
||||
SetUp: setup,
|
||||
SetUpTimeout: 3 * time.Minute,
|
||||
SetUpTimeout: 5 * time.Minute,
|
||||
OnSetupTimeout: onSetupTimeout,
|
||||
TearDown: teardown,
|
||||
TearDownTimeout: 2 * time.Minute,
|
||||
})
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package suites
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -22,7 +23,22 @@ func init() {
|
|||
return err
|
||||
}
|
||||
|
||||
return waitUntilAutheliaIsReady(dockerEnvironment)
|
||||
return waitUntilAutheliaBackendIsReady(dockerEnvironment)
|
||||
}
|
||||
|
||||
onSetupTimeout := func() error {
|
||||
backendLogs, err := dockerEnvironment.Logs("authelia-backend", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(backendLogs)
|
||||
|
||||
frontendLogs, err := dockerEnvironment.Logs("authelia-frontend", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(frontendLogs)
|
||||
return nil
|
||||
}
|
||||
|
||||
teardown := func(suitePath string) error {
|
||||
|
@ -32,7 +48,8 @@ func init() {
|
|||
GlobalRegistry.Register(shortTimeoutsSuiteName, Suite{
|
||||
SetUp: setup,
|
||||
SetUpTimeout: 5 * time.Minute,
|
||||
TestTimeout: 1 * time.Minute,
|
||||
OnSetupTimeout: onSetupTimeout,
|
||||
TestTimeout: 3 * time.Minute,
|
||||
TearDown: teardown,
|
||||
TearDownTimeout: 2 * time.Minute,
|
||||
Description: `This suite has been created to configure Authelia with short timeouts for sessions expiration
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package suites
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -24,7 +25,22 @@ func init() {
|
|||
return err
|
||||
}
|
||||
|
||||
return waitUntilAutheliaIsReady(dockerEnvironment)
|
||||
return waitUntilAutheliaBackendIsReady(dockerEnvironment)
|
||||
}
|
||||
|
||||
onSetupTimeout := func() error {
|
||||
backendLogs, err := dockerEnvironment.Logs("authelia-backend", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(backendLogs)
|
||||
|
||||
frontendLogs, err := dockerEnvironment.Logs("authelia-frontend", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(frontendLogs)
|
||||
return nil
|
||||
}
|
||||
|
||||
teardown := func(suitePath string) error {
|
||||
|
@ -35,8 +51,10 @@ func init() {
|
|||
GlobalRegistry.Register(standaloneSuiteName, Suite{
|
||||
SetUp: setup,
|
||||
SetUpTimeout: 5 * time.Minute,
|
||||
OnSetupTimeout: onSetupTimeout,
|
||||
TearDown: teardown,
|
||||
TearDownTimeout: 5 * time.Minute,
|
||||
TestTimeout: 2 * time.Minute,
|
||||
TearDownTimeout: 2 * time.Minute,
|
||||
Description: `This suite is used to test Authelia in a standalone
|
||||
configuration with in-memory sessions and a local sqlite db stored on disk`,
|
||||
})
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package suites
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -24,7 +25,22 @@ func init() {
|
|||
return err
|
||||
}
|
||||
|
||||
return waitUntilAutheliaIsReady(dockerEnvironment)
|
||||
return waitUntilAutheliaBackendIsReady(dockerEnvironment)
|
||||
}
|
||||
|
||||
onSetupTimeout := func() error {
|
||||
backendLogs, err := dockerEnvironment.Logs("authelia-backend", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(backendLogs)
|
||||
|
||||
frontendLogs, err := dockerEnvironment.Logs("authelia-frontend", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(frontendLogs)
|
||||
return nil
|
||||
}
|
||||
|
||||
teardown := func(suitePath string) error {
|
||||
|
@ -35,6 +51,7 @@ func init() {
|
|||
GlobalRegistry.Register(traefikSuiteName, Suite{
|
||||
SetUp: setup,
|
||||
SetUpTimeout: 5 * time.Minute,
|
||||
OnSetupTimeout: onSetupTimeout,
|
||||
TearDown: teardown,
|
||||
TearDownTimeout: 2 * time.Minute,
|
||||
})
|
||||
|
|
|
@ -11,8 +11,15 @@ import (
|
|||
|
||||
func (wds *WebDriverSession) verifyBodyContains(ctx context.Context, t *testing.T, pattern string) {
|
||||
err := wds.Wait(ctx, func(wd selenium.WebDriver) (bool, error) {
|
||||
bodyElement := wds.WaitElementLocatedByTagName(ctx, t, "body")
|
||||
require.NotNil(t, bodyElement)
|
||||
bodyElement, err := wds.WebDriver.FindElement(selenium.ByTagName, "body")
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if bodyElement == nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
content, err := bodyElement.Text()
|
||||
|
||||
|
|
|
@ -6,5 +6,5 @@ import (
|
|||
)
|
||||
|
||||
func (wds *WebDriverSession) verifySecretAuthorized(ctx context.Context, t *testing.T) {
|
||||
wds.verifyBodyContains(ctx, t, "This is a very important secret!")
|
||||
wds.WaitElementLocatedByID(ctx, t, "secret")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package utils
|
||||
|
||||
import "errors"
|
||||
|
||||
// ErrTimeoutReached error thrown when a timeout is reached
|
||||
var ErrTimeoutReached = errors.New("timeout reached")
|
|
@ -31,10 +31,8 @@ func Command(name string, args ...string) *exec.Cmd {
|
|||
// CommandWithStdout create a command forwarding stdout and stderr to the OS streams
|
||||
func CommandWithStdout(name string, args ...string) *exec.Cmd {
|
||||
cmd := Command(name, args...)
|
||||
if log.GetLevel() > log.InfoLevel {
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
}
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
return cmd
|
||||
}
|
||||
|
||||
|
@ -133,7 +131,7 @@ func RunCommandWithTimeout(cmd *exec.Cmd, timeout time.Duration) error {
|
|||
if err := cmd.Process.Kill(); err != nil {
|
||||
return err
|
||||
}
|
||||
return fmt.Errorf("timeout of %ds reached", int64(timeout/time.Second))
|
||||
return ErrTimeoutReached
|
||||
case err := <-done:
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
import React, { useEffect, Fragment, ReactNode, useState } from "react";
|
||||
import React, { useEffect, Fragment, ReactNode, useState, useCallback } from "react";
|
||||
import { Switch, Route, Redirect, useHistory, useLocation } from "react-router";
|
||||
import FirstFactorForm from "./FirstFactor/FirstFactorForm";
|
||||
import SecondFactorForm from "./SecondFactor/SecondFactorForm";
|
||||
import { FirstFactorRoute, SecondFactorRoute, SecondFactorTOTPRoute, SecondFactorPushRoute, SecondFactorU2FRoute, LogoutRoute } from "../../Routes";
|
||||
import {
|
||||
FirstFactorRoute, SecondFactorRoute, SecondFactorTOTPRoute,
|
||||
SecondFactorPushRoute, SecondFactorU2FRoute
|
||||
} from "../../Routes";
|
||||
import { useAutheliaState } from "../../hooks/State";
|
||||
import LoadingPage from "../LoadingPage/LoadingPage";
|
||||
import { AuthenticationLevel } from "../../services/State";
|
||||
|
@ -23,6 +26,8 @@ export default function () {
|
|||
const [preferences, fetchPreferences, , fetchPreferencesError] = useUserPreferences();
|
||||
const [configuration, fetchConfiguration, , fetchConfigurationError] = useAutheliaConfiguration();
|
||||
|
||||
const redirect = useCallback((url: string) => history.push(url), [history]);
|
||||
|
||||
// Fetch the state when portal is mounted.
|
||||
useEffect(() => { fetchState() }, [fetchState]);
|
||||
|
||||
|
@ -71,19 +76,19 @@ export default function () {
|
|||
|
||||
if (state.authentication_level === AuthenticationLevel.Unauthenticated) {
|
||||
setFirstFactorDisabled(false);
|
||||
history.push(`${FirstFactorRoute}${redirectionSuffix}`);
|
||||
redirect(`${FirstFactorRoute}${redirectionSuffix}`);
|
||||
} else if (state.authentication_level >= AuthenticationLevel.OneFactor && preferences) {
|
||||
console.log("redirect");
|
||||
if (preferences.method === SecondFactorMethod.U2F) {
|
||||
history.push(`${SecondFactorU2FRoute}${redirectionSuffix}`);
|
||||
redirect(`${SecondFactorU2FRoute}${redirectionSuffix}`);
|
||||
} else if (preferences.method === SecondFactorMethod.Duo) {
|
||||
history.push(`${SecondFactorPushRoute}${redirectionSuffix}`);
|
||||
redirect(`${SecondFactorPushRoute}${redirectionSuffix}`);
|
||||
} else {
|
||||
history.push(`${SecondFactorTOTPRoute}${redirectionSuffix}`);
|
||||
redirect(`${SecondFactorTOTPRoute}${redirectionSuffix}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [state, redirectionURL, history.push, preferences, setFirstFactorDisabled]);
|
||||
}, [state, redirectionURL, redirect, preferences, setFirstFactorDisabled]);
|
||||
|
||||
const handleFirstFactorSuccess = async (redirectionURL: string | undefined) => {
|
||||
if (redirectionURL) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React, { ReactNode, Fragment } from "react";
|
||||
import React, { ReactNode } from "react";
|
||||
import { makeStyles, Typography, Link } from "@material-ui/core";
|
||||
|
||||
interface MethodContainerProps {
|
||||
|
|
|
@ -31,7 +31,7 @@ export default function (props: Props) {
|
|||
console.error(err);
|
||||
createErrorNotification("There was an issue signing out");
|
||||
}
|
||||
}, [createErrorNotification, setTimedOut]);
|
||||
}, [createErrorNotification, setTimedOut, mounted]);
|
||||
|
||||
useEffect(() => { doSignOut() }, [doSignOut]);
|
||||
|
||||
|
|
Loading…
Reference in New Issue