You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by el...@apache.org on 2008/08/05 00:38:09 UTC

svn commit: r682532 - in /directory/apacheds/branches/bigbang: protocol-newldap/src/main/java/org/apache/directory/server/newldap/ protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/ protocol-newldap/src/main/java/org/apache/di...

Author: elecharny
Date: Mon Aug  4 15:38:08 2008
New Revision: 682532

URL: http://svn.apache.org/viewvc?rev=682532&view=rev
Log:
Fixed DIGEST-MD5

Modified:
    directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/LdapSession.java
    directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/NewBindHandler.java
    directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/AbstractSaslCallbackHandler.java
    directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/SaslConstants.java
    directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/SaslFilter.java
    directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/cramMD5/CramMd5CallbackHandler.java
    directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/cramMD5/CramMd5MechanismHandler.java
    directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/digestMD5/DigestMd5CallbackHandler.java
    directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/digestMD5/DigestMd5MechanismHandler.java
    directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/ntlm/NtlmMechanismHandler.java
    directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/ntlm/NtlmSaslServer.java
    directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/plain/PlainMechanismHandler.java
    directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/plain/PlainSaslServer.java
    directory/apacheds/branches/bigbang/server-unit/src/test/java/org/apache/directory/server/SaslBindITest.java
    directory/apacheds/branches/bigbang/server-unit/src/test/java/org/apache/directory/server/operations/bind/SaslBindITest.java

Modified: directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/LdapSession.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/LdapSession.java?rev=682532&r1=682531&r2=682532&view=diff
==============================================================================
--- directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/LdapSession.java (original)
+++ directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/LdapSession.java Mon Aug  4 15:38:08 2008
@@ -308,27 +308,39 @@
 
 
     /**
-     *  @return The SASL properties
-     */
-    public Map<String, Object> getSaslProperties()
-    {
-        return saslProperties;
-    }
-
-
-    /**
      * Add a Sasl property and value
      * 
      * @param property the property to add
      * @param value the value for this property
      */
-    public void putSaslProperties( String property, Object value )
+    public void putSaslProperty( String property, Object value )
     {
         saslProperties.put( property, value );
     }
     
     
     /**
+     * Get a Sasl property's value
+     * 
+     * @param property the property to get
+     * @return the associated value, or null if we don't have such a property
+     */
+    public Object getSaslProperty( String property )
+    {
+        return saslProperties.get( property );
+    }
+    
+    
+    /**
+     * Clear all the Sasl values stored into the Map
+     */
+    public void clearSaslProperties()
+    {
+        saslProperties.clear();
+    }
+    
+    
+    /**
      * Remove a property from the SaslProperty map
      *
      * @param property the property to remove

Modified: directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/NewBindHandler.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/NewBindHandler.java?rev=682532&r1=682531&r2=682532&view=diff
==============================================================================
--- directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/NewBindHandler.java (original)
+++ directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/NewBindHandler.java Mon Aug  4 15:38:08 2008
@@ -42,8 +42,10 @@
 import org.apache.directory.server.newldap.LdapSession;
 import org.apache.directory.server.newldap.handlers.bind.MechanismHandler;
 import org.apache.directory.server.newldap.handlers.bind.SaslConstants;
+import org.apache.directory.server.newldap.handlers.bind.SaslFilter;
 import org.apache.directory.server.protocol.shared.ServiceConfigurationException;
 import org.apache.directory.shared.ldap.constants.SchemaConstants;
+import org.apache.directory.shared.ldap.constants.SupportedSaslMechanisms;
 import org.apache.directory.shared.ldap.exception.LdapAuthenticationException;
 import org.apache.directory.shared.ldap.exception.LdapException;
 import org.apache.directory.shared.ldap.message.BindRequest;
@@ -53,6 +55,8 @@
 import org.apache.directory.shared.ldap.name.LdapDN;
 import org.apache.directory.shared.ldap.util.ExceptionUtils;
 import org.apache.directory.shared.ldap.util.StringTools;
+import org.apache.mina.common.IoFilterChain;
+import org.apache.mina.common.IoSession;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -207,6 +211,13 @@
     }
     
     
+    /**
+     * For challenge/response exchange, generate the challenge 
+     *
+     * @param ldapSession
+     * @param ss
+     * @param bindRequest
+     */
     private void generateSaslChallenge( LdapSession ldapSession, SaslServer ss, BindRequest bindRequest )
     {
         LdapResult result = bindRequest.getResultResponse().getLdapResult();
@@ -232,7 +243,7 @@
                      * so it will be returned in a SUCCESS message, after an LdapContext
                      * has been initialized for the client.
                      */
-                    ldapSession.getSaslProperties().put( SaslConstants.SASL_CREDS, tokenBytes );
+                    ldapSession.putSaslProperty( SaslConstants.SASL_CREDS, tokenBytes );
                 }
                 
                 // Return the successful response
@@ -254,7 +265,7 @@
                 ldapSession.setAuthPending();
                 
                 // Store the current mechanism, as the C/R is not finished
-                ldapSession.getSaslProperties().put( SaslConstants.SASL_MECH, bindRequest.getSaslMechanism() );
+                ldapSession.putSaslProperty( SaslConstants.SASL_MECH, bindRequest.getSaslMechanism() );
                 
                 // And write back the response
                 ldapSession.getIoSession().write( resp );
@@ -268,7 +279,7 @@
             result.setErrorMessage( se.getMessage() );
             
             // Reinitialize the state to Anonymous and clear the sasl properties
-            ldapSession.getSaslProperties().clear();
+            ldapSession.clearSaslProperties();
             ldapSession.setAnonymous();
             
             // Write back the error response
@@ -277,11 +288,14 @@
     }
     
     
+    /**
+     * Send back an AUTH-METH-NOT-SUPPORTED error message to the client
+     */
     private void sendAuthMethNotSupported( LdapSession ldapSession, BindRequest bindRequest )
     {
         // First, reinit the state to Anonymous, and clear the
         // saslProperty map
-        ldapSession.getSaslProperties().clear();
+        ldapSession.clearSaslProperties();
         ldapSession.setAnonymous();
         
         // And send the response to the client
@@ -296,16 +310,27 @@
     }
     
     
-    private void sendInvalidCredentials( LdapSession ldapSession, BindRequest bindRequest, SaslException se )
+    /**
+     * Send back an INVALID-CREDENTIAL error message to the user. If we have an exception
+     * as a third argument, then send back the associated message to the client. 
+     */
+    private void sendInvalidCredentials( LdapSession ldapSession, BindRequest bindRequest, Exception e )
     {
         LdapResult result = bindRequest.getResultResponse().getLdapResult();
         
-        LOG.error( se.getMessage() );
+        String message = "";
+        
+        if ( e != null )
+        {
+            message = e.getMessage();
+        }
+        
+        LOG.error( message );
         result.setResultCode( ResultCodeEnum.INVALID_CREDENTIALS );
-        result.setErrorMessage( se.getMessage() );
+        result.setErrorMessage( message );
         
         // Reinitialize the state to Anonymous and clear the sasl properties
-        ldapSession.getSaslProperties().clear();
+        ldapSession.clearSaslProperties();
         ldapSession.setAnonymous();
         
         // Write back the error response
@@ -313,6 +338,9 @@
     }
     
     
+    /**
+     * Send a SUCCESS message back to the client.
+     */
     private void sendBindSuccess( LdapSession ldapSession, BindRequest bindRequest, byte[] tokenBytes )
     {
         // Return the successful response
@@ -332,7 +360,12 @@
         }
         
         // Clean the SaslProperties, we don't need them anymore
-        ldapSession.getSaslProperties().clear();
+        // except the saslCreds and saslServer which will be used 
+        // by the DIGEST-MD5 mech.
+        ldapSession.removeSaslProperty( SaslConstants.SASL_MECH );
+        ldapSession.removeSaslProperty( SaslConstants.SASL_HOST );
+        ldapSession.removeSaslProperty( SaslConstants.SASL_AUTHENT_USER );
+        ldapSession.removeSaslProperty( SaslConstants.SASL_USER_BASE_DN );
 
         ldapSession.getIoSession().write( response );
         
@@ -345,7 +378,7 @@
         // First, check that we have the same mechanism
         String saslMechanism = bindRequest.getSaslMechanism();
         
-        if ( !ldapSession.getSaslProperties().get( SaslConstants.SASL_MECH ).equals( saslMechanism ) )
+        if ( !ldapSession.getSaslProperty( SaslConstants.SASL_MECH ).equals( saslMechanism ) )
         {
             sendAuthMethNotSupported( ldapSession, bindRequest );
             return;
@@ -384,13 +417,13 @@
                      * so it will be returned in a SUCCESS message, after an LdapContext
                      * has been initialized for the client.
                      */
-                    ldapSession.getSaslProperties().put( SaslConstants.SASL_CREDS, tokenBytes );
+                    ldapSession.putSaslProperty( SaslConstants.SASL_CREDS, tokenBytes );
                 }
                 
                 // Create the user's coreSession
                 try
                 {
-                    ServerEntry userEntry = (ServerEntry)ldapSession.getSaslProperties().get( SaslConstants.SASL_AUTHENT_USER );
+                    ServerEntry userEntry = (ServerEntry)ldapSession.getSaslProperty( SaslConstants.SASL_AUTHENT_USER );
                     
                     CoreSession userSession = ds.getSession( userEntry.getDn(), userEntry.get( SchemaConstants.USER_PASSWORD_AT ).getBytes(), saslMechanism, null );
                     
@@ -399,10 +432,30 @@
                     // Mark the user as authenticated
                     ldapSession.setAuthenticated();
                     
-                    // Clean the Sasl Properties so that we don't have the user password
-                    // stored in memory forever
-                    ldapSession.getSaslProperties().clear();
-                    
+                    /*
+                     * If the SASL mechanism is DIGEST-MD5 or GSSAPI, we insert a SASLFilter.
+                     */
+                    if ( saslMechanism.equals( SupportedSaslMechanisms.DIGEST_MD5 ) ||
+                         saslMechanism.equals( SupportedSaslMechanisms.GSSAPI ) )
+                    {
+                        LOG.debug( "Inserting SaslFilter to engage negotiated security layer." );
+                        IoSession ioSession = ldapSession.getIoSession();
+
+                        IoFilterChain chain = ioSession.getFilterChain();
+                        
+                        if ( !chain.contains( "SASL_FILTER" ) )
+                        {
+                            SaslServer saslServer = ( SaslServer ) ldapSession.getSaslProperty( SaslConstants.SASL_SERVER );
+                            chain.addBefore( "codec", "SASL_FILTER", new SaslFilter( saslServer ) );
+                        }
+
+                        /*
+                         * We disable the SASL security layer once, to write the outbound SUCCESS
+                         * message without SASL security layer processing.
+                         */
+                        ioSession.setAttribute( SaslFilter.DISABLE_SECURITY_LAYER_ONCE, Boolean.TRUE );
+                    }
+
                     // And send a Success response
                     sendBindSuccess( ldapSession, bindRequest, tokenBytes );
                 }
@@ -457,7 +510,7 @@
             ldapSession.setAnonymous();
             
             // Clean the sasl properties
-            ldapSession.getSaslProperties().clear();
+            ldapSession.clearSaslProperties();
             
             // Now we can continue as if the client was Anonymous from the beginning
         }
@@ -477,8 +530,13 @@
                 }
 
                 // Store the mechanism in the ldap session
-                ldapSession.getSaslProperties().put( SaslConstants.SASL_MECH, saslMechanism );
+                ldapSession.putSaslProperty( SaslConstants.SASL_MECH, saslMechanism );
                 
+
+                // Store the host in the ldap session
+                String saslHost = getLdapServer().getSaslHost();
+                ldapSession.putSaslProperty( SaslConstants.SASL_HOST, saslHost );
+
                 // Get the handler for this mechanism
                 MechanismHandler mechanismHandler = handlers.get( saslMechanism );
                 

Modified: directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/AbstractSaslCallbackHandler.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/AbstractSaslCallbackHandler.java?rev=682532&r1=682531&r2=682532&view=diff
==============================================================================
--- directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/AbstractSaslCallbackHandler.java (original)
+++ directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/AbstractSaslCallbackHandler.java Mon Aug  4 15:38:08 2008
@@ -21,7 +21,9 @@
 
 
 import org.apache.directory.server.constants.ServerDNConstants;
+import org.apache.directory.server.core.CoreSession;
 import org.apache.directory.server.core.DirectoryService;
+import org.apache.directory.server.newldap.LdapSession;
 import org.apache.directory.shared.ldap.constants.AuthenticationLevel;
 import org.apache.directory.shared.ldap.entry.EntryAttribute;
 import org.apache.directory.shared.ldap.exception.LdapException;
@@ -67,7 +69,13 @@
 
     private String username;
     private String realm;
+
+    /** The reference on the user ldap session */
+    protected LdapSession ldapSession;
     
+    /** The admin core session */
+    protected CoreSession adminSession;
+
     /** A reference on the DirectoryService instance */
     protected final DirectoryService directoryService;
     

Modified: directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/SaslConstants.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/SaslConstants.java?rev=682532&r1=682531&r2=682532&view=diff
==============================================================================
--- directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/SaslConstants.java (original)
+++ directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/SaslConstants.java Mon Aug  4 15:38:08 2008
@@ -67,4 +67,22 @@
      * A key constant for storing the evaluated credentials
      */
     public static final String SASL_CREDS = "saslCreds";
+
+
+    /**
+     * A key constant for storing the Quality Of Protection
+     */
+    public static final String SASL_QOP = "saslQop";
+    
+    
+    /**
+     * A key constant for storing the realm
+     */
+    public static final String SASL_REALM = "saslRealm";
+    
+    
+    /**
+     * A key constant representing the SASL IoFilter 
+     */
+    public static final String SASL_FILTER = "SASL_FILTER";
 }

Modified: directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/SaslFilter.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/SaslFilter.java?rev=682532&r1=682531&r2=682532&view=diff
==============================================================================
--- directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/SaslFilter.java (original)
+++ directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/SaslFilter.java Mon Aug  4 15:38:08 2008
@@ -58,7 +58,7 @@
      */
     public static final String DISABLE_SECURITY_LAYER_ONCE = SaslFilter.class.getName() + ".DisableSecurityLayerOnce";
 
-    private SaslServer context;
+    private SaslServer saslServer;
 
 
     /**
@@ -69,14 +69,14 @@
      *
      * @param context The initialized SASL context.
      */
-    public SaslFilter( SaslServer context )
+    public SaslFilter( SaslServer saslServer )
     {
-        if ( context == null )
+        if ( saslServer == null )
         {
             throw new IllegalStateException();
         }
 
-        this.context = context;
+        this.saslServer = saslServer;
     }
 
 
@@ -87,7 +87,7 @@
         /*
          * Unwrap the data for mechanisms that support QoP (DIGEST-MD5, GSSAPI).
          */
-        String qop = ( String ) context.getNegotiatedProperty( Sasl.QOP );
+        String qop = ( String ) saslServer.getNegotiatedProperty( Sasl.QOP );
         boolean hasSecurityLayer = ( qop != null && ( qop.equals( SaslQoP.QOP_AUTH_INT ) || qop.equals( SaslQoP.QOP_AUTH_CONF ) ) );
 
         if ( hasSecurityLayer )
@@ -101,7 +101,7 @@
             buf.get( bufferBytes );
 
             log.debug( "Will use SASL to unwrap received message of length:  {}", bufferLength );
-            byte[] token = context.unwrap( bufferBytes, 0, bufferBytes.length );
+            byte[] token = saslServer.unwrap( bufferBytes, 0, bufferBytes.length );
             nextFilter.messageReceived( session, ByteBuffer.wrap( token ) );
         }
         else
@@ -131,7 +131,7 @@
         /*
          * Wrap the data for mechanisms that support QoP (DIGEST-MD5, GSSAPI).
          */
-        String qop = ( String ) context.getNegotiatedProperty( Sasl.QOP );
+        String qop = ( String ) saslServer.getNegotiatedProperty( Sasl.QOP );
         boolean hasSecurityLayer = ( qop != null && ( qop.equals( SaslQoP.QOP_AUTH_INT ) || qop.equals( SaslQoP.QOP_AUTH_CONF ) ) );
 
         ByteBuffer saslLayerBuffer = null;
@@ -148,7 +148,7 @@
 
             log.debug( "Will use SASL to wrap message of length:  {}", bufferLength );
 
-            byte[] saslLayer = context.wrap( bufferBytes, 0, bufferBytes.length );
+            byte[] saslLayer = saslServer.wrap( bufferBytes, 0, bufferBytes.length );
 
             /*
              * Prepend 4 byte length.

Modified: directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/cramMD5/CramMd5CallbackHandler.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/cramMD5/CramMd5CallbackHandler.java?rev=682532&r1=682531&r2=682532&view=diff
==============================================================================
--- directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/cramMD5/CramMd5CallbackHandler.java (original)
+++ directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/cramMD5/CramMd5CallbackHandler.java Mon Aug  4 15:38:08 2008
@@ -55,10 +55,6 @@
 {
     private static final Logger LOG = LoggerFactory.getLogger( CramMd5CallbackHandler.class );
 
-    private LdapSession ldapSession;
-    
-    private CoreSession adminSession;
-
     private String bindDn;
     //private String userPassword;
 
@@ -87,7 +83,7 @@
             
             AttributeType passwordAT = adminSession.getDirectoryService().getRegistries().getAttributeTypeRegistry().lookup( SchemaConstants.USER_PASSWORD_AT );
             returningAttributes.add( new AttributeTypeOptions( passwordAT) );
-            bindDn = (String)ldapSession.getSaslProperties().get( SaslConstants.SASL_USER_BASE_DN );
+            bindDn = (String)ldapSession.getSaslProperty( SaslConstants.SASL_USER_BASE_DN );
             
             LdapDN baseDn = new LdapDN( bindDn );
 
@@ -105,7 +101,7 @@
             while ( cursor.next() )
             {
                 entry = cursor.get();
-                ldapSession.getSaslProperties().put( SaslConstants.SASL_AUTHENT_USER, entry );
+                ldapSession.putSaslProperty( SaslConstants.SASL_AUTHENT_USER, entry );
             }
 
             return entry.get( passwordAT );
@@ -124,7 +120,7 @@
             LOG.debug( "Converted username " + getUsername() + " to DN " + bindDn );
         }
 
-        ldapSession.getSaslProperties().put( Context.SECURITY_PRINCIPAL, bindDn );
+        ldapSession.putSaslProperty( Context.SECURITY_PRINCIPAL, bindDn );
 
         authorizeCB.setAuthorizedID( bindDn );
         authorizeCB.setAuthorized( true );

Modified: directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/cramMD5/CramMd5MechanismHandler.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/cramMD5/CramMd5MechanismHandler.java?rev=682532&r1=682531&r2=682532&view=diff
==============================================================================
--- directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/cramMD5/CramMd5MechanismHandler.java (original)
+++ directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/cramMD5/CramMd5MechanismHandler.java Mon Aug  4 15:38:08 2008
@@ -21,6 +21,7 @@
 
 
 import org.apache.directory.server.core.CoreSession;
+import org.apache.directory.server.newldap.LdapServer;
 import org.apache.directory.server.newldap.LdapSession;
 import org.apache.directory.server.newldap.handlers.bind.MechanismHandler;
 import org.apache.directory.server.newldap.handlers.bind.SaslConstants;
@@ -45,22 +46,21 @@
 {
     public SaslServer handleMechanism( LdapSession ldapSession, CoreSession adminSession, BindRequest bindRequest ) throws Exception
     {
-        SaslServer ss = (SaslServer)ldapSession.getSaslProperties().get( SaslConstants.SASL_SERVER );
+        SaslServer ss = (SaslServer)ldapSession.getSaslProperty( SaslConstants.SASL_SERVER );
 
         // TODO - don't use session properties anymore
         if ( ss == null )
         {
             String saslHost = ldapSession.getLdapServer().getSaslHost();
             String userBaseDn = ldapSession.getLdapServer().getSearchBaseDn();
-            ldapSession.getSaslProperties().put( SaslConstants.SASL_HOST, saslHost );
-            ldapSession.getSaslProperties().put( SaslConstants.SASL_USER_BASE_DN, userBaseDn );
-            
-
+            ldapSession.putSaslProperty( SaslConstants.SASL_HOST, saslHost );
+            ldapSession.putSaslProperty( SaslConstants.SASL_USER_BASE_DN, userBaseDn );
             Map<String, String> saslProps = new HashMap<String, String>();
+            
             CallbackHandler callbackHandler = new CramMd5CallbackHandler( ldapSession, adminSession, bindRequest );
 
             ss = Sasl.createSaslServer( SupportedSaslMechanisms.CRAM_MD5, SaslConstants.LDAP_PROTOCOL, saslHost, saslProps, callbackHandler );
-            ldapSession.putSaslProperties( SaslConstants.SASL_SERVER, ss );
+            ldapSession.putSaslProperty( SaslConstants.SASL_SERVER, ss );
         }
 
         return ss;

Modified: directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/digestMD5/DigestMd5CallbackHandler.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/digestMD5/DigestMd5CallbackHandler.java?rev=682532&r1=682531&r2=682532&view=diff
==============================================================================
--- directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/digestMD5/DigestMd5CallbackHandler.java (original)
+++ directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/digestMD5/DigestMd5CallbackHandler.java Mon Aug  4 15:38:08 2008
@@ -20,11 +20,25 @@
 package org.apache.directory.server.newldap.handlers.bind.digestMD5;
 
 
-import org.apache.directory.server.core.DirectoryService;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.directory.server.core.CoreSession;
+import org.apache.directory.server.core.entry.ClonedServerEntry;
+import org.apache.directory.server.core.filtering.EntryFilteringCursor;
+import org.apache.directory.server.newldap.LdapSession;
 import org.apache.directory.server.newldap.handlers.bind.AbstractSaslCallbackHandler;
-import org.apache.directory.shared.ldap.NotImplementedException;
+import org.apache.directory.server.newldap.handlers.bind.SaslConstants;
+import org.apache.directory.shared.ldap.constants.SchemaConstants;
 import org.apache.directory.shared.ldap.entry.EntryAttribute;
+import org.apache.directory.shared.ldap.filter.ExprNode;
+import org.apache.directory.shared.ldap.filter.FilterParser;
+import org.apache.directory.shared.ldap.filter.SearchScope;
+import org.apache.directory.shared.ldap.message.AliasDerefMode;
 import org.apache.directory.shared.ldap.message.BindRequest;
+import org.apache.directory.shared.ldap.name.LdapDN;
+import org.apache.directory.shared.ldap.schema.AttributeType;
+import org.apache.directory.shared.ldap.schema.AttributeTypeOptions;
 import org.apache.mina.common.IoSession;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -54,17 +68,51 @@
      * @param bindRequest the bind message
      * @param directoryService the directory service core
      */
-    public DigestMd5CallbackHandler( DirectoryService directoryService, BindRequest bindRequest )
+    public DigestMd5CallbackHandler( LdapSession ldapSession, CoreSession adminSession, BindRequest bindRequest )
     {
-        super( directoryService, bindRequest );
+        super( adminSession.getDirectoryService(), bindRequest );
+        this.ldapSession = ldapSession;
+        this.adminSession = adminSession;
     }
 
 
     // TODO - should return not be a byte[]
     protected EntryAttribute lookupPassword( String username, String realm )
     {
-        // TODO - Use realm with multi-realm support.
-        throw new NotImplementedException();
+        try
+        {
+            ExprNode filter = FilterParser.parse( "(uid=" + username + ")" );
+            Set<AttributeTypeOptions> returningAttributes = new HashSet<AttributeTypeOptions>();
+            
+            AttributeType passwordAT = adminSession.getDirectoryService().getRegistries().getAttributeTypeRegistry().lookup( SchemaConstants.USER_PASSWORD_AT );
+            returningAttributes.add( new AttributeTypeOptions( passwordAT) );
+            bindDn = (String)ldapSession.getSaslProperty( SaslConstants.SASL_USER_BASE_DN );
+            
+            LdapDN baseDn = new LdapDN( bindDn );
+
+            EntryFilteringCursor cursor = adminSession.search( 
+                baseDn, 
+                SearchScope.SUBTREE, 
+                filter, 
+                AliasDerefMode.DEREF_ALWAYS, 
+                returningAttributes );
+            
+            cursor.beforeFirst();
+            
+            ClonedServerEntry entry = null;
+            
+            while ( cursor.next() )
+            {
+                entry = cursor.get();
+                ldapSession.putSaslProperty( SaslConstants.SASL_AUTHENT_USER, entry );
+            }
+
+            return entry.get( passwordAT );
+        }
+        catch ( Exception e )
+        {
+            return null;
+        }
     }
 
 
@@ -75,7 +123,7 @@
             LOG.debug( "Converted username " + getUsername() + " to DN " + bindDn + " with password " + userPassword + "." );
         }
 
-        session.setAttribute( Context.SECURITY_PRINCIPAL, bindDn );
+        ldapSession.putSaslProperty( Context.SECURITY_PRINCIPAL, bindDn );
 
         authorizeCB.setAuthorizedID( bindDn );
         authorizeCB.setAuthorized( true );

Modified: directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/digestMD5/DigestMd5MechanismHandler.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/digestMD5/DigestMd5MechanismHandler.java?rev=682532&r1=682531&r2=682532&view=diff
==============================================================================
--- directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/digestMD5/DigestMd5MechanismHandler.java (original)
+++ directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/digestMD5/DigestMd5MechanismHandler.java Mon Aug  4 15:38:08 2008
@@ -21,6 +21,7 @@
 
 
 import org.apache.directory.server.core.CoreSession;
+import org.apache.directory.server.newldap.LdapServer;
 import org.apache.directory.server.newldap.LdapSession;
 import org.apache.directory.server.newldap.handlers.bind.MechanismHandler;
 import org.apache.directory.server.newldap.handlers.bind.SaslConstants;
@@ -30,6 +31,8 @@
 import javax.security.auth.callback.CallbackHandler;
 import javax.security.sasl.Sasl;
 import javax.security.sasl.SaslServer;
+
+import java.util.HashMap;
 import java.util.Map;
 
 
@@ -42,24 +45,55 @@
  */
 public class DigestMd5MechanismHandler implements MechanismHandler
 {
-    public SaslServer handleMechanism( LdapSession session, CoreSession adminSession, BindRequest bindRequest ) throws Exception
+    /**
+     * Create a list of all the configured realms.
+     * 
+     * @param ldapServer the LdapServer for which we want to get the realms
+     * @return a list of realms, separated by spaces
+     */
+    private String getActiveRealms( LdapServer ldapServer )
     {
-        SaslServer ss;
+        StringBuilder realms = new StringBuilder();
+        boolean isFirst = true;
 
-        if ( session.getIoSession().containsAttribute( SaslConstants.SASL_SERVER ) )
+        for ( String realm:ldapServer.getSaslRealms() )
         {
-            ss = ( SaslServer ) session.getIoSession().getAttribute( SaslConstants.SASL_SERVER );
+            if ( isFirst )
+            {
+                isFirst = false;
+            }
+            else
+            {
+                realms.append( ' ' );
+            }
+            
+            realms.append( realm );
         }
-        else
+
+        return realms.toString();
+    }
+
+
+    
+    public SaslServer handleMechanism( LdapSession ldapSession, CoreSession adminSession, BindRequest bindRequest ) throws Exception
+    {
+        SaslServer ss = (SaslServer)ldapSession.getSaslProperty( SaslConstants.SASL_SERVER );
+
+        if ( ss == null )
         {
-            String saslHost = ( String ) session.getIoSession().getAttribute( "saslHost" );
-            Map<String, String> saslProps = ( Map<String, String> ) session.getIoSession().getAttribute( "saslProps" );
+            String saslHost = ldapSession.getLdapServer().getSaslHost();
+            String userBaseDn = ldapSession.getLdapServer().getSearchBaseDn();
+            ldapSession.putSaslProperty( SaslConstants.SASL_HOST, saslHost );
+            ldapSession.putSaslProperty( SaslConstants.SASL_USER_BASE_DN, userBaseDn );
+
+            Map<String, String> saslProps = new HashMap<String, String>();
+            saslProps.put( Sasl.QOP, ldapSession.getLdapServer().getSaslQopString() );
+            saslProps.put( "com.sun.security.sasl.digest.realm", getActiveRealms( ldapSession.getLdapServer() ) );
 
-            CallbackHandler callbackHandler = new DigestMd5CallbackHandler( 
-                session.getCoreSession().getDirectoryService(), bindRequest );
+            CallbackHandler callbackHandler = new DigestMd5CallbackHandler( ldapSession, adminSession, bindRequest );
 
             ss = Sasl.createSaslServer( SupportedSaslMechanisms.DIGEST_MD5, SaslConstants.LDAP_PROTOCOL, saslHost, saslProps, callbackHandler );
-            session.getIoSession().setAttribute( SaslConstants.SASL_SERVER, ss );
+            ldapSession.putSaslProperty( SaslConstants.SASL_SERVER, ss );
         }
 
         return ss;

Modified: directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/ntlm/NtlmMechanismHandler.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/ntlm/NtlmMechanismHandler.java?rev=682532&r1=682531&r2=682532&view=diff
==============================================================================
--- directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/ntlm/NtlmMechanismHandler.java (original)
+++ directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/ntlm/NtlmMechanismHandler.java Mon Aug  4 15:38:08 2008
@@ -58,13 +58,9 @@
 
     public SaslServer handleMechanism( LdapSession ldapSession, CoreSession adminSession, BindRequest bindRequest ) throws Exception
     {
-        SaslServer ss;
+        SaslServer ss = ( SaslServer ) ldapSession.getSaslProperty( SaslConstants.SASL_SERVER );
 
-        if ( ldapSession.getIoSession().containsAttribute( SaslConstants.SASL_SERVER ) )
-        {
-            ss = ( SaslServer ) ldapSession.getIoSession().getAttribute( SaslConstants.SASL_SERVER );
-        }
-        else
+        if ( ss == null )
         {
             if ( provider == null )
             {
@@ -72,7 +68,7 @@
             }
             
             ss = new NtlmSaslServer( provider, bindRequest, ldapSession );
-            ldapSession.getIoSession().setAttribute( SaslConstants.SASL_SERVER, ss );
+            ldapSession.putSaslProperty( SaslConstants.SASL_SERVER, ss );
         }
 
         return ss;

Modified: directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/ntlm/NtlmSaslServer.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/ntlm/NtlmSaslServer.java?rev=682532&r1=682531&r2=682532&view=diff
==============================================================================
--- directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/ntlm/NtlmSaslServer.java (original)
+++ directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/ntlm/NtlmSaslServer.java Mon Aug  4 15:38:08 2008
@@ -39,8 +39,10 @@
  */
 public class NtlmSaslServer extends AbstractSaslServer
 {
+    /** The different states during a NTLM negotiation */ 
     enum NegotiationState { INITIALIZED, TYPE_1_RECEIVED, TYPE_2_SENT, TYPE_3_RECEIVED, COMPLETED }
 
+    /** The current state */
     private NegotiationState state = NegotiationState.INITIALIZED;
     private final NtlmProvider provider;
 
@@ -68,13 +70,17 @@
             case INITIALIZED:
                 state = NegotiationState.TYPE_1_RECEIVED;
                 break;
+                
             case TYPE_1_RECEIVED:
                 throw new IllegalStateException( "Cannot receive NTLM message before sending Type 2 challenge." );
+                
             case TYPE_2_SENT:
                 state = NegotiationState.TYPE_3_RECEIVED;
                 break;
+                
             case TYPE_3_RECEIVED:
                 throw new IllegalStateException( "Cannot receive NTLM message after Type 3 has been received." );
+                
             case COMPLETED:
                 throw new IllegalStateException( "Sasl challenge response already completed." );
         }
@@ -87,14 +93,18 @@
         {
             case INITIALIZED:
                 throw new IllegalStateException( "Cannot send Type 2 challenge before Type 1 response." );
+                
             case TYPE_1_RECEIVED:
                 state = NegotiationState.TYPE_2_SENT;
                 break;
+                
             case TYPE_2_SENT:
                 throw new IllegalStateException( "Cannot send Type 2 after it's already sent." );
+                
             case TYPE_3_RECEIVED:
                 state = NegotiationState.COMPLETED;
                 break;
+                
             case COMPLETED:
                 throw new IllegalStateException( "Sasl challenge response already completed." );
         }
@@ -130,7 +140,9 @@
                 {
                     throw new SaslException( "There was a failure during NTLM Type 1 message handling.", e );
                 }
+                
                 break;
+                
             case TYPE_3_RECEIVED:
                 boolean result;
                 try
@@ -147,8 +159,10 @@
                 {
                     throw new SaslException( "Authentication occurred but the credentials were invalid." );
                 }
+                
                 break;
-        }       
+        }
+        
         responseSent();
         return retval;
     }

Modified: directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/plain/PlainMechanismHandler.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/plain/PlainMechanismHandler.java?rev=682532&r1=682531&r2=682532&view=diff
==============================================================================
--- directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/plain/PlainMechanismHandler.java (original)
+++ directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/plain/PlainMechanismHandler.java Mon Aug  4 15:38:08 2008
@@ -44,13 +44,13 @@
      */
     public SaslServer handleMechanism( LdapSession ldapSession, CoreSession adminSession, BindRequest bindRequest ) throws Exception
     {
-        SaslServer ss = ( SaslServer ) ldapSession.getSaslProperties().get( SaslConstants.SASL_SERVER );
+        SaslServer ss = ( SaslServer ) ldapSession.getSaslProperty( SaslConstants.SASL_SERVER );
         
         if ( ss == null )
         {
             
             ss = new PlainSaslServer( ldapSession, adminSession, bindRequest );
-            ldapSession.getSaslProperties().put( SaslConstants.SASL_SERVER, ss );
+            ldapSession.putSaslProperty( SaslConstants.SASL_SERVER, ss );
         }
 
         return ss;

Modified: directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/plain/PlainSaslServer.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/plain/PlainSaslServer.java?rev=682532&r1=682531&r2=682532&view=diff
==============================================================================
--- directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/plain/PlainSaslServer.java (original)
+++ directory/apacheds/branches/bigbang/protocol-newldap/src/main/java/org/apache/directory/server/newldap/handlers/bind/plain/PlainSaslServer.java Mon Aug  4 15:38:08 2008
@@ -94,9 +94,9 @@
         state = NegotiationState.INITIALIZED;
         
         // Reinitialize the SASL properties
-        getLdapSession().getSaslProperties().remove( SASL_PLAIN_AUTHZID );
-        getLdapSession().getSaslProperties().remove( SASL_PLAIN_AUTHCID );
-        getLdapSession().getSaslProperties().remove( SASL_PLAIN_PASSWORD );
+        getLdapSession().removeSaslProperty( SASL_PLAIN_AUTHZID );
+        getLdapSession().removeSaslProperty( SASL_PLAIN_AUTHCID );
+        getLdapSession().removeSaslProperty( SASL_PLAIN_PASSWORD );
     }
 
 

Modified: directory/apacheds/branches/bigbang/server-unit/src/test/java/org/apache/directory/server/SaslBindITest.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/server-unit/src/test/java/org/apache/directory/server/SaslBindITest.java?rev=682532&r1=682531&r2=682532&view=diff
==============================================================================
--- directory/apacheds/branches/bigbang/server-unit/src/test/java/org/apache/directory/server/SaslBindITest.java (original)
+++ directory/apacheds/branches/bigbang/server-unit/src/test/java/org/apache/directory/server/SaslBindITest.java Mon Aug  4 15:38:08 2008
@@ -234,114 +234,6 @@
 
 
 
-    /**
-     * Tests to make sure DIGEST-MD5 binds below the RootDSE work.
-     *
-    @Test
-    public void testSaslDigestMd5Bind() throws Exception
-    {
-        Hashtable<String, String> env = new Hashtable<String, String>();
-        env.put( Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory" );
-        env.put( Context.PROVIDER_URL, "ldap://localhost:" + port );
-
-        env.put( Context.SECURITY_AUTHENTICATION, "DIGEST-MD5" );
-        env.put( Context.SECURITY_PRINCIPAL, "hnelson" );
-        env.put( Context.SECURITY_CREDENTIALS, "secret" );
-
-        // Specify realm
-        env.put( "java.naming.security.sasl.realm", "example.com" );
-
-        // Request privacy protection
-        env.put( "javax.security.sasl.qop", "auth-conf" );
-
-        DirContext context = new InitialDirContext( env );
-
-        String[] attrIDs =
-            { "uid" };
-
-        Attributes attrs = context.getAttributes( "uid=hnelson,ou=users,dc=example,dc=com", attrIDs );
-
-        String uid = null;
-
-        if ( attrs.get( "uid" ) != null )
-        {
-            uid = ( String ) attrs.get( "uid" ).get();
-        }
-
-        assertEquals( uid, "hnelson" );
-    }
-
-
-    /**
-     * Tests to make sure DIGEST-MD5 binds below the RootDSE fail if the realm is bad.
-     *
-    @Test
-    public void testSaslDigestMd5BindBadRealm()
-    {
-        try
-        {
-            Hashtable<String, String> env = new Hashtable<String, String>();
-            env.put( Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory" );
-            env.put( Context.PROVIDER_URL, "ldap://localhost:" + port );
-
-            env.put( Context.SECURITY_AUTHENTICATION, "DIGEST-MD5" );
-            env.put( Context.SECURITY_PRINCIPAL, "hnelson" );
-            env.put( Context.SECURITY_CREDENTIALS, "secret" );
-
-            // Bad realm
-            env.put( "java.naming.security.sasl.realm", "badrealm.com" );
-
-            // Request privacy protection
-            env.put( "javax.security.sasl.qop", "auth-conf" );
-
-            DirContext context = new InitialDirContext( env );
-
-            String[] attrIDs =
-                { "uid" };
-
-            context.getAttributes( "uid=hnelson,ou=users,dc=example,dc=com", attrIDs );
-
-            fail( "Should have thrown exception." );
-        }
-        catch ( NamingException e )
-        {
-            assertTrue( e.getMessage().contains( "Nonexistent realm" ) );
-        }
-    }
-
-
-    /**
-     * Tests to make sure DIGEST-MD5 binds below the RootDSE fail if the password is bad.
-     *
-    @Test
-    public void testSaslDigestMd5BindBadPassword()
-    {
-        try
-        {
-            Hashtable<String, String> env = new Hashtable<String, String>();
-            env.put( Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory" );
-            env.put( Context.PROVIDER_URL, "ldap://localhost:" + port );
-
-            env.put( Context.SECURITY_AUTHENTICATION, "DIGEST-MD5" );
-            env.put( Context.SECURITY_PRINCIPAL, "hnelson" );
-            env.put( Context.SECURITY_CREDENTIALS, "badsecret" );
-
-            DirContext context = new InitialDirContext( env );
-
-            String[] attrIDs =
-                { "uid" };
-
-            context.getAttributes( "uid=hnelson,ou=users,dc=example,dc=com", attrIDs );
-
-            fail( "Should have thrown exception." );
-        }
-        catch ( NamingException e )
-        {
-            assertTrue( e.getMessage().contains( "digest response format violation" ) );
-        }
-    }
-
-
 
 
     /**

Modified: directory/apacheds/branches/bigbang/server-unit/src/test/java/org/apache/directory/server/operations/bind/SaslBindITest.java
URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/server-unit/src/test/java/org/apache/directory/server/operations/bind/SaslBindITest.java?rev=682532&r1=682531&r2=682532&view=diff
==============================================================================
--- directory/apacheds/branches/bigbang/server-unit/src/test/java/org/apache/directory/server/operations/bind/SaslBindITest.java (original)
+++ directory/apacheds/branches/bigbang/server-unit/src/test/java/org/apache/directory/server/operations/bind/SaslBindITest.java Mon Aug  4 15:38:08 2008
@@ -395,4 +395,110 @@
              assertTrue( e.getMessage().contains( "Invalid response" ) );
          }
      }
+     /**
+      * Tests to make sure DIGEST-MD5 binds below the RootDSE work.
+      */
+     @Test
+     public void testSaslDigestMd5Bind() throws Exception
+     {
+         Hashtable<String, String> env = new Hashtable<String, String>();
+         env.put( Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory" );
+         env.put( Context.PROVIDER_URL, "ldap://localhost:" + port );
+
+         env.put( Context.SECURITY_AUTHENTICATION, "DIGEST-MD5" );
+         env.put( Context.SECURITY_PRINCIPAL, "hnelson" );
+         env.put( Context.SECURITY_CREDENTIALS, "secret" );
+
+         // Specify realm
+         env.put( "java.naming.security.sasl.realm", "example.com" );
+
+         // Request privacy protection
+         env.put( "javax.security.sasl.qop", "auth-conf" );
+
+         DirContext context = new InitialDirContext( env );
+
+         String[] attrIDs =
+             { "uid" };
+
+         Attributes attrs = context.getAttributes( "uid=hnelson,ou=users,dc=example,dc=com", attrIDs );
+
+         String uid = null;
+
+         if ( attrs.get( "uid" ) != null )
+         {
+             uid = ( String ) attrs.get( "uid" ).get();
+         }
+
+         assertEquals( uid, "hnelson" );
+     }
+
+     
+     /**
+      * Tests to make sure DIGEST-MD5 binds below the RootDSE fail if the realm is bad.
+      */
+     @Test
+     public void testSaslDigestMd5BindBadRealm()
+     {
+         try
+         {
+             Hashtable<String, String> env = new Hashtable<String, String>();
+             env.put( Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory" );
+             env.put( Context.PROVIDER_URL, "ldap://localhost:" + port );
+
+             env.put( Context.SECURITY_AUTHENTICATION, "DIGEST-MD5" );
+             env.put( Context.SECURITY_PRINCIPAL, "hnelson" );
+             env.put( Context.SECURITY_CREDENTIALS, "secret" );
+
+             // Bad realm
+             env.put( "java.naming.security.sasl.realm", "badrealm.com" );
+
+             // Request privacy protection
+             env.put( "javax.security.sasl.qop", "auth-conf" );
+
+             DirContext context = new InitialDirContext( env );
+
+             String[] attrIDs =
+                 { "uid" };
+
+             context.getAttributes( "uid=hnelson,ou=users,dc=example,dc=com", attrIDs );
+
+             fail( "Should have thrown exception." );
+         }
+         catch ( NamingException e )
+         {
+             assertTrue( e.getMessage().contains( "Nonexistent realm" ) );
+         }
+     }
+
+
+     /**
+      * Tests to make sure DIGEST-MD5 binds below the RootDSE fail if the password is bad.
+      */
+     @Test
+     public void testSaslDigestMd5BindBadPassword()
+     {
+         try
+         {
+             Hashtable<String, String> env = new Hashtable<String, String>();
+             env.put( Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory" );
+             env.put( Context.PROVIDER_URL, "ldap://localhost:" + port );
+
+             env.put( Context.SECURITY_AUTHENTICATION, "DIGEST-MD5" );
+             env.put( Context.SECURITY_PRINCIPAL, "hnelson" );
+             env.put( Context.SECURITY_CREDENTIALS, "badsecret" );
+
+             DirContext context = new InitialDirContext( env );
+
+             String[] attrIDs =
+                 { "uid" };
+
+             context.getAttributes( "uid=hnelson,ou=users,dc=example,dc=com", attrIDs );
+
+             fail( "Should have thrown exception." );
+         }
+         catch ( NamingException e )
+         {
+             assertTrue( e.getMessage().contains( "digest response format violation" ) );
+         }
+     }
 }