Beispiel #1
0
func TestGroupEntryFor(t *testing.T) {
	var testCases = []struct {
		name                string
		cacheSeed           map[string]*ldap.Entry
		queryBaseDNOverride string
		client              ldap.Client
		expectedError       error
		expectedEntry       *ldap.Entry
	}{
		{
			name:          "cached get",
			cacheSeed:     map[string]*ldap.Entry{"cn=testGroup,ou=groups,dc=example,dc=com": newTestGroup("testGroup", "cn=testUser,ou=users,dc=example,dc=com")},
			expectedError: nil,
			expectedEntry: newTestGroup("testGroup", "cn=testUser,ou=users,dc=example,dc=com"),
		},
		{
			name:                "search request failure",
			queryBaseDNOverride: "dc=foo",
			expectedError:       ldaputil.NewQueryOutOfBoundsError("cn=testGroup,ou=groups,dc=example,dc=com", "dc=foo"),
			expectedEntry:       nil,
		},
		{
			name: "query failure",
			client: testclient.NewMatchingSearchErrorClient(
				testclient.New(),
				"cn=testGroup,ou=groups,dc=example,dc=com",
				errors.New("generic search error"),
			),
			expectedError: errors.New("generic search error"),
			expectedEntry: nil,
		},
		{
			name: "no errors",
			client: testclient.NewDNMappingClient(
				testclient.New(),
				map[string][]*ldap.Entry{
					"cn=testGroup,ou=groups,dc=example,dc=com": {newTestGroup("testGroup", "cn=testUser,ou=users,dc=example,dc=com")},
				},
			),
			expectedError: nil,
			expectedEntry: newTestGroup("testGroup", "cn=testUser,ou=users,dc=example,dc=com"),
		},
	}
	for _, testCase := range testCases {
		ldapInterface := newTestLDAPInterface(testCase.client)
		if len(testCase.cacheSeed) > 0 {
			ldapInterface.cachedGroups = testCase.cacheSeed
		}
		if len(testCase.queryBaseDNOverride) > 0 {
			ldapInterface.groupQuery.BaseDN = testCase.queryBaseDNOverride
		}
		entry, err := ldapInterface.GroupEntryFor("cn=testGroup,ou=groups,dc=example,dc=com")
		if !reflect.DeepEqual(err, testCase.expectedError) {
			t.Errorf("%s: incorrect error returned:\n\texpected:\n\t%v\n\tgot:\n\t%v\n", testCase.name, testCase.expectedError, err)
		}
		if !reflect.DeepEqual(entry, testCase.expectedEntry) {
			t.Errorf("%s: incorrect entry returned:\n\texpected:\n\t%v\n\tgot:\n\t%v\n", testCase.name, testCase.expectedEntry, entry)
		}
	}
}
func TestExtractMembers(t *testing.T) {
	var testCases = []struct {
		name            string
		client          ldap.Client
		expectedError   error
		expectedMembers []*ldap.Entry
	}{
		{
			name: "group lookup errors",
			client: testclient.NewMatchingSearchErrorClient(
				testclient.New(),
				"cn=testGroup,ou=groups,dc=example,dc=com",
				errors.New("generic search error"),
			),
			expectedError:   errors.New("generic search error"),
			expectedMembers: nil,
		},
		{
			name: "member lookup errors",
			// this is a nested test client, the first nest tries to error on the user DN
			// the second nest attempts to give back from the DN mapping
			// the third nest is the default "safe" impl from ldaputil
			client: testclient.NewMatchingSearchErrorClient(
				testclient.NewDNMappingClient(
					testclient.New(),
					map[string][]*ldap.Entry{
						"cn=testGroup,ou=groups,dc=example,dc=com": {newTestGroup("testGroup", "cn=testUser,ou=users,dc=example,dc=com")},
					},
				),
				"cn=testUser,ou=users,dc=example,dc=com",
				errors.New("generic search error"),
			),
			expectedError:   interfaces.NewMemberLookupError("cn=testGroup,ou=groups,dc=example,dc=com", "cn=testUser,ou=users,dc=example,dc=com", errors.New("generic search error")),
			expectedMembers: nil,
		},
		{
			name: "no errors",
			client: testclient.NewDNMappingClient(
				testclient.New(),
				map[string][]*ldap.Entry{
					"cn=testGroup,ou=groups,dc=example,dc=com": {newTestGroup("testGroup", "cn=testUser,ou=users,dc=example,dc=com")},
					"cn=testUser,ou=users,dc=example,dc=com":   {newTestUser("testUser")},
				},
			),
			expectedError:   nil,
			expectedMembers: []*ldap.Entry{newTestUser("testUser")},
		},
	}
	for _, testCase := range testCases {
		ldapInterface := newTestLDAPInterface(testCase.client)
		members, err := ldapInterface.ExtractMembers("cn=testGroup,ou=groups,dc=example,dc=com")
		if !reflect.DeepEqual(err, testCase.expectedError) {
			t.Errorf("%s: incorrect error returned:\n\texpected:\n\t%v\n\tgot:\n\t%v\n", testCase.name, testCase.expectedError, err)
		}
		if !reflect.DeepEqual(members, testCase.expectedMembers) {
			t.Errorf("%s: incorrect members returned:\n\texpected:\n\t%v\n\tgot:\n\t%v\n", testCase.name, testCase.expectedMembers, members)
		}
	}
}
func TestPopulateCache(t *testing.T) {
	var testCases = []struct {
		name             string
		cacheSeed        map[string][]*ldap.Entry
		searchDNOverride string
		client           ldap.Client
		expectedError    error
		expectedCache    map[string][]*ldap.Entry
	}{
		{
			name: "cache already populated",
			cacheSeed: map[string][]*ldap.Entry{
				"testGroup": {newTestUser("testUser", "testGroup")},
			},
			expectedError: nil,
			expectedCache: map[string][]*ldap.Entry{
				"testGroup": {newTestUser("testUser", "testGroup")},
			},
		},
		{
			name: "user query error",
			client: testclient.NewMatchingSearchErrorClient(
				testclient.New(),
				"ou=users,dc=example,dc=com",
				errors.New("generic search error"),
			),
			expectedError: errors.New("generic search error"),
			expectedCache: make(map[string][]*ldap.Entry), // won't be nil but will be empty
		},
		{
			name: "cache populated correctly",
			client: testclient.NewDNMappingClient(
				testclient.New(),
				map[string][]*ldap.Entry{
					"ou=users,dc=example,dc=com": {newTestUser("testUser", "testGroup")},
				},
			),
			expectedError: nil,
			expectedCache: map[string][]*ldap.Entry{
				"testGroup": {newTestUser("testUser", "testGroup")},
			},
		},
	}
	for _, testCase := range testCases {
		ldapInterface := newTestADLDAPInterface(testCase.client)
		if len(testCase.cacheSeed) > 0 {
			ldapInterface.ldapGroupToLDAPMembers = testCase.cacheSeed
			ldapInterface.cacheFullyPopulated = true
		}
		err := ldapInterface.populateCache()
		if !reflect.DeepEqual(err, testCase.expectedError) {
			t.Errorf("%s: incorrect error returned:\n\texpected:\n\t%v\n\tgot:\n\t%v\n", testCase.name, testCase.expectedError, err)
		}
		if !reflect.DeepEqual(testCase.expectedCache, ldapInterface.ldapGroupToLDAPMembers) {
			t.Errorf("%s: incorrect cache state:\n\texpected:\n\t%v\n\tgot:\n\t%v\n", testCase.name, testCase.expectedCache, ldapInterface.ldapGroupToLDAPMembers)
		}
	}
}
Beispiel #4
0
func TestListGroups(t *testing.T) {
	var testCases = []struct {
		name              string
		client            ldap.Client
		groupUIDAttribute string
		expectedError     error
		expectedGroups    []string
	}{
		{
			name: "query errors",
			client: testclient.NewMatchingSearchErrorClient(
				testclient.New(),
				"ou=groups,dc=example,dc=com",
				errors.New("generic search error"),
			),
			expectedError:  errors.New("generic search error"),
			expectedGroups: nil,
		},
		{
			name: "no UID on entry",
			client: testclient.NewDNMappingClient(
				testclient.New(),
				map[string][]*ldap.Entry{
					"ou=groups,dc=example,dc=com": {newTestGroup("", "cn=testUser,ou=users,dc=example,dc=com")},
				},
			),
			groupUIDAttribute: "cn",
			expectedError:     fmt.Errorf("unable to find LDAP group UID for %s", newTestGroup("", "cn=testUser,ou=users,dc=example,dc=com")),
			expectedGroups:    nil,
		},
		{
			name: "no error",
			client: testclient.NewDNMappingClient(
				testclient.New(),
				map[string][]*ldap.Entry{
					"ou=groups,dc=example,dc=com": {newTestGroup("testGroup", "cn=testUser,ou=users,dc=example,dc=com")},
				},
			),
			expectedError:  nil,
			expectedGroups: []string{"cn=testGroup,ou=groups,dc=example,dc=com"},
		},
	}
	for _, testCase := range testCases {
		ldapInterface := newTestLDAPInterface(testCase.client)
		if len(testCase.groupUIDAttribute) > 0 {
			ldapInterface.groupQuery.QueryAttribute = testCase.groupUIDAttribute
		}
		groupNames, err := ldapInterface.ListGroups()
		if !reflect.DeepEqual(err, testCase.expectedError) {
			t.Errorf("%s: incorrect error returned:\n\texpected:\n\t%v\n\tgot:\n\t%v\n", testCase.name, testCase.expectedError, err)
		}
		if !reflect.DeepEqual(groupNames, testCase.expectedGroups) {
			t.Errorf("%s: incorrect entry returned:\n\texpected:\n\t%v\n\tgot:\n\t%v\n", testCase.name, testCase.expectedGroups, groupNames)
		}
	}
}
func TestExtractMembers(t *testing.T) {
	// we don't have a test case for an error on a bad search request as search request errors can only occur if
	// the search attribute is the DN, and we do not allow DN to be a group UID for this schema
	var testCases = []struct {
		name            string
		cacheSeed       map[string][]*ldap.Entry
		client          ldap.Client
		expectedError   error
		expectedMembers []*ldap.Entry
	}{
		{
			name: "members cached",
			cacheSeed: map[string][]*ldap.Entry{
				"testGroup": {newTestUser("testUser", "testGroup")},
			},
			expectedError:   nil,
			expectedMembers: []*ldap.Entry{newTestUser("testUser", "testGroup")},
		},
		{
			name: "user query error",
			client: testclient.NewMatchingSearchErrorClient(
				testclient.New(),
				"ou=users,dc=example,dc=com",
				errors.New("generic search error"),
			),
			expectedError:   errors.New("generic search error"),
			expectedMembers: nil,
		},
		{
			name: "no errors",
			client: testclient.NewDNMappingClient(
				testclient.New(),
				map[string][]*ldap.Entry{
					"ou=users,dc=example,dc=com": {newTestUser("testUser", "testGroup")},
				},
			),
			expectedError:   nil,
			expectedMembers: []*ldap.Entry{newTestUser("testUser", "testGroup")},
		},
	}
	for _, testCase := range testCases {
		ldapInterface := newTestADLDAPInterface(testCase.client)
		if len(testCase.cacheSeed) > 0 {
			ldapInterface.ldapGroupToLDAPMembers = testCase.cacheSeed
		}
		members, err := ldapInterface.ExtractMembers("testGroup")
		if !reflect.DeepEqual(err, testCase.expectedError) {
			t.Errorf("%s: incorrect error returned:\n\texpected:\n\t%v\n\tgot:\n\t%v\n", testCase.name, testCase.expectedError, err)
		}
		if !reflect.DeepEqual(members, testCase.expectedMembers) {
			t.Errorf("%s: incorrect members returned:\n\texpected:\n\t%v\n\tgot:\n\t%v\n", testCase.name, testCase.expectedMembers, members)
		}
	}
}
Beispiel #6
0
func TestQueryWithPaging(t *testing.T) {
	expectedResult := &ldap.SearchResult{
		Entries: []*ldap.Entry{ldap.NewEntry("cn=paging,ou=paging,dc=paging,dc=com", map[string][]string{"paging": {"true"}})},
	}

	testConfig := testclient.NewConfig(testclient.NewPagingOnlyClient(testclient.New(),
		expectedResult,
	))
	testSearchRequest := &ldap.SearchRequest{
		BaseDN:       "dc=example,dc=com",
		Scope:        ldap.ScopeWholeSubtree,
		DerefAliases: int(DefaultDerefAliases),
		SizeLimit:    DefaultSizeLimit,
		TimeLimit:    DefaultTimeLimit,
		TypesOnly:    DefaultTypesOnly,
		Filter:       "(objectClass=*)",
		Attributes:   append(DefaultAttributes),
		Controls:     []ldap.Control{ldap.NewControlPaging(5)},
	}

	// test that a search request with paging controls gets correctly routed to the SearchWithPaging call
	response, err := QueryForEntries(testConfig, testSearchRequest)
	if err != nil {
		t.Errorf("query with paging control should not create error, but got %v", err)
	}
	if !reflect.DeepEqual(expectedResult.Entries, response) {
		t.Errorf("query with paging did not return correct response: expected %v, got %v", expectedResult.Entries, response)
	}
}
Beispiel #7
0
// TestErrEntryNotFound checks that we wrap a zero-length list of results correctly if we search for a unique entry
func TestErrEntryNotFound(t *testing.T) {
	testConfig := testclient.NewConfig(testclient.New())
	testSearchRequest := &ldap.SearchRequest{
		BaseDN:       "dc=example,dc=com",
		Scope:        ldap.ScopeWholeSubtree,
		DerefAliases: int(DefaultDerefAliases),
		SizeLimit:    DefaultSizeLimit,
		TimeLimit:    DefaultTimeLimit,
		TypesOnly:    DefaultTypesOnly,
		Filter:       "(objectClass=*)",
		Attributes:   append(DefaultAttributes),
		Controls:     DefaultControls,
	}

	expectedErr := &errEntryNotFound{baseDN: "dc=example,dc=com", filter: "(objectClass=*)"}

	// test that a unique search errors on no result
	if _, err := QueryForUniqueEntry(testConfig, testSearchRequest); !reflect.DeepEqual(err, expectedErr) {
		t.Errorf("query for unique entry did not get correct error:\n\texpected:\n\t%v\n\tgot:\n\t%v", expectedErr, err)
	}

	// test that a non-unique search doesn't error
	if _, err := QueryForEntries(testConfig, testSearchRequest); !reflect.DeepEqual(err, nil) {
		t.Errorf("query for entries did not get correct error:\n\texpected:\n\t%v\n\tgot:\n\t%v", nil, err)
	}
}
Beispiel #8
0
// TestErrNoSuchObject tests that our LDAP search correctly wraps the LDAP server error
func TestErrNoSuchObject(t *testing.T) {
	var testCases = []struct {
		name          string
		searchRequest *ldap.SearchRequest
		expectedError error
	}{
		{
			name: "valid search",
			searchRequest: &ldap.SearchRequest{
				BaseDN: "uid=john,o=users,dc=example,dc=com",
			},
			expectedError: nil,
		},
		{
			name: "invalid search",
			searchRequest: &ldap.SearchRequest{
				BaseDN: "ou=groups,dc=example,dc=com",
			},
			expectedError: &errNoSuchObject{baseDN: "ou=groups,dc=example,dc=com"},
		},
	}
	for _, testCase := range testCases {
		testClient := testclient.NewMatchingSearchErrorClient(testclient.New(),
			"ou=groups,dc=example,dc=com",
			ldap.NewError(ldap.LDAPResultNoSuchObject, errors.New("")),
		)
		testConfig := testclient.NewConfig(testClient)
		if _, err := QueryForEntries(testConfig, testCase.searchRequest); !reflect.DeepEqual(err, testCase.expectedError) {
			t.Errorf("%s: error did not match:\n\texpected:\n\t%v\n\tgot:\n\t%v", testCase.name, testCase.expectedError, err)
		}
	}
}
// TestPopulateCacheAfterExtractMembers ensures that the cache is only listed as fully populated after a
// populateCache call and not after a partial fill from an ExtractMembers call
func TestPopulateCacheAfterExtractMembers(t *testing.T) {
	client := testclient.NewDNMappingClient(
		testclient.New(),
		map[string][]*ldap.Entry{
			"ou=users,dc=example,dc=com": {newTestUser("testUser", "testGroup")},
		},
	)
	ldapInterface := newTestADLDAPInterface(client)
	_, err := ldapInterface.ExtractMembers("testGroup")
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}

	// both queries use the same BaseDN so we change what the client returns to simulate not applying the group-specific filter
	client.(*testclient.DNMappingClient).DNMapping["ou=users,dc=example,dc=com"] = []*ldap.Entry{
		newTestUser("testUser", "testGroup"),
		newTestUser("testUser2", "testGroup2")}

	expectedCache := map[string][]*ldap.Entry{
		"testGroup":  {newTestUser("testUser", "testGroup")},
		"testGroup2": {newTestUser("testUser2", "testGroup2")},
	}

	err = ldapInterface.populateCache()
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	if !reflect.DeepEqual(expectedCache, ldapInterface.ldapGroupToLDAPMembers) {
		t.Errorf("incorrect cache state:\n\texpected:\n\t%v\n\tgot:\n\t%v\n", expectedCache, ldapInterface.ldapGroupToLDAPMembers)
	}
}
func TestListGroups(t *testing.T) {
	client := testclient.NewDNMappingClient(
		testclient.New(),
		map[string][]*ldap.Entry{
			"ou=users,dc=example,dc=com": {newTestUser("testUser", "testGroup")},
		},
	)
	ldapInterface := newTestADLDAPInterface(client)
	groups, err := ldapInterface.ListGroups()
	if !reflect.DeepEqual(err, nil) {
		t.Errorf("listing groups: incorrect error returned:\n\texpected:\n\t%v\n\tgot:\n\t%v\n", nil, err)
	}
	if !reflect.DeepEqual(groups, []string{"testGroup"}) {
		t.Errorf("listing groups: incorrect group list:\n\texpected:\n\t%v\n\tgot:\n\t%v\n", []string{"testGroup"}, groups)
	}
}