I'm using the following code:
private string GetTitle(string userName)
{
string title = string.Empty;
try
{
DirectoryEntry myLdapConnection = createDirectoryEntry();
DirectorySearcher search = new DirectorySearcher(myLdapConnection);
search.ReferralChasing = ReferralChasingOption.All;
search.Filter = "(cn=" + userName + ")";
search.PropertiesToLoad.Add("title");
SearchResult result = search.FindOne();
if (result != null)
{
// create new object from search result
DirectoryEntry entryToUpdate = result.GetDirectoryEntry();
title = entryToUpdate.Properties["title"][0].ToString();
}
else Console.WriteLine("User not found!");
}
catch (Exception e)
{
Console.WriteLine("Exception caught:\n\n" + e.ToString());
}
return title;
}
and get this error:
A referral was returned from the server.
from line: SearchResult result = search.FindOne();
How can I solve this?
Related
I have an application that uses Windows authentication and I am trying to get logged in users info using their domain IDs.
Part of the data returned is the user's manager's DN (in manager property). I need to query AD again to get manager's info (domain id, email, name, etc.).
I searched and can't find any hint of what I have to use in my filter.
This is what I am using and I always get null returned:
private static DirectoryEntry GetUserDEByDN(string sDN)
{
using (HostingEnvironment.Impersonate())
{
PrincipalContext pc = new PrincipalContext(ContextType.Domain, adUSADomain, adUSAContainer);
//UserPrincipal up = UserPrincipal.FindByIdentity(pc, IdentityType.SamAccountName, UserID);
UserPrincipal qbeUser = new UserPrincipal(pc);
//qbeUser.SamAccountName = UserID.Trim().ToUpper();
PrincipalSearcher srch = new PrincipalSearcher(qbeUser);
PrincipalSearchResult<Principal> psr = srch.FindAll();
string sDomain = ConfigurationManager.AppSettings["Domain"].ToString();
string adPath = ConfigurationManager.AppSettings["ADPath"].ToString();
DirectoryEntry de = new DirectoryEntry(adPath);
DirectorySearcher deSearch = new DirectorySearcher();
deSearch.SearchRoot = de;
deSearch.Filter = "(&(objectClass=user)(| (cn = " + sDN + ")(dn = " + sDN + ")))";
//deSearch.Filter = "(&(objectClass=user)(SAMAccountName=" + UserID + "))";
deSearch.SearchScope = SearchScope.Subtree;
SearchResult results = deSearch.FindOne();
if (null != results)
{
de = new DirectoryEntry(results.Path);
return de;
}
else
{
return null;
}
}
}
Is it possible to search Active Directory by DN? If so, what I am doing wrong?
This is what worked for me. However, I believe it is supposed to work with objectClass=user but I kept getting null returned. When I changed to distinguishedName = sDN, it worked.
The whole point of this code
DirectoryEntry de = new DirectoryEntry(adPath + "/" + sDN);
is to start the directory search at the user object; there shouldn’t be the need for the additional search of saying which distinguishedName.
private static DirectoryEntry GetUserDEByDN(string sDN)
{
string adPath = ConfigurationManager.AppSettings["ADPath"].ToString();
DirectoryEntry de = new DirectoryEntry(adPath + "/" + sDN);
DirectoryEntry deManager = null;
using (DirectorySearcher Search = new DirectorySearcher())
{
Search.SearchRoot = de;
Search.Filter = "(&(distinguishedName=" + sDN + "))";
//Search.Filter = "(objectClass = user)";
Search.SearchScope = SearchScope.Base;
SearchResult Result = Search.FindOne();
if (null != Result)
deManager = Result.GetDirectoryEntry();
}
return deManager;
}
i am facing the issue while searching the group name in active directory,
below link is related to my error but it doesn't solved my issue
DirectorySearcher FindAll SearchResultCollection Count throws COMException
string search = "*" + txtsearch.Text + "*";
if (string.IsNullOrEmpty(txtsearch.Text))
{
search = "*";
}
DirectoryEntry de = null;
try
{
de = new DirectoryEntry(strADPath,strUsreName,strUsrePassword);
}
catch (Exception ex)
{
LogMessageToFile("Fail to set the data for the DirectoryEntry : " + ex.ToString()+ "....Error message"+ ex.Message);
}
DirectorySearcher deSearch = new DirectorySearcher();
deSearch.PropertiesToLoad.Add("objectguid");
deSearch.PropertiesToLoad.Add("cn");
deSearch.SearchRoot = de;
try
{
deSearch.PropertiesToLoad.Add("cn"); deSearch.Filter = "(&(objectClass=group)(cn=" + search + "))";
}
catch (Exception ex)
{
LogMessageToFile("error while passing value to filter value" + ex.ToString()+"....Error message"+ ex.Message);
}
SearchResultCollection results= null;
try
{
results = deSearch.FindAll();
}
catch (Exception ex)
{
LogMessageToFile("Fail to FindAll method :" + ex.ToString() + "....Error message" + ex.Message);
}
DataTable tbGroup = dsGroup.Tables.Add("Groups");
tbGroup.Columns.Add("GroupName");
tbGroup.Columns.Add("GroupGuid");
if (results != null)
{
if (results.Count > 0)
{
foreach (SearchResult Result in results)
{
DataRow rwGroup = tbGroup.NewRow();
try
{
if (Result.Properties["cn"] != null)
{
if (Result.Properties["cn"].Count > 0)
{
rwGroup["GroupName"] = Result.Properties["cn"][0];
}
else
{
LogMessageToFile("Result.Properties count less then 0");
}
}
}
catch (Exception ex)
{
LogMessageToFile("try to obtain Result.Properties :" + ex.ToString() + "....Error message" + ex.Message);
}
try
{
rwGroup["GroupGuid"] = GetObjectIdetifier(Result);
}
catch (Exception ex)
{
LogMessageToFile("Fail to get the data for GroupGuid :" + ex.ToString()+"....Error message" + ex.Message);
}
tbGroup.Rows.Add(rwGroup);
}
listBox1.DataSource = tbGroup;
listBox1.DisplayMember = "GroupName";
listBox1.ValueMember = "GroupGuid";
}
}
I am using the below code for login in using Ldap Authentication in ASP.net. However, I don't know how to pass the values from plain-text to this code. I want to run this through button click.
public class LdapAuthentication
{
private string _path;
private string _filterAttribute;
public LdapAuthentication(string path)
{
_path = path;
}
public bool IsAuthenticated(string domain, string username, string pwd)
{
string domainAndUsername = domain + #"\" + username;
DirectoryEntry entry = new DirectoryEntry(_path, domainAndUsername, pwd);
try
{
// Bind to the native AdsObject to force authentication.
Object obj = entry.NativeObject;
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = "(SAMAccountName=" + username + ")";
search.PropertiesToLoad.Add("cn");
search.PropertiesToLoad.Add("mail");
SearchResult result = search.FindOne();
if (null == result)
{
return false;
}
//if (result != null)
//{
// string mail = result.Properties["mail"][0].ToString();
//}
// Update the new path to the user in the directory
_path = result.Path;
_filterAttribute = (String)result.Properties["cn"][0];
_filterAttribute = (String)result.Properties["mail"][0];
}
catch (Exception ex)
{
throw new Exception("Error authenticating user. " + ex.Message);
}
return true;
}
public string GetGroups()
{
DirectorySearcher search = new DirectorySearcher(_path);
search.Filter = "(cn=" + _filterAttribute + ")";
search.Filter = "(mail=" + _filterAttribute + ")";
search.PropertiesToLoad.Add("memberOf");
StringBuilder groupNames = new StringBuilder();
try
{
SearchResult result = search.FindOne();
int propertyCount = result.Properties["memberOf"].Count;
String dn;
//int equalsIndex, commaIndex;
for (int propertyCounter = 0; propertyCounter < propertyCount;
propertyCounter++)
{
dn = (String)result.Properties["memberOf"][propertyCounter];
//equalsIndex = dn.IndexOf("=", 1);
//commaIndex = dn.IndexOf(",", 1);
//if (-1 == equalsIndex)
//{
// return null;
//}
//groupNames.Append(dn.Substring((equalsIndex + 1),
// (commaIndex - equalsIndex) - 1));
//groupNames.Append("|");
}
}
catch (Exception ex)
{
throw new Exception("Error obtaining group names. " +
ex.Message);
}
return groupNames.ToString();
}
}
This may be an oversimplification but...
public void LoginButton_Clicked(object sender, EventArgs e)
{
LdapAuthentication auth = new LdapAuthentication("YOURPATH");
if (auth.IsAuthenticated("YOURDOMAIN", txtId.Text, txtPassword.Text))
{
//Login Passed
}
}
I'm assuming you are using WebForms and your username textbox has the ID "txtId", and your password textbox has ID "txtPassword".
If you are not using WebForms the implementation will be different. As spectacularbob mentioned, we can't really answer your question until we know which UI Framework you are using.
Hi I would like to avoid printing certain rows (valid accounts) in my foreach loop (in GetSAM)as opposed to printing everything.
When I try to do so by commenting away the line (in valSAM) that prints the valid accounts, the will be a blank in the area where a valid account once was. I understand that this is because the foreach loops through all the variables in the database.
How am I able to remove the gaps between the output?
GetSAM:
//Get SAMAccount
private static string GetSAM(string ldapAddress, string serviceAccountUserName, string serviceAccountPassword)
{
string ldapPath = "LDAP://" + ldapAddress;
string ldapFilter = "(&(objectclass=user)(objectcategory=person))";
DirectoryEntry directoryEntry = new DirectoryEntry(ldapPath, serviceAccountUserName, serviceAccountPassword);
string readOutput;
List<string> list = new List<string>();
List<int> invalid = new List<int>();
using (DirectorySearcher directorySearcher = new DirectorySearcher(directoryEntry))
{
string samAccountName;
directorySearcher.Filter = ldapFilter;
directorySearcher.SearchScope = SearchScope.Subtree;
directorySearcher.PageSize = 1000;
using (SearchResultCollection searchResultCollection = directorySearcher.FindAll())
{
**foreach (SearchResult result in searchResultCollection)
{
samAccountName = result.Properties["sAMAccountName"][0].ToString();
if (valSAM(samAccountName, ldapAddress, serviceAccountUserName, serviceAccountPassword)!= true)
{
invalid.Add('1');
}
list.Add(samAccountName);
} //end of foreach**
// Count all accounts
int totalAccounts = list.Count;
// Count all invalid accounts
int invalidAccounts = invalid.Count;
Console.WriteLine("Found " + invalidAccounts + " invalid accounts out of " + totalAccounts + " user accounts.\nQuery in " + ldapAddress + " has finished.\n");
Console.WriteLine("Press [enter] to continue.\n");
readOutput = Console.ReadLine();
}//SearchResultCollection will be disposed here
}
return readOutput;
}
valSAM:
//Validate SAMAccount
private static bool valSAM(string samAccountName, string ldapAddress, string serviceAccountUserName, string serviceAccountPassword)
{
string ldapPath = "LDAP://" + ldapAddress;
DirectoryEntry directoryEntry = new DirectoryEntry(ldapPath, serviceAccountUserName, serviceAccountPassword);
StringBuilder builder = new StringBuilder();
bool accountValidation = false;
//create instance fo the directory searcher
DirectorySearcher desearch = new DirectorySearcher(directoryEntry);
//set the search filter
desearch.Filter = "(&(sAMAccountName=" + samAccountName + ")(objectcategory=user))";
//find the first instance
SearchResult results = desearch.FindOne();
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, ldapAddress))
{
//if users are present in database
if (results != null)
{
//Check if account is activated
bool isAccountActived = IsActive(results.GetDirectoryEntry());
//Check if account is expired or locked
bool isAccountLocked = IsAccountLockOrExpired(results.GetDirectoryEntry());
accountValidation = ((isAccountActived != true) || (isAccountLocked));
//account is invalid
if (accountValidation)
{
builder.Append("User account " + samAccountName + " is invalid. ");
if ((isAccountActived != true) && (isAccountLocked))
{
builder.Append("Account is inactive and locked or expired.").Append('\n'); ;
} else if (isAccountActived != true)
{
builder.Append("Account is inactive.").Append('\n'); ;
}
else if (isAccountLocked)
{
builder.Append("Account is locked or has expired.").Append('\n'); ;
}
else
{
builder.Append("Unknown reason for status. Contact admin for help.").Append('\n'); ;
}
accountValidation = false;
}
//account is valid
if ((isAccountActived) && (isAccountLocked != true))
{
**//builder.Append("User account " + samAccountName + " is valid.").Append('\n');
accountValidation = true;
}
}
else Console.WriteLine("Nothing found.");
Console.WriteLine(builder);
}//end of using
return accountValidation;
}
You probably want to only write if builder has something otherwise it will print an empty line. Namely, change
Console.WriteLine(builder);
to
if (builder.Length > 0)
{
Console.WriteLine(builder);
}
or just
Console.Write(builder);
if you're going to handle all of the new lines in the builder itself. If you're going to do that, use StringBuilder.AppendLine() instead of hardcoding the '\n' like that.
StringBuilder.AppendLine https://msdn.microsoft.com/en-us/library/system.text.stringbuilder.appendline(v=vs.110).aspx
I've got a web application that is using Active Directory.
I create a function to perform authentication domain, in parameter ( User,Password, and own domain ).
In determinat line displays a messagem "Unspecified error", as the function below:
public bool IsAuthenticated(string domain, string username, string pwd)
{
string domainAndUsername = domain + #"\" + username;
DirectoryEntry entry = new DirectoryEntry(_path, domainAndUsername, pwd);
try
{
//Bind to the native AdsObject to force authentication.
---> This Line occurred error
**object obj = entry.NativeObject;**
---> Line Above occurred error
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = "(SAMAccountName=" + username + ")";
search.PropertiesToLoad.Add("cn");
SearchResult result = search.FindOne();
if (null == result)
{
return false;
}
//Update the new path to the user in the directory.
_path = result.Path;
_filterAttribute = (string)result.Properties["cn"][0];
}
catch (Exception ex)
{
throw new Exception("Error authenticating user. " + ex.Message);
}
return true;
}
using(PrincipalContext pc = new PrincipalContext(ContextType.Domain, "YOURDOMAIN"))
{
// validate the credentials
bool isValid = pc.ValidateCredentials("myuser", "mypassword")
}
This is probably going to work better for your needs. You need .NET3.5 at least and is what you should be using to authenticate.