[CI] Add godot linter (#958)

* [CI] Add godot linter

* Implement godot recommendations
This commit is contained in:
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:
gocyclo:
min-complexity: 15
godot:
check-all: true
goimports:
local-prefixes: github.com/authelia/authelia
linters:
enable:
- gocyclo
- godot
- gofmt
- goimports
- golint

View File

@ -13,16 +13,16 @@ import (
"github.com/authelia/authelia/internal/utils"
)
// HostEntry represents an entry in /etc/hosts
// HostEntry represents an entry in /etc/hosts.
type HostEntry struct {
Domain string
IP string
}
var hostEntries = []HostEntry{
// For authelia backend
// For authelia backend.
{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: "admin.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: "mail.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"},
// For HAProxy suite
// For HAProxy suite.
{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-client2.example.com", IP: "192.168.240.202"},
{Domain: "proxy-client3.example.com", IP: "192.168.240.203"},
// Kubernetes dashboard
// Kubernetes dashboard.
{Domain: "kubernetes.example.com", IP: "192.168.240.110"},
}
@ -170,7 +166,7 @@ func readVersions() {
readVersion("docker-compose", "--version")
}
// Bootstrap bootstrap authelia dev environment
// Bootstrap bootstrap authelia dev environment.
func Bootstrap(cobraCmd *cobra.Command, args []string) {
bootstrapPrintln("Checking command installation...")
checkCommandExist("node")

View File

@ -23,7 +23,7 @@ func buildAutheliaBinary() {
}
func buildFrontend() {
// Install npm dependencies
// Install npm dependencies.
cmd := utils.CommandWithStdout("yarn", "install")
cmd.Dir = "web"
@ -31,7 +31,7 @@ func buildFrontend() {
log.Fatal(err)
}
// Then build the frontend
// Then build the frontend.
cmd = utils.CommandWithStdout("yarn", "build")
cmd.Dir = "web"
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) {
log.Info("Building Authelia...")

View File

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

View File

@ -7,7 +7,7 @@ import (
"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) {
log.Debug("Removing `" + OutputDir + "` directory")
err := os.RemoveAll(OutputDir)

View File

@ -42,12 +42,12 @@ func checkArchIsSupported(arch string) {
func dockerBuildOfficialImage(arch string) error {
docker := &Docker{}
// Set default Architecture Dockerfile to amd64
// Set default Architecture Dockerfile to amd64.
dockerfile := "Dockerfile"
// Set version of QEMU
// Set version of QEMU.
qemuversion := "v4.2.0-7"
// If not the default value
// If not the default value.
if arch != defaultArch {
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{
Use: "push-image",
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{
Use: "push-manifest",
Short: "Publish Authelia docker manifest to Docker Hub",

View File

@ -7,7 +7,7 @@ import (
"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) {
log.Infof("Running Authelia with config %s...", 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.
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")
// runningSuiteFile name of the file containing the currently running suite
// runningSuiteFile name of the file containing the currently running suite.
var runningSuiteFile = ".suite"
var headless bool
@ -68,7 +68,7 @@ var SuitesSetupCmd = &cobra.Command{
Args: cobra.ExactArgs(1),
}
// SuitesTeardownCmd Command for tearing down a suite environment
// SuitesTeardownCmd Command for tearing down a suite environment.
var SuitesTeardownCmd = &cobra.Command{
Use: "teardown [suite]",
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),
}
// SuitesTestCmd Command for testing a suite
// SuitesTestCmd Command for testing a suite.
var SuitesTestCmd = &cobra.Command{
Use: "test [suite]",
Short: "Test a suite. Suites can be listed using the list command.",
@ -192,7 +192,7 @@ func testSuite(cmd *cobra.Command, args []string) {
log.Fatal(err)
}
// If suite(s) are provided as argument
// If suite(s) are provided as argument.
if len(args) >= 1 {
suiteArg := args[0]
@ -242,7 +242,7 @@ func runSuiteTests(suiteName string, withEnv bool) error {
suite := suites.GlobalRegistry.Get(suiteName)
// Default value is 1 minute
// Default value is 1 minute.
timeout := "60s"
if suite.TestTimeout > 0 {
timeout = fmt.Sprintf("%ds", int64(suite.TestTimeout/time.Second))
@ -279,7 +279,7 @@ func runSuiteTests(suiteName string, withEnv bool) error {
if withEnv {
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)
}
}

View File

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

View File

@ -1,10 +1,10 @@
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"
// DockerImageName the official name of authelia docker image
// DockerImageName the official name of Authelia docker image.
var DockerImageName = "authelia/authelia"
// IntermediateDockerImageName local name of the docker image
// IntermediateDockerImageName local name of the docker image.
var IntermediateDockerImageName = "authelia:dist"

View File

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

View File

@ -1,4 +1,5 @@
//usr/bin/env go run "$0" "$@"; exit
//nolint:godot
package main
@ -23,10 +24,10 @@ type AutheliaCommandDefinition struct {
SubCommands []*cobra.Command
}
// CobraCommands list of cobra commands
// CobraCommands list of cobra commands.
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{
{
Name: "bootstrap",

View File

@ -15,7 +15,7 @@ import (
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"
func init() {

View File

@ -21,7 +21,7 @@ const (
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}
const (

View File

@ -285,7 +285,7 @@ groups:
- 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(`
user:
john:

View File

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

View File

@ -12,7 +12,7 @@ import (
)
// 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 {
Algorithm string
Iterations int
@ -23,11 +23,11 @@ type PasswordHash struct {
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) {
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)
h := &PasswordHash{}
@ -81,8 +81,8 @@ func ParseHash(hash string) (passwordHash *PasswordHash, err error) {
return h, nil
}
// 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
// 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.
func HashPassword(password, salt, algorithm string, iterations, memory, parallelism, keyLength, saltLength int) (hash string, err error) {
var settings string
@ -105,7 +105,7 @@ func HashPassword(password, salt, algorithm string, iterations, memory, parallel
}
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 {
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 {
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 == "" {
@ -129,12 +129,12 @@ func HashPassword(password, salt, algorithm string, iterations, memory, parallel
}
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)
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) {
passwordHash, err := ParseHash(hash)
if err != nil {

View File

@ -45,7 +45,7 @@ func TestShouldHashArgon2idPassword(t *testing.T) {
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) {
data := string(HashingPossibleSaltCharacters)
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) {
data := string(HashingPossibleSaltCharacters)
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())
}
// Object object to check access control for
// Object object to check access control for.
type Object struct {
Domain string
Path string

View File

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

View File

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

View File

@ -7,19 +7,19 @@ import (
"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 {
Push(err error)
HasErrors() bool
Errors() []error
}
// Validator represents the validator interface
// Validator represents the validator interface.
type Validator struct {
errors map[string][]error
}
// NewValidator create a validator
// NewValidator create a validator.
func NewValidator() *Validator {
validator := new(Validator)
validator.errors = make(map[string][]error)
@ -67,7 +67,7 @@ func (v *Validator) validateOne(item QueueItem, q *queue.Queue) error { //nolint
return nil
}
// Validate validate a struct
// Validate validate a struct.
func (v *Validator) Validate(s interface{}) error {
q := queue.New(40)
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
}
// PrintErrors display the errors thrown during validation
// PrintErrors display the errors thrown during validation.
func (v *Validator) PrintErrors() {
for path, errs := range v.errors {
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 {
return v.errors
}
// StructValidator is a validator for structs
// StructValidator is a validator for structs.
type StructValidator struct {
errors []error
}
// NewStructValidator is a constructor of struct validator
// NewStructValidator is a constructor of struct validator.
func NewStructValidator() *StructValidator {
val := new(StructValidator)
val.errors = make([]error, 0)
@ -128,7 +128,7 @@ func (v *StructValidator) Errors() []error {
return v.errors
}
// Clear errors
// Clear errors.
func (v *StructValidator) Clear() {
v.errors = []error{}
}

View File

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

View File

@ -8,17 +8,17 @@ import (
"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 {
Call(values url.Values, ctx *middlewares.AutheliaCtx) (*Response, error)
}
// APIImpl implementation of DuoAPI interface
// APIImpl implementation of DuoAPI interface.
type APIImpl struct {
*duoapi.DuoApi
}
// Response response coming from Duo API
// Response response coming from Duo API.
type Response struct {
Response struct {
Result string `json:"result"`

View File

@ -5,10 +5,10 @@ import (
"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 {
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"`
}

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.
}
// SecondFactorTOTPIdentityFinish the handler for finishing the identity validation
// SecondFactorTOTPIdentityFinish the handler for finishing the identity validation.
var SecondFactorTOTPIdentityFinish = middlewares.IdentityVerificationFinish(
middlewares.IdentityVerificationFinishArgs{
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.
}
// SecondFactorU2FIdentityFinish the handler for finishing the identity validation
// SecondFactorU2FIdentityFinish the handler for finishing the identity validation.
var SecondFactorU2FIdentityFinish = middlewares.IdentityVerificationFinish(
middlewares.IdentityVerificationFinishArgs{
ActionClaim: U2FRegistrationAction,

View File

@ -6,13 +6,13 @@ import (
"github.com/authelia/authelia/internal/middlewares"
)
// ResetPasswordPost handler for resetting passwords
// ResetPasswordPost handler for resetting passwords.
func ResetPasswordPost(ctx *middlewares.AutheliaCtx) {
userSession := ctx.GetSession()
// 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
// 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 {
ctx.Error(fmt.Errorf("No identity verification process has been initiated"), unableToResetPasswordMessage)
return

View File

@ -26,7 +26,7 @@ func isSchemeWSS(url *url.URL) bool {
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) {
originalURL := ctx.XOriginalURL()
if originalURL != nil {
@ -64,8 +64,8 @@ func getOriginalURL(ctx *middlewares.AutheliaCtx) (*url.URL, error) {
return url, nil
}
// parseBasicAuth parses an HTTP Basic Authentication string
// "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" returns ("Aladdin", "open sesame", true)
// parseBasicAuth parses an HTTP Basic Authentication string.
// "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" returns ("Aladdin", "open sesame", true).
func parseBasicAuth(auth string) (username, password string, err error) {
if !strings.HasPrefix(auth, authPrefix) {
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
}
// 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,
username string, userGroups []string, clientIP net.IP, authLevel authentication.Level) authorizationMatching {
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
// 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
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)
}
// If the user is not correctly authenticated, send a 401
// If the user is not correctly authenticated, send a 401.
if !authenticated {
// Request Basic Authentication otherwise
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
}
// 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) {
if 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
maxInactivityPeriod := int64(ctx.Providers.SessionProvider.Inactivity.Seconds())
if maxInactivityPeriod == 0 {
@ -171,10 +171,10 @@ func hasUserBeenInactiveLongEnough(ctx *middlewares.AutheliaCtx) (bool, error) {
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
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 == ""
if isUserAnonymous && userSession.AuthenticationLevel != authentication.NotAuthenticated {
@ -188,7 +188,7 @@ func verifyFromSessionCookie(targetURL url.URL, ctx *middlewares.AutheliaCtx) (u
}
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)
if err != nil {
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) {
// 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
// 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"))
if rd != "" {
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
}
// Mark current activity
// Mark current activity.
userSession.LastActivity = ctx.Clock.Now().Unix()
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) {
ctx.Logger.Tracef("Headers=%s", ctx.Request.Header.String())
targetURL, err := getOriginalURL(ctx)

View File

@ -19,7 +19,7 @@ import (
"github.com/authelia/authelia/internal/session"
)
// Test getOriginalURL
// Test getOriginalURL.
func TestShouldGetOriginalURLFromOriginalURLHeader(t *testing.T) {
mock := mocks.NewMockAutheliaCtx(t)
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())
}
// Test parseBasicAuth
// Test parseBasicAuth.
func TestShouldRaiseWhenHeaderDoesNotContainBasicPrefix(t *testing.T) {
_, _, err := parseBasicAuth("alzefzlfzemjfej==")
assert.Error(t, err)
@ -138,7 +138,7 @@ func TestShouldReturnUsernameAndPassword(t *testing.T) {
assert.Equal(t, "password", password)
}
// Test isTargetURLAuthorized
// Test isTargetURLAuthorized.
func TestShouldCheckAuthorizationMatching(t *testing.T) {
type Rule struct {
Policy string
@ -185,7 +185,7 @@ func TestShouldCheckAuthorizationMatching(t *testing.T) {
}
}
// Test verifyBasicAuth
// Test verifyBasicAuth.
func TestShouldVerifyWrongCredentials(t *testing.T) {
mock := mocks.NewMockAutheliaCtx(t)
defer mock.Close()
@ -473,7 +473,7 @@ func TestShouldDestroySessionWhenInactiveForTooLong(t *testing.T) {
past := clock.Now().Add(-1 * time.Hour)
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)
assert.Equal(t, time.Second*10, mock.Ctx.Providers.SessionProvider.Inactivity)
@ -487,7 +487,7 @@ func TestShouldDestroySessionWhenInactiveForTooLong(t *testing.T) {
VerifyGet(mock.Ctx)
// The session has been destroyed
// The session has been destroyed.
newUserSession := mock.Ctx.GetSession()
assert.Equal(t, "", newUserSession.Username)
assert.Equal(t, authentication.NotAuthenticated, newUserSession.AuthenticationLevel)
@ -504,7 +504,7 @@ func TestShouldDestroySessionWhenInactiveForTooLongUsingDurationNotation(t *test
clock.Set(time.Now())
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)
assert.Equal(t, time.Second*10, mock.Ctx.Providers.SessionProvider.Inactivity)
@ -518,7 +518,7 @@ func TestShouldDestroySessionWhenInactiveForTooLongUsingDurationNotation(t *test
VerifyGet(mock.Ctx)
// The session has been destroyed
// The session has been destroyed.
newUserSession := mock.Ctx.GetSession()
assert.Equal(t, "", newUserSession.Username)
assert.Equal(t, authentication.NotAuthenticated, newUserSession.AuthenticationLevel)
@ -544,7 +544,7 @@ func TestShouldKeepSessionWhenUserCheckedRememberMeAndIsInactiveForTooLong(t *te
VerifyGet(mock.Ctx)
// The session has been destroyed
// The session has been destroyed.
newUserSession := mock.Ctx.GetSession()
assert.Equal(t, "john", newUserSession.Username)
assert.Equal(t, authentication.TwoFactor, newUserSession.AuthenticationLevel)
@ -574,7 +574,7 @@ func TestShouldKeepSessionWhenInactivityTimeoutHasNotBeenExceeded(t *testing.T)
VerifyGet(mock.Ctx)
// The session has been destroyed
// The session has been destroyed.
newUserSession := mock.Ctx.GetSession()
assert.Equal(t, "john", newUserSession.Username)
assert.Equal(t, authentication.TwoFactor, newUserSession.AuthenticationLevel)
@ -593,7 +593,7 @@ func TestShouldRedirectWhenSessionInactiveForTooLongAndRDParamProvided(t *testin
clock.Set(time.Now())
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)
assert.Equal(t, time.Second*10, mock.Ctx.Providers.SessionProvider.Inactivity)
@ -640,7 +640,7 @@ func TestShouldUpdateInactivityTimestampEvenWhenHittingForbiddenResources(t *tes
VerifyGet(mock.Ctx)
// The resource if forbidden
// The resource if forbidden.
assert.Equal(t, 403, mock.Ctx.Response.StatusCode())
// 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(
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
// with a different port as mentioned in https://tools.ietf.org/html/rfc6265#section-8.5
// 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.
assert.True(t, isURLUnderProtectedDomain(
GetURL("https://mytest.example.com:8080/abc/?query=abc"), "example.com"))
}

View File

@ -9,7 +9,7 @@ import (
"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) {
if targetURI == "" {
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.
}
// Handle2FAResponse handle the redirection upon 2FA authentication
// Handle2FAResponse handle the redirection upon 2FA authentication.
func Handle2FAResponse(ctx *middlewares.AutheliaCtx, targetURI string) {
if targetURI == "" {
if ctx.Configuration.DefaultRedirectionURL != "" {

View File

@ -17,7 +17,7 @@ func SetLevel(level logrus.Level) {
logrus.SetLevel(level)
}
// InitializeLogger initialize logger
// InitializeLogger initialize logger.
func InitializeLogger(filename string) error {
callerLevels := []logrus.Level{}
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)
}
// 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) {
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)
}
// ReplyUnauthorized response sent when user is unauthorized
// ReplyUnauthorized response sent when user is unauthorized.
func (c *AutheliaCtx) ReplyUnauthorized() {
c.RequestCtx.Error(fasthttp.StatusMessage(fasthttp.StatusUnauthorized), fasthttp.StatusUnauthorized)
// 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() {
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 {
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 {
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 {
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 {
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)
}
// ReplyOK is a helper method to reply ok
// ReplyOK is a helper method to reply ok.
func (c *AutheliaCtx) ReplyOK() {
c.SetContentType(applicationJSONContentType)
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 {
err := json.Unmarshal(c.PostBody(), &value)
@ -147,7 +147,7 @@ func (c *AutheliaCtx) ParseBody(value interface{}) error {
return nil
}
// SetJSONBody Set json body
// SetJSONBody Set json body.
func (c *AutheliaCtx) SetJSONBody(value interface{}) error {
b, err := json.Marshal(OKResponse{Status: "OK", Data: value})
if err != nil {

View File

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

View File

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

View File

@ -54,23 +54,23 @@ type IdentityVerificationStartArgs struct {
// is completed successfully.
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
// The function retrieving the identity to who the email will be sent.
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
}
// IdentityVerificationFinishArgs represent the arguments used to customize the finishing phase
// of the identity verification process.
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
// 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
}
@ -90,13 +90,13 @@ type IdentityVerificationFinishBody struct {
Token string `json:"token"`
}
// OKResponse model of a status OK response
// OKResponse model of a status OK response.
type OKResponse struct {
Status string `json:"status"`
Data interface{} `json:"data,omitempty"`
}
// ErrorResponse model of an error response
// ErrorResponse model of an error response.
type ErrorResponse struct {
Status string `json:"status"`
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) {
dir := filepath.Dir(n.path)
if _, err := os.Stat(dir); err != nil {

View File

@ -2,5 +2,5 @@ package regulation
import "fmt"
// ErrUserIsBanned user is banned error message
// ErrUserIsBanned user is banned error message.
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.
// 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 {
return r.storageProvider.AppendAuthenticationLog(models.AuthenticationAttempt{
Username: username,

View File

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

View File

@ -44,7 +44,7 @@ func NewProvider(configuration schema.SessionConfiguration) *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) {
store, err := p.sessionHolder.Get(ctx)

View File

@ -10,7 +10,7 @@ import (
"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 {
config := session.NewDefaultConfig()
@ -23,7 +23,7 @@ func NewProviderConfig(configuration schema.SessionConfiguration) ProviderConfig
// Only serve the header over HTTPS.
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)
// 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,
Port: configuration.Redis.Port,
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,
PoolSize: 8,
IdleTimeout: 300,

View File

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

View File

@ -9,24 +9,24 @@ var totpSecretsTableName = "totp_secrets"
var u2fDeviceHandlesTableName = "u2f_devices"
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(`
CREATE TABLE IF NOT EXISTS %s (
username VARCHAR(100) PRIMARY KEY,
second_factor_method VARCHAR(11)
)`, 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(`
CREATE TABLE IF NOT EXISTS %s (token VARCHAR(512))
`, identityVerificationTokensTableName)
// SQLCreateTOTPSecretsTable common SQL query to create totp_secrets table
// SQLCreateTOTPSecretsTable common SQL query to create totp_secrets table.
var SQLCreateTOTPSecretsTable = fmt.Sprintf(`
CREATE TABLE IF NOT EXISTS %s (username VARCHAR(100) PRIMARY KEY, secret VARCHAR(64))
`, 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(`
CREATE TABLE IF NOT EXISTS %s (
username VARCHAR(100) PRIMARY KEY,
@ -34,7 +34,7 @@ CREATE TABLE IF NOT EXISTS %s (
publicKey TEXT
)`, u2fDeviceHandlesTableName)
// SQLCreateAuthenticationLogsTable common SQL query to create authentication_logs table
// SQLCreateAuthenticationLogsTable common SQL query to create authentication_logs table.
var SQLCreateAuthenticationLogsTable = fmt.Sprintf(`
CREATE TABLE IF NOT EXISTS %s (
username VARCHAR(100),

View File

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

View File

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

View File

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

View File

@ -28,13 +28,13 @@ func (wds *WebDriverSession) doFillLoginPageAndClick(ctx context.Context, t *tes
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) {
wds.doVisitLoginPage(ctx, t, targetURL)
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) {
wds.doLoginOneFactor(ctx, t, username, password, keepMeLoggedIn, targetURL)
wds.verifyIsSecondFactorPage(ctx, t)

View File

@ -2,41 +2,41 @@ package suites
import "fmt"
// BaseDomain the base domain
// BaseDomain the base domain.
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)
// SingleFactorBaseURL the base URL of the singlefactor domain
// SingleFactorBaseURL the base URL of the singlefactor domain.
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)
// MailBaseURL the base URL of the mail domain
// MailBaseURL the base URL of the mail domain.
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)
// PublicBaseURL the base URL of the public domain
// PublicBaseURL the base URL of the public domain.
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)
// DevBaseURL the base URL of the dev domain
// DevBaseURL the base URL of the dev domain.
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)
// 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)
// DuoBaseURL the base URL of the Duo configuration API
// DuoBaseURL the base URL of the Duo configuration API.
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"

View File

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

View File

@ -8,17 +8,17 @@ import (
"github.com/stretchr/testify/require"
)
// DuoPolicy a type of policy
// DuoPolicy a type of policy.
type DuoPolicy int32
const (
// Deny deny policy
// Deny deny policy.
Deny DuoPolicy = iota
// Allow allow policy
// Allow allow policy.
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) {
url := fmt.Sprintf("%s/allow", DuoBaseURL)
if allowDeny == Deny {

View File

@ -5,7 +5,7 @@ import (
"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 {
tr := &http.Transport{
TLSClientConfig: &tls.Config{

View File

@ -12,7 +12,7 @@ import (
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)
// Kind used for running kind commands
// Kind used for running kind commands.
type Kind struct{}
func kindCommand(cmdline string) *exec.Cmd {
@ -20,7 +20,7 @@ func kindCommand(cmdline string) *exec.Cmd {
return utils.Shell(cmd)
}
// CreateCluster create a new Kubernetes cluster
// CreateCluster create a new Kubernetes cluster.
func (k Kind) CreateCluster() error {
cmd := kindCommand("kind create cluster --config /etc/kind/config.yml")
if err := cmd.Run(); err != nil {
@ -32,7 +32,7 @@ func (k Kind) CreateCluster() error {
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.
// 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 -'")
@ -42,13 +42,13 @@ func (k Kind) CreateCluster() error {
return nil
}
// DeleteCluster delete a Kubernetes cluster
// DeleteCluster delete a Kubernetes cluster.
func (k Kind) DeleteCluster() error {
cmd := kindCommand("kind delete cluster")
return cmd.Run()
}
// ClusterExists check whether a cluster exists
// ClusterExists check whether a cluster exists.
func (k Kind) ClusterExists() (bool, error) {
cmd := kindCommand("kind get clusters")
cmd.Stdout = nil
@ -62,28 +62,28 @@ func (k Kind) ClusterExists() (bool, error) {
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 {
cmd := kindCommand(fmt.Sprintf("kind load docker-image %s", imageName))
return cmd.Run()
}
// Kubectl used for running kubectl commands
// Kubectl used for running kubectl commands.
type Kubectl struct{}
// StartProxy start a proxy
// StartProxy start a proxy.
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")
return cmd.Run()
}
// StopProxy stop a proxy
// StopProxy stop a proxy.
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")
return cmd.Run()
}
// StartDashboard start Kube dashboard
// StartDashboard start Kube dashboard.
func (k Kubectl) StartDashboard() error {
if err := kindCommand("sh -c 'cd /authelia && ./bootstrap-dashboard.sh'").Run(); err != nil {
return err
@ -95,25 +95,25 @@ func (k Kubectl) StartDashboard() error {
return nil
}
// StopDashboard stop kube dashboard
// StopDashboard stop kube dashboard.
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")
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 {
cmd := kindCommand("sh -c 'cd /authelia && ./bootstrap.sh'")
return cmd.Run()
}
// DeployAuthelia deploy Authelia application
// DeployAuthelia deploy Authelia application.
func (k Kubectl) DeployAuthelia() error {
cmd := kindCommand("sh -c 'cd /authelia && ./bootstrap-authelia.sh'")
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 {
return utils.CheckUntil(5*time.Second, timeout, func() (bool, error) {
cmd := kindCommand("kubectl get -n authelia pods --no-headers")

View File

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

View File

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

View File

@ -57,11 +57,11 @@ func (s *StandaloneWebDriverSuite) TestShouldLetUserKnowHeIsAlreadyAuthenticated
_ = 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.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.verifyIsAuthenticatedPage(ctx, s.T())
}
@ -73,22 +73,22 @@ func (s *StandaloneWebDriverSuite) TestShouldCheckUserIsAskedToRegisterDevice()
username := "john"
password := "password"
// Clean up any TOTP secret already in DB
// Clean up any TOTP secret already in DB.
provider := storage.NewSQLiteProvider("/tmp/db.sqlite3")
require.NoError(s.T(), provider.DeleteTOTPSecret(username))
// Login one factor
// Login one factor.
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")
// Then register the TOTP factor
// Then register the TOTP factor.
s.doRegisterTOTP(ctx, s.T())
// And logout
// And logout.
s.doLogout(ctx, s.T())
// Login one factor again
// Login one factor again.
s.doLoginOneFactor(ctx, s.T(), username, password, false, "")
// now the user should be asked to perform 2FA
@ -103,7 +103,7 @@ func NewStandaloneSuite() *StandaloneSuite {
return &StandaloneSuite{}
}
// Standard case using nginx
// Standard case using nginx.
func (s *StandaloneSuite) TestShouldVerifyAPIVerifyUnauthorize() {
req, err := http.NewRequest("GET", fmt.Sprintf("%s/api/verify", AutheliaBaseURL), nil)
s.Assert().NoError(err)
@ -119,7 +119,7 @@ func (s *StandaloneSuite) TestShouldVerifyAPIVerifyUnauthorize() {
s.Assert().Equal(string(body), "Unauthorized")
}
// Standard case using Kubernetes
// Standard case using Kubernetes.
func (s *StandaloneSuite) TestShouldVerifyAPIVerifyRedirectFromXOriginalURL() {
req, err := http.NewRequest("GET", fmt.Sprintf("%s/api/verify?rd=%s", AutheliaBaseURL, LoginBaseURL), nil)
s.Assert().NoError(err)

View File

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

View File

@ -19,7 +19,7 @@ type WebDriverSession struct {
WebDriver selenium.WebDriver
}
// StartWebDriverWithProxy create a selenium session
// StartWebDriverWithProxy create a selenium session.
func StartWebDriverWithProxy(proxy string, port int) (*WebDriverSession, error) {
service, err := selenium.NewChromeDriverService("/usr/bin/chromedriver", port)
@ -62,12 +62,12 @@ func StartWebDriverWithProxy(proxy string, port int) (*WebDriverSession, error)
}, nil
}
// StartWebDriver create a selenium session
// StartWebDriver create a selenium session.
func StartWebDriver() (*WebDriverSession, error) {
return StartWebDriverWithProxy("", 4444)
}
// Stop stop the selenium session
// Stop stop the selenium session.
func (wds *WebDriverSession) Stop() error {
err := wds.WebDriver.Quit()
@ -78,7 +78,7 @@ func (wds *WebDriverSession) Stop() error {
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 {
wds, err := StartWebDriver()
@ -91,7 +91,7 @@ func WithWebdriver(fn func(webdriver selenium.WebDriver) error) error {
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 {
done := make(chan error, 1)
go func() {
@ -148,37 +148,37 @@ func (wds *WebDriverSession) waitElementsLocated(ctx context.Context, t *testing
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 {
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 {
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 {
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 {
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 {
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 {
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) {
err := wds.Wait(ctx, func(driver selenium.WebDriver) (bool, error) {
text, err := element.Text()

View File

@ -2,21 +2,21 @@ package utils
import "time"
// Clock is an interface for a clock
// Clock is an interface for a clock.
type Clock interface {
Now() 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{}
// Now return the current time
// Now return the current time.
func (RealClock) Now() time.Time {
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 {
return time.After(d)
}

View File

@ -10,17 +10,17 @@ import (
var ErrTimeoutReached = errors.New("timeout reached")
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
// Day is an int based representation of the time unit
// Day is an int based representation of the time unit.
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
// Year is an int based representation of the time unit
// Year is an int based representation of the time unit.
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

View File

@ -15,11 +15,11 @@ import (
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 {
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()
for !strings.HasSuffix(wd, "authelia") {
wd = filepath.Dir(wd)
@ -28,7 +28,7 @@ func Command(name string, args ...string) *exec.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 {
cmd := Command(name, args...)
cmd.Stdout = os.Stdout
@ -36,12 +36,12 @@ func CommandWithStdout(name string, args ...string) *exec.Cmd {
return cmd
}
// Shell create a shell command
// Shell create a shell command.
func Shell(command string) *exec.Cmd {
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) {
mutex := sync.Mutex{}
cond := sync.NewCond(&mutex)
@ -74,7 +74,7 @@ func RunCommandUntilCtrlC(cmd *exec.Cmd) {
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 {
mutex := sync.Mutex{}
cond := sync.NewCond(&mutex)

View File

@ -4,7 +4,7 @@ import (
"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) {
_, err := os.Stat(path)
if err == nil {

View File

@ -9,7 +9,7 @@ import (
// ParseDurationString parses a string to a duration
// Duration notations are an integer followed by a unit
// 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) {
var duration time.Duration
matches := parseDurationRegexp.FindStringSubmatch(input)