How to: Check if current user is member of ‘domain admins’

The scenario

Sometimes in business applications it’s interesting checking if current user is member of the ‘domain administrators’ role. For example I am used to checking if current user has administrative privileges in order to showing some advanced configuration options (changing the application’s connection string, or allow creating new users).

privileges_thumb

IsInRole

To acomplish this we could use WindowsPrincipal class and its IsInRole method (this method checks if an user is member of a Windows role and returns a bool value). One of its overrides allows to pass the SID of the role or a constant value based on the enumeration WindowsBuiltInrole.

Note: For performance reasons, it’s recommended to use the override: IsinRole(SecurityIdentifier).

To check if current user is a local administrator we only need to do this:

WindowsPrincipal wp = new WindowsPrincipal(WindowsIdentity.GetCurrent());
return wp.IsInRole(WindowsBuiltInRole.Administrator);

Notice that it’s realy easy, but as -its name indicates- WindowsBuiltInrole enumeration only contains local roles. So, if we would check if our user is member of a domain group, we should find the role SID, and then copy this value in our code.

As you can imagine, this is not the best solution, isn’t it? Well, let’s investigate a little bit more…

WellKnownSidType

Let’s take a look at the following enumeration WellKnownSidType, this enumeration provides commonly used security identifiers. Uhm… sounds good! Let’s try to use it in our code:

WindowsPrincipal wp = new WindowsPrincipal(WindowsIdentity.GetCurrent());
SecurityIdentifier sid = new SecurityIdentifier(WellKnownSidType.AccountDomainAdminsSid, null);
return wp.IsInRole(sid);

Do’h!It seems that we need to pass the second argument called DomainSId…

CurrentUserIsDomainAdminError

DomainSid

What the hell means DomainSId? At MSDN we can read a brief explanation: Represents the domain SID, and this value is required for some WellKnownSidType values.

At this point our goal should be know the domain SID, but wait… how can I retrieve the domain SID? After spend some time surfing the Internet, the only solution I could find was an utility called PSGetSid from Mark Russinovich inside PSTools components. If you want try it, you can download this utility and execute it from your console to know the SID of your domain (type your domain name as “microsoft.com” o “net.volvo.com”):

DomainSidConsole_thumb

However, I’m pretty sure exists a better solution to this issue. Thus, let’s try to ask to our domain their SID, using the namespace System.DirectoryServices:

Domain d = Domain.GetDomain(new DirectoryContext(DirectoryContextType.Domain, getDomainName()));
using (DirectoryEntry de = d.GetDirectoryEntry())
{
    byte[] domSid = (byte[])de.Properties["objectSid"].Value;
    string sdomainSid = sIDtoString(domSid);
    Console.WriteLine(sdomainSid);
}

Here we need a couple of auxiliar methods. The first one retrieves the domain name, and the second one retrieves a string that represents a SID value (from a byte array).

public static string getDomainName()
{
    return IPGlobalProperties.GetIPGlobalProperties().DomainName;
}

public static string sIDtoString(byte[] sidBinary)
{
    SecurityIdentifier sid = new SecurityIdentifier(sidBinary, 0);
    return sid.ToString();
}

Then, the value of sdomainSid corresponds to the SID of our domain. Great! Now, we can use it to retrieve the SID of the domain administrators role.

Putting it all together

Like my collegue and friend @alegrebandolero, I’m also a fan of extension methods. So, let’s create an extension method for the WindowsIdentity class:

using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
using System.Net.NetworkInformation;
using System.Security.Principal;

namespace TestAD
{
    public static class SecurityExtensions
    {
        public static bool IsDomainAdmin(this WindowsIdentity identity)
        {
            Domain d = Domain.GetDomain(new
                DirectoryContext(DirectoryContextType.Domain, getDomainName()));
            using (DirectoryEntry de = d.GetDirectoryEntry())
            {
                byte[] domainSIdArray = (byte[])de.Properties["objectSid"].Value;
                SecurityIdentifier domainSId = new SecurityIdentifier(domainSIdArray, 0);
                SecurityIdentifier domainAdminsSId = new SecurityIdentifier(
                WellKnownSidType.AccountDomainAdminsSid, domainSId);
                WindowsPrincipal wp = new WindowsPrincipal(identity);
                return wp.IsInRole(domainAdminsSId);
            }
        }

        private static string getDomainName()
        {
            return IPGlobalProperties.GetIPGlobalProperties().DomainName;
        }
    }
}

That’s all. Now, use it as follows:

if (WindowsIdentity.GetCurrent().IsDomainAdmin())
{
    //Some actions…
}

Edit 12/14/2010: Since Windows Vista, each Windows user have a couple of security tokens. The first one is the normal token with limited privileges, and the second one only works when you ‘run as administrator’. This code only works if you are using the second token, running the application as administrator.

HYEI, happy coding!

December 2010