[
https://issues.apache.org/jira/browse/DIRAPI-434?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Emmanuel Lécharny updated DIRAPI-434:
-------------------------------------
Description:
I've been re-running a simple paging search against apacheds and occasionally
fails, indicating that the cookie was bad. I ran directory server version
2.0.0.AM27 with directory api version 2.1.8. While the error is raised by
directory server, I think the problem is in the api library.
Here's the error from directory server
{code}
2026-08-06T18:55:05,375 DEBUG handlers.LdapResponseHandler
(SearchResultDoneHandler.java:handle(41)) - Message Sent : MessageType :
SEARCH_RESULT_DONE
Message ID : 65419
Search Result Done
Ldap Result
Result code : (UNWILLING_TO_PERFORM) unwillingToPerform
Matched Dn : 'null'
Diagnostic message : 'Invalid cookie for this PagedSearch request.'
{code}
I looked into the problem a bit and it seems that the cookie encoding does not
match the cookie decoding for some cases. From what I can tell, the page cookie
is BER-encoded shifted message id.
See
[PagedSearchContext|https://github.com/apache/directory-server/blob/master/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/controls/PagedSearchContext.java#L75-L80].
{code}
/**
* Creates a new instance of this class, storing the SearchRequest into it.
*
* @param searchRequest The SearchRequest
*/
public PagedSearchContext( SearchRequest searchRequest )
{
previousSearchRequest = searchRequest;
currentPosition = 0;
// We compute a key for this cookie. It combines the search request
// and some time seed, in order to avoid possible collisions, as
// a user may send more than one PagedSearch on the same session.
cookieValue = new AtomicInteger( searchRequest.getMessageId() << 16 );
cookie = BerValue.getBytes( cookieValue.get() );
}
{code}
BER encoding is performed by the
[BerValue|https://github.com/apache/directory-ldap-api/blob/master/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/BerValue.java#L315]
class.
The bytes are decoded back into an integer in
[SearchRequestHandler.doPagedSearch|https://github.com/apache/directory-server/blob/master/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/request/SearchRequestHandler.java#L691-L692].
{code}
int cookieValue = pagedSearchControl.getCookieValue();
pagedContext = session.getPagedSearchContext( cookieValue );
{code}
This is implemented by the
[PagedResultsImpl|https://github.com/apache/directory-ldap-api/blob/61bb5105971cda38ac56d20313554b680436a249/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/PagedResultsImpl.java#L121]
class.
However, PagedResultsImpl.getCookieValue does not match BerValue.getBytes for
some values. Here's a small unit test the illustrates the affected range that I
ran into. I have not tested all ranges.
{code}
package test;
import org.apache.directory.api.asn1.ber.tlv.BerValue;
import org.apache.directory.api.ldap.model.message.SearchRequest;
import org.apache.directory.api.ldap.model.message.SearchRequestImpl;
import org.apache.directory.api.ldap.model.message.controls.PagedResultsImpl;
import org.apache.directory.server.ldap.handlers.controls.PagedSearchContext;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
/**
* Tests illustrating that PagedResultsImpl cookie decoding does not match
PagedSearchContext cookie encoding for
* at least one range of message ids.
*/
public class CookieCalcTest {
@Test
public void testCookieCalculationGoodUpper() {
SearchRequest searchRequest = new SearchRequestImpl();
searchRequest.setMessageId(65536);
PagedSearchContext pagedSearchContext = new
PagedSearchContext(searchRequest);
int cookieValue = pagedSearchContext.getCookieValue();
byte[] cookie = BerValue.getBytes(cookieValue);
PagedResultsImpl pagedResults = new PagedResultsImpl();
pagedResults.setCookie(cookie);
int uncookieValue = pagedResults.getCookieValue();
assertEquals(cookieValue, uncookieValue); // succeeds
}
@Test
public void testCookieCalculationBadUpperLimit() {
SearchRequest searchRequest = new SearchRequestImpl();
searchRequest.setMessageId(65535);
PagedSearchContext pagedSearchContext = new
PagedSearchContext(searchRequest);
int cookieValue = pagedSearchContext.getCookieValue();
byte[] cookie = BerValue.getBytes(cookieValue);
PagedResultsImpl pagedResults = new PagedResultsImpl();
pagedResults.setCookie(cookie);
int uncookieValue = pagedResults.getCookieValue();
assertEquals(cookieValue, uncookieValue); // fails
}
@Test
public void testCookieCalculationBadLowerLimit() {
SearchRequest searchRequest = new SearchRequestImpl();
searchRequest.setMessageId(65408);
PagedSearchContext pagedSearchContext = new
PagedSearchContext(searchRequest);
int cookieValue = pagedSearchContext.getCookieValue();
byte[] cookie = BerValue.getBytes(cookieValue);
PagedResultsImpl pagedResults = new PagedResultsImpl();
pagedResults.setCookie(cookie);
int uncookieValue = pagedResults.getCookieValue();
assertEquals(cookieValue, uncookieValue); // fails
}
@Test
public void testCookieCalculationGoodLower() {
SearchRequest searchRequest = new SearchRequestImpl();
searchRequest.setMessageId(65407);
PagedSearchContext pagedSearchContext = new
PagedSearchContext(searchRequest);
int cookieValue = pagedSearchContext.getCookieValue();
byte[] cookie = BerValue.getBytes(cookieValue);
PagedResultsImpl pagedResults = new PagedResultsImpl();
pagedResults.setCookie(cookie);
int uncookieValue = pagedResults.getCookieValue();
assertEquals(cookieValue, uncookieValue); // succeeds
}
}
{code}
was:
I've been re-running a simple paging search against apacheds and occasionally
fails, indicating that the cookie was bad. I ran directory server version
2.0.0.AM27 with directory api version 2.1.8. While the error is raised by
directory server, I think the problem is in the api library.
Here's the error from directory server
```
2026-08-06T18:55:05,375 DEBUG handlers.LdapResponseHandler
(SearchResultDoneHandler.java:handle(41)) - Message Sent : MessageType :
SEARCH_RESULT_DONE
Message ID : 65419
Search Result Done
Ldap Result
Result code : (UNWILLING_TO_PERFORM) unwillingToPerform
Matched Dn : 'null'
Diagnostic message : 'Invalid cookie for this PagedSearch request.'
```
I looked into the problem a bit and it seems that the cookie encoding does not
match the cookie decoding for some cases. From what I can tell, the page cookie
is BER-encoded shifted message id.
See
[PagedSearchContext|https://github.com/apache/directory-server/blob/master/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/controls/PagedSearchContext.java#L75-L80].
```
/**
* Creates a new instance of this class, storing the SearchRequest into it.
*
* @param searchRequest The SearchRequest
*/
public PagedSearchContext( SearchRequest searchRequest )
{
previousSearchRequest = searchRequest;
currentPosition = 0;
// We compute a key for this cookie. It combines the search request
// and some time seed, in order to avoid possible collisions, as
// a user may send more than one PagedSearch on the same session.
cookieValue = new AtomicInteger( searchRequest.getMessageId() << 16 );
cookie = BerValue.getBytes( cookieValue.get() );
}
```
BER encoding is performed by the
[BerValue|https://github.com/apache/directory-ldap-api/blob/master/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/BerValue.java#L315]
class.
The bytes are decoded back into an integer in
[SearchRequestHandler.doPagedSearch|https://github.com/apache/directory-server/blob/master/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/request/SearchRequestHandler.java#L691-L692].
```
int cookieValue = pagedSearchControl.getCookieValue();
pagedContext = session.getPagedSearchContext( cookieValue );
```
This is implemented by the
[PagedResultsImpl|https://github.com/apache/directory-ldap-api/blob/61bb5105971cda38ac56d20313554b680436a249/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/PagedResultsImpl.java#L121]
class.
However, PagedResultsImpl.getCookieValue does not match BerValue.getBytes for
some values. Here's a small unit test the illustrates the affected range that I
ran into. I have not tested all ranges.
```
package test;
import org.apache.directory.api.asn1.ber.tlv.BerValue;
import org.apache.directory.api.ldap.model.message.SearchRequest;
import org.apache.directory.api.ldap.model.message.SearchRequestImpl;
import org.apache.directory.api.ldap.model.message.controls.PagedResultsImpl;
import org.apache.directory.server.ldap.handlers.controls.PagedSearchContext;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
/**
* Tests illustrating that PagedResultsImpl cookie decoding does not match
PagedSearchContext cookie encoding for
* at least one range of message ids.
*/
public class CookieCalcTest {
@Test
public void testCookieCalculationGoodUpper() {
SearchRequest searchRequest = new SearchRequestImpl();
searchRequest.setMessageId(65536);
PagedSearchContext pagedSearchContext = new
PagedSearchContext(searchRequest);
int cookieValue = pagedSearchContext.getCookieValue();
byte[] cookie = BerValue.getBytes(cookieValue);
PagedResultsImpl pagedResults = new PagedResultsImpl();
pagedResults.setCookie(cookie);
int uncookieValue = pagedResults.getCookieValue();
assertEquals(cookieValue, uncookieValue); // succeeds
}
@Test
public void testCookieCalculationBadUpperLimit() {
SearchRequest searchRequest = new SearchRequestImpl();
searchRequest.setMessageId(65535);
PagedSearchContext pagedSearchContext = new
PagedSearchContext(searchRequest);
int cookieValue = pagedSearchContext.getCookieValue();
byte[] cookie = BerValue.getBytes(cookieValue);
PagedResultsImpl pagedResults = new PagedResultsImpl();
pagedResults.setCookie(cookie);
int uncookieValue = pagedResults.getCookieValue();
assertEquals(cookieValue, uncookieValue); // fails
}
@Test
public void testCookieCalculationBadLowerLimit() {
SearchRequest searchRequest = new SearchRequestImpl();
searchRequest.setMessageId(65408);
PagedSearchContext pagedSearchContext = new
PagedSearchContext(searchRequest);
int cookieValue = pagedSearchContext.getCookieValue();
byte[] cookie = BerValue.getBytes(cookieValue);
PagedResultsImpl pagedResults = new PagedResultsImpl();
pagedResults.setCookie(cookie);
int uncookieValue = pagedResults.getCookieValue();
assertEquals(cookieValue, uncookieValue); // fails
}
@Test
public void testCookieCalculationGoodLower() {
SearchRequest searchRequest = new SearchRequestImpl();
searchRequest.setMessageId(65407);
PagedSearchContext pagedSearchContext = new
PagedSearchContext(searchRequest);
int cookieValue = pagedSearchContext.getCookieValue();
byte[] cookie = BerValue.getBytes(cookieValue);
PagedResultsImpl pagedResults = new PagedResultsImpl();
pagedResults.setCookie(cookie);
int uncookieValue = pagedResults.getCookieValue();
assertEquals(cookieValue, uncookieValue); // succeeds
}
}
```
> Directory server paging fails with UNWILLING_TO_PERFORM for some message ids
> ----------------------------------------------------------------------------
>
> Key: DIRAPI-434
> URL: https://issues.apache.org/jira/browse/DIRAPI-434
> Project: Directory Client API
> Issue Type: Bug
> Affects Versions: 2.1.8
> Reporter: David Han
> Priority: Major
>
> I've been re-running a simple paging search against apacheds and occasionally
> fails, indicating that the cookie was bad. I ran directory server version
> 2.0.0.AM27 with directory api version 2.1.8. While the error is raised by
> directory server, I think the problem is in the api library.
> Here's the error from directory server
> {code}
> 2026-08-06T18:55:05,375 DEBUG handlers.LdapResponseHandler
> (SearchResultDoneHandler.java:handle(41)) - Message Sent : MessageType :
> SEARCH_RESULT_DONE
> Message ID : 65419
> Search Result Done
> Ldap Result
> Result code : (UNWILLING_TO_PERFORM) unwillingToPerform
> Matched Dn : 'null'
> Diagnostic message : 'Invalid cookie for this PagedSearch
> request.'
> {code}
> I looked into the problem a bit and it seems that the cookie encoding does
> not match the cookie decoding for some cases. From what I can tell, the page
> cookie is BER-encoded shifted message id.
> See
> [PagedSearchContext|https://github.com/apache/directory-server/blob/master/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/controls/PagedSearchContext.java#L75-L80].
> {code}
> /**
> * Creates a new instance of this class, storing the SearchRequest into
> it.
> *
> * @param searchRequest The SearchRequest
> */
> public PagedSearchContext( SearchRequest searchRequest )
> {
> previousSearchRequest = searchRequest;
> currentPosition = 0;
> // We compute a key for this cookie. It combines the search request
> // and some time seed, in order to avoid possible collisions, as
> // a user may send more than one PagedSearch on the same session.
> cookieValue = new AtomicInteger( searchRequest.getMessageId() << 16 );
> cookie = BerValue.getBytes( cookieValue.get() );
> }
> {code}
> BER encoding is performed by the
> [BerValue|https://github.com/apache/directory-ldap-api/blob/master/asn1/ber/src/main/java/org/apache/directory/api/asn1/ber/tlv/BerValue.java#L315]
> class.
> The bytes are decoded back into an integer in
> [SearchRequestHandler.doPagedSearch|https://github.com/apache/directory-server/blob/master/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/request/SearchRequestHandler.java#L691-L692].
> {code}
> int cookieValue = pagedSearchControl.getCookieValue();
> pagedContext = session.getPagedSearchContext( cookieValue );
> {code}
> This is implemented by the
> [PagedResultsImpl|https://github.com/apache/directory-ldap-api/blob/61bb5105971cda38ac56d20313554b680436a249/ldap/model/src/main/java/org/apache/directory/api/ldap/model/message/controls/PagedResultsImpl.java#L121]
> class.
> However, PagedResultsImpl.getCookieValue does not match BerValue.getBytes for
> some values. Here's a small unit test the illustrates the affected range that
> I ran into. I have not tested all ranges.
> {code}
> package test;
> import org.apache.directory.api.asn1.ber.tlv.BerValue;
> import org.apache.directory.api.ldap.model.message.SearchRequest;
> import org.apache.directory.api.ldap.model.message.SearchRequestImpl;
> import org.apache.directory.api.ldap.model.message.controls.PagedResultsImpl;
> import org.apache.directory.server.ldap.handlers.controls.PagedSearchContext;
> import org.junit.Test;
> import static org.junit.Assert.assertEquals;
> /**
> * Tests illustrating that PagedResultsImpl cookie decoding does not match
> PagedSearchContext cookie encoding for
> * at least one range of message ids.
> */
> public class CookieCalcTest {
> @Test
> public void testCookieCalculationGoodUpper() {
> SearchRequest searchRequest = new SearchRequestImpl();
> searchRequest.setMessageId(65536);
> PagedSearchContext pagedSearchContext = new
> PagedSearchContext(searchRequest);
> int cookieValue = pagedSearchContext.getCookieValue();
> byte[] cookie = BerValue.getBytes(cookieValue);
> PagedResultsImpl pagedResults = new PagedResultsImpl();
> pagedResults.setCookie(cookie);
> int uncookieValue = pagedResults.getCookieValue();
> assertEquals(cookieValue, uncookieValue); // succeeds
> }
> @Test
> public void testCookieCalculationBadUpperLimit() {
> SearchRequest searchRequest = new SearchRequestImpl();
> searchRequest.setMessageId(65535);
> PagedSearchContext pagedSearchContext = new
> PagedSearchContext(searchRequest);
> int cookieValue = pagedSearchContext.getCookieValue();
> byte[] cookie = BerValue.getBytes(cookieValue);
> PagedResultsImpl pagedResults = new PagedResultsImpl();
> pagedResults.setCookie(cookie);
> int uncookieValue = pagedResults.getCookieValue();
> assertEquals(cookieValue, uncookieValue); // fails
> }
> @Test
> public void testCookieCalculationBadLowerLimit() {
> SearchRequest searchRequest = new SearchRequestImpl();
> searchRequest.setMessageId(65408);
> PagedSearchContext pagedSearchContext = new
> PagedSearchContext(searchRequest);
> int cookieValue = pagedSearchContext.getCookieValue();
> byte[] cookie = BerValue.getBytes(cookieValue);
> PagedResultsImpl pagedResults = new PagedResultsImpl();
> pagedResults.setCookie(cookie);
> int uncookieValue = pagedResults.getCookieValue();
> assertEquals(cookieValue, uncookieValue); // fails
> }
> @Test
> public void testCookieCalculationGoodLower() {
> SearchRequest searchRequest = new SearchRequestImpl();
> searchRequest.setMessageId(65407);
> PagedSearchContext pagedSearchContext = new
> PagedSearchContext(searchRequest);
> int cookieValue = pagedSearchContext.getCookieValue();
> byte[] cookie = BerValue.getBytes(cookieValue);
> PagedResultsImpl pagedResults = new PagedResultsImpl();
> pagedResults.setCookie(cookie);
> int uncookieValue = pagedResults.getCookieValue();
> assertEquals(cookieValue, uncookieValue); // succeeds
> }
> }
> {code}
--
This message was sent by Atlassian Jira
(v8.20.10#820010)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]