From 0ff7d551dd2aab42da9cfdb03a5267a73d4e470e Mon Sep 17 00:00:00 2001 From: rmartinc Date: Tue, 19 Aug 2025 10:18:21 +0200 Subject: [PATCH] Check null for new keySize and validity parameters when generating certificates Closes #41906 Signed-off-by: rmartinc --- .../models/utils/KeycloakModelUtils.java | 7 +++++-- .../ClientAttributeCertificateResource.java | 19 +++++++++--------- .../AbstractClientAuthSignedJWTTest.java | 20 ++++++++++++++++--- .../oauth/ClientAuthSignedJWTTest.java | 6 +++--- 4 files changed, 34 insertions(+), 18 deletions(-) diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java b/server-spi-private/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java index 30b139ca8d7..79b2b7fc5c3 100755 --- a/server-spi-private/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java +++ b/server-spi-private/src/main/java/org/keycloak/models/utils/KeycloakModelUtils.java @@ -110,6 +110,9 @@ public final class KeycloakModelUtils { public static final int MAX_CLIENT_LOOKUPS_DURING_ROLE_RESOLVE = 25; + public static final int DEFAULT_RSA_KEY_SIZE = 4096; + public static final int DEFAULT_CERTIFICATE_VALIDITY_YEARS = 3; + private KeycloakModelUtils() { } @@ -222,8 +225,8 @@ public final class KeycloakModelUtils { public static CertificateRepresentation generateKeyPairCertificate(String subject) { Calendar calendar = Calendar.getInstance(); - calendar.add(Calendar.YEAR, 3); - return generateKeyPairCertificate(subject, 4096, calendar); + calendar.add(Calendar.YEAR, DEFAULT_CERTIFICATE_VALIDITY_YEARS); + return generateKeyPairCertificate(subject, DEFAULT_RSA_KEY_SIZE, calendar); } public static CertificateRepresentation generateKeyPairCertificate(String subject, int keysize, Calendar endDate) { diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java index e86c235aa78..149a0263bcf 100755 --- a/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientAttributeCertificateResource.java @@ -18,7 +18,6 @@ package org.keycloak.services.resources.admin; import com.google.common.base.Strings; -import jakarta.ws.rs.QueryParam; import org.eclipse.microprofile.openapi.annotations.Operation; import org.eclipse.microprofile.openapi.annotations.extensions.Extension; import org.eclipse.microprofile.openapi.annotations.parameters.Parameter; @@ -342,15 +341,15 @@ public class ClientAttributeCertificateResource { throw new ErrorResponseException("password-missing", "Need to specify a store password for jks generation and download", Response.Status.BAD_REQUEST); } - CertificateRepresentation info; - if (config.getKeySize() <= 0 || config.getValidity() <= 0) { - info = KeycloakModelUtils.generateKeyPairCertificate(client.getClientId()); - } - else { - Calendar calendar = Calendar.getInstance(); - calendar.add(Calendar.YEAR, config.getValidity()); - info = KeycloakModelUtils.generateKeyPairCertificate(client.getClientId(), config.getKeySize(), calendar); - } + int keySize = config.getKeySize() != null && config.getKeySize() > 0 + ? config.getKeySize() + : KeycloakModelUtils.DEFAULT_RSA_KEY_SIZE; + int validity = config.getValidity() != null && config.getValidity() > 0 + ? config.getValidity() + : KeycloakModelUtils.DEFAULT_CERTIFICATE_VALIDITY_YEARS; + Calendar calendar = Calendar.getInstance(); + calendar.add(Calendar.YEAR, validity); + CertificateRepresentation info = KeycloakModelUtils.generateKeyPairCertificate(client.getClientId(), keySize, calendar); byte[] rtn = getKeystore(config, info.getPrivateKey(), info.getCertificate()); info.setPrivateKey(null); diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AbstractClientAuthSignedJWTTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AbstractClientAuthSignedJWTTest.java index 76963c04a24..6135154112d 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AbstractClientAuthSignedJWTTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/AbstractClientAuthSignedJWTTest.java @@ -37,9 +37,11 @@ import java.security.NoSuchProviderException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.cert.X509Certificate; +import java.security.interfaces.RSAKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; +import java.util.Calendar; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -62,6 +64,8 @@ import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.message.BasicNameValuePair; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; import org.junit.Before; import org.junit.BeforeClass; import org.junit.ClassRule; @@ -373,7 +377,7 @@ public abstract class AbstractClientAuthSignedJWTTest extends AbstractKeycloakTe } } - protected void testClientWithGeneratedKeys(String format) throws Exception { + protected void testClientWithGeneratedKeys(String format, Integer keySize, Integer validity) throws Exception { ClientRepresentation client = app3; UserRepresentation user = defaultUser; final String keyAlias = "somekey"; @@ -389,8 +393,12 @@ public abstract class AbstractClientAuthSignedJWTTest extends AbstractKeycloakTe keyStoreConfig.setKeyPassword(keyPassword); keyStoreConfig.setStorePassword(storePassword); keyStoreConfig.setKeyAlias(keyAlias); - keyStoreConfig.setKeySize(4096); - keyStoreConfig.setValidity(3); + if (keySize != null) { + keyStoreConfig.setKeySize(keySize); + } + if (validity != null) { + keyStoreConfig.setValidity(validity); + } client = getClient(testRealm.getRealm(), client.getId()).toRepresentation(); final String certOld = client.getAttributes().get(JWTClientAuthenticator.CERTIFICATE_ATTR); @@ -408,6 +416,12 @@ public abstract class AbstractClientAuthSignedJWTTest extends AbstractKeycloakTe assertCertificate(client, certOld, KeycloakModelUtils.getPemFromCertificate(x509Cert)); + MatcherAssert.assertThat(x509Cert.getPublicKey(), Matchers.instanceOf(RSAKey.class)); + Assert.assertEquals(keySize == null ? 4096 : keySize, ((RSAKey) x509Cert.getPublicKey()).getModulus().bitLength()); + Calendar calendar = Calendar.getInstance(); + calendar.add(Calendar.YEAR, validity == null ? 3 : validity); + MatcherAssert.assertThat(x509Cert.getNotAfter().getTime(), Matchers.allOf( + Matchers.greaterThan(calendar.getTime().getTime() - 5000), Matchers.lessThan(calendar.getTime().getTime() + 5000))); // Try to login with the new keys diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ClientAuthSignedJWTTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ClientAuthSignedJWTTest.java index e6bfc2b1aea..25f357bf344 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ClientAuthSignedJWTTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/oauth/ClientAuthSignedJWTTest.java @@ -342,19 +342,19 @@ public class ClientAuthSignedJWTTest extends AbstractClientAuthSignedJWTTest { @Test public void testClientWithGeneratedKeysJKS() throws Exception { KeystoreUtils.assumeKeystoreTypeSupported(KeystoreFormat.JKS); - testClientWithGeneratedKeys("JKS"); + testClientWithGeneratedKeys("JKS", null, null); } @Test public void testClientWithGeneratedKeysPKCS12() throws Exception { KeystoreUtils.assumeKeystoreTypeSupported(KeystoreFormat.PKCS12); - testClientWithGeneratedKeys("PKCS12"); + testClientWithGeneratedKeys("PKCS12", 2048, null); } @Test public void testClientWithGeneratedKeysBCFKS() throws Exception { KeystoreUtils.assumeKeystoreTypeSupported(KeystoreFormat.BCFKS); - testClientWithGeneratedKeys(KeystoreFormat.BCFKS.toString()); + testClientWithGeneratedKeys(KeystoreFormat.BCFKS.toString(), 3072, 5); } @Test