6829283: HTTP/Negotiate: Autheticator triggered again when user cancels the first one
Reviewed-by: chegar
This commit is contained in:
parent
69e5f8b791
commit
23a0fee518
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2005-2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2005-2010 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -45,43 +45,50 @@ public class NegotiateCallbackHandler implements CallbackHandler {
|
||||
private String username;
|
||||
private char[] password;
|
||||
|
||||
/**
|
||||
* Authenticator asks for username and password in a single prompt,
|
||||
* but CallbackHandler checks one by one. So, no matter which callback
|
||||
* gets handled first, make sure Authenticator is only called once.
|
||||
*/
|
||||
private boolean answered;
|
||||
|
||||
private final HttpCallerInfo hci;
|
||||
|
||||
public NegotiateCallbackHandler(HttpCallerInfo hci) {
|
||||
this.hci = hci;
|
||||
}
|
||||
|
||||
private void getAnswer() {
|
||||
if (!answered) {
|
||||
answered = true;
|
||||
PasswordAuthentication passAuth =
|
||||
Authenticator.requestPasswordAuthentication(
|
||||
hci.host, hci.addr, hci.port, hci.protocol,
|
||||
hci.prompt, hci.scheme, hci.url, hci.authType);
|
||||
/**
|
||||
* To be compatible with existing callback handler implementations,
|
||||
* when the underlying Authenticator is canceled, username and
|
||||
* password are assigned null. No exception is thrown.
|
||||
*/
|
||||
if (passAuth != null) {
|
||||
username = passAuth.getUserName();
|
||||
password = passAuth.getPassword();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handle(Callback[] callbacks) throws
|
||||
UnsupportedCallbackException, IOException {
|
||||
for (int i=0; i<callbacks.length; i++) {
|
||||
Callback callBack = callbacks[i];
|
||||
|
||||
if (callBack instanceof NameCallback) {
|
||||
if (username == null) {
|
||||
PasswordAuthentication passAuth =
|
||||
Authenticator.requestPasswordAuthentication(
|
||||
hci.host, hci.addr, hci.port, hci.protocol,
|
||||
hci.prompt, hci.scheme, hci.url, hci.authType);
|
||||
username = passAuth.getUserName();
|
||||
password = passAuth.getPassword();
|
||||
}
|
||||
NameCallback nameCallback =
|
||||
(NameCallback)callBack;
|
||||
nameCallback.setName(username);
|
||||
|
||||
getAnswer();
|
||||
((NameCallback)callBack).setName(username);
|
||||
} else if (callBack instanceof PasswordCallback) {
|
||||
PasswordCallback passwordCallback =
|
||||
(PasswordCallback)callBack;
|
||||
if (password == null) {
|
||||
PasswordAuthentication passAuth =
|
||||
Authenticator.requestPasswordAuthentication(
|
||||
hci.host, hci.addr, hci.port, hci.protocol,
|
||||
hci.prompt, hci.scheme, hci.url, hci.authType);
|
||||
username = passAuth.getUserName();
|
||||
password = passAuth.getPassword();
|
||||
}
|
||||
passwordCallback.setPassword(password);
|
||||
Arrays.fill(password, ' ');
|
||||
getAnswer();
|
||||
((PasswordCallback)callBack).setPassword(password);
|
||||
if (password != null) Arrays.fill(password, ' ');
|
||||
} else {
|
||||
throw new UnsupportedCallbackException(callBack,
|
||||
"Call back not supported");
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2009-2010 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -23,8 +23,9 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 6578647
|
||||
* @bug 6578647 6829283
|
||||
* @summary Undefined requesting URL in java.net.Authenticator.getPasswordAuthentication()
|
||||
* @summary HTTP/Negotiate: Authenticator triggered again when user cancels the first one
|
||||
*/
|
||||
|
||||
import com.sun.net.httpserver.Headers;
|
||||
@ -35,6 +36,8 @@ import com.sun.net.httpserver.HttpServer;
|
||||
import com.sun.net.httpserver.HttpPrincipal;
|
||||
import com.sun.security.auth.module.Krb5LoginModule;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
@ -79,6 +82,9 @@ public class HttpNegotiateServer {
|
||||
// web page content
|
||||
final static String CONTENT = "Hello, World!";
|
||||
|
||||
// For 6829283, count how many times the Authenticator is called.
|
||||
static int count = 0;
|
||||
|
||||
// URLs for web test, proxy test. The proxy server is not a real proxy
|
||||
// since it fakes the same content for any URL. :)
|
||||
final static URL webUrl, proxyUrl;
|
||||
@ -134,6 +140,17 @@ public class HttpNegotiateServer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This Authenticator knows nothing
|
||||
*/
|
||||
static class KnowNothingAuthenticator extends java.net.Authenticator {
|
||||
@Override
|
||||
public PasswordAuthentication getPasswordAuthentication () {
|
||||
HttpNegotiateServer.count++;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
throws Exception {
|
||||
|
||||
@ -147,7 +164,6 @@ public class HttpNegotiateServer {
|
||||
kdcp.addPrincipalRandKey("krbtgt/" + REALM_PROXY);
|
||||
kdcp.addPrincipalRandKey("HTTP/" + PROXY_HOST);
|
||||
|
||||
KDC.writeMultiKtab(KRB5_TAB, kdcw, kdcp);
|
||||
KDC.saveConfig(KRB5_CONF, kdcw, kdcp,
|
||||
"default_keytab_name = " + KRB5_TAB,
|
||||
"[domain_realm]",
|
||||
@ -157,6 +173,19 @@ public class HttpNegotiateServer {
|
||||
|
||||
System.setProperty("java.security.krb5.conf", KRB5_CONF);
|
||||
Config.refresh();
|
||||
KDC.writeMultiKtab(KRB5_TAB, kdcw, kdcp);
|
||||
|
||||
// Write a customized JAAS conf file, so that any kinit cache
|
||||
// will be ignored.
|
||||
System.setProperty("java.security.auth.login.config", OneKDC.JAAS_CONF);
|
||||
File f = new File(OneKDC.JAAS_CONF);
|
||||
FileOutputStream fos = new FileOutputStream(f);
|
||||
fos.write((
|
||||
"com.sun.security.jgss.krb5.initiate {\n" +
|
||||
" com.sun.security.auth.module.Krb5LoginModule required;\n};\n"
|
||||
).getBytes());
|
||||
fos.close();
|
||||
f.deleteOnExit();
|
||||
|
||||
HttpServer h1 = httpd(WEB_PORT, "Negotiate", false,
|
||||
"HTTP/" + WEB_HOST + "@" + REALM_WEB, KRB5_TAB);
|
||||
@ -164,23 +193,21 @@ public class HttpNegotiateServer {
|
||||
"HTTP/" + PROXY_HOST + "@" + REALM_PROXY, KRB5_TAB);
|
||||
|
||||
try {
|
||||
|
||||
BufferedReader reader;
|
||||
java.net.Authenticator.setDefault(new KnowAllAuthenticator());
|
||||
|
||||
reader = new BufferedReader(new InputStreamReader(
|
||||
webUrl.openConnection().getInputStream()));
|
||||
if (!reader.readLine().equals(CONTENT)) {
|
||||
throw new RuntimeException("Bad content");
|
||||
Exception e1 = null, e2 = null;
|
||||
try {
|
||||
test6578647();
|
||||
} catch (Exception e) {
|
||||
e1 = e;
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
reader = new BufferedReader(new InputStreamReader(
|
||||
proxyUrl.openConnection(
|
||||
new Proxy(Proxy.Type.HTTP,
|
||||
new InetSocketAddress(PROXY_HOST, PROXY_PORT)))
|
||||
.getInputStream()));
|
||||
if (!reader.readLine().equals(CONTENT)) {
|
||||
throw new RuntimeException("Bad content");
|
||||
try {
|
||||
test6829283();
|
||||
} catch (Exception e) {
|
||||
e2 = e;
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (e1 != null || e2 != null) {
|
||||
throw new RuntimeException("Test error");
|
||||
}
|
||||
} finally {
|
||||
// Must stop. Seems there's no HttpServer.startAsDaemon()
|
||||
@ -189,6 +216,40 @@ public class HttpNegotiateServer {
|
||||
}
|
||||
}
|
||||
|
||||
static void test6578647() throws Exception {
|
||||
BufferedReader reader;
|
||||
java.net.Authenticator.setDefault(new KnowAllAuthenticator());
|
||||
|
||||
reader = new BufferedReader(new InputStreamReader(
|
||||
webUrl.openConnection().getInputStream()));
|
||||
if (!reader.readLine().equals(CONTENT)) {
|
||||
throw new RuntimeException("Bad content");
|
||||
}
|
||||
|
||||
reader = new BufferedReader(new InputStreamReader(
|
||||
proxyUrl.openConnection(
|
||||
new Proxy(Proxy.Type.HTTP,
|
||||
new InetSocketAddress(PROXY_HOST, PROXY_PORT)))
|
||||
.getInputStream()));
|
||||
if (!reader.readLine().equals(CONTENT)) {
|
||||
throw new RuntimeException("Bad content");
|
||||
}
|
||||
}
|
||||
|
||||
static void test6829283() throws Exception {
|
||||
BufferedReader reader;
|
||||
java.net.Authenticator.setDefault(new KnowNothingAuthenticator());
|
||||
try {
|
||||
new BufferedReader(new InputStreamReader(
|
||||
webUrl.openConnection().getInputStream()));
|
||||
} catch (IOException ioe) {
|
||||
// Will fail since no username and password is provided.
|
||||
}
|
||||
if (count > 1) {
|
||||
throw new RuntimeException("Authenticator called twice");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and starts an HTTP or proxy server that requires
|
||||
* Negotiate authentication.
|
||||
|
Loading…
Reference in New Issue
Block a user