changeset 1738:9cd7133ea287

6882594: Remove static dependancy on NTLM authentication Reviewed-by: alanb, weijun
author chegar
date Fri, 18 Sep 2009 22:18:19 +0100
parents c9cbd2a09fd4
children 45a343706f73
files make/sun/net/FILES_java.gmk src/share/classes/sun/net/www/protocol/http/AuthCache.java src/share/classes/sun/net/www/protocol/http/AuthCacheValue.java src/share/classes/sun/net/www/protocol/http/AuthScheme.java src/share/classes/sun/net/www/protocol/http/AuthenticationInfo.java src/share/classes/sun/net/www/protocol/http/BasicAuthentication.java src/share/classes/sun/net/www/protocol/http/DigestAuthentication.java src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java src/share/classes/sun/net/www/protocol/http/NTLMAuthenticationProxy.java src/share/classes/sun/net/www/protocol/http/NegotiateAuthentication.java src/solaris/classes/sun/net/www/protocol/http/NTLMAuthentication.java src/windows/classes/sun/net/www/protocol/http/NTLMAuthentication.java
diffstat 12 files changed, 419 insertions(+), 162 deletions(-) [+]
line wrap: on
line diff
--- a/make/sun/net/FILES_java.gmk	Fri Sep 18 16:24:26 2009 +0100
+++ b/make/sun/net/FILES_java.gmk	Fri Sep 18 22:18:19 2009 +0100
@@ -86,9 +86,11 @@
 	sun/net/www/protocol/http/AuthCache.java \
 	sun/net/www/protocol/http/AuthCacheImpl.java \
 	sun/net/www/protocol/http/AuthCacheValue.java \
+	sun/net/www/protocol/http/AuthScheme.java \
 	sun/net/www/protocol/http/BasicAuthentication.java \
 	sun/net/www/protocol/http/DigestAuthentication.java \
 	sun/net/www/protocol/http/NTLMAuthentication.java \
+	sun/net/www/protocol/http/NTLMAuthenticationProxy.java \
 	sun/net/www/protocol/http/NegotiateAuthentication.java \
 	sun/net/www/protocol/http/NegotiatorImpl.java \
 	sun/net/www/protocol/http/NegotiateCallbackHandler.java \
--- a/src/share/classes/sun/net/www/protocol/http/AuthCache.java	Fri Sep 18 16:24:26 2009 +0100
+++ b/src/share/classes/sun/net/www/protocol/http/AuthCache.java	Fri Sep 18 22:18:19 2009 +0100
@@ -25,14 +25,6 @@
 
 package sun.net.www.protocol.http;
 
-import java.io.IOException;
-import java.net.URL;
-import java.util.Hashtable;
-import java.util.LinkedList;
-import java.util.ListIterator;
-import java.util.Enumeration;
-import java.util.HashMap;
-
 /**
  * @author Michael McMahon
  *
@@ -49,7 +41,7 @@
      * A:[B:]C:D:E[:F]   Between 4 and 6 fields separated by ":"
      *          where the fields have the following meaning:
      * A is "s" or "p" for server or proxy authentication respectively
-     * B is optional and is "D", "B", or "N" for digest, basic or ntlm auth.
+     * B is optional and is the {@link AuthScheme}, e.g. BASIC, DIGEST, NTLM, etc
      * C is either "http" or "https"
      * D is the hostname
      * E is the port number
--- a/src/share/classes/sun/net/www/protocol/http/AuthCacheValue.java	Fri Sep 18 16:24:26 2009 +0100
+++ b/src/share/classes/sun/net/www/protocol/http/AuthCacheValue.java	Fri Sep 18 22:18:19 2009 +0100
@@ -25,15 +25,8 @@
 
 package sun.net.www.protocol.http;
 
-import java.io.IOException;
 import java.io.Serializable;
-import java.net.*;
-import java.util.Hashtable;
-import java.util.LinkedList;
-import java.util.ListIterator;
-import java.util.Enumeration;
-import java.util.HashMap;
-
+import java.net.PasswordAuthentication;
 
 /**
  * AuthCacheValue: interface to minimise exposure to authentication cache
@@ -62,8 +55,16 @@
 
     AuthCacheValue() {}
 
+    /**
+     * Proxy or Server
+     */
     abstract Type getAuthType ();
 
+    /**
+     * Authentication scheme
+     */
+    abstract AuthScheme getAuthScheme();
+
    /**
     * name of server/proxy
     */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/net/www/protocol/http/AuthScheme.java	Fri Sep 18 22:18:19 2009 +0100
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2009 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package sun.net.www.protocol.http;
+
+/* Authentication schemes supported by the http implementation. New schemes, if
+ * supported, should be defined here.
+ */
+public enum AuthScheme {
+    BASIC,
+    DIGEST,
+    NTLM,
+    NEGOTIATE,
+    KERBEROS,
+    UNKNOWN;
+}
+
--- a/src/share/classes/sun/net/www/protocol/http/AuthenticationInfo.java	Fri Sep 18 16:24:26 2009 +0100
+++ b/src/share/classes/sun/net/www/protocol/http/AuthenticationInfo.java	Fri Sep 18 22:18:19 2009 +0100
@@ -85,6 +85,11 @@
             AuthCacheValue.Type.Server:
             AuthCacheValue.Type.Proxy;
     }
+
+    AuthScheme getAuthScheme() {
+        return authScheme;
+    }
+
     public String getHost() {
         return host;
     }
@@ -151,7 +156,7 @@
     }
 
     //public String toString () {
-        //return ("{"+type+":"+authType+":"+protocol+":"+host+":"+port+":"+realm+":"+path+"}");
+        //return ("{"+type+":"+authScheme+":"+protocol+":"+host+":"+port+":"+realm+":"+path+"}");
     //}
 
     // REMIND:  This cache just grows forever.  We should put in a bounded
@@ -160,8 +165,8 @@
     /** The type (server/proxy) of authentication this is.  Used for key lookup */
     char type;
 
-    /** The authentication type (basic/digest). Also used for key lookup */
-    char authType;
+    /** The authentication scheme (basic/digest). Also used for key lookup */
+    AuthScheme authScheme;
 
     /** The protocol/scheme (i.e. http or https ). Need to keep the caches
      *  logically separate for the two protocols. This field is only used
@@ -183,9 +188,9 @@
     String path;
 
     /** Use this constructor only for proxy entries */
-    AuthenticationInfo(char type, char authType, String host, int port, String realm) {
+    AuthenticationInfo(char type, AuthScheme authScheme, String host, int port, String realm) {
         this.type = type;
-        this.authType = authType;
+        this.authScheme = authScheme;
         this.protocol = "";
         this.host = host.toLowerCase();
         this.port = port;
@@ -206,9 +211,9 @@
      * Constructor used to limit the authorization to the path within
      * the URL. Use this constructor for origin server entries.
      */
-    AuthenticationInfo(char type, char authType, URL url, String realm) {
+    AuthenticationInfo(char type, AuthScheme authScheme, URL url, String realm) {
         this.type = type;
-        this.authType = authType;
+        this.authScheme = authScheme;
         this.protocol = url.getProtocol().toLowerCase();
         this.host = url.getHost().toLowerCase();
         this.port = url.getPort();
@@ -264,12 +269,12 @@
      * In this case we do not use the path because the protection space
      * is identified by the host:port:realm only
      */
-    static AuthenticationInfo getServerAuth(URL url, String realm, char atype) {
+    static AuthenticationInfo getServerAuth(URL url, String realm, AuthScheme scheme) {
         int port = url.getPort();
         if (port == -1) {
             port = url.getDefaultPort();
         }
-        String key = SERVER_AUTHENTICATION + ":" + atype + ":" + url.getProtocol().toLowerCase()
+        String key = SERVER_AUTHENTICATION + ":" + scheme + ":" + url.getProtocol().toLowerCase()
                      + ":" + url.getHost().toLowerCase() + ":" + port + ":" + realm;
         AuthenticationInfo cached = getAuth(key, null);
         if ((cached == null) && requestIsInProgress (key)) {
@@ -308,8 +313,8 @@
      * Used in response to a challenge. Note, the protocol field is always
      * blank for proxies.
      */
-    static AuthenticationInfo getProxyAuth(String host, int port, String realm, char atype) {
-        String key = PROXY_AUTHENTICATION + ":" + atype + "::" + host.toLowerCase()
+    static AuthenticationInfo getProxyAuth(String host, int port, String realm, AuthScheme scheme) {
+        String key = PROXY_AUTHENTICATION + ":" + scheme + "::" + host.toLowerCase()
                         + ":" + port + ":" + realm;
         AuthenticationInfo cached = (AuthenticationInfo) cache.get(key, null);
         if ((cached == null) && requestIsInProgress (key)) {
@@ -409,7 +414,7 @@
         // This must be kept in sync with the getXXXAuth() methods in this
         // class.
         if (includeRealm) {
-            return type + ":" + authType + ":" + protocol + ":"
+            return type + ":" + authScheme + ":" + protocol + ":"
                         + host + ":" + port + ":" + realm;
         } else {
             return type + ":" + protocol + ":" + host + ":" + port;
--- a/src/share/classes/sun/net/www/protocol/http/BasicAuthentication.java	Fri Sep 18 16:24:26 2009 +0100
+++ b/src/share/classes/sun/net/www/protocol/http/BasicAuthentication.java	Fri Sep 18 22:18:19 2009 +0100
@@ -44,8 +44,6 @@
 
     private static final long serialVersionUID = 100L;
 
-    static final char BASIC_AUTH = 'B';
-
     /** The authentication string for this host, port, and realm.  This is
         a simple BASE64 encoding of "login:password".    */
     String auth;
@@ -56,7 +54,7 @@
     public BasicAuthentication(boolean isProxy, String host, int port,
                                String realm, PasswordAuthentication pw) {
         super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
-              BASIC_AUTH, host, port, realm);
+              AuthScheme.BASIC, host, port, realm);
         String plain = pw.getUserName() + ":";
         byte[] nameBytes = null;
         try {
@@ -86,7 +84,7 @@
     public BasicAuthentication(boolean isProxy, String host, int port,
                                String realm, String auth) {
         super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
-              BASIC_AUTH, host, port, realm);
+              AuthScheme.BASIC, host, port, realm);
         this.auth = "Basic " + auth;
     }
 
@@ -96,7 +94,7 @@
     public BasicAuthentication(boolean isProxy, URL url, String realm,
                                    PasswordAuthentication pw) {
         super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
-              BASIC_AUTH, url, realm);
+              AuthScheme.BASIC, url, realm);
         String plain = pw.getUserName() + ":";
         byte[] nameBytes = null;
         try {
@@ -126,7 +124,7 @@
     public BasicAuthentication(boolean isProxy, URL url, String realm,
                                    String auth) {
         super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
-              BASIC_AUTH, url, realm);
+              AuthScheme.BASIC, url, realm);
         this.auth = "Basic " + auth;
     }
 
--- a/src/share/classes/sun/net/www/protocol/http/DigestAuthentication.java	Fri Sep 18 16:24:26 2009 +0100
+++ b/src/share/classes/sun/net/www/protocol/http/DigestAuthentication.java	Fri Sep 18 22:18:19 2009 +0100
@@ -38,7 +38,6 @@
 import java.security.NoSuchAlgorithmException;
 import static sun.net.www.protocol.http.HttpURLConnection.HTTP_CONNECT;
 
-
 /**
  * DigestAuthentication: Encapsulate an http server authentication using
  * the "Digest" scheme, as described in RFC2069 and updated in RFC2617
@@ -50,8 +49,6 @@
 
     private static final long serialVersionUID = 100L;
 
-    static final char DIGEST_AUTH = 'D';
-
     private String authMethod;
 
     // Authentication parameters defined in RFC2617.
@@ -178,7 +175,10 @@
     public DigestAuthentication(boolean isProxy, URL url, String realm,
                                 String authMethod, PasswordAuthentication pw,
                                 Parameters params) {
-        super(isProxy?PROXY_AUTHENTICATION:SERVER_AUTHENTICATION, DIGEST_AUTH,url, realm);
+        super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
+              AuthScheme.DIGEST,
+              url,
+              realm);
         this.authMethod = authMethod;
         this.pw = pw;
         this.params = params;
@@ -187,7 +187,11 @@
     public DigestAuthentication(boolean isProxy, String host, int port, String realm,
                                 String authMethod, PasswordAuthentication pw,
                                 Parameters params) {
-        super(isProxy?PROXY_AUTHENTICATION:SERVER_AUTHENTICATION, DIGEST_AUTH,host, port, realm);
+        super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
+              AuthScheme.DIGEST,
+              host,
+              port,
+              realm);
         this.authMethod = authMethod;
         this.pw = pw;
         this.params = params;
--- a/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java	Fri Sep 18 16:24:26 2009 +0100
+++ b/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java	Fri Sep 18 22:18:19 2009 +0100
@@ -62,6 +62,12 @@
 import java.util.TimeZone;
 import java.net.MalformedURLException;
 import java.nio.ByteBuffer;
+import static sun.net.www.protocol.http.AuthScheme.BASIC;
+import static sun.net.www.protocol.http.AuthScheme.DIGEST;
+import static sun.net.www.protocol.http.AuthScheme.NTLM;
+import static sun.net.www.protocol.http.AuthScheme.NEGOTIATE;
+import static sun.net.www.protocol.http.AuthScheme.KERBEROS;
+import static sun.net.www.protocol.http.AuthScheme.UNKNOWN;
 
 /**
  * A class to represent an HTTP connection to a remote object.
@@ -231,9 +237,11 @@
     boolean             needToCheck = true;
     private boolean doingNTLM2ndStage = false; /* doing the 2nd stage of an NTLM server authentication */
     private boolean doingNTLMp2ndStage = false; /* doing the 2nd stage of an NTLM proxy authentication */
-    /* try auth without calling Authenticator */
-    private boolean tryTransparentNTLMServer = NTLMAuthentication.supportsTransparentAuth();
-    private boolean tryTransparentNTLMProxy = NTLMAuthentication.supportsTransparentAuth();
+
+    /* try auth without calling Authenticator. Used for transparent NTLM authentication */
+    private boolean tryTransparentNTLMServer = true;
+    private boolean tryTransparentNTLMProxy = true;
+
     /* Used by Windows specific code */
     Object authObj;
 
@@ -1270,7 +1278,7 @@
                     String raw = srvHdr.raw();
                     if (!doingNTLM2ndStage) {
                         if ((serverAuthentication != null)&&
-                            !(serverAuthentication instanceof NTLMAuthentication)) {
+                            serverAuthentication.getAuthScheme() != NTLM) {
                             if (serverAuthentication.isAuthorizationStale (raw)) {
                                 /* we can retry with the current credentials */
                                 disconnectInternal();
@@ -1523,8 +1531,8 @@
      */
     private AuthenticationInfo
         resetProxyAuthentication(AuthenticationInfo proxyAuthentication, AuthenticationHeader auth) {
-        if ((proxyAuthentication != null )&& ! (proxyAuthentication instanceof
-                                                        NTLMAuthentication)) {
+        if ((proxyAuthentication != null )&&
+             proxyAuthentication.getAuthScheme() != NTLM) {
             String raw = auth.raw();
             if (proxyAuthentication.isAuthorizationStale (raw)) {
                 /* we can retry with the current credentials */
@@ -1776,28 +1784,31 @@
             HeaderParser p = authhdr.headerParser();
             String realm = p.findValue("realm");
             String scheme = authhdr.scheme();
-            char schemeID;
+            AuthScheme authScheme = UNKNOWN;
             if ("basic".equalsIgnoreCase(scheme)) {
-                schemeID = BasicAuthentication.BASIC_AUTH;
+                authScheme = BASIC;
             } else if ("digest".equalsIgnoreCase(scheme)) {
-                schemeID = DigestAuthentication.DIGEST_AUTH;
+                authScheme = DIGEST;
             } else if ("ntlm".equalsIgnoreCase(scheme)) {
-                schemeID = NTLMAuthentication.NTLM_AUTH;
+                authScheme = NTLM;
                 doingNTLMp2ndStage = true;
             } else if ("Kerberos".equalsIgnoreCase(scheme)) {
-                schemeID = NegotiateAuthentication.KERBEROS_AUTH;
+                authScheme = KERBEROS;
                 doingNTLMp2ndStage = true;
             } else if ("Negotiate".equalsIgnoreCase(scheme)) {
-                schemeID = NegotiateAuthentication.NEGOTIATE_AUTH;
+                authScheme = NEGOTIATE;
                 doingNTLMp2ndStage = true;
-            } else {
-                schemeID = 0;
             }
+
             if (realm == null)
                 realm = "";
-            ret = AuthenticationInfo.getProxyAuth(host, port, realm, schemeID);
+            ret = AuthenticationInfo.getProxyAuth(host,
+                                                  port,
+                                                  realm,
+                                                  authScheme);
             if (ret == null) {
-                if (schemeID == BasicAuthentication.BASIC_AUTH) {
+                switch (authScheme) {
+                case BASIC:
                     InetAddress addr = null;
                     try {
                         final String finalHost = host;
@@ -1818,9 +1829,9 @@
                     if (a != null) {
                         ret = new BasicAuthentication(true, host, port, realm, a);
                     }
-                } else if (schemeID == DigestAuthentication.DIGEST_AUTH) {
-                    PasswordAuthentication a =
-                        privilegedRequestPasswordAuthentication(
+                    break;
+                case DIGEST:
+                    a = privilegedRequestPasswordAuthentication(
                                     host, null, port, url.getProtocol(),
                                     realm, scheme, url, RequestorType.PROXY);
                     if (a != null) {
@@ -1829,29 +1840,49 @@
                         ret = new DigestAuthentication(true, host, port, realm,
                                                             scheme, a, params);
                     }
-                } else if (schemeID == NTLMAuthentication.NTLM_AUTH) {
-                    PasswordAuthentication a = null;
-                    if (!tryTransparentNTLMProxy) {
-                        a = privilegedRequestPasswordAuthentication(
-                                            host, null, port, url.getProtocol(),
-                                            "", scheme, url, RequestorType.PROXY);
+                    break;
+                case NTLM:
+                    if (NTLMAuthenticationProxy.proxy.supported) {
+                        /* tryTransparentNTLMProxy will always be true the first
+                         * time around, but verify that the platform supports it
+                         * otherwise don't try. */
+                        if (tryTransparentNTLMProxy) {
+                            tryTransparentNTLMProxy =
+                                    NTLMAuthenticationProxy.proxy.supportsTransparentAuth;
+                        }
+                        a = null;
+                        if (tryTransparentNTLMProxy) {
+                            HttpCapture.finest("Trying Transparent NTLM authentication");
+                        } else {
+                            a = privilegedRequestPasswordAuthentication(
+                                                host, null, port, url.getProtocol(),
+                                                "", scheme, url, RequestorType.PROXY);
+                        }
+                        /* If we are not trying transparent authentication then
+                         * we need to have a PasswordAuthentication instance. For
+                         * transparent authentication (Windows only) the username
+                         * and password will be picked up from the current logged
+                         * on users credentials.
+                        */
+                        if (tryTransparentNTLMProxy ||
+                              (!tryTransparentNTLMProxy && a != null)) {
+                            ret = NTLMAuthenticationProxy.proxy.create(true, host, port, a);
+                        }
+
+                        /* set to false so that we do not try again */
+                        tryTransparentNTLMProxy = false;
                     }
-                    /* If we are not trying transparent authentication then
-                     * we need to have a PasswordAuthentication instance. For
-                     * transparent authentication (Windows only) the username
-                     * and password will be picked up from the current logged
-                     * on users credentials.
-                    */
-                    if (tryTransparentNTLMProxy ||
-                          (!tryTransparentNTLMProxy && a != null)) {
-                        ret = new NTLMAuthentication(true, host, port, a);
-                    }
-
-                    tryTransparentNTLMProxy = false;
-                } else if (schemeID == NegotiateAuthentication.NEGOTIATE_AUTH) {
+                    break;
+                case NEGOTIATE:
                     ret = new NegotiateAuthentication(new HttpCallerInfo(authhdr.getHttpCallerInfo(), "Negotiate"));
-                } else if (schemeID == NegotiateAuthentication.KERBEROS_AUTH) {
+                    break;
+                case KERBEROS:
                     ret = new NegotiateAuthentication(new HttpCallerInfo(authhdr.getHttpCallerInfo(), "Kerberos"));
+                    break;
+                case UNKNOWN:
+                    HttpCapture.finest("Unknown/Unsupported authentication scheme: " + scheme);
+                default:
+                    throw new AssertionError("should not reach here");
                 }
             }
             // For backwards compatibility, we also try defaultAuth
@@ -1896,27 +1927,26 @@
             HeaderParser p = authhdr.headerParser();
             String realm = p.findValue("realm");
             String scheme = authhdr.scheme();
-            char schemeID;
+            AuthScheme authScheme = UNKNOWN;
             if ("basic".equalsIgnoreCase(scheme)) {
-                schemeID = BasicAuthentication.BASIC_AUTH;
+                authScheme = BASIC;
             } else if ("digest".equalsIgnoreCase(scheme)) {
-                schemeID = DigestAuthentication.DIGEST_AUTH;
+                authScheme = DIGEST;
             } else if ("ntlm".equalsIgnoreCase(scheme)) {
-                schemeID = NTLMAuthentication.NTLM_AUTH;
+                authScheme = NTLM;
                 doingNTLM2ndStage = true;
             } else if ("Kerberos".equalsIgnoreCase(scheme)) {
-                schemeID = NegotiateAuthentication.KERBEROS_AUTH;
+                authScheme = KERBEROS;
                 doingNTLM2ndStage = true;
             } else if ("Negotiate".equalsIgnoreCase(scheme)) {
-                schemeID = NegotiateAuthentication.NEGOTIATE_AUTH;
+                authScheme = NEGOTIATE;
                 doingNTLM2ndStage = true;
-            } else {
-                schemeID = 0;
             }
+
             domain = p.findValue ("domain");
             if (realm == null)
                 realm = "";
-            ret = AuthenticationInfo.getServerAuth(url, realm, schemeID);
+            ret = AuthenticationInfo.getServerAuth(url, realm, authScheme);
             InetAddress addr = null;
             if (ret == null) {
                 try {
@@ -1931,13 +1961,14 @@
                 port = url.getDefaultPort();
             }
             if (ret == null) {
-                if (schemeID == NegotiateAuthentication.KERBEROS_AUTH) {
+                switch(authScheme) {
+                case KERBEROS:
                     ret = new NegotiateAuthentication(new HttpCallerInfo(authhdr.getHttpCallerInfo(), "Kerberos"));
-                }
-                if (schemeID == NegotiateAuthentication.NEGOTIATE_AUTH) {
+                    break;
+                case NEGOTIATE:
                     ret = new NegotiateAuthentication(new HttpCallerInfo(authhdr.getHttpCallerInfo(), "Negotiate"));
-                }
-                if (schemeID == BasicAuthentication.BASIC_AUTH) {
+                    break;
+                case BASIC:
                     PasswordAuthentication a =
                         privilegedRequestPasswordAuthentication(
                             url.getHost(), addr, port, url.getProtocol(),
@@ -1945,45 +1976,60 @@
                     if (a != null) {
                         ret = new BasicAuthentication(false, url, realm, a);
                     }
-                }
-
-                if (schemeID == DigestAuthentication.DIGEST_AUTH) {
-                    PasswordAuthentication a =
-                        privilegedRequestPasswordAuthentication(
+                    break;
+                case DIGEST:
+                    a = privilegedRequestPasswordAuthentication(
                             url.getHost(), addr, port, url.getProtocol(),
                             realm, scheme, url, RequestorType.SERVER);
                     if (a != null) {
                         digestparams = new DigestAuthentication.Parameters();
                         ret = new DigestAuthentication(false, url, realm, scheme, a, digestparams);
                     }
-                }
+                    break;
+                case NTLM:
+                    if (NTLMAuthenticationProxy.proxy.supported) {
+                        URL url1;
+                        try {
+                            url1 = new URL (url, "/"); /* truncate the path */
+                        } catch (Exception e) {
+                            url1 = url;
+                        }
 
-                if (schemeID == NTLMAuthentication.NTLM_AUTH) {
-                    URL url1;
-                    try {
-                        url1 = new URL (url, "/"); /* truncate the path */
-                    } catch (Exception e) {
-                        url1 = url;
+                        /* tryTransparentNTLMServer will always be true the first
+                         * time around, but verify that the platform supports it
+                         * otherwise don't try. */
+                        if (tryTransparentNTLMServer) {
+                            tryTransparentNTLMServer =
+                                    NTLMAuthenticationProxy.proxy.supportsTransparentAuth;
+                        }
+                        a = null;
+                        if (tryTransparentNTLMServer) {
+                            HttpCapture.finest("Trying Transparent NTLM authentication");
+                        } else {
+                            a = privilegedRequestPasswordAuthentication(
+                                url.getHost(), addr, port, url.getProtocol(),
+                                "", scheme, url, RequestorType.SERVER);
+                        }
+
+                        /* If we are not trying transparent authentication then
+                         * we need to have a PasswordAuthentication instance. For
+                         * transparent authentication (Windows only) the username
+                         * and password will be picked up from the current logged
+                         * on users credentials.
+                         */
+                        if (tryTransparentNTLMServer ||
+                              (!tryTransparentNTLMServer && a != null)) {
+                            ret = NTLMAuthenticationProxy.proxy.create(false, url1, a);
+                        }
+
+                        /* set to false so that we do not try again */
+                        tryTransparentNTLMServer = false;
                     }
-                    PasswordAuthentication a = null;
-                    if (!tryTransparentNTLMServer) {
-                        a = privilegedRequestPasswordAuthentication(
-                            url.getHost(), addr, port, url.getProtocol(),
-                            "", scheme, url, RequestorType.SERVER);
-                    }
-
-                    /* If we are not trying transparent authentication then
-                     * we need to have a PasswordAuthentication instance. For
-                     * transparent authentication (Windows only) the username
-                     * and password will be picked up from the current logged
-                     * on users credentials.
-                     */
-                    if (tryTransparentNTLMServer ||
-                          (!tryTransparentNTLMServer && a != null)) {
-                        ret = new NTLMAuthentication(false, url1, a);
-                    }
-
-                    tryTransparentNTLMServer = false;
+                    break;
+                case UNKNOWN:
+                    HttpCapture.finest("Unknown/Unsupported authentication scheme: " + scheme);
+                default:
+                    throw new AssertionError("should not reach here");
                 }
             }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/net/www/protocol/http/NTLMAuthenticationProxy.java	Fri Sep 18 22:18:19 2009 +0100
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2009 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package sun.net.www.protocol.http;
+
+import java.net.URL;
+import java.net.PasswordAuthentication;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import sun.net.www.http.HttpCapture;
+
+/**
+ * Proxy class for loading NTLMAuthentication, so as to remove static
+ * dependancy.
+ */
+class NTLMAuthenticationProxy {
+    private static Method supportsTA;
+    private static final String clazzStr = "sun.net.www.protocol.http.NTLMAuthentication";
+    private static final String supportsTAStr = "supportsTransparentAuth";
+
+    static final NTLMAuthenticationProxy proxy = tryLoadNTLMAuthentication();
+    static final boolean supported = proxy != null ? true : false;
+    static final boolean supportsTransparentAuth = supported ? supportsTransparentAuth(supportsTA) : false;
+
+    private final Constructor<? extends AuthenticationInfo> threeArgCtr;
+    private final Constructor<? extends AuthenticationInfo> fiveArgCtr;
+
+    private NTLMAuthenticationProxy(Constructor<? extends AuthenticationInfo> threeArgCtr,
+                                    Constructor<? extends AuthenticationInfo> fiveArgCtr) {
+        this.threeArgCtr = threeArgCtr;
+        this.fiveArgCtr = fiveArgCtr;
+    }
+
+
+    AuthenticationInfo create(boolean isProxy,
+                              URL url,
+                              PasswordAuthentication pw) {
+        try {
+            return threeArgCtr.newInstance(isProxy, url, pw);
+        } catch (ReflectiveOperationException roe) {
+            log(roe);
+        }
+
+        return null;
+    }
+
+    AuthenticationInfo create(boolean isProxy,
+                              String host,
+                              int port,
+                              PasswordAuthentication pw) {
+        try {
+            return fiveArgCtr.newInstance(isProxy, host, port, pw);
+        } catch (ReflectiveOperationException roe) {
+            log(roe);
+        }
+
+        return null;
+    }
+
+    /* Returns true if the NTLM implementation supports transparent
+     * authentication (try with the current users credentials before
+     * prompting for username and password, etc).
+     */
+    private static boolean supportsTransparentAuth(Method method) {
+        try {
+            return (Boolean)method.invoke(null);
+        } catch (ReflectiveOperationException roe) {
+            log(roe);
+        }
+
+        return false;
+    }
+
+    /**
+     * Loads the NTLM authentiation implementation through reflection. If
+     * the class is present, then it must have the required constructors and
+     * method. Otherwise, it is considered an error.
+     */
+    @SuppressWarnings("unchecked")
+    private static NTLMAuthenticationProxy tryLoadNTLMAuthentication() {
+        Class<? extends AuthenticationInfo> cl;
+        Constructor<? extends AuthenticationInfo> threeArg, fiveArg;
+        try {
+            cl = (Class<? extends AuthenticationInfo>)Class.forName(clazzStr, true, null);
+            if (cl != null) {
+                threeArg = cl.getConstructor(boolean.class,
+                                             URL.class,
+                                             PasswordAuthentication.class);
+                fiveArg = cl.getConstructor(boolean.class,
+                                            String.class,
+                                            int.class,
+                                            PasswordAuthentication.class);
+                supportsTA = cl.getDeclaredMethod(supportsTAStr);
+                return new NTLMAuthenticationProxy(threeArg,
+                                                   fiveArg);
+            }
+        } catch (ClassNotFoundException cnfe) {
+            log(cnfe);
+        } catch (ReflectiveOperationException roe) {
+            throw new AssertionError(roe);
+        }
+
+        return null;
+    }
+
+    static void log(Exception e) {
+        if (HttpCapture.isLoggable("FINEST")) {
+            HttpCapture.finest("NTLMAuthenticationProxy: " + e);
+        }
+    }
+}
--- a/src/share/classes/sun/net/www/protocol/http/NegotiateAuthentication.java	Fri Sep 18 16:24:26 2009 +0100
+++ b/src/share/classes/sun/net/www/protocol/http/NegotiateAuthentication.java	Fri Sep 18 22:18:19 2009 +0100
@@ -34,7 +34,10 @@
 import java.net.URL;
 import java.io.IOException;
 import java.net.Authenticator.RequestorType;
-
+import java.lang.reflect.Constructor;
+import sun.net.www.http.HttpCapture;
+import static sun.net.www.protocol.http.AuthScheme.NEGOTIATE;
+import static sun.net.www.protocol.http.AuthScheme.KERBEROS;
 
 /**
  * NegotiateAuthentication:
@@ -49,9 +52,6 @@
 
     final private HttpCallerInfo hci;
 
-    static final char NEGOTIATE_AUTH = 'S';
-    static final char KERBEROS_AUTH = 'K';
-
     // These maps are used to manage the GSS availability for diffrent
     // hosts. The key for both maps is the host name.
     // <code>supported</code> is set when isSupported is checked,
@@ -68,11 +68,10 @@
     * @param hci a schemed object.
     */
     public NegotiateAuthentication(HttpCallerInfo hci) {
-        super(RequestorType.PROXY==hci.authType?
-                    PROXY_AUTHENTICATION:SERVER_AUTHENTICATION,
-                hci.scheme.equalsIgnoreCase("Negotiate")?
-                    NEGOTIATE_AUTH:KERBEROS_AUTH,
-                hci.url, "");
+        super(RequestorType.PROXY==hci.authType ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
+              hci.scheme.equalsIgnoreCase("Negotiate") ? NEGOTIATE : KERBEROS,
+              hci.url,
+              "");
         this.hci = hci;
     }
 
@@ -249,13 +248,42 @@
         // The current implementation will make sure NegotiatorImpl is not
         // directly referenced when compiling, thus smooth the way of building
         // the J2SE platform where HttpURLConnection is a bootstrap class.
+        //
+        // Makes NegotiatorImpl, and the security classes it references, a
+        // runtime dependency rather than a static one.
 
-        Class clazz = Class.forName("sun.net.www.protocol.http.NegotiatorImpl");
-        java.lang.reflect.Constructor c = clazz.getConstructor(HttpCallerInfo.class);
-        return (Negotiator) (c.newInstance(hci));
+        Class clazz;
+        Constructor c;
+        try {
+            clazz = Class.forName("sun.net.www.protocol.http.NegotiatorImpl", true, null);
+            c = clazz.getConstructor(HttpCallerInfo.class);
+        } catch (ClassNotFoundException cnfe) {
+            log(cnfe);
+            throw cnfe;
+        } catch (ReflectiveOperationException roe) {
+            // if the class is there then something seriously wrong if
+            // the constructor is not.
+            throw new AssertionError(roe);
+        }
+
+        try {
+            return (Negotiator) (c.newInstance(hci));
+        } catch (ReflectiveOperationException roe) {
+            log(roe);
+            Throwable t = roe.getCause();
+            if (t != null && t instanceof Exception)
+                log((Exception)t);
+            throw roe;
+        }
     }
 
     abstract byte[] firstToken() throws IOException;
 
     abstract byte[] nextToken(byte[] in) throws IOException;
+
+    static void log(Exception e) {
+        if (HttpCapture.isLoggable("FINEST")) {
+            HttpCapture.finest("NegotiateAuthentication: " + e);
+        }
+    }
 }
--- a/src/solaris/classes/sun/net/www/protocol/http/NTLMAuthentication.java	Fri Sep 18 16:24:26 2009 +0100
+++ b/src/solaris/classes/sun/net/www/protocol/http/NTLMAuthentication.java	Fri Sep 18 22:18:19 2009 +0100
@@ -25,18 +25,23 @@
 
 package sun.net.www.protocol.http;
 
-import java.util.Arrays;
-import java.util.StringTokenizer;
-import java.util.Random;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.InetAddress;
+import java.net.PasswordAuthentication;
+import java.net.UnknownHostException;
+import java.net.URL;
+import java.security.GeneralSecurityException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import javax.crypto.Cipher;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.DESKeySpec;
 
 import sun.net.www.HeaderParser;
 
-import java.io.*;
-import javax.crypto.*;
-import javax.crypto.spec.*;
-import java.security.*;
-import java.net.*;
-
 /**
  * NTLMAuthentication:
  *
@@ -66,8 +71,6 @@
 class NTLMAuthentication extends AuthenticationInfo {
     private static final long serialVersionUID = -2403849171106437142L;
 
-    static char NTLM_AUTH = 'N';
-
     private byte[] type1;
     private byte[] type3;
 
@@ -142,7 +145,10 @@
      * from a system property: "http.auth.ntlm.domain".
      */
     public NTLMAuthentication(boolean isProxy, URL url, PasswordAuthentication pw) {
-        super(isProxy?PROXY_AUTHENTICATION:SERVER_AUTHENTICATION, NTLM_AUTH, url, "");
+        super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
+                AuthScheme.NTLM,
+                url,
+                "");
         init (pw);
     }
 
@@ -166,7 +172,11 @@
     */
     public NTLMAuthentication(boolean isProxy, String host, int port,
                                 PasswordAuthentication pw) {
-        super(isProxy?PROXY_AUTHENTICATION:SERVER_AUTHENTICATION, NTLM_AUTH,host, port, "");
+        super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
+                AuthScheme.NTLM,
+                host,
+                port,
+                "");
         init (pw);
     }
 
--- a/src/windows/classes/sun/net/www/protocol/http/NTLMAuthentication.java	Fri Sep 18 16:24:26 2009 +0100
+++ b/src/windows/classes/sun/net/www/protocol/http/NTLMAuthentication.java	Fri Sep 18 22:18:19 2009 +0100
@@ -25,18 +25,13 @@
 
 package sun.net.www.protocol.http;
 
-import java.util.Arrays;
-import java.util.StringTokenizer;
-import java.util.Random;
-
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.PasswordAuthentication;
+import java.net.UnknownHostException;
+import java.net.URL;
 import sun.net.www.HeaderParser;
 
-import java.io.*;
-import javax.crypto.*;
-import javax.crypto.spec.*;
-import java.security.*;
-import java.net.*;
-
 /**
  * NTLMAuthentication:
  *
@@ -47,7 +42,6 @@
 
     private static final long serialVersionUID = 100L;
 
-    static final char NTLM_AUTH = 'N';
     private String hostname;
     private static String defaultDomain; /* Domain to use if not specified by user */
 
@@ -88,7 +82,10 @@
      * from a system property: "http.auth.ntlm.domain".
      */
     public NTLMAuthentication(boolean isProxy, URL url, PasswordAuthentication pw) {
-        super(isProxy?PROXY_AUTHENTICATION:SERVER_AUTHENTICATION, NTLM_AUTH, url, "");
+        super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
+              AuthScheme.NTLM,
+              url,
+              "");
         init (pw);
     }
 
@@ -119,7 +116,11 @@
     */
     public NTLMAuthentication(boolean isProxy, String host, int port,
                                 PasswordAuthentication pw) {
-        super(isProxy?PROXY_AUTHENTICATION:SERVER_AUTHENTICATION, NTLM_AUTH,host, port, "");
+        super(isProxy?PROXY_AUTHENTICATION:SERVER_AUTHENTICATION,
+              AuthScheme.NTLM,
+              host,
+              port,
+              "");
         init (pw);
     }