CLOUDSTACK-7468: Fixed the NetScaler SSL Termination behavior with Projects

Signed-off-by: Will Stevens <wstevens@cloudops.com>
This commit is contained in:
Will Stevens 2014-09-02 15:25:41 -04:00
parent dc3f0cbc63
commit 5d11385c31
5 changed files with 180 additions and 10 deletions

View File

@ -29,6 +29,7 @@ import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.AccountResponse;
import org.apache.cloudstack.api.response.FirewallRuleResponse;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.ProjectResponse;
import org.apache.cloudstack.api.response.SslCertResponse;
import org.apache.cloudstack.context.CallContext;
@ -58,6 +59,9 @@ public class ListSslCertsCmd extends BaseCmd {
@Parameter(name = ApiConstants.LBID, type = CommandType.UUID, entityType = FirewallRuleResponse.class, required = false, description = "Loadbalancer Rule Id")
private Long lbId;
@Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, entityType = ProjectResponse.class, required = false, description = "project who owns the ssl cert")
private Long projectId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -74,6 +78,10 @@ public class ListSslCertsCmd extends BaseCmd {
return lbId;
}
public Long getProjectId() {
return projectId;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////

View File

@ -26,6 +26,8 @@ import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.api.response.ProjectResponse;
import org.apache.cloudstack.api.response.SslCertResponse;
import org.apache.cloudstack.context.CallContext;
@ -62,6 +64,15 @@ public class UploadSslCertCmd extends BaseCmd {
@Parameter(name = ApiConstants.PASSWORD, type = CommandType.STRING, description = "Password for the private key")
private String password;
@Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "account who will own the ssl cert")
private String accountName;
@Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, entityType = ProjectResponse.class, description = "an optional project for the ssl cert")
private Long projectId;
@Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "domain ID of the account owning the ssl cert")
private Long domainId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -82,6 +93,18 @@ public class UploadSslCertCmd extends BaseCmd {
return password;
}
public String getAccountName() {
return accountName;
}
public Long getDomainId() {
return domainId;
}
public Long getProjectId() {
return projectId;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////

View File

@ -48,6 +48,22 @@ public class SslCertResponse extends BaseResponse {
@Param(description = "account for the certificate")
private String accountName;
@SerializedName(ApiConstants.PROJECT_ID)
@Param(description = "the project id of the certificate")
private String projectId;
@SerializedName(ApiConstants.PROJECT)
@Param(description = "the project name of the certificate")
private String projectName;
@SerializedName(ApiConstants.DOMAIN_ID)
@Param(description = "the domain id of the network owner")
private String domainId;
@SerializedName(ApiConstants.DOMAIN)
@Param(description = "the domain name of the network owner")
private String domain;
@SerializedName(ApiConstants.CERTIFICATE_CHAIN)
@Param(description = "certificate chain")
private String certchain;
@ -79,6 +95,22 @@ public class SslCertResponse extends BaseResponse {
this.accountName = accountName;
}
public void setProjectId(String projectId) {
this.projectId = projectId;
}
public void setProjectName(String projectName) {
this.projectName = projectName;
}
public void setDomainId(String domainId) {
this.domainId = domainId;
}
public void setDomainName(String domain) {
this.domain = domain;
}
public void setCertchain(String chain) {
this.certchain = chain;
}

View File

@ -63,6 +63,8 @@ import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMReader;
import org.bouncycastle.openssl.PasswordFinder;
import com.cloud.domain.dao.DomainDao;
import com.cloud.domain.DomainVO;
import com.cloud.event.ActionEvent;
import com.cloud.event.EventTypes;
import com.cloud.exception.InvalidParameterValueException;
@ -73,6 +75,8 @@ import com.cloud.network.dao.SslCertDao;
import com.cloud.network.dao.SslCertVO;
import com.cloud.network.lb.CertService;
import com.cloud.network.rules.LoadBalancer;
import com.cloud.projects.Project;
import com.cloud.projects.ProjectService;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.dao.AccountDao;
@ -90,6 +94,10 @@ public class CertServiceImpl implements CertService {
@Inject
AccountDao _accountDao;
@Inject
ProjectService _projectMgr;
@Inject
DomainDao _domainDao;
@Inject
SslCertDao _sslCertDao;
@Inject
LoadBalancerCertMapDao _lbCertDao;
@ -105,7 +113,6 @@ public class CertServiceImpl implements CertService {
@ActionEvent(eventType = EventTypes.EVENT_LB_CERT_UPLOAD, eventDescription = "Uploading a certificate to cloudstack", async = false)
public SslCertResponse uploadSslCert(UploadSslCertCmd certCmd) {
try {
String cert = certCmd.getCert();
String key = certCmd.getKey();
String password = certCmd.getPassword();
@ -116,8 +123,18 @@ public class CertServiceImpl implements CertService {
String fingerPrint = generateFingerPrint(parseCertificate(cert));
Long accountId = CallContext.current().getCallingAccount().getId();
Long domainId = CallContext.current().getCallingAccount().getDomainId();
CallContext ctx = CallContext.current();
Account caller = ctx.getCallingAccount();
Account owner = null;
if ((certCmd.getAccountName() != null && certCmd.getDomainId() != null) || certCmd.getProjectId() != null) {
owner = _accountMgr.finalizeOwner(caller, certCmd.getAccountName(), certCmd.getDomainId(), certCmd.getProjectId());
} else {
owner = caller;
}
Long accountId = owner.getId();
Long domainId = owner.getDomainId();
SslCertVO certVO = new SslCertVO(cert, key, password, chain, accountId, domainId, fingerPrint);
_sslCertDao.persist(certVO);
@ -170,18 +187,18 @@ public class CertServiceImpl implements CertService {
Long certId = listSslCertCmd.getCertId();
Long accountId = listSslCertCmd.getAccountId();
Long lbRuleId = listSslCertCmd.getLbId();
Long projectId = listSslCertCmd.getProjectId();
List<SslCertResponse> certResponseList = new ArrayList<SslCertResponse>();
if (certId == null && accountId == null && lbRuleId == null) {
throw new InvalidParameterValueException("Invalid parameters either certificate ID or Account ID or Loadbalancer ID required");
if (certId == null && accountId == null && lbRuleId == null && projectId == null) {
throw new InvalidParameterValueException("Invalid parameters either certificate ID or Account ID or Loadbalancer ID or Project ID required");
}
List<LoadBalancerCertMapVO> certLbMap = null;
SslCertVO certVO = null;
if (certId != null) {
certVO = _sslCertDao.findById(certId);
if (certVO == null) {
@ -200,7 +217,7 @@ public class CertServiceImpl implements CertService {
LoadBalancer lb = _entityMgr.findById(LoadBalancerVO.class, lbRuleId);
if (lb == null) {
throw new InvalidParameterValueException("found no loadbalancer wth id: " + lbRuleId);
throw new InvalidParameterValueException("Found no loadbalancer with id: " + lbRuleId);
}
_accountMgr.checkAccess(caller, SecurityChecker.AccessType.UseEntry, true, lb);
@ -222,6 +239,25 @@ public class CertServiceImpl implements CertService {
}
if (projectId != null) {
Project project = _projectMgr.getProject(projectId);
if (project == null) {
throw new InvalidParameterValueException("Found no project with id: " + projectId);
}
List<SslCertVO> projectCertVOList = _sslCertDao.listByAccountId(project.getProjectAccountId());
if (projectCertVOList == null || projectCertVOList.isEmpty())
return certResponseList;
_accountMgr.checkAccess(caller, SecurityChecker.AccessType.UseEntry, true, projectCertVOList.get(0));
for (SslCertVO cert : projectCertVOList) {
certLbMap = _lbCertDao.listByCertId(cert.getId());
certResponseList.add(createCertResponse(cert, certLbMap));
}
return certResponseList;
}
//reached here look by accountId
List<SslCertVO> certVOList = _sslCertDao.listByAccountId(accountId);
if (certVOList == null || certVOList.isEmpty())
@ -232,7 +268,6 @@ public class CertServiceImpl implements CertService {
certLbMap = _lbCertDao.listByCertId(cert.getId());
certResponseList.add(createCertResponse(cert, certLbMap));
}
return certResponseList;
}
@ -264,13 +299,24 @@ public class CertServiceImpl implements CertService {
SslCertResponse response = new SslCertResponse();
Account account = _accountDao.findByIdIncludingRemoved(cert.getAccountId());
if (account.getType() == Account.ACCOUNT_TYPE_PROJECT) {
// find the project
Project project = _projectMgr.findByProjectAccountIdIncludingRemoved(account.getId());
response.setProjectId(project.getUuid());
response.setProjectName(project.getName());
} else {
response.setAccountName(account.getAccountName());
}
DomainVO domain = _domainDao.findByIdIncludingRemoved(cert.getDomainId());
response.setDomainId(domain.getUuid());
response.setDomainName(domain.getName());
response.setObjectName("sslcert");
response.setId(cert.getUuid());
response.setCertificate(cert.getCertificate());
response.setPrivatekey(cert.getKey());
response.setFingerprint(cert.getFingerPrint());
response.setAccountName(account.getAccountName());
if (cert.getChain() != null)
response.setCertchain(cert.getChain());

View File

@ -40,6 +40,8 @@ import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import com.cloud.domain.dao.DomainDao;
import com.cloud.domain.DomainVO;
import com.cloud.network.dao.LoadBalancerCertMapDao;
import com.cloud.network.dao.LoadBalancerCertMapVO;
import com.cloud.network.dao.LoadBalancerVO;
@ -110,6 +112,10 @@ public class CertServiceTest {
Account account = new AccountVO("testaccount", 1, "networkdomain", (short)0, UUID.randomUUID().toString());
when(certService._accountMgr.getAccount(anyLong())).thenReturn(account);
certService._domainDao = Mockito.mock(DomainDao.class);
DomainVO domain = new DomainVO("networkdomain", 1L, 1L, "networkdomain");
when(certService._domainDao.findByIdIncludingRemoved(anyLong())).thenReturn(domain);
certService._sslCertDao = Mockito.mock(SslCertDao.class);
when(certService._sslCertDao.persist(any(SslCertVO.class))).thenReturn(new SslCertVO());
@ -161,6 +167,10 @@ public class CertServiceTest {
Account account = new AccountVO("testaccount", 1, "networkdomain", (short)0, UUID.randomUUID().toString());
when(certService._accountMgr.getAccount(anyLong())).thenReturn(account);
certService._domainDao = Mockito.mock(DomainDao.class);
DomainVO domain = new DomainVO("networkdomain", 1L, 1L, "networkdomain");
when(certService._domainDao.findByIdIncludingRemoved(anyLong())).thenReturn(domain);
certService._sslCertDao = Mockito.mock(SslCertDao.class);
when(certService._sslCertDao.persist(any(SslCertVO.class))).thenReturn(new SslCertVO());
@ -207,6 +217,10 @@ public class CertServiceTest {
Account account = new AccountVO("testaccount", 1, "networkdomain", (short)0, UUID.randomUUID().toString());
when(certService._accountMgr.getAccount(anyLong())).thenReturn(account);
certService._domainDao = Mockito.mock(DomainDao.class);
DomainVO domain = new DomainVO("networkdomain", 1L, 1L, "networkdomain");
when(certService._domainDao.findByIdIncludingRemoved(anyLong())).thenReturn(domain);
certService._sslCertDao = Mockito.mock(SslCertDao.class);
when(certService._sslCertDao.persist(any(SslCertVO.class))).thenReturn(new SslCertVO());
@ -248,6 +262,10 @@ public class CertServiceTest {
Account account = new AccountVO("testaccount", 1, "networkdomain", (short)0, UUID.randomUUID().toString());
when(certService._accountMgr.getAccount(anyLong())).thenReturn(account);
certService._domainDao = Mockito.mock(DomainDao.class);
DomainVO domain = new DomainVO("networkdomain", 1L, 1L, "networkdomain");
when(certService._domainDao.findByIdIncludingRemoved(anyLong())).thenReturn(domain);
certService._sslCertDao = Mockito.mock(SslCertDao.class);
when(certService._sslCertDao.persist(any(SslCertVO.class))).thenReturn(new SslCertVO());
@ -300,6 +318,10 @@ public class CertServiceTest {
Account account = new AccountVO("testaccount", 1, "networkdomain", (short)0, UUID.randomUUID().toString());
when(certService._accountMgr.getAccount(anyLong())).thenReturn(account);
certService._domainDao = Mockito.mock(DomainDao.class);
DomainVO domain = new DomainVO("networkdomain", 1L, 1L, "networkdomain");
when(certService._domainDao.findByIdIncludingRemoved(anyLong())).thenReturn(domain);
certService._sslCertDao = Mockito.mock(SslCertDao.class);
when(certService._sslCertDao.persist(any(SslCertVO.class))).thenReturn(new SslCertVO());
@ -351,6 +373,10 @@ public class CertServiceTest {
Account account = new AccountVO("testaccount", 1, "networkdomain", (short)0, UUID.randomUUID().toString());
when(certService._accountMgr.getAccount(anyLong())).thenReturn(account);
certService._domainDao = Mockito.mock(DomainDao.class);
DomainVO domain = new DomainVO("networkdomain", 1L, 1L, "networkdomain");
when(certService._domainDao.findByIdIncludingRemoved(anyLong())).thenReturn(domain);
certService._sslCertDao = Mockito.mock(SslCertDao.class);
when(certService._sslCertDao.persist(any(SslCertVO.class))).thenReturn(new SslCertVO());
@ -396,6 +422,10 @@ public class CertServiceTest {
Account account = new AccountVO("testaccount", 1, "networkdomain", (short)0, UUID.randomUUID().toString());
when(certService._accountMgr.getAccount(anyLong())).thenReturn(account);
certService._domainDao = Mockito.mock(DomainDao.class);
DomainVO domain = new DomainVO("networkdomain", 1L, 1L, "networkdomain");
when(certService._domainDao.findByIdIncludingRemoved(anyLong())).thenReturn(domain);
certService._sslCertDao = Mockito.mock(SslCertDao.class);
when(certService._sslCertDao.persist(any(SslCertVO.class))).thenReturn(new SslCertVO());
@ -440,6 +470,10 @@ public class CertServiceTest {
Account account = new AccountVO("testaccount", 1, "networkdomain", (short)0, UUID.randomUUID().toString());
when(certService._accountMgr.getAccount(anyLong())).thenReturn(account);
certService._domainDao = Mockito.mock(DomainDao.class);
DomainVO domain = new DomainVO("networkdomain", 1L, 1L, "networkdomain");
when(certService._domainDao.findByIdIncludingRemoved(anyLong())).thenReturn(domain);
certService._sslCertDao = Mockito.mock(SslCertDao.class);
when(certService._sslCertDao.persist(any(SslCertVO.class))).thenReturn(new SslCertVO());
@ -479,6 +513,10 @@ public class CertServiceTest {
Account account = new AccountVO("testaccount", 1, "networkdomain", (short)0, UUID.randomUUID().toString());
when(certService._accountMgr.getAccount(anyLong())).thenReturn(account);
certService._domainDao = Mockito.mock(DomainDao.class);
DomainVO domain = new DomainVO("networkdomain", 1L, 1L, "networkdomain");
when(certService._domainDao.findByIdIncludingRemoved(anyLong())).thenReturn(domain);
certService._sslCertDao = Mockito.mock(SslCertDao.class);
when(certService._sslCertDao.persist(any(SslCertVO.class))).thenReturn(new SslCertVO());
@ -519,6 +557,10 @@ public class CertServiceTest {
Account account = new AccountVO("testaccount", 1, "networkdomain", (short)0, UUID.randomUUID().toString());
when(certService._accountMgr.getAccount(anyLong())).thenReturn(account);
certService._domainDao = Mockito.mock(DomainDao.class);
DomainVO domain = new DomainVO("networkdomain", 1L, 1L, "networkdomain");
when(certService._domainDao.findByIdIncludingRemoved(anyLong())).thenReturn(domain);
certService._sslCertDao = Mockito.mock(SslCertDao.class);
when(certService._sslCertDao.persist(any(SslCertVO.class))).thenReturn(new SslCertVO());
@ -558,6 +600,10 @@ public class CertServiceTest {
Account account = new AccountVO("testaccount", 1, "networkdomain", (short)0, UUID.randomUUID().toString());
when(certService._accountMgr.getAccount(anyLong())).thenReturn(account);
certService._domainDao = Mockito.mock(DomainDao.class);
DomainVO domain = new DomainVO("networkdomain", 1L, 1L, "networkdomain");
when(certService._domainDao.findByIdIncludingRemoved(anyLong())).thenReturn(domain);
certService._sslCertDao = Mockito.mock(SslCertDao.class);
when(certService._sslCertDao.persist(any(SslCertVO.class))).thenReturn(new SslCertVO());
@ -598,6 +644,10 @@ public class CertServiceTest {
Account account = new AccountVO("testaccount", 1, "networkdomain", (short)0, UUID.randomUUID().toString());
when(certService._accountMgr.getAccount(anyLong())).thenReturn(account);
certService._domainDao = Mockito.mock(DomainDao.class);
DomainVO domain = new DomainVO("networkdomain", 1L, 1L, "networkdomain");
when(certService._domainDao.findByIdIncludingRemoved(anyLong())).thenReturn(domain);
certService._sslCertDao = Mockito.mock(SslCertDao.class);
when(certService._sslCertDao.persist(any(SslCertVO.class))).thenReturn(new SslCertVO());
@ -637,6 +687,10 @@ public class CertServiceTest {
Account account = new AccountVO("testaccount", 1, "networkdomain", (short)0, UUID.randomUUID().toString());
when(certService._accountMgr.getAccount(anyLong())).thenReturn(account);
certService._domainDao = Mockito.mock(DomainDao.class);
DomainVO domain = new DomainVO("networkdomain", 1L, 1L, "networkdomain");
when(certService._domainDao.findByIdIncludingRemoved(anyLong())).thenReturn(domain);
certService._sslCertDao = Mockito.mock(SslCertDao.class);
when(certService._sslCertDao.remove(anyLong())).thenReturn(true);
when(certService._sslCertDao.findById(anyLong())).thenReturn(new SslCertVO());
@ -671,6 +725,10 @@ public class CertServiceTest {
Account account = new AccountVO("testaccount", 1, "networkdomain", (short)0, UUID.randomUUID().toString());
when(certService._accountMgr.getAccount(anyLong())).thenReturn(account);
certService._domainDao = Mockito.mock(DomainDao.class);
DomainVO domain = new DomainVO("networkdomain", 1L, 1L, "networkdomain");
when(certService._domainDao.findByIdIncludingRemoved(anyLong())).thenReturn(domain);
certService._sslCertDao = Mockito.mock(SslCertDao.class);
when(certService._sslCertDao.remove(anyLong())).thenReturn(true);
when(certService._sslCertDao.findById(anyLong())).thenReturn(new SslCertVO());
@ -706,7 +764,6 @@ public class CertServiceTest {
@Test
public void runDeleteSslCertInvalidId() throws NoSuchFieldException, IllegalAccessException {
TransactionLegacy txn = TransactionLegacy.open("runDeleteSslCertInvalidId");
long certId = 1;
@ -716,6 +773,10 @@ public class CertServiceTest {
Account account = new AccountVO("testaccount", 1, "networkdomain", (short)0, UUID.randomUUID().toString());
when(certService._accountMgr.getAccount(anyLong())).thenReturn(account);
certService._domainDao = Mockito.mock(DomainDao.class);
DomainVO domain = new DomainVO("networkdomain", 1L, 1L, "networkdomain");
when(certService._domainDao.findByIdIncludingRemoved(anyLong())).thenReturn(domain);
certService._sslCertDao = Mockito.mock(SslCertDao.class);
when(certService._sslCertDao.remove(anyLong())).thenReturn(true);
when(certService._sslCertDao.findById(anyLong())).thenReturn(null);