Does uPortal 2.6 support multiple LDAP servers for redundancy?
It is also possible to apply very simple patches to enable uPortal to avail itself of JNDI support for transparent failover across LDAP URLs. uPortal Jira issue UP-713 includes trivial patches to add this capability for authentication and user attribute collection; a similarly trivial patch could add this capability to the LDAP-backed group store as well.
Introduction
This KBA includes commentary that has been included here because it seems relevant and valuable at the time of writing, but which may stale over time. This KBA was last edited 11 September 2007. It may be reviewed from time to time and updated, but if you are finding it to be out of date, please do contact Unicon to remind of your interest in seeing it updated.
Implementing Redundancy without uPortal even knowing you did it
Enterprise web applications often implement fault-detecting load-balancing or even stateful clustering so that if one application node failes, traffic can be routed to an intact node. An effective software or hardware load balancer abstracts this implementation detail so that end users need not be aware of it and simply interact with what they regard as a single web application. Enterprise RDBMS implementations sometimes support internal clustering such that a single DataSource / JDBC connection configuration points to a lightweight load balancer that dispatches to a working node within a cluster. Client code accessing such a database connects no differently and has no requirement of awareness of this clustering "implementation detail". Analogously, enterpise LDAP implementations may support internal clustering of the directory server such that clients need be configured no differently to take advantage of the potentially increased reliability of a clustered LDAP server implementation.
For example, see discussion of replication of OpenLDAP in this PDF.
Mark Wilcox, previously involved in the uPortal open source project and JA-SIG-participant-emeritus, has blogged on related topics.
[The linked PDF and page are provided by way of motivating example for the discussion above and are in no way affiliated with Unicon. No effort has been made to review them for correctness or anything more than a cursory indication of relevance. They're what you get when you Google search on this topic. -ed.]
Implementing Redundancy using JNDI's built-in support for multiple LDAP URLs
JNDI includes built-in support for trying several LDAP URLs to find a server able to make a connection. Unfortunately, a detail of the implementation of uPortal's abstraction for LDAP servers prevents use of this feature concurrently with use of SSL'ed LDAP connections. This is tracked in UP-713, which includes patches addressing the issue.
Since uPortal's SimpleLdapSecurityContext (for authenticating against an LDAP server) and LdapPersonAttributeDaoImpl (for user attribute collection from an LDAP server) both consume the ILdapServer uPortal-specific abstraction as configured in ldap.xml, implementation of this one trivial patch will make both the authentication and the user attribute collection uses of LDAP in uPortal support transparent failover across several configured LDAP URls.
However, the LdapGroupStore does not currently use LdapServices, nor does it use the ILdapServer abstraction. It also presently includes the same limitation that prevents use of SSL connections to LDAP in concert with the transparent failover across LDAP URLs provided by JNDI. Additional effort is therefore required to either implement this feature in the LdapGroupStore or, likely preferably, to refactor it to make use of the same LDAP abstraction used by the authentication and user attribute collection modules.
Implementing Redundancy using uPortal features
Implementing failover among redundant LDAP server instances should be implemented using either of the forgoing strategies: either internal to the LDAP server or by means of JNDI support for this feature. This discussion of using uPortal-internal features to implement this redundancy is largely academic.
It may be interesting to note that uPortal's authentication and user attribute collection systems internally include features that could be leveraged to implement this LDAP redundancy use case, albeit in a more (and given the other options, unnecessarily) complex way.
Use of Redundant LDAP Servers in Authentication
uPortal authenticates users using SecurityContexts. It obtains per-user-session SecurityContexts from SecurityContextFactorys
uPortal is capable of validating username and password at login against LDAP by means of SimpleLdapSecurityContexts created by SimpleLdapSecurityContextFactorys declared in security.properties. (There are other approaches to ultimately validating credentials using LDAP, e.g. using CAS for authentication to uPortal and configuring CAS to validate credentials against LDAP.)
It is possible to configure uPortal via security.properties to use several instances of the LDAP SecurityContextFactory (thanks especially to efforts by Eric Dalquist). Multiple SecurityContextFactorys are used in concert via a wrapper UnionSecurityContextFactory, which has the behavior of delegating authentication and succeeding in authenticating the user if any of its child contexts succeeds. The security.properties included in uPortal 2.6.0 includes an example of configuring multiple peer SimpleLdapSecurityContextFactorys to use different "connections" which map to LDAP connections configured in ldap.xml.
Note that the order in which SecurityContextFactorys are invoked is not specified by the order in which they are declared in security.properties. A present implementation detail about the way this properties file is read and hashed allows a workaround to implement a particular order of invocation of peer security contexts by use of carefully selected security context factory names as discussed in this KBA. This is a known annoyance in uPortal that is slated to be addressed in the next major release by re-implementation of the authentication tier of uPortal using Acegi or CAS.
The UnionSecurityContext produced by the UniconSecurityContextFactory extends ChainingSecurityContext and delegates to that superclass's authenticate implementation. ChainingSecurityContext iterates over its child contexts, attempting to authenticate each, and handles exceptions thrown by failing child contexts.
A viable approach to achieving fall-backing validation of {username, password} against a succession of redundant LDAP servers is therefore to simply declare those multiple SimpleLdapSecurityContextFactorys as children of a parent UniconSecurityContextFactory in the normal way. This requires no code changes.
Use of Redundant LDAP Servers in User Attribute Gathering
User attribute gathering in uPortal 2.6 is configured in properties/personDirectory.xml, though it is easy to re-introduce support for the traditional PersonDirs.xml domain-specific syntax.
Multiple sources of user attributes are gathered together using either MergingPersonAttributeDaoImpl or CascadingPersonAttributeDaoImpl (the former is appropriate when all sources use the same key to lookup users, whereas the latter is necessary when subsequent attribute sources depend on attributes gathered by earlier sources. While security.properties-defined SecurityContextFactory invocation order is poorly defined, order of execution of children of Merging and CascadingPersonAttributeDaoImpl is well defined as these are entered in a <list> in the language of Spring beans configuration.
Both Merging and CascadingPersonAttributeDao are also configurable as to policy for how to merge together the attributes gathered. For the use case of redundant attribute sources, the NoncollidingAttributeAdder strategy is appropriate.
However, under this approach, all child attribute sources will be attempted, even if an earlier in the ordering redundant source has already succeeded. This generates unnecessary querying of the redundant attribute sources. A trivial modification to Merging and CascadingPersonAttributeDaoImpl, proposed in uPortal enhancement proposal UP-1818, would add a "stopOnSuccess" configuration allowing configuration of these classes to implement this attempting to gather attributes from redundant sources use case. Note that this approach would provide for redundancy across sources of user attributes generally, whether those sources use LDAP or another strategy for acquiring user attributes.
Potential for related development activities
Clearly, UP-713 should be resolved in uPortal 2.6 patches series and in its HEAD towards a next major release.
security.properties configuration as presently implemented in uPortal should be replaced by a richer configuration syntax and API, potentially using Acegi or CAS within uPortal. This activity is on the roadmap for the next major release of uPortal, but it is not yet clear who will do this work.
As discussed above, a trivial enhancement to the wrapper IPersonAttributeDao implementations would enable use of redundant sources, whether those sources are LDAP or other implementations, without actually executing needless redundant queries, tracked in UP-1818. Further enhancements (or perhaps this should be moved into an entirely new ClusteringPersonAttributeDaoImpl specific to this use case) could implement sensible balancing of load across the "clustered" user attribute source DAO instances.
Additional documentation around any of the topics raised in this KBA could also be developed.
