HttpClient的检查Kerberos的担保网页。 NTLM登录不工作(HttpClient

2019-09-17 15:42发布

我必须写一个程序,它会检查公司的一个Kerberos安全网站。 我尝试用HttpClient的,并得到以下错误:

KrbException: Server not found in Kerberos database (7)
    at sun.security.krb5.KrbTgsRep.<init>(KrbTgsRep.java:61)
    at sun.security.krb5.KrbTgsReq.getReply(KrbTgsReq.java:185)
        ...

我已经写了NTLM登录5个月之前,但它不适用于本的Kerberos安全网站工作。 我认为Nego2被激活,因此它不会回落到NTLM如果Kerberos失败。

我读了Kerberos的维基百科条目: http://en.wikipedia.org/wiki/Kerberos_(protocol) ,我认为问题是TGS没有在数据库中找到所请求的服务。 我想这是因为我得到的错误之前一票(我认为它的TGT)。

Found ticket for userid@EXAMPLE.COM to go to krbtgt/EXAMPLE.COM@EXAMPLE.COM expiring on Thu May 31 01:35:56 CEST 2012

因此,在对子级“客户服务授权”发生错误 - > 2(见维基百科文章)

问题是,该服务必须是在Kerberos数据库,因为我可以用IE浏览器访问它(不登录,等工程单点登录)。

所以我的问题是:为什么TGS找不到Kerberos数据库服务器,但它与IE浏览器的工作原理?


额外的信息
我试图让顶部的必要的信息,但在这里是因为我不知道我是否得到了所有必要的信息的所有信息:

操作系统是Windows 7
火狐9.0.1版
Chrome版本19.0.1084.52
Safari浏览器5.0.2版本
IE版本8.0.7600.16385

我的Java代码:

    System.setProperty("java.security.auth.login.config", "file://c:/temp/jaas.conf");
    System.setProperty("java.security.krb5.conf", "c:/winnt/krb5.ini");
    System.setProperty("sun.security.krb5.debug", "true");
    System.setProperty("javax.security.auth.useSubjectCredsOnly","false");

    DefaultHttpClient httpclient = new DefaultHttpClient();
    try {
        httpclient.getAuthSchemes().register(AuthPolicy.SPNEGO, new SPNegoSchemeFactory());

        Credentials use_jaas_creds = new Credentials() {

            public String getPassword() {
                return null;
            }

            public Principal getUserPrincipal() {
                return null;
            }

        };

        httpclient.getCredentialsProvider().setCredentials(
                new AuthScope(null, -1, null),
                use_jaas_creds);

        HttpUriRequest request = new HttpGet("url.com:port/site"); //Kerberos secured url
        HttpResponse response = httpclient.execute(request);
        HttpEntity entity = response.getEntity();

        System.out.println("----------------------------------------");
        System.out.println(response.getStatusLine());
        System.out.println("----------------------------------------");
        if (entity != null) {
            System.out.println(EntityUtils.toString(entity));
        }
        System.out.println("----------------------------------------");

        // This ensures the connection gets released back to the manager
        EntityUtils.consume(entity);

的Jaas.conf

com.sun.security.jgss.login {
com.sun.security.auth.module.Krb5LoginModule required client=TRUE;
};
com.sun.security.jgss.initiate {
com.sun.security.auth.module.Krb5LoginModule required client=TRUE;
};
com.sun.security.jgss.accept {
com.sun.security.auth.module.Krb5LoginModule required client=TRUE;
};

krb5.ini

[logging]
 default = FILE:log/krb5libs.log
 kdc = FILE:log/krb5kdc.log
 admin_server = FILE:log/kadmind.log

[libdefaults]
 ticket_lifetime = 24000
 default_realm = EXAMPLE.COM
 dns_lookup_realm = false
 dns_lookup_kdc = false

[realms]
 EXAMPLE.COM = {
  kdc = url
  admin_server = url
 }

[domain_realm]
 url.com = EXAMPLE.COM

[kdc]
 profile = /var/kerberos/krb5kdc/kdc.conf

[appdefaults]
 pam = {
   debug = false
   ticket_lifetime = 36000
   renew_lifetime = 36000
   forwardable = true
   krb4_convert = false
 }

眼井测井从测试运行文件:

log4j:WARN No appenders could be found for logger (org.apache.http.impl.conn.BasicClientConnectionManager).
log4j:WARN Please initialize the log4j system properly.
Kerberos-Benutzername [user]: user
Kerberos-Passwort für user: *******
Using builtin default etypes for default_tkt_enctypes
default etypes for default_tkt_enctypes: 3 1 23 16 17.
Using builtin default etypes for default_tkt_enctypes
default etypes for default_tkt_enctypes: 3 1 23 16 17.
>>> KrbAsReq calling createMessage
>>> KrbAsReq in createMessage
>>> KrbKdcReq send: kdc=kdcurl UDP:88, timeout=30000, number of retries =3, #bytes=155
>>> KDCCommunication: kdc=kdcurl UDP:88, timeout=30000,Attempt =1, #bytes=155
>>> KrbKdcReq send: #bytes read=220
>>> KrbKdcReq send: #bytes read=220
>>> KDCRep: init() encoding tag is 126 req type is 11
>>>KRBError:
     sTime is Thu May 31 08:46:29 CEST 2012 1338446789000
     suSec is 51983
     error code is 25
     error Message is Additional pre-authentication required
     realm is EXAMPLE.COM
     sname is krbtgt/EXAMPLE.COM
     eData provided.
     msgType is 30
>>>Pre-Authentication Data:
     PA-DATA type = 11
     PA-ETYPE-INFO etype = 23
>>>Pre-Authentication Data:
     PA-DATA type = 2
     PA-ENC-TIMESTAMP
>>>Pre-Authentication Data:
     PA-DATA type = 15
AcquireTGT: PREAUTH FAILED/REQUIRED, re-send AS-REQ
Using builtin default etypes for default_tkt_enctypes
default etypes for default_tkt_enctypes: 3 1 23 16 17.
Pre-Authentication: Set preferred etype = 23
>>>KrbAsReq salt is EXAMPLE.COMuser
Pre-Authenticaton: find key for etype = 23
AS-REQ: Add PA_ENC_TIMESTAMP now
>>> EType: sun.security.krb5.internal.crypto.ArcFourHmacEType
>>> KrbAsReq calling createMessage
>>> KrbAsReq in createMessage
>>> KrbKdcReq send: kdc=kdcurl UDP:88, timeout=30000, number of retries =3, #bytes=219
>>> KDCCommunication: kdc=kdcurl UDP:88, timeout=30000,Attempt =1, #bytes=219
>>> KrbKdcReq send: #bytes read=100
>>> KrbKdcReq send: #bytes read=100
>>> KDCRep: init() encoding tag is 126 req type is 11
>>>KRBError:
     sTime is Thu May 31 08:46:29 CEST 2012 1338446789000
     suSec is 114485
     error code is 52
     error Message is Response too big for UDP, retry with TCP
     realm is EXAMPLE.COM
     sname is krbtgt/EXAMPLE.COM
     msgType is 30
>>> KrbKdcReq send: kdc=kdcurl TCP:88, timeout=30000, number of retries =3, #bytes=219
>>>DEBUG: TCPClient reading 3277 bytes
>>> KrbKdcReq send: #bytes read=3277
>>> KrbKdcReq send: #bytes read=3277
>>> EType: sun.security.krb5.internal.crypto.ArcFourHmacEType
>>> KrbAsRep cons in KrbAsReq.getReply user
Using builtin default etypes for default_tkt_enctypes
default etypes for default_tkt_enctypes: 3 1 23 16 17.
Found ticket for user@EXAMPLE.COM to go to krbtgt/EXAMPLE.COM@EXAMPLE.COM expiring on Thu May 31 18:46:29 CEST 2012
Entered Krb5Context.initSecContext with state=STATE_NEW
Service ticket not found in the subject
>>> Credentials acquireServiceCreds: same realm
Using builtin default etypes for default_tgs_enctypes
default etypes for default_tgs_enctypes: 3 1 23 16 17.
>>> CksumType: sun.security.krb5.internal.crypto.RsaMd5CksumType
>>> EType: sun.security.krb5.internal.crypto.ArcFourHmacEType
>>> KrbKdcReq send: kdc=kdcurl UDP:88, timeout=30000, number of retries =3, #bytes=3298
>>> KDCCommunication: kdc=kdcurl UDP:88, timeout=30000,Attempt =1, #bytes=3298
>>> KrbKdcReq send: #bytes read=110
>>> KrbKdcReq send: #bytes read=110
>>> KDCRep: init() encoding tag is 126 req type is 13
>>>KRBError:
     sTime is Thu May 31 08:46:29 CEST 2012 1338446789000
     suSec is 192613
     error code is 7
     error Message is Server not found in Kerberos database
     realm is EXAMPLE.COM
     sname is HTTP/url.com:port
     msgType is 30
KrbException: Server not found in Kerberos database (7)
    at sun.security.krb5.KrbTgsRep.<init>(KrbTgsRep.java:61)
    at sun.security.krb5.KrbTgsReq.getReply(KrbTgsReq.java:185)
    at sun.security.krb5.internal.CredentialsUtil.serviceCreds(CredentialsUtil.java:294)
    at sun.security.krb5.internal.CredentialsUtil.acquireServiceCreds(CredentialsUtil.java:106)
    at sun.security.krb5.Credentials.acquireServiceCreds(Credentials.java:562)
    at sun.security.jgss.krb5.Krb5Context.initSecContext(Krb5Context.java:594)
    at sun.security.jgss.GSSContextImpl.initSecContext(GSSContextImpl.java:230)
    at sun.security.jgss.GSSContextImpl.initSecContext(GSSContextImpl.java:162)
    at sun.security.jgss.spnego.SpNegoContext.GSS_initSecContext(SpNegoContext.java:851)
    at sun.security.jgss.spnego.SpNegoContext.initSecContext(SpNegoContext.java:309)
    at sun.security.jgss.GSSContextImpl.initSecContext(GSSContextImpl.java:230)
    at sun.security.jgss.GSSContextImpl.initSecContext(GSSContextImpl.java:162)
    at org.apache.http.impl.auth.GGSSchemeBase.generateGSSToken(GGSSchemeBase.java:99)
    at org.apache.http.impl.auth.SPNegoScheme.generateToken(SPNegoScheme.java:80)
    at org.apache.http.impl.auth.GGSSchemeBase.authenticate(GGSSchemeBase.java:155)
    at org.apache.http.impl.auth.SPNegoScheme.authenticate(SPNegoScheme.java:75)
    at org.apache.http.client.protocol.RequestAuthenticationBase.authenticate(RequestAuthenticationBase.java:125)
    at org.apache.http.client.protocol.RequestAuthenticationBase.process(RequestAuthenticationBase.java:83)
    at org.apache.http.client.protocol.RequestTargetAuthentication.process(RequestTargetAuthentication.java:80)
    at org.apache.http.protocol.ImmutableHttpProcessor.process(ImmutableHttpProcessor.java:109)
    at org.apache.http.protocol.HttpRequestExecutor.preProcess(HttpRequestExecutor.java:176)
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:516)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:805)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:784)
    at mypackage.ClientKerberosAuthentication.main(ClientKerberosAuthentication.java:152)
Caused by: KrbException: Identifier doesn't match expected value (906)
    at sun.security.krb5.internal.KDCRep.init(KDCRep.java:133)
    at sun.security.krb5.internal.TGSRep.init(TGSRep.java:58)
    at sun.security.krb5.internal.TGSRep.<init>(TGSRep.java:53)
    at sun.security.krb5.KrbTgsRep.<init>(KrbTgsRep.java:46)
    ... 25 more
----------------------------------------
HTTP/1.1 401 Unauthorized
----------------------------------------
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Draft//EN">
<HTML>
<HEAD>
<TITLE>Error 401--Unauthorized</TITLE>
</HEAD>
<BODY bgcolor="white">
<FONT FACE=Helvetica><BR CLEAR=all>
<TABLE border=0 cellspacing=5><TR><TD><BR CLEAR=all>
<FONT FACE="Helvetica" COLOR="black" SIZE="3"><H2>Error 401--Unauthorized</H2>
</FONT></TD></TR>
</TABLE>
<TABLE border=0 width=100% cellpadding=10><TR><TD VALIGN=top WIDTH=100% BGCOLOR=white><FONT FACE="Courier New"><FONT FACE="Helvetica" SIZE="3"><H3>From RFC 2068 <i>Hypertext Transfer Protocol -- HTTP/1.1</i>:</H3>
</FONT><FONT FACE="Helvetica" SIZE="3"><H4>10.4.2 401 Unauthorized</H4>
</FONT><P><FONT FACE="Courier New">The request requires user authentication. The response MUST include a WWW-Authenticate header field (section 14.46) containing a challenge applicable to the requested resource. The client MAY repeat the request with a suitable Authorization header field (section 14.8). If the request already included Authorization credentials, then the 401 response indicates that authorization has been refused for those credentials. If the 401 response contains the same challenge as the prior response, and the user agent has already attempted authentication at least once, then the user SHOULD be presented the entity that was given in the response, since that entity MAY include relevant diagnostic information. HTTP access authentication is explained in section 11.</FONT></P>
</FONT></TD></TR>
</TABLE>

</BODY>
</HTML>

----------------------------------------

Answer 1:

它不会工作。

  1. Active Directory不中的SPN使用任何端口。 不知道哪里是愚蠢的东西走进HttpClient的。
  2. 有没有在您的Active Directory目标主机上注册SPN。

问题的答案:

  1. 根本不是,只有服务类和主机名是强制性的 。 服务类已经标识与端口注册的服务,如LDAP,HTTP,FTP等等。 我们有几十万的SPN在我们的森林。 他们没有用的端口。 我想一个巨大的工作来注册一个HTTP服务器的每一个端口实例,例如。 在广告只知道目标主机。 它会相应加密服务票证。 这使得它独特。
  2. 浏览器为什么会失败? 它构建一个SPN作为HTTP/<FQDN> 只要在目录中存在这一条,一切顺利。

当我试图HttpClient的,我从来没有高兴的蹩脚SPNEGO支持。 我想重写东西,当我拿到手里的。



Answer 2:

我发现解决这个问题的方法。
就在参数(真)添加到SPNegoSchemeFactory对象的构造函数。


  httpclient.getAuthSchemes().register(AuthPolicy.SPNEGO, new SPNegoSchemeFactory(true));

这将使你的sname HTTP / url.com:端口 HTTP / url.com。
由于这个JIRA: https://issues.apache.org/jira/browse/HTTPCLIENT-966?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel



Answer 3:

我创建了一个小工具,以简化与HttpClient的3到Kerberos的连接(无需外部配置文件),你可能想试一试。 https://github.com/DovAmir/httpclientAuthHelper

DefaultHttpClient httpclient = new DefaultHttpClient();
AuthUtils.securityLogging(SecurityLogType.KERBEROS,true);
CredentialsUtils.setKerberosCredentials(client, new UsernamePasswordCredentials("xxx", "xxx"), "domain", "kdc");
client.executeMethod(httpget);


文章来源: HttpClient check Kerberos secured webpage. NTLM login didn't work