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.PublicKey;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
/**
@ -38,22 +39,30 @@ public class KeystoreUtil {
public enum KeystoreFormat {
JKS("jks"),
PKCS12("p12"),
PKCS12("p12", "pfx"),
BCFKS("bcfks");
// Typical file extension for this keystore format
private final String fileExtension;
KeystoreFormat(String extension) {
this.fileExtension = extension;
private final List<String> fileExtensions;
KeystoreFormat(String... extensions) {
this.fileExtensions = Arrays.asList(extensions);
}
public String getFileExtension() {
return fileExtension;
public List<String> getFileExtensions() {
return fileExtensions;
}
public String getPrimaryExtension() {
return fileExtensions.get(0);
}
}
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);
InputStream trustStream = null;
if (filename.startsWith(GenericConstants.PROTOCOL_CLASSPATH)) {
@ -71,7 +80,7 @@ public class KeystoreUtil {
trustStream = new FileInputStream(new File(filename));
}
try (InputStream is = trustStream) {
trustStore.load(is, password.toCharArray());
trustStore.load(is, password == null ? null : password.toCharArray());
}
return trustStore;
}
@ -115,7 +124,7 @@ public class KeystoreUtil {
if (lastDotIndex > -1) {
String ext = path.substring(lastDotIndex + 1).toLowerCase();
Optional<KeystoreFormat> detectedType = Arrays.stream(KeystoreUtil.KeystoreFormat.values())
.filter(ksFormat -> ksFormat.getFileExtension().equals(ext))
.filter(ksFormat -> ksFormat.getFileExtensions().contains(ext))
.findFirst();
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 java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
@ -100,12 +98,12 @@ public class FileTruststoreProviderFactory implements TruststoreProviderFactory
}
String type = KeystoreUtil.getKeystoreType(configuredType, storepath, KeyStore.getDefaultType());
try {
truststore = loadStore(storepath, type, pass == null ? null :pass.toCharArray());
truststore = KeystoreUtil.loadKeyStore(storepath, pass, type);
} catch (Exception e) {
// in fips mode the default truststore type can be pkcs12, but the cacerts file will still be jks
if (system && !"jks".equalsIgnoreCase(type)) {
try {
truststore = loadStore(storepath, "jks", pass == null ? null :pass.toCharArray());
truststore = KeystoreUtil.loadKeyStore(storepath, pass, "jks");
} 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);
}
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
public void postInit(KeycloakSessionFactory factory) {
}

View file

@ -18,11 +18,11 @@
package org.keycloak.truststore;
import org.jboss.logging.Logger;
import org.keycloak.common.util.KeystoreUtil;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.cert.Certificate;
@ -30,7 +30,6 @@ import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.Optional;
import java.util.stream.Stream;
/**
@ -155,8 +154,7 @@ public class TruststoreBuilder {
if (defaultTrustStore.exists()) {
String path = defaultTrustStore.getAbsolutePath();
mergeTrustStore(truststore, path,
loadStore(path, type, Optional.ofNullable(password).map(String::toCharArray).orElse(null)));
mergeTrustStore(truststore, path, loadStore(path, type, password));
} else {
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");
}
static KeyStore loadStore(String path, String type, char[] password) {
try (InputStream is = new FileInputStream(path)) {
KeyStore ks = KeyStore.getInstance(type);
ks.load(is, password);
return ks;
static KeyStore loadStore(String path, String type, String password) {
try {
return KeystoreUtil.loadKeyStore(path, password, type);
} catch (Exception e) {
throw new RuntimeException(
"Failed to initialize truststore: " + new File(path).getAbsolutePath() + ", type: " + type, e);

View file

@ -46,10 +46,9 @@ public class TruststoreBuilderTest {
assertTrue(storeWithDefaultsAliases.containsAll(storeWithoutDefaultsAliases));
// saving / loading should provide the certs even without a password
char[] password = null;
File saved = TruststoreBuilder.saveTruststore(storeWithDefaults, "target", password);
File saved = TruststoreBuilder.saveTruststore(storeWithDefaults, "target", null);
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());
}

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 {
String fileName = "keystore." + keystoreType.getFileExtension();
String fileName = "keystore." + keystoreType.getPrimaryExtension();
KeyPair keyPair = KeyUtils.generateRsaKeyPair(2048);
X509Certificate certificate = CertificateUtils.generateV1SelfSignedCertificate(keyPair, subject);

View file

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

View file

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