可以禁用Java在Windows上的"单点登录"(使用"凭据管理器"中的凭据)吗?

Mar*_*ica 14 java windows credentials authenticator

Java SE 6文档中的Oracle "Http Authentication"页面说"如果您作为域用户在Windows计算机上运行,​​或者您在已经发出kinit命令并获得凭据缓存的Linux或Solaris计算机上运行"那么实例传递给Authenticator.setDefault()"将被完全忽略".

这与我观察到的相符:在Windows系统上为主机X设置HTTP或HTTPS连接始终从"Windows Vault"的"Windows凭据"传递主机X的凭据,如我的Windows 7"凭据管理器"中所示控制面板页面.

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

有没有办法覆盖记录的行为,即有没有办法忽略Windows存储的凭据?

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

jme*_*end 6

我找了你问的同样的事情.到目前为止,我还没有找到JDK的方法来做到这一点.

有关Java Bug数据库的增强请求.看一下这份报告,看看是否得到了Sun的回复(投票通过报告,希望很快得到解决).

我最终做的是覆盖sun.net.www.protocol.http.NTLMAuthentication课程.通过观察sun.net.www.protocol.http.HttpURLAuthentication,我发现你唯一需要修改的是:

NTLMAuthentication.supportsTransparentAuth()
Run Code Online (Sandbox Code Playgroud)

该方法true在Windows平台上具有硬编码返回值false.此代码从Windows 7上安装的JDK中提取:

static boolean supportsTransparentAuth()
{
  return true;
}
Run Code Online (Sandbox Code Playgroud)

该方法告诉您的是,默认情况下是否应使用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);
}
Run Code Online (Sandbox Code Playgroud)

为了获得NTLMAuthentication源代码,我使用了这个Java反编译器.打开位于JDK安装文件夹中的rt.jar并复制所需的类代码.

然后,我只是改为supportsTransparentAuth返回false.但是,如果此方法首先检查系统属性然后根据该属性返回true或false,那将是非常期望的.

为了编译它,我只是将java文件放在sun/net/www/protocol/http文件夹结构下并运行:

javac NTLMAuthentication.java
Run Code Online (Sandbox Code Playgroud)

然后运行我的应用程序:

java -Xbootclasspath:"path/to/your/sun/net/www/protocol/http/classes;normal/JDK/boot/directories"
Run Code Online (Sandbox Code Playgroud)

这将告诉JVM NTLMAuthentication在rt.jar中加载我们的实现.您必须小心不要错过任何默认的类加载路径-Xbootclasspath,否则会出现ClassNotFound错误.

在那之后,一切正常.

这种方法有一些重要的缺点,你应该知道.

  • 存在安全风险.任何人都可以在您的启动文件夹中删除不同的.class文件并窃取用户凭据或其他重要信息.
  • Sun软件包中的代码如有更改,恕不另行通知,因此与您的更改不兼容.
  • 如果部署此代码,则将违反Sun代码许可证.从文档:

-Xbootclasspath:bootclasspath指定以分号分隔的目录,JAR存档和ZIP存档列表,以搜索引导类文件.这些用于代替Java 2 SDK中包含的引导类文件.注意:不应部署使用此选项来覆盖rt.jar中的类的应用程序,因为这样做会违反Java 2 Runtime Environment二进制代码许可证.

因此,这绝对不适合生产环境.

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

希望这可以帮助.


Rob*_*wer 6

至少在Java 7中有一个叫做的类sun.net.www.protocol.http.ntlm.NTLMAuthenticationCallback似乎有助于这种情况.仅针对"受信任"URL调用单点登录.

以下是关闭它的最简单实现(在打开HTTP连接之前调用此初始化程序):

static {
    NTLMAuthenticationCallback.setNTLMAuthenticationCallback(new NTLMAuthenticationCallback()
    {
        @Override
        public boolean isTrustedSite(URL url)
        {
            return false;
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

我想默认的实现是信任一切:(

  • 这个发现+1.是的,我在[DefaultNTLMAuthenticationCallback](http://www.docjar.com/docs/api/sun/net/www/protocol/http/ntlm/NTLMAuthenticationCallback$DefaultNTLMAuthenticationCallback.html#isTrustedSite%28URL%29)中看到默认实现是尝试静默(JavaDoc称之为'透明')身份验证. (2认同)