/*
* Directory Lookup Service *
* author: Florida Estrella
*/
package com.c2kernel.lookup;
import java.util.StringTokenizer;
import com.c2kernel.common.ObjectAlreadyExistsException;
import com.c2kernel.common.ObjectCannotBeUpdated;
import com.c2kernel.common.ObjectNotFoundException;
import com.c2kernel.entity.TraceableEntity;
import com.c2kernel.entity.agent.ActiveEntity;
import com.c2kernel.entity.proxy.EntityProxyManager;
import com.c2kernel.entity.proxy.ProxyMessage;
import com.c2kernel.process.Gateway;
import com.c2kernel.property.PropertyDescription;
import com.c2kernel.property.PropertyDescriptionList;
import com.c2kernel.utils.Logger;
import com.c2kernel.utils.Resource;
import com.novell.ldap.LDAPAttributeSet;
import com.novell.ldap.LDAPConnection;
import com.novell.ldap.LDAPDN;
import com.novell.ldap.LDAPEntry;
import com.novell.ldap.LDAPException;
import com.novell.ldap.LDAPSearchConstraints;
import com.novell.ldap.LDAPSearchResults;
/**
* The LDAPLookup object, statically accessible through the Gateway, manages
* the LDAP connection for the cristal process. It provides:
*
* - Authentication - returning an AgentProxy object if a user has logged in
*
- System key generation - through the NextKeyManager
*
- Agent and Role lookup/modification - through the RoleManager
*
-
* @version $Revision: 1.113 $ $Date: 2006/03/03 13:52:21 $
* @author $Author: abranson $
*/
public class LDAPLookup
{
private LDAPConnection mLDAPConn;
private final LDAPProperties mLDAPProps;
private final NextKeyManager mNextKeyManager;
private LDAPPropertyManager mPropManager;
private final LDAPRoleManager mRoleManager;
/**
* Creates a new LDAPLookup manager with the properties supplied.
* This should be only done by the Gateway during initialisation.
*
* @param props The LDAP properties object that extracts LDAP connection properties from the global c2kprops
*/
public LDAPLookup(LDAPProperties props) throws LDAPException
{
Logger.msg(8,"LDAPLookup - initialising.");
mLDAPProps = props;
mLDAPConn = createConnection(mLDAPProps);
Path.mGlobalPath=props.mGlobalPath;
Path.mRootPath=props.mRootPath;
Path.mLocalPath=props.mLocalPath;
EntityPath.mTypeRoot = "cn=entity,"+props.mLocalPath;
DomainPath.mTypeRoot = "cn=domain,"+props.mLocalPath;
mNextKeyManager = new NextKeyManager(this, "cn=last,"+EntityPath.mTypeRoot);
Logger.msg(7, "LDAP.useOldProps="+Gateway.getProperty("LDAP.useOldProps", "false"));
if (Gateway.getProperty("LDAP.useOldProps", "false").equals("true")) {
Logger.debug(1, "Using Kernel 2.1 LDAP Property Format");
mPropManager = new LegacyLDAPPropertyManager(this);
}
else {
Logger.debug(1, "Using Kernel 2.2 LDAP Property Format");
mPropManager = new LDAPPropertyManager(this);
}
mRoleManager = new LDAPRoleManager(this, "cn=agent,"+DomainPath.mTypeRoot, EntityPath.mTypeRoot);
}
/**
* Utility method to connect to an LDAP server
* @param lp LDAP properties to connect with
* @return a novell LDAPConnection object
* @throws LDAPException when the connection was unsuccessful
*/
public static LDAPConnection createConnection(LDAPProperties lp) throws LDAPException {
LDAPConnection ld;
if (lp.mTimeOut == 0) ld = new LDAPConnection();
else ld = new LDAPConnection(lp.mTimeOut);
Logger.msg(3, "LDAPLookup - connecting to " + lp.mHost);
ld.connect(lp.mHost, Integer.valueOf(lp.mPort).intValue());
Logger.msg(3, "LDAPLookup - authenticating user:" + lp.mUser);
ld.bind( LDAPConnection.LDAP_V3, lp.mUser,
String.valueOf(lp.mPassword).getBytes());
Logger.msg(3, "LDAPLookup - authentication successful");
LDAPSearchConstraints searchCons = new LDAPSearchConstraints();
searchCons.setMaxResults(0);
ld.setConstraints(searchCons);
return ld;
}
/**
* Gets the entity key generator, used to get a unique system key for new entities.
* @return the global NextKeyManager
*/
public NextKeyManager getNextKeyManager()
{
return mNextKeyManager;
}
/**
* Gets the property manager, that is used to read and write cristal properties to the LDAP store.
* @return Returns the global LDAPPropertyManager.
*/
public LDAPPropertyManager getPropManager() {
return mPropManager;
}
/**
* Gets the role manager, that is used to add and remove roles and agents.
* @return Returns the mRoleManager.
*/
public LDAPRoleManager getRoleManager() {
return mRoleManager;
}
/**
* Returns the current LDAP connection, and attempts to reconnect if it has been closed.
* @return
*/
protected LDAPConnection getConnection()
{
if (!mLDAPConn.isConnected()) {
Logger.warning("LDAPLookup - lost connection to LDAP server. Attempting to reconnect.");
try {
mLDAPConn = createConnection(mLDAPProps);
} catch (LDAPException ex) { }
}
return mLDAPConn;
}
/**
* Disconnects the connection with the LDAP server during shutdown
*/
public void disconnect() {
Logger.msg(1, "LDAP Lookup: Shutting down LDAP connection.");
if (mLDAPConn != null) {
try {
mLDAPConn.disconnect();
} catch (LDAPException e) {
Logger.error(e);
}
mLDAPConn = null;
}
}
/**
* Attempts to resolve the CORBA object for a Path, either directly or through an alias.
* @param path the path to resolve
* @return the CORBA object
* @throws ObjectNotFoundException When the path does not exist
*/
public org.omg.CORBA.Object getIOR(Path path)
throws ObjectNotFoundException
{
return resolveObject(path.getFullDN());
}
/**
* Attempts to resolve the CORBA object from the IOR attribute of a DN, either directly or through an alias
* @param dn The String dn
* @throws ObjectNotFoundException when the dn or aliased dn does not exist
*/
private org.omg.CORBA.Object resolveObject(String dn)
throws ObjectNotFoundException
{
Logger.msg(8,"LDAPLookup.resolveObject("+dn+")");
LDAPEntry anEntry = LDAPLookupUtils.getEntry(getConnection(),dn,LDAPSearchConstraints.DEREF_NEVER);
if (anEntry != null)
{
String iorString;
try {
iorString = LDAPLookupUtils.getFirstAttributeValue(anEntry, "ior");
org.omg.CORBA.Object ior=Gateway.getORB().string_to_object(iorString);
if (ior!=null)
return ior;
else
throw new ObjectNotFoundException("LDAPLookup.resolveObject() - " + dn + " has no IOR", "");
} catch (ObjectNotFoundException ex) {
return resolveObject(LDAPLookupUtils.getFirstAttributeValue(anEntry,"aliasedObjectName"));
}
}
else
throw new ObjectNotFoundException("LDAPLookup.resolveObject() LDAP node " + dn + " is not in LDAP or has no IOR.", "");
}
/**
*
* @param domPath
* @return
* @throws InvalidEntityPathException
* @throws ObjectNotFoundException
*/
protected EntityPath resolvePath(DomainPath domPath)
throws InvalidEntityPathException, ObjectNotFoundException {
EntityPath referencedPath = null;
LDAPEntry domEntry = LDAPLookupUtils.getEntry(getConnection(), domPath
.getFullDN(), LDAPSearchConstraints.DEREF_ALWAYS);
String entityKey = LDAPLookupUtils.getFirstAttributeValue(domEntry,
"intsyskey");
Logger.msg(7, "DomainPath " + domPath + " is a reference to "
+ entityKey);
String objClass = LDAPLookupUtils.getFirstAttributeValue(domEntry,
"objectClass");
if (objClass.equals("cristalagent"))
referencedPath = new AgentPath(Integer.parseInt(entityKey));
else
referencedPath = new EntityPath(Integer.parseInt(entityKey));
return referencedPath;
}
public LDAPEntry add(Path path)
throws ObjectCannotBeUpdated, ObjectAlreadyExistsException
{
try {
checkLDAPContext(path);
LDAPAttributeSet attrSet = path.createAttributeSet();
LDAPEntry newEntry = new LDAPEntry(path.getFullDN(),attrSet);
LDAPLookupUtils.addEntry(getConnection(),newEntry);
if (path instanceof DomainPath)
EntityProxyManager.sendProxyEvent(new ProxyMessage(ProxyMessage.NA, path.toString(), ProxyMessage.ADDED));
return newEntry;
} catch (LDAPException ex) {
if (ex.getResultCode() == LDAPException.ENTRY_ALREADY_EXISTS)
throw new ObjectAlreadyExistsException(ex.getLDAPErrorMessage(), "");
else
throw new ObjectCannotBeUpdated(ex.getLDAPErrorMessage(), "");
}
}
//deletes a node
//throws LDAPexception if node cannot be deleted (eg node is not a leaf)
public void delete(Path path) throws ObjectCannotBeUpdated
{
try {
LDAPLookupUtils.delete(getConnection(),path.getDN()+Path.mLocalPath);
} catch (LDAPException ex) {
throw new ObjectCannotBeUpdated(ex.getLDAPErrorMessage(), "");
}
if (path instanceof DomainPath) {
EntityProxyManager.sendProxyEvent(new ProxyMessage(ProxyMessage.NA, path.toString(), ProxyMessage.DELETED));
}
}
//change specs, add boolean alias leaf context
protected void checkLDAPContext(Path path)
{
String dn = path.getFullDN();
if (!LDAPLookupUtils.exists(getConnection(),dn))
{
String listDN[] = path.getPath();
String name = "cn="+ path.getRoot() + "," + Path.mLocalPath;
int i=0;
while (i getEntityClass(Path path) throws ObjectNotFoundException {
String[] attr = { LDAPConnection.ALL_USER_ATTRS };
try {
LDAPEntry anEntry=getConnection().read(path.getDN()+Path.mLocalPath,attr);
String type = LDAPLookupUtils.getFirstAttributeValue(anEntry, "objectClass");
if (type.equals("cristalentity"))
return TraceableEntity.class;
else if (type.equals("cristalagent"))
return ActiveEntity.class;
else
throw new ObjectNotFoundException("Not an entity", "");
} catch (LDAPException ex) {
if (ex.getResultCode() == LDAPException.NO_SUCH_OBJECT)
throw new ObjectNotFoundException("Entity does not exist", "");
Logger.error(ex);
throw new ObjectNotFoundException("Error getting entity class", "");
}
}
/** converts an LDAPentry to a Path object
* Note that the search producing the entry should have retrieved the attrs
* 'ior' and 'uniquemember'
* @throws ObjectNotFoundException
* @throws ObjectNotFoundException
*/
protected Path nodeToPath(LDAPEntry entry) throws InvalidEntityPathException, ObjectNotFoundException
{
String dn = entry.getDN();
// extract syskey
int entityKey = -1;
try {
String entityKeyStr = LDAPLookupUtils.getFirstAttributeValue(entry,"intsyskey");
entityKey = Integer.parseInt(entityKeyStr);
} catch (Exception e) { }
// extract IOR
org.omg.CORBA.Object ior = null;
try {
String stringIOR = LDAPLookupUtils.getFirstAttributeValue(entry,"ior");
ior = Gateway.getORB().string_to_object(stringIOR);
} catch (ObjectNotFoundException e2) { }
/* Find the right path class */
Path thisPath;
if (LDAPLookupUtils.existsAttributeValue(entry,"objectclass","cristalagent"))
{ //cristalagent
String agentID = LDAPLookupUtils.getFirstAttributeValue(entry,"uid");
thisPath = new AgentPath(entityKey, agentID);
}
else if (LDAPLookupUtils.existsAttributeValue(entry,"objectclass","cristalrole"))
{ //cristalrole
thisPath = new RolePath(LDAPDN.explodeDN(dn,true)[0],
LDAPLookupUtils.getFirstAttributeValue(entry, "jobList").equals("TRUE"));
}
else if (LDAPLookupUtils.existsAttributeValue(entry,"objectclass","aliasObject") ||
(LDAPLookupUtils.existsAttributeValue(entry,"objectclass","cristalcontext") && dn.endsWith(DomainPath.mTypeRoot)))
{
DomainPath domainPath = new DomainPath();
domainPath.setDN(dn);
thisPath = domainPath;
}
else if (LDAPLookupUtils.existsAttributeValue(entry,"objectclass","cristalentity") ||
(LDAPLookupUtils.existsAttributeValue(entry,"objectclass","cristalcontext") && dn.endsWith(EntityPath.mTypeRoot)))
{
if(dn.endsWith(EntityPath.mTypeRoot)) {
EntityPath entityPath;
if (entityKey != -1)
entityPath = new EntityPath(entityKey);
else {
entityPath = new EntityPath();
entityPath.setDN(dn);
}
thisPath = entityPath;
}
else
throw new ObjectNotFoundException("Entity found outside entity tree");
}
else
{
throw new ObjectNotFoundException("Unrecognised LDAP entry. Not a cristal entry");
}
//set IOR if we have one
if (ior!=null) thisPath.setIOR(ior);
return thisPath;
}
}