diff --git a/config.template.yml b/config.template.yml index 933a03eac..ef53de1cf 100644 --- a/config.template.yml +++ b/config.template.yml @@ -149,6 +149,9 @@ authentication_backend: ## Scheme can be ldap or ldaps in the format (port optional). url: ldap://127.0.0.1 + ## The dial timeout for LDAP. + timeout: 5s + ## Use StartTLS with the LDAP connection. start_tls: false diff --git a/docs/configuration/authentication/ldap.md b/docs/configuration/authentication/ldap.md index fc0bc81bf..452b9f080 100644 --- a/docs/configuration/authentication/ldap.md +++ b/docs/configuration/authentication/ldap.md @@ -7,11 +7,9 @@ nav_order: 2 --- # LDAP - **Authelia** supports using a LDAP server as the users database. ## Configuration - ```yaml authentication_backend: disable_reset_password: false @@ -19,12 +17,13 @@ authentication_backend: ldap: implementation: custom url: ldap://127.0.0.1 + timeout: 5s start_tls: false tls: server_name: ldap.example.com skip_verify: false minimum_version: TLS1.2 - base_dn: dc=example,dc=com + base_dn: DC=example,DC=com username_attribute: uid additional_users_dn: ou=users users_filter: (&({username_attribute}={input})(objectClass=person)) @@ -33,7 +32,7 @@ authentication_backend: group_name_attribute: cn mail_attribute: mail display_name_attribute: displayName - user: cn=admin,dc=example,dc=com + user: CN=admin,DC=example,DC=com password: password ``` @@ -70,6 +69,18 @@ If utilising an IPv6 literal address it must be enclosed by square brackets: url: ldap://[fd00:1111:2222:3333::1] ``` +### timeout +
+type: duration +{: .label .label-config .label-purple } +default: 5s +{: .label .label-config .label-blue } +required: no +{: .label .label-config .label-green } +
+ +The timeout for dialing an LDAP connection. + ### start_tls
type: boolean @@ -86,7 +97,6 @@ URL's are slightly more secure. ### tls - Controls the TLS connection validation process. You can see how to configure the tls section [here](../index.md#tls-configuration). @@ -143,11 +153,9 @@ The default value is dependent on the [implementation](#implementation), refer t [attribute defaults](#attribute-defaults) for more information. ### additional_groups_dn - Similar to [additional_users_dn](#additional_users_dn) but it applies to group searches. ### groups_filter - Similar to [users_filter](#users_filter) but it applies to group searches. In order to include groups the memeber is not a direct member of, but is a member of another group that is a member of those (i.e. recursive groups), you may try using the following filter which is currently only tested against Microsoft Active Directory: @@ -155,7 +163,6 @@ using the following filter which is currently only tested against Microsoft Acti `(&(member:1.2.840.113556.1.4.1941:={dn})(objectClass=group)(objectCategory=group))` ### mail_attribute - The attribute to retrieve which contains the users email addresses. This is important for the device registration and password reset processes. The user must have an email address in order for Authelia to perform @@ -163,32 +170,26 @@ identity verification when a user attempts to reset their password or register a second factor device. ### display_name_attribute - The attribute to retrieve which is shown on the Web UI to the user when they log in. ### user - The distinguished name of the user paired with the password to bind with for lookup and password change operations. ### password - The password of the user paired with the user to bind with for lookup and password change operations. Can also be defined using a [secret](../secrets.md) which is the recommended for containerized deployments. ## 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. ### Filter replacements - Various replacements occur in the user and groups filter. The replacements either occur at startup or upon an LDAP search. #### Users filter replacements - |Placeholder |Phase |Replacement | |:----------------------:|:-----:|:--------------------------------------------------------------:| |{username_attribute} |startup|The [username attribute](#username_attribute) configured | @@ -197,7 +198,6 @@ search. |{input} |search |The input into the username field | #### Groups filter replacements - |Placeholder |Phase |Replacement | |:----------------------:|:-----:|:-------------------------------------------------------------------------:| |{input} |search |The input into the username field | @@ -205,7 +205,6 @@ search. |{dn} |search |The distinguished name from the profile lookup | ### Defaults - The below tables describes the current attribute defaults for each implementation. #### Attribute defaults @@ -218,7 +217,6 @@ described by the Username column. |activedirectory|sAMAccountName|displayName |mail|cn | #### Filter defaults - The filters are probably the most important part to get correct when setting up LDAP. You want to exclude disabled accounts. The active directory example has two attribute filters that accomplish this as an example (more examples would be appreciated). The @@ -236,7 +234,6 @@ _**Note:**_ The Active Directory filter `(sAMAccountType=805306368)` is exactly and other Active Directory filters on the [TechNet wiki](https://social.technet.microsoft.com/wiki/contents/articles/5392.active-directory-ldap-syntax-filters.aspx). ## Refresh Interval - This setting takes a [duration notation](../index.md#duration-notation-format) that sets the max frequency for how often Authelia contacts the backend to verify the user still exists and that the groups stored in the session are up to date. This allows us to destroy sessions when the user no longer matches the @@ -254,7 +251,6 @@ on a page loads which could be substantially costly. It's a trade-off between lo you should adapt according to your own security policy. ## Important notes - Users must be uniquely identified by an attribute, this attribute must obviously contain a single value and be guaranteed by the administrator to be unique. If multiple users have the same value, Authelia will simply fail authenticating the user and display an error message in the logs. diff --git a/internal/authentication/ldap_connection_factory.go b/internal/authentication/ldap_connection_factory.go index b7b58a14d..a000ad005 100644 --- a/internal/authentication/ldap_connection_factory.go +++ b/internal/authentication/ldap_connection_factory.go @@ -64,7 +64,7 @@ func (lc *LDAPConnectionImpl) StartTLS(config *tls.Config) error { // LDAPConnectionFactory an interface of factory of ldap connections. type LDAPConnectionFactory interface { - DialURL(addr string, opts ldap.DialOpt) (LDAPConnection, error) + DialURL(addr string, opts ...ldap.DialOpt) (LDAPConnection, error) } // LDAPConnectionFactoryImpl the production implementation of an ldap connection factory. @@ -76,8 +76,8 @@ func NewLDAPConnectionFactoryImpl() *LDAPConnectionFactoryImpl { } // DialURL creates a connection from an LDAP URL when successful. -func (lcf *LDAPConnectionFactoryImpl) DialURL(addr string, opts ldap.DialOpt) (LDAPConnection, error) { - conn, err := ldap.DialURL(addr, opts) +func (lcf *LDAPConnectionFactoryImpl) DialURL(addr string, opts ...ldap.DialOpt) (LDAPConnection, error) { + conn, err := ldap.DialURL(addr, opts...) if err != nil { return nil, err } diff --git a/internal/authentication/ldap_connection_factory_mock.go b/internal/authentication/ldap_connection_factory_mock.go index c3f285f90..ef2777d1d 100644 --- a/internal/authentication/ldap_connection_factory_mock.go +++ b/internal/authentication/ldap_connection_factory_mock.go @@ -10,30 +10,30 @@ import ( gomock "github.com/golang/mock/gomock" ) -// MockLDAPConnection is a mock of LDAPConnection interface +// MockLDAPConnection is a mock of LDAPConnection interface. type MockLDAPConnection struct { ctrl *gomock.Controller recorder *MockLDAPConnectionMockRecorder } -// MockLDAPConnectionMockRecorder is the mock recorder for MockLDAPConnection +// MockLDAPConnectionMockRecorder is the mock recorder for MockLDAPConnection. type MockLDAPConnectionMockRecorder struct { mock *MockLDAPConnection } -// NewMockLDAPConnection creates a new mock instance +// NewMockLDAPConnection creates a new mock instance. func NewMockLDAPConnection(ctrl *gomock.Controller) *MockLDAPConnection { mock := &MockLDAPConnection{ctrl: ctrl} mock.recorder = &MockLDAPConnectionMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockLDAPConnection) EXPECT() *MockLDAPConnectionMockRecorder { return m.recorder } -// Bind mocks base method +// Bind mocks base method. func (m *MockLDAPConnection) Bind(username, password string) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Bind", username, password) @@ -41,25 +41,53 @@ func (m *MockLDAPConnection) Bind(username, password string) error { return ret0 } -// Bind indicates an expected call of Bind +// Bind indicates an expected call of Bind. func (mr *MockLDAPConnectionMockRecorder) Bind(username, password interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Bind", reflect.TypeOf((*MockLDAPConnection)(nil).Bind), username, password) } -// Close mocks base method +// Close mocks base method. func (m *MockLDAPConnection) Close() { m.ctrl.T.Helper() m.ctrl.Call(m, "Close") } -// Close indicates an expected call of Close +// Close indicates an expected call of Close. func (mr *MockLDAPConnectionMockRecorder) Close() *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockLDAPConnection)(nil).Close)) } -// Search mocks base method +// Modify mocks base method. +func (m *MockLDAPConnection) Modify(modifyRequest *ldap.ModifyRequest) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Modify", modifyRequest) + ret0, _ := ret[0].(error) + return ret0 +} + +// Modify indicates an expected call of Modify. +func (mr *MockLDAPConnectionMockRecorder) Modify(modifyRequest interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Modify", reflect.TypeOf((*MockLDAPConnection)(nil).Modify), modifyRequest) +} + +// PasswordModify mocks base method. +func (m *MockLDAPConnection) PasswordModify(pwdModifyRequest *ldap.PasswordModifyRequest) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PasswordModify", pwdModifyRequest) + ret0, _ := ret[0].(error) + return ret0 +} + +// PasswordModify indicates an expected call of PasswordModify. +func (mr *MockLDAPConnectionMockRecorder) PasswordModify(pwdModifyRequest interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PasswordModify", reflect.TypeOf((*MockLDAPConnection)(nil).PasswordModify), pwdModifyRequest) +} + +// Search mocks base method. func (m *MockLDAPConnection) Search(searchRequest *ldap.SearchRequest) (*ldap.SearchResult, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Search", searchRequest) @@ -68,41 +96,13 @@ func (m *MockLDAPConnection) Search(searchRequest *ldap.SearchRequest) (*ldap.Se return ret0, ret1 } -// Search indicates an expected call of Search +// Search indicates an expected call of Search. func (mr *MockLDAPConnectionMockRecorder) Search(searchRequest interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Search", reflect.TypeOf((*MockLDAPConnection)(nil).Search), searchRequest) } -// Modify mocks base method -func (m *MockLDAPConnection) Modify(modifyRequest *ldap.ModifyRequest) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Modify", modifyRequest) - ret0, _ := ret[0].(error) - return ret0 -} - -// Modify indicates an expected call of Modify -func (mr *MockLDAPConnectionMockRecorder) Modify(modifyRequest interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Modify", reflect.TypeOf((*MockLDAPConnection)(nil).Modify), modifyRequest) -} - -// PasswordModify mocks base method -func (m *MockLDAPConnection) PasswordModify(pwdModifyRequest *ldap.PasswordModifyRequest) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "PasswordModify", pwdModifyRequest) - ret0, _ := ret[0].(error) - return ret0 -} - -// PasswordModify indicates an expected call of PasswordModify -func (mr *MockLDAPConnectionMockRecorder) PasswordModify(pwdModifyRequest interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PasswordModify", reflect.TypeOf((*MockLDAPConnection)(nil).Modify), pwdModifyRequest) -} - -// StartTLS mocks base method +// StartTLS mocks base method. func (m *MockLDAPConnection) StartTLS(config *tls.Config) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "StartTLS", config) @@ -110,46 +110,51 @@ func (m *MockLDAPConnection) StartTLS(config *tls.Config) error { return ret0 } -// StartTLS indicates an expected call of StartTLS +// StartTLS indicates an expected call of StartTLS. func (mr *MockLDAPConnectionMockRecorder) StartTLS(config interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartTLS", reflect.TypeOf((*MockLDAPConnection)(nil).StartTLS), config) } -// MockLDAPConnectionFactory is a mock of LDAPConnectionFactory interface +// MockLDAPConnectionFactory is a mock of LDAPConnectionFactory interface. type MockLDAPConnectionFactory struct { ctrl *gomock.Controller recorder *MockLDAPConnectionFactoryMockRecorder } -// MockLDAPConnectionFactoryMockRecorder is the mock recorder for MockLDAPConnectionFactory +// MockLDAPConnectionFactoryMockRecorder is the mock recorder for MockLDAPConnectionFactory. type MockLDAPConnectionFactoryMockRecorder struct { mock *MockLDAPConnectionFactory } -// NewMockLDAPConnectionFactory creates a new mock instance +// NewMockLDAPConnectionFactory creates a new mock instance. func NewMockLDAPConnectionFactory(ctrl *gomock.Controller) *MockLDAPConnectionFactory { mock := &MockLDAPConnectionFactory{ctrl: ctrl} mock.recorder = &MockLDAPConnectionFactoryMockRecorder{mock} return mock } -// EXPECT returns an object that allows the caller to indicate expected use +// EXPECT returns an object that allows the caller to indicate expected use. func (m *MockLDAPConnectionFactory) EXPECT() *MockLDAPConnectionFactoryMockRecorder { return m.recorder } -// DialURL mocks base method -func (m *MockLDAPConnectionFactory) DialURL(addr string, opts ldap.DialOpt) (LDAPConnection, error) { +// DialURL mocks base method. +func (m *MockLDAPConnectionFactory) DialURL(addr string, opts ...ldap.DialOpt) (LDAPConnection, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DialURL", addr, opts) + varargs := []interface{}{addr} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DialURL", varargs...) ret0, _ := ret[0].(LDAPConnection) ret1, _ := ret[1].(error) return ret0, ret1 } -// DialURL indicates an expected call of DialURL -func (mr *MockLDAPConnectionFactoryMockRecorder) DialURL(addr, opts interface{}) *gomock.Call { +// DialURL indicates an expected call of DialURL. +func (mr *MockLDAPConnectionFactoryMockRecorder) DialURL(addr interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DialURL", reflect.TypeOf((*MockLDAPConnectionFactory)(nil).DialURL), addr, opts) + varargs := append([]interface{}{addr}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DialURL", reflect.TypeOf((*MockLDAPConnectionFactory)(nil).DialURL), varargs...) } diff --git a/internal/authentication/ldap_user_provider.go b/internal/authentication/ldap_user_provider.go index 15e51df56..5dfd6cbcb 100644 --- a/internal/authentication/ldap_user_provider.go +++ b/internal/authentication/ldap_user_provider.go @@ -4,6 +4,7 @@ import ( "crypto/tls" "crypto/x509" "fmt" + "net" "strings" "github.com/go-ldap/ldap/v3" @@ -19,7 +20,7 @@ import ( type LDAPUserProvider struct { configuration schema.LDAPAuthenticationBackendConfiguration tlsConfig *tls.Config - dialOpts ldap.DialOpt + dialOpts []ldap.DialOpt logger *logrus.Logger connectionFactory LDAPConnectionFactory @@ -65,10 +66,12 @@ func newLDAPUserProvider(configuration schema.LDAPAuthenticationBackendConfigura tlsConfig := utils.NewTLSConfig(configuration.TLS, tls.VersionTLS12, certPool) - var dialOpts ldap.DialOpt + var dialOpts = []ldap.DialOpt{ + ldap.DialWithDialer(&net.Dialer{Timeout: configuration.Timeout}), + } if tlsConfig != nil { - dialOpts = ldap.DialWithTLSConfig(tlsConfig) + dialOpts = append(dialOpts, ldap.DialWithTLSConfig(tlsConfig)) } if factory == nil { @@ -90,7 +93,7 @@ func newLDAPUserProvider(configuration schema.LDAPAuthenticationBackendConfigura } func (p *LDAPUserProvider) connect(userDN string, password string) (LDAPConnection, error) { - conn, err := p.connectionFactory.DialURL(p.configuration.URL, p.dialOpts) + conn, err := p.connectionFactory.DialURL(p.configuration.URL, p.dialOpts...) if err != nil { return nil, err } diff --git a/internal/configuration/config.template.yml b/internal/configuration/config.template.yml index 933a03eac..ef53de1cf 100644 --- a/internal/configuration/config.template.yml +++ b/internal/configuration/config.template.yml @@ -149,6 +149,9 @@ authentication_backend: ## Scheme can be ldap or ldaps in the format (port optional). url: ldap://127.0.0.1 + ## The dial timeout for LDAP. + timeout: 5s + ## Use StartTLS with the LDAP connection. start_tls: false diff --git a/internal/configuration/schema/authentication.go b/internal/configuration/schema/authentication.go index a4727d60f..648c711d8 100644 --- a/internal/configuration/schema/authentication.go +++ b/internal/configuration/schema/authentication.go @@ -1,22 +1,30 @@ package schema +import "time" + // LDAPAuthenticationBackendConfiguration represents the configuration related to LDAP server. type LDAPAuthenticationBackendConfiguration struct { - Implementation string `koanf:"implementation"` - URL string `koanf:"url"` - BaseDN string `koanf:"base_dn"` - AdditionalUsersDN string `koanf:"additional_users_dn"` - UsersFilter string `koanf:"users_filter"` - AdditionalGroupsDN string `koanf:"additional_groups_dn"` - GroupsFilter string `koanf:"groups_filter"` - GroupNameAttribute string `koanf:"group_name_attribute"` - UsernameAttribute string `koanf:"username_attribute"` - MailAttribute string `koanf:"mail_attribute"` - DisplayNameAttribute string `koanf:"display_name_attribute"` - User string `koanf:"user"` - Password string `koanf:"password"` - StartTLS bool `koanf:"start_tls"` - TLS *TLSConfig `koanf:"tls"` + Implementation string `koanf:"implementation"` + URL string `koanf:"url"` + Timeout time.Duration `koanf:"timeout"` + StartTLS bool `koanf:"start_tls"` + TLS *TLSConfig `koanf:"tls"` + + BaseDN string `koanf:"base_dn"` + + AdditionalUsersDN string `koanf:"additional_users_dn"` + UsersFilter string `koanf:"users_filter"` + + AdditionalGroupsDN string `koanf:"additional_groups_dn"` + GroupsFilter string `koanf:"groups_filter"` + + GroupNameAttribute string `koanf:"group_name_attribute"` + UsernameAttribute string `koanf:"username_attribute"` + MailAttribute string `koanf:"mail_attribute"` + DisplayNameAttribute string `koanf:"display_name_attribute"` + + User string `koanf:"user"` + Password string `koanf:"password"` } // FileAuthenticationBackendConfiguration represents the configuration related to file-based backend. @@ -77,6 +85,7 @@ var DefaultLDAPAuthenticationBackendConfiguration = LDAPAuthenticationBackendCon MailAttribute: "mail", DisplayNameAttribute: "displayName", GroupNameAttribute: "cn", + Timeout: time.Second * 5, TLS: &TLSConfig{ MinimumVersion: "TLS1.2", }, diff --git a/internal/configuration/validator/authentication.go b/internal/configuration/validator/authentication.go index 946c907a5..172dd57b0 100644 --- a/internal/configuration/validator/authentication.go +++ b/internal/configuration/validator/authentication.go @@ -106,6 +106,10 @@ func validateFileAuthenticationBackendArgon2id(configuration *schema.FileAuthent } func validateLDAPAuthenticationBackend(configuration *schema.LDAPAuthenticationBackendConfiguration, validator *schema.StructValidator) { + if configuration.Timeout == 0 { + configuration.Timeout = schema.DefaultLDAPAuthenticationBackendConfiguration.Timeout + } + if configuration.Implementation == "" { configuration.Implementation = schema.DefaultLDAPAuthenticationBackendConfiguration.Implementation } diff --git a/internal/configuration/validator/authentication_test.go b/internal/configuration/validator/authentication_test.go index 479db7071..151cf4662 100644 --- a/internal/configuration/validator/authentication_test.go +++ b/internal/configuration/validator/authentication_test.go @@ -2,6 +2,7 @@ package validator import ( "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -518,26 +519,30 @@ func (suite *ActiveDirectoryAuthenticationBackendSuite) TestShouldSetActiveDirec suite.Assert().False(suite.validator.HasErrors()) suite.Assert().Equal( - suite.configuration.LDAP.UsersFilter, - schema.DefaultLDAPAuthenticationBackendImplementationActiveDirectoryConfiguration.UsersFilter) + schema.DefaultLDAPAuthenticationBackendConfiguration.Timeout, + suite.configuration.LDAP.Timeout) suite.Assert().Equal( - suite.configuration.LDAP.UsernameAttribute, - schema.DefaultLDAPAuthenticationBackendImplementationActiveDirectoryConfiguration.UsernameAttribute) + schema.DefaultLDAPAuthenticationBackendImplementationActiveDirectoryConfiguration.UsersFilter, + suite.configuration.LDAP.UsersFilter) suite.Assert().Equal( - suite.configuration.LDAP.DisplayNameAttribute, - schema.DefaultLDAPAuthenticationBackendImplementationActiveDirectoryConfiguration.DisplayNameAttribute) + schema.DefaultLDAPAuthenticationBackendImplementationActiveDirectoryConfiguration.UsernameAttribute, + suite.configuration.LDAP.UsernameAttribute) suite.Assert().Equal( - suite.configuration.LDAP.MailAttribute, - schema.DefaultLDAPAuthenticationBackendImplementationActiveDirectoryConfiguration.MailAttribute) + schema.DefaultLDAPAuthenticationBackendImplementationActiveDirectoryConfiguration.DisplayNameAttribute, + suite.configuration.LDAP.DisplayNameAttribute) suite.Assert().Equal( - suite.configuration.LDAP.GroupsFilter, - schema.DefaultLDAPAuthenticationBackendImplementationActiveDirectoryConfiguration.GroupsFilter) + schema.DefaultLDAPAuthenticationBackendImplementationActiveDirectoryConfiguration.MailAttribute, + suite.configuration.LDAP.MailAttribute) suite.Assert().Equal( - suite.configuration.LDAP.GroupNameAttribute, - schema.DefaultLDAPAuthenticationBackendImplementationActiveDirectoryConfiguration.GroupNameAttribute) + schema.DefaultLDAPAuthenticationBackendImplementationActiveDirectoryConfiguration.GroupsFilter, + suite.configuration.LDAP.GroupsFilter) + suite.Assert().Equal( + schema.DefaultLDAPAuthenticationBackendImplementationActiveDirectoryConfiguration.GroupNameAttribute, + suite.configuration.LDAP.GroupNameAttribute) } func (suite *ActiveDirectoryAuthenticationBackendSuite) TestShouldOnlySetDefaultsIfNotManuallyConfigured() { + suite.configuration.LDAP.Timeout = time.Second * 2 suite.configuration.LDAP.UsersFilter = "(&({username_attribute}={input})(objectCategory=person)(objectClass=user)(!userAccountControl:1.2.840.113556.1.4.803:=2))" suite.configuration.LDAP.UsernameAttribute = "cn" suite.configuration.LDAP.MailAttribute = "userPrincipalName" @@ -548,23 +553,26 @@ func (suite *ActiveDirectoryAuthenticationBackendSuite) TestShouldOnlySetDefault ValidateAuthenticationBackend(&suite.configuration, suite.validator) suite.Assert().NotEqual( - suite.configuration.LDAP.UsersFilter, - schema.DefaultLDAPAuthenticationBackendImplementationActiveDirectoryConfiguration.UsersFilter) + schema.DefaultLDAPAuthenticationBackendConfiguration.Timeout, + suite.configuration.LDAP.Timeout) suite.Assert().NotEqual( - suite.configuration.LDAP.UsernameAttribute, - schema.DefaultLDAPAuthenticationBackendImplementationActiveDirectoryConfiguration.UsernameAttribute) + schema.DefaultLDAPAuthenticationBackendImplementationActiveDirectoryConfiguration.UsersFilter, + suite.configuration.LDAP.UsersFilter) suite.Assert().NotEqual( - suite.configuration.LDAP.DisplayNameAttribute, - schema.DefaultLDAPAuthenticationBackendImplementationActiveDirectoryConfiguration.DisplayNameAttribute) + schema.DefaultLDAPAuthenticationBackendImplementationActiveDirectoryConfiguration.UsernameAttribute, + suite.configuration.LDAP.UsernameAttribute) suite.Assert().NotEqual( - suite.configuration.LDAP.MailAttribute, - schema.DefaultLDAPAuthenticationBackendImplementationActiveDirectoryConfiguration.MailAttribute) + schema.DefaultLDAPAuthenticationBackendImplementationActiveDirectoryConfiguration.DisplayNameAttribute, + suite.configuration.LDAP.DisplayNameAttribute) suite.Assert().NotEqual( - suite.configuration.LDAP.GroupsFilter, - schema.DefaultLDAPAuthenticationBackendImplementationActiveDirectoryConfiguration.GroupsFilter) + schema.DefaultLDAPAuthenticationBackendImplementationActiveDirectoryConfiguration.MailAttribute, + suite.configuration.LDAP.MailAttribute) suite.Assert().NotEqual( - suite.configuration.LDAP.GroupNameAttribute, - schema.DefaultLDAPAuthenticationBackendImplementationActiveDirectoryConfiguration.GroupNameAttribute) + schema.DefaultLDAPAuthenticationBackendImplementationActiveDirectoryConfiguration.GroupsFilter, + suite.configuration.LDAP.GroupsFilter) + suite.Assert().NotEqual( + schema.DefaultLDAPAuthenticationBackendImplementationActiveDirectoryConfiguration.GroupNameAttribute, + suite.configuration.LDAP.GroupNameAttribute) } func TestActiveDirectoryAuthenticationBackend(t *testing.T) {