A mechanism for allowing authentication from more than
one directory, or easy switching between user
directories.
On our site, we have two main user groups one in an
LDAP directory and one in an external sqlserver
maintained by Atomwide. We also continue using the
local authentication module so that we can add ad-hoc
users when required. This requirement led to this
development. The mechanism can act as a direct
replacement for the existing authentication mechanism
as it caters for basic local authentication only, and has
a couple of other useful features:
Login failure messages specify whether the username
or password was wrong
Utility class allowing authentication modules to enforce
name uniqueness (we had to implement this as we have
a single sign on arrangement with some forum software
that requires name uniqueness.)
A framework is included that allows additional services
to be added to a user. This was intended for
personalisation services such as personalised news,
but allows any service to be declared in an interface and
any authentication module may implement the service
in any way they see fit (including the existing local login
module).
The idea is that with a com.arsdigita.kernel.User, you
can ask the authentication mechanism for a custom
user class for that user. If an external authentication
module has implemented a custom user class then this
is returned.
To do this, as well as creating a custom user class the
authentication module should implement the
ExternalUserIdentifier interface and register this during
initialisation by invoking
ExternalUserFactory.registerExternalUserIdentifier
(myUserIdentifier);
The custom user class may implement any number of
interfaces that specify additional services and as the
ExternalUserFactory returns an Object you can then
see if it implements specific interfaces using instanceof
before trying to invoke those services
As an example, in my news portlet, I have defined an
interface
PersonalisedNewsTarget
with a method
public DomainCollection getMyNews();
One of my authentication modules defines a custom
user class which implements this interface by mapping
content items to attributes of the user.
The news portlet includes the code
User thisUser = (User) Kernel.getContext().getParty();
Object customUserObject =
ExternalUserFactory.getCustomUserObject(thisUser);
if (customUserObject instanceof
PersonalisedNewsTarget) {
PersonalisedNewsTarget customUser =
(PersonalisedNewsTarget)customUserObject;
DomainCollection myNews = customUser.getMyNews();
........etc
} else {
DataQuery newsItems =
SessionManager.getSession().retrieveQuery
(NewsItem.RECENT_NEWS);
........etc
To implement this module seamlessly as a direct
replacement for the existing authentication, ensure
waf.login_config contains at least the following enties
waf.login_config=Request\:com.arsdigita.kernel.security.
AdminLoginModule\:sufficient,Request\:com.arsdigita.ke
rnel.security.RecoveryLoginModule\:sufficient,Request\:c
om.arsdigita.kernel.security.CookieLoginModule\:requisit
e,Register\:uk.gov.westsussex.authentication.MultipleDir
ectoryLoginModule\:requisite,Register\:com.arsdigita.ker
nel.security.CookieLoginModule\:optional,Local\:com.ars
digita.kernel.security.LocalLoginModule\:requisite,Local\:
com.arsdigita.kernel.security.UserIDLoginModule\:requis
ite
and set
uk.gov.westsussex.authentication.included_login_contex
ts=Local
uk.gov.westsussex.authentication.unique_names=false
Note unique name code relies on functions only
available in Oracle. There is sure to be an equivalent
way of doing it in Postgres if anyone wants to use this,
but I anticipate it is of limited interest.
tar file for complete application