diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SecurityServicesFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SecurityServicesFeature.java index b351532a41dd..689e53b31133 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SecurityServicesFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SecurityServicesFeature.java @@ -76,8 +76,11 @@ import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; +import javax.security.auth.callback.CallbackHandler; import javax.security.auth.login.Configuration; +import javax.security.sasl.SaslClient; import javax.security.sasl.SaslClientFactory; +import javax.security.sasl.SaslServer; import javax.security.sasl.SaslServerFactory; import javax.smartcardio.TerminalFactory; import javax.xml.crypto.dsig.TransformService; @@ -518,6 +521,30 @@ private static Set> computeKnownServices(BeforeAnalysisAccess access) { return allKnownServices; } + private void registerSpecialReachabilityHandlers(BeforeAnalysisAccess access) { + /* + * Sasl does not conform to the JCA - the service has no getInstance method. We instead use + * the Sasl facade class for our reachability handlers. + */ + String saslRegistrationFailureMessage = "Failed to enable automatic SASL provider registration: %s"; + String saslClassName = "javax.security.sasl.Sasl"; + try { + TypeResult> saslClassLookup = loader.findClass(saslClassName); + if (!saslClassLookup.isPresent()) { + trace(saslRegistrationFailureMessage, saslClassName); + return; + } + + Class saslClass = saslClassLookup.getOrFail(); + Method createSaslClient = ReflectionUtil.lookupMethod(saslClass, "createSaslClient", String[].class, String.class, String.class, String.class, Map.class, CallbackHandler.class); + access.registerReachabilityHandler(a -> registerServices(a, createSaslClient, SaslClient.class), createSaslClient); + Method createSaslServer = ReflectionUtil.lookupMethod(saslClass, "createSaslServer", String.class, String.class, String.class, Map.class, CallbackHandler.class); + access.registerReachabilityHandler(a -> registerServices(a, createSaslServer, SaslServer.class), createSaslServer); + } catch (ReflectionUtil.ReflectionUtilError e) { + trace(saslRegistrationFailureMessage, e); + } + } + private void registerServiceReachabilityHandlers(BeforeAnalysisAccess access) { ctrParamClassAccessor = getConstructorParameterClassAccessor(loader); getSpiClassMethod = getSpiClassMethod(); @@ -550,6 +577,8 @@ private void registerServiceReachabilityHandlers(BeforeAnalysisAccess access) { } } + registerSpecialReachabilityHandlers(access); + /* * On Oracle JDK the SecureRandom service implementations are not automatically discovered * by the mechanism above because SecureRandom.getInstance() is not invoked. For example @@ -568,15 +597,23 @@ private void registerServices(DuringAnalysisAccess access, Object trigger, Class * of a newly allocated SPI object. This only applies to SPIs in the java.security package, * but not any of its sub-packages. See java.security.Security.getSpiClass(). */ - // Checkstyle: allow Class.getSimpleName - String serviceType = serviceClass.getSimpleName(); - // Checkstyle: disallow Class.getSimpleName + String serviceType = getServiceType(serviceClass); + if (serviceClass.getPackage().getName().equals("java.security")) { registerSpiClass(getSpiClassMethod, serviceType); } registerServices(access, trigger, serviceType); } + private static String getServiceType(Class serviceClass) { + // Checkstyle: allow Class.getSimpleName + if (serviceClass == SaslClient.class || serviceClass == SaslServer.class) { + return serviceClass.getSimpleName() + "Factory"; + } + return serviceClass.getSimpleName(); + // Checkstyle: disallow Class.getSimpleName + } + ConcurrentHashMap processedServiceClasses = new ConcurrentHashMap<>(); private void registerServices(DuringAnalysisAccess access, Object trigger, String serviceType) {