如何使用SSPI从Kerberos获取服务令牌

5

目标: 我正在尝试构建一个Proof Of Concept客户端应用程序,通过使用SSPI实现单点登录。我对C#还不熟悉,感到有些困惑。

我的了解和已经做的事情: 所有用户都是Active Directory域的一部分,因此我知道在登录期间使用Kerberos进行身份验证。在这个阶段,我所需要做的就是从Kerberos获取服务令牌,以便我可以将其传递给服务资源,而不是用户名和密码(如果我错了,请纠正我)。我已经收到了已经在Kerberos中注册为服务的服务主体名称(SPN)和密码。

我希望不必使用平台调用服务来调用SSPI函数,但如果我必须这样做,我会使用它。我阅读了“.NET Remoting Authentication and Authorization Sample - Part I”,并使用Microsoft.Samples.Security.SSPI进行测试。我还尝试使用C#/.Net Interface To The Win32 SSPI Authentication API

到目前为止,我可以获得用户/客户端凭据,构建客户端安全上下文。但是我如何为给定的SPN请求服务票证?

我将非常感谢您的帮助和指导。如果可能,请具体说明,并让我知道您是否有任何问题。


“.NET Remoting身份验证和授权示例 - 第一部分”的链接为“https://msdn.microsoft.com/en-us/library/ms973911.aspx”。我现在无法在主体问题中添加超过两个链接。” - Furkat Kholmatov
你将使用哪种线协议进行通讯?自定义还是标准的? - Michael-O
标准。我们不使用任何自定义协议。 - Furkat Kholmatov
我猜我不确定你的意思或者它有什么关系。我将使用TCP/UDP作为传输层。用户使用Windows进行身份验证,因此他们应该已经拥有可用的TGT。如何获取当前活动的TGT并请求特定服务的票证?我不确定电线协议的重要性。你能解释一下吗? - Furkat Kholmatov
我已经阅读了已接受答案的建议,并使用了antiduh创建的包装器,它是我问题中的第二个链接。不幸的是,由于我的声望几乎不存在,我无法在那里发表评论。 - Furkat Kholmatov
显示剩余3条评论
2个回答

3
您可以使用以下内容通过提供SPN来获取令牌。
  public String getToken(string userName)
    {
     using (var domainContext = new PrincipalContext(ContextType.Domain, "domain"))
        {
          using (var foundUser = UserPrincipal.FindByIdentity(domainContext, IdentityType.SamAccountName, userName))
            {
                Console.WriteLine("User Principale name" + UserPrincipal.FindByIdentity(domainContext, IdentityType.SamAccountName, userName).UserPrincipalName);
                string spn = UserPrincipal.FindByIdentity(domainContext, IdentityType.SamAccountName, userName).UserPrincipalName;
                KerberosSecurityTokenProvider k1 = new KerberosSecurityTokenProvider(spn, System.Security.Principal.TokenImpersonationLevel.Impersonation, new System.Net.NetworkCredential(userName, "password", "domain"));
                KerberosRequestorSecurityToken T1 = k1.GetToken(TimeSpan.FromMinutes(1)) as KerberosRequestorSecurityToken;
                string sret = Convert.ToBase64String(T1.GetRequest());
                Console.WriteLine("=====sret========" + sret);
                return sret;
            }
        }

    }

谢谢您的回答,您能否详细说明以下内容?使用Kerberos需要执行3个主要步骤。第一步是验证客户端并获取票据授权票证。第二步是使用票据授权票证请求服务的票证,第三步是让服务验证客户端为其请求的票证。对于上面的代码示例,我感到困惑,因为用户名变量用于foundUser和spn。您能否详细说明答案,并指定哪一个是真正的客户端用户和服务用户? - Furkat Kholmatov
嗨,上面的代码说明了如何获取给定spn的票证。这里的用户名是AD用户的登录名,并且使用该方法将创建spn作为登录名@domain。通过使用该spn,您可以生成票证。我也正在执行同样类型的任务,并且我正在遵循C#/.Net接口到Win32 SSPI身份验证API。我也可以使用nsspi获取TGT,并正在寻找一种获取SGT的方法 :) - Hasanthi
2
对于所有复制上述代码的人,请注意,spn在其当前形式下是没有用处的。 spn的目的是指示您要向哪个服务证明身份验证,并且获得自己的spn票据提供了非常少的价值。 如果您的spn值采用user@realm的形式,则很可能是错误的,而应该是foo/service.domainfoo/service.domain@realm - Steve
相较于使用 SSPI,这种方法有什么缺点吗? - neelesh bodgal

3

Hasanthi提供的代码完美地满足了我的需求,我不需要使用SSPI。 我之前问了一些错误的问题,但是我学到了很多关于Kerberos和SSPI的知识。 这是我的代码要点:

AppDomain.CurrentDomain.SetPrincipalPolicy(System.Security.Principal.PrincipalPolicy.WindowsPrincipal);
var domain = Domain.GetCurrentDomain().ToString();

using (var domainContext = new PrincipalContext(ContextType.Domain, domain))
{
    string spn = UserPrincipal.FindByIdentity(domainContext, IdentityType.SamAccountName, serviceName).UserPrincipalName;
    KerberosSecurityTokenProvider tokenProvider = new KerberosSecurityTokenProvider(spn, System.Security.Principal.TokenImpersonationLevel.Impersonation, CredentialCache.DefaultNetworkCredentials);
    KerberosRequestorSecurityToken securityToken = tokenProvider.GetToken(TimeSpan.FromMinutes(1)) as KerberosRequestorSecurityToken;
    string serviceToken = Convert.ToBase64String(securityToken.GetRequest());
}

你知道如何回溯并从“serviceToken”中获取用户主体名称吗?这是否可行? - Scott Lin
我没有实现服务器端,但这是可能的。我相信用户主体名称包含在服务令牌中,为了解密它,您需要从发放令牌的Kerberos服务器获取密钥。 - Furkat Kholmatov
@FurkatKholmatov,你能举个例子说明什么是“serviceName”吗?我正在尝试使用当前网络凭据在模拟上下文(委派)中请求服务的票证。我对于你为什么获取UPN然后将其用作SPN感到困惑,因为对我来说(没有委派),只需在初始化TokenProvider时将spn设置为例如“HTTP/myservice.domain.com”即可工作。你能详细说明一下你的用例吗?这可能有助于我调试我的问题 :) - valorl
@valorl - 这是一段时间以前的事情,我记不清细节了。我想出于某种原因,我们允许客户的网络管理员命名自己的SPN并向用户提供它,如果他们允许单点登录。我认为“serviceName”就是用户输入的那个SPN。 - Furkat Kholmatov
1
你如何验证这个服务令牌? - Travis Rivera

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接