JNDI/LDAP Supplement: Guidelines for LDAP Service Providers

#

# JNDI Implementor Guidelines for LDAP Service Providers

# Draft 0.4.1

Please send feedback to jndi@java.sun.com

Table of Contents
1. Introduction
2. Conformance
3. Environment Properties
4. Names
5. Attributes
6. URLs
7. Java Objects
8. Schema
9. Exceptions
10. API Mapping
11. Federation
12. SASL
13. Extensions and Controls
14. Event Notification
15. SSL

## 1. Introduction

This document specifies guidelines that developers creating LDAP service providers and service providers that support LDAP-like features should follow. By following these guidelines, developers can produce implementations that JNDI API users can configure and use with minimal differences.

Not all of the features described in this document must be supported by an LDAP service provider. However, if a feature is supported, it should be supported in the way described by this document.

## 2. Conformance

An LDAP service provider that supports LDAP version 3 (LDAPv3) conforms to:

- RFC 2251 and related specifications.

An LDAP service provider that supports LDAP version 2 (LDAPv2) conforms to:

- RFC 1777 and related specifications.

## 3. Environment Properties

Environment properties are the means by which JNDI application users configure and affect the behavior of JNDI service providers. Consequently, service providers must interpret and handle environment properties in the same way.

There are four types of environment properties that affect LDAP service providers:

- Standard JNDI environment properties
- LDAP-specific environment properties
- Provider-specific environment properties
- Feature-specific environment properties

### 3.1 Overview

#### 3.1.1 Initialization

When creating an initial context, environment properties can be passed as an argument to the constructor or may be initialized as specified in the JNDI documentation.

In particular, if any of the following properties is not supplied in the environment properties then it is sought from the system properties, applet parameters, and both provider and application resource files (in that order):

- `java.naming.factory.control`
- `java.naming.factory.initial`
- `java.naming.factory.object`
- `java.naming.factory.state`
- `java.naming.provider.url`

In the case of the control, object and state factory properties, if more than one occurrence of the property is located, then its values are concatenated into a single list. In the case of the url property and all other properties, only the first occurrence is used.

A context's environment properties can be examined using the `Context.getEnvironment` method.

#### 3.1.2 Modification

A context's environment properties may be changed using the `Context.addToEnvironment` and `Context.removeFromEnvironment` methods.

#### 3.1.3 Scope

With the exception of the `java.naming.provider.url` and `java.naming.factory.initial` properties, changing a property using the `Context.addToEnvironment` or `Context.removeFromEnvironment` methods affects the context instance on which the method is invoked. For example, if you specify new credentials for a context to use, subsequent methods invoked on that context that require communication with the server will use those new credentials (perhaps internally by first creating a new connection to the server). These updated environment properties are inherited by context instances that are subsequently derived from the affected context instance, but do not otherwise affect other context instances that were in existence prior to the update.

#### 3.1.4 Timeliness

When a change is made to the environment properties, there is no requirement that the change be verified and acted upon at the time the `Context.addToEnvironment` or `Context.removeFromEnvironment` method is invoked. The only requirement is that the change (or changes) be effective the next time an operation that uses that property is invoked.

#### 3.1.5 Defaults

This specification defines defaults for the environment properties. In a few cases, the default is determined by the service provider. If a context does not have a particular environment property, it behaves as if it has that environment property with its default value.

When a property is removed from the environment properties of a context, the context assumes the default behavior specified for that property. This does not necessarily mean that the default value must be recorded as the property's value. The removal may also be indicated by the absence of the property from the context's environment properties.

#### 3.1.6 Acceptable Values

This specification defines acceptable values for the environment properties. Some environment properties have a fixed set of acceptable values while others have values that must follow a particular syntax. If an unacceptable value is presented, a property-specific exception will be thrown (for example, `ConfigurationException`, `IllegalArgumentException`, or `AuthenticationNotSupportedException`). In some cases, it might be reasonable for the service provider to accept additional values than those specified, in which case, those values should be documented.

### 3.2 JNDI Properties

LDAP service providers should process the JNDI environment properties according to the following specifications. In the examples given, `env` is an instance of `Hashtable` that holds the environment properties used to create an initial context.

`java.naming.batchsize`

> The value of this property is a string of decimal digits that specifies the batch size of search results returned by the server.

> This property affects the blocking behaviour of the `Context.list`, `Context.listBindings`, and `DirContext.search` methods and the `NamingEnumeration` objects that they return. It does not affect how many items are returned in the enumeration; it only affects how the items are batched or read at the LDAP protocol level.

> A setting of zero means that the provider should block until all results have been received. A setting of an integer n greater than zero means that the provider should block until n results have been received from the server or until the enumeration terminates, whichever produces the fewer number of results. After the application has read n results (using `NamingEnumeration.next` or `NamingEnumeration.nextElement`), the provider should read n more results from the server or until the enumeration terminates, whichever produces the fewer number of results.

> If this property is not set then its default value is implementation-specific.

> For example,

> >     env.put(Context.BATCHSIZE, "24");

> specifies that the provider should block until 24 entries have been read from the server or until the enumeration terminates, whichever produces the fewer number of results.

`java.naming.factory.control`

> The value of this property is a colon-separated list of fully qualified class names of control factory classes.

> The factories are responsible for narrowing the class of response controls. They create specific response controls from the generic response controls generated by the provider.

> No default value is defined for this property.

> For example,

> >     env.put(LdapContext.CONTROL_FACTORIES,
> >             "com.sun.jndi.ldap.ctl.ResponseControlFactory");

> sets the `ResponseControlFactory` class as the control factory to try.

`java.naming.factory.initial`

> The value of this property is the fully qualified class name of the factory class which creates the initial context for the LDAP service provider.

> It is used to select a particular LDAP service provider; it's not actually used by the provider itself. This property need not be set when the name argument to initial context methods is a URL.

> No default value is defined for this property.

> For example,

> > `env.put(Context.INITIAL_CONTEXT_FACTORY,`
> > `"com.sun.jndi.ldap.LdapCtxFactory");`

> selects Sun's LDAP provider.

`java.naming.factory.object`

> The value of this property is a colon-separated list of fully qualified class names of object factory classes.

> The factories are responsible for creating specific objects from the LDAP entries returned by the provider. For example, a Person object factory might generate a `Person` object from an LDAP entry of object class person. Object factories behave in the opposite way to state factories in that they generate objects from LDAP attributes.

> No default value is defined for this property.

> For example,

> >     env.put(Context.OBJECT_FACTORIES,
> >             "com.sun.jndi.ldap.obj.PersonFromLDAP");

> sets the `PersonFromLDAP` class as the object factory to try.

`java.naming.factory.state`

> The value of this property is a colon-separated list of fully qualified class names of state factory classes.

> The factories are responsible for creating an object's state (for storing) from the object itself. For example, a Person state factory might generate an LDAP entry of object class person from a `Person` object. State factories behave in the opposite way to object factories in that they generate LDAP attributes from objects.

> No default value is defined for this property.

> For example,

> >     env.put(Context.STATE_FACTORIES,
> >             "com.sun.jndi.ldap.obj.PersonToLDAP");

> sets the `PersonToLDAP` class as the state factory to try.

`java.naming.language`

> The value of this property is a string language tag according to RFC 1766.

This property indicates a preference for a particular natural language. A provider may adjust its LDAP requests and responses according to the value of this property.

The affect of this property is implementation-specific. No default value is defined.

For example:

    env.put(Context.LANGUAGE, "ja-JP");

indicates a preference for Japanese.

`java.naming.provider.url`

> The value of this property is a list of space-separated URL strings, each of which specifies the hostname and port number of the LDAP server, and the root distinguished name of the naming context to use. If the list contains more than one URL, the provider should attempt to use each URL in turn until it is able to create a successful connection, and after creation, set the property to the successful URL.

> The default hostname is `localhost`; the default port is `389`. The default root distinguished name is the empty string. If this property is not set, or if either the hostname or port number is omitted, then the default values are used in place of the missing information. If both the hostname and port are missing but a non-empty distinguished name is present in the URL, then the provider should use the distinguished name to determine the hostname and port of the LDAP server(s) as described in the LDAP URL section and when a connection has been established successfully, set the `java.naming.provider.url` property to an LDAP URL constructed using the successful hostname, port and distinguished name. See also the LDAP URL section for information on how the provider should treat other information found in the URL.

> For example:

> >     env.put(Context.PROVIDER_URL, "ldap://secserver:636");

> specifies that the LDAP server is running on a host named `secserver` at port `636`.

> NOTE: Changing this property using the `Context.addToEnvironment` or `Context.removeFromEnvironment` methods does not affect the context. It is only used by the initial context constructors.

`java.naming.referral`

> The value of this property is a string that specifies how referrals shall be handled by the provider. The following values are defined for this property:

`follow`
  automatically follow any referrals.
`throw`
  throw a `ReferralException` for each referral.
`ignore`
  ignore referrals if they appear in results. A `PartialResultException` is thrown to indicate an incomplete result. In addition, for LDAPv3 servers, the provider shall request that referrals be treated as ordinary attributes when they appear in entries. This is achieved by sending a non-critical ManageDsaIT (`draft-ietf-ldapext-namedref-00.txt`) LDAP control with each LDAP request. LDAP servers which do not support this LDAP control will simply ignore it and process the request as normal.

See LDAP URL for information on how to treat multiple URLs found in a single referral entry.

If this property is not set then its default value is `ignore`.

For example:

    env.put(Context.REFERRAL, "throw");

specifies that referrals encountered during an LDAP operation should throw a `ReferralException` to the application.

`java.naming.security.authentication`

> The value of this property is a string that specifies the authentication mechanism(s) for the provider to use. The following values are defined for this property:

`none`
  use no authentication (anonymous bind).
`simple`
  use simple authentication (a cleartext password).
A space-separated list of one or more SASL mechanism names:
  use the first available SASL mechanism in the list that conforms to the specified policy requirements

See the SASL section for information on how this property is used for SASL authentication. See RFC 2829 for information on LDAP authentication mechanisms.

If this property is not set then its default value is `none`, unless the java.naming.security.credentials property is set, in which case the default value is `simple`. If this property is set to a value that the provider does not recognize or support, it should throw `AuthenticationNotSupportedException`.

For example:

    env.put(Context.SECURITY_AUTHENTICATION, "simple");

specifies that simple authentication be used to authenticate to the LDAP server. Or,

    env.put(Context.SECURITY_AUTHENTICATION, "DIGEST-MD5 CRAM-MD5");

specifies that DIGEST-MD5 authentication be used and, if that SASL mechanism is unavailable, that CRAM-MD5 authentication be used. If neither is available then throw `AuthenticationNotSupportedException`.

`java.naming.security.credentials`

The value of this property is an object that specifies the credentials of the principal to be authenticated. Its format and handling depends on the value of the java.naming.security.authentication property.

For anonymous binds, this property is ignored - an empty string is always used for the credentials. For simple authentication and SASL authentication that requires a password, the value of this property may be supplied as a `java.lang.String`, a `char[]` or a `byte[]`. If it is a `String` or a `char[]` then it is encoded into a byte array using UTF-8 in the case of LDAPv3 and encoded using ISO-Latin-1 in the case of LDAPv2. If it is a `byte[]` then it is used as is.

See the SASL section for information on how this property is used for SASL authentication.

No default value is defined for this property.

For example:

    env.put(Context.SECURITY_CREDENTIALS, "secret");

sets the credentials to be the string "secret".

`java.naming.security.principal`

> The value of this property is a string that specifies the identity of the principal to be authenticated. Its format depends on the authentication type; see RFC 2829 for more information. The value is used as the `name` component in an LDAP ASN.1 BindRequest for non-SASL authentication. For SASL authentication, the value of this property is used as the authentication ID for SASL mechanisms that need an authentication ID.

> The provider is not required to verify the validity of the principal name. It may, for example, just pass the string to be verified by the server. If the principal identified is not a valid principal then the provider shall throw an `AuthenticationException`.

> No default value is defined for this property.

> For example:

> >     env.put(Context.SECURITY_PRINCIPAL, "cn=admin,o=sun,c=us");

> sets the principal name to be the distinguished name "cn=admin, o=sun, c=us".

`java.naming.security.protocol`

The value of this property is a string that specifies the security protocol for the provider to use. The following value is defined for this property:

`ssl`
  use Secure Sockets Layer version 3.0.

If this property is set to `ssl`, the provider must use SSL sockets, or throw `ConfigurationException` if it is unable to do so. In addition to the value listed above, a provider may support other security protocols. However, such provider-specific protocols might not be supported by all providers. If this property is set to a security protocol that the provider does not recognize or support, it should throw `ConfigurationException`.

If the java.naming.ldap.factory.socket property is set, then the socket factory identified by that property must create sockets that are appropriate for this protocol setting. For example, if the security protocol is set to `ssl`, then the socket factory must create SSL-compliant sockets.

If this property is not set then the default is to use no security protocol.

As a developer of the LDAP provider, you should be aware that using SSL to connect to a server on a port that is not listening for SSL connections causes the socket to hang. Similarly, using a plain socket to connect to a server that is listening for SSL connections also leads to hanging. This is a characteristic of the protocol that some implementations may choose to correct but is not otherwise required to do so. The provider's documentation, however, should describe this behavior to its users. See SSL for information on how to use SSL.

For example:

    env.put(Context.SECURITY_PROTOCOL, "ssl");

specifies that SSL-compliant sockets be used to communicate with the server.

### 3.3 LDAP-specific Properties

LDAP-specific properties are environment properties that apply to LDAP service providers in general. These properties' names have the prefix "`java.naming.ldap.`". The following table lists LDAP-specific properties that have been defined so far. If there is a property that you feel belongs on this list, please send a description of it to jndi@java.sun.com.

`java.naming.ldap.attributes.binary`

The value of this property is a string of space-separated attribute names. It specifies attributes which have non-string syntax. It extends the provider's built-in list of non-string attributes (below). The value of an attribute that has non-string syntax is returned as a byte array (`byte[]`) instead of a `String`.

No default is defined. If this property is not set then only the following attributes are considered to have non-string syntax:

Attribute ID | OID | Reference
--- | --- | ---
Any attribute ID with the "`;binary`" option. |  |
`photo` | 0.9.2342.19200300.100.1.7 | RFC 1274
`personalSignature` | 0.9.2342.19200300.100.1.53 | RFC 1274
`audio` | 0.9.2342.19200300.100.1.55 | RFC 1274
`jpegPhoto` | 0.9.2342.19200300.100.1.60 | RFC 2798
`javaSerializedData` | 1.3.6.1.4.1.42.2.27.4.1.7 | RFC 2713
`thumbnailPhoto` | 2.16.128.113533.1.1400.1 | NAC LIP Schema
`thumbnailLogo` | 2.16.128.113533.1.1400.2 | NAC LIP Schema
`userPassword` | 2.5.4.35 | RFC 2256
`userCertificate` | 2.5.4.36 | RFC 2256
`cACertificate` | 2.5.4.37 | RFC 2256
`authorityRevocationList` | 2.5.4.38 | RFC 2256
`certificateRevocationList` | 2.5.4.39 | RFC 2256
`crossCertificatePair` | 2.5.4.40 | RFC 2256
`x500UniqueIdentifier` | 2.5.4.45 | RFC 2256

For example:

    env.put("java.naming.ldap.attributes.binary",
            "mpegVideo myspecialkey");

informs the provider to return values of the `mpegVideo` and `myspecialkey` attributes as `byte[]`.

`java.naming.ldap.control.connect`

The value of this property is a `Control[]` object. It sets the connection request controls that are active on a connection. See `LdapContext`.

No default value is defined for this property.

For example:

    env.put("java.naming.ldap.control.connect",
            new Control[]{ new ManageReferralControl(true) });

sets a critical ManageDsaIT LDAP control as the connection request control.

`java.naming.ldap.deleteRDN`

The value of this property is a string that specifies whether the old RDN is removed by the `Context.rename` method. The following values are defined for this property:

`true`
  delete the old RDN from the entry during the rename operation.
`false`
  retain the old RDN as an attribute value of the entry.

If this property is not set then its default value is `true`.

For example:

    env.put("java.naming.ldap.deleteRDN", "false");

causes the old RDN to be retained as an attribute of the renamed entry.

`java.naming.ldap.derefAliases`

> The value of this property is a string that specifies how aliases are dereferenced during search operations. The following values are defined for this property:

> > `always`
> >   always dereference aliases.
> > `never`
> >   never dereference aliases.
> > `finding`
> >   dereference aliases only during name resolution (that is, while locating the target entry).
> > `searching`
> >   dereference aliases once name resolution has completed (that is, after locating the target entry).

> If this property is not set then its default value is `always`.

> For example:

>     env.put("java.naming.ldap.derefAliases", "searching");

> causes the provider to dereference aliases only once the target entry has been located.

> NOTE: this property is unrelated to the dereference-links flag in the `SearchControls` object.

`java.naming.ldap.factory.socket`

The value of this property is a string identifying the class name of a socket factory.

This property is used to override the default socket factory. The class specified in this property must implement the `javax.net.SocketFactory` interface. See http://java.sun.com/j2se/1.4/docs/guide/security/jsse/JSSERefGuide.html for more information. See SSL for information on how to use SSL.

In addition, if the java.naming.security.protocol property is set, then the socket factory identified by this property must create sockets which are appropriate for that protocol setting. For example, if the security protocol is set to `ssl` then the socket factory must create SSL-compliant sockets.

No default is defined for this property.

For example:

    env.put("java.naming.ldap.factory.socket",
            "javax.net.ssl.SSLSocketFactory");

sets the socket factory of the provider to be `javax.net.ssl.SSLSocketFactory`.

`java.naming.ldap.ref.separator`

The value of this property is a string containing the character to use when encoding a `RefAddr` object in the `javaReferenceAddress` attribute (see Java Objects).

This property is used to avoid a conflict in the case where the default separator character appears in the components of a `RefAddr` object.

If this property is not set then its default value is '`#`' (the hash character).

For example:

    env.put("java.naming.ldap.ref.separator", ":");

specifies that the separator '`:`' (the colon character) be used when storing `RefAddr` instances.

`java.naming.ldap.referral.limit`

The value of this property is a string of decimal digits specifying the maximum number of referrals to follow in a chain of referrals. A setting of zero indicates that there is no limit.

If this property is not set then the default value is `10`.

For example:

    env.put("java.naming.ldap.referral.limit", "5");

specifies that the referral limit is 5.

`java.naming.ldap.typesOnly`

The value of this property is a string that specifies whether only attribute IDs are returned in results - attribute values are omitted. Affects the `SearchResult.getAttributes` and `DirContext.getAttributes` methods. The following values are defined for this property:

`true`
  return only attribute IDs.
`false`
  return both attribute IDs and attribute values.

If this property is not set then its default value is `false`.

For example:

    env.put("java.naming.ldap.typesOnly", "true");

causes the server to return attribute IDs but not attribute values.

`java.naming.ldap.version`

The value of this property is a string that specifies the protocol version for the provider. The following values are defined for this property:

`2`
  selects LDAP version 2 (LDAPv2).
`3`
  selects LDAP version 3 (LDAPv3).

If this property is not set then the provider first attempts to bind using LDAP v3 and fails over to using LDAP v2 if a protocol error is received from the server. This failover mechanism is only used when the `java.naming.security.authentication` property indicates anonymous bind or simple authentication.

For example:

    env.put("java.naming.ldap.version", "2");

requests the LDAP provider to communicate with the server using LDAPv2.

### 3.4 Feature-specific Properties

Feature-specific properties are environment properties which apply to a particular feature which is supported by a provider.

#### 3.4.1 SASL Properties

There are two groups of SASL properties. The first group comprises those that relate to how the JNDI service provider interacts with the Java SASL API (JSR 28). These properties have the prefix `"java.naming.security.sasl."` The second group comprises those that affect the SASL mechanisms. These properties are specified in the Java SASL API and have the prefix `"javax.security.sasl."` See the SASL section and the Java SASL API for details about this second group of properties.

`java.naming.security.sasl.authorizationId`

> The value of this property is a string that specifies the authorization ID for the SASL mechanisms.

> If this property is not set, then the authorization ID passed to the SASL mechanisms is the empty string. According to SASL (RFC 2222), using an authorization ID of the empty string directs the server to derive an authorization ID from the client's authentication credentials.

> For example:

>     env.put("java.naming.security.sasl.authorizationId",
>             "dn:cn=administrators,ou=groups,o=sun,c=us");

> specifies the identity to use for authorization (access control) upon successful authentication.

`java.naming.security.sasl.realm`

> The value of this property is a string that specifies the realm information required by some SASL mechanisms such as DIGEST-MD5.

> If this property is not set, then a mechanism-specific default such as that negotiated between the client and server during the authentication exchange is used.

> For example:

>     env.put("java.naming.security.sasl.realm", "webusers");

> specifies that the client wants to use the "webusers" realm for authentication.

`java.naming.security.sasl.callback`

> The value of this property is an instance of `javax.security.auth.callback.CallbackHandler`. When the provider uses a SASL mechanism that requires callbacks, the SASL mechanism uses the object supplied in the property. The callback handler should satisfy a `NameCallback` by supplying the authentication ID.

> If this property is not set, then the provider should use a default callback handler that satisfies the `NameCallback` using the value of the `java.naming.security.principal` property, satisfies the `PasswordCallback` using the value of the `java.naming.security.credentials` property, and satisfies the `RealmCallback` and `RealmChoiceCallback` (described in the Java SASL API) using the value of the `java.naming.security.sasl.realm` property.

> For example:

>     env.put("java.naming.security.sasl.callback",
>             new MyCallbackHandler());

> supplies an instance of the callback handler for SASL mechanisms to use.

`javax.security.sasl.qop`

> The value of this property is a '`,`'-separated list of quality-of-protection (qop) values used to specify the client's qop preference. A qop value is one of
> - `"auth"` - authentication only
> - `"auth-int"` - authentication plus integrity protection
> - `"auth-conf"` - authentication plus integrity and confidentiality protection
> The order of the list specifies the preference order. If this property is absent, the default qop is `"auth"`.

`javax.security.sasl.strength`

> The value of this property is a '`,`'-separated list of cipher strength values used to specify the client's preference. A strength value is one of
> - `"low"`
> - `"medium"`
> - `"high"`
> The order of the list specifies the preference order. If this property is absent, the default strength is `"high,medium,low"`.

> For privacy in DIGEST-MD5, `"high"` maps to `"3des"`, `"medium"` to `"rc4"` or `"des"`, and `"low"` to `"rc4-56"` or `"rc4-40"`.

`javax.security.sasl.maxbuffer`

> The value of this property is the string representation of an integer that specifies the maximum size of the receive buffer in bytes that the client is willing to receive. If this property is absent, the default size is defined by the SASL mechanism.

`javax.security.sasl.server.authentication`

> The value of this property is either "true" or "false", specifying whether the server must authenticate to the client or not, respectively. If this property is absent, the default is "false".

`javax.security.sasl.policy.forward`

> The value of this property is either "true" or "false", specifying whether the selected SASL mechanism must support forward secrecy between sessions or not, respectively. If this property is absent, the default is "false".

`javax.security.sasl.policy.credentials`

> The value of this property is either "true" or "false", specifying whether the selected SASL mechanism must require client credentials or not, respectively. If this property is absent, the default is "false".

`javax.security.sasl.policy.noplaintext`

> The value of this property is either "true" or "false", specifying whether the selected SASL mechanism must not be susceptible to simple plain passive attacks or not, respectively. If this property is absent, the default is "false".

`javax.security.sasl.policy.noactive`

> The value of this property is either "true" or "false", specifying whether the selected SASL mechanism must not be susceptible to active (non-dictionary) attacks or not, respectively. If this property is absent, the default is "false".

`javax.security.sasl.policy.nodictionary`

> The value of this property is either "true" or "false", specifying whether the selected SASL mechanism must not be susceptible to dictionary attacks or not, respectively. If this property is absent, the default is "false".

`javax.security.sasl.policy.noanonymous`

> The value of this property is either "true" or "false", specifying whether the selected SASL mechanism must not accept anonymous logins or not, respectively. If this property is absent, the default is "false".

### 3.5 Provider-specific Properties

Provider-specific properties are environment properties which apply only to particular provider implementations. The names of these properties are chosen by the provider's implementor. The recommended policy for naming these properties is to use the implementor's reversed DNS domain name to prefix the provider's package name and to use that package name to prefix the property name. For example, Sun prefixes its provider-specific LDAP properties with "`com.sun.jndi.ldap`".

## 4. Names

Names are handled by the provider's context methods according to the following rules:

1. `String` names supplied as parameters to the context methods are in the composite name syntax.
The first component of the composite name is an LDAP distinguished name while the rest of the components are used for federation.
2. If a `Name` argument is a `CompositeName` object then its first component is assumed to be an LDAP distinguished name and the remaining components (if any) are used for federation.
3. If a `Name` argument is not a `CompositeName` object then all of its components are assumed to be the parsed form of an LDAP distinguished name. That is, each `Name` component is an LDAP relative distinguished name (RDN).
4. Names are parsed using the name parser returned by the `Context.getNameParser` method. The parser accepts LDAP distinguished names as `String` objects and produces LDAP distinguished names as `Name` objects.
5. Names returned by context operations are string composite names or string URLs.

The syntax of string LDAP distinguished names follows RFC 2253. For example:

> - `CN=Steve Kille, O=Isode Limited, C=GB`
> - `OU=Sales+CN=J. Smith, O=Widget Inc., C=US`
> - `CN=L. Eagle, O=Sue\, Grabbit and Runn, C=GB`

The name supplied to an LDAP context is always relative to that context. For example, given an LDAP context (`lctx`) for "`dc=widget,dc=com`", in order to name LDAP entries in that subtree, a name relative to "`dc=widget,dc=com`" must be supplied. For example, the following call obtains the attributes for the
"`cn=John Smith,dc=widget,dc=com`" entry,

`Attributes attrs = lctx.getAttributes("cn=John Smith");`

Similarly, when a context is enumerated using any of the enumeration methods (`Context.list`, `Context.listBindings`, `DirContext.search`), the names returned are relative to the target context--the context being enumerated. When referrals are invoked, instead of a relative name, an LDAP URL string, containing the fully qualified name, is returned. The format of LDAP URLs is defined in RFC 2255.

LDAP URLs that follow RFC 2255 may be supplied to any of the context methods. The hostname and port number are extracted from the URL and used to contact the LDAP server; the `java.naming.factory.initial` and `java.naming.provider.url` properties are ignored. For example,

`DirContext ictx = new InitialDirContext();`
`Attributes attrs = ictx.getAttributes(`
`"ldap://wserver:389/cn=John Smith,dc=widget,dc=com");`

This code fragment contacts the LDAP server at machine `wserver` at port `389`.

##

## 5. Attributes

The LDAP provider expects as input and returns as output all attribute values as either `String` or `byte[]` objects. See the `java.naming.ldap.attributes.binary` environment property for which ones are treated as `byte[]` and how to extend the list.

## 6. URLs

RFC 2255 describes the syntactic format of LDAP URLs. The format contains all the elements necessary to specify an LDAP search operation, with provisions for supporting extensions:

>     ldap://host:port/dn?attributes?scope?filter?extensions

Authentication information may be specified in the `extensions` portion of the URL. See the RFC for a complete description of the format.

URLs play a role in several places in JNDI:

1. Configuration of service providers.
To configure an LDAP service provider, you typically supply one or more space-separated LDAP URLs in the `java.naming.provider.url` property. This is used by the LDAP service provider to configure its connection to the directory server. Only the `host`, `port`, and `dn` parts of the URL are relevant in this setting. Supplying other parts of the URL results in a `ConfigurationException`.
2. Argument to initial context methods.
If a URL string (with syntax scheme_id:rest_of_name) is passed to the methods in `InitialContext`, either as a `String` argument or as the first component of `Name`, the URL's scheme id is used to locate the context factory for handling that scheme. If none is found, the URL string is treated as an ordinary name and passed to the initial context specified by the `java.naming.factory.initial` property is used. See the `java.naming.spi.NamingManager.getURLContext` method for details on how URL context factories are located. Note that this support for LDAP URLs as names is only available in the initial context.

With the exception of the search methods, when an LDAP URL is passed as a name to the initial context, the URL should not contain any query ('`?`') components. Otherwise, an `InvalidNameException` is thrown by the service provider. For the search methods, the query components of the URL override any corresponding components supplied as arguments. For example, if an LDAP URL containing a scope component is supplied, then that scope overrides any scope setting that may be passed in a `SearchControls` argument.

3. Referrals.
An LDAP referral contains a list of one or more URLs. To process an LDAP referral (either explicitly or implicitly by setting the `java.naming.referral` property), the service provider needs to use the information in the these URLs to create connections to LDAP servers to which they refer. When multiple LDAP URLs are present in a single referral they are treated as alternatives and each is followed until one succeeds. The complete URL (that is, including any query components) are used.
4. Returned as a name in list and search enumerations.
When the name of the entry being returned has a name that is not relative to the target context (i.e., the starting context for the list or search), the name is returned as a URL. See the `NameClassPair.isRelative` method for details.
5. Argument to the `getObjectInstance` method of `NamingManager` or `DirectoryManager`.
When an LDAP namespace is federated underneath another namespace (for example, such as DNS), the information that is stored in the superior namespace might be an LDAP URL. In such a scenario, a lookup/list/search operation in the superior namespace would return a `Reference` containing an LDAP URL for the LDAP namespace. The service provider for the superior namespace would pass the `Reference` to the `getObjectInstance` method to create an instance of an LDAP context.

For items (1), (2), (3), and (5), if the URL is missing the hostname and port but has a non-empty distinguished name, the provider should use the algorithm for discovering LDAP services with DNS as described in the Internet draft draft-ietf-ldapext-locate-08.txt. If the provider does not use this algorithm, or if the DNS configuration is not available, then the provider should use `localhost` and 389 as the hostname and port, respectively.

## 7. Java Objects

### 7.1 Storing

The LDAP provider should support the storing of Java objects into the directory. This is implemented in the following methods:

- `Context.bind()`
- `Context.rebind()`
- `DirContext.bind()`
- `DirContext.rebind()`

The provider should support at a minimum the storage of the following types of Java objects:

1. Instances of `Reference`
2. Objects that implement the `Referenceable` interface
3. Objects that implement the `Serializable` interface
4. Objects that implement the `DirContext` interface

It should check whether an object is in these four categories in the order listed because that is most likely to capture the intent of the client. For example, a `Reference` is `Serializable`, so if you performed the `Serializable` check first, no `Reference`s would ever be stored in the reference format (that is, they would all be serialized).

References, referenceable and serializable objects should be stored according to RFC 2713. `DirContext` objects should be stored by storing their attributes.

When storing a reference's list of `RefAddr` into the `javaReferenceAddress` attribute, the separator to use for delimiting the address's position, type and content are controlled using the environment property java.naming.ldap.ref.separator. If this environment property is not specified, the hash character '#' should be used as the separator.

The provider uses the `DirectoryManager.getStateToBind` method when storing objects in the directory. This allows objects of any type to be transformed into one of the four categories listed above so that they can be stored into the directory.

### 7.2 Reading

Objects are read from the directory using the following operations:

- `Context.lookup()`
- `Context.lookupLink()`
- `Binding.getObject()`

When the provider reads an entry from the directory, it will get LDAP attributes, and attributes defined in RFC 2713 if the entry has an associated Java object. If the entry contains Java object-related attributes, the provider should recreate the object using those attributes. Otherwise, the provider should return an instance of `DirContext` containing the attributes of the entry. For both `DirContext` and Java objects, the provider should then invoke `DirectoryManager.getObjectInstance()` on it and return the result to the caller.

## 8.0 Schema

JNDI does not specify schema-related details such as structure and contents of the schema tree, permission to modify to the contents of the schema tree, and the effect of such modifications on the directory are dependent on the underlying directory. JNDI specifies only that the root schema context--that returned by `DirContext.getSchema()`--contain the following bindings:

- AttributeDefinition
- ClassDefinition
- SyntaxDefinition

This document specifies the structure and content of schema trees that are derived from LDAP-based schemas. It describes how the schema tree is laid out, and the mandatory and optional attributes that you can expect to find associated with entries in different parts of this schema tree.

Permission to modify the contents of the schema tree is determined by the directory administrator. When the schema tree is modified, the changes are made to schema stored on the directory server.

### 8.1 Schema Tree Structure

In addition to the three bindings in the root schema context listed previously, the root schema context may also contain the following four bindings:

- MatchingRule
- ExtensionDefinition
- ControlDefinition
- SASLDefinition

Name of Binding | Description of Binding
--- | ---
AttributeDefinition | Root of the attribute definition tree: a flat namespace with attributes identified by their name or OID.
ClassDefinition | Root of the "objectclass" definition tree: a flat namespace with object classes identified by their name or OID.
SyntaxDefinition | Root of the syntax definition tree: a flat namespace with syntaxes identified by their OID.
MatchingRule | Root of matching rule tree: a flat namespace with matching rules identified by their name or OID.
ExtensionDefinition | Root of the extensions tree: a flat namespace with extensions identified by their OID.
ControlDefinition | Root of the controls tree: a flat namespace with controls identified by their OID.
SASLMechanism | Root of the SASL tree: a flat namespace with SASL authentication mechanisms identified by their string name.

Any or all of these bindings may be absent if the underlying directory does not publish such schema information, or the service provider does not support retrieving them. If these names are present in the root schema context, however, they must have the binding specified in the above table.

The attribute names and values of these entries' attributes are case-insensitive.

### 8.2 Attribute Definitions

The name "AttributeDefinition" is bound to a context containing `DirContext` objects representing attribute definitions in the schema. For example, if a directory supports a "commonName" attribute, the "AttributeDefinition" context would have a binding with name "commonName" that is bound to a `DirContext` object.

Each object in the "AttributeDefinition" context has the following mandatory and optional attributes:

Attribute Identifier | Attribute Value Description
--- | ---
NUMERICOID (mandatory) | unique identifier (OID)
NAME | attribute's name
DESC | attribute's description
OBSOLETE | "true" if obsolete, "false" or absent otherwise
SUP | name of superior attribute type from which this attribute's type is derived
EQUALITY | name or OID of matching rule if equality matching allowed, absent otherwise
ORDERING | name or OID of matching rule if ordering matching allowed, absent otherwise
SUBSTRING | name or OID of matching rule if substring matching allowed, absent otherwise
SYNTAX | numeric OID of syntax of values of this type
SINGLE-VALUE | "true" if attribute not multi-valued, "false" or absent otherwise.
COLLECTIVE | "true" if attribute is collective, "false" or absent otherwise.
NO-USER-MODIFICATION | "true" if not user-modifiable, "false" or absent otherwise.
USAGE | description of attribute usage

These attributes have a 1-to-1 correspondence with the names defined in RFC 2252 for "AttributeTypeDescription." All the attribute values are represented by the `java.lang.String` class.

You can, for example, obtain the object representing the "cn" attribute using the following code:

>     DirContext schema = ctx.getSchema(""); // get schema tree
>     DirContext cnSchema = schema.lookup("AttributeDefinition/cn");

If you then get the attributes of the "cnSchema" `DirContext` object, you would see:

>     NUMERICOID      2.5.4.3
>     NAME            cn
>     SYNTAX          1.3.6.1.4.1.1466.115.121.1.15
>     DESC            Standard Attribute, alias for commonName

An equivalent way of getting "cnSchema" is if you already have a "cn" attribute. The following code illustrates this alternative:

>     Attributes attrs = ctx.getAttributes("cn=John", new String[]{"cn"});
>     Attribute cnAttr = attrs.get("cn");
>     DirContext cnSchema = cnAttr.getAttributeDefinition();

### 8.3 Object Class Definitions

The name "ClassDefinition" is bound to a context containing `DirContext` objects representing object class definitions in the schema. For example, if a directory supports a "country" object class, the "ClassDefinition" context would have a binding with name "country" that is bound to a `DirContext` object.

Each object in the "ClassDefinition" context has the following mandatory and optional attributes:

Attribute Identifier | Attribute Value Description
--- | ---
NUMERICOID (mandatory) | unique identifier (OID)
NAME | object class's name
DESC | object class's description
OBSOLETE | "true" if obsolete, "false" or absent otherwise
SUP | name of superior object class from which this object class is derived
ABSTRACT | "true" if object class is abstract, "false" or absent otherwise
STRUCTURAL | "true" if object class is structural, "false" or absent otherwise
AUXILIARY | "true" if object class is auxiliary, "false" or absent otherwise
MUST | a list of type names of attributes that must be present
MAY | a list of type names of attributes that may be present

These attributes have a 1-to-1 correspondence with the names defined in RFC 2252 for "ObjectClassDescription." All the attribute values are represented by the `java.lang.String` class.

You can, for example, obtain the object representing the "country" object class using the following code:

>     DirContext schema = ctx.getSchema(""); // get schema tree
>     DirContext countrySchema = schema.lookup("ClassDefinition/country");

If you then get the attributes of the "countrySchema" `DirContext` object, you would see:

>     NUMERICOID      2.5.6.2
>     NAME            country
>     MAY             aci, searchguide, description
>     MUST            objectclass, c
>     DESC            Standard ObjectClass
>     SUP             top

An equivalent way of getting "countrySchema" is if you already have a "country" object. The following code illustrates this alternative:

>     // Read object from directory
>     DirContext countryObj = (DirContext)ctx.lookup("c=us", new String[]{"country"});

>     // Get all of object's object class definitions
>     DirContext objClasses = countryAttr.getSchemaClassDefinition();

>     // Pick out "country" object class in particular
>     DirContext countryClass = (DirContext)objClasses.lookup("country");

NOTE: JNDI 1.1's specification of `getSchemaClassDefinition()` implies that the service provider should return any one of an object's object class definitions. This specification is inadequate because an object usually has multiple object classes and the application might require knowledge about any of those object classes depending on what it is doing. The proposal as illustrated by the example above is to return a context containing all of the object class definitions.

### 8.4 Syntax Definitions

The name "SyntaxDefinition" is bound to a context containing `DirContext` objects representing syntax definitions in the schema. For example, if a directory supports the "1.3.6.1.4.1.1466.115.121.1.15" syntax (Directory String) syntax, the "SyntaxDefinition" context would have a binding with name "1.3.6.1.4.1.1466.115.121.1.15" that is bound to a `DirContext` object.

Each object in "SyntaxDefinition" context has the following mandatory and optional attributes:

Attribute Identifier | Attribute Value Description
--- | ---
NUMERICOID (mandatory) | unique identifier (OID)
DESC | syntax's description

These attributes have a 1-to-1 correspondence with the names defined in RFC 2252 for "SyntaxDescription." All the attribute values are represented by the `java.lang.String` class.

You can, for example, obtain the object representing the "1.3.6.1.4.1.1466.115.121.1.15" syntax using the following code:

>     DirContext schema = ctx.getSchema(""); // get schema tree
>     DirContext dirStringSchema =
>         schema.lookup("SyntaxDefinition/1.3.6.1.4.1.1466.115.121.1.15");

If you then get the attributes of the "dirStringSchema" `DirContext` object, you would see:

>     NUMERICOID      1.3.6.1.4.1.1466.115.121.1.15
>     DESC            Directory String

An equivalent way of getting "dirStringSchema" is if you already have an attribute that has that syntax (such as, the "country" attribute). The following code illustrates this alternative:

>     Attributes attrs = ctx.getAttributes("c=us", new String[]{"country"});
>     Attribute countryAttr = attrs.get("country");
>     DirContext dirStringSchema = countryAttr.getSyntaxAttributeDefinition();

### 8.5 Matching Rules

The name "MatchingRule" is bound to a context containing `DirContext` objects representing matching rules in the schema. A "matching rule" uniquely identifies the algorithm to use when comparing attribute values. For example, a directory might support a matching rule that is based on how a string sounds and define it as the "soundAlikeMatch" matching rule. Then, the "MatchingRule" context would have a binding with name "soundAlikeMatch" that is bound to a `DirContext` object.

When a matching rule is an extensible matching rule, it must also contain an "APPLIES" attribute listing the attributes to which this extensible matching rule can be applied.

Each object in "MatchingRule" context has the following mandatory and optional attributes:

Attribute Identifier | Attribute Value Description
--- | ---
NUMERICOID (mandatory) | unique identifier (OID)
NAME | name of matching rule
DESC | matching rule's description
OBSOLETE | "true" if obsolete, "false" or absent otherwise
SYNTAX | numeric oid of syntax to which this rule applies
APPLIES | a list type names of attributes to which this extensible matching rule applies

These attributes have a 1-to-1 correspondence with the names defined in RFC 2252 for "MatchingRuleDescription" and "MatchingRuleUseDescription." All the attribute values are represented by the `java.lang.String` class.

You can, for example, obtain the object representing the "soundAlikeMatch" syntax using the following code:

>     DirContext schema = ctx.getSchema(""); // get schema tree
>     DirContext soundMatchSchema =
>         schema.lookup("MatchingRule/soundAlikeMatch");

If you then get the attributes of the "soundMatchSchema" `DirContext` object, you would see:

>     NUMERICOID      1.2.3.4.5
>     NAME            soundAlikeMatch
>     SYNTAX          1.3.6.1.4.1.1466.115.121.1.15 (for directory string)
>     APPLIES         2.5.4.41, 2.5.4.15
>     DESC            Home-grown Phonetic match

### 8.6 Extension Definitions

The name "ExtensionDefinition" is bound to a context containing `DirContext` objects representing extensions supported by the server. For example, a directory might support the "Start TLS" extension ("1.3.6.1.4.1.1466.20037"). Then, the "ExtensionDefinition" context would have a binding with name "1.3.6.1.4.1.1466.20037" that is bound to a `DirContext` object.

Each object in "ExtensionDefinition" context has the following mandatory and optional attributes:

Attribute Identifier | Attribute Value Description
--- | ---
NUMERICOID (mandatory) | unique identifier (OID)
DESC | extension's description

All the attribute values are represented by the `java.lang.String` class.

You can, for example, obtain the object representing the Start TLS extension ("1.3.6.1.4.1.1466.20037") using the following code:

>     DirContext schema = ctx.getSchema(""); // get schema tree
>     DirContext startTLSSchema =
>         schema.lookup("ExtensionDefinition/1.3.6.1.4.1.1466.20037");

If you then get the attributes of the "startTLSSchema" `DirContext` object, you would see:

>     NUMERICOID      1.3.6.1.4.1.1466.20037
>     DESC            Start TLS (see RFC 2830)

### 8.7 Control Definitions

The name "ControlDefinition" is bound to a context containing `DirContext` objects representing controls supported by the server. For example, a directory might support the control for asking the server to sort the search results it returns.

Each object in "ControlDefinition" context has the following mandatory and optional attributes:

Attribute Identifier | Attribute Value Description
--- | ---
NUMERICOID (mandatory) | unique identifier (string)
DESC | control's description

All the attribute values are represented by the `java.lang.String` class.

You can, for example, obtain the object representing the server-side sorting control ("1.2.840.113556.1.4.473") using the following code:

>     DirContext schema = ctx.getSchema(""); // get schema tree
>     DirContext svrSortSchema =
>         schema.lookup("ControlDefinition/1.2.840.113556.1.4.473");

If you then get the attributes of the "svrSortSchema" `DirContext` object, you would see:

>     NUMERICOID      1.2.840.113556.1.4.473
>     DESC            server-side sorting of search results

### 8.8 SASL Mechanisms

The name "SASLMechanism" is bound to a context containing `DirContext` objects representing SASL authentication mechanisms supported by the server. For example, a directory might support the EXTERNAL SASL mechanism (RFC 2222) which requests that the server make use of security credentials exchanged by a lower layer.

Each object in "SASLMechanism" context has the following mandatory and optional attributes:

Attribute Identifier | Attribute Value Description
--- | ---
NAME (mandatory) | SASL mechanism's name
DESC | SASL mechanism's description

All the attribute values are represented by the `java.lang.String` class.

You can, for example, obtain the object representing the EXTERNAL SASL mechanism using the following code:

>     DirContext schema = ctx.getSchema(""); // get schema tree
>     DirContext saslExternalSchema =
>         schema.lookup("SASLMechanism/EXTERNAL");

If you then get the attributes of the "saslExternalSchema" `DirContext` object, you would see:

> `NAME EXTERNAL`
> `DESC EXTERNAL SASL mechanism (RFC 2222)`

## 9. Exceptions

When building an LDAP provider, you need to translate LDAP error codes (see RFC 2251) into JNDI exceptions. You should use the following table when performing the translation. Furthermore, you should encode as much information as possible about the error into the exception's detailed message, "root cause" exception, resolved and remaining names. Note that resolved name and resolved object should correspond to each other's setting.

LDAP error code | Exception or Action
--- | ---
success (0) | Report success.
operationsError (1) | `NamingException`
protocolError (2) | `CommunicationException`
timeLimitExceeded (3) | `TimeLimitExceededException`
sizeLimitExceeded (4) | `SizeLimitExceededException`
compareFalse (5) | Used by `DirContext.search()` and does not generate an exception.
compareTrue (6) | Used by `DirContext.search()` and does not generate an exception.
authMethodNotSupported (7) | `AuthenticationNotSupportedException`
strongAuthRequired (8) | `AuthenticationNotSupportedException`
partialResults (9) | If `java.naming.referral` is set to `ignore`, or contents of error does not contain a referral, throw `PartialResultException`. Otherwise, use the contents to build a referral.
referral (10) | If `java.naming.referral` is set to `ignore` then throw `PartialResultException`. If it is set to `throw` then throw `ReferralException`. If it is set to `follow` then the provider shall follow the referral. If the value for `java.naming.ldap.referral.limit` is exceeded while following the referral then throw `LimitExceededException`.
adminLimitExceeded (11) | `LimitExceededException`
unavailableCriticalExtension (12) | `OperationNotSupportedException`
confidentialityRequired (13) | `AuthenticationNotSupportedException`
saslBindInProgress (14) | Used internally by LDAP provider during multi-stage SASL authentication.
noSuchAttribute (16) | `NoSuchAttributeException`
undefinedAttributeType (17) | `InvalidAttributeIdentifierException`
inappropriateMatching (18) | `InvalidSearchFilterException`
constraintViolation (19) | `InvalidAttributeValueException`
attributeOrValueExists (20) | `AttributeInUseException`
invalidAttributeSyntax (21) | `InvalidAttributeValueException`
noSuchObject (32) | `NameNotFoundException`
aliasProblem (33) | `NamingException`
invalidDNSyntax (34) | `InvalidNameException`
isLeaf (35) | Used by provider; usually doesn't generate exception.
aliasDereferencingProblem (36) | `NamingException`
inappropriateAuthentication (48) | `AuthenticationNotSupportedException`
invalidCredentials (49) | `AuthenticationException`
insufficientAccessRights (50) | `NoPermissionException`
busy (51) | `ServiceUnavailableException`
unavailable (52) | `ServiceUnavailableException`
unwillingToPerform (53) | `OperationNotSupportedException`
loopDetect (54) | `NamingException`
namingViolation (64) | `InvalidNameException`
objectClassViolation (65) | `SchemaViolationException`
notAllowedOnNonLeaf (66) | `ContextNotEmptyException`
notAllowedOnRDN (67) | `SchemaViolationException`
entryAlreadyExists (68) | `NameAlreadyBoundException`
objectClassModsProhibited (69) | `SchemaViolationException`
affectsMultipleDSAs (71) | `NamingException`
other (80) | `NamingException`

## 10. API Mapping

The methods of the JNDI API context interfaces are mapped onto LDAP operations as follows.
`EventContext.addNamingListener`
`EventDirContext.addNamingListener`

> Register a listener for receiving naming events that take place in the specified subtree of LDAP entries. LDAP servers notify clients of events by means of LDAP controls attached to LDAP operation responses or by means of an LDAP unsolicited notifications. Such responses are then processed by the LDAP provider and indicated to the application in the form of `NamingEvent` or `UnsolicitedNotificationEvent`.

`Context.addToEnvironment`

> Update context's environment properties. If multiple contexts share the same set of environment properties, the provider should take care to only modify the intended context's environment. Changing an environment property might require changes to the existing connection the context is using.

Supplying null for the property value has the same effect as removing the property.

For all environment properties, the new property is recorded even if it does not affect the context. See the Environment Properties section.

`Context.bind`
`DirContext.bind`

Perform an LDAP add operation to create a new entry in the directory. The `DirContext.bind` method can accept null as the object to bind if it is also supplied a non-null set of attributes. Otherwise, if the method is given insufficient information (i.e., no object or attributes), no entry can be added. If an object is provided in the arguments, then it is converted into attributes and stored in the entry along with any supplied attributes, as described in the Java Objects section. The provider should use the `DirectoryManager.getStateToBind` method to transform the input object into a form that it can store.

If the provider does not support binding any objects in the directory then it should throw `OperationNotSupportedException`. Otherwise, if it does support binding objects but does not support the supplied object then it should throw `IllegalArgumentException`.

`Context.close`

Release resources associated with context. For example, if the connection being used by this context is not shared with another context, the provider may abandon any outstanding requests and close the network connection to the server. Precisely which resources are released is implementation-dependent.

`Context.composeName`

If the parent context is from the same LDAP namespace, then concatenate the names according to the LDAP name syntax described in `Context.getNameParser()`. Otherwise, concatenate the names as composite names.

`Context.createSubcontext`
`DirContext.createSubcontext`

Perform an LDAP add operation to create the named entry and its associated attributes. If no attributes are supplied then the objectClass attribute is generated with the values `top` and `javaContainer` (`javaContainer` is a structural class that is necessary to avoid a schema violation error).

`Context.destroySubcontext`

Perform an LDAP delete operation to remove the named entry and its associated attributes. The named entry must be a leaf entry; subtrees are not removed. If the leaf entry does not exist (but its parent exists), the operation still succeeds.

`LdapContext.extendedOperation`

> Perform an LDAP extended operation.

`DirContext.getAttributes`

Perform an LDAP base-object search operation to retrieve the LDAP entry's attributes. Use "(objectclass=*)" as the filter.

If the list of requested attributes is null or contains the special attribute identifier '*' then all the user attributes at the LDAP entry are returned. If operational attributes are required then those attribute identifiers must be present in the list of requested attributes.

`LdapContext.getConnectControls`

Retrieve the connection request controls in effect for LDAP bind operations invoked on this context.

`Context.getEnvironment`

Return the environment properties recorded at the context.

`Context.getNameInNamespace`

Return the LDAP distinguished name of the context.

`Context.getNameParser`

Return a name parser that parses LDAP names according to RFC 2253.

`LdapContext.getRequestControls`

Retrieve the request controls in effect for LDAP operations subsequently invoked on this context.

`LdapContext.getResponseControls`

Retrieve the response controls returned by the last LDAP operation invoked on this context.

`DirContext.getSchema`

See the Schema Section.

`DirContext.getSchemaClassDefinition`

See the Schema Section.

`Context.list`

Perform an LDAP one-level search operation of the named entry using the filter "(objectclass=*)" to retrieve the names of the entries immediately below the named entry.

Ask for, at a minimum, the `javaClassName` attributes so that the class name of each entry can be determined. If the class name cannot be determined, return `javax.naming.directory.DirContext` as the class name.

The names which are returned are either relative to the named context or they are LDAP URLs.

`Context.listBindings`

Perform an LDAP one-level search operation of the named entry using the filter "(objectclass=*)" to retrieve the attributes representing objects (or object references). Request the attributes for reconstructing the Java object and possibly other attributes as well. See Java Objects on how to reconstruct the object. If the object cannot be reconstructed according to RFC 2713 then return a `DirContext` object representing the LDAP entry. The provider should use the `DirectoryManager.getObjectInstance` method to satisfy calls to the `Binding.getObject` method.

The names which are returned are either relative to the named context or they are LDAP URLs.

`Context.lookup`
`Context.lookupLink`

Perform an LDAP base-object search operation of the named entry using the filter "(objectclass=*)". Request (possibly all) the attributes for reconstructing the Java object. See Java Objects on how to reconstruct the object. The provider should use the `DirectoryManager.getObjectInstance` method to satisfy calls to the `Binding.getObject` method.

`DirContext.modifyAttributes`

Perform an LDAP modify operation at the named entry using the supplied modifications. For the overloaded method that accepts an `Attributes`, first convert the `Attributes` argument into an ordered list of modifications by enumerating its contents using `Attributes.getAll()` and reusing the modification operation argument (`mod_op`).

`LdapContext.newInstance`

Initialize an new instance of this context with the specified request controls.

`Context.rebind`
`DirContext.rebind`

This method may involve several different LDAP operations. First get the existing entry's attributes. If the existing entry does not exist, this method behaves the same as `bind()`. Otherwise, if no attributes have been supplied and the object being bound is `DirContext`, invoke `DirContext.getAttributes()` and use the result as the attributes argument (`attrs`). If there are still no attributes, use the original entry's attributes as `attrs`. Remove the existing entry using the LDAP delete operation. Convert the object provided in the arguments into attributes (as described in the Java Objects section) and store in the entry along with `attrs` using the LDAP add operation. The provider should use the `DirectoryManager.getStateToBind` method to transform the input object into a form that it can store.

`LdapContext.reconnect`

Reconnect to the LDAP server using the supplied connection request controls and the current environment properties.

`Context.removeFromEnvironment`

> Remove context's environment properties. If multiple contexts share the same set of environment properties, the provider should take care to only modify the intended context's environment. Changing an environment property might require changes to the existing connection the context is using.

For all environment properties, the new property is recorded even if it does not affect the context. Removing a property should cause the context to assume the property's default.

`EventContext.removeNamingListener`

> Deregister a naming event listener so that subsequent events destined for that listener are not delivered.

`Context.rename`

Perform an LDAP modify DN operation to rename the entry. If LDAPv2 is being used then the new name and the old name must share the same immediate parent name. If the parents are not equal then throw `InvalidNameException`.

Note the effect of the java.naming.ldap.deleteRDN property on the behavior of this method.

`DirContext.search`

Perform an LDAP search operation according to the specified search controls.

If the list of requested attributes is null or contains the special attribute identifier '*' then all the user attributes at the LDAP entry are returned. If operational attributes are required then those attribute identifiers must be present in the list of requested attributes.

If objects are requested to be returned, then the Java object-related attributes (RFC 2713) are requested in addition to any requested by the API user. If these attributes are present then they are used to assemble the original objects (see Java Objects). If the object cannot be reconstructed according to RFC 2713 then return a `DirContext` object representing the LDAP entry. The provider should use the `DirectoryManager.getObjectInstance` method to satisfy calls to the `Binding.getObject` method.

The names which are returned are either relative to the named context or they are LDAP URLs.

The provider may use an LDAP compare operation instead of an LDAP search when the search filter supplied is suitably constrained:

- The filter must be of the form "`(<attributeID>=<value>)`"
- The scope must be object scope
- Zero attributes must be requested (empty returning-attributes list)

In the forms of search that accept a string filter as argument, the syntax of the filter follows RFC 2254 with the exception that Unicode characters are also allowed. The use of Unicode characters is preferable to the use of encoded UTF-8 octets. The service provider is responsible for translating the Unicode characters into their corresponding UTF-8 representation for transmission to the server. For example, the Greek letter alpha can be specified in the string filter either as "`\u03B1`" or as "`\\CE\\B1`".

In the form `search(Name, Attributes)` and related methods, the `Attributes` argument is converted into a string filter by creating a conjunctive expression out of its elements. Each attribute value is treated as a literal; therefore '*' and other special characters defined in RFC 2254 that appear in the values of an attribute should be escaped according to the rules in RFC 2254. For example, an attribute value of '*' should be encoded as the string "`\\2a`".

In the form `search(Name, String filterExpr, Object[] filterArgs)` and its `String` overloaded method, "{num}" expansion is done in the filter by putting in values from `filterArgs`. Each "{num}" component may appear in the place of "attr" or "value" in Section 4 from RFC 2254.

The objects in `filterArgs` should be encoded in the following way:

- byte arrays (`byte[]`) are encoded by encoding each byte as a string according to RFC 2254. For example, the array {0, 1, 10, 100} is encoded as the string "`\\00\\01\\0a\\64`".
- Strings are treated as literals. In other words, '*' and other special characters defined in RFC 2254 that appear in the string are escaped according to the rules in RFC 2254. For example, a string of "*" is encoded as the string "`\\2a`".
- Objects that are neither `String` nor `byte[]` are converted to their string form using `Object.toString()` and then the rules for `String` applied.

`LdapContext.setRequestControls`

Set the request controls for LDAP operations subsequently invoked on this context.

`EventContext.targetMustExist`

Determine whether a listener can register interest in an LDAP entry that doesn't exist.

`Context.unbind`

Perform an LDAP delete operation to remove the named entry. The named entry must be a leaf entry; subtrees are not removed. If the leaf entry does not exist (but its parents exist), the operation still succeeds.

## 11. Federation

The LDAP service provider should support federation using strong separation and either or both of junctions or implicit next naming system pointer.

## 12. SASL

The provider supports SASL mechanisms by means of the Java SASL API (JSR 28). This allows SASL mechanism drivers from different vendors to be used with the LDAP provider, and also allows a SASL mechanism driver to be used with different LDAP providers and even non-LDAP protocol libraries.

The Java SASL API depends on the Java Authentication and Authorization Service (JAAS), which provides callback support for SASL mechanisms that need to obtain or supply user/application information directly.

### 12.1 SASL Configuration

To specify that SASL authentication be used, you specify the official IANA-registered names of the SASL mechanisms in the `java.naming.security.authentication` property. The first SASL mechanism on the list that is both available and satisfies the optionally specified policies is used. That is, properties with the prefix `"javax.security.sasl.policy."` can be used to control the security characteristics of the selected SASL mechanism.

Some SASL mechanisms require the identity of the entity being authenticated. This is known as the authentication ID. Some SASL mechanisms, like DIGEST-MD5, require the use of a password and/or a realm. By default, the provider supplies the value of `java.naming.security.principal` property as the authentication ID to any SASL mechanism that requires the authentication ID, the value of the `java.naming.security.credentials` property as the password, and the value of the `java.naming.security.sasl.realm` property as the realm. To override these defaults, use the `java.naming.security.sasl.callback` property.

SASL mechanisms support the notion of authorization identity or authorization ID, which is the entity to which the server should grant access if the authentication succeeds. If the `java.naming.security.sasl.authorizationId` property has been set, then its value is used as the authorization ID. Otherwise, the empty string is used as the authorization ID, which directs the server to derive an authorization ID from the client's authentication credentials.

See SASL properties for a description of the properties used by an LDAP service provider for supporting SASL.

In addition to these properties, there might be properties required for specific SASL mechanisms. For example, a SASL mechanism that supports privacy and integrity needs to know the quality of protection that the client requires. Properties such as these are passed to the SASL mechanism via the environment properties. See the JNDI documentation for how to set environment properties.

For example, if the application needs privacy, it can do so by using a call such as:

`env.put("javax.security.sasl.qop", "auth-conf");`

before passing `env` to the initial context constructor. See the Java SASL API for details about these properties.

### 12.2 SASL Mechanism Drivers

The Java SASL API provides a framework for dynamically plugging in SASL mechanism drivers. The LDAP provider might provide a few default drivers. See the Java SASL API for details.

## 13. Extensions and Controls

The provider supports LDAP extensions and controls using the `javax.naming.ldap` package. In addition, the provider supports LDAP unsolicited notifications (which are transmitted in LDAP extended operation responses) using the services of the `javax.naming.event` package.

Several LDAP extensions and controls are defined by the IETF LDAPEXT working group.

The "Start TLS" extension ("1.3.6.1.4.1.1466.20037") is supported by the `StartTlsRequest` and `StartTlsResponse` classes. The LDAP provider must provide a concrete implementation of the abstract `StartTlsResponse` class and make its implementation available to the LDAP provider. See the description in StartTlsRequest.createExtendedResponse. Typically, the `StartTlsResponse` implementation would need access to the LDAP provider's data structures.

The LDAP service provider should perform hostname verification after Start TLS negotiation as specified in RFC 2830. If the LDAP server was discovered automatically by using information in DNS (as described in the URLs section), the provider should use the domain name derived from the distinguished name as the hostname to verify, as recommended by draft-ietf-ldapext-locate-08.txt.

## 14. Event Notification

The provider supports event notification using the `javax.naming.event` package.

A JNDI application can register for events that occur in the directory, such as the addition or removal of an entry, or the modification of an entry. Applications can also register for unsolicited notifications.

## 15. SSL

The provider supports SSL according to the SSL interface specification. SSL is activated by setting the `java.naming.security.protocol` environment property as follows:

> `env.put(Context.SECURITY_PROTOCOL, "ssl");`

and by selecting the hostname and port number of an LDAP server that supports SSL. Once an SSL connection has been established subsequent LDAP protocol exchanges take place over that secure connection.

If, in addition, LDAP authentication is also required then the `java.naming.security.authentication`, `java.naming.security.principal`, and `java.naming.security.credentials` environment properties should be set, as appropriate. If LDAP authentication is required and the SSL credentials should be reused for LDAP authentication then set the `java.naming.security.authentication` environment property to select the SASL EXTERNAL mechanism, as follows:

`env.put(Context.SECURITY_AUTHENTICATION, "EXTERNAL");`

Copyright © 2002 Sun Microsystems, Inc. All rights reserved.