【问题标题】:Reset the Authenticator credentials重置身份验证器凭据
【发布时间】:2010-10-03 14:42:52
【问题描述】:

我们在实用程序类中有一个静态方法,该方法将从 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 webapp 中 - 也许其中一项技术是在某处设置一些默认凭据?

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

【问题讨论】:

    标签: java


    【解决方案1】:

    看起来你需要在 finally 块中调用

    Authenticator.setDefault(null);
    

    【讨论】:

    • 很奇怪,这看起来像是 Java 文档中的内容。您是否尝试过摆脱静态 UrlAuthenticator?不知道为什么它需要是静态的。
    • 我进行了重构,使其不是静态的,并将 URLAuthenticator 拉到它自己的类中,但问题仍然存在。
    • 好吧,我对此一头雾水。我唯一的(坏的)想法是将 setDefault 设置为 null 来为其分配一个坏的(不会验证)身份验证器。抱歉,我没有任何好主意。
    【解决方案2】:

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

    【讨论】:

    • 我知道这已经很久了,但我刚刚遇到了同样的问题。你有没有想出一个更优雅的解决方法???
    • 不,我从来没有这样做过 - IIRC 这是我们最终不得不采用的解决方案。幸运的是(对我们来说)这从未投入生产。
    • @MattMcMinn 这个缓存问题只存在于 sun.net.www.protocol.http.HttpURLConnection 对吗?如果我使用 java.net.HttpURLConnection 这个缓存问题我相信不会有!!
    【解决方案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());
    
    }
    

    【讨论】:

      【解决方案4】:

      面对同样的问题,这些答案都不适合我。我花了一些时间查看 java 运行时源代码来解决这个问题。 Sun.net.www.protocol.http.ntlm.NTLMAuthentication 尝试使用透明身份验证,基本上是使用当前用户凭据登录远程服务器。在我的服务器到服务器场景(Java EE 服务器到 Sharepoint)中,这是不可接受的。 为了禁用透明身份验证,我们需要让身份验证提供者知道连接不受信任,并且需要在每次调用时进行身份验证:

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

      【讨论】:

      • 你好,这听起来很有希望。你有一些例子如何调用它。非常感谢这个
      • 你不要调用它,它是 Java 运行时中方法的覆盖。内部 NTLM 身份验证例程调用返回 false 的 isTrustedSite,然后它总是调用自定义身份验证器来获取凭据。有关示例验证器,请参阅以前的帖子。
      • 请注意,NTLMAuthenticationCallback 是一个隐藏的内部 sun.* 类,因此您必须向 javac 提供“-XDignore.symbol.file”参数来编译它。
      猜你喜欢
      • 1970-01-01
      • 2013-04-11
      • 1970-01-01
      • 2015-06-01
      • 1970-01-01
      • 2021-05-26
      • 2011-11-12
      • 1970-01-01
      • 2021-05-26
      相关资源
      最近更新 更多