[MISC] Add missing CLI suite test (#1607)

* [MISC] Add missing CLI suite test

* Add missing test for `authelia version` command in CLI suite.
* Standardise logger calls and swap CSP switch order
pull/1608/head
Amir Zarrinkafsh 2021-01-17 10:23:35 +11:00 committed by GitHub
parent 8bab8d47ef
commit 296efe2b32
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 85 additions and 59 deletions

View File

@ -25,11 +25,12 @@ var configPathFlag string
//nolint:gocyclo // TODO: Consider refactoring/simplifying, time permitting.
func startServer() {
logger := logging.Logger()
config, errs := configuration.Read(configPathFlag)
if len(errs) > 0 {
for _, err := range errs {
logging.Logger().Error(err)
logger.Error(err)
}
os.Exit(1)
@ -38,7 +39,7 @@ func startServer() {
autheliaCertPool, errs, nonFatalErrs := utils.NewX509CertPool(config.CertificatesDirectory, config)
if len(errs) > 0 {
for _, err := range errs {
logging.Logger().Error(err)
logger.Error(err)
}
os.Exit(2)
@ -46,28 +47,28 @@ func startServer() {
if len(nonFatalErrs) > 0 {
for _, err := range nonFatalErrs {
logging.Logger().Warn(err)
logger.Warn(err)
}
}
if err := logging.InitializeLogger(config.LogFormat, config.LogFilePath); err != nil {
logging.Logger().Fatalf("Cannot initialize logger: %v", err)
logger.Fatalf("Cannot initialize logger: %v", err)
}
switch config.LogLevel {
case "info":
logging.Logger().Info("Logging severity set to info")
logger.Info("Logging severity set to info")
logging.SetLevel(logrus.InfoLevel)
case "debug":
logging.Logger().Info("Logging severity set to debug")
logger.Info("Logging severity set to debug")
logging.SetLevel(logrus.DebugLevel)
case "trace":
logging.Logger().Info("Logging severity set to trace")
logger.Info("Logging severity set to trace")
logging.SetLevel(logrus.TraceLevel)
}
if os.Getenv("ENVIRONMENT") == "dev" {
logging.Logger().Info("===> Authelia is running in development mode. <===")
logger.Info("===> Authelia is running in development mode. <===")
}
var storageProvider storage.Provider
@ -80,7 +81,7 @@ func startServer() {
case config.Storage.Local != nil:
storageProvider = storage.NewSQLiteProvider(config.Storage.Local.Path)
default:
logging.Logger().Fatalf("Unrecognized storage backend")
logger.Fatalf("Unrecognized storage backend")
}
var userProvider authentication.UserProvider
@ -91,7 +92,7 @@ func startServer() {
case config.AuthenticationBackend.Ldap != nil:
userProvider = authentication.NewLDAPUserProvider(*config.AuthenticationBackend.Ldap, autheliaCertPool)
default:
logging.Logger().Fatalf("Unrecognized authentication backend")
logger.Fatalf("Unrecognized authentication backend")
}
var notifier notification.Notifier
@ -102,13 +103,13 @@ func startServer() {
case config.Notifier.FileSystem != nil:
notifier = notification.NewFileNotifier(*config.Notifier.FileSystem)
default:
logging.Logger().Fatalf("Unrecognized notifier")
logger.Fatalf("Unrecognized notifier")
}
if !config.Notifier.DisableStartupCheck {
_, err := notifier.StartupCheck()
if err != nil {
logging.Logger().Fatalf("Error during notifier startup check: %s", err)
logger.Fatalf("Error during notifier startup check: %s", err)
}
}
@ -129,6 +130,7 @@ func startServer() {
}
func main() {
logger := logging.Logger()
rootCmd := &cobra.Command{
Use: "authelia",
Run: func(cmd *cobra.Command, args []string) {
@ -150,6 +152,6 @@ func main() {
commands.ValidateConfigCmd, commands.CertificatesCmd)
if err := rootCmd.Execute(); err != nil {
logging.Logger().Fatal(err)
logger.Fatal(err)
}
}

View File

@ -36,10 +36,12 @@ type DatabaseModel struct {
// NewFileUserProvider creates a new instance of FileUserProvider.
func NewFileUserProvider(configuration *schema.FileAuthenticationBackendConfiguration) *FileUserProvider {
logger := logging.Logger()
errs := checkDatabase(configuration.Path)
if errs != nil {
for _, err := range errs {
logging.Logger().Error(err)
logger.Error(err)
}
os.Exit(1)

View File

@ -166,8 +166,9 @@ func (p *LDAPUserProvider) resolveUsersFilter(userFilter string, inputUsername s
}
func (p *LDAPUserProvider) getUserProfile(conn LDAPConnection, inputUsername string) (*ldapUserProfile, error) {
logger := logging.Logger()
userFilter := p.resolveUsersFilter(p.configuration.UsersFilter, inputUsername)
logging.Logger().Tracef("Computed user filter is %s", userFilter)
logger.Tracef("Computed user filter is %s", userFilter)
attributes := []string{"dn",
p.configuration.DisplayNameAttribute,
@ -239,6 +240,8 @@ func (p *LDAPUserProvider) resolveGroupsFilter(inputUsername string, profile *ld
// GetDetails retrieve the groups a user belongs to.
func (p *LDAPUserProvider) GetDetails(inputUsername string) (*UserDetails, error) {
logger := logging.Logger()
conn, err := p.connect(p.configuration.User, p.configuration.Password)
if err != nil {
return nil, err
@ -255,7 +258,7 @@ func (p *LDAPUserProvider) GetDetails(inputUsername string) (*UserDetails, error
return nil, fmt.Errorf("Unable to create group filter for user %s. Cause: %s", inputUsername, err)
}
logging.Logger().Tracef("Computed groups filter is %s", groupsFilter)
logger.Tracef("Computed groups filter is %s", groupsFilter)
// Search for the given username.
searchGroupRequest := ldap.NewSearchRequest(
@ -273,7 +276,7 @@ func (p *LDAPUserProvider) GetDetails(inputUsername string) (*UserDetails, error
for _, res := range sr.Entries {
if len(res.Attributes) == 0 {
logging.Logger().Warningf("No groups retrieved from LDAP for user %s", inputUsername)
logger.Warningf("No groups retrieved from LDAP for user %s", inputUsername)
break
}
// Append all values of the document. Normally there should be only one per document.

View File

@ -114,8 +114,8 @@ func (p *Authorizer) IsSecondFactorEnabled() bool {
// GetRequiredLevel retrieve the required level of authorization to access the object.
func (p *Authorizer) GetRequiredLevel(subject Subject, requestURL url.URL) Level {
logging.Logger().Tracef("Check authorization of subject %s and url %s.",
subject.String(), requestURL.String())
logger := logging.Logger()
logger.Tracef("Check authorization of subject %s and url %s.", subject.String(), requestURL.String())
matchingRules := selectMatchingRules(p.configuration.Rules, p.configuration.Networks, subject, Object{
Domain: requestURL.Hostname(),
@ -126,8 +126,7 @@ func (p *Authorizer) GetRequiredLevel(subject Subject, requestURL url.URL) Level
return PolicyToLevel(matchingRules[0].Policy)
}
logging.Logger().Tracef("No matching rule for subject %s and url %s... Applying default policy.",
subject.String(), requestURL.String())
logger.Tracef("No matching rule for subject %s and url %s... Applying default policy.", subject.String(), requestURL.String())
return PolicyToLevel(p.configuration.DefaultPolicy)
}

View File

@ -18,6 +18,8 @@ import (
// Read a YAML configuration and create a Configuration object out of it.
//go:generate broccoli -src ../../config.template.yml -var=cfg -o configuration
func Read(configPath string) (*schema.Configuration, []error) {
logger := logging.Logger()
if configPath == "" {
return nil, []error{errors.New("No config file path provided")}
}
@ -81,7 +83,7 @@ func Read(configPath string) (*schema.Configuration, []error) {
if val.HasWarnings() {
for _, warn := range val.Warnings() {
logging.Logger().Warnf(warn.Error())
logger.Warnf(warn.Error())
}
}

View File

@ -51,25 +51,26 @@ func NewSMTPNotifier(configuration schema.SMTPNotifierConfiguration, certPool *x
// Do startTLS if available (some servers only provide the auth extension after, and encryption is preferred).
func (n *SMTPNotifier) startTLS() error {
logger := logging.Logger()
// Only start if not already encrypted
if _, ok := n.client.TLSConnectionState(); ok {
logging.Logger().Debugf("Notifier SMTP connection is already encrypted, skipping STARTTLS")
logger.Debugf("Notifier SMTP connection is already encrypted, skipping STARTTLS")
return nil
}
switch ok, _ := n.client.Extension("STARTTLS"); ok {
case true:
logging.Logger().Debugf("Notifier SMTP server supports STARTTLS (disableVerifyCert: %t, ServerName: %s), attempting", n.tlsConfig.InsecureSkipVerify, n.tlsConfig.ServerName)
logger.Debugf("Notifier SMTP server supports STARTTLS (disableVerifyCert: %t, ServerName: %s), attempting", n.tlsConfig.InsecureSkipVerify, n.tlsConfig.ServerName)
if err := n.client.StartTLS(n.tlsConfig); err != nil {
return err
}
logging.Logger().Debug("Notifier SMTP STARTTLS completed without error")
logger.Debug("Notifier SMTP STARTTLS completed without error")
default:
switch n.disableRequireTLS {
case true:
logging.Logger().Warn("Notifier SMTP server does not support STARTTLS and SMTP configuration is set to disable the TLS requirement (only useful for unauthenticated emails over plain text)")
logger.Warn("Notifier SMTP server does not support STARTTLS and SMTP configuration is set to disable the TLS requirement (only useful for unauthenticated emails over plain text)")
default:
return errors.New("Notifier SMTP server does not support TLS and it is required by default (see documentation if you want to disable this highly recommended requirement)")
}
@ -80,6 +81,7 @@ func (n *SMTPNotifier) startTLS() error {
// Attempt Authentication.
func (n *SMTPNotifier) auth() error {
logger := logging.Logger()
// Attempt AUTH if password is specified only.
if n.password != "" {
_, ok := n.client.TLSConnectionState()
@ -92,18 +94,18 @@ func (n *SMTPNotifier) auth() error {
if ok {
var auth smtp.Auth
logging.Logger().Debugf("Notifier SMTP server supports authentication with the following mechanisms: %s", m)
logger.Debugf("Notifier SMTP server supports authentication with the following mechanisms: %s", m)
mechanisms := strings.Split(m, " ")
// Adaptively select the AUTH mechanism to use based on what the server advertised.
if utils.IsStringInSlice("PLAIN", mechanisms) {
auth = smtp.PlainAuth("", n.username, n.password, n.host)
logging.Logger().Debug("Notifier SMTP client attempting AUTH PLAIN with server")
logger.Debug("Notifier SMTP client attempting AUTH PLAIN with server")
} else if utils.IsStringInSlice("LOGIN", mechanisms) {
auth = newLoginAuth(n.username, n.password, n.host)
logging.Logger().Debug("Notifier SMTP client attempting AUTH LOGIN with server")
logger.Debug("Notifier SMTP client attempting AUTH LOGIN with server")
}
// Throw error since AUTH extension is not supported.
@ -116,7 +118,7 @@ func (n *SMTPNotifier) auth() error {
return err
}
logging.Logger().Debug("Notifier SMTP client authenticated successfully with the server")
logger.Debug("Notifier SMTP client authenticated successfully with the server")
return nil
}
@ -124,13 +126,14 @@ func (n *SMTPNotifier) auth() error {
return errors.New("Notifier SMTP server does not advertise the AUTH extension but config requires AUTH (password specified), either disable AUTH, or use an SMTP host that supports AUTH PLAIN or AUTH LOGIN")
}
logging.Logger().Debug("Notifier SMTP config has no password specified so authentication is being skipped")
logger.Debug("Notifier SMTP config has no password specified so authentication is being skipped")
return nil
}
func (n *SMTPNotifier) compose(recipient, subject, body, htmlBody string) error {
logging.Logger().Debugf("Notifier SMTP client attempting to send email body to %s", recipient)
logger := logging.Logger()
logger.Debugf("Notifier SMTP client attempting to send email body to %s", recipient)
if !n.disableRequireTLS {
_, ok := n.client.TLSConnectionState()
@ -141,7 +144,7 @@ func (n *SMTPNotifier) compose(recipient, subject, body, htmlBody string) error
wc, err := n.client.Data()
if err != nil {
logging.Logger().Debugf("Notifier SMTP client error while obtaining WriteCloser: %s", err)
logger.Debugf("Notifier SMTP client error while obtaining WriteCloser: %s", err)
return err
}
@ -171,13 +174,13 @@ func (n *SMTPNotifier) compose(recipient, subject, body, htmlBody string) error
_, err = fmt.Fprint(wc, msg)
if err != nil {
logging.Logger().Debugf("Notifier SMTP client error while sending email body over WriteCloser: %s", err)
logger.Debugf("Notifier SMTP client error while sending email body over WriteCloser: %s", err)
return err
}
err = wc.Close()
if err != nil {
logging.Logger().Debugf("Notifier SMTP client error while closing the WriteCloser: %s", err)
logger.Debugf("Notifier SMTP client error while closing the WriteCloser: %s", err)
return err
}
@ -186,10 +189,11 @@ func (n *SMTPNotifier) compose(recipient, subject, body, htmlBody string) error
// Dial the SMTP server with the SMTPNotifier config.
func (n *SMTPNotifier) dial() error {
logging.Logger().Debugf("Notifier SMTP client attempting connection to %s", n.address)
logger := logging.Logger()
logger.Debugf("Notifier SMTP client attempting connection to %s", n.address)
if n.port == 465 {
logging.Logger().Warnf("Notifier SMTP client configured to connect to a SMTPS server. It's highly recommended you use a non SMTPS port and STARTTLS instead of SMTPS, as the protocol is long deprecated.")
logger.Warnf("Notifier SMTP client configured to connect to a SMTPS server. It's highly recommended you use a non SMTPS port and STARTTLS instead of SMTPS, as the protocol is long deprecated.")
conn, err := tls.Dial("tcp", n.address, n.tlsConfig)
if err != nil {
@ -211,16 +215,18 @@ func (n *SMTPNotifier) dial() error {
n.client = client
}
logging.Logger().Debug("Notifier SMTP client connected successfully")
logger.Debug("Notifier SMTP client connected successfully")
return nil
}
// Closes the connection properly.
func (n *SMTPNotifier) cleanup() {
logger := logging.Logger()
err := n.client.Quit()
if err != nil {
logging.Logger().Warnf("Notifier SMTP client encountered error during cleanup: %s", err)
logger.Warnf("Notifier SMTP client encountered error during cleanup: %s", err)
}
}
@ -261,6 +267,7 @@ func (n *SMTPNotifier) StartupCheck() (bool, error) {
// Send is used to send an email to a recipient.
func (n *SMTPNotifier) Send(recipient, title, body, htmlBody string) error {
logger := logging.Logger()
subject := strings.ReplaceAll(n.subject, "{title}", title)
if err := n.dial(); err != nil {
@ -285,12 +292,12 @@ func (n *SMTPNotifier) Send(recipient, title, body, htmlBody string) error {
// Set the sender and recipient first.
if err := n.client.Mail(n.sender); err != nil {
logging.Logger().Debugf("Notifier SMTP failed while sending MAIL FROM (using sender) with error: %s", err)
logger.Debugf("Notifier SMTP failed while sending MAIL FROM (using sender) with error: %s", err)
return err
}
if err := n.client.Rcpt(recipient); err != nil {
logging.Logger().Debugf("Notifier SMTP failed while sending RCPT TO (using recipient) with error: %s", err)
logger.Debugf("Notifier SMTP failed while sending RCPT TO (using recipient) with error: %s", err)
return err
}
@ -299,7 +306,7 @@ func (n *SMTPNotifier) Send(recipient, title, body, htmlBody string) error {
return err
}
logging.Logger().Debug("Notifier SMTP client successfully sent email")
logger.Debug("Notifier SMTP client successfully sent email")
return nil
}

View File

@ -10,17 +10,19 @@ import (
// Replacement for the default error handler in fasthttp.
func autheliaErrorHandler(ctx *fasthttp.RequestCtx, err error) {
logger := logging.Logger()
if _, ok := err.(*fasthttp.ErrSmallBuffer); ok {
// Note: Getting X-Forwarded-For or Request URI is impossible for ths error.
logging.Logger().Tracef("Request was too large to handle from client %s. Response Code %d.", ctx.RemoteIP().String(), fasthttp.StatusRequestHeaderFieldsTooLarge)
logger.Tracef("Request was too large to handle from client %s. Response Code %d.", ctx.RemoteIP().String(), fasthttp.StatusRequestHeaderFieldsTooLarge)
ctx.Error("Request header too large", fasthttp.StatusRequestHeaderFieldsTooLarge)
} else if netErr, ok := err.(*net.OpError); ok && netErr.Timeout() {
// TODO: Add X-Forwarded-For Check here.
logging.Logger().Tracef("Request timeout occurred while handling from client %s: %s. Response Code %d.", ctx.RemoteIP().String(), ctx.RequestURI(), fasthttp.StatusRequestTimeout)
logger.Tracef("Request timeout occurred while handling from client %s: %s. Response Code %d.", ctx.RemoteIP().String(), ctx.RequestURI(), fasthttp.StatusRequestTimeout)
ctx.Error("Request timeout", fasthttp.StatusRequestTimeout)
} else {
// TODO: Add X-Forwarded-For Check here.
logging.Logger().Tracef("An unknown error occurred while handling a request from client %s: %s. Response Code %d.", ctx.RemoteIP().String(), ctx.RequestURI(), fasthttp.StatusBadRequest)
logger.Tracef("An unknown error occurred while handling a request from client %s: %s. Response Code %d.", ctx.RemoteIP().String(), ctx.RequestURI(), fasthttp.StatusBadRequest)
ctx.Error("Error when parsing request", fasthttp.StatusBadRequest)
}
}

View File

@ -24,6 +24,7 @@ import (
// StartServer start Authelia server with the given configuration and providers.
func StartServer(configuration schema.Configuration, providers middlewares.Providers) {
logger := logging.Logger()
autheliaMiddleware := middlewares.AutheliaMiddleware(configuration, providers)
embeddedAssets := "/public_html/"
swaggerAssets := embeddedAssets + "api/"
@ -147,30 +148,30 @@ func StartServer(configuration schema.Configuration, providers middlewares.Provi
listener, err := net.Listen("tcp", addrPattern)
if err != nil {
logging.Logger().Fatalf("Error initializing listener: %s", err)
logger.Fatalf("Error initializing listener: %s", err)
}
if configuration.AuthenticationBackend.File != nil && configuration.AuthenticationBackend.File.Password.Algorithm == "argon2id" && runtime.GOOS == "linux" {
f, err := ioutil.ReadFile("/sys/fs/cgroup/memory/memory.limit_in_bytes")
if err != nil {
logging.Logger().Warnf("Error reading hosts memory limit: %s", err)
logger.Warnf("Error reading hosts memory limit: %s", err)
} else {
m, _ := strconv.Atoi(strings.TrimSuffix(string(f), "\n"))
hostMem := float64(m) / 1024 / 1024 / 1024
argonMem := float64(configuration.AuthenticationBackend.File.Password.Memory) / 1024
if hostMem/argonMem <= 2 {
logging.Logger().Warnf("Authelia's password hashing memory parameter is set to: %gGB this is %g%% of the available memory: %gGB", argonMem, argonMem/hostMem*100, hostMem)
logging.Logger().Warn("Please read https://www.authelia.com/docs/configuration/authentication/file.html#memory and tune your deployment")
logger.Warnf("Authelia's password hashing memory parameter is set to: %gGB this is %g%% of the available memory: %gGB", argonMem, argonMem/hostMem*100, hostMem)
logger.Warn("Please read https://www.authelia.com/docs/configuration/authentication/file.html#memory and tune your deployment")
}
}
}
if configuration.TLSCert != "" && configuration.TLSKey != "" {
logging.Logger().Infof("Authelia is listening for TLS connections on %s%s", addrPattern, configuration.Server.Path)
logging.Logger().Fatal(server.ServeTLS(listener, configuration.TLSCert, configuration.TLSKey))
logger.Infof("Authelia is listening for TLS connections on %s%s", addrPattern, configuration.Server.Path)
logger.Fatal(server.ServeTLS(listener, configuration.TLSCert, configuration.TLSKey))
} else {
logging.Logger().Infof("Authelia is listening for non-TLS connections on %s%s", addrPattern, configuration.Server.Path)
logging.Logger().Fatal(server.Serve(listener))
logger.Infof("Authelia is listening for non-TLS connections on %s%s", addrPattern, configuration.Server.Path)
logger.Fatal(server.Serve(listener))
}
}

View File

@ -20,19 +20,21 @@ var alphaNumericRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV
// and generate a nonce to support a restrictive CSP while using material-ui.
//go:generate broccoli -src ../../public_html -o public_html
func ServeTemplatedFile(publicDir, file, base, session, rememberMe, resetPassword string) fasthttp.RequestHandler {
logger := logging.Logger()
f, err := br.Open(publicDir + file)
if err != nil {
logging.Logger().Fatalf("Unable to open %s: %s", file, err)
logger.Fatalf("Unable to open %s: %s", file, err)
}
b, err := ioutil.ReadAll(f)
if err != nil {
logging.Logger().Fatalf("Unable to read %s: %s", file, err)
logger.Fatalf("Unable to read %s: %s", file, err)
}
tmpl, err := template.New("file").Parse(string(b))
if err != nil {
logging.Logger().Fatalf("Unable to parse %s template: %s", file, err)
logger.Fatalf("Unable to parse %s template: %s", file, err)
}
return func(ctx *fasthttp.RequestCtx) {
@ -46,10 +48,10 @@ func ServeTemplatedFile(publicDir, file, base, session, rememberMe, resetPasswor
}
switch {
case os.Getenv("ENVIRONMENT") == dev:
ctx.Response.Header.Add("Content-Security-Policy", fmt.Sprintf("default-src 'self' 'unsafe-eval'; object-src 'none'; style-src 'self' 'nonce-%s'", nonce))
case publicDir == "/public_html/api/":
ctx.Response.Header.Add("Content-Security-Policy", fmt.Sprintf("base-uri 'self' ; default-src 'self' ; img-src 'self' https://validator.swagger.io data: ; object-src 'none' ; script-src 'self' 'unsafe-inline' 'nonce-%s' ; style-src 'self' 'nonce-%s'", nonce, nonce))
case os.Getenv("ENVIRONMENT") == dev:
ctx.Response.Header.Add("Content-Security-Policy", fmt.Sprintf("default-src 'self' 'unsafe-eval'; object-src 'none'; style-src 'self' 'nonce-%s'", nonce))
default:
ctx.Response.Header.Add("Content-Security-Policy", fmt.Sprintf("default-src 'self' ; object-src 'none'; style-src 'self' 'nonce-%s'", nonce))
}
@ -57,7 +59,7 @@ func ServeTemplatedFile(publicDir, file, base, session, rememberMe, resetPasswor
err := tmpl.Execute(ctx.Response.BodyWriter(), struct{ Base, CSPNonce, Session, RememberMe, ResetPassword string }{Base: base, CSPNonce: nonce, Session: session, RememberMe: rememberMe, ResetPassword: resetPassword})
if err != nil {
ctx.Error("An error occurred", 503)
logging.Logger().Errorf("Unable to execute template: %v", err)
logger.Errorf("Unable to execute template: %v", err)
return
}

View File

@ -37,6 +37,12 @@ func (s *CLISuite) SetupTest() {
s.coverageArg = coverageArg
}
func (s *CLISuite) TestShouldPrintVersion() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "version"})
s.Assert().Nil(err)
s.Assert().Contains(output, "Authelia version")
}
func (s *CLISuite) TestShouldValidateConfig() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "validate-config", "/config/configuration.yml"})
s.Assert().Nil(err)