Hi there I am trying to create a textbox that when a user types into it they get a list of users with the specific name:
Example: If I started to type Jane.Doe, and I had only typed in Ja a list would come up with users from the Active Directory who start with Ja. I need to figure out how I can get the Users to a list each time a user types. I pretty much have the ajax side done. Its just getting the list of users updated each time.
My current idea:
[HttpPost]
public ActionResult RemoteData(string query)
{
List<string> lstADUsers = new List<string>();
using (var context = new PrincipalContext(ContextType.Domain, null, "LDAPPATH"))
{
using (var searcher = new PrincipalSearcher(new UserPrincipal(context)))
{
foreach (var result in searcher.FindAll())
{
DirectoryEntry de = result.GetUnderlyingObject() as DirectoryEntry;
string usersWithName;
if (!String.IsNullOrEmpty((String)de.Properties["samaccountname"].Value))
{
usersWithName = de.Properties["samaccountname"].Value.ToString();
lstADUsers.Add(usersWithName);
}
}
}
}
List<string> listData = null;
if (!string.IsNullOrEmpty(query))
{
listData = lstADUsers.Where(q => q.ToLower().StartsWith(query.ToLower())).ToList();
}
return Json(new { Data = listData });
}
So this allows us to get EVERY user in the Active Directory but I don't want this because the issue at hand gets that there are too many users and the search takes FOREVER to load this before it even displays the list of names. I only want to be able to take a parameter and only search for user that starts with that. How would I go about doing this?
You need to populate the Name property of UserPrincipal with a wildcard to limit the result set:
// assume 'query' is 'Ja'
UserPrincipal user = new UserPrincipal(context);
user.Name = query + "*"; // builds 'Ja*', which finds names starting with 'Ja'
using (var searcher = new PrincipalSearcher(user))
// ...
Related
I'm trying to get a list of all upnsuffixes from AD using C#.
I tried this with no success
public static List<string> GetuPNSuffixes()
{
DirectoryEntry partitions = new DirectoryEntry("LDAP://xxxxx.com/CN=Partitions,CN=Configuration,DC=xxxxx,DC=com", "user", "pass");
DirectorySearcher searcher = new DirectorySearcher(partitions);
searcher.PropertiesToLoad.Add("uPNSuffixes");
List<string> suffixes = new List<string>();
foreach (SearchResult sr in searcher.FindAll())
{
foreach (string pn in sr.Properties.PropertyNames)
{
if (pn == "upnsuffixes")
{
suffixes.Add(sr.Properties[pn].ToString());
}
}
}
return suffixes;
}
This gives me a System.DirectoryServices.DirectoryServicesCOMException: There is no such object on the server error. I guess because it doesn't like my ldap string. The account I'm authenticating with is a domain admin and I'm using similar code in other places so the login is definitely correct. Maybe the CN=Partitions,CN=Configuration part is wrong?
I would hope there is a better way to do this without the nested loops. Just trying to get a list of the upnsuffixes.
Also tried this and got the same DirectoryServicesCOMException error:
public static string GetuPNSuffixes()
{
DirectoryEntry entry = new DirectoryEntry("LDAP://xxxxx.com/CN=Partitions,CN=Configuration,DC=xxxxx,DC=com", "user", "pass");
return entry.Properties["upnSuffixes"].ToString();
}
So I guess I'm doing something wrong here with the LDAP string there.
Was able to pull the list of UPN Suffixes with this:
public static List<string> GetuPNSuffixes()
{
//add root domain
List<string> suffixList = new List<string>();
suffixList.Add(Domain.GetCurrentDomain().Name);
//get the list of alternate domains
DirectoryEntry rootDSE = new DirectoryEntry(#"LDAP://RootDSE");
string context = rootDSE.Properties["configurationNamingContext"].Value.ToString();
DirectoryEntry partition = new DirectoryEntry(#"LDAP://CN=Partitions," + context);
foreach (string suffix in partition.Properties["uPNSuffixes"])
{
suffixList.Add(suffix);
}
return suffixList;
}
I am making an Active Directry managment tool but I am having trouble getting somethings working.
While I made a class where I want to find a specific user and return als his information(Name,Fullname,CN,...). I can find all this information but when I don't know the best way to return all the values from my class.
Here is the code I use so far:
DirectorySearcher search = new DirectorySearcher(ldapConnectie);
search.Filter = "(cn=" + username + ")";
SearchResult result = search.FindOne();
if (result != null)
{
List<string> listLdapFields = new List<string>();
List<Object> listLdapValues = new List<Object>();
ResultPropertyCollection fields = result.Properties;
foreach (String ldapField in fields.PropertyNames)
{
listLdapFields.Add(ldapField);
foreach (Object myCollection in fields[ldapField])
{
listLdapValues.Add(myCollection);
}
}
}
The program add everything well to a list. But if I return this I cannot search the list on "CN" or "Name". I can only find the information on Index Number.
Hope you can help me out.
If you're on .NET 3.5 and up, you should check out the System.DirectoryServices.AccountManagement (S.DS.AM) namespace. Read all about it here:
Managing Directory Security Principals in the .NET Framework 3.5
MSDN docs on System.DirectoryServices.AccountManagement
Basically, you can define a domain context and easily find users and/or groups in AD:
// set up domain context
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
// find a user
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, username);
if(user != null)
{
// do something here....
// the most often used attributes are available as nice, strongly-typed properties
string value = user.GivenName;
value = user.Surname;
value = user.EmailAddress;
value = user.VoiceTelephoneNumber;
}
}
The new S.DS.AM makes it really easy to play around with users and groups in AD!
Here's an approach where you can call the property by name. It also uses the authenticated account making the request.
string domainPath = String.Format("LDAP://{0},DC=site,DC=com", domain);
using (DirectoryEntry searchRoot = new DirectoryEntry(domainPath))
{
using (DirectorySearcher search =
filterSearch(new DirectorySearcher(searchRoot), username))
{
SearchResult result = null;
try
{
result = search.FindOne();
}
catch (DirectoryServicesCOMException e)
{
//handle the error
}
if (result != null)
{
string givenname = result.Properties["givenname"].Count > 0 ?
(string)result.Properties["givenname"][0] : "";
string sn = result.Properties["sn"].Count > 0 ?
(string)result.Properties["sn"][0] : "";
var samaccount= result.Properties["samaccountname"].Count > 0 ?
(string)result.Properties["samaccountname"][0] : "";
var name = String.Format("{0}, {1}", sn, givenname);
var email = result.Properties["mail"].Count > 0 ?
(string)result.Properties["mail"][0] : "";
}
}
}
//Apply a filter to search only specific classes and categories.
//Add the specific properties to be retrieved
private DirectorySearcher filterSearch(DirectorySearcher search, string username)
{
DirectorySearcher filteredSearch = search;
filteredSearch.Filter = "(&(objectClass=user)(objectCategory=person)(samaccountname=" + username + "))";
filteredSearch.PropertiesToLoad.Add("givenname");
filteredSearch.PropertiesToLoad.Add("sn");
filteredSearch.PropertiesToLoad.Add("samaccountname");
filteredSearch.PropertiesToLoad.Add("department");
filteredSearch.PropertiesToLoad.Add("physicalDeliveryOfficeName");
filteredSearch.PropertiesToLoad.Add("mail");
return filteredSearch;
}
This may be helpful if looking for specific properties, but if you want to retrieve a list of all attributes/values, take a look at this other SO question.
Google has a list of common filters you can use. Take a look through them and modify the filterSearch method appropriately.
I am trying to fetch a list of OU's from active directory. Unfortunately my search always ends up without any results even though I know there are 2 OU's inside the "myApp" domain component.
using (var entry = new DirectoryEntry("LDAP://myServer:1111/DC=myApp,DC=myDomain,DC=com", Username, Password)) {
using (var searcher = new DirectorySearcher()) {
searcher.SearchRoot = entry;
searcher.Filter = "(objectCategory=Organizational-Unit)";
searcher.PropertiesToLoad.Add("name");
//foo never gets results. :(
var foo = searcher.FindAll();
}
}
I tried following the code in a previous StackOverflow question, but, without luck.
I use something like this. It retrieve all OUs in dictionary name with path, just change SearchScope properly.
public Dictionary<string, string> GetOUInfo(SearchScope eSearchScope)
{
Dictionary<string, string> retValues = new Dictionary<string, string>();
try
{
DirectoryEntry oDirectoryEntry = new DirectoryEntry("LDAP://myServer:1111/DC=myApp,DC=myDomain,DC=com", Username, Password);
DirectorySearcher oDirectorySearcher = new DirectorySearcher(oDirectoryEntry,
"(objectCategory=organizationalUnit)", null, eSearchScope);
SearchResultCollection oSearchResultCollection = oDirectorySearcher.FindAll();
foreach (SearchResult item in oSearchResultCollection)
{
string name = item.Properties["name"][0].ToString();
string path = item.GetDirectoryEntry().Path;
retValues.Add(path, name);
}
}
catch (Exception ex)
{
}
return retValues;
}
1) Are you sure of the base search "DC=myApp,DC=myDomain,DC=com" ? Is "myApp" a domain component ?
2) Can you try to specify the search scope ?
searcher.SearchScope = SearchScope.Subtree;
3) "(objectCategory=Organizational-Unit)" is a shortcut understood by Active-Directory, but in fact the objectCategory attribute is a distinguished name (DN) and the real value for an OU is : CN=Organizational-Unit,CN=Schema,CN=Configuration,domain root DN.
Can you try this filter "(objectClas=Organizational-Unit)" which is more common to search an OU?
On the command line can you try this ?
C:\temp>ldifde -f c:\temp\out.txt -d "DC=myApp,DC=myDomain,DC=com" -r "(objectClass=organizationalUnit)"
Use this it will work
PrincipalContext yourOU = new PrincipalContext(ContextType.Domain, "mycompany.com", "OU=Marketing,OU=Corporate,DC=mycompany,DC=com");
GroupPrincipal findAllGroups = new GroupPrincipal(yourOU, "*");
PrincipalSearcher ps = new PrincipalSearcher(findAllGroups);
foreach (var group in ps.FindAll())
{
Console.WriteLine(group.DistinguishedName);
}
I need to get a specific user only knowing the "sAMAAccountName" field.
The thing is, this specific user can be inside of many groups:
OU=ThirdParty
OU=Company1
CN=User1
CN=User2
CN=User3
OU=Company2
CN=User1
CN=User2
CN=User3
Is there any way to get an user not knowing their groups, only using one attribute that they have?
My code:
DirectorySearcher search = new DirectorySearcher(_path);
search.Filter = "(&(objectCategory=person)(objectClass=User))";
StringBuilder groupNames = new StringBuilder();
try
{
SearchResultCollection result = search.FindAll();
.....
}
Thanks!
EDIT:
Ok, i got it using this code:
DirectorySearcher search = new DirectorySearcher(_entry, "(sAMAccountName=" + userCode + ")");
What information do you need to know about the user? We have used this type of code in the past to retrieve information about a user
using (var identity = new WindowsIdentity(username))
{
var user = new WindowsPrincipal(identity);
if (user.IsInRole("Some Role Name"))
return true;
return false;
}
EDIT
After your comment, I wonder if this post would provide you any further insite. They so show getting the field you're requesting, I'm just not sure the code to retrieve the employee will apply to you since this refers to InfoPath: http://msdn.microsoft.com/en-us/library/bb952744(v=office.12).aspx
If you switch to System.DirectoryServices.AccountManagement then you'll find out that the APIs are in fact much simpler.
For example:
public something FindUserByUserName( string UserName )
{
using ( var searcher =
new PrincipalSearcher( new UserPrincipal( ConfigurationContext ) { Name = UserName } ) )
{
var item = searcher.FindOne();
// do whatever you want with the found object and return it
}
}
where ConfigurationContext is a property which returns the PrincipalContext (credentials to connect to the AD, something like the "connection string")
Try this:
public static List<string> GetADUserInfo(string login)
{
//Using Hosting.HostingEnvironment.Impersonate()
List<string> info = new List<string>();
PrincipalContext infPC = new PrincipalContext(ContextType.Domain, "domain", "login", "password");
UserPrincipal infUP = new UserPrincipal(infPC);
PrincipalSearcher infPS = new PrincipalSearcher();
UserPrincipal foundUP;
infUP.SamAccountName = login;
infPS.QueryFilter = infUP;
foundUP = infPS.FindOne();
if (foundUP != null) {
info.Add(foundUP.SamAccountName.ToLower);
info.Add(foundUP.GivenName);
info.Add(foundUP.Surname);
info.Add(foundUP.EmailAddress.ToLower);
return info;
}
return null;
}
How To Get User group of user from LDAP active directory in C# .NET for ASP. In my Scenario I want to Pass user name to method which query from LDAP Active directory and tell me my user is Member of This User Groups. Please help me in this
If you're on .NET 3.5 or newer, you can also use the new System.DirectoryServices.AccountManagement (S.DS.AM) namespaces.
With this, you can do something like:
// create context for domain
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
// find the user
UserPrincipal up = UserPrincipal.FindByIdentity(ctx, "YourUserName");
if(up != null)
{
// get groups for that user
var authGroups = up.GetAuthorizationGroups();
}
Read more about the new S.DS.AM namespace:
Managing Directory Security Principals in the .NET Framework 3.5
Look into using the System.DirectoryServices namespace. You can use a DirectorySearcher to find the user. Once you have the DirectoryEntry object for that user do this:
public List<string> GetMemberOf(DirectoryEntry de)
{
List<string> memberof = new List<string>();
foreach (object oMember in de.Properties["memberOf"])
{
memberof.Add(oMember.ToString());
}
return memberof;
}
This will return a list of strings which are the group names the user is a member of.
Of course you could further refine this to include the DirectorySearcher code so you can just pass the function the samAccountName.
try this...
public override string[] GetRolesForUser(string username)
{
var allRoles = new List<string>();
var root = new DirectoryEntry(WebConfigurationManager.ConnectionStrings[ConnectionStringName].ConnectionString,
ConnectionUsername,
ConnectionPassword);
var searcher = new DirectorySearcher(root,
string.Format(CultureInfo.InvariantCulture, "(&(objectClass=user)({0}={1}))",
AttributeMapUsername,
username));
searcher.PropertiesToLoad.Add("memberOf");
SearchResult result = searcher.FindOne();
if (result != null && !string.IsNullOrEmpty(result.Path))
{
DirectoryEntry user = result.GetDirectoryEntry();
PropertyValueCollection groups = user.Properties["memberOf"];
foreach (string path in groups)
{
string[] parts = path.Split(',');
if (parts.Length > 0)
{
foreach (string part in parts)
{
string[] p = part.Split('=');
if (p[0].Equals("cn", StringComparison.OrdinalIgnoreCase))
{
allRoles.Add(p[1]);
}
}
}
}
}
return allRoles.ToArray();
}
Use the DirectorySearcher class to preform an ldap query.
For reference:
http://www.codeproject.com/KB/system/QueryADwithDotNet.aspx
I needed a method of authenticating a user and a check to see if they were in a specific user group. I did it by pushing the username and password and loading the "memberOf" property into the 'search' instance. Example below will display all the groups for that specific user name. The 'catch' statement will trap a wrong user name or password.
DirectoryEntry entry = new DirectoryEntry("LDAP://xxxxxxxx/OU=xxxxxxx,DC=xxxxxx,DC=xxxxx,DC=xxxxxx", strLdapUserName, strLdapPassword);
try
{
//the object is needed to fire off the ldap connection
object obj = entry.NativeObject;
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = "(SAMAccountName=" + strLdapUserName + ")";
search.PropertiesToLoad.Add("memberOf");
SearchResult result = search.FindOne();
string filterAttribute = (String)result.Properties["cn"][0];
foreach(string groupMemberShipName in result.Properties["memberOf"])
{
Console.WriteLine("Member of - {0}", groupMemberShipName);
}
}
catch (Exception ex)
{
//failed to authenticate
throw new Exception(ex.ToString());
}
Hope this helps. (Remember to reference System.DirectoryServices)
I think most methods listed above should work, but i would suggest adding code to ensure that your code can "detect circular loops in nested group memberships", and if found, break any infinite loops that your script of choice could potentially get into.