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

时间:2011-05-31 08:29:51

标签: java windows credentials authenticator

来自Java SE 6文档的Oracle "Http Authentication"页面说“如果您作为域用户在Windows计算机上运行,​​或者您在已发布{{{ 1}}命令并获得凭证缓存“然后传递给Authenticator.setDefault()的实例”将被完全忽略“。

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

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

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

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

4 个答案:

答案 0 :(得分:6)

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

有一项关于Java Bug数据库的增强请求。看看report,看看是否得到了Sun的回复(对报告进行投票,以便很快得到解决)。

我最终做的是覆盖sun.net.www.protocol.http.NTLMAuthentication类。通过查看sun.net.www.protocol.http.HttpURLAuthentication,我发现您需要修改的唯一内容是:

NTLMAuthentication.supportsTransparentAuth()

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

static boolean supportsTransparentAuth()
{
  return true;
}

该方法告诉我们默认情况下是否应使用Windows凭据。如果设置为true将不会调用自定义身份验证器代码。请参阅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);
}

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

然后,我只是将supportsTransparentAuth更改为false。但是,如果此方法首先检查系统属性,然后根据该方法返回true或false,则非常需要。

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

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:bootclasspath指定以分号分隔的目录,JAR存档和ZIP存档列表,以搜索引导类   文件。这些用于代替包含在其中的引导类文件   Java 2 SDK。注意:出于此目的使用此选项的应用程序   重写rt.jar中的类不应该这样做   违反Java 2 Runtime Environment二进制代码许可证。

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

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

希望这有帮助。

答案 1 :(得分: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;
        }
    });
}

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

答案 2 :(得分:2)

似乎sun.net.www.protocol.http.ntlm.NTLMAuthenticationCallback类被添加到java 6.0补丁24+中,因此建议的解决方案也可以在java 6.0中使用。 请参阅以下帖子中的参考: http://www.mail-archive.com/users@cxf.apache.org/msg22897.html

答案 3 :(得分:0)

在Java v8 212或更高版本中,由于此CVE:https://nvd.nist.gov/vuln/detail/CVE-2019-2426,默认情况下禁用通过NTLMv2的“透明” SSO身份验证。 有关更多信息:How to provide ntlm authentication while calling any url?