重置身份验证器凭据

9
我们有一个实用类中的静态方法,可以从URL下载文件。如果需要用户名和密码,已经设置了身份验证器,可以检索凭据。问题是,只要凭证有效,第一次成功连接的凭证就会用于之后的每个连接。这是一个问题,因为我们的代码是多用户的,由于不会为每个连接检查凭据,所以可能会出现没有适当凭据的用户下载文件的情况。
以下是我们正在使用的代码。
private static URLAuthenticator auth;

public static File download(String url, String username, String password, File newFile)
{
    auth.set(username, password);
    Authenticator.setDefault(auth);
    URL fURL = new URL(url);
    OutputStream out = new BufferedOutputStream(new FileOutputStream(newFile));
    URLConnection conn = fURL.openConnection();
    InputStream in = conn.getInputStream();

    try
    {
        copyStream(in, out);
    }
    finally
    {
        if (in != null)
            in.close();
        if (out != null)
            out.close();
    }

    return newFile;
}

public class URLAuthenticator extends Authenticator
{
    private String username;
    private String password;

    public URLAuthenticator(String username, String password)
    {
         set(username, password);
    }

    public void set(String username, String password)
    {
        this.username = username;
        this.password = password;
    }

    protected PasswordAuthentication getPasswordAuthentication()
    {
        log.debug("Retrieving credentials '" + username + "', '" + password + "'.");
        return new PasswordAuthentication(username, password.toCharArray());
    }
}

我只在第一次下载文件时看到了从getPasswordAuthentication中的日志声明。之后,即使凭据已重置,也不再调用getPasswordAuthentication。结果是,在第一次成功连接后,可以输入无效凭据,并且仍然可以成功连接。这可能是由于下载方法是静态的,并且位于静态类中的结果吗? 编辑 我忘记提到这是在Tomcat下运行的JSF Web应用程序 - 也许其中一种技术在某个地方设置了一些默认凭据?
我将URLAuthenticator分离成自己的类,并尽可能地使其非静态,但问题仍然存在。我读到过,如果使用Authenticator.setDefault(null)将默认验证器设置为null,则在Windows上将使用NTLM身份验证。这里不应该是问题,因为我每次都设置Authenticator,但我想提出来。明确使用了NTLM身份验证,因为如果服务器以具有对下载文件的访问权限的用户身份运行,则甚至不会要求凭据,文件只需下载即可。因此,显然有些东西正在获取我的凭据并在调用验证器之前传递它们。
4个回答

11
我至少找到了一些答案。看起来这个行为是一个bug。一个解决方法是使用一个Sun特定的类来显式地重置缓存,就像这样:
import sun.net.www.protocol.http.AuthCacheValue;
import sun.net.www.protocol.http.AuthCacheImpl;
....
AuthCacheValue.setAuthCache(new AuthCacheImpl());
Authenticator.setDefault(new URLAuthenticator(username, password));

我正在重置在问题描述中的下载函数顶部的AuthCache。在编译过程中,您将收到有关使用这些类的警告。这并不能完全解决问题:如果NTLM身份验证有效,认证器仍然不会被调用,但只要服务器在没有对所请求的文件具有权限的用户下运行,这应该会清除缓存。

我知道已经过了很长很长的时间,但我刚刚遇到了同样的问题。你是否找到更加优雅的解决方案? - user949300
不,我从来没有这样做过 - 如果我没记错的话,这就是我们最终不得不采用的解决方案。幸运的是(对我们来说),这从未投入生产。 - Matt McMinn
@MattMcMinn 这个缓存问题只存在于 sun.net.www.protocol.http.HttpURLConnection 对吧?如果我使用 java.net.HttpURLConnection,我相信这个缓存问题就不会出现了!! - R D

5
面对相同的问题,这些答案都没能解决我的问题。我花了一些时间查看Java运行时源代码才弄清楚。 Sun.net.www.protocol.http.ntlm.NTLMAuthentication 试图使用透明认证,也就是使用当前用户凭据来登录到远程服务器。在我的服务器到服务器场景(Java EE服务器到Sharepoint)中,这是不可接受的。 为了禁用透明认证,我们需要让认证提供者知道连接不受信任,并且它需要在每次调用时进行身份验证:
static {
    NTLMAuthenticationCallback.setNTLMAuthenticationCallback(new NTLMAuthenticationCallback()
    {
        @Override
        public boolean isTrustedSite(URL url)
        {
            return false;
        }
    });
}        

你好,这听起来很有前途。你有一些如何调用它的示例吗?非常感谢。 - unclescrouge
你不需要调用它,它是 Java 运行时内部方法的重写。内部 NTLM 认证例程调用 isTrustedSite 方法返回 false,然后总是调用自定义 Authenticator 来获取凭据。有关示例 Authenticator,请参见先前的帖子。 - Boris R.
1
请注意,NTLMAuthenticationCallback是一个隐藏的内部sun.*类,因此您需要提供“-XDignore.symbol.file”参数来编译它。 - Matthew Leidholm

3

以下是工作代码(即,每个请求都调用getPasswordAuthentication())。你会看到编译警告,可以忽略。

static class MyCache implements sun.net.www.protocol.http.AuthCache{
     public void put(String pkey, sun.net.www.protocol.http.AuthCacheValue value){

     }
     public sun.net.www.protocol.http.AuthCacheValue get(String pkey, String skey){
         return null;
     }
     public void remove(String pkey, sun.net.www.protocol.http.AuthCacheValue entry){

     }
}
static{
    sun.net.www.protocol.http.AuthCacheValue.setAuthCache(new MyCache());

}

2
似乎你的finally块中需要调用:
Authenticator.setDefault(null);

奇怪,从Java文档上看起来是这样的。你尝试过去掉静态UrlAuthenticator吗?不确定为什么需要它是静态的。 - Ken Henderson
我已经进行了重构,使其不再是静态的,并将URLAuthenticator提取到自己的类中,但问题仍然存在。 - Matt McMinn
好的,我对此感到困惑。我唯一(不好的)想法是,不要将setDefault设置为null,而是将其分配给一个不好的(无法验证的)Authenticator。抱歉我没有任何好的想法。 - Ken Henderson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接