cbaldacin
cbaldacin

Reputation: 51

Spring LDAP AD paging support not working - LDAP: error code 12 - 00000057: LdapErr: DSID-0C09079A

When trying to run the code above I'm getting javax.naming.OperationNotSupportedException with the message: [LDAP: error code 12 - 00000057: LdapErr: DSID-0C09079A, comment: Error processing control, data 0, v2580].

The first page is successfully retrieved and the exception is thrown only at second loop iteration.

public void pagedResults() {
    PagedResultsCookie cookie = null;
    SearchControls searchControls = new SearchControls();
    searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
    int page = 1;
    do {
        logger.info("Starting Page: " + page);
        PagedResultsDirContextProcessor processor = new PagedResultsDirContextProcessor(20, cookie);

        List<String> lastNames = ldapTemplate.search("", initialFilter.encode(), searchControls, UserMapper.USER_MAPPER_VNT, processor);
        for (String l : lastNames) {
            logger.info(l);
        }
        cookie = processor.getCookie();
        page = page + 1;
    } while (null != cookie.getCookie());
}

However, when I remove Spring LDAP using pure implementation as above, it works!

try {
        LdapContext ctx = new InitialLdapContext(env, null);

        // Activate paged results
        int pageSize = 5;
        byte[] cookie = null;
        ctx.setRequestControls(new Control[] { new PagedResultsControl(pageSize, Control.CRITICAL) });
        int total;

        do {
            /* perform the search */
            NamingEnumeration results = ctx .search("",
                            "(&(objectCategory=person)(objectClass=user)(SAMAccountName=vnt*))",
                            searchCtls);

            /* for each entry print out name + all attrs and values */
            while (results != null && results.hasMore()) {
                SearchResult entry = (SearchResult) results.next();
                System.out.println(entry.getName());
            }

            // Examine the paged results control response
            Control[] controls = ctx.getResponseControls();
            if (controls != null) {
                for (int i = 0; i < controls.length; i++) {
                    if (controls[i] instanceof PagedResultsResponseControl) {
                        PagedResultsResponseControl prrc = (PagedResultsResponseControl) controls[i];
                        total = prrc.getResultSize();
                        if (total != 0) {
                            System.out.println("***************** END-OF-PAGE "
                                    + "(total : " + total
                                    + ") *****************\n");
                        } else {
                            System.out.println("***************** END-OF-PAGE "
                                    + "(total: unknown) ***************\n");
                        }
                        cookie = prrc.getCookie();
                    }
                }
            } else {
                System.out.println("No controls were sent from the server");
            }
            // Re-activate paged results
            ctx.setRequestControls(new Control[] { new PagedResultsControl(
                    pageSize, cookie, Control.CRITICAL) });

        } while (cookie != null);

        ctx.close();

    } catch (NamingException e) {
        System.err.println("PagedSearch failed.");
        e.printStackTrace();
    } catch (IOException ie) {
        System.err.println("PagedSearch failed.");
        ie.printStackTrace();
    }

Any hints?

Upvotes: 4

Views: 8165

Answers (4)

icedew
icedew

Reputation: 1

you can replace ldapTemplate DirContext like this

ldapTemplate.setContextSource(new SingleContextSource(ldapContextSource().getReadWriteContext()));

Upvotes: 0

LukeM
LukeM

Reputation: 93

I found I could use your first example (Spring) as long as I set the ignorePartialResultException property to true in my ldapTemplate configuration and put the @Transactional on my method as suggested.

Upvotes: 1

cbaldacin
cbaldacin

Reputation: 51

I managed to make my example above work using SingleContextSource.doWithSingleContext approach.

However my scenario is different, my app is service oriented and the paged results as well as the cookie should be sent to an external client so that he decides to request next pages or not.

So as far as I can tell, spring-ldap does not support such case. I must use pure implementation so that I can keep track of the underlying connection during requests. Transaction support could help as well as SingleContextSource, but not among different requests.

@marthursson Is there any plan in spring ldap to such support in the future?

Upvotes: 1

marthursson
marthursson

Reputation: 3300

The bad thing about LDAP paged results is that they only work if the same underlying connection is used for all requests. The internals of Spring LDAP get a new connection for each LdapTemplate operation, unless you use the transactional support.

The easiest way to make sure the same connection will be used for a sequence of LDapTemplate operations is to use the transaction support, i.e. configure transactions for Spring LDAP and wrap the target method with a Transactional annotation.

Upvotes: 1

Related Questions