/*
* Directory Lookup Service *
* author: Florida Estrella
*/
package com.c2kernel.lookup.ldap;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.StringTokenizer;
import org.omg.CORBA.Object;
import com.c2kernel.common.ObjectAlreadyExists;
import com.c2kernel.common.ObjectCannotBeUpdated;
import com.c2kernel.common.ObjectNotFound;
import com.c2kernel.entity.proxy.ProxyMessage;
import com.c2kernel.lookup.AgentPath;
import com.c2kernel.lookup.DomainPath;
import com.c2kernel.lookup.InvalidItemPathException;
import com.c2kernel.lookup.ItemPath;
import com.c2kernel.lookup.LookupManager;
import com.c2kernel.lookup.Path;
import com.c2kernel.lookup.RolePath;
import com.c2kernel.process.Gateway;
import com.c2kernel.process.auth.Authenticator;
import com.c2kernel.property.Property;
import com.c2kernel.property.PropertyDescription;
import com.c2kernel.property.PropertyDescriptionList;
import com.c2kernel.utils.Logger;
import com.novell.ldap.LDAPAttribute;
import com.novell.ldap.LDAPAttributeSet;
import com.novell.ldap.LDAPConnection;
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 implements LookupManager{
protected LDAPAuthManager mLDAPAuth;
protected LDAPPropertyManager mPropManager;
protected LDAPProperties ldapProps;
private String mGlobalPath, mRootPath, mLocalPath, mRolePath, mItemTypeRoot, mDomainTypeRoot;
/**
*
*/
public LDAPLookup() {
super();
}
/**
* Initializes the DN paths from the Root, global and local paths supplied by the LDAP properties.
* @param props
*/
protected void initPaths(LDAPProperties props){
Logger.msg(8,"LDAPLookup.initPaths(): - initialising with LDAPProperties");
ldapProps = props;
mGlobalPath=props.mGlobalPath;
mRootPath=props.mRootPath;
mLocalPath=props.mLocalPath;
mItemTypeRoot = "cn=entity,"+props.mLocalPath;
mDomainTypeRoot = "cn=domain,"+props.mLocalPath;
mRolePath = "cn=agent,"+mDomainTypeRoot;
}
/**
* Initializes the LDAPLookup manager with the Gateway properties.
* This should be only done by the Gateway during initialisation.
*
* @param auth A LDAPAuthManager authenticator
*/
@Override
public void open(Authenticator auth) {
if (ldapProps == null)
initPaths(new LDAPProperties(Gateway.getProperties()));
mLDAPAuth = (LDAPAuthManager)auth;
mPropManager = new LDAPPropertyManager(this, mLDAPAuth);
}
/**
* 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;
}
/**
* Disconnects the connection with the LDAP server during shutdown
*/
@Override
public void close() {
Logger.msg(1, "LDAP Lookup: Shutting down LDAP connection.");
if (mLDAPAuth != null) {
mLDAPAuth.disconnect();
mLDAPAuth = 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 ObjectNotFound When the path does not exist
*/
public org.omg.CORBA.Object getIOR(Path path)
throws ObjectNotFound
{
return resolveObject(getFullDN(path));
}
/**
* 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 ObjectNotFound when the dn or aliased dn does not exist
*/
private org.omg.CORBA.Object resolveObject(String dn)
throws ObjectNotFound
{
Logger.msg(8,"LDAPLookup.resolveObject("+dn+")");
LDAPEntry anEntry = LDAPLookupUtils.getEntry(mLDAPAuth.getAuthObject(),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 ObjectNotFound("LDAPLookup.resolveObject() - " + dn + " has no IOR");
} catch (ObjectNotFound ex) {
return resolveObject(LDAPLookupUtils.getFirstAttributeValue(anEntry,"aliasedObjectName"));
}
}
else
throw new ObjectNotFound("LDAPLookup.resolveObject() LDAP node " + dn + " is not in LDAP or has no IOR.");
}
/**
*
* @param domPath
* @return
* @throws InvalidItemPathException
* @throws ObjectNotFound
*/
@Override
public ItemPath resolvePath(DomainPath domPath)
throws InvalidItemPathException, ObjectNotFound {
LDAPEntry domEntry = LDAPLookupUtils.getEntry(mLDAPAuth.getAuthObject(),
getFullDN(domPath), LDAPSearchConstraints.DEREF_ALWAYS);
String entityKey = LDAPLookupUtils.getFirstAttributeValue(domEntry,
"cn");
Logger.msg(7, "DomainPath " + domPath + " is a reference to "
+ entityKey);
String objClass = LDAPLookupUtils.getFirstAttributeValue(domEntry,
"objectClass");
ItemPath referencedPath = new ItemPath(entityKey);
if (objClass.equals("cristalagent"))
return new AgentPath(referencedPath);
return referencedPath;
}
@Override
public void add(Path path)
throws ObjectCannotBeUpdated, ObjectAlreadyExists
{
try {
checkLDAPContext(path);
LDAPAttributeSet attrSet = createAttributeSet(path);
LDAPEntry newEntry = new LDAPEntry(getFullDN(path),attrSet);
LDAPLookupUtils.addEntry(mLDAPAuth.getAuthObject(),newEntry);
if (path instanceof DomainPath)
Gateway.getProxyServer().sendProxyEvent(new ProxyMessage(null, path.toString(), ProxyMessage.ADDED));
} catch (LDAPException ex) {
if (ex.getResultCode() == LDAPException.ENTRY_ALREADY_EXISTS)
throw new ObjectAlreadyExists(ex.getLDAPErrorMessage());
else
throw new ObjectCannotBeUpdated(ex.getLDAPErrorMessage());
}
}
//deletes a node
//throws LDAPexception if node cannot be deleted (eg node is not a leaf)
@Override
public void delete(Path path) throws ObjectCannotBeUpdated
{
try {
LDAPLookupUtils.delete(mLDAPAuth.getAuthObject(),getDN(path)+mLocalPath);
} catch (LDAPException ex) {
throw new ObjectCannotBeUpdated(ex.getLDAPErrorMessage());
}
if (path instanceof DomainPath) {
Gateway.getProxyServer().sendProxyEvent(new ProxyMessage(null, path.toString(), ProxyMessage.DELETED));
}
}
//change specs, add boolean alias leaf context
protected void checkLDAPContext(Path path)
{
String dn = getFullDN(path);
if (!LDAPLookupUtils.exists(mLDAPAuth.getAuthObject(),dn))
{
String listDN[] = path.getPath();
String name = "cn="+ path.getRoot() + "," + mLocalPath;
int i=0;
while (i params = new ArrayList();
for (PropertyDescription propDesc: props.list) {
if (propDesc.getIsClassIdentifier())
params.add(propDesc.getProperty());
}
return search(start, params.toArray(new Property[params.size()]));
}
protected LDAPPathSet search(String startDN, int scope, String filter, LDAPSearchConstraints searchCons)
{
Logger.msg(8,"Searching for "+filter+" in "+startDN);
searchCons.setMaxResults(0);
String[] attr = { LDAPConnection.ALL_USER_ATTRS };
try
{
LDAPSearchResults res = mLDAPAuth.getAuthObject().search(startDN, scope,
filter,attr,false,searchCons);
return new LDAPPathSet(res, this);
}
catch (LDAPException ex)
{
Logger.error("LDAPException::LDAPLookup::search() " + ex.toString());
return new LDAPPathSet(this);
}
}
//typically search for (any filter combination)
public LDAPPathSet search(String startDN,String filter)
{
LDAPSearchConstraints searchCons = new LDAPSearchConstraints();
searchCons.setBatchSize(0);
searchCons.setDereference(LDAPSearchConstraints.DEREF_NEVER);
return search(startDN,LDAPConnection.SCOPE_SUB,filter,searchCons);
}
@Override
public LDAPPathSet searchAliases(ItemPath entity) {
LDAPSearchConstraints searchCons = new LDAPSearchConstraints();
searchCons.setBatchSize(0);
searchCons.setDereference(LDAPSearchConstraints.DEREF_NEVER);
return search(getFullDN(new DomainPath()), LDAPConnection.SCOPE_SUB, "(&(objectClass=aliasObject)(aliasedObjectName="+
LDAPLookupUtils.escapeDN(getFullDN(entity))+"))", searchCons);
}
@Override
public boolean exists(Path path) {
return LDAPLookupUtils.exists(mLDAPAuth.getAuthObject(), getFullDN(path));
}
@Override
public ItemPath getItemPath(String uuid) throws ObjectNotFound, InvalidItemPathException {
String[] attr = { LDAPConnection.ALL_USER_ATTRS };
try {
ItemPath item = new ItemPath(uuid);
LDAPEntry anEntry=mLDAPAuth.getAuthObject().read(getDN(item)+mLocalPath,attr);
String type = LDAPLookupUtils.getFirstAttributeValue(anEntry, "objectClass");
if (type.equals("cristalentity"))
return item;
else if (type.equals("cristalagent"))
return new AgentPath(item);
else
throw new ObjectNotFound("Not an entity");
} catch (LDAPException ex) {
if (ex.getResultCode() == LDAPException.NO_SUCH_OBJECT)
throw new ObjectNotFound("Entity does not exist");
Logger.error(ex);
throw new ObjectNotFound("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 ObjectNotFound
* @throws ObjectNotFound
* @throws
*/
protected Path nodeToPath(LDAPEntry entry) throws InvalidItemPathException, ObjectNotFound
{
String dn = entry.getDN();
ItemPath entityKey;
org.omg.CORBA.Object ior;
// extract syskey
try {
String entityKeyStr = LDAPLookupUtils.getFirstAttributeValue(entry, "cn");
entityKey = new ItemPath(entityKeyStr);
} catch (ObjectNotFound ex) {
entityKey = null;
} catch (InvalidItemPathException ex) {
entityKey = null;
}
// extract IOR
try {
String stringIOR = LDAPLookupUtils.getFirstAttributeValue(entry,"ior");
ior = Gateway.getORB().string_to_object(stringIOR);
} catch (ObjectNotFound ex) {
ior = null;
}
/* 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(getPathComponents(dn.substring(0, dn.lastIndexOf(mDomainTypeRoot))),
LDAPLookupUtils.getFirstAttributeValue(entry, "jobList").equals("TRUE"));
}
else if (LDAPLookupUtils.existsAttributeValue(entry,"objectclass","aliasObject") ||
(LDAPLookupUtils.existsAttributeValue(entry,"objectclass","cristalcontext") && dn.endsWith(mDomainTypeRoot)))
{
DomainPath domainPath = new DomainPath();
domainPath.setPath(getPathComponents(dn.substring(0, dn.lastIndexOf(mDomainTypeRoot))));
thisPath = domainPath;
}
else if (LDAPLookupUtils.existsAttributeValue(entry,"objectclass","cristalentity") ||
(LDAPLookupUtils.existsAttributeValue(entry,"objectclass","cristalcontext") && dn.endsWith(mItemTypeRoot)))
{
if(dn.endsWith(mItemTypeRoot)) {
if (entityKey == null) throw new InvalidItemPathException(entry.getDN()+" was not a valid itemPath");
thisPath = entityKey;
}
else
throw new ObjectNotFound("Entity found outside entity tree");
}
else
{
throw new ObjectNotFound("Unrecognised LDAP entry. Not a cristal entry");
}
//set IOR if we have one
if (ior!=null) thisPath.setIOR(ior);
return thisPath;
}
public String getDN(Path path) {
StringBuffer dnBuffer = new StringBuffer();
String[] pathComp = path.getPath();
for (int i=pathComp.length-1; i>=0; i--)
dnBuffer.append("cn=").append(LDAPLookupUtils.escapeDN(pathComp[i])).append(",");
dnBuffer.append("cn="+path.getRoot()+",");
return dnBuffer.toString();
}
public String getFullDN(Path path) {
return getDN(path)+mLocalPath;
}
public String[] getPathComponents(String dnFragment) {
ArrayList newPath = new ArrayList();
StringTokenizer tok = new StringTokenizer(dnFragment, ",");
String[] path = new String[tok.countTokens()];
while (tok.hasMoreTokens()) {
String nextPath = tok.nextToken();
if (nextPath.indexOf("cn=") == 0)
newPath.add(0, LDAPLookupUtils.unescapeDN(nextPath.substring(3)));
else
break;
}
return newPath.toArray(path);
}
@Override
public Object resolve(Path path) throws ObjectNotFound {
return resolveObject(getFullDN(path));
}
@Override
public Iterator getChildren(Path path) {
String filter = "objectclass=*";
LDAPSearchConstraints searchCons = new LDAPSearchConstraints();
searchCons.setBatchSize(10);
searchCons.setDereference(LDAPSearchConstraints.DEREF_FINDING );
return search(getFullDN(path), LDAPConnection.SCOPE_ONE,filter,searchCons);
}
protected LDAPAttributeSet createAttributeSet(Path path) throws ObjectCannotBeUpdated {
LDAPAttributeSet attrs = new LDAPAttributeSet();
if (path instanceof RolePath) {
RolePath rolePath = (RolePath)path;
attrs.add(new LDAPAttribute("objectclass","cristalrole"));
String jobListString = rolePath.hasJobList()?"TRUE":"FALSE";
attrs.add(new LDAPAttribute("jobList",jobListString));
attrs.add(new LDAPAttribute("cn", rolePath.getName()));
}
else if (path instanceof DomainPath) {
DomainPath domPath = (DomainPath)path;
attrs.add(new LDAPAttribute("cn",domPath.getName()));
try {
attrs.add(new LDAPAttribute("aliasedObjectName",getFullDN(domPath.getItemPath())));
String objectclass_values[] = { "alias", "aliasObject" };
attrs.add(new LDAPAttribute("objectclass",objectclass_values));
} catch (ObjectNotFound e) { // no entity - is a context
attrs.add(new LDAPAttribute("objectclass","cristalcontext"));
}
}
else if (path instanceof ItemPath) {
ItemPath itemPath = (ItemPath)path;
attrs.add(new LDAPAttribute("cn", itemPath.getUUID().toString()));
if (itemPath.getIOR() != null)
attrs.add(new LDAPAttribute("ior", Gateway.getORB().object_to_string(itemPath.getIOR())));
if (path instanceof AgentPath) {
AgentPath agentPath = (AgentPath)path;
attrs.add(new LDAPAttribute("objectclass","cristalagent"));
String agentName = agentPath.getAgentName();
if (agentName != null && agentName.length() > 0)
attrs.add(new LDAPAttribute("uid", agentName));
else
throw new ObjectCannotBeUpdated("Cannot create agent. No userId specified");
String agentPass = agentPath.getPassword();
if (agentPass != null && agentPass.length() > 0)
try {
attrs.add(new LDAPAttribute("userPassword", AgentPath.generateUserPassword(agentPass, "SHA")));
} catch (NoSuchAlgorithmException ex) {
throw new ObjectCannotBeUpdated("Cryptographic libraries for password hashing not found.");
}
else
throw new ObjectCannotBeUpdated("Cannot create agent. No password given");
}
else {
attrs.add(new LDAPAttribute("objectclass","cristalentity"));
}
}
return attrs;
}
//Creates a cristalRole
//CristalRole is-a specialized CristalContext which contains multi-valued uniqueMember attribute pointing to cristalagents
@Override
public RolePath createRole(RolePath rolePath)
throws ObjectAlreadyExists, ObjectCannotBeUpdated
{
// create the role
String roleDN = getFullDN(rolePath);
LDAPEntry roleNode;
try
{
roleNode = LDAPLookupUtils.getEntry(mLDAPAuth.getAuthObject(), getFullDN(rolePath));
throw new ObjectAlreadyExists();
} catch (ObjectNotFound ex) { }
//create CristalRole if it does not exist
roleNode = new LDAPEntry(roleDN, createAttributeSet(rolePath));
try {
LDAPLookupUtils.addEntry(mLDAPAuth.getAuthObject(),roleNode);
} catch (LDAPException e) {
throw new ObjectCannotBeUpdated(e.getLDAPErrorMessage());
}
return rolePath;
}
public void deleteRole(RolePath role) throws ObjectNotFound, ObjectCannotBeUpdated {
try {
LDAPLookupUtils.delete(mLDAPAuth.getAuthObject(), getFullDN(role));
} catch (LDAPException ex) {
throw new ObjectCannotBeUpdated("Could not remove role");
}
}
@Override
public void addRole(AgentPath agent, RolePath role)
throws ObjectCannotBeUpdated, ObjectNotFound
{
LDAPEntry roleEntry = LDAPLookupUtils.getEntry(mLDAPAuth.getAuthObject(), getFullDN(role));
//add memberDN to uniqueMember if it is not yet a member
if (!LDAPLookupUtils.existsAttributeValue(roleEntry, "uniqueMember", getFullDN(agent)))
LDAPLookupUtils.addAttributeValue(mLDAPAuth.getAuthObject(), roleEntry, "uniqueMember", getFullDN(agent));
else
throw new ObjectCannotBeUpdated("Agent " + agent.getAgentName() + " already has role " + role.getName());
}
@Override
public void removeRole(AgentPath agent, RolePath role)
throws ObjectCannotBeUpdated, ObjectNotFound
{
LDAPEntry roleEntry = LDAPLookupUtils.getEntry(mLDAPAuth.getAuthObject(), getFullDN(role));
if (LDAPLookupUtils.existsAttributeValue(roleEntry, "uniqueMember", getFullDN(agent)))
LDAPLookupUtils.removeAttributeValue(mLDAPAuth.getAuthObject(), roleEntry, "uniqueMember", getFullDN(agent));
else
throw new ObjectCannotBeUpdated("Agent did not have that role");
}
@Override
public boolean hasRole(AgentPath agent, RolePath role) {
String filter = "(&(objectclass=cristalrole)(uniqueMember="+getFullDN(agent)+")(cn="+role.getName()+"))";
LDAPSearchConstraints searchCons = new LDAPSearchConstraints();
searchCons.setBatchSize(0);
searchCons.setDereference(LDAPSearchConstraints.DEREF_NEVER );
return search(mRolePath,LDAPConnection.SCOPE_SUB,filter,searchCons).hasNext();
}
@Override
public AgentPath[] getAgents(RolePath role)
throws ObjectNotFound
{
//get the roleDN entry, and its uniqueMember entry pointing to
LDAPEntry roleEntry;
try {
roleEntry = LDAPLookupUtils.getEntry(mLDAPAuth.getAuthObject(), getFullDN(role));
} catch (ObjectNotFound e) {
throw new ObjectNotFound("Role does not exist");
}
String[] res = LDAPLookupUtils.getAllAttributeValues(roleEntry,"uniqueMember");
ArrayList agents = new ArrayList();
for (String userDN : res) {
try {
LDAPEntry userEntry = LDAPLookupUtils.getEntry(mLDAPAuth.getAuthObject(), userDN);
AgentPath path = (AgentPath)nodeToPath(userEntry);
agents.add(path);
} catch (ObjectNotFound ex) {
Logger.error("Agent "+userDN+" does not exist");
} catch (InvalidItemPathException ex) {
Logger.error("Agent "+userDN+" is not a valid entity");
}
}
AgentPath[] usersList = new AgentPath[0];
usersList = agents.toArray(usersList);
return usersList;
}
//returns the role/s of a user
@Override
public RolePath[] getRoles(AgentPath agentPath)
{
//search the mDomainPath tree uniqueMember=userDN
//filter = objectclass=cristalrole AND uniqueMember=userDN
String filter = "(&(objectclass=cristalrole)(uniqueMember="+getFullDN(agentPath)+"))";
LDAPSearchConstraints searchCons = new LDAPSearchConstraints();
searchCons.setBatchSize(0);
searchCons.setDereference(LDAPSearchConstraints.DEREF_NEVER );
Iterator> roles = search(mRolePath,LDAPConnection.SCOPE_SUB,filter,searchCons);
ArrayList roleList = new ArrayList();
while(roles.hasNext())
{
RolePath path = (RolePath) roles.next();
roleList.add(path);
}
RolePath[] roleArr = new RolePath[roleList.size()];
roleArr = roleList.toArray(roleArr);
return roleArr;
}
/**
* Utility for looking up a login name
*
* @param ld
* @param agentName
* @param baseDN
* @return
* @throws ObjectNotFound
*/
@Override
public AgentPath getAgentPath(String agentName) throws ObjectNotFound
{
//search to get the userDN equivalent of the userID
LDAPSearchConstraints searchCons = new LDAPSearchConstraints();
searchCons.setBatchSize(0);
searchCons.setDereference(LDAPSearchConstraints.DEREF_NEVER );
String filter = "(&(objectclass=cristalagent)(uid="+agentName+"))";
Iterator res = search(mItemTypeRoot,LDAPConnection.SCOPE_SUB,filter,searchCons);
if (!res.hasNext())
throw new ObjectNotFound("Agent not found: "+agentName);
Path result = res.next();
if (result instanceof AgentPath)
return (AgentPath)result;
else
throw new ObjectNotFound("Entry was not an Agent");
}
@Override
public RolePath getRolePath(String roleName) throws ObjectNotFound
{
LDAPSearchConstraints searchCons = new LDAPSearchConstraints();
searchCons.setBatchSize(0);
searchCons.setDereference(LDAPSearchConstraints.DEREF_NEVER );
String filter = "(&(objectclass=cristalrole)(cn="+roleName+"))";
Iterator res = search(mRolePath,LDAPConnection.SCOPE_SUB,filter,searchCons);
if (!res.hasNext())
throw new ObjectNotFound("Role not found");
Path result = res.next();
if (result instanceof RolePath)
return (RolePath)result;
else
throw new ObjectNotFound("Entry was not a Role");
}
@Override
public void setHasJobList(RolePath role, boolean hasJobList) throws ObjectNotFound, ObjectCannotBeUpdated {
// get entry
LDAPEntry roleEntry;
try {
roleEntry = LDAPLookupUtils.getEntry(mLDAPAuth.getAuthObject(), getFullDN(role));
} catch (ObjectNotFound e) {
throw new ObjectNotFound("Role does not exist");
}
// set attribute
LDAPLookupUtils.setAttributeValue(mLDAPAuth.getAuthObject(), roleEntry, "jobList", hasJobList?"TRUE":"FALSE");
}
@Override
public void setAgentPassword(AgentPath agent, String newPassword) throws ObjectNotFound, ObjectCannotBeUpdated, NoSuchAlgorithmException {
String encPasswd = AgentPath.generateUserPassword(newPassword, "SHA");
LDAPEntry agentEntry;
try {
agentEntry = LDAPLookupUtils.getEntry(mLDAPAuth.getAuthObject(), getFullDN(agent));
} catch (ObjectNotFound e) {
throw new ObjectNotFound("Agent "+agent.getAgentName()+" does not exist");
}
LDAPLookupUtils.setAttributeValue(mLDAPAuth.getAuthObject(), agentEntry, "userPassword", encPasswd);
}
@Override
public String getAgentName(AgentPath agentPath)
throws ObjectNotFound {
LDAPEntry agentEntry = LDAPLookupUtils.getEntry(mLDAPAuth.getAuthObject(), getFullDN(agentPath));
return LDAPLookupUtils.getFirstAttributeValue(agentEntry,"uid");
}
}