Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,14 @@ public boolean isIndexed(final AttributeType attributeType, final IndexType inde
return true;
}

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

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* information: "Portions Copyright [year] [name of copyright owner]".
*
* Copyright 2014-2016 ForgeRock AS.
* Portions Copyright 2026 3A Systems, LLC.
*/
package org.opends.server.backends;

Expand Down Expand Up @@ -47,6 +48,7 @@
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.DN;
import org.forgerock.opendj.ldap.DereferenceAliasesPolicy;
import org.forgerock.opendj.ldap.RDN;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.SearchScope;
Expand Down Expand Up @@ -783,6 +785,84 @@ public void searchWhenNoChangesShouldReturnRootEntryOnly() throws Exception
debugInfo(testName, "Ending test successfully");
}

/**
* The alias dereferencing policies which make the server look the search base entry up before
* handing the search over to the backend.
*/
@DataProvider
Object[][] getBaseEntryLookupDerefPolicies()
{
return new Object[][] {
{ DereferenceAliasesPolicy.ALWAYS },
{ DereferenceAliasesPolicy.FINDING_BASE },
// only looks the base entry up for subtree searches, which newSearchRequest() uses
{ DereferenceAliasesPolicy.IN_SEARCHING },
};
}

/**
* Dereferencing aliases makes the server read the base entry before searching, so the changelog
* backend must be able to return it rather than failing the whole search.
*
* @see <a href="https://github.com/OpenIdentityPlatform/OpenDJ/issues/737">issue #737</a>
*/
@Test(dataProvider = "getBaseEntryLookupDerefPolicies")
public void searchWhenNoChangesShouldReturnRootEntryOnlyWhenDereferencingAliases(
DereferenceAliasesPolicy derefPolicy) throws Exception
{
String testName = "EmptyRSDeref/" + derefPolicy;
debugInfo(testName, "Starting test\n\n");

SearchRequest request = newSearchRequest("(objectclass=*)").setDereferenceAliasesPolicy(derefPolicy);
searchChangelog(request, 1, SUCCESS, testName);

debugInfo(testName, "Ending test successfully");
}

/**
* Dereferencing aliases used to fail change number searches with an unexpected error, which broke
* every client defaulting to it, JNDI-based ones in particular.
*
* @see <a href="https://github.com/OpenIdentityPlatform/OpenDJ/issues/737">issue #737</a>
*/
@Test(dataProvider = "getBaseEntryLookupDerefPolicies")
public void searchInChangeNumberModeWhenDereferencingAliases(DereferenceAliasesPolicy derefPolicy) throws Exception
{
String testName = "ChangeNumberDeref/" + derefPolicy;
debugInfo(testName, "Starting test\n\n");

CSN[] csns = generateAndPublishUpdateMsgForEachOperationType(testName, false);

SearchRequest request = newSearchRequest("(changenumber>=1)").setDereferenceAliasesPolicy(derefPolicy);
InternalSearchOperation searchOp = searchChangelog(request, csns.length, SUCCESS, testName);

assertEntriesForEachOperationType(searchOp.getSearchEntries(), 1, testName, USER1_ENTRY_UUID, csns);

debugInfo(testName, "Ending test successfully");
}

/**
* The base changelog entry is the only one the backend can return by DN: change records need the
* search parameters to be located, so they are only reachable through a search.
*/
@Test
public void getEntryShouldReturnBaseEntryOnly() throws Exception
{
String testName = "getEntry";
debugInfo(testName, "Starting test\n\n");

generateAndPublishUpdateMsgForEachOperationType(testName, false);

final LocalBackend<?> backend = TestCaseUtils.getServerContext().getBackendConfigManager()
.getLocalBackendById(ChangelogBackend.BACKEND_ID);
assertEquals(backend.getEntry(ChangelogBackend.CHANGELOG_BASE_DN).getName(),
ChangelogBackend.CHANGELOG_BASE_DN);
assertNull(backend.getEntry(DN.valueOf("changeNumber=1,cn=changelog")));
assertNull(backend.getEntry(DN.valueOf("changeNumber=1000,cn=changelog")));

debugInfo(testName, "Ending test successfully");
}

@Test
public void operationalAndVirtualAttributesShouldNotBeVisibleOutsideRootDSE() throws Exception
{
Expand Down
Loading