Java / SPNEGO:不需要的SPN规范化?

时间:2012-09-01 16:57:37

标签: java windows kerberos spnego spn

我正在尝试使用SourceForge中的SPNEGO library(服务器使用相同的库)将Java客户端实现到SPNEGO受保护的Web服务。我无法成功进行身份验证,我的请求总是以

结束
HTTP/1.1 500 Failure unspecified at GSS-API level (Mechanism level: Checksum failed)

这类似于我从具有不适当主机名的浏览器访问Web服务时出现的症状,事实上Wireshark中的一些调试显示客户端发送了带有请求的错误SPN - 我发送给{{1} },已注册为SPN并在DNS中具有service-test.client.com记录,但在Windows域中注册为A。即使我将请求发送到server-1234.client.corp(请参阅匹配http://service-test.client.com标头),Java请求票证的SPN是“内部”Windows名称:

Wireshark decode of the HTTP request

从Chrome或IE发送的内容具有匹配的Host标头和SPN:

enter image description here

由于在我的代码或SPNEGO库中没有发生这种翻译,我认为它必须在JRE中发生。我一直在研究JGSS源代码,但有点难以理解。谁能告诉我如何跳过这个翻译并获得正确SPN的门票?

客户代码:

Host

1 个答案:

答案 0 :(得分:3)

上述评论摘要:

重新检查您的DNS。进行反向查找。大多数问题都是由错误的反向DNS条目引起的。

RFC2713中的第85页可能会帮助您检查RFC4120并搜索“佳能”。

当使用GSS-API构建基于主机的服务的SPN时,您必须使用目标机制规范化该名称。 RFC说

  

当解析对此类型名称的引用时,可以通过尝试DNS查找并使用返回的完全限定域名或使用DNS提供的“hostname”      查找失败。规范化操作还将主机名称映射为小写字符。

Kerberos 5 RFC说:

  

服务器和传输时。因此,例如,不应该依赖不受保护的DNS记录来将主机别名映射到主名称      服务器,接受主要名称作为一个打算的一方      联系,因为攻击者可以修改映射和模拟      派对。

     

基于Kerberos的Kerberos和协议的实现绝不可以      使用不安全的DNS查询来规范化主机名组件      服务主体名称(即,他们不得使用不安全的DNS      查询将一个名称映射到另一个名称以确定其中的主机部分      与之通信的主要名称)。在一个环境中      没有安全的名称服务,应用程序作者可以附加一个      以前将静态配置的域名设置为非限定主机名      将名称传递给安全机制,但他们不应该这样做      比那更多的。安全的名称服务设施(如果有)可能      被称为主机名规范化,但这种规范化      客户不应该被KDC实施所要求。

     

实施说明:许多当前的实施在某种程度上都有      规范化提供的服务名称,通常甚至使用DNS      虽然它会产生安全问题。但是,没有      实现之间关于服务名称是否一致的一致性      案例折叠为小写或是否使用反向分辨率。至      最大化互操作性和安全性,应该提供应用程序      具有由折叠用户产生的名称的安全机制 -      输入名称为小写而不执行任何其他修改      或规范化。

似乎GSS-API impls可以规范化,但如果DNS不受信任,Kerberos不应该这样做。 所以这取决于。反向查找是完全自然的。这是Kerberos验证主机名的方式。如果您正在运行DNS循环,这实际上至关重要。没有它,它将永远不能构建真正的SPN。

虽然我在Kerberos邮件列表上真的如此。这是一个非常有趣的观点。

我已经检查了MIT Kerberos实现,如果你检查sn2princ.c中的源代码,有krb5_sname_to_principal方法实际执行此操作:

if (type == KRB5_NT_SRV_HST) {
        struct addrinfo *ai = NULL, hints;
        int err;
        char hnamebuf[NI_MAXHOST];

        /* Note that the old code would accept numeric addresses,
           and if the gethostbyaddr step could convert them to
           real hostnames, you could actually get reasonable
           results.  If the mapping failed, you'd get dotted
           triples as realm names.  *sigh*

           The latter has been fixed in hst_realm.c, but we should
           keep supporting numeric addresses if they do have
           hostnames associated.  */

        memset(&hints, 0, sizeof(hints));
        hints.ai_flags = AI_CANONNAME;
        err = getaddrinfo(hostname, 0, &hints, &ai);
        if (err) {
#ifdef DEBUG_REFERRALS
            printf("sname_to_princ: failed to canonicalize %s; using as-is", hostname);
#endif
        }
        remote_host = strdup((ai && ai->ai_canonname) ? ai->ai_canonname : hostname);
        if (!remote_host) {
            if(ai)
                freeaddrinfo(ai);
            return ENOMEM;
        }

        if ((!err) && maybe_use_reverse_dns(context, DEFAULT_RDNS_LOOKUP)) {
            /*
             * Do a reverse resolution to get the full name, just in
             * case there's some funny business going on.  If there
             * isn't an in-addr record, give up.
             */
            /* XXX: This is *so* bogus.  There are several cases where
               this won't get us the canonical name of the host, but
               this is what we've trained people to expect.  We'll
               probably fix it at some point, but let's try to
               preserve the current behavior and only shake things up
               once when it comes time to fix this lossage.  */
            err = getnameinfo(ai->ai_addr, ai->ai_addrlen,
                              hnamebuf, sizeof(hnamebuf), 0, 0, NI_NAMEREQD);
            freeaddrinfo(ai);
            if (err == 0) {
                free(remote_host);
                remote_host = strdup(hnamebuf);
                if (!remote_host)
                    return ENOMEM;
            }
        } else
            freeaddrinfo(ai);
    }

所以,我想我们必须询问邮件列表。