2011-05-31 53 views
14

甲骨文在Java SE 6文档"Http Authentication"页说:“如果你在Windows机器上运行作为域用户,或者你是一个Linux或Solaris机器已经发布了kinit命令,并拿到了证书缓存上运行“那么传递给Authenticator.setDefault()的实例”将被完全忽略“。Windows上的Java'单一登录'(使用'Credential Manager'的凭据)是否被禁用?

这与我观察到的情况相匹配:在Windows系统上为主机设置HTTP或HTTPS连接X总是从“Windows Vault”的“Windows凭据”传递主机X的凭据,如我的Windows 7 'Credential Manager'控制面板页面。

但是,在我的使用案例中,我不想使用Windows可能存储的任何凭据,而是总是要使用我在代码中明确指定的凭据。

有没有办法重写记录的行为,即有没有办法忽略由Windows存储的凭据?

更新:如果不是,有人可以指向我在Java SE 6源代码中的位置,我可以看到存储的Windows凭据不能被忽略吗?

+0

您可以在'sun.net.www.protocol.http.HttpURLConnection'类上找到验证使用Windows凭据的代码。看看创建'NTLMAuthentication'实例和标志'tryTransparentNTLMServer'。我期待着和你一样做同样的事情,但我不知道该怎么做。 – jmend 2012-01-25 16:33:41

回答

6

我看你都在问同样的事情。到目前为止,我还没有在JDK上找到这样做的方法。

没有为增强对Java的错误数据库的请求。看看report,看看是否得到了Sun的回应(投票支持报告,希望尽快得到解决)。

我最终什么事做,是覆盖sun.net.www.protocol.http.NTLMAuthentication类。通过查看sun.net.www.protocol.http.HttpURLAuthentication,我发现需要修改的唯一的事情的结果是:

NTLMAuthentication.supportsTransparentAuth() 

这种方法有一个硬编码的返回值,true在Windows平台和false否则。此代码是从安装在Windows 7上的JDK中提取的:

static boolean supportsTransparentAuth() 
{ 
    return true; 
} 

该方法告诉的是,是否应默认使用Windows凭据。如果设置为true,您的自定义验证码不会被称为。见HttpURLConnection类的这个片段:

//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); 
} 

要获得NTLMAuthentication源代码,我用this Java decompiler。打开位于JDK安装文件夹中的rt.jar并复制所需的类代码。

然后,我只是改变supportsTransparentAuth返回false。但是,如果此方法首先检查一个系统属性,然后基于此属性返回true或false,则将非常合意。

要编译它,我只是放置在太阳/网/网络/协议/ HTTP文件夹结构中的java文件并运行:

javac NTLMAuthentication.java 

然后使用运行我的应用程序:

java -Xbootclasspath:"path/to/your/sun/net/www/protocol/http/classes;normal/JDK/boot/directories" 

那会告诉JVM在rt.jar之前加载我们的NTLMAuthentication实现。你必须小心,不要错过任何默认的类加载路径-Xbootclasspath,否则会有ClassNotFound错误。

之后,一切正常。

这种方法有很重要的缺点,您应该注意。

  • 存在安全隐患。任何人都可以在引导文件夹中放置不同的.class文件,并窃取用户凭据或其他重要信息。
  • Sun软件包中的代码可能会在没有通知的情况下更改,因此与您的更改不符。
  • 如果您部署此代码,您将违反Sun代码许可证。从documentation

-Xbootclasspath:启动类路径指定目录,JAR档案的分号分隔的列表,和ZIP文件搜索引导类 文件。这些用于代替包含在 Java 2 SDK中的引导类文件。注意:使用此选项的应用程序用于覆盖rt.jar中的类 不应该这样部署,因为 与Java 2运行时环境二进制代码许可证相冲突。

所以,这绝对不适合生产环境。

最后,这是关于引导类路径选项和Java类加载器的极好来源:PDF

希望这有助于。

+0

谢谢。我已经接受了这个答案,这与我之前的分析(也是通过Sun JRE代码反编译)一致,认为没有办法通过Sun的标准代码来避免这种情况。感谢您找出解决这个设计缺陷的方法(正如我所看到的那样) - 但这是为生产使用而设计的,我绝对不会(告诉同事)使用它。我会投票支持此错误ID 7133281。 – 2012-01-26 20:50:51

+0

是的,对于生产用途这应该是绝对避免的。幸运的是,我只是需要它进行演示,所以它对我有用。 – jmend 2012-01-26 21:31:35

+1

如果有人想到这一点,有一种更简单的方法,它使用[Apache HTTP Client 4](http://hc.apache.org/httpcomponents-client-ga/)而不是Java底层的[HTTP API]( http://docs.oracle.com/javase/6/docs/api/java/net/HttpURLConnection.html)。在我的特殊情况下,我最终使用了[Apache HTTP Client](http://hc.apache.org/httpcomponents-client-ga/)和[JCIFs NTLM](http://jcifs.samba.org) /src/docs/ntlmhttpauth.html)实现来解决Java中的所有NTLM相关问题。 – jmend 2012-09-03 19:49:20

6

至少在Java 7中有一个名为sun.net.www.protocol.http.ntlm.NTLMAuthenticationCallback的类似乎有助于这种情况。单一登录仅针对“可信”网址进行调用。

这里是将其关闭最简单的实现(也称为展开HTTP连接在此之前初始化器):

static { 
    NTLMAuthenticationCallback.setNTLMAuthenticationCallback(new NTLMAuthenticationCallback() 
    { 
     @Override 
     public boolean isTrustedSite(URL url) 
     { 
      return false; 
     } 
    }); 
} 

我猜默认的实现是要相信一切:(

+2

+1下运行应用程序以查找此应用程序。是的,我在[DefaultNTLMAuthenticationCallback](http://www.docjar.com/docs/api/sun/net/www/protocol/http/ntlm/NTLMAuthenticationCallback$DefaultNTLMAuthenticationCallback.html#isTrustedSite%28URL%29)中看到默认实现是尝试沉默(JavaDoc称为“透明”)的身份验证。 – 2013-02-05 17:25:47

2

似乎该类sun.net.www.protocol.http.ntlm.NTLMAuthenticationCallback被添加到Java 6.0补丁24+,所以解决方案建议可以在Java 6.0中工作。 请参阅以下文章中的参考: http://www.mail-archive.com/[email protected]/msg22897.html

+0

+1谢谢!请注意,引用的帖子说,Java 6上的软件包名称是不同的, 'sun.net.www.protocol.http'。 – 2013-04-11 15:52:03

相关问题