背景:
- 计算机
mycomputer
正在运行Windows 10,并且已加入域mydomain.com
- 用户在
mycomputer
上使用本地帐户mycomputerlocaluser
登录 - 用户还知道域帐户
mydomaindomainuser
的密码 - 服务主体名称
myprotocol/domainuser
在Active Directory中注册,并映射到域帐户mydomaindomainuser
- 不允许本地用户
mycomputerlocaluser
以mydomaindomainuser
的身份启动进程
用户希望在本地帐户下启动服务器进程,然后使用域帐户使用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_t
和const
正确性的现实有些丑陋。
还要注意,如果适当的凭据存储在控制面板的凭据管理器中,即主机名为domainuser
(原文如此(的,则本地用户启动此代码时,此代码即可工作
服务器代码:
我已经有了一个代码,当进程由mydomaindomainuser
:启动时可以工作
AcquireCredentialsHandle(
nullptr,
"Kerberos",
SECPKG_CRED_INBOUND,
nullptr,
nullptr,
nullptr,
nullptr,
&credentials,
&lifetime);
AcceptSecurityContext(
&credentials,
nullptr,
&inBufferArray,
attribs,
SECURITY_NATIVE_DREP,
&securityContext,
nullptr,
&attribs,
&lifetime);
但当mycomputerlocaluser
启动服务器时,对AcquireCredentialsHandle
的调用失败,代码为SEC_E_NO_CREDENTIALS
。
- 我尝试将该调用的第一个参数修改为
"myprotocol/domainuser"
、"domainuser"
、"mydomaindomainuser"
甚至"domainuser@mydomain.com"
- 我尝试使用主机名
mycomputer
甚至domainuser
在控制面板的凭据管理器中添加所需的凭据
在mycomputerlocaluser
启动的进程中,我可以做些什么来获取mydomaindomainuser
的凭据句柄
编译代码片段:
#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("Successn");
FreeCredentialsHandle(&credentials);
return 0;}
else{
std::printf("Failuren");
return res;}}
要获得与当前登录会话关联的凭据以外的凭据,请使用备用安全主体的信息填充SEC_WINNT_AUTH_IDENTITY
结构。使用pAuthData
参数将结构传递给AcquireCredentialsHandle
函数。
这个micrsoft示例演示了一个客户端调用,以获取特定用户帐户的摘要凭据:
#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.
);
}