How do I prevent leaking credentials between two different users with java.net.Authenticator without using private API?
<p>Java 9 is going to finally stop us using sun internal classes.</p>

<p>One such usages we still have is the following:</p>

<pre><code>import sun.net.www.protocol.http.AuthCache;
import sun.net.www.protocol.http.AuthCacheValue;

public static void authenticationHacks() {
    AuthCacheValue.setAuthCache(new NullAuthCache());
}

//...

class NullAuthCache implements AuthCache {
    @Override
    public void put(String s, AuthCacheValue authCacheValue) {
    }

    @Override
    public AuthCacheValue get(String s, String s1) {
        return null;
    }

    @Override
    public void remove(String s, AuthCacheValue authCacheValue) {
    }
}
</code></pre>

<p>Is there a public replacement for this?</p>

<p>As far as the X of the X-Y problem, this is a workaround for multiple users running in a single application where that application makes requests using <code>java.net.URL</code>. If you don't perform this hack, the credentials for the first successfully-authenticated user will be kept around and passed to other servers for requests which actually belong to different users.</p>

<p>If there is another way to do that, I'd like to know. I gather that this was a bug in the JRE, so if they have fixed it since, that would be good to know as well.</p>

<p>As an example of the problem at hand, using only the publicly available API, you run into the following problem:</p>

<pre><code>public class AuthenticationLeakBugDemo {
    public static void main(String[] args) throws Exception {
        // User 1
        {
            System.out.println("Simulating user 1 coming in " +
                "without authentication at first.");
            System.out.println("Expecting: 401");
            URL url = new URL("http://httpbin.org/basic-auth/a/a");
            HttpURLConnection connection = (HttpURLConnection)
                url.openConnection();
            System.out.println("Got: " + connection.getResponseCode());
        }

        // User 1
        {
            System.out.println("Simulating user 1 coming in " +
                "with proper authentication.");
            System.out.println("Expecting: 200");
            Authenticator.setDefault(new Authenticator() {
                @Override
                protected PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication("a", "a".toCharArray());
                }
            });
            try {
                URL url = new URL("http://httpbin.org/basic-auth/a/a");
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                System.out.println("Got: " + connection.getResponseCode());
            } finally {
                Authenticator.setDefault(null);
            }
        }

        // User 2
        {
            System.out.println("Simulating user 2 coming in with no authentication.");
            System.out.println("Expecting: 401");
            URL url = new URL("http://httpbin.org/basic-auth/a/a");
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            System.out.println("Got: " + connection.getResponseCode());
        }
    }
}
</code></pre>

<p>Output is of course:</p>

<pre class="lang-none prettyprint-override"><code>Simulating user 1 coming in without authentication at first.
Expecting: 401
Got: 401
Simulating user 1 coming in with proper authentication.
Expecting: 200
Got: 200
Simulating user 2 coming in with no authentication.
Expecting: 401
Got: 200
</code></pre>

<p>Indicating that Java's internal authentication cache has leaked one user's credentials to another user. :(</p>