I can check is user domain administrator with next lines of code:
using (Impersonation im = new Impersonation(UserName, Domain, Password))
{
System.Security.Principal.WindowsIdentity identity = System.Security.Principal.WindowsIdentity.GetCurrent();
bool isDomainAdmin = identity.IsDomainAdmin(Domain, UserName, Password);
if (!isDomainAdmin)
{
//deny access, for example
}
}
where IsDomainAdmin - is extension method
public static bool IsDomainAdmin(this WindowsIdentity identity, string domain, string userName, string password)
{
Domain d = Domain.GetDomain(new DirectoryContext(DirectoryContextType.Domain, domain, userName, password));
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);
}
}
But, when method IsDomainAdmin is called, it is trying to write some files to the %LOCALAPPDATA% for impersonated user, and if program is runnig not as administrator, it throws an exception
Could not load file or assembly 'System.DirectoryServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. Either a required impersonation level was not provided, or the provided impersonation level is invalid. (Exception from HRESULT: 0x80070542)
You certainly don't need a user's password to verify if the user is a member of a group. So why don't you just query AD in a straight-forward manner using DirectoryEntry or DirectorySearcher? If you also need to verify that the password supplied is correct you can do that in an additional step using PrincipalContext.ValidateCredentials. (See PrincipalContext.ValidateCredentials Method (String, String)).
static void Main(string[] args) {
string userDomain = "somedomain";
string userName = "username";
string password = "apassword";
if (IsDomainAdmin(userDomain, userName)) {
string fullUserName = userDomain + @"\" + userName;
PrincipalContext context = new PrincipalContext(
ContextType.Domain, userDomain);
if (context.ValidateCredentials(fullUserName, password)) {
Console.WriteLine("Success!");
}
}
}
public static bool IsDomainAdmin(string domain, string userName) {
string adminDn = GetAdminDn(domain);
SearchResult result = (new DirectorySearcher(
new DirectoryEntry("LDAP://" + domain),
"(&(objectCategory=user)(samAccountName=" + userName + "))",
new[] { "memberOf" })).FindOne();
return result.Properties["memberOf"].Contains(adminDn);
}
public static string GetAdminDn(string domain) {
return (string)(new DirectorySearcher(
new DirectoryEntry("LDAP://" + domain),
"(&(objectCategory=group)(cn=Domain Admins))")
.FindOne().Properties["distinguishedname"][0]);
}
We are modified @jmh_gr answer, and it seems to become independent from "Domain Admins" group name.
static string BuildOctetString(SecurityIdentifier sid)
{
byte[] items = new byte[sid.BinaryLength];
sid.GetBinaryForm(items, 0);
StringBuilder sb = new StringBuilder();
foreach (byte b in items)
{
sb.Append(b.ToString("X2"));
}
return sb.ToString();
}
public static bool IsDomainAdmin(string domain, string userName)
{
using (DirectoryEntry domainEntry = new DirectoryEntry(string.Format("LDAP://{0}", domain)))
{
byte[] domainSIdArray = (byte[])domainEntry.Properties["objectSid"].Value;
SecurityIdentifier domainSId = new SecurityIdentifier(domainSIdArray, 0);
SecurityIdentifier domainAdminsSId = new SecurityIdentifier(WellKnownSidType.AccountDomainAdminsSid, domainSId);
using (DirectoryEntry groupEntry = new DirectoryEntry(string.Format("LDAP://<SID={0}>", BuildOctetString(domainAdminsSId))))
{
string adminDn = groupEntry.Properties["distinguishedname"].Value as string;
SearchResult result = (new DirectorySearcher(domainEntry, string.Format("(&(objectCategory=user)(samAccountName={0}))", userName), new[] { "memberOf" })).FindOne();
return result.Properties["memberOf"].Contains(adminDn);
}
}
}
Anyway, thanks to @jmh_gr for the answer.
Using this code by @lluisfranco
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
using System.Net.NetworkInformation;
using System.Security.Principal;
namespace Alpha.Code
{
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[] bdomSid = (byte[])de.Properties["objectSid"].Value;
string sdomainSid = sIDtoString(bdomSid);
WindowsPrincipal wp = new WindowsPrincipal(identity);
SecurityIdentifier dsid = new SecurityIdentifier(sdomainSid);
SecurityIdentifier dasid = new SecurityIdentifier(
WellKnownSidType.AccountDomainAdminsSid, dsid);
return wp.IsInRole(dasid);
}
}
public static string getDomainName()
{
return IPGlobalProperties.GetIPGlobalProperties().DomainName;
}
public static string sIDtoString(byte[] sidBinary)
{
SecurityIdentifier sid = new SecurityIdentifier(sidBinary, 0);
return sid.ToString();
}
}
}
Usage sample:
if (WindowsIdentity.GetCurrent().IsDomainAdmin())
{
//Actions to do if user is domain admin
}
User contributions licensed under CC BY-SA 3.0