Giter Site home page Giter Site logo

ldapsdk's Introduction

UnboundID LDAP SDK for Java

Download the Latest Release of the LDAP SDK Here

The UnboundID LDAP SDK for Java is a fast, powerful, user-friendly, and completely free and open source Java library for communicating with LDAP directory servers. It offers better performance, better ease of use, and more features than other Java-based LDAP APIs. It is developed by Ping Identity Corporation and is actively being maintained and enhanced as a critical component of Ping Identity client and server software.

The UnboundID LDAP SDK for Java is free to use and redistribute in open source or proprietary applications under the terms of the Apache License, Version 2.0, which is a very permissive OSI-approved open source license. For legacy purposes, the software is also available under the terms of the GNU GPLv2 or LGPLv2.1 licenses, or the not-open-source-but-still-free-to-use UnboundID Free Use License.

The LDAP SDK does not have any third-party dependencies beyond a Java 8 or higher Java Runtime Environment, so a single jar file is all you need to add top-notch LDAP support to your Java application. It can also be used in conjunction with most other JVM-based languages, as well as on the Android mobile platform.

The full documentation for the LDAP SDK is available online at https://docs.ldap.com/ldap-sdk/docs/index.html. The API documentation (aka JavaDoc) for the UnboundID LDAP SDK for Java is available at https://docs.ldap.com/ldap-sdk/docs/javadoc/index.html. The LDAP.com website also has a lot of useful information about LDAP and directory services.

Advantages of the UnboundID LDAP SDK for Java

Some of the key advantages of the UnboundID LDAP SDK for Java include:

  • Full support for the LDAPv3 protocol as of the most recent specification update, including all operation types, intermediate response messages, the increment modification extension, and absolute true/false filters.

  • Built-in support for a wide range of official and de facto standard protocol extensions, including controls, extended operations, and SASL mechanisms. The LDAP SDK also includes APIs for developing support for any custom protocol extensions that you may need but aren't included as part of the LDAP SDK.

  • A very convenient and user-friendly API that reduces the amount of code you need to write in order to perform the desired operations.

  • A number of security-related features to help simplify secure communication and ensure that all interaction with LDAP servers and data remains safe and available to only properly-authorized users.

  • Powerful and flexible connection pooling, load balancing, and failover support to help ensure that your application keeps working flawlessly even if one or more of the directory servers becomes unavailable.

  • A simple yet powerful persistence framework that allows you to interact with LDAP entries as if they were Java objects. The persistence framework works with your existing schema and directory data without any changes so that it remains compatible with other applications that may need to access it.

  • Enhanced support for a number of special entry types, including the root DSE, subschema subentries, and changelog entries.

  • Support for a number of related APIs, including reading and writing LDIF entries and change records (including parallelized encoding and decoding for maximum performance), base64 encoding and decoding, and ASN.1 BER encoding and decoding. There are also APIs to simplify the creation of LDAP-enabled command-line tools.

  • Support for simplifying LDAP-based testing. The LDAP SDK includes an in-memory directory server is available to allow you easily create one or more simple LDAPv3-compliant servers to use in your testing frameworks. It also provides a set of utility methods for making assertions about the content stored in an LDAP directory server.

  • The LDAP SDK is provided as a single self-contained jar file with no dependencies on anything outside of Java SE version 8 or later.

How To Get the UnboundID LDAP SDK for Java

Packaged releases of the UnboundID LDAP SDK for Java are available for download from GitHub at https://github.com/pingidentity/ldapsdk/releases and from SourceForge at https://sourceforge.net/projects/ldap-sdk/files/.

If you prefer to use the Maven tool to manage your library dependencies, then you can get the UnboundID LDAP SDK for Java in the Maven Central Repository with a GroupId of "com.unboundid" and an ArtifactId of "unboundid-ldapsdk".

If you want to check out and build the LDAP SDK from source, then you can do that with the following git command:

git clone https://github.com/pingidentity/ldapsdk.git

Once the code has been checked out, you can build the LDAP SDK by running the build.sh shell script on UNIX-based systems or build.bat batch file on Windows. Once the build has completed, the zip file containing the packaged LDAP SDK may be found in the build/package directory.

How To Get Help with the UnboundID LDAP SDK for Java

If you run into a problem when using the LDAP SDK and you can't figure it out from the documentation, then there are a few ways that you can get help:

Contributing to the UnboundID LDAP SDK for Java

Ping Identity does not accept third-party code submissions. However, there are other ways that you can help, including submitting bug reports and feature requests. See the CONTRIBUTING.md file for additional information.

ldapsdk's People

Contributors

dirmgr avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ldapsdk's Issues

LDAP SDK and InterruptedException handling

Hi there,

Thx for the API, I would say is really great, and the best Java LDAP API I have worked with.

My issue is related with usage of the API in a multi threaded environment. I am using LDAPConnectionPool and sharing between multiple threads. Everything works fine, but I have found a little strange the behaviour of the API when the threads are interrupted. In some cases I got this errors:

LDAPSearchException(resultCode=82 (local error), numEntries=0, numReferences=0, errorMessage='Search processing was interrupted while waiting for a response from server localhost:6000.')
at com.unboundid.ldap.sdk.LDAPConnection.search(LDAPConnection.java:3645)
at com.unboundid.ldap.sdk.AbstractConnectionPool.search(AbstractConnectionPool.java:2022)
at com.unboundid.ldap.sdk.AbstractConnectionPool.search(AbstractConnectionPool.java:1759)

When a thraed using the API is interrupted and that is mapped to error code 82; but error 82 is also used also for internal errors. That makes very tricky to properly handle the interrupt signal in threads using the API (unless you parse the error message, that I think it is bad practice). In my view, it could much cleaner that the API is able to throw InterruptedException when the thread is interrupted while waiting for LDAP server response.

What do you think? What is the best approach with the current API to properly handle interrupt signal in threads using the SDK?

Thanks in advance,

/Evaristo

Replace BindRequest for new connections in LDAPConnectionPool

Hi there,

We are using LDAP SDK to connect to an LDAP server, and periodically the password for the bindDN used in the pool to create new connections is enforced to be changed by the users administrators.

Today the bindDN and the password are config parameters of the application. WHen the password is changed in runtime, we are closing the actual pool and creating a new one on the fly, but I think could be interesting addind in the pool a method like "setNewBindRequestNewConnections(BindRequest request)"
that is really doind the job.

Checking LDAPPoolCode I think should be enough to make bindRequest field as volatile and create new method as suggested.

DO you think is an interesting functionality to be added?

Thanks in advance

Migrate this repository to the Ping Identity organization

UnboundID has been acquired by Ping Identity and all public repositories in the UnboundID GitHub organization will be migrated to the Ping Identity organization. The migration should happen this weekend (March 4–5, 2017).

All repository history, issues, pull requests, releases, and settings should be migrated. URIs will change, but GitHub should automatically redirect the old URIs to the new ones. See https://help.github.com/articles/about-repository-transfers/ for more information.

TLSv1.2 support for JDK8

Please support TLSv1.2 for JDK 8.

ldapsdk/src/com/unboundid/util/ssl/SSLUtil.java

@param protocol The protocol to use. As per the Java SE 6 Cryptography
Architecture document, the set of supported protocols
should include at least "SSLv3", "TLSv1", "TLSv1.1", and
"SSLv2Hello". It must not be {@code null}.

And, at least a note on document is needed to say SSLv3 protocol disabled by default with JDK 8.
https://docs.oracle.com/javase/8/docs/technotes/guides/security/enhancements-8.html
http://www.oracle.com/technetwork/java/javase/8u31-relnotes-2389094.html

size limit over STARTTLS

Hey guys,

Thank you for the nice library first of all.

I noticed a strange behavior while doing searces over plain and starttls as a cn=manager.... Server side sizelimit seems not effective on a plain connection but kicks in when on STARTTLS. So I hit size limit exception when I jump to secure connection.

Is it an known/expected thing?

Thank you,
Philipp

warnings while building 3.2.0

Not sure about how much it may be useful, but while building 3.2.0 I've seen the following warnings:

compile:
[mkdir] Created dir: /builddir/build/BUILD/ldapsdk-3.2.0/build/classes
[javac] Compiling 25 source files to /builddir/build/BUILD/ldapsdk-3.2.0/build/classes
[javac] warning: [options] bootstrap class path not set in conjunction with -source 1.6
[javac] 1 warning
[javac] Compiling 969 source files to /builddir/build/BUILD/ldapsdk-3.2.0/build/classes
[javac] warning: [options] bootstrap class path not set in conjunction with -source 1.6
[javac] /builddir/build/BUILD/ldapsdk-3.2.0/src/com/unboundid/ldap/listener/InMemoryRequestHandler.java:3643: warning: [unchecked] unchecked cast
javac connectionState.get(
[javac] ^
[javac] required: ObjectPair<ASN1OctetString,List>
[javac] found: Object
[javac] 2 warnings

Launch Exception in com.unboundid.ldap.sdk.schema.Schema constructor

Hi there,

I have noticed that Schema class is able to create objects even when provided schema syntax is wrong. When that is happening the Schema object will have some attributes and objectClasses, but the API is not warning that provided schema is wrong. The implementation is able to detect problem, but simply logs them in debug level, creating an object.

 for (final String def : defs)
  {
    try
    {
      final AttributeSyntaxDefinition as =
           new AttributeSyntaxDefinition(def);
      s.add(as);
      m.put(toLowerCase(as.getOID()), as);
    }
    catch (final LDAPException le)
    {
      debugException(le);
    }
  }

In my view, the Schema class should provide and Exception when the provided schema info is wrong (e.g. via file). Basically the proposed change is throw the LDAPException instead of catching it.

Otherwise the library user does not have any mean to validate that the schema objects are constructed as expected.

Regards,

Evaristo

ldap search request no received

We actually implements the InMemoryOperationInterceptor class and override the required methods.

I use my system as ldapServe and send a ldapSearchRequest from other system.
The overridden method processSearchRequest(InMemoryInterceptedSearchRequest request)
sometime receive the request sometime not.

Don't shrink spaces in normalized RDN values

At least in AD, the following DNs are not considered equal:

CN=F      O  O, CN=Bar
,
CN=F    O          O, CN=Bar
.

However, it seems that the DN implementation in the sdk normalizes DNs, so that spaces are shrank in RDN values (it also changes them to be lower-cased, but I'm not sure that's actually an issue). The result is that two DNs like the aforementioned are considered equal.

processSync in SimpleBindRequest allows empty password with set bindDN

Hey folks,
Is there a reason why check for empty password when bindDN is set comes after logic for doing processing in synchronous mode?
https://github.com/pingidentity/ldapsdk/blob/master/src/com/unboundid/ldap/sdk/SimpleBindRequest.java#L513

protected BindResult process(final LDAPConnection connection, final int depth)
            throws LDAPException
  {
    if (connection.synchronousMode())
    {
      @SuppressWarnings("deprecation")
      final boolean autoReconnect =
           connection.getConnectionOptions().autoReconnect();
      return processSync(connection, autoReconnect);
    }

    // See if a bind DN was provided without a password.  If that is the case
    // and this should not be allowed, then throw an exception.
    if (password != null)
    {
      if ((bindDN.getValue().length > 0) && (password.getValue().length == 0) &&
           connection.getConnectionOptions().bindWithDNRequiresPassword())
      {
        final LDAPException le = new LDAPException(ResultCode.PARAM_ERROR,
             ERR_SIMPLE_BIND_DN_WITHOUT_PASSWORD.get());
        debugCodingError(le);
        throw le;
      }
    }
// Async stuff

At the moment that check only applies to async mode and leaves synchronous mode open to the old and nasty behaviour. Could that entire block be moved up to cover both sync and async methods?

Invalid OSGI Bundle-RequiredExecutionEnvironment

com.unboundid.ldap.sdk 4.0.0 has
Bundle-RequiredExecutionEnvironment: J2SE-1.7
starting with Java 6 these are named JavaSE- not J2SE- so this should be
Bundle-RequiredExecutionEnvironment: JavaSE-1.7

Breaks build with some tools, most notably tycho.

Create a `Schema` from an `InputStream`

We've added LDAP integration in Spring Boot and @mouellet submitted a PR to offer validation for embedded LDAP (see spring-projects/spring-boot#8195).

The problem is that the schema can be on disk or on the classpath (usually it would be in the classpath). There isn't a public method to create a Schema from a java.io.InputStream. It would be nice if that option was available.

Thoughts? Thanks!

Illegal escape character

Hi,

I get an illegal escape character error when trying to build the source on Windows. The problem is that when the Version.java source is built from the stub, it contains a reference to the svn.path as the value of the static REPOSITORY_PATH field. The issue is that the generated string in the java source is not escaped and therefore causes a compile error. If my svn.path for example is "C:\Users\test\git\ldapsdk", the following error is encountered:

[javac] C:\Users\namon\git\ldapsdk\src\com\unboundid\ldap\sdk\Version.java:117: error: illegal escape character
[javac]        "C:\Users\test\git\ldapsdk";

because the generated Version.java includes ...

public static final String REPOSITORY_PATH =
"C:\Users\test\git\ldapsdk";

when instead it should be:

public static final String REPOSITORY_PATH =
"C:\Users\test\git\ldapsdk";

Is there something I'm missing during the build?

Thanks

Add (preferably) Maven, Gradle or Ivy support

I wanted to change something in this project, but I couldn't even build it and publish artifacts to maven repo to reuse in my other projects, because this project uses ant and doesn't publish anything to Maven repos.

Handle access control exception when reading system properties

In Elasticsearch, we always run with the Java Security Manager enabled and we have somewhat restrictive permissions. Our policy allows reading system properties, but does not allow writing them. Unfortunately, Java does not make a distinction between System.getProperties and System.setProperties when it comes to permissions as getProperties returns the internal properties object, which is mutable.

    public static Properties getProperties() {
        SecurityManager sm = getSecurityManager();
        if (sm != null) {
            sm.checkPropertiesAccess();
        }

        return props;
    }
    public static void setProperties(Properties props) {
        SecurityManager sm = getSecurityManager();
        if (sm != null) {
            sm.checkPropertiesAccess();
        }
        if (props == null) {
            props = new Properties();
            initProperties(props);
        }
        System.props = props;
    }

In order to use the UnboundID library we need to grant it access to write any system property and perform some hacks around initialization:

https://github.com/elastic/elasticsearch/blob/f09190c14d28c04c937e6ceb2f01b381a1369ac8/x-pack/plugin/core/src/main/plugin-metadata/plugin-security.policy#L9

https://github.com/elastic/elasticsearch/blob/f09190c14d28c04c937e6ceb2f01b381a1369ac8/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackPlugin.java#L94-L110

There are some ways around this that would require changes within the ldapsdk library. I have a gist of one way to do this; it is not complete by any means since third party code contributions are not accepted.

Hashed user passwords not handled correctly during bind request

I have just gone through this Spring tutorial which uses an embedded UnboundId LDAP server.

While playing around with the sample code, I noticed that doing a simple bind request on the LDAP server fails if the user password is stored as a hash on the server (binding works fine if the password is stored as plaintext).

While looking at the UnboundId sources, I found the following code in the InMemoryRequestHandler class which does the authentication for a simple bind request:

if (userEntry.hasAttributeValue("userPassword", bindPassword.getValue(),
    OctetStringMatchingRule.getInstance()))
{
   ...
}

From what I see, hashed user passwords are not handled correctly by the above code since the password passed in for authentication will always be a plaintext password which is compared directly with the hashed password stored on the server.

Connections are not replaced if reconnect fails after connection reset

If a synchronous search request fails (LDAPConnectionPool#search(...), createIfNecessary is ‘false’) due to connection reset, AbstractConnectionPool#replaceDefunctConnection() tries to replace the connection. But if this method also fails, neither a new connection is put into the pool (of course not), nor the connection pool's ‘failedReplaceCount’ is incremented.

This being the case, one connection is lost forever, and never replaced (also not by further search attempts).

Instead of that, the pool should remember that one connection has been closed (maybe with the help of its ‘failedReplaceCount’), and re-create it later on.

DN.normalize throws away multi-value RDN

The following test produces unexpected output:

import javax.naming.ldap.LdapName;

import com.unboundid.ldap.sdk.DN;

public class Test {

    private static final String TEST_DN = "cn=foo +cn = bar, DC=example,dc=com";

    public static void main(String[] args) throws Exception {
        System.out.println(new LdapName(TEST_DN));
        System.out.println(new LdapName(new LdapName(TEST_DN).getRdns()));
        System.out.println(DN.normalize(TEST_DN));
    }

}
cn=foo +cn = bar, DC=example,dc=com
cn=bar+cn=foo,DC=example,dc=com
cn=bar,dc=example,dc=com

Expected behaviour would be to not drop the cn=foo value.

Filter contains =I{K when searching for a GUID

Hello,

I'm trying to create a filter from a string representation of a GUID for searching in AD/eDirectory.

For example if I have a GUID such as c8381f3d497b4bcca91564eadaee8b08 I can create a filter manually that looks like (objectGUID=\c8\38\1f\3d\49\7b\4b\cc\a9\15\64\ea\da\ee\8b\08).

If I then take that filter string and do a Filter.create, and then a toString() it looks fine.

But if I want to create an OR filter from several such filters and I add them to a List<Filter> first and then do Filter createORFilter = Filter.createORFilter(list); the filter is changed to contain the string =I{K.

I'm not sure sure of why, I can reproduce it with this code below:

import com.unboundid.ldap.sdk.Filter;
import java.util.ArrayList;
import java.util.List;


public class GUIDFilter {

    static String guid = "c8381f3d497b4bcca91564eadaee8b08";
    
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        try {
            Filter f = Filter.create("(objectGUID=" + GUIDtoSearchableString(guid) + ")");
            System.out.println(f.toString());//Prints (objectGUID=\c8\38\1f\3d\49\7b\4b\cc\a9\15\64\ea\da\ee\8b\08)
            List<Filter> list = new ArrayList<>();
            list.add(f);
            Filter createORFilter = Filter.createORFilter(list);
            System.out.println(createORFilter.toString());//Prints (&(objectGUID=\c8\38\1f=I{K\cc\a9\15d\ea\da\ee\8b\08))
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    
    public static String GUIDtoSearchableString(String guid) {
        
        assert guid.length() == 32;
        StringBuilder sb = new StringBuilder(64);
        sb.append("\\");
        char[] toCharArray = guid.toCharArray();
        for (int i=0; i<toCharArray.length; i++) {
            sb.append(toCharArray[i]);
            if (i % 2 == 1 && i != 31) {
                sb.append("\\");
            }
        }
        return sb.toString();
    }
    
    
}

Version qualifier is not applied

When building using a version qualifier of (e.g. .mytest-1) - to avoid a GAV clash with an existing version, I notice that it is not applied throughout consistently. For instance, the POM is still generated using MAJOR-MINOR-POINT rather than MAJOR-MINOR-POINT-QUALIFIER

Missing UnboundID LDAP SDK Free Use License terms in the *.properties files header

As the readme.txt states:

It is also available under the non-open source UnboundID LDAP SDK Free Use
License, which allows the LDAP SDK to be freely used in free or commercial
applications as long as the LDAP SDK itself is not altered.

Unfortunately for my purposes there are some files (mosty *properties) where the header contain different license terms.

f.e.:

https://github.com/pingidentity/ldapsdk/blob/master/messages/unboundid-ldapsdk-args.properties

# Copyright 2008-2017 UnboundID Corp.
# All Rights Reserved.


# Copyright (C) 2008-2017 UnboundID Corp.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License (GPLv2 only)
# or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
# as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses>.

There is no info about non-opensource licence.

Incomplete terms goes into the jar. License code scan for may organization forbid me to use yours library because of that.

Search filter with escaped comma

Some of our Active Directory accounts have commas in the CN field. For example: Smith, James K.

When I query the distinguishedName (which contains the CN) for this account, it returns this: cn=Smith\, James K.,ou=West,dc=MyDomain,dc=com.

However, if I try to use this string to construct a new filter for a subsequent query the groups that the account is a member of:
(&(objectClass=group)(member=cn=Smith\, James K.,ou=West,dc=MyDomain,dc=com))

Filter.readEscapedHexString throws an exception:

Exception in thread "main" LDAPException(resultCode=87 (filter error), errorMessage='Invalid hex character ',' encountered at position 38.')
    at com.unboundid.ldap.sdk.Filter.readEscapedHexString(Filter.java:1854)
    at com.unboundid.ldap.sdk.Filter.create(Filter.java:1630)
    at com.unboundid.ldap.sdk.Filter.parseFilterComps(Filter.java:1757)
    at com.unboundid.ldap.sdk.Filter.create(Filter.java:1159)
    at com.unboundid.ldap.sdk.Filter.create(Filter.java:1070)
    at com.unboundid.ldap.sdk.SearchRequest.<init>(SearchRequest.java:301)

It works when I modify the first switch statement in Filer.readEscapedHexString to contain this:

  case ',':
    b = (byte) 0x5c; // backslash
    buffer.append( b );
    b = (byte) 0x2c; // comma
    buffer.append( b );
    return startPos + 1;

But I don't know the code well to determine if this would create other bugs. Do you know if there are any other ways around this problem?

LDIFReader and mixed content from AD ldifde

Hello,
I performed an LDIF export from Active Directory using built-in ldifde tool on Windows 2012R2. The export included a group which has more than 1500 members and ldifde wrote the first 1500 members into an LDIF add record and the rest was written as an LDIF modify record.

When I try to read that LDIF using LDIFReader like this:

    while (true) {
                Entry entry = reader_leftLdif.readEntry();

                if (entry == null) {
                    break;
                }

              doSomething();
            }

I get this error when it comes to the modify change record:

LDIFException(lineNumber=12, mayContinueReading=true, message='The record starti
ng at or near line number 12 contains a line that does not begin with an attribu
te name followed by a colon.', dataLines='dn: CN=TestGroup,OU=MyGroups,DC=ad,DC=
acme,DC=se{end-of-line}changetype: modify{end-of-line}add: member{end-of-line}me
mber: CN=Resource Admin,OU=Corp,DC=ad,DC=acme,DC=se{end-of-line}-{end-of-line}ad
d: member{end-of-line}member: CN=Another User,OU=Corp,DC=ad,DC=acme,DC=se{end-of
-line}-{end-of-line}add: member{end-of-line}member: CN=Service User,OU=Corp,DC=a
d,DC=acme,DC=se{end-of-line}-{end-of-line}')
        at com.unboundid.ldif.LDIFReader.parseAttributes(LDIFReader.java:2744)
        at com.unboundid.ldif.LDIFReader.decodeEntry(LDIFReader.java:2070)
        at com.unboundid.ldif.LDIFReader.readEntryInternal(LDIFReader.java:1448)

        at com.unboundid.ldif.LDIFReader.readEntry(LDIFReader.java:1058)

Here is a small LDIF that reproduces the error without all the 1500 members.

version: 1

dn: CN=TestGroup,OU=MyGroups,DC=ad,DC=acme,DC=se
changetype: add
cn: TestGroup
member:: Q049QWxlZW4gQWxsYW1hbixPVT1Db3JwLERDPWFkLERDPWFjbWUsREM9c2UNCg==
member:: Q049QWxlamFuZHJhIEFsbGFuLE9VPUNvcnAsREM9YWQsREM9YWNtZSxEQz1zZQ==
member:: 
 Q049QWxlamFuZHJpbmEgQWxsYXJkLE9VPUNvcnAsREM9YWQsREM9YWNtZSxEQz1zZQ==
member:: Q049QWxlbmEgQWxsYXdheSxPVT1Db3JwLERDPWFkLERDPWFjbWUsREM9c2U=

dn: CN=TestGroup,OU=MyGroups,DC=ad,DC=acme,DC=se
changetype: modify
add: member
member: CN=Resource Admin,OU=Corp,DC=ad,DC=acme,DC=se
-
add: member
member: CN=Another User,OU=Corp,DC=ad,DC=acme,DC=se
-
add: member
member: CN=Service User,OU=Corp,DC=ad,DC=acme,DC=se
-

how to create new SearchResult from the old

Hello,

I'd like to change the implementation from the original to Paged one as https://docs.ldap.com/ldap-sdk/docs/javadoc/com/unboundid/ldap/sdk/SearchResult.html suggests.

But in many cases the code uses SearchResult, so I'd like to keep that object. I wonder how can I add more etries to it, or how to create a new one from the old.

getSearchEntries() helps, but I don't know how to construct a new one where I have to provide the SearchResult(int messageID, ResultCode resultCode, java.lang.String diagnosticMessage, java.lang.String matchedDN, java.lang.String[] referralURLs, java.util.List searchEntries, java.util.List searchReferences, int numEntries, int numReferences, Control[] responseControls)

and no idea where to get messageID, resultCode etc. because there are no getters in this class for them.

Any suggestion is welcomed,

Thanks

CaseExactMatch is not respected by in-memory server for "importFromLDIF" data

It seems that the "caseExactMatch" equality test is not respected for the in-memory server, but only for data coming from LDIF files loaded by "server.importFromLDIF(false, path)"

I tested with unboundid 3.2.0 and 2.3.6.
With the following definition:

attributeTypes: ( 1.3.6.1.4.1.35061.1.1.300.5
  NAME 'localAccountName'
  DESC 'A local account name (login) on the server'
  EQUALITY caseExactMatch
  SUBSTR caseIgnoreSubstringsMatch
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )

Then, adding an entry with "importFromLDIF" (before ".startListening", not sure if relevant) with

localAccountName: test
localAccountName: TEST

and the assert: ldap.server.assertValueExists(dn, "localAccountName", java.util.Arrays.asList("TEST","test")) lead to the error "no TEST".

On the other hand, if I'm adding by hand, with a modify request / add attribute value "TEST" on the entry, then the value is correctly added (and both "test" and "TEST" are present).

This not a very severe, but it took me some time to find the problem and workaround.

com.unboundid.ldap.sdk.DN.isValidDN changed between 2.3.6 and 2.3.7 and later versions

In version 2.3.6 and older versions the tests below were fine but since version 2.3.7 they fail (the test values are accepted as valid DNs). Is this on purpose or is a bug?

	@Test
	public void isValiDNTest_4(){
		String str = "cn=";		
		System.out.println("isValiDNTest_4="+com.unboundid.ldap.sdk.DN.isValidDN(str));
		assertFalse(StringUtil.isValidDN(str));
	}

	@Test
	public void isValiDNTest_5(){
		String str = "cn=, ou= test, o=VGR";
		System.out.println("isValiDNTest_5="+com.unboundid.ldap.sdk.DN.isValidDN(str));
		assertFalse(StringUtil.isValidDN(str));
	}

Outputs:
isValiDNTest_4=true
isValiDNTest_5=true

Undersized maps and sets (load factor not taken into account)

Hi everyone!

May I start a discussion about pre-sizing of maps and sets: according to openJDK8's javadoc, HashMaps are rehashed if more entries are stored than the product of the load factor and the current capacity:

When the number of entries in the hash table exceeds the product of the load factor and the current capacity, the hash table is rehashed (that is, internal data structures are rebuilt) so that the hash table has approximately twice the number of buckets.

This applies e.g. for HashMaps / LinkedHashMaps / HashSets and LinkedHashSets (but not for Lists): you can store only 0.75 * initialCapacity of elements.

Having a look at unboundId LDAP SDK sources, it looks like these collections are most often undersized if the number of elements is known in advance and all entries are stored immediately after creating the map, e.g. com.unboundid.ldap.sdk.Entry lines 234, 283, etc:

this.attributes = new LinkedHashMap<>(attributes.length);

or com.unboundid.ldap.sdk.Attribute lines 1734ff:

final HashSet<ASN1OctetString> unNormalizedValues = new HashSet<>(values.length);
Collections.addAll(unNormalizedValues, values);

For best performance, rehashing should be avoided, i.e. the initial capacity of maps or sets should take the load factor into account, e.g.

final int initialCapacity = (int) (expectedNumberOfElements/.75f) + 1

resulting in

this.attributes = new LinkedHashMap<>((int) (attributes.length/.75f) + 1);

To illustrate the rehashing algorithm (internal map size is always a power of two, rehashing takes place if load factor based threshold is exceeded), I've attached a short test class:

InitialCapacity.java.txt

Usually rehashing shouldn't make a big difference if only a few elements are stored, but if there are many different ones, it's worth to avoid rehashing if possible.

What's your opinion about that?

Best regards

Frank

Add refreshKrb5Config to GSSAPIBindRequestProperties

Currently it doesn't seem possible to specify refreshKrb5Config to force a refresh of the Kerberos configuration, via GSSAPIBindRequest and its associated properties class. I tried to extend GSSAPIBindRequest but writeSunJAASConfig() doesn't really allow for it. Is it possible to add a way to extend or support refreshKrb5Config directly?

Thanks.

AD authentification

I am trying to authenticate agains AD using Android app but it doesn't work, I am probably missing something. What should I enter in Bind DN, I have tried entering username alone, "CN={username}", "CN={username},CN={group},DN={domain name}" none of these work I am always getting:

LDAPException(resultCode=49 (invalid credentials), errorMessage='80090308: LdapErr: DSID-0C0903A9, comment: AcceptSecurityContext error, data 52e, v1db1��', diagnosticMessage='80090308: LdapErr: DSID-0C0903A9, comment: AcceptSecurityContext error, data 52e, v1db1��')

I am 100% positive that credentials are not invalid because I tried using other app and it worked. Could you please help me with this.

Possibility to test error scenarios

Hi!
I was wondering if it is possible to test ldap busy scenarios? (Sorry if I missed that info in the documentation).

Parameters that I used for starting the server:
unboundid-ldapsdk-se.jar com.unboundid.ldap.listener.InMemoryDirectoryServerTool --baseDN=dc=com --port=1389 --ldifFile=/tmp/ldapjHKOmH/ldap.ldif

Thank you a lot for your answer.

java.lang.NoSuchMethodError: No virtual method keySet()

I have followed instructions for building and installing UnboundID Android app, copied unboundid-ldapsdk-se.jar from .../package/unboundid-ldapsdk-3.2.1-se into lib folder but when I add server ID, IP address and hit Test Settings button I get this exception and application rashes:

va.lang.NoSuchMethodError: No virtual method keySet()Ljava/util/concurrent/ConcurrentHashMap$KeySetView; in class Ljava/util/concurrent/ConcurrentHashMap; or its super classes (declaration of 'java.util.concurrent.ConcurrentHashMap' appears in /system/framework/core-libart.jar)
at com.unboundid.ldap.sdk.LDAPConnectionReader.closeInternal(LDAPConnectionReader.java:1092)
at com.unboundid.ldap.sdk.LDAPConnectionReader.close(LDAPConnectionReader.java:1056)
at com.unboundid.ldap.sdk.LDAPConnectionInternals.close(LDAPConnectionInternals.java:617)
at com.unboundid.ldap.sdk.LDAPConnection.setClosed(LDAPConnection.java:4433)
at com.unboundid.ldap.sdk.LDAPConnectionReader.closeInternal(LDAPConnectionReader.java:1089)
at com.unboundid.ldap.sdk.LDAPConnectionReader.run(LDAPConnectionReader.java:417)

Could not find COMPLETELY_THREADSAFE in enum object ThreadSafetyLevel

Hi,

I'm working in a business where we use the unboundid ldapsdk to authenticate users. Our project management has decided to increase the "quality" of our code by forcing warnings to be treated as errors.
Now, the problem is, that when using the ldapsdk library, the scala compiler issues a warning stating that it cannot find COMPLETELY_THREADSAFE (which now breaks our build). See also:

While parsing annotations in path\to\unboundid-ldapsdk-3.0.0.jar (com/unboundid/util/ThreadSafetyLevel.class), could not find COMPLETELY_THREADSAFE in enum object ThreadSafetyLevel.
This is likely due to an implementation restriction: an annotation argument cannot refer to a member of the annotated class (SI-7014).

Do you have any idea on how I could solve this?

SocketException(Socket closed) when adding a very big entry

Hello,

When I try to add a very big entry (big == (nunber of values for an attribute x size of values) goes above some threshold), I get the following exception:

	at com.unboundid.ldap.sdk.LDAPConnectionInternals.sendMessage(LDAPConnectionInternals.java:611)
	at com.unboundid.ldap.sdk.LDAPConnection.sendMessage(LDAPConnection.java:4406)
	at com.unboundid.ldap.sdk.AddRequest.processAsync(AddRequest.java:1121)
	at com.unboundid.ldap.sdk.AddRequest.process(AddRequest.java:1025)
	at com.unboundid.ldap.sdk.LDAPConnection.add(LDAPConnection.java:2078)
       ......
Caused by: java.net.SocketException: Socket closed
	at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:118)
	at java.net.SocketOutputStream.write(SocketOutputStream.java:155)
	at java.io.BufferedOutputStream.write(BufferedOutputStream.java:122)
	at com.unboundid.util.ByteStringBuffer.write(ByteStringBuffer.java:1662)
	at com.unboundid.asn1.ASN1Buffer.writeTo(ASN1Buffer.java:1012)
	at com.unboundid.ldap.sdk.LDAPConnectionInternals.sendMessage(LDAPConnectionInternals.java:562)
	... 12 more

So it seems that somewhere inside unboundid, there is something that is limited by Integer.maxvalue.

You can reproduce it with the following code (it's scala, but should really be understandable anyhonw: add a sufficient number of sufficiently big values => you reach the point where the error happens).

  val provider = new RWPooledSimpleAuthConnectionProvider(
      host = "localhost",
      port = 1389,
      authDn = "cn=Manager,cn=rudder-configuration",
      authPw = "secret",
      poolSize = 1
  )
  def str(size: Int) = new String( Array.fill[Char](size)('x'))

  // run
  def main(args: Array[String]): Unit = {
    val dn = new DN("cn=Nodes Configuration,ou=Rudder,cn=rudder-configuration")
    // here, if I use 454 bytes for the last value, I get the exception. Below that, OK
    val values = for(i <- 0 until 167) yield i + "-"+str(100000) ++ str(454)


  val addRequest = new AddRequest(
        dn
      , new Attribute("objectClass", "top", "nodeConfigurations")
      , new Attribute("cn", "Nodes Configuration")
      , new Attribute("nodeConfig", values:_*) // here, we add 168 big value and one small
    )

    val x = for {
      ldap <- provider
      _ =  println("**** got connection")
      _ <- ldap.delete(dn) // that's just to clean up when testing multiple time
      _ =  println("**** deleted")
      _ =  ldap.backed.add(addRequest) // KABOUM
      _ =  println("**** added")
    } yield {
      "done"
    }
    println(x)
  }

I tried to understand both the code and the debug output, but failed for each one.

I understand that the use case is a little bit extreme (even if encoutered in Rudder https://www.rudder-project.org/redmine/issues/10646#note-24), but I'm wondering if there is a workaround ?

Thanks

Started thread but failed to stop it

I have a JRuby on Rails app running on tomcat which is recording a number of these warnings in catalina.out.

I recently took over ownership of this application from a developer who left our organization so I am still getting familiar with the SDK and the custom gem he built around it that we use with this app. Last week I updated the SDK version in use from 3.1.0 to 4.0.4 in our development app but these log messages are still occurring.

We generally have to restart Tomcat/Apache in production every two weeks or so and I think this may the the reason why.

09-Feb-2018 22:14:50.857 WARNING [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [ROOT] appears to have started a thread named [Health Check Thread for LDAPConnectionPool(serverSet=RoundRobinServerSet(servers={<SERVER:PORT>}, includesAuthentication=false, includesPostConnectProcessing=false), maxConnections=10)] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
- sun.misc.Unsafe.park(Native Method)
- java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
- java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
- java.util.concurrent.LinkedBlockingQueue.poll(LinkedBlockingQueue.java:467)
- com.unboundid.ldap.sdk.LDAPConnectionPoolHealthCheckThread.run(LDAPConnectionPoolHealthCheckThread.java:109)
09-Feb-2018 22:14:50.858 WARNING [localhost-startStop-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [ROOT] appears to have started a thread named [Connection reader for connection 40 to <SERVER:PORT>] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
- java.net.SocketInputStream.socketRead0(Native Method)
- java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
- java.net.SocketInputStream.read(SocketInputStream.java:171)
- java.net.SocketInputStream.read(SocketInputStream.java:141)
- sun.security.ssl.InputRecord.readFully(InputRecord.java:465)
- sun.security.ssl.InputRecord.read(InputRecord.java:503)
- sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:983)
- sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:940)
- sun.security.ssl.AppInputStream.read(AppInputStream.java:105)
- java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
- java.io.BufferedInputStream.read(BufferedInputStream.java:265)
- com.unboundid.asn1.ASN1StreamReader.read(ASN1StreamReader.java:1157)
- com.unboundid.asn1.ASN1StreamReader.readType(ASN1StreamReader.java:331)
- com.unboundid.asn1.ASN1StreamReader.beginSequence(ASN1StreamReader.java:1077)
- com.unboundid.ldap.protocol.LDAPMessage.readLDAPResponseFrom(LDAPMessage.java:1146)
- com.unboundid.ldap.sdk.LDAPConnectionReader.run(LDAPConnectionReader.java:225)

ldapsdk should stop suppressing `Error`

The ldapsdk currently has exception handling blocks that catch Throwable and then anything that is not an LDAPException, including Error instances, gets wrapped in an LDAPException. One such place in the code is:

catch (final Throwable t)
{
Debug.debugException(t);
if (t instanceof LDAPException)
{
final LDAPException le = (LDAPException) t;
boolean shouldThrow;
try
{
healthCheck.ensureConnectionValidAfterException(conn, le);
// The above call will throw an exception if the connection doesn't
// seem to be valid, so if we've gotten here then we should assume
// that it is valid and we will pass the exception onto the client
// without retrying the operation.
releaseAndReAuthenticateConnection(conn);
shouldThrow = true;
}
catch (final Exception e)
{
Debug.debugException(e);
// This implies that the connection is not valid. If the pool is
// configured to re-try bind operations on a newly-established
// connection, then that will be done later in this method.
// Otherwise, release the connection as defunct and pass the bind
// exception onto the client.
if (! getOperationTypesToRetryDueToInvalidConnections().contains(
OperationType.BIND))
{
releaseDefunctConnection(conn);
shouldThrow = true;
}
else
{
shouldThrow = false;
}
}
if (shouldThrow)
{
throw le;
}
}
else
{
releaseDefunctConnection(conn);
throw new LDAPException(ResultCode.LOCAL_ERROR,
ERR_POOL_OP_EXCEPTION.get(StaticUtils.getExceptionMessage(t)), t);
}
}

There are other places in the code where Throwable is caught:

$ git rev-parse HEAD
0eac394a077323485b850a90e55f926bc035023f
$ ack --type java "catch\s*\(\s*(final)?\s*Throwable" | wc -l
      43
$ ack --type java "catch\s*\(\s*(final)?\s*Throwable" tests/unit/src/com/unboundid/test/LDAPSDKTestListener.java 127: catch (final Throwable t)

tests/unit/src/com/unboundid/util/WakeableSleeperTestCaseHelperThread.java
182: catch (Throwable t)

tests/unit/src/com/unboundid/ldap/sdk/migrate/ldapjdk/LDAPConnectionTestCase.java
102: } catch (Throwable t) {}
162: } catch (Throwable t) {}
377: } catch (Throwable t) {}

tests/unit/src/com/unboundid/ldap/sdk/DSEETestCase.java
102: catch (Throwable t)

src/com/unboundid/util/parallel/ParallelProcessor.java
348: catch (final Throwable e)
377: catch (final Throwable e)

src/com/unboundid/util/parallel/AsynchronousParallelProcessor.java
291: catch (final Throwable e)

src/com/unboundid/ldap/listener/LDAPListenerClientConnection.java
624: catch (final Throwable t)

src/com/unboundid/ldap/sdk/ConnectThread.java
151: catch (final Throwable t)

src/com/unboundid/ldap/sdk/AbstractConnectionPool.java
458: catch (final Throwable t)
472: catch (final Throwable t2)
540: catch (final Throwable t)
554: catch (final Throwable t2)
619: catch (final Throwable t)
633: catch (final Throwable t2)
765: catch (final Throwable t)
779: catch (final Throwable t2)
869: catch (final Throwable t)
883: catch (final Throwable t2)
948: catch (final Throwable t)
962: catch (final Throwable t2)
1043: catch (final Throwable t)
1057: catch (final Throwable t2)
1181: catch (final Throwable t)
1196: catch (final Throwable t2)
1328: catch (final Throwable t)
1342: catch (final Throwable t2)
1460: catch (final Throwable t)
1474: catch (final Throwable t2)
2060: catch (final Throwable t)
2083: catch (final Throwable t2)
2429: catch (final Throwable t)
2452: catch (final Throwable t2)

src/com/unboundid/ldap/sdk/LDAPConnectionPool.java
1623: catch (final Throwable t)
1688: catch (final Throwable t)

src/com/unboundid/ldap/sdk/persist/DefaultObjectEncoder.java
1251: catch (final Throwable t)

src/com/unboundid/ldap/sdk/persist/LDAPObjectHandler.java
1233: catch (final Throwable t)
1302: catch (final Throwable t)
1401: catch (final Throwable t)

src/com/unboundid/ldap/sdk/LDAPThreadLocalConnectionPool.java
721: catch (final Throwable t)
786: catch (final Throwable t)

Some of these cases are in tests but from what I see the majority are not in tests. I did not inspect each case for the behavior of wrapping but I believe each one should be looked at to see if it indeed wraps and hides Errors.

The Javadocs for Error state:

An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch.

While it is reasonable to catch a Throwable and do some cleanup, if the Throwable is an Error it should not be suppressed by wrapping it in an LDAPException. Errors should bubble up to the application's handling (if any); in the Elasticsearch case if we hit an error, we want to "die with dignity" (see elastic/elasticsearch#19272).

Alias deref support for InMEmoryDirectoryServer

Hi there,

I am implementing alias deref for InMemoryRequestHandler via a new LDAPListenerRequestHandler. I have already a working implementation with JUnit tests. It is not tuned for performance, just to provide the fucntionality

I would like to contribute that to the project if you find it interesting. If that is the case could you send some link to understand the process to make contributions?

Cheers,

/evaristo

How to support Chinese characters in search base

realm.ldap.accountBase = OU=用户,DC=abc,DC=com

if search base include Chinese characters will cause this error

LDAPSearchException(resultCode=32 (no such object), numEntries=0, numReferences=0, errorMessage='0000208D: NameErr: DSID-03100238, problem 2001 (NO_OBJECT), data 0, best match of:

remove OU=用户 works fine.

connectionPool setBindRequest ignored in some cases

Hi,
I was trying to use credentials reconfiguration in a connected connection pool using setBindRequest support introduced in ldapsdk 4.0.6, but found a small issue.

The new bind credentials are only used when the connection pool is created with some constructors. Specifically, a pool created using the constructor

public LDAPConnectionPool(final LDAPConnection connection,
final int initialConnections,
final int maxConnections,
final int initialConnectThreads,
final PostConnectProcessor postConnectProcessor,
final boolean throwOnConnectFailure)

does not honor the new credentials set via setBindRequest (i.e. keeps using the original credentials from the passed connection for new connections). I looked at the code and saw that the internally created ServerSet keeps a reference to the original bindRequest that is not updated on setBindRequest calls, but didn't verify this is indeed the problem)

The problem is not triggered when the pool was created using the constructor which receives ServerSet and BindRequest arguments (I am currently this as a workaround)

Hostname verification failure leaves dangling connection

When hostname verification fails it appears that the connection cannot be closed.

    LDAPConnectionOptions options = new LDAPConnectionOptions();
    options.setSSLSocketVerifier(new SSLSocketVerifier()
    {   
      @Override
      public void verifySSLSocket(String h, int p, SSLSocket s)
        throws LDAPException
      {   
        throw new LDAPException(ResultCode.CONNECT_ERROR, "Hostname verification failed.");
      }   
    });

    SSLSocketFactory factory = (new SSLUtil()).createSSLSocketFactory();
    LDAPConnection conn = new LDAPConnection(factory, options);
    try {
      conn.connect("directory.host.com", 636);
    } catch (Exception e) {
      System.err.println(e.getMessage());
    } finally {
      conn.close();
    }   

    Thread.sleep(10000);

Perform a netstat while the thread is sleeping and you'll see an established connection after close has been called. I could be missing something, but I don't see another way to tear down the connection.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.