15

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 凭据不能被忽略的地方吗?

4

4 回答 4

7

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

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

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

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

于 2013-02-05T04:27:38.130 回答
6

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

有一个对 Java Bug 数据库进行增强的请求。查看该报告,了解 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则不会调用您的自定义 Authenticator 代码。看到这个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源代码,我使用了这个 Java 反编译器。打开位于 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"

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

之后,一切正常。

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

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

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

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

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

希望这可以帮助。

于 2012-01-26T20:21:33.273 回答
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

于 2013-04-04T12:49:50.373 回答
1

对于 Java v8 212 或更高版本,默认情况下禁用通过 NTLMv2 进行的“透明”SSO 身份验证,因为此 CVE:https ://nvd.nist.gov/vuln/detail/CVE-2019-2426 。有关更多信息:如何在调用任何 url 时提供 ntlm 身份验证?

于 2019-05-21T12:35:30.240 回答