How to check if a user belongs to an AD group? - c#

At first I thought the code below works because if I have the group as "IT" it functions correctly because my username is in the IT group in active directory. What I learned is it always returns true whether I have my username in the IT group or not and if i change it to any other group I am in it returns always returns false. Any help would be appreciated.
private void tabControl1_SelectedIndexChanged(object sender, EventArgs e)
{
// tab control security for admin tab
bool admin = checkGroup("IT");
if ((admin == true) && (tabControl1.SelectedTab == tpHistory))
{
tabControl1.SelectedTab = tpHistory;
}
else if ((admin == false) && (tabControl1.SelectedTab == tpHistory))
{
tabControl1.SelectedTab = tpRequests;
MessageBox.Show("Unable to load tab. You have insufficient privileges.",
"Access Denied", MessageBoxButtons.OK, MessageBoxIcon.Stop);
}
}
// check active directory to see if user is in Marketing department group
private static bool checkGroup(string group)
{
WindowsIdentity identity = WindowsIdentity.GetCurrent();
WindowsPrincipal principal = new WindowsPrincipal(identity);
return principal.IsInRole(group);
}

Since 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
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "DOMAINNAME");
// find a user
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, "SomeUserName");
// find the group in question
GroupPrincipal group = GroupPrincipal.FindByIdentity(ctx, "YourGroupNameHere");
if(user != null)
{
// check if user is member of that group
if (user.IsMemberOf(group))
{
// do something.....
}
}
The new S.DS.AM makes it really easy to play around with users and groups in AD!

Slight deviation from #marc_s example, implemented in the static void Main() method in Program:
DomainCtx = new PrincipalContext( ContextType.Domain , Environment.UserDomainName );
if ( DomainCtx != null ) {
User = UserPrincipal.FindByIdentity( DomainCtx , Environment.UserName );
}
DomainCtx and User are both static properties declared under Program
Then in other forms i simply do something like this:
if ( Program.User.IsMemberOf(GroupPrincipal.FindByIdentity(Program.DomainCtx, "IT-All") )) {
//Enable certain Form Buttons and objects for IT Users
}

Check if current user in a group
public bool AuthenticateGroup(string groupfind)
{
var p = new Process();
StringBuilder stringbd = new StringBuilder();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = #"/c gpresult /V";
p.StartInfo.CreateNoWindow = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardInput = false;
p.StartInfo.UseShellExecute = false;
p.OutputDataReceived += (a, b) => stringbd.AppendLine(b.Data);
p.ErrorDataReceived += (a, b) => stringbd.AppendLine(b.Data);
p.Start();
p.BeginErrorReadLine();
p.BeginOutputReadLine();
p.WaitForExit();
var textfind = stringbd.ToString();
int findpoint = textfind.IndexOf("The user is a part of");
string findgroup = "";
if (findpoint > 0)
{
findgroup = textfind.Substring(findpoint, textfind.Length - findpoint);
}
return findgroup.Split('\n').ToList().Any(r=>r.Trim().ToLower()==groupfind.Trim().ToLower());
}

You cannot do it by this way.
You should query the active directory.
You can use a wrapper for AD. Check out http://www.codeproject.com/Articles/10301/Wrapper-API-for-using-Microsoft-Active-Directory-S

Why not:
bool isUserInGroup = HttpContext.User.IsInRole(".nameOfAdGroup");

Related

How to check that windows account is disabled in C#?

I am trying to check if window account is disabled or not in active directory, for this reason I tried System.DirectoryServices.AccountManagement namespace but could not find any method to check if account is disable unlike IsAccountLockedOut method.
PrincipalContext oPrincipalContext = GetPrincipalContext();
UserPrincipal oUserPrincipal =UserPrincipal.FindByIdentity(oPrincipalContext, sUserName);
oUserPrincipal.IsAccountLockedOut();
We use this method:
var context = new DirectoryContext(DirectoryContextType.Domain, "domain");
using (var domainController = DomainController.FindOne(context))
{
using (var directorySearcher = domainController.GetDirectorySearcher())
{
directorySearcher.Filter = String.Format("(sAMAccountName={0})", "login");
directorySearcher.SizeLimit = 1;
var userDirectory = directorySearcher.FindOne();
using (var userDirectoryEntry = userDirectory.GetDirectoryEntry())
{
var active = userDirectoryEntry.IsActive();
}
}
}
IsActive - is an extension method:
public static bool IsActive(this DirectoryEntry directoryEntry)
{
if (directoryEntry.NativeGuid == null) return false;
var value = directoryEntry.Properties["userAccountControl"].Value;
if (value == null)
return true;
var flags = (int)value;
return !Convert.ToBoolean(flags & 0x0002);
}
So, get DirectoryEntry of your account and call this method.
PrincipalContext oPrincipalContext = GetPrincipalContext();
UserPrincipal oUserPrincipal =UserPrincipal.FindByIdentity(oPrincipalContext, sUserName);
bool? IsEnabled = oUserPrincipal.Enabled;
// if IsEnabled = true then User Account is Enabled
// if IsEnabled = false then User Account is Disabled

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 ?

Can I access a secured network folder with Directory.GetFiles()?

Is it possible to access a network folder with Directory.GetFiles() that I would normally have to enter my credentials for when opening through explorer?
If the running user is the logon user (with profil loading) and have already access to the remote path (by entering credentials), your application, which may run with user's profile loaded, should access to the UNC path without any login.
Otherwise, you can use this piece of code to logon you can find in GitHub :
using (UNCAccessWithCredentials unc = new UNCAccessWithCredentials())
{
if (unc.NetUseWithCredentials("uncpath", user, domain, password))
{
// Directory.GetFiles() here
}
}
It is possible. I usually spawn a process to pass the credentials to the system. Please see the code posted below which does exactly this. Once the process has completed you will be able to use the network share.
public void MapPath() {
string strServer = “ServerName”;
string strShare = “ServerShare”;
string strUsername = “ServerUsername”;
string strPassword = “ServerPassword”;
Process pNetDelete = new Process();
pNetDelete.StartInfo.CreateNoWindow = true;
pNetDelete.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
pNetDelete.StartInfo.UseShellExecute = false;
pNetDelete.StartInfo.FileName = “net”;
pNetDelete.StartInfo.Arguments = string.Format(“use /DELETE {0}\
{1} /Y”, strServer, strShare);
pNetDelete.Start();
pNetDelete.WaitForExit();
Process pNetShare = new Process();
pNetShare.StartInfo.CreateNoWindow = true;
pNetShare.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
pNetShare.StartInfo.UseShellExecute = false;
pNetShare.StartInfo.RedirectStandardError = true;
pNetShare.StartInfo.RedirectStandardOutput = true;
pNetShare.StartInfo.FileName = “net”;
pNetShare.StartInfo.Arguments = string.Format(“use \\{0}\{1} /u:"{2}" "{3}"”,
strServer, strShare, strUsername, strPassword);
pNetShare.Start();
pNetShare.WaitForExit();
string strError = pNetShare.StandardError.ReadToEnd();
if (pNetShare.ExitCode != 0)
{
throw new Exception(strError);
}
}

Directory Entry - Account Active

I'm trying to implement the IsActive method described here Is Account Active, but i'm getting an object reference not set to an instance of the the object.
private bool IsActive(DirectoryEntry de)
{
DirectoryEntry myEntry = GetDirectoryEntry();
if (myEntry.NativeGuid == null) return false;
int flags = (int)myEntry.Properties["userAccountControl"].Value;
if (!Convert.ToBoolean(flags & 0x0002)) return true; else return false;
return false;
}
private void SubmitData()
{
System.Guid guid = Guid.NewGuid();
logInfo.IPaddress = IPAddress;
if (!String.IsNullOrEmpty(txtUser.Text))
{
string username = txtUser.Text.ToString();
if (IsActive(de) != false)
{
if (DateTime.Now.Subtract(passwordLastSet).TotalHours > 1)
{
lblPasswordLastSet.Text = passwordLastSet.ToString();
lblStatus.Text = "all is good";
}
else
{
lblStatus.Text = "oops, you reset your password less than 24 hours ago!";
lblPasswordLastSet.Text = passwordLastSet.ToString();
}
}
else
{
lblStatus.Text = "your account is not active";
}
}
}
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
Basically, you can define a domain context and easily find users and/or groups in AD:
// set up domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
// find user by name
UserPrincipal user = UserPrincipal.FindByIdentity("John Doe");
if(user != null)
{
// check if account is locked out
if(user.IsAccountLockedOut)
{
// do something if locked out....
}
}
The new S.DS.AM makes it really easy to play around with users and groups in AD:

GroupPrincipal.Members.Remove() doesn't work with a large AD group

I'm using the System.DirectoryServices.AccountManagement namespace classes to manage the membership of several groups. These groups control the population of our print accounting system and some of them are very large. I'm running into a problem removing any user from one of these large groups. I have a test program that illustrates the problem. Note that the group I'm testing is not nested, but user.IsMemberOf() also seems to have the same problem, whereas GetAuthorizationGroups() correctly shows the groups a user is a member of. The group in question has about 81K members, which is more than it should have since Remove() isn't working, and will normally be about 65K or so.
I'd be interested to hear from other people who have had this problem and have resolved it. I've got an open case with Microsoft, but the turn around on the call is slow since the call center is about 17 hours time difference so they don't arrive for work until about an hour before I usually leave for home.
using (var context = new PrincipalContext( ContextType.Domain ))
{
using (var group = GroupPrincipal.FindByIdentity( context, groupName ))
{
using (var user = UserPrincipal.FindByIdentity( context, userName ))
{
if (user != null)
{
var isMember = user.GetAuthorizationGroups()
.Any( g => g.DistinguishedName == group.DistinguishedName );
Console.WriteLine( "1: check for membership returns: {0}", isMember );
if (group.Members.Remove( user ))
{
Console.WriteLine( "user removed successfully" );
group.Save();
}
else
{
// do save in case Remove() is lying to me
group.Save();
Console.WriteLine( "user remove failed" );
var isStillMember = user.GetAuthorizationGroups()
.Any( g => g.DistinguishedName == group.DistinguishedName );
Console.WriteLine( "2: check for membership returns: {0}", isStillMember );
}
}
}
}
}
Turns out this is a bug in the GroupPrincipal.Members.Remove() code in which remove fails for a group with more than 1500 members. This has been fixed in .NET 4.0 Beta 2. I don't know if they have plans to back port the fix into 2.0/3.x.
The work around is to get the underlying DirectoryEntry, then use Invoke to execute the Remove command on the IADsGroup object.
var entry = group.GetUnderlyingObject() as DirectoryEntry;
var userEntry = user.GetUnderlyingObject() as DirectoryEntry;
entry.Invoke( "Remove", new object[] { userEntry.Path } );
This post helped point me in the right direction, just wanted to add some addition info.
It also works binding directly to the group, and you can use it for adding group members.
using (var groupEntry = new DirectoryEntry(groupLdapPath))
{
groupEntry.Invoke("remove", new object[] { memberLdapPath });
groupEntry.Invoke("add", new object[] { memberLdapPath });
}
Also be aware, with the standard 'member' attribute, you use the user or group distinguishedName, but invoke requires the path with LDAP:// prefix, otherwise it throws a vague InnerException:
Exception from HRESULT: 0x80005000
public bool RemoveUserFromGroup(string UserName, string GroupName)
{
bool lResult = false;
if (String.IsNullOrEmpty(UserName) || String.IsNullOrEmpty(GroupName)) return lResult;
try
{
using (DirectoryEntry dirEntry = GetDirectoryEntry())
{
using (DirectoryEntry dirUser = GetUser(UserName))
{
if (dirEntry == null || dirUser == null)
{
return lResult;
}
using (DirectorySearcher deSearch = new DirectorySearcher())
{
deSearch.SearchRoot = dirEntry;
deSearch.Filter = String.Format("(&(objectClass=group) (cn={0}))", GroupName);
deSearch.PageSize = 1000;
SearchResultCollection result = deSearch.FindAll();
bool isAlreadyRemoved = false;
String sDN = dirUser.Path.Replace("LDAP://", String.Empty);
if (result != null && result.Count > 0)
{
for (int i = 0; i < result.Count; i++)
{
using (DirectoryEntry dirGroup = result[i].GetDirectoryEntry())
{
String sGrDN = dirGroup.Path.Replace("LDAP://", String.Empty);
if (dirUser.Properties[Constants.Properties.PROP_MEMBER_OF].Contains(sGrDN))
{
dirGroup.Properties[Constants.Properties.PROP_MEMBER].Remove(sDN);
dirGroup.CommitChanges();
dirGroup.Close();
lResult = true;
isAlreadyRemoved = true;
break;
}
}
if (isAlreadyRemoved)
break;
}
}
}
}
}
}
catch
{
lResult= false;
}
return lResult;
}

Categories