Java Naming and Directory Interface (JNDI API) - en
Java Naming and Directory Interface (JNDI API) - en
RESTRICTED RIGHTS: Use, duplication or disclosure by the government is subject to the restrictions as set forth
in subparagraph (c) (1) (ii) of the Rights in Technical Data and Computer Software Clause as DFARS 252.227-
7013 and FAR 52.227-19.
Sun, Sun Microsystems, the Sun logo, Java, and JavaSoft, are trademarks or registered trademarks of Sun Micro-
systems, Inc.
Contents
1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
4 Fundamentals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
4.1 Naming The Foundation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
4.2 Directory Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
4.3 URLs and Composite Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
4.4 Events . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
6 Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
6.1 Environment Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
6.2 Context Environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
6.3 Resource Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
6.4 Application/Applet-scope Standard JNDI Properties . . . . . . . . . . . . . . . 26
6.5 How the Environment Properties are Set . . . . . . . . . . . . . . . . . . . . . . . . . 26
6.6 Modifications to the Environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
7 Scenarios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
7.1 User authentication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
8 Security Considerations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
8.1 JNDI Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
8.2 Security Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
8.3 Access To Servers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
8.4 Sharing Context Handles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
8.5 Context Environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
8.6 Class Loading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
8.7 Serializable Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
8.8 Responsibilities of Service Providers . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
9 Design Choices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
9.1 Separation of Interfaces into Context and DirContext . . . . . . . . . . . . . . . 37
9.2 Separation of JNDI into Different Functional Packages . . . . . . . . . . . . . 37
9.3 Separation of Client APIs and Service Provider Interfaces . . . . . . . . . . . 37
9.4 Multiple methods for listing Context . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
9.5 Support for Federation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
9.6 DirContext versus DirObject . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
9.7 Support for Schemas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
9.8 Overloaded Methods in Context and DirContext . . . . . . . . . . . . . . . . . . 39
9.9 Reference and Referenceable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
9.10 Automatically Turning References into Objects . . . . . . . . . . . . . . . . . . 40
1 Introduction
Directory services play a vital role in Intranets and Internets by providing access to a variety
of information about users, machines, networks, services, and applications. By its very nature,
a directory service incorporates a naming facility for providing human understandable name-
spaces that characterize the arrangement and identification of the various entities.
The computing environment of an enterprise typically consists of several naming facilities of-
ten representing different parts of a composite namespace. For example, the Internet Domain
Name System (DNS) might be used as the top-level naming facility for different organizations
within an enterprise. The organizations themselves might use a directory service such as LDAP
or NDS or NIS. From a users perspective, there is one namespace consisting of composite
names. URLs are examples of composite names because they span namespaces of multiple
naming facilities. Applications which use directory services must support this user perspective.
Many JavaTM application developers can benefit from a directory service API that is not only
independent of the particular directory or naming service implementation, but also enables
seamless access to directory objects through multiple naming facilities. In fact, any application
can attach its own objects to the namespace. Such a facility enables any Java application to dis-
cover and retrieve objects of any type.
End users can benefit from logical namespaces that allow easier discovery and identification
of the objects in the network.
Directory service developers can benefit from a service-provider capability that enables them
to incorporate their respective implementations without requiring changes to the client.
Java Naming and Directory InterfaceTM (JNDI) is an API that provides directory and naming
functionality to Java applications. It is defined to be independent of any specific directory ser-
vice implementation. Thus, a variety of directories can be accessed in a common way.
Here are two examples to briefly illustrate some of the more commonly used features of JNDI.
An application that wants to access a printer needs the corresponding printer object. This is
simply done as follows:
prt = (Printer) building7.lookup("puffin");
prt.print(document);
JNDI does all the work of locating the information needed to construct the printer object.
An application that wants to find a persons phone numbers, which are stored in the organiza-
tions directory, can simply do:
String[] attrs = {"workPhone", "cellPhone", "faxNumber"};
bobsPhones = directory.getAttributes("cn=Bob, o=Widget, c=US", attrs);
If there may be several Bobs in the Widget organization, the application can search the organi-
zations directory to find the right Bob as follows:
bob = directory.search("o=Widget, c=US", "(cn=Bob)", searchctls);
This document describes the architecture and interfaces of JNDI.
2.3 Implementable over common directory and naming services and protocols
This goal is important for two reasons. First, it enables Java applications to take advantage of
information in a variety of existing naming and directory services such as DNS, NDS, NIS
(YP), X.500, and LDAP. Second, it helps limit the appearance of any implementation specific
artifacts in the API.
Providing a unified interface to multiple naming and directory services does not imply that ac-
cess of unique features of a particular service is precluded. The unified API which is designed
to cover the common case is still beneficial to applications that have explicit knowledge of the
underlying naming or directory service. Such applications still benefit from sharing the com-
mon portions that use the API. This is analogous to applications sharing commonly used class-
es and yet adding needed specificity via subclassing.
Java Application
JNDI API
JNDI SPI
4 Fundamentals
A directory service provides access to diverse kinds of information about users and resources
in a network environment. It uses a naming system for the purpose of identifying and organiz-
ing directory objects to represent this information. A directory object provides an association
between attributes and values. Thus, a directory service enables information to be organized in
a hierarchical manner to provide a mapping between human understandable names and direc-
tory objects.
Every name is interpreted relative to some context, and every naming operation is performed
on a context object. A client can obtain an initial context object that provides a starting point
for resolution of names.
DNS
InitialContext
NDS
LDAP
File System
Printer Service
User objects
Printer
File
To support composite names in general, JNDI defines a composite name syntax and utilities
for processing composite names. This allows clients of JNDI to refer to objects using names
that span multiple namespaces.
4.4 Events
As the naming/directory service plays an increasingly important role in the computing environ-
ment, the need to provide administration and monitoring tools to help manage changes in the
service also increases. For such tools and other applications, the traditional request/response
style of interaction needs to be augmented with an asynchronous notification model that allows
applications to register interest in changes in the service.
java.lang.Object
CompositeName Name
CompoundName
InitialContext Context
NameClassPair
Binding
RefAddr java.io.Serializable
BinaryRefAddr NamingEnumeration
StringRefAddr NameParser
Reference java.lang.Cloneable
LinkRef Referenceable
5.1.1 Contexts
Context is the core interface that specifies a naming context. It defines basic operations such
as adding a name-to-object binding, looking up the object bound to a specified name, listing
the bindings, removing a name-to-object binding, creating and destroying subcontexts of the
same type, etc.
public interface Context {
public Object lookup(Name name) throws NamingException;
public void bind(Name name, Object obj) throws NamingException;
public void rebind(Name name, Object obj) throws NamingException;
public void unbind(Name name) throws NamingException;
public void rename(Name old, Name new) throws NamingException;
public NamingEnumeration listBindings(Name name)
throws NamingException;
...
public Context createSubcontext(Name name) throws NamingException;
public void destroySubcontext(Name name) throws NamingException;
...
};
Every naming method in Context takes a name as an argument. The operation defined by the
method is performed on the Context object that is obtained by implicitly resolving the name.
If the name is empty () the operation is performed directly on the context itself. The name of
an object can be a composite name reflecting the arrangement of the namespaces used to refer
to the object. Of course, the client is not exposed to any naming service implementation. In fact,
a new type of naming service can be introduced without requiring the application to be modi-
fied or even disrupted if it is running.
5.1.2 The Initial Context
In JNDI, every name is relative to a context. There is no notion of absolute names. An appli-
cation can bootstrap by obtaining its first context of class InitialContext:
public class InitialContext implements Context {
public InitialContext()...;
...
}
The initial context contains a variety of bindings that hook up the client to useful and shared
contexts from one or more naming systems, such as the namespace of URLs or the root of DNS.
5.1.3 Names
The Name interface represents a generic namean ordered sequence of components. Each Con-
text method that takes a Name argument has a counterpart that takes the name as a String in-
stead. The versions using Name are useful for applications that need to manipulate names:
composing them, comparing components, and so on. The versions using String are likely to
be more useful for simple applications, such as those that simply read in a name and look up
the corresponding object. The String name parameter represents a composite name. The Name
parameter can represent a composite name or a compound name.
The CompositeName class represents a sequence of names (atomic or compound) from multi-
ple namespaces. If the Name parameter supplied to a method of the Context class is an in-
stance of CompositeName, the name represents a composite name.
If the Name parameter supplied to a method of the Context class is not an instance of Compos-
iteName, the name represents a compound name, which can be represented by the Compound-
Name class or some other implementation class. The CompoundName class represents
hierarchical names from a single namespace. A contexts name parser can be used to manipu-
late compound names in the syntax associated with that particular context:
public interface Context {
...
public NameParser getNameParser(Name name) throws NamingException;
...
}
A namespace browser is an example of the kind of application that might need to manipulate
names syntactically at this level. Most other applications will work with strings or composite
names.
5.1.4 Bindings
Context.lookup() is the most commonly used operation. The context implementation can re-
turn an object of whatever class is required by the Java application. For example, a client might
use the name of a printer to look up the corresponding Printer object, and then print to it di-
rectly:
Printer printer = (Printer) ctx.lookup(treekiller);
printer.print(report);
Context.listBindings() returns an enumeration of name-to-object bindings, each binding
represented by an object of class Binding. A binding is a tuple containing the name of the
bound object, the name of the objects class, and the object itself.
The Context.list() method is similar to listBindings(), except that it returns an enumer-
ation of NameClassPair objects. Each NameClassPair contains an objects name and the
name of the objects class. The list() method is useful for applications such as browsers that
wish to discover information about the objects bound within a context, but dont need all of the
actual objects. Although listBindings() provides all of the same information, it is poten-
tially a much more expensive operation.
public class NameClassPair ... {
public String getName() ...;
public String getClassName() ...;
...
}
5.1.5 References
Different Context implementations are able to bind different kinds of objects natively. A par-
ticularly useful object that should be supported by any general-purpose context implementation
is the Reference class. A reference represents an object that exists outside of the directory.
References are used to give JNDI clients the illusion that objects of arbitrary classes are able
to be bound in naming or directory servicessuch as X.500that do not have native support
for objects in the Java programming language.
To continue the operation, the application re-invokes the method on the referral context using
the same arguments it supplied to the original method.
java.lang.Object
BasicAttribute Attribute
BasicAttributes Attributes
ModificationItem
SearchControls
javax.naming.InitialContext java.io.Serializable
InitialDirContext DirContext
javax.naming.NameClassPair javax.naming.Context
javax.naming.Binding
SearchResult
Attributes() performs the specified operation on each element of a set of attributes. The sec-
ond form takes an array of objects of class ModificationItem:
public class ModificationItem {
public ModificationItem(int modOp, Attribute attr) ...;
...
}
Each operation is performed on its corresponding attribute in the order specified. When possi-
ble, a context implementation should perform each call to modifyAttributes() as an atomic
operation.
5.2.2 Attributes
A directory object contains a set of zero or more Attribute objects. Each attribute is denoted
by a string identifier and can have zero or more values of any type.
public interface Attribute ... {
...
public String getID();
public Object get(int n) throws NamingException;
public boolean isOrdered();
public NamingEnumeration getAll()
throws NamingException;
...
}
An attributes values can be ordered or unordered. If the values are unordered, no duplicates
are allowed. If the values are ordered, duplicates are allowed.
Attributes are grouped into a collection by using the Attributes interface.
public interface Attributes ... {
...
public Attribute get(String attrID);
public NamingEnumeration getIDs();
public NamingEnumeration getAll();
public Attribute put(Attribute attr);
public Attribute remove(String attrID);
...
}
JNDI provides implementations for these two interfaces, BasicAttribute and Basic-
Attributes, for convenience. Service providers and applications are free to use their own im-
plementations.
Note that updates to Attributes and Attribute, such as adding or removing an attribute or
its value, do not affect the corresponding representation in the directory. Updates to the direc-
tory can only be effected by using DirContext.modifyAttributes().
5.2.3 Directory Objects as Naming Contexts
The DirContext interface also behaves as a naming context by extending the Context inter-
face. This means that any directory object can also provide a naming context. In addition to a
directory object keeping a variety of information about a person, for example, it is also a natural
naming context for resources associated with that person: a persons printers, file system, cal-
endar, etc.
Hybrid operations perform certain naming and directory operations in a single atomic opera-
tion:
public interface DirContext extends Context {
...
public void bind(Name name, Object obj, Attributes attrs)
throws NamingException;
...
}
Other hybrid operations that are provided are rebind() and createSubcontext() that accept
an additional Attributes argument.
5.2.4 The Initial Context
An application that is performing directory operations can use InitialDirContext instead of
javax.naming.InitialContext to create its initial context:
public class InitialDirContext
extends InitialContext implements DirContext {
public InitialDirContext() ...;
...
}
It can then invoke any method in the Context or DirContext interface on the initial context.
5.2.5 Searches
The DirContext interface supports content-based searching of directories. In the simplest and
most common form of usage, the application specifies a set of attributes possibly with spe-
cific values to match. It then invokes the DirContext.search() method on the directory
object, which returns the matching directory objects along with the requested attributes.
public interface DirContext extends Context {
...
public NamingEnumeration search(Name name,
Attributes matchingAttributes)
throws NamingException;
5.2.6 Schema
A schema describes the rules that define the structure of a namespace and the attributes stored
within it. The granularity of the schema can range from a single schema that is associated with
the entire namespace, to a per-attribute, fine-grained schema description.
Because schemas can be expressed as an information tree, it is natural to use for this purpose
the naming and directory interfaces already defined in JNDI. This is powerful because the sche-
ma part of a namespace is accessible to applications in a uniform way. A browser, for example,
can access information in the schema tree just as though it were accessing any other directory
objects.
Applications can retrieve the schema associated with a directory object when the underlying
context implementation provides the appropriate support.
DirContext.getSchema() is used to retrieve the root of the schema tree associated with a di-
rectory object. The root has children such as ClassDefinition, AttributeDefinition, and
SyntaxDefinition, each denoting the kind of definition being described. The schema root and
its descendents are objects of type DirContext. The DirContext.getSchemaClassDefini-
tion() method returns a DirContext that contains class descriptions about a particular direc-
tory object.
Directory Tree
getSchema()
Schema Tree
ClassDefinition SyntaxDefinition
AttributeDefinition
getAttributeDefinition()
DirContext
getAttributeSyntaxDefinition()
Attribute
getSchemaClassDefinition()
java.lang.Object EventContext
java.util.EventObject java.io.Serializable
NamingEvent NamingListener
NamingExceptionEvent NamespaceChangeListener
ObjectChangeListener
EventDirContext
The javax.naming.event package contains classes and interfaces for supporting event noti-
fication in naming and directory services.
5.3.1 Naming Events
A NamingEvent represents an event that is generated by a naming/directory service.
public class NamingEvent extends java.util.EventObject {
...
public int getType();
public Binding getOldBinding();
public Binding getNewBinding();
...
}
The events type identifies the type of event. The NamingEvent class defines four types of
events:
OBJECT_ADDED
OBJECT_REMOVED
OBJECT_RENAMED
OBJECT_CHANGED
These types can be placed into two categories:
Those that affect the namespace (add/remove/rename an object)
Those that affect an objects contents
In addition to the events type, a NamingEvent contains other information about the change,
such as information about the object before and after the change.
5.3.2 Naming Listeners
A naming listener is an object that registers for NamingEvents. It is represented by the interface
NamingListener. Each category of NamingEvent is handled by a corresponding subtype of
NamingListener. The NamespaceChangeListener interface represents a listener interested in
namespace changes, while the ObjectChangeListener represents a listener interested in
changes to an objects contents. A listener implementation might implement one or both of
these interfaces, depending on the types of events it is interested in.
java.lang.Object ExtendedResponse
ControlFactory ExtendedRequest
java.util.EventObject java.io.Serializable
UnsolicitedNotificationEvent Control
javax.naming.InitialContext javax.naming.Context
javax.naming.directory.InitialDirContext javax.naming.directory.DirContext
InitialLdapContext LdapContext
HasControls
UnsolicitedNotification
UnsolicitedNotificationListener
The javax.naming.ldap package contains classes and interfaces for using LDAP v3-specific
features that are not already covered by the more generic javax.naming.directory package.
In fact, the majority of JNDI applications that use LDAP will find the javax.naming.direc-
tory package sufficient, and will not need to use this package at all. This package is primarily
for those applications that need to use extended operations, controls, or unsolicited notifica-
tions.
5.4.1 Extended Operations
In addition to specifying well-defined operations such as search and modify, the LDAP v3 pro-
tocol (Internet RFC 2251) specifies a way of transmitting yet-to-be defined operations between
the LDAP client and server. These operations are referred to as extended operations. An ex-
tended operation may be defined by a standards organization such as the IETF or by a vendor.
The LdapContext interface defines a method for executing an extended operation:
public interface LdapContext extends DirContext {
public ExtendedResponse extendedOperation(ExtendedRequest request)
throws NamingException;
...
}
The ExtendedRequest interface represents the argument to an extended operation, while the
ExtendedResponse interface represents the result of the extended operation. An Extended-
Request or ExtendedResponse consists of an identifier that identifies the extended operation
and a byte array containing the ASN.1 BER encoded contents of the request/response.
An application typically does not deal directly with the ExtendedRequest/ExtendedResponse
interfaces. Instead, it deals with classes that implement these interfaces. The application gets
these classes either as part of a repertoire of extended operations standardized through the
IETF, or from directory vendors for vendor-specific extended operations. The request classes
should have constructors that accept arguments in a type-safe and user-friendly manner, while
the response classes should have access methods for getting the data of the response in a type-
safe and user-friendly manner. Internally, the request/response classes deal with encoding and
decoding BER values.
For example, suppose an LDAP server supports a get time extended operation. It would sup-
ply classes such as GetTimeRequest and GetTimeResponse, so that applications can use this
feature. An application would use these classes as follows:
GetTimeResponse resp =
(GetTimeResponse)lctx.extendedOperation(new GetTimeRequest());
long time = resp.getTime();
5.4.2 Controls
The LDAP v3 protocol (Internet RFC 2251) allows any request or response to be augmented
by yet-to-be defined modifiers. These modifiers are referred to as controls. Controls that are
sent with requests are called request controls and those that are sent with responses are called
response controls. A control may be defined by a standards organization such as the IETF or
by a vendor. There is not necessarily a pairing between request controls and response controls.
JNDI classifies request controls into two categories:
connection request controls: those that affect how a connection is created
context request controls: those that affect context methods
Connection request controls are used whenever a connection needs to be established or re-es-
tablished with an LDAP server. Context request controls are used when all other LDAP oper-
ations are sent to the LDAP server. The reason for this distinction is because JNDI is a high-
level API that does not deal directly with connections. It is the job of service providers to do
any necessary connection management. Hence, a single connection might be shared by multi-
ple context instances, and a service provider is free to use its own algorithms to conserve con-
nection and network usage. Thus, when a method is invoked on the context instance, the
service provider might need to do some connection management in addition to performing the
corresponding LDAP operations. For connection management, it uses the connection request
controls, while for the normal LDAP operations, it uses the context request controls.
The LdapContext interface defines methods for dealing with controls:
public interface LdapContext extends DirContext {
public void reconnect(Control[] connCtls) throws NamingException;
public Control[] getConnectControls() throws NamingException;
...
public LdapContext newInstance(Control[] reqCtls)
throws NamingException;
public void setRequestControls(Control[] reqCtls)
throws NamingException;
public Control[] getRequestControls() throws NamingException;
...
public Control[] getResponseControls() throws NamingException;
}
The Control interface represents a control. It consists of an identifier that identifies the control
and a byte array containing the ASN.1 BER encoded contents of the control.
Connection request controls are initialized using the initial context constructor and are inherit-
ed by contexts that are derived from a context. reconnect() is used to change the connection
request controls of a context. A contexts connection request controls are retrieved using get-
ConnectControls().
Context request controls are initialized using newInstance() and changed using setRequest-
Controls(). newInstance() is a convenience method for creating a new instance of a context
for the purposes of multithreaded access. For example, if multiple threads want to use different
context request controls, each thread may use this method to get its own copy of this context
and set/get context request controls without having to synchronize with other threads.
Unlike connection request controls, context request controls are not inherited by context in-
stances that are derived from a context. Derived context instances are initialized with no con-
text request controls. You must set the request controls of a derived context instance explicitly
using setRequestControls(). A contexts context request controls are retrieved using get-
RequestControls().
6 Configuration
6.1 Environment Properties
Some JNDI applications need a way to communicate various preferences and information that
define the environment in which naming and directory services are accessed. For example, an
application might need to specify the level of security for accessing a directory service. Or,
when directory and naming services are distributed, the source of information is in more than
one placereplicas, master, caches, etc. An application might want to access information from
the authoritative source and needs to indicate this information to the JNDI system.
To address these requirements, JNDI defines a number of properties that developers and users
can use to provide configuration information to the JNDI system. These are called environment
properties.
There are different types of environment properties:
Standard JNDI environment properties. These properties are defined by JNDI and are
common across all service providers. They are defined in relatively generic terms. For
example, the property java.naming.security.principal is used to specify the security
principal for authentication to the naming service. Individual service providers map
these environment properties to an interpretation appropriate for their service. These
properties have the prefix java.naming.. Appendix A contains a list of standard JNDI
environment properties. The Context interface defines constants for most of these
environment property names.
Service-specific environment properties. These properties are common across all
service providers that implement a particular service or protocol. They have the prefix
java.naming.service., where service is the name of the service. For example, the
prefix java.naming.ldap. is used for LDAP-specific environment properties.
Feature-specific environment properties. These properties are common across all
service providers that support a particular feature. They have the prefix
java.naming.feature., where feature is the name of the feature. For example, the
prefix java.naming.security.sasl. is used for SASL-specific environment properties.
Provider-specific environment properties. These properties only apply to a particular
service provider. They should have a prefix that reflects this uniqueness. A common
practice is to use the package name of the service provider as the prefix. For example,
since Suns LDAP provider is primarily contained in the package
com.sun.jndi.ldap, properties specific to Suns LDAP provider have the prefix
com.sun.jndi.ldap..
See Section 8.5 for security-related considerations when using environment properties.
Although the support for environment properties is rather extensive, it is important to note that
an application typically does not need to deal with them, or only needs to set one or two prop-
erties. Most properties have reasonable defaults and only need to be adjusted when the appli-
cation has special requirements.
There are two kinds of JNDI resource files: application and provider.
6.3.1 Application Resource Files
When an application is deployed, it will generally have several codebase directories and JARs
in its classpath. Similarly, when an applet is deployed, it will have a codebase and archives
specifying where to find the applets classes. JNDI locates all application resource files named
jndi.properties in the classpath. In addition, if the file $JAVA_HOME/lib/jndi.proper-
ties exists and is readable, JNDI treats it as an additional application resource file.
($JAVA_HOME is the directory named by the java.home system property.) All of the properties
contained in these files are placed into the environment of the initial context. This environment
is then inherited by other contexts.
1. Note that if you use Properties, only the top-level properties are consultedits defaults are not consulted
because Hashtable.get() is used when retrieving entries from the environment. See java.util.Proper-
ties for details.
For each property found in more than one application resource file, JNDI uses the first value
found or, in a few cases where it makes sense to do so, it concatenates all of the values. For
example, if the java.naming.factory.object property is found in three jndi.properties
resource files, the list of object factories is a concatenation of the property values from all three
files. Using this scheme, each deployable component is responsible for listing the factories that
it exports. JNDI automatically collects and uses all of these export lists when searching for fac-
tory classes.
Application resource files are available beginning with the Java 2 Platform, except that the file
in $JAVA_HOME/lib can be used on all Java platforms.
6.3.2 Provider Resource Files
Each service provider has an optional resource file that contains properties specific to that pro-
vider. The name of this resource is:
[prefix/]jndiprovider.properties
where prefix is the package name of the providers context implementation(s), with each period
(.) converted to a slash (/).
The JNDI library will consult the provider resource file when determining the values of certain
properties. Properties other than these can be set in the provider resource file at the discretion
of the service provider. The service providers documentation should clearly state which prop-
erties are allowed.
necessary merging of the properties and their values, there is no need for the application or con-
text implementation to directly consult the system properties or applet parameters.
7 Scenarios
This section outlines a few application scenarios to help illustrate the capabilities enabled by
JNDI.
The examples below are not meant to be prescriptive. There are often several ways to solve
a problem, and JNDI is designed with flexibility in mind.
7.3 Databases
Database applications can use the directory to locate database servers. For example, a financial
application needs to get the stock quotes from a stock quote server using JDBC. This applica-
tion can enable the user to select the stock quote server based on specification of some at-
tributes (such as coverage of which markets and frequency of quote updates). The application
searches the directory for quote servers that meet these attributes, and then retrieves the loca-
tion attribute (a JDBC URL) of the selected quote server and connects to it.
NamingEnumeration matches =
ctx.search("service/stockQuotes",
"(&(market=NASDAQ)(updateFreqency<=300))",
searchctls);
while (matches.hasMore()) {
SearchResult item = (SearchResult)matches.next();
Attribute location = item.getAttributes().get("location");
...
}
7.4 Browsing
When using almost any kind of interactive application that asks a user to input names, the us-
ers job is made easier if a namespace browser is available to him. The browser can either be
built into the application and tailored to suit that application in particular, or it can be more gen-
eral-purpose such as a typical web browser.
A very simple example of a JNDI browser allows a user to walk through a namespace, view-
ing the atomic names at each step along the way. The browser prints a * to highlight the name
of each Context, thus telling the user where he can go next.1
1. The isContext() method used in the example is not part of JNDI. It is a method that must be provided by the
application.
8 Security Considerations
There are two main settings in which JNDI is used: with and without a security manager in-
stalled.
In the case of Java applications running with no security manager installed, the code is trusted
and the application can access service providers from the local classpath. Furthermore, there is
no restriction if the service providers access local files, or make network connections to naming
or directory servers anywhere on the network.
In the case of an applet or application running with a security manager installed, there can be
trusted code and untrusted code within the same applet or application. The Sharing Context
Handles and Context Environment sections below are especially applicable in such a scenario.
The ability of an applet or an application running with a security manager installed to access
service providers, especially service providers that require the use of restricted resources (like
the file system or network connections) may be severely limited.
When JNDI is run on the Java 2 platform, it will attempt to load such classes from the locations
specified in the codebase using the java.net.URLClassLoader. In order for the class loading
to succeed, you must grant the application and the JNDI and service provider classes the per-
missions appropriate for the URLs named in the codebase. For example, if the URL scheme is
http or ftp, you must grant the application the appropriate java.net.SocketPermission;
if the URL scheme is file, you must grant the application the appropriate java.io.File-
Permission.
a client using JNDI but a problem for any client accessing the directory. The service provider
should document the security implications associated with using the associated directory over
a network.
8.8.3 Accessing Local Files
Similar to network access, untrusted code has limited access to the local file system. If the ser-
vice provider has special privileges for accessing local files, it should do so with utmost pre-
caution so as not to compromise the security policies intended by the runtime/platform.
8.8.4 Privileged Code, Native Methods
A service provider that is written completely in the Java programming language with no priv-
ileged sections is controlled by the same security policies afforded other code written in the
Java programming language. All protected resources that it attempts to access go through the
same security manager and access controller.
If a service provider contains privileged code sections, or if it contains native methods, then it
needs to be especially careful to preserve the security policies intended by the runtime/plat-
form.
9 Design Choices
9.1 Separation of Interfaces into Context and DirContext
There are two core interfaces in JNDI: Context, and DirContext, with DirContext extending
the base naming operations in Context with directory service operations. They have been sep-
arated into separate interfaces both for modularity and also in keeping with the pay for what
you use goal of JNDI.
Naming is a basic component found in many computing services such as file systems, spread-
sheets, calendar services, and directory services. By having a base Context interface for the
naming operations, we enable its use by all these other services, not just for directory services.
DirContext extends Context to provide basic directory service operations, which include ma-
nipulation of attributes associated with named objects, attribute-based searches, and schema-
related operations of those attributes and named objects.
Some applications need to perform operations on objects within a context en-masse. For exam-
ple, a backup program might want to perform file stats operations on all the objects in a file
directory. A printer administration program might want to restart all the printers in a building.
To perform such operations, these programs need to obtain all the objects bound in a context.
With these two common styles of usage in mind, the Context interface has two types of list
methods: list() and listBindings(). list() returns a list of name/class-name pairs while
listBindings() returns a list of name/class-name/object tuples. list() is designed for
browser-style applications that want mostly just the names and types of objects bound in a con-
text. listBindings() is for applications that want to potentially get all the objects in the con-
text, as well as their names and types. listBindings() returns an enumeration of Binding.
Both the listBindings() operation itself and invocation of methods in the Binding class (e.g.
getObject()) could be implemented lazily or eagerly. Using listBindings() simply indi-
cates the potential that the caller might want all or many of the objects in the context so that
implementations that are able can optimize for it. Using list() indicates that the caller is un-
likely to want all, if any, objects in the context so implementations can optimize for that if pos-
sible.
An alternative is to have a single list operation and have the lazy or eager behavior as part of
the implementation of Binding. The advantage of this is that there is a single list operation to
learn. The disadvantage is that the caller has no way of indicating which piece of information
he wants back from list, and subsequently, implementations cannot optimize for the eventual
behavior of the program.
The problem with eliminating DirContext is that DirContext contains some hybrid opera-
tions that involve both naming and directories (bind(), createSubcontext() methods that
accept attributes as arguments). To keep these operations and have DirObject at the same time
would produce the need for a third interface (perhaps called DirContext) to contain just these
hybrids.
Furthermore, having DirContext instead of DirObject is somewhat more convenient in that
you can perform some operations in one step instead of two. For example DirContext.getAt-
tributes() could be used to get the attributes associated with a named object, whereas with
DirObject, you would need first to resolve to the object (Context.lookup()) and then use
DirObject.getAttributes() to get the attributes from it.
Evironment Configuration
Program Configurationb
Access Configurationc
Service-Related
java.naming.batchsize Specifies the preferred batch size to use when returning data via
(Context.BATCHSIZE) the services protocol. This is a hint to the provider to return the
results of operations in batches of the specified size, so that the
provider can optimize its performance and usage of resources. It
does not affect the total number or size of the data returned.
Defaults to provider default.
Security
Internationalization
a. The Context and LdapContext interfaces define constants for these property names. The names of the constants
are shown in parentheses below the propertys string names.
b. These properties may be set in the Java runtimes system properties or in an applets parameter list.
c. These properties may be set in the Java runtimes system properties or in an applets parameter list.
This appendix contains sample JNDI programs intended to help a developer familiar with the
LDAP C API. Starting with sample programs from the Netscape Directory SDK for accessing
and updating the directory using the LDAP C API, we show the equivalent way of doing the
same thing for Java applications using JNDI.
#include examples.h
int
main( int argc, char **argv )
{
LDAP *ld;
LDAPMessage *result, *e;
BerElement *ber;
char *a, *dn;
char **vals;
int i;
if ( ber != NULL ) {
ber_free( ber, 0 );
}
printf( \n );
}
ldap_msgfree( result );
ldap_unbind( ld );
return( 0 );
}
import java.util.Hashtable;
import java.util.Enumeration;
import javax.naming.*;
import javax.naming.directory.*;
/*
* Search the directory for all people whose surname (last name) is
* "Jensen". Since the "sn" attribute is a caseignorestring (cis), case
* is not significant when searching.
*
* [equivalent to search.c in Netscape's SDK.]
*
*/
class Search {
try {
/* get a handle to an Initial DirContext */
DirContext ctx = new InitialDirContext(env);
/* for each entry print out name + all attrs and values */
while (results != null && results.hasMore()) {
SearchResult si = (SearchResult)results.next();
e.printStackTrace();
}
}
}
#include examples.h
int
main( int argc, char **argv )
{
LDAP *ld;
LDAPMessage *result, *e;
BerElement *ber;
char *a, *dn;
char **vals;
int i;
import java.util.Hashtable;
import javax.naming.*;
import javax.naming.directory.*;
/*
* Search the directory for the specific entry
try {
/* get a handle to an Initial DirContext */
DirContext ctx = new InitialDirContext(env);
if (attrs == null) {
System.out.println(Env.ENTRYDN + "has no attributes");
} else {
/* print each attribute */
for (NamingEnumeration ae = attrs.getAll();
ae.hasMoreElements();) {
Attribute attr = (Attribute)ae.next();
String attrId = attr.getID();
* rights reserved.
*
* Retrieve several attributes of a particular entry.
*/
#include examples.h
int
main( int argc, char **argv )
{
LDAP *ld;
LDAPMessage *result, *e;
char **vals, *attrs[ 5 ];
int i;
/* print it out */
if (( e = ldap_first_entry( ld, result )) != NULL ) {
if (( vals = ldap_get_values( ld, e, cn )) != NULL ) {
printf( Full name:\n );
for ( i = 0; vals[i] != NULL; i++ ) {
printf( \t%s\n, vals[i] );
}
ldap_value_free( vals );
}
if (( vals = ldap_get_values( ld, e, sn )) != NULL ) {
printf( Last name (surname):\n );
for ( i = 0; vals[i] != NULL; i++ ) {
printf( \t%s\n, vals[i] );
}
ldap_value_free( vals );
}
if (( vals = ldap_get_values( ld, e, mail )) != NULL ) {
printf( Email address:\n );
for ( i = 0; vals[i] != NULL; i++ ) {
printf( \t%s\n, vals[i] );
}
ldap_value_free( vals );
}
if (( vals = ldap_get_values( ld, e, telephonenumber )) != NULL ) {
printf( Telephone number:\n );
import java.util.Hashtable;
import java.util.Enumeration;
import javax.naming.*;
import javax.naming.directory.*;
/*
* Retrieve several attributes of a particular entry.
*
* [equivalent to getattrs.c in Netscape SDK]
*/
class Getattrs {
try {
/* get a handle to an Initial DirContext */
DirContext ctx = new InitialDirContext(env);
if (result == null) {
System.out.println(Env.ENTRYDN +
"has none of the specified attributes.");
} else {
/* print it out */
Attribute attr = result.get("cn");
if (attr != null) {
System.out.println("Full name:" );
for (NamingEnumeration vals = attr.getAll();
vals.hasMoreElements();
System.out.println("\t" + vals.nextElement()))
;
}
attr = result.get("sn");
if (attr != null) {
System.out.println("Last name (surname):" );
for (NamingEnumeration vals = attr.getAll();
vals.hasMoreElements();
System.out.println("\t" + vals.nextElement()))
;
}
attr = result.get("mail");
if (attr != null) {
System.out.println("Email address:" );
for (NamingEnumeration vals = attr.getAll();
vals.hasMoreElements();
System.out.println("\t" + vals.nextElement()))
;
}
attr = result.get("telephonenumber");
if (attr != null) {
System.out.println("Telephone number:" );
for (NamingEnumeration vals = attr.getAll();
vals.hasMoreElements();
System.out.println("\t" + vals.nextElement()))
;
}
}
} catch (NamingException e) {
System.err.println("Getattrs example failed.");
e.printStackTrace();
}
}
}
#include examples.h
int
main( int main, char **argv )
{
LDAP *ld;
int rc;
ldap_unbind( ld );
return( 0 );
}
import java.util.Hashtable;
import javax.naming.*;
import javax.naming.directory.*;
/*
* Use search() to compare values against values contained in entry
* "cn=Barbara Jensen, ou=Product Development, o=Ace Industry, c=US".
* We test to see if (1) the value "person" is one of the values in the
* objectclass attribute (it is), and if (2) the value "xyzzy" is in the
* objectlass attribute (it isn't, or at least, it shouldn't be).
*
* [equivalent to compare.c in Netscape SDK]
*
*/
class Compare {
try {
/* get a handle to an Initial DirContext */
ctx = new InitialDirContext(env);
} catch (NamingException e) {
System.err.println("Cannot get initial context.");
return;
}
try {
NamingEnumeration results =
ctx.search(Env.ENTRYDN, "objectclass=person", ctls);
} else {
System.out.println(
"The value \"person\" is not contained in the objectclass attribute." );
}
} catch (NamingException e) {
System.err.println("Comparison of value person failed.");
}
try {
NamingEnumeration results =
ctx.search(Env.ENTRYDN, "objectclass=xyzzy", ctls);
#include examples.h
int
main( int argc, char **argv )
{
LDAP *ld;
LDAPMod mod0;
LDAPMod mod1;
LDAPMod *mods[ 3 ];
char *vals0[ 2 ];
char *vals1[ 2 ];
time_t now;
char buf[ 128 ];
/* authenticate */
if ( ldap_simple_bind_s( ld, ENTRYDN, ENTRYPW ) != LDAP_SUCCESS ) {
ldap_perror( ld, ldap_simple_bind_s );
return( 1 );
}
/* construct the list of modifications to make */
mod0.mod_op = LDAP_MOD_REPLACE;
mod0.mod_type = mail;
vals0[0] = [email protected];
vals0[1] = NULL;
mod0.mod_values = vals0;
mod1.mod_op = LDAP_MOD_ADD;
mod1.mod_type = description;
time( &now );
sprintf( buf, This entry was modified with the modattrs program on %s,
ctime( &now ));
/* Get rid of \n which ctime put on the end of the time string */
if ( buf[ strlen( buf ) - 1 ] == \n ) {
buf[ strlen( buf ) - 1 ] = \0;
}
vals1[ 0 ] = buf;
vals1[ 1 ] = NULL;
mod1.mod_values = vals1;
mods[ 0 ] = &mod0;
mods[ 1 ] = &mod1;
mods[ 2 ] = NULL;
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
* LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE
* OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
* ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
* CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
* REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
* OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
* This software is not designed or intended for use in on-line
* control of aircraft, air traffic, aircraft navigation or aircraft
* communications; or in the design, construction, operation or
* maintenance of any nuclear facility. Licensee represents and warrants
* that it will not use or redistribute the Software for such purposes.
*/
import java.util.Hashtable;
import java.util.Date;
import javax.naming.*;
import javax.naming.directory.*;
/*
* Modify an entry:
* - replace any existing values in the "mail" attribute with "[email protected]"
* - add a new value to the "description" attribute
*
* [equivalent to modattrs.c in Netscape SDK]
*/
class Modattrs {
try {
/* get a handle to an Initial DirContext */
DirContext ctx = new InitialDirContext(env);
} catch (NamingException e) {
System.err.println("modification failed. " + e);
}
}
}
#include examples.h
#define NMODS 4
int
main( int argc, char **argv )
{
LDAP *ld;
char *dn, *ndn, *nrdn;
int i;
int rc;
LDAPMod **mods;
ldap_unbind( ld );
return 0;
}
/*
* Free a mods array.
*/
static void
free_mods( LDAPMod **mods )
{
int i;
import java.util.Hashtable;
import java.util.Date;
import javax.naming.*;
import javax.naming.directory.*;
/*
* Modify the RDN (relative distinguished name) of an entry. In this
* example, we change the dn "cn=Jacques Smith, o=Ace Industry, c=US"
* to "cn=Jacques M Smith, o=Ace Industry, c=US".
*
* Since it is an error to either (1) attempt to modrdn an entry which
* does not exist, or (2) modrdn an entry where the destination name
* already exists, we take some steps, for this example, to make sure
* we'll succeed. We (1) add "cn=Jacques Smith" (if the entry exists,
* we just ignore the error, and (2) delete "cn=Jacques M Smith" (if the
try {
/* get a handle to an Initial DirContext */
ctx = new InitialDirContext(env);
Attributes orig = new BasicAttributes();
orig.put(objClasses);
orig.put(cn);
orig.put(sn);
orig.put(givenNames);
ctx.createSubcontext(dn, orig);
System.out.println( "Added entry " + dn + ".");
} catch (NameAlreadyBoundException e) {
/* If entry exists already, fine. Ignore this error. */
System.out.println("Entry " + dn + " already exists, no need to add");
} catch (NamingException e) {
System.err.println("Modrdn: problem adding entry." + e);
System.exit(1);
}
try {
/* Delete the destination entry, for this example */
ctx.destroySubcontext(ndn);
System.out.println( "Deleted entry " + ndn + "." );
} catch (NameNotFoundException e) {
/* If entry does not exist, fine. Ignore this error. */
System.out.println( "Entry " + ndn + " is not in the directory. " +
"No need to delete.");
} catch (NamingException e) {
System.err.println("Modrdn: problem deleting entry." + e);
System.exit(1);
}
java.lang.Object
MenuComponent
MenuItem
CheckboxMenuItem ItemSelectable
Menu
extends Interface
The current class
implements
API-related Changes
Added NamingEnumeration.close() for cancelling or terminating enumerations.
Added ReferralException.getReferralContext(Hashtable env) and ReferralExcep-
tion.retryReferral() to allow creation and retry of referral context with different environment properties.
Clarified how context methods that accept Name argument should deal with CompositeName and nonComposite-
Name arguments. Specifically, instances of CompositeName are treated as composite name, while all others are treated
as compound name.
Added Context.getNameInNamespace() for retrieving the full name of a context within its own namespace.
Clarified definition of the class factory location of a Reference object. Specifically, the location is a codebase, which
consists of a list space-separated URLs.
Added support for ordered multivalued attributes to Attribute and BasicAttribute.
Added BasicAttributes.equals() and BasicAttributes.hashCode().
Redefined semantics of DirContext.getSchemaClassDefinition() so that it returns a context that contains
the DirContext objects of class definitions, rather than returning one (arbitrary) class definition.
Added protected InitialContext/InitialDirContext constructors to allow lazy initialization. Useful for sub-
class implementations.
SPI-related Changes
Added StateFactory/NamingManager.getStateToBind(), analogous to ObjectFactory/NamingMan-
ager.getObjectInstance(), for transforming an objects state before the object is bound in the naming/directory
service.
Added interfaces DirObjectFactory and DirStateFactory to better support service providers that implement
the DirContext interface. Added DirectoryManager.getObjectInstance() and DirectoryMan-
ager.getStateToStore() to use these interfaces.
Refined definition of NamingManager.getObjectInstance() to not treat URL strings specially. Instead, the
URL should be wrapped inside a Reference whose RefAddr type is URL.
Made ResolveResult implement Serializable.
Defined a special form of Reference called a next naming system (nns) reference for supporting dynamic federation.
This reference has a RefAddr type of nns and a content consisting of the resolved object.
Added the string constant NamingManager.CPE which names a property set by NamingManager.getContinu-
ationContext()/DirectoryManager.getContinuationContext(). The value of this property is an
instance of CannotProceedException. This is useful to service providers that implement federation by chaining the
CPEs.
Defined a convention for service providers to use when naming environment properties. See Section 6.1.