HttpClient检查Kerberos安全网页。 NTLM登录无效

我必须编写一个程序来检查我们公司的Kerberos安全站点。 我尝试使用HttpClient并得到以下错误:

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

我在5个月前写过一个NTLM登录,但它对这个Kerberos安全站点不起作用。 我认为Nego2已激活,因此如果Kerberos失败,它不会回退到NTLM。

我阅读了Kerberos Wikipedia文章: 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
Firefox版本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 } 

测试运行中的Hole Log文件:

 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.(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.(TGSRep.java:53) at sun.security.krb5.KrbTgsRep.(KrbTgsRep.java:46) ... 25 more ---------------------------------------- HTTP/1.1 401 Unauthorized ----------------------------------------    Error 401--Unauthorized   

Error 401--Unauthorized

From RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1:

10.4.2 401 Unauthorized

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.

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

它不会起作用。

  1. Active Directory不使用SPN中的任何端口。 不知道那些愚蠢的东西进入HttpClient的地方。
  2. 您的Active Directory中没有为目标主机注册SPN。

您的问题的答案:

  1. 完全没有,只有服务类和主机名是必需的 。 服务类已经标识了端口注册的服务,例如LDAP,HTTP,FTP等。 我们的森林中有数十万个SPN。 他们都没有端口。 例如,如果要注册HTTP服务器的每个端口实例,我将付出巨大的努力。 AD必须仅知道目标主机。 它会相应地加密服务票证。 这使它独一无二。
  2. 为什么浏览器会失败? 它确实将SPN构造为HTTP/ 。 只要这个存在于目录中,一切都会顺利进行。

当我尝试使用HTTPClient时,我对SPNEGO的蹩脚支持感到满意。 当我开始接触时,我想重写那些东西。

我找到了解决这个问题的方法。
只需将参数(true)添加到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

我创建了一个小工具来简化与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);