【问题标题】:How to get Service Token from Kerberos using SSPI如何使用 SSPI 从 Kerberos 获取服务令牌
【发布时间】:2016-06-14 17:15:23
【问题描述】:

目标: 我正在尝试构建概念验证客户端应用程序以使用 SSPI 实现单点登录。我是 C# 新手,我很困惑。

到目前为止我所知道和所做的: 所有用户都是 Active Directory 域的一部分,所以我知道 Kerberos 在登录期间用于身份验证。此时我需要做的就是从 Kerberos 获取服务令牌,这样我就可以将其传递给服务资源,而不是用户名和密码(如果我错了,请纠正我)。我已获得服务主体名称 (SPN) 和已在 Kerberos 中注册该服务的密码。

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

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

感谢您的帮助和指导。如果可以,请具体说明,如果您有任何问题,请告诉我。

【问题讨论】:

  • 链接到“.NET 远程身份验证和授权示例 - 第一部分”是“msdn.microsoft.com/en-us/library/ms973911.aspx”我现在不能在问题主体中添加两个以上的链接
  • 你要说的有线协议是什么?定制还是标准?
  • 标准。我们没有使用任何自定义协议。
  • 哪种有线协议?请提供更多详细信息。
  • 我想我不确定您的意思或它的重要性。我将使用 TCP/UDP 作为传输层。用户已使用 Windows 进行身份验证,因此他们应该已经有可用的 TGT。如何获取当前活动的 TGT 并请求特定服务的票证。我不确定有线协议的重要性。你能解释一下吗?

标签: c# .net single-sign-on kerberos sspi


【解决方案1】:

您可以在下方通过提供 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 个主要步骤。首先是验证客户端并获取 Ticket Granting Ticket。第二个是使用 Ticket Granting Ticket 请求服务的票证,第三个是让服务验证客户端为其请求的票证。对于上面的代码示例,我很困惑,因为用户名变量用于 foundUser 和 spn。您能否详细说明答案并指定哪个是真正的客户用户和服务用户?
  • 您好,上面的代码说明了如何获取给定 spn 的票证。此处用户名是 AD 用户的登录名,通过使用该方法,它将创建 spn 作为登录名@域。通过使用该 spn,您可以生成票证。我也在做同样的任务,我正在关注 Win32 SSPI 身份验证 API 的 C#/.Net 接口。我也可以通过使用 nsspi 并寻找获得 SGT 的方法来获得 TGT :)
  • 对于复制上述代码的每个人,请注意当前形式的spn 没有用处。 spn 的目的是指出您想要证明您的身份验证的服务,并且获得您自己的spn 的票几乎没有价值。如果您的 spn 值采用 user@realm 的形式,则它可能是错误的,而应该是 foo/service.domainfoo/service.domain@realm
  • 与使用 SSPI 相比,这种方法有什么缺点吗?
【解决方案2】:

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'中获取用户主体名称吗?这甚至可能吗?
  • 我没有实现服务器端,但这是可能的。我相信用户主体名称包含在服务令牌中,为了解密它,您需要从发布令牌的 Kerberos 服务器获取密钥。
  • @FurkatKholmatov 你能举个例子什么是“serviceName”吗?我正在尝试类似地请求具有当前网络凭据的服务的票证,但在模拟上下文(委托)中。我很困惑为什么您要获得 UPN,然后将其用作 SPN,因为对我而言,只需将 spn 设置为例如,它就可以工作(没有委托)。初始化 TokenProvider 时的“HTTP/myservice.domain.com”。你能详细说明你的用例吗?它可能会帮助我调试我的:)
  • @valorl - 这是很久以前的事了,我不记得细节了。我认为出于某种原因,我们允许客户的网络管理员命名他们自己的 SPN,并在他们允许单点登录的情况下将其提供给用户。我认为“serviceName”是用户输入的 SPN。
  • 你如何验证这个服务令牌?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-10-08
  • 2016-11-11
  • 2021-03-02
  • 1970-01-01
  • 2019-03-20
  • 2017-10-07
  • 1970-01-01
相关资源
最近更新 更多