| | |
| | | */ |
| | | package org.opends.server.admin.client.ldap; |
| | | |
| | | |
| | | |
| | | import java.util.Collection; |
| | | import java.util.Hashtable; |
| | | import java.util.LinkedList; |
| | |
| | | import javax.naming.ldap.LdapName; |
| | | import javax.naming.ldap.Rdn; |
| | | |
| | | import org.opends.admin.ads.util.BlindTrustManager; |
| | | import org.opends.admin.ads.util.ConnectionUtils; |
| | | import org.opends.admin.ads.util.TrustedSocketFactory; |
| | | import org.opends.server.admin.client.AuthenticationException; |
| | | import org.opends.server.admin.client.AuthenticationNotSupportedException; |
| | | import org.opends.server.admin.client.CommunicationException; |
| | | import org.opends.server.schema.SchemaConstants; |
| | | |
| | | |
| | | |
| | | /** |
| | | * An LDAP connection adaptor which maps LDAP requests onto an |
| | | * underlying JNDI connection context. |
| | | * An LDAP connection adaptor which maps LDAP requests onto an underlying JNDI |
| | | * connection context. |
| | | */ |
| | | public final class JNDIDirContextAdaptor extends LDAPConnection { |
| | | |
| | | /** |
| | | * Adapts the provided JNDI <code>DirContext</code>. |
| | | * |
| | | * @param dirContext |
| | | * The JNDI connection. |
| | | * @return Returns a new JNDI connection adaptor. |
| | | */ |
| | | public static JNDIDirContextAdaptor adapt(DirContext dirContext) { |
| | | return new JNDIDirContextAdaptor(dirContext); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Creates a new JNDI connection adaptor by performing a simple bind |
| | | * operation to the specified LDAP server. |
| | | * |
| | | * @param host |
| | | * The host. |
| | | * @param port |
| | | * The port. |
| | | * @param name |
| | | * The LDAP bind DN. |
| | | * @param password |
| | | * The LDAP bind password. |
| | | * @return Returns a new JNDI connection adaptor. |
| | | * @throws CommunicationException |
| | | * If the client cannot contact the server due to an |
| | | * underlying communication problem. |
| | | * @throws AuthenticationNotSupportedException |
| | | * If the server does not support simple authentication. |
| | | * @throws AuthenticationException |
| | | * If authentication failed for some reason, usually due |
| | | * to invalid credentials. |
| | | */ |
| | | public static JNDIDirContextAdaptor simpleBind(String host, int port, |
| | | String name, String password) throws CommunicationException, |
| | | AuthenticationNotSupportedException, AuthenticationException { |
| | | Hashtable<String, Object> env = new Hashtable<String, Object>(); |
| | | env |
| | | .put(Context.INITIAL_CONTEXT_FACTORY, |
| | | "com.sun.jndi.ldap.LdapCtxFactory"); |
| | | String hostname = ConnectionUtils.getHostNameForLdapUrl(host) ; |
| | | env.put(Context.PROVIDER_URL, "ldap://" + hostname + ":" + port); |
| | | env.put(Context.SECURITY_PRINCIPAL, name); |
| | | env.put(Context.SECURITY_CREDENTIALS, password); |
| | | |
| | | DirContext ctx; |
| | | try { |
| | | ctx = new InitialLdapContext(env, null); |
| | | } catch (javax.naming.CommunicationException e) { |
| | | throw new CommunicationException(e); |
| | | } catch (javax.naming.AuthenticationException e) { |
| | | throw new AuthenticationException(e); |
| | | } catch (javax.naming.AuthenticationNotSupportedException e) { |
| | | throw new AuthenticationNotSupportedException(e); |
| | | } catch (NamingException e) { |
| | | // Assume some kind of communication problem. |
| | | throw new CommunicationException(e); |
| | | /** |
| | | * Adapts the provided JNDI <code>DirContext</code>. |
| | | * |
| | | * @param dirContext |
| | | * The JNDI connection. |
| | | * @return Returns a new JNDI connection adaptor. |
| | | */ |
| | | public static JNDIDirContextAdaptor adapt(DirContext dirContext) { |
| | | return new JNDIDirContextAdaptor(dirContext); |
| | | } |
| | | |
| | | return new JNDIDirContextAdaptor(ctx); |
| | | } |
| | | /** |
| | | * Creates a new JNDI connection adaptor by performing a simple bind |
| | | * operation to the specified LDAP server. |
| | | * |
| | | * @param host |
| | | * The host. |
| | | * @param port |
| | | * The port. |
| | | * @param name |
| | | * The LDAP bind DN. |
| | | * @param password |
| | | * The LDAP bind password. |
| | | * @return Returns a new JNDI connection adaptor. |
| | | * @throws CommunicationException |
| | | * If the client cannot contact the server due to an underlying |
| | | * communication problem. |
| | | * @throws AuthenticationNotSupportedException |
| | | * If the server does not support simple authentication. |
| | | * @throws AuthenticationException |
| | | * If authentication failed for some reason, usually due to |
| | | * invalid credentials. |
| | | */ |
| | | public static JNDIDirContextAdaptor simpleBind(String host, int port, String name, String password) |
| | | throws CommunicationException, AuthenticationNotSupportedException, AuthenticationException { |
| | | Hashtable<String, Object> env = new Hashtable<String, Object>(); |
| | | env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); |
| | | String hostname = ConnectionUtils.getHostNameForLdapUrl(host); |
| | | env.put(Context.PROVIDER_URL, "ldap://" + hostname + ":" + port); |
| | | env.put(Context.SECURITY_PRINCIPAL, name); |
| | | env.put(Context.SECURITY_CREDENTIALS, password); |
| | | |
| | | /** |
| | | * Creates a new JNDI connection adaptor by performing a simple bind |
| | | * operation to the specified LDAP server. |
| | | * |
| | | * @param host |
| | | * The host. |
| | | * @param port |
| | | * The port. |
| | | * @param name |
| | | * The LDAP bind DN. |
| | | * @param password |
| | | * The LDAP bind password. |
| | | * @return Returns a new JNDI connection adaptor. |
| | | * @throws CommunicationException |
| | | * If the client cannot contact the server due to an |
| | | * underlying communication problem. |
| | | * @throws AuthenticationNotSupportedException |
| | | * If the server does not support simple authentication. |
| | | * @throws AuthenticationException |
| | | * If authentication failed for some reason, usually due |
| | | * to invalid credentials. |
| | | */ |
| | | public static JNDIDirContextAdaptor simpleSSLBind(String host, int port, |
| | | String name, String password) throws CommunicationException, |
| | | AuthenticationNotSupportedException, AuthenticationException { |
| | | Hashtable<String, Object> env = new Hashtable<String, Object>(); |
| | | env.put(Context.INITIAL_CONTEXT_FACTORY, |
| | | "com.sun.jndi.ldap.LdapCtxFactory"); |
| | | String hostname = ConnectionUtils.getHostNameForLdapUrl(host) ; |
| | | env.put(Context.PROVIDER_URL, "ldaps://" + hostname + ":" + port); |
| | | env.put(Context.SECURITY_PRINCIPAL, name); |
| | | env.put(Context.SECURITY_CREDENTIALS, password); |
| | | env.put(Context.SECURITY_AUTHENTICATION, "simple"); |
| | | // Specify SSL |
| | | env.put(Context.SECURITY_PROTOCOL, "ssl"); |
| | | env.put("java.naming.ldap.factory.socket", |
| | | org.opends.admin.ads.util.TrustedSocketFactory.class.getName()); |
| | | TrustedSocketFactory.setCurrentThreadTrustManager(new BlindTrustManager(), |
| | | null); |
| | | DirContext ctx; |
| | | try { |
| | | ctx = new InitialLdapContext(env, null); |
| | | } catch (javax.naming.CommunicationException e) { |
| | | throw new CommunicationException(e); |
| | | } catch (javax.naming.AuthenticationException e) { |
| | | throw new AuthenticationException(e); |
| | | } catch (javax.naming.AuthenticationNotSupportedException e) { |
| | | throw new AuthenticationNotSupportedException(e); |
| | | } catch (NamingException e) { |
| | | // Assume some kind of communication problem. |
| | | throw new CommunicationException(e); |
| | | } |
| | | |
| | | return new JNDIDirContextAdaptor(ctx); |
| | | } |
| | | |
| | | |
| | | // The JNDI connection context. |
| | | private final DirContext dirContext; |
| | | |
| | | |
| | | |
| | | // Create a new JNDI connection adaptor using the provider JNDI |
| | | // DirContext. |
| | | private JNDIDirContextAdaptor(DirContext dirContext) { |
| | | this.dirContext = dirContext; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void createEntry(LdapName dn, Attributes attributes) |
| | | throws NamingException { |
| | | dirContext.createSubcontext(dn, attributes).close(); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void deleteSubtree(LdapName dn) throws NamingException { |
| | | // Delete the children first. |
| | | for (LdapName child : listEntries(dn, null)) { |
| | | deleteSubtree(child); |
| | | } |
| | | |
| | | // Delete the named entry. |
| | | dirContext.destroySubcontext(dn); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean entryExists(LdapName dn) throws NamingException { |
| | | boolean entryExists = false; |
| | | String filter = "(objectClass=*)"; |
| | | SearchControls controls = new SearchControls(); |
| | | controls.setSearchScope(SearchControls.OBJECT_SCOPE); |
| | | controls |
| | | .setReturningAttributes(new String[] { SchemaConstants.NO_ATTRIBUTES }); |
| | | try { |
| | | NamingEnumeration<SearchResult> results = dirContext.search(dn, filter, |
| | | controls); |
| | | try |
| | | { |
| | | while (results.hasMore()) { |
| | | // To avoid having a systematic abandon in the server. |
| | | results.next(); |
| | | entryExists = true; |
| | | DirContext ctx; |
| | | try { |
| | | ctx = new InitialLdapContext(env, null); |
| | | } catch (javax.naming.CommunicationException e) { |
| | | throw new CommunicationException(e); |
| | | } catch (javax.naming.AuthenticationException e) { |
| | | throw new AuthenticationException(e); |
| | | } catch (javax.naming.AuthenticationNotSupportedException e) { |
| | | throw new AuthenticationNotSupportedException(e); |
| | | } catch (NamingException e) { |
| | | // Assume some kind of communication problem. |
| | | throw new CommunicationException(e); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | results.close(); |
| | | } |
| | | } catch (NameNotFoundException e) { |
| | | // Fall through - entry not found. |
| | | } |
| | | return entryExists; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public Collection<LdapName> listEntries(LdapName dn, String filter) |
| | | throws NamingException { |
| | | if (filter == null) { |
| | | filter = "(objectClass=*)"; |
| | | return new JNDIDirContextAdaptor(ctx); |
| | | } |
| | | |
| | | SearchControls controls = new SearchControls(); |
| | | controls.setSearchScope(SearchControls.ONELEVEL_SCOPE); |
| | | /** |
| | | * Creates a new JNDI connection adaptor by performing a simple bind |
| | | * operation to the specified LDAP server. |
| | | * |
| | | * @param host |
| | | * The host. |
| | | * @param port |
| | | * The port. |
| | | * @param name |
| | | * The LDAP bind DN. |
| | | * @param password |
| | | * The LDAP bind password. |
| | | * @return Returns a new JNDI connection adaptor. |
| | | * @throws CommunicationException |
| | | * If the client cannot contact the server due to an underlying |
| | | * communication problem. |
| | | * @throws AuthenticationNotSupportedException |
| | | * If the server does not support simple authentication. |
| | | * @throws AuthenticationException |
| | | * If authentication failed for some reason, usually due to |
| | | * invalid credentials. |
| | | */ |
| | | public static JNDIDirContextAdaptor simpleSSLBind(String host, int port, String name, String password) |
| | | throws CommunicationException, AuthenticationNotSupportedException, AuthenticationException { |
| | | Hashtable<String, Object> env = new Hashtable<String, Object>(); |
| | | env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); |
| | | String hostname = ConnectionUtils.getHostNameForLdapUrl(host); |
| | | env.put(Context.PROVIDER_URL, "ldaps://" + hostname + ":" + port); |
| | | env.put(Context.SECURITY_PRINCIPAL, name); |
| | | env.put(Context.SECURITY_CREDENTIALS, password); |
| | | env.put(Context.SECURITY_AUTHENTICATION, "simple"); |
| | | // Specify SSL |
| | | env.put(Context.SECURITY_PROTOCOL, "ssl"); |
| | | env.put("java.naming.ldap.factory.socket", org.opends.admin.ads.util.TrustedSocketFactory.class.getName()); |
| | | TrustedSocketFactory.setCurrentThreadTrustManager(new BlindTrustManager(), null); |
| | | DirContext ctx; |
| | | try { |
| | | ctx = new InitialLdapContext(env, null); |
| | | } catch (javax.naming.CommunicationException e) { |
| | | throw new CommunicationException(e); |
| | | } catch (javax.naming.AuthenticationException e) { |
| | | throw new AuthenticationException(e); |
| | | } catch (javax.naming.AuthenticationNotSupportedException e) { |
| | | throw new AuthenticationNotSupportedException(e); |
| | | } catch (NamingException e) { |
| | | // Assume some kind of communication problem. |
| | | throw new CommunicationException(e); |
| | | } |
| | | |
| | | List<LdapName> children = new LinkedList<LdapName>(); |
| | | NamingEnumeration<SearchResult> results = dirContext.search(dn, filter, |
| | | controls); |
| | | try |
| | | { |
| | | while (results.hasMore()) { |
| | | SearchResult sr = results.next(); |
| | | LdapName child = new LdapName(dn.getRdns()); |
| | | child.add(new Rdn(sr.getName())); |
| | | children.add(child); |
| | | } |
| | | } |
| | | finally |
| | | { |
| | | results.close(); |
| | | return new JNDIDirContextAdaptor(ctx); |
| | | } |
| | | |
| | | return children; |
| | | } |
| | | // The JNDI connection context. |
| | | private final DirContext dirContext; |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void modifyEntry(LdapName dn, Attributes mods) throws NamingException { |
| | | ModificationItem[] modList = new ModificationItem[mods.size()]; |
| | | NamingEnumeration<? extends Attribute> ne = mods.getAll(); |
| | | for (int i = 0; ne.hasMore(); i++) { |
| | | ModificationItem modItem = new ModificationItem( |
| | | DirContext.REPLACE_ATTRIBUTE, ne.next()); |
| | | modList[i] = modItem; |
| | | // Create a new JNDI connection adaptor using the provider JNDI |
| | | // DirContext. |
| | | private JNDIDirContextAdaptor(DirContext dirContext) { |
| | | this.dirContext = dirContext; |
| | | } |
| | | dirContext.modifyAttributes(dn, modList); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public Attributes readEntry(LdapName dn, Collection<String> attrIds) |
| | | throws NamingException { |
| | | String[] attrIdList = attrIds.toArray(new String[attrIds.size()]); |
| | | return dirContext.getAttributes(dn, attrIdList); |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void unbind() { |
| | | try { |
| | | dirContext.close(); |
| | | } catch (NamingException e) { |
| | | // nothing to do |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void createEntry(LdapName dn, Attributes attributes) throws NamingException { |
| | | dirContext.createSubcontext(dn, attributes).close(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void deleteSubtree(LdapName dn) throws NamingException { |
| | | // Delete the children first. |
| | | for (LdapName child : listEntries(dn, null)) { |
| | | deleteSubtree(child); |
| | | } |
| | | |
| | | // Delete the named entry. |
| | | dirContext.destroySubcontext(dn); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public boolean entryExists(LdapName dn) throws NamingException { |
| | | boolean entryExists = false; |
| | | String filter = "(objectClass=*)"; |
| | | SearchControls controls = new SearchControls(); |
| | | controls.setSearchScope(SearchControls.OBJECT_SCOPE); |
| | | controls.setReturningAttributes(new String[] { SchemaConstants.NO_ATTRIBUTES }); |
| | | try { |
| | | NamingEnumeration<SearchResult> results = dirContext.search(dn, filter, controls); |
| | | try { |
| | | while (results.hasMore()) { |
| | | // To avoid having a systematic abandon in the server. |
| | | results.next(); |
| | | entryExists = true; |
| | | } |
| | | } finally { |
| | | results.close(); |
| | | } |
| | | } catch (NameNotFoundException e) { |
| | | // Fall through - entry not found. |
| | | } |
| | | return entryExists; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public Collection<LdapName> listEntries(LdapName dn, String filter) throws NamingException { |
| | | if (filter == null) { |
| | | filter = "(objectClass=*)"; |
| | | } |
| | | |
| | | SearchControls controls = new SearchControls(); |
| | | controls.setSearchScope(SearchControls.ONELEVEL_SCOPE); |
| | | |
| | | List<LdapName> children = new LinkedList<LdapName>(); |
| | | NamingEnumeration<SearchResult> results = dirContext.search(dn, filter, controls); |
| | | try { |
| | | while (results.hasMore()) { |
| | | SearchResult sr = results.next(); |
| | | LdapName child = new LdapName(dn.getRdns()); |
| | | child.add(new Rdn(sr.getName())); |
| | | children.add(child); |
| | | } |
| | | } finally { |
| | | results.close(); |
| | | } |
| | | |
| | | return children; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void modifyEntry(LdapName dn, Attributes mods) throws NamingException { |
| | | ModificationItem[] modList = new ModificationItem[mods.size()]; |
| | | NamingEnumeration<? extends Attribute> ne = mods.getAll(); |
| | | for (int i = 0; ne.hasMore(); i++) { |
| | | ModificationItem modItem = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, ne.next()); |
| | | modList[i] = modItem; |
| | | } |
| | | dirContext.modifyAttributes(dn, modList); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public Attributes readEntry(LdapName dn, Collection<String> attrIds) throws NamingException { |
| | | String[] attrIdList = attrIds.toArray(new String[attrIds.size()]); |
| | | return dirContext.getAttributes(dn, attrIdList); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public void unbind() { |
| | | try { |
| | | dirContext.close(); |
| | | } catch (NamingException e) { |
| | | // nothing to do |
| | | } |
| | | } |
| | | } |