/******************************************************************************
* 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 );
}
}
}
}