据我所知,当前的java.net.URL握手(对于GSS / Kerberos身份验证模式)总是需要401作为第一个分支操作,如果我们知道客户端和服务器将要使用,这种效率会很低GSS / Kerberos,对吗?有谁知道在java世界中是否可以使用抢占式身份验证(您可以在python one https://github.com/requests/requests-kerberos#preemptive-authentication中预先呈现令牌)?
快速谷歌指向https://hc.apache.org/httpcomponents-client-ga/tutorial/html/authentication.html,但先发制人的例子似乎仅针对基本方案。
谢谢!
答案 0 :(得分:2)
我遇到了同样的问题并得出了与您相同的结论 - Oracle JRE HttpUrlConnection和Apache HTTP Components都不支持抢占式SPNEGO身份验证。我还没有检查过其他HTTP客户端,但几乎可以肯定它应该是相同的。
我开始研究可以与任何HTTP客户端一起使用的替代Spnego客户端 - 它被称为Kerb4J
你可以像这样使用它:
SpnegoClient spnegoClient = SpnegoClient.loginWithKeyTab("clientPrincipal", "C:/kerberos/clientPrincipal.keytab");
URL url = new URL("http://kerberized.service/helloworld");
URLConnection urlConnection = url.openConnection();
HttpURLConnection huc = (HttpURLConnection) urlConnection;
SpnegoContext context = spnegoClient.createContext(url);
huc.setRequestProperty("Authorization", context.createTokenAsAuthroizationHeader());
// Optional mutual authentication step
String challenge = huc.getHeaderField("WWW-Authenticate").substring("Negotiate ".length());
byte[] decode = Base64.getDecoder().decode(challenge);
context.processMutualAuthorization(decode, 0, decode.length);
答案 1 :(得分:0)
经过大量调查,看起来默认的Hotspot java实现中没有抢占式kerberos身份验证。来自Apache的http组件也无法提供帮助。
但是,默认实现确实能够仅在有效负载可能很大时发送标头,如Expect Header and 100-Continue response部分所述。要启用此功能,我们需要使用the fixed length streaming mode(or other similar means)。但正如javadoc中所述,身份验证和重定向无法自动处理 - 我们再次回到原来的问题。
答案 2 :(得分:0)
以下示例显示了如何使用在login.conf中的自定义条目进行抢先spnego登录。这完全绕过了AuthScheme的工作,并完成了生成“授权”标头的所有工作。
import org.apache.commons.io.IOUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.ietf.jgss.GSSContext;
import org.ietf.jgss.GSSCredential;
import org.ietf.jgss.GSSException;
import org.ietf.jgss.GSSManager;
import org.ietf.jgss.GSSName;
import org.ietf.jgss.Oid;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import java.io.File;
import java.net.InetAddress;
import java.security.PrivilegedExceptionAction;
import java.util.Base64;
public class AsyncHttpSpnego {
public static final String SPNEGO_OID = "1.3.6.1.5.5.2";
private static final String KERBEROS_OID = "1.2.840.113554.1.2.2";
public static void main(String[] args) throws Exception {
InetAddress inetAddress = InetAddress.getLocalHost();
String host = inetAddress.getHostName().toUpperCase();
System.setProperty("java.security.krb5.conf", new File(host + "-krb5.ini").getCanonicalPath());
System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");
System.setProperty("java.security.auth.login.config", new File(host + "-login.conf").getCanonicalPath());
LoginContext lc = new LoginContext("anotherentry");
lc.login();
byte[] token = new byte[0];
token = getAuthToken(host, lc, token);
String authorizationHeader = "Negotiate" + " " + Base64.getEncoder().encodeToString(token);
System.out.println("Next Authorization header: " + authorizationHeader);
CloseableHttpClient closeableHttpClient = HttpClients.createMinimal();
HttpGet httpget = new HttpGet("http://" + host + ":81/nick.txt");
httpget.setHeader("Authorization", authorizationHeader);
CloseableHttpResponse closeableHttpResponse = closeableHttpClient.execute(httpget);
try {
System.out.println(IOUtils.toString(closeableHttpResponse.getEntity().getContent()));
} finally {
closeableHttpResponse.close();
}
}
private static byte[] getAuthToken(String host, LoginContext lc, byte[] inToken) throws GSSException, java.security.PrivilegedActionException {
Oid negotiationOid = new Oid(SPNEGO_OID);
GSSManager manager = GSSManager.getInstance();
final PrivilegedExceptionAction<GSSCredential> action = () -> manager.createCredential(null,
GSSCredential.INDEFINITE_LIFETIME, negotiationOid, GSSCredential.INITIATE_AND_ACCEPT);
boolean tryKerberos = false;
GSSContext gssContext = null;
try {
GSSName serverName = manager.createName("HTTP@" + host, GSSName.NT_HOSTBASED_SERVICE);
gssContext = manager.createContext(serverName.canonicalize(negotiationOid), negotiationOid, Subject.doAs(lc.getSubject(), action),
GSSContext.DEFAULT_LIFETIME);
gssContext.requestMutualAuth(true);
gssContext.requestCredDeleg(true);
} catch (GSSException ex) {
if (ex.getMajor() == GSSException.BAD_MECH) {
System.out.println("GSSException BAD_MECH, retry with Kerberos MECH");
tryKerberos = true;
} else {
throw ex;
}
}
if (tryKerberos) {
Oid kerbOid = new Oid(KERBEROS_OID);
GSSName serverName = manager.createName("HTTP@" + host, GSSName.NT_HOSTBASED_SERVICE);
gssContext = manager.createContext(serverName.canonicalize(kerbOid), kerbOid, Subject.doAs(lc.getSubject(), action),
GSSContext.DEFAULT_LIFETIME);
gssContext.requestMutualAuth(true);
gssContext.requestCredDeleg(true);
}
return gssContext.initSecContext(inToken, 0, inToken.length);
}
}