Mercurial > hg > release > icedtea7-forest-2.2 > jdk
changeset 2360:2796f839e337
6829283: HTTP/Negotiate: Autheticator triggered again when user cancels the first one
Reviewed-by: chegar
author | weijun |
---|---|
date | Thu, 18 Mar 2010 18:26:37 +0800 |
parents | 0500f7306cbe |
children | c52f292a8f86 |
files | src/share/classes/sun/net/www/protocol/http/spnego/NegotiateCallbackHandler.java test/sun/security/krb5/auto/HttpNegotiateServer.java |
diffstat | 2 files changed, 112 insertions(+), 44 deletions(-) [+] |
line wrap: on
line diff
--- a/src/share/classes/sun/net/www/protocol/http/spnego/NegotiateCallbackHandler.java Wed Mar 17 09:55:04 2010 +0800 +++ b/src/share/classes/sun/net/www/protocol/http/spnego/NegotiateCallbackHandler.java Thu Mar 18 18:26:37 2010 +0800 @@ -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 @@ 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");
--- a/test/sun/security/krb5/auto/HttpNegotiateServer.java Wed Mar 17 09:55:04 2010 +0800 +++ b/test/sun/security/krb5/auto/HttpNegotiateServer.java Thu Mar 18 18:26:37 2010 +0800 @@ -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.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 @@ // 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 @@ } } + /** + * 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 @@ 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 @@ 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 @@ "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 @@ } } + 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.