Defines options controlling Ldap operations on the directory. An LdapConstraints object is always associated with an LdapConnection object; its values can be changed with LdapConnection.setConstraints, or overridden by passing an LdapConstraints object to an operation.
Inheritance: System.ICloneable
コード例 #1
0
ファイル: LdapSearchConstraints.cs プロジェクト: cmsd2/oidc
        /// <summary> Constructs an LdapSearchConstraints object initialized with values
        /// from an existing constraints object (LdapConstraints
        /// or LdapSearchConstraints).
        /// </summary>
        public LdapSearchConstraints(LdapConstraints cons) : base(cons.TimeLimit, cons.ReferralFollowing, cons.getReferralHandler(), cons.HopLimit)
        {
            InitBlock();
            LdapControl[] lsc = cons.getControls();
            if (lsc != null)
            {
                LdapControl[] generated_var = new LdapControl[lsc.Length];
                lsc.CopyTo(generated_var, 0);
                setControls(generated_var);
            }
            System.Collections.Hashtable lp = cons.Properties;
            if (lp != null)
            {
                Properties = (System.Collections.Hashtable)lp.Clone();
            }

            if (cons is LdapSearchConstraints)
            {
                LdapSearchConstraints scons = (LdapSearchConstraints)cons;
                serverTimeLimit = scons.ServerTimeLimit;
                dereference     = scons.Dereference;
                maxResults      = scons.MaxResults;
                batchSize       = scons.BatchSize;
            }
            // Get a unique connection name for debug
        }
コード例 #2
0
        /// <summary> Constructs an LdapSearchConstraints object initialized with values
        /// from an existing constraints object (LdapConstraints
        /// or LdapSearchConstraints).
        /// </summary>
        public LdapSearchConstraints(LdapConstraints cons)
            : base(cons.TimeLimit, cons.ReferralFollowing, cons.getReferralHandler(), cons.HopLimit)
        {
            InitBlock();
            LdapControl[] lsc = cons.getControls();
            if (lsc != null)
            {
                LdapControl[] generated_var = new LdapControl[lsc.Length];
                lsc.CopyTo(generated_var, 0);
                base.setControls(generated_var);
            }
            Hashtable lp = cons.Properties;

            if (lp != null)
            {
                base.Properties = (Hashtable)lp.Clone();
            }

            if (cons is LdapSearchConstraints)
            {
                LdapSearchConstraints scons = (LdapSearchConstraints)cons;
                this.serverTimeLimit = scons.ServerTimeLimit;
                this.dereference     = scons.Dereference;
                this.maxResults      = scons.MaxResults;
                this.batchSize       = scons.BatchSize;
            }
        }
コード例 #3
0
        /// <summary>
        ///     Constructs an LdapSearchConstraints object initialized with values
        ///     from an existing constraints object (LdapConstraints
        ///     or LdapSearchConstraints).
        /// </summary>
        public LdapSearchConstraints(LdapConstraints cons)
            : base(cons.TimeLimit, cons.ReferralFollowing, cons.getReferralHandler(), cons.HopLimit)
        {
            var lsc = cons.GetControls();

            if (lsc != null)
            {
                var generatedVar = new LdapControl[lsc.Length];
                lsc.CopyTo(generatedVar, 0);
                SetControls(generatedVar);
            }

            var lp = cons.Properties;

            if (lp != null)
            {
                Properties = (Hashtable)lp.Clone();
            }

            if (cons is LdapSearchConstraints)
            {
                var scons = (LdapSearchConstraints)cons;
                ServerTimeLimit = scons.ServerTimeLimit;
                Dereference     = scons.Dereference;
                MaxResults      = scons.MaxResults;
                BatchSize       = scons.BatchSize;
            }
        }
コード例 #4
0
 /// <summary>
 ///     Abandon the request associated with MsgId.
 /// </summary>
 /// <param name="msgId">
 ///     the message id to abandon.
 /// </param>
 /// <param name="cons">
 ///     constraints associated with this request.
 /// </param>
 internal void Abandon(int msgId, LdapConstraints cons)
 {
     try
     {
         // Send abandon request and remove from connection list
         var info = _messages.FindMessageById(msgId);
         _messages.Remove(info);
         info.Abandon(cons, null);
     }
     catch (FieldAccessException ex)
     {
         Logger.Log.LogWarning("Exception swallowed", ex);
     }
 }
コード例 #5
0
 /// <summary>
 ///     Abandon the request associated with MsgId.
 /// </summary>
 /// <param name="msgId">
 ///     the message id to abandon.
 /// </param>
 /// <param name="cons">
 ///     constraints associated with this request.
 /// </param>
 /// <param name="cancellationToken"></param>
 internal async Task Abandon(int msgId, LdapConstraints cons, CancellationToken cancellationToken)
 {
     try
     {
         // Send abandon request and remove from connection list
         var info = _messages.FindMessageById(msgId);
         _messages.Remove(info);
         await info.Abandon(cons, null, cancellationToken).ConfigureAwait(false);
     }
     catch (FieldAccessException ex)
     {
         Logger.Log.LogWarning("Exception swallowed", ex);
     }
 }
コード例 #6
0
 /// <summary>
 ///     Abandon the request associated with MsgId.
 /// </summary>
 /// <param name="msgId">
 ///     the message id to abandon.
 /// </param>
 /// <param name="cons">
 ///     constraints associated with this request.
 /// </param>
 internal void Abandon(int msgId, LdapConstraints cons)
 {
     try
     {
         // Send abandon request and remove from connection list
         var info = _messages.FindMessageById(msgId);
         SupportClass.VectorRemoveElement(_messages, info); // This message is now dead
         info.Abandon(cons, null);
     }
     catch (FieldAccessException ex)
     {
         Logger.Log.LogWarning("Exception swallowed", ex);
     }
 }
コード例 #7
0
ファイル: MessageAgent.cs プロジェクト: cmsd2/oidc
        /// <summary> Abandon the request associated with MsgId
        ///
        /// </summary>
        /// <param name="msgId">the message id to abandon
        ///
        /// </param>
        /// <param name="cons">constraints associated with this request
        /// </param>
        /* package */
        internal void Abandon(int msgId, LdapConstraints cons)
        //, boolean informUser)
        {
            Message info = null;

            try
            {
                // Send abandon request and remove from connection list
                info = messages.findMessageById(msgId);
                SupportClass.VectorRemoveElement(messages, info); // This message is now dead
                info.Abandon(cons, null);
            }
            catch (FieldAccessException ex)
            {
            }
        }
コード例 #8
0
        internal virtual void Abandon(LdapConstraints cons, InterThreadException informUserEx)
        {
            if (!waitForReply_Renamed_Field)
            {
                return;
            }
            acceptReplies = false;              // don't listen to anyone
            waitForReply_Renamed_Field = false; // don't let sleeping threads lie
            if (!complete)
            {
                try
                {
                    // If a bind, release bind semaphore & wake up waiting threads
                    // Must do before writing abandon message, otherwise deadlock
                    if (bindprops != null)
                    {
                        int id;
                        if (conn.BindSemIdClear)
                        {
                            // Semaphore id for normal operations
                            id = msgId;
                        }
                        else
                        {
                            // Semaphore id for sasl bind
                            id = conn.BindSemId;
                            conn.clearBindSemId();
                        }
                        conn.freeWriteSemaphore(id);
                    }

                    // Create the abandon message, but don't track it.
                    LdapControl[] cont = null;
                    if (cons != null)
                    {
                        cont = cons.getControls();
                    }
                    LdapMessage msg = new LdapAbandonRequest(msgId, cont);
                    // Send abandon message to server
                    conn.writeMessage(msg);
                }
                catch (LdapException ex)
                {
                    LogManager.GetCurrentClassLogger().Warn("Exception swallowed", ex);
                }
                // If not informing user, remove message from agent
                if (informUserEx == null)
                {
                    agent.Abandon(msgId, null);
                }
                conn.removeMessage(this);
            }
            // Get rid of all replies queued
            if (informUserEx != null)
            {
                replies.Add(new LdapResponse(informUserEx, conn.ActiveReferral));
                stopTimer();
                // wake up waiting threads to receive exception
                sleepersAwake();
                // Message will get cleaned up when last response removed from queue
            }
            else
            {
                // Wake up any waiting threads, so they can terminate.
                // If informing the user, we wake sleepers after
                // caller queues dummy response with error status
                sleepersAwake();
                cleanup();
            }
        }
コード例 #9
0
		/// <summary> 
		/// 
		/// Notifies the server not to send additional results associated with
		/// this LdapSearchResults object, and discards any results already
		/// received.
		/// 
		/// </summary>
		/// <param name="results">  An object returned from a search.
		/// 
		/// </param>
		/// <param name="cons">    The contraints specific to the operation.
		/// 
		/// </param>
		/// <exception> LdapException A general exception which includes an error
		/// message and an Ldap error code.
		/// </exception>
		public virtual void  Abandon(LdapSearchResults results, LdapConstraints cons)
		{
			results.Abandon();
			return ;
		}
コード例 #10
0
		/// <summary> Check the result code and throw an exception if needed.
		/// 
		/// If referral following is enabled, checks if we need to
		/// follow a referral
		/// 
		/// </summary>
		/// <param name="queue">- the message queue of the current response
		/// 
		/// </param>
		/// <param name="cons">- the constraints that apply to the request
		/// 
		/// </param>
		/// <param name="response">- the LdapResponse to check
		/// </param>
		private void  chkResultCode(LdapMessageQueue queue, LdapConstraints cons, LdapResponse response)
		{
			if ((response.ResultCode == LdapException.REFERRAL) && cons.ReferralFollowing)
			{
				// Perform referral following and return
				System.Collections.ArrayList refConn = null;
				try
				{
					chaseReferral(queue, cons, response, response.Referrals, 0, false, null);
				}
				finally
				{
					releaseReferralConnections(refConn);
				}
			}
			else
			{
				// Throws exception for non success result
				response.chkResultCode();
			}
			return ;
		}
コード例 #11
0
		/// <summary> Asynchronously renames an existing entry in the directory, using the
		/// specified constraints and possibily repositioning the entry in the
		/// directory.
		/// 
		/// </summary>
		/// <param name="dn">            The current distinguished name of the entry.
		/// 
		/// </param>
		/// <param name="newRdn">        The new relative distinguished name for the entry.
		/// 
		/// </param>
		/// <param name="newParentdn">   The distinguished name of an existing entry which
		/// is to be the new parent of the entry.
		/// 
		/// </param>
		/// <param name="deleteOldRdn">  If true, the old name is not retained as an
		/// attribute value. If false, the old name is
		/// retained as an attribute value.
		/// 
		/// </param>
		/// <param name="queue">         The queue for messages returned from a server in
		/// response to this request. If it is null, a
		/// queue object is created internally.
		/// 
		/// </param>
		/// <param name="cons">          The constraints specific to the operation.
		/// 
		/// </param>
		/// <exception> LdapException A general exception which includes an error
		/// message and an Ldap error code.
		/// </exception>
		public virtual LdapResponseQueue Rename(System.String dn, System.String newRdn, System.String newParentdn, bool deleteOldRdn, LdapResponseQueue queue, LdapConstraints cons)
		{
			if ((System.Object) dn == null || (System.Object) newRdn == null)
			{
				// Invalid DN or RDN parameter
				throw new System.ArgumentException(ExceptionMessages.RDN_PARAM_ERROR);
			}
			
			if (cons == null)
				cons = defSearchCons;
			
			LdapMessage msg = new LdapModifyDNRequest(dn, newRdn, newParentdn, deleteOldRdn, cons.getControls());
			
			return SendRequestToServer(msg, cons.TimeLimit, queue, null);
		}
コード例 #12
0
		/// <summary> 
		/// Synchronously renames an existing entry in the directory, using the
		/// specified constraints and possibly repositioning the entry in the
		/// directory tree.
		/// 
		/// </summary>
		/// <param name="dn">            The current distinguished name of the entry.
		/// 
		/// </param>
		/// <param name="newRdn">        The new relative distinguished name for the entry.
		/// 
		/// </param>
		/// <param name="newParentdn">   The distinguished name of an existing entry which
		/// is to be the new parent of the entry.
		/// 
		/// </param>
		/// <param name="deleteOldRdn">  If true, the old name is not retained as an
		/// attribute value. If false, the old name is
		/// retained as an attribute value.
		/// 
		/// </param>
		/// <param name="cons">          The constraints specific to the operation.
		/// 
		/// </param>
		/// <exception> LdapException A general exception which includes an error
		/// message and an Ldap error code.
		/// </exception>
		public virtual void  Rename(System.String dn, System.String newRdn, System.String newParentdn, bool deleteOldRdn, LdapConstraints cons)
		{
			LdapResponseQueue queue = Rename(dn, newRdn, newParentdn, deleteOldRdn, null, cons);
			
			// Get a handle to the rename response
			LdapResponse renameResponse = (LdapResponse) (queue.getResponse());
			
			// Set local copy of responseControls synchronously - if there were any
			lock (responseCtlSemaphore)
			{
				responseCtls = renameResponse.Controls;
			}
			
			chkResultCode(queue, cons, renameResponse);
			return ;
		}
コード例 #13
0
		/// <summary> Asynchronously makes a set of changes to an existing entry in the
		/// directory, using the specified constraints and queue.
		/// 
		/// For example, this modify method can change attribute values, add new
		/// attribute values, or remove existing attribute values.
		/// 
		/// Because the server applies all changes in an LdapModification array
		/// atomically, the application can expect that no changes
		/// have been performed if an error is returned.
		/// If the request fails with {@link LdapException.CONNECT_ERROR},
		/// it is indeterminate whether or not the server made the modifications.
		/// 
		/// </summary>
		/// <param name="dn">        The distinguished name of the entry to modify.
		/// 
		/// </param>
		/// <param name="mods">      The changes to be made to the entry.
		/// 
		/// </param>
		/// <param name="queue">     The queue for messages returned from a server in
		/// response to this request. If it is null, a
		/// queue object is created internally.
		/// 
		/// </param>
		/// <param name="cons">      Constraints specific to the operation.
		/// 
		/// </param>
		/// <exception> LdapException A general exception which includes an error
		/// message and an Ldap error code.
		/// </exception>
		public virtual LdapResponseQueue Modify(System.String dn, LdapModification[] mods, LdapResponseQueue queue, LdapConstraints cons)
		{
			if ((System.Object) dn == null)
			{
				// Invalid DN parameter
				throw new System.ArgumentException(ExceptionMessages.DN_PARAM_ERROR);
			}
			
			if (cons == null)
				cons = defSearchCons;
			
			LdapMessage msg = new LdapModifyRequest(dn, mods, cons.getControls());
			
			return SendRequestToServer(msg, cons.TimeLimit, queue, null);
		}
コード例 #14
0
		/// <summary> Synchronously makes a set of changes to an existing entry in the
		/// directory, using the specified constraints.
		/// 
		/// For example, this modify method changes attribute values, adds new
		/// attribute values, or removes existing attribute values.
		/// 
		/// Because the server applies all changes in an LdapModification array
		/// atomically, the application can expect that no changes
		/// have been performed if an error is returned.
		/// If the request fails with {@link LdapException.CONNECT_ERROR},
		/// it is indeterminate whether or not the server made the modifications.
		/// 
		/// </summary>
		/// <param name="dn">     The distinguished name of the entry to modify.
		/// 
		/// </param>
		/// <param name="mods">   The changes to be made to the entry.
		/// 
		/// </param>
		/// <param name="cons">   The constraints specific to the operation.
		/// 
		/// </param>
		/// <exception> LdapException A general exception which includes an
		/// error message and an Ldap error code.
		/// </exception>
		public virtual void  Modify(System.String dn, LdapModification[] mods, LdapConstraints cons)
		{
			LdapResponseQueue queue = Modify(dn, mods, null, cons);
			
			// Get a handle to the modify response
			LdapResponse modifyResponse = (LdapResponse) (queue.getResponse());
			
			// Set local copy of responseControls synchronously - if there were any
			lock (responseCtlSemaphore)
			{
				responseCtls = modifyResponse.Controls;
			}
			
			chkResultCode(queue, cons, modifyResponse);
			
			return ;
		}
コード例 #15
0
		public virtual LdapResponseQueue Bind(int version, System.String dn, sbyte[] passwd, LdapResponseQueue queue, LdapConstraints cons, string mech)
		{
			int msgId;
			BindProperties bindProps;
			if (cons == null)
				cons = defSearchCons;
			
			if ((System.Object) dn == null)
			{
				dn = "";
			}
			else
			{
				dn = dn.Trim();
			}
			
			if (passwd == null)
				passwd = new sbyte[]{};
			
			bool anonymous = false;
			if (passwd.Length == 0)
			{
				anonymous = true; // anonymous, passwd length zero with simple bind
				dn = ""; // set to null if anonymous
			}

			LdapMessage msg;
#if TARGET_JVM
			if (mech != null)
				msg = new LdapBindRequest(version, "", mech, passwd, cons.getControls());
			else
#endif
				msg = new LdapBindRequest(version, dn, passwd, cons.getControls());
			
			msgId = msg.MessageID;
			bindProps = new BindProperties(version, dn, "simple", anonymous, null, null);
			
			// For bind requests, if not connected, attempt to reconnect
			if (!conn.Connected)
			{
				if ((System.Object) conn.Host != null)
				{
					conn.connect(conn.Host, conn.Port);
				}
				else
				{
					throw new LdapException(ExceptionMessages.CONNECTION_IMPOSSIBLE, LdapException.CONNECT_ERROR, null);
				}
			}
			
#if TARGET_JVM
			// stopping reader to enable stream replace after secure binding is complete, see Connection.ReplaceStreams()
			if (mech != null)
			{
				if (conn.BindSemIdClear) {
					// need to acquire a semaphore only if bindSemId is clear
					// because if we receive SASL_BIND_IN_PROGRESS the semaphore is not
					// released when the response is queued
					conn.acquireWriteSemaphore(msgId);
					conn.BindSemId = msgId;
				}
				conn.stopReaderOnReply(msgId);
			}
			else
#endif
			// The semaphore is released when the bind response is queued.
			conn.acquireWriteSemaphore(msgId);
			
			return SendRequestToServer(msg, cons.TimeLimit, queue, bindProps);
		}
コード例 #16
0
		public virtual void  Bind(int version, System.String dn, sbyte[] passwd, LdapConstraints cons)
		{
			LdapResponseQueue queue = Bind(version, dn, passwd, null, cons, null);
			LdapResponse res = (LdapResponse) queue.getResponse();
			if (res != null)
			{
				// Set local copy of responseControls synchronously if any
				lock (responseCtlSemaphore)
				{
					responseCtls = res.Controls;
				}
				
				chkResultCode(queue, cons, res);
			}
			return ;
		}
コード例 #17
0
		/// <summary> Synchronously authenticates to the Ldap server (that the object is
		/// currently connected to) using the specified name, password, Ldap version,
		/// and constraints.
		/// 
		/// If the object has been disconnected from an Ldap server,
		/// this method attempts to reconnect to the server. If the object
		/// has already authenticated, the old authentication is discarded.
		/// 
		/// </summary>
		/// <param name="version"> The Ldap protocol version, use Ldap_V3.
		/// Ldap_V2 is not supported.
		/// 
		/// </param>
		/// <param name="dn">      If non-null and non-empty, specifies that the
		/// connection and all operations through it should
		/// be authenticated with dn as the distinguished
		/// name.
		/// 
		/// </param>
		/// <param name="passwd"> If non-null and non-empty, specifies that the
		/// connection and all operations through it should
		/// be authenticated with dn as the distinguished
		/// name and passwd as password.
		/// 
		/// Note: the application should use care in the use
		/// of String password objects.  These are long lived
		/// objects, and may expose a security risk, especially
		/// in objects that are serialized.  The LdapConnection
		/// keeps no long lived instances of these objects.
		/// 
		/// </param>
		/// <param name="cons">   The constraints specific to the operation.
		/// 
		/// </param>
		/// <exception> LdapException A general exception which includes an error
		/// message and an Ldap error code.
		/// 
		/// </exception>
		public virtual void  Bind(int version, System.String dn, System.String passwd, LdapConstraints cons)
		{
			sbyte[] pw = null;
			if ((System.Object) passwd != null)
			{
				try
				{
					System.Text.Encoding encoder = System.Text.Encoding.GetEncoding("utf-8"); 
					byte[] ibytes = encoder.GetBytes(passwd);
					pw=SupportClass.ToSByteArray(ibytes);

					//					pw = passwd.getBytes("UTF8");
					passwd = null; // Keep no reference to String object
				}
				catch (System.IO.IOException ex)
				{
					passwd = null; // Keep no reference to String object
					throw new System.SystemException(ex.ToString());
				}
			}
			Bind(version, dn, pw, cons);
			return ;
		}
コード例 #18
0
		/// <summary> Synchronously authenticates to the Ldap server (that the object is
		/// currently connected to) as an Ldapv3 bind, using the specified name,
		/// password, and constraints.
		/// 
		/// If the object has been disconnected from an Ldap server,
		/// this method attempts to reconnect to the server. If the object
		/// has already authenticated, the old authentication is discarded.
		/// 
		/// </summary>
		/// <param name="dn">     If non-null and non-empty, specifies that the
		/// connection and all operations through it should
		/// be authenticated with dn as the distinguished
		/// name.
		/// 
		/// </param>
		/// <param name="passwd"> If non-null and non-empty, specifies that the
		/// connection and all operations through it should
		/// be authenticated with dn as the distinguished
		/// name and passwd as password.
		/// Note: the application should use care in the use
		/// of String password objects.  These are long lived
		/// objects, and may expose a security risk, especially
		/// in objects that are serialized.  The LdapConnection
		/// keeps no long lived instances of these objects.
		/// 
		/// </param>
		/// <param name="cons">    Constraints specific to the operation.
		/// 
		/// </param>
		/// <exception> LdapException A general exception which includes an error
		/// message and an Ldap error code.
		/// 
		/// </exception>
		public virtual void  Bind(System.String dn, System.String passwd, LdapConstraints cons)
		{
			Bind(Ldap_V3, dn, passwd, cons);
			return ;
		}
コード例 #19
0
		/// <summary> Asynchronously adds an entry to the directory, using the specified
		/// constraints.
		/// 
		/// </summary>
		/// <param name="entry">  LdapEntry object specifying the distinguished
		/// name and attributes of the new entry.
		/// 
		/// </param>
		/// <param name="queue"> Handler for messages returned from a server in
		/// response to this request. If it is null, a
		/// queue object is created internally.
		/// 
		/// </param>
		/// <param name="cons">  Constraints specific to the operation.
		/// 
		/// </param>
		/// <exception> LdapException A general exception which includes an error
		/// message and an Ldap error code.
		/// </exception>
		public virtual LdapResponseQueue Add(LdapEntry entry, LdapResponseQueue queue, LdapConstraints cons)
		{
			if (cons == null)
				cons = defSearchCons;
			
			// error check the parameters
			if (entry == null)
			{
				throw new System.ArgumentException("The LdapEntry parameter" + " cannot be null");
			}
			if ((System.Object) entry.DN == null)
			{
				throw new System.ArgumentException("The DN value must be present" + " in the LdapEntry object");
			}
			
			LdapMessage msg = new LdapAddRequest(entry, cons.getControls());
			
			return SendRequestToServer(msg, cons.TimeLimit, queue, null);
		}
コード例 #20
0
		/// <summary> 
		/// Synchronously adds an entry to the directory, using the specified
		/// constraints.
		/// 
		/// </summary>
		/// <param name="entry">  LdapEntry object specifying the distinguished
		/// name and attributes of the new entry.
		/// 
		/// </param>
		/// <param name="cons">   Constraints specific to the operation.
		/// 
		/// </param>
		/// <exception> LdapException A general exception which includes an error
		/// message and an Ldap error code.
		/// </exception>
		
		public virtual void  Add(LdapEntry entry, LdapConstraints cons)
		{
			LdapResponseQueue queue = Add(entry, null, cons);
			
			// Get a handle to the add response
			LdapResponse addResponse = (LdapResponse) (queue.getResponse());
			
			// Set local copy of responseControls synchronously if there were any
			lock (responseCtlSemaphore)
			{
				responseCtls = addResponse.Controls;
			}
			chkResultCode(queue, cons, addResponse);
			return ;
		}
コード例 #21
0
		/// <summary> Abandons all outstanding operations managed by the queue.
		/// 
		/// All operations in progress, which are managed by the specified
		/// queue, are abandoned.
		/// 
		/// </summary>
		/// <param name="queue">    The queue returned from an asynchronous request.
		/// All outstanding operations managed by the queue
		/// are abandoned, and the queue is emptied.
		/// 
		/// </param>
		/// <param name="cons">    The contraints specific to the operation.
		/// 
		/// </param>
		/// <exception> LdapException A general exception which includes an error
		/// message and an Ldap error code.
		/// </exception>
		public virtual void  Abandon(LdapMessageQueue queue, LdapConstraints cons)
		{
			if (queue != null)
			{
				MessageAgent agent;
				if (queue is LdapSearchQueue)
				{
					agent = queue.MessageAgent;
				}
				else
				{
					agent = queue.MessageAgent;
				}
				int[] msgIds = agent.MessageIDs;
				for (int i = 0; i < msgIds.Length; i++)
				{
					agent.Abandon(msgIds[i], cons);
				}
			}
			return ;
		}
コード例 #22
0
		/// <summary> 
		/// Synchronously checks to see if an entry contains an attribute with a
		/// specified value, using the specified constraints.
		/// 
		/// </summary>
		/// <param name="dn">     The distinguished name of the entry to use in the
		/// comparison.
		/// 
		/// </param>
		/// <param name="attr">   The attribute to compare against the entry. The
		/// method checks to see if the entry has an
		/// attribute with the same name and value as this
		/// attribute.
		/// 
		/// </param>
		/// <param name="cons">   Constraints specific to the operation.
		/// 
		/// </param>
		/// <returns> True if the entry has the value,
		/// and false if the entry does not
		/// have the value or the attribute.
		/// 
		/// </returns>
		/// <exception> LdapException A general exception which includes an error
		/// message and an Ldap error code.
		/// </exception>
		public virtual bool Compare(System.String dn, LdapAttribute attr, LdapConstraints cons)
		{
			bool ret = false;
			
			LdapResponseQueue queue = Compare(dn, attr, null, cons);
			
			LdapResponse res = (LdapResponse) queue.getResponse();
			
			// Set local copy of responseControls synchronously - if there were any
			lock (responseCtlSemaphore)
			{
				responseCtls = res.Controls;
			}
			
			if (res.ResultCode == LdapException.COMPARE_TRUE)
			{
				ret = true;
			}
			else if (res.ResultCode == LdapException.COMPARE_FALSE)
			{
				ret = false;
			}
			else
			{
				chkResultCode(queue, cons, res);
			}
			return ret;
		}
        public static async Task <LdapWhoAmIResponse> WhoAmIAsync(this LdapConnection conn, LdapConstraints cons = null)
        {
            var result = await conn.ExtendedOperationAsync(new LdapWhoAmIOperation(), cons).ConfigureAwait(false);

            if (result is LdapWhoAmIResponse whoami)
            {
                return(whoami);
            }

            return(new LdapWhoAmIResponse(result.Message));
        }
コード例 #24
0
		/// <summary> Asynchronously compares an attribute value with one in the directory,
		/// using the specified queue and contraints.
		/// 
		/// Please note that a successful completion of this command results in
		/// one of two status codes: LdapException.COMPARE_TRUE if the entry
		/// has the value, and LdapException.COMPARE_FALSE if the entry
		/// does not have the value or the attribute.
		/// 
		/// </summary>
		/// <param name="dn">     The distinguished name of the entry containing an
		/// attribute to compare.
		/// 
		/// </param>
		/// <param name="attr">   An attribute to compare.
		/// 
		/// </param>
		/// <param name="queue">    Handler for messages returned from a server in
		/// response to this request. If it is null, a
		/// queue object is created internally.
		/// 
		/// </param>
		/// <param name="cons">     Constraints specific to the operation.
		/// 
		/// </param>
		/// <exception> LdapException A general exception which includes an error
		/// message and an Ldap error code.
		/// 
		/// </exception>
		/// <seealso cref="LdapException.COMPARE_TRUE">
		/// </seealso>
		/// <seealso cref="LdapException.COMPARE_FALSE">
		/// </seealso>
		public virtual LdapResponseQueue Compare(System.String dn, LdapAttribute attr, LdapResponseQueue queue, LdapConstraints cons)
		{
			if (attr.size() != 1)
			{
				throw new System.ArgumentException("compare: Exactly one value " + "must be present in the LdapAttribute");
			}
			
			if ((System.Object) dn == null)
			{
				// Invalid parameter
				throw new System.ArgumentException("compare: DN cannot be null");
			}
			
			if (cons == null)
				cons = defSearchCons;
			
			LdapMessage msg = new LdapCompareRequest(dn, attr.Name, attr.ByteValue, cons.getControls());
			
			return SendRequestToServer(msg, cons.TimeLimit, queue, null);
		}
コード例 #25
0
		/// <summary> Asynchronously makes a single change to an existing entry in the
		/// directory, using the specified constraints and queue.
		/// 
		/// For example, this modify method can change the value of an attribute,
		/// add a new attribute value, or remove an existing attribute value.
		/// 
		/// The LdapModification object specifies both the change to be made
		/// and the LdapAttribute value to be changed.
		/// 
		/// If the request fails with {@link LdapException.CONNECT_ERROR},
		/// it is indeterminate whether or not the server made the modification.
		/// 
		/// </summary>
		/// <param name="dn">         Distinguished name of the entry to modify.
		/// 
		/// </param>
		/// <param name="mod">        A single change to be made to the entry.
		/// 
		/// </param>
		/// <param name="queue">      Handler for messages returned from a server in
		/// response to this request. If it is null, a
		/// queue object is created internally.
		/// 
		/// </param>
		/// <param name="cons">       Constraints specific to the operation.
		/// 
		/// </param>
		/// <exception> LdapException A general exception which includes an error
		/// message and an Ldap error code.
		/// </exception>
		public virtual LdapResponseQueue Modify(System.String dn, LdapModification mod, LdapResponseQueue queue, LdapConstraints cons)
		{
			LdapModification[] mods = new LdapModification[1];
			mods[0] = mod;
			return Modify(dn, mods, queue, cons);
		}
コード例 #26
0
		/// <summary> Synchronously deletes the entry with the specified distinguished name
		/// from the directory, using the specified constraints.
		/// 
		/// Note: A Delete operation will not remove an entry that contains
		/// subordinate entries, nor will it dereference alias entries. 
		/// 
		/// </summary>
		/// <param name="dn">     The distinguished name of the entry to delete.
		/// 
		/// </param>
		/// <param name="cons">   Constraints specific to the operation.
		/// 
		/// </param>
		/// <exception> LdapException A general exception which includes an error
		/// message and an Ldap error code.
		/// </exception>
		public virtual void  Delete(System.String dn, LdapConstraints cons)
		{
			LdapResponseQueue queue = Delete(dn, null, cons);
			
			// Get a handle to the delete response
			LdapResponse deleteResponse = (LdapResponse) (queue.getResponse());
			
			// Set local copy of responseControls synchronously - if there were any
			lock (responseCtlSemaphore)
			{
				responseCtls = deleteResponse.Controls;
			}
			chkResultCode(queue, cons, deleteResponse);
			return ;
		}
コード例 #27
0
		/// <summary> 
		/// Synchronously renames an existing entry in the directory, using the
		/// specified constraints.
		/// 
		/// </summary>
		/// <param name="dn">            The current distinguished name of the entry.
		/// 
		/// </param>
		/// <param name="newRdn">        The new relative distinguished name for the entry.
		/// 
		/// </param>
		/// <param name="deleteOldRdn">  If true, the old name is not retained as an
		/// attribute value. If false, the old name is
		/// retained as an attribute value.
		/// 
		/// </param>
		/// <param name="cons">          The constraints specific to the operation.
		/// 
		/// </param>
		/// <exception> LdapException A general exception which includes an error
		/// message and an Ldap error code.
		/// </exception>
		public virtual void  Rename(System.String dn, System.String newRdn, bool deleteOldRdn, LdapConstraints cons)
		{
			// null for newParentdn means that this is originating as an Ldapv2 call
			Rename(dn, newRdn, null, deleteOldRdn, cons);
			return ;
		}
コード例 #28
0
		/// <summary> Synchronously disconnects from the Ldap server.
		/// 
		/// Before the object can perform Ldap operations again, it must
		/// reconnect to the server by calling connect.
		/// 
		/// The disconnect method abandons any outstanding requests, issues an
		/// unbind request to the server, and then closes the socket.
		/// 
		/// </summary>
		/// <param name="cons">LDPConstraints to be set with the unbind request
		/// 
		/// </param>
		/// <exception> LdapException A general exception which includes an error
		/// message and an Ldap error code.
		/// </exception>
		public virtual void  Disconnect(LdapConstraints cons)
		{
			// disconnect from API call
			Disconnect(cons, true);
			return ;
		}
コード例 #29
0
		/// <summary> Asynchronously renames an existing entry in the directory, using the
		/// specified constraints.
		/// 
		/// </summary>
		/// <param name="dn">            The current distinguished name of the entry.
		/// 
		/// </param>
		/// <param name="newRdn">        The new relative distinguished name for the entry.
		/// 
		/// </param>
		/// <param name="deleteOldRdn">  If true, the old name is not retained as an
		/// attribute value. If false, the old name is
		/// retained as an attribute value.
		/// 
		/// </param>
		/// <param name="queue">         The queue for messages returned from a server in
		/// response to this request. If it is null, a
		/// queue object is created internally.
		/// 
		/// </param>
		/// <param name="cons">          The constraints specific to the operation.
		/// 
		/// </param>
		/// <exception> LdapException A general exception which includes an error
		/// message and an Ldap error code.
		/// </exception>
		public virtual LdapResponseQueue Rename(System.String dn, System.String newRdn, bool deleteOldRdn, LdapResponseQueue queue, LdapConstraints cons)
		{
			return Rename(dn, newRdn, null, deleteOldRdn, queue, cons);
		}
コード例 #30
0
		/// <summary> Synchronously disconnect from the server
		/// 
		/// </summary>
		/// <param name="how">true if application call disconnect API, false if finalize.
		/// </param>
		private void  Disconnect(LdapConstraints cons, bool how)
		{
			// disconnect doesn't affect other clones
			// If not a clone, distroys connection
			conn = conn.destroyClone(how);
			return ;
		}
コード例 #31
0
		/// <summary> Sends an Ldap request to a directory server.
		/// 
		/// The specified the Ldap request is sent to the directory server
		/// associated with this connection. An Ldap request object is an
		/// {@link LdapMessage} with the operation type set to one of the request
		/// types. You can build a request by using the request classes found in this
		/// package
		/// 
		/// You should note that, since Ldap requests sent to the server
		/// using sendRequest are asynchronous, automatic referral following
		/// does not apply to these requests.
		/// 
		/// </summary>
		/// <param name="request">The Ldap request to send to the directory server.
		/// </param>
		/// <param name="queue">   The queue for messages returned from a server in
		/// response to this request. If it is null, a
		/// queue object is created internally.
		/// </param>
		/// <param name="cons">   The constraints that apply to this request
		/// </param>
		/// <exception>     LdapException A general exception which includes an error
		/// message and an Ldap error code.
		/// 
		/// </exception>
		/// <seealso cref="LdapMessage.Type">
		/// </seealso>
		/// <seealso cref="RfcLdapMessage.isRequest">
		/// </seealso>
		public virtual LdapMessageQueue SendRequest(LdapMessage request, LdapMessageQueue queue, LdapConstraints cons)
		{
			
			
			if (!request.Request)
			{
				throw new System.SystemException("Object is not a request message");
			}
			
			if (cons == null)
			{
				cons = defSearchCons;
			}
			
			// Get the correct queue for a search request
			MessageAgent agent;
			LdapMessageQueue myqueue = queue;
			if (myqueue == null)
			{
				agent = new MessageAgent();
				if (request.Type == LdapMessage.SEARCH_REQUEST)
				{
					myqueue = new LdapSearchQueue(agent);
				}
				else
				{
					myqueue = new LdapResponseQueue(agent);
				}
			}
			else
			{
				if (request.Type == LdapMessage.SEARCH_REQUEST)
				{
					agent = queue.MessageAgent;
				}
				else
				{
					agent = queue.MessageAgent;
				}
			}
			
			try
			{
				agent.sendMessage(conn, request, cons.TimeLimit, myqueue, null);
			}
			catch (LdapException lex)
			{
				throw lex;
			}
			return myqueue;
		}
コード例 #32
0
        //, boolean informUser)
        /// <summary> Abandon the request associated with MsgId
        /// 
        /// </summary>
        /// <param name="msgId">the message id to abandon
        /// 
        /// </param>
        /// <param name="cons">constraints associated with this request
        /// </param>
        /* package */
        internal void Abandon(int msgId, LdapConstraints cons)
        {
            Message info = null;
            try
            {
                // Send abandon request and remove from connection list
                info = messages.findMessageById(msgId);
                SupportClass.VectorRemoveElement(messages, info); // This message is now dead
                info.Abandon(cons, null);

                return ;
            }
            catch (System.FieldAccessException ex)
            {
            }
            return ;
        }
コード例 #33
0
		/// <summary> Follow referrals if necessary referral following enabled.
		/// This function is called only by synchronous requests.
		/// Search responses come here only if referral following is
		/// enabled and if we are processing a SearchResultReference
		/// or a Response with a status of REFERRAL, i.e. we are
		/// going to follow a referral.
		/// 
		/// This functions recursively follows a referral until a result
		/// is returned or until the hop limit is reached.
		/// 
		/// </summary>
		/// <param name="queue">The LdapResponseQueue for this request
		/// 
		/// </param>
		/// <param name="cons">The constraints that apply to the request
		/// 
		/// </param>
		/// <param name="msg">The referral or search reference response message
		/// 
		/// </param>
		/// <param name="initialReferrals">The referral array returned from the
		/// initial request.
		/// 
		/// </param>
		/// <param name="hopCount">the number of hops already used while
		/// following this referral
		/// 
		/// </param>
		/// <param name="searchReference">true if the message is a search reference
		/// 
		/// </param>
		/// <param name="connectionList">An optional array list used to store
		/// the LdapConnection objects used in following the referral.
		/// 
		/// </param>
		/// <returns> The array list used to store the all LdapConnection objects
		/// used in following the referral.  The list will be empty
		/// if there were none.
		/// 
		/// </returns>
		/// <exception> LdapException A general exception which includes an error
		/// message and an Ldap error code.
		/// </exception>
		/* package */
		internal virtual System.Collections.ArrayList chaseReferral(LdapMessageQueue queue, LdapConstraints cons, LdapMessage msg, System.String[] initialReferrals, int hopCount, bool searchReference, System.Collections.ArrayList connectionList)
		{
			System.Collections.ArrayList connList = connectionList;
			LdapConnection rconn = null; // new conn for following referral
			ReferralInfo rinfo = null; // referral info
			LdapMessage origMsg;
			
			// Get a place to store new connections
			if (connList == null)
			{
				connList = new System.Collections.ArrayList(cons.HopLimit);
			}
			// Following referrals or search reference
			System.String[] refs; // referral list
			if (initialReferrals != null)
			{
				// Search continuation reference from a search request
				refs = initialReferrals;
				origMsg = msg.RequestingMessage;
			}
			else
			{
				// Not a search request
				LdapResponse resp = (LdapResponse) queue.getResponse();
				if (resp.ResultCode != LdapException.REFERRAL)
				{
					// Not referral result,throw Exception if nonzero result
					resp.chkResultCode();
					return connList;
				}
				// We have a referral response
				refs = resp.Referrals;
				origMsg = resp.RequestingMessage;
			}
			LdapUrl refUrl; // referral represented as URL
			try
			{
				// increment hop count, check max hops
				if (hopCount++ > cons.HopLimit)
				{
					throw new LdapLocalException("Max hops exceeded", LdapException.REFERRAL_LIMIT_EXCEEDED);
				}
				// Get a connection to follow the referral
				rinfo = getReferralConnection(refs);
				rconn = rinfo.ReferralConnection;
				refUrl = rinfo.ReferralUrl;
				connList.Add(rconn);
				
				
				// rebuild msg into new msg changing msgID,dn,scope,filter
				LdapMessage newMsg = rebuildRequest(origMsg, refUrl, searchReference);
				
				
				// Send new message on new connection
				try
				{
					MessageAgent agent;
					if (queue is LdapResponseQueue)
					{
						agent = queue.MessageAgent;
					}
					else
					{
						agent = queue.MessageAgent;
					}
					agent.sendMessage(rconn.Connection, newMsg, defSearchCons.TimeLimit, queue, null);
				}
				catch (InterThreadException ex)
				{
					// Error ending request to referred server
					LdapReferralException rex = new LdapReferralException(ExceptionMessages.REFERRAL_SEND, LdapException.CONNECT_ERROR, null, ex);
					rex.setReferrals(initialReferrals);
					ReferralInfo ref_Renamed = rconn.Connection.ActiveReferral;
					rex.FailedReferral = ref_Renamed.ReferralUrl.ToString();
					throw rex;
				}
				
				if (initialReferrals == null)
				{
					// For operation results, when all responses are complete,
					// the stack unwinds back to the original and returns
					// to the application.
					// An exception is thrown for an error
					connList = chaseReferral(queue, cons, null, null, hopCount, false, connList);
				}
				else
				{
					// For search, just return to LdapSearchResults object
					return connList;
				}
			}
			catch (System.Exception ex)
			{
				
				if (ex is LdapReferralException)
				{
					throw (LdapReferralException) ex;
				}
				else
				{
					
					// Set referral list and failed referral
					LdapReferralException rex = new LdapReferralException(ExceptionMessages.REFERRAL_ERROR, ex);
					rex.setReferrals(refs);
					if (rinfo != null)
					{
						rex.FailedReferral = rinfo.ReferralUrl.ToString();
					}
					else
					{
						rex.FailedReferral = refs[refs.Length - 1];
					}
					throw rex;
				}
			}
			return connList;
		}
コード例 #34
0
		/*
		*  Asynchronous Ldap extended request with SearchConstraints
		*/
		
		/// <summary> Provides an asynchronous means to access extended, non-mandatory
		/// operations offered by a particular Ldapv3 compliant server.
		/// 
		/// </summary>
		/// <param name="op"> The object which contains (1) an identifier of an extended
		/// operation which should be recognized by the particular Ldap
		/// server this client is connected to and (2) an operation-
		/// specific sequence of octet strings or BER-encoded values.
		/// 
		/// </param>
		/// <param name="queue">    The queue for messages returned from a server in
		/// response to this request. If it is null, a queue
		/// object is created internally.
		/// 
		/// </param>
		/// <param name="cons">     The constraints specific to this operation.
		/// 
		/// </param>
		/// <returns> An operation-specific object, containing an ID and either an
		/// octet string or BER-encoded values.
		/// 
		/// </returns>
		/// <exception> LdapException A general exception which includes an error
		/// message and an Ldap error code.
		/// </exception>
		
		public virtual LdapResponseQueue ExtendedOperation(LdapExtendedOperation op, LdapConstraints cons, LdapResponseQueue queue)
		{
			// Use default constraints if none-specified
			if (cons == null)
				cons = defSearchCons;
			LdapMessage msg = MakeExtendedOperation(op, cons);
			return SendRequestToServer(msg, cons.TimeLimit, queue, null);
		}
コード例 #35
0
		/// <summary>  Abandons an asynchronous operation, using the specified
		/// constraints.
		/// 
		/// </summary>
		/// <param name="id">The ID of the asynchronous operation to abandon.
		/// The ID can be obtained from the search
		/// queue for the operation.
		/// 
		/// </param>
		/// <param name="cons">The contraints specific to the operation.
		/// 
		/// </param>
		/// <exception> LdapException A general exception which includes an error
		/// message and an Ldap error code.
		/// </exception>
		public virtual void  Abandon(int id, LdapConstraints cons)
		{
			// We need to inform the Message Agent which owns this messageID to
			// remove it from the queue.
			try
			{
				MessageAgent agent = conn.getMessageAgent(id);
				agent.Abandon(id, cons);
				return ;
			}
			catch (System.FieldAccessException ex)
			{
				return ; // Ignore error
			}
		}
コード例 #36
0
		/// <summary> Formulates the extended operation, constraints into an
		/// LdapMessage and returns the LdapMessage.  This is used by
		/// extendedOperation and startTLS which needs the LdapMessage to
		/// get the MessageID.
		/// </summary>
		protected internal virtual LdapMessage MakeExtendedOperation(LdapExtendedOperation op, LdapConstraints cons)
		{
			// Use default constraints if none-specified
			if (cons == null)
				cons = defSearchCons;
			
			// error check the parameters
			if ((System.Object) op.getID() == null)
			{
				// Invalid extended operation parameter, no OID specified
				throw new System.ArgumentException(ExceptionMessages.OP_PARAM_ERROR);
			}
			
			return new LdapExtendedRequest(op, cons.getControls());
		}
コード例 #37
0
ファイル: Message.cs プロジェクト: EventStore/csharp-ldap
        internal virtual void Abandon(LdapConstraints cons, InterThreadException informUserEx)
        {
            if (!waitForReply_Renamed_Field)
            {
                return ;
            }
            acceptReplies = false; // don't listen to anyone
            waitForReply_Renamed_Field = false; // don't let sleeping threads lie
            if (!complete)
            {
                try
                {
                    // If a bind, release bind semaphore & wake up waiting threads
                    // Must do before writing abandon message, otherwise deadlock
                    if (bindprops != null)
                    {
                        int id;
                        if (conn.BindSemIdClear)
                        {
                            // Semaphore id for normal operations
                            id = msgId;
                        }
                        else
                        {
                            // Semaphore id for sasl bind
                            id = conn.BindSemId;
                            conn.clearBindSemId();
                        }
                        conn.freeWriteSemaphore(id);
                    }

                    // Create the abandon message, but don't track it.
                    LdapControl[] cont = null;
                    if (cons != null)
                    {
                        cont = cons.getControls();
                    }
                    LdapMessage msg = new LdapAbandonRequest(msgId, cont);
                    // Send abandon message to server
                    conn.writeMessage(msg);
                }
                catch (LdapException ex)
                {
                    ; // do nothing
                }
                // If not informing user, remove message from agent
                if (informUserEx == null)
                {
                    agent.Abandon(msgId, null);
                }
                conn.removeMessage(this);
            }
            // Get rid of all replies queued
            if (informUserEx != null)
            {
                replies.Add(new LdapResponse(informUserEx, conn.ActiveReferral));
                stopTimer();
                // wake up waiting threads to receive exception
                sleepersAwake();
                // Message will get cleaned up when last response removed from queue
            }
            else
            {
                // Wake up any waiting threads, so they can terminate.
                // If informing the user, we wake sleepers after
                // caller queues dummy response with error status
                sleepersAwake();
                cleanup();
            }
            return ;
        }
コード例 #38
0
		/// <summary> 
		/// Synchronously makes a single change to an existing entry in the
		/// directory, using the specified constraints.
		/// 
		/// For example, this modify method changes the value of an attribute,
		/// adds a new attribute value, or removes an existing attribute value.
		/// 
		/// The LdapModification object specifies both the change to be
		/// made and the LdapAttribute value to be changed.
		/// 
		/// If the request fails with {@link LdapException.CONNECT_ERROR},
		/// it is indeterminate whether or not the server made the modification.
		/// 
		/// </summary>
		/// <param name="dn">      The distinguished name of the entry to modify.
		/// 
		/// </param>
		/// <param name="mod">     A single change to be made to the entry.
		/// 
		/// </param>
		/// <param name="cons">    The constraints specific to the operation.
		/// 
		/// </param>
		/// <exception> LdapException A general exception which includes an error
		/// message and an Ldap error code.
		/// </exception>
		public virtual void  Modify(System.String dn, LdapModification mod, LdapConstraints cons)
		{
			LdapModification[] mods = new LdapModification[1];
			mods[0] = mod;
			Modify(dn, mods, cons);
			return ;
		}
コード例 #39
0
		/*
		*  Synchronous Ldap extended request with SearchConstraints
		*/
		
		/// <summary> 
		/// Provides a synchronous means to access extended, non-mandatory
		/// operations offered by a particular Ldapv3 compliant server.
		/// 
		/// </summary>
		/// <param name="op"> The object which contains (1) an identifier of an extended
		/// operation which should be recognized by the particular Ldap
		/// server this client is connected to and (2) an
		/// operation-specific sequence of octet strings
		/// or BER-encoded values.
		/// 
		/// </param>
		/// <param name="cons">The constraints specific to the operation.
		/// 
		/// </param>
		/// <returns> An operation-specific object, containing an ID and either an
		/// octet string or BER-encoded values.
		/// 
		/// </returns>
		/// <exception> LdapException A general exception which includes an error
		/// message and an Ldap error code.
		/// </exception>
		
		public virtual LdapExtendedResponse ExtendedOperation(LdapExtendedOperation op, LdapConstraints cons)
		{
			
			// Call asynchronous API and get back handler to reponse queue
			LdapResponseQueue queue = ExtendedOperation(op, cons, null);
			LdapExtendedResponse response = (LdapExtendedResponse) queue.getResponse();
			
			// Set local copy of responseControls synchronously - if there were any
			lock (responseCtlSemaphore)
			{
				responseCtls = response.Controls;
			}
			
			chkResultCode(queue, cons, response);
			return response;
		}
コード例 #40
0
        private byte[] SendLdapSaslBindRequest(byte[] toWrite, string mechanism, BindProperties bindProps, LdapConstraints constraints)
        {
            constraints = constraints ?? _defSearchCons;
            var msg = new LdapSaslBindRequest(LdapV3, mechanism, constraints.GetControls(), toWrite);

            var queue = SendRequestToServer(msg, constraints.TimeLimit, null, bindProps);

            if (!(queue.GetResponse() is LdapResponse ldapResponse))
            {
                throw new LdapException("Bind failure, no response received.");
            }

            var bindResponse = (RfcBindResponse)ldapResponse.Asn1Object.get_Renamed(1);

            lock (_responseCtlSemaphore)
            {
                _responseCtls = ldapResponse.Controls;
            }

            var serverCreds = bindResponse.ServerSaslCreds;
            var resultCode  = ldapResponse.ResultCode;

            byte[] replyBuf = null;
            if (resultCode == LdapException.SaslBindInProgress || resultCode == LdapException.Success)
            {
                if (serverCreds != null)
                {
                    replyBuf = serverCreds.ByteValue();
                }
            }
            else
            {
                ldapResponse.ChkResultCode();
                throw new LdapException("SASL Bind Error.", resultCode, null);
            }

            return(replyBuf);
        }