feat(configuration): rfc2307bis implementation (#4900)
This adds configuration defaults for RFC2307bis LDAP implementations such as OpenLDAP with the RFC2307bis LDIF which should service most user needs.pull/4901/head
parent
ba89200c19
commit
2e6d17ba8a
|
@ -56,6 +56,9 @@ The following implementations exist:
|
|||
- Specific configuration defaults for [Active Directory]
|
||||
- Special implementation details:
|
||||
- Includes a special encoding format required for changing passwords with [Active Directory]
|
||||
- `rfc2307bis`:
|
||||
- Specific configuration defaults for [RFC2307bis]
|
||||
- No special implementation details
|
||||
- `freeipa`:
|
||||
- Specific configuration defaults for [FreeIPA]
|
||||
- No special implementation details
|
||||
|
@ -70,11 +73,17 @@ The following implementations exist:
|
|||
[FreeIPA]: https://www.freeipa.org/
|
||||
[lldap]: https://github.com/nitnelave/lldap
|
||||
[GLAuth]: https://glauth.github.io/
|
||||
[RFC2307bis]: https://datatracker.ietf.org/doc/html/draft-howard-rfc2307bis-02
|
||||
|
||||
### Filter replacements
|
||||
|
||||
Various replacements occur in the user and groups filter. The replacements either occur at startup or upon an LDAP
|
||||
search.
|
||||
search which is indicated by the phase column.
|
||||
|
||||
The phases exist to optimize performance. The replacements in the startup phase are replaced once before the connection
|
||||
is ever established. In addition to this, during the startup phase we purposefully check the filters for which search
|
||||
phase replacements exist so we only have to check if the replacement is necessary once, and we don't needlessly perform
|
||||
every possible replacement on every search regardless of if it's needed or not.
|
||||
|
||||
#### Users filter replacements
|
||||
|
||||
|
@ -117,6 +126,7 @@ Username column.
|
|||
|:---------------:|:--------------:|:------------:|:----:|:----------:|
|
||||
| custom | N/A | displayName | mail | cn |
|
||||
| activedirectory | sAMAccountName | displayName | mail | cn |
|
||||
| rfc2307bis | uid | displayName | mail | cn |
|
||||
| freeipa | uid | displayName | mail | cn |
|
||||
| lldap | uid | cn | mail | cn |
|
||||
| glauth | cn | description | mail | cn |
|
||||
|
@ -130,17 +140,29 @@ the following conditions:
|
|||
- 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.
|
||||
- The following implementations have no suitable attribute for this as far as we're aware:
|
||||
- [RFC2307bis]
|
||||
- [lldap]
|
||||
- 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 following implementations have no suitable attribute for this as far as we're aware:
|
||||
- [RFC2307bis]
|
||||
- [GLAuth]
|
||||
- [lldap]
|
||||
- Their account is expired:
|
||||
- The [Active Directory] implementation achieves this via the `(|(!(accountExpires=*))(accountExpires=0)(accountExpires>={date-time:microsoft-nt}))` filter.
|
||||
- The [FreeIPA] implementation achieves this via the `(|(!(krbPrincipalExpiration=*))(krbPrincipalExpiration>={date-time:generalized}))` filter.
|
||||
- The following implementations have no suitable attribute for this as far as we're aware:
|
||||
- [RFC2307bis]
|
||||
- [GLAuth]
|
||||
- [lldap]
|
||||
|
||||
| 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:microsoft-nt}))) | (&(member={dn})(|(sAMAccountType=268435456)(sAMAccountType=536870912))) |
|
||||
| rfc2307bis | (&(|({username_attribute}={input})({mail_attribute}={input}))(|(objectClass=inetOrgPerson)(objectClass=organizationalPerson))) | (&(|(member={dn})(uniqueMember={dn}))(|(objectClass=groupOfNames)(objectClass=groupOfUniqueNames)(objectClass=groupOfMembers))) |
|
||||
| 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)) |
|
||||
|
|
|
@ -199,6 +199,20 @@ var DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory =
|
|||
},
|
||||
}
|
||||
|
||||
// DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis represents the default LDAP config for the LDAPImplementationRFC2307bis Implementation.
|
||||
var DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis = LDAPAuthenticationBackend{
|
||||
UsersFilter: "(&(|({username_attribute}={input})({mail_attribute}={input}))(|(objectClass=inetOrgPerson)(objectClass=organizationalPerson)))",
|
||||
UsernameAttribute: ldapAttrUserID,
|
||||
MailAttribute: ldapAttrMail,
|
||||
DisplayNameAttribute: ldapAttrDisplayName,
|
||||
GroupsFilter: "(&(|(member={dn})(uniqueMember={dn}))(|(objectClass=groupOfNames)(objectClass=groupOfUniqueNames)(objectClass=groupOfMembers)))",
|
||||
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))(krbPasswordExpiration>={date-time:generalized})(|(!(krbPrincipalExpiration=*))(krbPrincipalExpiration>={date-time:generalized})))",
|
||||
|
|
|
@ -65,6 +65,9 @@ const (
|
|||
// LDAPImplementationActiveDirectory is the string for the Active Directory LDAP implementation.
|
||||
LDAPImplementationActiveDirectory = "activedirectory"
|
||||
|
||||
// LDAPImplementationRFC2307bis is the string for the RFC2307bis LDAP implementation.
|
||||
LDAPImplementationRFC2307bis = "rfc2307bis"
|
||||
|
||||
// LDAPImplementationFreeIPA is the string for the FreeIPA LDAP implementation.
|
||||
LDAPImplementationFreeIPA = "freeipa"
|
||||
|
||||
|
|
|
@ -321,49 +321,19 @@ func validateLDAPAuthenticationBackend(config *schema.AuthenticationBackend, val
|
|||
config.LDAP.Implementation = schema.LDAPImplementationCustom
|
||||
}
|
||||
|
||||
var implementation *schema.LDAPAuthenticationBackend
|
||||
|
||||
switch config.LDAP.Implementation {
|
||||
case schema.LDAPImplementationCustom:
|
||||
implementation = &schema.DefaultLDAPAuthenticationBackendConfigurationImplementationCustom
|
||||
case schema.LDAPImplementationActiveDirectory:
|
||||
implementation = &schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory
|
||||
case schema.LDAPImplementationFreeIPA:
|
||||
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, "', '")))
|
||||
}
|
||||
|
||||
configDefaultTLS := &schema.TLSConfig{}
|
||||
|
||||
if implementation != nil {
|
||||
if config.LDAP.Timeout == 0 {
|
||||
config.LDAP.Timeout = implementation.Timeout
|
||||
}
|
||||
|
||||
configDefaultTLS = &schema.TLSConfig{
|
||||
MinimumVersion: implementation.TLS.MinimumVersion,
|
||||
MaximumVersion: implementation.TLS.MaximumVersion,
|
||||
}
|
||||
|
||||
setDefaultImplementationLDAPAuthenticationBackendProfileAttributes(config.LDAP, implementation)
|
||||
}
|
||||
defaultTLS := validateLDAPAuthenticationBackendImplementation(config, validator)
|
||||
|
||||
if config.LDAP.URL == "" {
|
||||
validator.Push(fmt.Errorf(errFmtLDAPAuthBackendMissingOption, "url"))
|
||||
} else {
|
||||
configDefaultTLS.ServerName = validateLDAPAuthenticationBackendURL(config.LDAP, validator)
|
||||
defaultTLS.ServerName = validateLDAPAuthenticationBackendURL(config.LDAP, validator)
|
||||
}
|
||||
|
||||
if config.LDAP.TLS == nil {
|
||||
config.LDAP.TLS = &schema.TLSConfig{}
|
||||
}
|
||||
|
||||
if err := ValidateTLSConfig(config.LDAP.TLS, configDefaultTLS); err != nil {
|
||||
if err := ValidateTLSConfig(config.LDAP.TLS, defaultTLS); err != nil {
|
||||
validator.Push(fmt.Errorf(errFmtLDAPAuthBackendTLSConfigInvalid, err))
|
||||
}
|
||||
|
||||
|
@ -382,6 +352,44 @@ func validateLDAPAuthenticationBackend(config *schema.AuthenticationBackend, val
|
|||
validateLDAPRequiredParameters(config, validator)
|
||||
}
|
||||
|
||||
func validateLDAPAuthenticationBackendImplementation(config *schema.AuthenticationBackend, validator *schema.StructValidator) *schema.TLSConfig {
|
||||
var implementation *schema.LDAPAuthenticationBackend
|
||||
|
||||
switch config.LDAP.Implementation {
|
||||
case schema.LDAPImplementationCustom:
|
||||
implementation = &schema.DefaultLDAPAuthenticationBackendConfigurationImplementationCustom
|
||||
case schema.LDAPImplementationActiveDirectory:
|
||||
implementation = &schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory
|
||||
case schema.LDAPImplementationRFC2307bis:
|
||||
implementation = &schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis
|
||||
case schema.LDAPImplementationFreeIPA:
|
||||
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, "', '")))
|
||||
}
|
||||
|
||||
tlsconfig := &schema.TLSConfig{}
|
||||
|
||||
if implementation != nil {
|
||||
if config.LDAP.Timeout == 0 {
|
||||
config.LDAP.Timeout = implementation.Timeout
|
||||
}
|
||||
|
||||
tlsconfig = &schema.TLSConfig{
|
||||
MinimumVersion: implementation.TLS.MinimumVersion,
|
||||
MaximumVersion: implementation.TLS.MaximumVersion,
|
||||
}
|
||||
|
||||
setDefaultImplementationLDAPAuthenticationBackendProfileAttributes(config.LDAP, implementation)
|
||||
}
|
||||
|
||||
return tlsconfig
|
||||
}
|
||||
|
||||
func ldapImplementationShouldSetStr(config, implementation string) bool {
|
||||
return config == "" && implementation != ""
|
||||
}
|
||||
|
|
|
@ -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', 'freeipa', 'lldap'")
|
||||
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', 'rfc2307bis', 'freeipa', 'lldap', 'glauth'")
|
||||
}
|
||||
|
||||
func (suite *LDAPAuthenticationBackendSuite) TestShouldRaiseErrorWhenURLNotProvided() {
|
||||
|
@ -1002,6 +1002,108 @@ func TestActiveDirectoryAuthenticationBackend(t *testing.T) {
|
|||
suite.Run(t, new(ActiveDirectoryAuthenticationBackendSuite))
|
||||
}
|
||||
|
||||
type RFC2307bisAuthenticationBackendSuite struct {
|
||||
suite.Suite
|
||||
config schema.AuthenticationBackend
|
||||
validator *schema.StructValidator
|
||||
}
|
||||
|
||||
func (suite *RFC2307bisAuthenticationBackendSuite) SetupTest() {
|
||||
suite.validator = schema.NewStructValidator()
|
||||
suite.config = schema.AuthenticationBackend{}
|
||||
suite.config.LDAP = &schema.LDAPAuthenticationBackend{}
|
||||
suite.config.LDAP.Implementation = schema.LDAPImplementationRFC2307bis
|
||||
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.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.TLS
|
||||
}
|
||||
|
||||
func (suite *RFC2307bisAuthenticationBackendSuite) TestShouldSetDefaults() {
|
||||
ValidateAuthenticationBackend(&suite.config, suite.validator)
|
||||
|
||||
suite.Assert().Len(suite.validator.Warnings(), 0)
|
||||
suite.Assert().Len(suite.validator.Errors(), 0)
|
||||
|
||||
suite.Assert().Equal(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.Timeout,
|
||||
suite.config.LDAP.Timeout)
|
||||
suite.Assert().Equal(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.AdditionalUsersDN,
|
||||
suite.config.LDAP.AdditionalUsersDN)
|
||||
suite.Assert().Equal(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.AdditionalGroupsDN,
|
||||
suite.config.LDAP.AdditionalGroupsDN)
|
||||
suite.Assert().Equal(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.UsersFilter,
|
||||
suite.config.LDAP.UsersFilter)
|
||||
suite.Assert().Equal(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.UsernameAttribute,
|
||||
suite.config.LDAP.UsernameAttribute)
|
||||
suite.Assert().Equal(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.DisplayNameAttribute,
|
||||
suite.config.LDAP.DisplayNameAttribute)
|
||||
suite.Assert().Equal(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.MailAttribute,
|
||||
suite.config.LDAP.MailAttribute)
|
||||
suite.Assert().Equal(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.GroupsFilter,
|
||||
suite.config.LDAP.GroupsFilter)
|
||||
suite.Assert().Equal(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.GroupNameAttribute,
|
||||
suite.config.LDAP.GroupNameAttribute)
|
||||
}
|
||||
|
||||
func (suite *RFC2307bisAuthenticationBackendSuite) TestShouldOnlySetDefaultsIfNotManuallyConfigured() {
|
||||
suite.config.LDAP.Timeout = time.Second * 2
|
||||
suite.config.LDAP.UsersFilter = "(&({username_attribute}={input})(objectClass=Person))"
|
||||
suite.config.LDAP.UsernameAttribute = "o"
|
||||
suite.config.LDAP.MailAttribute = "Email"
|
||||
suite.config.LDAP.DisplayNameAttribute = "Given"
|
||||
suite.config.LDAP.GroupsFilter = "(&(member={dn})(objectClass=posixGroup)(objectClass=top))"
|
||||
suite.config.LDAP.GroupNameAttribute = "gid"
|
||||
suite.config.LDAP.AdditionalUsersDN = "OU=users,OU=OpenLDAP"
|
||||
suite.config.LDAP.AdditionalGroupsDN = "OU=groups,OU=OpenLDAP"
|
||||
|
||||
ValidateAuthenticationBackend(&suite.config, suite.validator)
|
||||
|
||||
suite.Assert().NotEqual(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.Timeout,
|
||||
suite.config.LDAP.Timeout)
|
||||
suite.Assert().NotEqual(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.AdditionalUsersDN,
|
||||
suite.config.LDAP.AdditionalUsersDN)
|
||||
suite.Assert().NotEqual(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.AdditionalGroupsDN,
|
||||
suite.config.LDAP.AdditionalGroupsDN)
|
||||
suite.Assert().NotEqual(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.Timeout,
|
||||
suite.config.LDAP.Timeout)
|
||||
suite.Assert().NotEqual(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.UsersFilter,
|
||||
suite.config.LDAP.UsersFilter)
|
||||
suite.Assert().NotEqual(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.UsernameAttribute,
|
||||
suite.config.LDAP.UsernameAttribute)
|
||||
suite.Assert().NotEqual(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.DisplayNameAttribute,
|
||||
suite.config.LDAP.DisplayNameAttribute)
|
||||
suite.Assert().NotEqual(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.MailAttribute,
|
||||
suite.config.LDAP.MailAttribute)
|
||||
suite.Assert().NotEqual(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.GroupsFilter,
|
||||
suite.config.LDAP.GroupsFilter)
|
||||
suite.Assert().NotEqual(
|
||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.GroupNameAttribute,
|
||||
suite.config.LDAP.GroupNameAttribute)
|
||||
}
|
||||
|
||||
func TestRFC2307bisAuthenticationBackend(t *testing.T) {
|
||||
suite.Run(t, new(RFC2307bisAuthenticationBackendSuite))
|
||||
}
|
||||
|
||||
type FreeIPAAuthenticationBackendSuite struct {
|
||||
suite.Suite
|
||||
config schema.AuthenticationBackend
|
||||
|
|
|
@ -339,7 +339,14 @@ const (
|
|||
)
|
||||
|
||||
var (
|
||||
validLDAPImplementations = []string{schema.LDAPImplementationCustom, schema.LDAPImplementationActiveDirectory, schema.LDAPImplementationFreeIPA, schema.LDAPImplementationLLDAP}
|
||||
validLDAPImplementations = []string{
|
||||
schema.LDAPImplementationCustom,
|
||||
schema.LDAPImplementationActiveDirectory,
|
||||
schema.LDAPImplementationRFC2307bis,
|
||||
schema.LDAPImplementationFreeIPA,
|
||||
schema.LDAPImplementationLLDAP,
|
||||
schema.LDAPImplementationGLAuth,
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
Loading…
Reference in New Issue