Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import com.cloud.agent.api.LogLevel;
import com.cloud.agent.api.LogLevel.Log4jLevel;
import com.cloud.utils.Pair;
import com.cloud.utils.component.Manager;

public interface KeystoreManager extends Manager {
Expand Down Expand Up @@ -59,7 +60,7 @@ public String getRootCACert() {
}
}

boolean validateCertificate(String certificate, String key, String domainSuffix);
Pair<Boolean, String> validateCertificate(String certificate, String key, String domainSuffix);

void saveCertificate(String name, String certificate, String key, String domainSuffix);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

import javax.inject.Inject;

import com.cloud.utils.Pair;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
Expand All @@ -47,24 +48,28 @@ public class KeystoreManagerImpl extends ManagerBase implements KeystoreManager
private KeystoreDao _ksDao;

@Override
public boolean validateCertificate(String certificate, String key, String domainSuffix) {
public Pair<Boolean, String> validateCertificate(String certificate, String key, String domainSuffix) {
String errMsg = null;
if (StringUtils.isAnyEmpty(certificate, key, domainSuffix)) {
s_logger.error("Invalid parameter found in (certificate, key, domainSuffix) tuple for domain: " + domainSuffix);
return false;
errMsg = String.format("Invalid parameter found in (certificate, key, domainSuffix) tuple for domain: %s", domainSuffix);
s_logger.error(errMsg);
return new Pair<>(false, errMsg);
}

try {
String ksPassword = "passwordForValidation";
byte[] ksBits = CertificateHelper.buildAndSaveKeystore(domainSuffix, certificate, getKeyContent(key), ksPassword);
KeyStore ks = CertificateHelper.loadKeystore(ksBits, ksPassword);
if (ks != null)
return true;

s_logger.error("Unabled to construct keystore for domain: " + domainSuffix);
if (ks != null) {
return new Pair<>(true, errMsg);
}
errMsg = String.format("Unable to construct keystore for domain: %s", domainSuffix);
s_logger.error(errMsg);
} catch (Exception e) {
s_logger.error("Certificate validation failed due to exception for domain: " + domainSuffix, e);
errMsg = String.format("Certificate validation failed due to exception for domain: %s", domainSuffix);
s_logger.error(errMsg, e);
}
return false;
return new Pair<>(false, errMsg);
}

@Override
Expand Down
27 changes: 23 additions & 4 deletions server/src/main/java/com/cloud/server/ManagementServerImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.cloud.server;

import java.lang.reflect.Field;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
Expand All @@ -43,6 +44,7 @@
import javax.inject.Inject;
import javax.naming.ConfigurationException;

import com.cloud.utils.security.CertificateHelper;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.SecurityChecker;
import org.apache.cloudstack.affinity.AffinityGroupProcessor;
Expand Down Expand Up @@ -4483,13 +4485,12 @@ public String uploadCertificate(final UploadCustomCertificateCmd cmd) {

final String certificate = cmd.getCertificate();
final String key = cmd.getPrivateKey();
String domainSuffix = cmd.getDomainSuffix();

if (cmd.getPrivateKey() != null && !_ksMgr.validateCertificate(certificate, key, cmd.getDomainSuffix())) {
throw new InvalidParameterValueException("Failed to pass certificate validation check");
}
validateCertificate(certificate, key, domainSuffix);

if (cmd.getPrivateKey() != null) {
_ksMgr.saveCertificate(ConsoleProxyManager.CERTIFICATE_NAME, certificate, key, cmd.getDomainSuffix());
_ksMgr.saveCertificate(ConsoleProxyManager.CERTIFICATE_NAME, certificate, key, domainSuffix);

// Reboot ssvm here since private key is present - meaning server cert being passed
final List<SecondaryStorageVmVO> alreadyRunning = _secStorageVmDao.getSecStorageVmListInStates(null, State.Running, State.Migrating, State.Starting);
Expand All @@ -4506,6 +4507,24 @@ public String uploadCertificate(final UploadCustomCertificateCmd cmd) {
+ "please give a few minutes for console access and storage services service to be up and working again";
}

private void validateCertificate(String certificate, String key, String domainSuffix) {
if (key != null) {
Pair<Boolean, String> result = _ksMgr.validateCertificate(certificate, key, domainSuffix);
if (!result.first()) {
throw new InvalidParameterValueException(String.format("Failed to pass certificate validation check with error: %s", result.second()));
}
} else {
try {
s_logger.debug(String.format("Trying to validate the root certificate format"));
CertificateHelper.buildCertificate(certificate);
} catch (CertificateException e) {
String errorMsg = String.format("Failed to pass certificate validation check with error: Certificate validation failed due to exception: %s", e.getMessage());
s_logger.error(errorMsg);
throw new InvalidParameterValueException(errorMsg);
}
}
}

@Override
public List<String> getHypervisors(final Long zoneId) {
final List<String> result = new ArrayList<String>();
Expand Down