feat(configuration): freeipa ldap implementation (#4482)
This adds a FreeIPA LDAP implementation which purely adds sane defaults for FreeIPA. There are no functional differences just when the implementation option is set to 'freeipa' sane defaults which should be sufficient for most use cases are set. See the documentation at https://www.authelia.com/r/ldap#defaults for more details. Closes #2177, Closes #2161pull/4483/head^2
parent
c7f4d5999d
commit
d0d80b4f66
|
@ -284,8 +284,9 @@ authentication_backend:
|
|||
# ldap:
|
||||
## The LDAP implementation, this affects elements like the attribute utilised for resetting a password.
|
||||
## Acceptable options are as follows:
|
||||
## - 'activedirectory' - For Microsoft Active Directory.
|
||||
## - 'custom' - For custom specifications of attributes and filters.
|
||||
## - 'activedirectory' - for Microsoft Active Directory.
|
||||
## - 'freeipa' - for FreeIPA.
|
||||
## - 'custom' - for custom specifications of attributes and filters.
|
||||
## This currently defaults to 'custom' to maintain existing behaviour.
|
||||
##
|
||||
## Depending on the option here certain other values in this section have a default value, notably all of the
|
||||
|
|
|
@ -10,6 +10,8 @@ menu:
|
|||
parent: "guides"
|
||||
weight: 220
|
||||
toc: true
|
||||
aliases:
|
||||
- /r/ldap
|
||||
---
|
||||
|
||||
## Binding
|
||||
|
@ -46,10 +48,10 @@ Authelia primarily supports this method.
|
|||
|
||||
## Implementation Guide
|
||||
|
||||
There are currently two implementations, `custom` and `activedirectory`. The `activedirectory` implementation
|
||||
must be used if you wish to allow users to change or reset their password as Active Directory
|
||||
uses a custom attribute for this, and an input format other implementations do not use. The long term
|
||||
intention of this is to have logical defaults for various RFC implementations of LDAP.
|
||||
There are currently two implementations, `custom`, `activedirectory`, and `freeipa`. The `activedirectory`
|
||||
implementation must be used if you wish to allow users to change or reset their password as Active Directory
|
||||
uses a custom attribute and mechanism for this. The long term intention of this is to have logical defaults for various
|
||||
RFC implementations of LDAP.
|
||||
|
||||
### Filter replacements
|
||||
|
||||
|
@ -86,6 +88,7 @@ Username column.
|
|||
|:---------------:|:--------------:|:------------:|:----:|:----------:|
|
||||
| custom | N/A | displayName | mail | cn |
|
||||
| activedirectory | sAMAccountName | displayName | mail | cn |
|
||||
| freeipa | uid | displayName | mail | cn |
|
||||
|
||||
#### Filter defaults
|
||||
|
||||
|
@ -98,6 +101,7 @@ value is not 0 which means the password requires changing at the next login.
|
|||
|:---------------:|:---------------------------------------------------------------------------------------------------------------------------------------------------------------:|:----------------------------------------------------------------------------:|
|
||||
| custom | N/A | N/A |
|
||||
| activedirectory | (&(|({username_attribute}={input})({mail_attribute}={input}))(sAMAccountType=805306368)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(!(pwdLastSet=0))) | (&(member={dn})(|(sAMAccountType=268435456)(sAMAccountType=536870912))) |
|
||||
| freeipa | (&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=person)(!(nsAccountLock=TRUE))) | (&(member={dn})(objectClass=groupOfNames)) |
|
||||
|
||||
##### Microsoft Active Directory sAMAccountType
|
||||
|
||||
|
|
|
@ -284,8 +284,9 @@ authentication_backend:
|
|||
# ldap:
|
||||
## The LDAP implementation, this affects elements like the attribute utilised for resetting a password.
|
||||
## Acceptable options are as follows:
|
||||
## - 'activedirectory' - For Microsoft Active Directory.
|
||||
## - 'custom' - For custom specifications of attributes and filters.
|
||||
## - 'activedirectory' - for Microsoft Active Directory.
|
||||
## - 'freeipa' - for FreeIPA.
|
||||
## - 'custom' - for custom specifications of attributes and filters.
|
||||
## This currently defaults to 'custom' to maintain existing behaviour.
|
||||
##
|
||||
## Depending on the option here certain other values in this section have a default value, notably all of the
|
||||
|
|
|
@ -175,24 +175,38 @@ var DefaultCIPasswordConfig = Password{
|
|||
|
||||
// DefaultLDAPAuthenticationBackendConfigurationImplementationCustom represents the default LDAP config.
|
||||
var DefaultLDAPAuthenticationBackendConfigurationImplementationCustom = LDAPAuthenticationBackend{
|
||||
UsernameAttribute: "uid",
|
||||
MailAttribute: "mail",
|
||||
DisplayNameAttribute: "displayName",
|
||||
GroupNameAttribute: "cn",
|
||||
UsernameAttribute: ldapAttrUserID,
|
||||
MailAttribute: ldapAttrMail,
|
||||
DisplayNameAttribute: ldapAttrDisplayName,
|
||||
GroupNameAttribute: ldapAttrCommonName,
|
||||
Timeout: time.Second * 5,
|
||||
TLS: &TLSConfig{
|
||||
MinimumVersion: TLSVersion{tls.VersionTLS12},
|
||||
},
|
||||
}
|
||||
|
||||
// DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory represents the default LDAP config for the MSAD Implementation.
|
||||
// DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory represents the default LDAP config for the LDAPImplementationActiveDirectory Implementation.
|
||||
var DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory = LDAPAuthenticationBackend{
|
||||
UsersFilter: "(&(|({username_attribute}={input})({mail_attribute}={input}))(sAMAccountType=805306368)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(!(pwdLastSet=0)))",
|
||||
UsernameAttribute: "sAMAccountName",
|
||||
MailAttribute: "mail",
|
||||
DisplayNameAttribute: "displayName",
|
||||
MailAttribute: ldapAttrMail,
|
||||
DisplayNameAttribute: ldapAttrDisplayName,
|
||||
GroupsFilter: "(&(member={dn})(|(sAMAccountType=268435456)(sAMAccountType=536870912)))",
|
||||
GroupNameAttribute: "cn",
|
||||
GroupNameAttribute: ldapAttrCommonName,
|
||||
Timeout: time.Second * 5,
|
||||
TLS: &TLSConfig{
|
||||
MinimumVersion: TLSVersion{tls.VersionTLS12},
|
||||
},
|
||||
}
|
||||
|
||||
// DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA represents the default LDAP config for the LDAPImplementationFreeIPA Implementation.
|
||||
var DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA = LDAPAuthenticationBackend{
|
||||
UsersFilter: "(&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=person)(!(nsAccountLock=TRUE)))",
|
||||
UsernameAttribute: ldapAttrUserID,
|
||||
MailAttribute: ldapAttrMail,
|
||||
DisplayNameAttribute: ldapAttrDisplayName,
|
||||
GroupsFilter: "(&(member={dn})(objectClass=groupOfNames))",
|
||||
GroupNameAttribute: ldapAttrCommonName,
|
||||
Timeout: time.Second * 5,
|
||||
TLS: &TLSConfig{
|
||||
MinimumVersion: TLSVersion{tls.VersionTLS12},
|
||||
|
|
|
@ -64,6 +64,9 @@ const (
|
|||
|
||||
// LDAPImplementationActiveDirectory is the string for the Active Directory LDAP implementation.
|
||||
LDAPImplementationActiveDirectory = "activedirectory"
|
||||
|
||||
// LDAPImplementationFreeIPA is the string for the FreeIPA LDAP implementation.
|
||||
LDAPImplementationFreeIPA = "freeipa"
|
||||
)
|
||||
|
||||
// TOTP Algorithm.
|
||||
|
@ -99,3 +102,10 @@ const (
|
|||
blockCERTIFICATE = "CERTIFICATE"
|
||||
blockRSAPRIVATEKEY = "RSA PRIVATE KEY"
|
||||
)
|
||||
|
||||
const (
|
||||
ldapAttrMail = "mail"
|
||||
ldapAttrUserID = "uid"
|
||||
ldapAttrDisplayName = "displayName"
|
||||
ldapAttrCommonName = "cn"
|
||||
)
|
||||
|
|
|
@ -328,8 +328,10 @@ func validateLDAPAuthenticationBackend(config *schema.AuthenticationBackend, val
|
|||
implementation = &schema.DefaultLDAPAuthenticationBackendConfigurationImplementationCustom
|
||||
case schema.LDAPImplementationActiveDirectory:
|
||||
implementation = &schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory
|
||||
case schema.LDAPImplementationFreeIPA:
|
||||
implementation = &schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA
|
||||
default:
|
||||
validator.Push(fmt.Errorf(errFmtLDAPAuthBackendImplementation, config.LDAP.Implementation, strings.Join([]string{schema.LDAPImplementationCustom, schema.LDAPImplementationActiveDirectory}, "', '")))
|
||||
validator.Push(fmt.Errorf(errFmtLDAPAuthBackendImplementation, config.LDAP.Implementation, strings.Join(validLDAPImplementations, "', '")))
|
||||
}
|
||||
|
||||
configDefaultTLS := &schema.TLSConfig{}
|
||||
|
|
|
@ -609,7 +609,7 @@ func (suite *LDAPAuthenticationBackendSuite) TestShouldRaiseErrorWhenImplementat
|
|||
suite.Assert().Len(suite.validator.Warnings(), 0)
|
||||
suite.Require().Len(suite.validator.Errors(), 1)
|
||||
|
||||
suite.Assert().EqualError(suite.validator.Errors()[0], "authentication_backend: ldap: option 'implementation' is configured as 'masd' but must be one of the following values: 'custom', 'activedirectory'")
|
||||
suite.Assert().EqualError(suite.validator.Errors()[0], "authentication_backend: ldap: option 'implementation' is configured as 'masd' but must be one of the following values: 'custom', 'activedirectory', 'freeipa'")
|
||||
}
|
||||
|
||||
func (suite *LDAPAuthenticationBackendSuite) TestShouldRaiseErrorWhenURLNotProvided() {
|
||||
|
@ -875,7 +875,7 @@ func (suite *LDAPAuthenticationBackendSuite) TestShouldNotAllowTLSVerMinGreaterT
|
|||
suite.Assert().EqualError(suite.validator.Errors()[0], "authentication_backend: ldap: tls: option combination of 'minimum_version' and 'maximum_version' is invalid: minimum version TLS1.3 is greater than the maximum version TLS1.2")
|
||||
}
|
||||
|
||||
func TestLdapAuthenticationBackend(t *testing.T) {
|
||||
func TestLDAPAuthenticationBackend(t *testing.T) {
|
||||
suite.Run(t, new(LDAPAuthenticationBackendSuite))
|
||||
}
|
||||
|
||||
|
@ -894,7 +894,7 @@ func (suite *ActiveDirectoryAuthenticationBackendSuite) SetupTest() {
|
|||
suite.config.LDAP.User = testLDAPUser
|
||||
suite.config.LDAP.Password = testLDAPPassword
|
||||
suite.config.LDAP.BaseDN = testLDAPBaseDN
|
||||
suite.config.LDAP.TLS = schema.DefaultLDAPAuthenticationBackendConfigurationImplementationCustom.TLS
|
||||
suite.config.LDAP.TLS = schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.TLS
|
||||
}
|
||||
|
||||
func (suite *ActiveDirectoryAuthenticationBackendSuite) TestShouldSetActiveDirectoryDefaults() {
|
||||
|
@ -904,7 +904,7 @@ func (suite *ActiveDirectoryAuthenticationBackendSuite) TestShouldSetActiveDirec
|
|||
suite.Assert().Len(suite.validator.Errors(), 0)
|
||||
|
||||
suite.Assert().Equal(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationCustom.Timeout,
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.Timeout,
|
||||
suite.config.LDAP.Timeout)
|
||||
suite.Assert().Equal(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.UsersFilter,
|
||||
|
@ -938,7 +938,7 @@ func (suite *ActiveDirectoryAuthenticationBackendSuite) TestShouldOnlySetDefault
|
|||
ValidateAuthenticationBackend(&suite.config, suite.validator)
|
||||
|
||||
suite.Assert().NotEqual(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationCustom.Timeout,
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.Timeout,
|
||||
suite.config.LDAP.Timeout)
|
||||
suite.Assert().NotEqual(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.UsersFilter,
|
||||
|
@ -981,3 +981,88 @@ func (suite *ActiveDirectoryAuthenticationBackendSuite) TestShouldRaiseErrorOnIn
|
|||
func TestActiveDirectoryAuthenticationBackend(t *testing.T) {
|
||||
suite.Run(t, new(ActiveDirectoryAuthenticationBackendSuite))
|
||||
}
|
||||
|
||||
type FreeIPAAuthenticationBackendSuite struct {
|
||||
suite.Suite
|
||||
config schema.AuthenticationBackend
|
||||
validator *schema.StructValidator
|
||||
}
|
||||
|
||||
func (suite *FreeIPAAuthenticationBackendSuite) SetupTest() {
|
||||
suite.validator = schema.NewStructValidator()
|
||||
suite.config = schema.AuthenticationBackend{}
|
||||
suite.config.LDAP = &schema.LDAPAuthenticationBackend{}
|
||||
suite.config.LDAP.Implementation = schema.LDAPImplementationFreeIPA
|
||||
suite.config.LDAP.URL = testLDAPURL
|
||||
suite.config.LDAP.User = testLDAPUser
|
||||
suite.config.LDAP.Password = testLDAPPassword
|
||||
suite.config.LDAP.BaseDN = testLDAPBaseDN
|
||||
suite.config.LDAP.TLS = schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.TLS
|
||||
}
|
||||
|
||||
func (suite *FreeIPAAuthenticationBackendSuite) TestShouldSetDefaults() {
|
||||
ValidateAuthenticationBackend(&suite.config, suite.validator)
|
||||
|
||||
suite.Assert().Len(suite.validator.Warnings(), 0)
|
||||
suite.Assert().Len(suite.validator.Errors(), 0)
|
||||
|
||||
suite.Assert().Equal(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.Timeout,
|
||||
suite.config.LDAP.Timeout)
|
||||
suite.Assert().Equal(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.UsersFilter,
|
||||
suite.config.LDAP.UsersFilter)
|
||||
suite.Assert().Equal(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.UsernameAttribute,
|
||||
suite.config.LDAP.UsernameAttribute)
|
||||
suite.Assert().Equal(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.DisplayNameAttribute,
|
||||
suite.config.LDAP.DisplayNameAttribute)
|
||||
suite.Assert().Equal(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.MailAttribute,
|
||||
suite.config.LDAP.MailAttribute)
|
||||
suite.Assert().Equal(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.GroupsFilter,
|
||||
suite.config.LDAP.GroupsFilter)
|
||||
suite.Assert().Equal(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.GroupNameAttribute,
|
||||
suite.config.LDAP.GroupNameAttribute)
|
||||
}
|
||||
|
||||
func (suite *FreeIPAAuthenticationBackendSuite) TestShouldOnlySetDefaultsIfNotManuallyConfigured() {
|
||||
suite.config.LDAP.Timeout = time.Second * 2
|
||||
suite.config.LDAP.UsersFilter = "(&({username_attribute}={input})(objectClass=person)(!(nsAccountLock=TRUE)))"
|
||||
suite.config.LDAP.UsernameAttribute = "dn"
|
||||
suite.config.LDAP.MailAttribute = "email"
|
||||
suite.config.LDAP.DisplayNameAttribute = "gecos"
|
||||
suite.config.LDAP.GroupsFilter = "(&(member={dn})(objectClass=posixgroup))"
|
||||
suite.config.LDAP.GroupNameAttribute = "groupName"
|
||||
|
||||
ValidateAuthenticationBackend(&suite.config, suite.validator)
|
||||
|
||||
suite.Assert().NotEqual(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.Timeout,
|
||||
suite.config.LDAP.Timeout)
|
||||
suite.Assert().NotEqual(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.UsersFilter,
|
||||
suite.config.LDAP.UsersFilter)
|
||||
suite.Assert().NotEqual(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.UsernameAttribute,
|
||||
suite.config.LDAP.UsernameAttribute)
|
||||
suite.Assert().NotEqual(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.DisplayNameAttribute,
|
||||
suite.config.LDAP.DisplayNameAttribute)
|
||||
suite.Assert().NotEqual(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.MailAttribute,
|
||||
suite.config.LDAP.MailAttribute)
|
||||
suite.Assert().NotEqual(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.GroupsFilter,
|
||||
suite.config.LDAP.GroupsFilter)
|
||||
suite.Assert().NotEqual(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.GroupNameAttribute,
|
||||
suite.config.LDAP.GroupNameAttribute)
|
||||
}
|
||||
|
||||
func TestFreeIPAAuthenticationBackend(t *testing.T) {
|
||||
suite.Run(t, new(FreeIPAAuthenticationBackendSuite))
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@ import (
|
|||
|
||||
"github.com/go-webauthn/webauthn/protocol"
|
||||
|
||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||
|
||||
"github.com/authelia/authelia/v4/internal/oidc"
|
||||
)
|
||||
|
||||
|
@ -311,32 +313,6 @@ const (
|
|||
errFilePOptions = "config key incorrect: authentication_backend.file.password_options should be authentication_backend.file.password"
|
||||
)
|
||||
|
||||
var validArgon2Variants = []string{"argon2id", "id", "argon2i", "i", "argon2d", "d"}
|
||||
|
||||
var validSHA2CryptVariants = []string{digestSHA256, digestSHA512}
|
||||
|
||||
var validPBKDF2Variants = []string{digestSHA1, digestSHA224, digestSHA256, digestSHA384, digestSHA512}
|
||||
|
||||
var validBCryptVariants = []string{"standard", digestSHA256}
|
||||
|
||||
var validHashAlgorithms = []string{hashSHA2Crypt, hashPBKDF2, hashSCrypt, hashBCrypt, hashArgon2}
|
||||
|
||||
var validStoragePostgreSQLSSLModes = []string{"disable", "require", "verify-ca", "verify-full"}
|
||||
|
||||
var validThemeNames = []string{"light", "dark", "grey", "auto"}
|
||||
|
||||
var validSessionSameSiteValues = []string{"none", "lax", "strict"}
|
||||
|
||||
var validLoLevels = []string{"trace", "debug", "info", "warn", "error"}
|
||||
|
||||
var validWebauthnConveyancePreferences = []string{string(protocol.PreferNoAttestation), string(protocol.PreferIndirectAttestation), string(protocol.PreferDirectAttestation)}
|
||||
|
||||
var validWebauthnUserVerificationRequirement = []string{string(protocol.VerificationDiscouraged), string(protocol.VerificationPreferred), string(protocol.VerificationRequired)}
|
||||
|
||||
var validRFC7231HTTPMethodVerbs = []string{"GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "TRACE", "CONNECT", "OPTIONS"}
|
||||
|
||||
var validRFC4918HTTPMethodVerbs = []string{"COPY", "LOCK", "MKCOL", "MOVE", "PROPFIND", "PROPPATCH", "UNLOCK"}
|
||||
|
||||
const (
|
||||
operatorPresent = "present"
|
||||
operatorAbsent = "absent"
|
||||
|
@ -346,6 +322,29 @@ const (
|
|||
operatorNotPattern = "not pattern"
|
||||
)
|
||||
|
||||
var (
|
||||
validLDAPImplementations = []string{schema.LDAPImplementationCustom, schema.LDAPImplementationActiveDirectory, schema.LDAPImplementationFreeIPA}
|
||||
)
|
||||
|
||||
var (
|
||||
validArgon2Variants = []string{"argon2id", "id", "argon2i", "i", "argon2d", "d"}
|
||||
validSHA2CryptVariants = []string{digestSHA256, digestSHA512}
|
||||
validPBKDF2Variants = []string{digestSHA1, digestSHA224, digestSHA256, digestSHA384, digestSHA512}
|
||||
validBCryptVariants = []string{"standard", digestSHA256}
|
||||
validHashAlgorithms = []string{hashSHA2Crypt, hashPBKDF2, hashSCrypt, hashBCrypt, hashArgon2}
|
||||
)
|
||||
|
||||
var (
|
||||
validStoragePostgreSQLSSLModes = []string{"disable", "require", "verify-ca", "verify-full"}
|
||||
validThemeNames = []string{"light", "dark", "grey", "auto"}
|
||||
validSessionSameSiteValues = []string{"none", "lax", "strict"}
|
||||
validLogLevels = []string{"trace", "debug", "info", "warn", "error"}
|
||||
validWebauthnConveyancePreferences = []string{string(protocol.PreferNoAttestation), string(protocol.PreferIndirectAttestation), string(protocol.PreferDirectAttestation)}
|
||||
validWebauthnUserVerificationRequirement = []string{string(protocol.VerificationDiscouraged), string(protocol.VerificationPreferred), string(protocol.VerificationRequired)}
|
||||
validRFC7231HTTPMethodVerbs = []string{"GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "TRACE", "CONNECT", "OPTIONS"}
|
||||
validRFC4918HTTPMethodVerbs = []string{"COPY", "LOCK", "MKCOL", "MOVE", "PROPFIND", "PROPPATCH", "UNLOCK"}
|
||||
)
|
||||
|
||||
var (
|
||||
validACLHTTPMethodVerbs = append(validRFC7231HTTPMethodVerbs, validRFC4918HTTPMethodVerbs...)
|
||||
validACLRulePolicies = []string{policyBypass, policyOneFactor, policyTwoFactor, policyDeny}
|
||||
|
|
|
@ -18,7 +18,7 @@ func ValidateLog(config *schema.Configuration, validator *schema.StructValidator
|
|||
config.Log.Format = schema.DefaultLoggingConfiguration.Format
|
||||
}
|
||||
|
||||
if !utils.IsStringInSlice(config.Log.Level, validLoLevels) {
|
||||
validator.Push(fmt.Errorf(errFmtLoggingLevelInvalid, strings.Join(validLoLevels, "', '"), config.Log.Level))
|
||||
if !utils.IsStringInSlice(config.Log.Level, validLogLevels) {
|
||||
validator.Push(fmt.Errorf(errFmtLoggingLevelInvalid, strings.Join(validLogLevels, "', '"), config.Log.Level))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue