feat(configuration): glauth ldap implementation (#4499)

This adds a GLAuth LDAP implementation which purely adds sane defaults for GLAuth. There are no functional differences just when the implementation option is set to 'glauth' 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.
pull/4612/head
James Elliott 2022-12-21 22:14:22 +11:00 committed by GitHub
parent 5b8b3145ad
commit d3d87ffe30
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 150 additions and 15 deletions

View File

@ -62,10 +62,14 @@ The following implementations exist:
- `lldap`:
- Specific configuration defaults for [lldap]
- No special implementation details
- `glauth`:
- Specific configuration defaults for [GLAuth]
- No special implementation details
[Active Directory]: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/active-directory-domain-services
[FreeIPA]: https://www.freeipa.org/
[lldap]: https://github.com/nitnelave/lldap
[GLAuth]: https://glauth.github.io/
### Filter replacements
@ -115,6 +119,7 @@ Username column.
| activedirectory | sAMAccountName | displayName | mail | cn |
| freeipa | uid | displayName | mail | cn |
| lldap | uid | cn | mail | cn |
| glauth | cn | description | mail | cn |
#### Filter defaults
@ -122,21 +127,23 @@ The filters are probably the most important part to get correct when setting up
the following conditions:
- The account is disabled or locked:
- The Active Directory implementation achieves this via the `(!(userAccountControl:1.2.840.113556.1.4.803:=2))` filter.
- The FreeIPA implementation achieves this via the `(!(nsAccountLock=TRUE))` filter.
- The [Active Directory] implementation achieves this via the `(!(userAccountControl:1.2.840.113556.1.4.803:=2))` filter.
- The [FreeIPA] implementation achieves this via the `(!(nsAccountLock=TRUE))` filter.
- The [GLAuth] implementation achieves this via the `(!(accountStatus=inactive))` filter.
- Their password is expired:
- The Active Directory implementation achieves this via the `(!(pwdLastSet=0))` filter.
- The FreeIPA implementation achieves this via the `(krbPasswordExpiration>={date-time:generalized})` filter.
- The [Active Directory] implementation achieves this via the `(!(pwdLastSet=0))` filter.
- The [FreeIPA] implementation achieves this via the `(krbPasswordExpiration>={date-time:generalized})` filter.
- Their account is expired:
- The Active Directory implementation achieves this via the `(|(!(accountExpires=*))(accountExpires=0)(accountExpires>={date-time:msft-nt-epoch}))` filter.
- The FreeIPA implementation achieves this via the `(|(!(krbPrincipalExpiration=*))(krbPrincipalExpiration>={date-time:generalized}))` filter.
- The [Active Directory] implementation achieves this via the `(|(!(accountExpires=*))(accountExpires=0)(accountExpires>={date-time:msft-nt-epoch}))` filter.
- The [FreeIPA] implementation achieves this via the `(|(!(krbPrincipalExpiration=*))(krbPrincipalExpiration>={date-time:generalized}))` filter.
| Implementation | Users Filter | Groups Filter |
|:---------------:|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:----------------------------------------------------------------------------:|
|:---------------:|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|:----------------------------------------------:|
| 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))(|(!(accountExpires=*))(accountExpires=0)(accountExpires>={date-time:msft-nt-epoch}))) | (&(member={dn})(|(sAMAccountType=268435456)(sAMAccountType=536870912))) |
| activedirectory | (&(|({username_attribute}={input})({mail_attribute}={input}))(sAMAccountType=805306368)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(!(pwdLastSet=0))(|(!(accountExpires=*))(accountExpires=0)(accountExpires>={date-time:msft-nt-epoch}))) | (&(member={dn})(sAMAccountType=268435456)) |
| freeipa | (&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=person)(!(nsAccountLock=TRUE))(krbPasswordExpiration>={date-time:generalized})(|(!(krbPrincipalExpiration=*))(krbPrincipalExpiration>={date-time:generalized}))) | (&(member={dn})(objectClass=groupOfNames)) |
| lldap | (&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=person)) | (&(member={dn})(objectClass=groupOfNames)) |
| glauth | (&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=posixAccount)(!(accountStatus=inactive))) | (&(uniqueMember={dn})(objectClass=posixGroup)) |
##### Microsoft Active Directory sAMAccountType

View File

@ -228,3 +228,17 @@ var DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP = LDAPAuthe
MinimumVersion: TLSVersion{tls.VersionTLS12},
},
}
// DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth represents the default LDAP config for the LDAPImplementationGLAuth Implementation.
var DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth = LDAPAuthenticationBackend{
UsersFilter: "(&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=posixAccount)(!(accountStatus=inactive)))",
UsernameAttribute: ldapAttrCommonName,
MailAttribute: ldapAttrMail,
DisplayNameAttribute: ldapAttrDescription,
GroupsFilter: "(&(uniqueMember={dn})(objectClass=posixGroup))",
GroupNameAttribute: ldapAttrCommonName,
Timeout: time.Second * 5,
TLS: &TLSConfig{
MinimumVersion: TLSVersion{tls.VersionTLS12},
},
}

View File

@ -70,6 +70,9 @@ const (
// LDAPImplementationLLDAP is the string for the lldap LDAP implementation.
LDAPImplementationLLDAP = "lldap"
// LDAPImplementationGLAuth is the string for the GLAuth LDAP implementation.
LDAPImplementationGLAuth = "glauth"
)
// TOTP Algorithm.
@ -110,5 +113,6 @@ const (
ldapAttrMail = "mail"
ldapAttrUserID = "uid"
ldapAttrDisplayName = "displayName"
ldapAttrDescription = "description"
ldapAttrCommonName = "cn"
)

View File

@ -332,6 +332,8 @@ func validateLDAPAuthenticationBackend(config *schema.AuthenticationBackend, val
implementation = &schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA
case schema.LDAPImplementationLLDAP:
implementation = &schema.DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP
case schema.LDAPImplementationGLAuth:
implementation = &schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth
default:
validator.Push(fmt.Errorf(errFmtLDAPAuthBackendImplementation, config.LDAP.Implementation, strings.Join(validLDAPImplementations, "', '")))
}

View File

@ -912,6 +912,12 @@ func (suite *ActiveDirectoryAuthenticationBackendSuite) TestShouldSetActiveDirec
suite.Assert().Equal(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.AdditionalGroupsDN,
suite.config.LDAP.AdditionalGroupsDN)
suite.Assert().Equal(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.AdditionalUsersDN,
suite.config.LDAP.AdditionalUsersDN)
suite.Assert().Equal(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.AdditionalGroupsDN,
suite.config.LDAP.AdditionalGroupsDN)
suite.Assert().Equal(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.UsersFilter,
suite.config.LDAP.UsersFilter)
@ -1153,9 +1159,9 @@ func (suite *LLDAPAuthenticationBackendSuite) TestShouldOnlySetDefaultsIfNotManu
suite.config.LDAP.UsersFilter = "(&({username_attribute}={input})(objectClass=Person)(!(nsAccountLock=TRUE)))"
suite.config.LDAP.UsernameAttribute = "username"
suite.config.LDAP.MailAttribute = "m"
suite.config.LDAP.DisplayNameAttribute = "given"
suite.config.LDAP.GroupsFilter = "(&(member={dn})(objectClass=posixGroup))"
suite.config.LDAP.GroupNameAttribute = "grp"
suite.config.LDAP.DisplayNameAttribute = "fn"
suite.config.LDAP.GroupsFilter = "(&(member={dn})(!(objectClass=posixGroup)))"
suite.config.LDAP.GroupNameAttribute = "grpz"
suite.config.LDAP.AdditionalUsersDN = "OU=no"
suite.config.LDAP.AdditionalGroupsDN = "OU=yes"
@ -1196,3 +1202,105 @@ func (suite *LLDAPAuthenticationBackendSuite) TestShouldOnlySetDefaultsIfNotManu
func TestLLDAPAuthenticationBackend(t *testing.T) {
suite.Run(t, new(LLDAPAuthenticationBackendSuite))
}
type GLAuthAuthenticationBackendSuite struct {
suite.Suite
config schema.AuthenticationBackend
validator *schema.StructValidator
}
func (suite *GLAuthAuthenticationBackendSuite) SetupTest() {
suite.validator = schema.NewStructValidator()
suite.config = schema.AuthenticationBackend{}
suite.config.LDAP = &schema.LDAPAuthenticationBackend{}
suite.config.LDAP.Implementation = schema.LDAPImplementationGLAuth
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.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.TLS
}
func (suite *GLAuthAuthenticationBackendSuite) TestShouldSetDefaults() {
ValidateAuthenticationBackend(&suite.config, suite.validator)
suite.Assert().Len(suite.validator.Warnings(), 0)
suite.Assert().Len(suite.validator.Errors(), 0)
suite.Assert().Equal(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.Timeout,
suite.config.LDAP.Timeout)
suite.Assert().Equal(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.AdditionalUsersDN,
suite.config.LDAP.AdditionalUsersDN)
suite.Assert().Equal(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.AdditionalGroupsDN,
suite.config.LDAP.AdditionalGroupsDN)
suite.Assert().Equal(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.UsersFilter,
suite.config.LDAP.UsersFilter)
suite.Assert().Equal(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.UsernameAttribute,
suite.config.LDAP.UsernameAttribute)
suite.Assert().Equal(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.DisplayNameAttribute,
suite.config.LDAP.DisplayNameAttribute)
suite.Assert().Equal(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.MailAttribute,
suite.config.LDAP.MailAttribute)
suite.Assert().Equal(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.GroupsFilter,
suite.config.LDAP.GroupsFilter)
suite.Assert().Equal(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.GroupNameAttribute,
suite.config.LDAP.GroupNameAttribute)
}
func (suite *GLAuthAuthenticationBackendSuite) TestShouldOnlySetDefaultsIfNotManuallyConfigured() {
suite.config.LDAP.Timeout = time.Second * 2
suite.config.LDAP.UsersFilter = "(&({username_attribute}={input})(objectClass=Person)(!(accountStatus=inactive)))"
suite.config.LDAP.UsernameAttribute = "description"
suite.config.LDAP.MailAttribute = "sender"
suite.config.LDAP.DisplayNameAttribute = "given"
suite.config.LDAP.GroupsFilter = "(&(member={dn})(objectClass=posixGroup))"
suite.config.LDAP.GroupNameAttribute = "grp"
suite.config.LDAP.AdditionalUsersDN = "OU=users,OU=GlAuth"
suite.config.LDAP.AdditionalGroupsDN = "OU=groups,OU=GLAuth"
ValidateAuthenticationBackend(&suite.config, suite.validator)
suite.Assert().NotEqual(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.Timeout,
suite.config.LDAP.Timeout)
suite.Assert().NotEqual(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.AdditionalUsersDN,
suite.config.LDAP.AdditionalUsersDN)
suite.Assert().NotEqual(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.AdditionalGroupsDN,
suite.config.LDAP.AdditionalGroupsDN)
suite.Assert().NotEqual(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.Timeout,
suite.config.LDAP.Timeout)
suite.Assert().NotEqual(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.UsersFilter,
suite.config.LDAP.UsersFilter)
suite.Assert().NotEqual(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.UsernameAttribute,
suite.config.LDAP.UsernameAttribute)
suite.Assert().NotEqual(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.DisplayNameAttribute,
suite.config.LDAP.DisplayNameAttribute)
suite.Assert().NotEqual(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.MailAttribute,
suite.config.LDAP.MailAttribute)
suite.Assert().NotEqual(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.GroupsFilter,
suite.config.LDAP.GroupsFilter)
suite.Assert().NotEqual(
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.GroupNameAttribute,
suite.config.LDAP.GroupNameAttribute)
}
func TestGLAuthAuthenticationBackend(t *testing.T) {
suite.Run(t, new(GLAuthAuthenticationBackendSuite))
}