Slow AD group membership lookup - c#

I have some code to check if a domain user is a member of the machines administrators group:
public static bool ActiveDirectoryGroupMembershipOk(string userid, string groupName)
{
using (PrincipalContext ctx = new PrincipalContext(ContextType.Machine, "my_pc_name"))
{
using (GroupPrincipal grp = GroupPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, "administrators"))
{
if (grp != null)
{
foreach (Principal p in grp.GetMembers(false))
{
if (p is UserPrincipal && p.SamAccountName.Equals(userid, StringComparison.InvariantCultureIgnoreCase))
{
return true;
}
}
}
}
}
return false;
}
It works, but the below code line takes some seconds to complete:
using (GroupPrincipal grp = GroupPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, "administrators"))
Is there a faster way to lookup the membership?
I don't know if it is important or not, but the userid is a Domain User and the windows group is on the local PC.

I found that it seems to be faster not to look up the user in a group but instead to check the user's role membership.
Here is the code that performs faster than the code in my question:
public static bool ActiveDirectoryGroupMembershipOk(string userid, string groupName)
{
bool membershipOk = false;
using (var pc = new PrincipalContext(ContextType.Machine, "my_pc_name"))
{
using (var p = Principal.FindByIdentity(pc, IdentityType.SamAccountName, userid))
{
// if user account exists, check the group membership
if(p != null)
{
System.Security.Principal.WindowsIdentity wi = new System.Security.Principal.WindowsIdentity(userid);
System.Security.Principal.WindowsPrincipal wp = new System.Security.Principal.WindowsPrincipal(wi);
membershipOk = wp.IsInRole(groupName);
}
}
}
return membershipOk;
}

I found a better way to do this still (assuming an AD domain), using part of Mr. Blonde's answer:
public static bool ActiveDirectoryGroupMembershipOk(String userid, String groupname)
{
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, userid);
GroupPrincipal group = GroupPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, groupname);
return user.IsMemberOf(group);
}

Related

get all users from a group in Active Directory using GroupPrincipal

Im trying to get all users of a particular group in AD but i am getting Exception : "The specified directory service attribute or value does not exist."
//using (var principalContext = new PrincipalContext(ContextType.Domain))
using (var principalContext = new PrincipalContext(ContextType.Domain, "domainName"))
{
//using (var group = GroupPrincipal.FindByIdentity(context, windowsGroup.TrimEnd('*')))
using (var groupPrincipal = GroupPrincipal.FindByIdentity(principalContext, IdentityType.SamAccountName, "groupName"))
{
if (groupPrincipal != null)
{
var users = groupPrincipal.GetMembers();
foreach (UserPrincipal userPrincipal in users)
{
//user variable has the details about the user
}
}
}
}
use container to specify your root
using (var principalContext = new PrincipalContext(ContextType.Domain, "TEST.COM", "DC=TEST,DC=COM"))
{
//using (var group = GroupPrincipal.FindByIdentity(context, windowsGroup.TrimEnd('*')))
using (var groupPrincipal = GroupPrincipal.FindByIdentity(principalContext, IdentityType.SamAccountName, "groupName"))
{
if (groupPrincipal != null)
{
var users = groupPrincipal.GetMembers();
foreach (UserPrincipal userPrincipal in users)
{
//user variable has the details about the user
}
}
}
}

How to check if every users on the system has administrator rights in C#

I have a list of users created in my system:
Administrator (by default)
Guest
User1 (Standard User)
User2 (Administrator User)
I want to know the rights given to all these users in C# through WMI
,how is this possible??Is there any other way to find them.
Even If one user has this right it must exit from the loop
I use the below code :
WindowsIdentity identity = WindowsIdentity.GetCurrent();
WindowsPrincipal principal = new WindowsPrincipal(identity);
bool isAdmin = principal.IsInRole(WindowsBuiltInRole.Administrator);
if (isAdmin == true)
{
current_logged_user = "Yes";
}
else
{
current_logged_user = "No";
}
This gives me only the currently logged info,but I need for all the users
link
The below link just give the members of administrartors
link
You should be able to return all users via WMI with
string groupNameToSearchFor = "Administrators"; // can be any group,maybe better to use something like builtin.administrators
using (PrincipalContext pc = new PrincipalContext(ContextType.Machine, null))
{
ManagementObjectSearcher usersSearcher = new ManagementObjectSearcher(#"SELECT * FROM Win32_UserAccount");
ManagementObjectCollection users = usersSearcher.Get();
foreach (ManagementObject user in users)
{
if ((bool)user["LocalAccount"] == true && int.Parse(user["SIDType"].ToString()) == 1)
{
var userPrincipal = UserPrincipal.FindByIdentity(pc, IdentityType.SamAccountName, user["Name"].ToString());
GroupPrincipal gp = GroupPrincipal.FindByIdentity(pc, groupNameToSearchFor);
MessageBox.Show("Is User admin? -> " + (bool)userPrincipal.IsMemberOf(gp));
}
}
}
You have to include the usings for
using System.DirectoryServices.AccountManagement;
using System.Management;
And also check if the user is really a user and not a different object (not sure if my checks are enough).
Edit: you can cast the users you need after you got the list with
var localUsers = users.Cast<ManagementObject>().Where(
u => (bool)u["LocalAccount"] == true &&
(bool)u["Disabled"] == false &&
(bool)u["Lockout"] == false &&
int.Parse(u["SIDType"].ToString()) == 1 &&
u["Name"].ToString() != "HomeGroupUser$");
You can try this:
bool IsInGroup(string user, string group)
{
using (var identity = new WindowsIdentity(user))
{
var principal = new WindowsPrincipal(identity);
return principal.IsInRole(group);
}
}
You can change IsInRole(group) to IsInRole(WindowsBuiltInRole.Administrator)
Do you have a domain server ?

Principal Context object returns null after hosting application in IIS

Below is my code:
public List<ActiveDirectory> GetActiveDirectoryUsers(string user = "")
{
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, Constants.DomainName);
if (user == "User")
{
adUsers = GetSpecificGroupUsers(ctx, Constants.UserGroup);
}
else
{
adUsers = GetSpecificGroupUsers(ctx, Constants.AdminGroup);
adUsers = GetSpecificGroupUsers(ctx, Constants.UserGroup);
}
ctx.Dispose();
return adUsers;
}
public List<ActiveDirectory> GetSpecificGroupUsers(PrincipalContext ctx,string groupName)
{
GroupPrincipal grp = GroupPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, groupName);
if (grp != null)
{
foreach (Principal p in grp.GetMembers(false))
{
if (p.DisplayName != null)
{
adUsers.Add(new ActiveDirectory()
{
UserName = p.DisplayName,
DisplayName = p.SamAccountName
});
}
}
grp.Dispose();
}
return adUsers;
}
The above code works in Visual studio editor (in dev environment). But the Principal Context object returns null after hosting the application in IIS. I have used form authentication and not windows authentication as I need a custom login page.
This line is throwing error:
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, Constants.DomainName);
Where Constants.DomainName = "My_Domain_Name".
Please let me know if there is any way to sort it out.
Thanks for reading and kindly give some suggestions.

Active Directory - weird behaviour

I'm trying to get informations (members of groups).
I get every time the message "Information about the domain could not be retrieved (1355)"
For getting the groups, it helped to try it just 2 times. The first time doesn't work, but the second time brings me the groups. But for getting the Members of a group, I have no work aroung.
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "192.168.178.105:3268", "DC=ibcdev,DC=local", ContextOptions.Negotiate, "Administrator", "123");
// define a "query-by-example" principal - here, we search for a GroupPrincipal
GroupPrincipal qbeGroup = new GroupPrincipal(ctx);
// create your principal searcher passing in the QBE principal
PrincipalSearcher srch = new PrincipalSearcher(qbeGroup);
// find all matches
try
{
var re2s = srch.FindAll().ToList();
}
catch (Exception)
{
}
var res = srch.FindAll();
foreach (Principal found in res)
{
Console.WriteLine(found.SamAccountName);
var group = GroupPrincipal.FindByIdentity(ctx, found.Name);
foreach (var user in group.Members)
{
Console.WriteLine(user.SamAccountName);
}
}
Does somebody know what I am doing wrong?
Regards
This is what I use for finding a groups members in a domain:
public List<String> GetIDs(string domainName, string groupName)
{
using(PrincipalContext ctx = new PrincipalContext(ContextType.Domain, domainName))
using(GroupPrincipal grp = GroupPrincipal.FindByIdentity(ctx, IdentityType.Name, groupName))
return (from x in grp.GetMembers(true).AsParallel() select x.SamAccountName).ToList();
}

Get parent OU of user in Active Directory using C#

I want to check, if a a user is in a specific parent OU.
How can I do that?
Check below code for a clear desciption of what I am looking for.
using System.DirectoryServices.AccountManagement;
public bool IsUserInOU(string samAccountName, string OUName){
using (var context = new PrincipalContext(ContextType.Domain))
{
using (var user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, samAccountName))
{
//Check if the user is in the OU specified in OUName
//Something like:
//return user.IsInOU(OUName);
}
}
}
public void TestIt_1(){
//The parent OU of this user is "AwesomeOU"
string samAccountName = "Joe";
string OUName = "AwesomeOU";
bool expected = true;
bool actual = IsUserInOU(samAccountName, OUName);
Assert.AreEqual(expected, actual);
}
public void TestIt_2(){
//The parent OU of this user is "WhateverOU"
string samAccountName = "Mike";
string OUName = "AwesomeOU";
bool expected = false;
bool actual = IsUserInOU(samAccountName, OUName);
Assert.AreEqual(expected, actual);
}
The Domain:
National OU
Awesome OU
Joe
Whatever OU
Mike
Solution 1 after empi's answer
With the information given by empi, I wrote the below method to extract the first OU in the DistinguishedName. Having done that, the rest is a breeze.
public static string GetOUForUser(string samAccountName)
{
using (var context = new PrincipalContext(ContextType.Domain))
{
using (var user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, samAccountName))
{
//System.Console.WriteLine(user.DistinguishedName);
int startIndex = user.DistinguishedName.IndexOf("OU=", 1) + 3; //+3 for length of "OU="
int endIndex = user.DistinguishedName.IndexOf(",", startIndex);
var group = user.DistinguishedName.Substring((startIndex), (endIndex - startIndex));
return group;
}
}
}
Solution 2 after JPBlanc's answer
public static string GetOUForUser(string samAccountName)
{
using (var context = new PrincipalContext(ContextType.Domain))
{
using (var user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, samAccountName))
{
using (DirectoryEntry deUser = user.GetUnderlyingObject() as DirectoryEntry)
{
using (DirectoryEntry deUserContainer = deUser.Parent)
{
return deUserContainer.Properties["Name"].Value.ToString();
}
}
}
}
}
Ok #Empi solution is working, but UserPrincipal is built on DirectoryEntry objects that provides a parent or container properties that just give you the object you are looking for, without using string way.
/* Retreiving a principal context
*/
PrincipalContext domainContext = new PrincipalContext(ContextType.Domain, "WM2008R2ENT:389", "dc=dom,dc=fr", "dom\\jpb", "MyPwd");
/* Retreive a user
*/
UserPrincipal user = UserPrincipal.FindByIdentity(domainContext, "user1");
/* Retreive the container
*/
DirectoryEntry deUser = user.GetUnderlyingObject() as DirectoryEntry;
DirectoryEntry deUserContainer = deUser.Parent;
Console.WriteLine (deUserContainer.Properties["distinguishedName"].Value);
This information is in UserPrincipal.DistinguishedName. You should check if DistinguishedName ends with "," + ou distinguished name (case insensitive). However, you must know the distingushed name of ou you're checking.
For example, if dn is: CN=Jeff Smith,OU=Sales,DC=Fabrikam,DC=COM, then it says that user is in OU=Sales,DC=Fabrikam,DC=COM ou.
This is how I would get the Distinguished Name for a specific AD user, hope it helps :-)
private static string GetDNOfUser(string user)
{
var ctx = new PrincipalContext(ContextType.Domain, Environmentals.Domain, Environmentals.OUPath);
//Creating object for search filter
UserPrincipal userPrin = new UserPrincipal(ctx)
{
//Only getting users with the same name as the input
Name = user
};
var searcher = new PrincipalSearcher
{
//Applying filter to query
QueryFilter = userPrin
};
//Finding the user
var results = searcher.FindOne();
searcher.Dispose();
//Return the distinguishedname
return results.DistinguishedName;
}

Categories