package org.ovirt.engine.core.bll.adbroker;
import java.net.URI;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import org.ovirt.engine.core.compat.LogCompat;
import org.ovirt.engine.core.compat.LogFactoryCompat;
/**
* Anonymous query an LDAP server to get the rootDSE object. rootDSE provides data on the directory server. This query
* is needed in order to fetch the base DN and the domain functionality level and does not require authentication
*/
public class GetRootDSE {
private URI ldapURI;
private Attributes attributes;
private final static LogCompat log = LogFactoryCompat.getLog(GetRootDSE.class);
public GetRootDSE(URI ldapURI) {
this.ldapURI = ldapURI;
}
/**
* Perform an LDAP query to the inner LDAP server to fetch the rootDSE table.
*
* @return EnumMap with the attributes as key and their string values.
*/
private void execute(LdapProviderType ldapProviderType, String domain) {
Hashtable<String, String> env = new Hashtable<String, String>();
initContextVariables(env);
Attributes results = null;
DirContext ctx = null;
try {
ctx = createContext(env);
LdapQueryData ldapQueryData = new LdapQueryDataImpl();
ldapQueryData.setLdapQueryType(LdapQueryType.rootDSE);
ldapQueryData.setDomain(domain);
LdapQueryExecution queryExecution =
LdapQueryExecutionBuilderImpl.getInstance().build(ldapProviderType, ldapQueryData);
SearchControls searchControls = new SearchControls();
searchControls.setReturningAttributes(queryExecution.getReturningAttributes());
searchControls.setSearchScope(queryExecution.getSearchScope());
NamingEnumeration<SearchResult> search =
ctx.search(queryExecution.getBaseDN(), queryExecution.getFilter(), searchControls);
try {
// build a map of attributes and their string values
results = search.next().getAttributes();
} finally {
// make sure we close this search, otherwise the ldap connection will stick until GC kills it
search.close();
}
} catch (NamingException e) {
log.errorFormat("Failed to query rootDSE for LDAP server {0} due to {1}", ldapURI, e.getMessage());
} finally {
closeContext(ctx);
}
attributes = results;
}
/**
* Bullet proof close of a director context. Possible exceptions are caught and logged.
*
* @param ctx
* a directory context, can be null
*/
private void closeContext(final DirContext ctx) {
log.trace("closing directory context");
try {
if (ctx != null) {
ctx.close();
}
} catch (NamingException e) {
// ignore, but log
log.warn("Could not close directory context", e);
}
}
protected DirContext createContext(Hashtable<String, String> env) throws NamingException {
return new InitialDirContext(env);
}
public LdapProviderType retrieveLdapProviderType(String domain) {
LdapProviderType retVal = LdapProviderType.general;
Attributes attributes = getDomainAttributes(LdapProviderType.general, domain);
if (attributes != null) {
if (attributes.get(ADRootDSEAttributes.domainControllerFunctionality.name()) != null) {
retVal = LdapProviderType.activeDirectory;
} else if (attributes.get(RHDSRootDSEAttributes.netscapemdsuffix.name()) != null) {
retVal = LdapProviderType.rhds;
} else if (attributes.get(IPARootDSEAttributes.namingContexts.name()) != null) {
retVal = LdapProviderType.ipa;
}
}
return retVal;
}
public Attributes getDomainAttributes(LdapProviderType general, String domain) {
if (attributes == null) {
execute(general, domain);
}
return attributes;
}
protected URI getLdapURI() {
return ldapURI;
}
private void initContextVariables(Hashtable<String, String> env) {
env.put(Context.SECURITY_AUTHENTICATION, "SIMPLE");
env.put(Context.SECURITY_PRINCIPAL, "");
env.put(Context.SECURITY_CREDENTIALS, "");
env.put(Context.REFERRAL, "follow");
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, getLdapURI().toString());
}
}