{{ v.name }}
{{ v.cls }}类
{{ v.price }} ¥{{ v.price }}
第4章http认证
httpclient提供对由http标准规范定义的认证方案以及许多广泛使用的非标准认证方案的全面支持,例如ntlm和spnego。
用户认证的任何过程都需要一组可用于建立用户身份的凭据。在最简单的形式中,用户凭据只能是用户名/密码对。usernamepasswordcredentials表示由安全主体和密码以明文形式组成的一组凭据。该实现对于由http标准规范定义的标准认证方案是足够的。
usernamepasswordcredentialscreds=newusernamepasswordcredentials("user","pwd");system.out.println(creds.getuserprincipal().getname());system.out.println(creds.getpassword());
stdout>
userpwd
ntcredentials是一个microsoftwindows特定的实现,除了用户名/密码对之外还包括一组额外的windows特定属性,例如用户域的名称。在microsoftwindows网络中,同一用户可以属于多个域,每个域具有不同的授权集。
ntcredentialscreds=newntcredentials("user","pwd","workstation","domain");system.out.println(creds.getuserprincipal().getname());system.out.println(creds.getpassword());
stdout>
domain/userpwd4.2。认证方案
该authscheme接口表示一种抽象的面向挑战响应的认证方案。认证方案有望支持以下功能:
解析并处理目标服务器响应于对受保护资源的请求发送的挑战。
提供处理过的质询的属性:认证方案类型及其参数,如果可用,该认证方案适用于该领域
为给定的凭证集和http请求生成授权字符串以响应实际的授权挑战。
请注意,认证方案可能是有状态的,涉及一系列质询-响应交换。
httpclient附带了几个authscheme实现:
基本:rfc2617中定义的基本认证方案。该认证方案不安全,因为凭证以明文形式发送。尽管其不安全性如果与tls/ssl加密结合使用,则基本认证方案是完全适用的。
消化。摘要认证方案如rfc2617所定义。摘要认证方案比基本安全性更好,对于那些不希望通过tls/ssl加密实现全传输安全性开销的应用程序,这是一个不错的选择。
ntlm:ntlm是由microsoft开发的专有认证方案,针对windows平台进行了优化。ntlm被认为比digest更安全。
spnego:spnego(小号imple和protectedgssapi戈tiation机制)是一个gssapi被用于协商许多可能的真实机制之一“伪机制”。spnego最明显的用途是microsoft的httpnegotiate身份验证扩展。可协商的子机制包括activedirectory支持的ntlm和kerberos。目前httpclient只支持kerberos子机制。
kerberos:kerberos身份验证实现。
凭证提供者旨在维护一组用户凭据,并能够为特定的认证范围生成用户凭据。认证范围由主机名,端口号,域名和认证方案名称组成。当与凭证提供者注册凭证时,可以提供通配符(任何主机,任何端口,任何领域,任何方案)而不是具体的属性值。然后,如果无法找到直接匹配,则凭证提供者将被期望能够找到特定范围的最接近的匹配项。
httpclient可以使用实现该credentialsprovider接口的凭据提供者的任何物理表示。credentialsprovider调用的默认实现basiccredentialsprovider是一个由a支持的简单实现java.util.hashmap。
credentialsprovidercredsprovider=newbasiccredentialsprovider();credsprovider.setcredentials(newauthscope("somehost",authscope.any_port),newusernamepasswordcredentials("u1","p1"));credsprovider.setcredentials(newauthscope("somehost",8080),newusernamepasswordcredentials("u2","p2"));credsprovider.setcredentials(newauthscope("otherhost",8080,authscope.any_realm,"ntlm"),newusernamepasswordcredentials("u3","p3"));system.out.println(credsprovider.getcredentials(newauthscope("somehost",80,"realm","basic")));system.out.println(credsprovider.getcredentials(newauthscope("somehost",8080,"realm","basic")));system.out.println(credsprovider.getcredentials(newauthscope("otherhost",8080,"realm","basic")));system.out.println(credsprovider.getcredentials(newauthscope("otherhost",8080,null,"ntlm")));
stdout>
[principal:u1][principal:u2]null[principal:u3]4.4。http认证和执行上下文
httpclient依赖authstate类跟踪有关身份验证过程状态的详细信息。httpclientauthstate在http请求执行过程中创建两个实例:一个用于目标主机身份验证,另一个用于代理身份验证。在情况下,目标服务器或代理要求用户认证的各authscope实例将与所述被填充authscope,authscheme并且crednetials在认证过程期间使用。该authstate可为了找出请求种类的认证,匹配是否进行检查authscheme落实,发现和证书提供商是否设法找到了给定的认证范围的用户凭据。
在http请求执行过程中,httpclient将以下与认证相关的对象添加到执行上下文中:
lookup表示实际的认证方案注册表。在本地上下文中设置的此属性的值优先于默认值。
credentialsprovider代表实际凭证提供者的实例。在本地上下文中设置的此属性的值优先于默认值。
authstate表示实际的目标认证状态。在本地上下文中设置的此属性的值优先于默认值。
authstate表示实际的代理身份验证状态。在本地上下文中设置的此属性的值优先于默认值。
authcache表示实际认证数据高速缓存的实例。在本地上下文中设置的此属性的值优先于默认值。
httpcontext可以使用本地对象在请求执行之前自定义http认证上下文,或者在执行请求后检查其状态:
closeablehttpclienthttpclient=<...>credentialsprovidercredsprovider=<...>lookup
从版本4.1起httpclient自动缓存有关已成功验证的主机的信息。请注意,必须使用相同的执行上下文来执行逻辑相关的请求,以便缓存的身份验证数据从一个请求传播到另一个请求。一旦执行上下文超出范围,认证数据就会丢失。
httpclient不支持开箱即用的抢占式身份验证,因为如果滥用或使用不当,抢占式身份验证可能会导致严重的安全问题,例如以明文方式将用户凭据发送给未经授权的第三方。因此,用户预期将在其特定应用环境的上下文中评估抢先认证与安全风险的潜在优势。
尽管如此,可以通过预先填写认证数据高速缓存来配置httpclient来抢占。
closeablehttpclienthttpclient=<...>httphosttargethost=newhttphost("localhost",80,"http");credentialsprovidercredsprovider=newbasiccredentialsprovider();credsprovider.setcredentials(newauthscope(targethost.gethostname(),targethost.getport()),newusernamepasswordcredentials("username","password"));//createauthcacheinstanceauthcacheauthcache=newbasicauthcache();//generatebasicschemeobjectandaddittothelocalauthcachebasicschemebasicauth=newbasicscheme();authcache.put(targethost,basicauth);//addauthcachetotheexecutioncontexthttpclientcontextcontext=httpclientcontext.create();context.setcredentialsprovider(credsprovider);context.setauthcache(authcache);httpgethttpget=newhttpget("/");for(inti=0;i<3;i++){closeablehttpresponseresponse=httpclient.execute(targethost,httpget,context);try{httpentityentity=response.getentity();}finally{response.close();}}4.7。ntlm认证
从版本4.1开始,httpclient全面支持ntlmv1,ntlmv2和ntlm2会话认证。仍然可以继续使用由samba项目开发的jcifs库ntlm等外部引擎作为windows互操作性程序套件的一部分。
该ntlm认证方案是在计算开销,比标准的性能影响方面显著更昂贵basic和digest方案。这可能是微软选择ntlm认证方案状态的主要原因之一。也就是说,一旦被认证,用户身份在整个生命周期中与该连接相关联。ntlm连接的有状态使连接持久性更加复杂,因为持久的明显原因ntlm具有不同用户身份的用户可能无法重新使用连接。httpclient附带的标准连接管理器完全能够管理状态连接。但是,在同一会话中的逻辑相关请求使用相同的执行上下文以使其知道当前用户身份是至关重要的。否则,httpclient将最终针对ntlm受保护的资源为每个http请求创建一个新的http连接。有关有状态http连接的详细讨论,请参阅本节。
由于ntlm连接是有状态的,因此通常建议ntlm使用相对便宜的方法来触发身份验证,例如get或head重新使用相同的连接来执行更昂贵的方法,特别是那些包含请求实体(如post或)的方法put。
closeablehttpclienthttpclient=<...>credentialsprovidercredsprovider=newbasiccredentialsprovider();credsprovider.setcredentials(authscope.any,newntcredentials("user","pwd","myworkstation","microsoft.com"));httphosttarget=newhttphost("www.microsoft.com",80,"http");//makesurethesamecontextisusedtoexecutelogicallyrelatedrequestshttpclientcontextcontext=httpclientcontext.create();context.setcredentialsprovider(credsprovider);//executeacheapmethodfirst.thiswilltriggerntlmauthenticationhttpgethttpget=newhttpget("/ntlm-protected/info");closeablehttpresponseresponse1=httpclient.execute(target,httpget,context);try{httpentityentity1=response1.getentity();}finally{response1.close();}//executeanexpensivemethodnextreusingthesamecontext(andconnection)httpposthttppost=newhttppost("/ntlm-protected/form");httppost.setentity(newstringentity("lotsandlotsofdata"));closeablehttpresponseresponse2=httpclient.execute(target,httppost,context);try{httpentityentity2=response2.getentity();}finally{response2.close();}4.8。spnego/kerberos身份验证
该spnego(小号imple和protectedgssapi戈tiation机制)被设计为允许身份验证服务时,既不知道到底对方可以用什么/提供。最常用于执行kerberos身份验证。它可以包装其他机制,但是httpclient中的当前版本只是考虑到kerberos的设计。
客户端web浏览器为资源提供httpget。
web服务器返回http401状态和标题:www-authenticate:negotiate
客户端生成一个negtokeninitbase64编码,并重新提交get授权头文件:authorization:negotiate
服务器解码negtokeninit,提取支持的mechtypes(在我们的情况下只有kerberosv5),确保它是预期的之一,然后提取mechtoken(kerberos令牌)并进行身份验证。
如果需要更多处理,则另一个http401将返回给客户端,其中更多的数据在www-authenticate头中。客户端获取信息并生成另一个令牌,通过这个authorization标题,直到完成。
当客户端被认证后,web服务器应该返回http200的状态,最后的www-authenticate头部和页面内容。
该spnego认证方案是与sun的java版本1.5及更高版本兼容。但是,强烈建议使用java>=1.6,因为它spnego更全面地支持认证。
sunjre提供支持类来执行几乎所有的kerberos和spnego令牌处理。这意味着很多设置适用于gss类。这spnegoscheme是一个简单的类来处理标记并读取和写入正确的标题。
最好的方法是kerberoshttpclient.java在示例中抓取文件,并尝试使其正常工作。有很多问题可能会发生,但如果幸运的话,它会工作没有太多的问题。它还应该提供一些调试输出。
在windows中,应该默认使用登录的凭据;这可以通过使用'kinit'来覆盖,例如$java_homebinkinittestuser@ad.example.net,这对于测试和调试问题非常有帮助。删除由kinit创建的缓存文件,以恢复到windowskerberos缓存。
确保domain_realms在krb5.conf文件中列出。这是问题的主要来源。
本文档假设您正在使用windows,但大部分信息也适用于unix。
这些org.ietf.jgss类有很多可能的配置参数,主要在krb5.conf/krb5.ini文件中。有关格式的更多信息,请访问http://web.mit.edu/kerberos/krb5-1.4/krb5-1.4.1/doc/krb5-admin/krb5.conf.html。
以下配置是一种基本设置,可在windowsxpiis和windowsxp中运行jbossnegotiation。
系统属性java.security.auth.login.config可用于指向login.conf文件。
login.conf内容可能如下所示:
com.sun.security.jgss.login{com.sun.security.auth.module.krb5loginmodulerequiredclient=trueuseticketcache=true;};com.sun.security.jgss.initiate{com.sun.security.auth.module.krb5loginmodulerequiredclient=trueuseticketcache=true;};com.sun.security.jgss.accept{com.sun.security.auth.module.krb5loginmodulerequiredclient=trueuseticketcache=true;};4.8.4。krb5.conf/krb5.ini文件
如果未指定,将使用系统默认值。如果需要,通过将系统属性设置java.security.krb5.conf为指向自定义krb5.conf文件来覆盖。
krb5.conf内容可能如下所示:
[libdefaults]default_realm=ad.example.netudp_preference_limit=1[realms]ad.example.net={kdc=kdc.ad.example.net}[domain_realms].ad.example.net=ad.example.netad.example.net=ad.example.net4.8.5。windows具体配置
要允许windows使用当前用户的票证,javax.security.auth.usesubjectcredsonly必须将系统属性设置为false,并且windows注册表项allowtgtsessionkey应该被正确添加和设置,以允许在kerberos票证授予票证中发送会话密钥。
在windowsserver2003和windows2000sp4上,以下是必需的注册表设置:
hkey_local_machinesystemcurrentcontrolsetcontrollsakerberosparametersvaluename:allowtgtsessionkeyvaluetype:reg_dwordvalue:0x01
以下是windowsxpsp2上注册表设置的位置: