Replace typescript version of authelia-scripts by Go version.

pull/424/head
Clement Michaud 2019-10-29 21:54:47 +01:00 committed by Clément Michaud
parent 2dccd10a27
commit 9d7224b7ad
43 changed files with 1004 additions and 617 deletions

View File

@ -14,22 +14,18 @@ addons:
packages:
- libgif-dev
- google-chrome-stable
before_script:
- curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash
- nvm install v9 && nvm use v9 && npm i
- nvm install v11 && nvm use v11 && npm i
script:
- "./scripts/authelia-scripts travis"
- "source bootstrap.sh"
- "authelia-scripts ci"
after_success:
- "./scripts/authelia-scripts docker publish"
deploy:
provider: npm
email: clement.michaud34@gmail.com
skip_cleanup: true
api_key:
secure: HpaWykYM6zaTXrDRGvyRvsIhn1BLT5gxdU1VXB6PMlr+FpTUoOXsYqLf+S1ipmR8rfjCGXIM1dRPfp/UmEgeWBSJ8PDjipcjYLEWkJSsW8IAO6GVR+pNPO6TgBQmR5RljZRwBd/uIh43nW9tG1YeoERVxdF4OvqwIeu0+jFrVnMdQngfAhXOiEMDSwH328q8QZIkQUmEhWn+IksHG34rLyo29hQQtJ1OnPkJwB9ZSJ71EEp0VH5UtJBCy5eDxKo9NQgvZpf+t6b2jfmHzp1uHlc8h7frpsCIJ0mborzWgc7P0VT/eaNbiFEC0oYkm+0lYVa0kgwbpxB02b/N/VGNXp8Tg8cWQmDly9NomR2BXeCgoQr4hvwpbXNw/I1FunVHVM66o0lMJmFJllFhqSWYLtqHrJb1qNIIFJGCqkTb6pnj35pTC50HjITAK9hQqvhwQ8v142qEpxu9rIvQ+ao90sY9IPxTedhGRs6gjF32JEeXjzysysecZ16jnae4bxmGVT21VF4zcDabCz6IMPje/aGg4flGxGJ5rwYb9p9vWXcgO2FXQzmNg3USTqCQWL+4oN0aiv9IknStkZ9bHLSK+tQ/SGjSlIpn5ou2CfQgkBSkj1vmmG+M+eJN0x/BzRYwURrQRm2t4BBPpcj+PkLVDoNuw6I8ETfsLf9b/B1mi2E=
on:
tags: true
repo: clems4ever/authelia
- "authelia-scripts docker publish"
# TODO(c.michaud): publish built artifact on Github.
notifications:
email:
recipients:

View File

@ -82,7 +82,7 @@ func RandomString(n int) string {
func HashPassword(password string, salt *string) string {
var generatedSalt string
if salt == nil {
generatedSalt = fmt.Sprintf("$6$rounds=5000$%s$", RandomString(16))
generatedSalt = fmt.Sprintf("$6$rounds=50000$%s$", RandomString(16))
} else {
generatedSalt = *salt
}

View File

@ -1,33 +1,19 @@
export PATH=$(pwd)/scripts:/tmp:$PATH
set -e
export PS1="(authelia) $PS1"
export PATH=./cmd/authelia-scripts/:/tmp:$PATH
npm i
if [ -z "$OLD_PS1" ]; then
OLD_PS1="$PS1"
export PS1="(authelia) $PS1"
fi
pushd client
npm i
popd
echo "[BOOTSTRAP] Checking if Docker is installed..."
if [ ! -x "$(command -v docker)" ];
echo "[BOOTSTRAP] Checking if Go is installed..."
if [ ! -x "$(command -v go)" ];
then
echo "[ERROR] You must install docker on your machine.";
echo "[ERROR] You must install Go on your machine.";
return
fi
echo "[BOOTSTRAP] Checking if docker-compose is installed..."
if [ ! -x "$(command -v docker-compose)" ];
then
echo "[ERROR] You must install docker-compose on your machine.";
return;
fi
echo "[BOOTSTRAP] Running additional bootstrap steps..."
authelia-scripts bootstrap
# Create temporary directory that will contain the databases used in tests.
mkdir -p /tmp/authelia
echo "[BOOTSTRAP] Run 'authelia-scripts suites start dockerhub' to start Authelia and visit https://home.example.com:8080."
echo "[BOOTSTRAP] More details at https://github.com/clems4ever/authelia/blob/master/docs/getting-started.md"

View File

@ -0,0 +1,3 @@
#!/bin/bash
go run cmd/authelia-scripts/*.go $*

View File

@ -0,0 +1,225 @@
package main
import (
"fmt"
"io/ioutil"
"log"
"os"
"os/exec"
"strings"
"github.com/spf13/cobra"
)
// HostEntry represents an entry in /etc/hosts
type HostEntry struct {
Domain string
IP string
}
var hostEntries = []HostEntry{
// For common tests
HostEntry{Domain: "login.example.com", IP: "192.168.240.100"},
HostEntry{Domain: "admin.example.com", IP: "192.168.240.100"},
HostEntry{Domain: "singlefactor.example.com", IP: "192.168.240.100"},
HostEntry{Domain: "dev.example.com", IP: "192.168.240.100"},
HostEntry{Domain: "home.example.com", IP: "192.168.240.100"},
HostEntry{Domain: "mx1.mail.example.com", IP: "192.168.240.100"},
HostEntry{Domain: "mx2.mail.example.com", IP: "192.168.240.100"},
HostEntry{Domain: "public.example.com", IP: "192.168.240.100"},
HostEntry{Domain: "secure.example.com", IP: "192.168.240.100"},
HostEntry{Domain: "mail.example.com", IP: "192.168.240.100"},
HostEntry{Domain: "duo.example.com", IP: "192.168.240.100"},
// For Traefik suite
HostEntry{Domain: "traefik.example.com", IP: "192.168.240.100"},
// For testing network ACLs
HostEntry{Domain: "proxy-client1.example.com", IP: "192.168.240.201"},
HostEntry{Domain: "proxy-client2.example.com", IP: "192.168.240.202"},
HostEntry{Domain: "proxy-client3.example.com", IP: "192.168.240.203"},
}
func runCommand(cmd string, args ...string) {
command := CommandWithStdout(cmd, args...)
err := command.Run()
if err != nil {
panic(err)
}
}
func installNpmPackages() {
runCommand("npm", "ci")
}
func checkCommandExist(cmd string) {
fmt.Print("Checking if '" + cmd + "' command is installed...")
command := exec.Command("bash", "-c", "command -v "+cmd)
err := command.Run()
if err != nil {
log.Fatal("[ERROR] You must install " + cmd + " on your machine.")
}
fmt.Println(" OK")
}
func installClientNpmPackages() {
command := CommandWithStdout("npm", "ci")
command.Dir = "client"
err := command.Run()
if err != nil {
panic(err)
}
}
func createTemporaryDirectory() {
err := os.MkdirAll("/tmp/authelia", 0755)
if err != nil {
panic(err)
}
}
func bootstrapPrintln(args ...interface{}) {
a := make([]interface{}, 0)
a = append(a, "[BOOTSTRAP]")
a = append(a, args...)
fmt.Println(a...)
}
func shell(cmd string) {
runCommand("bash", "-c", cmd)
}
func buildDockerImages() {
shell("docker build -t authelia-example-backend example/compose/nginx/backend")
shell("docker build -t authelia-duo-api example/compose/duo-api")
}
func installKubernetesDependencies() {
if exist, err := FileExists("/tmp/kind"); err == nil && !exist {
shell("wget -nv https://github.com/kubernetes-sigs/kind/releases/download/v0.5.1/kind-linux-amd64 -O /tmp/kind && chmod +x /tmp/kind")
} else {
bootstrapPrintln("Skip installing Kind since it's already installed")
}
if exist, err := FileExists("/tmp/kubectl"); err == nil && !exist {
shell("wget -nv https://storage.googleapis.com/kubernetes-release/release/v1.13.0/bin/linux/amd64/kubectl -O /tmp/kubectl && chmod +x /tmp/kubectl")
} else {
bootstrapPrintln("Skip installing Kubectl since it's already installed")
}
}
func prepareHostsFile() {
contentBytes, err := readHostsFile()
if err != nil {
panic(err)
}
lines := strings.Split(string(contentBytes), "\n")
toBeAddedLine := make([]string, 0)
modified := false
for _, entry := range hostEntries {
domainInHostFile := false
for i, line := range lines {
domainFound := strings.Contains(line, entry.Domain)
ipFound := strings.Contains(line, entry.IP)
if domainFound {
domainInHostFile = true
// The IP is not up to date.
if ipFound {
break
} else {
lines[i] = entry.IP + " " + entry.Domain
modified = true
break
}
}
}
if !domainInHostFile {
toBeAddedLine = append(toBeAddedLine, entry.IP+" "+entry.Domain)
}
}
if len(toBeAddedLine) > 0 {
lines = append(lines, toBeAddedLine...)
modified = true
}
err = ioutil.WriteFile("/tmp/authelia/hosts", []byte(strings.Join(lines, "\n")), 0644)
if err != nil {
panic(err)
}
if modified {
bootstrapPrintln("/etc/hosts needs to be updated")
shell("/usr/bin/sudo mv /tmp/authelia/hosts /etc/hosts")
}
}
// ReadHostsFile reads the hosts file.
func readHostsFile() ([]byte, error) {
bs, err := ioutil.ReadFile("/etc/hosts")
if err != nil {
return nil, err
}
return bs, nil
}
func readVersion(cmd string, args ...string) {
command := exec.Command(cmd, args...)
b, err := command.Output()
if err != nil {
panic(err)
}
fmt.Print(cmd + " => " + string(b))
}
func readVersions() {
readVersion("go", "version")
readVersion("node", "--version")
readVersion("docker", "--version")
readVersion("docker-compose", "--version")
}
// Bootstrap bootstrap authelia dev environment
func Bootstrap(cobraCmd *cobra.Command, args []string) {
bootstrapPrintln("Checking command installation...")
checkCommandExist("node")
checkCommandExist("docker")
checkCommandExist("docker-compose")
bootstrapPrintln("Getting versions of tools")
readVersions()
bootstrapPrintln("Installing NPM packages for development...")
installNpmPackages()
bootstrapPrintln("Install NPM packages for frontend...")
installClientNpmPackages()
bootstrapPrintln("Building development Docker images...")
buildDockerImages()
bootstrapPrintln("Installing Kubernetes dependencies for testing in /tmp... (no junk installed on host)")
installKubernetesDependencies()
createTemporaryDirectory()
bootstrapPrintln("Preparing /etc/hosts to serve subdomains of example.com...")
prepareHostsFile()
bootstrapPrintln("Run 'authelia-scripts suites start basic' to start Authelia and visit https://home.example.com:8080.")
bootstrapPrintln("More details at https://github.com/clems4ever/authelia/blob/master/docs/getting-started.md")
}

View File

@ -0,0 +1,54 @@
package main
import (
"fmt"
"os"
"github.com/spf13/cobra"
)
func buildAutheliaBinary() {
cmd := CommandWithStdout("go", "build", "-o", OutputDir+"/authelia")
cmd.Env = append(os.Environ(),
"GOOS=linux", "GOARCH=amd64", "CGO_ENABLED=1")
err := cmd.Run()
if err != nil {
panic(err)
}
}
func buildFrontend() {
cmd := CommandWithStdout("npm", "run", "build")
cmd.Dir = "client"
err := cmd.Run()
if err != nil {
panic(err)
}
err = os.Rename("client/build", OutputDir+"/public_html")
if err != nil {
panic(err)
}
}
// Build build Authelia
func Build(cobraCmd *cobra.Command, args []string) {
Clean(cobraCmd, args)
fmt.Println("Creating `" + OutputDir + "` directory")
err := os.MkdirAll(OutputDir, os.ModePerm)
if err != nil {
panic(err)
}
fmt.Println("Building Authelia Go binary...")
buildAutheliaBinary()
fmt.Println("Building Authelia frontend...")
buildFrontend()
}

View File

@ -0,0 +1,59 @@
package main
import (
"fmt"
"github.com/spf13/cobra"
)
const dockerPullCommandLine = "docker-compose -f docker-compose.yml " +
"-f example/compose/mongo/docker-compose.yml " +
"-f example/compose/redis/docker-compose.yml " +
"-f example/compose/nginx/portal/docker-compose.yml " +
"-f example/compose/smtp/docker-compose.yml " +
"-f example/compose/httpbin/docker-compose.yml " +
"-f example/compose/ldap/docker-compose.admin.yml " +
"-f example/compose/ldap/docker-compose.yml " +
"pull"
// RunCI run the CI scripts
func RunCI(cmd *cobra.Command, args []string) {
command := CommandWithStdout("bash", "-c", dockerPullCommandLine)
err := command.Run()
if err != nil {
panic(err)
}
fmt.Println("===== Build stage =====")
command = CommandWithStdout("authelia-scripts", "build")
err = command.Run()
if err != nil {
panic(err)
}
fmt.Println("===== Unit testing stage =====")
command = CommandWithStdout("authelia-scripts", "unittest")
err = command.Run()
if err != nil {
panic(err)
}
fmt.Println("===== Docker image build stage =====")
command = CommandWithStdout("authelia-scripts", "docker", "build")
err = command.Run()
if err != nil {
panic(err)
}
fmt.Println("===== End-to-end testing stage =====")
command = CommandWithStdout("authelia-scripts", "suites", "test", "--headless", "--only-forbidden")
err = command.Run()
if err != nil {
panic(err)
}
}

View File

@ -0,0 +1,18 @@
package main
import (
"fmt"
"os"
"github.com/spf13/cobra"
)
// Clean artifacts built and installed by authelia-scripts
func Clean(cobraCmd *cobra.Command, args []string) {
fmt.Println("Removing `" + OutputDir + "` directory")
err := os.RemoveAll(OutputDir)
if err != nil {
panic(err)
}
}

View File

@ -0,0 +1,96 @@
package main
import (
"errors"
"fmt"
"os"
"github.com/spf13/cobra"
)
// DockerBuildCmd Command for building docker image of Authelia.
var DockerBuildCmd = &cobra.Command{
Use: "build",
Short: "Build the docker image of Authelia",
Run: func(cmd *cobra.Command, args []string) {
docker := &Docker{}
err := docker.Build(IntermediateDockerImageName, ".")
if err != nil {
panic(err)
}
err = docker.Tag(IntermediateDockerImageName, DockerImageName)
if err != nil {
panic(err)
}
},
}
// DockerPushCmd Command for pushing Authelia docker image to Dockerhub
var DockerPushCmd = &cobra.Command{
Use: "publish",
Short: "Publish Authelia docker image to Dockerhub",
Run: func(cmd *cobra.Command, args []string) {
publishDockerImage()
},
}
func login(docker *Docker) {
username := os.Getenv("DOCKER_USERNAME")
password := os.Getenv("DOCKER_PASSWORD")
if username == "" {
panic(errors.New("DOCKER_USERNAME is empty"))
}
if password == "" {
panic(errors.New("DOCKER_PASSWORD is empty"))
}
fmt.Println("Login to dockerhub as " + username)
err := docker.Login(username, password)
if err != nil {
fmt.Println("Login to dockerhub failed")
panic(err)
}
}
func deploy(docker *Docker, tag string) {
imageWithTag := DockerImageName + ":" + tag
fmt.Println("===================================================")
fmt.Println("Docker image " + imageWithTag + " will be deployed on Dockerhub.")
fmt.Println("===================================================")
err := docker.Tag(DockerImageName, imageWithTag)
if err != nil {
panic(err)
}
docker.Push(imageWithTag)
if err != nil {
panic(err)
}
}
func publishDockerImage() {
docker := &Docker{}
travisBranch := os.Getenv("TRAVIS_BRANCH")
travisPullRequest := os.Getenv("TRAVIS_PULL_REQUEST")
travisTag := os.Getenv("TRAVIS_TAG")
if travisBranch == "master" && travisPullRequest == "false" {
login(docker)
deploy(docker, "master")
} else if travisTag != "" {
login(docker)
deploy(docker, travisTag)
deploy(docker, "latest")
} else {
fmt.Println("Docker image will not be built")
}
}

View File

@ -0,0 +1,13 @@
package main
import (
"fmt"
"github.com/clems4ever/authelia/authentication"
"github.com/spf13/cobra"
)
// HashPassword hash the provided password with crypt sha256 hash function
func HashPassword(cobraCmd *cobra.Command, args []string) {
fmt.Println(authentication.HashPassword(args[0], nil))
}

View File

@ -0,0 +1,14 @@
package main
import (
"os"
"github.com/spf13/cobra"
)
// ServeCmd serve authelia with the provided configuration
func ServeCmd(cobraCmd *cobra.Command, args []string) {
cmd := CommandWithStdout(OutputDir+"/authelia", "-config", args[0])
cmd.Env = append(os.Environ(), "PUBLIC_DIR=dist/public_html")
RunCommandUntilCtrlC(cmd)
}

View File

@ -0,0 +1,234 @@
package main
import (
"errors"
"fmt"
"io/ioutil"
"os"
"os/exec"
"os/signal"
"strings"
"syscall"
"github.com/spf13/cobra"
)
func listDirectories(path string) ([]string, error) {
files, err := ioutil.ReadDir(path)
if err != nil {
return nil, err
}
dirs := make([]string, 0)
for _, f := range files {
if f.IsDir() {
dirs = append(dirs, f.Name())
}
}
return dirs, nil
}
func listSuites() ([]string, error) {
return listDirectories("./test/suites/")
}
func suiteAvailable(suite string, suites []string) (bool, error) {
suites, err := listSuites()
if err != nil {
return false, err
}
for _, s := range suites {
if s == suite {
return true, nil
}
}
return false, nil
}
// SuitesListCmd Command for listing the available suites
var SuitesListCmd = &cobra.Command{
Use: "list",
Short: "List available suites.",
Run: func(cmd *cobra.Command, args []string) {
suites, err := listSuites()
if err != nil {
panic(err)
}
fmt.Println(strings.Join(suites, "\n"))
},
Args: cobra.ExactArgs(0),
}
// SuitesCleanCmd Command for cleaning suite environments
var SuitesCleanCmd = &cobra.Command{
Use: "clean",
Short: "Clean suite environments.",
Run: func(cmd *cobra.Command, args []string) {
command := CommandWithStdout("bash", "-c",
"./node_modules/.bin/ts-node -P test/tsconfig.json -- ./scripts/clean-environment.ts")
err := command.Run()
if err != nil {
panic(err)
}
},
Args: cobra.ExactArgs(0),
}
// SuitesStartCmd Command for starting a suite
var SuitesStartCmd = &cobra.Command{
Use: "start [suite]",
Short: "Start a suite. Suites can be listed using the list command.",
Run: func(cmd *cobra.Command, args []string) {
suites, err := listSuites()
if err != nil {
panic(err)
}
selectedSuite := args[0]
available, err := suiteAvailable(selectedSuite, suites)
if err != nil {
panic(err)
}
if !available {
panic(errors.New("Suite named " + selectedSuite + " does not exist"))
}
err = ioutil.WriteFile(RunningSuiteFile, []byte(selectedSuite), 0644)
if err != nil {
panic(err)
}
signalChannel := make(chan os.Signal)
signal.Notify(signalChannel, os.Interrupt, syscall.SIGTERM)
cmdline := "./node_modules/.bin/ts-node -P test/tsconfig.json -- ./scripts/run-environment.ts " + selectedSuite
command := CommandWithStdout("bash", "-c", cmdline)
command.Env = append(os.Environ(), "ENVIRONMENT=dev")
err = command.Run()
if err != nil {
panic(err)
}
err = os.Remove(RunningSuiteFile)
if err != nil {
panic(err)
}
},
Args: cobra.ExactArgs(1),
}
// SuitesTestCmd Command for testing a suite
var SuitesTestCmd = &cobra.Command{
Use: "test [suite]",
Short: "Test a suite. Suites can be listed using the list command.",
Run: func(cmd *cobra.Command, args []string) {
runningSuite, err := getRunningSuite()
if err != nil {
panic(err)
}
if len(args) == 1 {
suite := args[0]
if runningSuite != "" && suite != runningSuite {
panic(errors.New("Running suite (" + runningSuite + ") is different than suite to be tested (" + suite + "). Shutdown running suite and retry"))
}
runSuiteTests(suite, runningSuite == "")
} else {
if runningSuite != "" {
panic(errors.New("Cannot run all tests while a suite is currently running. Shutdown running suite and retry"))
}
fmt.Println("No suite provided therefore all suites will be tested")
runAllSuites()
}
},
Args: cobra.MaximumNArgs(1),
}
func getRunningSuite() (string, error) {
exist, err := FileExists(RunningSuiteFile)
if err != nil {
return "", err
}
if !exist {
return "", nil
}
b, err := ioutil.ReadFile(RunningSuiteFile)
return string(b), err
}
func runSuiteTests(suite string, withEnv bool) {
mochaArgs := []string{"--exit", "--colors", "--require", "ts-node/register", "test/suites/" + suite + "/test.ts"}
if onlyForbidden {
mochaArgs = append(mochaArgs, "--forbid-only", "--forbid-pending")
}
mochaCmdLine := "./node_modules/.bin/mocha " + strings.Join(mochaArgs, " ")
fmt.Println(mochaCmdLine)
headlessValue := "n"
if headless {
headlessValue = "y"
}
var cmd *exec.Cmd
if withEnv {
fmt.Println("No running suite detected, setting up an environment for running the tests")
cmd = CommandWithStdout("bash", "-c",
"./node_modules/.bin/ts-node ./scripts/run-environment.ts "+suite+" '"+mochaCmdLine+"'")
} else {
fmt.Println("Running suite detected. Running tests...")
cmd = CommandWithStdout("bash", "-c", mochaCmdLine)
}
cmd.Env = append(os.Environ(),
"TS_NODE_PROJECT=test/tsconfig.json",
"HEADLESS="+headlessValue,
"ENVIRONMENT=dev")
err := cmd.Run()
if err != nil {
os.Exit(1)
}
}
func runAllSuites() {
suites, err := listSuites()
if err != nil {
panic(err)
}
for _, s := range suites {
runSuiteTests(s, true)
}
}
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")
}

View File

@ -0,0 +1,11 @@
package main
import "github.com/spf13/cobra"
// RunUnitTest run the unit tests
func RunUnitTest(cobraCmd *cobra.Command, args []string) {
err := CommandWithStdout("go", "test", "./...").Run()
if err != nil {
panic(err)
}
}

View File

@ -0,0 +1,13 @@
package main
// OutputDir the output directory where the built version of Authelia is located
var OutputDir = "dist"
// DockerImageName the official name of authelia docker image
var DockerImageName = "clems4ever/authelia"
// IntermediateDockerImageName local name of the docker image
var IntermediateDockerImageName = "authelia:dist"
// RunningSuiteFile name of the file containing the currently running suite
var RunningSuiteFile = ".suite"

View File

@ -0,0 +1,24 @@
package main
// Docker a docker object
type Docker struct{}
// Build build a docker image
func (d *Docker) Build(tag string, target string) error {
return CommandWithStdout("docker", "build", "-t", tag, target).Run()
}
// Tag tag a docker image.
func (d *Docker) Tag(image, tag string) error {
return CommandWithStdout("docker", "tag", image, tag).Run()
}
// Login login to the dockerhub registry.
func (d *Docker) Login(username, password string) error {
return CommandWithStdout("docker", "login", "-u", username, "-p", password).Run()
}
// Push push a docker image to dockerhub.
func (d *Docker) Push(tag string) error {
return CommandWithStdout("docker", "push", tag).Run()
}

View File

@ -0,0 +1,52 @@
package main
import (
"bufio"
"fmt"
"os"
"os/exec"
"os/signal"
"sync"
"syscall"
)
// CommandWithStdout execute the command and forward stdout and stderr to the OS streams
func CommandWithStdout(name string, args ...string) *exec.Cmd {
cmd := exec.Command(name, args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd
}
// RunCommandUntilCtrlC run a command until ctrl-c is hit
func RunCommandUntilCtrlC(cmd *exec.Cmd) {
mutex := sync.Mutex{}
cond := sync.NewCond(&mutex)
signalChannel := make(chan os.Signal)
signal.Notify(signalChannel, os.Interrupt, syscall.SIGTERM)
mutex.Lock()
go func() {
mutex.Lock()
f := bufio.NewWriter(os.Stdout)
defer f.Flush()
fmt.Println("Hit Ctrl+C to shutdown...")
err := cmd.Run()
if err != nil {
fmt.Println(err)
cond.Broadcast()
mutex.Unlock()
return
}
<-signalChannel
cond.Broadcast()
mutex.Unlock()
}()
cond.Wait()
}

View File

@ -0,0 +1,15 @@
package main
import "os"
// FileExists returns whether the given file or directory exists
func FileExists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return true, err
}

View File

@ -0,0 +1,121 @@
//usr/bin/env go run "$0" "$@"; exit
package main
import (
"github.com/spf13/cobra"
)
// AutheliaCommandDefinition is the definition of one authelia-scripts command.
type AutheliaCommandDefinition struct {
Name string
Short string
Long string
CommandLine string
Args cobra.PositionalArgs
Func func(cmd *cobra.Command, args []string)
SubCommands []*cobra.Command
}
// CobraCommands list of cobra commands
type CobraCommands = []*cobra.Command
// Commands is the list of commands of authelia-scripts
var Commands = []AutheliaCommandDefinition{
AutheliaCommandDefinition{
Name: "bootstrap",
Short: "Prepare environment for development and testing.",
Long: `Prepare environment for development and testing. This command prepares docker
images and download tools like Kind for Kubernetes testing.`,
Func: Bootstrap,
},
AutheliaCommandDefinition{
Name: "build",
Short: "Build Authelia binary and static assets",
Func: Build,
},
AutheliaCommandDefinition{
Name: "clean",
Short: "Clean build artifacts",
Func: Clean,
},
AutheliaCommandDefinition{
Name: "docker",
Short: "Commands related to building and publishing docker image",
SubCommands: CobraCommands{DockerBuildCmd, DockerPushCmd},
},
AutheliaCommandDefinition{
Name: "hash-password [password]",
Short: "Compute hash of a password for creating a file-based users database",
Func: HashPassword,
Args: cobra.MinimumNArgs(1),
},
AutheliaCommandDefinition{
Name: "serve [config]",
Short: "Serve compiled version of Authelia",
Func: ServeCmd,
Args: cobra.MinimumNArgs(1),
},
AutheliaCommandDefinition{
Name: "suites",
Short: "Compute hash of a password for creating a file-based users database",
SubCommands: CobraCommands{SuitesCleanCmd, SuitesListCmd, SuitesStartCmd, SuitesTestCmd},
},
AutheliaCommandDefinition{
Name: "ci",
Short: "Run continuous integration script",
Func: RunCI,
},
AutheliaCommandDefinition{
Name: "unittest",
Short: "Run unit tests",
Func: RunUnitTest,
},
}
func main() {
var rootCmd = &cobra.Command{Use: "authelia-scripts"}
cobraCommands := make([]*cobra.Command, 0)
for _, autheliaCommand := range Commands {
var fn func(cobraCmd *cobra.Command, args []string)
if autheliaCommand.CommandLine != "" {
cmdline := autheliaCommand.CommandLine
fn = func(cobraCmd *cobra.Command, args []string) {
cmd := CommandWithStdout(cmdline, args...)
err := cmd.Run()
if err != nil {
panic(err)
}
}
} else if autheliaCommand.Func != nil {
fn = autheliaCommand.Func
}
command := &cobra.Command{
Use: autheliaCommand.Name,
Short: autheliaCommand.Short,
}
if autheliaCommand.Long != "" {
command.Long = autheliaCommand.Long
}
if fn != nil {
command.Run = fn
}
if autheliaCommand.Args != nil {
command.Args = autheliaCommand.Args
}
if autheliaCommand.SubCommands != nil {
command.AddCommand(autheliaCommand.SubCommands...)
}
cobraCommands = append(cobraCommands, command)
}
rootCmd.AddCommand(cobraCommands...)
rootCmd.Execute()
}

View File

@ -2,7 +2,6 @@ package validator
import (
"errors"
"fmt"
"strings"
"github.com/clems4ever/authelia/configuration/schema"
@ -37,7 +36,6 @@ func validateLdapAuthenticationBackend(configuration *schema.LDAPAuthenticationB
} else {
configuration.URL = validateLdapURL(configuration.URL, validator)
}
fmt.Println(configuration.URL)
if configuration.User == "" {
validator.Push(errors.New("Please provide a user name to connect to the LDAP server"))

1
go.mod
View File

@ -15,6 +15,7 @@ require (
github.com/mattn/go-sqlite3 v1.11.0
github.com/pquerna/otp v1.2.0
github.com/sirupsen/logrus v1.4.2
github.com/spf13/cobra v0.0.5
github.com/stretchr/testify v1.4.0
github.com/tstranex/u2f v1.0.0
github.com/valyala/fasthttp v1.6.0

26
go.sum
View File

@ -1,10 +1,16 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Workiva/go-datastructures v1.0.50 h1:slDmfW6KCHcC7U+LP3DDBbm4fqTwZGn1beOFPfGaLvo=
github.com/Workiva/go-datastructures v1.0.50/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
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=
@ -16,6 +22,7 @@ github.com/fasthttp/router v0.5.2 h1:xdmx8uYc9IFDtlbG2/FhE1Gyowv7/sqMgMonRjoW0Yo
github.com/fasthttp/router v0.5.2/go.mod h1:Y5JAeRTSPwSLoUgH4x75UnT1j1IcAgVshMDMMrnNmKQ=
github.com/fasthttp/session v1.1.3 h1:2qjxNltI7iv0yh7frsIdhbsGmSoRnTajU8xtpC6Hd80=
github.com/fasthttp/session v1.1.3/go.mod h1:DRxVb1PWFtAUTE4U+GgggsVkUaQyacoL8TN+3o4/yLw=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4=
github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
@ -25,6 +32,8 @@ github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/klauspost/compress v1.8.2 h1:Bx0qjetmNjdFXASH02NSAREKpiaDwkO1DRZ3dV2KCcs=
github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/cpuid v1.2.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w=
@ -32,21 +41,34 @@ github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgo
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q=
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ=
github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok=
github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/savsgio/dictpool v0.0.0-20191028211042-a886cee3358a h1:HHo8bk/5tOTL+UJ2VBkzGWhurfjyrLMRnvdRBnXYlfs=
github.com/savsgio/dictpool v0.0.0-20191028211042-a886cee3358a/go.mod h1:hnGRFeigcU3gTEMTWW8OjfoSYztn2GPcriOY9iIzCrA=
github.com/savsgio/gotils v0.0.0-20190925070755-524bc4f47500 h1:9Pi10H7E8E79/x2HSe1FmMGd7BJ1WAqDKzwjpv+ojFg=
github.com/savsgio/gotils v0.0.0-20190925070755-524bc4f47500/go.mod h1:lHhJedqxCoHN+zMtwGNTXWmF0u9Jt363FYRhV6g0CdY=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
@ -57,6 +79,7 @@ github.com/tinylib/msgp v1.1.0 h1:9fQd+ICuRIu/ue4vxJZu6/LzxN0HwMds2nq/0cFvxHU=
github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
github.com/tstranex/u2f v1.0.0 h1:HhJkSzDDlVSVIVt7pDJwCHQj67k7A5EeBgPmeD+pVsQ=
github.com/tstranex/u2f v1.0.0/go.mod h1:eahSLaqAS0zsIEv80+vXT7WanXs7MQQDg3j3wGBSayo=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.6.0 h1:uWF8lgKmeaIewWVPwi4GRq2P6+R46IgYZdxWtM+GtEY=
@ -66,14 +89,17 @@ github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
github.com/xdg/stringprep v1.0.0 h1:d9X0esnoa3dFsV0FG35rAT0RIhYFlPq7MiP+DW89La0=
github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
go.mongodb.org/mongo-driver v1.1.2 h1:jxcFYjlkl8xaERsgLo+RNquI0epW6zuy/ZRQs6jnrFA=
go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

View File

@ -42,28 +42,21 @@
"@types/request": "^2.0.5",
"@types/request-promise": "^4.1.38",
"@types/selenium-webdriver": "^3.0.16",
"@types/sinon": "^4.3.0",
"@types/speakeasy": "^2.0.2",
"@types/tmp": "0.0.33",
"chokidar": "^2.0.4",
"chromedriver": "^77.0.0",
"commander": "^2.19.0",
"istanbul": "^0.4.5",
"ejs": "^2.6.2",
"mocha": "^6.1.4",
"mockdate": "^2.0.1",
"node-fetch": "^2.3.0",
"nodemon": "^1.18.9",
"query-string": "^6.0.0",
"readable-stream": "^2.3.3",
"redis": "^2.8.0",
"request": "^2.88.0",
"request-promise": "^4.2.2",
"selenium-webdriver": "^4.0.0-alpha.4",
"should": "^13.2.1",
"sinon": "^5.0.7",
"speakeasy": "^2.0.0",
"tmp": "0.0.33",
"tree-kill": "^1.2.1",
"ts-node": "^6.0.1",
"tslint": "^5.2.0",

View File

@ -1,18 +0,0 @@
#!/usr/bin/env node
var program = require('commander');
program
.version('0.0.1')
.command('bootstrap', 'Prepare some containers for development.')
.command('suites', 'Run Authelia in specific environments.')
.command('serve', 'Run Authelia with a customized configuration.')
.command('build', 'Build production version of Authelia from source.')
.command('clean', 'Clean the production version of Authelia.')
.command('unittest', 'Run Authelia integration tests.')
.command('travis', 'Build and test Authelia on Travis.')
.command('hash-password <password>', 'Hash a password with SSHA512.')
.command('docker', 'Docker related commands.')
.parse(process.argv);

View File

@ -1,86 +0,0 @@
#!/usr/bin/env node
var { exec } = require('./utils/exec');
var fs = require('fs');
async function buildDockerImages() {
console.log("[BOOTSTRAP] Building required Docker images...");
console.log('Build authelia-example-backend docker image.')
await exec('docker build -t authelia-example-backend example/compose/nginx/backend');
console.log('Build authelia-duo-api docker image.')
await exec('docker build -t authelia-duo-api example/compose/duo-api');
}
async function checkHostsFile() {
async function checkAndFixEntry(entries, domain, ip) {
const foundEntry = entries.filter(l => l[1] == domain);
if (foundEntry.length > 0) {
if (foundEntry[0][0] == ip) {
// The entry exists and is correct.
return;
}
else {
// We need to remove the entry and replace it.
console.log(`Update entry for ${domain}.`);
await exec(`cat /etc/hosts | grep -v "${domain}" | /usr/bin/sudo tee /etc/hosts > /dev/null`);
await exec(`echo "${ip} ${domain}" | /usr/bin/sudo tee -a /etc/hosts > /dev/null`);
}
}
else {
// We need to add the new entry.
console.log(`Add entry for ${domain}.`);
await exec(`echo "${ip} ${domain}" | /usr/bin/sudo tee -a /etc/hosts > /dev/null`);
}
}
console.log("[BOOTSTRAP] Checking if example.com domain is forwarded to your machine...");
const actualEntries = fs.readFileSync("/etc/hosts").toString("utf-8")
.split("\n").filter(l => l !== '').map(l => l.split(" ").filter(w => w !== ''));
await checkAndFixEntry(actualEntries, 'login.example.com', '192.168.240.100');
await checkAndFixEntry(actualEntries, 'admin.example.com', '192.168.240.100');
await checkAndFixEntry(actualEntries, 'singlefactor.example.com', '192.168.240.100');
await checkAndFixEntry(actualEntries, 'dev.example.com', '192.168.240.100');
await checkAndFixEntry(actualEntries, 'home.example.com', '192.168.240.100');
await checkAndFixEntry(actualEntries, 'mx1.mail.example.com', '192.168.240.100');
await checkAndFixEntry(actualEntries, 'mx2.mail.example.com', '192.168.240.100');
await checkAndFixEntry(actualEntries, 'public.example.com', '192.168.240.100');
await checkAndFixEntry(actualEntries, 'secure.example.com', '192.168.240.100');
await checkAndFixEntry(actualEntries, 'mail.example.com', '192.168.240.100');
await checkAndFixEntry(actualEntries, 'duo.example.com', '192.168.240.100');
// For Traefik suite.
await checkAndFixEntry(actualEntries, 'traefik.example.com', '192.168.240.100');
// For testing network ACLs.
await checkAndFixEntry(actualEntries, 'proxy-client1.example.com', '192.168.240.201');
await checkAndFixEntry(actualEntries, 'proxy-client2.example.com', '192.168.240.202');
await checkAndFixEntry(actualEntries, 'proxy-client3.example.com', '192.168.240.203');
}
async function checkKubernetesDependencies() {
console.log("[BOOTSTRAP] Checking Kubernetes tools in /tmp to allow testing a Kube cluster... (no junk installed on host)");
if (!fs.existsSync('/tmp/kind')) {
console.log('Install Kind for spawning a Kubernetes cluster.');
await exec('wget -nv https://github.com/kubernetes-sigs/kind/releases/download/v0.5.1/kind-linux-amd64 -O /tmp/kind && chmod +x /tmp/kind');
}
if (!fs.existsSync('/tmp/kubectl')) {
console.log('Install Kubectl for interacting with Kubernetes.');
await exec('wget -nv https://storage.googleapis.com/kubernetes-release/release/v1.13.0/bin/linux/amd64/kubectl -O /tmp/kubectl && chmod +x /tmp/kubectl');
}
}
async function main() {
await checkHostsFile();
await buildDockerImages();
await checkKubernetesDependencies();
}
main().catch((err) => {
console.error(err);
process.exit(1);
})

View File

@ -1,19 +0,0 @@
#!/bin/bash
set -x
set -e
DIST_DIR=dist
rm -rf $DIST_DIR
mkdir -p $DIST_DIR
GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -o $DIST_DIR/authelia
# Build the client
pushd client
npm run build
popd
mv client/build $DIST_DIR/public_html

View File

@ -1,3 +0,0 @@
#!/bin/bash
rm -rf dist

View File

@ -1,8 +0,0 @@
#!/usr/bin/env node
var program = require('commander');
program
.command('build', 'Build docker image clems4ever/authelia.')
.command('publish', 'Publish image clems4ever/authelia to Dockerhub.')
.parse(process.argv);

View File

@ -1,14 +0,0 @@
#!/usr/bin/env node
var { exec } = require('./utils/exec');
var { IMAGE_NAME, DOCKERHUB_IMAGE_NAME } = require('./utils/docker');
async function main() {
await exec(`docker build -t ${IMAGE_NAME}:dist .`);
await exec(`docker tag ${IMAGE_NAME}:dist ${DOCKERHUB_IMAGE_NAME}`);
}
main().catch((err) => {
console.error(err);
process.exit(1);
})

View File

@ -1,42 +0,0 @@
#!/bin/bash
# Parameters:
# TAG - The name of the tag to use for publishing in Dockerhub
function login_to_dockerhub {
echo "Logging in to Dockerhub as $DOCKER_USERNAME."
docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD
if [ "$?" -ne "0" ];
then
echo "Logging in to Dockerhub failed.";
exit 1
fi
}
function deploy_on_dockerhub {
TAG=$1
IMAGE_NAME=authelia:dist
DOCKERHUB_IMAGE_NAME=clems4ever/authelia
IMAGE_WITH_TAG=$DOCKERHUB_IMAGE_NAME:$TAG
echo "==========================================================="
echo "Docker image $IMAGE_WITH_TAG will be deployed on Dockerhub."
echo "==========================================================="
docker tag $IMAGE_NAME $IMAGE_WITH_TAG;
docker push $IMAGE_WITH_TAG;
echo "Docker image deployed successfully."
}
if [ "$TRAVIS_BRANCH" == "master" ] && [ "$TRAVIS_PULL_REQUEST" == "false" ]; then
echo "Building on master branch"
login_to_dockerhub
deploy_on_dockerhub master
elif [ ! -z "$TRAVIS_TAG" ]; then
login_to_dockerhub
deploy_on_dockerhub $TRAVIS_TAG
deploy_on_dockerhub latest
else
echo "Docker image will not be deployed on Dockerhub."
fi

View File

@ -1,32 +0,0 @@
#!/usr/bin/env node
var program = require('commander');
var RandomString = require("randomstring");
var Util = require("util");
var crypt = require("crypt3");
function ssha512(password, saltSize, rounds) {
// $6 means SHA512
const _salt = Util.format("$6$rounds=%d$%s", rounds,
RandomString.generate(saltSize));
const hash = crypt(password, _salt);
return Util.format("{CRYPT}%s", hash);
}
let password;
program
.option('-s, --salt <size>', 'The size of the salt to generate.')
.option('-r, --rounds <rounds>', 'The number of rounds.')
.arguments('<password>')
.action(function (_password) {
password = _password;
})
.parse(process.argv);
if (!password) {
program.help();
}
console.log(ssha512(password, program.salt || 16, program.rounds || 500000));

View File

@ -1,31 +0,0 @@
#!/usr/bin/env node
var program = require('commander');
var spawn = require('child_process').spawn;
let config;
program
.description('Run Authelia server with a custom configuration file. This is an alternative to suites in the case the environment is already set up.')
.arguments('[config_file]', 'Configuration file to run Authelia with.')
.action((configArg) => config = configArg)
.parse(process.argv);
if (!config) {
config = 'config.yml'; // set default config file.;
}
const server = spawn(__dirname + '/../dist/authelia', ['-config', config], {
env: {
...process.env,
PUBLIC_DIR: __dirname + "/../dist/public_html"
}
});
server.stdout.pipe(process.stdout);
server.stderr.pipe(process.stderr);
server.on('exit', function(statusCode) {
process.exit(statusCode);
});

View File

@ -1,10 +0,0 @@
#!/usr/bin/env node
var program = require('commander');
program
.command('start', 'Start a suite.')
.command('list', 'List the available suites')
.command('test', 'Test a suite.')
.command('clean', 'Clean remaining environment artifacts (like docker-compose env).')
.parse(process.argv);

View File

@ -1,18 +0,0 @@
#!/usr/bin/env node
var program = require('commander');
var spawn = require('child_process').spawn;
program
.description(`Clean environment artifacts from previous suites.`)
.parse(process.argv)
runEnvProcess = spawn('./node_modules/.bin/ts-node -P test/tsconfig.json -- ./scripts/clean-environment.ts', {
shell: true
});
runEnvProcess.stdout.pipe(process.stdout);
runEnvProcess.stderr.pipe(process.stderr);
runEnvProcess.on('exit', function(statusCode) {
process.exit(statusCode);
});

View File

@ -1,10 +0,0 @@
#!/usr/bin/env node
var program = require('commander');
var ListSuites = require('./utils/ListSuites');
program
.description(`List the available suites.`)
.parse(process.argv)
console.log(ListSuites().join("\n"));

View File

@ -1,64 +0,0 @@
#!/usr/bin/env node
var program = require('commander');
var spawn = require('child_process').spawn;
var fs = require('fs');
var ListSuites = require('./utils/ListSuites');
let suite;
program
.description(`Start the suite provided as argument. You can list the suites with the 'list' command.`)
.arguments('<suite>')
.action((suiteArg) => suite = suiteArg)
.parse(process.argv)
if (!suite) {
program.help();
}
if (ListSuites().indexOf(suite) == -1) {
console.log("[WARNING] This suite does not exist. Use 'list' command to check the existing suites.");
process.exit(1);
}
const ENVIRONMENT_FILENAME = '.suite';
let runEnvProcess;
// Sometime SIGINT is received twice, we make sure with this variable that we cleanup
// only once.
var alreadyCleaningUp = false;
// Properly cleanup server and client if ctrl-c is hit
process.on('SIGINT', function() {
if (alreadyCleaningUp) return;
alreadyCleaningUp = true;
console.log('Cleanup procedure is running...');
});
async function main() {
fs.writeFileSync(ENVIRONMENT_FILENAME, suite);
// Start the environment from ts-node process.
runEnvProcess = spawn('./node_modules/.bin/ts-node -P test/tsconfig.json -- ./scripts/run-environment.ts ' + suite, {
shell: true,
env: {
...process.env,
ENVIRONMENT: 'dev',
}
});
runEnvProcess.stdout.pipe(process.stdout);
runEnvProcess.stderr.pipe(process.stderr);
runEnvProcess.on('exit', function(statusCode) {
fs.unlinkSync(ENVIRONMENT_FILENAME);
process.exit(statusCode);
});
}
main()
.catch((err) => {
console.error(err);
process.exit(1)
});

View File

@ -1,120 +0,0 @@
#!/usr/bin/env node
var program = require('commander');
var spawn = require('child_process').spawn;
var fs = require('fs');
var ListSuites = require('./utils/ListSuites');
let suite;
program
.description('Run the tests for the current suite or the provided one.')
.arguments('[suite]')
.option('--headless', 'Run in headless mode.')
.option('--forbid-only', 'Forbid only and pending filters.')
.action((suiteArg) => suite = suiteArg)
.parse(process.argv);
async function runTests(suite, withEnv) {
return new Promise((resolve, reject) => {
let mochaArgs = ['--exit', '--colors', '--require', 'ts-node/register', 'test/suites/' + suite + '/test.ts']
if (program.forbidOnly) {
mochaArgs = ['--forbid-only', '--forbid-pending'].concat(mochaArgs);
}
const mochaCommand = './node_modules/.bin/mocha ' + mochaArgs.join(' ');
let testProcess;
if (!withEnv) {
testProcess = spawn(mochaCommand, {
shell: true,
env: {
...process.env,
TS_NODE_PROJECT: 'test/tsconfig.json',
HEADLESS: (program.headless) ? 'y' : 'n',
ENVIRONMENT: 'dev',
}
});
} else {
testProcess = spawn('./node_modules/.bin/ts-node',
['-P', 'test/tsconfig.json', '--', './scripts/run-environment.ts', suite, mochaCommand], {
env: {
...process.env,
TS_NODE_PROJECT: 'test/tsconfig.json',
HEADLESS: (program.headless) ? 'y' : 'n',
ENVIRONMENT: 'dev',
}
});
}
testProcess.stdout.pipe(process.stdout);
testProcess.stderr.pipe(process.stderr);
testProcess.on('exit', function(statusCode) {
if (statusCode == 0) resolve();
reject(new Error('Tests exited with status ' + statusCode));
});
});
}
async function runAllTests() {
const suites = ListSuites();
let failure = false;
for(var s in suites) {
try {
console.log('Running suite %s', suites[s]);
await runTests(suites[s], true);
} catch (e) {
console.error(e);
failure = true;
}
}
if (failure) {
throw new Error('Some tests failed.');
}
}
const ENVIRONMENT_FILENAME = '.suite'; // This file is created by the start command.
const suiteFileExists = fs.existsSync(ENVIRONMENT_FILENAME);
if (suite) {
if (suiteFileExists && suite != fs.readFileSync(ENVIRONMENT_FILENAME)) {
console.error('You cannot test a suite while another one is running. If you want to test the current suite, ' +
'do not provide the suite argument. Otherwise, stop the current suite and run the command again.');
process.exit(1);
}
console.log('Suite %s provided. Running test related to this suite against built version of Authelia.', suite);
runTests(suite, !suiteFileExists)
.catch((err) => {
console.error(err);
process.exit(1);
});
}
else if (suiteFileExists) {
suite = fs.readFileSync(ENVIRONMENT_FILENAME);
console.log('Suite %s detected from dev env. Running test related to this suite.', suite);
runTests(suite, false)
.catch((err) => {
console.error(err);
process.exit(1);
});
}
else {
console.log('No suite provided therefore all suites will be tested.');
runAllTests(suite)
.catch((err) => {
console.error(err);
process.exit(1);
});
}
// Sometime SIGINT is received twice, we make sure with this variable that we cleanup
// only once.
var alreadyCleaningUp = false;
// Properly cleanup server and client if ctrl-c is hit
process.on('SIGINT', function() {
if (alreadyCleaningUp) return;
alreadyCleaningUp = true;
console.log('Cleanup procedure is running...');
});

View File

@ -1,39 +0,0 @@
#!/bin/bash
set -e
source bootstrap.sh
docker --version
docker-compose --version
authelia-scripts bootstrap
docker-compose -f docker-compose.yml \
-f example/compose/mongo/docker-compose.yml \
-f example/compose/redis/docker-compose.yml \
-f example/compose/nginx/portal/docker-compose.yml \
-f example/compose/smtp/docker-compose.yml \
-f example/compose/httpbin/docker-compose.yml \
-f example/compose/ldap/docker-compose.admin.yml \
-f example/compose/ldap/docker-compose.yml \
pull
# Build
echo "===> Build stage"
authelia-scripts build
# Run unit tests
echo "===> Unit tests stage"
authelia-scripts unittest
# Build the docker image
echo "===> Docker image build stage"
authelia-scripts docker build
# Run integration tests
echo "===> e2e stage"
authelia-scripts suites test --headless --forbid-only
# Test npm deployment before actual deployment
# ./scripts/npm-deployment-test.sh

View File

@ -1,3 +0,0 @@
#!/bin/bash
go test ./...

View File

@ -1,43 +0,0 @@
#!/bin/bash
set -e
NPM_UNPACK_DIR=/tmp/npm-unpack
echo "--- Packing npm package into a tarball"
npm pack
AUTHELIA_PACKAGE=`ls | grep "authelia-\([0-9]\+.\)\{2\}[0-9]\+.tgz"`
echo "--- Authelia package is ${AUTHELIA_PACKAGE}"
tar -tzvf ${AUTHELIA_PACKAGE}
echo "--- Copy package into "${NPM_UNPACK_DIR}" to test unpacking"
mkdir -p ${NPM_UNPACK_DIR}
cp ${AUTHELIA_PACKAGE} ${NPM_UNPACK_DIR}
pushd ${NPM_UNPACK_DIR}
echo "--- Test unpacking..."
npm install ${AUTHELIA_PACKAGE}
RET_CODE_INSTALL=$?
# echo ${RET_CODE}
# The binary must start and display the help menu
./node_modules/.bin/authelia | grep "No config file has been provided."
RET_CODE_RUN=$?
popd
if [ "$RET_CODE_INSTALL" != "0" ] || [ "$RET_CODE_RUN" != "0" ]
then
echo "--- Unpacking failed..."
exit 1
else
echo "+++ Unpacking succeeded"
exit 0
fi

View File

@ -39,11 +39,12 @@ async function stop() {
console.error('Teardown timed out...');
process.exit(1);
}, teardown_timeout);
console.log('>>> Tearing down environment <<<');
try {
console.log('>>> Tearing down environment <<<');
await teardown();
clearTimeout(timer);
} catch (err) {
} catch(err) {
console.error(err);
throw err;
}

View File

@ -1,6 +0,0 @@
module.exports = {
IMAGE_NAME: 'authelia',
DOCKERHUB_IMAGE_NAME: 'clems4ever/authelia'
}

View File

@ -14,8 +14,8 @@ class AutheliaServerFromDist implements AutheliaServerInterface {
}
async start() {
console.log("Spawn authelia server from dist.");
this.serverProcess = ChildProcess.spawn('./scripts/authelia-scripts serve ' + this.configPath, {
console.log("Spawn authelia server from dist using config " + this.configPath);
this.serverProcess = ChildProcess.spawn('./cmd/authelia-scripts/authelia-scripts serve ' + this.configPath, {
shell: true,
env: process.env,
} as any);

View File

@ -30,7 +30,7 @@ export default function(timeout: number = 5000) {
await VisitPage(this.driver, "https://admin.example.com:8080/secret.html");
// the url should be the one from the portal.
await VerifyUrlContains(this.driver, "https://login.example.com:8080/#/?rd=https://admin.example.com:8080", timeout);
await VerifyUrlContains(this.driver, "https://login.example.com:8080/#/?rd=https://admin.example.com:8080/secret.html", timeout);
// And the user should end up on the second factor page.
await VerifyIsSecondFactorStage(this.driver, timeout);