8304818: Prune HttpURLConnection cache when corresponding Authenticator is garbage collected

Reviewed-by: dfuchs, djelinski
This commit is contained in:
Michael McMahon 2023-04-24 17:25:32 +00:00
parent 6b81342c22
commit 314db55f6d
18 changed files with 340 additions and 680 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1994, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1994, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -38,7 +38,7 @@ import sun.net.www.MessageHeader;
import sun.net.www.HeaderParser;
import sun.net.www.MeteredStream;
import sun.net.www.ParseUtil;
import sun.net.www.protocol.http.AuthenticatorKeys;
import sun.net.www.protocol.http.AuthCacheImpl;
import sun.net.www.protocol.http.HttpURLConnection;
import sun.util.logging.PlatformLogger;
import static sun.net.www.protocol.http.HttpURLConnection.TunnelState.*;
@ -116,6 +116,8 @@ public class HttpClient extends NetworkClient {
The default value is 'true'. */
private static final boolean cacheSPNEGOProp;
protected volatile AuthCacheImpl authcache;
volatile boolean keepingAlive; /* this is a keep-alive connection */
volatile boolean disableKeepAlive;/* keep-alive has been disabled for this
connection - this will be used when
@ -167,8 +169,6 @@ public class HttpClient extends NetworkClient {
}
}
protected volatile String authenticatorKey;
/**
* A NOP method kept for backwards binary compatibility
* @deprecated -- system properties are no longer cached.
@ -349,10 +349,11 @@ public class HttpClient extends NetworkClient {
}
}
if (ret != null) {
String ak = httpuc == null ? AuthenticatorKeys.DEFAULT
: httpuc.getAuthenticatorKey();
AuthCacheImpl ak = httpuc == null
? AuthCacheImpl.getDefault()
: httpuc.getAuthCache();
boolean compatible = Objects.equals(ret.proxy, p)
&& Objects.equals(ret.getAuthenticatorKey(), ak);
&& Objects.equals(ret.getAuthCache(), ak);
if (compatible) {
ret.lock();
try {
@ -384,7 +385,7 @@ public class HttpClient extends NetworkClient {
if (ret == null) {
ret = new HttpClient(url, p, to);
if (httpuc != null) {
ret.authenticatorKey = httpuc.getAuthenticatorKey();
ret.authcache = httpuc.getAuthCache();
}
} else {
@SuppressWarnings("removal")
@ -422,10 +423,8 @@ public class HttpClient extends NetworkClient {
to, useCache, httpuc);
}
public final String getAuthenticatorKey() {
String k = authenticatorKey;
if (k == null) return AuthenticatorKeys.DEFAULT;
return k;
public final AuthCacheImpl getAuthCache() {
return authcache == null ? AuthCacheImpl.getDefault() : authcache;
}
/* return it to the cache as still usable, if:

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -38,8 +38,7 @@ public interface AuthCache {
/**
* Put an entry in the cache. pkey is a string specified as follows:
*
* A:[B:]C:D:E[:F][;key=value] Between 4 and 6 fields separated by ":",
* and an optional semicolon-separated key=value list postfix,
* A:[B:]C:D:E[:F] Between 4 and 6 fields separated by ":",
* where the fields have the following meaning:
* A is "s" or "p" for server or proxy authentication respectively
* B is optional and is the {@link AuthScheme}, e.g. BASIC, DIGEST, NTLM, etc
@ -48,11 +47,6 @@ public interface AuthCache {
* E is the port number
* F is optional and if present is the realm
*
* The semi-colon separated key=value list postfix can be used to
* provide additional contextual information, thus allowing
* to separate AuthCacheValue instances obtained from different
* contexts.
*
* Generally, two entries are created for each AuthCacheValue,
* one including the realm and one without the realm.
* Also, for some schemes (digest) multiple entries may be created

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,9 +25,13 @@
package sun.net.www.protocol.http;
import java.net.Authenticator;
import java.util.Collections;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
/**
* @author Michael McMahon
@ -105,4 +109,23 @@ public class AuthCacheImpl implements AuthCache {
}
}
}
private static final Map<Authenticator,AuthCacheImpl> caches =
Collections.synchronizedMap(new WeakHashMap<>());
/**
* The default cache is stored under null key which is never garbage
* collected.
*/
public static AuthCacheImpl getDefault() {
return getAuthCacheFor(null);
}
/**
* Atomically check if a cache exists for given Authenticator and return it
* or create one and return it
*/
public static AuthCacheImpl getAuthCacheFor(Authenticator auth) {
return caches.computeIfAbsent(auth, (k) -> new AuthCacheImpl());
}
}

View file

@ -25,7 +25,6 @@
package sun.net.www.protocol.http;
import java.io.Serializable;
import java.net.PasswordAuthentication;
/**
@ -35,25 +34,13 @@ import java.net.PasswordAuthentication;
* @author Michael McMahon
*/
public abstract class AuthCacheValue implements Serializable {
@java.io.Serial
static final long serialVersionUID = 735249334068211611L;
public abstract class AuthCacheValue {
public enum Type {
Proxy,
Server
};
/**
* Caches authentication info entered by user. See cacheKey()
*/
protected static AuthCache cache = new AuthCacheImpl();
public static void setAuthCache (AuthCache map) {
cache = map;
}
/* Package private ctor to prevent extension outside package */
AuthCacheValue() {}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1995, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1995, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -33,7 +33,7 @@ import java.util.HashMap;
import java.util.Objects;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Function;
import java.util.function.BiFunction;
import sun.net.www.HeaderParser;
@ -55,9 +55,6 @@ import sun.net.www.HeaderParser;
public abstract class AuthenticationInfo extends AuthCacheValue implements Cloneable {
@java.io.Serial
static final long serialVersionUID = -2588378268010453259L;
// Constants saying what kind of authorization this is. This determines
// the namespace in the hash table lookup.
public static final char SERVER_AUTHENTICATION = 's';
@ -76,7 +73,7 @@ public abstract class AuthenticationInfo extends AuthCacheValue implements Clone
/* AuthCacheValue: */
protected transient PasswordAuthentication pw;
protected PasswordAuthentication pw;
public PasswordAuthentication credentials() {
return pw;
@ -135,8 +132,10 @@ public abstract class AuthenticationInfo extends AuthCacheValue implements Clone
* and returns the cached authentication value.
* Otherwise, returns the cached authentication value, which may be null.
*/
private static AuthenticationInfo requestAuthentication(String key, Function<String, AuthenticationInfo> cache) {
AuthenticationInfo cached = cache.apply(key);
private static AuthenticationInfo requestAuthentication(
String key, AuthCacheImpl acache, BiFunction<String, AuthCacheImpl, AuthenticationInfo> cachefunc)
{
AuthenticationInfo cached = cachefunc.apply(key, acache);
if (cached != null || !serializeAuth) {
// either we already have a value in the cache, and we can
// use that immediately, or the serializeAuth behavior is disabled,
@ -147,7 +146,7 @@ public abstract class AuthenticationInfo extends AuthCacheValue implements Clone
try {
// check again after locking, and if available
// just return the cached value.
cached = cache.apply(key);
cached = cachefunc.apply(key, acache);
if (cached != null) return cached;
// Otherwise, if no request is in progress, record this
@ -166,7 +165,7 @@ public abstract class AuthenticationInfo extends AuthCacheValue implements Clone
requestLock.unlock();
}
/* entry may be in cache now. */
return cache.apply(key);
return cachefunc.apply(key, acache);
}
/* signal completion of an authentication (whether it succeeded or not)
@ -186,10 +185,6 @@ public abstract class AuthenticationInfo extends AuthCacheValue implements Clone
}
}
//public String toString () {
//return ("{"+type+":"+authScheme+":"+protocol+":"+host+":"+port+":"+realm+":"+path+"}");
//}
// REMIND: This cache just grows forever. We should put in a bounded
// cache, or maybe something using WeakRef's.
@ -218,18 +213,9 @@ public abstract class AuthenticationInfo extends AuthCacheValue implements Clone
/** The shortest path from the URL we authenticated against. */
String path;
/**
* A key identifying the authenticator from which the credentials
* were obtained.
* {@link AuthenticatorKeys#DEFAULT} identifies the {@linkplain
* java.net.Authenticator#setDefault(java.net.Authenticator) default}
* authenticator.
*/
String authenticatorKey;
/** Use this constructor only for proxy entries */
public AuthenticationInfo(char type, AuthScheme authScheme, String host,
int port, String realm, String authenticatorKey) {
int port, String realm) {
this.type = type;
this.authScheme = authScheme;
this.protocol = "";
@ -237,7 +223,6 @@ public abstract class AuthenticationInfo extends AuthCacheValue implements Clone
this.port = port;
this.realm = realm;
this.path = null;
this.authenticatorKey = Objects.requireNonNull(authenticatorKey);
}
public Object clone() {
@ -253,8 +238,7 @@ public abstract class AuthenticationInfo extends AuthCacheValue implements Clone
* Constructor used to limit the authorization to the path within
* the URL. Use this constructor for origin server entries.
*/
public AuthenticationInfo(char type, AuthScheme authScheme, URL url, String realm,
String authenticatorKey) {
public AuthenticationInfo(char type, AuthScheme authScheme, URL url, String realm) {
this.type = type;
this.authScheme = authScheme;
this.protocol = url.getProtocol().toLowerCase();
@ -271,16 +255,6 @@ public abstract class AuthenticationInfo extends AuthCacheValue implements Clone
else {
this.path = reducePath (urlPath);
}
this.authenticatorKey = Objects.requireNonNull(authenticatorKey);
}
/**
* The {@linkplain java.net.Authenticator#getKey(java.net.Authenticator) key}
* of the authenticator that was used to obtain the credentials.
* @return The authenticator's key.
*/
public final String getAuthenticatorKey() {
return authenticatorKey;
}
/*
@ -305,15 +279,14 @@ public abstract class AuthenticationInfo extends AuthCacheValue implements Clone
* don't yet know the realm
* (i.e. when we're preemptively setting the auth).
*/
static AuthenticationInfo getServerAuth(URL url, String authenticatorKey) {
static AuthenticationInfo getServerAuth(URL url, AuthCacheImpl cache) {
int port = url.getPort();
if (port == -1) {
port = url.getDefaultPort();
}
String key = SERVER_AUTHENTICATION + ":" + url.getProtocol().toLowerCase()
+ ":" + url.getHost().toLowerCase() + ":" + port
+ ";auth=" + authenticatorKey;
return getAuth(key, url);
+ ":" + url.getHost().toLowerCase() + ":" + port;
return getAuth(key, url, cache);
}
/**
@ -322,8 +295,7 @@ public abstract class AuthenticationInfo extends AuthCacheValue implements Clone
* In this case we do not use the path because the protection space
* is identified by the host:port:realm only
*/
static String getServerAuthKey(URL url, String realm, AuthScheme scheme,
String authenticatorKey) {
static String getServerAuthKey(URL url, String realm, AuthScheme scheme) {
int port = url.getPort();
if (port == -1) {
port = url.getDefaultPort();
@ -331,30 +303,29 @@ public abstract class AuthenticationInfo extends AuthCacheValue implements Clone
String key = SERVER_AUTHENTICATION + ":" + scheme + ":"
+ url.getProtocol().toLowerCase()
+ ":" + url.getHost().toLowerCase()
+ ":" + port + ":" + realm
+ ";auth=" + authenticatorKey;
+ ":" + port + ":" + realm;
return key;
}
private static AuthenticationInfo getCachedServerAuth(String key) {
return getAuth(key, null);
private static AuthenticationInfo getCachedServerAuth(String key, AuthCacheImpl cache) {
return getAuth(key, null, cache);
}
static AuthenticationInfo getServerAuth(String key) {
if (!serializeAuth) return getCachedServerAuth(key);
return requestAuthentication(key, AuthenticationInfo::getCachedServerAuth);
static AuthenticationInfo getServerAuth(String key, AuthCacheImpl cache) {
if (!serializeAuth) return getCachedServerAuth(key, cache);
return requestAuthentication(key, cache, AuthenticationInfo::getCachedServerAuth);
}
/**
* Return the AuthenticationInfo object from the cache if it's path is
* a substring of the supplied URLs path.
*/
static AuthenticationInfo getAuth(String key, URL url) {
static AuthenticationInfo getAuth(String key, URL url, AuthCacheImpl acache) {
Objects.requireNonNull(acache);
if (url == null) {
return (AuthenticationInfo)cache.get (key, null);
return (AuthenticationInfo)acache.get (key, null);
} else {
return (AuthenticationInfo)cache.get (key, url.getPath());
return (AuthenticationInfo)acache.get (key, url.getPath());
}
}
@ -363,11 +334,10 @@ public abstract class AuthenticationInfo extends AuthCacheValue implements Clone
* for preemptive header-setting. Note, the protocol field is always
* blank for proxies.
*/
static AuthenticationInfo getProxyAuth(String host, int port,
String authenticatorKey) {
String key = PROXY_AUTHENTICATION + "::" + host.toLowerCase() + ":" + port
+ ";auth=" + authenticatorKey;
AuthenticationInfo result = (AuthenticationInfo) cache.get(key, null);
static AuthenticationInfo getProxyAuth(String host, int port, AuthCacheImpl acache) {
Objects.requireNonNull(acache);
String key = PROXY_AUTHENTICATION + "::" + host.toLowerCase() + ":" + port;
AuthenticationInfo result = (AuthenticationInfo) acache.get(key, null);
return result;
}
@ -376,34 +346,34 @@ public abstract class AuthenticationInfo extends AuthCacheValue implements Clone
* Used in response to a challenge. Note, the protocol field is always
* blank for proxies.
*/
static String getProxyAuthKey(String host, int port, String realm,
AuthScheme scheme, String authenticatorKey) {
static String getProxyAuthKey(String host, int port, String realm, AuthScheme scheme) {
String key = PROXY_AUTHENTICATION + ":" + scheme
+ "::" + host.toLowerCase()
+ ":" + port + ":" + realm
+ ";auth=" + authenticatorKey;
+ ":" + port + ":" + realm;
return key;
}
private static AuthenticationInfo getCachedProxyAuth(String key) {
return (AuthenticationInfo) cache.get(key, null);
private static AuthenticationInfo getCachedProxyAuth(String key, AuthCacheImpl acache) {
Objects.requireNonNull(acache);
return (AuthenticationInfo) acache.get(key, null);
}
static AuthenticationInfo getProxyAuth(String key) {
if (!serializeAuth) return getCachedProxyAuth(key);
return requestAuthentication(key, AuthenticationInfo::getCachedProxyAuth);
static AuthenticationInfo getProxyAuth(String key, AuthCacheImpl acache) {
if (!serializeAuth) return getCachedProxyAuth(key, acache);
return requestAuthentication(key, acache, AuthenticationInfo::getCachedProxyAuth);
}
/**
* Add this authentication to the cache
*/
void addToCache() {
void addToCache(AuthCacheImpl authcache) {
Objects.requireNonNull(authcache);
String key = cacheKey(true);
if (useAuthCache()) {
cache.put(key, this);
authcache.put(key, this);
if (supportsPreemptiveAuthorization()) {
cache.put(cacheKey(false), this);
authcache.put(cacheKey(false), this);
}
}
endAuthRequest(key);
@ -419,10 +389,11 @@ public abstract class AuthenticationInfo extends AuthCacheValue implements Clone
/**
* Remove this authentication from the cache
*/
void removeFromCache() {
cache.remove(cacheKey(true), this);
void removeFromCache(AuthCacheImpl authcache) {
Objects.requireNonNull(authcache);
authcache.remove(cacheKey(true), this);
if (supportsPreemptiveAuthorization()) {
cache.remove(cacheKey(false), this);
authcache.remove(cacheKey(false), this);
}
}
@ -483,43 +454,14 @@ public abstract class AuthenticationInfo extends AuthCacheValue implements Clone
String cacheKey(boolean includeRealm) {
// This must be kept in sync with the getXXXAuth() methods in this
// class.
String authenticatorKey = getAuthenticatorKey();
if (includeRealm) {
return type + ":" + authScheme + ":" + protocol + ":"
+ host + ":" + port + ":" + realm
+ ";auth=" + authenticatorKey;
+ host + ":" + port + ":" + realm;
} else {
return type + ":" + protocol + ":" + host + ":" + port
+ ";auth=" + authenticatorKey;
return type + ":" + protocol + ":" + host + ":" + port;
}
}
String s1, s2; /* used for serialization of pw */
@java.io.Serial
// should be safe to keep synchronized here
private synchronized void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException
{
s.defaultReadObject ();
pw = new PasswordAuthentication (s1, s2.toCharArray());
s1 = null; s2= null;
if (authenticatorKey == null) {
authenticatorKey = AuthenticatorKeys.DEFAULT;
}
}
@java.io.Serial
// should be safe to keep synchronized here
private synchronized void writeObject(java.io.ObjectOutputStream s)
throws IOException
{
Objects.requireNonNull(authenticatorKey);
s1 = pw.getUserName();
s2 = new String (pw.getPassword());
s.defaultWriteObject ();
}
/**
* Releases any system or cryptographic resources.
* It is up to implementors to override disposeContext()

View file

@ -1,76 +0,0 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.www.protocol.http;
import java.net.Authenticator;
import java.util.concurrent.atomic.AtomicLong;
/**
* A class used to tie a key to an authenticator instance.
*/
public final class AuthenticatorKeys {
private AuthenticatorKeys() {
throw new InternalError("Trying to instantiate static class");
}
public static final String DEFAULT = "default";
private static final AtomicLong IDS = new AtomicLong();
public static String computeKey(Authenticator a) {
return System.identityHashCode(a) + "-" + IDS.incrementAndGet()
+ "@" + a.getClass().getName();
}
/**
* Returns a key for the given authenticator.
*
* @param authenticator The authenticator; {@code null} should be
* passed when the {@linkplain
* Authenticator#setDefault(java.net.Authenticator) default}
* authenticator is meant.
* @return A key for the given authenticator, {@link #DEFAULT} for
* {@code null}.
*/
public static String getKey(Authenticator authenticator) {
if (authenticator == null) {
return DEFAULT;
}
return authenticatorKeyAccess.getKey(authenticator);
}
@FunctionalInterface
public interface AuthenticatorKeyAccess {
public String getKey(Authenticator a);
}
private static AuthenticatorKeyAccess authenticatorKeyAccess;
public static void setAuthenticatorKeyAccess(AuthenticatorKeyAccess access) {
if (authenticatorKeyAccess == null && access != null) {
authenticatorKeyAccess = access;
}
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -63,10 +63,9 @@ class BasicAuthentication extends AuthenticationInfo {
*/
public BasicAuthentication(boolean isProxy, String host, int port,
String realm, PasswordAuthentication pw,
boolean isUTF8, String authenticatorKey) {
boolean isUTF8) {
super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
AuthScheme.BASIC, host, port, realm,
Objects.requireNonNull(authenticatorKey));
AuthScheme.BASIC, host, port, realm);
this.auth = authValueFrom(pw, isUTF8);
this.pw = pw;
}
@ -75,11 +74,9 @@ class BasicAuthentication extends AuthenticationInfo {
* Create a BasicAuthentication
*/
public BasicAuthentication(boolean isProxy, String host, int port,
String realm, String auth,
String authenticatorKey) {
String realm, String auth) {
super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
AuthScheme.BASIC, host, port, realm,
Objects.requireNonNull(authenticatorKey));
AuthScheme.BASIC, host, port, realm);
this.auth = "Basic " + auth;
}
@ -87,11 +84,9 @@ class BasicAuthentication extends AuthenticationInfo {
* Create a BasicAuthentication
*/
public BasicAuthentication(boolean isProxy, URL url, String realm,
PasswordAuthentication pw, boolean isUTF8,
String authenticatorKey) {
PasswordAuthentication pw, boolean isUTF8) {
super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
AuthScheme.BASIC, url, realm,
Objects.requireNonNull(authenticatorKey));
AuthScheme.BASIC, url, realm);
this.auth = authValueFrom(pw, isUTF8);
this.pw = pw;
}
@ -116,10 +111,9 @@ class BasicAuthentication extends AuthenticationInfo {
* Create a BasicAuthentication
*/
public BasicAuthentication(boolean isProxy, URL url, String realm,
String auth, String authenticatorKey) {
String auth) {
super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
AuthScheme.BASIC, url, realm,
Objects.requireNonNull(authenticatorKey));
AuthScheme.BASIC, url, realm);
this.auth = "Basic " + auth;
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -296,12 +296,11 @@ class DigestAuthentication extends AuthenticationInfo {
*/
public DigestAuthentication(boolean isProxy, URL url, String realm,
String authMethod, PasswordAuthentication pw,
Parameters params, String authenticatorKey) {
Parameters params){
super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
AuthScheme.DIGEST,
url,
realm,
Objects.requireNonNull(authenticatorKey));
realm);
this.authMethod = authMethod;
this.pw = pw;
this.params = params;
@ -309,13 +308,12 @@ class DigestAuthentication extends AuthenticationInfo {
public DigestAuthentication(boolean isProxy, String host, int port, String realm,
String authMethod, PasswordAuthentication pw,
Parameters params, String authenticatorKey) {
Parameters params) {
super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
AuthScheme.DIGEST,
host,
port,
realm,
Objects.requireNonNull(authenticatorKey));
realm);
this.authMethod = authMethod;
this.pw = pw;
this.params = params;

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1995, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1995, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -310,7 +310,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
protected Handler handler;
protected Proxy instProxy;
protected volatile Authenticator authenticator;
protected volatile String authenticatorKey;
protected volatile AuthCacheImpl authCache = AuthCacheImpl.getDefault();
private CookieHandler cookieHandler;
private final ResponseCache cacheHandler;
@ -447,7 +447,6 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
return connectionLock.isHeldByCurrentThread();
}
/*
* privileged request password authentication
*
@ -539,16 +538,14 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
"Authenticator must be set before connecting");
}
authenticator = Objects.requireNonNull(auth);
authenticatorKey = AuthenticatorKeys.getKey(authenticator);
authCache = AuthCacheImpl.getAuthCacheFor(authenticator);
} finally {
unlock();
}
}
public String getAuthenticatorKey() {
String k = authenticatorKey;
if (k == null) return AuthenticatorKeys.getKey(authenticator);
return k;
public AuthCacheImpl getAuthCache() {
return authCache;
}
/*
@ -684,8 +681,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
requests.setIfNotSet("If-Modified-Since", fo.format(date));
}
// check for preemptive authorization
AuthenticationInfo sauth = AuthenticationInfo.getServerAuth(url,
getAuthenticatorKey());
AuthenticationInfo sauth = AuthenticationInfo.getServerAuth(url, authCache);
if (sauth != null && sauth.supportsPreemptiveAuthorization() ) {
// Sets "Authorization"
requests.setIfNotSet(sauth.getHeaderName(), sauth.getHeaderValue(url,method));
@ -1769,7 +1765,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
// cache proxy authentication info
if (proxyAuthentication != null) {
// cache auth info on success, domain header not relevant.
proxyAuthentication.addToCache();
proxyAuthentication.addToCache(authCache);
}
if (respCode == HTTP_UNAUTHORIZED) {
@ -1817,7 +1813,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
setCookieHeader();
continue;
} else {
serverAuthentication.removeFromCache();
serverAuthentication.removeFromCache(authCache);
}
}
serverAuthentication = getServerAuthentication(srvHdr);
@ -1858,11 +1854,11 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
// remove the entry and create a new one
BasicAuthentication a =
(BasicAuthentication) serverAuthentication.clone();
serverAuthentication.removeFromCache();
serverAuthentication.removeFromCache(authCache);
a.path = npath;
serverAuthentication = a;
}
serverAuthentication.addToCache();
serverAuthentication.addToCache(authCache);
} else {
// what we cache is based on the domain list in the request
DigestAuthentication srv = (DigestAuthentication)
@ -1878,8 +1874,8 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
URL u = newURL (url, path);
DigestAuthentication d = new DigestAuthentication (
false, u, realm, "Digest", pw,
digestparams, srv.authenticatorKey);
d.addToCache ();
digestparams);
d.addToCache (authCache);
} catch (Exception e) {}
}
}
@ -2090,7 +2086,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
currentProxyCredentials = proxyAuthentication;
return proxyAuthentication;
} else {
proxyAuthentication.removeFromCache();
proxyAuthentication.removeFromCache(authCache);
}
}
proxyAuthentication = getHttpProxyAuthentication(auth);
@ -2231,7 +2227,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
// cache proxy authentication info
if (proxyAuthentication != null) {
// cache auth info on success, domain header not relevant.
proxyAuthentication.addToCache();
proxyAuthentication.addToCache(authCache);
}
if (respCode == HTTP_OK) {
@ -2333,7 +2329,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
AuthenticationInfo pauth
= AuthenticationInfo.getProxyAuth(http.getProxyHostUsed(),
http.getProxyPortUsed(),
getAuthenticatorKey());
authCache);
if (pauth != null && pauth.supportsPreemptiveAuthorization()) {
String value;
if (pauth instanceof DigestAuthentication) {
@ -2393,9 +2389,8 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
if (realm == null)
realm = "";
proxyAuthKey = AuthenticationInfo.getProxyAuthKey(host, port, realm,
authScheme, getAuthenticatorKey());
ret = AuthenticationInfo.getProxyAuth(proxyAuthKey);
proxyAuthKey = AuthenticationInfo.getProxyAuthKey(host, port, realm, authScheme);
ret = AuthenticationInfo.getProxyAuth(proxyAuthKey, authCache);
if (ret == null) {
switch (authScheme) {
case BASIC:
@ -2418,8 +2413,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
host, addr, port, "http",
realm, scheme, url, RequestorType.PROXY);
if (a != null) {
ret = new BasicAuthentication(true, host, port, realm, a,
isUTF8, getAuthenticatorKey());
ret = new BasicAuthentication(true, host, port, realm, a, isUTF8);
}
break;
case DIGEST:
@ -2431,8 +2425,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
DigestAuthentication.Parameters params =
new DigestAuthentication.Parameters();
ret = new DigestAuthentication(true, host, port, realm,
scheme, a, params,
getAuthenticatorKey());
scheme, a, params);
}
break;
case NTLM:
@ -2471,8 +2464,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
*/
if (tryTransparentNTLMProxy ||
(!tryTransparentNTLMProxy && a != null)) {
ret = NTLMAuthenticationProxy.proxy.create(true, host,
port, a, getAuthenticatorKey());
ret = NTLMAuthenticationProxy.proxy.create(true, host, port, a);
}
/* set to false so that we do not try again */
@ -2504,8 +2496,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
URL u = new URL("http", host, port, "/");
String a = defaultAuth.authString(u, scheme, realm);
if (a != null) {
ret = new BasicAuthentication (true, host, port, realm, a,
getAuthenticatorKey());
ret = new BasicAuthentication (true, host, port, realm, a);
// not in cache by default - cache on success
}
} catch (java.net.MalformedURLException ignored) {
@ -2566,9 +2557,8 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
domain = p.findValue ("domain");
if (realm == null)
realm = "";
serverAuthKey = AuthenticationInfo.getServerAuthKey(url, realm, authScheme,
getAuthenticatorKey());
ret = AuthenticationInfo.getServerAuth(serverAuthKey);
serverAuthKey = AuthenticationInfo.getServerAuthKey(url, realm, authScheme);
ret = AuthenticationInfo.getServerAuth(serverAuthKey, authCache);
InetAddress addr = null;
if (ret == null) {
try {
@ -2597,8 +2587,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
url.getHost(), addr, port, url.getProtocol(),
realm, scheme, url, RequestorType.SERVER);
if (a != null) {
ret = new BasicAuthentication(false, url, realm, a,
isUTF8, getAuthenticatorKey());
ret = new BasicAuthentication(false, url, realm, a, isUTF8);
}
break;
case DIGEST:
@ -2609,8 +2598,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
if (a != null) {
digestparams = new DigestAuthentication.Parameters();
ret = new DigestAuthentication(false, url, realm, scheme,
a, digestparams,
getAuthenticatorKey());
a, digestparams);
}
break;
case NTLM:
@ -2655,8 +2643,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
*/
if (tryTransparentNTLMServer ||
(!tryTransparentNTLMServer && a != null)) {
ret = NTLMAuthenticationProxy.proxy.create(false,
url1, a, getAuthenticatorKey());
ret = NTLMAuthenticationProxy.proxy.create(false, url1, a);
}
/* set to false so that we do not try again */
@ -2680,8 +2667,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
&& defaultAuth.schemeSupported(scheme)) {
String a = defaultAuth.authString(url, scheme, realm);
if (a != null) {
ret = new BasicAuthentication (false, url, realm, a,
getAuthenticatorKey());
ret = new BasicAuthentication (false, url, realm, a);
// not in cache by default - cache on success
}
}
@ -2932,7 +2918,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
// check for preemptive authorization
AuthenticationInfo sauth =
AuthenticationInfo.getServerAuth(url, getAuthenticatorKey());
AuthenticationInfo.getServerAuth(url, authCache);
if (sauth != null && sauth.supportsPreemptiveAuthorization() ) {
// Sets "Authorization"
requests.setIfNotSet(sauth.getHeaderName(), sauth.getHeaderValue(url,method));

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -45,22 +45,21 @@ class NTLMAuthenticationProxy {
static final boolean supported = proxy != null ? true : false;
static final boolean supportsTransparentAuth = supported ? supportsTransparentAuth() : false;
private final Constructor<? extends AuthenticationInfo> threeArgCtr;
private final Constructor<? extends AuthenticationInfo> fourArgCtr;
private final Constructor<? extends AuthenticationInfo> sixArgCtr;
private NTLMAuthenticationProxy(Constructor<? extends AuthenticationInfo> fourArgCtr,
Constructor<? extends AuthenticationInfo> sixArgCtr) {
private NTLMAuthenticationProxy(Constructor<? extends AuthenticationInfo> threeArgCtr,
Constructor<? extends AuthenticationInfo> fourArgCtr) {
this.threeArgCtr = threeArgCtr;
this.fourArgCtr = fourArgCtr;
this.sixArgCtr = sixArgCtr;
}
AuthenticationInfo create(boolean isProxy,
URL url,
PasswordAuthentication pw,
String authenticatorKey) {
PasswordAuthentication pw) {
try {
return fourArgCtr.newInstance(isProxy, url, pw, authenticatorKey);
return threeArgCtr.newInstance(isProxy, url, pw);
} catch (ReflectiveOperationException roe) {
finest(roe);
}
@ -71,10 +70,9 @@ class NTLMAuthenticationProxy {
AuthenticationInfo create(boolean isProxy,
String host,
int port,
PasswordAuthentication pw,
String authenticatorKey) {
PasswordAuthentication pw) {
try {
return sixArgCtr.newInstance(isProxy, host, port, pw, authenticatorKey);
return fourArgCtr.newInstance(isProxy, host, port, pw);
} catch (ReflectiveOperationException roe) {
finest(roe);
}
@ -117,23 +115,21 @@ class NTLMAuthenticationProxy {
@SuppressWarnings("unchecked")
private static NTLMAuthenticationProxy tryLoadNTLMAuthentication() {
Class<? extends AuthenticationInfo> cl;
Constructor<? extends AuthenticationInfo> fourArg, sixArg;
Constructor<? extends AuthenticationInfo> threeArg, fourArg;
try {
cl = (Class<? extends AuthenticationInfo>)Class.forName(clazzStr, true, null);
if (cl != null) {
fourArg = cl.getConstructor(boolean.class,
threeArg = cl.getConstructor(boolean.class,
URL.class,
PasswordAuthentication.class,
String.class);
sixArg = cl.getConstructor(boolean.class,
PasswordAuthentication.class);
fourArg = cl.getConstructor(boolean.class,
String.class,
int.class,
PasswordAuthentication.class,
String.class);
PasswordAuthentication.class);
supportsTA = cl.getDeclaredMethod(supportsTAStr);
isTrustedSite = cl.getDeclaredMethod(isTrustedSiteStr, java.net.URL.class);
return new NTLMAuthenticationProxy(fourArg,
sixArg);
return new NTLMAuthenticationProxy(threeArg,
fourArg);
}
} catch (ClassNotFoundException cnfe) {
finest(cnfe);

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -80,9 +80,7 @@ class NegotiateAuthentication extends AuthenticationInfo {
public NegotiateAuthentication(HttpCallerInfo hci) {
super(RequestorType.PROXY==hci.authType ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
hci.scheme.equalsIgnoreCase("Negotiate") ? NEGOTIATE : KERBEROS,
hci.url,
"",
AuthenticatorKeys.getKey(hci.authenticator));
hci.url, "");
this.hci = hci;
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -46,7 +46,7 @@ import java.util.StringTokenizer;
import javax.net.ssl.*;
import sun.net.www.http.HttpClient;
import sun.net.www.protocol.http.AuthenticatorKeys;
import sun.net.www.protocol.http.AuthCacheImpl;
import sun.net.www.protocol.http.HttpURLConnection;
import sun.security.action.*;
@ -335,11 +335,10 @@ final class HttpsClient extends HttpClient
}
if (ret != null) {
String ak = httpuc == null ? AuthenticatorKeys.DEFAULT
: httpuc.getAuthenticatorKey();
AuthCacheImpl ak = httpuc == null ? null : httpuc.getAuthCache();
boolean compatible = ((ret.proxy != null && ret.proxy.equals(p)) ||
(ret.proxy == null && p == Proxy.NO_PROXY))
&& Objects.equals(ret.getAuthenticatorKey(), ak);
&& Objects.equals(ret.getAuthCache(), ak);
if (compatible) {
ret.lock();
@ -377,7 +376,7 @@ final class HttpsClient extends HttpClient
if (ret == null) {
ret = new HttpsClient(sf, url, p, connectTimeout);
if (httpuc != null) {
ret.authenticatorKey = httpuc.getAuthenticatorKey();
ret.authcache = httpuc.getAuthCache();
}
} else {
@SuppressWarnings("removal")