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

Posted

技术标签:

【中文标题】可以禁用 Windows 上 Java 的“单点登录”(使用“凭据管理器”中的凭据)吗?【英文标题】:Can Java's 'single sign-on' (use credentials from 'Credential Manager') on Windows be disabled? 【发布时间】:2011-09-05 07:21:41 【问题描述】:

Java SE 6 文档中 Oracle 的 "Http Authentication" 页面说:“如果您以域用户身份在 Windows 机器上运行,或者,您在已经发出 kinit 命令的 Linux 或 Solaris 机器上运行并获得了凭证缓存”然后传递给Authenticator.setDefault()的实例“将被完全忽略”。

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

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

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

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

【问题讨论】:

您可以在“sun.net.www.protocol.http.HttpURLConnection”类上找到验证是否使用 Windows 凭据的代码。查看“NTLMAuthentication”实例的创建和“tryTransparentNTLMServer”标志。我想做和你一样的事情,但我也不知道该怎么做。 【参考方案1】:

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

【讨论】:

【参考方案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

【讨论】:

+1 谢谢!请注意,引用的帖子说 Java 6 上的包名称不同,即。 sun.net.www.protocol.http.【参考方案3】:

至少在 Java 7 中有一个名为 sun.net.www.protocol.http.ntlm.NTLMAuthenticationCallback 的类似乎有助于解决这种情况。单点登录仅对“受信任”的 URL 调用。

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

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

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

【讨论】:

这个发现+1。是的,我在DefaultNTLMAuthenticationCallback 中看到默认实现是尝试静默(JavaDoc 称之为“透明”)身份验证。【参考方案4】:

我一直在寻找您所要求的相同内容。到目前为止,我还没有在 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 类的这个片段:

//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 开发工具包。注意:使用此选项的应用程序 不应部署覆盖 rt.jar 中的类,因为这样做会 违反 Java 2 Runtime Environment 二进制代码许可。

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

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

希望这会有所帮助。

【讨论】:

谢谢。我已经接受了这个答案,这与我自己之前的分析(也通过 Sun JRE 代码反编译)一致,即 Sun 的标准代码无法避免这种情况。感谢您找到解决此设计缺陷的方法(如我所见)——但这是为生产使用而设计的,我绝对不会(告诉同事)使用它。我将投票给这个错误 ID 7133281。 是的,对于生产用途,绝对应该避免这种情况。幸运的是,我只是需要它来进行演示,所以它对我有用。 如果有人遇到这个问题,有一个更简单的方法,即使用 Apache HTTP Client 4 而不是 Java 底层的 HTTP API。在我的特殊情况下,我最终使用Apache HTTP Client 和JCIFs NTLM 的组合实现来解决Java 中所有与NTLM 相关的问题。 @Marnix-Klooster 提到的错误 ID 7133281 似乎不再存在:bugs.sun.com/bugdatabase/view_bug.do?bug_id=7133281 -- 有人知道发生了什么吗? 我在这种情况下使用的另一个解决方案是 runas 命令,我只需使用我想要进行身份验证的用户启动我的 java 进程。可以像这样使用bat文件自动启动应用程序,或者使用其他Windows工具在不同用户下运行应用程序

以上是关于可以禁用 Windows 上 Java 的“单点登录”(使用“凭据管理器”中的凭据)吗?的主要内容,如果未能解决你的问题,请参考以下文章

单点登录单例

单点登录是什么意思?单点登录在办公中起到什么作用?

CAS单点登录学习:服务端搭建

单点登录方案[学习]

如何在Windows2008中禁用IPv6

如何在 Windows 7 上删除 Java 程序的标题栏和任务栏图标?