重置身份验证器凭据

时间:2009-01-26 18:46:33

标签: java

我们在实用程序类中有一个静态方法,它将从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的log语句一次。在第一次成功尝试之后,即使已重置凭据,也不会再次调用getPasswordAuthentication。结果是,在第一次成功连接后,可以输入无效凭证,并且仍然可以成功建立连接。这可能是下载方法静态的结果吗?在静态类中?

修改的 我忘了提到这是在tomcat下运行的JSF webapp中 - 也许其中一种技术是在某处设置一些默认凭据?

我已将URLAuthenticator拉出到自己的类中,并使其尽可能非静态,但问题仍然存在。我已经读过如果使用Authenticator.setDefault(null)将默认验证器设置为null,那么在Windows上将使用NTLM验证。这应该不是问题,因为我每次都设置Authenticator,但我想我会把它扔出去。 NTLM身份验证肯定会被使用,因为如果服务器作为可以访问下载文件的用户运行,则甚至不会要求凭据,该文件只是下载。因此,在调用身份验证器之前,显然是抓住我的凭据并传递它们。

4 个答案:

答案 0 :(得分:10)

我至少想出了什么。看来这种行为是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身份验证有效,则仍然无法调用身份验证器,但只要服务器在没有所请求文件权限的用户下运行,就应该清除缓存进行。

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

答案 2 :(得分:2)

在你的finally块中,你需要调用

Authenticator.setDefault(null);

答案 3 :(得分:1)

这是工作(即为每个请求调用的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());

}