6882594: Remove static dependancy on NTLM authentication
Reviewed-by: alanb, weijun
This commit is contained in:
parent
be7dddc8a3
commit
fc6bda88ab
@ -86,9 +86,11 @@ FILES_java = \
|
||||
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 \
|
||||
|
@ -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 @@ public interface AuthCache {
|
||||
* 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
|
||||
|
@ -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 @@ public abstract class AuthCacheValue implements Serializable {
|
||||
|
||||
AuthCacheValue() {}
|
||||
|
||||
/**
|
||||
* Proxy or Server
|
||||
*/
|
||||
abstract Type getAuthType ();
|
||||
|
||||
/**
|
||||
* Authentication scheme
|
||||
*/
|
||||
abstract AuthScheme getAuthScheme();
|
||||
|
||||
/**
|
||||
* name of server/proxy
|
||||
*/
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -85,6 +85,11 @@ abstract class AuthenticationInfo extends AuthCacheValue implements Cloneable {
|
||||
AuthCacheValue.Type.Server:
|
||||
AuthCacheValue.Type.Proxy;
|
||||
}
|
||||
|
||||
AuthScheme getAuthScheme() {
|
||||
return authScheme;
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
@ -151,7 +156,7 @@ abstract class AuthenticationInfo extends AuthCacheValue implements Cloneable {
|
||||
}
|
||||
|
||||
//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 @@ abstract class AuthenticationInfo extends AuthCacheValue implements Cloneable {
|
||||
/** 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 @@ abstract class AuthenticationInfo extends AuthCacheValue implements Cloneable {
|
||||
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 @@ abstract class AuthenticationInfo extends AuthCacheValue implements Cloneable {
|
||||
* 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 @@ abstract class AuthenticationInfo extends AuthCacheValue implements Cloneable {
|
||||
* 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 @@ abstract class AuthenticationInfo extends AuthCacheValue implements Cloneable {
|
||||
* 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 @@ abstract class AuthenticationInfo extends AuthCacheValue implements Cloneable {
|
||||
// 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;
|
||||
|
@ -44,8 +44,6 @@ class BasicAuthentication extends AuthenticationInfo {
|
||||
|
||||
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 @@ class BasicAuthentication extends AuthenticationInfo {
|
||||
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 @@ class BasicAuthentication extends AuthenticationInfo {
|
||||
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 @@ class BasicAuthentication extends AuthenticationInfo {
|
||||
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 @@ class BasicAuthentication extends AuthenticationInfo {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,6 @@ import java.security.MessageDigest;
|
||||
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 @@ class DigestAuthentication extends AuthenticationInfo {
|
||||
|
||||
private static final long serialVersionUID = 100L;
|
||||
|
||||
static final char DIGEST_AUTH = 'D';
|
||||
|
||||
private String authMethod;
|
||||
|
||||
// Authentication parameters defined in RFC2617.
|
||||
@ -178,7 +175,10 @@ class DigestAuthentication extends AuthenticationInfo {
|
||||
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 @@ class DigestAuthentication extends AuthenticationInfo {
|
||||
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;
|
||||
|
@ -62,6 +62,12 @@ import java.text.SimpleDateFormat;
|
||||
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 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
||||
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 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
||||
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 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
||||
*/
|
||||
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 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
||||
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 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
||||
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 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
||||
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);
|
||||
}
|
||||
/* 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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
tryTransparentNTLMProxy = false;
|
||||
} else if (schemeID == NegotiateAuthentication.NEGOTIATE_AUTH) {
|
||||
/* set to false so that we do not try again */
|
||||
tryTransparentNTLMProxy = false;
|
||||
}
|
||||
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 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
||||
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 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
||||
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 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
|
||||
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;
|
||||
}
|
||||
PasswordAuthentication a = null;
|
||||
if (!tryTransparentNTLMServer) {
|
||||
a = privilegedRequestPasswordAuthentication(
|
||||
url.getHost(), addr, port, url.getProtocol(),
|
||||
"", scheme, url, RequestorType.SERVER);
|
||||
}
|
||||
/* 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 = new NTLMAuthentication(false, url1, a);
|
||||
}
|
||||
/* 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);
|
||||
}
|
||||
|
||||
tryTransparentNTLMServer = false;
|
||||
/* set to false so that we do not try again */
|
||||
tryTransparentNTLMServer = false;
|
||||
}
|
||||
break;
|
||||
case UNKNOWN:
|
||||
HttpCapture.finest("Unknown/Unsupported authentication scheme: " + scheme);
|
||||
default:
|
||||
throw new AssertionError("should not reach here");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -34,7 +34,10 @@ import sun.misc.BASE64Encoder;
|
||||
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 @@ class NegotiateAuthentication extends AuthenticationInfo {
|
||||
|
||||
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 @@ class NegotiateAuthentication extends AuthenticationInfo {
|
||||
* @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 @@ abstract class Negotiator {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 @@ import java.net.*;
|
||||
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 @@ class NTLMAuthentication extends AuthenticationInfo {
|
||||
* 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 @@ class NTLMAuthentication extends AuthenticationInfo {
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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 @@ class NTLMAuthentication extends AuthenticationInfo {
|
||||
|
||||
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 @@ class NTLMAuthentication extends AuthenticationInfo {
|
||||
* 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 @@ class NTLMAuthentication extends AuthenticationInfo {
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user