/*
* This file is part of the WfMOpen project.
* Copyright (C) 2001-2005 Danet GmbH (www.danet.de), BU BTS.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Id: LdapRmsManagedConnection.java 2589 2007-11-06 13:57:41Z drmlipp $
*
* $Log$
* Revision 1.4.4.1 2007/11/05 20:14:12 mlipp
* Added authentication properties.
*
* Revision 1.4 2007/09/02 22:19:53 mlipp
* Made LDAP EIS RA realy work.
*
* Revision 1.3 2007/05/17 21:52:59 mlipp
* Refactored resource adaptors.
*
* Revision 1.2 2006/09/29 12:32:07 drmlipp
* Consistently using WfMOpen as projct name now.
*
* Revision 1.1 2006/09/24 20:57:16 mlipp
* Moved RMS implementations in own sub-package.
*
* Revision 1.1 2006/07/11 08:59:55 drmlipp
* Started LDAP RMS RA.
*
*/
package de.danet.an.workflow.rmsimpls.ldaprmsra;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Hashtable;
import java.util.List;
import javax.naming.Binding;
import javax.naming.InvalidNameException;
import javax.naming.NameNotFoundException;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.NotContextException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.InitialLdapContext;
import javax.resource.ResourceException;
import javax.resource.spi.CommException;
import javax.resource.spi.ConnectionRequestInfo;
import javax.security.auth.Subject;
import de.danet.an.util.ra.ConnectionSupport;
import de.danet.an.util.ra.FactoryConfigurationError;
import de.danet.an.util.ra.ManagedConnectionFactorySupport;
import de.danet.an.util.ra.ManagedConnectionSupport;
import de.danet.an.workflow.rmsimpls.eisrms.aci.RmsEntry;
/**
* This class provides the managed connection used by the resource adapter
* for the properties files based RMS.
* @author Michael Lipp
*/
public class LdapRmsManagedConnection extends ManagedConnectionSupport {
private static final org.apache.commons.logging.Log logger
= org.apache.commons.logging.LogFactory
.getLog(LdapRmsManagedConnection.class);
private LdapRmsManagedConnectionFactory factory = null;
private InitialLdapContext ctx = null;
/**
* Create a new instance.
* @param mcf the managed connection factory
* @param subject the subject
*/
public LdapRmsManagedConnection
(ManagedConnectionFactorySupport mcf, Subject subject) {
super (mcf, subject);
factory = (LdapRmsManagedConnectionFactory)mcf;
Hashtable env = new Hashtable ();
env.put("java.naming.factory.initial",
factory.getJavaNamingFactoryInitial());
env.put("java.naming.provider.url", factory.getJavaNamingProviderUrl());
env.put("java.naming.security.authentication",
factory.getJavaNamingSecurityAuthentication());
if (factory.getJavaNamingSecurityPrincipal() != null
&& factory.getJavaNamingSecurityPrincipal().length() > 0) {
env.put ("java.naming.security.principal",
factory.getJavaNamingSecurityPrincipal());
env.put ("java.naming.security.credentials",
factory.getJavaNamingSecurityCredentials());
}
if (logger.isDebugEnabled ()) {
logger.debug ("Logging into LDAP server, env=" + env);
}
try {
ctx = new InitialLdapContext(env, null);
} catch (NamingException e) {
throw new FactoryConfigurationError
("Cannot create LDAP connection: " + e.getMessage (), e);
}
}
/* (non-Javadoc)
* Comment copied from interface or superclass.
*/
protected void doDestroy() {
try {
ctx.close();
} catch (NamingException e) {
logger.debug
("Problem closing ldap context (ignored): " + e.getMessage());
}
ctx = null;
}
/* (non-Javadoc)
* Comment copied from interface or superclass.
*/
protected ConnectionSupport createConnection
(Subject subject, ConnectionRequestInfo cxRequestInfo) {
return new LdapRmsConnection ();
}
/* (non-Javadoc)
* @see de.danet.an.workflow.rmsimpls.eisrms.aci.RmsConnection#findResource
*/
public RmsEntry lookupUserByAccountName(String name)
throws ResourceException, NameNotFoundException {
return searchResource (RmsEntry.RESOURCE_TYPE_USER, name);
}
/* (non-Javadoc)
* @see de.danet.an.workflow.rmsimpls.eisrms.aci.RmsConnection#lookupResource
*/
public RmsEntry lookupResource(String key)
throws ResourceException, NameNotFoundException {
String dn = key.substring(2);
int resType = 0;
if (key.startsWith(RmsEntry.RESOURCE_TYPE_USER + "/")) {
resType = RmsEntry.RESOURCE_TYPE_USER;
} else if (key.startsWith(RmsEntry.RESOURCE_TYPE_GROUP + "/")) {
resType = RmsEntry.RESOURCE_TYPE_GROUP;
} else if (key.startsWith(RmsEntry.RESOURCE_TYPE_ROLE + "/")) {
resType = RmsEntry.RESOURCE_TYPE_ROLE;
} else {
throw new IllegalArgumentException
("Resource with invalid key " + key);
}
String rna = factory
.getQueryInfos(resType).getResourceNameAttribute();
try {
Attributes pd = ctx.getAttributes(dn);
String name = dn;
if (pd.get(rna) != null) {
name = (String)pd.get(rna).get();
}
return new RmsEntry (resType, key, name);
} catch (InvalidNameException e) {
throw (NameNotFoundException)
(new NameNotFoundException
("Unknown LDAP resource \"" + dn + "\": "
+ e.getMessage())).initCause(e);
} catch (NotContextException e) {
throw (NameNotFoundException)
(new NameNotFoundException
("Unknown LDAP resource \"" + dn + "\": "
+ e.getMessage())).initCause(e);
} catch (NamingException e) {
throw (ResourceException)
(new ResourceException
("Problem accessing LDAP: " + e.getMessage())).initCause(e);
}
}
/* (non-Javadoc)
* @see de.danet.an.workflow.rmsimpls.eisrms.aci.RmsConnection#listResources()
*/
public Collection listResources() throws ResourceException {
List result = new ArrayList ();
listResourceType
(result, factory.getQueryInfos(RmsEntry.RESOURCE_TYPE_USER));
listResourceType
(result, factory.getQueryInfos(RmsEntry.RESOURCE_TYPE_GROUP));
listResourceType
(result, factory.getQueryInfos(RmsEntry.RESOURCE_TYPE_ROLE));
return result;
}
private void listResourceType (List result, QueryInfos qi)
throws ResourceException {
if (qi.getCtxDN() == null) {
return;
}
try {
NamingEnumeration resources = null;
if (qi.getFilter() == null) {
resources = ctx.listBindings (qi.getCtxDN());
} else {
SearchControls ctrls = new SearchControls ();
ctrls.setReturningObjFlag (true);
ctrls.setReturningAttributes
(new String[] { qi.getSearchAttribute(),
qi.getResourceNameAttribute() });
resources = ctx.search
(qi.getCtxDN(), qi.getFilter(), ctrls);
}
while (resources.hasMore()) {
Binding b = (Binding)resources.next();
result.add (resourceFromBinding (b, qi));
}
} catch (NameNotFoundException e) {
logger.warn
("Cannot access configured context \"" + qi.getCtxDN() + "\"");
} catch (InvalidNameException e) {
logger.warn
("Cannot access configured context \"" + qi.getCtxDN() + "\"");
} catch (NotContextException e) {
logger.warn
("Cannot access configured context \"" + qi.getCtxDN() + "\"");
} catch (NamingException e) {
throw (CommException)
(new CommException
("Problem accessing LDAP: " + e.getMessage())).initCause(e);
}
}
/* (non-Javadoc)
* @see de.danet.an.workflow.rmsimpls.eisrms.aci.RmsConnection#authorizers
*/
public Collection authorizers(String key) throws ResourceException {
List result = new ArrayList ();
if (!key.startsWith(RmsEntry.RESOURCE_TYPE_USER + "/")) {
return result;
}
String dn = key.substring(2);
String mka = factory.getQueryInfos(RmsEntry.RESOURCE_TYPE_USER)
.getMemberAttribute();
if (mka != null) {
try {
Attributes attrs
= ctx.getAttributes (dn, new String[] { mka });
Attribute attr = attrs.get(mka);
if (attr == null) {
throw new IllegalStateException
("Configuration or data problem: " + dn
+ " should have attribute \"" + mka + "\""
+ " for use as member key.");
}
dn = (String)attr.get ();
} catch (NameNotFoundException e) {
throw (IllegalArgumentException)
(new IllegalArgumentException
("Unknown LDAP resource \"" + dn + "\": "
+ e.getMessage())).initCause(e);
} catch (InvalidNameException e) {
throw (IllegalArgumentException)
(new IllegalArgumentException
("Unknown LDAP resource \"" + dn + "\": "
+ e.getMessage())).initCause(e);
} catch (NotContextException e) {
throw (IllegalArgumentException)
(new IllegalArgumentException
("Unknown LDAP resource \"" + dn + "\": "
+ e.getMessage())).initCause(e);
} catch (NamingException e) {
throw (CommException)
(new CommException
("Problem accessing LDAP: " + e.getMessage())).initCause(e);
}
}
appendAuthorizers
(result, factory.getQueryInfos(RmsEntry.RESOURCE_TYPE_GROUP), dn);
appendAuthorizers
(result, factory.getQueryInfos(RmsEntry.RESOURCE_TYPE_ROLE), dn);
return result;
}
private void appendAuthorizers (List result, QueryInfos qi, String crit)
throws ResourceException {
if (qi.getCtxDN() == null) {
return;
}
try {
String filter = "(" + qi.getMemberAttribute() + "=" + crit + ")";
SearchControls ctrls = new SearchControls ();
ctrls.setReturningObjFlag (true);
ctrls.setReturningAttributes
(new String[] { qi.getSearchAttribute(),
qi.getResourceNameAttribute() });
NamingEnumeration resources
= ctx.search (qi.getCtxDN(), filter, ctrls);
while (resources.hasMore()) {
Binding b = (Binding)resources.next();
result.add (resourceFromBinding (b, qi));
}
} catch (NameNotFoundException e) {
logger.warn
("Cannot access configured context \"" + qi.getCtxDN() + "\"");
} catch (InvalidNameException e) {
logger.warn
("Cannot access configured context \"" + qi.getCtxDN() + "\"");
} catch (NotContextException e) {
logger.warn
("Cannot access configured context \"" + qi.getCtxDN() + "\"");
} catch (NamingException e) {
throw (CommException)
(new CommException
("Problem accessing LDAP: " + e.getMessage())).initCause(e);
}
}
/* (non-Javadoc)
* @see de.danet.an.workflow.rmsimpls.eisrms.aci.RmsConnection#selectResources
*/
public Collection selectResources(Object resSel) throws ResourceException {
Collection res = new ArrayList();
if (resSel == null || !(resSel instanceof String)) {
return res;
}
String crit = (String)resSel;
String selType = crit.substring(0, 1);
int resType = 0;
if (selType.equals("M") || selType.equals("U")) {
resType = RmsEntry.RESOURCE_TYPE_USER;
} else if (selType.equals("G")) {
resType = RmsEntry.RESOURCE_TYPE_GROUP;
} else if (selType.equals("R")) {
resType = RmsEntry.RESOURCE_TYPE_ROLE;
} else {
return null;
}
try {
res.add(searchResource (resType, crit.substring(2)));
} catch (NameNotFoundException e) {
}
return res;
}
private RmsEntry searchResource (int resType, String crit)
throws ResourceException, NameNotFoundException {
QueryInfos qi = factory.getQueryInfos(resType);
if (qi.getCtxDN() == null) {
throw new IllegalArgumentException
("No context configured for searching \"" + crit + "\"");
}
try {
String filter = "(" + qi.getSearchAttribute() + "=" + crit + ")";
if (qi.getFilter() != null) {
filter = "(&" + qi.getFilter() + filter + ")";
}
SearchControls ctrls = new SearchControls ();
ctrls.setReturningObjFlag (true);
ctrls.setReturningAttributes
(new String[] { qi.getSearchAttribute(),
qi.getResourceNameAttribute() });
NamingEnumeration resources
= ctx.search (qi.getCtxDN(), filter, ctrls);
if (!resources.hasMore()) {
throw (NameNotFoundException)
(new NameNotFoundException
("No LDAP resource in context \""
+ qi.getCtxDN() + "\" with \""
+ qi.getSearchAttribute() + "=" + crit + "\""));
}
Binding b = (Binding)resources.next();
return resourceFromBinding(b, qi);
} catch (NameNotFoundException e) {
throw (NameNotFoundException)
(new NameNotFoundException
("Unknown LDAP context \"" + qi.getCtxDN() + "\": "
+ e.getMessage())).initCause(e);
} catch (InvalidNameException e) {
throw (NameNotFoundException)
(new NameNotFoundException
("Unknown LDAP context \"" + qi.getCtxDN() + "\": "
+ e.getMessage())).initCause(e);
} catch (NotContextException e) {
throw (NameNotFoundException)
(new NameNotFoundException
("Unknown LDAP context \"" + qi.getCtxDN() + "\": "
+ e.getMessage())).initCause(e);
} catch (NamingException e) {
throw (CommException)
(new CommException
("Problem accessing LDAP: " + e.getMessage())).initCause(e);
}
}
private RmsEntry resourceFromBinding
(Binding binding, QueryInfos qi) throws NamingException {
DirContext resource = (DirContext)binding.getObject();
String resDN = resource.getNameInNamespace();
String resKey = qi.getResType() + "/" + resDN;
Attributes attrs = null;
if (binding instanceof SearchResult) {
attrs = ((SearchResult)binding).getAttributes ();
} else {
attrs = resource.getAttributes
("", new String[] { qi.getResourceNameAttribute(),
qi.getSearchAttribute() });
}
String resName = null;
if (attrs.get(qi.getResourceNameAttribute()) != null) {
resName = (String)attrs.get(qi.getResourceNameAttribute()).get();
} else if (qi.getSearchAttribute() != null
&& attrs.get(qi.getSearchAttribute()) != null) {
resName = (String)attrs.get(qi.getSearchAttribute()).get();
}
return new RmsEntry (qi.getResType(), resKey, resName);
}
}