diff --git a/docs/content/en/reference/guides/ldap.md b/docs/content/en/reference/guides/ldap.md index d6ccec9b8..7c9d994db 100644 --- a/docs/content/en/reference/guides/ldap.md +++ b/docs/content/en/reference/guides/ldap.md @@ -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))) | -| 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)) | +| 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)) | +| 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 diff --git a/internal/configuration/schema/authentication.go b/internal/configuration/schema/authentication.go index 98e514f4a..b99e209ba 100644 --- a/internal/configuration/schema/authentication.go +++ b/internal/configuration/schema/authentication.go @@ -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}, + }, +} diff --git a/internal/configuration/schema/const.go b/internal/configuration/schema/const.go index 1578327cc..726f23e01 100644 --- a/internal/configuration/schema/const.go +++ b/internal/configuration/schema/const.go @@ -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" ) diff --git a/internal/configuration/validator/authentication.go b/internal/configuration/validator/authentication.go index 0106c4e37..f05d264c2 100644 --- a/internal/configuration/validator/authentication.go +++ b/internal/configuration/validator/authentication.go @@ -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, "', '"))) } diff --git a/internal/configuration/validator/authentication_test.go b/internal/configuration/validator/authentication_test.go index e2305c56a..4db6efba5 100644 --- a/internal/configuration/validator/authentication_test.go +++ b/internal/configuration/validator/authentication_test.go @@ -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)) +}