1 /******************************************************************************
3 * Copyright (c) 2003 Novell Inc. www.novell.com
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
22 *******************************************************************************/
24 // Novell.Directory.Ldap.LdapConnection.cs
27 // Sunil Kumar (Sunilk@novell.com)
29 // (C) 2003 Novell, Inc (http://www.novell.com)
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.
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.
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.
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.
68 /// 0 is returned if no authentication has been performed.
71 /// <returns> The protol version used for authentication or 0
72 /// not authenticated.
75 virtual public int ProtocolVersion
79 BindProperties prop
= conn
.BindProperties
;
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.
94 /// <returns> The distinguished name if authenticated; otherwise, null.
97 virtual public System
.String AuthenticationDN
101 BindProperties prop
= conn
.BindProperties
;
110 return prop
.AuthenticationDN
;
114 /// <summary> Returns the method used to authenticate the connection. The return
115 /// value is one of the following:
118 /// <li>"none" indicates the connection is not authenticated.</li>
121 /// <li>"simple" indicates simple authentication was used or that a null
122 /// or empty authentication DN was specified.</li>
124 /// <li>"sasl" indicates that a SASL mechanism was used to authenticate</li>
128 /// <returns> The method used to authenticate the connection.
130 virtual public System
.String AuthenticationMethod
134 BindProperties prop
= conn
.BindProperties
;
139 return conn
.BindProperties
.AuthenticationMethod
;
143 /// <summary> Returns the properties if any specified on binding with a
146 /// Null is returned if no authentication has been performed
147 /// or no authentication Map is present.
150 /// <returns> The bind properties Map Object used for SASL bind or null if
151 /// the connection is not present or not authenticated.
154 virtual public System
.Collections
.IDictionary SaslBindProperties
158 BindProperties prop
= conn
.BindProperties
;
163 return conn
.BindProperties
.SaslBindProperties
;
167 /// <summary> Returns the call back handler if any specified on binding with a
170 /// Null is returned if no authentication has been performed
171 /// or no authentication call back handler is present.
174 /// <returns> The call back handler used for SASL bind or null if the
175 /// object is not present or not authenticated.
178 virtual public System
.Object SaslBindCallbackHandler
182 BindProperties prop
= conn
.BindProperties
;
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).
197 /// <returns> The set of default contraints that apply to this connection.
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.
207 /// <param name="cons"> An LdapConstraints or LdapSearchConstraints Object
208 /// containing the contstraint values to set.
211 /// <seealso cref="Constraints()">
213 /// <seealso cref="SearchConstraints()">
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();
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();
241 newCons
.setControls(lsc
);
243 System
.Collections
.Hashtable lp
= newCons
.Properties
;
246 newCons
.Properties
= lp
;
248 defSearchCons
= newCons
;
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.
257 /// <returns> The host name of the Ldap server to which the object last
258 /// connected or null if the object has never connected.
261 virtual public System
.String Host
269 /// <summary> Returns the port number of the Ldap server to which the object is or
270 /// was last connected.
273 /// <returns> The port number of the Ldap server to which the object last
274 /// connected or -1 if the object has never connected.
277 virtual public int 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).
291 /// <returns> The set of default search contraints that apply to
295 /// <seealso cref="Constraints">
297 /// <seealso cref="LdapSearchConstraints">
299 virtual public LdapSearchConstraints SearchConstraints
303 return (LdapSearchConstraints
) this.defSearchCons
.Clone();
307 /// <summary> Indicates whether the object has authenticated to the connected Ldap
311 /// <returns> True if the object has authenticated; false if it has not
315 virtual public bool Bound
323 /// <summary> Indicates whether the connection represented by this object is open
327 /// <returns> True if connection is open; false if the connection is closed.
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.
344 /// <returns> The server controls associated with the most recent response
345 /// to a synchronous request or null if the response contains no server
349 /// <seealso cref="LdapMessage.Controls">
351 virtual public LdapControl
[] ResponseControls
355 if (responseCtls
== null)
361 // We have to clone the control just in case
362 // we have two client threads that end up retreiving the
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
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
388 /// <returns> the Connection object
390 virtual internal Connection Connection
400 /// <summary> Return the Connection object name associated with this LdapConnection
403 /// <returns> the Connection object name
405 virtual internal System
.String ConnectionName
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.
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.
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.
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.
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.
458 /// ALL_USER_ATTRS = "*"
460 public const System
.String ALL_USER_ATTRS
= "*";
462 /// <summary> Specifies the Ldapv3 protocol version when performing a bind operation.
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
473 public const int Ldap_V3
= 3;
475 /// <summary> The default port number for Ldap servers.
477 /// You can use this identifier to specify the port when establishing
478 /// a clear text connection to a server. This the default port.
480 /// DEFAULT_PORT = 389
483 public const int DEFAULT_PORT
= 389;
486 /// <summary> The default SSL port number for Ldap servers.
488 /// DEFAULT_SSL_PORT = 636
490 /// You can use this identifier to specify the port when establishing
491 /// a an SSL connection to a server..
493 public const int DEFAULT_SSL_PORT
= 636;
495 /// <summary> A string that can be passed in to the getProperty method.
497 /// Ldap_PROPERTY_SDK = "version.sdk"
499 /// You can use this string to request the version of the SDK.
501 public const System
.String Ldap_PROPERTY_SDK
= "version.sdk";
503 /// <summary> A string that can be passed in to the getProperty method.
505 /// Ldap_PROPERTY_PROTOCOL = "version.protocol"
507 /// You can use this string to request the version of the
510 public const System
.String Ldap_PROPERTY_PROTOCOL
= "version.protocol";
512 /// <summary> A string that can be passed in to the getProperty method.
514 /// Ldap_PROPERTY_SECURITY = "version.security"
516 /// You can use this string to request the type of security
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
526 /// SERVER_SHUTDOWN_OID = "1.3.6.1.4.1.1466.20036"
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";
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.
543 /// <param name="factory"> An object capable of producing a Socket.
546 public LdapConnection()
549 // Get a unique connection name for debug
550 conn
= new Connection();
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.
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.
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.
575 /// <returns> A of the object.
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();
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();
611 newClone
.responseCtls
= null;
613 conn
.incrCloneCount(); // Increment the count of clones
617 /// <summary> Closes the connection, if open, and releases any other resources held
621 /// <exception> LdapException A general exception which includes an error
622 /// message and an Ldap error code.
625 /// <seealso cref="Disconnect">
629 // Disconnect did not come from user API call
630 Disconnect(defSearchCons
, false);
634 /// <summary> Returns a property of a connection object.
637 /// <param name="name"> Name of the property to be returned.
639 /// The following read-only properties are available
640 /// for any given connection:
642 /// <li>Ldap_PROPERTY_SDK returns the version of this SDK,
643 /// as a Float data type.</li>
645 /// <li>Ldap_PROPERTY_PROTOCOL returns the highest supported version of
646 /// the Ldap protocol, as a Float data type.</li>
648 /// <li>Ldap_PROPERTY_SECURITY returns a comma-separated list of the
649 /// types of authentication supported, as a
653 /// A deep copy of the property is provided where applicable; a
654 /// client does not need to clone the object received.
657 /// <returns> The object associated with the requested property,
658 /// or null if the property is not defined.
661 /// <seealso cref="LdapConstraints.getProperty">
663 /// <seealso cref="Object">
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
;
679 /// <summary> Registers an object to be notified on arrival of an unsolicited
680 /// message from a server.
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
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.
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.
707 /// <param name="listener"> An object to no longer be notified on arrival of
708 /// an unsolicited message from a server.
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.
721 /// This affects the LdapConnection object and all cloned objects. A
722 /// socket factory that implements LdapTLSSocketFactory must be set on the
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.
731 //*************************************************************************
732 // Below are all of the Ldap protocol operation methods
733 //*************************************************************************
735 //*************************************************************************
737 //*************************************************************************
741 /// Notifies the server not to send additional results associated with
742 /// this LdapSearchResults object, and discards any results already
746 /// <param name="results"> An object returned from a search.
749 /// <exception> LdapException A general exception which includes an error
750 /// message and an Ldap error code.
752 public virtual void Abandon(LdapSearchResults results
)
754 Abandon(results
, defSearchCons
);
760 /// Notifies the server not to send additional results associated with
761 /// this LdapSearchResults object, and discards any results already
765 /// <param name="results"> An object returned from a search.
768 /// <param name="cons"> The contraints specific to the operation.
771 /// <exception> LdapException A general exception which includes an error
772 /// message and an Ldap error code.
774 public virtual void Abandon(LdapSearchResults results
, LdapConstraints cons
)
781 /// Abandons an asynchronous operation.
784 /// <param name="id"> The ID of the asynchronous operation to abandon. The ID
785 /// can be obtained from the response queue for the
789 /// <exception> LdapException A general exception which includes an error
790 /// message and an Ldap error code.
792 public virtual void Abandon(int id
)
794 Abandon(id
, defSearchCons
);
798 /// <summary> Abandons an asynchronous operation, using the specified
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.
807 /// <param name="cons">The contraints specific to the operation.
810 /// <exception> LdapException A general exception which includes an error
811 /// message and an Ldap error code.
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
);
823 catch (System
.FieldAccessException ex
)
825 return ; // Ignore error
829 /// <summary> Abandons all outstanding operations managed by the queue.
831 /// All operations in progress, which are managed by the specified queue,
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.
840 /// <exception> LdapException A general exception which includes an error
841 /// message and an Ldap error code.
843 public virtual void Abandon(LdapMessageQueue queue
)
845 Abandon(queue
, defSearchCons
);
849 /// <summary> Abandons all outstanding operations managed by the queue.
851 /// All operations in progress, which are managed by the specified
852 /// queue, are abandoned.
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.
860 /// <param name="cons"> The contraints specific to the operation.
863 /// <exception> LdapException A general exception which includes an error
864 /// message and an Ldap error code.
866 public virtual void Abandon(LdapMessageQueue queue
, LdapConstraints cons
)
871 if (queue
is LdapSearchQueue
)
873 agent
= queue
.MessageAgent
;
877 agent
= queue
.MessageAgent
;
879 int[] msgIds
= agent
.MessageIDs
;
880 for (int i
= 0; i
< msgIds
.Length
; i
++)
882 agent
.Abandon(msgIds
[i
], cons
);
888 //*************************************************************************
890 //*************************************************************************
892 /// <summary> Synchronously adds an entry to the directory.
895 /// <param name="entry"> LdapEntry object specifying the distinguished
896 /// name and attributes of the new entry.
899 /// <exception> LdapException A general exception which includes an error
900 /// message and an Ldap error code.
902 public virtual void Add(LdapEntry entry
)
904 Add(entry
, defSearchCons
);
909 /// Synchronously adds an entry to the directory, using the specified
913 /// <param name="entry"> LdapEntry object specifying the distinguished
914 /// name and attributes of the new entry.
917 /// <param name="cons"> Constraints specific to the operation.
920 /// <exception> LdapException A general exception which includes an error
921 /// message and an Ldap error code.
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
);
940 /// <summary> Asynchronously adds an entry to the directory.
943 /// <param name="entry"> LdapEntry object specifying the distinguished
944 /// name and attributes of the new entry.
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.
952 /// <exception> LdapException A general exception which includes an error
953 /// message and an Ldap error code.
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
964 /// <param name="entry"> LdapEntry object specifying the distinguished
965 /// name and attributes of the new entry.
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.
973 /// <param name="cons"> Constraints specific to the operation.
976 /// <exception> LdapException A general exception which includes an error
977 /// message and an Ldap error code.
979 public virtual LdapResponseQueue
Add(LdapEntry entry
, LdapResponseQueue queue
, LdapConstraints cons
)
982 cons
= defSearchCons
;
984 // error check the parameters
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 //*************************************************************************
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
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.
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
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.
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.
1030 /// <exception> LdapException A general exception which includes an error
1031 /// message and an Ldap error code.
1034 public virtual void Bind(System
.String dn
, System
.String passwd
)
1036 Bind(Ldap_V3
, dn
, passwd
, defSearchCons
);
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.
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.
1049 /// <param name="version"> The Ldap protocol version, use Ldap_V3.
1050 /// Ldap_V2 is not supported.
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
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.
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.
1071 /// <exception> LdapException A general exception which includes an error
1072 /// message and an Ldap error code.
1075 public virtual void Bind(int version
, System
.String dn
, System
.String passwd
)
1077 Bind(version
, dn
, passwd
, defSearchCons
);
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.
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.
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
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.
1107 /// <param name="cons"> Constraints specific to the operation.
1110 /// <exception> LdapException A general exception which includes an error
1111 /// message and an Ldap error code.
1114 public virtual void Bind(System
.String dn
, System
.String passwd
, LdapConstraints cons
)
1116 Bind(Ldap_V3
, dn
, passwd
, cons
);
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.
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.
1129 /// <param name="version"> The Ldap protocol version, use Ldap_V3.
1130 /// Ldap_V2 is not supported.
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
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.
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.
1151 /// <param name="cons"> The constraints specific to the operation.
1154 /// <exception> LdapException A general exception which includes an error
1155 /// message and an Ldap error code.
1158 public virtual void Bind(int version
, System
.String dn
, System
.String passwd
, LdapConstraints cons
)
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
);
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.
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.
1191 /// <param name="version"> The version of the Ldap protocol to use
1192 /// in the bind, use Ldap_V3. Ldap_V2 is not supported.
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
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.
1207 /// <exception> LdapException A general exception which includes an error
1208 /// message and an Ldap error code.
1210 [CLSCompliantAttribute(false)]
1211 public virtual void Bind(int version
, System
.String dn
, sbyte[] passwd
)
1213 Bind(version
, dn
, passwd
, defSearchCons
);
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.
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.
1227 /// <param name="version"> The Ldap protocol version, use Ldap_V3.
1228 /// Ldap_V2 is not supported.
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
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.
1243 /// <param name="cons"> The constraints specific to the operation.
1246 /// <exception> LdapException A general exception which includes an error
1247 /// message and an Ldap error code.
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();
1256 // Set local copy of responseControls synchronously if any
1257 lock (responseCtlSemaphore
)
1259 responseCtls
= res
.Controls
;
1262 chkResultCode(queue
, cons
, res
);
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.
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.
1277 /// <param name="version"> The Ldap protocol version, use Ldap_V3.
1278 /// Ldap_V2 is not supported.
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
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.
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.
1298 /// <exception> LdapException A general exception which includes an error
1299 /// message and an Ldap error code.
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.
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.
1316 /// <param name="version"> The Ldap protocol version, use Ldap_V3.
1317 /// Ldap_V2 is not supported.
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
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.
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.
1337 /// <param name="cons"> Constraints specific to the operation.
1340 /// <exception> LdapException A general exception which includes an error
1341 /// message and an Ldap error code.
1343 [CLSCompliantAttribute(false)]
1344 public virtual LdapResponseQueue
Bind(int version
, System
.String dn
, sbyte[] passwd
, LdapResponseQueue queue
, LdapConstraints cons
)
1347 BindProperties bindProps
;
1349 cons
= defSearchCons
;
1351 if ((System
.Object
) dn
== 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
);
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 //*************************************************************************
1396 //*************************************************************************
1399 /// Synchronously checks to see if an entry contains an attribute
1400 /// with a specified value.
1403 /// <param name="dn"> The distinguished name of the entry to use in the
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
1413 /// <returns> True if the entry has the value,
1414 /// and false if the entry does not
1415 /// have the value or the attribute.
1418 /// <exception> LdapException A general exception which includes an error
1419 /// message and an Ldap error code.
1421 public virtual bool Compare(System
.String dn
, LdapAttribute attr
)
1423 return Compare(dn
, attr
, defSearchCons
);
1427 /// Synchronously checks to see if an entry contains an attribute with a
1428 /// specified value, using the specified constraints.
1431 /// <param name="dn"> The distinguished name of the entry to use in the
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
1441 /// <param name="cons"> Constraints specific to the operation.
1444 /// <returns> True if the entry has the value,
1445 /// and false if the entry does not
1446 /// have the value or the attribute.
1449 /// <exception> LdapException A general exception which includes an error
1450 /// message and an Ldap error code.
1452 public virtual bool Compare(System
.String dn
, LdapAttribute attr
, LdapConstraints cons
)
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
)
1470 else if (res
.ResultCode
== LdapException
.COMPARE_FALSE
)
1476 chkResultCode(queue
, cons
, res
);
1481 /// <summary> Asynchronously compares an attribute value with one in the directory,
1482 /// using the specified queue.
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.
1490 /// <param name="dn"> The distinguished name of the entry containing an
1491 /// attribute to compare.
1494 /// <param name="attr"> An attribute to compare.
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.
1502 /// <exception> LdapException A general exception which includes an error
1503 /// message and an Ldap error code.
1506 /// <seealso cref="LdapException.COMPARE_TRUE">
1508 /// <seealso cref="LdapException.COMPARE_FALSE">
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.
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.
1524 /// <param name="dn"> The distinguished name of the entry containing an
1525 /// attribute to compare.
1528 /// <param name="attr"> An attribute to compare.
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.
1536 /// <param name="cons"> Constraints specific to the operation.
1539 /// <exception> LdapException A general exception which includes an error
1540 /// message and an Ldap error code.
1543 /// <seealso cref="LdapException.COMPARE_TRUE">
1545 /// <seealso cref="LdapException.COMPARE_FALSE">
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");
1561 cons
= defSearchCons
;
1563 LdapMessage msg
= new LdapCompareRequest(dn
, attr
.Name
, attr
.ByteValue
, cons
.getControls());
1565 return SendRequestToServer(msg
, cons
.TimeLimit
, queue
, null);
1568 //*************************************************************************
1570 //*************************************************************************
1573 /// Connects to the specified host and port.
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.
1580 /// When more than one host name is specified, each host is contacted
1581 /// in turn until a connection can be established.
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.
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
1596 /// <exception> LdapException A general exception which includes an error
1597 /// message and an Ldap error code.
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;
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
);
1636 catch (LdapException LE
)
1638 if (!hostList
.HasMoreTokens())
1645 //*************************************************************************
1647 //*************************************************************************
1650 /// Synchronously deletes the entry with the specified distinguished name
1651 /// from the directory.
1653 /// Note: A Delete operation will not remove an entry that contains
1654 /// subordinate entries, nor will it dereference alias entries.
1657 /// <param name="dn"> The distinguished name of the entry to delete.
1660 /// <exception> LdapException A general exception which includes an error
1661 /// message and an Ldap error code.
1663 public virtual void Delete(System
.String dn
)
1665 Delete(dn
, defSearchCons
);
1670 /// <summary> Synchronously deletes the entry with the specified distinguished name
1671 /// from the directory, using the specified constraints.
1673 /// Note: A Delete operation will not remove an entry that contains
1674 /// subordinate entries, nor will it dereference alias entries.
1677 /// <param name="dn"> The distinguished name of the entry to delete.
1680 /// <param name="cons"> Constraints specific to the operation.
1683 /// <exception> LdapException A general exception which includes an error
1684 /// message and an Ldap error code.
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
);
1702 /// <summary> Asynchronously deletes the entry with the specified distinguished name
1703 /// from the directory and returns the results to the specified queue.
1705 /// Note: A Delete operation will not remove an entry that contains
1706 /// subordinate entries, nor will it dereference alias entries.
1709 /// <param name="dn"> The distinguished name of the entry to modify.
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.
1717 /// <exception> LdapException A general exception which includes an error
1718 /// message and an Ldap error code.
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.
1729 /// Note: A Delete operation will not remove an entry that contains
1730 /// subordinate entries, nor will it dereference alias entries.
1733 /// <param name="dn"> The distinguished name of the entry to delete.
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.
1741 /// <param name="cons"> The constraints specific to the operation.
1744 /// <exception> LdapException A general exception which includes an error
1745 /// message and an Ldap error code.
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
);
1757 cons
= defSearchCons
;
1759 LdapMessage msg
= new LdapDeleteRequest(dn
, cons
.getControls());
1761 return SendRequestToServer(msg
, cons
.TimeLimit
, queue
, null);
1764 //*************************************************************************
1765 // disconnect method
1766 //*************************************************************************
1769 /// Synchronously disconnects from the Ldap server.
1771 /// Before the object can perform Ldap operations again, it must
1772 /// reconnect to the server by calling connect.
1774 /// The disconnect method abandons any outstanding requests, issues an
1775 /// unbind request to the server, and then closes the socket.
1778 /// <exception> LdapException A general exception which includes an error
1779 /// message and an Ldap error code.
1782 public virtual void Disconnect()
1784 // disconnect from API call
1785 Disconnect(defSearchCons
, true);
1789 /// <summary> Synchronously disconnects from the Ldap server.
1791 /// Before the object can perform Ldap operations again, it must
1792 /// reconnect to the server by calling connect.
1794 /// The disconnect method abandons any outstanding requests, issues an
1795 /// unbind request to the server, and then closes the socket.
1798 /// <param name="cons">LDPConstraints to be set with the unbind request
1801 /// <exception> LdapException A general exception which includes an error
1802 /// message and an Ldap error code.
1804 public virtual void Disconnect(LdapConstraints cons
)
1806 // disconnect from API call
1807 Disconnect(cons
, true);
1811 /// <summary> Synchronously disconnect from the server
1814 /// <param name="how">true if application call disconnect API, false if finalize.
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
);
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.
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.
1839 /// <returns> An operation-specific object, containing an ID and either an octet
1840 /// string or BER-encoded values.
1843 /// <exception> LdapException A general exception which includes an error
1844 /// message and an Ldap error code.
1846 public virtual LdapExtendedResponse
ExtendedOperation(LdapExtendedOperation op
)
1848 return ExtendedOperation(op
, defSearchCons
);
1852 * Synchronous Ldap extended request with SearchConstraints
1856 /// Provides a synchronous means to access extended, non-mandatory
1857 /// operations offered by a particular Ldapv3 compliant server.
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.
1867 /// <param name="cons">The constraints specific to the operation.
1870 /// <returns> An operation-specific object, containing an ID and either an
1871 /// octet string or BER-encoded values.
1874 /// <exception> LdapException A general exception which includes an error
1875 /// message and an Ldap error code.
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
);
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.
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.
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.
1916 /// <returns> An operation-specific object, containing an ID and either an octet
1917 /// string or BER-encoded values.
1920 /// <exception> LdapException A general exception which includes an error
1921 /// message and an Ldap error code.
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.
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.
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.
1950 /// <param name="cons"> The constraints specific to this operation.
1953 /// <returns> An operation-specific object, containing an ID and either an
1954 /// octet string or BER-encoded values.
1957 /// <exception> LdapException A general exception which includes an error
1958 /// message and an Ldap error code.
1961 public virtual LdapResponseQueue
ExtendedOperation(LdapExtendedOperation op
, LdapConstraints cons
, LdapResponseQueue queue
)
1963 // Use default constraints if none-specified
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.
1975 protected internal virtual LdapMessage
MakeExtendedOperation(LdapExtendedOperation op
, LdapConstraints cons
)
1977 // Use default constraints if none-specified
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 //*************************************************************************
1997 //*************************************************************************
1999 /// <summary> Synchronously makes a single change to an existing entry in the
2002 /// For example, this modify method changes the value of an attribute,
2003 /// adds a new attribute value, or removes an existing attribute value.
2005 /// The LdapModification object specifies both the change to be made and
2006 /// the LdapAttribute value to be changed.
2008 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2009 /// it is indeterminate whether or not the server made the modification.
2012 /// <param name="dn"> The distinguished name of the entry to modify.
2015 /// <param name="mod"> A single change to be made to the entry.
2018 /// <exception> LdapException A general exception which includes an error
2019 /// message and an Ldap error code.
2021 public virtual void Modify(System
.String dn
, LdapModification mod
)
2023 Modify(dn
, mod
, defSearchCons
);
2028 /// Synchronously makes a single change to an existing entry in the
2029 /// directory, using the specified constraints.
2031 /// For example, this modify method changes the value of an attribute,
2032 /// adds a new attribute value, or removes an existing attribute value.
2034 /// The LdapModification object specifies both the change to be
2035 /// made and the LdapAttribute value to be changed.
2037 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2038 /// it is indeterminate whether or not the server made the modification.
2041 /// <param name="dn"> The distinguished name of the entry to modify.
2044 /// <param name="mod"> A single change to be made to the entry.
2047 /// <param name="cons"> The constraints specific to the operation.
2050 /// <exception> LdapException A general exception which includes an error
2051 /// message and an Ldap error code.
2053 public virtual void Modify(System
.String dn
, LdapModification mod
, LdapConstraints cons
)
2055 LdapModification
[] mods
= new LdapModification
[1];
2057 Modify(dn
, mods
, cons
);
2062 /// Synchronously makes a set of changes to an existing entry in the
2065 /// For example, this modify method changes attribute values, adds
2066 /// new attribute values, or removes existing attribute values.
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.
2075 /// <param name="dn"> Distinguished name of the entry to modify.
2078 /// <param name="mods"> The changes to be made to the entry.
2081 /// <exception> LdapException A general exception which includes an error
2082 /// message and an Ldap error code.
2084 public virtual void Modify(System
.String dn
, LdapModification
[] mods
)
2086 Modify(dn
, mods
, defSearchCons
);
2090 /// <summary> Synchronously makes a set of changes to an existing entry in the
2091 /// directory, using the specified constraints.
2093 /// For example, this modify method changes attribute values, adds new
2094 /// attribute values, or removes existing attribute values.
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.
2103 /// <param name="dn"> The distinguished name of the entry to modify.
2106 /// <param name="mods"> The changes to be made to the entry.
2109 /// <param name="cons"> The constraints specific to the operation.
2112 /// <exception> LdapException A general exception which includes an
2113 /// error message and an Ldap error code.
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
);
2133 /// <summary> Asynchronously makes a single change to an existing entry in the
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.
2139 /// The LdapModification object specifies both the change to be made and
2140 /// the LdapAttribute value to be changed.
2142 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2143 /// it is indeterminate whether or not the server made the modification.
2146 /// <param name="dn"> Distinguished name of the entry to modify.
2149 /// <param name="mod"> A single change to be made to the entry.
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.
2157 /// <exception> LdapException A general exception which includes an error
2158 /// message and an Ldap error code.
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.
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.
2171 /// The LdapModification object specifies both the change to be made
2172 /// and the LdapAttribute value to be changed.
2174 /// If the request fails with {@link LdapException.CONNECT_ERROR},
2175 /// it is indeterminate whether or not the server made the modification.
2178 /// <param name="dn"> Distinguished name of the entry to modify.
2181 /// <param name="mod"> A single change to be made to the entry.
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.
2189 /// <param name="cons"> Constraints specific to the operation.
2192 /// <exception> LdapException A general exception which includes an error
2193 /// message and an Ldap error code.
2195 public virtual LdapResponseQueue
Modify(System
.String dn
, LdapModification mod
, LdapResponseQueue queue
, LdapConstraints cons
)
2197 LdapModification
[] mods
= new LdapModification
[1];
2199 return Modify(dn
, mods
, queue
, cons
);
2202 /// <summary> Asynchronously makes a set of changes to an existing entry in the
2205 /// For example, this modify method can change attribute values, add new
2206 /// attribute values, or remove existing attribute values.
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.
2215 /// <param name="dn"> The distinguished name of the entry to modify.
2218 /// <param name="mods"> The changes to be made to the entry.
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.
2226 /// <exception> LdapException A general exception which includes an error
2227 /// message and an Ldap error code.
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.
2237 /// For example, this modify method can change attribute values, add new
2238 /// attribute values, or remove existing attribute values.
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.
2247 /// <param name="dn"> The distinguished name of the entry to modify.
2250 /// <param name="mods"> The changes to be made to the entry.
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.
2258 /// <param name="cons"> Constraints specific to the operation.
2261 /// <exception> LdapException A general exception which includes an error
2262 /// message and an Ldap error code.
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
);
2273 cons
= defSearchCons
;
2275 LdapMessage msg
= new LdapModifyRequest(dn
, mods
, cons
.getControls());
2277 return SendRequestToServer(msg
, cons
.TimeLimit
, queue
, null);
2280 //*************************************************************************
2282 //*************************************************************************
2284 /// <summary> Synchronously reads the entry for the specified distiguished name (DN)
2285 /// and retrieves all attributes for the entry.
2288 /// <param name="dn"> The distinguished name of the entry to retrieve.
2291 /// <returns> the LdapEntry read from the server.
2294 /// <exception> LdapException if the object was not found
2296 public virtual LdapEntry
Read(System
.String dn
)
2298 return Read(dn
, defSearchCons
);
2303 /// Synchronously reads the entry for the specified distiguished name (DN),
2304 /// using the specified constraints, and retrieves all attributes for the
2308 /// <param name="dn"> The distinguished name of the entry to retrieve.
2311 /// <param name="cons"> The constraints specific to the operation.
2314 /// <returns> the LdapEntry read from the server
2317 /// <exception> LdapException if the object was not found
2319 public virtual LdapEntry
Read(System
.String dn
, LdapSearchConstraints cons
)
2321 return Read(dn
, null, cons
);
2325 /// Synchronously reads the entry for the specified distinguished name (DN)
2326 /// and retrieves only the specified attributes from the entry.
2329 /// <param name="dn"> The distinguished name of the entry to retrieve.
2332 /// <param name="attrs"> The names of the attributes to retrieve.
2335 /// <returns> the LdapEntry read from the server
2338 /// <exception> LdapException if the object was not found
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.
2350 /// <param name="dn"> The distinguished name of the entry to retrieve.
2353 /// <param name="attrs"> The names of the attributes to retrieve.
2356 /// <param name="cons"> The constraints specific to the operation.
2359 /// <returns> the LdapEntry read from the server
2362 /// <exception> LdapException if the object was not found
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;
2374 // "Read response is ambiguous, multiple entries returned"
2375 throw new LdapLocalException(ExceptionMessages
.READ_MULTIPLE
, LdapException
.AMBIGUOUS_RESPONSE
);
2381 /// <summary> Synchronously reads the entry specified by the Ldap URL.
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).
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.
2394 /// <param name="toGet"> Ldap URL specifying the entry to read.
2397 /// <returns> The entry specified by the base DN.
2400 /// <exception> LdapException if the object was not found
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
);
2411 /// <summary> Synchronously reads the entry specified by the Ldap URL, using the
2412 /// specified constraints.
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).
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.
2425 /// <returns> The entry specified by the base DN.
2428 /// <param name="toGet"> Ldap URL specifying the entry to read.
2431 /// <param name="cons"> Constraints specific to the operation.
2434 /// <exception> LdapException if the object was not found
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
);
2445 //*************************************************************************
2447 //*************************************************************************
2450 /// Synchronously renames an existing entry in the directory.
2453 /// <param name="dn"> The current distinguished name of the entry.
2456 /// <param name="newRdn"> The new relative distinguished name for the entry.
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.
2464 /// <exception> LdapException A general exception which includes an error
2465 /// message and an Ldap error code.
2467 public virtual void Rename(System
.String dn
, System
.String newRdn
, bool deleteOldRdn
)
2469 Rename(dn
, newRdn
, deleteOldRdn
, defSearchCons
);
2474 /// Synchronously renames an existing entry in the directory, using the
2475 /// specified constraints.
2478 /// <param name="dn"> The current distinguished name of the entry.
2481 /// <param name="newRdn"> The new relative distinguished name for the entry.
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.
2489 /// <param name="cons"> The constraints specific to the operation.
2492 /// <exception> LdapException A general exception which includes an error
2493 /// message and an Ldap error code.
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
);
2502 /// <summary> Synchronously renames an existing entry in the directory, possibly
2503 /// repositioning the entry in the directory tree.
2506 /// <param name="dn"> The current distinguished name of the entry.
2509 /// <param name="newRdn"> The new relative distinguished name for the entry.
2512 /// <param name="newParentdn"> The distinguished name of an existing entry which
2513 /// is to be the new parent of the entry.
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.
2521 /// <exception> LdapException A general exception which includes an error
2522 /// message and an Ldap error code.
2524 public virtual void Rename(System
.String dn
, System
.String newRdn
, System
.String newParentdn
, bool deleteOldRdn
)
2526 Rename(dn
, newRdn
, newParentdn
, deleteOldRdn
, defSearchCons
);
2531 /// Synchronously renames an existing entry in the directory, using the
2532 /// specified constraints and possibly repositioning the entry in the
2536 /// <param name="dn"> The current distinguished name of the entry.
2539 /// <param name="newRdn"> The new relative distinguished name for the entry.
2542 /// <param name="newParentdn"> The distinguished name of an existing entry which
2543 /// is to be the new parent of the entry.
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.
2551 /// <param name="cons"> The constraints specific to the operation.
2554 /// <exception> LdapException A general exception which includes an error
2555 /// message and an Ldap error code.
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
);
2578 /// <summary> Asynchronously renames an existing entry in the directory.
2581 /// <param name="dn"> The current distinguished name of the entry.
2584 /// <param name="newRdn"> The new relative distinguished name for the entry.
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.
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.
2597 /// <exception> LdapException A general exception which includes an error
2598 /// message and an Ldap error code.
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.
2609 /// <param name="dn"> The current distinguished name of the entry.
2612 /// <param name="newRdn"> The new relative distinguished name for the entry.
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.
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.
2625 /// <param name="cons"> The constraints specific to the operation.
2628 /// <exception> LdapException A general exception which includes an error
2629 /// message and an Ldap error code.
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.
2640 /// <param name="dn"> The current distinguished name of the entry.
2643 /// <param name="newRdn"> The new relative distinguished name for the entry.
2646 /// <param name="newParentdn"> The distinguished name of an existing entry which
2647 /// is to be the new parent of the entry.
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.
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.
2660 /// <exception> LdapException A general exception which includes an error
2661 /// message and an Ldap error code.
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
2673 /// <param name="dn"> The current distinguished name of the entry.
2676 /// <param name="newRdn"> The new relative distinguished name for the entry.
2679 /// <param name="newParentdn"> The distinguished name of an existing entry which
2680 /// is to be the new parent of the entry.
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.
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.
2693 /// <param name="cons"> The constraints specific to the operation.
2696 /// <exception> LdapException A general exception which includes an error
2697 /// message and an Ldap error code.
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
);
2708 cons
= defSearchCons
;
2710 LdapMessage msg
= new LdapModifyDNRequest(dn
, newRdn
, newParentdn
, deleteOldRdn
, cons
.getControls());
2712 return SendRequestToServer(msg
, cons
.TimeLimit
, queue
, null);
2715 //*************************************************************************
2717 //*************************************************************************
2720 /// Synchronously performs the search specified by the parameters.
2723 /// <param name="base"> The base distinguished name to search from.
2726 /// <param name="scope"> The scope of the entries to search. The following
2727 /// are the valid options:
2729 /// <li>SCOPE_BASE - searches only the base DN</li>
2731 /// <li>SCOPE_ONE - searches only entries under the base DN</li>
2733 /// <li>SCOPE_SUB - searches the base DN and all entries
2734 /// within its subtree</li>
2737 /// <param name="filter"> Search filter specifying the search criteria.
2740 /// <param name="attrs"> Names of attributes to retrieve.
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.
2748 /// <exception> LdapException A general exception which includes an error
2749 /// message and an Ldap error code.
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
);
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).
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.
2769 /// <param name="base"> The base distinguished name to search from.
2772 /// <param name="scope"> The scope of the entries to search. The following
2773 /// are the valid options:
2775 /// <li>SCOPE_BASE - searches only the base DN</li>
2777 /// <li>SCOPE_ONE - searches only entries under the base DN</li>
2779 /// <li>SCOPE_SUB - searches the base DN and all entries
2780 /// within its subtree</li>
2783 /// <param name="filter"> The search filter specifying the search criteria.
2786 /// <param name="attrs"> The names of attributes to retrieve.
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.
2794 /// <param name="cons"> The constraints specific to the search.
2797 /// <exception> LdapException A general exception which includes an error
2798 /// message and an Ldap error code.
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
);
2805 cons
= defSearchCons
;
2806 return new LdapSearchResults(this, queue
, cons
);
2809 /// <summary> Asynchronously performs the search specified by the parameters.
2812 /// <param name="base"> The base distinguished name to search from.
2815 /// <param name="scope"> The scope of the entries to search. The following
2816 /// are the valid options:
2818 /// <li>SCOPE_BASE - searches only the base DN</li>
2820 /// <li>SCOPE_ONE - searches only entries under the base DN</li>
2822 /// <li>SCOPE_SUB - searches the base DN and all entries
2823 /// within its subtree</li>
2826 /// <param name="filter"> Search filter specifying the search criteria.
2829 /// <param name="attrs"> Names of attributes to retrieve.
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.
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.
2842 /// <exception> LdapException A general exception which includes an error
2843 /// message and an Ldap error code.
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).
2856 /// <param name="base"> The base distinguished name to search from.
2859 /// <param name="scope"> The scope of the entries to search. The following
2860 /// are the valid options:
2862 /// <li>SCOPE_BASE - searches only the base DN</li>
2864 /// <li>SCOPE_ONE - searches only entries under the base DN</li>
2866 /// <li>SCOPE_SUB - searches the base DN and all entries
2867 /// within its subtree</li>
2870 /// <param name="filter"> The search filter specifying the search criteria.
2873 /// <param name="attrs"> The names of attributes to retrieve.
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.
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.
2886 /// <param name="cons"> The constraints specific to the search.
2889 /// <exception> LdapException A general exception which includes an error
2890 /// message and an Ldap error code.
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=*";
2899 cons
= defSearchCons
;
2901 LdapMessage msg
= new LdapSearchRequest(base_Renamed
, scope
, filter
, attrs
, cons
.Dereference
, cons
.MaxResults
, cons
.ServerTimeLimit
, typesOnly
, cons
.getControls());
2903 LdapSearchQueue myqueue
= queue
;
2904 if (myqueue
== null)
2906 agent
= new MessageAgent();
2907 myqueue
= new LdapSearchQueue(agent
);
2911 agent
= queue
.MessageAgent
;
2916 agent
.sendMessage(conn
, msg
, cons
.TimeLimit
, myqueue
, null);
2918 catch (LdapException lex
)
2929 /// <summary> Synchronously performs the search specified by the Ldap URL, returning
2930 /// an enumerable LdapSearchResults object.
2933 /// <param name="toGet">The Ldap URL specifying the entry to read.
2936 /// <exception> LdapException A general exception which includes an error
2937 /// message and an Ldap error code.
2939 public static LdapSearchResults
Search(LdapUrl toGet
)
2941 // Get a clone of default search constraints, method alters batchSize
2942 return Search(toGet
, null);
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).
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
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.
2966 /// <param name="toGet"> Ldap URL specifying the entry to read.
2969 /// <param name="cons"> The constraints specific to the search.
2972 /// <exception> LdapException A general exception which includes an error
2973 /// message and an Ldap error code.
2975 public static LdapSearchResults
Search(LdapUrl toGet
, LdapSearchConstraints cons
)
2977 LdapConnection lconn
= new LdapConnection();
2978 lconn
.Connect(toGet
.Host
, toGet
.Port
);
2981 // This is a clone, so we already have our own copy
2982 cons
= lconn
.SearchConstraints
;
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
);
2995 /// <summary> Sends an Ldap request to a directory server.
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
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.
3008 /// <param name="request">The Ldap request to send to the directory server.
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.
3014 /// <exception> LdapException A general exception which includes an error
3015 /// message and an Ldap error code.
3018 /// <seealso cref="LdapMessage.Type">
3020 /// <seealso cref="RfcLdapMessage.isRequest">
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.
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
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.
3040 /// <param name="request">The Ldap request to send to the directory server.
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.
3046 /// <param name="cons"> The constraints that apply to this request
3048 /// <exception> LdapException A general exception which includes an error
3049 /// message and an Ldap error code.
3052 /// <seealso cref="LdapMessage.Type">
3054 /// <seealso cref="RfcLdapMessage.isRequest">
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");
3067 cons
= defSearchCons
;
3070 // Get the correct queue for a search request
3072 LdapMessageQueue myqueue
= queue
;
3073 if (myqueue
== null)
3075 agent
= new MessageAgent();
3076 if (request
.Type
== LdapMessage
.SEARCH_REQUEST
)
3078 myqueue
= new LdapSearchQueue(agent
);
3082 myqueue
= new LdapResponseQueue(agent
);
3087 if (request
.Type
== LdapMessage
.SEARCH_REQUEST
)
3089 agent
= queue
.MessageAgent
;
3093 agent
= queue
.MessageAgent
;
3099 agent
.sendMessage(conn
, request
, cons
.TimeLimit
, myqueue
, null);
3101 catch (LdapException lex
)
3108 //*************************************************************************
3110 //*************************************************************************
3112 /// <summary> Locates the appropriate message agent and sends
3113 /// the Ldap request to a directory server.
3116 /// <param name="msg">the message to send
3119 /// <param name="timeout">the timeout value
3122 /// <param name="queue">the response queue or null
3125 /// <returns> the LdapResponseQueue for this request
3128 /// <exception> LdapException A general exception which includes an error
3129 /// message and an Ldap error code.
3131 private LdapResponseQueue
SendRequestToServer(LdapMessage msg
, int timeout
, LdapResponseQueue queue
, BindProperties bindProps
)
3136 agent
= new MessageAgent();
3137 queue
= new LdapResponseQueue(agent
);
3141 agent
= queue
.MessageAgent
;
3144 agent
.sendMessage(conn
, msg
, timeout
, queue
, bindProps
);
3148 /// <summary> get an LdapConnection object so that we can follow a referral.
3149 /// This function is never called if cons.getReferralFollowing() returns
3153 /// <param name="referrals">the array of referral strings
3157 /// <returns> The referralInfo object
3160 /// <exception> LdapReferralException A general exception which includes
3161 /// an error message and an Ldap error code.
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();
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;
3180 rconn
= new LdapConnection();
3181 rconn
.Constraints
= defSearchCons
;
3182 LdapUrl url
= new LdapUrl(referrals
[i
]);
3183 rconn
.Connect(url
.Host
, url
.Port
);
3186 if (rh
is LdapAuthHandler
)
3188 // Get application supplied dn and pw
3189 LdapAuthProvider ap
= ((LdapAuthHandler
) rh
).getAuthProvider(url
.Host
, url
.Port
);
3194 rconn
.Bind(Ldap_V3
, dn
, pw
);
3196 refInfo
= new ReferralInfo(rconn
, referrals
, url
);
3197 // Indicate this connection created to follow referral
3198 rconn
.Connection
.ActiveReferral
= refInfo
;
3201 catch (System
.Exception lex
)
3211 catch (LdapException e
)
3219 // Check if application gets connection and does bind
3222 // rh instanceof LdapBind
3225 rconn
= ((LdapBindHandler
) rh
).Bind(referrals
, this);
3228 LdapReferralException rex
= new LdapReferralException(ExceptionMessages
.REFERRAL_ERROR
);
3229 rex
.setReferrals(referrals
);
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
);
3244 catch (System
.Exception e
)
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
)
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
;
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];
3285 // We now have an authenticated connection
3286 // to be used to follow the referral.
3290 /// <summary> Check the result code and throw an exception if needed.
3292 /// If referral following is enabled, checks if we need to
3293 /// follow a referral
3296 /// <param name="queue">- the message queue of the current response
3299 /// <param name="cons">- the constraints that apply to the request
3302 /// <param name="response">- the LdapResponse to check
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);
3316 releaseReferralConnections(refConn
);
3321 // Throws exception for non success result
3322 response
.chkResultCode();
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.
3334 /// This functions recursively follows a referral until a result
3335 /// is returned or until the hop limit is reached.
3338 /// <param name="queue">The LdapResponseQueue for this request
3341 /// <param name="cons">The constraints that apply to the request
3344 /// <param name="msg">The referral or search reference response message
3347 /// <param name="initialReferrals">The referral array returned from the
3348 /// initial request.
3351 /// <param name="hopCount">the number of hops already used while
3352 /// following this referral
3355 /// <param name="searchReference">true if the message is a search reference
3358 /// <param name="connectionList">An optional array list used to store
3359 /// the LdapConnection objects used in following the referral.
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.
3367 /// <exception> LdapException A general exception which includes an error
3368 /// message and an Ldap error code.
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
;
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();
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
3428 if (queue
is LdapResponseQueue
)
3430 agent
= queue
.MessageAgent
;
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();
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
);
3458 // For search, just return to LdapSearchResults object
3462 catch (System
.Exception ex
)
3465 if (ex
is LdapReferralException
)
3467 throw (LdapReferralException
) ex
;
3472 // Set referral list and failed referral
3473 LdapReferralException rex
= new LdapReferralException(ExceptionMessages
.REFERRAL_ERROR
, ex
);
3474 rex
.setReferrals(refs
);
3477 rex
.FailedReferral
= rinfo
.ReferralUrl
.ToString();
3481 rex
.FailedReferral
= refs
[refs
.Length
- 1];
3489 /// <summary> Builds a new request replacing dn, scope, and filter where approprate
3492 /// <param name="msg">the original LdapMessage to build the new request from
3495 /// <param name="url">the referral url
3498 /// <returns> a new LdapMessage with appropriate information replaced
3501 /// <exception> LdapException A general exception which includes an error
3502 /// message and an Ldap error code.
3504 private LdapMessage
rebuildRequest(LdapMessage msg
, LdapUrl url
, bool reference
)
3507 System
.String dn
= url
.getDN(); // new base
3508 System
.String filter
= null;
3513 case LdapMessage
.SEARCH_REQUEST
:
3516 filter
= url
.Filter
;
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
:
3529 // The following return no response
3531 case LdapMessage
.ABANDON_REQUEST
:
3532 case LdapMessage
.UNBIND_REQUEST
:
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
3546 internal virtual void releaseReferralConnections(System
.Collections
.ArrayList list
)
3552 // Release referral connections
3553 for (int i
= list
.Count
- 1; i
>= 0; i
--)
3555 LdapConnection rconn
= null;
3558 rconn
=(LdapConnection
)list
[i
];
3560 // rconn = (LdapConnection) list.RemoveAt(i);
3563 catch (System
.IndexOutOfRangeException ex
)
3567 catch (LdapException lex
)
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
3585 /// <param name="schemaDN">The schema DN used to fetch the schema.
3588 /// <returns> An LDAPSchema entry containing schema attributes. If the
3589 /// entry contains no schema attributes then the returned LDAPSchema object
3593 /// <exception> LDAPException This exception occurs if the schema entry
3594 /// cannot be retrieved with this connection.
3596 /// <seealso cref="GetSchemaDN()">
3598 /// <seealso cref="GetSchemaDN(String)">
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.
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>.
3617 /// <returns> Distinguished Name of a schema entry in effect for the
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.
3625 /// <seealso cref="FetchSchema">
3627 /// <seealso cref="Modify">
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.
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
3642 /// <param name="dn"> Distinguished Name of any entry. The subschemaSubentry
3643 /// attribute is queried from this entry.
3646 /// <returns> Distinguished Name of a schema entry in effect for the entry
3647 /// identified by <code>dn</code>.
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.
3655 /// <seealso cref="FetchSchema">
3657 /// <seealso cref="Modify">
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
);