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 *******************************************************************************/
25 // System.DirectoryServices.DirectoryEntry.cs
28 // Sunil Kumar (sunilk@novell.com)
29 // Andreas Nahr (ClassDevelopment@A-SoftTech.com)
34 using System.ComponentModel;
35 using Novell.Directory.Ldap;
36 using Novell.Directory.Ldap.Utilclass;
37 using System.Globalization;
38 using System.DirectoryServices.Design;
40 namespace System.DirectoryServices
44 ///Encapsulates a node or object in the Ldap Directory hierarchy.
46 [TypeConverter (typeof (DirectoryEntryConverter))]
47 public class DirectoryEntry : Component
50 private LdapConnection _conn = null;
51 private AuthenticationTypes _AuthenticationType=AuthenticationTypes.None;
52 private DirectoryEntries _Children;
53 private string _Fdn = null;
54 private string _Path="";
55 private string _Name=null;
56 private DirectoryEntry _Parent=null;
57 private string _Username;
58 private string _Password;
59 //private string _Nativeguid;
60 private PropertyCollection _Properties = null;
61 private string _SchemaClassName=null;
62 private bool _Nflag = false;
63 private bool _usePropertyCache=true;
64 private bool _inPropertiesLoading;
67 /// Returns entry's Fully distinguished name.
73 LdapUrl lUrl = new LdapUrl(Path);
74 string fDn=lUrl.getDN();
85 /// Returns the connection object used to communicate with
88 internal LdapConnection conn
102 /// Flag to check whether the entry is to be cerated or it already
115 /// <summary> Initializes the Connection and other properties.
118 private void InitBlock()
121 _conn= new LdapConnection ();
122 LdapUrl lUrl=new LdapUrl (Path);
123 _conn.Connect(lUrl.Host,lUrl.Port);
124 _conn.Bind(Username,Password);
126 catch(LdapException ex) {
135 /// Initializes the Entry specific properties e.g entry DN etc.
139 LdapUrl lUrl=new LdapUrl (Path);
140 if(lUrl.getDN()!=null) {
141 DN userDn = new DN(lUrl.getDN());
142 String[] lRdn = userDn.explodeDN(false);
143 _Name = (string)lRdn[0];
144 _Parent = new DirectoryEntry(conn);
145 LdapUrl cUrl=new LdapUrl(lUrl.Host,lUrl.Port,userDn.Parent.ToString());
146 _Parent.Path=cUrl.ToString();
149 _Name=lUrl.Host+":"+lUrl.Port;
150 _Parent = new DirectoryEntry(conn);
151 _Parent.Path = "Ldap:";
156 /// Initializes a new instance of the DirectoryEntry class
158 public DirectoryEntry()
163 /// Initializes a new instance of the DirectoryEntry class that binds
164 /// to the specified native Active Directory object.
166 /// <param name="adsObject"> native active directory object</param>
167 public DirectoryEntry(object adsObject)
169 throw new NotImplementedException();
173 /// Initializes a new instance of the DirectoryEntry class that binds
174 /// this instance to the node in Ldap Directory located at the
177 /// <param name="path"> Path of the entry i.e Ldap URL specifying
178 /// entry path</param>
179 public DirectoryEntry(string path)
185 /// Initializes a new instance of the DirectoryEntry class. The Path,
186 /// Username, and Password properties are set to the specified values.
188 /// <param name="path">Path of the entry i.e Ldap URL specifying
189 /// entry path</param>
190 /// <param name="username">user name to use when authenticating the client
192 /// <param name="password">password to use when authenticating the client
194 public DirectoryEntry(string path,string username,string password)
202 /// Initializes a new instance of the DirectoryEntry class. The Path,
203 /// Username, and Password properties are set to the specified values.
205 /// <param name="path">Path of the entry i.e Ldap URL specifying
206 /// entry path</param>
207 /// <param name="username">user name to use when authenticating the client
209 /// <param name="password">password to use when authenticating the client
211 /// <param name="authenticationType"> type of authentication to use</param>
212 public DirectoryEntry(
216 AuthenticationTypes authenticationType)
221 _AuthenticationType=authenticationType;
225 /// Creates the entry object
227 /// <param name="lconn">Connection object used to communicate with
228 /// Ldap server</param>
229 internal DirectoryEntry(LdapConnection lconn)
235 /// Returns Type of authentication to use while Binding to Ldap server
237 [DSDescription ("Type of authentication to use while Binding to Ldap server")]
238 [DefaultValue (AuthenticationTypes.None)]
239 public AuthenticationTypes AuthenticationType
243 return _AuthenticationType;
247 _AuthenticationType = value;
252 /// Gets a DirectoryEntries containing the child entries of this node
253 /// in the Ldap Directory hierarchy.
255 /// <value>A DirectoryEntries containing the child entries of this node
256 /// in the Ldap Directory hierarchy.</value>
258 /// The child entries are only the immediate children of this node.
259 /// Use this property to find, retrieve, or create a directory entry
260 /// in the hierarchy. This property is a collection that, along with
261 /// usual iteration capabilities, provides an Add method through which
262 /// you add a node to the collection directly below the parent node
263 /// that you are currently bound to. When adding a node to the
264 /// collection, you must specify a name for the new node and the name of
265 /// a schema template that you want to associate with the node. For
266 /// example, you might want to use a schema titled "Computer" to add
267 /// new computers to the hierarchy.
269 [DSDescription ("Child entries of this node")]
270 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
272 public DirectoryEntries Children
276 _Children = new DirectoryEntries(Path, conn);
282 /// Gets the globally unique identifier (GUID) of the DirectoryEntry
284 /// <value>The globally unique identifier of the DirectoryEntry.</value>
286 /// Not implemented yet.
288 [DSDescription ("A globally unique identifier for this DirectoryEntry")]
289 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
296 throw new NotImplementedException();
302 /// Gets the name of the object as named with the underlying directory
305 /// <value>The name of the object as named with the underlying directory
307 /// <remarks>This name, along with SchemaClassName, distinguishes this
308 /// entry from its siblings and must be unique amongst its siblings
309 /// in each instance of DirectoryEntry.</remarks>
310 [DSDescription ("The name of the object as named with the underlying directory")]
311 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
317 if(CheckEntry(conn,Path))
320 throw new SystemException("There is no such object on the server");
327 /// Gets this entry's parent in the Ldap Directory hierarchy.
329 /// <value>This entry's parent in the Active Directory hierarc</value>
330 [DSDescription ("This entry's parent in the Ldap Directory hierarchy.")]
331 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
333 public DirectoryEntry Parent
337 if(CheckEntry(conn,Path))
340 throw new SystemException("There is no such object on the server");
347 /// Gets the globally unique identifier of the DirectoryEntry, as
348 /// returned from the provider
351 /// The globally unique identifier of the DirectoryEntry, as returned
352 /// from the provider.
355 /// Not implemented yet.
357 [DSDescription ("The globally unique identifier of the DirectoryEntry, as returned from the provider")]
358 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
361 public string NativeGuid
364 throw new NotImplementedException();
369 /// Gets the native Active Directory Service Interfaces (ADSI) object.
372 /// Not implemented yet
373 [DSDescription ("The native Active Directory Service Interfaces (ADSI) object.")]
374 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
376 public object NativeObject
380 throw new NotImplementedException();
385 /// Determines if a cache should be used.
387 [DSDescription ("Determines if a cache should be used.")]
388 [DefaultValue (true)]
389 public bool UsePropertyCache
393 return _usePropertyCache;
397 _usePropertyCache = value;
402 /// Gets or sets the password to use when authenticating the client.
405 /// The password to use when authenticating the client.
408 /// You can set the Username and password in order to specify alternate
409 /// credentials with which to access the information in Ldap Directory.
410 /// Any other DirectoryEntry objects retrieved from this instance (for
411 /// example, through Children) are automatically created with the same
412 /// alternate credentials.
414 [DSDescription ("The password to use when authenticating the client.")]
415 [DefaultValue (null)]
417 public string Password
429 /// Gets or sets the user name to use when authenticating the client.
432 /// The user name to use when authenticating the client.
435 /// You can set the user name and Password in order to specify alternate
436 /// credentials with which to access the information in Ldap Directory.
437 /// Any other DirectoryEntry objects retrieved from this instance (for
438 /// example, through Children) are automatically created with the same
441 [DSDescription ("The user name to use when authenticating the client.")]
442 [DefaultValue (null)]
444 [TypeConverter ("System.Diagnostics.Design.StringValueConverter, " + Consts.AssemblySystem_Design)]
445 public string Username
457 /// Gets or sets the path for this DirectoryEntry.
460 /// The path of this DirectoryEntry. The default is an empty string ("").
463 /// The Path property uniquely identifies this entry in a networked
464 /// environment. This entry can always be retrieved using this Path.
466 /// Setting the Path retrieves a new entry from the directory store; it
467 /// does not change the path of the currently bound entry.
469 /// The classes associated with the DirectoryEntry component can be used
470 /// with any of the Directory service providers. Some of the current
471 /// providers are Internet Information Services (IIS), Lightweight Directory
472 /// Access Protocol (Ldap), Novell NetWare Directory Service (NDS), and WinNT.
474 /// Currently we Support only Ldap provider.
475 /// e.g Ldap://[hostname]:[port number]/[ObjectFDN]
477 [DSDescription ("The path for this DirectoryEntry.")]
479 [RecommendedAsConfigurable (true)]
480 [TypeConverter ("System.Diagnostics.Design.StringValueConverter, " + Consts.AssemblySystem_Design)]
493 /// Gets a PropertyCollection of properties set on this object.
496 /// A PropertyCollection of properties set on this object.
498 [DSDescription ("Properties set on this object.")]
499 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
501 public PropertyCollection Properties
504 if ( _Properties == null ) {
506 _Properties = new PropertyCollection(this);
507 _inPropertiesLoading = true;
510 LdapSearchResults lsc=conn.Search( Fdn,
511 LdapConnection.SCOPE_BASE,
515 while(lsc.hasMore()) {
517 LdapEntry nextEntry = null;
519 nextEntry = lsc.next();
521 catch(LdapException e) {
522 // Exception is thrown, go for next entry
525 LdapAttributeSet attributeSet = nextEntry.getAttributeSet();
526 System.Collections.IEnumerator ienum=attributeSet.GetEnumerator();
528 while(ienum.MoveNext()) {
529 LdapAttribute attribute=(LdapAttribute)ienum.Current;
530 string attributeName = attribute.Name;
531 _Properties[attributeName].AddRange(attribute.StringValueArray);
532 _Properties[attributeName].Mbit=false;
533 // string attributeVal = attribute.StringValue;
534 // _Properties[attributeName].Add(attributeVal);
540 catch( LdapException le) {
541 if(le.ResultCode == LdapException.NO_SUCH_OBJECT)
545 _inPropertiesLoading = false;
553 /// Gets the name of the schema used for this DirectoryEntry
556 /// The name of the schema used for this DirectoryEntry.
558 [DSDescription ("The name of the schema used for this DirectoryEntry.")]
559 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
561 public string SchemaClassName
564 if(_SchemaClassName==null) {
565 _SchemaClassName = FindAttrValue("structuralObjectClass");
567 return _SchemaClassName;
572 /// Gets the current schema directory entry.
575 /// Not implemented yet
576 [DSDescription ("The current schema directory entry.")]
577 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
579 public DirectoryEntry SchemaEntry
583 throw new NotImplementedException();
588 /// Searches an entry in the Ldap directory and returns the attribute value
590 /// <param name="attrName">attribute whose value is required</param>
591 /// <returns> value of the attribute stored in Ldap directory</returns>
592 private string FindAttrValue(string attrName)
595 string[] attrs={attrName};
597 LdapSearchResults lsc=conn.Search( Fdn,
598 LdapConnection.SCOPE_BASE,
602 while(lsc.hasMore()) {
603 LdapEntry nextEntry = null;
605 nextEntry = lsc.next();
607 catch(LdapException e) {
608 // Exception is thrown, go for next entry
611 LdapAttribute attribute = nextEntry.getAttribute(attrName);
612 aValue = attribute.StringValue;
619 /// Modifies an entry in the Ldap directory with the input LdapModification
622 /// <param name="mods">Array consisting of the entry attribute name and the
623 /// attribute values to be modified.</param>
624 private void ModEntry(LdapModification[] mods)
628 conn.Modify(Fdn,mods);
630 catch(LdapException le) {
636 /// Checks whether the entry exists in the Ldap directory or not
638 /// <param name="lconn">
639 /// Connection used to communicate with directory
641 /// <param name="epath">
642 /// path of the entry
645 /// true of the entry exists in the Ldap directory
646 /// false if entry doesn't exists
648 private static bool CheckEntry(LdapConnection lconn, string epath)
650 LdapUrl lUrl=new LdapUrl(epath);
651 string eDn=lUrl.getDN();
656 string[] attrs={"objectClass"};
659 LdapSearchResults lsc=lconn.Search( eDn,
660 LdapConnection.SCOPE_BASE,
666 LdapEntry nextEntry = null;
669 nextEntry = lsc.next();
671 catch(LdapException e)
673 // Exception is thrown, go for next entry
680 catch(LdapException le)
682 if(le.ResultCode == LdapException.NO_SUCH_OBJECT)
699 /// Closes the DirectoryEntry and releases any system resources associated
700 /// with this component.
703 /// Following a call to Close, any operations on the DirectoryEntry might
704 /// raise exceptions.
708 if (conn.Connected) {
714 /// Creates a copy of this entry as a child of the specified parent.
716 /// <param name="newParent">The parent DirectoryEntry. </param>
717 /// <returns>A copy of this entry as a child of the specified parent.
719 public DirectoryEntry CopyTo(DirectoryEntry newParent)
721 throw new NotImplementedException();
725 /// Deletes this entry and its entire subtree from the Active Directory
729 /// CAUTION The entry and its entire subtree are deleted from the
730 /// Ldap Directory hierarchy.
732 public void DeleteTree()
734 System.Collections.IEnumerator ienum = Children.GetEnumerator();
735 while(ienum.MoveNext())
737 DirectoryEntry de=(DirectoryEntry)ienum.Current;
744 /// Searches the directory store at the specified path to see whether
747 /// <param name="path">
748 /// The path at which to search the directory store.
751 /// true if an entry exists in the directory store at the specified
752 /// path; otherwise, false.
754 public static bool Exists(string path)
756 LdapConnection aconn=new LdapConnection();
757 LdapUrl lurl=new LdapUrl(path);
758 aconn.Connect(lurl.Host,lurl.Port);
760 if(CheckEntry(aconn,path))
767 /// Moves this entry to the specified parent.
769 /// <param name="pentry">
770 /// The parent to which you want to move this entry
772 public void MoveTo(DirectoryEntry newParent)
774 string oldParentFdn = Parent.Fdn;
775 conn.Rename(Fdn, Name, newParent.Fdn, true);
776 // TBD : threat multiple name instance in path
777 Path = Path.Replace(oldParentFdn,newParent.Fdn);
782 /// Moves this entry to the specified parent and changes its name to
783 /// the value of the newName parameter.
785 /// <param name="newParent"> The parent to which you want to move
788 /// <param name="newName">
789 /// The new name of this entry.
791 public void MoveTo( DirectoryEntry newParent,
794 string oldParentFdn = Parent.Fdn;
795 conn.Rename(Fdn, newName, newParent.Fdn, true);
796 // TBD : threat multiple name instance in path
797 Path = Path.Replace(oldParentFdn,newParent.Fdn).Replace(Name,newName);
802 /// Changes the name of this entry.
804 /// <param name="newName">
805 /// The new name of the entry.
808 /// Note This will also affect the path used to refer to this entry.
810 public void Rename( string newName )
812 string oldName = Name;
813 conn.Rename( Fdn, newName, true);
814 // TBD : threat multiple name instance in path
815 Path = Path.Replace(oldName,newName);
820 /// Calls a method on the native Active Directory.
822 /// <param name="methodName">The name of the method to invoke.
824 /// <param name="args">
825 /// An array of type Object that contains the arguments of the method
828 /// <returns>The return value of the invoked method</returns>
832 public object Invoke(string methodName,
833 params object[] args)
835 throw new NotImplementedException();
839 /// Creates a copy of this entry, as a child of the specified parent, with
840 /// the specified new name.
842 /// <param name="newParent">The parent DirectoryEntry. </param>
843 /// <param name="newName"> The name of the copy of this entry.
845 /// <returns>A renamed copy of this entry as a child of the specified parent.
847 public DirectoryEntry CopyTo( DirectoryEntry newParent,
850 throw new NotImplementedException();
854 /// Saves any changes to the entry in the Ldap Directory store.
857 /// By default, changes to properties are done locally to a cache, and
858 /// property values to be read are cached after the first read. For more
859 /// information, see UsePropertyCache.
860 /// Changes made to the cache include changes to the properties as well as
861 /// calls to Add (if this is the newly created entry).
863 public void CommitChanges()
865 if(UsePropertyCache)
\r
871 private void CommitEntry()
\r
875 System.Collections.ArrayList modList = new System.Collections.ArrayList();
876 System.Collections.IDictionaryEnumerator id = Properties.GetEnumerator();
879 string attribute=(string)id.Key;
880 LdapAttribute attr=null;
881 if(Properties[attribute].Mbit)
883 if(Properties[attribute].Count==1)
885 String val = (String)Properties[attribute].Value;
886 attr = new LdapAttribute( attribute , val);
890 Object[] vals=(Object [])Properties[attribute].Value;
891 String[] aStrVals= new String[Properties[attribute].Count];
892 Array.Copy(vals,0,aStrVals,0,Properties[attribute].Count);
893 attr = new LdapAttribute( attribute , aStrVals);
895 modList.Add( new LdapModification(LdapModification.REPLACE, attr));
896 Properties[attribute].Mbit=false;
899 if (modList.Count > 0) {
900 LdapModification[] mods = new LdapModification[modList.Count];
901 Type mtype=Type.GetType("System.DirectoryServices.LdapModification");
902 mods = (LdapModification[])modList.ToArray(typeof(LdapModification));
908 LdapAttributeSet attributeSet = new LdapAttributeSet();
909 System.Collections.IDictionaryEnumerator id = Properties.GetEnumerator();
912 string attribute=(string)id.Key;
913 if(Properties[attribute].Count==1)
915 String val = (String)Properties[attribute].Value;
916 attributeSet.Add(new LdapAttribute(attribute, val));
920 Object[] vals=(Object [])Properties[attribute].Value;
921 String[] aStrVals= new String[Properties[attribute].Count];
922 Array.Copy(vals,0,aStrVals,0,Properties[attribute].Count);
923 attributeSet.Add( new LdapAttribute( attribute , aStrVals));
926 LdapEntry newEntry = new LdapEntry( Fdn, attributeSet );
927 conn.Add( newEntry );
932 internal void CommitDeferred()
\r
934 if (!_inPropertiesLoading && !UsePropertyCache && !Nflag)
\r
946 _SchemaClassName = null;
951 public void RefreshCache ()
953 throw new NotImplementedException ("System.DirectoryServices.DirectoryEntry.RefreshCache()");
957 public void RefreshCache (string[] args)
959 throw new NotImplementedException ("System.DirectoryServices.DirectoryEntry.RefreshCache(System.String[])");
962 protected override void Dispose (bool disposing)
967 base.Dispose (disposing);