diff options
| author | James Elliott <james-d-elliott@users.noreply.github.com> | 2023-06-18 14:40:38 +1000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-06-18 14:40:38 +1000 |
| commit | f79db588be089909e8b430a928213eb104ae2972 (patch) | |
| tree | eb12e2960794d38eb18b14b803f23ca8dcd22fe1 /internal/authentication/ldap_user_provider_test.go | |
| parent | 68ac62acab1f8834f30ccf4e06ffb31c5f49c4a6 (diff) | |
feat(authentication): ldap memberof group search (#5418)
Introduces the concept of group search mode into the LDAP configuration. This also adds the filter and memberof search modes. The full description of these is included in the docs but the filter mode is the same mode as previous which is also the default and recommended value. The memberof mode should only be used by users who are aware of how the concept works as per the docs.
Closes #2161
Signed-off-by: James Elliott <james-d-elliott@users.noreply.github.com>
Diffstat (limited to 'internal/authentication/ldap_user_provider_test.go')
| -rw-r--r-- | internal/authentication/ldap_user_provider_test.go | 2373 |
1 files changed, 1904 insertions, 469 deletions
diff --git a/internal/authentication/ldap_user_provider_test.go b/internal/authentication/ldap_user_provider_test.go index 7dc7c7e20..1664909fa 100644 --- a/internal/authentication/ldap_user_provider_test.go +++ b/internal/authentication/ldap_user_provider_test.go @@ -16,6 +16,20 @@ import ( "github.com/authelia/authelia/v4/internal/utils" ) +func TestNewLDAPUserProvider(t *testing.T) { + provider := NewLDAPUserProvider(schema.AuthenticationBackend{LDAP: &schema.LDAPAuthenticationBackend{}}, nil) + + assert.NotNil(t, provider) +} + +func TestNewLDAPUserProviderWithFactoryWithoutFactory(t *testing.T) { + provider := NewLDAPUserProviderWithFactory(schema.LDAPAuthenticationBackend{}, false, nil, nil) + + assert.NotNil(t, provider) + + assert.IsType(t, &ProductionLDAPClientFactory{}, provider.factory) +} + func TestShouldCreateRawConnectionWhenSchemeIsLDAP(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() @@ -128,6 +142,79 @@ func TestEscapeSpecialCharsInGroupsFilter(t *testing.T) { assert.Equal(t, "(|(member=cn=john \\28external\\29,dc=example,dc=com)(uid=john)(uid=john\\#\\=\\28abc\\,def\\29))", filter) } +func TestResolveGroupsFilter(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockFactory := NewMockLDAPClientFactory(ctrl) + + testCases := []struct { + name string + have schema.LDAPAuthenticationBackend + input string + profile ldapUserProfile + expected string + }{ + { + "ShouldResolveEmptyFilter", + schema.LDAPAuthenticationBackend{}, + "", + ldapUserProfile{}, + "", + }, + { + "ShouldResolveMemberOfRDNFilter", + schema.LDAPAuthenticationBackend{ + GroupsFilter: "(|{memberof:rdn})", + Attributes: schema.LDAPAuthenticationAttributes{ + DistinguishedName: "distinguishedName", + GroupName: "cn", + MemberOf: "memberOf", + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + }, + }, + "", + ldapUserProfile{ + MemberOf: []string{"CN=abc,DC=example,DC=com", "CN=xyz,DC=example,DC=com"}, + }, + "(|(CN=abc)(CN=xyz))", + }, + { + "ShouldResolveMemberOfDNFilter", + schema.LDAPAuthenticationBackend{ + GroupsFilter: "(|{memberof:dn})", + Attributes: schema.LDAPAuthenticationAttributes{ + DistinguishedName: "distinguishedName", + GroupName: "cn", + MemberOf: "memberOf", + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + }, + }, + "", + ldapUserProfile{ + MemberOf: []string{"CN=abc,DC=example,DC=com", "CN=xyz,DC=example,DC=com"}, + }, + "(|(distinguishedName=CN=abc,DC=example,DC=com)(distinguishedName=CN=xyz,DC=example,DC=com))", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + provider := NewLDAPUserProviderWithFactory( + tc.have, + false, + nil, + mockFactory) + + assert.Equal(t, tc.expected, provider.resolveGroupsFilter("", &tc.profile)) + }) + } +} + type ExtendedSearchRequestMatcher struct { filter string baseDN string @@ -156,6 +243,81 @@ func (e *ExtendedSearchRequestMatcher) String() string { return fmt.Sprintf("baseDN: %s, filter %s", e.baseDN, e.filter) } +func TestShouldCheckLDAPEpochFilters(t *testing.T) { + type have struct { + users string + attr schema.LDAPAuthenticationAttributes + } + + type expected struct { + dtgeneralized bool + dtmsftnt bool + dtunix bool + } + + testCases := []struct { + name string + have have + expected expected + }{ + { + "ShouldNotEnableAny", + have{}, + expected{}, + }, + { + "ShouldNotEnableMSFTNT", + have{ + users: "(abc={date-time:microsoft-nt})", + }, + expected{ + dtmsftnt: true, + }, + }, + { + "ShouldNotEnableUnix", + have{ + users: "(abc={date-time:unix})", + }, + expected{ + dtunix: true, + }, + }, + { + "ShouldNotEnableGeneralized", + have{ + users: "(abc={date-time:generalized})", + }, + expected{ + dtgeneralized: true, + }, + }, + } + + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockFactory := NewMockLDAPClientFactory(ctrl) + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + provider := NewLDAPUserProviderWithFactory( + schema.LDAPAuthenticationBackend{ + UsersFilter: tc.have.users, + Attributes: tc.have.attr, + BaseDN: "dc=example,dc=com", + }, + false, + nil, + mockFactory) + + assert.Equal(t, tc.expected.dtgeneralized, provider.usersFilterReplacementDateTimeGeneralized) + assert.Equal(t, tc.expected.dtmsftnt, provider.usersFilterReplacementDateTimeMicrosoftNTTimeEpoch) + assert.Equal(t, tc.expected.dtunix, provider.usersFilterReplacementDateTimeUnixEpoch) + }) + } +} + func TestShouldCheckLDAPServerExtensions(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() @@ -165,15 +327,18 @@ func TestShouldCheckLDAPServerExtensions(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - UsersFilter: "(|({username_attribute}={input})({mail_attribute}={input}))", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - Password: "password", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + UsersFilter: "(|({username_attribute}={input})({mail_attribute}={input}))", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + Password: "password", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", }, false, nil, @@ -230,15 +395,18 @@ func TestShouldNotCheckLDAPServerExtensionsWhenRootDSEReturnsMoreThanOneEntry(t provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - UsersFilter: "(|({username_attribute}={input})({mail_attribute}={input}))", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - Password: "password", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + UsersFilter: "(|({username_attribute}={input})({mail_attribute}={input}))", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + Password: "password", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", }, false, nil, @@ -296,15 +464,18 @@ func TestShouldCheckLDAPServerControlTypes(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - UsersFilter: "(|({username_attribute}={input})({mail_attribute}={input}))", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - Password: "password", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + UsersFilter: "(|({username_attribute}={input})({mail_attribute}={input}))", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + Password: "password", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", }, false, nil, @@ -361,15 +532,18 @@ func TestShouldNotEnablePasswdModifyExtensionOrControlTypes(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - UsersFilter: "(|({username_attribute}={input})({mail_attribute}={input}))", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - Password: "password", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + UsersFilter: "(|({username_attribute}={input})({mail_attribute}={input}))", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + Password: "password", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", }, false, nil, @@ -426,15 +600,18 @@ func TestShouldReturnCheckServerConnectError(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - UsersFilter: "(|({username_attribute}={input})({mail_attribute}={input}))", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - Password: "password", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + UsersFilter: "(|({username_attribute}={input})({mail_attribute}={input}))", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + Password: "password", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", }, false, nil, @@ -459,15 +636,18 @@ func TestShouldReturnCheckServerSearchError(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - UsersFilter: "(|({username_attribute}={input})({mail_attribute}={input}))", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - Password: "password", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + UsersFilter: "(|({username_attribute}={input})({mail_attribute}={input}))", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + Password: "password", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", }, false, nil, @@ -495,6 +675,53 @@ func TestShouldReturnCheckServerSearchError(t *testing.T) { assert.False(t, provider.features.Extensions.PwdModifyExOp) } +func TestShouldPermitRootDSEFailure(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockFactory := NewMockLDAPClientFactory(ctrl) + mockClient := NewMockLDAPClient(ctrl) + + provider := NewLDAPUserProviderWithFactory( + schema.LDAPAuthenticationBackend{ + PermitFeatureDetectionFailure: true, + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + UsersFilter: "(|({username_attribute}={input})({mail_attribute}={input}))", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + Password: "password", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", + }, + false, + nil, + mockFactory) + + dialURL := mockFactory.EXPECT(). + DialURL(gomock.Eq("ldap://127.0.0.1:389"), gomock.Any()). + Return(mockClient, nil) + + connBind := mockClient.EXPECT(). + Bind(gomock.Eq("cn=admin,dc=example,dc=com"), gomock.Eq("password")). + Return(nil) + + searchOIDs := mockClient.EXPECT(). + Search(NewExtendedSearchRequestMatcher("(objectClass=*)", "", ldap.ScopeBaseObject, ldap.NeverDerefAliases, false, []string{ldapSupportedExtensionAttribute, ldapSupportedControlAttribute})). + Return(nil, errors.New("could not perform the search")) + + connClose := mockClient.EXPECT().Close() + + gomock.InOrder(dialURL, connBind, searchOIDs, connClose) + + err := provider.StartupCheck() + assert.NoError(t, err) +} + type SearchRequestMatcher struct { expected string } @@ -521,16 +748,19 @@ func TestShouldEscapeUserInput(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - UsersFilter: "(|({username_attribute}={input})({mail_attribute}={input}))", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - Password: "password", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", - PermitReferrals: true, + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + UsersFilter: "(|({username_attribute}={input})({mail_attribute}={input}))", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + Password: "password", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", + PermitReferrals: true, }, false, nil, @@ -555,21 +785,24 @@ func TestShouldReturnEmailWhenAttributeSameAsUsername(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "mail", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "(&({username_attribute}={input})(objectClass=inetOrgPerson))", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "mail", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "(&({username_attribute}={input})(objectClass=inetOrgPerson))", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", }, false, nil, mockFactory) - assert.Equal(t, []string{"mail", "displayName"}, provider.usersAttributes) + assert.Equal(t, []string{"mail", "displayName", "memberOf"}, provider.usersAttributes) dialURL := mockFactory.EXPECT(). DialURL(gomock.Eq("ldap://127.0.0.1:389"), gomock.Any()). @@ -626,21 +859,24 @@ func TestShouldReturnUsernameAndBlankDisplayNameWhenAttributesTheSame(t *testing provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "uid", - UsersFilter: "(&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=inetOrgPerson))", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "uid", + MemberOf: "memberOf", + }, + UsersFilter: "(&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=inetOrgPerson))", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", }, false, nil, mockFactory) - assert.Equal(t, []string{"uid", "mail"}, provider.usersAttributes) + assert.Equal(t, []string{"uid", "mail", "memberOf"}, provider.usersAttributes) dialURL := mockFactory.EXPECT(). DialURL(gomock.Eq("ldap://127.0.0.1:389"), gomock.Any()). @@ -697,21 +933,24 @@ func TestShouldReturnBlankEmailAndDisplayNameWhenAttrsLenZero(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "(&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=inetOrgPerson))", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "(&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=inetOrgPerson))", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", }, false, nil, mockFactory) - assert.Equal(t, []string{"uid", "mail", "displayName"}, provider.usersAttributes) + assert.Equal(t, []string{"uid", "mail", "displayName", "memberOf"}, provider.usersAttributes) dialURL := mockFactory.EXPECT(). DialURL(gomock.Eq("ldap://127.0.0.1:389"), gomock.Any()). @@ -740,6 +979,10 @@ func TestShouldReturnBlankEmailAndDisplayNameWhenAttrsLenZero(t *testing.T) { Name: "displayName", Values: []string{}, }, + { + Name: "memberOf", + Values: []string{}, + }, }, }, }, @@ -771,22 +1014,25 @@ func TestShouldCombineUsernameFilterAndUsersFilter(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - UsernameAttribute: "uid", - UsersFilter: "(&({username_attribute}={input})(&(objectCategory=person)(objectClass=user)))", - Password: "password", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - PermitReferrals: true, + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + UsersFilter: "(&({username_attribute}={input})(&(objectCategory=person)(objectClass=user)))", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", + PermitReferrals: true, }, false, nil, mockFactory) - assert.Equal(t, []string{"uid", "mail", "displayName"}, provider.usersAttributes) + assert.Equal(t, []string{"uid", "mail", "displayName", "memberOf"}, provider.usersAttributes) assert.True(t, provider.usersFilterReplacementInput) @@ -807,10 +1053,35 @@ func createSearchResultWithAttributes(attributes ...*ldap.EntryAttribute) *ldap. } } -func createSearchResultWithAttributeValues(values ...string) *ldap.SearchResult { - return createSearchResultWithAttributes(&ldap.EntryAttribute{ - Values: values, - }) +func createGroupSearchResultModeFilter(name string, groupNames ...string) *ldap.SearchResult { + result := &ldap.SearchResult{ + Entries: make([]*ldap.Entry, len(groupNames)), + } + + for i, groupName := range groupNames { + result.Entries[i] = &ldap.Entry{Attributes: []*ldap.EntryAttribute{{Name: name, Values: []string{groupName}}}} + } + + return result +} + +func createGroupSearchResultModeFilterWithDN(name string, groupNames []string, groupDNs []string) *ldap.SearchResult { + if len(groupNames) != len(groupDNs) { + panic("input sizes mismatch") + } + + result := &ldap.SearchResult{ + Entries: make([]*ldap.Entry, len(groupNames)), + } + + for i, groupName := range groupNames { + result.Entries[i] = &ldap.Entry{ + DN: groupDNs[i], + Attributes: []*ldap.EntryAttribute{{Name: name, Values: []string{groupName}}}, + } + } + + return result } func TestShouldNotCrashWhenGroupsAreNotRetrievedFromLDAP(t *testing.T) { @@ -822,16 +1093,20 @@ func TestShouldNotCrashWhenGroupsAreNotRetrievedFromLDAP(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "uid={input}", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", - PermitReferrals: true, + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + GroupName: "cn", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", + PermitReferrals: true, }, false, nil, @@ -886,6 +1161,127 @@ func TestShouldNotCrashWhenGroupsAreNotRetrievedFromLDAP(t *testing.T) { assert.Equal(t, details.Username, "john") } +func TestLDAPUserProvider_GetDetails_ShouldReturnOnUserError(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockFactory := NewMockLDAPClientFactory(ctrl) + mockClient := NewMockLDAPClient(ctrl) + + provider := NewLDAPUserProviderWithFactory( + schema.LDAPAuthenticationBackend{ + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", + PermitReferrals: true, + }, + false, + nil, + mockFactory) + + dialURL := mockFactory.EXPECT(). + DialURL(gomock.Eq("ldap://127.0.0.1:389"), gomock.Any()). + Return(mockClient, nil) + + connBind := mockClient.EXPECT(). + Bind(gomock.Eq("cn=admin,dc=example,dc=com"), gomock.Eq("password")). + Return(nil) + + connClose := mockClient.EXPECT().Close() + + searchProfile := mockClient.EXPECT(). + Search(gomock.Any()). + Return(nil, fmt.Errorf("failed to search")) + + gomock.InOrder(dialURL, connBind, searchProfile, connClose) + + details, err := provider.GetDetails("john") + assert.Nil(t, details) + assert.EqualError(t, err, "cannot find user DN of user 'john'. Cause: failed to search") +} + +func TestLDAPUserProvider_GetDetails_ShouldReturnOnGroupsError(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockFactory := NewMockLDAPClientFactory(ctrl) + mockClient := NewMockLDAPClient(ctrl) + + provider := NewLDAPUserProviderWithFactory( + schema.LDAPAuthenticationBackend{ + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", + PermitReferrals: true, + }, + false, + nil, + mockFactory) + + dialURL := mockFactory.EXPECT(). + DialURL(gomock.Eq("ldap://127.0.0.1:389"), gomock.Any()). + Return(mockClient, nil) + + connBind := mockClient.EXPECT(). + Bind(gomock.Eq("cn=admin,dc=example,dc=com"), gomock.Eq("password")). + Return(nil) + + connClose := mockClient.EXPECT().Close() + + searchGroups := mockClient.EXPECT(). + Search(gomock.Any()). + Return(nil, fmt.Errorf("failed to search groups")) + + searchProfile := mockClient.EXPECT(). + Search(gomock.Any()). + Return(&ldap.SearchResult{ + Entries: []*ldap.Entry{ + { + DN: "uid=test,dc=example,dc=com", + Attributes: []*ldap.EntryAttribute{ + { + Name: "displayName", + Values: []string{"John Doe"}, + }, + { + Name: "mail", + Values: []string{"test@example.com"}, + }, + { + Name: "uid", + Values: []string{"john"}, + }, + }, + }, + }, + }, nil) + + gomock.InOrder(dialURL, connBind, searchProfile, searchGroups, connClose) + + details, err := provider.GetDetails("john") + + assert.Nil(t, details) + assert.EqualError(t, err, "unable to retrieve groups of user 'john'. Cause: failed to search groups") +} + func TestShouldNotCrashWhenEmailsAreNotRetrievedFromLDAP(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() @@ -895,10 +1291,15 @@ func TestShouldNotCrashWhenEmailsAreNotRetrievedFromLDAP(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + DisplayName: "displayName", + MemberOf: "memberOf", + GroupName: "displayName", + }, UsersFilter: "uid={input}", AdditionalUsersDN: "ou=users", BaseDN: "dc=example,dc=com", @@ -919,7 +1320,73 @@ func TestShouldNotCrashWhenEmailsAreNotRetrievedFromLDAP(t *testing.T) { searchGroups := mockClient.EXPECT(). Search(gomock.Any()). - Return(createSearchResultWithAttributeValues("group1", "group2"), nil) + Return(createGroupSearchResultModeFilter(provider.config.Attributes.GroupName, "group1", "group2"), nil) + + searchProfile := mockClient.EXPECT(). + Search(gomock.Any()). + Return(&ldap.SearchResult{ + Entries: []*ldap.Entry{ + { + DN: "uid=test,dc=example,dc=com", + Attributes: []*ldap.EntryAttribute{ + { + Name: "uid", + Values: []string{"john"}, + }, + }, + }, + }, + }, nil) + + gomock.InOrder(dialURL, connBind, searchProfile, searchGroups, connClose) + + details, err := provider.GetDetails("john") + require.NoError(t, err) + + assert.ElementsMatch(t, details.Groups, []string{"group1", "group2"}) + assert.ElementsMatch(t, details.Emails, []string{}) + assert.Equal(t, details.Username, "john") +} + +func TestShouldUnauthenticatedBind(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockFactory := NewMockLDAPClientFactory(ctrl) + mockClient := NewMockLDAPClient(ctrl) + + provider := NewLDAPUserProviderWithFactory( + schema.LDAPAuthenticationBackend{ + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + DisplayName: "displayName", + MemberOf: "memberOf", + GroupName: "displayName", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", + }, + false, + nil, + mockFactory) + + dialURL := mockFactory.EXPECT(). + DialURL(gomock.Eq("ldap://127.0.0.1:389"), gomock.Any()). + Return(mockClient, nil) + + connBind := mockClient.EXPECT(). + UnauthenticatedBind(gomock.Eq("cn=admin,dc=example,dc=com")). + Return(nil) + + connClose := mockClient.EXPECT().Close() + + searchGroups := mockClient.EXPECT(). + Search(gomock.Any()). + Return(createGroupSearchResultModeFilter(provider.config.Attributes.GroupName, "group1", "group2"), nil) searchProfile := mockClient.EXPECT(). Search(gomock.Any()). @@ -956,15 +1423,19 @@ func TestShouldReturnUsernameFromLDAP(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "uid={input}", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + GroupName: "cn", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", }, false, nil, @@ -982,7 +1453,7 @@ func TestShouldReturnUsernameFromLDAP(t *testing.T) { searchGroups := mockClient.EXPECT(). Search(gomock.Any()). - Return(createSearchResultWithAttributeValues("group1", "group2"), nil) + Return(createGroupSearchResultModeFilter(provider.config.Attributes.GroupName, "group1", "group2"), nil) searchProfile := mockClient.EXPECT(). Search(gomock.Any()). @@ -1019,26 +1490,30 @@ func TestShouldReturnUsernameFromLDAP(t *testing.T) { assert.Equal(t, details.Username, "John") } -func TestShouldReturnUsernameFromLDAPWithReferrals(t *testing.T) { +func TestShouldReturnUsernameFromLDAPSearchModeMemberOfRDN(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockFactory := NewMockLDAPClientFactory(ctrl) mockClient := NewMockLDAPClient(ctrl) - mockClientReferral := NewMockLDAPClient(ctrl) provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "uid={input}", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", - PermitReferrals: true, + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + GroupName: "cn", + }, + GroupSearchMode: "memberof", + UsersFilter: "uid={input}", + GroupsFilter: "(|{memberof:rdn})", + AdditionalUsersDN: "ou=users", + BaseDN: "DC=example,DC=com", }, false, nil, @@ -1054,28 +1529,580 @@ func TestShouldReturnUsernameFromLDAPWithReferrals(t *testing.T) { connClose := mockClient.EXPECT().Close() + requestGroups := ldap.NewSearchRequest( + provider.groupsBaseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, + 0, 0, false, "(|(CN=admins)(CN=users))", provider.groupsAttributes, nil, + ) + + // This ensures the filtering works correctly in the following ways: + // Item 1 (0th element), has the wrong case. + // Item 2 (1st element), has the wrong DN. searchGroups := mockClient.EXPECT(). + Search(requestGroups). + Return(createGroupSearchResultModeFilterWithDN(provider.config.Attributes.GroupName, []string{"admins", "notadmins", "users"}, []string{"CN=ADMINS,OU=groups,DC=example,DC=com", "CN=notadmins,OU=wronggroups,DC=example,DC=com", "CN=users,OU=groups,DC=example,DC=com"}), nil) + + searchProfile := mockClient.EXPECT(). Search(gomock.Any()). - Return(createSearchResultWithAttributeValues("group1", "group2"), nil) + Return(&ldap.SearchResult{ + Entries: []*ldap.Entry{ + { + DN: "uid=test,dc=example,dc=com", + Attributes: []*ldap.EntryAttribute{ + { + Name: "displayName", + Values: []string{"John Doe"}, + }, + { + Name: "mail", + Values: []string{"test@example.com"}, + }, + { + Name: "uid", + Values: []string{"John"}, + }, + { + Name: "memberOf", + Values: []string{"CN=admins,OU=groups,DC=example,DC=com", "CN=users,OU=groups,DC=example,DC=com"}, + }, + }, + }, + }, + }, nil) + + gomock.InOrder(dialURL, connBind, searchProfile, searchGroups, connClose) + + details, err := provider.GetDetails("john") + require.NoError(t, err) + + assert.ElementsMatch(t, details.Groups, []string{"admins", "users"}) + assert.ElementsMatch(t, details.Emails, []string{"test@example.com"}) + assert.Equal(t, details.DisplayName, "John Doe") + assert.Equal(t, details.Username, "John") +} + +func TestShouldReturnUsernameFromLDAPSearchModeMemberOfDN(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockFactory := NewMockLDAPClientFactory(ctrl) + mockClient := NewMockLDAPClient(ctrl) + + provider := NewLDAPUserProviderWithFactory( + schema.LDAPAuthenticationBackend{ + Address: testLDAPAddress, + User: "CN=Administrator,CN=Users,DC=example,DC=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + DistinguishedName: "distinguishedName", + Username: "sAMAccountName", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + GroupName: "cn", + }, + GroupSearchMode: "memberof", + UsersFilter: "sAMAccountName={input}", + GroupsFilter: "(|{memberof:dn})", + AdditionalUsersDN: "CN=users", + BaseDN: "DC=example,DC=com", + }, + false, + nil, + mockFactory) + + dialURL := mockFactory.EXPECT(). + DialURL(gomock.Eq("ldap://127.0.0.1:389"), gomock.Any()). + Return(mockClient, nil) + + connBind := mockClient.EXPECT(). + Bind(gomock.Eq("CN=Administrator,CN=Users,DC=example,DC=com"), gomock.Eq("password")). + Return(nil) + + connClose := mockClient.EXPECT().Close() + + requestGroups := ldap.NewSearchRequest( + provider.groupsBaseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, + 0, 0, false, "(|(distinguishedName=CN=admins,OU=groups,DC=example,DC=com)(distinguishedName=CN=users,OU=groups,DC=example,DC=com))", provider.groupsAttributes, nil, + ) + + searchGroups := mockClient.EXPECT(). + Search(requestGroups). + Return(createGroupSearchResultModeFilterWithDN(provider.config.Attributes.GroupName, []string{"admins", "admins", "users"}, []string{"CN=admins,OU=groups,DC=example,DC=com", "CN=admins,OU=wronggroups,DC=example,DC=com", "CN=users,OU=groups,DC=example,DC=com"}), nil) searchProfile := mockClient.EXPECT(). Search(gomock.Any()). Return(&ldap.SearchResult{ - Entries: []*ldap.Entry{}, - Referrals: []string{"ldap://192.168.2.1"}, + Entries: []*ldap.Entry{ + { + DN: "uid=test,dc=example,dc=com", + Attributes: []*ldap.EntryAttribute{ + { + Name: "displayName", + Values: []string{"John Doe"}, + }, + { + Name: "mail", + Values: []string{"test@example.com"}, + }, + { + Name: "sAMAccountName", + Values: []string{"John"}, + }, + { + Name: "memberOf", + Values: []string{"CN=admins,OU=groups,DC=example,DC=com", "CN=users,OU=groups,DC=example,DC=com"}, + }, + }, + }, + }, }, nil) - dialURLReferral := mockFactory.EXPECT(). - DialURL(gomock.Eq("ldap://192.168.2.1"), gomock.Any()). - Return(mockClientReferral, nil) + gomock.InOrder(dialURL, connBind, searchProfile, searchGroups, connClose) - connBindReferral := mockClientReferral.EXPECT(). + details, err := provider.GetDetails("john") + require.NoError(t, err) + + assert.ElementsMatch(t, details.Groups, []string{"admins", "users"}) + assert.ElementsMatch(t, details.Emails, []string{"test@example.com"}) + assert.Equal(t, details.DisplayName, "John Doe") + assert.Equal(t, details.Username, "John") +} + +func TestShouldReturnErrSearchMemberOf(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockFactory := NewMockLDAPClientFactory(ctrl) + mockClient := NewMockLDAPClient(ctrl) + + provider := NewLDAPUserProviderWithFactory( + schema.LDAPAuthenticationBackend{ + Address: testLDAPAddress, + User: "CN=Administrator,CN=Users,DC=example,DC=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + DistinguishedName: "distinguishedName", + Username: "sAMAccountName", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + GroupName: "cn", + }, + GroupSearchMode: "memberof", + UsersFilter: "sAMAccountName={input}", + GroupsFilter: "(|{memberof:dn})", + AdditionalUsersDN: "CN=users", + BaseDN: "DC=example,DC=com", + }, + false, + nil, + mockFactory) + + dialURL := mockFactory.EXPECT(). + DialURL(gomock.Eq("ldap://127.0.0.1:389"), gomock.Any()). + Return(mockClient, nil) + + connBind := mockClient.EXPECT(). + Bind(gomock.Eq("CN=Administrator,CN=Users,DC=example,DC=com"), gomock.Eq("password")). + Return(nil) + + connClose := mockClient.EXPECT().Close() + + requestGroups := ldap.NewSearchRequest( + provider.groupsBaseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, + 0, 0, false, "(|(distinguishedName=CN=admins,OU=groups,DC=example,DC=com)(distinguishedName=CN=users,OU=groups,DC=example,DC=com))", provider.groupsAttributes, nil, + ) + + searchGroups := mockClient.EXPECT(). + Search(requestGroups). + Return(nil, fmt.Errorf("failed to get groups")) + + searchProfile := mockClient.EXPECT(). + Search(gomock.Any()). + Return(&ldap.SearchResult{ + Entries: []*ldap.Entry{ + { + DN: "uid=test,dc=example,dc=com", + Attributes: []*ldap.EntryAttribute{ + { + Name: "displayName", + Values: []string{"John Doe"}, + }, + { + Name: "mail", + Values: []string{"test@example.com"}, + }, + { + Name: "sAMAccountName", + Values: []string{"John"}, + }, + { + Name: "memberOf", + Values: []string{"CN=admins,OU=groups,DC=example,DC=com", "CN=users,OU=groups,DC=example,DC=com"}, + }, + }, + }, + }, + }, nil) + + gomock.InOrder(dialURL, connBind, searchProfile, searchGroups, connClose) + + details, err := provider.GetDetails("john") + assert.Nil(t, details) + assert.EqualError(t, err, "unable to retrieve groups of user 'john'. Cause: failed to get groups") +} + +func TestShouldReturnErrUnknownSearchMode(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockFactory := NewMockLDAPClientFactory(ctrl) + mockClient := NewMockLDAPClient(ctrl) + + provider := NewLDAPUserProviderWithFactory( + schema.LDAPAuthenticationBackend{ + Address: testLDAPAddress, + User: "CN=Administrator,CN=Users,DC=example,DC=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + DistinguishedName: "distinguishedName", + Username: "sAMAccountName", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + GroupName: "cn", + }, + GroupSearchMode: "bad", + UsersFilter: "sAMAccountName={input}", + GroupsFilter: "(|{memberof:dn})", + AdditionalUsersDN: "CN=users", + BaseDN: "DC=example,DC=com", + }, + false, + nil, + mockFactory) + + dialURL := mockFactory.EXPECT(). + DialURL(gomock.Eq("ldap://127.0.0.1:389"), gomock.Any()). + Return(mockClient, nil) + + connBind := mockClient.EXPECT(). + Bind(gomock.Eq("CN=Administrator,CN=Users,DC=example,DC=com"), gomock.Eq("password")). + Return(nil) + + connClose := mockClient.EXPECT().Close() + + searchProfile := mockClient.EXPECT(). + Search(gomock.Any()). + Return(&ldap.SearchResult{ + Entries: []*ldap.Entry{ + { + DN: "uid=test,dc=example,dc=com", + Attributes: []*ldap.EntryAttribute{ + { + Name: "displayName", + Values: []string{"John Doe"}, + }, + { + Name: "mail", + Values: []string{"test@example.com"}, + }, + { + Name: "sAMAccountName", + Values: []string{"John"}, + }, + { + Name: "memberOf", + Values: []string{"CN=admins,OU=groups,DC=example,DC=com", "CN=users,OU=groups,DC=example,DC=com"}, + }, + }, + }, + }, + }, nil) + + gomock.InOrder(dialURL, connBind, searchProfile, connClose) + + details, err := provider.GetDetails("john") + assert.Nil(t, details) + + assert.EqualError(t, err, "could not perform group search with mode 'bad' as it's unknown") +} + +func TestShouldSkipEmptyAttributesSearchModeMemberOf(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockFactory := NewMockLDAPClientFactory(ctrl) + mockClient := NewMockLDAPClient(ctrl) + + provider := NewLDAPUserProviderWithFactory( + schema.LDAPAuthenticationBackend{ + Address: testLDAPAddress, + User: "CN=Administrator,CN=Users,DC=example,DC=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + DistinguishedName: "distinguishedName", + Username: "sAMAccountName", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + GroupName: "cn", + }, + GroupSearchMode: "memberof", + UsersFilter: "sAMAccountName={input}", + GroupsFilter: "(|{memberof:dn})", + AdditionalUsersDN: "CN=users", + BaseDN: "DC=example,DC=com", + }, + false, + nil, + mockFactory) + + dialURL := mockFactory.EXPECT(). + DialURL(gomock.Eq("ldap://127.0.0.1:389"), gomock.Any()). + Return(mockClient, nil) + + connBind := mockClient.EXPECT(). + Bind(gomock.Eq("CN=Administrator,CN=Users,DC=example,DC=com"), gomock.Eq("password")). + Return(nil) + + connClose := mockClient.EXPECT().Close() + + searchProfile := mockClient.EXPECT(). + Search(gomock.Any()). + Return(&ldap.SearchResult{ + Entries: []*ldap.Entry{ + { + DN: "uid=test,dc=example,dc=com", + Attributes: []*ldap.EntryAttribute{ + { + Name: "displayName", + Values: []string{"John Doe"}, + }, + { + Name: "mail", + Values: []string{"test@example.com"}, + }, + { + Name: "sAMAccountName", + Values: []string{"John"}, + }, + { + Name: "memberOf", + Values: []string{"CN=admins,OU=groups,DC=example,DC=com", "CN=users,OU=groups,DC=example,DC=com", "CN=multi,OU=groups,DC=example,DC=com"}, + }, + }, + }, + }, + }, nil) + + searchGroups := mockClient.EXPECT(). + Search(gomock.Any()). + Return(&ldap.SearchResult{ + Entries: []*ldap.Entry{ + { + DN: "uid=grp,dc=example,dc=com", + Attributes: []*ldap.EntryAttribute{}, + }, + { + DN: "CN=users,OU=groups,DC=example,DC=com", + Attributes: []*ldap.EntryAttribute{ + { + Name: "cn", + Values: []string{}, + }, + }, + }, + { + DN: "CN=admins,OU=groups,DC=example,DC=com", + Attributes: []*ldap.EntryAttribute{ + { + Name: "cn", + Values: []string{""}, + }, + }, + }, + { + DN: "CN=multi,OU=groups,DC=example,DC=com", + Attributes: []*ldap.EntryAttribute{ + { + Name: "cn", + Values: []string{"a", "b"}, + }, + }, + }, + }, + }, nil) + + gomock.InOrder(dialURL, connBind, searchProfile, searchGroups, connClose) + + details, err := provider.GetDetails("john") + + assert.NoError(t, err) + assert.NotNil(t, details) +} + +func TestShouldSkipEmptyAttributesSearchModeFilter(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockFactory := NewMockLDAPClientFactory(ctrl) + mockClient := NewMockLDAPClient(ctrl) + + provider := NewLDAPUserProviderWithFactory( + schema.LDAPAuthenticationBackend{ + Address: testLDAPAddress, + User: "CN=Administrator,CN=Users,DC=example,DC=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + DistinguishedName: "distinguishedName", + Username: "sAMAccountName", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + GroupName: "cn", + }, + GroupSearchMode: "filter", + UsersFilter: "sAMAccountName={input}", + GroupsFilter: "(|{memberof:dn})", + AdditionalUsersDN: "CN=users", + BaseDN: "DC=example,DC=com", + }, + false, + nil, + mockFactory) + + dialURL := mockFactory.EXPECT(). + DialURL(gomock.Eq("ldap://127.0.0.1:389"), gomock.Any()). + Return(mockClient, nil) + + connBind := mockClient.EXPECT(). + Bind(gomock.Eq("CN=Administrator,CN=Users,DC=example,DC=com"), gomock.Eq("password")). + Return(nil) + + connClose := mockClient.EXPECT().Close() + + searchProfile := mockClient.EXPECT(). + Search(gomock.Any()). + Return(&ldap.SearchResult{ + Entries: []*ldap.Entry{ + { + DN: "uid=test,dc=example,dc=com", + Attributes: []*ldap.EntryAttribute{ + { + Name: "displayName", + Values: []string{"John Doe"}, + }, + { + Name: "mail", + Values: []string{"test@example.com"}, + }, + { + Name: "sAMAccountName", + Values: []string{"John"}, + }, + { + Name: "memberOf", + Values: []string{"CN=admins,OU=groups,DC=example,DC=com", "CN=users,OU=groups,DC=example,DC=com", "CN=multi,OU=groups,DC=example,DC=com"}, + }, + }, + }, + }, + }, nil) + + searchGroups := mockClient.EXPECT(). + Search(gomock.Any()). + Return(&ldap.SearchResult{ + Entries: []*ldap.Entry{ + { + DN: "uid=grp,dc=example,dc=com", + Attributes: []*ldap.EntryAttribute{}, + }, + { + DN: "CN=users,OU=groups,DC=example,DC=com", + Attributes: []*ldap.EntryAttribute{ + { + Name: "cn", + Values: []string{}, + }, + }, + }, + { + DN: "CN=admins,OU=groups,DC=example,DC=com", + Attributes: []*ldap.EntryAttribute{ + { + Name: "cn", + Values: []string{""}, + }, + }, + }, + { + DN: "CN=multi,OU=groups,DC=example,DC=com", + Attributes: []*ldap.EntryAttribute{ + { + Name: "cn", + Values: []string{"a", "b"}, + }, + }, + }, + }, + }, nil) + + gomock.InOrder(dialURL, connBind, searchProfile, searchGroups, connClose) + + details, err := provider.GetDetails("john") + + assert.NoError(t, err) + assert.NotNil(t, details) +} + +func TestShouldSkipEmptyGroupsResultMemberOf(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockFactory := NewMockLDAPClientFactory(ctrl) + mockClient := NewMockLDAPClient(ctrl) + + provider := NewLDAPUserProviderWithFactory( + schema.LDAPAuthenticationBackend{ + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + GroupName: "cn", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", + PermitReferrals: true, + }, + false, + nil, + mockFactory) + + dialURL := mockFactory.EXPECT(). + DialURL(gomock.Eq("ldap://127.0.0.1:389"), gomock.Any()). + Return(mockClient, nil) + + connBind := mockClient.EXPECT(). Bind(gomock.Eq("cn=admin,dc=example,dc=com"), gomock.Eq("password")). Return(nil) - connCloseReferral := mockClientReferral.EXPECT().Close() + connClose := mockClient.EXPECT().Close() - searchProfileReferral := mockClientReferral.EXPECT(). + searchGroups := mockClient.EXPECT(). + Search(gomock.Any()). + Return(&ldap.SearchResult{ + Entries: []*ldap.Entry{ + {}, + }, + }, nil) + + searchProfile := mockClient.EXPECT(). Search(gomock.Any()). Return(&ldap.SearchResult{ Entries: []*ldap.Entry{ @@ -1099,12 +2126,11 @@ func TestShouldReturnUsernameFromLDAPWithReferrals(t *testing.T) { }, }, nil) - gomock.InOrder(dialURL, connBind, searchProfile, dialURLReferral, connBindReferral, searchProfileReferral, connCloseReferral, searchGroups, connClose) + gomock.InOrder(dialURL, connBind, searchProfile, searchGroups, connClose) details, err := provider.GetDetails("john") require.NoError(t, err) - assert.ElementsMatch(t, details.Groups, []string{"group1", "group2"}) assert.ElementsMatch(t, details.Emails, []string{"test@example.com"}) assert.Equal(t, details.DisplayName, "John Doe") assert.Equal(t, details.Username, "John") @@ -1121,16 +2147,20 @@ func TestShouldReturnUsernameFromLDAPWithReferralsInErrorAndResult(t *testing.T) provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "uid={input}", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", - PermitReferrals: true, + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + GroupName: "cn", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", + PermitReferrals: true, }, false, nil, @@ -1148,17 +2178,17 @@ func TestShouldReturnUsernameFromLDAPWithReferralsInErrorAndResult(t *testing.T) searchGroups := mockClient.EXPECT(). Search(gomock.Any()). - Return(createSearchResultWithAttributeValues("group1", "group2"), nil) + Return(createGroupSearchResultModeFilter(provider.config.Attributes.GroupName, "group1", "group2"), nil) searchProfile := mockClient.EXPECT(). Search(gomock.Any()). Return(&ldap.SearchResult{ Entries: []*ldap.Entry{}, - Referrals: []string{"ldap://192.168.2.1"}, + Referrals: []string{"ldap://192.168.0.1"}, }, &ldap.Error{ResultCode: ldap.LDAPResultReferral, Err: errors.New("referral"), Packet: &testBERPacketReferral}) dialURLReferral := mockFactory.EXPECT(). - DialURL(gomock.Eq("ldap://192.168.2.1"), gomock.Any()). + DialURL(gomock.Eq("ldap://192.168.0.1"), gomock.Any()). Return(mockClientReferral, nil) connBindReferral := mockClientReferral.EXPECT(). @@ -1236,6 +2266,266 @@ func TestShouldReturnUsernameFromLDAPWithReferralsInErrorAndResult(t *testing.T) assert.Equal(t, details.Username, "John") } +func TestShouldReturnUsernameFromLDAPWithReferralsInErrorAndNoResult(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockFactory := NewMockLDAPClientFactory(ctrl) + mockClient := NewMockLDAPClient(ctrl) + mockClientReferral := NewMockLDAPClient(ctrl) + + provider := NewLDAPUserProviderWithFactory( + schema.LDAPAuthenticationBackend{ + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + GroupName: "cn", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", + PermitReferrals: true, + }, + false, + nil, + mockFactory) + + dialURL := mockFactory.EXPECT(). + DialURL(gomock.Eq("ldap://127.0.0.1:389"), gomock.Any()). + Return(mockClient, nil) + + connBind := mockClient.EXPECT(). + Bind(gomock.Eq("cn=admin,dc=example,dc=com"), gomock.Eq("password")). + Return(nil) + + connClose := mockClient.EXPECT().Close() + + searchGroups := mockClient.EXPECT(). + Search(gomock.Any()). + Return(createGroupSearchResultModeFilter(provider.config.Attributes.GroupName, "group1", "group2"), nil) + + searchProfile := mockClient.EXPECT(). + Search(gomock.Any()). + Return(nil, &ldap.Error{ResultCode: ldap.LDAPResultReferral, Err: errors.New("referral"), Packet: &testBERPacketReferral}) + + dialURLReferral := mockFactory.EXPECT(). + DialURL(gomock.Eq("ldap://192.168.0.1"), gomock.Any()). + Return(mockClientReferral, nil) + + connBindReferral := mockClientReferral.EXPECT(). + Bind(gomock.Eq("cn=admin,dc=example,dc=com"), gomock.Eq("password")). + Return(nil) + + connCloseReferral := mockClientReferral.EXPECT().Close() + + searchProfileReferral := mockClientReferral.EXPECT(). + Search(gomock.Any()). + Return(&ldap.SearchResult{ + Entries: []*ldap.Entry{ + { + DN: "uid=test,dc=example,dc=com", + Attributes: []*ldap.EntryAttribute{ + { + Name: "displayName", + Values: []string{"John Doe"}, + }, + { + Name: "mail", + Values: []string{"test@example.com"}, + }, + { + Name: "uid", + Values: []string{"John"}, + }, + }, + }, + }, + }, nil) + + gomock.InOrder(dialURL, connBind, searchProfile, dialURLReferral, connBindReferral, searchProfileReferral, connCloseReferral, searchGroups, connClose) + + details, err := provider.GetDetails("john") + require.NoError(t, err) + + assert.ElementsMatch(t, details.Groups, []string{"group1", "group2"}) + assert.ElementsMatch(t, details.Emails, []string{"test@example.com"}) + assert.Equal(t, details.DisplayName, "John Doe") + assert.Equal(t, details.Username, "John") +} + +func TestShouldReturnDialErrDuringReferralSearchUsernameFromLDAPWithReferralsInErrorAndNoResult(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockFactory := NewMockLDAPClientFactory(ctrl) + mockClient := NewMockLDAPClient(ctrl) + + provider := NewLDAPUserProviderWithFactory( + schema.LDAPAuthenticationBackend{ + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + GroupName: "cn", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", + PermitReferrals: true, + }, + false, + nil, + mockFactory) + + dialURL := mockFactory.EXPECT(). + DialURL(gomock.Eq("ldap://127.0.0.1:389"), gomock.Any()). + Return(mockClient, nil) + + connBind := mockClient.EXPECT(). + Bind(gomock.Eq("cn=admin,dc=example,dc=com"), gomock.Eq("password")). + Return(nil) + + connClose := mockClient.EXPECT().Close() + + searchProfile := mockClient.EXPECT(). + Search(gomock.Any()). + Return(nil, &ldap.Error{ResultCode: ldap.LDAPResultReferral, Err: errors.New("referral"), Packet: &testBERPacketReferral}) + + dialURLReferral := mockFactory.EXPECT(). + DialURL(gomock.Eq("ldap://192.168.0.1"), gomock.Any()). + Return(nil, fmt.Errorf("failed to connect")) + + gomock.InOrder(dialURL, connBind, searchProfile, dialURLReferral, connClose) + + details, err := provider.GetDetails("john") + + assert.Nil(t, details) + assert.EqualError(t, err, "cannot find user DN of user 'john'. Cause: error occurred connecting to referred LDAP server 'ldap://192.168.0.1': dial failed with error: failed to connect") +} + +func TestShouldReturnSearchErrDuringReferralSearchUsernameFromLDAPWithReferralsInErrorAndNoResult(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockFactory := NewMockLDAPClientFactory(ctrl) + mockClient := NewMockLDAPClient(ctrl) + mockClientReferral := NewMockLDAPClient(ctrl) + + provider := NewLDAPUserProviderWithFactory( + schema.LDAPAuthenticationBackend{ + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + GroupName: "cn", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", + PermitReferrals: true, + }, + false, + nil, + mockFactory) + + dialURL := mockFactory.EXPECT(). + DialURL(gomock.Eq("ldap://127.0.0.1:389"), gomock.Any()). + Return(mockClient, nil) + + connBind := mockClient.EXPECT(). + Bind(gomock.Eq("cn=admin,dc=example,dc=com"), gomock.Eq("password")). + Return(nil) + + connClose := mockClient.EXPECT().Close() + + searchProfile := mockClient.EXPECT(). + Search(gomock.Any()). + Return(nil, &ldap.Error{ResultCode: ldap.LDAPResultReferral, Err: errors.New("referral"), Packet: &testBERPacketReferral}) + + dialURLReferral := mockFactory.EXPECT(). + DialURL(gomock.Eq("ldap://192.168.0.1"), gomock.Any()). + Return(mockClientReferral, nil) + + connBindReferral := mockClientReferral.EXPECT(). + Bind(gomock.Eq("cn=admin,dc=example,dc=com"), gomock.Eq("password")). + Return(nil) + + connCloseReferral := mockClientReferral.EXPECT().Close() + + searchProfileReferral := mockClientReferral.EXPECT(). + Search(gomock.Any()). + Return(nil, fmt.Errorf("not found")) + + gomock.InOrder(dialURL, connBind, searchProfile, dialURLReferral, connBindReferral, searchProfileReferral, connCloseReferral, connClose) + + details, err := provider.GetDetails("john") + + assert.Nil(t, details) + assert.EqualError(t, err, "cannot find user DN of user 'john'. Cause: error occurred performing search on referred LDAP server 'ldap://192.168.0.1': not found") +} + +func TestShouldNotReturnUsernameFromLDAPWithReferralsInErrorAndReferralsNotPermitted(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockFactory := NewMockLDAPClientFactory(ctrl) + mockClient := NewMockLDAPClient(ctrl) + + provider := NewLDAPUserProviderWithFactory( + schema.LDAPAuthenticationBackend{ + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + GroupName: "cn", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", + PermitReferrals: false, + }, + false, + nil, + mockFactory) + + dialURL := mockFactory.EXPECT(). + DialURL(gomock.Eq("ldap://127.0.0.1:389"), gomock.Any()). + Return(mockClient, nil) + + connBind := mockClient.EXPECT(). + Bind(gomock.Eq("cn=admin,dc=example,dc=com"), gomock.Eq("password")). + Return(nil) + + connClose := mockClient.EXPECT().Close() + + searchProfile := mockClient.EXPECT(). + Search(gomock.Any()). + Return(nil, &ldap.Error{ResultCode: ldap.LDAPResultReferral, Err: errors.New("referral"), Packet: &testBERPacketReferral}) + + gomock.InOrder(dialURL, connBind, searchProfile, connClose) + + details, err := provider.GetDetails("john") + assert.EqualError(t, err, "cannot find user DN of user 'john'. Cause: LDAP Result Code 10 \"Referral\": referral") + assert.Nil(t, details) +} + func TestShouldReturnUsernameFromLDAPWithReferralsErr(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() @@ -1246,16 +2536,20 @@ func TestShouldReturnUsernameFromLDAPWithReferralsErr(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "uid={input}", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", - PermitReferrals: true, + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + GroupName: "cn", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", + PermitReferrals: true, }, false, nil, @@ -1273,7 +2567,7 @@ func TestShouldReturnUsernameFromLDAPWithReferralsErr(t *testing.T) { searchGroups := mockClient.EXPECT(). Search(gomock.Any()). - Return(createSearchResultWithAttributeValues("group1", "group2"), nil) + Return(createGroupSearchResultModeFilter(provider.config.Attributes.GroupName, "group1", "group2"), nil) searchProfile := mockClient.EXPECT(). Search(gomock.Any()). @@ -1333,16 +2627,19 @@ func TestShouldNotUpdateUserPasswordConnect(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "uid={input}", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", - PermitReferrals: false, + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", + PermitReferrals: false, }, false, nil, @@ -1400,16 +2697,19 @@ func TestShouldNotUpdateUserPasswordGetDetails(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "uid={input}", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", - PermitReferrals: false, + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", + PermitReferrals: false, }, false, nil, @@ -1477,15 +2777,18 @@ func TestShouldUpdateUserPassword(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "uid={input}", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", }, false, nil, @@ -1584,16 +2887,19 @@ func TestShouldUpdateUserPasswordMSAD(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Implementation: "activedirectory", - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "uid={input}", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", + Implementation: "activedirectory", + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", }, false, nil, @@ -1694,17 +3000,20 @@ func TestShouldUpdateUserPasswordMSADWithReferrals(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Implementation: "activedirectory", - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "uid={input}", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", - PermitReferrals: true, + Implementation: "activedirectory", + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", + PermitReferrals: true, }, false, nil, @@ -1822,17 +3131,20 @@ func TestShouldUpdateUserPasswordMSADWithReferralsWithReferralConnectErr(t *test provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Implementation: "activedirectory", - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "uid={input}", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", - PermitReferrals: true, + Implementation: "activedirectory", + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", + PermitReferrals: true, }, false, nil, @@ -1941,17 +3253,20 @@ func TestShouldUpdateUserPasswordMSADWithReferralsWithReferralModifyErr(t *testi provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Implementation: "activedirectory", - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "uid={input}", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", - PermitReferrals: true, + Implementation: "activedirectory", + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", + PermitReferrals: true, }, false, nil, @@ -2073,17 +3388,20 @@ func TestShouldUpdateUserPasswordMSADWithoutReferrals(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Implementation: "activedirectory", - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "uid={input}", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", - PermitReferrals: false, + Implementation: "activedirectory", + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", + PermitReferrals: false, }, false, nil, @@ -2187,15 +3505,18 @@ func TestShouldUpdateUserPasswordPasswdModifyExtension(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "uid={input}", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", }, false, nil, @@ -2294,16 +3615,19 @@ func TestShouldUpdateUserPasswordPasswdModifyExtensionWithReferrals(t *testing.T provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "uid={input}", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", - PermitReferrals: true, + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", + PermitReferrals: true, }, false, nil, @@ -2421,16 +3745,19 @@ func TestShouldUpdateUserPasswordPasswdModifyExtensionWithoutReferrals(t *testin provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "uid={input}", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", - PermitReferrals: false, + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", + PermitReferrals: false, }, false, nil, @@ -2534,16 +3861,19 @@ func TestShouldUpdateUserPasswordPasswdModifyExtensionWithReferralsReferralConne provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "uid={input}", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", - PermitReferrals: true, + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", + PermitReferrals: true, }, false, nil, @@ -2652,16 +3982,19 @@ func TestShouldUpdateUserPasswordPasswdModifyExtensionWithReferralsReferralPassw provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "uid={input}", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", - PermitReferrals: true, + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", + PermitReferrals: true, }, false, nil, @@ -2783,16 +4116,20 @@ func TestShouldUpdateUserPasswordActiveDirectoryWithServerPolicyHints(t *testing provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Implementation: "activedirectory", - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "sAMAccountName", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "cn={input}", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", + Implementation: "activedirectory", + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + DistinguishedName: "distinguishedName", + Username: "sAMAccountName", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "cn={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", }, false, nil, @@ -2894,16 +4231,20 @@ func TestShouldUpdateUserPasswordActiveDirectoryWithServerPolicyHintsDeprecated( provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Implementation: "activedirectory", - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "sAMAccountName", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "cn={input}", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", + Implementation: "activedirectory", + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + DistinguishedName: "distinguishedName", + Username: "sAMAccountName", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "cn={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", }, false, nil, @@ -3005,16 +4346,20 @@ func TestShouldUpdateUserPasswordActiveDirectory(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Implementation: "activedirectory", - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "sAMAccountName", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "cn={input}", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", + Implementation: "activedirectory", + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + DistinguishedName: "distinguishedName", + Username: "sAMAccountName", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "cn={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", }, false, nil, @@ -3116,16 +4461,19 @@ func TestShouldUpdateUserPasswordBasic(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Implementation: "custom", - Address: testLDAPAddress, - User: "uid=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "uid={input}", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", + Implementation: "custom", + Address: testLDAPAddress, + User: "uid=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", }, false, nil, @@ -3224,15 +4572,18 @@ func TestShouldReturnErrorWhenMultipleUsernameAttributes(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "uid={input}", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", }, false, nil, @@ -3290,15 +4641,18 @@ func TestShouldReturnErrorWhenZeroUsernameAttributes(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "uid={input}", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", }, false, nil, @@ -3356,15 +4710,18 @@ func TestShouldReturnErrorWhenUsernameAttributeNotReturned(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "uid={input}", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", }, false, nil, @@ -3418,15 +4775,18 @@ func TestShouldReturnErrorWhenMultipleUsersFound(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "(|(uid={input})(uid=*))", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "(|(uid={input})(uid=*))", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", }, false, nil, @@ -3501,15 +4861,18 @@ func TestShouldReturnErrorWhenNoDN(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "(|(uid={input})(uid=*))", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "(|(uid={input})(uid=*))", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", }, false, nil, @@ -3567,15 +4930,18 @@ func TestShouldCheckValidUserPassword(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "uid={input}", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", }, false, nil, @@ -3635,15 +5001,18 @@ func TestShouldNotCheckValidUserPasswordWithConnectError(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "uid={input}", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", }, false, nil, @@ -3665,6 +5034,51 @@ func TestShouldNotCheckValidUserPasswordWithConnectError(t *testing.T) { assert.EqualError(t, err, "bind failed with error: LDAP Result Code 49 \"Invalid Credentials\": invalid username or password") } +func TestShouldNotCheckValidUserPasswordWithGetProfileError(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + mockFactory := NewMockLDAPClientFactory(ctrl) + mockClient := NewMockLDAPClient(ctrl) + + provider := NewLDAPUserProviderWithFactory( + schema.LDAPAuthenticationBackend{ + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", + }, + false, + nil, + mockFactory) + + gomock.InOrder( + mockFactory.EXPECT(). + DialURL(gomock.Eq("ldap://127.0.0.1:389"), gomock.Any()). + Return(mockClient, nil), + mockClient.EXPECT(). + Bind(gomock.Eq("cn=admin,dc=example,dc=com"), gomock.Eq("password")). + Return(nil), + mockClient.EXPECT(). + Search(gomock.Any()). + Return(nil, &ldap.Error{ResultCode: ldap.LDAPResultBusy, Err: errors.New("directory server busy")}), + mockClient.EXPECT().Close(), + ) + + valid, err := provider.CheckUserPassword("john", "password") + + assert.False(t, valid) + assert.EqualError(t, err, "cannot find user DN of user 'john'. Cause: LDAP Result Code 51 \"Busy\": directory server busy") +} + func TestShouldCheckInvalidUserPassword(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() @@ -3674,15 +5088,18 @@ func TestShouldCheckInvalidUserPassword(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "uid={input}", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", }, false, nil, @@ -3742,16 +5159,20 @@ func TestShouldCallStartTLSWhenEnabled(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "uid={input}", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", - StartTLS: true, + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + GroupName: "cn", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", + StartTLS: true, }, false, nil, @@ -3817,18 +5238,21 @@ func TestShouldParseDynamicConfiguration(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "(&(|({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})(accountExpires>={date-time:generalized})))", - GroupsFilter: "(&(|(member={dn})(member={input})(member={username}))(objectClass=group))", - AdditionalUsersDN: "ou=users", - AdditionalGroupsDN: "ou=groups", - BaseDN: "dc=example,dc=com", - StartTLS: true, + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "(&(|({username_attribute}={input})({mail_attribute}={input}))(sAMAccountType=805306368)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(!(pwdLastSet=0))(|(!(accountExpires=*))(accountExpires=0)(accountExpiresM>={date-time:microsoft-nt})(accountExpiresU>={date-time:unix})(accountExpiresG>={date-time:generalized})))", + GroupsFilter: "(&(|(member={dn})(member={input})(member={username}))(objectClass=group))", + AdditionalUsersDN: "ou=users", + AdditionalGroupsDN: "ou=groups", + BaseDN: "dc=example,dc=com", + StartTLS: true, }, false, nil, @@ -3848,12 +5272,12 @@ func TestShouldParseDynamicConfiguration(t *testing.T) { assert.True(t, provider.usersFilterReplacementDateTimeGeneralized) assert.True(t, provider.usersFilterReplacementDateTimeMicrosoftNTTimeEpoch) - assert.Equal(t, "(&(|(uid={input})(mail={input}))(sAMAccountType=805306368)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(!(pwdLastSet=0))(|(!(accountExpires=*))(accountExpires=0)(accountExpires>={date-time:microsoft-nt})(accountExpires>={date-time:generalized})))", provider.config.UsersFilter) + assert.Equal(t, "(&(|(uid={input})(mail={input}))(sAMAccountType=805306368)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(!(pwdLastSet=0))(|(!(accountExpires=*))(accountExpires=0)(accountExpiresM>={date-time:microsoft-nt})(accountExpiresU>={date-time:unix})(accountExpiresG>={date-time:generalized})))", provider.config.UsersFilter) assert.Equal(t, "(&(|(member={dn})(member={input})(member={username}))(objectClass=group))", provider.config.GroupsFilter) assert.Equal(t, "ou=users,dc=example,dc=com", provider.usersBaseDN) assert.Equal(t, "ou=groups,dc=example,dc=com", provider.groupsBaseDN) - assert.Equal(t, "(&(|(uid=test@example.com)(mail=test@example.com))(sAMAccountType=805306368)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(!(pwdLastSet=0))(|(!(accountExpires=*))(accountExpires=0)(accountExpires>=133147241190000000)(accountExpires>=20221205142839.0Z)))", provider.resolveUsersFilter("test@example.com")) + assert.Equal(t, "(&(|(uid=test@example.com)(mail=test@example.com))(sAMAccountType=805306368)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(!(pwdLastSet=0))(|(!(accountExpires=*))(accountExpires=0)(accountExpiresM>=133147241190000000)(accountExpiresU>=1670250519)(accountExpiresG>=20221205142839.0Z)))", provider.resolveUsersFilter("test@example.com")) assert.Equal(t, "(&(|(member=cn=admin,dc=example,dc=com)(member=test@example.com)(member=test))(objectClass=group))", provider.resolveGroupsFilter("test@example.com", &ldapUserProfile{Username: "test", DN: "cn=admin,dc=example,dc=com"})) } @@ -3866,16 +5290,20 @@ func TestShouldCallStartTLSWithInsecureSkipVerifyWhenSkipVerifyTrue(t *testing.T provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "uid={input}", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", - StartTLS: true, + Address: testLDAPAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + GroupName: "cn", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", + StartTLS: true, TLS: &schema.TLSConfig{ SkipVerify: true, }, @@ -3924,6 +5352,10 @@ func TestShouldCallStartTLSWithInsecureSkipVerifyWhenSkipVerifyTrue(t *testing.T Name: "uid", Values: []string{"john"}, }, + { + Name: "memberOf", + Values: []string{"CN=example,DC=corp,DC=com"}, + }, }, }, }, @@ -3949,16 +5381,19 @@ func TestShouldReturnLDAPSAlreadySecuredWhenStartTLSAttempted(t *testing.T) { provider := NewLDAPUserProviderWithFactory( schema.LDAPAuthenticationBackend{ - Address: testLDAPSAddress, - User: "cn=admin,dc=example,dc=com", - Password: "password", - UsernameAttribute: "uid", - MailAttribute: "mail", - DisplayNameAttribute: "displayName", - UsersFilter: "uid={input}", - AdditionalUsersDN: "ou=users", - BaseDN: "dc=example,dc=com", - StartTLS: true, + Address: testLDAPSAddress, + User: "cn=admin,dc=example,dc=com", + Password: "password", + Attributes: schema.LDAPAuthenticationAttributes{ + Username: "uid", + Mail: "mail", + DisplayName: "displayName", + MemberOf: "memberOf", + }, + UsersFilter: "uid={input}", + AdditionalUsersDN: "ou=users", + BaseDN: "dc=example,dc=com", + StartTLS: true, TLS: &schema.TLSConfig{ SkipVerify: true, }, |
