|
WebObjects 5.2.3 | ||||||||||
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |
See:
Description
Interface Summary | |
JNDIPlugIn.ChannelOperation | The ChannelOperation interface encapsulates an operation
to be performed in the JNDIChannel. |
JNDIType | The JNDIType class represents the external type of an EOAttribute. |
Class Summary | |
JNDIAdaptor | The JNDIAdaptor class represents a Java Naming and Directory Interface service. |
JNDICallbackHandler | |
JNDIChannel | The JNDIChannel class represents a communication channel to a
Java Naming and Directory Interface service. |
JNDIContext | The JNDIContext class represents a transaction scope on a
Java Naming and Directory Interface service. |
JNDIPlugIn | The JNDIPlugIn class represents a plug-in to the JNDIAdaptor. |
LDAPPlugIn | The LDAPPlugIn class represents a plug-in to the JNDIAdaptor for
Lightweight Directory Access Protocol services. |
Exception Summary | |
JNDIAdaptorException | The JNDIAdaptorException class represents a runtime exception
that wraps an instance of NamingException . |
Provides an implementation of an Enterprise Objects Frameworks adaptor for JNDI data sources.
The Java Naming and Directory Interface (JNDI) enables connectivity to heterogeneous enterprise naming and directory services, including but not limited to the Lightweight Directory Access Protocol (LDAP). Sun distributes several different service providers for use with JNDI, such as an LDAP service provider and a file service provider (see http://java.sun.com/products/jndi/index.html).
The JNDI adaptor has a plug-in architecture that allows developers to change the behavior of the adaptor or even to implement a plug-in for a new kind of directory service. Currently, the JNDI adaptor supports only one plug-in, the LDAP plug-in. In theory, one could write a plug-in for another directory service, such as NetInfo. The class of the plug-in used by the adaptor is specified in the EOModel's connection dictionary.
Basic FeaturesLike the JDBC adaptor, the JNDI adaptor supports basic read and write operations as well as integration with the EOModeler application. Using EOModeler, one can create a model that uses the JNDI adaptor. With a JNDI model, one can use the data browser window in EOModeler to look at the entries on a server. The JNDI adaptor supports reverse engineering of data sources, but reverse engineering can only be used if the server to be modeled accepts connections and makes information about the schema publicly available. Not all public LDAP servers publish a schema.
With the JNDI adaptor one can write a WebObjects application to fetch, insert, update, and delete objects that correspond to entries in a naming and directory service. In fact, creating a fully functional, administrative application is trivial when using Direct to Web or Direct to Java Client.
LimitationsThe JNDI adaptor does not support schema synchronization. It is expected that the JNDI adaptor will be used with LDAP servers that come with pre-defined schemas. Third-party tools or other mechanisms exist for modifying schemas.
The LDAP plug-in (see below) does not support the use of key-comparison qualifiers mostly because LDAP does not support the comparison of attribute values.
Another issue concerns the flattening of attributes and relationships. Although one can create a relationship between an entity in a JNDI model and an entity in a JDBC model, EOF currently will not support the flattening of attributes or relationships between entities in models that use different adaptors.
Plug-inThe plug-in has large control over the behavior of the JNDI adaptor. For example, one could change the way that the initial directory context gets created by creating a subclass of the LDAPPlugIn class that overrides the createInitialDirContext
method. Remember to specify the new plug-in name in the connection dictionary of the model. For further details, see the reference documentation for the JNDIPlugIn class.
One could also write a plug-in to specify the external types to be used for a directory service. The JNDIType interface represents the external type of an EOAttribute. The JNDI adaptor relies on JNDIType to store the knowledge required to do the "raw guts" of the adaptation between JNDI and EOF. The LDAPPlugIn class implements the jndiTypes
method to return a set of JNDITypes for use with LDAP. For further details, see the reference documentation for the JNDIType and JNDIPlugIn classes.
Another compelling reason to write a customized plug-in is to enable authentication using a different security scheme, such as Kerberos.
Relative Distinguished NameThe distinguished name is a unique, human-readable identifier of an entry in a naming and directory service. The relative distinguished name is the distinguished name minus the search base (the base is usually related to the domain of a server). For example, suppose the distinguished name of an entry is
cn=Ernest Hemingway,dc=apple,dc=com
and the base of the server is
dc=apple,dc=com
In such a case, the relative distinguished name is:
cn=Ernest Hemingway
which is the part of the distinguished name up to but excluding the base.
In a JNDI model, every entity has exactly one attribute named relativeDistinguishedName
which holds the value of the relative distinguished name and serves as the primary key. By default, reverse engineering sets the relativeDistinguishedName
attribute to be neither a class property nor an attribute that participates in locking.
Although a relative distinguished name is similar to EOF's definition of a primary key, there are differences. While in EOF most often an integer type is used, with values that are usually not visible to the user, in JNDI/LDAP the relative distinguished name is of type String, and usually in a human readable form. More importantly, in EOF the primary key is usually an independently determined value, whereas in JNDI/LDAP, the relative distinguished name is in general derived from the values of other attributes. For a "Person" entity, a JNDI/LDAP database might use the first plus the last name of a person instead of a hidden unique number.
There are basically two ways to handle the creation or generation of new relative distinguished names (primary keys) with the JNDI adaptor:
relativeDistinguishedName
attribute (primary key) a class property. This will allow application code to assign the primary key (like any other attribute) by storing its value into the enterprise object before the first save operation. Application code can then make appropriate decisions as to which relative distinguished name to use for a specific enterprise object.relativeDistinguishedName
attribute in the EOModel: Use EOModeler Custom Formatting inspector to fill in a write format for the relativeDistinguishedName
attribute. The write format specifies the syntax of the generated relative distinguished names, including which attribute values the relative distinguished name will be composed of, for example cn=<cn>
. In this typical example, the value of the attribute cn
will be used within the relative distinguished name, resulting in the string "cn=Harry" if the value of the cn
attribute is "Harry". So the value of the relative distinguished name reads like an equation, with one or more assignments. The exact syntax should be derived from the server(s) being used, the adaptor itself only defines (superimposes) the syntax for replacing the attribute values being referenced. This is simply the attribute name (as defined with EOModeler) enclosed in "<" and ">". These two characters are already defined as special characters and would not otherwise appear unquoted in a relative distinguished name.There are provisions to alter the automatic behavior: Subclassing and overriding the specific plug-in methods the JNDI adaptor uses to generate relative distinguished names. The methods to override are relativeDistinguishedNameForNewRow
(defined in the JNDIPlugIn class) and convertSpecialCharactersForDistinguishedName
(defined in the LDAPPlugIn class). See the descriptions of these methods for more detail.
If this value of the relative distinguished name contains special characters (, = + < > # ; and even more special \ and "), the JNDI adaptor uses a special syntax for the value (but not for the attribute): Conforming with RFC 2253 (and 1779), these are escaped by preceding them with a backslash "\". Two exceptions are the "more special" characters backslash and quote, for which this doesn't (always) work. For these two characters, their hexadecimal notation (again according to RFC 2253) is used, which is "#5C" and "#22", respectively.
Unfortunately some servers handle special characters in a very unique way, and the above scheme doesn't work with all of them. If the server you use does not work with this scheme, your application needs to handle special characters explicitly or you should consider avoiding the use of special characters in relative distinguished names completely.
Object ClassThe object class represents the type of an entry on a directory server. One way to think of an object class is as a static collection of attributes. At some level, the idea of an object class is similar to that of a class in a programming language like Java. In a JNDI model, every entity has exactly one attribute named objectClass
which holds the value of the object class.
By default, reverse engineering sets the objectClass
attribute to be neither a class property nor an attribute that participates in locking. Although not a primary key, the objectClass
is not a property in the common sense. The reason is that the type of an entry is static (much like the class of an object in Java), as opposed to a property that is, in principle, dynamic or variable.
An object class can extend or inherit attributes from another object class. For example, the attributes of the object class "person" include:
aci, cn, description, objectclass, seeAlso, sn, telephonenumber, userpassword
The object class "organizationalPerson" extends "person" and has all of the above attributes plus:
destinationindicator, facsimiletelephonenumber, internationalisdnnumber, l, ou, physicaldeliveryofficename, postofficebox, postaladdress, postalcode, preferreddeliverymethod, registeredaddress, st, street, teletexterminalidentifier, telexnumber, title, x121address
Since an "organizationalPerson" entry is also a "person" entry, a search on the "person" object class will also yield entries from the "organizationalPerson" object class.
In a JNDI model created by reverse engineering, there may be an entity Person
that corresponds to the "person" object class and an entity OrganizationalPerson
for the "organizationalPerson" object class. For each attribute in the object class, there is an attribute in the entity in addition to the relativeDistinguishedName
and objectClass
attributes. The OrganizationalPerson
entity, however, does not necessarily extend the Person
entity.
Fetching on the Person
entity also returns "organizationalPerson" rows; however, only the Person
attributes will be visible because each row is treated as an instance of the Person
entity. Thus, there is a subtle but important distinction to be made between object class inheritance in a directory service and entity inheritance in the EOF.
The LDAPPlugin that is part of the JNDI adaptor communicates with LDAP directory servers. It performs LDAP queries and updates from within a WebObjects application by using the JNDI API's to communicate to one or more LDAP servers. This communication is not encrytped, so saving user names, passwords, or other sensitive information can be dangerous from a security standpoint.
The default authentication mechnisms offered by the JNDI adaptor are None
and Simple
. In the None
configuration, no authentication to the directory is performed and all operations are performed annonymously. In the Simple
configuration, a user name and password are used to bind to the directory before performing dirrectory operations, but the server cannot guarantee that the user working with the directory is truly who they claim to be.
The plug-in architecture of the JNDI adaptor allows you to use other authentication mechanisms like Kerberos while communicating with an LDAP directory server and to encrypt the communication: The purpose of a KerberosLDAPPlugin would be to look like a regular LDAPPlugin, while performing all of its directory operations in a channel through JAAS as a Kerberos princpal that has been authenticated through GSSAPI. The necessary steps for such a plug-in would be:
javax.security.auth.Subject
object that contains credentials (tickets) received from your Kerberos server and an authenticated principal associated with those credentials. You use this subject as the first argument to the static method javax.security.auth.Subject.doAs(javax.security.auth.Subject, java.security.PrivilegedAction)
. The class java.security.PrivilegedAction
encapsulates the notion of performing Java code as an authenticated principal. In the KerberosLDAPPlugin, the Java code to perform would create an InitialDirContext or perform a channel operation. The code that is executed is called from within a PrivilegedAction's run()
method.createInitialDirContext
to return an initial context with its Context.SECURITY_AUTHENTICATION
environment property set to the string GSSAPI
: In order to begin working with the LDAP directory, you must first bind to it by creating an InitialDirContext. Once you have authenticated, you can use a ChannelOperation and KerberosPrivilegedAction to do this in your plug-in's createInitialDirContext
method:
// set up the InitialDirContext's environment as a Hashtable Hashtable hashtable = new Hashtable(3); // two values are read from the adaptors connection dictionary NSDictionary connectionDictionary = ...; // the adaptor's connection dictionary hashtable.put(Context.PROVIDER_URL, (String)(connectionDictionary.objectForKey("serverUrl"))); hashtable.put(Context.INITIAL_CONTEXT_FACTORY, (String)(connectionDictionary.objectForKey("initialContextFactory"))); // a third value is set to force the authentication mechanism for the InitialDirContext to be GSSAPI hashtable.put(Context.SECURITY_AUTHENTICATION, "GSSAPI"); // create a ChannelOperation that creates the new InitialDirContext ChannelOperation channelOperation = new ChannelOperation() { public Object performOperation() { try { return new InitialDirContext(hashtable); } catch (NamingException exception) { throw new NSForwardException(exception); } } }; // return the context as a result of a privileged action. Subject loginContext = ...; // login context is retrieved when assuming identity of the authenticated principal return (InitialDirContext)(Subject.doAs(loginContext.getSubject(), new KerberosPrivilegedAction(channelOperation)));
performChannelOperation
to perform operations as an authenticated principal: The JDNIPlugin defines an inner interface named ChannelOperation which encapsulates the notion of perfoming a directory operation in an EOAdaptorChannel and defines one method, performOperation
. The JNDI adaptor classes that work with a directory enclose that work code in a ChannelOperation and invoke performChannelOperation
on the plug-in with the ChannelOperation as the argument. In a KerberosLDAPPlugin, you would override the performChannelOperation
method to invoke the ChannelOperation's performOperation
method from within a PrivilegedAction:
public Object performChannelOperation(ChannelOperation operation) { Subject loginContext = ...; // login context is retrieved when assuming identity of the authenticated principal KerberosPrivilegedAction action = new KerberosPrivilegedAction(operation); return Subject.doAs(loginContext.getSubject(), action); } class KerberosPrivilegedAction extends Object implements PrivilegedAction { private ChannelOperation _operation = null; KerberosPrivilegedAction(ChannelOperation operation) { super(); _operation = operation; } public Object run() { return _operation.performOperation(); } }
|
Last updated Thu Oct 21 15:04:16 PDT 2004. | ||||||||||
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |