67

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);
    }
Ruben Steins
  • 2,782
  • 4
  • 27
  • 48
Sealer_05
  • 5,346
  • 8
  • 35
  • 53

6 Answers6

135

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:

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!

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • I am getting PrincipalOperationException was unhandled on the if (user.IsMemberOf(group)). – Sealer_05 Aug 19 '12 at 20:02
  • 1
    Apparently its a bug in 4.0 http://social.msdn.microsoft.com/Forums/pl-PL/csharplanguage/thread/4c9fea6c-1d0a-4733-a8ac-e3b78d10e999 and I fixed it by adding Environment.UserDomainName to the principle context. http://stackoverflow.com/questions/4518472/userprincipal-getgroups-fails-with-unknown-error If you want to edit that in to your code I will accept your answer. Thanks a ton for the help!! – Sealer_05 Aug 19 '12 at 21:28
  • 1
    @osiris355: updated my response with the workaround given in that thread on social.msdn. – marc_s Aug 20 '12 at 04:38
  • 1
    This is a great guidance. I am able to convert it into a few lines of PowerShell for the convenience of playing with the APIs. I've documented it in [this blog post](http://kflu.github.io/2016/03/24/setup-iis-nodejs-enterprise.html#check-if-a-domain-user-is-a-member-of-a-security-group). – KFL Mar 29 '16 at 19:06
  • @marc_s Is this still the best way to do this with 4/4.5? – AnotherDeveloper Apr 28 '17 at 20:46
  • @AnotherDeveloper: as far as I know, yes - but I haven't been very active in the AD space anymore lately – marc_s Apr 28 '17 at 20:51
  • In AD (Kerberos) environments, Principal acquisition is just about the only way to effectively perform the operation. Its when you want a Fall Back approach is when the authentication pattern gets really heavy. – GoldBishop Nov 10 '17 at 15:49
  • This code is not working after deploying in IIS. Please advice. – Saurabh Dec 13 '17 at 10:39
  • @Saurabh, Your Application Pool Identity should be a Domain User. Please use using(PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "DOMAINNAME")) if a class is IDisposable (see https://msdn.microsoft.com/en-us/library/system.idisposable(v=vs.110).aspx) – Gideon Mulder Apr 18 '18 at 13:56
  • These classes are IDisposable, don't forget using a "using" statement – Cesar Jan 17 '23 at 16:59
14

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

}
GoldBishop
  • 2,820
  • 4
  • 47
  • 82
1

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());
        }
0

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

Ibrahim ULUDAG
  • 450
  • 3
  • 9
  • 3
    Although this method is the long way around to get the information, utilizing the WindowsIdentity available from IIS utilizes the current token loaded in the user's profile. No need to query the AD Forest/Node in order to get the same information that is already locally loaded. – GoldBishop May 14 '16 at 22:34
0

Why not:

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

lennoxGER
  • 284
  • 1
  • 6
  • IsInRole works perfectly but we have an Active Directory with about 200.000 User/Computer object and the Domain controllers slow down dramatically if many users does this call in parallel. My solution above solved this as I don't know what Microsoft does internally with IsInRole. – Mickey Mouse Aug 13 '23 at 12:47
0

I have a perfect solution with error handling which also works with subgroups automatically without scanning all subgroups in a loop. The IsMemberOf is NOT working with subgroups. Therefore you must use this:

LDAP_MATCHING_RULE_IN_CHAIN

using System.DirectoryServices;
using System.DirectoryServices.AccountManagement;

public static bool IsUserInGroup(string userName, string groupName)
{
    try
    {
        using (PrincipalContext pc = new PrincipalContext(ContextType.Domain))
        {
            var gp = GroupPrincipal.FindByIdentity(pc, groupName);
            var up = UserPrincipal.FindByIdentity(pc, userName);

            if (gp == null) throw new ApplicationException($"Group '{groupName}' not found in Active Directory");
            if (up == null) throw new ApplicationException($"User '{userName}' not found in Active Directory");

            DirectoryEntry user = new DirectoryEntry($"LDAP://{up.DistinguishedName}");
            DirectorySearcher mySearcher = new DirectorySearcher(user)
            {
                SearchScope = SearchScope.Subtree,
                Filter = $"(memberOf:1.2.840.113556.1.4.1941:={gp.DistinguishedName})"  // takes also subgroups
            };

            return !(mySearcher.FindOne() is null);
        }
    }
    catch (Exception)
    {
        throw;
    }
}

public static bool IsComputerInGroup(string computerName, string groupName)
{
    try
    {
        using (PrincipalContext pc = new PrincipalContext(ContextType.Domain))
        {
            var gp = GroupPrincipal.FindByIdentity(pc, groupName);
            var cp = ComputerPrincipal.FindByIdentity(pc, computerName);

            if (gp == null) throw new ApplicationException($"Group '{groupName}' not found in Active Directory");
            if (cp == null) throw new ApplicationException($"Computer '{computerName}' not found in Active Directory");

            DirectoryEntry computer = new DirectoryEntry($"LDAP://{cp.DistinguishedName}");
            DirectorySearcher mySearcher = new DirectorySearcher(computer)
            {
                SearchScope = SearchScope.Subtree,
                Filter = $"(memberOf:1.2.840.113556.1.4.1941:={gp.DistinguishedName})"
            };

            return !(mySearcher.FindOne() is null);
        }
    }
    catch (Exception)
    {
        throw;
    }
}
Mickey Mouse
  • 723
  • 6
  • 4