通过桌面应用程序中的VPN模拟用户

时间:2019-06-04 17:39:18

标签: c# active-directory vpn impersonation network-security

在模拟桌面应用程序中的活动目录用户时遇到问题。每次我使用LogOn API时,结果均为false。

用户和域确实存在,因为我还可以通过同一应用程序上的DirectoryServices.AccountManagement对用户进行身份验证。

已经阅读了Microsoft网站上有关假冒的文档,甚至在堆栈上还有一些文章。另外,使用SimpleImpersonation库的结果相同。

public class Demo
{
    private WindowsImpersonationContext impersonationContext = null;

    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern int LogonUser(string lpszUserName, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern int DuplicateToken(IntPtr hToken, int impersonationLevel, ref IntPtr hNewToken);
    private void Enter()
    {
        try
        {
            IntPtr token = IntPtr.Zero;
            IntPtr tokenDuplicate = IntPtr.Zero;
            string userName = "myValidUser";
            string domain = "my.domain.example";
            string password = "myValidPassword";

            if (LogonUser(userName, domain, password, (int)LogonType.LOGON32_LOGON_INTERACTIVE, (int)LogonProvider.LOGON32_PROVIDER_WINNT35, ref token) != 0)
            {
                WindowsIdentity WindowsIdentityPrincipal = new WindowsIdentity(token);
                if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
                {
                    WindowsIdentity tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
                    impersonationContext = tempWindowsIdentity.Impersonate();
                }
                else
                {
                    throw new Win32Exception(new Win32Exception(Marshal.GetLastWin32Error()).Message);
                }
            }
            else
            {
                //throws username or pass incorrect
                throw new Win32Exception(new Win32Exception(Marshal.GetLastWin32Error()).Message);
            }
        }
        catch (Exception exc)
        {
            throw exc;
        }
    }

    public enum LogonProvider
    {
        LOGON32_PROVIDER_DEFAULT = 0,
        LOGON32_PROVIDER_WINNT35 = 1,
        LOGON32_PROVIDER_WINNT40 = 2,
        LOGON32_PROVIDER_WINNT50 = 3
    }

    private enum LogonType
    {
        LOGON32_LOGON_INTERACTIVE = 2,
        LOGON32_LOGON_NETWORK = 3,
        LOGON32_LOGON_BATCH = 4,
        LOGON32_LOGON_SERVICE = 5,
        LOGON32_LOGON_UNLOCK = 7,
        LOGON32_LOGON_NETWORK_CLEARTEXT = 8,
        LOGON32_LOGON_NEW_CREDENTIALS = 9,
    }
}

我不知道它不起作用的原因是否是我的计算机正在外部网络上运行并通过VPN连接/认证到公司网络。

  

编辑1.结果错误代码为1326(用户名未知或错误)   密码)

     

编辑2。该方法正在尝试获取标识令牌,以备后用   用于线程模拟。

2 个答案:

答案 0 :(得分:0)

您可能想查看LogonUser function的文档。

如果您的用户名格式为user@domain.example,则需要传递:

  • lpszUserName = "user@domain.example"
  • lpszDomain = null

如果您的用户名格式为domain\user,则需要传递:

  • lpszUserName = "user"
  • lpszDomain = "domain"

用错误的方式处理完全合格的用户名会导致您看到错误代码。

答案 1 :(得分:-1)

您不能使用 LogonUser 登录到远程计算机。您需要使用 WNetAddConnection2 API函数。请参阅msdn文档。

LogonUser: https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-logonuserw

对于WNetAddConnection2: https://docs.microsoft.com/en-us/windows/desktop/api/winnetwk/nf-winnetwk-wnetaddconnection2w

这是我写的一堂课:

public class RemoteNetworkConnector : IDisposable
{
    readonly string _networkName;

    public RemoteNetworkConnector(string networkName, NetworkCredential credentials)
    {
        _networkName = networkName;

        NetResource netResource = new NetResource
        {
            Scope = ResourceScope.GlobalNetwork,
            ResourceType = ResourceType.Disk,
            DisplayType = ResourceDisplaytype.Share,
            RemoteName = networkName
        };

        var userName = string.IsNullOrEmpty(credentials.Domain)
            ? credentials.UserName
            : string.Format(@"{0}\{1}", credentials.Domain, credentials.UserName);

        var connectionResult = WNetAddConnection2(
            netResource,
            credentials.Password,
            userName,
            0);

        if (connectionResult != 0)
        {
            throw new Win32Exception(connectionResult, "Error connecting to remote share");
        }
    }

    ~RemoteNetworkConnector()
    {
        Dispose(false);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        WNetCancelConnection2(_networkName, 0, true);
    }

    [DllImport("mpr.dll")]
    private static extern int WNetAddConnection2(NetResource netResource,
        string password, string username, int flags);

    [DllImport("mpr.dll")]
    private static extern int WNetCancelConnection2(string name, int flags,
        bool force);

    [StructLayout(LayoutKind.Sequential)]
    public class NetResource
    {
        public ResourceScope Scope;
        public ResourceType ResourceType;
        public ResourceDisplaytype DisplayType;
        public int Usage;
        public string LocalName;
        public string RemoteName;
        public string Comment;
        public string Provider;
    }

    public enum ResourceScope : int
    {
        Connected = 1,
        GlobalNetwork,
        Remembered,
        Recent,
        Context
    };

    public enum ResourceType : int
    {
        Any = 0,
        Disk = 1,
        Print = 2,
        Reserved = 8,
    }

    public enum ResourceDisplaytype : int
    {
        Generic = 0x0,
        Domain = 0x01,
        Server = 0x02,
        Share = 0x03,
        File = 0x04,
        Group = 0x05,
        Network = 0x06,
        Root = 0x07,
        Shareadmin = 0x08,
        Directory = 0x09,
        Tree = 0x0a,
        Ndscontainer = 0x0b
    }
}

我希望这会有所帮助。