diff --git a/docs/src/main/asciidoc/security-customization.adoc b/docs/src/main/asciidoc/security-customization.adoc index 827de651640cc..7e81f69b602ab 100644 --- a/docs/src/main/asciidoc/security-customization.adoc +++ b/docs/src/main/asciidoc/security-customization.adoc @@ -484,6 +484,40 @@ keytool -genkey -alias server -keyalg RSA -keystore server-keystore.jks -keysize `BCFIPSJSSE` provider option is currently not supported in native image. ==== +[[sun-pkcs11]] +=== SunPKCS11 + +`SunPKCS11` provider provides a bridge to specific `PKCS#11` implementations such as cryptographic smartcards and other Hardware Security Modules, Network Security Services in FIPS mode, etc. + +Typically, in order to work with `SunPKCS11`, one needs to install a `PKCS#11` implementation, generate a configuration which usually refers to a shared library, token slot, etc and write the following Java code: + +[source,java] +---- +import java.security.Provider; +import java.security.Security; + +String configuration = "pkcs11.cfg" + +Provider sunPkcs11 = Security.getProvider("SunPKCS11"); +Provider pkcsImplementation = sunPkcs11.configure(configuration); +// or prepare configuration in the code or read it from the file such as "pkcs11.cfg" and do +// sunPkcs11.configure("--" + configuration); +Security.addProvider(pkcsImplementation); +---- + +In Quarkus you can achieve the same at the configuration level only without having to modify the code, for example: + +[source,properties] +---- +quarkus.security.security-providers=SunPKCS11 +quarkus.security.security-provider-config.SunPKCS11=pkcs11.cfg +---- + +[NOTE] +==== +Note that while accessing the `SunPKCS11` bridge provider is supported in native image, configuring `SunPKCS11` is currently not supported in native image at the Quarkus level. +==== + == Reactive Security If you are going to use security in a reactive environment, you will likely need SmallRye Context Propagation: diff --git a/extensions/security/deployment/src/main/java/io/quarkus/security/deployment/JCAProviderBuildItem.java b/extensions/security/deployment/src/main/java/io/quarkus/security/deployment/JCAProviderBuildItem.java index 8c37b803f5a53..f9b67745564f6 100644 --- a/extensions/security/deployment/src/main/java/io/quarkus/security/deployment/JCAProviderBuildItem.java +++ b/extensions/security/deployment/src/main/java/io/quarkus/security/deployment/JCAProviderBuildItem.java @@ -6,13 +6,19 @@ * Metadata for the names of JCA {@linkplain java.security.Provider} to register for reflection */ public final class JCAProviderBuildItem extends MultiBuildItem { - private String providerName; + final private String providerName; + final private String providerConfig; - public JCAProviderBuildItem(String providerName) { + public JCAProviderBuildItem(String providerName, String providerConfig) { this.providerName = providerName; + this.providerConfig = providerConfig; } public String getProviderName() { return providerName; } + + public String getProviderConfig() { + return providerConfig; + } } diff --git a/extensions/security/deployment/src/main/java/io/quarkus/security/deployment/SecurityConfig.java b/extensions/security/deployment/src/main/java/io/quarkus/security/deployment/SecurityConfig.java index 44c1701855ebd..3b267255a15c0 100644 --- a/extensions/security/deployment/src/main/java/io/quarkus/security/deployment/SecurityConfig.java +++ b/extensions/security/deployment/src/main/java/io/quarkus/security/deployment/SecurityConfig.java @@ -1,7 +1,8 @@ package io.quarkus.security.deployment; -import java.util.List; +import java.util.Map; import java.util.Optional; +import java.util.Set; import io.quarkus.runtime.annotations.ConfigItem; import io.quarkus.runtime.annotations.ConfigPhase; @@ -20,8 +21,14 @@ public final class SecurityConfig { public boolean authorizationEnabledInDevMode; /** - * List of security providers to enable for reflection + * List of security providers to register */ @ConfigItem - public Optional> securityProviders; + public Optional> securityProviders; + + /** + * Security provider configuration + */ + @ConfigItem + public Map securityProviderConfig; } diff --git a/extensions/security/deployment/src/main/java/io/quarkus/security/deployment/SecurityProcessor.java b/extensions/security/deployment/src/main/java/io/quarkus/security/deployment/SecurityProcessor.java index 099d3edd078e9..47e1a82a4c012 100644 --- a/extensions/security/deployment/src/main/java/io/quarkus/security/deployment/SecurityProcessor.java +++ b/extensions/security/deployment/src/main/java/io/quarkus/security/deployment/SecurityProcessor.java @@ -12,7 +12,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -94,7 +93,7 @@ public class SecurityProcessor { void produceJcaSecurityProviders(BuildProducer jcaProviders, BuildProducer bouncyCastleProvider, BuildProducer bouncyCastleJsseProvider) { - Set providers = new HashSet<>(security.securityProviders.orElse(Collections.emptyList())); + Set providers = security.securityProviders.orElse(Set.of()); for (String providerName : providers) { if (SecurityProviderUtils.BOUNCYCASTLE_PROVIDER_NAME.equals(providerName)) { bouncyCastleProvider.produce(new BouncyCastleProviderBuildItem()); @@ -105,7 +104,7 @@ void produceJcaSecurityProviders(BuildProducer jcaProvider } else if (SecurityProviderUtils.BOUNCYCASTLE_FIPS_JSSE_PROVIDER_NAME.equals(providerName)) { bouncyCastleJsseProvider.produce(new BouncyCastleJsseProviderBuildItem(true)); } else { - jcaProviders.produce(new JCAProviderBuildItem(providerName)); + jcaProviders.produce(new JCAProviderBuildItem(providerName, security.securityProviderConfig.get(providerName))); } log.debugf("Added providerName: %s", providerName); } @@ -124,7 +123,8 @@ void registerJCAProvidersForReflection(BuildProducer c List jcaProviders, BuildProducer additionalProviders) throws IOException, URISyntaxException { for (JCAProviderBuildItem provider : jcaProviders) { - List providerClasses = registerProvider(provider.getProviderName(), additionalProviders); + List providerClasses = registerProvider(provider.getProviderName(), provider.getProviderConfig(), + additionalProviders); for (String className : providerClasses) { classes.produce(new ReflectiveClassBuildItem(true, true, className)); log.debugf("Register JCA class: %s", className); @@ -354,6 +354,7 @@ private Optional getOne(List items) { * @return class names that make up the provider and its services */ private List registerProvider(String providerName, + String providerConfig, BuildProducer additionalProviders) { List providerClasses = new ArrayList<>(); Provider provider = Security.getProvider(providerName); @@ -367,6 +368,14 @@ private List registerProvider(String providerName, providerClasses.addAll(Arrays.asList(supportedKeyClasses.split("\\|"))); } } + + if (providerConfig != null) { + Provider configuredProvider = provider.configure(providerConfig); + if (configuredProvider != null) { + Security.addProvider(configuredProvider); + providerClasses.add(configuredProvider.getClass().getName()); + } + } } if (SecurityProviderUtils.SUN_PROVIDERS.containsKey(providerName)) {