8273026: Slow LoginContext.login() on multi threading application

Reviewed-by: weijun
This commit is contained in:
Ilarion Nakonechnyy 2021-10-29 11:37:45 +00:00 committed by Weijun Wang
parent 15fd8a300b
commit c0cda1db4f
3 changed files with 36 additions and 27 deletions

View File

@ -40,6 +40,10 @@ import java.util.ServiceLoader;
import sun.security.util.PendingException; import sun.security.util.PendingException;
import sun.security.util.ResourcesMgr; import sun.security.util.ResourcesMgr;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.stream.*;
import java.util.ServiceLoader.Provider;
/** /**
* <p> The {@code LoginContext} class describes the basic methods used * <p> The {@code LoginContext} class describes the basic methods used
* to authenticate Subjects and provides a way to develop an * to authenticate Subjects and provides a way to develop an
@ -222,6 +226,8 @@ public class LoginContext {
private static final sun.security.util.Debug debug = private static final sun.security.util.Debug debug =
sun.security.util.Debug.getInstance("logincontext", "\t[LoginContext]"); sun.security.util.Debug.getInstance("logincontext", "\t[LoginContext]");
private static final WeakHashMap<ClassLoader, Set<Provider<LoginModule>>> providersCache =
new WeakHashMap<>();
@SuppressWarnings("removal") @SuppressWarnings("removal")
private void init(String name) throws LoginException { private void init(String name) throws LoginException {
@ -288,6 +294,7 @@ public class LoginContext {
return loader; return loader;
} }
}); });
} }
@SuppressWarnings("removal") @SuppressWarnings("removal")
@ -691,21 +698,35 @@ public class LoginContext {
// locate and instantiate the LoginModule // locate and instantiate the LoginModule
// //
String name = moduleStack[i].entry.getLoginModuleName(); String name = moduleStack[i].entry.getLoginModuleName();
@SuppressWarnings("removal") Set<Provider<LoginModule>> lmProviders;
ServiceLoader<LoginModule> sc = AccessController.doPrivileged( synchronized(providersCache){
(PrivilegedAction<ServiceLoader<LoginModule>>) lmProviders = providersCache.get(contextClassLoader);
() -> ServiceLoader.load( if (lmProviders == null){
LoginModule.class, contextClassLoader)); if (debug != null){
for (LoginModule m: sc) { debug.println("Build ServiceProviders cache for ClassLoader: " + contextClassLoader.getName());
if (m.getClass().getName().equals(name)) { }
moduleStack[i].module = m; @SuppressWarnings("removal")
ServiceLoader<LoginModule> sc = AccessController.doPrivileged(
(PrivilegedAction<ServiceLoader<LoginModule>>)
() -> java.util.ServiceLoader.load(
LoginModule.class, contextClassLoader));
lmProviders = sc.stream().collect(Collectors.toSet());
if (debug != null){
debug.println("Discovered ServiceProviders for ClassLoader: " + contextClassLoader.getName());
lmProviders.forEach(System.err::println);
}
providersCache.put(contextClassLoader,lmProviders);
}
}
for (Provider<LoginModule> lm: lmProviders){
if (lm.type().getName().equals(name)){
moduleStack[i].module = lm.get();
if (debug != null) { if (debug != null) {
debug.println(name + " loaded as a service"); debug.println(name + " loaded as a service");
} }
break; break;
} }
} }
if (moduleStack[i].module == null) { if (moduleStack[i].module == null) {
try { try {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")

View File

@ -26,9 +26,13 @@ import java.io.File;
/* /*
* @test * @test
* @bug 8047789 * @bug 8047789 8273026
* @summary auth.login.LoginContext needs to be updated to work with modules * @summary auth.login.LoginContext needs to be updated to work with modules
* @build FirstLoginModule SecondLoginModule * @comment shows that the SecondLoginModule is still needed even if it's not in the JAAS login config file
* @build FirstLoginModule
* @clean SecondLoginModule
* @run main/othervm/fail Loader
* @build SecondLoginModule
* @run main/othervm Loader * @run main/othervm Loader
*/ */
public class Loader { public class Loader {
@ -39,18 +43,7 @@ public class Loader {
new File(System.getProperty("test.src"), "sl.conf").toString()); new File(System.getProperty("test.src"), "sl.conf").toString());
LoginContext lc = new LoginContext("me"); LoginContext lc = new LoginContext("me");
if (SecondLoginModule.isLoaded) {
throw new Exception();
}
lc.login(); lc.login();
// Although only FirstLoginModule is specified in the JAAS login
// config file, LoginContext will first create all LoginModule
// implementations that are registered as services, which include
// SecondLoginModule.
if (!SecondLoginModule.isLoaded) {
throw new Exception();
}
} }
} }

View File

@ -29,11 +29,6 @@ import java.util.Map;
public class SecondLoginModule implements LoginModule { public class SecondLoginModule implements LoginModule {
public static boolean isLoaded;
public SecondLoginModule() {
isLoaded = true;
}
@Override @Override
public void initialize(Subject subject, CallbackHandler callbackHandler, public void initialize(Subject subject, CallbackHandler callbackHandler,