**** Merged from MCS ****
[mono-project.git] / mcs / class / Novell.Directory.Ldap / Novell.Directory.Ldap / LdapConnection.cs
bloba217f3b7faa9b68e7b5afa130692755e8958b0c0
1 /******************************************************************************
2 * The MIT License
3 * Copyright (c) 2003 Novell Inc. www.novell.com
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the Software), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *******************************************************************************/
24 // Novell.Directory.Ldap.LdapConnection.cs
26 // Author:
27 // Sunil Kumar (Sunilk@novell.com)
29 // (C) 2003 Novell, Inc (http://www.novell.com)
32 using System;
33 using Novell.Directory.Ldap;
34 using Novell.Directory.Ldap.Asn1;
35 using Novell.Directory.Ldap.Rfc2251;
36 using Novell.Directory.Ldap.Utilclass;
38 namespace Novell.Directory.Ldap
41 /// <summary> The central class that encapsulates the connection
42 /// to a directory server through the Ldap protocol.
43 /// LdapConnection objects are used to perform common Ldap
44 /// operations such as search, modify and add.
45 ///
46 /// In addition, LdapConnection objects allow you to bind to an
47 /// Ldap server, set connection and search constraints, and perform
48 /// several other tasks.
49 ///
50 /// An LdapConnection object is not connected on
51 /// construction and can only be connected to one server at one
52 /// port. Multiple threads may share this single connection, typically
53 /// by cloning the connection object, one for each thread. An
54 /// application may have more than one LdapConnection object, connected
55 /// to the same or different directory servers.
56 ///
57 ///
58 /// </summary>
59 public class LdapConnection : System.ICloneable
61 private void InitBlock()
63 defSearchCons = new LdapSearchConstraints();
64 responseCtlSemaphore = new System.Object();
66 /// <summary> Returns the protocol version uses to authenticate.
67 ///
68 /// 0 is returned if no authentication has been performed.
69 ///
70 /// </summary>
71 /// <returns> The protol version used for authentication or 0
72 /// not authenticated.
73 ///
74 /// </returns>
75 virtual public int ProtocolVersion
77 get
79 BindProperties prop = conn.BindProperties;
80 if (prop == null)
82 return Ldap_V3;
84 return prop.ProtocolVersion;
88 /// <summary> Returns the distinguished name (DN) used for as the bind name during
89 /// the last successful bind operation. <code>null</code> is returned
90 /// if no authentication has been performed or if the bind resulted in
91 /// an aonymous connection.
92 ///
93 /// </summary>
94 /// <returns> The distinguished name if authenticated; otherwise, null.
95 ///
96 /// </returns>
97 virtual public System.String AuthenticationDN
99 get
101 BindProperties prop = conn.BindProperties;
102 if (prop == null)
104 return null;
106 if (prop.Anonymous)
108 return null;
110 return prop.AuthenticationDN;
114 /// <summary> Returns the method used to authenticate the connection. The return
115 /// value is one of the following:
116 ///
117 /// <ul>
118 /// <li>"none" indicates the connection is not authenticated.</li>
119 ///
120 ///
121 /// <li>"simple" indicates simple authentication was used or that a null
122 /// or empty authentication DN was specified.</li>
123 ///
124 /// <li>"sasl" indicates that a SASL mechanism was used to authenticate</li>
125 /// </ul>
126 ///
127 /// </summary>
128 /// <returns> The method used to authenticate the connection.
129 /// </returns>
130 virtual public System.String AuthenticationMethod
134 BindProperties prop = conn.BindProperties;
135 if (prop == null)
137 return "simple";
139 return conn.BindProperties.AuthenticationMethod;
143 /// <summary> Returns the properties if any specified on binding with a
144 /// SASL mechanism.
145 ///
146 /// Null is returned if no authentication has been performed
147 /// or no authentication Map is present.
148 ///
149 /// </summary>
150 /// <returns> The bind properties Map Object used for SASL bind or null if
151 /// the connection is not present or not authenticated.
152 ///
153 /// </returns>
154 virtual public System.Collections.IDictionary SaslBindProperties
158 BindProperties prop = conn.BindProperties;
159 if (prop == null)
161 return null;
163 return conn.BindProperties.SaslBindProperties;
167 /// <summary> Returns the call back handler if any specified on binding with a
168 /// SASL mechanism.
169 ///
170 /// Null is returned if no authentication has been performed
171 /// or no authentication call back handler is present.
172 ///
173 /// </summary>
174 /// <returns> The call back handler used for SASL bind or null if the
175 /// object is not present or not authenticated.
176 ///
177 /// </returns>
178 virtual public System.Object SaslBindCallbackHandler
182 BindProperties prop = conn.BindProperties;
183 if (prop == null)
185 return null;
187 return conn.BindProperties.SaslCallbackHandler;
191 /// <summary> Returns a copy of the set of constraints associated with this
192 /// connection. These constraints apply to all operations performed
193 /// through this connection (unless a different set of constraints is
194 /// specified when calling an operation method).
195 ///
196 /// </summary>
197 /// <returns> The set of default contraints that apply to this connection.
198 ///
199 /// </returns>
200 /// <summary> Sets the constraints that apply to all operations performed through
201 /// this connection (unless a different set of constraints is specified
202 /// when calling an operation method). An LdapSearchConstraints object
203 /// which is passed to this method sets all constraints, while an
204 /// LdapConstraints object passed to this method sets only base constraints.
205 ///
206 /// </summary>
207 /// <param name="cons"> An LdapConstraints or LdapSearchConstraints Object
208 /// containing the contstraint values to set.
209 ///
210 /// </param>
211 /// <seealso cref="Constraints()">
212 /// </seealso>
213 /// <seealso cref="SearchConstraints()">
214 /// </seealso>
215 virtual public LdapConstraints Constraints
219 return (LdapConstraints) (this.defSearchCons).Clone();
224 // Set all constraints, replace the object with a new one
225 if (value is LdapSearchConstraints)
227 defSearchCons = (LdapSearchConstraints) value.Clone();
228 return ;
231 // We set the constraints this way, so a thread doesn't get an
232 // conconsistant view of the referrals.
233 LdapSearchConstraints newCons = (LdapSearchConstraints) defSearchCons.Clone();
234 newCons.HopLimit = value.HopLimit;
235 newCons.TimeLimit = value.TimeLimit;
236 newCons.setReferralHandler(value.getReferralHandler());
237 newCons.ReferralFollowing = value.ReferralFollowing;
238 LdapControl[] lsc = value.getControls();
239 if (lsc != null)
241 newCons.setControls(lsc);
243 System.Collections.Hashtable lp = newCons.Properties;
244 if (lp != null)
246 newCons.Properties = lp;
248 defSearchCons = newCons;
249 return ;
253 /// <summary> Returns the host name of the Ldap server to which the object is or
254 /// was last connected, in the format originally specified.
255 ///
256 /// </summary>
257 /// <returns> The host name of the Ldap server to which the object last
258 /// connected or null if the object has never connected.
259 ///
260 /// </returns>
261 virtual public System.String Host
265 return conn.Host;
269 /// <summary> Returns the port number of the Ldap server to which the object is or
270 /// was last connected.
271 ///
272 /// </summary>
273 /// <returns> The port number of the Ldap server to which the object last
274 /// connected or -1 if the object has never connected.
275 ///
276 /// </returns>
277 virtual public int Port
281 return conn.Port;
285 /// <summary> Returns a copy of the set of search constraints associated with this
286 /// connection. These constraints apply to search operations performed
287 /// through this connection (unless a different set of
288 /// constraints is specified when calling the search operation method).
289 ///
290 /// </summary>
291 /// <returns> The set of default search contraints that apply to
292 /// this connection.
293 ///
294 /// </returns>
295 /// <seealso cref="Constraints">
296 /// </seealso>
297 /// <seealso cref="LdapSearchConstraints">
298 /// </seealso>
299 virtual public LdapSearchConstraints SearchConstraints
303 return (LdapSearchConstraints) this.defSearchCons.Clone();
307 /// <summary> Indicates whether the object has authenticated to the connected Ldap
308 /// server.
309 ///
310 /// </summary>
311 /// <returns> True if the object has authenticated; false if it has not
312 /// authenticated.
313 ///
314 /// </returns>
315 virtual public bool Bound
319 return conn.Bound;
323 /// <summary> Indicates whether the connection represented by this object is open
324 /// at this time.
325 ///
326 /// </summary>
327 /// <returns> True if connection is open; false if the connection is closed.
328 /// </returns>
329 virtual public bool Connected
333 return conn.Connected;
337 /// <summary> Returns the Server Controls associated with the most recent response
338 /// to a synchronous request on this connection object, or null
339 /// if the latest response contained no Server Controls. The method
340 /// always returns null for asynchronous requests. For asynchronous
341 /// requests, the response controls are available in LdapMessage.
342 ///
343 /// </summary>
344 /// <returns> The server controls associated with the most recent response
345 /// to a synchronous request or null if the response contains no server
346 /// controls.
347 ///
348 /// </returns>
349 /// <seealso cref="LdapMessage.Controls">
350 /// </seealso>
351 virtual public LdapControl[] ResponseControls
355 if (responseCtls == null)
357 return null;
361 // We have to clone the control just in case
362 // we have two client threads that end up retreiving the
363 // same control.
364 LdapControl[] clonedControl = new LdapControl[responseCtls.Length];
366 // Also note we synchronize access to the local response
367 // control object just in case another message containing controls
368 // comes in from the server while we are busy duplicating
369 // this one.
370 lock (responseCtlSemaphore)
372 for (int i = 0; i < responseCtls.Length; i++)
374 clonedControl[i] = (LdapControl) (responseCtls[i]).Clone();
378 // Return the cloned copy. Note we have still left the
379 // control in the local responseCtls variable just in case
380 // somebody requests it again.
381 return clonedControl;
385 /// <summary> Return the Connection object associated with this LdapConnection
386 ///
387 /// </summary>
388 /// <returns> the Connection object
389 /// </returns>
390 virtual internal Connection Connection
392 /* package */
396 return conn;
400 /// <summary> Return the Connection object name associated with this LdapConnection
401 ///
402 /// </summary>
403 /// <returns> the Connection object name
404 /// </returns>
405 virtual internal System.String ConnectionName
407 /* package */
411 return name;
415 private LdapSearchConstraints defSearchCons;
416 private LdapControl[] responseCtls = null;
418 // Synchronization Object used to synchronize access to responseCtls
419 private System.Object responseCtlSemaphore;
421 private Connection conn = null;
423 private static System.Object nameLock; // protect agentNum
424 private static int lConnNum = 0; // Debug, LdapConnection number
425 private System.String name; // String name for debug
427 /// <summary> Used with search to specify that the scope of entrys to search is to
428 /// search only the base obect.
429 ///
430 /// SCOPE_BASE = 0
431 /// </summary>
432 public const int SCOPE_BASE = 0;
434 /// <summary> Used with search to specify that the scope of entrys to search is to
435 /// search only the immediate subordinates of the base obect.
436 ///
437 /// SCOPE_ONE = 1
438 /// </summary>
439 public const int SCOPE_ONE = 1;
441 /// <summary> Used with search to specify that the scope of entrys to search is to
442 /// search the base object and all entries within its subtree.
443 ///
444 /// SCOPE_ONE = 2
445 /// </summary>
446 public const int SCOPE_SUB = 2;
448 /// <summary> Used with search instead of an attribute list to indicate that no
449 /// attributes are to be returned.
450 ///
451 /// NO_ATTRS = "1.1"
452 /// </summary>
453 public const System.String NO_ATTRS = "1.1";
455 /// <summary> Used with search instead of an attribute list to indicate that all
456 /// attributes are to be returned.
457 ///
458 /// ALL_USER_ATTRS = "*"
459 /// </summary>
460 public const System.String ALL_USER_ATTRS = "*";
462 /// <summary> Specifies the Ldapv3 protocol version when performing a bind operation.
463 ///
464 /// Specifies Ldap version V3 of the protocol, and is specified
465 /// when performing bind operations.
466 /// You can use this identifier in the version parameter
467 /// of the bind method to specify an Ldapv3 bind.
468 /// Ldap_V3 is the default protocol version
469 ///
470 /// Ldap_V3 = 3
471 ///
472 /// </summary>
473 public const int Ldap_V3 = 3;
475 /// <summary> The default port number for Ldap servers.
476 ///
477 /// You can use this identifier to specify the port when establishing
478 /// a clear text connection to a server. This the default port.
479 ///
480 /// DEFAULT_PORT = 389
481 ///
482 /// </summary>
483 public const int DEFAULT_PORT = 389;
486 /// <summary> The default SSL port number for Ldap servers.
487 ///
488 /// DEFAULT_SSL_PORT = 636
489 ///
490 /// You can use this identifier to specify the port when establishing
491 /// a an SSL connection to a server..
492 /// </summary>
493 public const int DEFAULT_SSL_PORT = 636;
495 /// <summary> A string that can be passed in to the getProperty method.
496 ///
497 /// Ldap_PROPERTY_SDK = "version.sdk"
498 ///
499 /// You can use this string to request the version of the SDK.
500 /// </summary>
501 public const System.String Ldap_PROPERTY_SDK = "version.sdk";
503 /// <summary> A string that can be passed in to the getProperty method.
504 ///
505 /// Ldap_PROPERTY_PROTOCOL = "version.protocol"
506 ///
507 /// You can use this string to request the version of the
508 /// Ldap protocol.
509 /// </summary>
510 public const System.String Ldap_PROPERTY_PROTOCOL = "version.protocol";
512 /// <summary> A string that can be passed in to the getProperty method.
513 ///
514 /// Ldap_PROPERTY_SECURITY = "version.security"
515 ///
516 /// You can use this string to request the type of security
517 /// being used.
518 /// </summary>
519 public const System.String Ldap_PROPERTY_SECURITY = "version.security";
521 /// <summary> A string that corresponds to the server shutdown notification OID.
522 /// This notification may be used by the server to advise the client that
523 /// the server is about to close the connection due to an error
524 /// condition.
525 ///
526 /// SERVER_SHUTDOWN_OID = "1.3.6.1.4.1.1466.20036"
527 /// </summary>
528 public const System.String SERVER_SHUTDOWN_OID = "1.3.6.1.4.1.1466.20036";
530 /// <summary> The OID string that identifies a StartTLS request and response.</summary>
531 private const System.String START_TLS_OID = "1.3.6.1.4.1.1466.20037";
534 * Constructors
538 /// <summary> Constructs a new LdapConnection object, which will use the supplied
539 /// class factory to construct a socket connection during
540 /// LdapConnection.connect method.
541 ///
542 /// </summary>
543 /// <param name="factory"> An object capable of producing a Socket.
544 ///
545 /// </param>
546 public LdapConnection()
548 InitBlock();
549 // Get a unique connection name for debug
550 conn = new Connection();
551 return ;
554 * The following are methods that affect the operation of
555 * LdapConnection, but are not Ldap requests.
558 /// <summary> Returns a copy of the object with a private context, but sharing the
559 /// network connection if there is one.
560 ///
561 /// The network connection remains open until all clones have
562 /// disconnected or gone out of scope. Any connection opened after
563 /// cloning is private to the object making the connection.
564 ///
565 /// The clone can issue requests and freely modify options and search
566 /// constraints, and , without affecting the source object or other clones.
567 /// If the clone disconnects or reconnects, it is completely dissociated
568 /// from the source object and other clones. Reauthenticating in a clone,
569 /// however, is a global operation which will affect the source object
570 /// and all associated clones, because it applies to the single shared
571 /// physical connection. Any request by an associated object after one
572 /// has reauthenticated will carry the new identity.
573 ///
574 /// </summary>
575 /// <returns> A of the object.
576 /// </returns>
577 public System.Object Clone()
579 LdapConnection newClone;
580 System.Object newObj;
583 newObj = base.MemberwiseClone();
584 newClone = (LdapConnection) newObj;
586 catch (System.Exception ce)
588 throw new System.SystemException("Internal error, cannot create clone");
590 newClone.conn = conn; // same underlying connection
592 //now just duplicate the defSearchCons and responseCtls
593 if (defSearchCons != null)
595 newClone.defSearchCons = (LdapSearchConstraints) defSearchCons.Clone();
597 else
599 newClone.defSearchCons = null;
601 if (responseCtls != null)
603 newClone.responseCtls = new LdapControl[responseCtls.Length];
604 for (int i = 0; i < responseCtls.Length; i++)
606 newClone.responseCtls[i] = (LdapControl) responseCtls[i].Clone();
609 else
611 newClone.responseCtls = null;
613 conn.incrCloneCount(); // Increment the count of clones
614 return newObj;
617 /// <summary> Closes the connection, if open, and releases any other resources held
618 /// by the object.
619 ///
620 /// </summary>
621 /// <exception> LdapException A general exception which includes an error
622 /// message and an Ldap error code.
623 ///
624 /// </exception>
625 /// <seealso cref="Disconnect">
626 /// </seealso>
627 ~LdapConnection()
629 // Disconnect did not come from user API call
630 Disconnect(defSearchCons, false);
631 return ;
634 /// <summary> Returns a property of a connection object.
635 ///
636 /// </summary>
637 /// <param name="name"> Name of the property to be returned.
638 ///
639 /// The following read-only properties are available
640 /// for any given connection:
641 /// <ul>
642 /// <li>Ldap_PROPERTY_SDK returns the version of this SDK,
643 /// as a Float data type.</li>
644 ///
645 /// <li>Ldap_PROPERTY_PROTOCOL returns the highest supported version of
646 /// the Ldap protocol, as a Float data type.</li>
647 ///
648 /// <li>Ldap_PROPERTY_SECURITY returns a comma-separated list of the
649 /// types of authentication supported, as a
650 /// string.</li>
651 /// </ul>
652 ///
653 /// A deep copy of the property is provided where applicable; a
654 /// client does not need to clone the object received.
655 ///
656 /// </param>
657 /// <returns> The object associated with the requested property,
658 /// or null if the property is not defined.
659 ///
660 /// </returns>
661 /// <seealso cref="LdapConstraints.getProperty">
662 /// </seealso>
663 /// <seealso cref="Object">
664 /// </seealso>
665 public virtual System.Object getProperty(System.String name)
667 if (name.ToUpper().Equals(Ldap_PROPERTY_SDK.ToUpper()))
668 return Connection.sdk;
669 else if (name.ToUpper().Equals(Ldap_PROPERTY_PROTOCOL.ToUpper()))
670 return Connection.protocol;
671 else if (name.ToUpper().Equals(Ldap_PROPERTY_SECURITY.ToUpper()))
672 return Connection.security;
673 else
675 return null;
679 /// <summary> Registers an object to be notified on arrival of an unsolicited
680 /// message from a server.
681 ///
682 /// An unsolicited message has the ID 0. A new thread is created and
683 /// the method "messageReceived" in each registered object is called in
684 /// turn.
685 ///
686 /// </summary>
687 /// <param name="listener"> An object to be notified on arrival of an
688 /// unsolicited message from a server. This object must
689 /// implement the LdapUnsolicitedNotificationListener interface.
690 ///
691 /// </param>
692 public virtual void AddUnsolicitedNotificationListener(LdapUnsolicitedNotificationListener listener)
694 if (listener != null)
695 conn.AddUnsolicitedNotificationListener(listener);
700 /// <summary> Deregisters an object so that it will no longer be notified on
701 /// arrival of an unsolicited message from a server. If the object is
702 /// null or was not previously registered for unsolicited notifications,
703 /// the method does nothing.
704 ///
705 ///
706 /// </summary>
707 /// <param name="listener"> An object to no longer be notified on arrival of
708 /// an unsolicited message from a server.
709 ///
710 /// </param>
711 public virtual void RemoveUnsolicitedNotificationListener(LdapUnsolicitedNotificationListener listener)
714 if (listener != null)
715 conn.RemoveUnsolicitedNotificationListener(listener);
718 /// <summary> Starts Transport Layer Security (TLS) protocol on this connection
719 /// to enable session privacy.
720 ///
721 /// This affects the LdapConnection object and all cloned objects. A
722 /// socket factory that implements LdapTLSSocketFactory must be set on the
723 /// connection.
724 ///
725 /// </summary>
726 /// <exception> LdapException Thrown if TLS cannot be started. If a
727 /// SocketFactory has been specified that does not implement
728 /// LdapTLSSocketFactory an LdapException is thrown.
729 ///
730 /// </exception>
731 //*************************************************************************
732 // Below are all of the Ldap protocol operation methods
733 //*************************************************************************
735 //*************************************************************************
736 // abandon methods
737 //*************************************************************************
739 /// <summary>
740 ///
741 /// Notifies the server not to send additional results associated with
742 /// this LdapSearchResults object, and discards any results already
743 /// received.
744 ///
745 /// </summary>
746 /// <param name="results"> An object returned from a search.
747 ///
748 /// </param>
749 /// <exception> LdapException A general exception which includes an error
750 /// message and an Ldap error code.
751 /// </exception>
752 public virtual void Abandon(LdapSearchResults results)
754 Abandon(results, defSearchCons);
755 return ;
758 /// <summary>
759 ///
760 /// Notifies the server not to send additional results associated with
761 /// this LdapSearchResults object, and discards any results already
762 /// received.
763 ///
764 /// </summary>
765 /// <param name="results"> An object returned from a search.
766 ///
767 /// </param>
768 /// <param name="cons"> The contraints specific to the operation.
769 ///
770 /// </param>
771 /// <exception> LdapException A general exception which includes an error
772 /// message and an Ldap error code.
773 /// </exception>
774 public virtual void Abandon(LdapSearchResults results, LdapConstraints cons)
776 results.Abandon();
777 return ;
780 /// <summary>
781 /// Abandons an asynchronous operation.
782 ///
783 /// </summary>
784 /// <param name="id"> The ID of the asynchronous operation to abandon. The ID
785 /// can be obtained from the response queue for the
786 /// operation.
787 ///
788 /// </param>
789 /// <exception> LdapException A general exception which includes an error
790 /// message and an Ldap error code.
791 /// </exception>
792 public virtual void Abandon(int id)
794 Abandon(id, defSearchCons);
795 return ;
798 /// <summary> Abandons an asynchronous operation, using the specified
799 /// constraints.
800 ///
801 /// </summary>
802 /// <param name="id">The ID of the asynchronous operation to abandon.
803 /// The ID can be obtained from the search
804 /// queue for the operation.
805 ///
806 /// </param>
807 /// <param name="cons">The contraints specific to the operation.
808 ///
809 /// </param>
810 /// <exception> LdapException A general exception which includes an error
811 /// message and an Ldap error code.
812 /// </exception>
813 public virtual void Abandon(int id, LdapConstraints cons)
815 // We need to inform the Message Agent which owns this messageID to
816 // remove it from the queue.
819 MessageAgent agent = conn.getMessageAgent(id);
820 agent.Abandon(id, cons);
821 return ;
823 catch (System.FieldAccessException ex)
825 return ; // Ignore error
829 /// <summary> Abandons all outstanding operations managed by the queue.
830 ///
831 /// All operations in progress, which are managed by the specified queue,
832 /// are abandoned.
833 ///
834 /// </summary>
835 /// <param name="queue"> The queue returned from an asynchronous request.
836 /// All outstanding operations managed by the queue
837 /// are abandoned, and the queue is emptied.
838 ///
839 /// </param>
840 /// <exception> LdapException A general exception which includes an error
841 /// message and an Ldap error code.
842 /// </exception>
843 public virtual void Abandon(LdapMessageQueue queue)
845 Abandon(queue, defSearchCons);
846 return ;
849 /// <summary> Abandons all outstanding operations managed by the queue.
850 ///
851 /// All operations in progress, which are managed by the specified
852 /// queue, are abandoned.
853 ///
854 /// </summary>
855 /// <param name="queue"> The queue returned from an asynchronous request.
856 /// All outstanding operations managed by the queue
857 /// are abandoned, and the queue is emptied.
858 ///
859 /// </param>
860 /// <param name="cons"> The contraints specific to the operation.
861 ///
862 /// </param>
863 /// <exception> LdapException A general exception which includes an error
864 /// message and an Ldap error code.
865 /// </exception>
866 public virtual void Abandon(LdapMessageQueue queue, LdapConstraints cons)
868 if (queue != null)
870 MessageAgent agent;
871 if (queue is LdapSearchQueue)
873 agent = queue.MessageAgent;
875 else
877 agent = queue.MessageAgent;
879 int[] msgIds = agent.MessageIDs;
880 for (int i = 0; i < msgIds.Length; i++)
882 agent.Abandon(msgIds[i], cons);
885 return ;
888 //*************************************************************************
889 // add methods
890 //*************************************************************************
892 /// <summary> Synchronously adds an entry to the directory.
893 ///
894 /// </summary>
895 /// <param name="entry"> LdapEntry object specifying the distinguished
896 /// name and attributes of the new entry.
897 ///
898 /// </param>
899 /// <exception> LdapException A general exception which includes an error
900 /// message and an Ldap error code.
901 /// </exception>
902 public virtual void Add(LdapEntry entry)
904 Add(entry, defSearchCons);
905 return ;
908 /// <summary>
909 /// Synchronously adds an entry to the directory, using the specified
910 /// constraints.
911 ///
912 /// </summary>
913 /// <param name="entry"> LdapEntry object specifying the distinguished
914 /// name and attributes of the new entry.
915 ///
916 /// </param>
917 /// <param name="cons"> Constraints specific to the operation.
918 ///
919 /// </param>
920 /// <exception> LdapException A general exception which includes an error
921 /// message and an Ldap error code.
922 /// </exception>
924 public virtual void Add(LdapEntry entry, LdapConstraints cons)
926 LdapResponseQueue queue = Add(entry, null, cons);
928 // Get a handle to the add response
929 LdapResponse addResponse = (LdapResponse) (queue.getResponse());
931 // Set local copy of responseControls synchronously if there were any
932 lock (responseCtlSemaphore)
934 responseCtls = addResponse.Controls;
936 chkResultCode(queue, cons, addResponse);
937 return ;
940 /// <summary> Asynchronously adds an entry to the directory.
941 ///
942 /// </summary>
943 /// <param name="entry"> LdapEntry object specifying the distinguished
944 /// name and attributes of the new entry.
945 ///
946 /// </param>
947 /// <param name="queue"> Handler for messages returned from a server in
948 /// response to this request. If it is null, a
949 /// queue object is created internally.
950 ///
951 /// </param>
952 /// <exception> LdapException A general exception which includes an error
953 /// message and an Ldap error code.
954 /// </exception>
955 public virtual LdapResponseQueue Add(LdapEntry entry, LdapResponseQueue queue)
957 return Add(entry, queue, defSearchCons);
960 /// <summary> Asynchronously adds an entry to the directory, using the specified
961 /// constraints.
962 ///
963 /// </summary>
964 /// <param name="entry"> LdapEntry object specifying the distinguished
965 /// name and attributes of the new entry.
966 ///
967 /// </param>
968 /// <param name="queue"> Handler for messages returned from a server in
969 /// response to this request. If it is null, a
970 /// queue object is created internally.
971 ///
972 /// </param>
973 /// <param name="cons"> Constraints specific to the operation.
974 ///
975 /// </param>
976 /// <exception> LdapException A general exception which includes an error
977 /// message and an Ldap error code.
978 /// </exception>
979 public virtual LdapResponseQueue Add(LdapEntry entry, LdapResponseQueue queue, LdapConstraints cons)
981 if (cons == null)
982 cons = defSearchCons;
984 // error check the parameters
985 if (entry == null)
987 throw new System.ArgumentException("The LdapEntry parameter" + " cannot be null");
989 if ((System.Object) entry.DN == null)
991 throw new System.ArgumentException("The DN value must be present" + " in the LdapEntry object");
994 LdapMessage msg = new LdapAddRequest(entry, cons.getControls());
996 return SendRequestToServer(msg, cons.TimeLimit, queue, null);
999 //*************************************************************************
1000 // bind methods
1001 //*************************************************************************
1003 /// <summary> Synchronously authenticates to the Ldap server (that the object is
1004 /// currently connected to) as an Ldapv3 bind, using the specified name and
1005 /// password.
1006 ///
1007 /// If the object has been disconnected from an Ldap server,
1008 /// this method attempts to reconnect to the server. If the object
1009 /// has already authenticated, the old authentication is discarded.
1010 ///
1011 /// </summary>
1012 /// <param name="dn"> If non-null and non-empty, specifies that the
1013 /// connection and all operations through it should
1014 /// be authenticated with dn as the distinguished
1015 /// name.
1016 ///
1017 /// </param>
1018 /// <param name="passwd"> If non-null and non-empty, specifies that the
1019 /// connection and all operations through it should
1020 /// be authenticated with dn as the distinguished
1021 /// name and passwd as password.
1022 ///
1023 /// Note: the application should use care in the use
1024 /// of String password objects. These are long lived
1025 /// objects, and may expose a security risk, especially
1026 /// in objects that are serialized. The LdapConnection
1027 /// keeps no long lived instances of these objects.
1028 ///
1029 /// </param>
1030 /// <exception> LdapException A general exception which includes an error
1031 /// message and an Ldap error code.
1032 ///
1033 /// </exception>
1034 public virtual void Bind(System.String dn, System.String passwd)
1036 Bind(Ldap_V3, dn, passwd, defSearchCons);
1037 return ;
1040 /// <summary> Synchronously authenticates to the Ldap server (that the object is
1041 /// currently connected to) using the specified name, password,
1042 /// and Ldap version.
1043 ///
1044 /// If the object has been disconnected from an Ldap server,
1045 /// this method attempts to reconnect to the server. If the object
1046 /// has already authenticated, the old authentication is discarded.
1047 ///
1048 /// </summary>
1049 /// <param name="version"> The Ldap protocol version, use Ldap_V3.
1050 /// Ldap_V2 is not supported.
1051 ///
1052 /// </param>
1053 /// <param name="dn"> If non-null and non-empty, specifies that the
1054 /// connection and all operations through it should
1055 /// be authenticated with dn as the distinguished
1056 /// name.
1057 ///
1058 /// </param>
1059 /// <param name="passwd"> If non-null and non-empty, specifies that the
1060 /// connection and all operations through it should
1061 /// be authenticated with dn as the distinguished
1062 /// name and passwd as password.
1063 ///
1064 /// Note: the application should use care in the use
1065 /// of String password objects. These are long lived
1066 /// objects, and may expose a security risk, especially
1067 /// in objects that are serialized. The LdapConnection
1068 /// keeps no long lived instances of these objects.
1069 ///
1070 /// </param>
1071 /// <exception> LdapException A general exception which includes an error
1072 /// message and an Ldap error code.
1073 ///
1074 /// </exception>
1075 public virtual void Bind(int version, System.String dn, System.String passwd)
1077 Bind(version, dn, passwd, defSearchCons);
1078 return ;
1081 /// <summary> Synchronously authenticates to the Ldap server (that the object is
1082 /// currently connected to) as an Ldapv3 bind, using the specified name,
1083 /// password, and constraints.
1084 ///
1085 /// If the object has been disconnected from an Ldap server,
1086 /// this method attempts to reconnect to the server. If the object
1087 /// has already authenticated, the old authentication is discarded.
1088 ///
1089 /// </summary>
1090 /// <param name="dn"> If non-null and non-empty, specifies that the
1091 /// connection and all operations through it should
1092 /// be authenticated with dn as the distinguished
1093 /// name.
1094 ///
1095 /// </param>
1096 /// <param name="passwd"> If non-null and non-empty, specifies that the
1097 /// connection and all operations through it should
1098 /// be authenticated with dn as the distinguished
1099 /// name and passwd as password.
1100 /// Note: the application should use care in the use
1101 /// of String password objects. These are long lived
1102 /// objects, and may expose a security risk, especially
1103 /// in objects that are serialized. The LdapConnection
1104 /// keeps no long lived instances of these objects.
1105 ///
1106 /// </param>
1107 /// <param name="cons"> Constraints specific to the operation.
1108 ///
1109 /// </param>
1110 /// <exception> LdapException A general exception which includes an error
1111 /// message and an Ldap error code.
1112 ///
1113 /// </exception>
1114 public virtual void Bind(System.String dn, System.String passwd, LdapConstraints cons)
1116 Bind(Ldap_V3, dn, passwd, cons);
1117 return ;
1120 /// <summary> Synchronously authenticates to the Ldap server (that the object is
1121 /// currently connected to) using the specified name, password, Ldap version,
1122 /// and constraints.
1123 ///
1124 /// If the object has been disconnected from an Ldap server,
1125 /// this method attempts to reconnect to the server. If the object
1126 /// has already authenticated, the old authentication is discarded.
1127 ///
1128 /// </summary>
1129 /// <param name="version"> The Ldap protocol version, use Ldap_V3.
1130 /// Ldap_V2 is not supported.
1131 ///
1132 /// </param>
1133 /// <param name="dn"> If non-null and non-empty, specifies that the
1134 /// connection and all operations through it should
1135 /// be authenticated with dn as the distinguished
1136 /// name.
1137 ///
1138 /// </param>
1139 /// <param name="passwd"> If non-null and non-empty, specifies that the
1140 /// connection and all operations through it should
1141 /// be authenticated with dn as the distinguished
1142 /// name and passwd as password.
1143 ///
1144 /// Note: the application should use care in the use
1145 /// of String password objects. These are long lived
1146 /// objects, and may expose a security risk, especially
1147 /// in objects that are serialized. The LdapConnection
1148 /// keeps no long lived instances of these objects.
1149 ///
1150 /// </param>
1151 /// <param name="cons"> The constraints specific to the operation.
1152 ///
1153 /// </param>
1154 /// <exception> LdapException A general exception which includes an error
1155 /// message and an Ldap error code.
1156 ///
1157 /// </exception>
1158 public virtual void Bind(int version, System.String dn, System.String passwd, LdapConstraints cons)
1160 sbyte[] pw = null;
1161 if ((System.Object) passwd != null)
1165 System.Text.Encoding encoder = System.Text.Encoding.GetEncoding("utf-8");
1166 byte[] ibytes = encoder.GetBytes(passwd);
1167 pw=SupportClass.ToSByteArray(ibytes);
1169 // pw = passwd.getBytes("UTF8");
1170 passwd = null; // Keep no reference to String object
1172 catch (System.IO.IOException ex)
1174 passwd = null; // Keep no reference to String object
1175 throw new System.SystemException(ex.ToString());
1178 Bind(version, dn, pw, cons);
1179 return ;
1182 /// <summary> Synchronously authenticates to the Ldap server (that the object is
1183 /// currently connected to) using the specified name, password,
1184 /// and Ldap version.
1185 ///
1186 /// If the object has been disconnected from an Ldap server,
1187 /// this method attempts to reconnect to the server. If the object
1188 /// has already authenticated, the old authentication is discarded.
1189 ///
1190 /// </summary>
1191 /// <param name="version"> The version of the Ldap protocol to use
1192 /// in the bind, use Ldap_V3. Ldap_V2 is not supported.
1193 ///
1194 /// </param>
1195 /// <param name="dn"> If non-null and non-empty, specifies that the
1196 /// connection and all operations through it should
1197 /// be authenticated with dn as the distinguished
1198 /// name.
1199 ///
1200 /// </param>
1201 /// <param name="passwd"> If non-null and non-empty, specifies that the
1202 /// connection and all operations through it should
1203 /// be authenticated with dn as the distinguished
1204 /// name and passwd as password.
1205 ///
1206 /// </param>
1207 /// <exception> LdapException A general exception which includes an error
1208 /// message and an Ldap error code.
1209 /// </exception>
1210 [CLSCompliantAttribute(false)]
1211 public virtual void Bind(int version, System.String dn, sbyte[] passwd)
1213 Bind(version, dn, passwd, defSearchCons);
1214 return ;
1217 /// <summary>
1218 /// Synchronously authenticates to the Ldap server (that the object is
1219 /// currently connected to) using the specified name, password, Ldap version,
1220 /// and constraints.
1221 ///
1222 /// If the object has been disconnected from an Ldap server,
1223 /// this method attempts to reconnect to the server. If the object
1224 /// has already authenticated, the old authentication is discarded.
1225 ///
1226 /// </summary>
1227 /// <param name="version"> The Ldap protocol version, use Ldap_V3.
1228 /// Ldap_V2 is not supported.
1229 ///
1230 /// </param>
1231 /// <param name="dn"> If non-null and non-empty, specifies that the
1232 /// connection and all operations through it should
1233 /// be authenticated with dn as the distinguished
1234 /// name.
1235 ///
1236 /// </param>
1237 /// <param name="passwd"> If non-null and non-empty, specifies that the
1238 /// connection and all operations through it should
1239 /// be authenticated with dn as the distinguished
1240 /// name and passwd as password.
1241 ///
1242 /// </param>
1243 /// <param name="cons"> The constraints specific to the operation.
1244 ///
1245 /// </param>
1246 /// <exception> LdapException A general exception which includes an error
1247 /// message and an Ldap error code.
1248 /// </exception>
1249 [CLSCompliantAttribute(false)]
1250 public virtual void Bind(int version, System.String dn, sbyte[] passwd, LdapConstraints cons)
1252 LdapResponseQueue queue = Bind(version, dn, passwd, null, cons);
1253 LdapResponse res = (LdapResponse) queue.getResponse();
1254 if (res != null)
1256 // Set local copy of responseControls synchronously if any
1257 lock (responseCtlSemaphore)
1259 responseCtls = res.Controls;
1262 chkResultCode(queue, cons, res);
1264 return ;
1267 /// <summary> Asynchronously authenticates to the Ldap server (that the object is
1268 /// currently connected to) using the specified name, password, Ldap
1269 /// version, and queue.
1270 ///
1271 /// If the object has been disconnected from an Ldap server,
1272 /// this method attempts to reconnect to the server. If the object
1273 /// has already authenticated, the old authentication is discarded.
1274 ///
1275 ///
1276 /// </summary>
1277 /// <param name="version"> The Ldap protocol version, use Ldap_V3.
1278 /// Ldap_V2 is not supported.
1279 ///
1280 /// </param>
1281 /// <param name="dn"> If non-null and non-empty, specifies that the
1282 /// connection and all operations through it should
1283 /// be authenticated with dn as the distinguished
1284 /// name.
1285 ///
1286 /// </param>
1287 /// <param name="passwd"> If non-null and non-empty, specifies that the
1288 /// connection and all operations through it should
1289 /// be authenticated with dn as the distinguished
1290 /// name and passwd as password.
1291 ///
1292 /// </param>
1293 /// <param name="queue"> Handler for messages returned from a server in
1294 /// response to this request. If it is null, a
1295 /// queue object is created internally.
1296 ///
1297 /// </param>
1298 /// <exception> LdapException A general exception which includes an error
1299 /// message and an Ldap error code.
1300 /// </exception>
1301 [CLSCompliantAttribute(false)]
1302 public virtual LdapResponseQueue Bind(int version, System.String dn, sbyte[] passwd, LdapResponseQueue queue)
1304 return Bind(version, dn, passwd, queue, defSearchCons);
1307 /// <summary> Asynchronously authenticates to the Ldap server (that the object is
1308 /// currently connected to) using the specified name, password, Ldap
1309 /// version, queue, and constraints.
1310 ///
1311 /// If the object has been disconnected from an Ldap server,
1312 /// this method attempts to reconnect to the server. If the object
1313 /// had already authenticated, the old authentication is discarded.
1314 ///
1315 /// </summary>
1316 /// <param name="version"> The Ldap protocol version, use Ldap_V3.
1317 /// Ldap_V2 is not supported.
1318 ///
1319 /// </param>
1320 /// <param name="dn"> If non-null and non-empty, specifies that the
1321 /// connection and all operations through it should
1322 /// be authenticated with dn as the distinguished
1323 /// name.
1324 ///
1325 /// </param>
1326 /// <param name="passwd"> If non-null and non-empty, specifies that the
1327 /// connection and all operations through it should
1328 /// be authenticated with dn as the distinguished
1329 /// name and passwd as password.
1330 ///
1331 /// </param>
1332 /// <param name="queue"> Handler for messages returned from a server in
1333 /// response to this request. If it is null, a
1334 /// queue object is created internally.
1335 ///
1336 /// </param>
1337 /// <param name="cons"> Constraints specific to the operation.
1338 ///
1339 /// </param>
1340 /// <exception> LdapException A general exception which includes an error
1341 /// message and an Ldap error code.
1342 /// </exception>
1343 [CLSCompliantAttribute(false)]
1344 public virtual LdapResponseQueue Bind(int version, System.String dn, sbyte[] passwd, LdapResponseQueue queue, LdapConstraints cons)
1346 int msgId;
1347 BindProperties bindProps;
1348 if (cons == null)
1349 cons = defSearchCons;
1351 if ((System.Object) dn == null)
1353 dn = "";
1355 else
1357 dn = dn.Trim();
1360 if (passwd == null)
1361 passwd = new sbyte[]{};
1363 bool anonymous = false;
1364 if (passwd.Length == 0)
1366 anonymous = true; // anonymous, passwd length zero with simple bind
1367 dn = ""; // set to null if anonymous
1370 LdapMessage msg = new LdapBindRequest(version, dn, passwd, cons.getControls());
1372 msgId = msg.MessageID;
1373 bindProps = new BindProperties(version, dn, "simple", anonymous, null, null);
1375 // For bind requests, if not connected, attempt to reconnect
1376 if (!conn.Connected)
1378 if ((System.Object) conn.Host != null)
1380 conn.connect(conn.Host, conn.Port);
1382 else
1384 throw new LdapException(ExceptionMessages.CONNECTION_IMPOSSIBLE, LdapException.CONNECT_ERROR, null);
1388 // The semaphore is released when the bind response is queued.
1389 conn.acquireWriteSemaphore(msgId);
1391 return SendRequestToServer(msg, cons.TimeLimit, queue, bindProps);
1394 //*************************************************************************
1395 // compare methods
1396 //*************************************************************************
1398 /// <summary>
1399 /// Synchronously checks to see if an entry contains an attribute
1400 /// with a specified value.
1401 ///
1402 /// </summary>
1403 /// <param name="dn"> The distinguished name of the entry to use in the
1404 /// comparison.
1405 ///
1406 /// </param>
1407 /// <param name="attr"> The attribute to compare against the entry. The
1408 /// method checks to see if the entry has an
1409 /// attribute with the same name and value as this
1410 /// attribute.
1411 ///
1412 /// </param>
1413 /// <returns> True if the entry has the value,
1414 /// and false if the entry does not
1415 /// have the value or the attribute.
1416 ///
1417 /// </returns>
1418 /// <exception> LdapException A general exception which includes an error
1419 /// message and an Ldap error code.
1420 /// </exception>
1421 public virtual bool Compare(System.String dn, LdapAttribute attr)
1423 return Compare(dn, attr, defSearchCons);
1426 /// <summary>
1427 /// Synchronously checks to see if an entry contains an attribute with a
1428 /// specified value, using the specified constraints.
1429 ///
1430 /// </summary>
1431 /// <param name="dn"> The distinguished name of the entry to use in the
1432 /// comparison.
1433 ///
1434 /// </param>
1435 /// <param name="attr"> The attribute to compare against the entry. The
1436 /// method checks to see if the entry has an
1437 /// attribute with the same name and value as this
1438 /// attribute.
1439 ///
1440 /// </param>
1441 /// <param name="cons"> Constraints specific to the operation.
1442 ///
1443 /// </param>
1444 /// <returns> True if the entry has the value,
1445 /// and false if the entry does not
1446 /// have the value or the attribute.
1447 ///
1448 /// </returns>
1449 /// <exception> LdapException A general exception which includes an error
1450 /// message and an Ldap error code.
1451 /// </exception>
1452 public virtual bool Compare(System.String dn, LdapAttribute attr, LdapConstraints cons)
1454 bool ret = false;
1456 LdapResponseQueue queue = Compare(dn, attr, null, cons);
1458 LdapResponse res = (LdapResponse) queue.getResponse();
1460 // Set local copy of responseControls synchronously - if there were any
1461 lock (responseCtlSemaphore)
1463 responseCtls = res.Controls;
1466 if (res.ResultCode == LdapException.COMPARE_TRUE)
1468 ret = true;
1470 else if (res.ResultCode == LdapException.COMPARE_FALSE)
1472 ret = false;
1474 else
1476 chkResultCode(queue, cons, res);
1478 return ret;
1481 /// <summary> Asynchronously compares an attribute value with one in the directory,
1482 /// using the specified queue.
1483 ///
1484 /// Please note that a successful completion of this command results in
1485 /// one of two status codes: LdapException.COMPARE_TRUE if the entry
1486 /// has the value, and LdapException.COMPARE_FALSE if the entry
1487 /// does not have the value or the attribute.
1488 ///
1489 /// </summary>
1490 /// <param name="dn"> The distinguished name of the entry containing an
1491 /// attribute to compare.
1492 ///
1493 /// </param>
1494 /// <param name="attr"> An attribute to compare.
1495 ///
1496 /// </param>
1497 /// <param name="queue"> The queue for messages returned from a server in
1498 /// response to this request. If it is null, a
1499 /// queue object is created internally.
1500 ///
1501 /// </param>
1502 /// <exception> LdapException A general exception which includes an error
1503 /// message and an Ldap error code.
1504 ///
1505 /// </exception>
1506 /// <seealso cref="LdapException.COMPARE_TRUE">
1507 /// </seealso>
1508 /// <seealso cref="LdapException.COMPARE_FALSE">
1509 /// </seealso>
1510 public virtual LdapResponseQueue Compare(System.String dn, LdapAttribute attr, LdapResponseQueue queue)
1512 return Compare(dn, attr, queue, defSearchCons);
1515 /// <summary> Asynchronously compares an attribute value with one in the directory,
1516 /// using the specified queue and contraints.
1517 ///
1518 /// Please note that a successful completion of this command results in
1519 /// one of two status codes: LdapException.COMPARE_TRUE if the entry
1520 /// has the value, and LdapException.COMPARE_FALSE if the entry
1521 /// does not have the value or the attribute.
1522 ///
1523 /// </summary>
1524 /// <param name="dn"> The distinguished name of the entry containing an
1525 /// attribute to compare.
1526 ///
1527 /// </param>
1528 /// <param name="attr"> An attribute to compare.
1529 ///
1530 /// </param>
1531 /// <param name="queue"> Handler for messages returned from a server in
1532 /// response to this request. If it is null, a
1533 /// queue object is created internally.
1534 ///
1535 /// </param>
1536 /// <param name="cons"> Constraints specific to the operation.
1537 ///
1538 /// </param>
1539 /// <exception> LdapException A general exception which includes an error
1540 /// message and an Ldap error code.
1541 ///
1542 /// </exception>
1543 /// <seealso cref="LdapException.COMPARE_TRUE">
1544 /// </seealso>
1545 /// <seealso cref="LdapException.COMPARE_FALSE">
1546 /// </seealso>
1547 public virtual LdapResponseQueue Compare(System.String dn, LdapAttribute attr, LdapResponseQueue queue, LdapConstraints cons)
1549 if (attr.size() != 1)
1551 throw new System.ArgumentException("compare: Exactly one value " + "must be present in the LdapAttribute");
1554 if ((System.Object) dn == null)
1556 // Invalid parameter
1557 throw new System.ArgumentException("compare: DN cannot be null");
1560 if (cons == null)
1561 cons = defSearchCons;
1563 LdapMessage msg = new LdapCompareRequest(dn, attr.Name, attr.ByteValue, cons.getControls());
1565 return SendRequestToServer(msg, cons.TimeLimit, queue, null);
1568 //*************************************************************************
1569 // connect methods
1570 //*************************************************************************
1572 /// <summary>
1573 /// Connects to the specified host and port.
1574 ///
1575 /// If this LdapConnection object represents an open connection, the
1576 /// connection is closed first before the new connection is opened.
1577 /// At this point, there is no authentication, and any operations are
1578 /// conducted as an anonymous client.
1579 ///
1580 /// When more than one host name is specified, each host is contacted
1581 /// in turn until a connection can be established.
1582 ///
1583 /// </summary>
1584 /// <param name="host">A host name or a dotted string representing the IP address
1585 /// of a host running an Ldap server. It may also
1586 /// contain a list of host names, space-delimited. Each host
1587 /// name can include a trailing colon and port number.
1588 ///
1589 /// </param>
1590 /// <param name="port">The TCP or UDP port number to connect to or contact.
1591 /// The default Ldap port is 389. The port parameter is
1592 /// ignored for any host hame which includes a colon and
1593 /// port number.
1594 ///
1595 /// </param>
1596 /// <exception> LdapException A general exception which includes an error
1597 /// message and an Ldap error code.
1598 ///
1599 /// </exception>
1600 public virtual void Connect(System.String host, int port)
1602 // connect doesn't affect other clones
1603 // If not a clone, destroys old connection.
1604 // Step through the space-delimited list
1605 SupportClass.Tokenizer hostList = new SupportClass.Tokenizer(host, " ");
1606 System.String address = null;
1608 int specifiedPort;
1609 int colonIndex; //after the colon is the port
1610 while (hostList.HasMoreTokens())
1614 specifiedPort = port;
1615 address = hostList.NextToken();
1616 colonIndex = address.IndexOf((System.Char) ':');
1617 if (colonIndex != - 1 && colonIndex + 1 != address.Length)
1619 //parse Port out of address
1622 specifiedPort = System.Int32.Parse(address.Substring(colonIndex + 1));
1623 address = address.Substring(0, (colonIndex) - (0));
1625 catch (System.Exception e)
1627 throw new System.ArgumentException(ExceptionMessages.INVALID_ADDRESS);
1630 // This may return a different conn object
1631 // Disassociate this clone with the underlying connection.
1632 conn = conn.destroyClone(true);
1633 conn.connect(address, specifiedPort);
1634 break;
1636 catch (LdapException LE)
1638 if (!hostList.HasMoreTokens())
1639 throw LE;
1642 return ;
1645 //*************************************************************************
1646 // delete methods
1647 //*************************************************************************
1649 /// <summary>
1650 /// Synchronously deletes the entry with the specified distinguished name
1651 /// from the directory.
1652 ///
1653 /// Note: A Delete operation will not remove an entry that contains
1654 /// subordinate entries, nor will it dereference alias entries.
1655 ///
1656 /// </summary>
1657 /// <param name="dn"> The distinguished name of the entry to delete.
1658 ///
1659 /// </param>
1660 /// <exception> LdapException A general exception which includes an error
1661 /// message and an Ldap error code.
1662 /// </exception>
1663 public virtual void Delete(System.String dn)
1665 Delete(dn, defSearchCons);
1666 return ;
1670 /// <summary> Synchronously deletes the entry with the specified distinguished name
1671 /// from the directory, using the specified constraints.
1672 ///
1673 /// Note: A Delete operation will not remove an entry that contains
1674 /// subordinate entries, nor will it dereference alias entries.
1675 ///
1676 /// </summary>
1677 /// <param name="dn"> The distinguished name of the entry to delete.
1678 ///
1679 /// </param>
1680 /// <param name="cons"> Constraints specific to the operation.
1681 ///
1682 /// </param>
1683 /// <exception> LdapException A general exception which includes an error
1684 /// message and an Ldap error code.
1685 /// </exception>
1686 public virtual void Delete(System.String dn, LdapConstraints cons)
1688 LdapResponseQueue queue = Delete(dn, null, cons);
1690 // Get a handle to the delete response
1691 LdapResponse deleteResponse = (LdapResponse) (queue.getResponse());
1693 // Set local copy of responseControls synchronously - if there were any
1694 lock (responseCtlSemaphore)
1696 responseCtls = deleteResponse.Controls;
1698 chkResultCode(queue, cons, deleteResponse);
1699 return ;
1702 /// <summary> Asynchronously deletes the entry with the specified distinguished name
1703 /// from the directory and returns the results to the specified queue.
1704 ///
1705 /// Note: A Delete operation will not remove an entry that contains
1706 /// subordinate entries, nor will it dereference alias entries.
1707 ///
1708 /// </summary>
1709 /// <param name="dn"> The distinguished name of the entry to modify.
1710 ///
1711 /// </param>
1712 /// <param name="queue"> The queue for messages returned from a server in
1713 /// response to this request. If it is null, a
1714 /// queue object is created internally.
1715 ///
1716 /// </param>
1717 /// <exception> LdapException A general exception which includes an error
1718 /// message and an Ldap error code.
1719 ///
1720 /// </exception>
1721 public virtual LdapResponseQueue Delete(System.String dn, LdapResponseQueue queue)
1723 return Delete(dn, queue, defSearchCons);
1726 /// <summary> Asynchronously deletes the entry with the specified distinguished name
1727 /// from the directory, using the specified contraints and queue.
1728 ///
1729 /// Note: A Delete operation will not remove an entry that contains
1730 /// subordinate entries, nor will it dereference alias entries.
1731 ///
1732 /// </summary>
1733 /// <param name="dn"> The distinguished name of the entry to delete.
1734 ///
1735 /// </param>
1736 /// <param name="queue"> The queue for messages returned from a server in
1737 /// response to this request. If it is null, a
1738 /// queue object is created internally.
1739 ///
1740 /// </param>
1741 /// <param name="cons"> The constraints specific to the operation.
1742 ///
1743 /// </param>
1744 /// <exception> LdapException A general exception which includes an error
1745 /// message and an Ldap error code.
1746 ///
1747 /// </exception>
1748 public virtual LdapResponseQueue Delete(System.String dn, LdapResponseQueue queue, LdapConstraints cons)
1750 if ((System.Object) dn == null)
1752 // Invalid DN parameter
1753 throw new System.ArgumentException(ExceptionMessages.DN_PARAM_ERROR);
1756 if (cons == null)
1757 cons = defSearchCons;
1759 LdapMessage msg = new LdapDeleteRequest(dn, cons.getControls());
1761 return SendRequestToServer(msg, cons.TimeLimit, queue, null);
1764 //*************************************************************************
1765 // disconnect method
1766 //*************************************************************************
1768 /// <summary>
1769 /// Synchronously disconnects from the Ldap server.
1770 ///
1771 /// Before the object can perform Ldap operations again, it must
1772 /// reconnect to the server by calling connect.
1773 ///
1774 /// The disconnect method abandons any outstanding requests, issues an
1775 /// unbind request to the server, and then closes the socket.
1776 ///
1777 /// </summary>
1778 /// <exception> LdapException A general exception which includes an error
1779 /// message and an Ldap error code.
1780 ///
1781 /// </exception>
1782 public virtual void Disconnect()
1784 // disconnect from API call
1785 Disconnect(defSearchCons, true);
1786 return ;
1789 /// <summary> Synchronously disconnects from the Ldap server.
1790 ///
1791 /// Before the object can perform Ldap operations again, it must
1792 /// reconnect to the server by calling connect.
1793 ///
1794 /// The disconnect method abandons any outstanding requests, issues an
1795 /// unbind request to the server, and then closes the socket.
1796 ///
1797 /// </summary>
1798 /// <param name="cons">LDPConstraints to be set with the unbind request
1799 ///
1800 /// </param>
1801 /// <exception> LdapException A general exception which includes an error
1802 /// message and an Ldap error code.
1803 /// </exception>
1804 public virtual void Disconnect(LdapConstraints cons)
1806 // disconnect from API call
1807 Disconnect(cons, true);
1808 return ;
1811 /// <summary> Synchronously disconnect from the server
1812 ///
1813 /// </summary>
1814 /// <param name="how">true if application call disconnect API, false if finalize.
1815 /// </param>
1816 private void Disconnect(LdapConstraints cons, bool how)
1818 // disconnect doesn't affect other clones
1819 // If not a clone, distroys connection
1820 conn = conn.destroyClone(how);
1821 return ;
1824 //*************************************************************************
1825 // extendedOperation methods
1826 //*************************************************************************
1828 /// <summary> Provides a synchronous means to access extended, non-mandatory
1829 /// operations offered by a particular Ldapv3 compliant server.
1830 ///
1831 /// </summary>
1832 /// <param name="op"> The object which contains (1) an identifier of an extended
1833 /// operation which should be recognized by the particular Ldap
1834 /// server this client is connected to and (2)
1835 /// an operation-specific sequence of octet strings
1836 /// or BER-encoded values.
1837 ///
1838 /// </param>
1839 /// <returns> An operation-specific object, containing an ID and either an octet
1840 /// string or BER-encoded values.
1841 ///
1842 /// </returns>
1843 /// <exception> LdapException A general exception which includes an error
1844 /// message and an Ldap error code.
1845 /// </exception>
1846 public virtual LdapExtendedResponse ExtendedOperation(LdapExtendedOperation op)
1848 return ExtendedOperation(op, defSearchCons);
1852 * Synchronous Ldap extended request with SearchConstraints
1855 /// <summary>
1856 /// Provides a synchronous means to access extended, non-mandatory
1857 /// operations offered by a particular Ldapv3 compliant server.
1858 ///
1859 /// </summary>
1860 /// <param name="op"> The object which contains (1) an identifier of an extended
1861 /// operation which should be recognized by the particular Ldap
1862 /// server this client is connected to and (2) an
1863 /// operation-specific sequence of octet strings
1864 /// or BER-encoded values.
1865 ///
1866 /// </param>
1867 /// <param name="cons">The constraints specific to the operation.
1868 ///
1869 /// </param>
1870 /// <returns> An operation-specific object, containing an ID and either an
1871 /// octet string or BER-encoded values.
1872 ///
1873 /// </returns>
1874 /// <exception> LdapException A general exception which includes an error
1875 /// message and an Ldap error code.
1876 /// </exception>
1878 public virtual LdapExtendedResponse ExtendedOperation(LdapExtendedOperation op, LdapConstraints cons)
1881 // Call asynchronous API and get back handler to reponse queue
1882 LdapResponseQueue queue = ExtendedOperation(op, cons, null);
1883 LdapExtendedResponse response = (LdapExtendedResponse) queue.getResponse();
1885 // Set local copy of responseControls synchronously - if there were any
1886 lock (responseCtlSemaphore)
1888 responseCtls = response.Controls;
1891 chkResultCode(queue, cons, response);
1892 return response;
1897 * Asynchronous Ldap extended request
1900 /// <summary> Provides an asynchronous means to access extended, non-mandatory
1901 /// operations offered by a particular Ldapv3 compliant server.
1902 ///
1903 /// </summary>
1904 /// <param name="op"> The object which contains (1) an identifier of an extended
1905 /// operation which should be recognized by the particular Ldap
1906 /// server this client is connected to and (2) an
1907 /// operation-specific sequence of octet strings
1908 /// or BER-encoded values.
1909 ///
1910 /// </param>
1911 /// <param name="queue"> The queue for messages returned from a server in
1912 /// response to this request. If it is null, a queue
1913 /// object is created internally.
1914 ///
1915 /// </param>
1916 /// <returns> An operation-specific object, containing an ID and either an octet
1917 /// string or BER-encoded values.
1918 ///
1919 /// </returns>
1920 /// <exception> LdapException A general exception which includes an error
1921 /// message and an Ldap error code.
1922 /// </exception>
1924 public virtual LdapResponseQueue ExtendedOperation(LdapExtendedOperation op, LdapResponseQueue queue)
1927 return ExtendedOperation(op, defSearchCons, queue);
1932 * Asynchronous Ldap extended request with SearchConstraints
1935 /// <summary> Provides an asynchronous means to access extended, non-mandatory
1936 /// operations offered by a particular Ldapv3 compliant server.
1937 ///
1938 /// </summary>
1939 /// <param name="op"> The object which contains (1) an identifier of an extended
1940 /// operation which should be recognized by the particular Ldap
1941 /// server this client is connected to and (2) an operation-
1942 /// specific sequence of octet strings or BER-encoded values.
1943 ///
1944 /// </param>
1945 /// <param name="queue"> The queue for messages returned from a server in
1946 /// response to this request. If it is null, a queue
1947 /// object is created internally.
1948 ///
1949 /// </param>
1950 /// <param name="cons"> The constraints specific to this operation.
1951 ///
1952 /// </param>
1953 /// <returns> An operation-specific object, containing an ID and either an
1954 /// octet string or BER-encoded values.
1955 ///
1956 /// </returns>
1957 /// <exception> LdapException A general exception which includes an error
1958 /// message and an Ldap error code.
1959 /// </exception>
1961 public virtual LdapResponseQueue ExtendedOperation(LdapExtendedOperation op, LdapConstraints cons, LdapResponseQueue queue)
1963 // Use default constraints if none-specified
1964 if (cons == null)
1965 cons = defSearchCons;
1966 LdapMessage msg = MakeExtendedOperation(op, cons);
1967 return SendRequestToServer(msg, cons.TimeLimit, queue, null);
1970 /// <summary> Formulates the extended operation, constraints into an
1971 /// LdapMessage and returns the LdapMessage. This is used by
1972 /// extendedOperation and startTLS which needs the LdapMessage to
1973 /// get the MessageID.
1974 /// </summary>
1975 protected internal virtual LdapMessage MakeExtendedOperation(LdapExtendedOperation op, LdapConstraints cons)
1977 // Use default constraints if none-specified
1978 if (cons == null)
1979 cons = defSearchCons;
1981 // error check the parameters
1982 if ((System.Object) op.getID() == null)
1984 // Invalid extended operation parameter, no OID specified
1985 throw new System.ArgumentException(ExceptionMessages.OP_PARAM_ERROR);
1988 return new LdapExtendedRequest(op, cons.getControls());
1991 //*************************************************************************
1992 // getResponseControls method
1993 //*************************************************************************
1995 //*************************************************************************
1996 // modify methods
1997 //*************************************************************************
1999 /// <summary> Synchronously makes a single change to an existing entry in the
2000 /// directory.
2001 ///
2002 /// For example, this modify method changes the value of an attribute,
2003 /// adds a new attribute value, or removes an existing attribute value.
2004 ///
2005 /// The LdapModification object specifies both the change to be made and
2006 /// the LdapAttribute value to be changed.
2007 ///
2008 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2009 /// it is indeterminate whether or not the server made the modification.
2010 ///
2011 /// </summary>
2012 /// <param name="dn"> The distinguished name of the entry to modify.
2013 ///
2014 /// </param>
2015 /// <param name="mod"> A single change to be made to the entry.
2016 ///
2017 /// </param>
2018 /// <exception> LdapException A general exception which includes an error
2019 /// message and an Ldap error code.
2020 /// </exception>
2021 public virtual void Modify(System.String dn, LdapModification mod)
2023 Modify(dn, mod, defSearchCons);
2024 return ;
2027 /// <summary>
2028 /// Synchronously makes a single change to an existing entry in the
2029 /// directory, using the specified constraints.
2030 ///
2031 /// For example, this modify method changes the value of an attribute,
2032 /// adds a new attribute value, or removes an existing attribute value.
2033 ///
2034 /// The LdapModification object specifies both the change to be
2035 /// made and the LdapAttribute value to be changed.
2036 ///
2037 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2038 /// it is indeterminate whether or not the server made the modification.
2039 ///
2040 /// </summary>
2041 /// <param name="dn"> The distinguished name of the entry to modify.
2042 ///
2043 /// </param>
2044 /// <param name="mod"> A single change to be made to the entry.
2045 ///
2046 /// </param>
2047 /// <param name="cons"> The constraints specific to the operation.
2048 ///
2049 /// </param>
2050 /// <exception> LdapException A general exception which includes an error
2051 /// message and an Ldap error code.
2052 /// </exception>
2053 public virtual void Modify(System.String dn, LdapModification mod, LdapConstraints cons)
2055 LdapModification[] mods = new LdapModification[1];
2056 mods[0] = mod;
2057 Modify(dn, mods, cons);
2058 return ;
2061 /// <summary>
2062 /// Synchronously makes a set of changes to an existing entry in the
2063 /// directory.
2064 ///
2065 /// For example, this modify method changes attribute values, adds
2066 /// new attribute values, or removes existing attribute values.
2067 ///
2068 /// Because the server applies all changes in an LdapModification array
2069 /// atomically, the application can expect that no changes
2070 /// have been performed if an error is returned.
2071 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2072 /// it is indeterminate whether or not the server made the modifications.
2073 ///
2074 /// </summary>
2075 /// <param name="dn"> Distinguished name of the entry to modify.
2076 ///
2077 /// </param>
2078 /// <param name="mods"> The changes to be made to the entry.
2079 ///
2080 /// </param>
2081 /// <exception> LdapException A general exception which includes an error
2082 /// message and an Ldap error code.
2083 /// </exception>
2084 public virtual void Modify(System.String dn, LdapModification[] mods)
2086 Modify(dn, mods, defSearchCons);
2087 return ;
2090 /// <summary> Synchronously makes a set of changes to an existing entry in the
2091 /// directory, using the specified constraints.
2092 ///
2093 /// For example, this modify method changes attribute values, adds new
2094 /// attribute values, or removes existing attribute values.
2095 ///
2096 /// Because the server applies all changes in an LdapModification array
2097 /// atomically, the application can expect that no changes
2098 /// have been performed if an error is returned.
2099 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2100 /// it is indeterminate whether or not the server made the modifications.
2101 ///
2102 /// </summary>
2103 /// <param name="dn"> The distinguished name of the entry to modify.
2104 ///
2105 /// </param>
2106 /// <param name="mods"> The changes to be made to the entry.
2107 ///
2108 /// </param>
2109 /// <param name="cons"> The constraints specific to the operation.
2110 ///
2111 /// </param>
2112 /// <exception> LdapException A general exception which includes an
2113 /// error message and an Ldap error code.
2114 /// </exception>
2115 public virtual void Modify(System.String dn, LdapModification[] mods, LdapConstraints cons)
2117 LdapResponseQueue queue = Modify(dn, mods, null, cons);
2119 // Get a handle to the modify response
2120 LdapResponse modifyResponse = (LdapResponse) (queue.getResponse());
2122 // Set local copy of responseControls synchronously - if there were any
2123 lock (responseCtlSemaphore)
2125 responseCtls = modifyResponse.Controls;
2128 chkResultCode(queue, cons, modifyResponse);
2130 return ;
2133 /// <summary> Asynchronously makes a single change to an existing entry in the
2134 /// directory.
2135 ///
2136 /// For example, this modify method can change the value of an attribute,
2137 /// add a new attribute value, or remove an existing attribute value.
2138 ///
2139 /// The LdapModification object specifies both the change to be made and
2140 /// the LdapAttribute value to be changed.
2141 ///
2142 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2143 /// it is indeterminate whether or not the server made the modification.
2144 ///
2145 /// </summary>
2146 /// <param name="dn"> Distinguished name of the entry to modify.
2147 ///
2148 /// </param>
2149 /// <param name="mod"> A single change to be made to the entry.
2150 ///
2151 /// </param>
2152 /// <param name="queue"> Handler for messages returned from a server in
2153 /// response to this request. If it is null, a
2154 /// queue object is created internally.
2155 ///
2156 /// </param>
2157 /// <exception> LdapException A general exception which includes an error
2158 /// message and an Ldap error code.
2159 /// </exception>
2160 public virtual LdapResponseQueue Modify(System.String dn, LdapModification mod, LdapResponseQueue queue)
2162 return Modify(dn, mod, queue, defSearchCons);
2165 /// <summary> Asynchronously makes a single change to an existing entry in the
2166 /// directory, using the specified constraints and queue.
2167 ///
2168 /// For example, this modify method can change the value of an attribute,
2169 /// add a new attribute value, or remove an existing attribute value.
2170 ///
2171 /// The LdapModification object specifies both the change to be made
2172 /// and the LdapAttribute value to be changed.
2173 ///
2174 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2175 /// it is indeterminate whether or not the server made the modification.
2176 ///
2177 /// </summary>
2178 /// <param name="dn"> Distinguished name of the entry to modify.
2179 ///
2180 /// </param>
2181 /// <param name="mod"> A single change to be made to the entry.
2182 ///
2183 /// </param>
2184 /// <param name="queue"> Handler for messages returned from a server in
2185 /// response to this request. If it is null, a
2186 /// queue object is created internally.
2187 ///
2188 /// </param>
2189 /// <param name="cons"> Constraints specific to the operation.
2190 ///
2191 /// </param>
2192 /// <exception> LdapException A general exception which includes an error
2193 /// message and an Ldap error code.
2194 /// </exception>
2195 public virtual LdapResponseQueue Modify(System.String dn, LdapModification mod, LdapResponseQueue queue, LdapConstraints cons)
2197 LdapModification[] mods = new LdapModification[1];
2198 mods[0] = mod;
2199 return Modify(dn, mods, queue, cons);
2202 /// <summary> Asynchronously makes a set of changes to an existing entry in the
2203 /// directory.
2204 ///
2205 /// For example, this modify method can change attribute values, add new
2206 /// attribute values, or remove existing attribute values.
2207 ///
2208 /// Because the server applies all changes in an LdapModification array
2209 /// atomically, the application can expect that no changes
2210 /// have been performed if an error is returned.
2211 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2212 /// it is indeterminate whether or not the server made the modifications.
2213 ///
2214 /// </summary>
2215 /// <param name="dn"> The distinguished name of the entry to modify.
2216 ///
2217 /// </param>
2218 /// <param name="mods"> The changes to be made to the entry.
2219 ///
2220 /// </param>
2221 /// <param name="queue"> The queue for messages returned from a server in
2222 /// response to this request. If it is null, a
2223 /// queue object is created internally.
2224 ///
2225 /// </param>
2226 /// <exception> LdapException A general exception which includes an error
2227 /// message and an Ldap error code.
2228 /// </exception>
2229 public virtual LdapResponseQueue Modify(System.String dn, LdapModification[] mods, LdapResponseQueue queue)
2231 return Modify(dn, mods, queue, defSearchCons);
2234 /// <summary> Asynchronously makes a set of changes to an existing entry in the
2235 /// directory, using the specified constraints and queue.
2236 ///
2237 /// For example, this modify method can change attribute values, add new
2238 /// attribute values, or remove existing attribute values.
2239 ///
2240 /// Because the server applies all changes in an LdapModification array
2241 /// atomically, the application can expect that no changes
2242 /// have been performed if an error is returned.
2243 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2244 /// it is indeterminate whether or not the server made the modifications.
2245 ///
2246 /// </summary>
2247 /// <param name="dn"> The distinguished name of the entry to modify.
2248 ///
2249 /// </param>
2250 /// <param name="mods"> The changes to be made to the entry.
2251 ///
2252 /// </param>
2253 /// <param name="queue"> The queue for messages returned from a server in
2254 /// response to this request. If it is null, a
2255 /// queue object is created internally.
2256 ///
2257 /// </param>
2258 /// <param name="cons"> Constraints specific to the operation.
2259 ///
2260 /// </param>
2261 /// <exception> LdapException A general exception which includes an error
2262 /// message and an Ldap error code.
2263 /// </exception>
2264 public virtual LdapResponseQueue Modify(System.String dn, LdapModification[] mods, LdapResponseQueue queue, LdapConstraints cons)
2266 if ((System.Object) dn == null)
2268 // Invalid DN parameter
2269 throw new System.ArgumentException(ExceptionMessages.DN_PARAM_ERROR);
2272 if (cons == null)
2273 cons = defSearchCons;
2275 LdapMessage msg = new LdapModifyRequest(dn, mods, cons.getControls());
2277 return SendRequestToServer(msg, cons.TimeLimit, queue, null);
2280 //*************************************************************************
2281 // read methods
2282 //*************************************************************************
2284 /// <summary> Synchronously reads the entry for the specified distiguished name (DN)
2285 /// and retrieves all attributes for the entry.
2286 ///
2287 /// </summary>
2288 /// <param name="dn"> The distinguished name of the entry to retrieve.
2289 ///
2290 /// </param>
2291 /// <returns> the LdapEntry read from the server.
2292 ///
2293 /// </returns>
2294 /// <exception> LdapException if the object was not found
2295 /// </exception>
2296 public virtual LdapEntry Read(System.String dn)
2298 return Read(dn, defSearchCons);
2302 /// <summary>
2303 /// Synchronously reads the entry for the specified distiguished name (DN),
2304 /// using the specified constraints, and retrieves all attributes for the
2305 /// entry.
2306 ///
2307 /// </summary>
2308 /// <param name="dn"> The distinguished name of the entry to retrieve.
2309 ///
2310 /// </param>
2311 /// <param name="cons"> The constraints specific to the operation.
2312 ///
2313 /// </param>
2314 /// <returns> the LdapEntry read from the server
2315 ///
2316 /// </returns>
2317 /// <exception> LdapException if the object was not found
2318 /// </exception>
2319 public virtual LdapEntry Read(System.String dn, LdapSearchConstraints cons)
2321 return Read(dn, null, cons);
2324 /// <summary>
2325 /// Synchronously reads the entry for the specified distinguished name (DN)
2326 /// and retrieves only the specified attributes from the entry.
2327 ///
2328 /// </summary>
2329 /// <param name="dn"> The distinguished name of the entry to retrieve.
2330 ///
2331 /// </param>
2332 /// <param name="attrs"> The names of the attributes to retrieve.
2333 ///
2334 /// </param>
2335 /// <returns> the LdapEntry read from the server
2336 ///
2337 /// </returns>
2338 /// <exception> LdapException if the object was not found
2339 /// </exception>
2340 public virtual LdapEntry Read(System.String dn, System.String[] attrs)
2342 return Read(dn, attrs, defSearchCons);
2345 /// <summary> Synchronously reads the entry for the specified distinguished name (DN),
2346 /// using the specified constraints, and retrieves only the specified
2347 /// attributes from the entry.
2348 ///
2349 /// </summary>
2350 /// <param name="dn"> The distinguished name of the entry to retrieve.
2351 ///
2352 /// </param>
2353 /// <param name="attrs"> The names of the attributes to retrieve.
2354 ///
2355 /// </param>
2356 /// <param name="cons"> The constraints specific to the operation.
2357 ///
2358 /// </param>
2359 /// <returns> the LdapEntry read from the server
2360 ///
2361 /// </returns>
2362 /// <exception> LdapException if the object was not found
2363 /// </exception>
2364 public virtual LdapEntry Read(System.String dn, System.String[] attrs, LdapSearchConstraints cons)
2366 LdapSearchResults sr = Search(dn, SCOPE_BASE, null, attrs, false, cons);
2368 LdapEntry ret = null;
2369 if (sr.hasMore())
2371 ret = sr.next();
2372 if (sr.hasMore())
2374 // "Read response is ambiguous, multiple entries returned"
2375 throw new LdapLocalException(ExceptionMessages.READ_MULTIPLE, LdapException.AMBIGUOUS_RESPONSE);
2378 return ret;
2381 /// <summary> Synchronously reads the entry specified by the Ldap URL.
2382 ///
2383 /// When this read method is called, a new connection is created
2384 /// automatically, using the host and port specified in the URL. After
2385 /// finding the entry, the method closes the connection (in other words,
2386 /// it disconnects from the Ldap server).
2387 ///
2388 /// If the URL specifies a filter and scope, they are not used. Of the
2389 /// information specified in the URL, this method only uses the Ldap host
2390 /// name and port number, the base distinguished name (DN), and the list
2391 /// of attributes to return.
2392 ///
2393 /// </summary>
2394 /// <param name="toGet"> Ldap URL specifying the entry to read.
2395 ///
2396 /// </param>
2397 /// <returns> The entry specified by the base DN.
2398 ///
2399 /// </returns>
2400 /// <exception> LdapException if the object was not found
2401 /// </exception>
2402 public static LdapEntry Read(LdapUrl toGet)
2404 LdapConnection lconn = new LdapConnection();
2405 lconn.Connect(toGet.Host, toGet.Port);
2406 LdapEntry toReturn = lconn.Read(toGet.getDN(), toGet.AttributeArray);
2407 lconn.Disconnect();
2408 return toReturn;
2411 /// <summary> Synchronously reads the entry specified by the Ldap URL, using the
2412 /// specified constraints.
2413 ///
2414 /// When this method is called, a new connection is created
2415 /// automatically, using the host and port specified in the URL. After
2416 /// finding the entry, the method closes the connection (in other words,
2417 /// it disconnects from the Ldap server).
2418 ///
2419 /// If the URL specifies a filter and scope, they are not used. Of the
2420 /// information specified in the URL, this method only uses the Ldap host
2421 /// name and port number, the base distinguished name (DN), and the list
2422 /// of attributes to return.
2423 ///
2424 /// </summary>
2425 /// <returns> The entry specified by the base DN.
2426 ///
2427 /// </returns>
2428 /// <param name="toGet"> Ldap URL specifying the entry to read.
2429 ///
2430 /// </param>
2431 /// <param name="cons"> Constraints specific to the operation.
2432 ///
2433 /// </param>
2434 /// <exception> LdapException if the object was not found
2435 /// </exception>
2436 public static LdapEntry Read(LdapUrl toGet, LdapSearchConstraints cons)
2438 LdapConnection lconn = new LdapConnection();
2439 lconn.Connect(toGet.Host, toGet.Port);
2440 LdapEntry toReturn = lconn.Read(toGet.getDN(), toGet.AttributeArray, cons);
2441 lconn.Disconnect();
2442 return toReturn;
2445 //*************************************************************************
2446 // rename methods
2447 //*************************************************************************
2449 /// <summary>
2450 /// Synchronously renames an existing entry in the directory.
2451 ///
2452 /// </summary>
2453 /// <param name="dn"> The current distinguished name of the entry.
2454 ///
2455 /// </param>
2456 /// <param name="newRdn"> The new relative distinguished name for the entry.
2457 ///
2458 /// </param>
2459 /// <param name="deleteOldRdn"> If true, the old name is not retained as an
2460 /// attribute value. If false, the old name is
2461 /// retained as an attribute value.
2462 ///
2463 /// </param>
2464 /// <exception> LdapException A general exception which includes an error
2465 /// message and an Ldap error code.
2466 /// </exception>
2467 public virtual void Rename(System.String dn, System.String newRdn, bool deleteOldRdn)
2469 Rename(dn, newRdn, deleteOldRdn, defSearchCons);
2470 return ;
2473 /// <summary>
2474 /// Synchronously renames an existing entry in the directory, using the
2475 /// specified constraints.
2476 ///
2477 /// </summary>
2478 /// <param name="dn"> The current distinguished name of the entry.
2479 ///
2480 /// </param>
2481 /// <param name="newRdn"> The new relative distinguished name for the entry.
2482 ///
2483 /// </param>
2484 /// <param name="deleteOldRdn"> If true, the old name is not retained as an
2485 /// attribute value. If false, the old name is
2486 /// retained as an attribute value.
2487 ///
2488 /// </param>
2489 /// <param name="cons"> The constraints specific to the operation.
2490 ///
2491 /// </param>
2492 /// <exception> LdapException A general exception which includes an error
2493 /// message and an Ldap error code.
2494 /// </exception>
2495 public virtual void Rename(System.String dn, System.String newRdn, bool deleteOldRdn, LdapConstraints cons)
2497 // null for newParentdn means that this is originating as an Ldapv2 call
2498 Rename(dn, newRdn, null, deleteOldRdn, cons);
2499 return ;
2502 /// <summary> Synchronously renames an existing entry in the directory, possibly
2503 /// repositioning the entry in the directory tree.
2504 ///
2505 /// </summary>
2506 /// <param name="dn"> The current distinguished name of the entry.
2507 ///
2508 /// </param>
2509 /// <param name="newRdn"> The new relative distinguished name for the entry.
2510 ///
2511 /// </param>
2512 /// <param name="newParentdn"> The distinguished name of an existing entry which
2513 /// is to be the new parent of the entry.
2514 ///
2515 /// </param>
2516 /// <param name="deleteOldRdn"> If true, the old name is not retained as an
2517 /// attribute value. If false, the old name is
2518 /// retained as an attribute value.
2519 ///
2520 /// </param>
2521 /// <exception> LdapException A general exception which includes an error
2522 /// message and an Ldap error code.
2523 /// </exception>
2524 public virtual void Rename(System.String dn, System.String newRdn, System.String newParentdn, bool deleteOldRdn)
2526 Rename(dn, newRdn, newParentdn, deleteOldRdn, defSearchCons);
2527 return ;
2530 /// <summary>
2531 /// Synchronously renames an existing entry in the directory, using the
2532 /// specified constraints and possibly repositioning the entry in the
2533 /// directory tree.
2534 ///
2535 /// </summary>
2536 /// <param name="dn"> The current distinguished name of the entry.
2537 ///
2538 /// </param>
2539 /// <param name="newRdn"> The new relative distinguished name for the entry.
2540 ///
2541 /// </param>
2542 /// <param name="newParentdn"> The distinguished name of an existing entry which
2543 /// is to be the new parent of the entry.
2544 ///
2545 /// </param>
2546 /// <param name="deleteOldRdn"> If true, the old name is not retained as an
2547 /// attribute value. If false, the old name is
2548 /// retained as an attribute value.
2549 ///
2550 /// </param>
2551 /// <param name="cons"> The constraints specific to the operation.
2552 ///
2553 /// </param>
2554 /// <exception> LdapException A general exception which includes an error
2555 /// message and an Ldap error code.
2556 /// </exception>
2557 public virtual void Rename(System.String dn, System.String newRdn, System.String newParentdn, bool deleteOldRdn, LdapConstraints cons)
2559 LdapResponseQueue queue = Rename(dn, newRdn, newParentdn, deleteOldRdn, null, cons);
2561 // Get a handle to the rename response
2562 LdapResponse renameResponse = (LdapResponse) (queue.getResponse());
2564 // Set local copy of responseControls synchronously - if there were any
2565 lock (responseCtlSemaphore)
2567 responseCtls = renameResponse.Controls;
2570 chkResultCode(queue, cons, renameResponse);
2571 return ;
2575 * rename
2578 /// <summary> Asynchronously renames an existing entry in the directory.
2579 ///
2580 /// </summary>
2581 /// <param name="dn"> The current distinguished name of the entry.
2582 ///
2583 /// </param>
2584 /// <param name="newRdn"> The new relative distinguished name for the entry.
2585 ///
2586 /// </param>
2587 /// <param name="deleteOldRdn"> If true, the old name is not retained as an
2588 /// attribute value. If false, the old name is
2589 /// retained as an attribute value.
2590 ///
2591 /// </param>
2592 /// <param name="queue"> The queue for messages returned from a server in
2593 /// response to this request. If it is null, a
2594 /// queue object is created internally.
2595 ///
2596 /// </param>
2597 /// <exception> LdapException A general exception which includes an error
2598 /// message and an Ldap error code.
2599 /// </exception>
2600 public virtual LdapResponseQueue Rename(System.String dn, System.String newRdn, bool deleteOldRdn, LdapResponseQueue queue)
2602 return Rename(dn, newRdn, deleteOldRdn, queue, defSearchCons);
2605 /// <summary> Asynchronously renames an existing entry in the directory, using the
2606 /// specified constraints.
2607 ///
2608 /// </summary>
2609 /// <param name="dn"> The current distinguished name of the entry.
2610 ///
2611 /// </param>
2612 /// <param name="newRdn"> The new relative distinguished name for the entry.
2613 ///
2614 /// </param>
2615 /// <param name="deleteOldRdn"> If true, the old name is not retained as an
2616 /// attribute value. If false, the old name is
2617 /// retained as an attribute value.
2618 ///
2619 /// </param>
2620 /// <param name="queue"> The queue for messages returned from a server in
2621 /// response to this request. If it is null, a
2622 /// queue object is created internally.
2623 ///
2624 /// </param>
2625 /// <param name="cons"> The constraints specific to the operation.
2626 ///
2627 /// </param>
2628 /// <exception> LdapException A general exception which includes an error
2629 /// message and an Ldap error code.
2630 /// </exception>
2631 public virtual LdapResponseQueue Rename(System.String dn, System.String newRdn, bool deleteOldRdn, LdapResponseQueue queue, LdapConstraints cons)
2633 return Rename(dn, newRdn, null, deleteOldRdn, queue, cons);
2636 /// <summary> Asynchronously renames an existing entry in the directory, possibly
2637 /// repositioning the entry in the directory.
2638 ///
2639 /// </summary>
2640 /// <param name="dn"> The current distinguished name of the entry.
2641 ///
2642 /// </param>
2643 /// <param name="newRdn"> The new relative distinguished name for the entry.
2644 ///
2645 /// </param>
2646 /// <param name="newParentdn"> The distinguished name of an existing entry which
2647 /// is to be the new parent of the entry.
2648 ///
2649 /// </param>
2650 /// <param name="deleteOldRdn"> If true, the old name is not retained as an
2651 /// attribute value. If false, the old name is
2652 /// retained as an attribute value.
2653 ///
2654 /// </param>
2655 /// <param name="queue"> The queue for messages returned from a server in
2656 /// response to this request. If it is null, a
2657 /// queue object is created internally.
2658 ///
2659 /// </param>
2660 /// <exception> LdapException A general exception which includes an error
2661 /// message and an Ldap error code.
2662 /// </exception>
2663 public virtual LdapResponseQueue Rename(System.String dn, System.String newRdn, System.String newParentdn, bool deleteOldRdn, LdapResponseQueue queue)
2665 return Rename(dn, newRdn, newParentdn, deleteOldRdn, queue, defSearchCons);
2668 /// <summary> Asynchronously renames an existing entry in the directory, using the
2669 /// specified constraints and possibily repositioning the entry in the
2670 /// directory.
2671 ///
2672 /// </summary>
2673 /// <param name="dn"> The current distinguished name of the entry.
2674 ///
2675 /// </param>
2676 /// <param name="newRdn"> The new relative distinguished name for the entry.
2677 ///
2678 /// </param>
2679 /// <param name="newParentdn"> The distinguished name of an existing entry which
2680 /// is to be the new parent of the entry.
2681 ///
2682 /// </param>
2683 /// <param name="deleteOldRdn"> If true, the old name is not retained as an
2684 /// attribute value. If false, the old name is
2685 /// retained as an attribute value.
2686 ///
2687 /// </param>
2688 /// <param name="queue"> The queue for messages returned from a server in
2689 /// response to this request. If it is null, a
2690 /// queue object is created internally.
2691 ///
2692 /// </param>
2693 /// <param name="cons"> The constraints specific to the operation.
2694 ///
2695 /// </param>
2696 /// <exception> LdapException A general exception which includes an error
2697 /// message and an Ldap error code.
2698 /// </exception>
2699 public virtual LdapResponseQueue Rename(System.String dn, System.String newRdn, System.String newParentdn, bool deleteOldRdn, LdapResponseQueue queue, LdapConstraints cons)
2701 if ((System.Object) dn == null || (System.Object) newRdn == null)
2703 // Invalid DN or RDN parameter
2704 throw new System.ArgumentException(ExceptionMessages.RDN_PARAM_ERROR);
2707 if (cons == null)
2708 cons = defSearchCons;
2710 LdapMessage msg = new LdapModifyDNRequest(dn, newRdn, newParentdn, deleteOldRdn, cons.getControls());
2712 return SendRequestToServer(msg, cons.TimeLimit, queue, null);
2715 //*************************************************************************
2716 // search methods
2717 //*************************************************************************
2719 /// <summary>
2720 /// Synchronously performs the search specified by the parameters.
2721 ///
2722 /// </summary>
2723 /// <param name="base"> The base distinguished name to search from.
2724 ///
2725 /// </param>
2726 /// <param name="scope"> The scope of the entries to search. The following
2727 /// are the valid options:
2728 /// <ul>
2729 /// <li>SCOPE_BASE - searches only the base DN</li>
2730 ///
2731 /// <li>SCOPE_ONE - searches only entries under the base DN</li>
2732 ///
2733 /// <li>SCOPE_SUB - searches the base DN and all entries
2734 /// within its subtree</li>
2735 /// </ul>
2736 /// </param>
2737 /// <param name="filter"> Search filter specifying the search criteria.
2738 ///
2739 /// </param>
2740 /// <param name="attrs"> Names of attributes to retrieve.
2741 ///
2742 /// </param>
2743 /// <param name="typesOnly"> If true, returns the names but not the values of
2744 /// the attributes found. If false, returns the
2745 /// names and values for attributes found.
2746 ///
2747 /// </param>
2748 /// <exception> LdapException A general exception which includes an error
2749 /// message and an Ldap error code.
2750 /// </exception>
2751 public virtual LdapSearchResults Search(System.String base_Renamed, int scope, System.String filter, System.String[] attrs, bool typesOnly)
2753 return Search(base_Renamed, scope, filter, attrs, typesOnly, defSearchCons);
2756 /// <summary>
2757 /// Synchronously performs the search specified by the parameters,
2758 /// using the specified search constraints (such as the
2759 /// maximum number of entries to find or the maximum time to wait for
2760 /// search results).
2761 ///
2762 /// As part of the search constraints, the method allows specifying
2763 /// whether or not the results are to be delivered all at once or in
2764 /// smaller batches. If specified that the results are to be delivered in
2765 /// smaller batches, each iteration blocks only until the next batch of
2766 /// results is returned.
2767 ///
2768 /// </summary>
2769 /// <param name="base"> The base distinguished name to search from.
2770 ///
2771 /// </param>
2772 /// <param name="scope"> The scope of the entries to search. The following
2773 /// are the valid options:
2774 /// <ul>
2775 /// <li>SCOPE_BASE - searches only the base DN</li>
2776 ///
2777 /// <li>SCOPE_ONE - searches only entries under the base DN</li>
2778 ///
2779 /// <li>SCOPE_SUB - searches the base DN and all entries
2780 /// within its subtree</li>
2781 /// </ul>
2782 /// </param>
2783 /// <param name="filter"> The search filter specifying the search criteria.
2784 ///
2785 /// </param>
2786 /// <param name="attrs"> The names of attributes to retrieve.
2787 ///
2788 /// </param>
2789 /// <param name="typesOnly"> If true, returns the names but not the values of
2790 /// the attributes found. If false, returns the
2791 /// names and values for attributes found.
2792 ///
2793 /// </param>
2794 /// <param name="cons"> The constraints specific to the search.
2795 ///
2796 /// </param>
2797 /// <exception> LdapException A general exception which includes an error
2798 /// message and an Ldap error code.
2799 /// </exception>
2800 public virtual LdapSearchResults Search(System.String base_Renamed, int scope, System.String filter, System.String[] attrs, bool typesOnly, LdapSearchConstraints cons)
2802 LdapSearchQueue queue = Search(base_Renamed, scope, filter, attrs, typesOnly, null, cons);
2804 if (cons == null)
2805 cons = defSearchCons;
2806 return new LdapSearchResults(this, queue, cons);
2809 /// <summary> Asynchronously performs the search specified by the parameters.
2810 ///
2811 /// </summary>
2812 /// <param name="base"> The base distinguished name to search from.
2813 ///
2814 /// </param>
2815 /// <param name="scope"> The scope of the entries to search. The following
2816 /// are the valid options:
2817 /// <ul>
2818 /// <li>SCOPE_BASE - searches only the base DN</li>
2819 ///
2820 /// <li>SCOPE_ONE - searches only entries under the base DN</li>
2821 ///
2822 /// <li>SCOPE_SUB - searches the base DN and all entries
2823 /// within its subtree</li>
2824 /// </ul>
2825 /// </param>
2826 /// <param name="filter"> Search filter specifying the search criteria.
2827 ///
2828 /// </param>
2829 /// <param name="attrs"> Names of attributes to retrieve.
2830 ///
2831 /// </param>
2832 /// <param name="typesOnly"> If true, returns the names but not the values of
2833 /// the attributes found. If false, returns the
2834 /// names and values for attributes found.
2835 ///
2836 /// </param>
2837 /// <param name="queue"> Handler for messages returned from a server in
2838 /// response to this request. If it is null, a
2839 /// queue object is created internally.
2840 ///
2841 /// </param>
2842 /// <exception> LdapException A general exception which includes an error
2843 /// message and an Ldap error code.
2844 /// </exception>
2845 public virtual LdapSearchQueue Search(System.String base_Renamed, int scope, System.String filter, System.String[] attrs, bool typesOnly, LdapSearchQueue queue)
2847 return Search(base_Renamed, scope, filter, attrs, typesOnly, queue, defSearchCons);
2850 /// <summary> Asynchronously performs the search specified by the parameters,
2851 /// also allowing specification of constraints for the search (such
2852 /// as the maximum number of entries to find or the maximum time to
2853 /// wait for search results).
2854 ///
2855 /// </summary>
2856 /// <param name="base"> The base distinguished name to search from.
2857 ///
2858 /// </param>
2859 /// <param name="scope"> The scope of the entries to search. The following
2860 /// are the valid options:
2861 /// <ul>
2862 /// <li>SCOPE_BASE - searches only the base DN</li>
2863 ///
2864 /// <li>SCOPE_ONE - searches only entries under the base DN</li>
2865 ///
2866 /// <li>SCOPE_SUB - searches the base DN and all entries
2867 /// within its subtree</li>
2868 /// </ul>
2869 /// </param>
2870 /// <param name="filter"> The search filter specifying the search criteria.
2871 ///
2872 /// </param>
2873 /// <param name="attrs"> The names of attributes to retrieve.
2874 ///
2875 /// </param>
2876 /// <param name="typesOnly"> If true, returns the names but not the values of
2877 /// the attributes found. If false, returns the
2878 /// names and values for attributes found.
2879 ///
2880 /// </param>
2881 /// <param name="queue"> The queue for messages returned from a server in
2882 /// response to this request. If it is null, a
2883 /// queue object is created internally.
2884 ///
2885 /// </param>
2886 /// <param name="cons"> The constraints specific to the search.
2887 ///
2888 /// </param>
2889 /// <exception> LdapException A general exception which includes an error
2890 /// message and an Ldap error code.
2891 /// </exception>
2892 public virtual LdapSearchQueue Search(System.String base_Renamed, int scope, System.String filter, System.String[] attrs, bool typesOnly, LdapSearchQueue queue, LdapSearchConstraints cons)
2894 if ((System.Object) filter == null)
2896 filter = "objectclass=*";
2898 if (cons == null)
2899 cons = defSearchCons;
2901 LdapMessage msg = new LdapSearchRequest(base_Renamed, scope, filter, attrs, cons.Dereference, cons.MaxResults, cons.ServerTimeLimit, typesOnly, cons.getControls());
2902 MessageAgent agent;
2903 LdapSearchQueue myqueue = queue;
2904 if (myqueue == null)
2906 agent = new MessageAgent();
2907 myqueue = new LdapSearchQueue(agent);
2909 else
2911 agent = queue.MessageAgent;
2916 agent.sendMessage(conn, msg, cons.TimeLimit, myqueue, null);
2918 catch (LdapException lex)
2920 throw lex;
2922 return myqueue;
2926 * Ldap URL search
2929 /// <summary> Synchronously performs the search specified by the Ldap URL, returning
2930 /// an enumerable LdapSearchResults object.
2931 ///
2932 /// </summary>
2933 /// <param name="toGet">The Ldap URL specifying the entry to read.
2934 ///
2935 /// </param>
2936 /// <exception> LdapException A general exception which includes an error
2937 /// message and an Ldap error code.
2938 /// </exception>
2939 public static LdapSearchResults Search(LdapUrl toGet)
2941 // Get a clone of default search constraints, method alters batchSize
2942 return Search(toGet, null);
2946 * Ldap URL search
2949 /// <summary> Synchronously perfoms the search specified by the Ldap URL, using
2950 /// the specified search constraints (such as the maximum number of
2951 /// entries to find or the maximum time to wait for search results).
2952 ///
2953 /// When this method is called, a new connection is created
2954 /// automatically, using the host and port specified in the URL. After
2955 /// all search results have been received from the server, the method
2956 /// closes the connection (in other words, it disconnects from the Ldap
2957 /// server).
2958 ///
2959 /// As part of the search constraints, a choice can be made as to whether
2960 /// to have the results delivered all at once or in smaller batches. If
2961 /// the results are to be delivered in smaller batches, each iteration
2962 /// blocks only until the next batch of results is returned.
2963 ///
2964 ///
2965 /// </summary>
2966 /// <param name="toGet"> Ldap URL specifying the entry to read.
2967 ///
2968 /// </param>
2969 /// <param name="cons"> The constraints specific to the search.
2970 ///
2971 /// </param>
2972 /// <exception> LdapException A general exception which includes an error
2973 /// message and an Ldap error code.
2974 /// </exception>
2975 public static LdapSearchResults Search(LdapUrl toGet, LdapSearchConstraints cons)
2977 LdapConnection lconn = new LdapConnection();
2978 lconn.Connect(toGet.Host, toGet.Port);
2979 if (cons == null)
2981 // This is a clone, so we already have our own copy
2982 cons = lconn.SearchConstraints;
2984 else
2986 // get our own copy of user's constraints because we modify it
2987 cons = (LdapSearchConstraints) cons.Clone();
2989 cons.BatchSize = 0; // Must wait until all results arrive
2990 LdapSearchResults toReturn = lconn.Search(toGet.getDN(), toGet.Scope, toGet.Filter, toGet.AttributeArray, false, cons);
2991 lconn.Disconnect();
2992 return toReturn;
2995 /// <summary> Sends an Ldap request to a directory server.
2996 ///
2997 /// The specified the Ldap request is sent to the directory server
2998 /// associated with this connection using default constraints. An Ldap
2999 /// request object is a subclass {@link LdapMessage} with the operation
3000 /// type set to one of the request types. You can build a request by using
3001 /// the request classes found in this package
3002 ///
3003 /// You should note that, since Ldap requests sent to the server
3004 /// using sendRequest are asynchronous, automatic referral following
3005 /// does not apply to these requests.
3006 ///
3007 /// </summary>
3008 /// <param name="request">The Ldap request to send to the directory server.
3009 /// </param>
3010 /// <param name="queue"> The queue for messages returned from a server in
3011 /// response to this request. If it is null, a
3012 /// queue object is created internally.
3013 /// </param>
3014 /// <exception> LdapException A general exception which includes an error
3015 /// message and an Ldap error code.
3016 ///
3017 /// </exception>
3018 /// <seealso cref="LdapMessage.Type">
3019 /// </seealso>
3020 /// <seealso cref="RfcLdapMessage.isRequest">
3021 /// </seealso>
3022 public virtual LdapMessageQueue SendRequest(LdapMessage request, LdapMessageQueue queue)
3024 return SendRequest(request, queue, null);
3027 /// <summary> Sends an Ldap request to a directory server.
3028 ///
3029 /// The specified the Ldap request is sent to the directory server
3030 /// associated with this connection. An Ldap request object is an
3031 /// {@link LdapMessage} with the operation type set to one of the request
3032 /// types. You can build a request by using the request classes found in this
3033 /// package
3034 ///
3035 /// You should note that, since Ldap requests sent to the server
3036 /// using sendRequest are asynchronous, automatic referral following
3037 /// does not apply to these requests.
3038 ///
3039 /// </summary>
3040 /// <param name="request">The Ldap request to send to the directory server.
3041 /// </param>
3042 /// <param name="queue"> The queue for messages returned from a server in
3043 /// response to this request. If it is null, a
3044 /// queue object is created internally.
3045 /// </param>
3046 /// <param name="cons"> The constraints that apply to this request
3047 /// </param>
3048 /// <exception> LdapException A general exception which includes an error
3049 /// message and an Ldap error code.
3050 ///
3051 /// </exception>
3052 /// <seealso cref="LdapMessage.Type">
3053 /// </seealso>
3054 /// <seealso cref="RfcLdapMessage.isRequest">
3055 /// </seealso>
3056 public virtual LdapMessageQueue SendRequest(LdapMessage request, LdapMessageQueue queue, LdapConstraints cons)
3060 if (!request.Request)
3062 throw new System.SystemException("Object is not a request message");
3065 if (cons == null)
3067 cons = defSearchCons;
3070 // Get the correct queue for a search request
3071 MessageAgent agent;
3072 LdapMessageQueue myqueue = queue;
3073 if (myqueue == null)
3075 agent = new MessageAgent();
3076 if (request.Type == LdapMessage.SEARCH_REQUEST)
3078 myqueue = new LdapSearchQueue(agent);
3080 else
3082 myqueue = new LdapResponseQueue(agent);
3085 else
3087 if (request.Type == LdapMessage.SEARCH_REQUEST)
3089 agent = queue.MessageAgent;
3091 else
3093 agent = queue.MessageAgent;
3099 agent.sendMessage(conn, request, cons.TimeLimit, myqueue, null);
3101 catch (LdapException lex)
3103 throw lex;
3105 return myqueue;
3108 //*************************************************************************
3109 // helper methods
3110 //*************************************************************************
3112 /// <summary> Locates the appropriate message agent and sends
3113 /// the Ldap request to a directory server.
3114 ///
3115 /// </summary>
3116 /// <param name="msg">the message to send
3117 ///
3118 /// </param>
3119 /// <param name="timeout">the timeout value
3120 ///
3121 /// </param>
3122 /// <param name="queue">the response queue or null
3123 ///
3124 /// </param>
3125 /// <returns> the LdapResponseQueue for this request
3126 ///
3127 /// </returns>
3128 /// <exception> LdapException A general exception which includes an error
3129 /// message and an Ldap error code.
3130 /// </exception>
3131 private LdapResponseQueue SendRequestToServer(LdapMessage msg, int timeout, LdapResponseQueue queue, BindProperties bindProps)
3133 MessageAgent agent;
3134 if (queue == null)
3136 agent = new MessageAgent();
3137 queue = new LdapResponseQueue(agent);
3139 else
3141 agent = queue.MessageAgent;
3144 agent.sendMessage(conn, msg, timeout, queue, bindProps);
3145 return queue;
3148 /// <summary> get an LdapConnection object so that we can follow a referral.
3149 /// This function is never called if cons.getReferralFollowing() returns
3150 /// false.
3151 ///
3152 /// </summary>
3153 /// <param name="referrals">the array of referral strings
3154 ///
3155 ///
3156 /// </param>
3157 /// <returns> The referralInfo object
3158 ///
3159 /// </returns>
3160 /// <exception> LdapReferralException A general exception which includes
3161 /// an error message and an Ldap error code.
3162 /// </exception>
3163 private ReferralInfo getReferralConnection(System.String[] referrals)
3165 ReferralInfo refInfo = null;
3166 System.Exception ex = null;
3167 LdapConnection rconn = null;
3168 LdapReferralHandler rh = defSearchCons.getReferralHandler();
3169 int i = 0;
3170 // Check if we use LdapRebind to get authentication credentials
3171 if ((rh == null) || (rh is LdapAuthHandler))
3173 for (i = 0; i < referrals.Length; i++)
3175 // dn, pw are null in the default case (anonymous bind)
3176 System.String dn = null;
3177 sbyte[] pw = null;
3180 rconn = new LdapConnection();
3181 rconn.Constraints = defSearchCons;
3182 LdapUrl url = new LdapUrl(referrals[i]);
3183 rconn.Connect(url.Host, url.Port);
3184 if (rh != null)
3186 if (rh is LdapAuthHandler)
3188 // Get application supplied dn and pw
3189 LdapAuthProvider ap = ((LdapAuthHandler) rh).getAuthProvider(url.Host, url.Port);
3190 dn = ap.DN;
3191 pw = ap.Password;
3194 rconn.Bind(Ldap_V3, dn, pw);
3195 ex = null;
3196 refInfo = new ReferralInfo(rconn, referrals, url);
3197 // Indicate this connection created to follow referral
3198 rconn.Connection.ActiveReferral = refInfo;
3199 break;
3201 catch (System.Exception lex)
3203 if (rconn != null)
3207 rconn.Disconnect();
3208 rconn = null;
3209 ex = lex;
3211 catch (LdapException e)
3213 ; // ignore
3219 // Check if application gets connection and does bind
3220 else
3222 // rh instanceof LdapBind
3225 rconn = ((LdapBindHandler) rh).Bind(referrals, this);
3226 if (rconn == null)
3228 LdapReferralException rex = new LdapReferralException(ExceptionMessages.REFERRAL_ERROR);
3229 rex.setReferrals(referrals);
3230 throw rex;
3232 // Figure out which Url belongs to the connection
3233 for (int idx = 0; idx < referrals.Length; idx++)
3237 LdapUrl url = new LdapUrl(referrals[idx]);
3238 if (url.Host.ToUpper().Equals(rconn.Host.ToUpper()) && (url.Port == rconn.Port))
3240 refInfo = new ReferralInfo(rconn, referrals, url);
3241 break;
3244 catch (System.Exception e)
3246 ; // ignore
3249 if (refInfo == null)
3251 // Could not match LdapBind.bind() connecction with URL list
3252 ex = new LdapLocalException(ExceptionMessages.REFERRAL_BIND_MATCH, LdapException.CONNECT_ERROR);
3255 catch (System.Exception lex)
3257 rconn = null;
3258 ex = lex;
3261 if (ex != null)
3263 // Could not connect to any server, throw an exception
3264 LdapException ldapex;
3265 if (ex is LdapReferralException)
3267 throw (LdapReferralException) ex;
3269 else if (ex is LdapException)
3271 ldapex = (LdapException) ex;
3273 else
3275 ldapex = new LdapLocalException(ExceptionMessages.SERVER_CONNECT_ERROR, new System.Object[]{conn.Host}, LdapException.CONNECT_ERROR, ex);
3277 // Error attempting to follow a referral
3278 LdapReferralException rex = new LdapReferralException(ExceptionMessages.REFERRAL_ERROR, ldapex);
3279 rex.setReferrals(referrals);
3280 // Use last URL string for the failed referral
3281 rex.FailedReferral = referrals[referrals.Length - 1];
3282 throw rex;
3285 // We now have an authenticated connection
3286 // to be used to follow the referral.
3287 return refInfo;
3290 /// <summary> Check the result code and throw an exception if needed.
3291 ///
3292 /// If referral following is enabled, checks if we need to
3293 /// follow a referral
3294 ///
3295 /// </summary>
3296 /// <param name="queue">- the message queue of the current response
3297 ///
3298 /// </param>
3299 /// <param name="cons">- the constraints that apply to the request
3300 ///
3301 /// </param>
3302 /// <param name="response">- the LdapResponse to check
3303 /// </param>
3304 private void chkResultCode(LdapMessageQueue queue, LdapConstraints cons, LdapResponse response)
3306 if ((response.ResultCode == LdapException.REFERRAL) && cons.ReferralFollowing)
3308 // Perform referral following and return
3309 System.Collections.ArrayList refConn = null;
3312 chaseReferral(queue, cons, response, response.Referrals, 0, false, null);
3314 finally
3316 releaseReferralConnections(refConn);
3319 else
3321 // Throws exception for non success result
3322 response.chkResultCode();
3324 return ;
3327 /// <summary> Follow referrals if necessary referral following enabled.
3328 /// This function is called only by synchronous requests.
3329 /// Search responses come here only if referral following is
3330 /// enabled and if we are processing a SearchResultReference
3331 /// or a Response with a status of REFERRAL, i.e. we are
3332 /// going to follow a referral.
3333 ///
3334 /// This functions recursively follows a referral until a result
3335 /// is returned or until the hop limit is reached.
3336 ///
3337 /// </summary>
3338 /// <param name="queue">The LdapResponseQueue for this request
3339 ///
3340 /// </param>
3341 /// <param name="cons">The constraints that apply to the request
3342 ///
3343 /// </param>
3344 /// <param name="msg">The referral or search reference response message
3345 ///
3346 /// </param>
3347 /// <param name="initialReferrals">The referral array returned from the
3348 /// initial request.
3349 ///
3350 /// </param>
3351 /// <param name="hopCount">the number of hops already used while
3352 /// following this referral
3353 ///
3354 /// </param>
3355 /// <param name="searchReference">true if the message is a search reference
3356 ///
3357 /// </param>
3358 /// <param name="connectionList">An optional array list used to store
3359 /// the LdapConnection objects used in following the referral.
3360 ///
3361 /// </param>
3362 /// <returns> The array list used to store the all LdapConnection objects
3363 /// used in following the referral. The list will be empty
3364 /// if there were none.
3365 ///
3366 /// </returns>
3367 /// <exception> LdapException A general exception which includes an error
3368 /// message and an Ldap error code.
3369 /// </exception>
3370 /* package */
3371 internal virtual System.Collections.ArrayList chaseReferral(LdapMessageQueue queue, LdapConstraints cons, LdapMessage msg, System.String[] initialReferrals, int hopCount, bool searchReference, System.Collections.ArrayList connectionList)
3373 System.Collections.ArrayList connList = connectionList;
3374 LdapConnection rconn = null; // new conn for following referral
3375 ReferralInfo rinfo = null; // referral info
3376 LdapMessage origMsg;
3378 // Get a place to store new connections
3379 if (connList == null)
3381 connList = new System.Collections.ArrayList(cons.HopLimit);
3383 // Following referrals or search reference
3384 System.String[] refs; // referral list
3385 if (initialReferrals != null)
3387 // Search continuation reference from a search request
3388 refs = initialReferrals;
3389 origMsg = msg.RequestingMessage;
3391 else
3393 // Not a search request
3394 LdapResponse resp = (LdapResponse) queue.getResponse();
3395 if (resp.ResultCode != LdapException.REFERRAL)
3397 // Not referral result,throw Exception if nonzero result
3398 resp.chkResultCode();
3399 return connList;
3401 // We have a referral response
3402 refs = resp.Referrals;
3403 origMsg = resp.RequestingMessage;
3405 LdapUrl refUrl; // referral represented as URL
3408 // increment hop count, check max hops
3409 if (hopCount++ > cons.HopLimit)
3411 throw new LdapLocalException("Max hops exceeded", LdapException.REFERRAL_LIMIT_EXCEEDED);
3413 // Get a connection to follow the referral
3414 rinfo = getReferralConnection(refs);
3415 rconn = rinfo.ReferralConnection;
3416 refUrl = rinfo.ReferralUrl;
3417 connList.Add(rconn);
3420 // rebuild msg into new msg changing msgID,dn,scope,filter
3421 LdapMessage newMsg = rebuildRequest(origMsg, refUrl, searchReference);
3424 // Send new message on new connection
3427 MessageAgent agent;
3428 if (queue is LdapResponseQueue)
3430 agent = queue.MessageAgent;
3432 else
3434 agent = queue.MessageAgent;
3436 agent.sendMessage(rconn.Connection, newMsg, defSearchCons.TimeLimit, queue, null);
3438 catch (InterThreadException ex)
3440 // Error ending request to referred server
3441 LdapReferralException rex = new LdapReferralException(ExceptionMessages.REFERRAL_SEND, LdapException.CONNECT_ERROR, null, ex);
3442 rex.setReferrals(initialReferrals);
3443 ReferralInfo ref_Renamed = rconn.Connection.ActiveReferral;
3444 rex.FailedReferral = ref_Renamed.ReferralUrl.ToString();
3445 throw rex;
3448 if (initialReferrals == null)
3450 // For operation results, when all responses are complete,
3451 // the stack unwinds back to the original and returns
3452 // to the application.
3453 // An exception is thrown for an error
3454 connList = chaseReferral(queue, cons, null, null, hopCount, false, connList);
3456 else
3458 // For search, just return to LdapSearchResults object
3459 return connList;
3462 catch (System.Exception ex)
3465 if (ex is LdapReferralException)
3467 throw (LdapReferralException) ex;
3469 else
3472 // Set referral list and failed referral
3473 LdapReferralException rex = new LdapReferralException(ExceptionMessages.REFERRAL_ERROR, ex);
3474 rex.setReferrals(refs);
3475 if (rinfo != null)
3477 rex.FailedReferral = rinfo.ReferralUrl.ToString();
3479 else
3481 rex.FailedReferral = refs[refs.Length - 1];
3483 throw rex;
3486 return connList;
3489 /// <summary> Builds a new request replacing dn, scope, and filter where approprate
3490 ///
3491 /// </summary>
3492 /// <param name="msg">the original LdapMessage to build the new request from
3493 ///
3494 /// </param>
3495 /// <param name="url">the referral url
3496 ///
3497 /// </param>
3498 /// <returns> a new LdapMessage with appropriate information replaced
3499 ///
3500 /// </returns>
3501 /// <exception> LdapException A general exception which includes an error
3502 /// message and an Ldap error code.
3503 /// </exception>
3504 private LdapMessage rebuildRequest(LdapMessage msg, LdapUrl url, bool reference)
3507 System.String dn = url.getDN(); // new base
3508 System.String filter = null;
3510 switch (msg.Type)
3513 case LdapMessage.SEARCH_REQUEST:
3514 if (reference)
3516 filter = url.Filter;
3518 break;
3519 // We are allowed to get a referral for the following
3521 case LdapMessage.ADD_REQUEST:
3522 case LdapMessage.BIND_REQUEST:
3523 case LdapMessage.COMPARE_REQUEST:
3524 case LdapMessage.DEL_REQUEST:
3525 case LdapMessage.EXTENDED_REQUEST:
3526 case LdapMessage.MODIFY_RDN_REQUEST:
3527 case LdapMessage.MODIFY_REQUEST:
3528 break;
3529 // The following return no response
3531 case LdapMessage.ABANDON_REQUEST:
3532 case LdapMessage.UNBIND_REQUEST:
3533 default:
3534 throw new LdapLocalException(ExceptionMessages.IMPROPER_REFERRAL, new System.Object[]{msg.Type}, LdapException.LOCAL_ERROR);
3537 return msg.Clone(dn, filter, reference);
3541 * Release connections acquired by following referrals
3543 * @param list the list of the connections
3545 /* package */
3546 internal virtual void releaseReferralConnections(System.Collections.ArrayList list)
3548 if (list == null)
3550 return ;
3552 // Release referral connections
3553 for (int i = list.Count - 1; i >= 0; i--)
3555 LdapConnection rconn = null;
3558 rconn=(LdapConnection)list[i];
3559 list.RemoveAt(i);
3560 // rconn = (LdapConnection) list.RemoveAt(i);
3561 rconn.Disconnect();
3563 catch (System.IndexOutOfRangeException ex)
3565 continue;
3567 catch (LdapException lex)
3569 continue;
3572 return ;
3575 //*************************************************************************
3576 // Schema Related methods
3577 //*************************************************************************
3579 /// <summary> Retrieves the schema associated with a particular schema DN in the
3580 /// directory server.
3581 /// The schema DN for a particular entry is obtained by calling the
3582 /// getSchemaDN method of LDAPConnection
3583 ///
3584 /// </summary>
3585 /// <param name="schemaDN">The schema DN used to fetch the schema.
3586 ///
3587 /// </param>
3588 /// <returns> An LDAPSchema entry containing schema attributes. If the
3589 /// entry contains no schema attributes then the returned LDAPSchema object
3590 /// will be empty.
3591 ///
3592 /// </returns>
3593 /// <exception> LDAPException This exception occurs if the schema entry
3594 /// cannot be retrieved with this connection.
3595 /// </exception>
3596 /// <seealso cref="GetSchemaDN()">
3597 /// </seealso>
3598 /// <seealso cref="GetSchemaDN(String)">
3599 /// </seealso>
3600 public virtual LdapSchema FetchSchema(System.String schemaDN)
3602 LdapEntry ent = Read(schemaDN, LdapSchema.schemaTypeNames);
3603 return new LdapSchema(ent);
3606 /// <summary> Retrieves the Distiguished Name (DN) for the schema advertised in the
3607 /// root DSE of the Directory Server.
3608 ///
3609 /// The DN can be used with the methods fetchSchema and modify to retreive
3610 /// and extend schema definitions. The schema entry is located by reading
3611 /// subschemaSubentry attribute of the root DSE. This is equivalent to
3612 /// calling {@link #getSchemaDN(String) } with the DN parameter as an empty
3613 /// string: <code>getSchemaDN("")</code>.
3614 ///
3615 ///
3616 /// </summary>
3617 /// <returns> Distinguished Name of a schema entry in effect for the
3618 /// Directory.
3619 /// </returns>
3620 /// <exception> LDAPException This exception occurs if the schema DN
3621 /// cannot be retrieved, or if the subschemaSubentry attribute associated
3622 /// with the root DSE contains multiple values.
3623 ///
3624 /// </exception>
3625 /// <seealso cref="FetchSchema">
3626 /// </seealso>
3627 /// <seealso cref="Modify">
3628 /// </seealso>
3629 public virtual System.String GetSchemaDN()
3631 return GetSchemaDN("");
3634 /// <summary> Retrieves the Distiguished Name (DN) of the schema associated with a
3635 /// entry in the Directory.
3636 ///
3637 /// The DN can be used with the methods fetchSchema and modify to retreive
3638 /// and extend schema definitions. Reads the subschemaSubentry of the entry
3639 /// specified.
3640 ///
3641 /// </summary>
3642 /// <param name="dn"> Distinguished Name of any entry. The subschemaSubentry
3643 /// attribute is queried from this entry.
3644 ///
3645 /// </param>
3646 /// <returns> Distinguished Name of a schema entry in effect for the entry
3647 /// identified by <code>dn</code>.
3648 ///
3649 /// </returns>
3650 /// <exception> LDAPException This exception occurs if a null or empty
3651 /// value is passed as dn, if the subschemasubentry attribute cannot
3652 /// be retrieved, or the subschemasubentry contains multiple values.
3653 ///
3654 /// </exception>
3655 /// <seealso cref="FetchSchema">
3656 /// </seealso>
3657 /// <seealso cref="Modify">
3658 /// </seealso>
3659 public virtual System.String GetSchemaDN(System.String dn)
3661 System.String[] attrSubSchema = new System.String[]{"subschemaSubentry"};
3663 /* Read the entries subschemaSubentry attribute. Throws an exception if
3664 * no entries are returned. */
3665 LdapEntry ent = this.Read(dn, attrSubSchema);
3667 LdapAttribute attr = ent.getAttribute(attrSubSchema[0]);
3668 System.String[] values = attr.StringValueArray;
3669 if (values == null || values.Length < 1)
3671 throw new LdapLocalException(ExceptionMessages.NO_SCHEMA, new System.Object[]{dn}, LdapException.NO_RESULTS_RETURNED);
3673 else if (values.Length > 1)
3675 throw new LdapLocalException(ExceptionMessages.MULTIPLE_SCHEMA, new System.Object[]{dn}, LdapException.CONSTRAINT_VIOLATION);
3677 return values[0];