Code development platform for open source projects from the European Union institutions

Skip to content
Snippets Groups Projects
Commit 726195bf authored by Joze RIHTARSIC's avatar Joze RIHTARSIC
Browse files

[EDELIVERY-13125] update keystore keys handling

parent 80ff7f6e
Branches bugfix/EDELIVERY-13125-remove-caching-of-the-keys
No related tags found
No related merge requests found
Pipeline #159271 passed with warnings
...@@ -51,7 +51,7 @@ cleanExternalImageResources() { ...@@ -51,7 +51,7 @@ cleanExternalImageResources() {
} }
composeBuildImage() { composeBuildImage() {
echo "Build ${IMAGE_NAME_DOMIBUS_SOAPUI} image..." echo "Build ${IMAGE_SMP_WEBLOGIC122} image..."
docker compose -f docker-compose.build.yml build docker compose -f docker-compose.build.yml build
} }
......
...@@ -51,7 +51,7 @@ cleanExternalImageResources() { ...@@ -51,7 +51,7 @@ cleanExternalImageResources() {
} }
composeBuildImage() { composeBuildImage() {
echo "Build ${IMAGE_NAME_DOMIBUS_SOAPUI} image..." echo "Build ${IMAGE_SMP_WEBLOGIC141} image..."
docker compose -f docker-compose.build.yml build docker compose -f docker-compose.build.yml build
} }
......
...@@ -8,9 +8,9 @@ ...@@ -8,9 +8,9 @@
* versions of the EUPL (the "Licence"); * versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence. * You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at: * You may obtain a copy of the Licence at:
* *
* [PROJECT_HOME]\license\eupl-1.2\license.txt or https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 * [PROJECT_HOME]\license\eupl-1.2\license.txt or https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
* *
* Unless required by applicable law or agreed to in writing, software distributed under the Licence is * Unless required by applicable law or agreed to in writing, software distributed under the Licence is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the Licence for the specific language governing permissions and limitations under the Licence. * See the Licence for the specific language governing permissions and limitations under the Licence.
...@@ -32,7 +32,11 @@ import org.springframework.stereotype.Service; ...@@ -32,7 +32,11 @@ import org.springframework.stereotype.Service;
import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.KeyManagerFactory;
import java.io.*; import javax.net.ssl.X509KeyManager;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files; import java.nio.file.Files;
import java.security.*; import java.security.*;
import java.security.cert.Certificate; import java.security.cert.Certificate;
...@@ -62,7 +66,7 @@ public class UIKeystoreService extends BasicKeystoreService { ...@@ -62,7 +66,7 @@ public class UIKeystoreService extends BasicKeystoreService {
this.configurationService = configurationService; this.configurationService = configurationService;
} }
private final Map<String, Key> keystoreKeys = new HashMap<>(); private final List<String> keystoreKeys = new ArrayList<>(); // list of aliases with private keys
private final Map<String, X509Certificate> keystoreCertificates = new HashMap<>(); private final Map<String, X509Certificate> keystoreCertificates = new HashMap<>();
private final List<CertificateRO> certificateROList = new ArrayList<>(); private final List<CertificateRO> certificateROList = new ArrayList<>();
...@@ -97,19 +101,20 @@ public class UIKeystoreService extends BasicKeystoreService { ...@@ -97,19 +101,20 @@ public class UIKeystoreService extends BasicKeystoreService {
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, keystoreSecToken.toCharArray()); kmf.init(keyStore, keystoreSecToken.toCharArray());
keyManagersTemp = kmf.getKeyManagers(); keyManagersTemp = kmf.getKeyManagers();
} catch (KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException exception) { } catch (KeyStoreException | NoSuchAlgorithmException |
UnrecoverableKeyException exception) {
LOG.error("Error occurred while initialize keyManagers : " LOG.error("Error occurred while initialize keyManagers : "
+ keystoreFile.getAbsolutePath() + " Error: " + ExceptionUtils.getRootCauseMessage(exception), exception); + keystoreFile.getAbsolutePath() + " Error: " + ExceptionUtils.getRootCauseMessage(exception), exception);
return; return;
} }
// load keys for signature // load keys for signature
Map<String, Key> hmKeys = new HashMap<>(); List<String> keyList = new ArrayList<>();
Map<String, X509Certificate> hmCertificates = new HashMap<>(); Map<String, X509Certificate> hmCertificates = new HashMap<>();
try { try {
List<String> aliases = list(keyStore.aliases()); List<String> aliases = list(keyStore.aliases());
for (String alias : aliases) { for (String alias : aliases) {
loadKeyAndCert(keyStore, alias, keystoreSecToken, hmKeys, hmCertificates); loadKeyAndCert(keyStore, alias, keyList, hmCertificates);
} }
} catch (Exception exception) { } catch (Exception exception) {
LOG.error("Could not load signing certificate amd private keys Error: " + ExceptionUtils.getRootCauseMessage(exception), exception); LOG.error("Could not load signing certificate amd private keys Error: " + ExceptionUtils.getRootCauseMessage(exception), exception);
...@@ -123,7 +128,7 @@ public class UIKeystoreService extends BasicKeystoreService { ...@@ -123,7 +128,7 @@ public class UIKeystoreService extends BasicKeystoreService {
keystoreKeys.clear(); keystoreKeys.clear();
keystoreCertificates.clear(); keystoreCertificates.clear();
keystoreKeys.putAll(hmKeys); keystoreKeys.addAll(keyList);
keystoreCertificates.putAll(hmCertificates); keystoreCertificates.putAll(hmCertificates);
// add last file date // add last file date
lastUpdateKeystoreFileTime = keystoreFile.lastModified(); lastUpdateKeystoreFileTime = keystoreFile.lastModified();
...@@ -172,15 +177,17 @@ public class UIKeystoreService extends BasicKeystoreService { ...@@ -172,15 +177,17 @@ public class UIKeystoreService extends BasicKeystoreService {
return keyStore; return keyStore;
} }
private void loadKeyAndCert(KeyStore keyStore, String alias, String keySecurityToken, Map<String, Key> hmKeys, Map<String, X509Certificate> hmCertificates) throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException { private void loadKeyAndCert(KeyStore keyStore, String alias, List<String> keyList, Map<String, X509Certificate> hmCertificates) throws KeyStoreException {
Key key = keyStore.getKey(alias, keySecurityToken.toCharArray());
Certificate certificate = keyStore.getCertificate(alias); Certificate certificate = keyStore.getCertificate(alias);
if (!(certificate instanceof X509Certificate)) { if (!(certificate instanceof X509Certificate)) {
LOG.warn("Wrong certificate type found in keystore, entry alias: [{}]. Entry is ignored", alias); LOG.warn("Wrong certificate type found in keystore, entry alias: [{}]. Entry is ignored", alias);
return; return;
} }
// add to cache // add to cache
hmKeys.put(alias, key); if (keyStore.isKeyEntry(alias)) {
keyList.add(alias);
}
hmCertificates.put(alias, (X509Certificate) certificate); hmCertificates.put(alias, (X509Certificate) certificate);
} }
...@@ -196,7 +203,7 @@ public class UIKeystoreService extends BasicKeystoreService { ...@@ -196,7 +203,7 @@ public class UIKeystoreService extends BasicKeystoreService {
CertificateRO certificateRO = convertToRo(cert); CertificateRO certificateRO = convertToRo(cert);
basicCertificateValidation(cert, certificateRO); basicCertificateValidation(cert, certificateRO);
certificateRO.setAlias(alias); certificateRO.setAlias(alias);
certificateRO.setContainingKey(keystoreKeys.get(alias) != null); certificateRO.setContainingKey(keystoreKeys.contains(alias));
certificateROList.add(certificateRO); certificateROList.add(certificateRO);
}); });
} }
...@@ -208,30 +215,52 @@ public class UIKeystoreService extends BasicKeystoreService { ...@@ -208,30 +215,52 @@ public class UIKeystoreService extends BasicKeystoreService {
return conversionService.convert(d, CertificateRO.class); return conversionService.convert(d, CertificateRO.class);
} }
/**
* Get key from keystore by the alias from the registered keyManagers
*
* @param keyAlias alias of the key or null for the only key in the keystore
* @return key from keystore
* @throws SMPRuntimeException if the key for alias is not found in the keystore
*/
public Key getKey(String keyAlias) { public Key getKey(String keyAlias) {
if (isKeyStoreChanged()) { if (isKeyStoreChanged()) {
refreshData(); refreshData();
} }
if (keystoreKeys.isEmpty()) { if (keystoreKeys.isEmpty() || keyManagers == null || keyManagers.length < 1) {
throw new SMPRuntimeException(ErrorCode.CONFIGURATION_ERROR, "Could not retrieve key: [" + keyAlias + "] from empty keystore: [" + configurationService.getKeystoreFile() +"]!"); throw new SMPRuntimeException(ErrorCode.CONFIGURATION_ERROR, "Could not retrieve key: [" + keyAlias + "] from empty keystore: [" + configurationService.getKeystoreFile() + "]!");
} }
final String searchAlias = getKeyAlias(keyAlias);
// get all X509KeyManager
return Arrays.stream(keyManagers)
.filter(X509KeyManager.class::isInstance)
.map(X509KeyManager.class::cast)
.map(km -> km.getPrivateKey(searchAlias))
.findFirst()
.orElseThrow(() -> new SMPRuntimeException(ErrorCode.CONFIGURATION_ERROR,
"Could not retrieve key: [" + keyAlias + "] from empty keystore: [" + configurationService.getKeystoreFile() + "]!"));
}
if (keystoreKeys.size() == 1) { /**
// for backward compatibility... * Get key from keystore by the alias from the registered keyManagers.
// don't care about configured alias in single-domain setup * Legacy behaviour: If the alias is not provided and there is only one key in the keystore, the key is returned.
// and return the only key *
LOG.warn("Returning the only key in keystore regardless the configuration"); * @param keyAlias alias of the key or null
return keystoreKeys.values().iterator().next(); * @return non null key alias
* @throws SMPRuntimeException if the keyAlias is not found in the keystore
*/
private String getKeyAlias(String keyAlias) {
String trimAlias = StringUtils.trim(keyAlias);
if (StringUtils.isBlank(trimAlias) && keystoreKeys.size() == 1) {
trimAlias = keystoreKeys.get(0);
} }
if (isBlank(keyAlias) || !keystoreKeys.containsKey(keyAlias)) { if (isBlank(trimAlias) || !keystoreKeys.contains(trimAlias)) {
throw new SMPRuntimeException(ErrorCode.CONFIGURATION_ERROR, "Wrong configuration, missing key pair from keystore or wrong alias: " + keyAlias); throw new SMPRuntimeException(ErrorCode.CONFIGURATION_ERROR, "Wrong configuration, missing key pair from keystore or wrong alias: " + keyAlias);
} }
return trimAlias;
return keystoreKeys.get(keyAlias);
} }
public X509Certificate getCert(String certAlias) { public X509Certificate getCert(String certAlias) {
...@@ -256,7 +285,7 @@ public class UIKeystoreService extends BasicKeystoreService { ...@@ -256,7 +285,7 @@ public class UIKeystoreService extends BasicKeystoreService {
/** /**
* Import keys smp keystore * Import keys smp keystore
* *
* @param newKeystore new keystore file to import * @param newKeystore new keystore file to import
* @param password password for new keystore file * @param password password for new keystore file
*/ */
public List<CertificateRO> importKeys(KeyStore newKeystore, String password) throws UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException, IOException, CertificateException { public List<CertificateRO> importKeys(KeyStore newKeystore, String password) throws UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException, IOException, CertificateException {
...@@ -276,7 +305,7 @@ public class UIKeystoreService extends BasicKeystoreService { ...@@ -276,7 +305,7 @@ public class UIKeystoreService extends BasicKeystoreService {
/** /**
* Returns entries having certificates that are already present in the current keystore. * Returns entries having certificates that are already present in the current keystore.
* *
* @param newKeystore new keystore file to import * @param newKeystore new keystore file to import
* @return the set of duplicate certificates * @return the set of duplicate certificates
* @throws KeyStoreException when not able to read the keystore aliases * @throws KeyStoreException when not able to read the keystore aliases
*/ */
...@@ -312,10 +341,10 @@ public class UIKeystoreService extends BasicKeystoreService { ...@@ -312,10 +341,10 @@ public class UIKeystoreService extends BasicKeystoreService {
* Store keystore * Store keystore
* *
* @param keyStore to store * @param keyStore to store
* @throws IOException if the keystore can not be persisted * @throws IOException if the keystore can not be persisted
* @throws CertificateException if keystore cannot be stored * @throws CertificateException if keystore cannot be stored
* @throws NoSuchAlgorithmException if keystore type algorithm is not supported * @throws NoSuchAlgorithmException if keystore type algorithm is not supported
* @throws KeyStoreException if keystore cannot be stored * @throws KeyStoreException if keystore cannot be stored
*/ */
private void storeKeystore(KeyStore keyStore) throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException { private void storeKeystore(KeyStore keyStore) throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException {
File keystoreFilePath = configurationService.getKeystoreFile(); File keystoreFilePath = configurationService.getKeystoreFile();
......
...@@ -45,11 +45,13 @@ import java.util.UUID; ...@@ -45,11 +45,13 @@ import java.util.UUID;
import static eu.europa.ec.edelivery.smp.testutil.TestConstants.SIMPLE_EXTENSION_XML; import static eu.europa.ec.edelivery.smp.testutil.TestConstants.SIMPLE_EXTENSION_XML;
public class TestDBUtils { public class TestDBUtils {
// valid key alias for testing from the keystore
public static final String TEST_KEY_ALIAS = "single_domain_key";
public static DBDomain createDBDomain(String domainCode) { public static DBDomain createDBDomain(String domainCode) {
DBDomain domain = new DBDomain(); DBDomain domain = new DBDomain();
domain.setDomainCode(domainCode); domain.setDomainCode(domainCode);
domain.setSignatureKeyAlias(anyString()); domain.setSignatureKeyAlias(TEST_KEY_ALIAS);
domain.setSmlClientKeyAlias(anyString()); domain.setSmlClientKeyAlias(anyString());
domain.setSmlSubdomain(anyString()); domain.setSmlSubdomain(anyString());
domain.setSmlSmpId(anyString()); domain.setSmlSmpId(anyString());
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment