I've looked for the same thing you are asking. So far, I haven't found a way on the JDK to do that.
There is a request for enhancement on Java Bug Database. Take a look at the report to find out if that gets a response from Sun (vote up the report so that hopefully that gets fixed soon).
What I ended up doing, was override sun.net.www.protocol.http.NTLMAuthentication
class. By looking at sun.net.www.protocol.http.HttpURLAuthentication
, I found that the only thing you need to modify is the result of:
NTLMAuthentication.supportsTransparentAuth()
That method has a hardcoded return value, true
on Windows platforms and false
otherwise. This code is extracted from a JDK installed on Windows 7:
static boolean supportsTransparentAuth()
{
return true;
}
What that method tells is if Windows credentials should be used by default. If set to true
, your custom Authenticator code won't be called. See this fragment of HttpURLConnection
class:
//Declared as a member variable of HttpURLConnection
private boolean tryTransparentNTLMServer = NTLMAuthentication.supportsTransparentAuth();
//Inside of getServerAuthentication method.
PasswordAuthentication a = null;
if (!tryTransparentNTLMServer) {
//If set to false, this will call Authenticator.requestPasswordAuthentication().
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)) {
//If set to true or if Authenticator did not return any credentials, use Windows credentials.
//NTLMAuthentication constructor, if receives a == null will fetch current looged user credentials.
ret = new NTLMAuthentication(false, url1, a);
}
To get NTLMAuthentication
source code, I used this Java decompiler. Opened rt.jar located on the JDK installation folder and copied the desired class code.
Then, I simply changed supportsTransparentAuth
to return false. However, it would be highly desirable if this method checked first a system property and then return true or false based on that.
To compile it, I just placed the java file under sun/net/www/protocol/http folder structure and run:
javac NTLMAuthentication.java
Then run my application using:
java -Xbootclasspath:"path/to/your/sun/net/www/protocol/http/classes;normal/JDK/boot/directories"
That will tell the JVM to load our implementation of NTLMAuthentication
before the one in rt.jar. You have to be careful to don't miss any default class loading paths with -Xbootclasspath
, or there will be ClassNotFound
errors.
After that, everything worked just fine.
This approach has important drawbacks that you should be aware of.
- There are security risks. Anyone could drop a different .class file on your boot folder and steal the user credentials or other important information.
- Code from Sun packages can change without notice and thus be incompatible with your changes.
- If you deploy this code, you will be contravening the Sun code license. From the documentation:
-Xbootclasspath:bootclasspath Specify a semicolon-separated list of directories, JAR archives, and ZIP archives to search for boot class
files. These are used in place of the boot class files included in the
Java 2 SDK. Note: Applications that use this option for the purpose of
overriding a class in rt.jar should not be deployed as doing so would
contravene the Java 2 Runtime Environment binary code license.
So, this is definitely not suitable for production environments.
Finally, this is an excellent source about boot class path option and Java class loaders: PDF
Hope this helps.