欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

HttpClient 中文官方教程----第4章HTTP认证-只收录,未测试

程序员文章站 2022-05-07 12:09:12
...


第4章HTTP认证

HttpClient提供对由HTTP标准规范定义的认证方案以及许多广泛使用的非标准认证方案的全面支持,例如NTLMSPNEGO

4.1。用户凭证

用户认证的任何过程都需要一组可用于建立用户身份的凭据。在最简单的形式中,用户凭据只能是用户名/密码对。UsernamePasswordCredentials表示由安全主体和密码以明文形式组成的一组凭据。该实现对于由HTTP标准规范定义的标准认证方案是足够的。

UsernamePasswordCredentials creds = new UsernamePasswordCredentials("user", "pwd");
System.out.println(creds.getUserPrincipal().getName());
System.out.println(creds.getPassword());

stdout>

user
pwd

NTCredentials是一个Microsoft Windows特定的实现,除了用户名/密码对之外还包括一组额外的Windows特定属性,例如用户域的名称。在Microsoft Windows网络中,同一用户可以属于多个域,每个域具有不同的授权集。

NTCredentials creds = new NTCredentials("user", "pwd", "workstation", "domain");
System.out.println(creds.getUserPrincipal().getName());
System.out.println(creds.getPassword());

stdout>

DOMAIN/user
pwd

4.2。认证方案

AuthScheme接口表示一种抽象的面向挑战响应的认证方案。认证方案有望支持以下功能:

  • 解析并处理目标服务器响应于对受保护资源的请求发送的挑战。

  • 提供处理过的质询的属性:认证方案类型及其参数,如果可用,该认证方案适用于该领域

  • 为给定的凭证集和HTTP请求生成授权字符串以响应实际的授权挑战。

请注意,认证方案可能是有状态的,涉及一系列质询 - 响应交换。

HttpClient附带了几个AuthScheme实现:

  • 基本:  RFC 2617中定义的基本认证方案。该认证方案不安全,因为凭证以明文形式发送。尽管其不安全性如果与TLS / SSL加密结合使用,则基本认证方案是完全适用的。

  • 消化。 摘要认证方案如RFC 2617所定义。摘要认证方案比基本安全性更好,对于那些不希望通过TLS / SSL加密实现全传输安全性开销的应用程序,这是一个不错的选择。

  • NTLM:  NTLM是由Microsoft开发的专有认证方案,针对Windows平台进行了优化。NTLM被认为比Digest更安全。

  • SPNEGO:  SPNEGO小号 imple和P rotected GSSAPI  tiation机制)是一个GSSAPI被用于协商许多可能的真实机制之一“伪机制”。SPNEGO最明显的用途是Microsoft的HTTP Negotiate身份验证扩展。可协商的子机制包括Active Directory支持的NTLM和Kerberos。目前HttpClient只支持Kerberos子机制。

  • Kerberos:  Kerberos身份验证实现。

4.3。证书提供者

凭证提供者旨在维护一组用户凭据,并能够为特定的认证范围生成用户凭据。认证范围由主机名,端口号,域名和认证方案名称组成。当与凭证提供者注册凭证时,可以提供通配符(任何主机,任何端口,任何领域,任何方案)而不是具体的属性值。然后,如果无法找到直接匹配,则凭证提供者将被期望能够找到特定范围的最接近的匹配项。

HttpClient可以使用实现该CredentialsProvider接口的凭据提供者的任何物理表示。CredentialsProvider调用的默认实现BasicCredentialsProvider是一个由a支持的简单实现java.util.HashMap

CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
    new AuthScope("somehost", AuthScope.ANY_PORT), 
    new UsernamePasswordCredentials("u1", "p1"));
credsProvider.setCredentials(
    new AuthScope("somehost", 8080), 
    new UsernamePasswordCredentials("u2", "p2"));
credsProvider.setCredentials(
    new AuthScope("otherhost", 8080, AuthScope.ANY_REALM, "ntlm"), 
    new UsernamePasswordCredentials("u3", "p3"));

System.out.println(credsProvider.getCredentials(
    new AuthScope("somehost", 80, "realm", "basic")));
System.out.println(credsProvider.getCredentials(
    new AuthScope("somehost", 8080, "realm", "basic")));
System.out.println(credsProvider.getCredentials(
    new AuthScope("otherhost", 8080, "realm", "basic")));
System.out.println(credsProvider.getCredentials(
    new AuthScope("otherhost", 8080, null, "ntlm")));

stdout>

[principal: u1]
[principal: u2]
null
[principal: u3]

4.4。HTTP认证和执行上下文

HttpClient依赖AuthState类跟踪有关身份验证过程状态的详细信息。HttpClient AuthState在HTTP请求执行过程中创建两个实例:一个用于目标主机身份验证,另一个用于代理身份验证。在情况下,目标服务器或代理要求用户认证的各AuthScope实例将与所述被填充AuthScopeAuthScheme并且Crednetials在认证过程期间使用。该AuthState可为了找出请求种类的认证,匹配是否进行检查AuthScheme落实,发现和证书提供商是否设法找到了给定的认证范围的用户凭据。

在HTTP请求执行过程中,HttpClient将以下与认证相关的对象添加到执行上下文中:

  • Lookup表示实际的认证方案注册表。在本地上下文中设置的此属性的值优先于默认值。

  • CredentialsProvider代表实际凭证提供者的实例。在本地上下文中设置的此属性的值优先于默认值。

  • AuthState表示实际的目标认证状态。在本地上下文中设置的此属性的值优先于默认值。

  • AuthState表示实际的代理身份验证状态。在本地上下文中设置的此属性的值优先于默认值。

  • AuthCache表示实际认证数据高速缓存的实例。在本地上下文中设置的此属性的值优先于默认值。

HttpContext可以使用本地对象在请求执行之前自定义HTTP认证上下文,或者在执行请求后检查其状态:

CloseableHttpClient httpclient = <...>

CredentialsProvider credsProvider = <...>
Lookup<AuthSchemeProvider> authRegistry = <...>
AuthCache authCache = <...>

HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credsProvider);
context.setAuthSchemeRegistry(authRegistry);
context.setAuthCache(authCache);
HttpGet httpget = new HttpGet("http://somehost/");
CloseableHttpResponse response1 = httpclient.execute(httpget, context);
<...>

AuthState proxyAuthState = context.getProxyAuthState();
System.out.println("Proxy auth state: " + proxyAuthState.getState());
System.out.println("Proxy auth scheme: " + proxyAuthState.getAuthScheme());
System.out.println("Proxy auth credentials: " + proxyAuthState.getCredentials());
AuthState targetAuthState = context.getTargetAuthState();
System.out.println("Target auth state: " + targetAuthState.getState());
System.out.println("Target auth scheme: " + targetAuthState.getAuthScheme());
System.out.println("Target auth credentials: " + targetAuthState.getCredentials());

4.5。缓存认证数据

从版本4.1起HttpClient自动缓存有关已成功验证的主机的信息。请注意,必须使用相同的执行上下文来执行逻辑相关的请求,以便缓存的身份验证数据从一个请求传播到另一个请求。一旦执行上下文超出范围,认证数据就会丢失。

4.6。抢先认证

HttpClient不支持开箱即用的抢占式身份验证,因为如果滥用或使用不当,抢占式身份验证可能会导致严重的安全问题,例如以明文方式将用户凭据发送给未经授权的第三方。因此,用户预期将在其特定应用环境的上下文中评估抢先认证与安全风险的潜在优势。

尽管如此,可以通过预先填写认证数据高速缓存来配置HttpClient来抢占。

CloseableHttpClient httpclient = <...>

HttpHost targetHost = new HttpHost("localhost", 80, "http");
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
        new AuthScope(targetHost.getHostName(), targetHost.getPort()),
        new UsernamePasswordCredentials("username", "password"));

// Create AuthCache instance
AuthCache authCache = new BasicAuthCache();
// Generate BASIC scheme object and add it to the local auth cache
BasicScheme basicAuth = new BasicScheme();
authCache.put(targetHost, basicAuth);

// Add AuthCache to the execution context
HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credsProvider);
context.setAuthCache(authCache);

HttpGet httpget = new HttpGet("/");
for (int i = 0; i < 3; i++) {
    CloseableHttpResponse response = httpclient.execute(
            targetHost, httpget, context);
    try {
        HttpEntity entity = response.getEntity();

    } finally {
        response.close();
    }
}

4.7。NTLM认证

从版本4.1开始,HttpClient全面支持NTLMv1,NTLMv2和NTLM2会话认证。仍然可以继续使用由Samba项目开发的JCIFSNTLM等外部引擎作为Windows互操作性程序套件的一部分。

4.7.1。NTLM连接持久性

NTLM认证方案是在计算开销,比标准的性能影响方面显著更昂贵BasicDigest方案。这可能是微软选择NTLM认证方案状态的主要原因之一。也就是说,一旦被认证,用户身份在整个生命周期中与该连接相关联。NTLM连接的有状态使连接持久性更加复杂,因为持久的明显原因NTLM具有不同用户身份的用户可能无法重新使用连接。HttpClient附带的标准连接管理器完全能够管理状态连接。但是,在同一会话中的逻辑相关请求使用相同的执行上下文以使其知道当前用户身份是至关重要的。否则,HttpClient将最终针对NTLM受保护的资源为每个HTTP请求创建一个新的HTTP连接。有关有状态HTTP连接的详细讨论,请参阅节。

由于NTLM连接是有状态的,因此通常建议NTLM使用相对便宜的方法来触发身份验证,例如GETHEAD重新使用相同的连接来执行更昂贵的方法,特别是那些包含请求实体(如POST或)的方法PUT

CloseableHttpClient httpclient = <...>

CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(AuthScope.ANY,
        new NTCredentials("user", "pwd", "myworkstation", "microsoft.com"));

HttpHost target = new HttpHost("www.microsoft.com", 80, "http");

// Make sure the same context is used to execute logically related requests
HttpClientContext context = HttpClientContext.create();
context.setCredentialsProvider(credsProvider);

// Execute a cheap method first. This will trigger NTLM authentication
HttpGet httpget = new HttpGet("/ntlm-protected/info");
CloseableHttpResponse response1 = httpclient.execute(target, httpget, context);
try {
    HttpEntity entity1 = response1.getEntity();
} finally {
    response1.close();
}

// Execute an expensive method next reusing the same context (and connection)
HttpPost httppost = new HttpPost("/ntlm-protected/form");
httppost.setEntity(new StringEntity("lots and lots of data"));
CloseableHttpResponse response2 = httpclient.execute(target, httppost, context);
try {
    HttpEntity entity2 = response2.getEntity();
} finally {
    response2.close();
}

4.8。 SPNEGO/ Kerberos身份验证

SPNEGO小号 imple和P rotected GSSAPI  tiation机制)被设计为允许身份验证服务时,既不知道到底对方可以用什么/提供。最常用于执行Kerberos身份验证。它可以包装其他机制,但是HttpClient中的当前版本只是考虑到Kerberos的设计。

  1. 客户端Web浏览器为资源提供HTTP GET。

  2. Web服务器返回HTTP 401状态和标题: WWW-Authenticate: Negotiate

  3. 客户端生成一个NegTokenInitbase64编码,并重新提交GET授权头文件:Authorization: Negotiate <base64 encoding>

  4. 服务器解码NegTokenInit,提取支持的MechTypes(在我们的情况下只有Kerberos V5),确保它是预期的之一,然后提取MechToken(Kerberos令牌)并进行身份验证。

    如果需要更多处理,则另一个HTTP 401将返回给客户端,其中更多的数据在WWW-Authenticate头中。客户端获取信息并生成另一个令牌,通过这个Authorization标题,直到完成。

  5. 当客户端被认证后,Web服务器应该返回HTTP 200的状态,最后的WWW-Authenticate头部和页面内容。

4.8.1。 SPNEGO支持HttpClient

SPNEGO认证方案是与Sun的Java版本1.5及更高版本兼容。但是,强烈建议使用Java> = 1.6,因为它SPNEGO更全面地支持认证。

Sun JRE提供支持类来执行几乎所有的Kerberos和SPNEGO令牌处理。这意味着很多设置适用于GSS类。这SPNegoScheme是一个简单的类来处理标记并读取和写入正确的标题。

最好的方法是KerberosHttpClient.java在示例中抓取文件,并尝试使其正常工作。有很多问题可能会发生,但如果幸运的话,它会工作没有太多的问题。它还应该提供一些调试输出。

在Windows中,应该默认使用登录的凭据; 这可以通过使用'kinit'来覆盖,例如$JAVA_HOME\bin\kinit [email protected],这对于测试和调试问题非常有帮助。删除由kinit创建的缓存文件,以恢复到Windows Kerberos缓存。

确保domain_realmskrb5.conf文件中列出。这是问题的主要来源。

4.8.2。GSS / Java Kerberos设置

本文档假设您正在使用Windows,但大部分信息也适用于Unix。

这些org.ietf.jgss类有很多可能的配置参数,主要在krb5.confkrb5.ini文件中。有关格式的更多信息,请访问http://web.mit.edu/kerberos/krb5-1.4/krb5-1.4.1/doc/krb5-admin/krb5.conf.html

4.8.3。 login.conf文件

以下配置是一种基本设置,可在Windows XP IIS和Windows XP中运行JBoss Negotiation

系统属性java.security.auth.login.config可用于指向login.conf文件。

login.conf 内容可能如下所示:

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

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

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

4.8.4。 krb5.confkrb5.ini文件

如果未指定,将使用系统默认值。如果需要,通过将系统属性设置java.security.krb5.conf为指向自定义krb5.conf文件来覆盖。

krb5.conf 内容可能如下所示:

[libdefaults]
    default_realm = AD.EXAMPLE.NET
    udp_preference_limit = 1
[realms]
    AD.EXAMPLE.NET = {
        kdc = KDC.AD.EXAMPLE.NET
    }
[domain_realms]
.ad.example.net=AD.EXAMPLE.NET
ad.example.net=AD.EXAMPLE.NET

4.8.5。Windows具体配置

要允许Windows使用当前用户的票证,javax.security.auth.useSubjectCredsOnly必须将系统属性设置为false,并且Windows注册表项allowtgtsessionkey应该被正确添加和设置,以允许在Kerberos票证授予票证中发送会话**。

在Windows Server 2003和Windows 2000 SP4上,以下是必需的注册表设置:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa\Kerberos\Parameters
Value Name: allowtgtsessionkey
Value Type: REG_DWORD
Value: 0x01

以下是Windows XP SP2上注册表设置的位置:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa\Kerberos\
Value Name: allowtgtsessionkey
Value Type: REG_DWORD
Value: 0x01
     

转载于:https://my.oschina.net/ch66880/blog/1526210