Only available RSA key sizes should be shown in admin console
Closes #16437
This commit is contained in:
parent
29888dbf1a
commit
16888eaeab
9 changed files with 58 additions and 19 deletions
|
@ -15,7 +15,6 @@ import java.security.cert.CertificateException;
|
||||||
import java.security.cert.CertificateFactory;
|
import java.security.cert.CertificateFactory;
|
||||||
import java.security.cert.CollectionCertStoreParameters;
|
import java.security.cert.CollectionCertStoreParameters;
|
||||||
import java.security.spec.ECParameterSpec;
|
import java.security.spec.ECParameterSpec;
|
||||||
import java.util.function.Supplier;
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import javax.crypto.Cipher;
|
import javax.crypto.Cipher;
|
||||||
|
@ -124,4 +123,11 @@ public interface CryptoProvider {
|
||||||
* @return decorated factory
|
* @return decorated factory
|
||||||
*/
|
*/
|
||||||
SSLSocketFactory wrapFactoryForTruststore(SSLSocketFactory delegate);
|
SSLSocketFactory wrapFactoryForTruststore(SSLSocketFactory delegate);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Allowed key sizes of RSA key modulus, which this cryptoProvider supports
|
||||||
|
*/
|
||||||
|
default String[] getSupportedRsaKeySizes() {
|
||||||
|
return new String[] {"1024", "2048", "4096"};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,4 +14,10 @@ public class Fips1402StrictCryptoProvider extends FIPS1402Provider {
|
||||||
static {
|
static {
|
||||||
System.setProperty("org.bouncycastle.fips.approved_only", Boolean.TRUE.toString());
|
System.setProperty("org.bouncycastle.fips.approved_only", Boolean.TRUE.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getSupportedRsaKeySizes() {
|
||||||
|
// RSA key of 1024 bits not supported in BCFIPS approved mode
|
||||||
|
return new String[] {"2048", "4096"};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,7 @@ public abstract class AbstractGeneratedRsaKeyProviderFactory extends AbstractRsa
|
||||||
public void validateConfiguration(KeycloakSession session, RealmModel realm, ComponentModel model) throws ComponentValidationException {
|
public void validateConfiguration(KeycloakSession session, RealmModel realm, ComponentModel model) throws ComponentValidationException {
|
||||||
super.validateConfiguration(session, realm, model);
|
super.validateConfiguration(session, realm, model);
|
||||||
|
|
||||||
ConfigurationValidationHelper.check(model).checkList(Attributes.KEY_SIZE_PROPERTY, false);
|
ConfigurationValidationHelper.check(model).checkList(Attributes.KEY_SIZE_PROPERTY.get(), false);
|
||||||
|
|
||||||
int size = model.get(Attributes.KEY_SIZE_KEY, 2048);
|
int size = model.get(Attributes.KEY_SIZE_KEY, 2048);
|
||||||
|
|
||||||
|
@ -103,6 +103,10 @@ public abstract class AbstractGeneratedRsaKeyProviderFactory extends AbstractRsa
|
||||||
keyPair = KeyUtils.generateRsaKeyPair(size);
|
keyPair = KeyUtils.generateRsaKeyPair(size);
|
||||||
model.put(Attributes.PRIVATE_KEY_KEY, PemUtils.encodeKey(keyPair.getPrivate()));
|
model.put(Attributes.PRIVATE_KEY_KEY, PemUtils.encodeKey(keyPair.getPrivate()));
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
|
getLogger().warnf("Failed to generate keys for key provider '%s' in realm '%s'. Details: %s", model.getName(), realm.getName(), t.getMessage());
|
||||||
|
if (getLogger().isDebugEnabled()) {
|
||||||
|
getLogger().debug(t.getMessage(), t);
|
||||||
|
}
|
||||||
throw new ComponentValidationException("Failed to generate keys", t);
|
throw new ComponentValidationException("Failed to generate keys", t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,6 +118,10 @@ public abstract class AbstractGeneratedRsaKeyProviderFactory extends AbstractRsa
|
||||||
Certificate certificate = CertificateUtils.generateV1SelfSignedCertificate(keyPair, realm.getName());
|
Certificate certificate = CertificateUtils.generateV1SelfSignedCertificate(keyPair, realm.getName());
|
||||||
model.put(Attributes.CERTIFICATE_KEY, PemUtils.encodeCertificate(certificate));
|
model.put(Attributes.CERTIFICATE_KEY, PemUtils.encodeCertificate(certificate));
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
|
getLogger().warnf("Failed to generate certificate for key provider '%s' in realm '%s'. Details: %s", model.getName(), realm.getName(), t.getMessage());
|
||||||
|
if (getLogger().isDebugEnabled()) {
|
||||||
|
getLogger().debug(t.getMessage(), t);
|
||||||
|
}
|
||||||
throw new ComponentValidationException("Failed to generate certificate", t);
|
throw new ComponentValidationException("Failed to generate certificate", t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,9 @@
|
||||||
|
|
||||||
package org.keycloak.keys;
|
package org.keycloak.keys;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import org.keycloak.common.crypto.CryptoIntegration;
|
||||||
import org.keycloak.crypto.Algorithm;
|
import org.keycloak.crypto.Algorithm;
|
||||||
import org.keycloak.crypto.KeyUse;
|
import org.keycloak.crypto.KeyUse;
|
||||||
import org.keycloak.jose.jwe.JWEConstants;
|
import org.keycloak.jose.jwe.JWEConstants;
|
||||||
|
@ -45,7 +48,8 @@ public interface Attributes {
|
||||||
ProviderConfigProperty CERTIFICATE_PROPERTY = new ProviderConfigProperty(CERTIFICATE_KEY, "X509 Certificate", "X509 Certificate encoded in PEM format", FILE_TYPE, null);
|
ProviderConfigProperty CERTIFICATE_PROPERTY = new ProviderConfigProperty(CERTIFICATE_KEY, "X509 Certificate", "X509 Certificate encoded in PEM format", FILE_TYPE, null);
|
||||||
|
|
||||||
String KEY_SIZE_KEY = "keySize";
|
String KEY_SIZE_KEY = "keySize";
|
||||||
ProviderConfigProperty KEY_SIZE_PROPERTY = new ProviderConfigProperty(KEY_SIZE_KEY, "Key size", "Size for the generated keys", LIST_TYPE, "2048", "1024", "2048", "4096");
|
Supplier<ProviderConfigProperty> KEY_SIZE_PROPERTY = () -> new ProviderConfigProperty(KEY_SIZE_KEY, "Key size", "Size for the generated keys", LIST_TYPE, "2048",
|
||||||
|
CryptoIntegration.getProvider().getSupportedRsaKeySizes());
|
||||||
|
|
||||||
String KEY_USE = "keyUse";
|
String KEY_USE = "keyUse";
|
||||||
ProviderConfigProperty KEY_USE_PROPERTY = new ProviderConfigProperty(KEY_USE, "Key use", "Whether the key should be used for signing or encryption.", LIST_TYPE,
|
ProviderConfigProperty KEY_USE_PROPERTY = new ProviderConfigProperty(KEY_USE, "Key use", "Whether the key should be used for signing or encryption.", LIST_TYPE,
|
||||||
|
|
|
@ -37,11 +37,6 @@ public class GeneratedRsaEncKeyProviderFactory extends AbstractGeneratedRsaKeyPr
|
||||||
|
|
||||||
private static final String HELP_TEXT = "Generates RSA keys for key encryption and creates a self-signed certificate";
|
private static final String HELP_TEXT = "Generates RSA keys for key encryption and creates a self-signed certificate";
|
||||||
|
|
||||||
private static final List<ProviderConfigProperty> CONFIG_PROPERTIES = AbstractGeneratedRsaKeyProviderFactory.rsaKeyConfigurationBuilder()
|
|
||||||
.property(Attributes.KEY_SIZE_PROPERTY)
|
|
||||||
.property(Attributes.RS_ENC_ALGORITHM_PROPERTY)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KeyProvider create(KeycloakSession session, ComponentModel model) {
|
public KeyProvider create(KeycloakSession session, ComponentModel model) {
|
||||||
model.put(Attributes.KEY_USE, KeyUse.ENC.name());
|
model.put(Attributes.KEY_USE, KeyUse.ENC.name());
|
||||||
|
@ -55,7 +50,10 @@ public class GeneratedRsaEncKeyProviderFactory extends AbstractGeneratedRsaKeyPr
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ProviderConfigProperty> getConfigProperties() {
|
public List<ProviderConfigProperty> getConfigProperties() {
|
||||||
return CONFIG_PROPERTIES;
|
return AbstractGeneratedRsaKeyProviderFactory.rsaKeyConfigurationBuilder()
|
||||||
|
.property(Attributes.KEY_SIZE_PROPERTY.get())
|
||||||
|
.property(Attributes.RS_ENC_ALGORITHM_PROPERTY)
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -37,11 +37,6 @@ public class GeneratedRsaKeyProviderFactory extends AbstractGeneratedRsaKeyProvi
|
||||||
|
|
||||||
private static final String HELP_TEXT = "Generates RSA signature keys and creates a self-signed certificate";
|
private static final String HELP_TEXT = "Generates RSA signature keys and creates a self-signed certificate";
|
||||||
|
|
||||||
private static final List<ProviderConfigProperty> CONFIG_PROPERTIES = AbstractGeneratedRsaKeyProviderFactory.rsaKeyConfigurationBuilder()
|
|
||||||
.property(Attributes.KEY_SIZE_PROPERTY)
|
|
||||||
.property(Attributes.RS_ALGORITHM_PROPERTY)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KeyProvider create(KeycloakSession session, ComponentModel model) {
|
public KeyProvider create(KeycloakSession session, ComponentModel model) {
|
||||||
if (model.getConfig().get(Attributes.KEY_USE) == null) {
|
if (model.getConfig().get(Attributes.KEY_USE) == null) {
|
||||||
|
@ -58,7 +53,10 @@ public class GeneratedRsaKeyProviderFactory extends AbstractGeneratedRsaKeyProvi
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ProviderConfigProperty> getConfigProperties() {
|
public List<ProviderConfigProperty> getConfigProperties() {
|
||||||
return CONFIG_PROPERTIES;
|
return AbstractGeneratedRsaKeyProviderFactory.rsaKeyConfigurationBuilder()
|
||||||
|
.property(Attributes.KEY_SIZE_PROPERTY.get())
|
||||||
|
.property(Attributes.RS_ALGORITHM_PROPERTY)
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -992,6 +992,7 @@ For running testsuite with server using BCFIPS approved mode, those additional p
|
||||||
-Dauth.server.fips.mode=strict \
|
-Dauth.server.fips.mode=strict \
|
||||||
-Dauth.server.supported.keystore.types=BCFKS \
|
-Dauth.server.supported.keystore.types=BCFKS \
|
||||||
-Dauth.server.keystore.type=bcfks
|
-Dauth.server.keystore.type=bcfks
|
||||||
|
-Dauth.server.supported.rsa.key.sizes=2048,4096
|
||||||
```
|
```
|
||||||
The log should contain `KeycloakFipsSecurityProvider` mentioning "Approved mode". Something like:
|
The log should contain `KeycloakFipsSecurityProvider` mentioning "Approved mode". Something like:
|
||||||
```
|
```
|
||||||
|
|
|
@ -19,11 +19,17 @@ package org.keycloak.testsuite.admin;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.common.Version;
|
import org.keycloak.common.Version;
|
||||||
|
import org.keycloak.keys.Attributes;
|
||||||
|
import org.keycloak.keys.GeneratedRsaKeyProviderFactory;
|
||||||
|
import org.keycloak.keys.KeyProvider;
|
||||||
|
import org.keycloak.representations.idm.ComponentTypeRepresentation;
|
||||||
|
import org.keycloak.representations.idm.ConfigPropertyRepresentation;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
import org.keycloak.representations.info.ProviderRepresentation;
|
import org.keycloak.representations.info.ProviderRepresentation;
|
||||||
import org.keycloak.representations.info.ServerInfoRepresentation;
|
import org.keycloak.representations.info.ServerInfoRepresentation;
|
||||||
import org.keycloak.testsuite.AbstractKeycloakTest;
|
import org.keycloak.testsuite.AbstractKeycloakTest;
|
||||||
import org.keycloak.testsuite.Assert;
|
import org.keycloak.testsuite.Assert;
|
||||||
|
import org.keycloak.testsuite.util.KeystoreUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -59,11 +65,21 @@ public class ServerInfoTest extends AbstractKeycloakTest {
|
||||||
assertNotNull(info.getMemoryInfo());
|
assertNotNull(info.getMemoryInfo());
|
||||||
assertNotNull(info.getSystemInfo());
|
assertNotNull(info.getSystemInfo());
|
||||||
assertNotNull(info.getCryptoInfo());
|
assertNotNull(info.getCryptoInfo());
|
||||||
String expectedSupportedKeystoreTypes = System.getProperty("auth.server.supported.keystore.types");
|
Assert.assertNames(info.getCryptoInfo().getSupportedKeystoreTypes(), KeystoreUtils.getSupportedKeystoreTypes());
|
||||||
if (expectedSupportedKeystoreTypes == null) {
|
|
||||||
fail("Property 'auth.server.supported.keystore.types' not set");
|
String expectedSupportedRsaKeySizes = System.getProperty("auth.server.supported.rsa.key.sizes");
|
||||||
|
if (expectedSupportedRsaKeySizes == null || expectedSupportedRsaKeySizes.trim().isEmpty()) {
|
||||||
|
fail("Property 'auth.server.supported.rsa.key.sizes' not set");
|
||||||
}
|
}
|
||||||
Assert.assertNames(info.getCryptoInfo().getSupportedKeystoreTypes(), expectedSupportedKeystoreTypes.split(","));
|
ComponentTypeRepresentation rsaGeneratedProviderInfo = info.getComponentTypes().get(KeyProvider.class.getName())
|
||||||
|
.stream()
|
||||||
|
.filter(componentType -> GeneratedRsaKeyProviderFactory.ID.equals(componentType.getId()))
|
||||||
|
.findFirst().orElseThrow(() -> new RuntimeException("Not found provider with ID 'rsa-generated'"));
|
||||||
|
ConfigPropertyRepresentation keySizeRep = rsaGeneratedProviderInfo.getProperties()
|
||||||
|
.stream()
|
||||||
|
.filter(configProp -> Attributes.KEY_SIZE_KEY.equals(configProp.getName()))
|
||||||
|
.findFirst().orElseThrow(() -> new RuntimeException("Not found provider with ID 'rsa-generated'"));
|
||||||
|
Assert.assertNames(keySizeRep.getOptions(), expectedSupportedRsaKeySizes.split(","));
|
||||||
|
|
||||||
assertEquals(Version.VERSION, info.getSystemInfo().getVersion());
|
assertEquals(Version.VERSION, info.getSystemInfo().getVersion());
|
||||||
assertNotNull(info.getSystemInfo().getServerTime());
|
assertNotNull(info.getSystemInfo().getServerTime());
|
||||||
|
|
|
@ -265,6 +265,7 @@
|
||||||
<auth.server.quarkus.cluster.config>local</auth.server.quarkus.cluster.config>
|
<auth.server.quarkus.cluster.config>local</auth.server.quarkus.cluster.config>
|
||||||
<auth.server.fips.mode>disabled</auth.server.fips.mode>
|
<auth.server.fips.mode>disabled</auth.server.fips.mode>
|
||||||
<auth.server.supported.keystore.types>JKS,PKCS12,BCFKS</auth.server.supported.keystore.types>
|
<auth.server.supported.keystore.types>JKS,PKCS12,BCFKS</auth.server.supported.keystore.types>
|
||||||
|
<auth.server.supported.rsa.key.sizes>1024,2048,4096</auth.server.supported.rsa.key.sizes>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -690,6 +691,7 @@
|
||||||
<auth.server.fips.mode>${auth.server.fips.mode}</auth.server.fips.mode>
|
<auth.server.fips.mode>${auth.server.fips.mode}</auth.server.fips.mode>
|
||||||
<auth.server.fips.keystore.type>${auth.server.fips.keystore.type}</auth.server.fips.keystore.type>
|
<auth.server.fips.keystore.type>${auth.server.fips.keystore.type}</auth.server.fips.keystore.type>
|
||||||
<auth.server.supported.keystore.types>${auth.server.supported.keystore.types}</auth.server.supported.keystore.types>
|
<auth.server.supported.keystore.types>${auth.server.supported.keystore.types}</auth.server.supported.keystore.types>
|
||||||
|
<auth.server.supported.rsa.key.sizes>${auth.server.supported.rsa.key.sizes}</auth.server.supported.rsa.key.sizes>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
~ Used for Wildfly Elytron 1.13.0.CR3+ RESTEasy client SSL truststore configuration.
|
~ Used for Wildfly Elytron 1.13.0.CR3+ RESTEasy client SSL truststore configuration.
|
||||||
|
|
Loading…
Reference in a new issue