java 重置身份验证器凭据
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/480895/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Reset the Authenticator credentials
提问by Matt McMinn
We have a static method in a utility class that will download a file from a URL. An authenticator has been set up so that if a username and password is required, the credentials can be retrieved. The problem is that the credentials from the first successful connection are used for every connection afterwords, as long as the credentials are valid. This is a problem because our code is multi user, and since the credentials are not checked for every connection, it's possible that a user without proper credentials could download a file.
我们在实用程序类中有一个静态方法,可以从 URL 下载文件。已设置身份验证器,以便在需要用户名和密码时可以检索凭据。问题是第一次成功连接的凭据用于每个连接后记,只要凭据有效。这是一个问题,因为我们的代码是多用户的,并且由于没有为每个连接检查凭据,没有正确凭据的用户可能会下载文件。
Here's the code we're using
这是我们正在使用的代码
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());
}
}
I only see the log statement from getPasswordAuthentication once, the first time that a file is downloaded. After that first successful attempt, getPasswordAuthentication is not called again, even though the credentials have been reset. The result is that after the first successful connection, invalid credentials can be entered, and a successful connection can still be made. Is this possibly a result of the download method being static, and in a static class?
我只在第一次下载文件时看到 getPasswordAuthentication 的日志语句一次。在第一次成功尝试之后,即使凭据已重置,也不会再次调用 getPasswordAuthentication。结果是第一次连接成功后,可以输入无效的凭据,仍然可以连接成功。这可能是由于下载方法是静态的,并且在静态类中吗?
EditI forgot to mention that this is in a JSF webapp running under tomcat - maybe one of those technologies is setting some default credentials somewhere?
编辑我忘了提到这是在 tomcat 下运行的 JSF webapp 中 - 也许这些技术之一是在某处设置一些默认凭据?
I've pulled the URLAuthenticator out into its own class, and made it as non-static as possible, but the problem still exists. I've read that if the default authenticator is set to null with Authenticator.setDefault(null), then on windows the NTLM authentication will be used. That shouldn't be the problem here since I'm setting the Authenticator everytime, but I thought I'd throw it out there. The NTLM authentication is definately getting used, because if the server is run as a user that has access to the downloaded file, the credentials aren't even asked for, the file just downloads. So something obviously is grabbing my credentials and passing them in before the authenticator is called.
我已经将 URLAuthenticator 拉到它自己的类中,并使其尽可能非静态,但问题仍然存在。我读过,如果使用 Authenticator.setDefault(null) 将默认身份验证器设置为 null,则在 Windows 上将使用 NTLM 身份验证。这不应该是这里的问题,因为我每次都设置身份验证器,但我想我会把它扔在那里。NTLM 身份验证肯定会得到使用,因为如果服务器以有权访问下载文件的用户身份运行,则甚至不需要凭据,只需下载文件。所以很明显,在调用身份验证器之前,某些东西正在获取我的凭据并传递它们。
回答by Matt McMinn
I've figured something out at least. It appears that this behavior is a bug. A workaround is to use a Sun specific class to explicitly reset the cache, like so:
至少我已经想通了。看来这种行为是一个错误。一种解决方法是使用特定于 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));
I'm resetting the AuthCache at the top of the download function described in the question. During compile, you'll get warnings about using these classes. This doesn't completely fix the problem: if NTLM authentication works, the authenticator still won't get called, but as long as the server is running under a user that has does not have permission for the requested file, this should clear the cache out.
我正在问题中描述的下载功能顶部重置 AuthCache。在编译期间,您将收到有关使用这些类的警告。这并不能完全解决问题:如果 NTLM 身份验证有效,身份验证器仍然不会被调用,但只要服务器在对请求的文件没有权限的用户下运行,这应该清除缓存出去。
回答by Boris R.
Facing the same problem, none of these answers worked for me. It took me some time and looking through the java runtime source to figure this out. Sun.net.www.protocol.http.ntlm.NTLMAuthentication attempts to use transparent authentication, what is basically use of current user credentials to login to remote server. In my server to server scenario (Java EE server to Sharepoint) this wasn't acceptable. In order to disable transparent authentication we need to let authentication provider know that connection is not trusted and it needs to authenticate with every call:
面对同样的问题,这些答案都不适合我。我花了一些时间并查看 java 运行时源来解决这个问题。Sun.net.www.protocol.http.ntlm.NTLMAuthentication 尝试使用透明身份验证,基本上是使用当前用户凭据登录远程服务器。在我的服务器到服务器场景(Java EE 服务器到 Sharepoint)中,这是不可接受的。为了禁用透明身份验证,我们需要让身份验证提供者知道连接不受信任,并且每次调用都需要进行身份验证:
static {
NTLMAuthenticationCallback.setNTLMAuthenticationCallback(new NTLMAuthenticationCallback()
{
@Override
public boolean isTrustedSite(URL url)
{
return false;
}
});
}
回答by Ken Henderson
It looks like in your finally block you need to call
看起来在你的 finally 块中你需要调用
Authenticator.setDefault(null);
回答by so_mv
Here is the working( i.e., getPasswordAuthentication() called for every request) code. You will see compilation warning which can be ignored.
这是工作(即为每个请求调用的 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());
}

