

                ------------------------------
                LDAP Service Provider for JNDI
                ------------------------------


1.0 INTRODUCTION
----------------

The LDAP service provider implements the DirContext interface.  You
can use this provider with JNDI in order to access LDAP directories.
The provider presents the entries and associated attributes from the
LDAP directory as JNDI DirContext and Attribute objects,
respectively. LDAP distinguished names are used to name DirContext
objects. LDAP attribute types are used to identify Attribute objects.



2.0 CONFORMANCE
---------------

The LDAP service provider for JNDI supports LDAP Version 2 (LDAPv2)
and conforms to the following specifications:

    - Lightweight Directory Access Protocol
      [RFC-1777]
    - The String Representation of Standard Attribute Syntaxes
      [RFC-1778]
    - A String Representation of Distinguished Names
      [RFC-1779]
    - A String Representation of LDAP Search Filters
      [RFC-1960]
    - An LDAP URL Format
      [RFC-1959]
In addition, it also supports LDAP Version 3 (LDAPv3) and conforms
to the following draft specifications:

    - Lightweight Directory Access Protocol (v3)
      [draft-ietf-asid-ldapv3-protocol-09.txt]
    - Lightweight Directory Access Protocol (v3): Attribute Syntax Definitions
      [draft-ietf-asid-ldapv3-attributes-08.txt]



3.0 ENVIRONMENT PROPERTIES
--------------------------

The following JNDI environment properties are relevant for the LDAP
service provider:

java.naming.factory.initial
    This environment property is used to select the LDAP provider;
    it's not actually used by the provider itself. It specifies the
    class name of the initial context factory for the provider.

    For example:

      java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory

    This environment property must be set if you are using LDAP
    for the initial context. The only exception is if you supply
    only URLs to the initial context, in which case, you don't need
    to specify this property. See NAMES & URL section below.

java.naming.provider.url
    Specifies LDAP server information.

    For example:

      java.naming.provider.url=ldap://localhost:636

    If this environment property is not set then the provider will
    attempt to access an LDAP server at TCP port number 389 on the
    local host. The only exception is if you supply URLs to the
    initial context, in which case, the server and port information
    will be extracted from the URLs.

java.naming.ldap.version
    Specifies the protocol version for the provider. Two values
    are currently defined:

      2 - selects LDAP Version 2 (LDAPv2)
      3 - selects LDAP Version 3 (LDAPv3)

    For example:

      java.naming.provider.version=3

    If this environment property is not set then the provider will
    attempt to use LDAPv3 and failover to LDAPv2.

java.naming.referral
    Specifies how referrals shall be handled by the provider. Three
    possible values are defined:

	follow - automatically follow any referrals
	throw  - throw a ReferralException for each referral
      ignore - ignore referrals if they appear in results and
             instruct the server to treat them like ordinary
             attributes if they appear in entries.

    For example:

      java.naming.referral=throw

    If this environment property is not set then the provider will
    ignore referrals.

java.naming.ldap.policies
    To allow applications to be written in a more service-neutral style,
    a service provider may support the notion of a policy mapping.
    Policies are used to translate a few service-neutral names into
    names that may be used directly by the underlying services.

    The LDAP provider accepts policies in the form of an environment 
    property "java.naming.ldap.policies".  Its value is a string 
    containing each policy component and its mapping onto LDAP.
    The first character of the string is the delimiter used throughout
    the string.
    
    For example, the name "user" may be mapped onto the LDAP name 
    "ou=people":

	java.naming.ldap.policies=:user:ou=people:

    Then, the following calls
        ctx.search("ou=people", "uid=jsmith", ctls);
        ctx.search("user", "uid=jsmith", ctls); 
    will produce equivalent results.

java.naming.security.authentication
    Specifies the authentication mechanism for the provider to use.
    Three possible values are defined:

	strong - use a strong authentication mechanism (public-key)
	simple - use a weak authentication mechanism (cleartext password)
	none - use no authentication (anonymous)

    For example:

      java.naming.security.authentication=simple

    If this environment property is not set then the provider will
    use no authentication. However, if the following 2 environment
    properties are both set then weak authentication will be used.

    NOTE: the strong authentication setting is currently not supported.

java.naming.security.principal
    Specifies the identity of the principal to be authenticated.
    It depends on the authentication mechanism that is selected.

    For example:

      java.naming.security.principal=cn=admin,o=sun,c=us

java.naming.security.credentials
    Specifies the credentials of the principal to be authenticated.
    It depends on the authentication mechanism that is selected.

    For example:

      java.naming.security.credentials=secret

java.naming.security.protocol
    Specifies the security protocol for the provider to use. Two
    possible values are defined:

	ssl - use SSL Version 3.0
	tls - use SSL Version 3.0

    For example:

      java.naming.security.protocol=ssl

    If this environment property is not set then no security protocol
    will be used.

    NOTE: this environment property is currently ignored.

java.naming.batchsize
    NOTE: this environment property is currently ignored.

java.naming.language
    NOTE: this environment property is currently ignored.


4.0 NAMES & URLS
----------------

The syntax of names supplied to an LDAP context follows RFC 1779. 
Examples of such names are:

	dc=widget, dc=com
	o=widget, c=gb
	cn=John Smith, o=widget, c=gb

The name supplied to an LDAP context is always relative to the
context.  For example, if you have an LDAP context (lctx) for
"o=widget,c=gb", to name LDAP entries in that subtree, you would
supply a name relative to "o=widget,c=gb". For example, to obtain
the attributes for the entry "cn=John Smith" entry, you would do
as follows:

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

Similarly, when you enumerate a context using any of the enumeration
methods (list(), listBindings(), search()), the names you get back are
relative to the target context--the context being enumerated.  When
there are referrals are invoked, instead of a relative name, you get
back a LDAP URL string of the fully qualified name.

You can supply names that follow RFC 1779 to any of the context
operations. In addition, you can supply LDAP URLS (RFC 1959) without
the search query to the initial context. When you do this, the host
and port number to use for contacting the LDAP server is extracted
from the URL supplied (i.e. the values of the
java.naming.factory.initial and java.naming.provider.url environment
or system properties are ignored).

For example,

	InitialContext ictx = new InitialContext();
	Attributes attrs = ictx.getAttributes(
	    "ldap://wserver:389/cn=John Smith, o=widget, c=gb");


5.0 API MAPPINGS
----------------

The LDAP service provider provides a class, LdapCtx, that implements
the DirContext interface.  DirContext methods are mapped onto LDAP
operations as described below.

When attributes are supplied as arguments to JNDI calls then they
must satisfy whatever schema is in force at the LDAP directory.
In particular, the objectClass attribute is normally required.

addToEnvironment()
    NOTE: This method is currently not supported.

bind()
    An LDAP add operation is performed to create the named entry and
    its associated attributes. If an object is provided in the arguments 
    to bind() then it is converted into attributes and stored in the 
    entry along with any supplied attributes. 

    If an object that implements Referenceable, or if an instance of
    Reference, its Reference is stored into LDAP attributes.
    If an object implements the Serializable interface, it is
    serialized into an attribute. See Section 6.0 for details.

close()
    If the connection being used by this context is not shared with
    another context, any outstanding requests are abandoned
    and the connection is unbound from the server.

composeName()
    Concatenates names according to the LDAP name syntax described 
    in getNameParser() below.

createSubcontext()
    An LDAP add operation is performed to create the named entry and
    its associated attributes. If no attributes are supplied then the
    objectClass attribute is generated with the single value "top".

destroySubcontext()
    An LDAP delete operation is performed to remove the named entry and
    its associated attributes. The named entry must be a leaf entry;
    subtrees are not removed.

getAttributes()
    An LDAP search operation is performed to retrieve the LDAP entry's
    attributes.

getEnvironment()
    NOTE: This method is currently not supported.

getNameParser()
    LDAP names are comma-separated and ordered right-to-left
    (little-endian). Each namepart is an equals-separated
    type/value pair. Case is ignored. A character is escaped
    by preceding it by a backslash. Characters are quoted
    using double-quotes. Additional spaces are ignored.

getSchema()
    See SCHEMA section below.

getSchemaClassDefinition()
    See SCHEMA section below.

lookup()
lookupLink()
    An LDAP base-object search operation is performed at the named
    entry to retrieve the attributes representing an object (or an
    object reference). If object or reference attributes are present
    then they are used to assemble the original object using
    NamingManager.getObjectInstance(). If none are present then an 
    LdapCtx object is assembled and returned.

list()
    An LDAP one-level search operation is performed to retrieve
    the names of the entries immediately below the named entry.
    The names which are returned are either relative to the
    named context or they are LDAP URLs.

listBindings()
    An LDAP one-level search operation is performed below the
    named entry to retrieve the attributes representing objects
    (or object references). If object or reference attributes are
    present then they are used to assemble the original objects
    using NamingManager.getObjectInstance().
    If none are present then LdapCtx objects are assembled instead
    and returned.

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

modifyAttributes()
    An LDAP modify operation is performed at the named entry
    using the supplied modifications. The operation is
    performed atomically.

removeFromEnvironment()
    NOTE: This method is currently not supported.

rebind()
    If no attributes are supplied then this method is implemented as
    an unbind() followed by a bind(). Otherwise, an LDAP modify
    operation is performed which replaces existing attributes with
    the supplied attributes.

    NOTE: This behavior is incorrect and will be fixed in the future.
    Also, when both attributes and an object is supplied to rebind(),
    the object is ignored and not added to the directory. This
    will be fixed in the future.

rename()
    An LDAP modify DN operation is performed to rename the entry.
    If LDAPv2 is being used then the new name and the old name must
    share the same immediate parent name.

search()
    An LDAP search operation is performed according to the specified
    search controls. If objects should be returned then the attributes
    representing objects (or object references) are requested. If
    these attributes are present then they are used to assemble the
    original objects using NamingManager.getObjectInstance(). 
    If none are present then LdapCtx objects are assembled instead 
    and returned.

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

    NOTE: an LDAP compare operation is performed instead of an LDAP
    search when a JNDI search filter is suitably constrained. 

unbind()
    An LDAP delete operation is performed to remove the named entry.
    The named entry must be a leaf entry; subtrees are not removed.


6.0 BINDINGS
------------

Objects are bound to names in the directory service by calling the
bind()/rebind() methods. A Reference to an object or an instance of a
Serializable object, may be bound. Objects are retrieved from the
directory service by calling lookup(), listBindings or search().

A Reference contains the information necessary to construct the object
being referenced, including where to load the class file (byte codes)
for the object.  The serialized form of the object, however, contains
the state of the object. The JNDI client looking up a serialized
object must have access to the class file of the object (e.g. by
including it in the program's classpath).

6.1 How Objects Are Stored

6.1.1 Storing References

If the object being bound implements the Referenceable interface, or
is an instance of Reference, its Reference is stored along with the
name supplied into the directory.

The LDAP provider then stores the contents of the reference in several
attributes: javaClassname, javaFactory, javaFactoryLocation and
javaObjectAddress.

	getClassName() -> javaClassname
	getFactoryClassName() -> javaFactory
	getFactoryClassLocation() -> javaFactoryLocation

Each RefAddr in the reference is stored in the multivalued attribute
javaObjectAddress. See 5.2.5 for the syntax of this attribute's value.


The entry's objectClass attribute will include one of
javaObjectWithAttributes or javaObject (see Attributes).


6.1.2 Storing Serializable Objects

If the object implements the Serializable interface, the object is
serialized and stored, along with a name, into the directory. 

The serialized object is stored in the javaObjectInstance attribute
and the class name is stored in the javaClassname attribute.

The entry's objectClass attribute will include one of
javaObjectWithAttributes or javaObject (as Attributes).


6.1.3 Attributes

If there are attributes supplied as parameters to the bind() method,
an objectClass attribute containing the value
"javaObjectWithAttribute" is added to these attributes, along with
those generated by Sections 6.1.1 or 6.1.2.

If no attributes are supplied, an attribute set is created with an
objectClass attribute containing the value "javaObject", and the
attributes generated by Sections 6.1.1 or 6.1.2.

These attributes are stored in the named directory entry.


6.2 Schema Definitions To Support Storing Objects

6.2.1 The JavaObject Object Class definition

This structural object class may contain a Java object instance or a
Java object reference. The javaClassname and javaObjectInstance
attributes are used to store an object instance. The javaClassname,
javaObjectAddress, javaFactory and javaFactoryLocation attributes are
used to store an object reference.

This object class is intended to be used for entries in which no other
LDAP information is being stored.

    ( sun.javaObject
      NAME 'javaObject' 
      DESC 'This class indicates that the entry can support a
            Java object instance or object reference.'
      SUP top 
      STRUCTURAL 
      MAY ( javaClassname $ 
          javaObjectInstance $ 
          javaObjectAddress $
          javaFactory $ 
          javaFactoryLocation $ 
          * )
    )


6.2.2 The javaObjectWithAttributes Object Class definition

This auxiliary object class may contain a Java object instance or a
Java object reference. The javaClassname and javaObjectInstance
attributes are used to store an object instance. The javaClassname,
javaObjectAddress, javaFactory and javaFactoryLocation attributes are
used to store an object reference.

This object class is intended to be used in entries for which there is
already a structural object class.

    ( sun.javaObjectWithAttributes
      NAME 'javaObjectWithAttributes' 
      DESC 'This class, if present in an entry, indicates that
           the entry can support a Java object instance or
           object reference.'
      SUP top 
      AUXILIARY 
      MAY ( javaClassname $ 
          javaObjectInstance $ 
          javaObjectAddress $
          javaFactory $ 
          javaFactoryLocation ) 
    )


6.2.3 The javaClassname Attribute Type definition

This attribute type stores a Java object's class name. Its syntax is
Directory String.

    ( sun.javaClassname
      NAME 'javaClassname'
      DESC 'This attribute is used to store the class name of
          a Java object.'
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
    )


6.2.4 The javaObjectInstance Attribute Type definition

This attribute type stores the serialized form of a Java object
instance. Its syntax is Binary.

    ( sun.javaObjectInstance
      NAME 'javaObjectInstance'
      DESC 'This attribute is used to store the serialized
          form of a Java object instance.'
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.5
    )


6.2.5 The javaObjectAddress Attribute Type definition

This attribute type stores the address information necessary to locate
the referenced object. Its values are a concatenation of an address
type and content pair. The separator is '#' when the content is a
string and '##' when it is a binary value.  If the content is a binary
value it is encoded as a Base64 string before concatenation.

The attribute's syntax is Directory String.

    ( sun.javaObjectAddress
      NAME 'javaObjectAddress'
      DESC 'This attribute is used to store addresses for
           the referenced object.'
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
    )


6.2.6 The javaFactory Attribute Type definition

This attribute type stores the class name of an object factory.  Its
syntax is Directory String.

    ( sun.javaFactory
      NAME 'javaFactory'
      DESC 'This attribute is used to store the class name
           of an object factory.'
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
    )


6.2.7 The javaFactoryLocation Attribute Type definition

This attribute type stores the location of an object factory.  Its
syntax is Directory String.

    ( sun.javaFactoryLocation
      NAME 'javaFactoryLocation'
      DESC 'This attribute is used to store the location of
           an object factory.'
      SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
    )


7.0 SCHEMA
----------

The DirContext returned by DirContext.getSchema() has the same
hierarchical structure described in the JNDI API document.  On an LDAP
server, schema are stored as a set of attribute values in the
"subschema" entry. getSchema() uses this set of values to construct a
corresponding schema tree. Any modification made to the schema tree
triggers a change on the server's "subschema" entry and may throw an
exception if the change violates the server's rules.

The root of the schema tree has two children:

    AttributeDefinition
    ClassDefinition

Each of these children has a child for each corresponding schema
definition on the server. "AttributeDefinition" has a child for
each value of the "AttributeTypes" attribute of the server's
"subschema" entry. "ClassDefinition" has a a child for each value
of the "objectClass" attribute of the server's "subschema" entry. 
These children are the leaves of the schema tree. Each child
contains attributes that describe their particular definition
(see the table below).

The attributes for these schema have a 1-to-1 correspondence with the
names defined in draft-ietf-asid-ldapv3-attributes for
AttributeTypeDescription and ObjectClassDescription.  Just like the
tags in the descriptions, only the NUMERICOID attribute is required,
the rest are optional. The values for all attributes are simple
strings.

The following are the attribute IDs and values that objects in the
AttributeDefinition schema tree can have. They correspond directly to
the AttributeTypeDescriptions in draft-ietf-asid-ldapv3-attributes:

ATTR ID			VALUE DESCRIPTION
--------------		-----------------------------
NUMERICOID		unique identifier (required)
NAME			attribute's name
DESC			attribute's description
OBSOLETE		value = "true" if obsolete, otherwise non-existent
SUP			superior the attribuite's type is derived from
EQUALITY		value = "true" if equality matching allowed,
			otherwise non-existent
ORDERING		value = "true" if ordering matching allowed,
			otherwise non-existent
SUBSTRING		value = "true" if substring matching allowed,
			otherwise non-existent
SYNTAX			numeric oid of syntax of values of this type
SINGLE-VALUE		value = "true" if attribute not multi-valued
			otherwise non-existent
COLLECTIVE		value = "true" if attribute is collective
			otherwise non-existent
NO-USER-MODIFICATION	value = "true" if not user-modifiable,
			otherwise non-existent
USAGE			attribute usage

The following are the attribute IDs and values that objects in the
ClassDefinition schema tree can have. They correspond directly to the
ObjectClassDescriptions in draft-ietf-asid-ldapv3-attributes:

ATTR ID			VALUE DESCRIPTION
--------------		-----------------------------
NUMERICOID		unique identifier (required)
NAME			class's name
DESC			class's description
OBSOLETE		value = "true" if obsolete, otherwise non-existent
SUP			superior the class's type is derived from

ABSTRACT 
STRUCTURAL
AUXILARY
			one of these three attributes will always present
			to indicate the kind of objectclass this is. 
			The other two attributes will not be present. 
			The value of the attribute that is present will
			be "true".

MUST			A list of Attribute IDs that must be present
MAY			A list of Attribute IDs that may be present

Note: Attribute IDs are case-sensitive

The schema tree can be searched, modified and traversed like any other
DirContext. The tree's name syntax is left-to-right slash-separated.
If a child entry has a NAME attribute, it is used as the entry's name;
otherwise, its NUMERICOID is used as the name.

Examples:

The following code fragment is used to get the attributes for the LDAP
attribute definition of "cn":

    DirContext schemaCtx = ctx.getSchema();
    Attributes cnDesc = schemaCtx.getAttributes("AttributeDefinition/cn");

Using this result, you can get the LDAP syntax attribute for "cn" as
follows:

    String syntax = cnDesc.get("SYNTAX");


To get the LDAP attribute definition for an LDAP attribute which is
unnamed but has "1.2.3.4.5" as its numeric OID:

    DirContext schemaCtx = ctx.getSchema();
    DirContext cnDefn = schemaCtx.lookup("AttributeDefinition/1.2.3.4.5");

DirContext.getSchemaClassDefinition() and
Attributes.getAttributeDefinition() are implemented by searching this
schema tree for the appropriate entries.

Attributes.getAttributeSyntaxDefinition() is currently not supported.


8.0 KNOWN PROBLEMS


- rebind() does not behave correctly with respect to the object it
  is asked to bind, nor wrt existing attributes that might already be bound.

- Context hangs if server kills connection.


