• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

使用C# impersonation进行windows帐号的校验

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

一早在浏览代码时看到如下代码(我想这段代码的来源是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登陆用户的校验大致有了一点了解。


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
C#使用Quartz.NET详细讲解发布时间:2022-07-10
下一篇:
c#浅谈反射内存的处理发布时间:2022-07-10
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap