Validate user in a trusted domain using DirectoryServices
In previous post, we talk about using Active Directory membership provider in a trusted domain scenario. Using an Active Directory membership provider should be necessary to configure connection string and provider for each domain. There could be situation you prefer not to configure connection string and provider. You may try to use DirectoryServices in such scenario.
Environment
==================
Domain1: lab.com - forest root domain
DC account: lab\Administrator (ADDC2008R2)
Web server account: lab\webserver (Application host server)
User account: lab\backend
Domain2: yinshi.net - forest root domain
DC account: yinshi\Administrator (AD2DC2008R2)
User account: yinshi\yinshiweb
Note: The trust relationship is a two-way forest trust in my test and only root domain in the forest. The situation may be different for the different trust situation.
Access to application from different trusted domain
====================
I created a simple test web application using DirectoryServices. The application is hosted in a web server in Domain1 (lab.com).
Note: In both scenarios, you need to locate the correct forest or domain so that you can continue validating the user.
Scenario 1:
We provide domain\username as UserName and Password in the Login page.
And then try to validate the user from the entry domain using code below:
string[] partsOfname = UserName.Text.Split("\\".ToCharArray());
//Get the domain name, username and password
strdomain = partsOfname[0];
strUsername = partsOfname[1];
strPassword = Password.Text;
bool authenticated = false;
//Initializes a new instance of the DirectoryEntry class that binds this instance to the node in Active Directory Domain Services located at entered domain.
//Use the given username and password to try to retrieve the NativeObject property from this DirectoryEntry class instance.
using (DirectoryEntry oDEfind = new DirectoryEntry(@"LDAP://" + strdomain, strUsername, strPassword))
{
try
{
//If you get the object without having a thrown exception, this means that the AD was able to authenticate the user.
object obj = oDEfind.NativeObject;
authenticated = true;
msg.Text = authenticated.ToString();
}
catch (Exception ex)
{
//strdomain, strUsername or strPassword invalid
msg.Text = ex.Message;
}
}
The results:
Scenario 2:
I have also tried to retrieve user using UserName and Password in the Login page. But in this attempt, I haven’t take a duplicate username in all trusted domains into account. And to search in all trusted forest may influence the application performance and the risk of exception.
1. Try to get the user from current forest.
//Not consider the duplicate credentials
strUsername = UserName.Text;
strPassword = Password.Text;
bool authenticated = false;
//get current forest
Forest currentforest = Forest.GetCurrentForest();
//search in current forest first
DirectoryEntry oDEcurrent = new DirectoryEntry("LDAP://" + currentforest.Name);
DirectorySearcher search = new DirectorySearcher(oDEcurrent);
search.Filter = "(SAMAccountName=" + strUsername + ")";
search.ReferralChasing = ReferralChasingOption.All;
SearchResult res = search.FindOne();
if (res != null)
{
//Create new instance in current forest and validate user with credential
oDEcurrent = new DirectoryEntry("LDAP://" + currentforest.Name, strUsername, strPassword, AuthenticationTypes.Secure);
try
{
object obj = oDEcurrent.NativeObject;
authenticated = true;
msg.Text = authenticated.ToString();
}
catch (Exception exp)
{
msg.Text = exp.Message;
}
}
2. If no user found, get forest trust information from the current forest and search in trusted forests.
//get trust target forest name
foreach (ForestTrustRelationshipInformation trust1 in currentforest.GetAllTrustRelationships())
{
string trustforest = trust1.TargetName;
DirectoryEntry oDEtrust = new DirectoryEntry("LDAP://" + trustforest);
search = new DirectorySearcher(oDEtrust);
search.Filter = "(SAMAccountName=" + strUsername + ")";
search.ReferralChasing = ReferralChasingOption.All;
res = search.FindOne();
if (res != null)
{
oDEtrust = new DirectoryEntry("LDAP://" + trustforest, strUsername, strPassword, AuthenticationTypes.Secure);
try
{
object obj = oDEtrust.NativeObject;
authenticated = true;
msg.Text = authenticated.ToString();
//if get the user, exit for
break;
}
catch (Exception exp)
{
msg.Text = exp.Message;
}
}
else
{
msg.Text = "No user";
}
}
Reference
======================
Introduction to System.DirectoryServices.ActiveDirectory (S.DS.AD)
https://msdn.microsoft.com/en-us/library/bb267453.aspx
Example26. Get forest trust information from the current forest
https://msdn.microsoft.com/en-us/library/bb267453.aspx#sdsadintro_topic3_managetrusts
DirectoryEntry Class
https://msdn.microsoft.com/en-us/library/System.DirectoryServices.DirectoryEntry(v=vs.110).aspx
Best Regards
Yingjie Shi from APAC DSI Team