Friday Jun 29, 2007

OpenDS talk rollup

Need an intro to OpenDS? Checkout the OpenDS related talks and collateral below.

Tuesday Jun 26, 2007

Filling the Atompub AAA void with an OpenDS backed Atom server

Authentication, Authorization and Accounting, or "triple A", are key requirements for enterprise applications and if Web 2.0 apps are to succeed behind the firewall they too must integrate within the hairball that is the enterprise. The Atom syndication server backed by the OpenDS LDAP server cleanly address the issues and here's how:

Authentication: Assertion that the user is who they claim they are; e.g., via username/password

The Atom publishing protocol specification recommends that servers implement a mechanism to ensure agents performing write operations are authenticated. Authentication is handled as follows:
  • The user agent is prompted for credentials when an agent performs a POST, PUT, DELETE, and in some cases, a GET request
  • In the typical case, a username and password or posted using HTTP BASIC
  • The username and password are used to perform an LDAP bind that asserts that the user is present in the directory server and the provided password matches
  • On success the principal is stored in the Atom server and a client token is sent in response for future client interactions with the server. Nothing new here.

Authorization: What resources can the authenticated user access and what can they do with them.

The server leverages the underlying servlet container for coarse grained access control and the directory for fine grained control. All atompub operations are protected using container access control that, in the end, simply requires that the user belong to an administratively defined LDAP group; e.g., "atompubwriters". That is, the container simply checks that the context's principal is a member of the appropriate LDAP group.

Fine grain access control is a bit more interesting. In most enterprise applications access controls must be implemented at least twice; 1) the user interface (API or GUI); e.g., locking down fields, screens, modules, etc. and 2) in the database (field, table, etc). Obviously, this is difficult to maintain and when database connection pooling is thrown in the mix correlating the "real" user and the database connection is no longer feasible since the "real" user is lost.

OpenDS solves the connection pooling identity problem with the "proxy authorization control" and fine grain access control with access control instructions (ACIs). The proxy auth control enables the developer to create a connection pool with a common user, say "atomproxy", with just enough privileges to connect to the directory. When a connection is taken from the pool the proxy auth control containing the principal name is attached to the connection thus propagating the real user to the directory. The directory server, recognizing that the proxy auth control is present, uses the proxy principal versus the connection principal to determine access rights. Hence, you get the best of both worlds - connection pooling performance and preservation of end user identity.

For the most part, ACI's are used to narrow or widen user access to some part of the directory information tree. In the case of the Atom syndication server ACI's are added allowing end users write access beneath their LDAP entry enabling them to add blog entries, media resources (podcasts, pictures), etc. Other ACIs are used to filter content available to anonymous users (unauthenticated searching of the Atom server). By using ACI's versus application specific access control a system adminstrator can reliably set user access permissions in a single place throughout the enterprise - the directory.

Accounting/Auditing: Record of user/resource activity; e.g., who changed what when

Accounting comes free! Out-of-the-box OpenDS provides both access and audit logging. The former captures who and what was modified and the latter the contents of the modification (the specific data changes). Further, OpenDS logging/auditing is extensible, hence custom auditing loggers can be written for domain/application specific purposes.

Wednesday Jun 13, 2007

OpenDS and Atom - enabling Web 2.0 behind the firewall

The latest Identity Management Buzz podcast features Brandon Whichard, Don Bowen, and myself discussing Atom, the Atom Publishing Protocol, OpenDS, and how these technologies intersect. Give it a listen. IMO, we cover the highlights without stretching your noodle.

Monday Jun 04, 2007

OpenDS Atom server up to snuff

The OpenDS Atom server is now compliant with the latest Atompub (draft 15) specification and passes all APE tests to include: adding, updating, deleting atom entries and associated media resources. Next up, a bit more hardening and user documentation.

Friday May 25, 2007

Atom and LDAP sitting in a tree...

"Tree", as in a directory information tree. Its been slightly over a year since Don and I had a gee whiz moment to front end the directory server with Atom and the Atom Publishing Protocol (APP). A year ago might have been a bit too early for a directory based APP server, though its clearly the right time now. Why?
  • Finally, there's a directory server that is lightweight, very fast (read AND write), and developer friendly - OpenDS
  • The APP spec appears to be close to completion
  • Facilities for search and user authorization are noticeably absent from the APP spec (that's a good thing)
  • DSML (LDAP over XML) is deader than a doornail
  • Think "syndicated databases"; i.e., databases queried, edited and generally mangled via feeds. I know I'm not the only one thinking about it (checkout Google GBase and Yahoo Pipes).


Atom, APP, and OpenDS
  • Atom is a simple, extensible specification that describes lists of related information. In its simplest form it is no more than a blog feed.
  • APP is a web-based protocol for publishing, editing and retrieving web resources; e.g., Atom documents, xhtml, images, podcast episodes, et al. APP relies on tried and true HTTP and ReST interfaces gaining it a distinct advantage over previous attempts. That is, a widely deployed infrastructure, simple to grok, and relatively simple server and client side implementations.
  • OpenDS is an open source, 100% Java directory service

Why is an OpenDS based Atom server interesting?
  • I have yet to see an Atom/APP implementation application that is identity aware. That is, a server that has intrinsic user knowledge with regards to roles, authorization, authentication mechanisms and user relationships
  • Most certainly not file based. Resources posted and fetched are stored in the directory thus enabling synchronization, access control, search, etc.
  • Powerful, ReST search based on LDAP Urls
  • Built on a scalable architecture. Back-ended by OpenDS, front-ended by Glassfish application server, and written atop Java

What can you do with it?
  • "Web 2.0" enable your directory. Atom is easily parsed within a web browser and for that matter any other HTTP agent. Therefore, access to the info rich directory is more accessible to external applications and more easily programmed by the neophyte LDAP developer.
  • Centrally secure, replicate, and backup Atom documents;e.g., blogs in the directory
  • Re-use existing infrastructure and expertise (directory server) to store next gen web content, again, in a secure, scalable fashion
  • Monitor the directory through feeds. A simple search on the OpenDS monitor (/atom/search?q=cn=monitor??sub?) dumps a feed of all significant directory statistics
  • ...

Where can you get it (and contribute to it!)?

Right here, in the first OpenDS sub-project @ http://atom.dev.java.net

Sunday Apr 22, 2007

An out-of-the-box OpenID server built atop OpenDS and Java EE

I've been tinkering with public domain OpenIDs for the past few months and found the OpenID service, as it is described, to be useful indeed. I say "as described" since it is clearly not the end all be all Internet authentication service, however, it is interesting and worth exploring further. To that end, I've developed a light-weight, demo quality, OpenID provider. It's easily deployable atop any Java EE container and backed by the OpenDS directory server. Note: Credit goes to Paul Bryan (an OpenSSO contributor) for the initial OpenID protocol handler.

Why develop yet another OpenID provider? Unfortunately, I could not find a maintained, easily deployable, Java EE based provider that actually worked. In addition, as a directory guy, I believe people and identity centric data belong in the directory and not spread amongst n different databases. I'm currently at the O'Reilly Web 2.0 Expo and have been informally polling attendees on general identity management topics; e.g., where are your users stored?, what authentication protocols do you support?, and the like. Brandon, I was wrong - you are right, new applications are still emerging with their own, siloed "user tables" to stuff people and their passwords. Evidently, there is still much education to be done around directory. I trust that this proof-of-concept will assist in showing others the light on how simple it is to support the newest of the new protocols. Give it a try.


I'm running the demo atop Ubuntu, Java 6, Glassfish V2, and the latest OpenDS download. Ensure you obtain a build dated 4/21/2007 or later.
  1. Install OpenDS
  2. Drop in the OpenID schema file. In the case of OpenDS simply drop this file in $opends_home/config and restart OpenDS.
  3. Download the OpenID application (WAR) and deploy to your application server. Please note the fine print below.
  4. To get started register a new user by "claiming in ID" via the bundled user interface http://localhost:8080/opendsidp/. Copy the generated claim URL; e.g., http://yourhost/opendsidp/claims/username and go use it. For starters try using your claim at http://jyte.com.

The fine print:
Since this is demoware, I made many assumptions about the environment. Most of these assumptions are configurable though a few currently are not. Also, I've left a few features out. In particular, I've left manually accepting/rejecting trust roots for another day.

Please note the following: It is assumed the directory server is on the localhost, listening on port 1389, and may be read by the user cn="directory manager" with the password "password". The base DN is "dc=example,dc=com" and the people base DN is "ou=people,dc=example,dc=com". Additionally, it is required that all OpenID users must belong to the group "openidusers" and that group is located in ou=groups,dc=example,dc=com. The OpenID configuration and authentication tokens (user cookies) are stored in ou=openid, dc=example,dc=com. You do not need to create the groups or openid configuration buckets, they will be created on startup. If your ldap host, port, query user, based dn, or base people dn are different you are free to change the default values by editing the web.xml file located in the WEB-INF directory. The attributes that need changing should be obvious. Confused? Don't be, if you install OpenDS out-of-the-box and accept the default installation configuration you'll be good to go. Good luck!

Monday Mar 26, 2007

Java LDAP JSR proposal in the works

Last week I posted a proposal for a new, LDAP centric, Java client. I'm pleased to announce that Neil Wilson will take the lead on creating a JSR "early draft" for submission to the JCP. In less than a week there's already momentum building around the proposal, evidently, this effort is long over due. Of note, Mark Wahl posted his views on the subject and broadened the scope of the proposal even further.

Thursday Mar 22, 2007

Resurrecting The Java LDAP Centric API

LDAP server development and usage is on the upswing. As Java developers attempt to take advantage of the full capabilities of modern directory servers, shortcomings in the built-in SDK are more evident than ever. Neil and I believe its high time to resurrect the call for a Java LDAP client. Its been done in the past (Netscape SDK, Novell, and so on) though this round we're shooting for standardization via the IETF or better yet a JSR. Interested? Let us know what you think.

Proposal for a Java LDAP Application Programming Interface

The Lightweight Directory Access Protocol (LDAP, as defined in RFC 4510 et al.) provides a standard means of communicating with directory servers. It is commonly used in identity management, authentication/authorization, naming services, user/application configuration, and general data storage. There are a growing number of commercial and open source server implementations, and many enterprises and service providers are significantly increasing the use of LDAP in their web applications, desktop clients, and mission-critical infrastructure.

While LDAP innovation and development continues on the server side the same is not true of the client. Java SE and EE clients typically use Java Naming and Directory Interface (JNDI) to communicate with directory servers. This is primarily because JNDI and the accompanying LDAP SPI are embedded within Java SE and is rarely based on the merits of the API itself. JNDI is intended to be a generic interface for accessing very different kinds of data stores, and as such uses an abstract API. As a result, critical LDAP functionality is difficult to access and the developer experience is significantly impaired. For example:

  • The abstract nature of JNDI terminology is confusing for the LDAP neophyte. That is, the Java LDAP developer must learn 2 different vocabularies, LDAP and JNDI. For example, the terms "bind" and "unbind" have standard meanings in LDAP which are very different from the way those terms are used in JNDI. In addition, a given JNDI method may result in different LDAP operations based on the arguments provided (e.g., while most variations of the JNDI "search" method will result in LDAP search operations, one usage will result in an LDAP compare operation, which may have different semantics).

  • LDAP functionality can be enhanced through the use of elements such as controls, extended operations, and SASL mechanisms, and such extensions are frequently described in new specifications. JNDI does not provide an adequate mechanism for adding client-side support for these elements.

  • Standard LDAP idioms are difficult or exposed in a bizarre manner; e.g., failed operation codes must be parsed out of exception messages, search enumerations must be closed.
We propose the creation of a new Java API specifically designed for communicating with LDAP directory servers. An IETF draft addresses this subject and will likely serve as a starting point for future discussion as the the goal of this draft and our proposal are identical: a simple, developer-friendly interaction model for LDAP communication. In addition, the API should provide a convenient means of extending its functionality by adding support for new controls and extended operations as they are defined by various standards bodies. There have been successful implementations of the draft API in the past, but they were based on older versions of the Java language and as such did not not take advantage of recent improvements in Java performance and usability.

In many ways this API could provide for LDAP what JDBC has done for Java relational database clients. The beauty of LDAP is that it is a wire protocol, hence there is no need for vendor specific driver implementations. As such, a Java-based LDAP API could easily be self-contained and free of external dependencies, making it more immediately accessible to developers. Standardization will relieve LDAP vendors of the mundane and repetitive task of maintaining vendor specific client libraries and provide developers with a pleasurable LDAP experience.

Get the PDF proposal

Thursday Feb 22, 2007

LDAP vs relational database (Part 2)

A continuation of my previous post on pointing out the advantages of LDAP over relational databases. In this round I address fewer points though delve a bit deeper.

Universal drivers: No vendor specific database drivers are needed as LDAP specifies a standard wire protocol. That is, any vendor’s LDAP client should be interoperable with any other vendor’s directory server. Therefore, the onerous task of obtaining and managing vendor database drivers is no longer necessary.

LDAP controls: Controls provide a mechanism for both the client and the server to send additional information with a LDAP request. A very useful LDAP control is persistent search (not all servers support the control, but it is a common feature). This control notifies the search requester of a change in the search results. For example, if an application centrally stores configuration information in a directory it needs to be notified if the configuration is changed. This is easily accomplished by running a persistent search on the config data - if a change (add, modify, delete, move) occurs the server will asynchronously notify the client. Checkout controls supported by OpenDS.

Directory Service Markup Language (DSML): I'm sure I'll get ribbed for pointing out this one as I haven't seen any production use of DSMLv2 since its introduction in 2002. DSML is simply LDAP translated to XML (typically transported over HTTP). The primary benefits of which are: no LDAP client required, LDAP operations may easily pass through the firewall, and directory operations can be batched together and executed in a single request. We’re going to make interesting use of this capability in the near future with the introduction of a Javascript library that nicely models LDAP and talks DSML. The advantage? This will enable web developers to write browser-based applications that talk directly to OpenDS. Dare I say web 2.0?

URL based searches: Depending on the capabilities of your LDAP client, a standardized URL may be used to execute a search; e.g., ldap://localhost/dc=example,dc=com???(uid=treydrake) returns the entry associated with “treydrake”. With a bit of practice, fine grained entry/attribute retrieval and search criteria is easily expressed on the "web command line". Not quite ReST, but convenient nonetheless.

LDAP schema constructs: I've noted that LDAP schema consists of objectclasses and attributes. A point worth mentioning is that objectclasses are much more flexible than flat RDBMS tables. Specifically, there are 3 types of objectclasses: structural, abstract, and auxiliary. Structural types are concrete classes that represent an LDAP entry. Abstract classes are simply structural parents; i.e., they define attributes for inheritance by more specialized, structural classes. Finally, auxiliary types are supplemental classes that may be associated with structural or abstract classes. To make these concepts concrete consider the typical person example, "inetorgperson" (the LDAP standard defines numerous standard objectclass types, one of which is "inetorgperson"). This type is derived as follows: top -> person -> organizationalPerson -> inetorgPerson. Where top is the parent of all LDAP classes and inetorgperson defines new person attributes and inherits all superior objectclass attributes. Objectclass inheritance is a heck of a lot cleaner than defining numerous tables and linking them together with foreign keys!

Globally unique schema: An interesting aspect of LDAP schema is the identification of objectclasses and attributes as globally unique objects known as OIDs. That is, every attribute and objectclass has both a name and a unique ID. This makes sharing schema objects throughout the enterprise much more precise and traceable as an OID is associated with an authority (a company, standard, etc). For example, I may create an objectclass named "blog" with the OID 1.3.6.1.4.1.26922.1.1. OIDs are also hierarchal; breaking apart the OID, "1.3.6.1.4.1" identifies the object is owned by a private enterprise, "26922" identifies the specific enterprise and the trailing suffix "1.1" is completely defined by the enterprise. An enterprise, having defined a new globally unique object, may then publish a detailed description of the new objectclass for reference by consumers. Clearly, identifying schema elements with collision proof ids versus names is a distinct advantage. Need your own OID namespace? Get one here.

Monday Feb 12, 2007

The facts on OpenDS ACID properties and LDAP transactions

Readers left numerous comments on last week's post (LDAP vs relational databases) that need further elaboration. To that end, Neil Wilson (OpenDS architect) just posted an excellent summary describing OpenDS ACID properties and our plans to support LDAP transactions. Thanks Neil!

Thursday Feb 08, 2007

OpenDS <> Roller integration

A recent experiment had me working out how to LDAP enable Roller authentication. With Dave's (Roller team) help the configuration below has been proven to work. You may find it kludgey in that 1) after registration the user must close and re-open the browser due to a Roller bug and 2) enabling SSO doesn't have anything to do with enabling LDAP authentication, but it works.

Prepare or install a directory server

For starters if you don't have a directory (LDAP) server available get one. You will need modify rights as all Roller users must belong to the group “register” to successfully login. Properly adding LDAP users/groups can be confusing. Review the first section of my previous entry on OpenDS configuration and use this sample LDIF to add a properly defined Roller user.

Configure Roller

Enable single sign on

Open the roller.properties file and change the property “users.sso.enabled” from “false” to “true”; i.e., “users.sso.enabled=true”

Swap out the internal Roller authentication provider and replace with LDAP

Open the security.xml file and edit as follows: Uncomment the elements beginning with “<!-- Sample LDAP/RollerDB hybrid security configuration -->” Secure the user registration page by adding the line " /roller-ui/user.do\*=register" to the filterInvocationInterceptor bean value; i.e.,

   <bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
       <property name="authenticationManager" ref="authenticationManager"/>
       <property name="accessDecisionManager" ref="accessDecisionManager"/>
        <property name="objectDefinitionSource">
           <value>
               PATTERN_TYPE_APACHE_ANT
               /roller-ui/login-redirect.jsp=admin,editor
               /roller-ui/yourProfile\*\*=admin,editor
               /roller-ui/createWebsite\*\*=admin,editor
               /roller-ui/yourWebsites\*\*=admin,editor
               /roller-ui/authoring/\*\*=admin,editor
               /roller-ui/admin/\*\*=admin
               /roller-ui/user.do\*=register
               /rewrite-status\*=admin
           </value>
       </property>
   </bean>
Securing the registration page enables Roller to prompt for LDAP credentials and use the authenticated user information to pre-populate the user registration form. Note: the user must belong to a LDAP group named “register”.


Comment out the DAO authentication provider (Roller) and replace with the LDAP provider; i.e.,
   <bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
       <property name="providers">
           <list>
               <!-- <ref local="daoAuthenticationProvider"/> -->
               <ref local="ldapAuthProvider"/>
               <ref local="anonymousAuthenticationProvider"/>
               <!-- rememberMeAuthenticationProvider added programmatically -->
           </list>
       </property>
   </bean>

Point the authentication provider to your OpenDS instance. Note that the configuration below is specific to your OpenDS installation. For example:
 
  <bean id="initialDirContextFactory"
class="org.acegisecurity.ldap.DefaultInitialDirContextFactory">
     <constructor-arg value="ldap://localhost:1389/dc=example,dc=com"/>
     <property name="managerDn">
       <value>cn=Directory Manager</value>
     </property>
     <property name="managerPassword">
       <value>password</value>
     </property>
   </bean>
  • constructor-arg = the LDAP URL to the OpenDS server and base suffix
  • managerDN = (Optional) If you do not allow anonymous search specify a user capable of searching the user/group tree
  • managerPassword = (Optional) The managerDN password


Specify the user search criteria. The attribute “uid” is a typical unique identifier. Note the token '{0}' is replaced with the username entered on the Roller login form.

   <bean id="ldapUserSearch"
class="org.acegisecurity.ldap.search.FilterBasedLdapUserSearch">
     <constructor-arg index="0">
       <value></value>
     </constructor-arg>
     <constructor-arg index="1">
       <value>uid={0}</value>
     </constructor-arg>
     <constructor-arg index="2">
       <ref local="initialDirContextFactory" />
     </constructor-arg>
     <property name="searchSubtree">
       <value>true</value>
     </property>
   </bean>


You may find my security.xml file and roller.properties file helpful as a guide. Good luck.

Wednesday Feb 07, 2007

LDAP vs relational database

Typically, when I ask enterprise developers where they'll store application data the response is immediate, a relational database. The directory server isn't even an afterthought. There's a long laundry list of reasons why: no one gets fired for choosing Oracle, its already there, familiarity with SQL, plethora of RDBMS tools, LDAP writes are slow, JNDI interface - are you kidding?!... While all of these are legitimate retorts, LDAP, and in particular OpenDS, bring with it clear advantages for certain classes of applications.

A short list of OpenDS differentiators include:

It's a database! LDAP isn't just a dumping ground for user profile data, it's a full-fledged hierarchical database. If your data is modeled in a parent-child fashion, not unusual in a XML world, then LDAP might be a better fit. LDAP data modeling is very different than relational modeling though at a simplistic level you might map tables to entries and columns to attributes.

Change schema over protocol: Schema is modifiable over the standard LDAP protocol - no vendor specific tools or syntax required. Building an application that requires frequent and/or unpredictable schema changes is difficult with relational databases and, I've found, often handled by creating generic trees (parent child relationships). Highly, dynamic “Web 2.0'ish” applications come to mind; e.g., generic Atom server where arbitrary schema changes are expected.

Out-of-the-box synchronization: Synchronizing directory databases is a standard feature and requires minimal administration. It just works...at least that's the idea. A very cool feature for H/A and solving data adjacency issues.

Read/write performance parity: At the moment I'm unable to release specifics on OpenDS performance, but those of you with memories of slow write performance are in for a pleasant surprise

Embedded mode: OpenDS need not run in a separate process, rather it can be directly embedded in your application. This is especially useful for cases where one may need the benefits of a LDAP (the other bullets) database with zero external administration.

Scalability: OpenDS, stripped down, runs on PDA's and scales to telcos.

Extensibility: Aside from standard plugin extensions there are numerous hooks within OpenDS that are easily modified by a Java developer. OpenDS is 100% Java after-all. A deployer is free to customize protocol handlers, client connection handlers, configuration, monitors, loggers, and even the backend (we use Berkley DB).

Internationalization over protocol: Fetching language specific directory attributes is easily done over protocol using LDAP attribute options. For example, you may search for the English specific “description” attribute by searching “description;lang-en: software products” or the German version “description;lang-de: Softwareprodukte”

Matching rules: Directory servers provide a flexible facility for determining attribute value equality. Typical equality matching is supported out-of-the-box; e.g., case ignore, greater/less than, etc. The differentiating feature is the ability to write your own matching rules for specific attributes. An interesting application of this is fuzzy matching rules; instead of implementing approximate matches in your application logic this can be done within the data repository. For example, if I search for all Atom entries with the an attribute named “category” and the value “foo” I may have a matching rule that finds and return all entries that contain category values with “bar” and “baz” as well.

More to follow...

Friday Jan 26, 2007

Glassfish OpenDS integration

There's little need to explain why one would want to integrate application authentication with a centralized LDAP server so I'll get right to business. For test purposes I'm using the OpenDS directory and the Glassfish application server. In case you haven't heard, OpenDS is a 100% pure Java, open source, directory server specifically designed for large deployments where high performance is critical and ease of management is required. And, of course, Glassfish is a JEE 5 compliant application server.

To get started, you'll first need to install an OpenDS instance. Installation is made quick and easy via the "Quick Setup" Web Start installer and step-by-step instructions. During the installation process note the installation path, LDAP listener port, administrative User DN/password and the Directory Base DN as you'll need these properties to configure the Glassfish realm.

Next, load sample users and groups into OpenDS. The sample data is provided in LDIF format as it is the quickest and easiest method to import data into OpenDS. For test purposes I defined a single group, "webappgroup", with 1 member "treydrake". An additional user "noaccess" is defined to verify the solution works. Note that the web.xml, defined at the bottom of the page, grants access only to members of the group "webappgroup".

# add group
dn: ou=Groups,dc=example,dc=com
changetype: add
ou: Groups
description: Group ou
objectClass: top
objectClass: organizationalUnit

# add people ou
dn: ou=People,dc=example,dc=com
changetype: add
ou: People
description: People
objectClass: top
objectClass: organizationalUnit

# add an authorized user (belongs to the group webappgroup)
dn: uid=treydrake,ou=People,dc=example,dc=com
changetype: add
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
uid: treydrake
cn: Trey Drake
sn: Drake
givenName: Trey
userPassword: password

# unauthorized user
dn: uid=noaccess,ou=People,dc=example,dc=com
changetype: add
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
uid: noaccess
cn: No Access
sn: access
givenName: no
userPassword: noaccess

# add user to the webapp group
dn: cn=webappgroup,ou=Groups,dc=example,dc=com
changetype: add
objectClass: top
objectClass: groupOfUniqueNames
uniqueMember: uid=treydrake,ou=People,dc=example,dc=com
cn: webappgroup

Use the ldapmodify tool included in the OpenDS install to import the LDIF file as shown below. In the following examples I assume OpenDS is installed locally, the port is 1389, and the administrative user/password is the default "Directory Manager"/"password". If you customized the install and/or need to use more advanced options type "ldapmodify -H" to get complete usage info. For example:

~/OpenDS/bin treydrake$ ~/OpenDS/bin/ldapmodify -p 1389 -a -D "cn=Directory Manager" -w password -f ~/dev/opendsglassfishrealm-wksp/opendsauthtest/ldifs/data.ldif

Use ldapsearch to verify that the new user 'treydrake' can successfully authenticate to OpenDS and that the user is a member of the webappgroup. For example:

~/OpenDS/bin treydrake$ ~/OpenDS/bin/ldapsearch -p 1389 -D "uid=treydrake,ou=People,dc=example,dc=com" -w password -b ou=Groups,dc=example,dc=com objectclass=groupofuniquenames

Next, add an OpenDS realm to the Glassfish application server via the Glassfish console. Login to the console; e.g., http://localhost:4848 and navigate to Configuration -> Security -> Realms and click the "New" button. See the screen shot below for property settings:

The Glassfish LDAP realm requires the following properties:
  • directory - LDAP URL to the OpenDS instance; e.g., ldap://localhost:1389
  • base-dn - Base Distinguished Name (DN) for the location of user data, which can be at any level above the user data, since a tree scope search is performed. The smaller the search tree, the better the performance.
  • jaas-context - Must be "ldapRealm".
The following properties are optional:
  • search-filter - Search filter to use to find the user. The default value is uid=%s (%s expands to the subject name).
  • group-base-dn - Base DN for the location of group data. Same as the base-dn but it can be tuned if necessary.
  • group-search-filter - Search filter to find group memberships for the user. Defaults to uniquemember=%d (%d expands to the user element DN).
  • group-target - LDAP attribute name that contains group name entries. Defaults to CN.
  • search-bind-dn - Optional DN used to authenticate to the directory for performing the search-filter lookup. Only required for directories that do not allow anonymous search.
  • search-bind-password - LDAP password for the DN given in search-bind-dn.

Next, configure the web.xml and sun-web.xml descriptors to authenticate using the OpenDS realm by adding the security-constraint and login-config elements to your application's web.xml file and the role <-> group mapping in sun-web.xml. See samples below: web.xml

<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xsi="http://www.w3.org/2001/XMLSchema-instance"
schemalocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

<welcome-file-list>
<welcome-file>Index.jsp</welcome-file>
</welcome-file-list>

<!-- grant access to all users that possess the role
'secure' and deny all others -->

<security-constraint>
<web-resource-collection>
<web-resource-name>opendsauthtest</web-resource-name>
<url-pattern>/\*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>secure</role-name>
</auth-constraint>
</security-constraint>

<!-- declare the app uses FORM based authentication
using your newly created OpenDS realm -->

<login-config>
<auth-method>FORM</auth-method>
<realm-name>OpenDS</realm-name>
<form-login-config>
<form-login-page>/WEB-INF/jsp/Login.jsp</form-login-page>
<form-error-page>/WEB-INF/jsp/LoginError.jsp</form-error-page>
</form-login-config>
</login-config>

</web-app>
The Glassfish specific descriptor (sun-web.xml) maps the web application role defined in the web.xml descriptor to a LDAP group. sun-web.xml
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE sun-web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Application Server 8.1 Servlet 2.4//EN"
"http://www.sun.com/software/appserver/dtds/sun-web-app_2_4-1.dtd">
<sun-web-app>
<security-role-mapping>
<role-name>secure</role-name>
<group-name>webappgroup</group-name>
</security-role-mapping>
</sun-web-app>

Finally, deploy your application and attempt to login using the username "treydrake" and password "password". Authenticating as "noaccess", or any other user for that matter, should fail. For convenience sake, I've uploaded a web application that's configured using the above instructions. Good luck.

About

treydrake

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today