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)
33 using System.ComponentModel;
34 using Novell.Directory.Ldap;
35 using Novell.Directory.Ldap.Utilclass;
37 namespace System.DirectoryServices
41 ///Encapsulates a node or object in the Ldap Directory hierarchy.
43 public class DirectoryEntry : Component
46 private LdapConnection _conn = null;
47 private AuthenticationTypes _AuthenticationType=AuthenticationTypes.None;
48 private DirectoryEntries _Children;
49 private string _Fdn = null;
50 private string _Path="";
51 private string _Name=null;
52 private DirectoryEntry _Parent=null;
53 private string _Username="";
54 private string _Password="";
55 private string _Nativeguid;
56 private PropertyCollection _Properties = null;
57 private string _SchemaClassName=null;
58 private bool _Nflag = false;
61 /// Returns entry's Fully distinguished name.
67 LdapUrl lUrl = new LdapUrl(Path);
68 string fDn=lUrl.getDN();
79 /// Returns the connection object used to communicate with
82 internal LdapConnection conn
96 /// Flag to check whether the entry is to be cerated or it already
109 /// <summary> Initializes the Connection and other properties.
112 private void InitBlock()
115 _conn= new LdapConnection ();
116 LdapUrl lUrl=new LdapUrl (Path);
117 _conn.Connect(lUrl.Host,lUrl.Port);
118 _conn.Bind(Username,Password);
120 catch(LdapException ex) {
121 Console.WriteLine("Error:" + ex.LdapErrorMessage);
125 Console.WriteLine("Error:" + e.Message);
131 /// Initializes the Entry specific properties e.g entry DN etc.
135 LdapUrl lUrl=new LdapUrl (Path);
136 if(lUrl.getDN()!=null) {
137 DN userDn = new DN(lUrl.getDN());
138 String[] lRdn = userDn.explodeDN(false);
139 _Name = (string)lRdn[0];
140 _Parent = new DirectoryEntry(conn);
141 LdapUrl cUrl=new LdapUrl(lUrl.Host,lUrl.Port,userDn.Parent.ToString());
142 _Parent.Path=cUrl.ToString();
145 _Name=lUrl.Host+":"+lUrl.Port;
146 _Parent = new DirectoryEntry(conn);
147 _Parent.Path = "Ldap:";
152 /// Initializes a new instance of the DirectoryEntry class
154 public DirectoryEntry()
159 /// Initializes a new instance of the DirectoryEntry class that binds
160 /// to the specified native Active Directory object.
162 /// <param name="adsObject"> native active directory object</param>
163 public DirectoryEntry(object adsObject)
165 throw new NotImplementedException();
169 /// Initializes a new instance of the DirectoryEntry class that binds
170 /// this instance to the node in Ldap Directory located at the
173 /// <param name="path"> Path of the entry i.e Ldap URL specifying
174 /// entry path</param>
175 public DirectoryEntry(string path)
181 /// Initializes a new instance of the DirectoryEntry class. The Path,
182 /// Username, and Password properties are set to the specified values.
184 /// <param name="path">Path of the entry i.e Ldap URL specifying
185 /// entry path</param>
186 /// <param name="username">user name to use when authenticating the client
188 /// <param name="password">password to use when authenticating the client
190 public DirectoryEntry(string path,string username,string password)
198 /// Initializes a new instance of the DirectoryEntry class. The Path,
199 /// Username, and Password properties are set to the specified values.
201 /// <param name="path">Path of the entry i.e Ldap URL specifying
202 /// entry path</param>
203 /// <param name="username">user name to use when authenticating the client
205 /// <param name="password">password to use when authenticating the client
207 /// <param name="authenticationType"> type of authentication to use</param>
208 public DirectoryEntry(
212 AuthenticationTypes authenticationType)
217 _AuthenticationType=authenticationType;
221 /// Creates the entry object
223 /// <param name="lconn">Connection object used to communicate with
224 /// Ldap server</param>
225 internal DirectoryEntry(LdapConnection lconn)
231 /// Returns Type of authentication to use while Binding to Ldap server
233 public AuthenticationTypes AuthenticationType
237 return _AuthenticationType;
241 _AuthenticationType = value;
246 /// Gets a DirectoryEntries containing the child entries of this node
247 /// in the Ldap Directory hierarchy.
249 /// <value>A DirectoryEntries containing the child entries of this node
250 /// in the Ldap Directory hierarchy.</value>
252 /// The child entries are only the immediate children of this node.
253 /// Use this property to find, retrieve, or create a directory entry
254 /// in the hierarchy. This property is a collection that, along with
255 /// usual iteration capabilities, provides an Add method through which
256 /// you add a node to the collection directly below the parent node
257 /// that you are currently bound to. When adding a node to the
258 /// collection, you must specify a name for the new node and the name of
259 /// a schema template that you want to associate with the node. For
260 /// example, you might want to use a schema titled "Computer" to add
261 /// new computers to the hierarchy.
263 public DirectoryEntries Children
267 _Children = new DirectoryEntries(Path, conn);
273 /// Gets the globally unique identifier (GUID) of the DirectoryEntry
275 /// <value>The globally unique identifier of the DirectoryEntry.</value>
277 /// Not implemented yet.
283 throw new NotImplementedException();
289 /// Gets the name of the object as named with the underlying directory
292 /// <value>The name of the object as named with the underlying directory
294 /// <remarks>This name, along with SchemaClassName, distinguishes this
295 /// entry from its siblings and must be unique amongst its siblings
296 /// in each instance of DirectoryEntry.</remarks>
301 if(CheckEntry(conn,Path))
304 throw new Exception("There is no such object on the server");
311 /// Gets this entry's parent in the Ldap Directory hierarchy.
313 /// <value>This entry's parent in the Active Directory hierarc</value>
314 public DirectoryEntry Parent
318 if(CheckEntry(conn,Path))
321 throw new Exception("There is no such object on the server");
328 /// Gets the globally unique identifier of the DirectoryEntry, as
329 /// returned from the provider
332 /// The globally unique identifier of the DirectoryEntry, as returned
333 /// from the provider.
336 /// Not implemented yet.
338 public string NativeGuid
341 throw new NotImplementedException();
346 /// Gets the native Active Directory Service Interfaces (ADSI) object.
349 /// Not implemented yet
350 public object NativeObject
353 throw new NotImplementedException();
358 /// Gets or sets the password to use when authenticating the client.
361 /// The password to use when authenticating the client.
364 /// You can set the Username and password in order to specify alternate
365 /// credentials with which to access the information in Ldap Directory.
366 /// Any other DirectoryEntry objects retrieved from this instance (for
367 /// example, through Children) are automatically created with the same
368 /// alternate credentials.
370 public string Password
382 /// Gets or sets the user name to use when authenticating the client.
385 /// The user name to use when authenticating the client.
388 /// You can set the user name and Password in order to specify alternate
389 /// credentials with which to access the information in Ldap Directory.
390 /// Any other DirectoryEntry objects retrieved from this instance (for
391 /// example, through Children) are automatically created with the same
394 public string Username
406 /// Gets or sets the path for this DirectoryEntry.
409 /// The path of this DirectoryEntry. The default is an empty string ("").
412 /// The Path property uniquely identifies this entry in a networked
413 /// environment. This entry can always be retrieved using this Path.
415 /// Setting the Path retrieves a new entry from the directory store; it
416 /// does not change the path of the currently bound entry.
418 /// The classes associated with the DirectoryEntry component can be used
419 /// with any of the Directory service providers. Some of the current
420 /// providers are Internet Information Services (IIS), Lightweight Directory
421 /// Access Protocol (Ldap), Novell NetWare Directory Service (NDS), and WinNT.
423 /// Currently we Support only Ldap provider.
424 /// e.g Ldap://[hostname]:[port number]/[ObjectFDN]
439 /// Gets a PropertyCollection of properties set on this object.
442 /// A PropertyCollection of properties set on this object.
444 public PropertyCollection Properties
447 if ( _Properties == null ) {
449 _Properties = new PropertyCollection();
452 LdapSearchResults lsc=conn.Search( Fdn,
453 LdapConnection.SCOPE_BASE,
457 while(lsc.hasMore()) {
459 LdapEntry nextEntry = null;
461 nextEntry = lsc.next();
463 catch(LdapException e) {
464 Console.WriteLine("Error: " + e.LdapErrorMessage);
465 // Exception is thrown, go for next entry
468 LdapAttributeSet attributeSet = nextEntry.getAttributeSet();
469 System.Collections.IEnumerator ienum=attributeSet.GetEnumerator();
471 while(ienum.MoveNext()) {
472 LdapAttribute attribute=(LdapAttribute)ienum.Current;
473 string attributeName = attribute.Name;
474 _Properties[attributeName].AddRange(attribute.StringValueArray);
475 _Properties[attributeName].Mbit=false;
476 // string attributeVal = attribute.StringValue;
477 // _Properties[attributeName].Add(attributeVal);
483 catch( LdapException le) {
484 if(le.ResultCode == LdapException.NO_SUCH_OBJECT)
494 /// Gets the name of the schema used for this DirectoryEntry
497 /// The name of the schema used for this DirectoryEntry.
500 public string SchemaClassName
503 if(_SchemaClassName==null) {
504 _SchemaClassName = FindAttrValue("structuralObjectClass");
506 return _SchemaClassName;
511 /// Searches an entry in the Ldap directory and returns the attribute value
513 /// <param name="attrName">attribute whose value is required</param>
514 /// <returns> value of the attribute stored in Ldap directory</returns>
515 private string FindAttrValue(string attrName)
518 string[] attrs={attrName};
520 LdapSearchResults lsc=conn.Search( Fdn,
521 LdapConnection.SCOPE_BASE,
525 while(lsc.hasMore()) {
526 LdapEntry nextEntry = null;
528 nextEntry = lsc.next();
530 catch(LdapException e) {
531 Console.WriteLine("Error: " + e.LdapErrorMessage);
532 // Exception is thrown, go for next entry
535 LdapAttribute attribute = nextEntry.getAttribute(attrName);
536 aValue = attribute.StringValue;
543 /// Modifies an entry in the Ldap directory with the input LdapModification
546 /// <param name="mods">Array consisting of the entry attribute name and the
547 /// attribute values to be modified.</param>
548 private void ModEntry(LdapModification[] mods)
552 conn.Modify(Fdn,mods);
554 catch(LdapException le) {
560 /// Checks whether the entry exists in the Ldap directory or not
562 /// <param name="lconn">
563 /// Connection used to communicate with directory
565 /// <param name="epath">
566 /// path of the entry
569 /// true of the entry exists in the Ldap directory
570 /// false if entry doesn't exists
572 private static bool CheckEntry(LdapConnection lconn, string epath)
574 LdapUrl lUrl=new LdapUrl(epath);
575 string eDn=lUrl.getDN();
580 string[] attrs={"objectClass"};
583 LdapSearchResults lsc=lconn.Search( eDn,
584 LdapConnection.SCOPE_BASE,
590 LdapEntry nextEntry = null;
593 nextEntry = lsc.next();
595 catch(LdapException e)
597 Console.WriteLine("Error: " + e.LdapErrorMessage);
598 // Exception is thrown, go for next entry
605 catch(LdapException le)
607 if(le.ResultCode == LdapException.NO_SUCH_OBJECT)
624 /// Closes the DirectoryEntry and releases any system resources associated
625 /// with this component.
628 /// Following a call to Close, any operations on the DirectoryEntry might
629 /// raise exceptions.
637 /// Creates a copy of this entry as a child of the specified parent.
639 /// <param name="newParent">The parent DirectoryEntry. </param>
640 /// <returns>A copy of this entry as a child of the specified parent.
641 public DirectoryEntry CopyTo(DirectoryEntry newParent)
643 throw new NotImplementedException();
647 /// Deletes this entry and its entire subtree from the Active Directory
651 /// CAUTION The entry and its entire subtree are deleted from the
652 /// Ldap Directory hierarchy.
654 public void DeleteTree()
656 System.Collections.IEnumerator ienum = Children.GetEnumerator();
657 while(ienum.MoveNext())
659 DirectoryEntry de=(DirectoryEntry)ienum.Current;
666 /// Searches the directory store at the specified path to see whether
669 /// <param name="path">
670 /// The path at which to search the directory store.
673 /// true if an entry exists in the directory store at the specified
674 /// path; otherwise, false.
676 public static bool Exists(string path)
678 LdapConnection aconn=new LdapConnection();
679 LdapUrl lurl=new LdapUrl(path);
680 aconn.Connect(lurl.Host,lurl.Port);
682 if(CheckEntry(aconn,path))
689 /// Moves this entry to the specified parent.
691 /// <param name="pentry">
692 /// The parent to which you want to move this entry
694 public void MoveTo(DirectoryEntry newParent)
696 conn.Rename(Fdn, Name, newParent.Fdn, true);
700 /// Moves this entry to the specified parent and changes its name to
701 /// the value of the newName parameter.
703 /// <param name="newParent"> The parent to which you want to move
706 /// <param name="newName">
707 /// The new name of this entry.
709 public void MoveTo( DirectoryEntry newParent,
712 conn.Rename(Fdn, newName, newParent.Fdn, true);
716 /// Changes the name of this entry.
718 /// <param name="newName">
719 /// The new name of the entry.
722 /// Note This will also affect the path used to refer to this entry.
724 public void Rename( string newName )
726 conn.Rename( Fdn, newName, true);
730 /// Calls a method on the native Active Directory.
732 /// <param name="methodName">The name of the method to invoke.
734 /// <param name="args">
735 /// An array of type Object that contains the arguments of the method
738 /// <returns>The return value of the invoked method</returns>
741 public object Invoke(string methodName,
742 params object[] args)
744 throw new NotImplementedException();
748 /// Creates a copy of this entry, as a child of the specified parent, with
749 /// the specified new name.
751 /// <param name="newParent">The parent DirectoryEntry. </param>
752 /// <param name="newName"> The name of the copy of this entry.
754 /// <returns>A renamed copy of this entry as a child of the specified parent.
755 public DirectoryEntry CopyTo( DirectoryEntry newParent,
758 throw new NotImplementedException();
762 /// Saves any changes to the entry in the Ldap Directory store.
765 /// By default, changes to properties are done locally to a cache, and
766 /// property values to be read are cached after the first read. For more
767 /// information, see UsePropertyCache.
768 /// Changes made to the cache include changes to the properties as well as
769 /// calls to Add (if this is the newly created entry).
771 public void CommitChanges()
775 System.Collections.ArrayList modList = new System.Collections.ArrayList();
776 System.Collections.IDictionaryEnumerator id = Properties.GetEnumerator();
779 string attribute=(string)id.Key;
780 LdapAttribute attr=null;
781 if(Properties[attribute].Mbit)
783 if(Properties[attribute].Count==1)
785 String val = (String)Properties[attribute].Value;
786 attr = new LdapAttribute( attribute , val);
790 Object[] vals=(Object [])Properties[attribute].Value;
791 String[] aStrVals= new String[Properties[attribute].Count];
792 Array.Copy(vals,0,aStrVals,0,Properties[attribute].Count);
793 attr = new LdapAttribute( attribute , aStrVals);
795 modList.Add( new LdapModification(LdapModification.REPLACE, attr));
796 Properties[attribute].Mbit=false;
798 // Console.WriteLine(attribute + "Total no of attr value" + Properties[attribute].Count);
800 LdapModification[] mods = new LdapModification[modList.Count];
801 Type mtype=Type.GetType("System.DirectoryServices.LdapModification");
802 mods = (LdapModification[])modList.ToArray(typeof(LdapModification));
807 LdapAttributeSet attributeSet = new LdapAttributeSet();
808 System.Collections.IDictionaryEnumerator id = Properties.GetEnumerator();
811 string attribute=(string)id.Key;
812 // Console.WriteLine("attribute:" + attribute + "Vals:" + Properties[attribute][0]);
813 if(Properties[attribute].Count==1)
815 String val = (String)Properties[attribute].Value;
816 attributeSet.Add(new LdapAttribute(attribute, val));
820 Object[] vals=(Object [])Properties[attribute].Value;
821 String[] aStrVals= new String[Properties[attribute].Count];
822 Array.Copy(vals,0,aStrVals,0,Properties[attribute].Count);
823 attributeSet.Add( new LdapAttribute( attribute , aStrVals));
826 LdapEntry newEntry = new LdapEntry( Fdn, attributeSet );
827 conn.Add( newEntry );