Managing Configuration Information

An Introduction to LDAP

In the preceding section, you have seen how to read a username and password from a database. In this section, we look at LDAP (Lightweight Directory Access Protocol). LDAP servers are more flexible and efficient for managing user information than are database servers. Particularly in large organizations, in which data replication is an issue, LDAP is preferred over relational databases for storing directory information.

Because LDAP is less commonly used than relational database technology, we briefly introduce it here. For an in-depth discussion of LDAP, we recommend the "LDAP bible": Howes, Timothy et al, 2003. Understanding and Deploying LDAP Directory Services, (2nd ed.). Addison-Wesley Professional.

LDAP Directories

LDAP uses a hierarchical database. It keeps all data in a tree structure, not in a set of tables as a relational database would. Each entry in the tree has:

  • Zero or more attributes. An attribute has a key and a value. An example attribute is cn=John Q. Smith. The key cn stores the "common name." (See Table 10-3 for the meaning of commonly used LDAP attributes.)

    Table 10-3. Commonly Used LDAP Attributes
    Attribute Name Meaning
    dc Domain component
    cn Common name
    sn Surname
    dn Distinguished name
    o Organization
    ou Organizational unit
    uid Unique identifier


  • One or more object classes. An object class defines the set of required and optional attributes for this element. For example, the object class person defines a required attribute cn and an optional attribute telephoneNumber. Of course, the object classes are different than Java classes, but they also support a notion of inheritance. For example, inetOrgPerson is a subclass of person with additional attributes.

  • A distinguished name (for example, uid=troosevelt,ou=people,dc=corejsf,dc=com). The distinguished name is a sequence of attributes that trace a path joining the entry with the root of the tree. There may be alternate paths, but one of them must be specified as distinguished.

Figure 10-10 shows an example of a directory tree.

Figure 10-10. A directory tree


How to organize the directory tree and what information to put in it can be a matter of intense debate. We do not discuss the issues here. Instead, we assume that an organizational scheme has been established and that the directory has been populated with the relevant user data.

Configuring an LDAP Server

You have several options for running an LDAP server to try out the programs in this section. Here are the most popular choices:

  • The free OpenLDAP server (http://openldap.org), available for Linux and Windows, and built into Mac OS X

  • A high-performance server such as the Sun Java System Directory Server (http://www.sun.com/software/products/directory_srvr/home_directory.html), which is available on a variety of platforms

  • Microsoft Active Directory

We give you brief instructions for configuring OpenLDAP. If you use another directory server, the basic steps are similar.

Our sample directory uses the standard object class inetOrgPerson. (We use that class because it has useful attributes such as uid and mail.) You should make sure that your LDAP server recognizes this object class.

If you use OpenLDAP, you need to edit the slapd.conf file before starting the LDAP server. Locate the line that includes the core.schema file, and add lines to include the cosine.schema and inetorgperson.schema files. (On Linux, the default location for the slapd.conf file is /etc/ldap, /etc/openldap, or /usr/local/etc/openldap. The schema files are in the schema subdirectory.)

Note

Alternatively, you can make adjustments to our sample data. For example, you can change inetOrgPerson to the more commonly available person, omit the uid and mail attributes, and use the sn attribute as the login name. If you follow that approach, you will need to change the attributes in the sample programs as well.


In OpenLDAP, edit the suffix entry in slapd.conf to match the sample data set. This entry specifies the distinguished name suffix for this server. It should read

  suffix  "dc=corejsf,dc=com"

You also need to configure an LDAP user with administrative rights to edit the directory data. In OpenLDAP, add these lines to slapd.conf:

  rootdn  "cn=Manager,dc=corejsf,dc=com"   rootpw  secret

We recommend that you specify authorization settings, although they are not strictly necessary for running the examples in this sections. The following settings in slapd.conf permit the Manager user to read and write passwords, and everyone else to read all other attributes.

  access to attr=userPassword               by dn.base="cn=Manager,dc=corejsf,dc=com" write               by self write               by * none   access to *               by dn.base="cn=Manager,dc=corejsf,dc=com" write               by self write               by * read

You can now start the LDAP server. On Linux, run the slapd service (typically in the /usr/sbin or /usr/local/libexec directory).

Next, populate the server with the sample data. Most LDAP servers allow the import of LDIF (Lightweight Directory Interchange Format) data. LDIF is a humanly readable format that lists all directory entries, including their distinguished names, object classes, and attributes. Listing 10-7 shows an LDIF file that describes our sample data:

  . ldap/misc/sample.ldif

For example, with OpenLDAP, you use the ldapadd tool to add the data to the directory:

  ldapadd -f sample.ldif -x -D "cn=Manager,dc=corejsf,dc=com" -w secret

Before proceeding, it is a good idea to double-check that the directory contains the data that you need. We suggest that you use an LDAP browser such as JXPlorer (http://sourceforge.net/projects/jxplorer/) or Jarek Gawor's LDAP Browser/Editor (http://www.mcs.anl.gov/~gawor/ldap/). Both are convenient Java programs that let you browse the contents of any LDAP server. Launch the program and configure it with the following options:

  • Host: localhost

  • Port: 389

  • Base DN: dc=corejsf,dc=com

  • User DN: cn=Manager,dc=corejsf,dc=com

  • Password: secret

Make sure that the LDAP server has started, then connect. If everything is in order, you should see a directory tree similar to the one shown in Figure 10-11.

Figure 10-11. Inspecting an LDAP directory tree


Listing 10-7. ldap/setup/sample.ldif

  1. # Define top-level entry   2. dn: dc=corejsf,dc=com   3. objectClass: dcObject   4. objectClass: organization   5. dc: corejsf   6. o: A Sample Organization   7.   8. # Define an entry to contain people   9. # searches for users are based on this entry  10. dn: ou=people,dc=corejsf,dc=com  11. objectClass: organizationalUnit  12. ou: people  13.  14. # Define a user entry for Theodore Roosevelt  15. dn: uid=troosevelt,ou=people,dc=corejsf,dc=com  16. objectClass: inetOrgPerson  17. uid: troosevelt  18. sn: Roosevelt  19. cn: Theodore Roosevelt  20. mail: troosevelt@corejsf.com  21. userPassword: jabberwock  22.  23. # Define a user entry for Thomas Jefferson  24. dn: uid=tjefferson,ou=people,dc=corejsf,dc=com  25. objectClass: inetOrgPerson  26. uid: tjefferson  27. sn: Jefferson  28. cn: Thomas Jefferson  29. mail: tjefferson@corejsf.com  30. userPassword: mockturtle  31.  32. # Define an entry to contain LDAP groups  33. # searches for roles are based on this entry  34. dn: ou=groups,dc=corejsf,dc=com  35. objectClass: organizationalUnit  36. ou: groups  37.  38. # Define an entry for the "registereduser" role  39. dn: cn=registereduser,ou=groups,dc=corejsf,dc=com  40. objectClass: groupOfUniqueNames  41. cn: registereduser  42. uniqueMember: uid=tjefferson,ou=people,dc=corejsf,dc=com  43.  44. # Define an entry for the "invitedguest" role  45. dn: cn=invitedguest,ou=groups,dc=corejsf,dc=com  46. objectClass: groupOfUniqueNames  47. cn: invitedguest  48. uniqueMember: uid=troosevelt,ou=people,dc=corejsf,dc=com  49. uniqueMember: uid=tjefferson,ou=people,dc=corejsf,dc=com     

Accessing LDAP Directory Information

Once you have your LDAP database populated, it is time to connect to it with a Java program. You use JNDI, an interface that unifies various directory protocols.

Start by getting a directory context to the LDAP directory, with the following incantation:

  Hashtable env = new Hashtable();   env.put(Context.SECURITY_PRINCIPAL, userDN);   env.put(Context.SECURITY_CREDENTIALS, password);   DirContext initial = new InitialDirContext(env);   DirContext context = (DirContext) initial.lookup("ldap://localhost:389");

Here, we connect to the LDAP server at the local host. The port number 389 is the default LDAP port.

If you connect to the LDAP database with an invalid username/password combination, an AuthenticationException is thrown.

Note

Sun's JNDI tutorial suggests an alternative way to connect to the server:

Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, "ldap://localhost:389"); env.put(Context.SECURITY_PRINCIPAL, userDN); env.put(Context.SECURITY_CREDENTIALS, password); DirContext context = new InitialDirContext(env);     

However, it seems undesirable to hardwire the Sun LDAP provider into your code. JNDI has an elaborate mechanism for configuring providers, and you should not lightly bypass it.


To list the attributes of a given entry, specify its distinguished name and then use the getAttributes method:

  Attributes answer      = context.getAttributes("uid=troosevelt,ou=people,dc=corejsf,dc=com");

You can get a specific attribute with the get method for example:

  Attribute commonNameAttribute = answer.get("cn");

To enumerate all attributes, you use the NamingEnumeration class. The designers of this class felt that they too could improve on the standard Java iteration protocol, and they gave us this usage pattern:

  NamingEnumeration attrEnum = answer.getAll();   while (attrEnum.hasMore()) {       Attribute attr = (Attribute) attrEnum.next();       String id = attr.getID();       ...   }

Note the use of hasMore instead of hasNext.

Since an attribute can have multiple values, you need to use another NamingEnumeration to list them all:

  NamingEnumeration valueEnum = attr.getAll();   while (valueEnum.hasMore()) {       Object value = valueEnum.next();       ...   }

However, if you know that the attribute has a single value, you can call the get method to retrieve it:

  String commonName = (String) commonNameAttribute.get();

You now know how to query the directory for user data. Next, we take up operations for modifying the directory contents.

To add a new entry, gather the set of attributes in a BasicAttributes object. (The BasicAttributes class implements the Attributes interface.)

  Attributes attrs = new BasicAttributes();   attrs.put("objectClass", "inetOrgPerson");   attrs.put("uid", "alincoln");   attrs.put("sn", "Lincoln");   attrs.put("cn", "Abraham Lincoln");   attrs.put("mail", "alincoln@corejsf.com");   String pw = "redqueen";   attrs.put("userPassword", pw.getBytes());

Then call the createSubcontext method. Provide the distinguished name of the new entry and the attribute set.

  context.createSubcontext("uid=alincoln,ou=people,dc=corejsf,dc=com", attrs);     

Caution

When assembling the attributes, remember that the attributes are checked against the schema. Do not supply unknown attributes and be sure to supply all attributes that are required by the object class. For example, if you omit the sn of person, the createSubcontext method will fail.


To remove an entry, call destroySubcontext:

  context.destroySubcontext("uid=alincoln,ou=people,dc=corejsf,dc=com");

Finally, you may want to edit the attributes of an existing entry. You call the method

  context.modifyAttributes(distinguishedName, flag, attrs);

Here, flag is one of

  DirContext.ADD_ATTRIBUTE   DirContext.REMOVE_ATTRIBUTE   DirContext.REPLACE_ATTRIBUTE

The attrs parameter contains a set of the attributes to be added, removed, or replaced.

Conveniently, the BasicAttributes(String, Object) constructor constructs an attribute set with a single attribute. For example,

  context.modifyAttributes(      "uid=alincoln,ou=people,dc=corejsf,dc=com",      DirContext.ADD_ATTRIBUTE,      new BasicAttributes("telephonenumber", "+18005551212"));   context.modifyAttributes(      "uid=alincoln,ou=people,dc=corejsf,dc=com",      DirContext.REMOVE_ATTRIBUTE,      new BasicAttributes("mail", "alincoln@coresjf.com"));   context.modifyAttributes(      "uid=alincoln,ou=people,dc=corejsf,dc=com",      DirContext.REPLACE_ATTRIBUTE,      new BasicAttributes("userPassword", newpw.getBytes()));

Finally, when you are done with a context, you should close it:

  context.close();

You now know enough about directory operations to carry out the tasks that you will commonly need when working with LDAP directories. A good source for more advanced information is the JNDI tutorial at http://java.sun.com/products/jndi/tutorial.

However, we are not quite ready to put together a JSF application that uses LDAP. It would be extremely unprofessional to hardcode the directory URL and the manager password into a program. Instead, these values should be specified in a configuration file.

The next section discusses various options for the management of configuration parameters. We put the alternatives to work with an application that allows users to self-register on a web site; we use LDAP to store the user information.

javax.naming.directory.InitialDirContext Java SE 1.3

  • InitialDirContext(Hashtable env)

    Constructs a directory context, using the given environment settings. The hash table can contain bindings for Context.SECURITY_PRINCIPAL, Context.SECURITY_CREDENTIALS, and other keys (see the API documentation for the javax.naming.Context interface for details).


javax.naming.Context Java SE 1.3

  • Object lookup(String name)

    Looks up the object with the given name. The return value depends on the nature of this context. It commonly is a subtree context or a leaf object.

  • Context createSubcontext(String name)

    Creates a subcontext with the given name. The subcontext becomes a child of this context. All path components of the name, except for the last one, must exist.

  • void destroySubcontext(String name)

    Destroys the subcontext with the given name. All path components of the name, except for the last one, must exist.

  • void close()

    Closes this context.


javax.naming.directory.DirContext Java SE 1.3

  • Attributes getAttributes(String name)

    Gets the attributes of the entry with the given name.

  • void modifyAttributes(String name, int flag, Attributes modes)

    Modifies the attributes of the entry with the given name. The value flag is one of DirContext.ADD_ATTRIBUTE, DirContext.REMOVE_ATTRIBUTE, or DirContext.REPLACE_ATTRIBUTE


javax.naming.directory.Attributes Java SE 1.3

  • Attribute get(String id)

    Gets the attribute with the given ID.

  • NamingEnumeration getAll()

    Yields an enumeration that iterates through all attributes in this attribute set.

  • void put(String id, Object value)

    Adds an attribute to this attribute set.


javax.naming.directory.BasicAttributes Java SE 1.3

  • BasicAttributes(String id, Object value)

    Constructs an attribute set that contains a single attribute with the given ID and value.


javax.naming.directory.Attribute Java SE 1.3

  • String getID()

    Gets the ID of this attribute.

  • Object get()

    Gets the first attribute value of this attribute if the values are ordered or an arbitrary value if they are unordered.

  • NamingEnumeration getAll()

    Yields an enumeration that iterates through all values of this attribute.


javax.naming.NamingEnumeration Java SE 1.3

  • boolean hasMore()

    Returns true if this enumeration object has more elements.

  • Object next()

    Returns the next element of this enumeration.



Core JavaServerT Faces
Core JavaServer(TM) Faces (2nd Edition)
ISBN: 0131738860
EAN: 2147483647
Year: 2004
Pages: 84

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net