log.logDebug("Matched " + pattern + " to " + rdn + ',' + ldap.getNameInNamespace());
    public final HashMap authenticate(final Credentials userCredentials, final String[] attributeRequest)    throws AuthenticationFailedException, BackendException {        log.logDebug("authenticate: Truststore is " + System.getProperty("javax.net.ssl.trustStore")); // DEBUG        // Sanity check.        if (userCredentials == null)            throw new IllegalArgumentException("Credentials cannot be NULL");        // Go through all references.        for (int i = 0; i < myReferences.length; i++) {            final String[] references = myReferences[i].getReferences();            final String[] usernames = myReferences[i].getUsernames();            final String[] passwords = myReferences[i].getPasswords();            for (int j = 0; j < references.length; j++) {                // For the benefit of the finally block below.                InitialLdapContext ldap = null;                try {                    // Context for this reference.                    ldap = connect(references[j]);                    // Skip search phase if the reference(s) are explicit.                    String rdn = "";                    if (myReferences[i].isExplicitlyIndexed()) {                        // Add the explicit reference; no search phase, no RDN.                        ldap.addToEnvironment(Context.SECURITY_PRINCIPAL, references[j].substring(references[j].lastIndexOf('/') + 1));                    } else {                        // Anonymous search or not?                        ldap.addToEnvironment(Context.SECURITY_AUTHENTICATION, "simple");                        if ((usernames[j].length() == 0) && (passwords[j].length() > 0))                            log.logWarn("Search username is empty but search password is not - possible index problem");                        else if ((passwords[j].length() == 0) && (usernames[j].length() > 0))                            log.logWarn("Search password is empty but search username is not - possible index problem");                        else if ((passwords[j].length() == 0) && (usernames[j].length() == 0)) {                            log.logDebug("Anonymous search for user element DN");                            ldap.removeFromEnvironment(Context.SECURITY_AUTHENTICATION);                        } else                            log.logDebug("Non-anonymous search for user element DN");                        ldap.addToEnvironment(Context.SECURITY_PRINCIPAL, usernames[j]);                        ldap.addToEnvironment(Context.SECURITY_CREDENTIALS, passwords[j]);                        // Search using the implicit reference.                        String pattern = usernameAttribute + '=' + userCredentials.getUsername();                        rdn = ldapSearch(ldap, pattern);                        if (rdn == null) {                            // No user element found. Try to guess the RDN.                            rdn = userCredentials.getUsername();                            rdn = guessedAttribute + '=' + rdn.substring(0, rdn.indexOf('@'));                            log.logDebug("No subtree match for " + pattern + " on " + references[j] + " - guessing on RDN " + rdn, mySessionTicket);                        }                        ldap.addToEnvironment(Context.SECURITY_PRINCIPAL, rdn + ',' + ldap.getNameInNamespace());                    }                    // Authenticate and get attributes.                    ldap.addToEnvironment(Context.SECURITY_AUTHENTICATION, "simple");                    ldap.addToEnvironment(Context.SECURITY_CREDENTIALS, userCredentials.getPassword());                    try {                        ldap.reconnect(null);                        log.logDebug("Successfully authenticated " + userCredentials.getUsername() + " on " + references[j], mySessionTicket);                        return getAttributes(ldap, rdn, attributeRequest); // Success.                    } catch (AuthenticationException e) {                        // Authentication failed, but we may have other                        // references.                        log.logDebug("Failed to authenticate user " + userCredentials.getUsername() + " on " + references[j], mySessionTicket);                        continue;                    } catch (AuthenticationNotSupportedException e) {                        // Password authentication not supported for the DN.                        // We may still have other references.                        log.logDebug("Failed to authenticate user " + userCredentials.getUsername() + " on " + references[j], mySessionTicket);                        continue;                    }                } catch (ConfigurationException e) {                    throw new BackendException("Backend configuration problem with " + references[j], e);                } catch (NamingException e) {                    throw new BackendException("Unable to access the backend on " + references[j], e);                } finally {                    // Close the LDAP connection.                    if (ldap != null) {                        try {                            ldap.close();                        } catch (NamingException e) {                            // Ignored.                            log.logInfo("Unable to close the backend connection to " + references[j] + " - ignoring", mySessionTicket, e);                        }                    }                }            }        }        // No user was found.        throw new AuthenticationFailedException("Failed to authenticate user " + userCredentials.getUsername());    }