Client/Server 应用程序,如何在不将该用户 username/password 转移到远程系统的情况下以域用户身份在远程系统上创建进程?

Client/Server app, how to create process on remote system as a domain user without transferring that users username/password to the remote system?

我有两个系统,都是 运行 我的 C# client/server 软件代码。我想从计算机 1 创建一个进程作为计算机 2 上给定的 Active Directory 域用户,而不必让我的 client/server 软件将 AD 用户的纯文本用户名和密码从计算机 1 发送到计算机 2。

我得到的最接近结果似乎是我可以在计算机 1 上使用函数 KerberosRequestorSecurityToken 来生成一个 kerberos 票证,然后通过我的 client/server 代码将该字节 [] 结果发送到计算机 2 它应该在哪里然后能够针对传递的 byte[] kerberos 票证调用 KerberosReceiverSecurityToken。如果一切正常,那么 KerberosReceiverSecurityToken 将有一个 WindowsIdentity 属性,然后我可以使用它在计算机 2 上创建一个进程,用户帐户最初是通过 KerberosRequestorSecurityToken 流程在计算机 1 上指定的。

我需要使用我想要模拟的现有域用户帐户,而不是注册服务帐户 SPN。这是我最初发布问题时没有提到的问题的症结所在。

我似乎无法让它工作,但更重要的是我什至不知道这是否真的可行 - 例如这些 API 是否应该允许我做我想做的事?

计算机 1 生成 kerberos 票据的代码。 byte[] 结果通过我的 client/server 应用程序发送到计算机 2。

public static byte[] GetRequestToken(string userName, string password, string domain)
{
    using (var domainContext = new PrincipalContext(ContextType.Domain, domain))
    {
        using (var foundUser = UserPrincipal.FindByIdentity(domainContext, IdentityType.SamAccountName, userName))
        {
            Console.WriteLine("User Principal name" + UserPrincipal.FindByIdentity(domainContext, IdentityType.SamAccountName, userName).UserPrincipalName);
            string spn = UserPrincipal.FindByIdentity(domainContext, IdentityType.SamAccountName, userName).UserPrincipalName;
            KerberosSecurityTokenProvider k1 = new KerberosSecurityTokenProvider(spn, TokenImpersonationLevel.Impersonation, new NetworkCredential(userName, password, domain));
            KerberosRequestorSecurityToken T1 = k1.GetToken(TimeSpan.FromMinutes(1)) as KerberosRequestorSecurityToken;
            var req = T1.GetRequest();
            return req;
        }
    }
}

计算机 2 获取生成的 byte[] kerberos 票证并尝试接收它以访问 WindowsIdentity,但它抛出异常,提示登录无效。

KerberosReceiverSecurityToken receiverToken = new KerberosReceiverSecurityToken(requestToken);
byte[] receiverTokenTicket = receiverToken.GetRequest();

//Identity for impersonation
var impersonatedIdentity = receiverToken.WindowsIdentity;

第一段代码的来源在功能上是错误的。 SPN 必须是接收票证的目标,而不是请求票证的用户。所以你需要做以下事情...

  1. 在 AD 中注册一个服务主体帐户 (user/computer)。
  2. 向该帐户添加一个服务主体名称,格式为 foo/host.domain.com,其中 foo 是您的服务名称,例如httphost,或 myapp
  3. 客户需要申请 foo/host.domain.com
  4. 的票证
  5. KerberosReceiverSecurityToken 应该解析 that ticket

现在您拥有了某种不同模拟级别的身份。该模拟级别决定您是否可以作为该用户启动进程。碰巧……你就是做不到,因为那不是 Windows 安全工作的方式。你有一个模拟 NT 令牌,因为你正在模拟一个用户,而你需要一个主 NT 令牌来启动进程。

因此您需要使用 DuplicateTokenEx 将其转换为主要令牌,并且您实际上需要成为 SYSTEM 才能执行此操作。

获得主令牌后,您可以调用 CreateProcessAsUser

此时您可能已经以用户身份启动了该进程,但它没有任何凭据来访问网络共享或 Web 服务等其他网络属性。为此,您可以在服务主体上启用对任何下游服务的约束委派。

另一种可能更安全、更容易的选择是将工作进程作为低权限用户启动,并告诉 那个 进程进行模拟。请参阅