从Windows 10上本地用户启动的过程中获取域用户凭据的句柄

问题描述

背景

  • 计算机mycomputer正在运行Windows 10,并已加入域mydomain.com
  • 使用mycomputer\localuser上的本地帐户mycomputer登录用户
  • 用户还知道域帐户mydomain\domainuser的密码。
  • 服务主体名称myprotocol/domainuser已在Active Directory中注册,并映射到域帐户mydomain\domainuser
  • 不允许本地用户mycomputer\localusermydomain\domainuser身份启动进程

用户希望在本地帐户下启动服务器进程,然后该服务器进程将使用域帐户来验证与Kerberos的传入连接。

我要编写该服务器的代码

客户代码

客户端代码很简单,包括AcquireCredentialsHandle调用以及对InitializeSecurityContext调用

AcquireCredentialsHandle(
    nullptr,"Kerberos",SECPKG_CRED_OUTBOUND,nullptr,&credentials,&lifetime);
InitializeSecurityContext(
    &credentials,"myprotocol/myport",ISC_REQ_CONFIDENTIALITY,Security_NATIVE_DREP,&securityContext,&outBufferArray,&contextAttributes,&lifetime);

请注意代码段中字符串的简化用法。必须处理wchar_tconst正确性的现实有些丑陋。

还请注意,如果适当的凭据存储在控制面板的凭据管理器中,即主机名为domainuser(如此),则该代码在由本地用户启动时有效。

服务器代码

mydomain\domainuser启动该过程时,我已经有一个可以使用的代码

AcquireCredentialsHandle(
    nullptr,SECPKG_CRED_INBOUND,&lifetime);
AcceptSecurityContext(
    &credentials,&inBufferArray,attribs,&attribs,&lifetime);

但是,当服务器由mycomputer\localuser启动时,对AcquireCredentialsHandle调用失败,代码SEC_E_NO_CREDENTIALS

  • 我尝试将该调用的第一个参数修改"myprotocol/domainuser""domainuser""mydomain\domainuser"甚至"domainuser@mydomain.com"
  • 我尝试使用主机名mycomputer甚至domainuser在控制面板的凭据管理器中添加所需的凭据。

mydomain\domainuser启动的过程中如何获取mycomputer\localuser的凭证句柄?

编译代码段:

#include <string>

#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define Security_WIN32
#include <sspi.h>//Requires linking on Secur32.lib

int main(){
    CredHandle credentials;
    TimeStamp lifetime;
    std::string package="Kerberos";
    std::string principal="myprotocol/domainuser";
    auto res=AcquireCredentialsHandle(
        principal.data(),package.data(),&lifetime);
    if(res==SEC_E_OK){
        std::printf("Success\n");
        FreeCredentialsHandle(&credentials);
        return 0;}
    else{
        std::printf("Failure\n");
        return res;}}

解决方法

要获取除与当前登录会话关联的凭据以外的凭据,请在SEC_WINNT_AUTH_IDENTITY结构中填充备用安全主体的信息。使用AcquireCredentialsHandle参数将结构传递给pAuthData函数。

this micrsoft example演示了客户端调用以获取特定用户帐户的摘要凭据:

#include <windows.h>

#ifdef UNICODE
  ClientAuthID.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
#else
  ClientAuthID.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
#endif

void main()
{
    SECURITY_STATUS SecStatus; 
    TimeStamp tsLifetime; 
    CredHandle hCred;
    SEC_WINNT_AUTH_IDENTITY ClientAuthID;
    LPTSTR UserName = TEXT("ASecurityPrinciple");
    LPTSTR DomainName = TEXT("AnAuthenticatingDomain");

    // Initialize the memory.
    ZeroMemory( &ClientAuthID,sizeof(ClientAuthID) );

    // Specify string format for the ClientAuthID structure.


    // Specify an alternate user,domain and password.
      ClientAuthID.User = (unsigned char *) UserName;
      ClientAuthID.UserLength = _tcslen(UserName);

      ClientAuthID.Domain = (unsigned char *) DomainName;
      ClientAuthID.DomainLength = _tcslen(DomainName);

    // Password is an application-defined LPTSTR variable
    // containing the user password.
      ClientAuthID.Password = Password;
      ClientAuthID.PasswordLength = _tcslen(Password);

    // Get the client side credential handle.
    SecStatus = AcquireCredentialsHandle (
      NULL,// Default principal.
      WDIGEST_SP_NAME,// The Digest SSP. 
      SECPKG_CRED_OUTBOUND,// Client will use the credentials.
      NULL,// Do not specify LOGON id.
      &ClientAuthID,// User information.
      NULL,// Not used with Digest SSP.
      NULL,// Not used with Digest SSP.
      &hCred,// Receives the credential handle.
      &tsLifetime            // Receives the credential time limit.
    );
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...