Add support for PostgreSQL.
parent
b2ced06402
commit
6303485fd2
|
@ -136,7 +136,7 @@ func runSuiteSetupTeardown(command string, suite string) error {
|
|||
|
||||
s := suites.GlobalRegistry.Get(selectedSuite)
|
||||
|
||||
cmd := utils.CommandWithStdout("bash", "-c", "go run cmd/authelia-suites/*.go "+command+" "+selectedSuite)
|
||||
cmd := utils.CommandWithStdout("go", "run", "cmd/authelia-suites/main.go", command, selectedSuite)
|
||||
cmd.Env = os.Environ()
|
||||
return utils.RunCommandWithTimeout(cmd, s.SetUpTimeout)
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
// RunUnitTest run the unit tests
|
||||
func RunUnitTest(cobraCmd *cobra.Command, args []string) {
|
||||
log.SetLevel(log.TraceLevel)
|
||||
err := utils.Shell("go test $(go list ./... | grep -v suites)").Run()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
|
|
@ -54,6 +54,9 @@ func main() {
|
|||
logging.SetLevel(logrus.InfoLevel)
|
||||
break
|
||||
case "debug":
|
||||
logging.SetLevel(logrus.DebugLevel)
|
||||
break
|
||||
case "trace":
|
||||
logging.SetLevel(logrus.TraceLevel)
|
||||
}
|
||||
|
||||
|
@ -68,8 +71,10 @@ func main() {
|
|||
}
|
||||
|
||||
var storageProvider storage.Provider
|
||||
if config.Storage.SQL != nil {
|
||||
storageProvider = storage.NewSQLProvider(*config.Storage.SQL)
|
||||
if config.Storage.PostgreSQL != nil {
|
||||
storageProvider = storage.NewPostgreSQLProvider(*config.Storage.PostgreSQL)
|
||||
} else if config.Storage.MySQL != nil {
|
||||
storageProvider = storage.NewMySQLProvider(*config.Storage.MySQL)
|
||||
} else if config.Storage.Local != nil {
|
||||
storageProvider = storage.NewSQLiteProvider(config.Storage.Local.Path)
|
||||
} else {
|
||||
|
|
|
@ -249,14 +249,22 @@ storage:
|
|||
## local:
|
||||
## path: /var/lib/authelia/db.sqlite3
|
||||
|
||||
# Settings to connect to SQL server
|
||||
sql:
|
||||
# Settings to connect to MySQL server
|
||||
mysql:
|
||||
host: 127.0.0.1
|
||||
port: 3306
|
||||
database: authelia
|
||||
username: authelia
|
||||
password: mypassword
|
||||
|
||||
# Settings to connect to MySQL server
|
||||
# postgres:
|
||||
# host: 127.0.0.1
|
||||
# port: 3306
|
||||
# database: authelia
|
||||
# username: authelia
|
||||
# password: mypassword
|
||||
|
||||
# Configuration of the notification system.
|
||||
#
|
||||
# Notifications are sent to users when they require a password reset, a u2f
|
||||
|
|
|
@ -14,8 +14,20 @@ type SQLStorageConfiguration struct {
|
|||
Password string `yaml:"password"`
|
||||
}
|
||||
|
||||
// MySQLStorageConfiguration represents the configuration of a MySQL database
|
||||
type MySQLStorageConfiguration struct {
|
||||
SQLStorageConfiguration `yaml:",inline"`
|
||||
}
|
||||
|
||||
// PostgreSQLStorageConfiguration represents the configuration of a Postgres database
|
||||
type PostgreSQLStorageConfiguration struct {
|
||||
SQLStorageConfiguration `yaml:",inline"`
|
||||
SSLMode string `yaml:"sslmode"`
|
||||
}
|
||||
|
||||
// StorageConfiguration represents the configuration of the storage backend.
|
||||
type StorageConfiguration struct {
|
||||
Local *LocalStorageConfiguration `yaml:"local"`
|
||||
SQL *SQLStorageConfiguration `yaml:"sql"`
|
||||
MySQL *MySQLStorageConfiguration `yaml:"mysql"`
|
||||
PostgreSQL *PostgreSQLStorageConfiguration `yaml:"postgres"`
|
||||
}
|
||||
|
|
|
@ -30,4 +30,6 @@ func Validate(configuration *schema.Configuration, validator *schema.StructValid
|
|||
configuration.TOTP = &schema.TOTPConfiguration{}
|
||||
ValidateTOTP(configuration.TOTP, validator)
|
||||
}
|
||||
|
||||
ValidateSQLStorage(configuration.Storage, validator)
|
||||
}
|
||||
|
|
|
@ -19,6 +19,11 @@ func newDefaultConfig() schema.Configuration {
|
|||
Name: "authelia_session",
|
||||
Secret: "secret",
|
||||
}
|
||||
config.Storage = &schema.StorageConfiguration{
|
||||
Local: &schema.LocalStorageConfiguration{
|
||||
Path: "abc",
|
||||
},
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
|
|
|
@ -8,12 +8,14 @@ import (
|
|||
|
||||
// ValidateSQLStorage validates storage configuration.
|
||||
func ValidateSQLStorage(configuration *schema.StorageConfiguration, validator *schema.StructValidator) {
|
||||
if configuration.Local == nil && configuration.SQL == nil {
|
||||
validator.Push(errors.New("A storage configuration must be provided. It could be 'local' or 'sql'"))
|
||||
if configuration.Local == nil && configuration.MySQL == nil && configuration.PostgreSQL == nil {
|
||||
validator.Push(errors.New("A storage configuration must be provided. It could be 'local', 'mysql' or 'postgres'"))
|
||||
}
|
||||
|
||||
if configuration.SQL != nil {
|
||||
validateSQLConfiguration(configuration.SQL, validator)
|
||||
if configuration.MySQL != nil {
|
||||
validateSQLConfiguration(&configuration.MySQL.SQLStorageConfiguration, validator)
|
||||
} else if configuration.PostgreSQL != nil {
|
||||
validatePostgreSQLConfiguration(configuration.PostgreSQL, validator)
|
||||
} else if configuration.Local != nil {
|
||||
validateLocalStorageConfiguration(configuration.Local, validator)
|
||||
}
|
||||
|
@ -29,6 +31,19 @@ func validateSQLConfiguration(configuration *schema.SQLStorageConfiguration, val
|
|||
}
|
||||
}
|
||||
|
||||
func validatePostgreSQLConfiguration(configuration *schema.PostgreSQLStorageConfiguration, validator *schema.StructValidator) {
|
||||
validateSQLConfiguration(&configuration.SQLStorageConfiguration, validator)
|
||||
|
||||
if configuration.SSLMode == "" {
|
||||
configuration.SSLMode = "disable"
|
||||
}
|
||||
|
||||
if !(configuration.SSLMode == "disable" || configuration.SSLMode == "require" ||
|
||||
configuration.SSLMode == "verify-ca" || configuration.SSLMode == "verify-full") {
|
||||
validator.Push(errors.New("SSL mode must be 'disable', 'require', 'verify-ca' or 'verify-full'"))
|
||||
}
|
||||
}
|
||||
|
||||
func validateLocalStorageConfiguration(configuration *schema.LocalStorageConfiguration, validator *schema.StructValidator) {
|
||||
if configuration.Path == "" {
|
||||
validator.Push(errors.New("A file path must be provided with key 'path'"))
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
version: "3"
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:12
|
||||
environment:
|
||||
- POSTGRES_PASSWORD=password
|
||||
- POSTGRES_USER=admin
|
||||
- POSTGRES_DB=authelia
|
||||
networks:
|
||||
- authelianet
|
|
@ -89,7 +89,7 @@ regulation:
|
|||
ban_time: 300
|
||||
|
||||
storage:
|
||||
sql:
|
||||
mysql:
|
||||
host: mariadb-service
|
||||
port: 3306
|
||||
database: authelia
|
||||
|
|
3
go.mod
3
go.mod
|
@ -3,17 +3,20 @@ module github.com/clems4ever/authelia
|
|||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/Gurpartap/logrus-stack v0.0.0-20170710170904-89c00d8a28f4
|
||||
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/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
|
||||
github.com/fasthttp/router v0.5.2
|
||||
github.com/fasthttp/session v1.1.3
|
||||
github.com/go-sql-driver/mysql v1.4.1
|
||||
github.com/golang/mock v1.3.1
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/kr/pty v1.1.8 // indirect
|
||||
github.com/lib/pq v1.2.0
|
||||
github.com/mattn/go-sqlite3 v1.11.0
|
||||
github.com/ogier/pflag v0.0.1 // indirect
|
||||
github.com/onsi/ginkgo v1.10.3 // indirect
|
||||
|
|
6
go.sum
6
go.sum
|
@ -7,6 +7,8 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOC
|
|||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/BurntSushi/xgbutil v0.0.0-20160919175755-f7c97cef3b4e h1:4ZrkT/RzpnROylmoQL57iVUL57wGKTR5O6KpVnbm2tA=
|
||||
github.com/BurntSushi/xgbutil v0.0.0-20160919175755-f7c97cef3b4e/go.mod h1:uw9h2sd4WWHOPdJ13MQpwK5qYWKYDumDqxWWIknEQ+k=
|
||||
github.com/Gurpartap/logrus-stack v0.0.0-20170710170904-89c00d8a28f4 h1:vdT7QwBhJJEVNFMBNhRSFDRCB6O16T28VhvqRgqFyn8=
|
||||
github.com/Gurpartap/logrus-stack v0.0.0-20170710170904-89c00d8a28f4/go.mod h1:SvXOG8ElV28oAiG9zv91SDe5+9PfIr7PPccpr8YyXNs=
|
||||
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=
|
||||
|
@ -35,6 +37,8 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumC
|
|||
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=
|
||||
github.com/duosecurity/duo_api_golang v0.0.0-20190308151101-6c680f768e74/go.mod h1:UqXY1lYT/ERa4OEAywUqdok1T4RCRdArkhic1Opuavo=
|
||||
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A=
|
||||
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg=
|
||||
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=
|
||||
|
@ -87,6 +91,8 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv
|
|||
github.com/kr/pty v1.1.8 h1:AkaSdXYQOWeaO3neb8EM634ahkXXe3jYbVh/F9lq+GI=
|
||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
|
|
|
@ -5,13 +5,11 @@ import (
|
|||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/clems4ever/authelia/regulation"
|
||||
|
||||
"github.com/clems4ever/authelia/session"
|
||||
|
||||
"github.com/clems4ever/authelia/authentication"
|
||||
"github.com/clems4ever/authelia/authorization"
|
||||
"github.com/clems4ever/authelia/middlewares"
|
||||
"github.com/clems4ever/authelia/regulation"
|
||||
"github.com/clems4ever/authelia/session"
|
||||
)
|
||||
|
||||
// FirstFactorPost is the handler performing the first factory.
|
||||
|
@ -51,7 +49,7 @@ func FirstFactorPost(ctx *middlewares.AutheliaCtx) {
|
|||
}
|
||||
|
||||
if !userPasswordOk {
|
||||
ctx.Error(fmt.Errorf("Credentials are wrong for user %s", bodyJSON.Username), authenticationFailedMessage)
|
||||
ctx.ReplyError(fmt.Errorf("Credentials are wrong for user %s", bodyJSON.Username), authenticationFailedMessage)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -89,7 +87,7 @@ func FirstFactorPost(ctx *middlewares.AutheliaCtx) {
|
|||
return
|
||||
}
|
||||
|
||||
ctx.Logger.Debugf("Details for user %s => groups: %s, emails %s", bodyJSON.Username, userDetails.Groups, userDetails.Emails)
|
||||
ctx.Logger.Tracef("Details for user %s => groups: %s, emails %s", bodyJSON.Username, userDetails.Groups, userDetails.Emails)
|
||||
|
||||
// And set those information in the new session.
|
||||
userSession := ctx.GetSession()
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
|
||||
// LogoutPost is the handler logging out the user attached to the given cookie.
|
||||
func LogoutPost(ctx *middlewares.AutheliaCtx) {
|
||||
ctx.Logger.Debug("Destroy session")
|
||||
ctx.Logger.Tracef("Destroy session")
|
||||
err := ctx.Providers.SessionProvider.DestroySession(ctx.RequestCtx)
|
||||
|
||||
if err != nil {
|
||||
|
|
|
@ -158,7 +158,7 @@ func hasUserBeenInactiveLongEnough(ctx *middlewares.AutheliaCtx) (bool, error) {
|
|||
lastActivity := ctx.GetSession().LastActivity
|
||||
inactivityPeriod := time.Now().Unix() - lastActivity
|
||||
|
||||
ctx.Logger.Debugf("Inactivity report: Inactivity=%d, MaxInactivity=%d",
|
||||
ctx.Logger.Tracef("Inactivity report: Inactivity=%d, MaxInactivity=%d",
|
||||
inactivityPeriod, maxInactivityPeriod)
|
||||
|
||||
if inactivityPeriod > maxInactivityPeriod {
|
||||
|
|
|
@ -1,10 +1,17 @@
|
|||
package logging
|
||||
|
||||
import (
|
||||
logrus_stack "github.com/Gurpartap/logrus-stack"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
func init() {
|
||||
callerLevels := []logrus.Level{}
|
||||
stackLevels := []logrus.Level{logrus.PanicLevel, logrus.FatalLevel, logrus.ErrorLevel}
|
||||
logrus.AddHook(logrus_stack.NewHook(callerLevels, stackLevels))
|
||||
}
|
||||
|
||||
// Logger return the standard logrues logger.
|
||||
func Logger() *logrus.Logger {
|
||||
return logrus.StandardLogger()
|
||||
|
|
|
@ -45,6 +45,7 @@ func AutheliaMiddleware(configuration schema.Configuration, providers Providers)
|
|||
}
|
||||
}
|
||||
|
||||
// Error reply with an error and display the stack trace in the logs.
|
||||
func (c *AutheliaCtx) Error(err error, message string) {
|
||||
b, _ := json.Marshal(ErrorResponse{Status: "KO", Message: message})
|
||||
c.SetContentType("application/json")
|
||||
|
@ -52,6 +53,14 @@ func (c *AutheliaCtx) Error(err error, message string) {
|
|||
c.Logger.Error(err)
|
||||
}
|
||||
|
||||
// ReplyError reply with an error but does not display any stack trace in the logs
|
||||
func (c *AutheliaCtx) ReplyError(err error, message string) {
|
||||
b, _ := json.Marshal(ErrorResponse{Status: "KO", Message: message})
|
||||
c.SetContentType("application/json")
|
||||
c.SetBody(b)
|
||||
c.Logger.Debug(err)
|
||||
}
|
||||
|
||||
// ReplyUnauthorized response sent when user is unauthorized
|
||||
func (c *AutheliaCtx) ReplyUnauthorized() {
|
||||
c.RequestCtx.Error(fasthttp.StatusMessage(fasthttp.StatusUnauthorized), fasthttp.StatusUnauthorized)
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
package storage
|
||||
|
||||
var preferencesTableName = "PreferencesTableName"
|
||||
var identityVerificationTokensTableName = "IdentityVerificationTokens"
|
||||
var totpSecretsTableName = "TOTPSecrets"
|
||||
var u2fDeviceHandlesTableName = "U2FDeviceHandles"
|
||||
var authenticationLogsTableName = "AuthenticationLogs"
|
|
@ -14,8 +14,8 @@ type MySQLProvider struct {
|
|||
SQLProvider
|
||||
}
|
||||
|
||||
// NewSQLProvider a SQL provider
|
||||
func NewSQLProvider(configuration schema.SQLStorageConfiguration) *MySQLProvider {
|
||||
// NewMySQLProvider a MySQL provider
|
||||
func NewMySQLProvider(configuration schema.MySQLStorageConfiguration) *MySQLProvider {
|
||||
connectionString := configuration.Username
|
||||
|
||||
if configuration.Password != "" {
|
||||
|
@ -36,14 +36,30 @@ func NewSQLProvider(configuration schema.SQLStorageConfiguration) *MySQLProvider
|
|||
connectionString += fmt.Sprintf("/%s", configuration.Database)
|
||||
}
|
||||
|
||||
fmt.Println(connectionString)
|
||||
|
||||
db, err := sql.Open("mysql", connectionString)
|
||||
if err != nil {
|
||||
logging.Logger().Fatalf("Unable to connect to SQL database: %v", err)
|
||||
}
|
||||
|
||||
provider := MySQLProvider{}
|
||||
provider := MySQLProvider{
|
||||
SQLProvider{
|
||||
sqlGetPreferencesByUsername: fmt.Sprintf("SELECT second_factor_method FROM %s WHERE username=?", preferencesTableName),
|
||||
sqlUpsertSecondFactorPreference: fmt.Sprintf("REPLACE INTO %s (username, second_factor_method) VALUES (?, ?)", preferencesTableName),
|
||||
|
||||
sqlTestIdentityVerificationTokenExistence: fmt.Sprintf("SELECT EXISTS (SELECT * FROM %s WHERE token=?)", identityVerificationTokensTableName),
|
||||
sqlInsertIdentityVerificationToken: fmt.Sprintf("INSERT INTO %s (token) VALUES (?)", identityVerificationTokensTableName),
|
||||
sqlDeleteIdentityVerificationToken: fmt.Sprintf("DELETE FROM %s WHERE token=?", identityVerificationTokensTableName),
|
||||
|
||||
sqlGetTOTPSecretByUsername: fmt.Sprintf("SELECT secret FROM %s WHERE username=?", totpSecretsTableName),
|
||||
sqlUpsertTOTPSecret: fmt.Sprintf("REPLACE INTO %s (username, secret) VALUES (?, ?)", totpSecretsTableName),
|
||||
|
||||
sqlGetU2FDeviceHandleByUsername: fmt.Sprintf("SELECT deviceHandle FROM %s WHERE username=?", u2fDeviceHandlesTableName),
|
||||
sqlUpsertU2FDeviceHandle: fmt.Sprintf("REPLACE INTO %s (username, deviceHandle) VALUES (?, ?)", u2fDeviceHandlesTableName),
|
||||
|
||||
sqlInsertAuthenticationLog: fmt.Sprintf("INSERT INTO %s (username, successful, time) VALUES (?, ?, ?)", authenticationLogsTableName),
|
||||
sqlGetLatestAuthenticationLogs: fmt.Sprintf("SELECT successful, time FROM %s WHERE time>? AND username=? ORDER BY time DESC", authenticationLogsTableName),
|
||||
},
|
||||
}
|
||||
if err := provider.initialize(db); err != nil {
|
||||
logging.Logger().Fatalf("Unable to initialize SQL database: %v", err)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/clems4ever/authelia/configuration/schema"
|
||||
"github.com/clems4ever/authelia/logging"
|
||||
_ "github.com/lib/pq" // Load the PostgreSQL Driver used in the connection string.
|
||||
)
|
||||
|
||||
// PostgreSQLProvider is a Postrgres provider
|
||||
type PostgreSQLProvider struct {
|
||||
SQLProvider
|
||||
}
|
||||
|
||||
// NewPostgreSQLProvider a SQL provider
|
||||
func NewPostgreSQLProvider(configuration schema.PostgreSQLStorageConfiguration) *PostgreSQLProvider {
|
||||
args := make([]string, 0)
|
||||
if configuration.Username != "" {
|
||||
args = append(args, fmt.Sprintf("user='%s'", configuration.Username))
|
||||
}
|
||||
|
||||
if configuration.Password != "" {
|
||||
args = append(args, fmt.Sprintf("password='%s'", configuration.Password))
|
||||
}
|
||||
|
||||
if configuration.Host != "" {
|
||||
args = append(args, fmt.Sprintf("host=%s", configuration.Host))
|
||||
}
|
||||
|
||||
if configuration.Port > 0 {
|
||||
args = append(args, fmt.Sprintf("port=%d", configuration.Port))
|
||||
}
|
||||
|
||||
if configuration.Database != "" {
|
||||
args = append(args, fmt.Sprintf("dbname=%s", configuration.Database))
|
||||
}
|
||||
|
||||
if configuration.SSLMode != "" {
|
||||
args = append(args, fmt.Sprintf("sslmode=%s", configuration.SSLMode))
|
||||
}
|
||||
|
||||
connectionString := strings.Join(args, " ")
|
||||
|
||||
db, err := sql.Open("postgres", connectionString)
|
||||
if err != nil {
|
||||
logging.Logger().Fatalf("Unable to connect to SQL database: %v", err)
|
||||
}
|
||||
|
||||
provider := PostgreSQLProvider{
|
||||
SQLProvider{
|
||||
sqlGetPreferencesByUsername: fmt.Sprintf("SELECT second_factor_method FROM %s WHERE username=$1", preferencesTableName),
|
||||
sqlUpsertSecondFactorPreference: fmt.Sprintf("INSERT INTO %s (username, second_factor_method) VALUES ($1, $2) ON CONFLICT (username) DO UPDATE SET method=$2", preferencesTableName),
|
||||
|
||||
sqlTestIdentityVerificationTokenExistence: fmt.Sprintf("SELECT EXISTS (SELECT * FROM %s WHERE token=$1)", identityVerificationTokensTableName),
|
||||
sqlInsertIdentityVerificationToken: fmt.Sprintf("INSERT INTO %s (token) VALUES ($1)", identityVerificationTokensTableName),
|
||||
sqlDeleteIdentityVerificationToken: fmt.Sprintf("DELETE FROM %s WHERE token=$1", identityVerificationTokensTableName),
|
||||
|
||||
sqlGetTOTPSecretByUsername: fmt.Sprintf("SELECT secret FROM %s WHERE username=$1", totpSecretsTableName),
|
||||
sqlUpsertTOTPSecret: fmt.Sprintf("INSERT INTO %s (username, secret) VALUES ($1, $2) ON CONFLICT (username) DO UPDATE SET secret=$2", totpSecretsTableName),
|
||||
|
||||
sqlGetU2FDeviceHandleByUsername: fmt.Sprintf("SELECT deviceHandle FROM %s WHERE username=$1", u2fDeviceHandlesTableName),
|
||||
sqlUpsertU2FDeviceHandle: fmt.Sprintf("INSERT INTO %s (username, deviceHandle) VALUES ($1, $2) ON CONFLICT (username) DO UPDATE SET deviceHandle=$2", u2fDeviceHandlesTableName),
|
||||
|
||||
sqlInsertAuthenticationLog: fmt.Sprintf("INSERT INTO %s (username, successful, time) VALUES ($1, $2, $3)", authenticationLogsTableName),
|
||||
sqlGetLatestAuthenticationLogs: fmt.Sprintf("SELECT successful, time FROM %s WHERE time>$1 AND username=$2 ORDER BY time DESC", authenticationLogsTableName),
|
||||
},
|
||||
}
|
||||
if err := provider.initialize(db); err != nil {
|
||||
logging.Logger().Fatalf("Unable to initialize SQL database: %v", err)
|
||||
}
|
||||
return &provider
|
||||
}
|
|
@ -2,6 +2,8 @@ package storage
|
|||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/clems4ever/authelia/models"
|
||||
|
@ -10,42 +12,58 @@ import (
|
|||
// SQLProvider is a storage provider persisting data in a SQL database.
|
||||
type SQLProvider struct {
|
||||
db *sql.DB
|
||||
|
||||
sqlGetPreferencesByUsername string
|
||||
sqlUpsertSecondFactorPreference string
|
||||
|
||||
sqlTestIdentityVerificationTokenExistence string
|
||||
sqlInsertIdentityVerificationToken string
|
||||
sqlDeleteIdentityVerificationToken string
|
||||
|
||||
sqlGetTOTPSecretByUsername string
|
||||
sqlUpsertTOTPSecret string
|
||||
|
||||
sqlGetU2FDeviceHandleByUsername string
|
||||
sqlUpsertU2FDeviceHandle string
|
||||
|
||||
sqlInsertAuthenticationLog string
|
||||
sqlGetLatestAuthenticationLogs string
|
||||
}
|
||||
|
||||
func (p *SQLProvider) initialize(db *sql.DB) error {
|
||||
p.db = db
|
||||
|
||||
_, err := db.Exec("CREATE TABLE IF NOT EXISTS SecondFactorPreferences (username VARCHAR(100) PRIMARY KEY, method VARCHAR(10))")
|
||||
_, err := db.Exec(fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s (username VARCHAR(100) PRIMARY KEY, second_factor_method VARCHAR(10))", preferencesTableName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = db.Exec("CREATE TABLE IF NOT EXISTS IdentityVerificationTokens (token VARCHAR(512))")
|
||||
_, err = db.Exec(fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s (token VARCHAR(512))", identityVerificationTokensTableName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = db.Exec("CREATE TABLE IF NOT EXISTS TOTPSecrets (username VARCHAR(100) PRIMARY KEY, secret VARCHAR(64))")
|
||||
_, err = db.Exec(fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s (username VARCHAR(100) PRIMARY KEY, secret VARCHAR(64))", totpSecretsTableName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = db.Exec("CREATE TABLE IF NOT EXISTS U2FDeviceHandles (username VARCHAR(100) PRIMARY KEY, deviceHandle BLOB)")
|
||||
_, err = db.Exec(fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s (username VARCHAR(100) PRIMARY KEY, deviceHandle TEXT)", u2fDeviceHandlesTableName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = db.Exec("CREATE TABLE IF NOT EXISTS AuthenticationLogs (username VARCHAR(100), successful BOOL, time INTEGER)")
|
||||
_, err = db.Exec(fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s (username VARCHAR(100), successful BOOL, time INTEGER)", authenticationLogsTableName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = db.Exec("CREATE INDEX IF NOT EXISTS time ON AuthenticationLogs (time);")
|
||||
_, err = db.Exec(fmt.Sprintf("CREATE INDEX IF NOT EXISTS time ON %s (time);", authenticationLogsTableName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = db.Exec("CREATE INDEX IF NOT EXISTS username ON AuthenticationLogs (username);")
|
||||
_, err = db.Exec(fmt.Sprintf("CREATE INDEX IF NOT EXISTS username ON %s (username);", authenticationLogsTableName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -54,11 +72,7 @@ func (p *SQLProvider) initialize(db *sql.DB) error {
|
|||
|
||||
// LoadPrefered2FAMethod load the prefered method for 2FA from sqlite db.
|
||||
func (p *SQLProvider) LoadPrefered2FAMethod(username string) (string, error) {
|
||||
stmt, err := p.db.Prepare("SELECT method FROM SecondFactorPreferences WHERE username=?")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
rows, err := stmt.Query(username)
|
||||
rows, err := p.db.Query(p.sqlGetPreferencesByUsername, username)
|
||||
defer rows.Close()
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
@ -76,70 +90,42 @@ func (p *SQLProvider) LoadPrefered2FAMethod(username string) (string, error) {
|
|||
|
||||
// SavePrefered2FAMethod save the prefered method for 2FA in sqlite db.
|
||||
func (p *SQLProvider) SavePrefered2FAMethod(username string, method string) error {
|
||||
stmt, err := p.db.Prepare("REPLACE INTO SecondFactorPreferences (username, method) VALUES (?, ?)")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = stmt.Exec(username, method)
|
||||
_, err := p.db.Exec(p.sqlUpsertSecondFactorPreference, username, method)
|
||||
return err
|
||||
}
|
||||
|
||||
// FindIdentityVerificationToken look for an identity verification token in DB.
|
||||
func (p *SQLProvider) FindIdentityVerificationToken(token string) (bool, error) {
|
||||
stmt, err := p.db.Prepare("SELECT token FROM IdentityVerificationTokens WHERE token=?")
|
||||
var found bool
|
||||
err := p.db.QueryRow(p.sqlTestIdentityVerificationTokenExistence, token).Scan(&found)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
var found string
|
||||
err = stmt.QueryRow(token).Scan(&found)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
return found, nil
|
||||
}
|
||||
|
||||
// SaveIdentityVerificationToken save an identity verification token in DB.
|
||||
func (p *SQLProvider) SaveIdentityVerificationToken(token string) error {
|
||||
stmt, err := p.db.Prepare("INSERT INTO IdentityVerificationTokens (token) VALUES (?)")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = stmt.Exec(token)
|
||||
_, err := p.db.Exec(p.sqlInsertIdentityVerificationToken, token)
|
||||
return err
|
||||
}
|
||||
|
||||
// RemoveIdentityVerificationToken remove an identity verification token from the DB.
|
||||
func (p *SQLProvider) RemoveIdentityVerificationToken(token string) error {
|
||||
stmt, err := p.db.Prepare("DELETE FROM IdentityVerificationTokens WHERE token=?")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = stmt.Exec(token)
|
||||
_, err := p.db.Exec(p.sqlDeleteIdentityVerificationToken, token)
|
||||
return err
|
||||
}
|
||||
|
||||
// SaveTOTPSecret save a TOTP secret of a given user.
|
||||
func (p *SQLProvider) SaveTOTPSecret(username string, secret string) error {
|
||||
stmt, err := p.db.Prepare("REPLACE INTO TOTPSecrets (username, secret) VALUES (?, ?)")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = stmt.Exec(username, secret)
|
||||
_, err := p.db.Exec(p.sqlUpsertTOTPSecret, username, secret)
|
||||
return err
|
||||
}
|
||||
|
||||
// LoadTOTPSecret load a TOTP secret given a username.
|
||||
func (p *SQLProvider) LoadTOTPSecret(username string) (string, error) {
|
||||
stmt, err := p.db.Prepare("SELECT secret FROM TOTPSecrets WHERE username=?")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
var secret string
|
||||
err = stmt.QueryRow(username).Scan(&secret)
|
||||
if err != nil {
|
||||
if err := p.db.QueryRow(p.sqlGetTOTPSecretByUsername, username).Scan(&secret); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return "", nil
|
||||
}
|
||||
|
@ -150,45 +136,32 @@ func (p *SQLProvider) LoadTOTPSecret(username string) (string, error) {
|
|||
|
||||
// SaveU2FDeviceHandle save a registered U2F device registration blob.
|
||||
func (p *SQLProvider) SaveU2FDeviceHandle(username string, keyHandle []byte) error {
|
||||
stmt, err := p.db.Prepare("REPLACE INTO U2FDeviceHandles (username, deviceHandle) VALUES (?, ?)")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = stmt.Exec(username, keyHandle)
|
||||
_, err := p.db.Exec(p.sqlUpsertU2FDeviceHandle, username, base64.StdEncoding.EncodeToString(keyHandle))
|
||||
return err
|
||||
}
|
||||
|
||||
// LoadU2FDeviceHandle load a U2F device registration blob for a given username.
|
||||
func (p *SQLProvider) LoadU2FDeviceHandle(username string) ([]byte, error) {
|
||||
stmt, err := p.db.Prepare("SELECT deviceHandle FROM U2FDeviceHandles WHERE username=?")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var deviceHandle []byte
|
||||
err = stmt.QueryRow(username).Scan(&deviceHandle)
|
||||
if err != nil {
|
||||
var deviceHandle string
|
||||
if err := p.db.QueryRow(p.sqlGetU2FDeviceHandleByUsername, username).Scan(&deviceHandle); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, ErrNoU2FDeviceHandle
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return deviceHandle, nil
|
||||
|
||||
return base64.StdEncoding.DecodeString(deviceHandle)
|
||||
}
|
||||
|
||||
// AppendAuthenticationLog append a mark to the authentication log.
|
||||
func (p *SQLProvider) AppendAuthenticationLog(attempt models.AuthenticationAttempt) error {
|
||||
stmt, err := p.db.Prepare("INSERT INTO AuthenticationLogs (username, successful, time) VALUES (?, ?, ?)")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = stmt.Exec(attempt.Username, attempt.Successful, attempt.Time.Unix())
|
||||
_, err := p.db.Exec(p.sqlInsertAuthenticationLog, attempt.Username, attempt.Successful, attempt.Time.Unix())
|
||||
return err
|
||||
}
|
||||
|
||||
// LoadLatestAuthenticationLogs retrieve the latest marks from the authentication log.
|
||||
func (p *SQLProvider) LoadLatestAuthenticationLogs(username string, fromDate time.Time) ([]models.AuthenticationAttempt, error) {
|
||||
rows, err := p.db.Query("SELECT successful, time FROM AuthenticationLogs WHERE time>? AND username=? ORDER BY time DESC",
|
||||
fromDate.Unix(), username)
|
||||
rows, err := p.db.Query(p.sqlGetLatestAuthenticationLogs, fromDate.Unix(), username)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -2,6 +2,7 @@ package storage
|
|||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
"github.com/clems4ever/authelia/logging"
|
||||
_ "github.com/mattn/go-sqlite3" // Load the SQLite Driver used in the connection string.
|
||||
|
@ -19,7 +20,25 @@ func NewSQLiteProvider(path string) *SQLiteProvider {
|
|||
logging.Logger().Fatalf("Unable to create SQLite database %s: %s", path, err)
|
||||
}
|
||||
|
||||
provider := SQLiteProvider{}
|
||||
provider := SQLiteProvider{
|
||||
SQLProvider{
|
||||
sqlGetPreferencesByUsername: fmt.Sprintf("SELECT second_factor_method FROM %s WHERE username=?", preferencesTableName),
|
||||
sqlUpsertSecondFactorPreference: fmt.Sprintf("REPLACE INTO %s (username, second_factor_method) VALUES (?, ?)", preferencesTableName),
|
||||
|
||||
sqlTestIdentityVerificationTokenExistence: fmt.Sprintf("SELECT EXISTS (SELECT * FROM %s WHERE token=?)", identityVerificationTokensTableName),
|
||||
sqlInsertIdentityVerificationToken: fmt.Sprintf("INSERT INTO %s (token) VALUES (?)", identityVerificationTokensTableName),
|
||||
sqlDeleteIdentityVerificationToken: fmt.Sprintf("DELETE FROM %s WHERE token=?", identityVerificationTokensTableName),
|
||||
|
||||
sqlGetTOTPSecretByUsername: fmt.Sprintf("SELECT secret FROM %s WHERE username=?", totpSecretsTableName),
|
||||
sqlUpsertTOTPSecret: fmt.Sprintf("REPLACE INTO %s (username, secret) VALUES (?, ?)", totpSecretsTableName),
|
||||
|
||||
sqlGetU2FDeviceHandleByUsername: fmt.Sprintf("SELECT deviceHandle FROM %s WHERE username=?", u2fDeviceHandlesTableName),
|
||||
sqlUpsertU2FDeviceHandle: fmt.Sprintf("REPLACE INTO %s (username, deviceHandle) VALUES (?, ?)", u2fDeviceHandlesTableName),
|
||||
|
||||
sqlInsertAuthenticationLog: fmt.Sprintf("INSERT INTO %s (username, successful, time) VALUES (?, ?, ?)", authenticationLogsTableName),
|
||||
sqlGetLatestAuthenticationLogs: fmt.Sprintf("SELECT successful, time FROM %s WHERE time>? AND username=? ORDER BY time DESC", authenticationLogsTableName),
|
||||
},
|
||||
}
|
||||
if err := provider.initialize(db); err != nil {
|
||||
logging.Logger().Fatalf("Unable to initialize SQLite database %s: %s", path, err)
|
||||
}
|
||||
|
|
|
@ -223,7 +223,7 @@ regulation:
|
|||
# You must use only an available configuration: local, sql
|
||||
storage:
|
||||
# Settings to connect to mariadb server
|
||||
sql:
|
||||
mysql:
|
||||
host: mariadb
|
||||
port: 3306
|
||||
database: authelia
|
||||
|
|
|
@ -22,7 +22,7 @@ session:
|
|||
|
||||
# Configuration of the storage backend used to store data and secrets. i.e. totp data
|
||||
storage:
|
||||
sql:
|
||||
mysql:
|
||||
host: mariadb
|
||||
port: 3306
|
||||
database: authelia
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
###############################################################
|
||||
# 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: users.yml
|
||||
|
||||
session:
|
||||
secret: unsecure_session_secret
|
||||
domain: example.com
|
||||
expiration: 3600 # 1 hour
|
||||
inactivity: 300 # 5 minutes
|
||||
|
||||
# Configuration of the storage backend used to store data and secrets. i.e. totp data
|
||||
storage:
|
||||
postgres:
|
||||
host: postgres
|
||||
port: 5432
|
||||
database: authelia
|
||||
username: admin
|
||||
password: password
|
||||
|
||||
# TOTP Issuer Name
|
||||
#
|
||||
# This will be the issuer name displayed in Google Authenticator
|
||||
# See: https://github.com/google/google-authenticator/wiki/Key-Uri-Format for more info on issuer names
|
||||
totp:
|
||||
issuer: example.com
|
||||
|
||||
access_control:
|
||||
default_policy: deny
|
||||
rules:
|
||||
- domain: "public.example.com"
|
||||
policy: bypass
|
||||
- domain: "admin.example.com"
|
||||
policy: two_factor
|
||||
- domain: "secure.example.com"
|
||||
policy: two_factor
|
||||
- domain: "singlefactor.example.com"
|
||||
policy: one_factor
|
||||
|
||||
# Configuration of the authentication regulation mechanism.
|
||||
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: 8
|
||||
|
||||
# The length of time before a banned user can login again.
|
||||
ban_time: 10
|
||||
|
||||
notifier:
|
||||
# Use a SMTP server for sending notifications
|
||||
smtp:
|
||||
host: smtp
|
||||
port: 1025
|
||||
sender: admin@example.com
|
|
@ -0,0 +1,29 @@
|
|||
###############################################################
|
||||
# Users Database #
|
||||
###############################################################
|
||||
|
||||
# This file can be used if you do not have an LDAP set up.
|
||||
|
||||
# List of users
|
||||
users:
|
||||
john:
|
||||
password: "{CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/"
|
||||
email: john.doe@authelia.com
|
||||
groups:
|
||||
- admins
|
||||
- dev
|
||||
|
||||
harry:
|
||||
password: "{CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/"
|
||||
email: harry.potter@authelia.com
|
||||
groups: []
|
||||
|
||||
bob:
|
||||
password: "{CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/"
|
||||
email: bob.dylan@authelia.com
|
||||
groups:
|
||||
- dev
|
||||
|
||||
james:
|
||||
password: "{CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/"
|
||||
email: james.dean@authelia.com
|
|
@ -0,0 +1,40 @@
|
|||
package suites
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
var postgresSuiteName = "Postgres"
|
||||
|
||||
func init() {
|
||||
dockerEnvironment := NewDockerEnvironment([]string{
|
||||
"docker-compose.yml",
|
||||
"example/compose/authelia/docker-compose.backend.yml",
|
||||
"example/compose/authelia/docker-compose.frontend.yml",
|
||||
"example/compose/nginx/backend/docker-compose.yml",
|
||||
"example/compose/nginx/portal/docker-compose.yml",
|
||||
"example/compose/smtp/docker-compose.yml",
|
||||
"example/compose/postgres/docker-compose.yml",
|
||||
"example/compose/ldap/docker-compose.yml",
|
||||
})
|
||||
|
||||
setup := func(suitePath string) error {
|
||||
if err := dockerEnvironment.Up(suitePath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return waitUntilAutheliaIsReady(dockerEnvironment)
|
||||
}
|
||||
|
||||
teardown := func(suitePath string) error {
|
||||
err := dockerEnvironment.Down(suitePath)
|
||||
return err
|
||||
}
|
||||
|
||||
GlobalRegistry.Register(postgresSuiteName, Suite{
|
||||
SetUp: setup,
|
||||
SetUpTimeout: 3 * time.Minute,
|
||||
TearDown: teardown,
|
||||
TearDownTimeout: 2 * time.Minute,
|
||||
})
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package suites
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
type PostgresSuite struct {
|
||||
*SeleniumSuite
|
||||
}
|
||||
|
||||
func NewPostgresSuite() *PostgresSuite {
|
||||
return &PostgresSuite{SeleniumSuite: new(SeleniumSuite)}
|
||||
}
|
||||
|
||||
func TestPostgresSuite(t *testing.T) {
|
||||
suite.Run(t, NewOneFactorSuite())
|
||||
suite.Run(t, NewTwoFactorSuite())
|
||||
}
|
|
@ -105,7 +105,7 @@ regulation:
|
|||
ban_time: 300
|
||||
|
||||
storage:
|
||||
sql:
|
||||
mysql:
|
||||
host: 127.0.0.1
|
||||
port: 3306
|
||||
database: authelia
|
||||
|
|
|
@ -10,11 +10,11 @@ import { exec } from '../../helpers/utils/exec';
|
|||
import BypassPolicy from "./scenarii/BypassPolicy";
|
||||
import NoDuoPushOption from "./scenarii/NoDuoPushOption";
|
||||
|
||||
AutheliaSuite("/tmp/authelia/suites/Basic/", function() {
|
||||
AutheliaSuite("/tmp/authelia/suites/Standalone/", function() {
|
||||
this.timeout(10000);
|
||||
|
||||
beforeEach(async function() {
|
||||
await exec(`cp ${__dirname}/../../../suites/Basic/users.yml /tmp/authelia/suites/Basic/users.yml`);
|
||||
await exec(`cp ${__dirname}/../../../suites/Standalone/users.yml /tmp/authelia/suites/Standalone/users.yml`);
|
||||
});
|
||||
|
||||
describe('Bypass policy', BypassPolicy)
|
|
@ -114,9 +114,8 @@ func RunCommandWithTimeout(cmd *exec.Cmd, timeout time.Duration) error {
|
|||
select {
|
||||
case <-time.After(timeout):
|
||||
fmt.Printf("Timeout of %ds reached... Killing process...\n", int64(timeout/time.Second))
|
||||
err := cmd.Process.Kill()
|
||||
|
||||
if err != nil {
|
||||
if err := cmd.Process.Kill(); err != nil {
|
||||
return err
|
||||
}
|
||||
return fmt.Errorf("timeout of %ds reached", int64(timeout/time.Second))
|
||||
|
|
Loading…
Reference in New Issue