从Authorization标头中的Kerberos票证中读取用户名

时间:2013-01-16 08:53:41

标签: java kerberos

我想从Authorization HTTP标头中的Kerberos票证中读取用户名。我正在使用Java。

我花了几天的时间试图通过阅读关于这个主题的一堆网站来实现这一目标但却未能做到这一点。 Kerberos对我来说是新的/陌生的。

这就是我所取得的成就:

  • 当用户首次访问该站点时 - 没有Authorization标头,服务器将响应401 +标头:WWW-Authenticate = Negotiate。
  • 各种神奇的事情都发生在客户身上。
  • 用户返回一个HTTP请求,其中包含Authorization标头,其值类似于:“Negotiate YHcGB ... ==”
  • 将base64编码的故障单解码为字节数组。

从这里开始,这是一段通过未知世界的可怕旅程。据我所知,接下来的步骤应该是:

  • 使用用户登录AD / Kerberos / Server。
  • 解码门票。

这就是我所拥有的:

login.conf的

 ServicePrincipalLoginContext
{
      com.sun.security.auth.module.Krb5LoginModule 
      required 
      principal="HTTP/some.server.com@MY.DOMAIN.COM" 
      doNotPrompt=true
      useTicketCache=true
      password=mYpasSword
      debug=true;
};

JavaClass.java

String encodedTicket = authorization.substring("Negotiate ".length());
byte[] ticket = Base64.decode(encodedTicket);       

LoginContext lc = new LoginContext("ServicePrincipalLoginContext");
lc.login();
Subject serviceSubject = lc.getSubject();
Subject.doAs(serviceSubject, new ServiceTicketDecoder(ticket));

ServiceTicketDecoder.java

public String run() throws Exception {
    Oid kerberos5Oid = new Oid("1.2.840.113554.1.2.2");

    GSSManager gssManager = GSSManager.getInstance();

    String service = "krbtgt/MY.DOMAIN.COM@MY.DOMAIN.COM";
    GSSName serviceName = gssManager.createName(service, GSSName.NT_USER_NAME);

    GSSCredential serviceCredentials = gssManager.createCredential(serviceName, GSSCredential.INDEFINITE_LIFETIME, kerberos5Oid, GSSCredential.ACCEPT_ONLY);

    GSSContext gssContext = gssManager.createContext(serviceCredentials);
    gssContext.acceptSecContext(this.serviceTicket, 0, this.serviceTicket.length);

    GSSName srcName = gssContext.getSrcName();
    return srcName.toString;
}

JavaClass.java中的登录工作正常,所以我假设login.conf没问题。在ServiceTicketDecoder.java中的“GSSCredential serviceCredentials = gssManager.createCredential(...”)中抛出以下异常:

java.security.PrivilegedActionException: GSSException: No valid credentials provided (Mechanism level: Failed to find any Kerberos Key)

我不确定这是否是正确的做法。我也不知道“字符串服务”的价值应该是什么,或者如何获取该信息。你能救我吗?


编辑: login.conf

 ServicePrincipalLoginContext
{
      com.sun.security.auth.module.Krb5LoginModule 
      required 
      principal="HTTP/some.server.com@MY.DOMAIN.COM" 
      doNotPrompt=true
      useTicketCache=true
      keyTab="C:/server-http.keytab" 
      debug=true;
};

我收到了一个keytab文件。显然,HTTP / some.server.com用户的帐户已经是服务主体帐户。我现在在lc.login()的JavaClass.java上遇到了问题:

javax.security.auth.login.LoginException: KDC has no support for encryption type (14)
Caused by: KrbException: KDC has no support for encryption type (14)
Caused by: KrbException: Identifier doesn't match expected value (906)

keytab文件使用des-cbc-md5加密,我在krb.conf文件中定义了以下内容:

[libdefaults]
default_realm = MY.DOMAIN.COM
default_tkt_enctypes = des-cbc-md5
default_tgs_enctypes = des-cbc-md5

如果我将默认的enctype更改为例如aes128-cts,我得到以下异常:

javax.security.auth.login.LoginException: Do not have keys of types listed in default_tkt_enctypes available; only have keys of following type: DES CBC mode with MD5

我不明白有什么不对......

2 个答案:

答案 0 :(得分:5)

Kerberos是受信任的第三方安全系统:您从客户端收到的安全令牌只能由您解密,并且不需要联系任何Kerberos基础结构服务器(例如KDC)。你走在正确的轨道上;但是,您似乎缺少这一背景Kerberos知识来指导您进一步研究。

实现这一目标的方法是,在服务器上,您需要一个包含服务器密钥的 keytab 文件。 Kerberos服务器(Microsoft Windows Server,我认为)必须为您的服务创建服务主体帐户。管理员可以为您提供为此帐户生成的密钥表文件,该文件将包含密钥。

然后,您需要配置服务器以查找此密钥表文件;它用于涉及LoginContext.login的服务器端步骤。您接受安全上下文的代码必须在服务器端凭据生效的doPrivileged代码段内执行。

答案 1 :(得分:-3)