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 _disposed;
66 /// Returns entry's Fully distinguished name.
72 LdapUrl lUrl = new LdapUrl(Path);
73 string fDn=lUrl.getDN();
84 /// Returns the connection object used to communicate with
87 internal LdapConnection conn
101 /// Flag to check whether the entry is to be cerated or it already
114 /// <summary> Initializes the Connection and other properties.
117 private void InitBlock()
120 _conn= new LdapConnection ();
121 LdapUrl lUrl=new LdapUrl (Path);
122 _conn.Connect(lUrl.Host,lUrl.Port);
123 _conn.Bind(Username,Password);
125 catch(LdapException ex) {
126 Console.WriteLine("Error:" + ex.LdapErrorMessage);
130 Console.WriteLine("Error:" + e.Message);
136 /// Initializes the Entry specific properties e.g entry DN etc.
140 LdapUrl lUrl=new LdapUrl (Path);
141 if(lUrl.getDN()!=null) {
142 DN userDn = new DN(lUrl.getDN());
143 String[] lRdn = userDn.explodeDN(false);
144 _Name = (string)lRdn[0];
145 _Parent = new DirectoryEntry(conn);
146 LdapUrl cUrl=new LdapUrl(lUrl.Host,lUrl.Port,userDn.Parent.ToString());
147 _Parent.Path=cUrl.ToString();
150 _Name=lUrl.Host+":"+lUrl.Port;
151 _Parent = new DirectoryEntry(conn);
152 _Parent.Path = "Ldap:";
157 /// Initializes a new instance of the DirectoryEntry class
159 public DirectoryEntry()
164 /// Initializes a new instance of the DirectoryEntry class that binds
165 /// to the specified native Active Directory object.
167 /// <param name="adsObject"> native active directory object</param>
168 public DirectoryEntry(object adsObject)
170 throw new NotImplementedException();
174 /// Initializes a new instance of the DirectoryEntry class that binds
175 /// this instance to the node in Ldap Directory located at the
178 /// <param name="path"> Path of the entry i.e Ldap URL specifying
179 /// entry path</param>
180 public DirectoryEntry(string path)
186 /// Initializes a new instance of the DirectoryEntry class. The Path,
187 /// Username, and Password properties are set to the specified values.
189 /// <param name="path">Path of the entry i.e Ldap URL specifying
190 /// entry path</param>
191 /// <param name="username">user name to use when authenticating the client
193 /// <param name="password">password to use when authenticating the client
195 public DirectoryEntry(string path,string username,string password)
203 /// Initializes a new instance of the DirectoryEntry class. The Path,
204 /// Username, and Password properties are set to the specified values.
206 /// <param name="path">Path of the entry i.e Ldap URL specifying
207 /// entry path</param>
208 /// <param name="username">user name to use when authenticating the client
210 /// <param name="password">password to use when authenticating the client
212 /// <param name="authenticationType"> type of authentication to use</param>
213 public DirectoryEntry(
217 AuthenticationTypes authenticationType)
222 _AuthenticationType=authenticationType;
226 /// Creates the entry object
228 /// <param name="lconn">Connection object used to communicate with
229 /// Ldap server</param>
230 internal DirectoryEntry(LdapConnection lconn)
236 /// Returns Type of authentication to use while Binding to Ldap server
238 [DSDescription ("Type of authentication to use while Binding to Ldap server")]
239 [DefaultValue (AuthenticationTypes.None)]
240 public AuthenticationTypes AuthenticationType
244 return _AuthenticationType;
248 _AuthenticationType = value;
253 /// Gets a DirectoryEntries containing the child entries of this node
254 /// in the Ldap Directory hierarchy.
256 /// <value>A DirectoryEntries containing the child entries of this node
257 /// in the Ldap Directory hierarchy.</value>
259 /// The child entries are only the immediate children of this node.
260 /// Use this property to find, retrieve, or create a directory entry
261 /// in the hierarchy. This property is a collection that, along with
262 /// usual iteration capabilities, provides an Add method through which
263 /// you add a node to the collection directly below the parent node
264 /// that you are currently bound to. When adding a node to the
265 /// collection, you must specify a name for the new node and the name of
266 /// a schema template that you want to associate with the node. For
267 /// example, you might want to use a schema titled "Computer" to add
268 /// new computers to the hierarchy.
270 [DSDescription ("Child entries of this node")]
271 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
273 public DirectoryEntries Children
277 _Children = new DirectoryEntries(Path, conn);
283 /// Gets the globally unique identifier (GUID) of the DirectoryEntry
285 /// <value>The globally unique identifier of the DirectoryEntry.</value>
287 /// Not implemented yet.
289 [DSDescription ("A globally unique identifier for this DirectoryEntry")]
290 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
297 throw new NotImplementedException();
303 /// Gets the name of the object as named with the underlying directory
306 /// <value>The name of the object as named with the underlying directory
308 /// <remarks>This name, along with SchemaClassName, distinguishes this
309 /// entry from its siblings and must be unique amongst its siblings
310 /// in each instance of DirectoryEntry.</remarks>
311 [DSDescription ("The name of the object as named with the underlying directory")]
312 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
318 if(CheckEntry(conn,Path))
321 throw new SystemException("There is no such object on the server");
328 /// Gets this entry's parent in the Ldap Directory hierarchy.
330 /// <value>This entry's parent in the Active Directory hierarc</value>
331 [DSDescription ("This entry's parent in the Ldap Directory hierarchy.")]
332 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
334 public DirectoryEntry Parent
338 if(CheckEntry(conn,Path))
341 throw new SystemException("There is no such object on the server");
348 /// Gets the globally unique identifier of the DirectoryEntry, as
349 /// returned from the provider
352 /// The globally unique identifier of the DirectoryEntry, as returned
353 /// from the provider.
356 /// Not implemented yet.
358 [DSDescription ("The globally unique identifier of the DirectoryEntry, as returned from the provider")]
359 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
362 public string NativeGuid
365 throw new NotImplementedException();
370 /// Gets the native Active Directory Service Interfaces (ADSI) object.
373 /// Not implemented yet
374 [DSDescription ("The native Active Directory Service Interfaces (ADSI) object.")]
375 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
377 public object NativeObject
381 throw new NotImplementedException();
386 /// Determines if a cache should be used.
388 [DSDescription ("Determines if a cache should be used.")]
389 [DefaultValue (true)]
390 public bool UsePropertyCache
395 throw new NotImplementedException();
400 throw new NotImplementedException();
405 /// Gets or sets the password to use when authenticating the client.
408 /// The password to use when authenticating the client.
411 /// You can set the Username and password in order to specify alternate
412 /// credentials with which to access the information in Ldap Directory.
413 /// Any other DirectoryEntry objects retrieved from this instance (for
414 /// example, through Children) are automatically created with the same
415 /// alternate credentials.
417 [DSDescription ("The password to use when authenticating the client.")]
418 [DefaultValue (null)]
420 public string Password
432 /// Gets or sets the user name to use when authenticating the client.
435 /// The user name to use when authenticating the client.
438 /// You can set the user name and Password in order to specify alternate
439 /// credentials with which to access the information in Ldap Directory.
440 /// Any other DirectoryEntry objects retrieved from this instance (for
441 /// example, through Children) are automatically created with the same
444 [DSDescription ("The user name to use when authenticating the client.")]
445 [DefaultValue (null)]
447 [TypeConverter ("System.Diagnostics.Design.StringValueConverter, " + Consts.AssemblySystem_Design)]
448 public string Username
460 /// Gets or sets the path for this DirectoryEntry.
463 /// The path of this DirectoryEntry. The default is an empty string ("").
466 /// The Path property uniquely identifies this entry in a networked
467 /// environment. This entry can always be retrieved using this Path.
469 /// Setting the Path retrieves a new entry from the directory store; it
470 /// does not change the path of the currently bound entry.
472 /// The classes associated with the DirectoryEntry component can be used
473 /// with any of the Directory service providers. Some of the current
474 /// providers are Internet Information Services (IIS), Lightweight Directory
475 /// Access Protocol (Ldap), Novell NetWare Directory Service (NDS), and WinNT.
477 /// Currently we Support only Ldap provider.
478 /// e.g Ldap://[hostname]:[port number]/[ObjectFDN]
480 [DSDescription ("The path for this DirectoryEntry.")]
482 [RecommendedAsConfigurable (true)]
483 [TypeConverter ("System.Diagnostics.Design.StringValueConverter, " + Consts.AssemblySystem_Design)]
496 /// Gets a PropertyCollection of properties set on this object.
499 /// A PropertyCollection of properties set on this object.
501 [DSDescription ("Properties set on this object.")]
502 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
504 public PropertyCollection Properties
507 if ( _Properties == null ) {
509 _Properties = new PropertyCollection();
512 LdapSearchResults lsc=conn.Search( Fdn,
513 LdapConnection.SCOPE_BASE,
517 while(lsc.hasMore()) {
519 LdapEntry nextEntry = null;
521 nextEntry = lsc.next();
523 catch(LdapException e) {
524 Console.WriteLine("Error: " + e.LdapErrorMessage);
525 // Exception is thrown, go for next entry
528 LdapAttributeSet attributeSet = nextEntry.getAttributeSet();
529 System.Collections.IEnumerator ienum=attributeSet.GetEnumerator();
531 while(ienum.MoveNext()) {
532 LdapAttribute attribute=(LdapAttribute)ienum.Current;
533 string attributeName = attribute.Name;
534 _Properties[attributeName].AddRange(attribute.StringValueArray);
535 _Properties[attributeName].Mbit=false;
536 // string attributeVal = attribute.StringValue;
537 // _Properties[attributeName].Add(attributeVal);
543 catch( LdapException le) {
544 if(le.ResultCode == LdapException.NO_SUCH_OBJECT)
554 /// Gets the name of the schema used for this DirectoryEntry
557 /// The name of the schema used for this DirectoryEntry.
559 [DSDescription ("The name of the schema used for this DirectoryEntry.")]
560 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
562 public string SchemaClassName
565 if(_SchemaClassName==null) {
566 _SchemaClassName = FindAttrValue("structuralObjectClass");
568 return _SchemaClassName;
573 /// Gets the current schema directory entry.
576 /// Not implemented yet
577 [DSDescription ("The current schema directory entry.")]
578 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
580 public DirectoryEntry SchemaEntry
584 throw new NotImplementedException();
589 /// Searches an entry in the Ldap directory and returns the attribute value
591 /// <param name="attrName">attribute whose value is required</param>
592 /// <returns> value of the attribute stored in Ldap directory</returns>
593 private string FindAttrValue(string attrName)
596 string[] attrs={attrName};
598 LdapSearchResults lsc=conn.Search( Fdn,
599 LdapConnection.SCOPE_BASE,
603 while(lsc.hasMore()) {
604 LdapEntry nextEntry = null;
606 nextEntry = lsc.next();
608 catch(LdapException e) {
609 Console.WriteLine("Error: " + e.LdapErrorMessage);
610 // Exception is thrown, go for next entry
613 LdapAttribute attribute = nextEntry.getAttribute(attrName);
614 aValue = attribute.StringValue;
621 /// Modifies an entry in the Ldap directory with the input LdapModification
624 /// <param name="mods">Array consisting of the entry attribute name and the
625 /// attribute values to be modified.</param>
626 private void ModEntry(LdapModification[] mods)
630 conn.Modify(Fdn,mods);
632 catch(LdapException le) {
638 /// Checks whether the entry exists in the Ldap directory or not
640 /// <param name="lconn">
641 /// Connection used to communicate with directory
643 /// <param name="epath">
644 /// path of the entry
647 /// true of the entry exists in the Ldap directory
648 /// false if entry doesn't exists
650 private static bool CheckEntry(LdapConnection lconn, string epath)
652 LdapUrl lUrl=new LdapUrl(epath);
653 string eDn=lUrl.getDN();
658 string[] attrs={"objectClass"};
661 LdapSearchResults lsc=lconn.Search( eDn,
662 LdapConnection.SCOPE_BASE,
668 LdapEntry nextEntry = null;
671 nextEntry = lsc.next();
673 catch(LdapException e)
675 Console.WriteLine("Error: " + e.LdapErrorMessage);
676 // Exception is thrown, go for next entry
683 catch(LdapException le)
685 if(le.ResultCode == LdapException.NO_SUCH_OBJECT)
702 /// Closes the DirectoryEntry and releases any system resources associated
703 /// with this component.
706 /// Following a call to Close, any operations on the DirectoryEntry might
707 /// raise exceptions.
715 /// Creates a copy of this entry as a child of the specified parent.
717 /// <param name="newParent">The parent DirectoryEntry. </param>
718 /// <returns>A copy of this entry as a child of the specified parent.
720 public DirectoryEntry CopyTo(DirectoryEntry newParent)
722 throw new NotImplementedException();
726 /// Deletes this entry and its entire subtree from the Active Directory
730 /// CAUTION The entry and its entire subtree are deleted from the
731 /// Ldap Directory hierarchy.
733 public void DeleteTree()
735 System.Collections.IEnumerator ienum = Children.GetEnumerator();
736 while(ienum.MoveNext())
738 DirectoryEntry de=(DirectoryEntry)ienum.Current;
745 /// Searches the directory store at the specified path to see whether
748 /// <param name="path">
749 /// The path at which to search the directory store.
752 /// true if an entry exists in the directory store at the specified
753 /// path; otherwise, false.
755 public static bool Exists(string path)
757 LdapConnection aconn=new LdapConnection();
758 LdapUrl lurl=new LdapUrl(path);
759 aconn.Connect(lurl.Host,lurl.Port);
761 if(CheckEntry(aconn,path))
768 /// Moves this entry to the specified parent.
770 /// <param name="pentry">
771 /// The parent to which you want to move this entry
773 public void MoveTo(DirectoryEntry newParent)
775 conn.Rename(Fdn, Name, newParent.Fdn, true);
779 /// Moves this entry to the specified parent and changes its name to
780 /// the value of the newName parameter.
782 /// <param name="newParent"> The parent to which you want to move
785 /// <param name="newName">
786 /// The new name of this entry.
788 public void MoveTo( DirectoryEntry newParent,
791 conn.Rename(Fdn, newName, newParent.Fdn, true);
795 /// Changes the name of this entry.
797 /// <param name="newName">
798 /// The new name of the entry.
801 /// Note This will also affect the path used to refer to this entry.
803 public void Rename( string newName )
805 conn.Rename( Fdn, newName, true);
809 /// Calls a method on the native Active Directory.
811 /// <param name="methodName">The name of the method to invoke.
813 /// <param name="args">
814 /// An array of type Object that contains the arguments of the method
817 /// <returns>The return value of the invoked method</returns>
821 public object Invoke(string methodName,
822 params object[] args)
824 throw new NotImplementedException();
828 /// Creates a copy of this entry, as a child of the specified parent, with
829 /// the specified new name.
831 /// <param name="newParent">The parent DirectoryEntry. </param>
832 /// <param name="newName"> The name of the copy of this entry.
834 /// <returns>A renamed copy of this entry as a child of the specified parent.
836 public DirectoryEntry CopyTo( DirectoryEntry newParent,
839 throw new NotImplementedException();
843 /// Saves any changes to the entry in the Ldap Directory store.
846 /// By default, changes to properties are done locally to a cache, and
847 /// property values to be read are cached after the first read. For more
848 /// information, see UsePropertyCache.
849 /// Changes made to the cache include changes to the properties as well as
850 /// calls to Add (if this is the newly created entry).
852 public void CommitChanges()
856 System.Collections.ArrayList modList = new System.Collections.ArrayList();
857 System.Collections.IDictionaryEnumerator id = Properties.GetEnumerator();
860 string attribute=(string)id.Key;
861 LdapAttribute attr=null;
862 if(Properties[attribute].Mbit)
864 if(Properties[attribute].Count==1)
866 String val = (String)Properties[attribute].Value;
867 attr = new LdapAttribute( attribute , val);
871 Object[] vals=(Object [])Properties[attribute].Value;
872 String[] aStrVals= new String[Properties[attribute].Count];
873 Array.Copy(vals,0,aStrVals,0,Properties[attribute].Count);
874 attr = new LdapAttribute( attribute , aStrVals);
876 modList.Add( new LdapModification(LdapModification.REPLACE, attr));
877 Properties[attribute].Mbit=false;
879 // Console.WriteLine(attribute + "Total no of attr value" + Properties[attribute].Count);
881 LdapModification[] mods = new LdapModification[modList.Count];
882 Type mtype=Type.GetType("System.DirectoryServices.LdapModification");
883 mods = (LdapModification[])modList.ToArray(typeof(LdapModification));
888 LdapAttributeSet attributeSet = new LdapAttributeSet();
889 System.Collections.IDictionaryEnumerator id = Properties.GetEnumerator();
892 string attribute=(string)id.Key;
893 // Console.WriteLine("attribute:" + attribute + "Vals:" + Properties[attribute][0]);
894 if(Properties[attribute].Count==1)
896 String val = (String)Properties[attribute].Value;
897 attributeSet.Add(new LdapAttribute(attribute, val));
901 Object[] vals=(Object [])Properties[attribute].Value;
902 String[] aStrVals= new String[Properties[attribute].Count];
903 Array.Copy(vals,0,aStrVals,0,Properties[attribute].Count);
904 attributeSet.Add( new LdapAttribute( attribute , aStrVals));
907 LdapEntry newEntry = new LdapEntry( Fdn, attributeSet );
908 conn.Add( newEntry );
913 public void RefreshCache ()
915 throw new NotImplementedException ("System.DirectoryServices.DirectoryEntry.RefreshCache()");
919 public void RefreshCache (string[] args)
921 throw new NotImplementedException ("System.DirectoryServices.DirectoryEntry.RefreshCache(System.String[])");
924 protected override void Dispose (bool disposing)
926 if (!_disposed && disposing) {
930 base.Dispose (disposing);