/****************************************************************************** * The MIT License * Copyright (c) 2003 Novell Inc., www.novell.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the Software), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. *******************************************************************************/ // // System.DirectoryServices.DirectoryEntry.cs // // Author: // Sunil Kumar (sunilk@novell.com) // // (C) Novell Inc. // using System.ComponentModel; using Novell.Directory.Ldap; using Novell.Directory.Ldap.Utilclass; namespace System.DirectoryServices { /// ///Encapsulates a node or object in the Ldap Directory hierarchy. /// public class DirectoryEntry : Component { private LdapConnection _conn = null; private AuthenticationTypes _AuthenticationType=AuthenticationTypes.None; private DirectoryEntries _Children; private string _Fdn = null; private string _Path=""; private string _Name=null; private DirectoryEntry _Parent=null; private string _Username=""; private string _Password=""; private string _Nativeguid; private PropertyCollection _Properties = null; private string _SchemaClassName=null; private bool _Nflag = false; /// /// Returns entry's Fully distinguished name. /// internal string Fdn { get { if (_Fdn == null) { LdapUrl lUrl = new LdapUrl(Path); string fDn=lUrl.getDN(); if(fDn != null) _Fdn = fDn; else _Fdn=""; } return _Fdn; } } /// /// Returns the connection object used to communicate with /// Ldap server /// internal LdapConnection conn { get { if( _conn == null) InitBlock(); return _conn; } set { _conn=value; } } /// /// Flag to check whether the entry is to be cerated or it already /// exists. /// internal bool Nflag { get { return _Nflag; } set { _Nflag = value; } } /// Initializes the Connection and other properties. /// /// private void InitBlock() { try { _conn= new LdapConnection (); LdapUrl lUrl=new LdapUrl (Path); _conn.Connect(lUrl.Host,lUrl.Port); _conn.Bind(Username,Password); } catch(LdapException ex) { Console.WriteLine("Error:" + ex.LdapErrorMessage); throw ex; } catch(Exception e) { Console.WriteLine("Error:" + e.Message); throw e; } } /// /// Initializes the Entry specific properties e.g entry DN etc. /// void InitEntry() { LdapUrl lUrl=new LdapUrl (Path); if(lUrl.getDN()!=null) { DN userDn = new DN(lUrl.getDN()); String[] lRdn = userDn.explodeDN(false); _Name = (string)lRdn[0]; _Parent = new DirectoryEntry(conn); LdapUrl cUrl=new LdapUrl(lUrl.Host,lUrl.Port,userDn.Parent.ToString()); _Parent.Path=cUrl.ToString(); } else { _Name=lUrl.Host+":"+lUrl.Port; _Parent = new DirectoryEntry(conn); _Parent.Path = "Ldap:"; } } /// /// Initializes a new instance of the DirectoryEntry class /// public DirectoryEntry() { } /// /// Initializes a new instance of the DirectoryEntry class that binds /// to the specified native Active Directory object. /// /// native active directory object public DirectoryEntry(object adsObject) { throw new NotImplementedException(); } /// /// Initializes a new instance of the DirectoryEntry class that binds /// this instance to the node in Ldap Directory located at the /// specified path. /// /// Path of the entry i.e Ldap URL specifying /// entry path public DirectoryEntry(string path) { _Path=path; } /// /// Initializes a new instance of the DirectoryEntry class. The Path, /// Username, and Password properties are set to the specified values. /// /// Path of the entry i.e Ldap URL specifying /// entry path /// user name to use when authenticating the client /// /// password to use when authenticating the client /// public DirectoryEntry(string path,string username,string password) { _Path=path; _Username=username; _Password=password; } /// /// Initializes a new instance of the DirectoryEntry class. The Path, /// Username, and Password properties are set to the specified values. /// /// Path of the entry i.e Ldap URL specifying /// entry path /// user name to use when authenticating the client /// /// password to use when authenticating the client /// /// type of authentication to use public DirectoryEntry( string path, string username, string password, AuthenticationTypes authenticationType) { _Path=path; _Username=username; _Password=password; _AuthenticationType=authenticationType; } /// /// Creates the entry object /// /// Connection object used to communicate with /// Ldap server internal DirectoryEntry(LdapConnection lconn) { conn = lconn; } /// /// Returns Type of authentication to use while Binding to Ldap server /// public AuthenticationTypes AuthenticationType { get { return _AuthenticationType; } set { _AuthenticationType = value; } } /// /// Gets a DirectoryEntries containing the child entries of this node /// in the Ldap Directory hierarchy. /// /// A DirectoryEntries containing the child entries of this node /// in the Ldap Directory hierarchy. /// /// The child entries are only the immediate children of this node. /// Use this property to find, retrieve, or create a directory entry /// in the hierarchy. This property is a collection that, along with /// usual iteration capabilities, provides an Add method through which /// you add a node to the collection directly below the parent node /// that you are currently bound to. When adding a node to the /// collection, you must specify a name for the new node and the name of /// a schema template that you want to associate with the node. For /// example, you might want to use a schema titled "Computer" to add /// new computers to the hierarchy. /// public DirectoryEntries Children { get { _Children = new DirectoryEntries(Path, conn); return _Children; } } /// /// Gets the globally unique identifier (GUID) of the DirectoryEntry /// /// The globally unique identifier of the DirectoryEntry. /// /// Not implemented yet. /// public Guid Guid { get { throw new NotImplementedException(); } } /// /// Gets the name of the object as named with the underlying directory /// service /// /// The name of the object as named with the underlying directory /// service /// This name, along with SchemaClassName, distinguishes this /// entry from its siblings and must be unique amongst its siblings /// in each instance of DirectoryEntry. public string Name { get { if(_Name==null) { if(CheckEntry(conn,Path)) InitEntry(); else throw new Exception("There is no such object on the server"); } return _Name; } } /// /// Gets this entry's parent in the Ldap Directory hierarchy. /// /// This entry's parent in the Active Directory hierarc public DirectoryEntry Parent { get { if(_Parent==null) { if(CheckEntry(conn,Path)) InitEntry(); else throw new Exception("There is no such object on the server"); } return _Parent; } } /// /// Gets the globally unique identifier of the DirectoryEntry, as /// returned from the provider /// /// /// The globally unique identifier of the DirectoryEntry, as returned /// from the provider. /// /// /// Not implemented yet. /// public string NativeGuid { get { throw new NotImplementedException(); } } /// /// Gets the native Active Directory Service Interfaces (ADSI) object. /// /// /// Not implemented yet public object NativeObject { get { throw new NotImplementedException(); } } /// /// Gets or sets the password to use when authenticating the client. /// /// /// The password to use when authenticating the client. /// /// /// You can set the Username and password in order to specify alternate /// credentials with which to access the information in Ldap Directory. /// Any other DirectoryEntry objects retrieved from this instance (for /// example, through Children) are automatically created with the same /// alternate credentials. /// public string Password { get { return _Password; } set { _Password = value; } } /// /// Gets or sets the user name to use when authenticating the client. /// /// /// The user name to use when authenticating the client. /// /// /// You can set the user name and Password in order to specify alternate /// credentials with which to access the information in Ldap Directory. /// Any other DirectoryEntry objects retrieved from this instance (for /// example, through Children) are automatically created with the same /// alternate /// public string Username { get { return _Username ; } set { _Username = value; } } /// /// Gets or sets the path for this DirectoryEntry. /// /// /// The path of this DirectoryEntry. The default is an empty string (""). /// /// /// The Path property uniquely identifies this entry in a networked /// environment. This entry can always be retrieved using this Path. /// /// Setting the Path retrieves a new entry from the directory store; it /// does not change the path of the currently bound entry. /// /// The classes associated with the DirectoryEntry component can be used /// with any of the Directory service providers. Some of the current /// providers are Internet Information Services (IIS), Lightweight Directory /// Access Protocol (Ldap), Novell NetWare Directory Service (NDS), and WinNT. /// /// Currently we Support only Ldap provider. /// e.g Ldap://[hostname]:[port number]/[ObjectFDN] /// public string Path { get { return _Path; } set { _Path = value; } } /// /// Gets a PropertyCollection of properties set on this object. /// /// /// A PropertyCollection of properties set on this object. /// public PropertyCollection Properties { get { if ( _Properties == null ) { _Properties = new PropertyCollection(); try { LdapSearchResults lsc=conn.Search( Fdn, LdapConnection.SCOPE_BASE, "objectClass=*", null, false); while(lsc.hasMore()) { LdapEntry nextEntry = null; try { nextEntry = lsc.next(); } catch(LdapException e) { Console.WriteLine("Error: " + e.LdapErrorMessage); // Exception is thrown, go for next entry throw e; } LdapAttributeSet attributeSet = nextEntry.getAttributeSet(); System.Collections.IEnumerator ienum=attributeSet.GetEnumerator(); if(ienum!=null) { while(ienum.MoveNext()) { LdapAttribute attribute=(LdapAttribute)ienum.Current; string attributeName = attribute.Name; _Properties[attributeName].AddRange(attribute.StringValueArray); _Properties[attributeName].Mbit=false; // string attributeVal = attribute.StringValue; // _Properties[attributeName].Add(attributeVal); // Console.WriteLine( attributeName + "value:" + attributeVal); } } break; } } catch( LdapException le) { if(le.ResultCode == LdapException.NO_SUCH_OBJECT) { } } } return _Properties; } } /// /// Gets the name of the schema used for this DirectoryEntry /// /// /// The name of the schema used for this DirectoryEntry. /// /// public string SchemaClassName { get { if(_SchemaClassName==null) { _SchemaClassName = FindAttrValue("structuralObjectClass"); } return _SchemaClassName; } } /// /// Searches an entry in the Ldap directory and returns the attribute value /// /// attribute whose value is required /// value of the attribute stored in Ldap directory private string FindAttrValue(string attrName) { string aValue=null; string[] attrs={attrName}; LdapSearchResults lsc=conn.Search( Fdn, LdapConnection.SCOPE_BASE, "objectClass=*", attrs, false); while(lsc.hasMore()) { LdapEntry nextEntry = null; try { nextEntry = lsc.next(); } catch(LdapException e) { Console.WriteLine("Error: " + e.LdapErrorMessage); // Exception is thrown, go for next entry throw e; } LdapAttribute attribute = nextEntry.getAttribute(attrName); aValue = attribute.StringValue; break; } return aValue; } /// /// Modifies an entry in the Ldap directory with the input LdapModification /// values. /// /// Array consisting of the entry attribute name and the /// attribute values to be modified. private void ModEntry(LdapModification[] mods) { try { conn.Modify(Fdn,mods); } catch(LdapException le) { throw le; } } /// /// Checks whether the entry exists in the Ldap directory or not /// /// /// Connection used to communicate with directory /// /// /// path of the entry /// /// /// true of the entry exists in the Ldap directory /// false if entry doesn't exists /// private static bool CheckEntry(LdapConnection lconn, string epath) { LdapUrl lUrl=new LdapUrl(epath); string eDn=lUrl.getDN(); if(eDn==null) { eDn=""; } string[] attrs={"objectClass"}; try { LdapSearchResults lsc=lconn.Search( eDn, LdapConnection.SCOPE_BASE, "objectClass=*", attrs, false); while(lsc.hasMore()) { LdapEntry nextEntry = null; try { nextEntry = lsc.next(); } catch(LdapException e) { Console.WriteLine("Error: " + e.LdapErrorMessage); // Exception is thrown, go for next entry throw e; } break; } } catch(LdapException le) { if(le.ResultCode == LdapException.NO_SUCH_OBJECT) { return false; } else { throw le; } } catch(Exception e) { throw e; } return true; } /// /// Closes the DirectoryEntry and releases any system resources associated /// with this component. /// /// /// Following a call to Close, any operations on the DirectoryEntry might /// raise exceptions. /// public void Close() { conn.Disconnect(); } /// /// Creates a copy of this entry as a child of the specified parent. /// /// The parent DirectoryEntry. /// A copy of this entry as a child of the specified parent. public DirectoryEntry CopyTo(DirectoryEntry newParent) { throw new NotImplementedException(); } /// /// Deletes this entry and its entire subtree from the Active Directory /// hierarchy. /// /// /// CAUTION The entry and its entire subtree are deleted from the /// Ldap Directory hierarchy. /// public void DeleteTree() { System.Collections.IEnumerator ienum = Children.GetEnumerator(); while(ienum.MoveNext()) { DirectoryEntry de=(DirectoryEntry)ienum.Current; conn.Delete(de.Fdn); } conn.Delete(Fdn); } /// /// Searches the directory store at the specified path to see whether /// an entry exists /// /// /// The path at which to search the directory store. /// /// /// true if an entry exists in the directory store at the specified /// path; otherwise, false. /// public static bool Exists(string path) { LdapConnection aconn=new LdapConnection(); LdapUrl lurl=new LdapUrl(path); aconn.Connect(lurl.Host,lurl.Port); aconn.Bind("",""); if(CheckEntry(aconn,path)) return true; else return false; } /// /// Moves this entry to the specified parent. /// /// /// The parent to which you want to move this entry /// public void MoveTo(DirectoryEntry newParent) { conn.Rename(Fdn, Name, newParent.Fdn, true); } /// /// Moves this entry to the specified parent and changes its name to /// the value of the newName parameter. /// /// The parent to which you want to move /// this entry /// /// /// The new name of this entry. /// public void MoveTo( DirectoryEntry newParent, string newName ) { conn.Rename(Fdn, newName, newParent.Fdn, true); } /// /// Changes the name of this entry. /// /// /// The new name of the entry. /// /// /// Note This will also affect the path used to refer to this entry. /// public void Rename( string newName ) { conn.Rename( Fdn, newName, true); } /// /// Calls a method on the native Active Directory. /// /// The name of the method to invoke. /// /// /// An array of type Object that contains the arguments of the method /// to invoke. /// /// The return value of the invoked method /// /// Not implemented. public object Invoke(string methodName, params object[] args) { throw new NotImplementedException(); } /// /// Creates a copy of this entry, as a child of the specified parent, with /// the specified new name. /// /// The parent DirectoryEntry. /// The name of the copy of this entry. /// /// A renamed copy of this entry as a child of the specified parent. public DirectoryEntry CopyTo( DirectoryEntry newParent, string newName ) { throw new NotImplementedException(); } /// /// Saves any changes to the entry in the Ldap Directory store. /// /// /// By default, changes to properties are done locally to a cache, and /// property values to be read are cached after the first read. For more /// information, see UsePropertyCache. /// Changes made to the cache include changes to the properties as well as /// calls to Add (if this is the newly created entry). /// public void CommitChanges() { if(!Nflag) { System.Collections.ArrayList modList = new System.Collections.ArrayList(); System.Collections.IDictionaryEnumerator id = Properties.GetEnumerator(); while(id.MoveNext()) { string attribute=(string)id.Key; LdapAttribute attr=null; if(Properties[attribute].Mbit) { if(Properties[attribute].Count==1) { String val = (String)Properties[attribute].Value; attr = new LdapAttribute( attribute , val); } else { Object[] vals=(Object [])Properties[attribute].Value; String[] aStrVals= new String[Properties[attribute].Count]; Array.Copy(vals,0,aStrVals,0,Properties[attribute].Count); attr = new LdapAttribute( attribute , aStrVals); } modList.Add( new LdapModification(LdapModification.REPLACE, attr)); Properties[attribute].Mbit=false; } Console.WriteLine(attribute + "Total no of attr value" + Properties[attribute].Count); } LdapModification[] mods = new LdapModification[modList.Count]; Type mtype=Type.GetType("System.DirectoryServices.LdapModification"); mods = (LdapModification[])modList.ToArray(typeof(LdapModification)); ModEntry(mods); } else { LdapAttributeSet attributeSet = new LdapAttributeSet(); System.Collections.IDictionaryEnumerator id = Properties.GetEnumerator(); while(id.MoveNext()) { string attribute=(string)id.Key; Console.WriteLine("attribute:" + attribute + "Vals:" + Properties[attribute][0]); if(Properties[attribute].Count==1) { String val = (String)Properties[attribute].Value; attributeSet.Add(new LdapAttribute(attribute, val)); } else { Object[] vals=(Object [])Properties[attribute].Value; String[] aStrVals= new String[Properties[attribute].Count]; Array.Copy(vals,0,aStrVals,0,Properties[attribute].Count); attributeSet.Add( new LdapAttribute( attribute , aStrVals)); } } LdapEntry newEntry = new LdapEntry( Fdn, attributeSet ); conn.Add( newEntry ); } } } }