Skip to content

Commit ba2b247

Browse files
authored
[#737] Fix cn=changelog search failing when aliases are dereferenced (#740)
1 parent 69f502a commit ba2b247

2 files changed

Lines changed: 93 additions & 1 deletion

File tree

opendj-server-legacy/src/main/java/org/opends/server/backends/ChangelogBackend.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,14 @@ public boolean isIndexed(final AttributeType attributeType, final IndexType inde
297297
return true;
298298
}
299299

300+
/**
301+
* {@inheritDoc}
302+
* <p>
303+
* Only the base changelog entry can be retrieved by DN. Change records are streamed by
304+
* {@link #search(SearchOperation)}, which needs the search filter and the change number range to
305+
* position its cursors, so they cannot be looked up individually and {@code null} is returned for
306+
* them. None of them is ever an alias, so callers dereferencing aliases get the answer they need.
307+
*/
300308
@Override
301309
public Entry getEntry(final DN entryDN) throws DirectoryException
302310
{
@@ -305,7 +313,11 @@ public Entry getEntry(final DN entryDN) throws DirectoryException
305313
throw new DirectoryException(DirectoryServer.getCoreConfigManager().getServerErrorResultCode(),
306314
ERR_BACKEND_GET_ENTRY_NULL.get(getBackendID()));
307315
}
308-
throw new RuntimeException("Not implemented");
316+
if (CHANGELOG_BASE_DN.equals(entryDN))
317+
{
318+
return buildBaseChangelogEntry();
319+
}
320+
return null;
309321
}
310322

311323
@Override

opendj-server-legacy/src/test/java/org/opends/server/backends/ChangelogBackendTestCase.java

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
* information: "Portions Copyright [year] [name of copyright owner]".
1313
*
1414
* Copyright 2014-2016 ForgeRock AS.
15+
* Portions Copyright 2026 3A Systems, LLC.
1516
*/
1617
package org.opends.server.backends;
1718

@@ -47,6 +48,7 @@
4748
import org.forgerock.i18n.slf4j.LocalizedLogger;
4849
import org.forgerock.opendj.ldap.ByteString;
4950
import org.forgerock.opendj.ldap.DN;
51+
import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
5052
import org.forgerock.opendj.ldap.RDN;
5153
import org.forgerock.opendj.ldap.ResultCode;
5254
import org.forgerock.opendj.ldap.SearchScope;
@@ -783,6 +785,84 @@ public void searchWhenNoChangesShouldReturnRootEntryOnly() throws Exception
783785
debugInfo(testName, "Ending test successfully");
784786
}
785787

788+
/**
789+
* The alias dereferencing policies which make the server look the search base entry up before
790+
* handing the search over to the backend.
791+
*/
792+
@DataProvider
793+
Object[][] getBaseEntryLookupDerefPolicies()
794+
{
795+
return new Object[][] {
796+
{ DereferenceAliasesPolicy.ALWAYS },
797+
{ DereferenceAliasesPolicy.FINDING_BASE },
798+
// only looks the base entry up for subtree searches, which newSearchRequest() uses
799+
{ DereferenceAliasesPolicy.IN_SEARCHING },
800+
};
801+
}
802+
803+
/**
804+
* Dereferencing aliases makes the server read the base entry before searching, so the changelog
805+
* backend must be able to return it rather than failing the whole search.
806+
*
807+
* @see <a href="https://github.com/OpenIdentityPlatform/OpenDJ/issues/737">issue #737</a>
808+
*/
809+
@Test(dataProvider = "getBaseEntryLookupDerefPolicies")
810+
public void searchWhenNoChangesShouldReturnRootEntryOnlyWhenDereferencingAliases(
811+
DereferenceAliasesPolicy derefPolicy) throws Exception
812+
{
813+
String testName = "EmptyRSDeref/" + derefPolicy;
814+
debugInfo(testName, "Starting test\n\n");
815+
816+
SearchRequest request = newSearchRequest("(objectclass=*)").setDereferenceAliasesPolicy(derefPolicy);
817+
searchChangelog(request, 1, SUCCESS, testName);
818+
819+
debugInfo(testName, "Ending test successfully");
820+
}
821+
822+
/**
823+
* Dereferencing aliases used to fail change number searches with an unexpected error, which broke
824+
* every client defaulting to it, JNDI-based ones in particular.
825+
*
826+
* @see <a href="https://github.com/OpenIdentityPlatform/OpenDJ/issues/737">issue #737</a>
827+
*/
828+
@Test(dataProvider = "getBaseEntryLookupDerefPolicies")
829+
public void searchInChangeNumberModeWhenDereferencingAliases(DereferenceAliasesPolicy derefPolicy) throws Exception
830+
{
831+
String testName = "ChangeNumberDeref/" + derefPolicy;
832+
debugInfo(testName, "Starting test\n\n");
833+
834+
CSN[] csns = generateAndPublishUpdateMsgForEachOperationType(testName, false);
835+
836+
SearchRequest request = newSearchRequest("(changenumber>=1)").setDereferenceAliasesPolicy(derefPolicy);
837+
InternalSearchOperation searchOp = searchChangelog(request, csns.length, SUCCESS, testName);
838+
839+
assertEntriesForEachOperationType(searchOp.getSearchEntries(), 1, testName, USER1_ENTRY_UUID, csns);
840+
841+
debugInfo(testName, "Ending test successfully");
842+
}
843+
844+
/**
845+
* The base changelog entry is the only one the backend can return by DN: change records need the
846+
* search parameters to be located, so they are only reachable through a search.
847+
*/
848+
@Test
849+
public void getEntryShouldReturnBaseEntryOnly() throws Exception
850+
{
851+
String testName = "getEntry";
852+
debugInfo(testName, "Starting test\n\n");
853+
854+
generateAndPublishUpdateMsgForEachOperationType(testName, false);
855+
856+
final LocalBackend<?> backend = TestCaseUtils.getServerContext().getBackendConfigManager()
857+
.getLocalBackendById(ChangelogBackend.BACKEND_ID);
858+
assertEquals(backend.getEntry(ChangelogBackend.CHANGELOG_BASE_DN).getName(),
859+
ChangelogBackend.CHANGELOG_BASE_DN);
860+
assertNull(backend.getEntry(DN.valueOf("changeNumber=1,cn=changelog")));
861+
assertNull(backend.getEntry(DN.valueOf("changeNumber=1000,cn=changelog")));
862+
863+
debugInfo(testName, "Ending test successfully");
864+
}
865+
786866
@Test
787867
public void operationalAndVirtualAttributesShouldNotBeVisibleOutsideRootDSE() throws Exception
788868
{

0 commit comments

Comments
 (0)