[CI] Add godot linter (#958)

* [CI] Add godot linter

* Implement godot recommendations
pull/964/head
Amir Zarrinkafsh 2020-05-02 15:06:39 +10:00 committed by GitHub
parent ce5f5e9214
commit e67f63ee44
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
63 changed files with 241 additions and 242 deletions

View File

@ -4,12 +4,15 @@ run:
linters-settings: linters-settings:
gocyclo: gocyclo:
min-complexity: 15 min-complexity: 15
godot:
check-all: true
goimports: goimports:
local-prefixes: github.com/authelia/authelia local-prefixes: github.com/authelia/authelia
linters: linters:
enable: enable:
- gocyclo - gocyclo
- godot
- gofmt - gofmt
- goimports - goimports
- golint - golint

View File

@ -13,16 +13,16 @@ import (
"github.com/authelia/authelia/internal/utils" "github.com/authelia/authelia/internal/utils"
) )
// HostEntry represents an entry in /etc/hosts // HostEntry represents an entry in /etc/hosts.
type HostEntry struct { type HostEntry struct {
Domain string Domain string
IP string IP string
} }
var hostEntries = []HostEntry{ var hostEntries = []HostEntry{
// For authelia backend // For authelia backend.
{Domain: "authelia.example.com", IP: "192.168.240.50"}, {Domain: "authelia.example.com", IP: "192.168.240.50"},
// For common tests // For common tests.
{Domain: "login.example.com", IP: "192.168.240.100"}, {Domain: "login.example.com", IP: "192.168.240.100"},
{Domain: "admin.example.com", IP: "192.168.240.100"}, {Domain: "admin.example.com", IP: "192.168.240.100"},
{Domain: "singlefactor.example.com", IP: "192.168.240.100"}, {Domain: "singlefactor.example.com", IP: "192.168.240.100"},
@ -34,19 +34,15 @@ var hostEntries = []HostEntry{
{Domain: "secure.example.com", IP: "192.168.240.100"}, {Domain: "secure.example.com", IP: "192.168.240.100"},
{Domain: "mail.example.com", IP: "192.168.240.100"}, {Domain: "mail.example.com", IP: "192.168.240.100"},
{Domain: "duo.example.com", IP: "192.168.240.100"}, {Domain: "duo.example.com", IP: "192.168.240.100"},
// For Traefik suite.
// For Traefik suite
{Domain: "traefik.example.com", IP: "192.168.240.100"}, {Domain: "traefik.example.com", IP: "192.168.240.100"},
// For HAProxy suite.
// For HAProxy suite
{Domain: "haproxy.example.com", IP: "192.168.240.100"}, {Domain: "haproxy.example.com", IP: "192.168.240.100"},
// For testing network ACLs.
// For testing network ACLs
{Domain: "proxy-client1.example.com", IP: "192.168.240.201"}, {Domain: "proxy-client1.example.com", IP: "192.168.240.201"},
{Domain: "proxy-client2.example.com", IP: "192.168.240.202"}, {Domain: "proxy-client2.example.com", IP: "192.168.240.202"},
{Domain: "proxy-client3.example.com", IP: "192.168.240.203"}, {Domain: "proxy-client3.example.com", IP: "192.168.240.203"},
// Kubernetes dashboard.
// Kubernetes dashboard
{Domain: "kubernetes.example.com", IP: "192.168.240.110"}, {Domain: "kubernetes.example.com", IP: "192.168.240.110"},
} }
@ -170,7 +166,7 @@ func readVersions() {
readVersion("docker-compose", "--version") readVersion("docker-compose", "--version")
} }
// Bootstrap bootstrap authelia dev environment // Bootstrap bootstrap authelia dev environment.
func Bootstrap(cobraCmd *cobra.Command, args []string) { func Bootstrap(cobraCmd *cobra.Command, args []string) {
bootstrapPrintln("Checking command installation...") bootstrapPrintln("Checking command installation...")
checkCommandExist("node") checkCommandExist("node")

View File

@ -23,7 +23,7 @@ func buildAutheliaBinary() {
} }
func buildFrontend() { func buildFrontend() {
// Install npm dependencies // Install npm dependencies.
cmd := utils.CommandWithStdout("yarn", "install") cmd := utils.CommandWithStdout("yarn", "install")
cmd.Dir = "web" cmd.Dir = "web"
@ -31,7 +31,7 @@ func buildFrontend() {
log.Fatal(err) log.Fatal(err)
} }
// Then build the frontend // Then build the frontend.
cmd = utils.CommandWithStdout("yarn", "build") cmd = utils.CommandWithStdout("yarn", "build")
cmd.Dir = "web" cmd.Dir = "web"
cmd.Env = append(os.Environ(), "INLINE_RUNTIME_CHUNK=false") cmd.Env = append(os.Environ(), "INLINE_RUNTIME_CHUNK=false")
@ -68,7 +68,7 @@ func generateEmbeddedAssets() {
} }
} }
// Build build Authelia // Build build Authelia.
func Build(cobraCmd *cobra.Command, args []string) { func Build(cobraCmd *cobra.Command, args []string) {
log.Info("Building Authelia...") log.Info("Building Authelia...")

View File

@ -7,7 +7,7 @@ import (
"github.com/authelia/authelia/internal/utils" "github.com/authelia/authelia/internal/utils"
) )
// RunCI run the CI scripts // RunCI run the CI scripts.
func RunCI(cmd *cobra.Command, args []string) { 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 { if err := utils.CommandWithStdout("authelia-scripts", "--log-level", "debug", "build").Run(); err != nil {

View File

@ -7,7 +7,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
// Clean artifacts built and installed by authelia-scripts // Clean artifacts built and installed by authelia-scripts.
func Clean(cobraCmd *cobra.Command, args []string) { func Clean(cobraCmd *cobra.Command, args []string) {
log.Debug("Removing `" + OutputDir + "` directory") log.Debug("Removing `" + OutputDir + "` directory")
err := os.RemoveAll(OutputDir) err := os.RemoveAll(OutputDir)

View File

@ -42,12 +42,12 @@ func checkArchIsSupported(arch string) {
func dockerBuildOfficialImage(arch string) error { func dockerBuildOfficialImage(arch string) error {
docker := &Docker{} docker := &Docker{}
// Set default Architecture Dockerfile to amd64 // Set default Architecture Dockerfile to amd64.
dockerfile := "Dockerfile" dockerfile := "Dockerfile"
// Set version of QEMU // Set version of QEMU.
qemuversion := "v4.2.0-7" qemuversion := "v4.2.0-7"
// If not the default value // If not the default value.
if arch != defaultArch { if arch != defaultArch {
dockerfile = fmt.Sprintf("%s.%s", dockerfile, arch) dockerfile = fmt.Sprintf("%s.%s", dockerfile, arch)
} }
@ -120,7 +120,7 @@ var DockerBuildCmd = &cobra.Command{
}, },
} }
// DockerPushCmd Command for pushing Authelia docker image to Docker Hub // DockerPushCmd Command for pushing Authelia docker image to DockerHub.
var DockerPushCmd = &cobra.Command{ var DockerPushCmd = &cobra.Command{
Use: "push-image", Use: "push-image",
Short: "Publish Authelia docker image to Docker Hub", Short: "Publish Authelia docker image to Docker Hub",
@ -131,7 +131,7 @@ var DockerPushCmd = &cobra.Command{
}, },
} }
// DockerManifestCmd Command for pushing Authelia docker manifest to Docker Hub // DockerManifestCmd Command for pushing Authelia docker manifest to DockerHub.
var DockerManifestCmd = &cobra.Command{ var DockerManifestCmd = &cobra.Command{
Use: "push-manifest", Use: "push-manifest",
Short: "Publish Authelia docker manifest to Docker Hub", Short: "Publish Authelia docker manifest to Docker Hub",

View File

@ -7,7 +7,7 @@ import (
"github.com/authelia/authelia/internal/utils" "github.com/authelia/authelia/internal/utils"
) )
// ServeCmd serve authelia with the provided configuration // ServeCmd serve Authelia with the provided configuration.
func ServeCmd(cobraCmd *cobra.Command, args []string) { func ServeCmd(cobraCmd *cobra.Command, args []string) {
log.Infof("Running Authelia with config %s...", args[0]) log.Infof("Running Authelia with config %s...", args[0])
cmd := utils.CommandWithStdout(OutputDir+"/authelia", "--config", args[0]) cmd := utils.CommandWithStdout(OutputDir+"/authelia", "--config", args[0])

View File

@ -21,10 +21,10 @@ import (
// ErrNotAvailableSuite error raised when suite is not available. // ErrNotAvailableSuite error raised when suite is not available.
var ErrNotAvailableSuite = errors.New("unavailable suite") var ErrNotAvailableSuite = errors.New("unavailable suite")
// ErrNoRunningSuite error raised when no suite is running // ErrNoRunningSuite error raised when no suite is running.
var ErrNoRunningSuite = errors.New("no running suite") var ErrNoRunningSuite = errors.New("no running suite")
// runningSuiteFile name of the file containing the currently running suite // runningSuiteFile name of the file containing the currently running suite.
var runningSuiteFile = ".suite" var runningSuiteFile = ".suite"
var headless bool var headless bool
@ -68,7 +68,7 @@ var SuitesSetupCmd = &cobra.Command{
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
} }
// SuitesTeardownCmd Command for tearing down a suite environment // SuitesTeardownCmd Command for tearing down a suite environment.
var SuitesTeardownCmd = &cobra.Command{ var SuitesTeardownCmd = &cobra.Command{
Use: "teardown [suite]", Use: "teardown [suite]",
Short: "Teardown a Go suite environment. Suites can be listed using the list command.", Short: "Teardown a Go suite environment. Suites can be listed using the list command.",
@ -96,7 +96,7 @@ var SuitesTeardownCmd = &cobra.Command{
Args: cobra.MaximumNArgs(1), Args: cobra.MaximumNArgs(1),
} }
// SuitesTestCmd Command for testing a suite // SuitesTestCmd Command for testing a suite.
var SuitesTestCmd = &cobra.Command{ var SuitesTestCmd = &cobra.Command{
Use: "test [suite]", Use: "test [suite]",
Short: "Test a suite. Suites can be listed using the list command.", Short: "Test a suite. Suites can be listed using the list command.",
@ -192,7 +192,7 @@ func testSuite(cmd *cobra.Command, args []string) {
log.Fatal(err) log.Fatal(err)
} }
// If suite(s) are provided as argument // If suite(s) are provided as argument.
if len(args) >= 1 { if len(args) >= 1 {
suiteArg := args[0] suiteArg := args[0]
@ -242,7 +242,7 @@ func runSuiteTests(suiteName string, withEnv bool) error {
suite := suites.GlobalRegistry.Get(suiteName) suite := suites.GlobalRegistry.Get(suiteName)
// Default value is 1 minute // Default value is 1 minute.
timeout := "60s" timeout := "60s"
if suite.TestTimeout > 0 { if suite.TestTimeout > 0 {
timeout = fmt.Sprintf("%ds", int64(suite.TestTimeout/time.Second)) timeout = fmt.Sprintf("%ds", int64(suite.TestTimeout/time.Second))
@ -279,7 +279,7 @@ func runSuiteTests(suiteName string, withEnv bool) error {
if withEnv { if withEnv {
if err := teardownSuite(suiteName); err != nil { if err := teardownSuite(suiteName); err != nil {
// Do not return this error to return the test error instead // Do not return this error to return the test error instead.
log.Errorf("Error running teardown: %v", err) log.Errorf("Error running teardown: %v", err)
} }
} }

View File

@ -9,7 +9,7 @@ import (
"github.com/authelia/authelia/internal/utils" "github.com/authelia/authelia/internal/utils"
) )
// RunUnitTest run the unit tests // RunUnitTest run the unit tests.
func RunUnitTest(cobraCmd *cobra.Command, args []string) { func RunUnitTest(cobraCmd *cobra.Command, args []string) {
log.SetLevel(log.TraceLevel) log.SetLevel(log.TraceLevel)
if err := utils.Shell("go test $(go list ./... | grep -v suites)").Run(); err != nil { if err := utils.Shell("go test $(go list ./... | grep -v suites)").Run(); err != nil {

View File

@ -1,10 +1,10 @@
package main package main
// OutputDir the output directory where the built version of Authelia is located // OutputDir the output directory where the built version of Authelia is located.
var OutputDir = "dist" var OutputDir = "dist"
// DockerImageName the official name of authelia docker image // DockerImageName the official name of Authelia docker image.
var DockerImageName = "authelia/authelia" var DockerImageName = "authelia/authelia"
// IntermediateDockerImageName local name of the docker image // IntermediateDockerImageName local name of the docker image.
var IntermediateDockerImageName = "authelia:dist" var IntermediateDockerImageName = "authelia:dist"

View File

@ -4,10 +4,10 @@ import (
"github.com/authelia/authelia/internal/utils" "github.com/authelia/authelia/internal/utils"
) )
// Docker a docker object // Docker a docker object.
type Docker struct{} type Docker struct{}
// Build build a docker image // Build build a docker image.
func (d *Docker) Build(tag, dockerfile, target, gitTag, gitCommit string) error { func (d *Docker) Build(tag, dockerfile, target, gitTag, gitCommit string) error {
return utils.CommandWithStdout( return utils.CommandWithStdout(
"docker", "build", "-t", tag, "-f", dockerfile, "--build-arg", "docker", "build", "-t", tag, "-f", dockerfile, "--build-arg",

View File

@ -1,4 +1,5 @@
//usr/bin/env go run "$0" "$@"; exit //usr/bin/env go run "$0" "$@"; exit
//nolint:godot
package main package main
@ -23,10 +24,10 @@ type AutheliaCommandDefinition struct {
SubCommands []*cobra.Command SubCommands []*cobra.Command
} }
// CobraCommands list of cobra commands // CobraCommands list of cobra commands.
type CobraCommands = []*cobra.Command type CobraCommands = []*cobra.Command
// Commands is the list of commands of authelia-scripts // Commands is the list of commands of authelia-scripts.
var Commands = []AutheliaCommandDefinition{ var Commands = []AutheliaCommandDefinition{
{ {
Name: "bootstrap", Name: "bootstrap",

View File

@ -15,7 +15,7 @@ import (
var tmpDirectory = "/tmp/authelia/suites/" var tmpDirectory = "/tmp/authelia/suites/"
// runningSuiteFile name of the file containing the currently running suite // runningSuiteFile name of the file containing the currently running suite.
var runningSuiteFile = ".suite" var runningSuiteFile = ".suite"
func init() { func init() {

View File

@ -21,7 +21,7 @@ const (
Push = "mobile_push" Push = "mobile_push"
) )
// PossibleMethods is the set of all possible 2FA methods // PossibleMethods is the set of all possible 2FA methods.
var PossibleMethods = []string{TOTP, U2F, Push} var PossibleMethods = []string{TOTP, U2F, Push}
const ( const (

View File

@ -285,7 +285,7 @@ groups:
- dev - dev
`) `)
// The YAML is valid but the root key is user instead of users // The YAML is valid but the root key is user instead of users.
var BadSchemaUserDatabaseContent = []byte(` var BadSchemaUserDatabaseContent = []byte(`
user: user:
john: john:

View File

@ -6,7 +6,7 @@ import (
"github.com/go-ldap/ldap/v3" "github.com/go-ldap/ldap/v3"
) )
// ********************* CONNECTION ********************* // ********************* CONNECTION *********************.
// LDAPConnection interface representing a connection to the ldap. // LDAPConnection interface representing a connection to the ldap.
type LDAPConnection interface { type LDAPConnection interface {
@ -47,7 +47,7 @@ func (lc *LDAPConnectionImpl) Modify(modifyRequest *ldap.ModifyRequest) error {
return lc.conn.Modify(modifyRequest) return lc.conn.Modify(modifyRequest)
} }
// ********************* FACTORY *********************** // ********************* FACTORY ***********************.
// LDAPConnectionFactory an interface of factory of ldap connections. // LDAPConnectionFactory an interface of factory of ldap connections.
type LDAPConnectionFactory interface { type LDAPConnectionFactory interface {

View File

@ -12,7 +12,7 @@ import (
) )
// PasswordHash represents all characteristics of a password hash. // PasswordHash represents all characteristics of a password hash.
// Authelia only supports salted SHA512 or salted argon2id method, i.e., $6$ mode or $argon2id$ mode // Authelia only supports salted SHA512 or salted argon2id method, i.e., $6$ mode or $argon2id$ mode.
type PasswordHash struct { type PasswordHash struct {
Algorithm string Algorithm string
Iterations int Iterations int
@ -23,11 +23,11 @@ type PasswordHash struct {
Parallelism int Parallelism int
} }
// ParseHash extracts all characteristics of a hash given its string representation // ParseHash extracts all characteristics of a hash given its string representation.
func ParseHash(hash string) (passwordHash *PasswordHash, err error) { func ParseHash(hash string) (passwordHash *PasswordHash, err error) {
parts := strings.Split(hash, "$") parts := strings.Split(hash, "$")
// This error can be ignored as it's always nil // This error can be ignored as it's always nil.
code, parameters, salt, key, _ := crypt.DecodeSettings(hash) code, parameters, salt, key, _ := crypt.DecodeSettings(hash)
h := &PasswordHash{} h := &PasswordHash{}
@ -81,8 +81,8 @@ func ParseHash(hash string) (passwordHash *PasswordHash, err error) {
return h, nil return h, nil
} }
// HashPassword generate a salt and hash the password with the salt and a constant number of rounds // HashPassword generate a salt and hash the password with the salt and a constant number of rounds.
//nolint:gocyclo // TODO: Consider refactoring/simplifying, time permitting //nolint:gocyclo // TODO: Consider refactoring/simplifying, time permitting.
func HashPassword(password, salt, algorithm string, iterations, memory, parallelism, keyLength, saltLength int) (hash string, err error) { func HashPassword(password, salt, algorithm string, iterations, memory, parallelism, keyLength, saltLength int) (hash string, err error) {
var settings string var settings string
@ -105,7 +105,7 @@ func HashPassword(password, salt, algorithm string, iterations, memory, parallel
} }
if algorithm == HashingAlgorithmArgon2id { if algorithm == HashingAlgorithmArgon2id {
// Caution: Increasing any of the values in the below block has a high chance in old passwords that cannot be verified // Caution: Increasing any of the values in the below block has a high chance in old passwords that cannot be verified.
if memory < 8 { if memory < 8 {
return "", fmt.Errorf("Memory (argon2id) input of %d is invalid, it must be 8 or higher", memory) return "", fmt.Errorf("Memory (argon2id) input of %d is invalid, it must be 8 or higher", memory)
} }
@ -121,7 +121,7 @@ func HashPassword(password, salt, algorithm string, iterations, memory, parallel
if iterations < 1 { if iterations < 1 {
return "", fmt.Errorf("Iterations (argon2id) input of %d is invalid, it must be 1 or more", iterations) return "", fmt.Errorf("Iterations (argon2id) input of %d is invalid, it must be 1 or more", iterations)
} }
// Caution: Increasing any of the values in the above block has a high chance in old passwords that cannot be verified // Caution: Increasing any of the values in the above block has a high chance in old passwords that cannot be verified.
} }
if salt == "" { if salt == "" {
@ -129,12 +129,12 @@ func HashPassword(password, salt, algorithm string, iterations, memory, parallel
} }
settings = getCryptSettings(salt, algorithm, iterations, memory, parallelism, keyLength) settings = getCryptSettings(salt, algorithm, iterations, memory, parallelism, keyLength)
// This error can be ignored because we check for it before a user gets here // This error can be ignored because we check for it before a user gets here.
hash, _ = crypt.Crypt(password, settings) hash, _ = crypt.Crypt(password, settings)
return hash, nil return hash, nil
} }
// CheckPassword check a password against a hash // CheckPassword check a password against a hash.
func CheckPassword(password, hash string) (ok bool, err error) { func CheckPassword(password, hash string) (ok bool, err error) {
passwordHash, err := ParseHash(hash) passwordHash, err := ParseHash(hash)
if err != nil { if err != nil {

View File

@ -45,7 +45,7 @@ func TestShouldHashArgon2idPassword(t *testing.T) {
assert.Equal(t, schema.DefaultCIPasswordConfiguration.KeyLength, parameters.GetInt("k", HashingDefaultArgon2idKeyLength)) assert.Equal(t, schema.DefaultCIPasswordConfiguration.KeyLength, parameters.GetInt("k", HashingDefaultArgon2idKeyLength))
} }
// This checks the method of hashing (for argon2id) supports all the characters we allow in Authelia's hash function // This checks the method of hashing (for argon2id) supports all the characters we allow in Authelia's hash function.
func TestArgon2idHashSaltValidValues(t *testing.T) { func TestArgon2idHashSaltValidValues(t *testing.T) {
data := string(HashingPossibleSaltCharacters) data := string(HashingPossibleSaltCharacters)
datas := utils.SliceString(data, 16) datas := utils.SliceString(data, 16)
@ -58,7 +58,7 @@ func TestArgon2idHashSaltValidValues(t *testing.T) {
} }
} }
// This checks the method of hashing (for sha512) supports all the characters we allow in Authelia's hash function // This checks the method of hashing (for sha512) supports all the characters we allow in Authelia's hash function.
func TestSHA512HashSaltValidValues(t *testing.T) { func TestSHA512HashSaltValidValues(t *testing.T) {
data := string(HashingPossibleSaltCharacters) data := string(HashingPossibleSaltCharacters)
datas := utils.SliceString(data, 16) datas := utils.SliceString(data, 16)

View File

@ -36,7 +36,7 @@ func (s Subject) String() string {
return fmt.Sprintf("username=%s groups=%s ip=%s", s.Username, strings.Join(s.Groups, ","), s.IP.String()) return fmt.Sprintf("username=%s groups=%s ip=%s", s.Username, strings.Join(s.Groups, ","), s.IP.String())
} }
// Object object to check access control for // Object object to check access control for.
type Object struct { type Object struct {
Domain string Domain string
Path string Path string

View File

@ -19,7 +19,7 @@ type SessionConfiguration struct {
Redis *RedisSessionConfiguration `mapstructure:"redis"` Redis *RedisSessionConfiguration `mapstructure:"redis"`
} }
// DefaultSessionConfiguration is the default session configuration // DefaultSessionConfiguration is the default session configuration.
var DefaultSessionConfiguration = SessionConfiguration{ var DefaultSessionConfiguration = SessionConfiguration{
Name: "authelia_session", Name: "authelia_session",
Expiration: "1h", Expiration: "1h",

View File

@ -5,7 +5,7 @@ type LocalStorageConfiguration struct {
Path string `mapstructure:"path"` Path string `mapstructure:"path"`
} }
// SQLStorageConfiguration represents the configuration of the SQL database // SQLStorageConfiguration represents the configuration of the SQL database.
type SQLStorageConfiguration struct { type SQLStorageConfiguration struct {
Host string `mapstructure:"host"` Host string `mapstructure:"host"`
Port int `mapstructure:"port"` Port int `mapstructure:"port"`
@ -14,12 +14,12 @@ type SQLStorageConfiguration struct {
Password string `mapstructure:"password"` Password string `mapstructure:"password"`
} }
// MySQLStorageConfiguration represents the configuration of a MySQL database // MySQLStorageConfiguration represents the configuration of a MySQL database.
type MySQLStorageConfiguration struct { type MySQLStorageConfiguration struct {
SQLStorageConfiguration `mapstructure:",squash"` SQLStorageConfiguration `mapstructure:",squash"`
} }
// PostgreSQLStorageConfiguration represents the configuration of a Postgres database // PostgreSQLStorageConfiguration represents the configuration of a Postgres database.
type PostgreSQLStorageConfiguration struct { type PostgreSQLStorageConfiguration struct {
SQLStorageConfiguration `mapstructure:",squash"` SQLStorageConfiguration `mapstructure:",squash"`
SSLMode string `mapstructure:"sslmode"` SSLMode string `mapstructure:"sslmode"`

View File

@ -7,19 +7,19 @@ import (
"github.com/Workiva/go-datastructures/queue" "github.com/Workiva/go-datastructures/queue"
) )
// ErrorContainer represents a container where we can add errors and retrieve them // ErrorContainer represents a container where we can add errors and retrieve them.
type ErrorContainer interface { type ErrorContainer interface {
Push(err error) Push(err error)
HasErrors() bool HasErrors() bool
Errors() []error Errors() []error
} }
// Validator represents the validator interface // Validator represents the validator interface.
type Validator struct { type Validator struct {
errors map[string][]error errors map[string][]error
} }
// NewValidator create a validator // NewValidator create a validator.
func NewValidator() *Validator { func NewValidator() *Validator {
validator := new(Validator) validator := new(Validator)
validator.errors = make(map[string][]error) validator.errors = make(map[string][]error)
@ -67,7 +67,7 @@ func (v *Validator) validateOne(item QueueItem, q *queue.Queue) error { //nolint
return nil return nil
} }
// Validate validate a struct // Validate validate a struct.
func (v *Validator) Validate(s interface{}) error { func (v *Validator) Validate(s interface{}) error {
q := queue.New(40) q := queue.New(40)
q.Put(QueueItem{value: reflect.ValueOf(s), path: "root"}) //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting. q.Put(QueueItem{value: reflect.ValueOf(s), path: "root"}) //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting.
@ -86,7 +86,7 @@ func (v *Validator) Validate(s interface{}) error {
return nil return nil
} }
// PrintErrors display the errors thrown during validation // PrintErrors display the errors thrown during validation.
func (v *Validator) PrintErrors() { func (v *Validator) PrintErrors() {
for path, errs := range v.errors { for path, errs := range v.errors {
fmt.Printf("Errors at %s:\n", path) fmt.Printf("Errors at %s:\n", path)
@ -96,17 +96,17 @@ func (v *Validator) PrintErrors() {
} }
} }
// Errors return the errors thrown during validation // Errors return the errors thrown during validation.
func (v *Validator) Errors() map[string][]error { func (v *Validator) Errors() map[string][]error {
return v.errors return v.errors
} }
// StructValidator is a validator for structs // StructValidator is a validator for structs.
type StructValidator struct { type StructValidator struct {
errors []error errors []error
} }
// NewStructValidator is a constructor of struct validator // NewStructValidator is a constructor of struct validator.
func NewStructValidator() *StructValidator { func NewStructValidator() *StructValidator {
val := new(StructValidator) val := new(StructValidator)
val.errors = make([]error, 0) val.errors = make([]error, 0)
@ -128,7 +128,7 @@ func (v *StructValidator) Errors() []error {
return v.errors return v.errors
} }
// Clear errors // Clear errors.
func (v *StructValidator) Clear() { func (v *StructValidator) Clear() {
v.errors = []error{} v.errors = []error{}
} }

View File

@ -9,14 +9,14 @@ import (
"github.com/authelia/authelia/internal/middlewares" "github.com/authelia/authelia/internal/middlewares"
) )
// NewDuoAPI create duo API instance // NewDuoAPI create duo API instance.
func NewDuoAPI(duoAPI *duoapi.DuoApi) *APIImpl { func NewDuoAPI(duoAPI *duoapi.DuoApi) *APIImpl {
api := new(APIImpl) api := new(APIImpl)
api.DuoApi = duoAPI api.DuoApi = duoAPI
return api return api
} }
// Call call to the DuoAPI // Call call to the DuoAPI.
func (d *APIImpl) Call(values url.Values, ctx *middlewares.AutheliaCtx) (*Response, error) { func (d *APIImpl) Call(values url.Values, ctx *middlewares.AutheliaCtx) (*Response, error) {
_, responseBytes, err := d.DuoApi.SignedCall("POST", "/auth/v2/auth", values) _, responseBytes, err := d.DuoApi.SignedCall("POST", "/auth/v2/auth", values)

View File

@ -8,17 +8,17 @@ import (
"github.com/authelia/authelia/internal/middlewares" "github.com/authelia/authelia/internal/middlewares"
) )
// API interface wrapping duo api library for testing purpose // API interface wrapping duo api library for testing purpose.
type API interface { type API interface {
Call(values url.Values, ctx *middlewares.AutheliaCtx) (*Response, error) Call(values url.Values, ctx *middlewares.AutheliaCtx) (*Response, error)
} }
// APIImpl implementation of DuoAPI interface // APIImpl implementation of DuoAPI interface.
type APIImpl struct { type APIImpl struct {
*duoapi.DuoApi *duoapi.DuoApi
} }
// Response response coming from Duo API // Response response coming from Duo API.
type Response struct { type Response struct {
Response struct { Response struct {
Result string `json:"result"` Result string `json:"result"`

View File

@ -5,10 +5,10 @@ import (
"github.com/authelia/authelia/internal/middlewares" "github.com/authelia/authelia/internal/middlewares"
) )
// ExtendedConfigurationBody the content returned by extended configuration endpoint // ExtendedConfigurationBody the content returned by extended configuration endpoint.
type ExtendedConfigurationBody struct { type ExtendedConfigurationBody struct {
AvailableMethods MethodList `json:"available_methods"` AvailableMethods MethodList `json:"available_methods"`
SecondFactorEnabled bool `json:"second_factor_enabled"` // whether second factor is enabled or not SecondFactorEnabled bool `json:"second_factor_enabled"` // whether second factor is enabled or not.
TOTPPeriod int `json:"totp_period"` TOTPPeriod int `json:"totp_period"`
} }

View File

@ -63,7 +63,7 @@ func secondFactorTOTPIdentityFinish(ctx *middlewares.AutheliaCtx, username strin
ctx.SetJSONBody(response) //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting. ctx.SetJSONBody(response) //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting.
} }
// SecondFactorTOTPIdentityFinish the handler for finishing the identity validation // SecondFactorTOTPIdentityFinish the handler for finishing the identity validation.
var SecondFactorTOTPIdentityFinish = middlewares.IdentityVerificationFinish( var SecondFactorTOTPIdentityFinish = middlewares.IdentityVerificationFinish(
middlewares.IdentityVerificationFinishArgs{ middlewares.IdentityVerificationFinishArgs{
ActionClaim: TOTPRegistrationAction, ActionClaim: TOTPRegistrationAction,

View File

@ -58,7 +58,7 @@ func secondFactorU2FIdentityFinish(ctx *middlewares.AutheliaCtx, username string
ctx.SetJSONBody(u2f.NewWebRegisterRequest(challenge, []u2f.Registration{})) //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting. ctx.SetJSONBody(u2f.NewWebRegisterRequest(challenge, []u2f.Registration{})) //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting.
} }
// SecondFactorU2FIdentityFinish the handler for finishing the identity validation // SecondFactorU2FIdentityFinish the handler for finishing the identity validation.
var SecondFactorU2FIdentityFinish = middlewares.IdentityVerificationFinish( var SecondFactorU2FIdentityFinish = middlewares.IdentityVerificationFinish(
middlewares.IdentityVerificationFinishArgs{ middlewares.IdentityVerificationFinishArgs{
ActionClaim: U2FRegistrationAction, ActionClaim: U2FRegistrationAction,

View File

@ -6,13 +6,13 @@ import (
"github.com/authelia/authelia/internal/middlewares" "github.com/authelia/authelia/internal/middlewares"
) )
// ResetPasswordPost handler for resetting passwords // ResetPasswordPost handler for resetting passwords.
func ResetPasswordPost(ctx *middlewares.AutheliaCtx) { func ResetPasswordPost(ctx *middlewares.AutheliaCtx) {
userSession := ctx.GetSession() userSession := ctx.GetSession()
// Those checks unsure that the identity verification process has been initiated and completed successfully // Those checks unsure that the identity verification process has been initiated and completed successfully
// otherwise PasswordReset would not be set to true. We can improve the security of this check by making the // otherwise PasswordReset would not be set to true. We can improve the security of this check by making the
// request expire at some point because here it only expires when the cookie expires... // request expire at some point because here it only expires when the cookie expires.
if userSession.PasswordResetUsername == nil { if userSession.PasswordResetUsername == nil {
ctx.Error(fmt.Errorf("No identity verification process has been initiated"), unableToResetPasswordMessage) ctx.Error(fmt.Errorf("No identity verification process has been initiated"), unableToResetPasswordMessage)
return return

View File

@ -26,7 +26,7 @@ func isSchemeWSS(url *url.URL) bool {
return url.Scheme == "wss" return url.Scheme == "wss"
} }
// getOriginalURL extract the URL from the request headers (X-Original-URI or X-Forwarded-* headers) // getOriginalURL extract the URL from the request headers (X-Original-URI or X-Forwarded-* headers).
func getOriginalURL(ctx *middlewares.AutheliaCtx) (*url.URL, error) { func getOriginalURL(ctx *middlewares.AutheliaCtx) (*url.URL, error) {
originalURL := ctx.XOriginalURL() originalURL := ctx.XOriginalURL()
if originalURL != nil { if originalURL != nil {
@ -64,8 +64,8 @@ func getOriginalURL(ctx *middlewares.AutheliaCtx) (*url.URL, error) {
return url, nil return url, nil
} }
// parseBasicAuth parses an HTTP Basic Authentication string // parseBasicAuth parses an HTTP Basic Authentication string.
// "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" returns ("Aladdin", "open sesame", true) // "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" returns ("Aladdin", "open sesame", true).
func parseBasicAuth(auth string) (username, password string, err error) { func parseBasicAuth(auth string) (username, password string, err error) {
if !strings.HasPrefix(auth, authPrefix) { if !strings.HasPrefix(auth, authPrefix) {
return "", "", fmt.Errorf("%s prefix not found in %s header", strings.Trim(authPrefix, " "), AuthorizationHeader) return "", "", fmt.Errorf("%s prefix not found in %s header", strings.Trim(authPrefix, " "), AuthorizationHeader)
@ -82,7 +82,7 @@ func parseBasicAuth(auth string) (username, password string, err error) {
return cs[:s], cs[s+1:], nil return cs[:s], cs[s+1:], nil
} }
// isTargetURLAuthorized check whether the given user is authorized to access the resource // isTargetURLAuthorized check whether the given user is authorized to access the resource.
func isTargetURLAuthorized(authorizer *authorization.Authorizer, targetURL url.URL, func isTargetURLAuthorized(authorizer *authorization.Authorizer, targetURL url.URL,
username string, userGroups []string, clientIP net.IP, authLevel authentication.Level) authorizationMatching { username string, userGroups []string, clientIP net.IP, authLevel authentication.Level) authorizationMatching {
level := authorizer.GetRequiredLevel(authorization.Subject{ level := authorizer.GetRequiredLevel(authorization.Subject{
@ -114,7 +114,7 @@ func isTargetURLAuthorized(authorizer *authorization.Authorizer, targetURL url.U
} }
// verifyBasicAuth verify that the provided username and password are correct and // verifyBasicAuth verify that the provided username and password are correct and
// that the user is authorized to target the resource // that the user is authorized to target the resource.
func verifyBasicAuth(auth []byte, targetURL url.URL, ctx *middlewares.AutheliaCtx) (username string, groups []string, authLevel authentication.Level, err error) { //nolint:unparam func verifyBasicAuth(auth []byte, targetURL url.URL, ctx *middlewares.AutheliaCtx) (username string, groups []string, authLevel authentication.Level, err error) { //nolint:unparam
username, password, err := parseBasicAuth(string(auth)) username, password, err := parseBasicAuth(string(auth))
@ -128,7 +128,7 @@ func verifyBasicAuth(auth []byte, targetURL url.URL, ctx *middlewares.AutheliaCt
return "", nil, authentication.NotAuthenticated, fmt.Errorf("Unable to check credentials extracted from %s header: %s", AuthorizationHeader, err) return "", nil, authentication.NotAuthenticated, fmt.Errorf("Unable to check credentials extracted from %s header: %s", AuthorizationHeader, err)
} }
// If the user is not correctly authenticated, send a 401 // If the user is not correctly authenticated, send a 401.
if !authenticated { if !authenticated {
// Request Basic Authentication otherwise // Request Basic Authentication otherwise
return "", nil, authentication.NotAuthenticated, fmt.Errorf("User %s is not authenticated", username) return "", nil, authentication.NotAuthenticated, fmt.Errorf("User %s is not authenticated", username)
@ -143,7 +143,7 @@ func verifyBasicAuth(auth []byte, targetURL url.URL, ctx *middlewares.AutheliaCt
return username, details.Groups, authentication.OneFactor, nil return username, details.Groups, authentication.OneFactor, nil
} }
// setForwardedHeaders set the forwarded User and Groups headers // setForwardedHeaders set the forwarded User and Groups headers.
func setForwardedHeaders(headers *fasthttp.ResponseHeader, username string, groups []string) { func setForwardedHeaders(headers *fasthttp.ResponseHeader, username string, groups []string) {
if username != "" { if username != "" {
headers.Set(remoteUserHeader, username) headers.Set(remoteUserHeader, username)
@ -151,7 +151,7 @@ func setForwardedHeaders(headers *fasthttp.ResponseHeader, username string, grou
} }
} }
// hasUserBeenInactiveLongEnough check whether the user has been inactive for too long // hasUserBeenInactiveLongEnough check whether the user has been inactive for too long.
func hasUserBeenInactiveLongEnough(ctx *middlewares.AutheliaCtx) (bool, error) { //nolint:unparam func hasUserBeenInactiveLongEnough(ctx *middlewares.AutheliaCtx) (bool, error) { //nolint:unparam
maxInactivityPeriod := int64(ctx.Providers.SessionProvider.Inactivity.Seconds()) maxInactivityPeriod := int64(ctx.Providers.SessionProvider.Inactivity.Seconds())
if maxInactivityPeriod == 0 { if maxInactivityPeriod == 0 {
@ -171,10 +171,10 @@ func hasUserBeenInactiveLongEnough(ctx *middlewares.AutheliaCtx) (bool, error) {
return false, nil return false, nil
} }
// verifyFromSessionCookie verify if a user identified by a cookie is allowed to access target URL // verifyFromSessionCookie verify if a user identified by a cookie is allowed to access target URL.
func verifyFromSessionCookie(targetURL url.URL, ctx *middlewares.AutheliaCtx) (username string, groups []string, authLevel authentication.Level, err error) { //nolint:unparam func verifyFromSessionCookie(targetURL url.URL, ctx *middlewares.AutheliaCtx) (username string, groups []string, authLevel authentication.Level, err error) { //nolint:unparam
userSession := ctx.GetSession() userSession := ctx.GetSession()
// No username in the session means the user is anonymous // No username in the session means the user is anonymous.
isUserAnonymous := userSession.Username == "" isUserAnonymous := userSession.Username == ""
if isUserAnonymous && userSession.AuthenticationLevel != authentication.NotAuthenticated { if isUserAnonymous && userSession.AuthenticationLevel != authentication.NotAuthenticated {
@ -188,7 +188,7 @@ func verifyFromSessionCookie(targetURL url.URL, ctx *middlewares.AutheliaCtx) (u
} }
if inactiveLongEnough { if inactiveLongEnough {
// Destroy the session a new one will be regenerated on next request // Destroy the session a new one will be regenerated on next request.
err := ctx.Providers.SessionProvider.DestroySession(ctx.RequestCtx) err := ctx.Providers.SessionProvider.DestroySession(ctx.RequestCtx)
if err != nil { if err != nil {
return "", nil, authentication.NotAuthenticated, fmt.Errorf("Unable to destroy user session after long inactivity: %s", err) return "", nil, authentication.NotAuthenticated, fmt.Errorf("Unable to destroy user session after long inactivity: %s", err)
@ -203,7 +203,7 @@ func verifyFromSessionCookie(targetURL url.URL, ctx *middlewares.AutheliaCtx) (u
func handleUnauthorized(ctx *middlewares.AutheliaCtx, targetURL fmt.Stringer, username string) { func handleUnauthorized(ctx *middlewares.AutheliaCtx, targetURL fmt.Stringer, username string) {
// Kubernetes ingress controller and Traefik use the rd parameter of the verify // Kubernetes ingress controller and Traefik use the rd parameter of the verify
// endpoint to provide the URL of the login portal. The target URL of the user // endpoint to provide the URL of the login portal. The target URL of the user
// is computed from X-Fowarded-* headers or X-Original-URL // is computed from X-Fowarded-* headers or X-Original-URL.
rd := string(ctx.QueryArgs().Peek("rd")) rd := string(ctx.QueryArgs().Peek("rd"))
if rd != "" { if rd != "" {
redirectionURL := fmt.Sprintf("%s?rd=%s", rd, url.QueryEscape(targetURL.String())) redirectionURL := fmt.Sprintf("%s?rd=%s", rd, url.QueryEscape(targetURL.String()))
@ -230,12 +230,12 @@ func updateActivityTimestamp(ctx *middlewares.AutheliaCtx, isBasicAuth bool, use
return nil return nil
} }
// Mark current activity // Mark current activity.
userSession.LastActivity = ctx.Clock.Now().Unix() userSession.LastActivity = ctx.Clock.Now().Unix()
return ctx.SaveSession(userSession) return ctx.SaveSession(userSession)
} }
// VerifyGet is the handler verifying if a request is allowed to go through // VerifyGet is the handler verifying if a request is allowed to go through.
func VerifyGet(ctx *middlewares.AutheliaCtx) { func VerifyGet(ctx *middlewares.AutheliaCtx) {
ctx.Logger.Tracef("Headers=%s", ctx.Request.Header.String()) ctx.Logger.Tracef("Headers=%s", ctx.Request.Header.String())
targetURL, err := getOriginalURL(ctx) targetURL, err := getOriginalURL(ctx)

View File

@ -19,7 +19,7 @@ import (
"github.com/authelia/authelia/internal/session" "github.com/authelia/authelia/internal/session"
) )
// Test getOriginalURL // Test getOriginalURL.
func TestShouldGetOriginalURLFromOriginalURLHeader(t *testing.T) { func TestShouldGetOriginalURLFromOriginalURLHeader(t *testing.T) {
mock := mocks.NewMockAutheliaCtx(t) mock := mocks.NewMockAutheliaCtx(t)
defer mock.Close() defer mock.Close()
@ -110,7 +110,7 @@ func TestShouldRaiseWhenXForwardedURIIsNotParseable(t *testing.T) {
assert.Equal(t, "Unable to parse URL https://myhost.local!:;;:,: parse https://myhost.local!:;;:,: invalid port \":,\" after host", err.Error()) assert.Equal(t, "Unable to parse URL https://myhost.local!:;;:,: parse https://myhost.local!:;;:,: invalid port \":,\" after host", err.Error())
} }
// Test parseBasicAuth // Test parseBasicAuth.
func TestShouldRaiseWhenHeaderDoesNotContainBasicPrefix(t *testing.T) { func TestShouldRaiseWhenHeaderDoesNotContainBasicPrefix(t *testing.T) {
_, _, err := parseBasicAuth("alzefzlfzemjfej==") _, _, err := parseBasicAuth("alzefzlfzemjfej==")
assert.Error(t, err) assert.Error(t, err)
@ -138,7 +138,7 @@ func TestShouldReturnUsernameAndPassword(t *testing.T) {
assert.Equal(t, "password", password) assert.Equal(t, "password", password)
} }
// Test isTargetURLAuthorized // Test isTargetURLAuthorized.
func TestShouldCheckAuthorizationMatching(t *testing.T) { func TestShouldCheckAuthorizationMatching(t *testing.T) {
type Rule struct { type Rule struct {
Policy string Policy string
@ -185,7 +185,7 @@ func TestShouldCheckAuthorizationMatching(t *testing.T) {
} }
} }
// Test verifyBasicAuth // Test verifyBasicAuth.
func TestShouldVerifyWrongCredentials(t *testing.T) { func TestShouldVerifyWrongCredentials(t *testing.T) {
mock := mocks.NewMockAutheliaCtx(t) mock := mocks.NewMockAutheliaCtx(t)
defer mock.Close() defer mock.Close()
@ -473,7 +473,7 @@ func TestShouldDestroySessionWhenInactiveForTooLong(t *testing.T) {
past := clock.Now().Add(-1 * time.Hour) past := clock.Now().Add(-1 * time.Hour)
mock.Ctx.Configuration.Session.Inactivity = "10" mock.Ctx.Configuration.Session.Inactivity = "10"
// Reload the session provider since the configuration is indirect // Reload the session provider since the configuration is indirect.
mock.Ctx.Providers.SessionProvider = session.NewProvider(mock.Ctx.Configuration.Session) mock.Ctx.Providers.SessionProvider = session.NewProvider(mock.Ctx.Configuration.Session)
assert.Equal(t, time.Second*10, mock.Ctx.Providers.SessionProvider.Inactivity) assert.Equal(t, time.Second*10, mock.Ctx.Providers.SessionProvider.Inactivity)
@ -487,7 +487,7 @@ func TestShouldDestroySessionWhenInactiveForTooLong(t *testing.T) {
VerifyGet(mock.Ctx) VerifyGet(mock.Ctx)
// The session has been destroyed // The session has been destroyed.
newUserSession := mock.Ctx.GetSession() newUserSession := mock.Ctx.GetSession()
assert.Equal(t, "", newUserSession.Username) assert.Equal(t, "", newUserSession.Username)
assert.Equal(t, authentication.NotAuthenticated, newUserSession.AuthenticationLevel) assert.Equal(t, authentication.NotAuthenticated, newUserSession.AuthenticationLevel)
@ -504,7 +504,7 @@ func TestShouldDestroySessionWhenInactiveForTooLongUsingDurationNotation(t *test
clock.Set(time.Now()) clock.Set(time.Now())
mock.Ctx.Configuration.Session.Inactivity = "10s" mock.Ctx.Configuration.Session.Inactivity = "10s"
// Reload the session provider since the configuration is indirect // Reload the session provider since the configuration is indirect.
mock.Ctx.Providers.SessionProvider = session.NewProvider(mock.Ctx.Configuration.Session) mock.Ctx.Providers.SessionProvider = session.NewProvider(mock.Ctx.Configuration.Session)
assert.Equal(t, time.Second*10, mock.Ctx.Providers.SessionProvider.Inactivity) assert.Equal(t, time.Second*10, mock.Ctx.Providers.SessionProvider.Inactivity)
@ -518,7 +518,7 @@ func TestShouldDestroySessionWhenInactiveForTooLongUsingDurationNotation(t *test
VerifyGet(mock.Ctx) VerifyGet(mock.Ctx)
// The session has been destroyed // The session has been destroyed.
newUserSession := mock.Ctx.GetSession() newUserSession := mock.Ctx.GetSession()
assert.Equal(t, "", newUserSession.Username) assert.Equal(t, "", newUserSession.Username)
assert.Equal(t, authentication.NotAuthenticated, newUserSession.AuthenticationLevel) assert.Equal(t, authentication.NotAuthenticated, newUserSession.AuthenticationLevel)
@ -544,7 +544,7 @@ func TestShouldKeepSessionWhenUserCheckedRememberMeAndIsInactiveForTooLong(t *te
VerifyGet(mock.Ctx) VerifyGet(mock.Ctx)
// The session has been destroyed // The session has been destroyed.
newUserSession := mock.Ctx.GetSession() newUserSession := mock.Ctx.GetSession()
assert.Equal(t, "john", newUserSession.Username) assert.Equal(t, "john", newUserSession.Username)
assert.Equal(t, authentication.TwoFactor, newUserSession.AuthenticationLevel) assert.Equal(t, authentication.TwoFactor, newUserSession.AuthenticationLevel)
@ -574,7 +574,7 @@ func TestShouldKeepSessionWhenInactivityTimeoutHasNotBeenExceeded(t *testing.T)
VerifyGet(mock.Ctx) VerifyGet(mock.Ctx)
// The session has been destroyed // The session has been destroyed.
newUserSession := mock.Ctx.GetSession() newUserSession := mock.Ctx.GetSession()
assert.Equal(t, "john", newUserSession.Username) assert.Equal(t, "john", newUserSession.Username)
assert.Equal(t, authentication.TwoFactor, newUserSession.AuthenticationLevel) assert.Equal(t, authentication.TwoFactor, newUserSession.AuthenticationLevel)
@ -593,7 +593,7 @@ func TestShouldRedirectWhenSessionInactiveForTooLongAndRDParamProvided(t *testin
clock.Set(time.Now()) clock.Set(time.Now())
mock.Ctx.Configuration.Session.Inactivity = "10" mock.Ctx.Configuration.Session.Inactivity = "10"
// Reload the session provider since the configuration is indirect // Reload the session provider since the configuration is indirect.
mock.Ctx.Providers.SessionProvider = session.NewProvider(mock.Ctx.Configuration.Session) mock.Ctx.Providers.SessionProvider = session.NewProvider(mock.Ctx.Configuration.Session)
assert.Equal(t, time.Second*10, mock.Ctx.Providers.SessionProvider.Inactivity) assert.Equal(t, time.Second*10, mock.Ctx.Providers.SessionProvider.Inactivity)
@ -640,7 +640,7 @@ func TestShouldUpdateInactivityTimestampEvenWhenHittingForbiddenResources(t *tes
VerifyGet(mock.Ctx) VerifyGet(mock.Ctx)
// The resource if forbidden // The resource if forbidden.
assert.Equal(t, 403, mock.Ctx.Response.StatusCode()) assert.Equal(t, 403, mock.Ctx.Response.StatusCode())
// Check the inactivity timestamp has been updated to current time in the new session. // Check the inactivity timestamp has been updated to current time in the new session.
@ -683,8 +683,8 @@ func TestIsDomainProtected(t *testing.T) {
assert.True(t, isURLUnderProtectedDomain( assert.True(t, isURLUnderProtectedDomain(
GetURL("https://mytest.example.com/abc/?query=abc"), "example.com")) GetURL("https://mytest.example.com/abc/?query=abc"), "example.com"))
// cookies readable by a service on a machine is also readable by a service on the same machine // Cookies readable by a service on a machine is also readable by a service on the same machine
// with a different port as mentioned in https://tools.ietf.org/html/rfc6265#section-8.5 // with a different port as mentioned in https://tools.ietf.org/html/rfc6265#section-8.5.
assert.True(t, isURLUnderProtectedDomain( assert.True(t, isURLUnderProtectedDomain(
GetURL("https://mytest.example.com:8080/abc/?query=abc"), "example.com")) GetURL("https://mytest.example.com:8080/abc/?query=abc"), "example.com"))
} }

View File

@ -9,7 +9,7 @@ import (
"github.com/authelia/authelia/internal/utils" "github.com/authelia/authelia/internal/utils"
) )
// Handle1FAResponse handle the redirection upon 1FA authentication // Handle1FAResponse handle the redirection upon 1FA authentication.
func Handle1FAResponse(ctx *middlewares.AutheliaCtx, targetURI string, username string, groups []string) { func Handle1FAResponse(ctx *middlewares.AutheliaCtx, targetURI string, username string, groups []string) {
if targetURI == "" { if targetURI == "" {
if !ctx.Providers.Authorizer.IsSecondFactorEnabled() && ctx.Configuration.DefaultRedirectionURL != "" { if !ctx.Providers.Authorizer.IsSecondFactorEnabled() && ctx.Configuration.DefaultRedirectionURL != "" {
@ -56,7 +56,7 @@ func Handle1FAResponse(ctx *middlewares.AutheliaCtx, targetURI string, username
ctx.SetJSONBody(response) //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting. ctx.SetJSONBody(response) //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting.
} }
// Handle2FAResponse handle the redirection upon 2FA authentication // Handle2FAResponse handle the redirection upon 2FA authentication.
func Handle2FAResponse(ctx *middlewares.AutheliaCtx, targetURI string) { func Handle2FAResponse(ctx *middlewares.AutheliaCtx, targetURI string) {
if targetURI == "" { if targetURI == "" {
if ctx.Configuration.DefaultRedirectionURL != "" { if ctx.Configuration.DefaultRedirectionURL != "" {

View File

@ -17,7 +17,7 @@ func SetLevel(level logrus.Level) {
logrus.SetLevel(level) logrus.SetLevel(level)
} }
// InitializeLogger initialize logger // InitializeLogger initialize logger.
func InitializeLogger(filename string) error { func InitializeLogger(filename string) error {
callerLevels := []logrus.Level{} callerLevels := []logrus.Level{}
stackLevels := []logrus.Level{logrus.PanicLevel, logrus.FatalLevel, logrus.ErrorLevel} stackLevels := []logrus.Level{logrus.PanicLevel, logrus.FatalLevel, logrus.ErrorLevel}

View File

@ -62,7 +62,7 @@ func (c *AutheliaCtx) Error(err error, message string) {
c.Logger.Error(err) c.Logger.Error(err)
} }
// ReplyError reply with an error but does not display any stack trace in the logs // ReplyError reply with an error but does not display any stack trace in the logs.
func (c *AutheliaCtx) ReplyError(err error, message string) { func (c *AutheliaCtx) ReplyError(err error, message string) {
b, marshalErr := json.Marshal(ErrorResponse{Status: "KO", Message: message}) b, marshalErr := json.Marshal(ErrorResponse{Status: "KO", Message: message})
@ -75,33 +75,33 @@ func (c *AutheliaCtx) ReplyError(err error, message string) {
c.Logger.Debug(err) c.Logger.Debug(err)
} }
// ReplyUnauthorized response sent when user is unauthorized // ReplyUnauthorized response sent when user is unauthorized.
func (c *AutheliaCtx) ReplyUnauthorized() { func (c *AutheliaCtx) ReplyUnauthorized() {
c.RequestCtx.Error(fasthttp.StatusMessage(fasthttp.StatusUnauthorized), fasthttp.StatusUnauthorized) c.RequestCtx.Error(fasthttp.StatusMessage(fasthttp.StatusUnauthorized), fasthttp.StatusUnauthorized)
// c.Response.Header.Set("WWW-Authenticate", "Basic realm=Restricted") // c.Response.Header.Set("WWW-Authenticate", "Basic realm=Restricted")
} }
// ReplyForbidden response sent when access is forbidden to user // ReplyForbidden response sent when access is forbidden to user.
func (c *AutheliaCtx) ReplyForbidden() { func (c *AutheliaCtx) ReplyForbidden() {
c.RequestCtx.Error(fasthttp.StatusMessage(fasthttp.StatusForbidden), fasthttp.StatusForbidden) c.RequestCtx.Error(fasthttp.StatusMessage(fasthttp.StatusForbidden), fasthttp.StatusForbidden)
} }
// XForwardedProto return the content of the header X-Forwarded-Proto // XForwardedProto return the content of the header X-Forwarded-Proto.
func (c *AutheliaCtx) XForwardedProto() []byte { func (c *AutheliaCtx) XForwardedProto() []byte {
return c.RequestCtx.Request.Header.Peek(xForwardedProtoHeader) return c.RequestCtx.Request.Header.Peek(xForwardedProtoHeader)
} }
// XForwardedHost return the content of the header X-Forwarded-Host // XForwardedHost return the content of the header X-Forwarded-Host.
func (c *AutheliaCtx) XForwardedHost() []byte { func (c *AutheliaCtx) XForwardedHost() []byte {
return c.RequestCtx.Request.Header.Peek(xForwardedHostHeader) return c.RequestCtx.Request.Header.Peek(xForwardedHostHeader)
} }
// XForwardedURI return the content of the header X-Forwarded-URI // XForwardedURI return the content of the header X-Forwarded-URI.
func (c *AutheliaCtx) XForwardedURI() []byte { func (c *AutheliaCtx) XForwardedURI() []byte {
return c.RequestCtx.Request.Header.Peek(xForwardedURIHeader) return c.RequestCtx.Request.Header.Peek(xForwardedURIHeader)
} }
// XOriginalURL return the content of the header X-Original-URL // XOriginalURL return the content of the header X-Original-URL.
func (c *AutheliaCtx) XOriginalURL() []byte { func (c *AutheliaCtx) XOriginalURL() []byte {
return c.RequestCtx.Request.Header.Peek(xOriginalURLHeader) return c.RequestCtx.Request.Header.Peek(xOriginalURLHeader)
} }
@ -121,13 +121,13 @@ func (c *AutheliaCtx) SaveSession(userSession session.UserSession) error {
return c.Providers.SessionProvider.SaveSession(c.RequestCtx, userSession) return c.Providers.SessionProvider.SaveSession(c.RequestCtx, userSession)
} }
// ReplyOK is a helper method to reply ok // ReplyOK is a helper method to reply ok.
func (c *AutheliaCtx) ReplyOK() { func (c *AutheliaCtx) ReplyOK() {
c.SetContentType(applicationJSONContentType) c.SetContentType(applicationJSONContentType)
c.SetBody(okMessageBytes) c.SetBody(okMessageBytes)
} }
// ParseBody parse the request body into the type of value // ParseBody parse the request body into the type of value.
func (c *AutheliaCtx) ParseBody(value interface{}) error { func (c *AutheliaCtx) ParseBody(value interface{}) error {
err := json.Unmarshal(c.PostBody(), &value) err := json.Unmarshal(c.PostBody(), &value)
@ -147,7 +147,7 @@ func (c *AutheliaCtx) ParseBody(value interface{}) error {
return nil return nil
} }
// SetJSONBody Set json body // SetJSONBody Set json body.
func (c *AutheliaCtx) SetJSONBody(value interface{}) error { func (c *AutheliaCtx) SetJSONBody(value interface{}) error {
b, err := json.Marshal(OKResponse{Status: "OK", Data: value}) b, err := json.Marshal(OKResponse{Status: "OK", Data: value})
if err != nil { if err != nil {

View File

@ -1,6 +1,6 @@
package middlewares package middlewares
// JWTIssuer is // JWTIssuer is.
const jwtIssuer = "Authelia" const jwtIssuer = "Authelia"
const xForwardedProtoHeader = "X-Forwarded-Proto" const xForwardedProtoHeader = "X-Forwarded-Proto"

View File

@ -144,8 +144,7 @@ func TestShouldSucceedIdentityVerificationStartProcess(t *testing.T) {
assert.Equal(t, 200, mock.Ctx.Response.StatusCode()) assert.Equal(t, 200, mock.Ctx.Response.StatusCode())
} }
// Test Finish process // Test Finish process.
type IdentityVerificationFinishProcess struct { type IdentityVerificationFinishProcess struct {
suite.Suite suite.Suite

View File

@ -54,23 +54,23 @@ type IdentityVerificationStartArgs struct {
// is completed successfully. // is completed successfully.
TargetEndpoint string TargetEndpoint string
// The action claim that will be stored in the JWT token // The action claim that will be stored in the JWT token.
ActionClaim string ActionClaim string
// The function retrieving the identity to who the email will be sent. // The function retrieving the identity to who the email will be sent.
IdentityRetrieverFunc func(ctx *AutheliaCtx) (*session.Identity, error) IdentityRetrieverFunc func(ctx *AutheliaCtx) (*session.Identity, error)
// The function for checking the user in the token is valid for the current action // The function for checking the user in the token is valid for the current action.
IsTokenUserValidFunc func(ctx *AutheliaCtx, username string) bool IsTokenUserValidFunc func(ctx *AutheliaCtx, username string) bool
} }
// IdentityVerificationFinishArgs represent the arguments used to customize the finishing phase // IdentityVerificationFinishArgs represent the arguments used to customize the finishing phase
// of the identity verification process. // of the identity verification process.
type IdentityVerificationFinishArgs struct { type IdentityVerificationFinishArgs struct {
// The action claim that should be in the token to consider the action legitimate // The action claim that should be in the token to consider the action legitimate.
ActionClaim string ActionClaim string
// The function for checking the user in the token is valid for the current action // The function for checking the user in the token is valid for the current action.
IsTokenUserValidFunc func(ctx *AutheliaCtx, username string) bool IsTokenUserValidFunc func(ctx *AutheliaCtx, username string) bool
} }
@ -90,13 +90,13 @@ type IdentityVerificationFinishBody struct {
Token string `json:"token"` Token string `json:"token"`
} }
// OKResponse model of a status OK response // OKResponse model of a status OK response.
type OKResponse struct { type OKResponse struct {
Status string `json:"status"` Status string `json:"status"`
Data interface{} `json:"data,omitempty"` Data interface{} `json:"data,omitempty"`
} }
// ErrorResponse model of an error response // ErrorResponse model of an error response.
type ErrorResponse struct { type ErrorResponse struct {
Status string `json:"status"` Status string `json:"status"`
Message string `json:"message"` Message string `json:"message"`

View File

@ -22,7 +22,7 @@ func NewFileNotifier(configuration schema.FileSystemNotifierConfiguration) *File
} }
} }
// StartupCheck checks the file provider can write to the specified file // StartupCheck checks the file provider can write to the specified file.
func (n *FileNotifier) StartupCheck() (bool, error) { func (n *FileNotifier) StartupCheck() (bool, error) {
dir := filepath.Dir(n.path) dir := filepath.Dir(n.path)
if _, err := os.Stat(dir); err != nil { if _, err := os.Stat(dir); err != nil {

View File

@ -2,5 +2,5 @@ package regulation
import "fmt" import "fmt"
// ErrUserIsBanned user is banned error message // ErrUserIsBanned user is banned error message.
var ErrUserIsBanned = fmt.Errorf("User is banned") var ErrUserIsBanned = fmt.Errorf("User is banned")

View File

@ -38,7 +38,7 @@ func NewRegulator(configuration *schema.RegulationConfiguration, provider storag
} }
// Mark mark an authentication attempt. // Mark mark an authentication attempt.
// We split Mark and Regulate in order to avoid timing attacks since if // We split Mark and Regulate in order to avoid timing attacks.
func (r *Regulator) Mark(username string, successful bool) error { func (r *Regulator) Mark(username string, successful bool) error {
return r.storageProvider.AppendAuthenticationLog(models.AuthenticationAttempt{ return r.storageProvider.AppendAuthenticationLog(models.AuthenticationAttempt{
Username: username, Username: username,

View File

@ -14,13 +14,13 @@ type EncryptingSerializer struct {
key [32]byte key [32]byte
} }
// NewEncryptingSerializer return new encrypt instance // NewEncryptingSerializer return new encrypt instance.
func NewEncryptingSerializer(secret string) *EncryptingSerializer { func NewEncryptingSerializer(secret string) *EncryptingSerializer {
key := sha256.Sum256([]byte(secret)) key := sha256.Sum256([]byte(secret))
return &EncryptingSerializer{key} return &EncryptingSerializer{key}
} }
// Encode encode and encrypt session // Encode encode and encrypt session.
func (e *EncryptingSerializer) Encode(src session.Dict) ([]byte, error) { func (e *EncryptingSerializer) Encode(src session.Dict) ([]byte, error) {
if len(src.D) == 0 { if len(src.D) == 0 {
return nil, nil return nil, nil
@ -39,7 +39,7 @@ func (e *EncryptingSerializer) Encode(src session.Dict) ([]byte, error) {
return encryptedDst, nil return encryptedDst, nil
} }
// Decode decrypt and decode session // Decode decrypt and decode session.
func (e *EncryptingSerializer) Decode(dst *session.Dict, src []byte) error { func (e *EncryptingSerializer) Decode(dst *session.Dict, src []byte) error {
if len(src) == 0 { if len(src) == 0 {
return nil return nil

View File

@ -44,7 +44,7 @@ func NewProvider(configuration schema.SessionConfiguration) *Provider {
return provider return provider
} }
// GetSession return the user session from a request // GetSession return the user session from a request.
func (p *Provider) GetSession(ctx *fasthttp.RequestCtx) (UserSession, error) { func (p *Provider) GetSession(ctx *fasthttp.RequestCtx) (UserSession, error) {
store, err := p.sessionHolder.Get(ctx) store, err := p.sessionHolder.Get(ctx)

View File

@ -10,7 +10,7 @@ import (
"github.com/authelia/authelia/internal/utils" "github.com/authelia/authelia/internal/utils"
) )
// NewProviderConfig creates a configuration for creating the session provider // NewProviderConfig creates a configuration for creating the session provider.
func NewProviderConfig(configuration schema.SessionConfiguration) ProviderConfig { func NewProviderConfig(configuration schema.SessionConfiguration) ProviderConfig {
config := session.NewDefaultConfig() config := session.NewDefaultConfig()
@ -23,7 +23,7 @@ func NewProviderConfig(configuration schema.SessionConfiguration) ProviderConfig
// Only serve the header over HTTPS. // Only serve the header over HTTPS.
config.Secure = true config.Secure = true
// Ignore the error as it will be handled by validator // Ignore the error as it will be handled by validator.
config.Expires, _ = utils.ParseDurationString(configuration.Expiration) config.Expires, _ = utils.ParseDurationString(configuration.Expiration)
// TODO(c.michaud): Make this configurable by giving the list of IPs that are trustable. // TODO(c.michaud): Make this configurable by giving the list of IPs that are trustable.
@ -42,7 +42,7 @@ func NewProviderConfig(configuration schema.SessionConfiguration) ProviderConfig
Host: configuration.Redis.Host, Host: configuration.Redis.Host,
Port: configuration.Redis.Port, Port: configuration.Redis.Port,
Password: configuration.Redis.Password, Password: configuration.Redis.Password,
// DbNumber is the fasthttp/session property for the Redis DB Index // DbNumber is the fasthttp/session property for the Redis DB Index.
DbNumber: configuration.Redis.DatabaseIndex, DbNumber: configuration.Redis.DatabaseIndex,
PoolSize: 8, PoolSize: 8,
IdleTimeout: 300, IdleTimeout: 300,

View File

@ -14,7 +14,7 @@ type ProviderConfig struct {
providerConfig session.ProviderConfig providerConfig session.ProviderConfig
} }
// U2FRegistration is a serializable version of a U2F registration // U2FRegistration is a serializable version of a U2F registration.
type U2FRegistration struct { type U2FRegistration struct {
KeyHandle []byte KeyHandle []byte
PublicKey []byte PublicKey []byte

View File

@ -9,24 +9,24 @@ var totpSecretsTableName = "totp_secrets"
var u2fDeviceHandlesTableName = "u2f_devices" var u2fDeviceHandlesTableName = "u2f_devices"
var authenticationLogsTableName = "authentication_logs" var authenticationLogsTableName = "authentication_logs"
// SQLCreateUserPreferencesTable common SQL query to create user_preferences table // SQLCreateUserPreferencesTable common SQL query to create user_preferences table.
var SQLCreateUserPreferencesTable = fmt.Sprintf(` var SQLCreateUserPreferencesTable = fmt.Sprintf(`
CREATE TABLE IF NOT EXISTS %s ( CREATE TABLE IF NOT EXISTS %s (
username VARCHAR(100) PRIMARY KEY, username VARCHAR(100) PRIMARY KEY,
second_factor_method VARCHAR(11) second_factor_method VARCHAR(11)
)`, preferencesTableName) )`, preferencesTableName)
// SQLCreateIdentityVerificationTokensTable common SQL query to create identity_verification_tokens table // SQLCreateIdentityVerificationTokensTable common SQL query to create identity_verification_tokens table.
var SQLCreateIdentityVerificationTokensTable = fmt.Sprintf(` var SQLCreateIdentityVerificationTokensTable = fmt.Sprintf(`
CREATE TABLE IF NOT EXISTS %s (token VARCHAR(512)) CREATE TABLE IF NOT EXISTS %s (token VARCHAR(512))
`, identityVerificationTokensTableName) `, identityVerificationTokensTableName)
// SQLCreateTOTPSecretsTable common SQL query to create totp_secrets table // SQLCreateTOTPSecretsTable common SQL query to create totp_secrets table.
var SQLCreateTOTPSecretsTable = fmt.Sprintf(` var SQLCreateTOTPSecretsTable = fmt.Sprintf(`
CREATE TABLE IF NOT EXISTS %s (username VARCHAR(100) PRIMARY KEY, secret VARCHAR(64)) CREATE TABLE IF NOT EXISTS %s (username VARCHAR(100) PRIMARY KEY, secret VARCHAR(64))
`, totpSecretsTableName) `, totpSecretsTableName)
// SQLCreateU2FDeviceHandlesTable common SQL query to create u2f_device_handles table // SQLCreateU2FDeviceHandlesTable common SQL query to create u2f_device_handles table.
var SQLCreateU2FDeviceHandlesTable = fmt.Sprintf(` var SQLCreateU2FDeviceHandlesTable = fmt.Sprintf(`
CREATE TABLE IF NOT EXISTS %s ( CREATE TABLE IF NOT EXISTS %s (
username VARCHAR(100) PRIMARY KEY, username VARCHAR(100) PRIMARY KEY,
@ -34,7 +34,7 @@ CREATE TABLE IF NOT EXISTS %s (
publicKey TEXT publicKey TEXT
)`, u2fDeviceHandlesTableName) )`, u2fDeviceHandlesTableName)
// SQLCreateAuthenticationLogsTable common SQL query to create authentication_logs table // SQLCreateAuthenticationLogsTable common SQL query to create authentication_logs table.
var SQLCreateAuthenticationLogsTable = fmt.Sprintf(` var SQLCreateAuthenticationLogsTable = fmt.Sprintf(`
CREATE TABLE IF NOT EXISTS %s ( CREATE TABLE IF NOT EXISTS %s (
username VARCHAR(100), username VARCHAR(100),

View File

@ -10,12 +10,12 @@ import (
"github.com/authelia/authelia/internal/logging" "github.com/authelia/authelia/internal/logging"
) )
// MySQLProvider is a MySQL provider // MySQLProvider is a MySQL provider.
type MySQLProvider struct { type MySQLProvider struct {
SQLProvider SQLProvider
} }
// NewMySQLProvider a MySQL provider // NewMySQLProvider a MySQL provider.
func NewMySQLProvider(configuration schema.MySQLStorageConfiguration) *MySQLProvider { func NewMySQLProvider(configuration schema.MySQLStorageConfiguration) *MySQLProvider {
connectionString := configuration.Username connectionString := configuration.Username

View File

@ -11,12 +11,12 @@ import (
"github.com/authelia/authelia/internal/logging" "github.com/authelia/authelia/internal/logging"
) )
// PostgreSQLProvider is a Postrgres provider // PostgreSQLProvider is a PostgreSQL provider.
type PostgreSQLProvider struct { type PostgreSQLProvider struct {
SQLProvider SQLProvider
} }
// NewPostgreSQLProvider a SQL provider // NewPostgreSQLProvider a PostgreSQL provider.
func NewPostgreSQLProvider(configuration schema.PostgreSQLStorageConfiguration) *PostgreSQLProvider { func NewPostgreSQLProvider(configuration schema.PostgreSQLStorageConfiguration) *PostgreSQLProvider {
args := make([]string, 0) args := make([]string, 0)
if configuration.Username != "" { if configuration.Username != "" {

View File

@ -9,12 +9,12 @@ import (
"github.com/authelia/authelia/internal/logging" "github.com/authelia/authelia/internal/logging"
) )
// SQLiteProvider is a sqlite3 provider // SQLiteProvider is a SQLite3 provider.
type SQLiteProvider struct { type SQLiteProvider struct {
SQLProvider SQLProvider
} }
// NewSQLiteProvider construct a sqlite provider. // NewSQLiteProvider constructs a SQLite provider.
func NewSQLiteProvider(path string) *SQLiteProvider { func NewSQLiteProvider(path string) *SQLiteProvider {
db, err := sql.Open("sqlite3", path) db, err := sql.Open("sqlite3", path)
if err != nil { if err != nil {

View File

@ -28,13 +28,13 @@ func (wds *WebDriverSession) doFillLoginPageAndClick(ctx context.Context, t *tes
require.NoError(t, err) require.NoError(t, err)
} }
// Login 1FA // Login 1FA.
func (wds *WebDriverSession) doLoginOneFactor(ctx context.Context, t *testing.T, username, password string, keepMeLoggedIn bool, targetURL string) { func (wds *WebDriverSession) doLoginOneFactor(ctx context.Context, t *testing.T, username, password string, keepMeLoggedIn bool, targetURL string) {
wds.doVisitLoginPage(ctx, t, targetURL) wds.doVisitLoginPage(ctx, t, targetURL)
wds.doFillLoginPageAndClick(ctx, t, username, password, keepMeLoggedIn) wds.doFillLoginPageAndClick(ctx, t, username, password, keepMeLoggedIn)
} }
// Login 1FA and 2FA subsequently (must already be registered) // Login 1FA and 2FA subsequently (must already be registered).
func (wds *WebDriverSession) doLoginTwoFactor(ctx context.Context, t *testing.T, username, password string, keepMeLoggedIn bool, otpSecret, targetURL string) { func (wds *WebDriverSession) doLoginTwoFactor(ctx context.Context, t *testing.T, username, password string, keepMeLoggedIn bool, otpSecret, targetURL string) {
wds.doLoginOneFactor(ctx, t, username, password, keepMeLoggedIn, targetURL) wds.doLoginOneFactor(ctx, t, username, password, keepMeLoggedIn, targetURL)
wds.verifyIsSecondFactorPage(ctx, t) wds.verifyIsSecondFactorPage(ctx, t)

View File

@ -2,41 +2,41 @@ package suites
import "fmt" import "fmt"
// BaseDomain the base domain // BaseDomain the base domain.
var BaseDomain = "example.com:8080" var BaseDomain = "example.com:8080"
// LoginBaseURL the base URL of the login portal // LoginBaseURL the base URL of the login portal.
var LoginBaseURL = fmt.Sprintf("https://login.%s", BaseDomain) var LoginBaseURL = fmt.Sprintf("https://login.%s", BaseDomain)
// SingleFactorBaseURL the base URL of the singlefactor domain // SingleFactorBaseURL the base URL of the singlefactor domain.
var SingleFactorBaseURL = fmt.Sprintf("https://singlefactor.%s", BaseDomain) var SingleFactorBaseURL = fmt.Sprintf("https://singlefactor.%s", BaseDomain)
// AdminBaseURL the base URL of the admin domain // AdminBaseURL the base URL of the admin domain.
var AdminBaseURL = fmt.Sprintf("https://admin.%s", BaseDomain) var AdminBaseURL = fmt.Sprintf("https://admin.%s", BaseDomain)
// MailBaseURL the base URL of the mail domain // MailBaseURL the base URL of the mail domain.
var MailBaseURL = fmt.Sprintf("https://mail.%s", BaseDomain) var MailBaseURL = fmt.Sprintf("https://mail.%s", BaseDomain)
// HomeBaseURL the base URL of the home domain // HomeBaseURL the base URL of the home domain.
var HomeBaseURL = fmt.Sprintf("https://home.%s", BaseDomain) var HomeBaseURL = fmt.Sprintf("https://home.%s", BaseDomain)
// PublicBaseURL the base URL of the public domain // PublicBaseURL the base URL of the public domain.
var PublicBaseURL = fmt.Sprintf("https://public.%s", BaseDomain) var PublicBaseURL = fmt.Sprintf("https://public.%s", BaseDomain)
// SecureBaseURL the base URL of the secure domain // SecureBaseURL the base URL of the secure domain.
var SecureBaseURL = fmt.Sprintf("https://secure.%s", BaseDomain) var SecureBaseURL = fmt.Sprintf("https://secure.%s", BaseDomain)
// DevBaseURL the base URL of the dev domain // DevBaseURL the base URL of the dev domain.
var DevBaseURL = fmt.Sprintf("https://dev.%s", BaseDomain) var DevBaseURL = fmt.Sprintf("https://dev.%s", BaseDomain)
// MX1MailBaseURL the base URL of the mx1.mail domain // MX1MailBaseURL the base URL of the mx1.mail domain.
var MX1MailBaseURL = fmt.Sprintf("https://mx1.mail.%s", BaseDomain) var MX1MailBaseURL = fmt.Sprintf("https://mx1.mail.%s", BaseDomain)
// MX2MailBaseURL the base URL of the mx2.mail domain // MX2MailBaseURL the base URL of the mx2.mail domain.
var MX2MailBaseURL = fmt.Sprintf("https://mx2.mail.%s", BaseDomain) var MX2MailBaseURL = fmt.Sprintf("https://mx2.mail.%s", BaseDomain)
// DuoBaseURL the base URL of the Duo configuration API // DuoBaseURL the base URL of the Duo configuration API.
var DuoBaseURL = "https://duo.example.com" var DuoBaseURL = "https://duo.example.com"
// AutheliaBaseURL the base URL of Authelia service // AutheliaBaseURL the base URL of Authelia service.
var AutheliaBaseURL = "https://authelia.example.com:9091" var AutheliaBaseURL = "https://authelia.example.com:9091"

View File

@ -11,12 +11,12 @@ import (
"github.com/authelia/authelia/internal/utils" "github.com/authelia/authelia/internal/utils"
) )
// DockerEnvironment represent a docker environment // DockerEnvironment represent a docker environment.
type DockerEnvironment struct { type DockerEnvironment struct {
dockerComposeFiles []string dockerComposeFiles []string
} }
// NewDockerEnvironment create a new docker environment // NewDockerEnvironment create a new docker environment.
func NewDockerEnvironment(files []string) *DockerEnvironment { func NewDockerEnvironment(files []string) *DockerEnvironment {
if os.Getenv("CI") == "true" { if os.Getenv("CI") == "true" {
for i := range files { for i := range files {
@ -42,22 +42,22 @@ func (de *DockerEnvironment) createCommand(cmd string) *exec.Cmd {
return utils.Command("bash", "-c", dockerCmdLine) return utils.Command("bash", "-c", dockerCmdLine)
} }
// Up spawn a docker environment // Up spawn a docker environment.
func (de *DockerEnvironment) Up() error { func (de *DockerEnvironment) Up() error {
return de.createCommandWithStdout("up --build -d").Run() return de.createCommandWithStdout("up --build -d").Run()
} }
// Restart restarts a service // Restart restarts a service.
func (de *DockerEnvironment) Restart(service string) error { func (de *DockerEnvironment) Restart(service string) error {
return de.createCommandWithStdout(fmt.Sprintf("restart %s", service)).Run() return de.createCommandWithStdout(fmt.Sprintf("restart %s", service)).Run()
} }
// Down spawn a docker environment // Down spawn a docker environment.
func (de *DockerEnvironment) Down() error { func (de *DockerEnvironment) Down() error {
return de.createCommandWithStdout("down -v").Run() return de.createCommandWithStdout("down -v").Run()
} }
// Logs get logs of a given service of the environment // Logs get logs of a given service of the environment.
func (de *DockerEnvironment) Logs(service string, flags []string) (string, error) { func (de *DockerEnvironment) Logs(service string, flags []string) (string, error) {
cmd := de.createCommand(fmt.Sprintf("logs %s %s", strings.Join(flags, " "), service)) cmd := de.createCommand(fmt.Sprintf("logs %s %s", strings.Join(flags, " "), service))
content, err := cmd.Output() content, err := cmd.Output()

View File

@ -8,17 +8,17 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
// DuoPolicy a type of policy // DuoPolicy a type of policy.
type DuoPolicy int32 type DuoPolicy int32
const ( const (
// Deny deny policy // Deny deny policy.
Deny DuoPolicy = iota Deny DuoPolicy = iota
// Allow allow policy // Allow allow policy.
Allow DuoPolicy = iota Allow DuoPolicy = iota
) )
// ConfigureDuo configure duo api to allow or block auth requests // ConfigureDuo configure duo api to allow or block auth requests.
func ConfigureDuo(t *testing.T, allowDeny DuoPolicy) { func ConfigureDuo(t *testing.T, allowDeny DuoPolicy) {
url := fmt.Sprintf("%s/allow", DuoBaseURL) url := fmt.Sprintf("%s/allow", DuoBaseURL)
if allowDeny == Deny { if allowDeny == Deny {

View File

@ -5,7 +5,7 @@ import (
"net/http" "net/http"
) )
// NewHTTPClient create a new client skipping TLS verification and not redirecting // NewHTTPClient create a new client skipping TLS verification and not redirecting.
func NewHTTPClient() *http.Client { func NewHTTPClient() *http.Client {
tr := &http.Transport{ tr := &http.Transport{
TLSClientConfig: &tls.Config{ TLSClientConfig: &tls.Config{

View File

@ -12,7 +12,7 @@ import (
var kindImageName = "authelia-kind-proxy" var kindImageName = "authelia-kind-proxy"
var dockerCmdLine = fmt.Sprintf("docker-compose -p authelia -f internal/suites/docker-compose.yml -f internal/suites/example/compose/kind/docker-compose.yml run --rm %s", kindImageName) var dockerCmdLine = fmt.Sprintf("docker-compose -p authelia -f internal/suites/docker-compose.yml -f internal/suites/example/compose/kind/docker-compose.yml run --rm %s", kindImageName)
// Kind used for running kind commands // Kind used for running kind commands.
type Kind struct{} type Kind struct{}
func kindCommand(cmdline string) *exec.Cmd { func kindCommand(cmdline string) *exec.Cmd {
@ -20,7 +20,7 @@ func kindCommand(cmdline string) *exec.Cmd {
return utils.Shell(cmd) return utils.Shell(cmd)
} }
// CreateCluster create a new Kubernetes cluster // CreateCluster create a new Kubernetes cluster.
func (k Kind) CreateCluster() error { func (k Kind) CreateCluster() error {
cmd := kindCommand("kind create cluster --config /etc/kind/config.yml") cmd := kindCommand("kind create cluster --config /etc/kind/config.yml")
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
@ -32,7 +32,7 @@ func (k Kind) CreateCluster() error {
return err return err
} }
// This command is necessary to fix the coredns loop detected when using user-defined docker network // This command is necessary to fix the coredns loop detected when using user-defined docker network.
// In that case /etc/resolv.conf use 127.0.0.11 as DNS and CoreDNS thinks it is talking to itself which is wrong. // In that case /etc/resolv.conf use 127.0.0.11 as DNS and CoreDNS thinks it is talking to itself which is wrong.
// This IP is the docker internal DNS so it is safe to disable the loop check. // This IP is the docker internal DNS so it is safe to disable the loop check.
cmd = kindCommand("sh -c 'kubectl -n kube-system get configmap/coredns -o yaml | grep -v loop | kubectl replace -f -'") cmd = kindCommand("sh -c 'kubectl -n kube-system get configmap/coredns -o yaml | grep -v loop | kubectl replace -f -'")
@ -42,13 +42,13 @@ func (k Kind) CreateCluster() error {
return nil return nil
} }
// DeleteCluster delete a Kubernetes cluster // DeleteCluster delete a Kubernetes cluster.
func (k Kind) DeleteCluster() error { func (k Kind) DeleteCluster() error {
cmd := kindCommand("kind delete cluster") cmd := kindCommand("kind delete cluster")
return cmd.Run() return cmd.Run()
} }
// ClusterExists check whether a cluster exists // ClusterExists check whether a cluster exists.
func (k Kind) ClusterExists() (bool, error) { func (k Kind) ClusterExists() (bool, error) {
cmd := kindCommand("kind get clusters") cmd := kindCommand("kind get clusters")
cmd.Stdout = nil cmd.Stdout = nil
@ -62,28 +62,28 @@ func (k Kind) ClusterExists() (bool, error) {
return strings.Contains(string(output), "kind"), nil return strings.Contains(string(output), "kind"), nil
} }
// LoadImage load an image in the Kubernetes container // LoadImage load an image in the Kubernetes container.
func (k Kind) LoadImage(imageName string) error { func (k Kind) LoadImage(imageName string) error {
cmd := kindCommand(fmt.Sprintf("kind load docker-image %s", imageName)) cmd := kindCommand(fmt.Sprintf("kind load docker-image %s", imageName))
return cmd.Run() return cmd.Run()
} }
// Kubectl used for running kubectl commands // Kubectl used for running kubectl commands.
type Kubectl struct{} type Kubectl struct{}
// StartProxy start a proxy // StartProxy start a proxy.
func (k Kubectl) StartProxy() error { func (k Kubectl) StartProxy() error {
cmd := utils.Shell("docker-compose -p authelia -f internal/suites/docker-compose.yml -f internal/suites/example/compose/kind/docker-compose.yml up -d authelia-kind-proxy") cmd := utils.Shell("docker-compose -p authelia -f internal/suites/docker-compose.yml -f internal/suites/example/compose/kind/docker-compose.yml up -d authelia-kind-proxy")
return cmd.Run() return cmd.Run()
} }
// StopProxy stop a proxy // StopProxy stop a proxy.
func (k Kubectl) StopProxy() error { func (k Kubectl) StopProxy() error {
cmd := utils.Shell("docker-compose -p authelia -f internal/suites/docker-compose.yml -f internal/suites/example/compose/kind/docker-compose.yml rm -s -f authelia-kind-proxy") cmd := utils.Shell("docker-compose -p authelia -f internal/suites/docker-compose.yml -f internal/suites/example/compose/kind/docker-compose.yml rm -s -f authelia-kind-proxy")
return cmd.Run() return cmd.Run()
} }
// StartDashboard start Kube dashboard // StartDashboard start Kube dashboard.
func (k Kubectl) StartDashboard() error { func (k Kubectl) StartDashboard() error {
if err := kindCommand("sh -c 'cd /authelia && ./bootstrap-dashboard.sh'").Run(); err != nil { if err := kindCommand("sh -c 'cd /authelia && ./bootstrap-dashboard.sh'").Run(); err != nil {
return err return err
@ -95,25 +95,25 @@ func (k Kubectl) StartDashboard() error {
return nil return nil
} }
// StopDashboard stop kube dashboard // StopDashboard stop kube dashboard.
func (k Kubectl) StopDashboard() error { func (k Kubectl) StopDashboard() error {
cmd := utils.Shell("docker-compose -p authelia -f internal/suites/docker-compose.yml -f internal/suites/example/compose/kind/docker-compose.yml rm -s -f kube-dashboard") cmd := utils.Shell("docker-compose -p authelia -f internal/suites/docker-compose.yml -f internal/suites/example/compose/kind/docker-compose.yml rm -s -f kube-dashboard")
return cmd.Run() return cmd.Run()
} }
// DeployThirdparties deploy thirdparty services (ldap, db, ingress controllers, etc...) // DeployThirdparties deploy thirdparty services (ldap, db, ingress controllers, etc...).
func (k Kubectl) DeployThirdparties() error { func (k Kubectl) DeployThirdparties() error {
cmd := kindCommand("sh -c 'cd /authelia && ./bootstrap.sh'") cmd := kindCommand("sh -c 'cd /authelia && ./bootstrap.sh'")
return cmd.Run() return cmd.Run()
} }
// DeployAuthelia deploy Authelia application // DeployAuthelia deploy Authelia application.
func (k Kubectl) DeployAuthelia() error { func (k Kubectl) DeployAuthelia() error {
cmd := kindCommand("sh -c 'cd /authelia && ./bootstrap-authelia.sh'") cmd := kindCommand("sh -c 'cd /authelia && ./bootstrap-authelia.sh'")
return cmd.Run() return cmd.Run()
} }
// WaitPodsReady wait for all pods to be ready // WaitPodsReady wait for all pods to be ready.
func (k Kubectl) WaitPodsReady(timeout time.Duration) error { func (k Kubectl) WaitPodsReady(timeout time.Duration) error {
return utils.CheckUntil(5*time.Second, timeout, func() (bool, error) { return utils.CheckUntil(5*time.Second, timeout, func() (bool, error) {
cmd := kindCommand("kubectl get -n authelia pods --no-headers") cmd := kindCommand("kubectl get -n authelia pods --no-headers")

View File

@ -7,7 +7,7 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
// Suite the definition of a suite // Suite the definition of a suite.
type Suite struct { type Suite struct {
SetUp func(tmpPath string) error SetUp func(tmpPath string) error
SetUpTimeout time.Duration SetUpTimeout time.Duration
@ -15,7 +15,7 @@ type Suite struct {
// Callback called when an error occur during setup phase. // Callback called when an error occur during setup phase.
OnSetupTimeout func() error OnSetupTimeout func() error
// Callback called when at least one test fail // Callback called when at least one test fail.
OnError func() error OnError func() error
TestTimeout time.Duration TestTimeout time.Duration
@ -27,24 +27,24 @@ type Suite struct {
Description string Description string
} }
// Registry represent a registry of suite by name // Registry represent a registry of suite by name.
type Registry struct { type Registry struct {
registry map[string]Suite registry map[string]Suite
} }
// GlobalRegistry a global registry used by Authelia tooling // GlobalRegistry a global registry used by Authelia tooling.
var GlobalRegistry *Registry var GlobalRegistry *Registry
func init() { func init() {
GlobalRegistry = NewSuitesRegistry() GlobalRegistry = NewSuitesRegistry()
} }
// NewSuitesRegistry create a suites registry // NewSuitesRegistry create a suites registry.
func NewSuitesRegistry() *Registry { func NewSuitesRegistry() *Registry {
return &Registry{make(map[string]Suite)} return &Registry{make(map[string]Suite)}
} }
// Register register a suite by name // Register register a suite by name.
func (sr *Registry) Register(name string, suite Suite) { func (sr *Registry) Register(name string, suite Suite) {
if _, found := sr.registry[name]; found { if _, found := sr.registry[name]; found {
log.Fatal(fmt.Sprintf("Trying to register the suite %s multiple times", name)) log.Fatal(fmt.Sprintf("Trying to register the suite %s multiple times", name))
@ -52,7 +52,7 @@ func (sr *Registry) Register(name string, suite Suite) {
sr.registry[name] = suite sr.registry[name] = suite
} }
// Get return a suite by name // Get return a suite by name.
func (sr *Registry) Get(name string) Suite { func (sr *Registry) Get(name string) Suite {
s, found := sr.registry[name] s, found := sr.registry[name]
if !found { if !found {
@ -61,7 +61,7 @@ func (sr *Registry) Get(name string) Suite {
return s return s
} }
// Suites list available suites // Suites list available suites.
func (sr *Registry) Suites() []string { func (sr *Registry) Suites() []string {
suites := make([]string, 0) suites := make([]string, 0)
for k := range sr.registry { for k := range sr.registry {

View File

@ -33,7 +33,7 @@ func (s *NetworkACLSuite) TestShouldAccessSecretUpon2FA() {
wds.verifySecretAuthorized(ctx, s.T()) wds.verifySecretAuthorized(ctx, s.T())
} }
// from network 192.168.240.201/32 // from network 192.168.240.201/32.
func (s *NetworkACLSuite) TestShouldAccessSecretUpon1FA() { func (s *NetworkACLSuite) TestShouldAccessSecretUpon1FA() {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel() defer cancel()
@ -51,7 +51,7 @@ func (s *NetworkACLSuite) TestShouldAccessSecretUpon1FA() {
wds.verifySecretAuthorized(ctx, s.T()) wds.verifySecretAuthorized(ctx, s.T())
} }
// from network 192.168.240.202/32 // from network 192.168.240.202/32.
func (s *NetworkACLSuite) TestShouldAccessSecretUpon0FA() { func (s *NetworkACLSuite) TestShouldAccessSecretUpon0FA() {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel() defer cancel()

View File

@ -57,11 +57,11 @@ func (s *StandaloneWebDriverSuite) TestShouldLetUserKnowHeIsAlreadyAuthenticated
_ = s.doRegisterAndLogin2FA(ctx, s.T(), "john", "password", false, "") _ = s.doRegisterAndLogin2FA(ctx, s.T(), "john", "password", false, "")
// Visit home page to change context // Visit home page to change context.
s.doVisit(s.T(), HomeBaseURL) s.doVisit(s.T(), HomeBaseURL)
s.verifyIsHome(ctx, s.T()) s.verifyIsHome(ctx, s.T())
// Visit the login page and wait for redirection to 2FA page with success icon displayed // Visit the login page and wait for redirection to 2FA page with success icon displayed.
s.doVisit(s.T(), LoginBaseURL) s.doVisit(s.T(), LoginBaseURL)
s.verifyIsAuthenticatedPage(ctx, s.T()) s.verifyIsAuthenticatedPage(ctx, s.T())
} }
@ -73,22 +73,22 @@ func (s *StandaloneWebDriverSuite) TestShouldCheckUserIsAskedToRegisterDevice()
username := "john" username := "john"
password := "password" password := "password"
// Clean up any TOTP secret already in DB // Clean up any TOTP secret already in DB.
provider := storage.NewSQLiteProvider("/tmp/db.sqlite3") provider := storage.NewSQLiteProvider("/tmp/db.sqlite3")
require.NoError(s.T(), provider.DeleteTOTPSecret(username)) require.NoError(s.T(), provider.DeleteTOTPSecret(username))
// Login one factor // Login one factor.
s.doLoginOneFactor(ctx, s.T(), username, password, false, "") s.doLoginOneFactor(ctx, s.T(), username, password, false, "")
// Check the user is asked to register a new device // Check the user is asked to register a new device.
s.WaitElementLocatedByClassName(ctx, s.T(), "state-not-registered") s.WaitElementLocatedByClassName(ctx, s.T(), "state-not-registered")
// Then register the TOTP factor // Then register the TOTP factor.
s.doRegisterTOTP(ctx, s.T()) s.doRegisterTOTP(ctx, s.T())
// And logout // And logout.
s.doLogout(ctx, s.T()) s.doLogout(ctx, s.T())
// Login one factor again // Login one factor again.
s.doLoginOneFactor(ctx, s.T(), username, password, false, "") s.doLoginOneFactor(ctx, s.T(), username, password, false, "")
// now the user should be asked to perform 2FA // now the user should be asked to perform 2FA
@ -103,7 +103,7 @@ func NewStandaloneSuite() *StandaloneSuite {
return &StandaloneSuite{} return &StandaloneSuite{}
} }
// Standard case using nginx // Standard case using nginx.
func (s *StandaloneSuite) TestShouldVerifyAPIVerifyUnauthorize() { func (s *StandaloneSuite) TestShouldVerifyAPIVerifyUnauthorize() {
req, err := http.NewRequest("GET", fmt.Sprintf("%s/api/verify", AutheliaBaseURL), nil) req, err := http.NewRequest("GET", fmt.Sprintf("%s/api/verify", AutheliaBaseURL), nil)
s.Assert().NoError(err) s.Assert().NoError(err)
@ -119,7 +119,7 @@ func (s *StandaloneSuite) TestShouldVerifyAPIVerifyUnauthorize() {
s.Assert().Equal(string(body), "Unauthorized") s.Assert().Equal(string(body), "Unauthorized")
} }
// Standard case using Kubernetes // Standard case using Kubernetes.
func (s *StandaloneSuite) TestShouldVerifyAPIVerifyRedirectFromXOriginalURL() { func (s *StandaloneSuite) TestShouldVerifyAPIVerifyRedirectFromXOriginalURL() {
req, err := http.NewRequest("GET", fmt.Sprintf("%s/api/verify?rd=%s", AutheliaBaseURL, LoginBaseURL), nil) req, err := http.NewRequest("GET", fmt.Sprintf("%s/api/verify?rd=%s", AutheliaBaseURL, LoginBaseURL), nil)
s.Assert().NoError(err) s.Assert().NoError(err)

View File

@ -5,14 +5,14 @@ import (
"github.com/tebeka/selenium" "github.com/tebeka/selenium"
) )
// SeleniumSuite is a selenium suite // SeleniumSuite is a selenium suite.
type SeleniumSuite struct { type SeleniumSuite struct {
suite.Suite suite.Suite
*WebDriverSession *WebDriverSession
} }
// WebDriver return the webdriver of the suite // WebDriver return the webdriver of the suite.
func (s *SeleniumSuite) WebDriver() selenium.WebDriver { func (s *SeleniumSuite) WebDriver() selenium.WebDriver {
return s.WebDriverSession.WebDriver return s.WebDriverSession.WebDriver
} }

View File

@ -19,7 +19,7 @@ type WebDriverSession struct {
WebDriver selenium.WebDriver WebDriver selenium.WebDriver
} }
// StartWebDriverWithProxy create a selenium session // StartWebDriverWithProxy create a selenium session.
func StartWebDriverWithProxy(proxy string, port int) (*WebDriverSession, error) { func StartWebDriverWithProxy(proxy string, port int) (*WebDriverSession, error) {
service, err := selenium.NewChromeDriverService("/usr/bin/chromedriver", port) service, err := selenium.NewChromeDriverService("/usr/bin/chromedriver", port)
@ -62,12 +62,12 @@ func StartWebDriverWithProxy(proxy string, port int) (*WebDriverSession, error)
}, nil }, nil
} }
// StartWebDriver create a selenium session // StartWebDriver create a selenium session.
func StartWebDriver() (*WebDriverSession, error) { func StartWebDriver() (*WebDriverSession, error) {
return StartWebDriverWithProxy("", 4444) return StartWebDriverWithProxy("", 4444)
} }
// Stop stop the selenium session // Stop stop the selenium session.
func (wds *WebDriverSession) Stop() error { func (wds *WebDriverSession) Stop() error {
err := wds.WebDriver.Quit() err := wds.WebDriver.Quit()
@ -78,7 +78,7 @@ func (wds *WebDriverSession) Stop() error {
return wds.service.Stop() return wds.service.Stop()
} }
// WithWebdriver run some actions against a webdriver // WithWebdriver run some actions against a webdriver.
func WithWebdriver(fn func(webdriver selenium.WebDriver) error) error { func WithWebdriver(fn func(webdriver selenium.WebDriver) error) error {
wds, err := StartWebDriver() wds, err := StartWebDriver()
@ -91,7 +91,7 @@ func WithWebdriver(fn func(webdriver selenium.WebDriver) error) error {
return fn(wds.WebDriver) return fn(wds.WebDriver)
} }
// Wait wait until condition holds true // Wait wait until condition holds true.
func (wds *WebDriverSession) Wait(ctx context.Context, condition selenium.Condition) error { func (wds *WebDriverSession) Wait(ctx context.Context, condition selenium.Condition) error {
done := make(chan error, 1) done := make(chan error, 1)
go func() { go func() {
@ -148,37 +148,37 @@ func (wds *WebDriverSession) waitElementsLocated(ctx context.Context, t *testing
return el return el
} }
// WaitElementLocatedByID wait an element is located by id // WaitElementLocatedByID wait an element is located by id.
func (wds *WebDriverSession) WaitElementLocatedByID(ctx context.Context, t *testing.T, id string) selenium.WebElement { func (wds *WebDriverSession) WaitElementLocatedByID(ctx context.Context, t *testing.T, id string) selenium.WebElement {
return wds.waitElementLocated(ctx, t, selenium.ByID, id) return wds.waitElementLocated(ctx, t, selenium.ByID, id)
} }
// WaitElementLocatedByTagName wait an element is located by tag name // WaitElementLocatedByTagName wait an element is located by tag name.
func (wds *WebDriverSession) WaitElementLocatedByTagName(ctx context.Context, t *testing.T, tagName string) selenium.WebElement { func (wds *WebDriverSession) WaitElementLocatedByTagName(ctx context.Context, t *testing.T, tagName string) selenium.WebElement {
return wds.waitElementLocated(ctx, t, selenium.ByTagName, tagName) return wds.waitElementLocated(ctx, t, selenium.ByTagName, tagName)
} }
// WaitElementLocatedByClassName wait an element is located by class name // WaitElementLocatedByClassName wait an element is located by class name.
func (wds *WebDriverSession) WaitElementLocatedByClassName(ctx context.Context, t *testing.T, className string) selenium.WebElement { func (wds *WebDriverSession) WaitElementLocatedByClassName(ctx context.Context, t *testing.T, className string) selenium.WebElement {
return wds.waitElementLocated(ctx, t, selenium.ByClassName, className) return wds.waitElementLocated(ctx, t, selenium.ByClassName, className)
} }
// WaitElementLocatedByLinkText wait an element is located by link text // WaitElementLocatedByLinkText wait an element is located by link text.
func (wds *WebDriverSession) WaitElementLocatedByLinkText(ctx context.Context, t *testing.T, linkText string) selenium.WebElement { func (wds *WebDriverSession) WaitElementLocatedByLinkText(ctx context.Context, t *testing.T, linkText string) selenium.WebElement {
return wds.waitElementLocated(ctx, t, selenium.ByLinkText, linkText) return wds.waitElementLocated(ctx, t, selenium.ByLinkText, linkText)
} }
// WaitElementLocatedByCSSSelector wait an element is located by class name // WaitElementLocatedByCSSSelector wait an element is located by class name.
func (wds *WebDriverSession) WaitElementLocatedByCSSSelector(ctx context.Context, t *testing.T, cssSelector string) selenium.WebElement { func (wds *WebDriverSession) WaitElementLocatedByCSSSelector(ctx context.Context, t *testing.T, cssSelector string) selenium.WebElement {
return wds.waitElementLocated(ctx, t, selenium.ByCSSSelector, cssSelector) return wds.waitElementLocated(ctx, t, selenium.ByCSSSelector, cssSelector)
} }
// WaitElementsLocatedByCSSSelector wait an element is located by CSS selector // WaitElementsLocatedByCSSSelector wait an element is located by CSS selector.
func (wds *WebDriverSession) WaitElementsLocatedByCSSSelector(ctx context.Context, t *testing.T, cssSelector string) []selenium.WebElement { func (wds *WebDriverSession) WaitElementsLocatedByCSSSelector(ctx context.Context, t *testing.T, cssSelector string) []selenium.WebElement {
return wds.waitElementsLocated(ctx, t, selenium.ByCSSSelector, cssSelector) return wds.waitElementsLocated(ctx, t, selenium.ByCSSSelector, cssSelector)
} }
// WaitElementTextContains wait the text of an element contains a pattern // WaitElementTextContains wait the text of an element contains a pattern.
func (wds *WebDriverSession) WaitElementTextContains(ctx context.Context, t *testing.T, element selenium.WebElement, pattern string) { func (wds *WebDriverSession) WaitElementTextContains(ctx context.Context, t *testing.T, element selenium.WebElement, pattern string) {
err := wds.Wait(ctx, func(driver selenium.WebDriver) (bool, error) { err := wds.Wait(ctx, func(driver selenium.WebDriver) (bool, error) {
text, err := element.Text() text, err := element.Text()

View File

@ -2,21 +2,21 @@ package utils
import "time" import "time"
// Clock is an interface for a clock // Clock is an interface for a clock.
type Clock interface { type Clock interface {
Now() time.Time Now() time.Time
After(d time.Duration) <-chan time.Time After(d time.Duration) <-chan time.Time
} }
// RealClock is the implementation of a clock for production code // RealClock is the implementation of a clock for production code.
type RealClock struct{} type RealClock struct{}
// Now return the current time // Now return the current time.
func (RealClock) Now() time.Time { func (RealClock) Now() time.Time {
return time.Now() return time.Now()
} }
// After return a channel receiving the time after the defined duration // After return a channel receiving the time after the defined duration.
func (RealClock) After(d time.Duration) <-chan time.Time { func (RealClock) After(d time.Duration) <-chan time.Time {
return time.After(d) return time.After(d)
} }

View File

@ -10,17 +10,17 @@ import (
var ErrTimeoutReached = errors.New("timeout reached") var ErrTimeoutReached = errors.New("timeout reached")
var parseDurationRegexp = regexp.MustCompile(`^(?P<Duration>[1-9]\d*?)(?P<Unit>[smhdwMy])?$`) var parseDurationRegexp = regexp.MustCompile(`^(?P<Duration>[1-9]\d*?)(?P<Unit>[smhdwMy])?$`)
// Hour is an int based representation of the time unit // Hour is an int based representation of the time unit.
const Hour = time.Minute * 60 const Hour = time.Minute * 60
// Day is an int based representation of the time unit // Day is an int based representation of the time unit.
const Day = Hour * 24 const Day = Hour * 24
// Week is an int based representation of the time unit // Week is an int based representation of the time unit.
const Week = Day * 7 const Week = Day * 7
// Year is an int based representation of the time unit // Year is an int based representation of the time unit.
const Year = Day * 365 const Year = Day * 365
// Month is an int based representation of the time unit // Month is an int based representation of the time unit.
const Month = Year / 12 const Month = Year / 12

View File

@ -15,11 +15,11 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
// Command create a command at the project root // Command create a command at the project root.
func Command(name string, args ...string) *exec.Cmd { func Command(name string, args ...string) *exec.Cmd {
cmd := exec.Command(name, args...) cmd := exec.Command(name, args...)
// By default set the working directory to the project root directory // By default set the working directory to the project root directory.
wd, _ := os.Getwd() wd, _ := os.Getwd()
for !strings.HasSuffix(wd, "authelia") { for !strings.HasSuffix(wd, "authelia") {
wd = filepath.Dir(wd) wd = filepath.Dir(wd)
@ -28,7 +28,7 @@ func Command(name string, args ...string) *exec.Cmd {
return cmd return cmd
} }
// CommandWithStdout create a command forwarding stdout and stderr to the OS streams // CommandWithStdout create a command forwarding stdout and stderr to the OS streams.
func CommandWithStdout(name string, args ...string) *exec.Cmd { func CommandWithStdout(name string, args ...string) *exec.Cmd {
cmd := Command(name, args...) cmd := Command(name, args...)
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
@ -36,12 +36,12 @@ func CommandWithStdout(name string, args ...string) *exec.Cmd {
return cmd return cmd
} }
// Shell create a shell command // Shell create a shell command.
func Shell(command string) *exec.Cmd { func Shell(command string) *exec.Cmd {
return CommandWithStdout("bash", "-c", command) return CommandWithStdout("bash", "-c", command)
} }
// RunCommandUntilCtrlC run a command until ctrl-c is hit // RunCommandUntilCtrlC run a command until ctrl-c is hit.
func RunCommandUntilCtrlC(cmd *exec.Cmd) { func RunCommandUntilCtrlC(cmd *exec.Cmd) {
mutex := sync.Mutex{} mutex := sync.Mutex{}
cond := sync.NewCond(&mutex) cond := sync.NewCond(&mutex)
@ -74,7 +74,7 @@ func RunCommandUntilCtrlC(cmd *exec.Cmd) {
cond.Wait() cond.Wait()
} }
// RunFuncUntilCtrlC run a function until ctrl-c is hit // RunFuncUntilCtrlC run a function until ctrl-c is hit.
func RunFuncUntilCtrlC(fn func() error) error { func RunFuncUntilCtrlC(fn func() error) error {
mutex := sync.Mutex{} mutex := sync.Mutex{}
cond := sync.NewCond(&mutex) cond := sync.NewCond(&mutex)

View File

@ -4,7 +4,7 @@ import (
"os" "os"
) )
// FileExists returns whether the given file or directory exists // FileExists returns whether the given file or directory exists.
func FileExists(path string) (bool, error) { func FileExists(path string) (bool, error) {
_, err := os.Stat(path) _, err := os.Stat(path)
if err == nil { if err == nil {

View File

@ -9,7 +9,7 @@ import (
// ParseDurationString parses a string to a duration // ParseDurationString parses a string to a duration
// Duration notations are an integer followed by a unit // Duration notations are an integer followed by a unit
// Units are s = second, m = minute, d = day, w = week, M = month, y = year // Units are s = second, m = minute, d = day, w = week, M = month, y = year
// Example 1y is the same as 1 year // Example 1y is the same as 1 year.
func ParseDurationString(input string) (time.Duration, error) { func ParseDurationString(input string) (time.Duration, error) {
var duration time.Duration var duration time.Duration
matches := parseDurationRegexp.FindStringSubmatch(input) matches := parseDurationRegexp.FindStringSubmatch(input)