fix: adds pfx as a recognized extension (#26876)

closes #24661

Signed-off-by: Steve Hawkins <shawkins@redhat.com>
This commit is contained in:
Steven Hawkins 2024-02-13 09:38:12 -05:00 committed by GitHub
parent 5a2b145e4e
commit 3a04acab51
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 48 additions and 38 deletions

View file

@ -28,6 +28,7 @@ import java.security.KeyStore;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.security.PublicKey; import java.security.PublicKey;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import java.util.Optional; import java.util.Optional;
/** /**
@ -38,22 +39,30 @@ public class KeystoreUtil {
public enum KeystoreFormat { public enum KeystoreFormat {
JKS("jks"), JKS("jks"),
PKCS12("p12"), PKCS12("p12", "pfx"),
BCFKS("bcfks"); BCFKS("bcfks");
// Typical file extension for this keystore format // Typical file extension for this keystore format
private final String fileExtension; private final List<String> fileExtensions;
KeystoreFormat(String extension) { KeystoreFormat(String... extensions) {
this.fileExtension = extension; this.fileExtensions = Arrays.asList(extensions);
} }
public String getFileExtension() { public List<String> getFileExtensions() {
return fileExtension; return fileExtensions;
}
public String getPrimaryExtension() {
return fileExtensions.get(0);
} }
} }
public static KeyStore loadKeyStore(String filename, String password) throws Exception { public static KeyStore loadKeyStore(String filename, String password) throws Exception {
String keystoreType = getKeystoreType(null, filename, KeyStore.getDefaultType()); return loadKeyStore(filename, password, null);
}
public static KeyStore loadKeyStore(String filename, String password, String preferedType) throws Exception {
String keystoreType = getKeystoreType(preferedType, filename, KeyStore.getDefaultType());
KeyStore trustStore = KeyStore.getInstance(keystoreType); KeyStore trustStore = KeyStore.getInstance(keystoreType);
InputStream trustStream = null; InputStream trustStream = null;
if (filename.startsWith(GenericConstants.PROTOCOL_CLASSPATH)) { if (filename.startsWith(GenericConstants.PROTOCOL_CLASSPATH)) {
@ -71,7 +80,7 @@ public class KeystoreUtil {
trustStream = new FileInputStream(new File(filename)); trustStream = new FileInputStream(new File(filename));
} }
try (InputStream is = trustStream) { try (InputStream is = trustStream) {
trustStore.load(is, password.toCharArray()); trustStore.load(is, password == null ? null : password.toCharArray());
} }
return trustStore; return trustStore;
} }
@ -115,7 +124,7 @@ public class KeystoreUtil {
if (lastDotIndex > -1) { if (lastDotIndex > -1) {
String ext = path.substring(lastDotIndex + 1).toLowerCase(); String ext = path.substring(lastDotIndex + 1).toLowerCase();
Optional<KeystoreFormat> detectedType = Arrays.stream(KeystoreUtil.KeystoreFormat.values()) Optional<KeystoreFormat> detectedType = Arrays.stream(KeystoreUtil.KeystoreFormat.values())
.filter(ksFormat -> ksFormat.getFileExtension().equals(ext)) .filter(ksFormat -> ksFormat.getFileExtensions().contains(ext))
.findFirst(); .findFirst();
if (detectedType.isPresent()) return detectedType.get().toString(); if (detectedType.isPresent()) return detectedType.get().toString();
} }

View file

@ -0,0 +1,16 @@
package org.keycloak.common.util;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class KeystoreUtilTest {
@Test
public void testGetType() {
assertEquals("x", KeystoreUtil.getKeystoreType("x", "y", "z"));
assertEquals("z", KeystoreUtil.getKeystoreType(null, "y", "z"));
assertEquals(KeystoreUtil.KeystoreFormat.PKCS12.name(), KeystoreUtil.getKeystoreType(null, "y.pfx", "z"));
}
}

View file

@ -27,8 +27,6 @@ import org.keycloak.provider.ProviderConfigProperty;
import org.keycloak.provider.ProviderConfigurationBuilder; import org.keycloak.provider.ProviderConfigurationBuilder;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.security.KeyStore; import java.security.KeyStore;
import java.security.KeyStoreException; import java.security.KeyStoreException;
@ -100,12 +98,12 @@ public class FileTruststoreProviderFactory implements TruststoreProviderFactory
} }
String type = KeystoreUtil.getKeystoreType(configuredType, storepath, KeyStore.getDefaultType()); String type = KeystoreUtil.getKeystoreType(configuredType, storepath, KeyStore.getDefaultType());
try { try {
truststore = loadStore(storepath, type, pass == null ? null :pass.toCharArray()); truststore = KeystoreUtil.loadKeyStore(storepath, pass, type);
} catch (Exception e) { } catch (Exception e) {
// in fips mode the default truststore type can be pkcs12, but the cacerts file will still be jks // in fips mode the default truststore type can be pkcs12, but the cacerts file will still be jks
if (system && !"jks".equalsIgnoreCase(type)) { if (system && !"jks".equalsIgnoreCase(type)) {
try { try {
truststore = loadStore(storepath, "jks", pass == null ? null :pass.toCharArray()); truststore = KeystoreUtil.loadKeyStore(storepath, pass, "jks");
} catch (Exception e1) { } catch (Exception e1) {
} }
} }
@ -130,14 +128,6 @@ public class FileTruststoreProviderFactory implements TruststoreProviderFactory
log.debugf("File truststore provider initialized: %s, Truststore type: %s", new File(storepath).getAbsolutePath(), type); log.debugf("File truststore provider initialized: %s, Truststore type: %s", new File(storepath).getAbsolutePath(), type);
} }
private KeyStore loadStore(String path, String type, char[] password) throws Exception {
KeyStore ks = KeyStore.getInstance(type);
try (InputStream is = new FileInputStream(path)) {
ks.load(is, password);
return ks;
}
}
@Override @Override
public void postInit(KeycloakSessionFactory factory) { public void postInit(KeycloakSessionFactory factory) {
} }

View file

@ -18,11 +18,11 @@
package org.keycloak.truststore; package org.keycloak.truststore;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.common.util.KeystoreUtil;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.InputStream;
import java.security.KeyStore; import java.security.KeyStore;
import java.security.KeyStoreException; import java.security.KeyStoreException;
import java.security.cert.Certificate; import java.security.cert.Certificate;
@ -30,7 +30,6 @@ import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory; import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.Collections; import java.util.Collections;
import java.util.Optional;
import java.util.stream.Stream; import java.util.stream.Stream;
/** /**
@ -155,8 +154,7 @@ public class TruststoreBuilder {
if (defaultTrustStore.exists()) { if (defaultTrustStore.exists()) {
String path = defaultTrustStore.getAbsolutePath(); String path = defaultTrustStore.getAbsolutePath();
mergeTrustStore(truststore, path, mergeTrustStore(truststore, path, loadStore(path, type, password));
loadStore(path, type, Optional.ofNullable(password).map(String::toCharArray).orElse(null)));
} else { } else {
LOGGER.warnf("Default truststore was to be included, but could not be found at: %s", defaultTrustStore); LOGGER.warnf("Default truststore was to be included, but could not be found at: %s", defaultTrustStore);
} }
@ -173,11 +171,9 @@ public class TruststoreBuilder {
return new File(securityDirectory, "cacerts"); return new File(securityDirectory, "cacerts");
} }
static KeyStore loadStore(String path, String type, char[] password) { static KeyStore loadStore(String path, String type, String password) {
try (InputStream is = new FileInputStream(path)) { try {
KeyStore ks = KeyStore.getInstance(type); return KeystoreUtil.loadKeyStore(path, password, type);
ks.load(is, password);
return ks;
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException( throw new RuntimeException(
"Failed to initialize truststore: " + new File(path).getAbsolutePath() + ", type: " + type, e); "Failed to initialize truststore: " + new File(path).getAbsolutePath() + ", type: " + type, e);

View file

@ -46,10 +46,9 @@ public class TruststoreBuilderTest {
assertTrue(storeWithDefaultsAliases.containsAll(storeWithoutDefaultsAliases)); assertTrue(storeWithDefaultsAliases.containsAll(storeWithoutDefaultsAliases));
// saving / loading should provide the certs even without a password // saving / loading should provide the certs even without a password
char[] password = null; File saved = TruststoreBuilder.saveTruststore(storeWithDefaults, "target", null);
File saved = TruststoreBuilder.saveTruststore(storeWithDefaults, "target", password);
KeyStore savedLoaded = TruststoreBuilder.loadStore(saved.getAbsolutePath(), TruststoreBuilder.PKCS12, password); KeyStore savedLoaded = TruststoreBuilder.loadStore(saved.getAbsolutePath(), TruststoreBuilder.PKCS12, null);
assertEquals(certs, Collections.list(savedLoaded.aliases()).size()); assertEquals(certs, Collections.list(savedLoaded.aliases()).size());
} }

View file

@ -64,7 +64,7 @@ public class KeystoreUtils {
} }
public static KeystoreInfo generateKeystore(TemporaryFolder folder, KeystoreUtil.KeystoreFormat keystoreType, String subject, String keystorePassword, String keyPassword) throws Exception { public static KeystoreInfo generateKeystore(TemporaryFolder folder, KeystoreUtil.KeystoreFormat keystoreType, String subject, String keystorePassword, String keyPassword) throws Exception {
String fileName = "keystore." + keystoreType.getFileExtension(); String fileName = "keystore." + keystoreType.getPrimaryExtension();
KeyPair keyPair = KeyUtils.generateRsaKeyPair(2048); KeyPair keyPair = KeyUtils.generateRsaKeyPair(2048);
X509Certificate certificate = CertificateUtils.generateV1SelfSignedCertificate(keyPair, subject); X509Certificate certificate = CertificateUtils.generateV1SelfSignedCertificate(keyPair, subject);

View file

@ -513,13 +513,13 @@ public class KcAdmTest extends AbstractAdmCliTest {
@Test @Test
public void testCRUDWithOnTheFlyUserAuthWithSignedJwtClient_JKSKeystore() throws IOException { public void testCRUDWithOnTheFlyUserAuthWithSignedJwtClient_JKSKeystore() throws IOException {
KeystoreUtils.assumeKeystoreTypeSupported(KeystoreUtil.KeystoreFormat.JKS); KeystoreUtils.assumeKeystoreTypeSupported(KeystoreUtil.KeystoreFormat.JKS);
testCRUDWithOnTheFlyUserAuthWithSignedJwtClient(KeystoreUtil.KeystoreFormat.JKS.getFileExtension()); testCRUDWithOnTheFlyUserAuthWithSignedJwtClient(KeystoreUtil.KeystoreFormat.JKS.getPrimaryExtension());
} }
@Test @Test
public void testCRUDWithOnTheFlyUserAuthWithSignedJwtClient_PKCS12Keystore() throws IOException { public void testCRUDWithOnTheFlyUserAuthWithSignedJwtClient_PKCS12Keystore() throws IOException {
KeystoreUtils.assumeKeystoreTypeSupported(KeystoreUtil.KeystoreFormat.PKCS12); KeystoreUtils.assumeKeystoreTypeSupported(KeystoreUtil.KeystoreFormat.PKCS12);
testCRUDWithOnTheFlyUserAuthWithSignedJwtClient(KeystoreUtil.KeystoreFormat.PKCS12.getFileExtension()); testCRUDWithOnTheFlyUserAuthWithSignedJwtClient(KeystoreUtil.KeystoreFormat.PKCS12.getPrimaryExtension());
} }
private void testCRUDWithOnTheFlyUserAuthWithSignedJwtClient(String keystoreFileExtension) throws IOException { private void testCRUDWithOnTheFlyUserAuthWithSignedJwtClient(String keystoreFileExtension) throws IOException {

View file

@ -506,13 +506,13 @@ public class KcRegTest extends AbstractRegCliTest {
@Test @Test
public void testCRUDWithOnTheFlyUserAuthWithSignedJwtClient_JKSKeystore() throws IOException { public void testCRUDWithOnTheFlyUserAuthWithSignedJwtClient_JKSKeystore() throws IOException {
KeystoreUtils.assumeKeystoreTypeSupported(KeystoreUtil.KeystoreFormat.JKS); KeystoreUtils.assumeKeystoreTypeSupported(KeystoreUtil.KeystoreFormat.JKS);
testCRUDWithOnTheFlyUserAuthWithSignedJwtClient(KeystoreUtil.KeystoreFormat.JKS.getFileExtension()); testCRUDWithOnTheFlyUserAuthWithSignedJwtClient(KeystoreUtil.KeystoreFormat.JKS.getPrimaryExtension());
} }
@Test @Test
public void testCRUDWithOnTheFlyUserAuthWithSignedJwtClient_PKCS12Keystore() throws IOException { public void testCRUDWithOnTheFlyUserAuthWithSignedJwtClient_PKCS12Keystore() throws IOException {
KeystoreUtils.assumeKeystoreTypeSupported(KeystoreUtil.KeystoreFormat.PKCS12); KeystoreUtils.assumeKeystoreTypeSupported(KeystoreUtil.KeystoreFormat.PKCS12);
testCRUDWithOnTheFlyUserAuthWithSignedJwtClient(KeystoreUtil.KeystoreFormat.PKCS12.getFileExtension()); testCRUDWithOnTheFlyUserAuthWithSignedJwtClient(KeystoreUtil.KeystoreFormat.PKCS12.getPrimaryExtension());
} }
private void testCRUDWithOnTheFlyUserAuthWithSignedJwtClient(String keystoreFileExtension) throws IOException { private void testCRUDWithOnTheFlyUserAuthWithSignedJwtClient(String keystoreFileExtension) throws IOException {