zoukankan      html  css  js  c++  java
  • 使用C# impersonation进行windows帐号的校验

    一早在浏览代码时看到如下代码(我想这段代码的来源是kb306158),这段代码的作用是,当一个通过Active Directory账号登陆系统的用户,需要上传、创建目录、下载时,需要先校验该用户是否具有目录操作权限, 代码如下:

    public const int LOGON32_LOGON_INTERACTIVE = 2;
    public const int LOGON32_PROVIDER_DEFAULT = 0;
    private string _logOnUsername;
    private string _logOnDomain;
    private string _logOnPassword;
    
    WindowsImpersonationContext impersonationContext;
    
    // to check whether the acct info input is a logoned one, 
    // if past the validation, output a token 
    [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
    public static extern int LogonUser(String lpszUserName,
        String lpszDomain,
        String lpszPassword,
        int dwLogonType,
        int dwLogonProvider,
        ref IntPtr phToken);
    
    // create a new token derived from the input token
    [DllImport("advapi32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto,
            SetLastError = true)]
    public extern static int DuplicateToken(IntPtr hToken,
        int impersonationLevel,
        ref IntPtr hNewToken);
    
    // to impersonate
    private bool impersonateValidUser(String userName, String domain, String password)
    {
        WindowsIdentity tempWindowsIdentity;
        IntPtr token = IntPtr.Zero;
        IntPtr tokenDuplicate = IntPtr.Zero;
    
        // validate whether logoned on with the supplied parameters
        if (LogonUser(userName, domain, password, LOGON32_LOGON_INTERACTIVE,
            LOGON32_PROVIDER_DEFAULT, ref token) != 0)
        {
    	 // SecurityImpersonation
    	 // The server can impersonate the client's security context on the local system.
    	 if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
            {
                tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
                impersonationContext = tempWindowsIdentity.Impersonate();
                if (impersonationContext != null)
                    return true;
                else
                    return false;
            }
            else
                return false;
        }
        else
            return false;
    }
    
    private void undoImpersonation()
    {
        impersonationContext.Undo();
    }
    
    // the parameters' value are all kept in web.config,
    // it's a fixed account, not current logined user's acct.
    public FileAccess(string logonDomain, string logonUsername, string logonPassword)
    {
        _logOnDomain = logonDomain;
        _logOnUsername = logonUsername;
        _logOnPassword = logonPassword;
    }
    
    public bool FileExists(string filePathName)
    {
        if (impersonateValidUser(_logOnUsername, _logOnDomain, _logOnPassword))
        {
            try
            {
                if (File.Exists(filePathName))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            finally
            {
                undoImpersonation();
            }
        }
        else
        {
            throw (new Exception("Failed in impersonation."));
        }
    }


    代码中使用FileAccess进行对象初始化,其中logonDomain,logonUserName,logonPWD均被配置于web.config中。使用impersonateValidUser方法校验目录操作权限,

    Q: 为什么需要DuplicateToken

    A: 先要了解进行Windows校验所需要的一点基础,文中认为使用LogonUser后拿到的token是当前用户的,我们不能用它来创建对象或是做别的什么事,这样不安全,所以应该使用如下两种中的一种来创建被复制的新token,

    > SecurityImpersonation    The server can impersonate the client's security context on the local system.

    > SecurityDelegation    The server can impersonate the client's security context on remote systems.

    At the SecurityImpersonation level, most of the thread's actions occur in the security context of the thread's impersonation token rather than in the primary token of the process that owns the thread. For example, if an impersonating thread opens a securable object, the system uses the impersonation token to check the thread's access. Similarly, if an impersonating thread creates a new object, for example by calling the CreateFile function, the owner of the new object is the default owner from the client's access token.

    Q: 这个被模拟的用户(即此处的FileAccess中传入的帐号信息)的权限应该设置为什么?

    A: 在KB306158中,已经给出如下解决方案

    > 为 ASPNET 帐户授予“作为操作系统的一部分”权限。(注意:我们不建议使用这种方法解决此问题。)

    > 在 Machine.config 文件的 <processModel> 配置节中,将运行 Aspnet_wp.exe 进程所使用的帐户更改为 System 帐户。

    在此贴中,这位大牛提出了这个问题,他认为无论是使用LogonUser还是使用System.DiretoryServices都是不完美的,有漏洞的。比如LogonUser必须会提供一个有SE_CHANGE_NOTIFY_NAME权限的账号,这个比较麻烦,使用DirectoryServices则需要查看AD属性,并认为这种方式会在客户端留下AD scheme的缓存,代价太大不划算,且GetLastError捕捉的异常也并不能100%定位是否是用户校验未通过,见下面这段代码。

    // create a "principal context" - e.g. your domain (could be machine, too)
    using(PrincipalContext pc = new PrincipalContext(ContextType.Domain, "YOURDOMAIN"))
    {
        // validate the credentials
        bool isValid = pc.ValidateCredentials("myuser", "mypassword")
    }

    还可以进行一些延伸阅读 See also:

    1. Create a Web Service Method to Manage a NT Service
    2. 微软KB306158:How to implement impersonation in an ASP.NET application (可自行将en-us改成zh-cn转向中文版)
    3. 关于etern关键字和DLLImport
    4. DuplicateToken Function
    5. WindowsIdentity
    6. impersonationContext.Undo()
    7. WindowsIdentity.Impersonate Method ()

    我觉得到了这一步,我已经对windows/AD登陆用户的校验大致有了一点了解。

  • 相关阅读:
    java 的 CopyOnWriteArrayList类
    AtomicInteger类的简单应用
    关于java的关键字 transient
    关于ArrayList的一些源码分析
    Eclipse新建java类的时候,自动创建注释
    关于spring-data-jpa的排序问题
    hibernate CascadeType属性
    springBoot框架不同环境读取不同的配置文件
    你迷茫的原因在于读书太少而想的太多!!!
    学历是铜牌,能力是银牌,人脉是金牌,思维是王牌
  • 原文地址:https://www.cnblogs.com/syveen/p/1972265.html
Copyright © 2011-2022 走看看