From 47af38c52ff484dad4364e39ff0ccbf624c4c0ff Mon Sep 17 00:00:00 2001 From: Helen Fu <25168806+helenfufu@users.noreply.github.com> Date: Fri, 3 Jan 2025 10:54:59 -0600 Subject: [PATCH 1/5] ensure one result entry in getUserDN --- ldap/client.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ldap/client.go b/ldap/client.go index 0c1ffd3..707e89b 100644 --- a/ldap/client.go +++ b/ldap/client.go @@ -736,9 +736,10 @@ func (c *Client) getUserDN(bindDN, username string) (string, error) { if err != nil { return userDN, fmt.Errorf("%s: LDAP search failed for detecting user (baseDN: %q / filter: %q): %w", op, c.conf.UserDN, filter, err) } - for _, e := range result.Entries { - userDN = e.DN + if len(result.Entries) != 1 { + return "", fmt.Errorf("%s: LDAP search for user 0 or not unique", op) } + userDN = result.Entries[0].DN } else { userDN = bindDN } From 32d34d3d0d6d1f27a02f0affca90559ff7fb0e25 Mon Sep 17 00:00:00 2001 From: Helen Fu <25168806+helenfufu@users.noreply.github.com> Date: Fri, 3 Jan 2025 14:27:38 -0600 Subject: [PATCH 2/5] add failed-with-anon-bind-upn-domain-multiple-users-returned test case to TestClient_Authenticate --- ldap/client_exported_test.go | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/ldap/client_exported_test.go b/ldap/client_exported_test.go index d795f52..0c98b55 100644 --- a/ldap/client_exported_test.go +++ b/ldap/client_exported_test.go @@ -23,6 +23,8 @@ func TestClient_Authenticate(t *testing.T) { Name: "test-logger", Level: hclog.Error, }) + + // Set up test directory td := testdirectory.Start(t, testdirectory.WithDefaults(t, &testdirectory.Defaults{AllowAnonymousBind: true}), testdirectory.WithLogger(t, logger), @@ -59,6 +61,21 @@ func TestClient_Authenticate(t *testing.T) { td.SetUsers(users...) td.SetGroups(groups...) td.SetTokenGroups(tokenGroups) + + // Set up test directory with duplicate users. This directory is used to test that we error when multiple users are found. + duplicatedUsers := append([]*gldap.Entry{}, users...) + duplicatedUsers = append( + duplicatedUsers, + users..., + ) + tdWithDuplicatedUsers := testdirectory.Start(t, + testdirectory.WithDefaults(t, &testdirectory.Defaults{AllowAnonymousBind: true}), + testdirectory.WithLogger(t, logger), + ) + tdWithDuplicatedUsers.SetUsers(duplicatedUsers...) + tdWithDuplicatedUsers.SetGroups(groups...) + tdWithDuplicatedUsers.SetTokenGroups(tokenGroups) + tests := []struct { name string username string @@ -509,6 +526,22 @@ func TestClient_Authenticate(t *testing.T) { opts: []ldap.Option{ldap.WithGroups(), ldap.WithEmptyAnonymousGroupSearch()}, wantGroups: []string{groups[0].DN}, }, + { + name: "failed-with-anon-bind-upn-domain-multiple-users-returned", + username: "eve", + password: "password", + clientConfig: &ldap.ClientConfig{ + URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", tdWithDuplicatedUsers.Port())}, + Certificates: []string{tdWithDuplicatedUsers.Cert()}, + DiscoverDN: true, + UserDN: testdirectory.DefaultUserDN, + GroupDN: testdirectory.DefaultGroupDN, + UPNDomain: "example.com", + }, + opts: []ldap.Option{ldap.WithGroups()}, + wantErr: true, + wantErrContains: "LDAP search for binddn 0 or not unique", + }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { From 0d3267c952c6bbf738718cd22ee9bbfab14f47ba Mon Sep 17 00:00:00 2001 From: Helen Fu <25168806+helenfufu@users.noreply.github.com> Date: Fri, 3 Jan 2025 18:14:08 -0600 Subject: [PATCH 3/5] add unit tests for getUserDN --- ldap/client_test.go | 151 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) diff --git a/ldap/client_test.go b/ldap/client_test.go index 693c644..728bc0b 100644 --- a/ldap/client_test.go +++ b/ldap/client_test.go @@ -11,6 +11,7 @@ import ( "testing" "github.com/hashicorp/go-hclog" + "github.com/jimlambrt/gldap" "github.com/jimlambrt/gldap/testdirectory" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -456,6 +457,156 @@ func TestClient_connect(t *testing.T) { }) } +func TestClient_getUserDN(t *testing.T) { + t.Parallel() + testCtx := context.Background() + logger := hclog.New(&hclog.LoggerOptions{ + Name: "test-logger", + Level: hclog.Error, + }) + td := testdirectory.Start(nil, + testdirectory.WithDefaults(nil, &testdirectory.Defaults{AllowAnonymousBind: true}), + testdirectory.WithLogger(t, logger), + ) + users := testdirectory.NewUsers(t, []string{"alice", "bob"}) + users = append( + users, + testdirectory.NewUsers( + t, + []string{"eve"}, + testdirectory.WithDefaults(t, &testdirectory.Defaults{UPNDomain: "example.com"}))..., + ) + td.SetUsers(users...) + + duplicatedUsers := append([]*gldap.Entry{}, users...) + duplicatedUsers = append( + duplicatedUsers, + users..., + ) + tdWithDuplicatedUsers := testdirectory.Start(t, + testdirectory.WithDefaults(t, &testdirectory.Defaults{AllowAnonymousBind: true}), + testdirectory.WithLogger(t, logger), + ) + tdWithDuplicatedUsers.SetUsers(duplicatedUsers...) + + tests := map[string]struct { + conf *ClientConfig + bindDN string + username string + + want string + wantErr bool + wantErrIs error + wantErrContains string + }{ + "fail: missing bind dn": { + conf: &ClientConfig{ + URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())}, + Certificates: []string{td.Cert()}, + }, + bindDN: "", + username: "alice", + + wantErr: true, + wantErrIs: ErrInvalidParameter, + wantErrContains: "missing bind dn", + }, + "fail: missing username": { + conf: &ClientConfig{ + URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())}, + Certificates: []string{td.Cert()}, + }, + bindDN: fmt.Sprintf("%s=%s,%s", testdirectory.DefaultUserAttr, "bob", testdirectory.DefaultUserDN), + username: "", + + wantErr: true, + wantErrIs: ErrInvalidParameter, + wantErrContains: "missing username", + }, + "success: no upn domain": { + conf: &ClientConfig{ + URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())}, + Certificates: []string{td.Cert()}, + }, + bindDN: "cn=alice,ou=people,dc=example,dc=org", + username: "alice", + + want: "cn=alice,ou=people,dc=example,dc=org", + }, + "success: upn domain with samaccountname": { + conf: &ClientConfig{ + URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())}, + Certificates: []string{td.Cert()}, + UPNDomain: "example.com", + EnableSamaccountnameLogin: true, + }, + bindDN: "userPrincipalName=eve@example.com,ou=people,dc=example,dc=org", + username: "eve", + + want: "userPrincipalName=eve@example.com,ou=people,dc=example,dc=org", + }, + "success: upn domain without samaccountname": { + conf: &ClientConfig{ + URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())}, + Certificates: []string{td.Cert()}, + UPNDomain: "example.com", + }, + bindDN: "userPrincipalName=eve@example.com,ou=people,dc=example,dc=org", + username: "eve", + + want: "userPrincipalName=eve@example.com,ou=people,dc=example,dc=org", + }, + "fail: upn domain search fails to detect user": { + conf: &ClientConfig{ + URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())}, + Certificates: []string{td.Cert()}, + UPNDomain: "example.com", + }, + bindDN: "userPrincipalName=invalid-name@example.com,ou=people,dc=example,dc=org", + username: "invalid-name", + + wantErr: true, + wantErrContains: "LDAP search failed for detecting user", + }, + "fail: upn domain search returns multiple users": { + conf: &ClientConfig{ + URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", tdWithDuplicatedUsers.Port())}, + Certificates: []string{tdWithDuplicatedUsers.Cert()}, + UPNDomain: "example.com", + }, + bindDN: "userPrincipalName=eve@example.com,ou=people,dc=example,dc=org", + username: "eve", + + wantErr: true, + wantErrContains: "LDAP search for user 0 or not unique", + }, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + c, err := NewClient(testCtx, tc.conf) + require.NoError(err) + err = c.connect(testCtx) + require.NoError(err) + defer func() { c.Close(testCtx) }() + got, err := c.getUserDN(tc.bindDN, tc.username) + if tc.wantErr { + require.Error(err) + if tc.wantErrIs != nil { + assert.ErrorIs(err, tc.wantErrIs) + } + if tc.wantErrContains != "" { + assert.Contains(err.Error(), tc.wantErrContains) + } + return + } + require.NoError(err) + assert.Equal(tc.want, got) + }) + } +} + func Test_sidBytesToString(t *testing.T) { testcases := map[string][]byte{ "S-1-5-21-2127521184-1604012920-1887927527-72713": {0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x15, 0x00, 0x00, 0x00, 0xA0, 0x65, 0xCF, 0x7E, 0x78, 0x4B, 0x9B, 0x5F, 0xE7, 0x7C, 0x87, 0x70, 0x09, 0x1C, 0x01, 0x00}, From 966e1359eaffdf159114470a0dd2f69b3501ce96 Mon Sep 17 00:00:00 2001 From: Helen Fu <25168806+helenfufu@users.noreply.github.com> Date: Fri, 3 Jan 2025 18:19:16 -0600 Subject: [PATCH 4/5] add unit tests for getUserBindDN --- ldap/client_test.go | 213 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 189 insertions(+), 24 deletions(-) diff --git a/ldap/client_test.go b/ldap/client_test.go index 728bc0b..f3daae9 100644 --- a/ldap/client_test.go +++ b/ldap/client_test.go @@ -457,6 +457,171 @@ func TestClient_connect(t *testing.T) { }) } +func TestClient_getUserBindDN(t *testing.T) { + t.Parallel() + testCtx := context.Background() + logger := hclog.New(&hclog.LoggerOptions{ + Name: "test-logger", + Level: hclog.Error, + }) + td := testdirectory.Start(nil, + testdirectory.WithDefaults(nil, &testdirectory.Defaults{AllowAnonymousBind: true}), + testdirectory.WithLogger(t, logger), + ) + users := testdirectory.NewUsers(t, []string{"alice", "bob"}) + users = append( + users, + testdirectory.NewUsers( + t, + []string{"eve"}, + testdirectory.WithDefaults(t, &testdirectory.Defaults{UPNDomain: "example.com"}))..., + ) + td.SetUsers(users...) + + duplicatedUsers := append([]*gldap.Entry{}, users...) + duplicatedUsers = append( + duplicatedUsers, + users..., + ) + tdWithDuplicatedUsers := testdirectory.Start(t, + testdirectory.WithDefaults(t, &testdirectory.Defaults{AllowAnonymousBind: true}), + testdirectory.WithLogger(t, logger), + ) + tdWithDuplicatedUsers.SetUsers(duplicatedUsers...) + + cases := map[string]struct { + conf *ClientConfig + username string + + want string + wantErr bool + wantErrIs error + wantErrContains string + }{ + "fail: missing username": { + conf: &ClientConfig{ + URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())}, + Certificates: []string{td.Cert()}, + }, + username: "", + + wantErr: true, + wantErrIs: ErrInvalidParameter, + wantErrContains: "missing username", + }, + "fail: missing all of discoverdn, binddn, bindpass, upndomain, userdn": { + conf: &ClientConfig{ + URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())}, + Certificates: []string{td.Cert()}, + }, + username: "alice", + + wantErr: true, + wantErrIs: ErrInvalidParameter, + wantErrContains: "cannot derive UserBindDN based on config (see combination of: discoverdn, binddn, bindpass, upndomain, userdn)", + }, + "fail: search fails to find user": { + conf: &ClientConfig{ + URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())}, + Certificates: []string{td.Cert()}, + DiscoverDN: true, + }, + username: "nonexistent", + + wantErr: true, + wantErrContains: "LDAP search for binddn failed", + }, + "fail: search returns multiple users": { + conf: &ClientConfig{ + URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", tdWithDuplicatedUsers.Port())}, + Certificates: []string{tdWithDuplicatedUsers.Cert()}, + DiscoverDN: true, + }, + username: "alice", + + wantErr: true, + wantErrContains: "LDAP search for binddn 0 or not unique", + }, + "fail: invalid search filter": { + conf: &ClientConfig{ + URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())}, + Certificates: []string{td.Cert()}, + DiscoverDN: true, + UserFilter: "({{.BadFilter}}={{.Username}})", + }, + username: "alice", + + wantErr: true, + wantErrContains: "search failed due to template parsing error", + }, + "success: discoverdn": { + conf: &ClientConfig{ + URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())}, + Certificates: []string{td.Cert()}, + DiscoverDN: true, + }, + username: "alice", + + want: "cn=alice,ou=people,dc=example,dc=org", + }, + "success: binddn and bindpass": { + conf: &ClientConfig{ + URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())}, + Certificates: []string{td.Cert()}, + BindDN: "cn=bob,ou=people,dc=example,dc=org", + BindPassword: "password", + }, + username: "alice", + + want: "cn=alice,ou=people,dc=example,dc=org", + }, + "success: upndomain": { + conf: &ClientConfig{ + URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())}, + Certificates: []string{td.Cert()}, + UPNDomain: "example.com", + }, + username: "eve", + + want: "eve@example.com", + }, + "success: userdn": { + conf: &ClientConfig{ + URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())}, + Certificates: []string{td.Cert()}, + UserDN: testdirectory.DefaultUserDN, + }, + username: "alice", + + want: "cn=alice,ou=people,dc=example,dc=org", + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + assert, require := assert.New(t), require.New(t) + c, err := NewClient(testCtx, tc.conf) + require.NoError(err) + err = c.connect(testCtx) + require.NoError(err) + defer func() { c.Close(testCtx) }() + got, err := c.getUserBindDN(tc.username) + if tc.wantErr { + require.Error(err) + if tc.wantErrIs != nil { + assert.ErrorIs(err, tc.wantErrIs) + } + if tc.wantErrContains != "" { + assert.Contains(err.Error(), tc.wantErrContains) + } + return + } + require.NoError(err) + assert.Equal(tc.want, got) + }) + } +} + func TestClient_getUserDN(t *testing.T) { t.Parallel() testCtx := context.Background() @@ -523,6 +688,30 @@ func TestClient_getUserDN(t *testing.T) { wantErrIs: ErrInvalidParameter, wantErrContains: "missing username", }, + "fail: upn domain search fails to find user": { + conf: &ClientConfig{ + URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", tdWithDuplicatedUsers.Port())}, + Certificates: []string{tdWithDuplicatedUsers.Cert()}, + UPNDomain: "example.com", + }, + bindDN: "userPrincipalName=nonexistent@example.com,ou=people,dc=example,dc=org", + username: "nonexistent", + + wantErr: true, + wantErrContains: "LDAP search failed for detecting user", + }, + "fail: upn domain search returns multiple users": { + conf: &ClientConfig{ + URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", tdWithDuplicatedUsers.Port())}, + Certificates: []string{tdWithDuplicatedUsers.Cert()}, + UPNDomain: "example.com", + }, + bindDN: "userPrincipalName=eve@example.com,ou=people,dc=example,dc=org", + username: "eve", + + wantErr: true, + wantErrContains: "LDAP search for user 0 or not unique", + }, "success: no upn domain": { conf: &ClientConfig{ URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())}, @@ -556,30 +745,6 @@ func TestClient_getUserDN(t *testing.T) { want: "userPrincipalName=eve@example.com,ou=people,dc=example,dc=org", }, - "fail: upn domain search fails to detect user": { - conf: &ClientConfig{ - URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())}, - Certificates: []string{td.Cert()}, - UPNDomain: "example.com", - }, - bindDN: "userPrincipalName=invalid-name@example.com,ou=people,dc=example,dc=org", - username: "invalid-name", - - wantErr: true, - wantErrContains: "LDAP search failed for detecting user", - }, - "fail: upn domain search returns multiple users": { - conf: &ClientConfig{ - URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", tdWithDuplicatedUsers.Port())}, - Certificates: []string{tdWithDuplicatedUsers.Cert()}, - UPNDomain: "example.com", - }, - bindDN: "userPrincipalName=eve@example.com,ou=people,dc=example,dc=org", - username: "eve", - - wantErr: true, - wantErrContains: "LDAP search for user 0 or not unique", - }, } for name, tc := range tests { From 6fa6450889365559c2d55b9efea01338af02dcbb Mon Sep 17 00:00:00 2001 From: Helen Fu <25168806+helenfufu@users.noreply.github.com> Date: Mon, 6 Jan 2025 11:41:55 -0600 Subject: [PATCH 5/5] use single test directory with duplicated user instead of multiple test directories --- ldap/client_exported_test.go | 31 ++++++++----------- ldap/client_test.go | 58 ++++++++++++++++-------------------- 2 files changed, 38 insertions(+), 51 deletions(-) diff --git a/ldap/client_exported_test.go b/ldap/client_exported_test.go index 0c98b55..9fdcf1a 100644 --- a/ldap/client_exported_test.go +++ b/ldap/client_exported_test.go @@ -23,8 +23,6 @@ func TestClient_Authenticate(t *testing.T) { Name: "test-logger", Level: hclog.Error, }) - - // Set up test directory td := testdirectory.Start(t, testdirectory.WithDefaults(t, &testdirectory.Defaults{AllowAnonymousBind: true}), testdirectory.WithLogger(t, logger), @@ -49,6 +47,15 @@ func TestClient_Authenticate(t *testing.T) { testdirectory.WithDefaults(t, &testdirectory.Defaults{UPNDomain: "example.com"}), testdirectory.WithMembersOf(t, "admin"))..., ) + // Set up a duplicated user to test the case where the search returns multiple users + users = append( + users, + testdirectory.NewUsers( + t, + []string{"mallory", "mallory"}, + testdirectory.WithDefaults(t, &testdirectory.Defaults{UPNDomain: "example.com"}), + )..., + ) // add some attributes that we always want to filter out of an AuthResult, // so if we ever start seeing tests fail because of them; we know that we've // messed up the default filtering @@ -62,20 +69,6 @@ func TestClient_Authenticate(t *testing.T) { td.SetGroups(groups...) td.SetTokenGroups(tokenGroups) - // Set up test directory with duplicate users. This directory is used to test that we error when multiple users are found. - duplicatedUsers := append([]*gldap.Entry{}, users...) - duplicatedUsers = append( - duplicatedUsers, - users..., - ) - tdWithDuplicatedUsers := testdirectory.Start(t, - testdirectory.WithDefaults(t, &testdirectory.Defaults{AllowAnonymousBind: true}), - testdirectory.WithLogger(t, logger), - ) - tdWithDuplicatedUsers.SetUsers(duplicatedUsers...) - tdWithDuplicatedUsers.SetGroups(groups...) - tdWithDuplicatedUsers.SetTokenGroups(tokenGroups) - tests := []struct { name string username string @@ -528,11 +521,11 @@ func TestClient_Authenticate(t *testing.T) { }, { name: "failed-with-anon-bind-upn-domain-multiple-users-returned", - username: "eve", + username: "mallory", password: "password", clientConfig: &ldap.ClientConfig{ - URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", tdWithDuplicatedUsers.Port())}, - Certificates: []string{tdWithDuplicatedUsers.Cert()}, + URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())}, + Certificates: []string{td.Cert()}, DiscoverDN: true, UserDN: testdirectory.DefaultUserDN, GroupDN: testdirectory.DefaultGroupDN, diff --git a/ldap/client_test.go b/ldap/client_test.go index f3daae9..af93894 100644 --- a/ldap/client_test.go +++ b/ldap/client_test.go @@ -11,7 +11,6 @@ import ( "testing" "github.com/hashicorp/go-hclog" - "github.com/jimlambrt/gldap" "github.com/jimlambrt/gldap/testdirectory" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -476,18 +475,15 @@ func TestClient_getUserBindDN(t *testing.T) { []string{"eve"}, testdirectory.WithDefaults(t, &testdirectory.Defaults{UPNDomain: "example.com"}))..., ) - td.SetUsers(users...) - - duplicatedUsers := append([]*gldap.Entry{}, users...) - duplicatedUsers = append( - duplicatedUsers, - users..., - ) - tdWithDuplicatedUsers := testdirectory.Start(t, - testdirectory.WithDefaults(t, &testdirectory.Defaults{AllowAnonymousBind: true}), - testdirectory.WithLogger(t, logger), + // Set up a duplicated user to test the case where the search returns multiple users + users = append( + users, + testdirectory.NewUsers( + t, + []string{"mallory", "mallory"}, + )..., ) - tdWithDuplicatedUsers.SetUsers(duplicatedUsers...) + td.SetUsers(users...) cases := map[string]struct { conf *ClientConfig @@ -533,11 +529,11 @@ func TestClient_getUserBindDN(t *testing.T) { }, "fail: search returns multiple users": { conf: &ClientConfig{ - URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", tdWithDuplicatedUsers.Port())}, - Certificates: []string{tdWithDuplicatedUsers.Cert()}, + URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())}, + Certificates: []string{td.Cert()}, DiscoverDN: true, }, - username: "alice", + username: "mallory", wantErr: true, wantErrContains: "LDAP search for binddn 0 or not unique", @@ -641,18 +637,16 @@ func TestClient_getUserDN(t *testing.T) { []string{"eve"}, testdirectory.WithDefaults(t, &testdirectory.Defaults{UPNDomain: "example.com"}))..., ) - td.SetUsers(users...) - - duplicatedUsers := append([]*gldap.Entry{}, users...) - duplicatedUsers = append( - duplicatedUsers, - users..., - ) - tdWithDuplicatedUsers := testdirectory.Start(t, - testdirectory.WithDefaults(t, &testdirectory.Defaults{AllowAnonymousBind: true}), - testdirectory.WithLogger(t, logger), + // Set up a duplicated user to test the case where the search returns multiple users + users = append( + users, + testdirectory.NewUsers( + t, + []string{"mallory", "mallory"}, + testdirectory.WithDefaults(t, &testdirectory.Defaults{UPNDomain: "example.com"}), + )..., ) - tdWithDuplicatedUsers.SetUsers(duplicatedUsers...) + td.SetUsers(users...) tests := map[string]struct { conf *ClientConfig @@ -690,8 +684,8 @@ func TestClient_getUserDN(t *testing.T) { }, "fail: upn domain search fails to find user": { conf: &ClientConfig{ - URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", tdWithDuplicatedUsers.Port())}, - Certificates: []string{tdWithDuplicatedUsers.Cert()}, + URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())}, + Certificates: []string{td.Cert()}, UPNDomain: "example.com", }, bindDN: "userPrincipalName=nonexistent@example.com,ou=people,dc=example,dc=org", @@ -702,12 +696,12 @@ func TestClient_getUserDN(t *testing.T) { }, "fail: upn domain search returns multiple users": { conf: &ClientConfig{ - URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", tdWithDuplicatedUsers.Port())}, - Certificates: []string{tdWithDuplicatedUsers.Cert()}, + URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())}, + Certificates: []string{td.Cert()}, UPNDomain: "example.com", }, - bindDN: "userPrincipalName=eve@example.com,ou=people,dc=example,dc=org", - username: "eve", + bindDN: "userPrincipalName=mallory@example.com,ou=people,dc=example,dc=org", + username: "mallory", wantErr: true, wantErrContains: "LDAP search for user 0 or not unique",