/* See LICENSE for licensing and NOTICE for copyright. */ package org.ldaptive; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import org.ldaptive.ad.control.ForceUpdateControl; import org.ldaptive.ad.control.GetStatsControl; import org.ldaptive.ad.control.LazyCommitControl; import org.ldaptive.ad.control.PermissiveModifyControl; import org.ldaptive.ad.control.RangeRetrievalNoerrControl; import org.ldaptive.ad.control.SearchOptionsControl; import org.ldaptive.ad.control.ShowDeactivatedLinkControl; import org.ldaptive.ad.control.ShowDeletedControl; import org.ldaptive.ad.control.ShowRecycledControl; import org.ldaptive.ad.handler.ObjectGuidHandler; import org.ldaptive.ad.handler.ObjectSidHandler; import org.ldaptive.ad.handler.PrimaryGroupIdHandler; import org.ldaptive.ad.handler.RangeEntryHandler; import org.ldaptive.control.PagedResultsControl; import org.ldaptive.control.ProxyAuthorizationControl; import org.ldaptive.control.SortKey; import org.ldaptive.control.SortRequestControl; import org.ldaptive.control.VirtualListViewRequestControl; import org.ldaptive.control.VirtualListViewResponseControl; import org.ldaptive.handler.CaseChangeEntryHandler; import org.ldaptive.handler.CaseChangeEntryHandler.CaseChange; import org.ldaptive.handler.DnAttributeEntryHandler; import org.ldaptive.handler.HandlerResult; import org.ldaptive.handler.MergeAttributeEntryHandler; import org.ldaptive.handler.NoOpEntryHandler; import org.ldaptive.handler.RecursiveEntryHandler; import org.ldaptive.handler.SearchEntryHandler; import org.ldaptive.handler.SearchReferenceHandler; import org.ldaptive.io.GeneralizedTimeValueTranscoder; import org.ldaptive.pool.BlockingConnectionPool; import org.ldaptive.pool.PooledConnectionFactory; import org.ldaptive.referral.SearchReferralHandler; import org.testng.AssertJUnit; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Parameters; import org.testng.annotations.Test; /** * Unit test for {@link SearchOperation}. * * @author Middleware Services */ public class SearchOperationTest extends AbstractTest { /** Entry created for ldap tests. */ private static LdapEntry testLdapEntry; /** Entry created for ldap tests. */ private static LdapEntry specialCharsLdapEntry; /** Entries for group tests. */ private static final Map<String, LdapEntry[]> GROUP_ENTRIES = new HashMap<>(); /** * Initialize the map of group entries. */ static { for (int i = 2; i <= 5; i++) { GROUP_ENTRIES.put(String.valueOf(i), new LdapEntry[2]); } } /** Connection instance for concurrency testing. */ protected Connection singleConn; /** * Default constructor. * * @throws Exception On test failure. */ public SearchOperationTest() throws Exception { singleConn = TestUtils.createConnection(); } /** @throws Exception On test failure. */ @BeforeClass(groups = {"search"}) public void openConnection() throws Exception { singleConn.open(); } /** * @param ldifFile to create. * * @throws Exception On test failure. */ @Parameters("createEntry2") @BeforeClass(groups = {"search", "searchInit"}) public void createLdapEntry(final String ldifFile) throws Exception { final String ldif = TestUtils.readFileIntoString(ldifFile); testLdapEntry = TestUtils.convertLdifToResult(ldif).getEntry(); super.createLdapEntry(testLdapEntry); } /** * @param ldifFile2 to create. * @param ldifFile3 to create. * @param ldifFile4 to create. * @param ldifFile5 to create. * * @throws Exception On test failure. */ @Parameters( { "createGroup2", "createGroup3", "createGroup4", "createGroup5" }) @BeforeClass(groups = {"search"}, dependsOnGroups = {"searchInit"}) public void createGroupEntry( final String ldifFile2, final String ldifFile3, final String ldifFile4, final String ldifFile5) throws Exception { // CheckStyle:Indentation OFF GROUP_ENTRIES.get("2")[0] = TestUtils.convertLdifToResult(TestUtils.readFileIntoString(ldifFile2)).getEntry(); GROUP_ENTRIES.get("3")[0] = TestUtils.convertLdifToResult(TestUtils.readFileIntoString(ldifFile3)).getEntry(); GROUP_ENTRIES.get("4")[0] = TestUtils.convertLdifToResult(TestUtils.readFileIntoString(ldifFile4)).getEntry(); GROUP_ENTRIES.get("5")[0] = TestUtils.convertLdifToResult(TestUtils.readFileIntoString(ldifFile5)).getEntry(); // CheckStyle:Indentation ON for (Map.Entry<String, LdapEntry[]> e : GROUP_ENTRIES.entrySet()) { super.createLdapEntry(e.getValue()[0]); } final String baseDn = DnParser.substring(GROUP_ENTRIES.get("2")[0].getDn(), 1); // setup group relationships try (Connection conn = TestUtils.createSetupConnection()) { conn.open(); final ModifyOperation modify = new ModifyOperation(conn); try { modify.execute( new ModifyRequest( GROUP_ENTRIES.get("2")[0].getDn(), new AttributeModification( AttributeModificationType.ADD, new LdapAttribute("member", "cn=Group 3," + baseDn)))); } catch (LdapException e) { // ignore attribute already exists if (ResultCode.ATTRIBUTE_OR_VALUE_EXISTS != e.getResultCode()) { throw e; } } try { modify.execute( new ModifyRequest( GROUP_ENTRIES.get("3")[0].getDn(), new AttributeModification( AttributeModificationType.ADD, new LdapAttribute("member", "cn=Group 4," + baseDn, "cn=Group 5," + baseDn)))); } catch (LdapException e) { // ignore attribute already exists if (ResultCode.ATTRIBUTE_OR_VALUE_EXISTS != e.getResultCode()) { throw e; } } try { modify.execute( new ModifyRequest( GROUP_ENTRIES.get("4")[0].getDn(), new AttributeModification( AttributeModificationType.ADD, new LdapAttribute("member", "cn=Group 2," + baseDn, "cn=Group 3," + baseDn)))); } catch (LdapException e) { // ignore attribute already exists if (ResultCode.ATTRIBUTE_OR_VALUE_EXISTS != e.getResultCode()) { throw e; } } } } /** * @param ldifFile to create. * * @throws Exception On test failure. */ @Parameters("createSpecialCharsEntry") @BeforeClass(groups = {"search"}) public void createSpecialCharsEntry(final String ldifFile) throws Exception { final String ldif = TestUtils.readFileIntoString(ldifFile); specialCharsLdapEntry = TestUtils.convertLdifToResult(ldif).getEntry(); super.createLdapEntry(specialCharsLdapEntry); } /** @throws Exception On test failure. */ @AfterClass(groups = {"search"}) public void deleteLdapEntry() throws Exception { super.deleteLdapEntry(testLdapEntry.getDn()); super.deleteLdapEntry(specialCharsLdapEntry.getDn()); super.deleteLdapEntry(GROUP_ENTRIES.get("2")[0].getDn()); super.deleteLdapEntry(GROUP_ENTRIES.get("3")[0].getDn()); super.deleteLdapEntry(GROUP_ENTRIES.get("4")[0].getDn()); super.deleteLdapEntry(GROUP_ENTRIES.get("5")[0].getDn()); } /** * @param createNew whether to construct a new connection. * * @return connection * * @throws Exception On connection failure. */ public Connection createLdapConnection(final boolean createNew) throws Exception { if (createNew) { return TestUtils.createConnection(); } return singleConn; } /** * @param dn to search on. * @param filter to search with. * @param filterParameters to replace parameters in filter with. * @param returnAttrs to return from search. * @param ldifFile to compare with * * @throws Exception On test failure. */ @Parameters( { "searchDn", "searchFilter", "searchFilterParameters", "searchReturnAttrs", "searchResults" }) @Test( groups = {"search"}, threadPoolSize = TEST_THREAD_POOL_SIZE, invocationCount = TEST_INVOCATION_COUNT, timeOut = TEST_TIME_OUT) public void search( final String dn, final String filter, final String filterParameters, final String returnAttrs, final String ldifFile) throws Exception { final SearchOperation search = new SearchOperation(createLdapConnection(false)); final String expected = TestUtils.readFileIntoString(ldifFile); final SearchResult entryDnResult = TestUtils.convertLdifToResult(expected); entryDnResult.getEntry().addAttribute(new LdapAttribute("entryDN", entryDnResult.getEntry().getDn())); // test searching SearchResult result = search.execute( new SearchRequest( dn, new SearchFilter(filter, filterParameters.split("\\|")), returnAttrs.split("\\|"))).getResult(); TestUtils.assertEquals(TestUtils.convertLdifToResult(expected), result); // test searching no attributes result = search.execute( new SearchRequest( dn, new SearchFilter(filter, filterParameters.split("\\|")), ReturnAttributes.NONE.value())).getResult(); AssertJUnit.assertTrue(result.getEntry().getAttributes().isEmpty()); // test searching without handler final SearchRequest sr = new SearchRequest( dn, new SearchFilter(filter, filterParameters.split("\\|")), returnAttrs.split("\\|")); sr.setSearchEntryHandlers(new SearchEntryHandler[0]); result = search.execute(sr).getResult(); TestUtils.assertEquals(TestUtils.convertLdifToResult(expected), result); // test searching with multiple handlers final DnAttributeEntryHandler srh = new DnAttributeEntryHandler(); sr.setSearchEntryHandlers(new NoOpEntryHandler(), srh); result = search.execute(sr).getResult(); // ignore the case of entryDN; some directories return those in mixed case AssertJUnit.assertEquals( 0, (new LdapEntryIgnoreCaseComparator("entryDN")).compare(entryDnResult.getEntry(), result.getEntry())); // test that entry dn handler is no-op if attribute name conflicts srh.setDnAttributeName("givenName"); sr.setSearchEntryHandlers(new NoOpEntryHandler(), srh); result = search.execute(sr).getResult(); // ignore the case of entryDN; some directories return those in mixed case AssertJUnit.assertEquals( 0, (new LdapEntryIgnoreCaseComparator("entryDN")).compare( TestUtils.convertLdifToResult(expected).getEntry(), result.getEntry())); } /** * @param filter to search with. * @param filterParameters to replace parameters in filter with. * @param returnAttrs to return from search. * @param ldifFile to compare with * * @throws Exception On test failure. */ @Parameters( { "searchFilter", "searchFilterParameters", "searchReturnAttrs", "searchResults" }) @Test(groups = {"search"}) public void searchScopes( final String filter, final String filterParameters, final String returnAttrs, final String ldifFile) throws Exception { final SearchResult expectedResult = TestUtils.convertLdifToResult(TestUtils.readFileIntoString(ldifFile)); try (Connection conn = createLdapConnection(true)) { conn.open(); final SearchOperation search = new SearchOperation(conn); final SearchRequest subtreeRequest = new SearchRequest( DnParser.substring(expectedResult.getEntry().getDn(), 2), new SearchFilter(filter, filterParameters.split("\\|")), returnAttrs.split("\\|")); subtreeRequest.setSearchScope(SearchScope.SUBTREE); SearchResult result = search.execute(subtreeRequest).getResult(); TestUtils.assertEquals(expectedResult, result); final SearchRequest onelevelRequest = new SearchRequest( DnParser.substring(expectedResult.getEntry().getDn(), 1), new SearchFilter(filter, filterParameters.split("\\|")), returnAttrs.split("\\|")); onelevelRequest.setSearchScope(SearchScope.ONELEVEL); result = search.execute(onelevelRequest).getResult(); TestUtils.assertEquals(expectedResult, result); final SearchRequest objectRequest = new SearchRequest( expectedResult.getEntry().getDn(), new SearchFilter("(objectClass=*)"), returnAttrs.split("\\|")); objectRequest.setSearchScope(SearchScope.OBJECT); result = search.execute(objectRequest).getResult(); TestUtils.assertEquals(expectedResult, result); } } /** * @param filter to search with. * @param filterParameters to replace parameters in filter with. * @param returnAttrs to return from search. * @param ldifFile to compare with * * @throws Exception On test failure. */ @Parameters( { "searchFilter", "searchFilterParameters", "searchReturnAttrs", "searchResults" }) @Test(groups = {"search"}) public void jndiSearchScopes( final String filter, final String filterParameters, final String returnAttrs, final String ldifFile) throws Exception { if (!TestControl.isJndiProvider()) { return; } final SearchResult expectedResult = TestUtils.convertLdifToResult(TestUtils.readFileIntoString(ldifFile)); // test URL with baseDn included for (int i = 0; i <= 2; i++) { final ConnectionConfig cc = TestUtils.readConnectionConfig(null); cc.setLdapUrl(String.format("%s/%s", cc.getLdapUrl(), LdapUtils.percentEncode(DnParser.substring(expectedResult.getEntry().getDn(), i)))); try (Connection conn = DefaultConnectionFactory.getConnection(cc)) { conn.open(); final SearchOperation search = new SearchOperation(conn); final SearchRequest subtreeRequest = new SearchRequest( i > 0 ? DnParser.substring(expectedResult.getEntry().getDn(), 0, i) : "", new SearchFilter(filter, filterParameters.split("\\|")), returnAttrs.split("\\|")); subtreeRequest.setSearchScope(SearchScope.SUBTREE); SearchResult result = search.execute(subtreeRequest).getResult(); AssertJUnit.assertEquals(1, result.size()); TestUtils.assertEquals(expectedResult, result); final SearchRequest onelevelRequest = new SearchRequest( i > 0 ? DnParser.substring(expectedResult.getEntry().getDn(), 0, i) : "", new SearchFilter(filter, filterParameters.split("\\|")), returnAttrs.split("\\|")); onelevelRequest.setSearchScope(SearchScope.ONELEVEL); result = search.execute(onelevelRequest).getResult(); AssertJUnit.assertEquals(0, result.size()); final SearchRequest objectRequest = new SearchRequest( i > 0 ? DnParser.substring(expectedResult.getEntry().getDn(), 0, i) : "", new SearchFilter("(objectClass=*)"), returnAttrs.split("\\|")); objectRequest.setSearchScope(SearchScope.OBJECT); result = search.execute(objectRequest).getResult(); AssertJUnit.assertEquals(1, result.size()); TestUtils.assertEquals(expectedResult, result); } } } /** * @param dn to search on. * @param filter to search with. * @param filterParameters to replace parameters in filter with. * @param ldifFile to compare with * * @throws Exception On test failure. */ @Parameters( { "searchDn", "searchFilter", "searchFilterParameters", "searchResults" }) @Test(groups = {"search"}) public void returnAttributesSearch( final String dn, final String filter, final String filterParameters, final String ldifFile) throws Exception { final SearchOperation search = new SearchOperation(createLdapConnection(false)); final String expected = TestUtils.readFileIntoString(ldifFile); final SearchResult entryDnResult = TestUtils.convertLdifToResult(expected); // test searching, no attributes SearchResult result = search.execute( new SearchRequest( dn, new SearchFilter(filter, filterParameters.split("\\|")), ReturnAttributes.NONE.value())).getResult(); AssertJUnit.assertNotNull(result.getEntry()); AssertJUnit.assertTrue(result.getEntry().getAttributes().isEmpty()); // test searching, user attributes result = search.execute( new SearchRequest( dn, new SearchFilter(filter, filterParameters.split("\\|")), ReturnAttributes.ALL_USER.value())).getResult(); AssertJUnit.assertNotNull(result.getEntry()); AssertJUnit.assertNotNull(result.getEntry().getAttribute("cn")); AssertJUnit.assertNull(result.getEntry().getAttribute("createTimestamp")); // test searching, operations attributes if (TestControl.isActiveDirectory() || TestControl.isOracleDirectory()) { // directory ignores '+' result = search.execute( new SearchRequest( dn, new SearchFilter(filter, filterParameters.split("\\|")), ReturnAttributes.ALL_OPERATIONAL.add("createTimestamp"))).getResult(); } else { result = search.execute( new SearchRequest( dn, new SearchFilter(filter, filterParameters.split("\\|")), ReturnAttributes.ALL_OPERATIONAL.value())).getResult(); } AssertJUnit.assertNotNull(result.getEntry()); AssertJUnit.assertNull(result.getEntry().getAttribute("cn")); AssertJUnit.assertNotNull(result.getEntry().getAttribute("createTimestamp")); // test searching, all attributes if (TestControl.isActiveDirectory() || TestControl.isOracleDirectory()) { // directory ignores '+' result = search.execute( new SearchRequest( dn, new SearchFilter(filter, filterParameters.split("\\|")), ReturnAttributes.ALL.add("createTimestamp"))).getResult(); } else { result = search.execute( new SearchRequest( dn, new SearchFilter(filter, filterParameters.split("\\|")), ReturnAttributes.ALL.value())).getResult(); } AssertJUnit.assertNotNull(result.getEntry()); AssertJUnit.assertNotNull(result.getEntry().getAttribute("cn")); AssertJUnit.assertNotNull(result.getEntry().getAttribute("createTimestamp")); } /** * @param dn to search on. * @param filter to search with. * @param returnAttrs to return from search. * @param ldifFile to compare with * * @throws Exception On test failure. */ @Parameters( { "pagedSearchDn", "pagedSearchFilter", "pagedSearchReturnAttrs", "pagedSearchResults" }) @Test(groups = {"search"}) public void pagedSearch(final String dn, final String filter, final String returnAttrs, final String ldifFile) throws Exception { final PagedResultsControl prc = new PagedResultsControl(1, true); try (Connection conn = TestUtils.createConnection()) { conn.open(); final SearchOperation search = new SearchOperation(conn); final String expected = TestUtils.readFileIntoString(ldifFile); // test searching final SearchRequest request = new SearchRequest(dn, new SearchFilter(filter), returnAttrs.split("\\|")); request.setControls(prc); final SearchResult result = new SearchResult(); byte[] cookie = null; do { prc.setCookie(cookie); final Response<SearchResult> response = search.execute(request); result.addEntries(response.getResult().getEntries()); cookie = null; final PagedResultsControl ctl = (PagedResultsControl) response.getControl(PagedResultsControl.OID); if (ctl != null) { if (ctl.getCookie() != null && ctl.getCookie().length > 0) { cookie = ctl.getCookie(); } } } while (cookie != null); // ignore the case of member and contactPerson; // some directories return those in mixed case AssertJUnit.assertEquals( 0, (new SearchResultIgnoreCaseComparator("member", "contactPerson")).compare( TestUtils.convertLdifToResult(expected), result)); } catch (LdapException e) { // ignore this test if not supported by the server AssertJUnit.assertEquals(ResultCode.UNAVAILABLE_CRITICAL_EXTENSION, e.getResultCode()); } catch (UnsupportedOperationException e) { // ignore this test if not supported AssertJUnit.assertNotNull(e); } } /** * @param dn to search on. * @param filter to search with. * @param returnAttrs to return from search. * @param ldifFile to compare with * * @throws Exception On test failure. */ @Parameters( { "virtualListViewSearchDn", "virtualListViewSearchFilter", "virtualListViewSearchReturnAttrs", "virtualListViewSearchResults" }) @Test(groups = {"search"}) public void virtualListViewSearch( final String dn, final String filter, final String returnAttrs, final String ldifFile) throws Exception { // AD server says vlv is a supported control, but returns UNAVAIL_EXTENSION // OracleDS returns protocol error if (TestControl.isActiveDirectory() || TestControl.isOracleDirectory()) { return; } // provider doesn't support this control if (TestControl.isApacheProvider()) { throw new UnsupportedOperationException("Apache LDAP does not support this control"); } final SortRequestControl src = new SortRequestControl(new SortKey[] {new SortKey("uugid", "caseExactMatch")}, true); VirtualListViewRequestControl vlvrc = new VirtualListViewRequestControl(3, 1, 1, true); byte[] contextID; try (Connection conn = TestUtils.createConnection()) { conn.open(); final SearchOperation search = new SearchOperation(conn); final String expected = TestUtils.readFileIntoString(ldifFile); // test searching final SearchRequest request = new SearchRequest(dn, new SearchFilter(filter), returnAttrs.split("\\|")); request.setControls(src, vlvrc); Response<SearchResult> response = search.execute(request); SearchResult result = response.getResult(); // ignore the case of member and contactPerson; // some directories return those in mixed case AssertJUnit.assertEquals( 0, (new SearchResultIgnoreCaseComparator("member", "contactPerson")).compare( TestUtils.convertLdifToResult(expected), result)); contextID = ((VirtualListViewResponseControl) response.getControl(VirtualListViewResponseControl.OID)).getContextID(); vlvrc = new VirtualListViewRequestControl("group4", 1, 1, contextID, true); request.setControls(src, vlvrc); response = search.execute(request); result = response.getResult(); // ignore the case of member and contactPerson; // some directories return those in mixed case AssertJUnit.assertEquals( 0, (new SearchResultIgnoreCaseComparator("member", "contactPerson")).compare( TestUtils.convertLdifToResult(expected), result)); } catch (LdapException e) { // ignore this test if not supported by the server AssertJUnit.assertEquals(ResultCode.UNAVAILABLE_CRITICAL_EXTENSION, e.getResultCode()); } catch (UnsupportedOperationException e) { // ignore this test if not supported AssertJUnit.assertNotNull(e); } } /** * @param dn to search on. * @param filter to search with. * * @throws Exception On test failure. */ @Parameters( { "sortSearchDn", "sortSearchFilter" }) @Test(groups = {"search"}) public void sortedSearch(final String dn, final String filter) throws Exception { // OracleDS returns protocol error if (TestControl.isOracleDirectory()) { return; } try (Connection conn = TestUtils.createConnection()) { conn.open(); final SearchOperation search = new SearchOperation(conn); final SearchRequest request = new SearchRequest(dn, new SearchFilter(filter)); request.setSortBehavior(SortBehavior.ORDERED); // test sort by uugid SortRequestControl src = new SortRequestControl(new SortKey[] {new SortKey("uugid", "caseExactMatch")}, true); request.setControls(src); SearchResult result = search.execute(request).getResult(); // confirm sorted int i = 2; for (LdapEntry e : result.getEntries()) { AssertJUnit.assertEquals(String.valueOf(2000 + i), e.getAttribute("uid").getStringValue()); i++; } // test sort by uid src = new SortRequestControl(new SortKey[] {new SortKey("uid", "integerMatch", true)}, true); request.setControls(src); result = search.execute(request).getResult(); // confirm sorted i = 5; for (LdapEntry e : result.getEntries()) { AssertJUnit.assertEquals(String.valueOf(2000 + i), e.getAttribute("uid").getStringValue()); i--; } } catch (LdapException e) { // ignore this test if not supported by the server AssertJUnit.assertEquals(ResultCode.UNAVAILABLE_CRITICAL_EXTENSION, e.getResultCode()); } catch (UnsupportedOperationException e) { // ignore this test if not supported by the provider AssertJUnit.assertNotNull(e); } } /** * @param authzFrom to proxy from * @param authzTo to proxy to * @param dn to search on. * @param filter to search with. * * @throws Exception On test failure. */ @Parameters( { "proxyAuthzFrom", "proxyAuthzTo", "proxyAuthzSearchDn", "proxyAuthzSearchFilter" }) @Test(groups = {"search"}) public void proxyAuthzSearch(final String authzFrom, final String authzTo, final String dn, final String filter) throws Exception { // provider doesn't support this control if (TestControl.isApacheProvider()) { throw new UnsupportedOperationException("Apache LDAP does not support this control"); } boolean addedAttribute = false; final Connection conn = TestUtils.createSetupConnection(); try { conn.open(); final SearchOperation search = new SearchOperation(conn); final SearchRequest request = new SearchRequest(dn, new SearchFilter(filter)); // no authz Response<SearchResult> response = search.execute(request); AssertJUnit.assertEquals(ResultCode.SUCCESS, response.getResultCode()); AssertJUnit.assertEquals(1, response.getResult().size()); // anonymous authz request.setControls(new ProxyAuthorizationControl("dn:")); response = search.execute(request); if (ResultCode.UNAVAILABLE_CRITICAL_EXTENSION.equals(response.getResultCode())) { // ignore this test if not supported by the server throw new UnsupportedOperationException("LDAP server does not support this control"); } AssertJUnit.assertEquals(ResultCode.SUCCESS, response.getResultCode()); AssertJUnit.assertEquals(0, response.getResult().size()); // authz denied request.setControls(new ProxyAuthorizationControl("dn:" + authzTo)); try { response = search.execute(request); AssertJUnit.assertEquals(ResultCode.AUTHORIZATION_DENIED, response.getResultCode()); } catch (LdapException e) { AssertJUnit.assertEquals(ResultCode.AUTHORIZATION_DENIED, e.getResultCode()); } // add authzTo final ModifyOperation modify = new ModifyOperation(conn); modify.execute( new ModifyRequest( authzFrom, new AttributeModification(AttributeModificationType.ADD, new LdapAttribute("authzTo", "dn:" + authzTo)))); addedAttribute = true; response = search.execute(request); AssertJUnit.assertEquals(ResultCode.SUCCESS, response.getResultCode()); AssertJUnit.assertEquals(1, response.getResult().size()); } catch (LdapException e) { // ignore this test if not supported by the server AssertJUnit.assertEquals(ResultCode.UNAVAILABLE_CRITICAL_EXTENSION, e.getResultCode()); } catch (UnsupportedOperationException e) { // ignore this test if not supported by the provider AssertJUnit.assertNotNull(e); } finally { if (addedAttribute) { try { // remove authzTo final ModifyOperation modify = new ModifyOperation(conn); modify.execute( new ModifyRequest( authzFrom, new AttributeModification(AttributeModificationType.REMOVE, new LdapAttribute("authzTo")))); } catch (LdapException e) { AssertJUnit.fail(e.getMessage()); } } conn.close(); } } /** * @param dn to search on. * @param filter to search with. * @param filterParameters to replace parameters in filter with. * @param returnAttrs to return from search. * @param ldifFile to compare with * * @throws Exception On test failure. */ @Parameters( { "recursiveSearchDn", "recursiveSearchFilter", "recursiveSearchFilterParameters", "recursiveSearchReturnAttrs", "recursiveHandlerResults" }) @Test(groups = {"search"}) public void recursiveHandlerSearch( final String dn, final String filter, final String filterParameters, final String returnAttrs, final String ldifFile) throws Exception { final SearchOperation search = new SearchOperation(createLdapConnection(false)); final String expected = TestUtils.readFileIntoString(ldifFile); // test recursive searching final RecursiveEntryHandler rsrh = new RecursiveEntryHandler("member", "uugid", "uid"); final SearchRequest sr = new SearchRequest( dn, new SearchFilter(filter, filterParameters.split("\\|")), returnAttrs.split("\\|")); sr.setSearchEntryHandlers(rsrh); final SearchResult result = search.execute(sr).getResult(); // ignore the case of member and contactPerson; some directories return // those in mixed case AssertJUnit.assertEquals( 0, (new LdapEntryIgnoreCaseComparator("member", "contactPerson")).compare( TestUtils.convertLdifToResult(expected).getEntry(), result.getEntry())); } /** * @param dn to search on. * @param filter to search with. * @param returnAttrs to return from search. * @param ldifFile to compare with * * @throws Exception On test failure. */ @Parameters( { "recursiveSearch2Dn", "recursiveSearch2Filter", "recursiveSearch2ReturnAttrs", "recursiveHandlerResults2" }) @Test(groups = {"search"}) public void recursiveHandlerSearch2( final String dn, final String filter, final String returnAttrs, final String ldifFile) throws Exception { final SearchOperation search = new SearchOperation(createLdapConnection(false)); final String expected = TestUtils.readFileIntoString(ldifFile); // test recursive searching final RecursiveEntryHandler rsrh = new RecursiveEntryHandler("member", "member"); final SearchRequest sr = new SearchRequest(dn, new SearchFilter(filter), returnAttrs.split("\\|")); sr.setSearchEntryHandlers(rsrh); final SearchResult result = search.execute(sr).getResult(); // ignore the case of member and contactPerson; some directories return // those in mixed case AssertJUnit.assertEquals( 0, (new LdapEntryIgnoreCaseComparator("member")).compare( TestUtils.convertLdifToResult(expected).getEntry(), result.getEntry())); } /** * @param dn to search on. * @param filter to search with. * @param returnAttrs to return from search. * @param ldifFile to compare with * * @throws Exception On test failure. */ @Parameters( { "mergeSearchDn", "mergeSearchFilter", "mergeSearchReturnAttrs", "mergeSearchResults" }) @Test(groups = {"search"}) public void mergeSearch(final String dn, final String filter, final String returnAttrs, final String ldifFile) throws Exception { try (Connection conn = createLdapConnection(true)) { conn.open(); final SearchOperation search = new SearchOperation(conn); final String expected = TestUtils.readFileIntoString(ldifFile); // test result merge final SearchRequest sr = new SearchRequest(dn, new SearchFilter(filter), returnAttrs.split("\\|")); sr.setSortBehavior(SortBehavior.SORTED); final SearchResult result = search.execute(sr).getResult(); // ignore the case of member and contactPerson; some directories return // those in mixed case AssertJUnit.assertEquals( 0, (new LdapEntryIgnoreCaseComparator("member", "contactPerson")).compare( TestUtils.convertLdifToResult(expected).getEntry(), SearchResult.mergeEntries(result).getEntry())); } } /** * @param dn to search on. * @param filter to search with. * @param returnAttrs to return from search. * @param ldifFile to compare with * * @throws Exception On test failure. */ @Parameters( { "mergeDuplicateSearchDn", "mergeDuplicateSearchFilter", "mergeDuplicateReturnAttrs", "mergeDuplicateSearchResults" }) @Test(groups = {"search"}) public void mergeDuplicateSearch( final String dn, final String filter, final String returnAttrs, final String ldifFile) throws Exception { try (Connection conn = createLdapConnection(true)) { conn.open(); final SearchOperation search = new SearchOperation(conn); final String expected = TestUtils.readFileIntoString(ldifFile); // test result merge final SearchRequest sr = new SearchRequest(dn, new SearchFilter(filter), returnAttrs.split("\\|")); sr.setSortBehavior(SortBehavior.SORTED); final SearchResult result = search.execute(sr).getResult(); // ignore the case of member and contactPerson; some directories return // those in mixed case AssertJUnit.assertEquals( 0, (new LdapEntryIgnoreCaseComparator("member", "contactPerson")).compare( TestUtils.convertLdifToResult(expected).getEntry(), SearchResult.mergeEntries(result).getEntry())); } } /** * @param dn to search on. * @param filter to search with. * @param returnAttrs to return from search. * @param ldifFile to compare with * * @throws Exception On test failure. */ @Parameters( { "mergeAttributeSearchDn", "mergeAttributeSearchFilter", "mergeAttributeReturnAttrs", "mergeAttributeSearchResults" }) @Test(groups = {"search"}) public void mergeAttributeSearch( final String dn, final String filter, final String returnAttrs, final String ldifFile) throws Exception { try (Connection conn = createLdapConnection(true)) { conn.open(); final SearchOperation search = new SearchOperation(conn); final String expected = TestUtils.readFileIntoString(ldifFile); // test merge searching final MergeAttributeEntryHandler handler = new MergeAttributeEntryHandler(); handler.setMergeAttributeName("cn"); handler.setAttributeNames("displayName", "givenName", "sn"); final SearchRequest sr = new SearchRequest(dn, new SearchFilter(filter), returnAttrs.split("\\|")); sr.setSearchEntryHandlers(handler); sr.setSortBehavior(SortBehavior.SORTED); final SearchResult result = search.execute(sr).getResult(); TestUtils.assertEquals(TestUtils.convertLdifToResult(expected), result); } } /** * @param dn to search on. * @param filter to search with. * @param returnAttr to return from search. * @param base64Value to compare with * * @throws Exception On test failure. */ @Parameters( { "binarySearchDn", "binarySearchFilter", "binarySearchReturnAttr", "binarySearchResult" }) @Test(groups = {"search"}) public void binarySearch(final String dn, final String filter, final String returnAttr, final String base64Value) throws Exception { final SearchOperation search = new SearchOperation(createLdapConnection(false)); // test binary searching SearchRequest request = new SearchRequest(dn, new SearchFilter(filter), returnAttr); request.setBinaryAttributes(returnAttr); SearchResult result = search.execute(request).getResult(); AssertJUnit.assertTrue(result.getEntry().getAttribute().isBinary()); AssertJUnit.assertEquals(base64Value, result.getEntry().getAttribute().getStringValue()); request = new SearchRequest(dn, new SearchFilter(filter), "sn"); result = search.execute(request).getResult(); AssertJUnit.assertFalse(result.getEntry().getAttribute().isBinary()); AssertJUnit.assertNotNull(result.getEntry().getAttribute().getBinaryValue()); request = new SearchRequest(dn, new SearchFilter(filter), "sn"); request.setBinaryAttributes("sn"); result = search.execute(request).getResult(); AssertJUnit.assertTrue(result.getEntry().getAttribute().isBinary()); AssertJUnit.assertNotNull(result.getEntry().getAttribute().getBinaryValue()); request = new SearchRequest(dn, new SearchFilter(filter), "userCertificate;binary"); result = search.execute(request).getResult(); AssertJUnit.assertTrue(result.getEntry().getAttribute().isBinary()); AssertJUnit.assertNotNull(result.getEntry().getAttribute().getBinaryValue()); } /** * @param dn to search on. * @param filter to search with. * @param filterParameters to replace parameters in filter with. * @param returnAttrs to return from search. * @param ldifFile to compare with * * @throws Exception On test failure. */ @Parameters( { "searchDn", "searchFilter", "searchFilterParameters", "searchReturnAttrs", "searchResults" }) @Test(groups = {"search"}) public void caseChangeSearch( final String dn, final String filter, final String filterParameters, final String returnAttrs, final String ldifFile) throws Exception { try (Connection conn = createLdapConnection(true)) { conn.open(); final SearchOperation search = new SearchOperation(conn); final CaseChangeEntryHandler srh = new CaseChangeEntryHandler(); final String expected = TestUtils.readFileIntoString(ldifFile); // test no case change final SearchResult noChangeResult = TestUtils.convertLdifToResult(expected); SearchRequest sr = new SearchRequest( dn, new SearchFilter(filter, filterParameters.split("\\|")), returnAttrs.split("\\|")); sr.setSearchEntryHandlers(srh); SearchResult result = search.execute(sr).getResult(); TestUtils.assertEquals(noChangeResult, result); // test lower case attribute values srh.setAttributeNameCaseChange(CaseChange.NONE); srh.setAttributeValueCaseChange(CaseChange.LOWER); srh.setDnCaseChange(CaseChange.NONE); final SearchResult lcValuesChangeResult = TestUtils.convertLdifToResult(expected); for (LdapAttribute la : lcValuesChangeResult.getEntry().getAttributes()) { final Set<String> s = la.getStringValues().stream().map(String::toLowerCase).collect(Collectors.toSet()); la.clear(); la.addStringValues(s); } sr = new SearchRequest(dn, new SearchFilter(filter, filterParameters.split("\\|")), returnAttrs.split("\\|")); sr.setSearchEntryHandlers(srh); result = search.execute(sr).getResult(); TestUtils.assertEquals(lcValuesChangeResult, result); // test upper case attribute names srh.setAttributeNameCaseChange(CaseChange.UPPER); srh.setAttributeValueCaseChange(CaseChange.NONE); srh.setDnCaseChange(CaseChange.NONE); final SearchResult ucNamesChangeResult = TestUtils.convertLdifToResult(expected); for (LdapAttribute la : ucNamesChangeResult.getEntry().getAttributes()) { la.setName(la.getName().toUpperCase()); } sr = new SearchRequest(dn, new SearchFilter(filter, filterParameters.split("\\|")), returnAttrs.split("\\|")); sr.setSearchEntryHandlers(srh); result = search.execute(sr).getResult(); TestUtils.assertEquals(ucNamesChangeResult, result); // test lower case everything srh.setAttributeNameCaseChange(CaseChange.LOWER); srh.setAttributeValueCaseChange(CaseChange.LOWER); srh.setDnCaseChange(CaseChange.LOWER); final SearchResult lcAllChangeResult = TestUtils.convertLdifToResult(expected); for (LdapAttribute la : ucNamesChangeResult.getEntry().getAttributes()) { lcAllChangeResult.getEntry().setDn(lcAllChangeResult.getEntry().getDn().toLowerCase()); la.setName(la.getName().toLowerCase()); final Set<String> s = la.getStringValues().stream().map(String::toLowerCase).collect(Collectors.toSet()); la.clear(); la.addStringValues(s); } sr = new SearchRequest(dn, new SearchFilter(filter, filterParameters.split("\\|")), returnAttrs.split("\\|")); sr.setSearchEntryHandlers(srh); result = search.execute(sr).getResult(); TestUtils.assertEquals(ucNamesChangeResult, result); // test lower case specific attributes srh.setAttributeNames("givenName"); srh.setAttributeNameCaseChange(CaseChange.NONE); srh.setAttributeValueCaseChange(CaseChange.LOWER); srh.setDnCaseChange(CaseChange.NONE); final SearchResult lcgivenNameChangeResult = TestUtils.convertLdifToResult(expected); lcgivenNameChangeResult.getEntry().getAttributes().stream().filter( la -> la.getName().equals("givenName")).forEach(la -> { final Set<String> s = la.getStringValues().stream().map(String::toLowerCase).collect(Collectors.toSet()); la.clear(); la.addStringValues(s); }); sr = new SearchRequest(dn, new SearchFilter(filter, filterParameters.split("\\|")), returnAttrs.split("\\|")); sr.setSearchEntryHandlers(srh); result = search.execute(sr).getResult(); TestUtils.assertEquals(lcgivenNameChangeResult, result); } } /** * @param dn to search on. * @param filter to search with. * @param returnAttrs to return from search. * @param ldifFile to compare with * * @throws Exception On test failure. */ @Parameters( { "rangeSearchDn", "rangeSearchFilter", "rangeSearchReturnAttrs", "rangeHandlerResults" }) @Test(groups = {"search"}) public void rangeHandlerSearch(final String dn, final String filter, final String returnAttrs, final String ldifFile) throws Exception { if (!TestControl.isActiveDirectory()) { return; } // OpenDJ will not parse DNs used by this entry handler if (TestControl.isOpenDJProvider()) { return; } final String expected = TestUtils.readFileIntoString(ldifFile); try (Connection conn = createLdapConnection(true)) { conn.open(); final SearchOperation search = new SearchOperation(conn); final SearchRequest sr = new SearchRequest(dn, new SearchFilter(filter), returnAttrs.split("\\|")); sr.setSearchEntryHandlers(new RangeEntryHandler(), new ObjectSidHandler(), new ObjectGuidHandler()); final SearchResult result = search.execute(sr).getResult(); // ignore the case of member; some directories return it in mixed case AssertJUnit.assertEquals( 0, (new LdapEntryIgnoreCaseComparator("member")).compare( TestUtils.convertLdifToResult(expected).getEntry(), result.getEntry())); } catch (LdapException e) { // some providers don't support this DN syntax AssertJUnit.assertEquals(ResultCode.DECODING_ERROR, e.getResultCode()); } } /** * @param dn to search on. * @param filter to search with. * * @throws Exception On test failure. */ @Parameters( { "statsSearchDn", "statsSearchFilter" }) @Test(groups = {"search"}) public void getStatsSearch(final String dn, final String filter) throws Exception { if (!TestControl.isActiveDirectory()) { return; } // provider doesn't support this control if (TestControl.isApacheProvider()) { throw new UnsupportedOperationException("Apache LDAP does not support this control"); } try (Connection conn = createLdapConnection(true)) { conn.open(); final SearchOperation search = new SearchOperation(conn); final SearchRequest sr = new SearchRequest(dn, new SearchFilter(filter)); sr.setSearchEntryHandlers(new ObjectSidHandler(), new ObjectGuidHandler()); sr.setControls(new GetStatsControl()); final Response<SearchResult> response = search.execute(sr); final GetStatsControl ctrl = (GetStatsControl) response.getControl(GetStatsControl.OID); AssertJUnit.assertTrue(ctrl.getStatistics().size() > 1); final LdapAttribute whenCreated = response.getResult().getEntry().getAttribute("whenCreated"); AssertJUnit.assertNotNull(whenCreated.getValue(new GeneralizedTimeValueTranscoder())); final LdapAttribute whenChanged = response.getResult().getEntry().getAttribute("whenChanged"); AssertJUnit.assertNotNull(whenChanged.getValue(new GeneralizedTimeValueTranscoder())); } catch (UnsupportedOperationException e) { // ignore this test if not supported by the provider AssertJUnit.assertNotNull(e); } } /** * @param host for verify name * @param dn to search on. * @param filter to search with. * * @throws Exception On test failure. */ @Parameters( { "miscADControlsHost", "miscADControlsDn", "miscADControlsFilter" }) @Test(groups = {"search"}) public void miscADControlsSearch(final String host, final String dn, final String filter) throws Exception { if (!TestControl.isActiveDirectory()) { return; } // provider doesn't support this control if (TestControl.isApacheProvider()) { throw new UnsupportedOperationException("Apache LDAP does not support this control"); } try (Connection conn = createLdapConnection(true)) { conn.open(); final SearchOperation search = new SearchOperation(conn); final SearchRequest sr = new SearchRequest(dn, new SearchFilter(filter)); sr.setSearchEntryHandlers(new ObjectSidHandler(), new ObjectGuidHandler()); sr.setControls( new ForceUpdateControl(), new LazyCommitControl(), /* * new NotificationControl()); * new VerifyNameControl(host)); */ new PermissiveModifyControl(), new RangeRetrievalNoerrControl(), new SearchOptionsControl(), new ShowDeactivatedLinkControl(), new ShowDeletedControl(), new ShowRecycledControl()); search.execute(sr); } catch (UnsupportedOperationException e) { // ignore this test if not supported by the provider AssertJUnit.assertNotNull(e); } } /** * @param dn to search on. * @param filter to search with. * @param filterParameters to replace parameters in filter with. * @param binaryFilter to search for binary attributes. * @param binaryFilterParameters to replace parameters in binary filter with. * @param returnAttrs to return from search. * @param ldifFile to compare with. * * @throws Exception On test failure. */ @Parameters( { "specialCharSearchDn", "specialCharSearchFilter", "specialCharSearchFilterParameters", "specialCharBinarySearchFilter", "specialCharBinarySearchFilterParameters", "specialCharReturnAttrs", "specialCharSearchResults" }) @Test(groups = {"search"}) public void specialCharsSearch( final String dn, final String filter, final String filterParameters, final String binaryFilter, final String binaryFilterParameters, final String returnAttrs, final String ldifFile) throws Exception { final SearchOperation search = new SearchOperation(createLdapConnection(false)); final String expected = TestUtils.readFileIntoString(ldifFile); final SearchResult specialCharsResult = TestUtils.convertLdifToResult(expected); SearchResult result = search.execute( new SearchRequest( dn, new SearchFilter(filter, filterParameters.split("\\|")), returnAttrs.split("\\|"))).getResult(); // DNs returned from JNDI may have escaped characters result.getEntry().setDn(result.getEntry().getDn().replaceAll("\\\\", "")); TestUtils.assertEquals(specialCharsResult, result); result = search.execute( new SearchRequest( dn, new SearchFilter( binaryFilter, new Object[] {LdapUtils.base64Decode(binaryFilterParameters)}), returnAttrs.split("\\|"))).getResult(); // DNs returned from JNDI may have escaped characters result.getEntry().setDn(result.getEntry().getDn().replaceAll("\\\\", "")); TestUtils.assertEquals(specialCharsResult, result); } /** * @param dn to search on. * @param filter to search with. * @param ldifFile to compare with * * @throws Exception On test failure. */ @Parameters( { "rewriteSearchDn", "rewriteSearchFilter", "rewriteSearchResults" }) @Test(groups = {"search"}) public void rewriteSearch(final String dn, final String filter, final String ldifFile) throws Exception { if (TestControl.isActiveDirectory()) { return; } final String expected = TestUtils.readFileIntoString(ldifFile); final SearchResult specialCharsResult = TestUtils.convertLdifToResult(expected); specialCharsResult.getEntry().setDn(specialCharsResult.getEntry().getDn().replaceAll("\\\\", "")); try (Connection conn = createLdapConnection(true)) { conn.open(); final SearchOperation search = new SearchOperation(conn); // test special character searching final SearchRequest request = new SearchRequest(dn, new SearchFilter(filter)); final SearchResult result = search.execute(request).getResult(); TestUtils.assertEquals(specialCharsResult, result); } catch (LdapException e) { // ignore this test if not supported by the server AssertJUnit.assertEquals(ResultCode.NO_SUCH_OBJECT, e.getResultCode()); } } /** * @param dn to search on. * @param filter to search with. * @param resultsSize of search results. * * @throws Exception On test failure. */ @Parameters( { "searchExceededDn", "searchExceededFilter", "searchExceededResultsSize" }) @Test(groups = {"search"}) public void searchExceeded(final String dn, final String filter, final int resultsSize) throws Exception { try (Connection conn = createLdapConnection(true)) { conn.open(); final SearchOperation search = new SearchOperation(conn); final SearchRequest request = new SearchRequest(); request.setBaseDn(dn); request.setSizeLimit(resultsSize); request.setSearchFilter(new SearchFilter("(uugid=*)")); Response<SearchResult> response = search.execute(request); AssertJUnit.assertEquals(resultsSize, response.getResult().size()); AssertJUnit.assertEquals(ResultCode.SIZE_LIMIT_EXCEEDED, response.getResultCode()); request.setSearchFilter(new SearchFilter(filter)); response = search.execute(request); AssertJUnit.assertEquals(resultsSize, response.getResult().size()); AssertJUnit.assertEquals(ResultCode.SUCCESS, response.getResultCode()); } } /** * @param dn to search on. * @param filter to search with. * * @throws Exception On test failure. */ @Parameters( { "searchReferralDn", "searchReferralFilter" }) @Test(groups = {"search"}) public void searchReferral(final String dn, final String filter) throws Exception { if (TestControl.isActiveDirectory() || TestControl.isOracleDirectory()) { return; } final Connection conn = createLdapConnection(true); // expects a referral on the dn ou=referrals final String referralDn = "ou=referrals," + DnParser.substring(dn, 1); final SearchRequest request = new SearchRequest(); request.setBaseDn(referralDn); request.setSearchScope(SearchScope.ONELEVEL); request.setReturnAttributes(ReturnAttributes.NONE.value()); request.setSearchFilter(new SearchFilter(filter)); try { conn.open(); final SearchOperation search = new SearchOperation(conn); try { final Response<SearchResult> response = search.execute(request); AssertJUnit.assertEquals(ResultCode.REFERRAL, response.getResultCode()); AssertJUnit.assertTrue(response.getReferralURLs().length > 0); for (String s : response.getReferralURLs()) { AssertJUnit.assertTrue(response.getReferralURLs()[0].startsWith(conn.getConnectionConfig().getLdapUrl())); } } catch (LdapException e) { AssertJUnit.assertEquals(ResultCode.REFERRAL, e.getResultCode()); AssertJUnit.assertTrue(e.getReferralURLs().length > 0); for (String s : e.getReferralURLs()) { AssertJUnit.assertTrue(e.getReferralURLs()[0].startsWith(conn.getConnectionConfig().getLdapUrl())); } } } finally { conn.close(); } request.setReferralHandler(new SearchReferralHandler()); try { conn.open(); final SearchOperation search = new SearchOperation(conn); try { final Response<SearchResult> response = search.execute(request); if (response.getResultCode() == ResultCode.SUCCESS) { AssertJUnit.assertTrue(response.getResult().size() > 0); } else { // some providers don't support authenticated referrals AssertJUnit.assertEquals(ResultCode.REFERRAL, response.getResultCode()); } } catch (UnsupportedOperationException e) { // ignore this test if not supported AssertJUnit.assertNotNull(e); } } finally { conn.close(); } } /** * @param dn to search on. * @param filter to search with. * * @throws Exception On test failure. */ @Parameters( { "searchReferenceDn", "searchReferenceFilter" }) @Test(groups = {"search"}) public void searchReference(final String dn, final String filter) throws Exception { if (TestControl.isActiveDirectory() || TestControl.isOracleDirectory()) { return; } final Connection conn = createLdapConnection(true); final List<SearchReference> refs = new ArrayList<>(); // expects a referral on the root dn final String referralDn = DnParser.substring(dn, 1); final SearchRequest request = new SearchRequest(); request.setBaseDn(referralDn); request.setSearchScope(SearchScope.ONELEVEL); request.setReturnAttributes(ReturnAttributes.NONE.value()); request.setSearchFilter(new SearchFilter(filter)); request.setSearchReferenceHandlers( new SearchReferenceHandler() { @Override public HandlerResult<SearchReference> handle( final Connection conn, final SearchRequest request, final SearchReference reference) throws LdapException { refs.add(reference); return new HandlerResult<>(reference); } @Override public void initializeRequest(final SearchRequest request) {} }); try { conn.open(); final SearchOperation search = new SearchOperation(conn); final Response<SearchResult> response = search.execute(request); AssertJUnit.assertTrue(response.getResult().size() > 0); // some providers don't support search references // in that case URLs are provided on the response if (refs.size() > 0) { AssertJUnit.assertTrue(refs.size() > 0); for (SearchReference r : refs) { AssertJUnit.assertNotNull(r.getReferralUrls()); for (String s : r.getReferralUrls()) { AssertJUnit.assertNotNull(s); } } } else { AssertJUnit.assertTrue(response.getReferralURLs().length > 0); for (String s : response.getReferralURLs()) { AssertJUnit.assertTrue(response.getReferralURLs()[0].startsWith(conn.getConnectionConfig().getLdapUrl())); } } // providers may return either result code if (response.getResultCode() != ResultCode.SUCCESS && response.getResultCode() != ResultCode.REFERRAL) { AssertJUnit.fail("Invalid result code: " + response); } } finally { conn.close(); } refs.clear(); request.setReferralHandler(new SearchReferralHandler(3)); try { conn.open(); final SearchOperation search = new SearchOperation(conn); try { final Response<SearchResult> response = search.execute(request); // providers may return either result code if ( response.getResultCode() != ResultCode.SUCCESS && response.getResultCode() != ResultCode.REFERRAL && response.getResultCode() != ResultCode.PARTIAL_RESULTS) { AssertJUnit.fail("Invalid result code: " + response); } AssertJUnit.assertTrue(response.getResult().size() > 0); } catch (LdapException e) { if (e.getCause() instanceof UnsupportedOperationException) { // ignore this test if not supported AssertJUnit.assertNotNull(e); } else { AssertJUnit.assertEquals(ResultCode.REFERRAL, e.getResultCode()); } } catch (UnsupportedOperationException e) { // ignore this test if not supported AssertJUnit.assertNotNull(e); } } finally { conn.close(); } } /** * @param dn to search on. * @param filter to search with. * * @throws Exception On test failure. */ @Parameters( { "searchActiveDirectoryDn", "searchActiveDirectoryFilter" }) @Test(groups = {"search"}) public void searchActiveDirectory(final String dn, final String filter) throws Exception { if (!TestControl.isActiveDirectory()) { return; } final Connection conn = createLdapConnection(true); final List<SearchReference> refs = new ArrayList<>(); // expects a referral on the root dn final String referralDn = DnParser.substring(dn, 1); final SearchRequest request = new SearchRequest(); request.setBaseDn(referralDn); request.setSearchScope(SearchScope.ONELEVEL); request.setReturnAttributes(ReturnAttributes.NONE.value()); request.setSearchFilter(new SearchFilter(filter)); request.setSearchEntryHandlers(new ObjectSidHandler(), new ObjectGuidHandler(), new PrimaryGroupIdHandler()); request.setSearchReferenceHandlers( new SearchReferenceHandler() { @Override public HandlerResult<SearchReference> handle( final Connection conn, final SearchRequest request, final SearchReference reference) throws LdapException { refs.add(reference); return new HandlerResult<>(reference); } @Override public void initializeRequest(final SearchRequest request) {} }); try { conn.open(); final SearchOperation search = new SearchOperation(conn); final Response<SearchResult> response = search.execute(request); AssertJUnit.assertTrue(response.getResult().size() > 0); // some providers don't support search references // in that case URLs are provided on the response if (refs.size() > 0) { AssertJUnit.assertTrue(refs.size() > 0); for (SearchReference r : refs) { AssertJUnit.assertNotNull(r.getReferralUrls()); for (String s : r.getReferralUrls()) { AssertJUnit.assertNotNull(s); } } } else { AssertJUnit.assertTrue(response.getReferralURLs().length > 0); for (String s : response.getReferralURLs()) { AssertJUnit.assertNotNull(s); } } // AssertJUnit.assertTrue(response.getReferralURLs().length > 0); // providers may return either result code if (response.getResultCode() != ResultCode.SUCCESS && response.getResultCode() != ResultCode.REFERRAL) { AssertJUnit.fail("Invalid result code: " + response); } } finally { conn.close(); } refs.clear(); request.setReferralHandler(new SearchReferralHandler()); try { conn.open(); final SearchOperation search = new SearchOperation(conn); try { final Response<SearchResult> response = search.execute(request); AssertJUnit.assertTrue(response.getResult().size() > 0); // AssertJUnit.assertNull(response.getReferralURLs()); // AD referrals cannot be followed // providers may return either result code if (response.getResultCode() != ResultCode.SUCCESS && response.getResultCode() != ResultCode.PARTIAL_RESULTS) { AssertJUnit.fail("Invalid result code: " + response); } } catch (LdapException e) { // some providers throw referral exception here AssertJUnit.assertEquals(ResultCode.REFERRAL, e.getResultCode()); } catch (UnsupportedOperationException e) { // ignore this test if referrals not supported AssertJUnit.assertNotNull(e); } } finally { conn.close(); } } /** * @param dn to search on. * @param resultCode to retry operations on. * * @throws Exception On test failure. */ @Parameters( { "searchRetryDn", "searchRetryResultCode" }) @Test(groups = {"search-with-retry"}, dependsOnGroups = {"search"}) public void searchWithRetry(final String dn, final String resultCode) throws Exception { final ResultCode retryResultCode = ResultCode.valueOf(resultCode); final ConnectionConfig cc = TestUtils.readConnectionConfig(null); DefaultConnectionFactory cf = new DefaultConnectionFactory(cc); cf.getProvider().getProviderConfig().setOperationExceptionResultCodes(retryResultCode); Connection conn = cf.getConnection(); RetrySearchOperation search = new RetrySearchOperation( conn, new LdapException("Retry search exception", ResultCode.NO_SUCH_OBJECT)); try { conn.open(); // test no retry search.setAllowRetry(false); try { final Response<SearchResult> response = search.execute( new SearchRequest(dn, new SearchFilter("(objectclass=*)"))); AssertJUnit.fail("Should have thrown LdapException, returned: " + response); } catch (LdapException e) { AssertJUnit.assertEquals(ResultCode.NO_SUCH_OBJECT, e.getResultCode()); } AssertJUnit.assertEquals(0, search.getRetryCount()); AssertJUnit.assertEquals(0, search.getRunTime()); } finally { conn.close(); } // test no exception search.setAllowRetry(true); cf = new DefaultConnectionFactory(cc); cf.getProvider().getProviderConfig().setOperationExceptionResultCodes((ResultCode[]) null); conn = cf.getConnection(); search = new RetrySearchOperation(conn, new LdapException("Retry search exception", ResultCode.NO_SUCH_OBJECT)); try { conn.open(); try { final Response<SearchResult> response = search.execute( new SearchRequest(dn, new SearchFilter("(objectclass=*)"))); AssertJUnit.assertEquals(ResultCode.NO_SUCH_OBJECT, response.getResultCode()); } catch (LdapException e) { AssertJUnit.assertEquals(ResultCode.NO_SUCH_OBJECT, e.getResultCode()); } AssertJUnit.assertEquals(0, search.getRetryCount()); AssertJUnit.assertEquals(0, search.getRunTime()); } finally { conn.close(); } // test retry count and wait time cf = new DefaultConnectionFactory(cc); cf.getProvider().getProviderConfig().setOperationExceptionResultCodes(retryResultCode); conn = cf.getConnection(); search = new RetrySearchOperation(conn, new LdapException("Retry search exception", ResultCode.NO_SUCH_OBJECT)); search.setReopenRetry(3); search.setReopenRetryWait(1); try { conn.open(); try { final Response<SearchResult> response = search.execute( new SearchRequest(dn, new SearchFilter("(objectclass=*)"))); AssertJUnit.fail("Should have thrown LdapException, returned: " + response); } catch (LdapException e) { AssertJUnit.assertEquals(ResultCode.NO_SUCH_OBJECT, e.getResultCode()); } AssertJUnit.assertEquals(3, search.getRetryCount()); AssertJUnit.assertTrue(search.getRunTime() > 0); // test backoff interval search.reset(); search.setReopenRetryBackoff(2); try { final Response<SearchResult> response = search.execute( new SearchRequest(dn, new SearchFilter("(objectclass=*)"))); AssertJUnit.fail("Should have thrown LdapException, returned: " + response); } catch (LdapException e) { AssertJUnit.assertEquals(ResultCode.NO_SUCH_OBJECT, e.getResultCode()); } AssertJUnit.assertEquals(3, search.getRetryCount()); AssertJUnit.assertTrue(search.getRunTime() > 0); // test infinite retries search.reset(); search.setStopCount(10); search.setReopenRetry(-1); try { final Response<SearchResult> response = search.execute( new SearchRequest(dn, new SearchFilter("(objectclass=*)"))); AssertJUnit.fail("Should have thrown LdapException, returned: " + response); } catch (LdapException e) { AssertJUnit.assertEquals(ResultCode.NO_SUCH_OBJECT, e.getResultCode()); } AssertJUnit.assertEquals(10, search.getRetryCount()); AssertJUnit.assertTrue(search.getRunTime() > 0); } finally { conn.close(); } } /** * @param dn to search on. * @param returnAttrs to return from search. * @param results to compare with * * @throws Exception On test failure. */ @Parameters( { "getAttributesDn", "getAttributesReturnAttrs", "getAttributesResults" }) @Test( groups = {"search"}, threadPoolSize = TEST_THREAD_POOL_SIZE, invocationCount = TEST_INVOCATION_COUNT, timeOut = TEST_TIME_OUT) public void getAttributes(final String dn, final String returnAttrs, final String results) throws Exception { final Connection conn = createLdapConnection(false); final SearchOperation search = new SearchOperation(conn); final SearchResult result = search.execute( SearchRequest.newObjectScopeSearchRequest(dn, returnAttrs.split("\\|"))).getResult(); TestUtils.assertEquals(TestUtils.convertStringToEntry(dn, results), result.getEntry()); } /** * @param dn to search on. * @param returnAttrs to return from search. * @param results to compare with * * @throws Exception On test failure. */ @Parameters( { "getAttributesBase64Dn", "getAttributesBase64ReturnAttrs", "getAttributesBase64Results" }) @Test(groups = {"search"}) public void getAttributesBase64(final String dn, final String returnAttrs, final String results) throws Exception { try (Connection conn = createLdapConnection(true)) { conn.open(); final SearchOperation search = new SearchOperation(conn); final SearchRequest request = SearchRequest.newObjectScopeSearchRequest(dn, returnAttrs.split("\\|")); request.setBinaryAttributes("jpegPhoto"); final SearchResult result = search.execute(request).getResult(); AssertJUnit.assertEquals( TestUtils.convertStringToEntry(dn, results).getAttribute("jpegPhoto").getStringValue(), result.getEntry().getAttribute("jpegPhoto").getStringValue()); } } /** @throws Exception On test failure. */ @Test(groups = {"search"}) public void getSaslMechanisms() throws Exception { try (Connection conn = createLdapConnection(true)) { conn.open(); final SearchOperation search = new SearchOperation(conn); final SearchResult result = search.execute( SearchRequest.newObjectScopeSearchRequest("", new String[] {"supportedSASLMechanisms"})).getResult(); AssertJUnit.assertTrue(result.getEntry().getAttributes().size() > 0); } } /** @throws Exception On test failure. */ @Test(groups = {"search"}) public void getSupportedControls() throws Exception { try (Connection conn = createLdapConnection(true)) { conn.open(); final SearchOperation search = new SearchOperation(conn); final SearchResult result = search.execute( SearchRequest.newObjectScopeSearchRequest("", new String[] {"supportedcontrol"})).getResult(); AssertJUnit.assertTrue(result.getEntry().getAttributes().size() > 0); } } /** * @param dn to search on. * @param filter to search with. * @param filterParameters to replace parameters in filter with. * @param returnAttrs to return from search. * @param ldifFile to compare with * * @throws Exception On test failure. */ @Parameters( { "digestMd5SearchDn", "digestMd5SearchFilter", "digestMd5SearchFilterParameters", "digestMd5SearchReturnAttrs", "digestMd5SearchResults" }) @Test(groups = {"search"}) public void digestMd5Search( final String dn, final String filter, final String filterParameters, final String returnAttrs, final String ldifFile) throws Exception { // TODO ignore active directory until it's configured if (TestControl.isActiveDirectory()) { return; } final String expected = TestUtils.readFileIntoString(ldifFile); try (Connection conn = TestUtils.createDigestMd5Connection()) { conn.open(); final SearchOperation search = new SearchOperation(conn); final SearchResult result = search.execute( new SearchRequest( dn, new SearchFilter(filter, filterParameters.split("\\|")), returnAttrs.split("\\|"))).getResult(); TestUtils.assertEquals(TestUtils.convertLdifToResult(expected), result); } } /** * @param dn to search on. * @param filter to search with. * @param filterParameters to replace parameters in filter with. * @param returnAttrs to return from search. * @param ldifFile to compare with * * @throws Exception On test failure. */ @Parameters( { "cramMd5SearchDn", "cramMd5SearchFilter", "cramMd5SearchFilterParameters", "cramMd5SearchReturnAttrs", "cramMd5SearchResults" }) @Test(groups = {"search"}) public void cramMd5Search( final String dn, final String filter, final String filterParameters, final String returnAttrs, final String ldifFile) throws Exception { // TODO ignore active directory until it's configured if (TestControl.isActiveDirectory()) { return; } final String expected = TestUtils.readFileIntoString(ldifFile); try (Connection conn = TestUtils.createCramMd5Connection()) { conn.open(); final SearchOperation search = new SearchOperation(conn); final SearchResult result = search.execute( new SearchRequest( dn, new SearchFilter(filter, filterParameters.split("\\|")), returnAttrs.split("\\|"))).getResult(); TestUtils.assertEquals(TestUtils.convertLdifToResult(expected), result); } catch (LdapException e) { // ignore this test if not supported by the server AssertJUnit.assertEquals(ResultCode.AUTH_METHOD_NOT_SUPPORTED, e.getResultCode()); } catch (UnsupportedOperationException e) { // ignore this test if not supported by the provider AssertJUnit.assertNotNull(e); } } /** * @param dn to search on. * @param filter to search with. * @param filterParameters to replace parameters in filter with. * @param returnAttrs to return from search. * @param ldifFile to compare with * * @throws Exception On test failure. */ @Parameters( { "saslExternalSearchDn", "saslExternalSearchFilter", "saslExternalSearchFilterParameters", "saslExternalSearchReturnAttrs", "saslExternalSearchResults" }) @Test(groups = {"search"}) public void saslExternalSearch( final String dn, final String filter, final String filterParameters, final String returnAttrs, final String ldifFile) throws Exception { // TODO ignore active directory until it's configured if (TestControl.isActiveDirectory()) { return; } final String expected = TestUtils.readFileIntoString(ldifFile); Connection conn = null; try { conn = TestUtils.createSaslExternalConnection(); conn.open(); final SearchOperation search = new SearchOperation(conn); final SearchResult result = search.execute( new SearchRequest( dn, new SearchFilter(filter, filterParameters.split("\\|")), returnAttrs.split("\\|"))).getResult(); TestUtils.assertEquals(TestUtils.convertLdifToResult(expected), result); } catch (UnsupportedOperationException e) { // ignore this test if not supported AssertJUnit.assertNotNull(e); } finally { if (conn != null) { conn.close(); } } } /** * @param krb5Realm kerberos realm * @param krb5Kdc kerberos kdc * @param dn to search on. * @param filter to search with. * @param filterParameters to replace parameters in filter with. * @param returnAttrs to return from search. * @param ldifFile to compare with * * @throws Exception On test failure. */ @Parameters( { "krb5Realm", "ldapTestHost", "gssApiSearchDn", "gssApiSearchFilter", "gssApiSearchFilterParameters", "gssApiSearchReturnAttrs", "gssApiSearchResults" }) @Test(groups = {"search"}) public void gssApiSearch( final String krb5Realm, final String krb5Kdc, final String dn, final String filter, final String filterParameters, final String returnAttrs, final String ldifFile) throws Exception { // ignore directory until it's configured if (TestControl.isActiveDirectory() || TestControl.isOracleDirectory()) { return; } final LdapURL ldapUrl = new LdapURL(krb5Kdc); System.setProperty("java.security.auth.login.config", "target/test-classes/ldap_jaas.config"); System.setProperty("javax.security.auth.useSubjectCredsOnly", "false"); System.setProperty("java.security.krb5.realm", krb5Realm); System.setProperty("java.security.krb5.kdc", ldapUrl.getEntry().getHostname()); final String expected = TestUtils.readFileIntoString(ldifFile); try (Connection conn = TestUtils.createGssApiConnection()) { conn.open(); final SearchOperation search = new SearchOperation(conn); final SearchResult result = search.execute( new SearchRequest( dn, new SearchFilter(filter, filterParameters.split("\\|")), returnAttrs.split("\\|"))).getResult(); TestUtils.assertEquals(TestUtils.convertLdifToResult(expected), result); } catch (UnsupportedOperationException e) { // ignore this test if not supported AssertJUnit.assertNotNull(e); } finally { System.clearProperty("java.security.auth.login.config"); System.clearProperty("javax.security.auth.useSubjectCredsOnly"); System.clearProperty("java.security.krb5.realm"); System.clearProperty("java.security.krb5.kdc"); } } /** * @param dn to search on. * @param filter to search with. * @param filterParameters to replace parameters in filter with. * @param returnAttrs to return from search. * @param ldifFile to compare with * * @throws Exception On test failure. */ @Parameters( { "searchDn", "searchFilter", "searchFilterParameters", "searchReturnAttrs", "searchResults" }) @Test(groups = {"search"}) public void executorSearch( final String dn, final String filter, final String filterParameters, final String returnAttrs, final String ldifFile) throws Exception { final SearchExecutor executor = new SearchExecutor(); executor.setBaseDn(dn); executor.setSearchFilter(new SearchFilter(filter, filterParameters.split("\\|"))); executor.setReturnAttributes(returnAttrs.split("\\|")); final String expected = TestUtils.readFileIntoString(ldifFile); final ConnectionFactory cf = new DefaultConnectionFactory(TestUtils.readConnectionConfig(null)); SearchResult result = executor.search(cf).getResult(); TestUtils.assertEquals(TestUtils.convertLdifToResult(expected), result); BlockingConnectionPool pool = new BlockingConnectionPool( new DefaultConnectionFactory(TestUtils.readConnectionConfig(null))); pool.setConnectOnCreate(false); pool.initialize(); PooledConnectionFactory pcf = new PooledConnectionFactory(pool); result = executor.search(pcf).getResult(); pool.close(); TestUtils.assertEquals(TestUtils.convertLdifToResult(expected), result); pool = new BlockingConnectionPool(new DefaultConnectionFactory(TestUtils.readConnectionConfig(null))); pool.setConnectOnCreate(true); pool.initialize(); pcf = new PooledConnectionFactory(pool); result = executor.search(pcf).getResult(); pool.close(); TestUtils.assertEquals(TestUtils.convertLdifToResult(expected), result); } }