2014-10-01 106 views
1

我需要检查用户是否是运行该应用程序的机器上的管理员。基本上,用户可能会从另一台机器提供用户名,密码和域名。这些通过WCF传输,在这个阶段我需要验证提供的用户名,密码和域是否具有该机器的管理权限。这意味着没有必要使用WMI,因为一切都是在本地发生的(用户只需通过WCF发送用户名,密码,域作为字符串)如何检查用户是否是该机器上的管理员

用户可以位于域上,因此可以链接到Active Directory,但也可以是本地用户,这意味着我无法回复从Active Directory中查找它。

我设法模拟用户,并可以验证此用户是本地组中的管理员。我使用下面的命令测试了这个:

net localgroup administrators 

我现在正在用当前模拟用户创建一个WindowsPrincipal。但是,在检查此用户是否为管理员时,我收到了错误信息。这里是重要的代码:

// obtains user token 
[DllImport("advapi32.dll", SetLastError=true)] 
public static extern bool LogonUser(string pszUsername, string pszDomain, string pszPassword, 
    int dwLogonType, int dwLogonProvider, ref IntPtr phToken); 

// closes open handes returned by LogonUser 
[DllImport("kernel32.dll", CharSet=CharSet.Auto)] 
public extern static bool CloseHandle(IntPtr handle); 

// creates duplicate token handle 
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)] 
public extern static bool DuplicateToken(IntPtr ExistingTokenHandle, 
    int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle); 

bool bImpersonated = LogonUser(sUsername, sDomain, sPassword, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref pExistingTokenHandle); 

bool bRetVal = DuplicateToken(pExistingTokenHandle, (int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, ref pDuplicateTokenHandle); 

WindowsIdentity newId = new WindowsIdentity(pDuplicateTokenHandle); 
WindowsImpersonationContext impersonatedUser = newId.Impersonate(); 
WindowsPrincipal wp = new WindowsPrincipal(WindowsIdentity.GetCurrent()); 

if (wp.IsInRole(WindowsBuiltInRole.Administrator)) 
{ 
    //is admin 
} 
else 
{ 
    //is not an admin (I am still getting this when user is an admin) 
} 

bImpersonated返回true(因此模拟工作) bRetVal也会返回true。(因此令牌是有效的)

的模拟代码是从here(除了管理员检查)

任何帮助将不胜感激。

+0

模仿用户,然后获取活动主体,再检查'IsInRole'? – 2014-10-01 17:23:52

+0

@PeterRitchie这看起来不错,但由于某些原因,IsInRole(WindowsBuiltInRole.Administrator)总是返回false(对于本地帐户和域帐户)。有任何想法吗? – seedg 2014-10-02 07:30:56

+0

你有没有试过[这](http://stackoverflow.com/questions/1089046/in-net-c-test-if-user-is-an-administrative-user)? – 2014-10-02 09:58:58

回答

1

我使用支票通过令牌:

private static Boolean IsAdministratorByToken(WindowsIdentity identity) 
{ 
    WindowsPrincipal principal = new WindowsPrincipal(identity); 

    // Check if this user has the Administrator role. If they do, return immediately. 
    // If UAC is on, and the process is not elevated, then this will actually return false. 
    if (principal.IsInRole(WindowsBuiltInRole.Administrator)) 
    { 
     return true; 
    } 

    // If we're not running in Vista onwards, we don't have to worry about checking for UAC. 
    if (Environment.OSVersion.Platform != PlatformID.Win32NT || Environment.OSVersion.Version.Major < 6) 
    { 
     // Operating system does not support UAC; skipping elevation check. 
     return false; 
    } 

    int tokenInfLength = Marshal.SizeOf(typeof(int)); 
    IntPtr tokenInformation = Marshal.AllocHGlobal(tokenInfLength); 

    try 
    { 
     IntPtr token = identity.Token; 
     Boolean result = NativeMethods.GetTokenInformation(token, NativeMethods.TokenInformationClass.TokenElevationType, tokenInformation, tokenInfLength, out tokenInfLength); 

     if (!result) 
     { 
      Exception exception = Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error()); 
      throw new InvalidOperationException("Couldn't get token information", exception); 
     } 

     NativeMethods.TokenElevationType elevationType = (NativeMethods.TokenElevationType)Marshal.ReadInt32(tokenInformation); 

     switch (elevationType) 
     { 
      case NativeMethods.TokenElevationType.TokenElevationTypeDefault: 
       // TokenElevationTypeDefault - User is not using a split token, so they cannot elevate. 
       return false; 

      case NativeMethods.TokenElevationType.TokenElevationTypeFull: 
       // TokenElevationTypeFull - User has a split token, and the process is running elevated. Assuming they're an administrator. 
       return true; 

      case NativeMethods.TokenElevationType.TokenElevationTypeLimited: 
       // TokenElevationTypeLimited - User has a split token, but the process is not running elevated. Assuming they're an administrator. 
       return true; 

      default: 
       // Unknown token elevation type. 
       return false; 
     } 
    } 
    finally 
    { 
     if (tokenInformation != IntPtr.Zero) 
     { 
      Marshal.FreeHGlobal(tokenInformation); 
     } 
    } 
} 

这是来自this blog

您也可以使用PrincipalContext进行检查,但如果服务器服务未运行,则此解决方案不起作用。

0

来自Xaruth的代码对于TokenElevationTypeLimited是错误的,在这种情况下,您应该返回false,并且在管理员中构建您将获得TokenElevationTypeDefault,因此在这种情况下,请检查用户是否是admin,而不是仅返回false。 下面是这篇文章的代码: https://candritzky.wordpress.com/2012/08/28/uac-elevation-and-the-default-administrator-account/

/// <summary> 
/// Base on code found here: 
/// http://stackoverflow.com/questions/1220213/c-detect-if-running-with-elevated-privileges 
/// </summary> 
public static class UacHelper 
{ 
    private const string uacRegistryKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"; 
    private const string uacRegistryValue = "EnableLUA"; 

    private const uint STANDARD_RIGHTS_READ = 0x00020000; 
    private const uint TOKEN_QUERY = 0x0008; 
    private const uint TOKEN_READ = (STANDARD_RIGHTS_READ | TOKEN_QUERY); 

    [DllImport("advapi32.dll", SetLastError = true)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    static extern bool OpenProcessToken(IntPtr ProcessHandle, UInt32 DesiredAccess, out IntPtr TokenHandle); 

    [DllImport("advapi32.dll", SetLastError = true)] 
    public static extern bool GetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, 
     IntPtr TokenInformation, uint TokenInformationLength, 
     out uint ReturnLength); 

    public enum TOKEN_INFORMATION_CLASS 
    { 
     TokenUser = 1, 
     TokenGroups, 
     TokenPrivileges, 
     TokenOwner, 
     TokenPrimaryGroup, 
     TokenDefaultDacl, 
     TokenSource, 
     TokenType, 
     TokenImpersonationLevel, 
     TokenStatistics, 
     TokenRestrictedSids, 
     TokenSessionId, 
     TokenGroupsAndPrivileges, 
     TokenSessionReference, 
     TokenSandBoxInert, 
     TokenAuditPolicy, 
     TokenOrigin, 
     TokenElevationType, 
     TokenLinkedToken, 
     TokenElevation, 
     TokenHasRestrictions, 
     TokenAccessInformation, 
     TokenVirtualizationAllowed, 
     TokenVirtualizationEnabled, 
     TokenIntegrityLevel, 
     TokenUIAccess, 
     TokenMandatoryPolicy, 
     TokenLogonSid, 
     MaxTokenInfoClass 
    } 

    public enum TOKEN_ELEVATION_TYPE 
    { 
     TokenElevationTypeDefault = 1, 
     TokenElevationTypeFull, 
     TokenElevationTypeLimited 
    } 

    private static bool? _isUacEnabled; 

    public static bool IsUacEnabled 
    { 
     get 
     { 
      if (_isUacEnabled == null) 
      { 
       var uacKey = Registry.LocalMachine.OpenSubKey(uacRegistryKey, false); 
       if (uacKey == null) 
       { 
        _isUacEnabled = false; 
       } 
       else 
       { 
        var enableLua = uacKey.GetValue(uacRegistryValue); 
        _isUacEnabled = enableLua.Equals(1); 
       } 
      } 
      return _isUacEnabled.Value; 
     } 
    } 

    private static bool? _isAdministrator; 

    public static bool IsAdministrator 
    { 
     get 
     { 
      if (_isAdministrator == null) 
      { 
       var identity = WindowsIdentity.GetCurrent(); 
       Debug.Assert(identity != null); 
       var principal = new WindowsPrincipal(identity); 
       _isAdministrator = principal.IsInRole(WindowsBuiltInRole.Administrator); 
      } 
      return _isAdministrator.Value; 
     } 
    } 

    private static bool? _isProcessElevated; 

    public static bool IsProcessElevated 
    { 
     get 
     { 
      if (_isProcessElevated == null) 
      { 
       if (IsUacEnabled) 
       { 
        var process = Process.GetCurrentProcess(); 

        IntPtr tokenHandle; 
        if (!OpenProcessToken(process.Handle, TOKEN_READ, out tokenHandle)) 
        { 
         throw new ApplicationException("Could not get process token. Win32 Error Code: " + 
                 Marshal.GetLastWin32Error()); 
        } 

        var elevationResult = TOKEN_ELEVATION_TYPE.TokenElevationTypeDefault; 

        var elevationResultSize = Marshal.SizeOf((int) elevationResult); 
        uint returnedSize; 
        var elevationTypePtr = Marshal.AllocHGlobal(elevationResultSize); 

        var success = GetTokenInformation(tokenHandle, TOKEN_INFORMATION_CLASS.TokenElevationType, 
         elevationTypePtr, (uint) elevationResultSize, out returnedSize); 
        if (!success) 
        { 
         Marshal.FreeHGlobal(elevationTypePtr); 
         throw new ApplicationException("Unable to determine the current elevation."); 
        } 

        elevationResult = (TOKEN_ELEVATION_TYPE) Marshal.ReadInt32(elevationTypePtr); 
        Marshal.FreeHGlobal(elevationTypePtr); 

        // Special test for TokenElevationTypeDefault. 
        // If the current user is the default Administrator, then the 
        // process is also assumed to run elevated. This is assumed 
        // because by default the default Administrator (which is disabled by default) 
        // gets all access rights even without showing a UAC prompt. 
        switch (elevationResult) 
        { 
         case TOKEN_ELEVATION_TYPE.TokenElevationTypeFull: 
          _isProcessElevated = true; 
          break; 
         case TOKEN_ELEVATION_TYPE.TokenElevationTypeLimited: 
          _isProcessElevated = false; 
          break; 
         default: 
          // Will come here if either 
          // 1. We are running as the default Administrator. 
          // 2. We were started using "Run as administrator" from a non-admin 
          // account and logged on as the default Administrator account from 
          // the list of available Administrator accounts. 
          // 
          // Note: By default the default Administrator account always behaves 
          //  as if UAC was turned off. 
          // 
          // This can be controlled through the Local Security Policy editor 
          // (secpol.msc) using the 
          // "User Account Control: Use Admin Approval Mode for the built-in Administrator account" 
          // option of the Security Settings\Local Policies\Security Options branch. 
          _isProcessElevated = IsAdministrator; 
          break; 
        } 
       } 
       else 
       { 
        _isProcessElevated = IsAdministrator; 
       } 
      } 
      return _isProcessElevated.Value; 
     } 
    } 
}