0

背景:

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

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

我想编写该服务器的代码。

客户端代码:

客户端代码很简单,由一个调用组成,AcquireCredentialsHandle然后调用InitializeSecurityContext

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

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

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

服务器代码:

我已经有一个代码可以在进程启动时工作mydomain\domainuser

AcquireCredentialsHandle(
    nullptr,
    "Kerberos",
    SECPKG_CRED_INBOUND,
    nullptr,
    nullptr,
    nullptr,
    nullptr,
    &credentials,
    &lifetime);
AcceptSecurityContext(
    &credentials,
    nullptr,
    &inBufferArray,
    attribs,
    SECURITY_NATIVE_DREP,
    &securityContext,
    nullptr,
    &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(),
        SECPKG_CRED_INBOUND,
        nullptr,
        nullptr,
        nullptr,
        nullptr,
        &credentials,
        &lifetime);
    if(res==SEC_E_OK){
        std::printf("Success\n");
        FreeCredentialsHandle(&credentials);
        return 0;}
    else{
        std::printf("Failure\n");
        return res;}}
4

1 回答 1

1

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

这个 micrsoft 示例演示了获取特定用户帐户的 Digest 凭据的客户端调用:

#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.
    );
}
于 2020-09-30T09:18:04.333 回答