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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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 String username;
|
||||||
private char[] password;
|
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;
|
private final HttpCallerInfo hci;
|
||||||
|
|
||||||
public NegotiateCallbackHandler(HttpCallerInfo hci) {
|
public NegotiateCallbackHandler(HttpCallerInfo hci) {
|
||||||
this.hci = 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
|
public void handle(Callback[] callbacks) throws
|
||||||
UnsupportedCallbackException, IOException {
|
UnsupportedCallbackException, IOException {
|
||||||
for (int i=0; i<callbacks.length; i++) {
|
for (int i=0; i<callbacks.length; i++) {
|
||||||
Callback callBack = callbacks[i];
|
Callback callBack = callbacks[i];
|
||||||
|
|
||||||
if (callBack instanceof NameCallback) {
|
if (callBack instanceof NameCallback) {
|
||||||
if (username == null) {
|
getAnswer();
|
||||||
PasswordAuthentication passAuth =
|
((NameCallback)callBack).setName(username);
|
||||||
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);
|
|
||||||
|
|
||||||
} else if (callBack instanceof PasswordCallback) {
|
} else if (callBack instanceof PasswordCallback) {
|
||||||
PasswordCallback passwordCallback =
|
getAnswer();
|
||||||
(PasswordCallback)callBack;
|
((PasswordCallback)callBack).setPassword(password);
|
||||||
if (password == null) {
|
if (password != null) Arrays.fill(password, ' ');
|
||||||
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, ' ');
|
|
||||||
} else {
|
} else {
|
||||||
throw new UnsupportedCallbackException(callBack,
|
throw new UnsupportedCallbackException(callBack,
|
||||||
"Call back not supported");
|
"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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -23,8 +23,9 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* @test
|
* @test
|
||||||
* @bug 6578647
|
* @bug 6578647 6829283
|
||||||
* @summary Undefined requesting URL in java.net.Authenticator.getPasswordAuthentication()
|
* @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;
|
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.net.httpserver.HttpPrincipal;
|
||||||
import com.sun.security.auth.module.Krb5LoginModule;
|
import com.sun.security.auth.module.Krb5LoginModule;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
@ -79,6 +82,9 @@ public class HttpNegotiateServer {
|
|||||||
// web page content
|
// web page content
|
||||||
final static String CONTENT = "Hello, World!";
|
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
|
// URLs for web test, proxy test. The proxy server is not a real proxy
|
||||||
// since it fakes the same content for any URL. :)
|
// since it fakes the same content for any URL. :)
|
||||||
final static URL webUrl, proxyUrl;
|
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)
|
public static void main(String[] args)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
|
||||||
@ -147,7 +164,6 @@ public class HttpNegotiateServer {
|
|||||||
kdcp.addPrincipalRandKey("krbtgt/" + REALM_PROXY);
|
kdcp.addPrincipalRandKey("krbtgt/" + REALM_PROXY);
|
||||||
kdcp.addPrincipalRandKey("HTTP/" + PROXY_HOST);
|
kdcp.addPrincipalRandKey("HTTP/" + PROXY_HOST);
|
||||||
|
|
||||||
KDC.writeMultiKtab(KRB5_TAB, kdcw, kdcp);
|
|
||||||
KDC.saveConfig(KRB5_CONF, kdcw, kdcp,
|
KDC.saveConfig(KRB5_CONF, kdcw, kdcp,
|
||||||
"default_keytab_name = " + KRB5_TAB,
|
"default_keytab_name = " + KRB5_TAB,
|
||||||
"[domain_realm]",
|
"[domain_realm]",
|
||||||
@ -157,6 +173,19 @@ public class HttpNegotiateServer {
|
|||||||
|
|
||||||
System.setProperty("java.security.krb5.conf", KRB5_CONF);
|
System.setProperty("java.security.krb5.conf", KRB5_CONF);
|
||||||
Config.refresh();
|
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,
|
HttpServer h1 = httpd(WEB_PORT, "Negotiate", false,
|
||||||
"HTTP/" + WEB_HOST + "@" + REALM_WEB, KRB5_TAB);
|
"HTTP/" + WEB_HOST + "@" + REALM_WEB, KRB5_TAB);
|
||||||
@ -164,7 +193,30 @@ public class HttpNegotiateServer {
|
|||||||
"HTTP/" + PROXY_HOST + "@" + REALM_PROXY, KRB5_TAB);
|
"HTTP/" + PROXY_HOST + "@" + REALM_PROXY, KRB5_TAB);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
Exception e1 = null, e2 = null;
|
||||||
|
try {
|
||||||
|
test6578647();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e1 = e;
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
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()
|
||||||
|
if (h1 != null) h1.stop(0);
|
||||||
|
if (h2 != null) h2.stop(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test6578647() throws Exception {
|
||||||
BufferedReader reader;
|
BufferedReader reader;
|
||||||
java.net.Authenticator.setDefault(new KnowAllAuthenticator());
|
java.net.Authenticator.setDefault(new KnowAllAuthenticator());
|
||||||
|
|
||||||
@ -182,10 +234,19 @@ public class HttpNegotiateServer {
|
|||||||
if (!reader.readLine().equals(CONTENT)) {
|
if (!reader.readLine().equals(CONTENT)) {
|
||||||
throw new RuntimeException("Bad content");
|
throw new RuntimeException("Bad content");
|
||||||
}
|
}
|
||||||
} finally {
|
}
|
||||||
// Must stop. Seems there's no HttpServer.startAsDaemon()
|
|
||||||
if (h1 != null) h1.stop(0);
|
static void test6829283() throws Exception {
|
||||||
if (h2 != null) h2.stop(0);
|
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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user