From 0076307863e9155273d9e4c14282de429388c9e9 Mon Sep 17 00:00:00 2001 From: Syed Date: Wed, 6 Nov 2013 15:08:42 -0500 Subject: [PATCH] Squashed merge of Ssl Termination feature Bug: https://issues.apache.org/jira/browse/CLOUDSTACK-4821 FS: https://cwiki.apache.org/confluence/display/CLOUDSTACK/SSL+Termination+Support This patch implements the SSL offload feature for loadbalancers and includes the implementaion for this to work with Netscaler. The following are the new API's that this patch adds uploadSslCert deleteSslCert listSslCert assignCertToLoadBalancer removeCertFromLoadBalancer Unit tests are also included in the patch. --- CHANGES | 1 + .../cloud/agent/api/to/LoadBalancerTO.java | 23 +- api/src/com/cloud/event/EventTypes.java | 8 + api/src/com/cloud/network/Network.java | 1 + api/src/com/cloud/network/lb/CertService.java | 32 + .../cloud/network/lb/LoadBalancingRule.java | 61 +- .../network/lb/LoadBalancingRulesService.java | 8 +- api/src/com/cloud/network/lb/SslCert.java | 16 + .../apache/cloudstack/api/ApiConstants.java | 3 + .../AssignCertToLoadBalancerCmd.java | 92 ++ .../CreateLoadBalancerRuleCmd.java | 9 +- .../user/loadbalancer/DeleteSslCertCmd.java | 83 ++ .../user/loadbalancer/ListSslCertsCmd.java | 106 +++ .../RemoveCertFromLoadBalancerCmd.java | 82 ++ .../user/loadbalancer/UploadSslCertCmd.java | 103 +++ .../api/response/SslCertResponse.java | 90 ++ client/tomcatconf/commands.properties.in | 8 + .../routing/LoadBalancerConfigCommand.java | 1 + .../network/lb/LoadBalancingRulesManager.java | 5 +- ...spring-engine-schema-core-daos-context.xml | 2 + .../network/dao/LoadBalancerCertMapDao.java | 29 + .../dao/LoadBalancerCertMapDaoImpl.java | 79 ++ .../network/dao/LoadBalancerCertMapVO.java | 96 +++ .../com/cloud/network/dao/LoadBalancerVO.java | 16 +- .../src/com/cloud/network/dao/SslCertDao.java | 27 + .../com/cloud/network/dao/SslCertDaoImpl.java | 31 + .../src/com/cloud/network/dao/SslCertVO.java | 132 +++ .../lb/ElasticLoadBalancerManagerImpl.java | 10 +- .../lb/InternalLoadBalancerVMManagerImpl.java | 1 + .../InternalLBVMManagerTest.java | 8 +- .../network/element/NetscalerElement.java | 14 +- .../network/resource/NetscalerResource.java | 259 +++++- .../spring-server-core-managers-context.xml | 2 + ...ExternalLoadBalancerDeviceManagerImpl.java | 6 +- .../lb/LoadBalancingRulesManagerImpl.java | 200 ++++- .../VirtualNetworkApplianceManagerImpl.java | 12 +- .../cloud/server/ManagementServerImpl.java | 10 + .../ApplicationLoadBalancerManagerImpl.java | 2 +- .../network/lb/CertServiceImpl.java | 477 +++++++++++ .../lb/ApplicationLoadBalancerTest.java | 5 +- .../network/lb/CertServiceTest.java | 791 ++++++++++++++++++ .../test/resources/certs/bad_format_cert.crt | 1 + .../test/resources/certs/dsa_self_signed.crt | 26 + .../test/resources/certs/dsa_self_signed.key | 20 + server/test/resources/certs/expired_cert.crt | 20 + server/test/resources/certs/non_x509_pem.crt | 17 + server/test/resources/certs/root_chain.crt | 22 + server/test/resources/certs/rsa_ca_signed.crt | 23 + server/test/resources/certs/rsa_ca_signed.key | 30 + .../test/resources/certs/rsa_ca_signed2.crt | 23 + .../test/resources/certs/rsa_ca_signed2.key | 30 + .../test/resources/certs/rsa_random_pkey.key | 28 + .../test/resources/certs/rsa_self_signed.crt | 19 + .../test/resources/certs/rsa_self_signed.key | 27 + .../certs/rsa_self_signed_with_pwd.crt | 19 + .../certs/rsa_self_signed_with_pwd.key | 30 + setup/db/db/schema-421to430.sql | 28 + utils/src/com/cloud/utils/net/NetUtils.java | 3 + 58 files changed, 3265 insertions(+), 42 deletions(-) create mode 100644 api/src/com/cloud/network/lb/CertService.java create mode 100644 api/src/com/cloud/network/lb/SslCert.java create mode 100644 api/src/org/apache/cloudstack/api/command/user/loadbalancer/AssignCertToLoadBalancerCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/user/loadbalancer/DeleteSslCertCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/user/loadbalancer/ListSslCertsCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/user/loadbalancer/RemoveCertFromLoadBalancerCmd.java create mode 100644 api/src/org/apache/cloudstack/api/command/user/loadbalancer/UploadSslCertCmd.java create mode 100644 api/src/org/apache/cloudstack/api/response/SslCertResponse.java create mode 100644 engine/schema/src/com/cloud/network/dao/LoadBalancerCertMapDao.java create mode 100644 engine/schema/src/com/cloud/network/dao/LoadBalancerCertMapDaoImpl.java create mode 100644 engine/schema/src/com/cloud/network/dao/LoadBalancerCertMapVO.java create mode 100644 engine/schema/src/com/cloud/network/dao/SslCertDao.java create mode 100644 engine/schema/src/com/cloud/network/dao/SslCertDaoImpl.java create mode 100644 engine/schema/src/com/cloud/network/dao/SslCertVO.java create mode 100644 server/src/org/apache/cloudstack/network/lb/CertServiceImpl.java rename server/test/org/apache/cloudstack/{ => network}/lb/ApplicationLoadBalancerTest.java (99%) create mode 100644 server/test/org/apache/cloudstack/network/lb/CertServiceTest.java create mode 100644 server/test/resources/certs/bad_format_cert.crt create mode 100644 server/test/resources/certs/dsa_self_signed.crt create mode 100644 server/test/resources/certs/dsa_self_signed.key create mode 100644 server/test/resources/certs/expired_cert.crt create mode 100644 server/test/resources/certs/non_x509_pem.crt create mode 100644 server/test/resources/certs/root_chain.crt create mode 100644 server/test/resources/certs/rsa_ca_signed.crt create mode 100644 server/test/resources/certs/rsa_ca_signed.key create mode 100644 server/test/resources/certs/rsa_ca_signed2.crt create mode 100644 server/test/resources/certs/rsa_ca_signed2.key create mode 100644 server/test/resources/certs/rsa_random_pkey.key create mode 100644 server/test/resources/certs/rsa_self_signed.crt create mode 100644 server/test/resources/certs/rsa_self_signed.key create mode 100644 server/test/resources/certs/rsa_self_signed_with_pwd.crt create mode 100644 server/test/resources/certs/rsa_self_signed_with_pwd.key diff --git a/CHANGES b/CHANGES index 054e7b06615..e3e316e9dc9 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,4 @@ + Apache CloudStack CHANGES ====================================== diff --git a/api/src/com/cloud/agent/api/to/LoadBalancerTO.java b/api/src/com/cloud/agent/api/to/LoadBalancerTO.java index df2f8a87490..4caa1b2f85c 100644 --- a/api/src/com/cloud/agent/api/to/LoadBalancerTO.java +++ b/api/src/com/cloud/agent/api/to/LoadBalancerTO.java @@ -33,6 +33,7 @@ import com.cloud.network.lb.LoadBalancingRule.LbCondition; import com.cloud.network.lb.LoadBalancingRule.LbDestination; import com.cloud.network.lb.LoadBalancingRule.LbHealthCheckPolicy; import com.cloud.network.lb.LoadBalancingRule.LbStickinessPolicy; +import com.cloud.network.lb.LoadBalancingRule.LbSslCert; import com.cloud.utils.Pair; @@ -41,6 +42,7 @@ public class LoadBalancerTO { String srcIp; int srcPort; String protocol; + String lbProtocol; String algorithm; boolean revoked; boolean alreadyAdded; @@ -48,6 +50,7 @@ public class LoadBalancerTO { DestinationTO[] destinations; private StickinessPolicyTO[] stickinessPolicies; private HealthCheckPolicyTO[] healthCheckPolicies; + private LbSslCert sslCert; /* XXX: Should this be SslCertTO? */ private AutoScaleVmGroupTO autoScaleVmGroupTO; final static int MAX_STICKINESS_POLICIES = 1; final static int MAX_HEALTHCHECK_POLICIES = 1; @@ -66,6 +69,8 @@ public class LoadBalancerTO { this.inline = inline; this.destinations = new DestinationTO[destinations.size()]; this.stickinessPolicies = null; + this.sslCert = null; + this.lbProtocol = null; int i = 0; for (LbDestination destination : destinations) { this.destinations[i++] = new DestinationTO(destination.getIpAddress(), destination.getDestinationPortStart(), destination.isRevoked(), false); @@ -77,12 +82,12 @@ public class LoadBalancerTO { List stickinessPolicies) { this(id, srcIp, srcPort, protocol, algorithm, revoked, alreadyAdded, inline, arg_destinations, - stickinessPolicies, null); + stickinessPolicies, null, null, null); } public LoadBalancerTO(String id, String srcIp, int srcPort, String protocol, String algorithm, boolean revoked, boolean alreadyAdded, boolean inline, List arg_destinations, - List stickinessPolicies, List healthCheckPolicies) { + List stickinessPolicies, List healthCheckPolicies, LbSslCert sslCert, String lbProtocol) { this(id, srcIp, srcPort, protocol, algorithm, revoked, alreadyAdded, inline, arg_destinations); this.stickinessPolicies = null; this.healthCheckPolicies = null; @@ -117,6 +122,9 @@ public class LoadBalancerTO { if (index == 0) this.healthCheckPolicies = null; } + + this.sslCert = sslCert; + this.lbProtocol = lbProtocol; } protected LoadBalancerTO() { @@ -142,6 +150,10 @@ public class LoadBalancerTO { return protocol; } + public String getLbProtocol() { + return lbProtocol; + } + public boolean isRevoked() { return revoked; } @@ -178,6 +190,10 @@ public class LoadBalancerTO { return this.autoScaleVmGroupTO != null; } + public LbSslCert getSslCert(){ + return this.sslCert; + } + public static class StickinessPolicyTO { private String _methodName; private List> _paramsList; @@ -294,6 +310,8 @@ public class LoadBalancerTO { public String getMonitorState() { return monitorState; } + + } public static class CounterTO implements Serializable { private final String name; @@ -558,5 +576,4 @@ public class LoadBalancerTO { autoScaleVmGroupTO = new AutoScaleVmGroupTO(autoScaleVmGroup.getUuid(), autoScaleVmGroup.getMinMembers(), autoScaleVmGroup.getMaxMembers(), autoScaleVmGroup.getMemberPort(), autoScaleVmGroup.getInterval(), autoScalePolicyTOs, autoScaleVmProfileTO, autoScaleVmGroup.getState(), lbAutoScaleVmGroup.getCurrentState()); } - } diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java index d9f80eb2a2c..a3e45fadce2 100755 --- a/api/src/com/cloud/event/EventTypes.java +++ b/api/src/com/cloud/event/EventTypes.java @@ -133,6 +133,10 @@ public class EventTypes { public static final String EVENT_LB_HEALTHCHECKPOLICY_CREATE = "LB.HEALTHCHECKPOLICY.CREATE"; public static final String EVENT_LB_HEALTHCHECKPOLICY_DELETE = "LB.HEALTHCHECKPOLICY.DELETE"; public static final String EVENT_LOAD_BALANCER_UPDATE = "LB.UPDATE"; + public static final String EVENT_LB_CERT_UPLOAD = "LB.CERT.UPLOAD"; + public static final String EVENT_LB_CERT_DELETE = "LB.CERT.DELETE"; + public static final String EVENT_LB_CERT_ASSIGN = "LB.CERT.ASSIGN"; + public static final String EVENT_LB_CERT_REMOVE = "LB.CERT.REMOVE"; // Global Load Balancer rules public static final String EVENT_ASSIGN_TO_GLOBAL_LOAD_BALANCER_RULE = "GLOBAL.LB.ASSIGN"; @@ -511,6 +515,10 @@ public class EventTypes { entityEventDetails.put(EVENT_LB_STICKINESSPOLICY_CREATE, LoadBalancer.class.getName()); entityEventDetails.put(EVENT_LB_STICKINESSPOLICY_DELETE, LoadBalancer.class.getName()); entityEventDetails.put(EVENT_LOAD_BALANCER_UPDATE, LoadBalancer.class.getName()); + entityEventDetails.put(EVENT_LB_CERT_UPLOAD, LoadBalancer.class.getName()); + entityEventDetails.put(EVENT_LB_CERT_DELETE, LoadBalancer.class.getName()); + entityEventDetails.put(EVENT_LB_CERT_ASSIGN, LoadBalancer.class.getName()); + entityEventDetails.put(EVENT_LB_CERT_REMOVE, LoadBalancer.class.getName()); // Account events entityEventDetails.put(EVENT_ACCOUNT_DISABLE, Account.class.getName()); diff --git a/api/src/com/cloud/network/Network.java b/api/src/com/cloud/network/Network.java index 318ac192252..4eadd61aa25 100644 --- a/api/src/com/cloud/network/Network.java +++ b/api/src/com/cloud/network/Network.java @@ -181,6 +181,7 @@ public interface Network extends ControlledEntity, StateObject, I public static final Capability SupportedTrafficDirection = new Capability("SupportedTrafficDirection"); public static final Capability SupportedEgressProtocols = new Capability("SupportedEgressProtocols"); public static final Capability HealthCheckPolicy = new Capability("HealthCheckPolicy"); + public static final Capability SslTermination = new Capability("SslTermination"); public static final Capability LbSchemes = new Capability("LbSchemes"); public static final Capability DhcpAccrossMultipleSubnets = new Capability("DhcpAccrossMultipleSubnets"); diff --git a/api/src/com/cloud/network/lb/CertService.java b/api/src/com/cloud/network/lb/CertService.java new file mode 100644 index 00000000000..69d77d6ff4d --- /dev/null +++ b/api/src/com/cloud/network/lb/CertService.java @@ -0,0 +1,32 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.lb; + + +import org.apache.cloudstack.api.command.user.loadbalancer.DeleteSslCertCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.ListSslCertsCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.UploadSslCertCmd; +import org.apache.cloudstack.api.response.SslCertResponse; + +import java.util.List; + +public interface CertService { + + public SslCertResponse uploadSslCert(UploadSslCertCmd certCmd); + public void deleteSslCert(DeleteSslCertCmd deleteSslCertCmd); + public List listSslCerts(ListSslCertsCmd listSslCertCmd); +} \ No newline at end of file diff --git a/api/src/com/cloud/network/lb/LoadBalancingRule.java b/api/src/com/cloud/network/lb/LoadBalancingRule.java index 4b37782a8c7..39c969c7001 100644 --- a/api/src/com/cloud/network/lb/LoadBalancingRule.java +++ b/api/src/com/cloud/network/lb/LoadBalancingRule.java @@ -36,9 +36,11 @@ public class LoadBalancingRule { private List stickinessPolicies; private LbAutoScaleVmGroup autoScaleVmGroup; private List healthCheckPolicies; + private LbSslCert sslCert; + private String lbProtocol; public LoadBalancingRule(LoadBalancer lb, List destinations, - List stickinessPolicies, List healthCheckPolicies, Ip sourceIp) { + List stickinessPolicies, List healthCheckPolicies, Ip sourceIp) { this.lb = lb; this.destinations = destinations; this.stickinessPolicies = stickinessPolicies; @@ -46,6 +48,17 @@ public class LoadBalancingRule { this.sourceIp = sourceIp; } + public LoadBalancingRule(LoadBalancer lb, List destinations, + List stickinessPolicies, List healthCheckPolicies, Ip sourceIp, LbSslCert sslCert, String lbProtocol) { + this.lb = lb; + this.destinations = destinations; + this.stickinessPolicies = stickinessPolicies; + this.healthCheckPolicies = healthCheckPolicies; + this.sourceIp = sourceIp; + this.sslCert = sslCert; + this.lbProtocol = lbProtocol; + } + public long getId() { return lb.getId(); } @@ -90,6 +103,10 @@ public class LoadBalancingRule { return lb.getProtocol(); } + public String getLbProtocol() { + return this.lbProtocol; + } + public FirewallRule.Purpose getPurpose() { return FirewallRule.Purpose.LoadBalancing; } @@ -123,6 +140,10 @@ public class LoadBalancingRule { return healthCheckPolicies; } + public LbSslCert getLbSslCert(){ + return sslCert; + } + public interface Destination { String getIpAddress(); @@ -415,6 +436,44 @@ public class LoadBalancingRule { } } + public static class LbSslCert { + private String cert; + private String key; + private String password=null; + private String chain=null; + private boolean revoked; + + + public LbSslCert(String cert, String key, String password, String chain, boolean revoked) { + this.cert = cert; + this.key = key; + this.password = password; + this.chain = chain; + this.revoked = revoked; + } + + public String getCert() { + + return cert; + } + + public String getKey() { + return key; + } + + public String getPassword() { + return password; + } + + public String getChain() { + return chain; + } + + public boolean isRevoked(){ + return revoked; + } + } + public Ip getSourceIp() { return sourceIp; } diff --git a/api/src/com/cloud/network/lb/LoadBalancingRulesService.java b/api/src/com/cloud/network/lb/LoadBalancingRulesService.java index 59d5c8dec05..298426b27b4 100644 --- a/api/src/com/cloud/network/lb/LoadBalancingRulesService.java +++ b/api/src/com/cloud/network/lb/LoadBalancingRulesService.java @@ -52,7 +52,7 @@ public interface LoadBalancingRulesService { */ LoadBalancer createPublicLoadBalancerRule(String xId, String name, String description, int srcPortStart, int srcPortEnd, int defPortStart, int defPortEnd, Long ipAddrId, String protocol, String algorithm, - long networkId, long lbOwnerId, boolean openFirewall) throws NetworkRuleConflictException, InsufficientAddressCapacityException; + long networkId, long lbOwnerId, boolean openFirewall, String lbProtocol) throws NetworkRuleConflictException, InsufficientAddressCapacityException; LoadBalancer updateLoadBalancerRule(UpdateLoadBalancerRuleCmd cmd); @@ -94,10 +94,16 @@ public interface LoadBalancingRulesService { */ boolean assignToLoadBalancer(long lbRuleId, List vmIds); + boolean assignSSLCertToLoadBalancerRule(Long lbRuleId, String certName, String publicCert, String privateKey); + boolean removeFromLoadBalancer(long lbRuleId, List vmIds); boolean applyLoadBalancerConfig(long lbRuleId) throws ResourceUnavailableException; + boolean assignCertToLoadBalancer(long lbRuleId, Long CertId); + boolean removeCertFromLoadBalancer(long lbRuleId); + + /** * List instances that have either been applied to a load balancer or are eligible to be assigned to a load * balancer. diff --git a/api/src/com/cloud/network/lb/SslCert.java b/api/src/com/cloud/network/lb/SslCert.java new file mode 100644 index 00000000000..f7a7c4b790e --- /dev/null +++ b/api/src/com/cloud/network/lb/SslCert.java @@ -0,0 +1,16 @@ +package com.cloud.network.lb; + + +import org.apache.cloudstack.acl.ControlledEntity; +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + +public interface SslCert extends InternalIdentity, Identity, ControlledEntity { + + public String getCertificate(); + public String getKey() ; + public String getChain(); + public String getPassword(); + public String getFingerPrint(); + +} diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index a348684f18f..ae6be63dcf9 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -36,6 +36,9 @@ public class ApiConstants { public static final String CATEGORY = "category"; public static final String CAN_REVERT = "canrevert"; public static final String CERTIFICATE = "certificate"; + public static final String CERTIFICATE_CHAIN = "certchain"; + public static final String CERTIFICATE_FINGERPRINT = "fingerprint"; + public static final String CERTIFICATE_ID = "certid"; public static final String PRIVATE_KEY = "privatekey"; public static final String DOMAIN_SUFFIX = "domainsuffix"; public static final String DNS_SEARCH_ORDER = "dnssearchorder"; diff --git a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/AssignCertToLoadBalancerCmd.java b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/AssignCertToLoadBalancerCmd.java new file mode 100644 index 00000000000..253c015469e --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/AssignCertToLoadBalancerCmd.java @@ -0,0 +1,92 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.user.loadbalancer; + +import com.cloud.event.EventTypes; +import com.cloud.exception.*; +import com.cloud.network.rules.LoadBalancer; +import com.cloud.user.Account; +import org.apache.cloudstack.api.*; +import org.apache.cloudstack.api.response.FirewallRuleResponse; +import org.apache.cloudstack.api.response.SslCertResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.log4j.Logger; + +@APICommand(name = "assignCertToLoadBalancer", description = "Assigns a certificate to a Load Balancer Rule", responseObject = SuccessResponse.class) +public class AssignCertToLoadBalancerCmd extends BaseAsyncCmd { + + public static final Logger s_logger = Logger + .getLogger(AssignCertToLoadBalancerCmd.class.getName()); + + private static final String s_name = "assignCertToLoadBalancer"; + + + @Parameter(name = ApiConstants.LBID, type = CommandType.UUID, entityType = FirewallRuleResponse.class, + required = true, description = "the ID of the load balancer rule") + Long lbRuleId; + + @Parameter(name = ApiConstants.CERTIFICATE_ID, type = CommandType.UUID, entityType = SslCertResponse.class, + required = true, description = "the ID of the certificate") + Long certId; + + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + //To change body of implemented methods use File | Settings | File Templates. + if ( _lbService.assignCertToLoadBalancer( getLbRuleId(), getCertId()) ) { + SuccessResponse response = new SuccessResponse(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to assign certificate to loadbalancer"); + } + } + + @Override + public String getEventType() { + return EventTypes.EVENT_LB_CERT_ASSIGN; + } + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public String getEventDescription() { + return "Assigining a certificate to a loadbalancer"; + } + + + @Override + public long getEntityOwnerId() { + LoadBalancer lb = _entityMgr.findById(LoadBalancer.class, getLbRuleId()); + if (lb == null) { + return Account.ACCOUNT_ID_SYSTEM; // bad id given, parent this command to SYSTEM so ERROR events are tracked + } + return lb.getAccountId(); + } + + + + public Long getCertId(){ + return certId; + } + + public Long getLbRuleId(){ + return lbRuleId; + } +} diff --git a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerRuleCmd.java b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerRuleCmd.java index a36843634cc..e4cc0e613db 100644 --- a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerRuleCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/CreateLoadBalancerRuleCmd.java @@ -102,6 +102,9 @@ public class CreateLoadBalancerRuleCmd extends BaseAsyncCreateCmd /*implements "rule will be created for. Required when public Ip address is not associated with any Guest network yet (VPC case)") private Long networkId; + @Parameter(name=ApiConstants.PROTOCOL, type=CommandType.STRING, description="The protocol for the LB") + private String lbProtocol; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -227,6 +230,10 @@ public class CreateLoadBalancerRuleCmd extends BaseAsyncCreateCmd /*implements return null; } + public String getLbProtocol(){ + return lbProtocol; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -282,7 +289,7 @@ public class CreateLoadBalancerRuleCmd extends BaseAsyncCreateCmd /*implements try { LoadBalancer result = _lbService.createPublicLoadBalancerRule(getXid(), getName(), getDescription(), getSourcePortStart(), getSourcePortEnd(), getDefaultPortStart(), getDefaultPortEnd(), getSourceIpAddressId(), getProtocol(), getAlgorithm(), - getNetworkId(), getEntityOwnerId(), getOpenFirewall()); + getNetworkId(), getEntityOwnerId(), getOpenFirewall(), getLbProtocol()); this.setEntityId(result.getId()); this.setEntityUuid(result.getUuid()); } catch (NetworkRuleConflictException e) { diff --git a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/DeleteSslCertCmd.java b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/DeleteSslCertCmd.java new file mode 100644 index 00000000000..19e36d2b7b6 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/DeleteSslCertCmd.java @@ -0,0 +1,83 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.user.loadbalancer; + + +import com.cloud.network.lb.CertService; +import org.apache.cloudstack.api.response.SslCertResponse; +import com.cloud.exception.*; +import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.cloudstack.api.*; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.log4j.Logger; + +import javax.inject.Inject; + +@APICommand(name = "deleteSslCert", description="Delete a certificate to cloudstack", responseObject=SuccessResponse.class) +public class DeleteSslCertCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(DeleteSslCertCmd.class.getName()); + + private static final String s_name = "deletesslcertresponse"; + + @Inject + CertService _certService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name= ApiConstants.ID, type=CommandType.UUID, entityType = SslCertResponse.class, required=true, description="Id of SSL certificate") + private Long id; + + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + try { + _certService.deleteSslCert(this); + SuccessResponse rsp = new SuccessResponse(); + rsp.setResponseName(getCommandName()); + rsp.setObjectName("success"); + this.setResponseObject(rsp); + } catch (Exception e) { + throw new CloudRuntimeException(e); + } + } + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + return CallContext.current().getCallingAccount().getId(); + } + +} \ No newline at end of file diff --git a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/ListSslCertsCmd.java b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/ListSslCertsCmd.java new file mode 100644 index 00000000000..3df28a39b80 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/ListSslCertsCmd.java @@ -0,0 +1,106 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.user.loadbalancer; + + +import org.apache.cloudstack.api.response.FirewallRuleResponse; +import org.apache.cloudstack.api.response.SslCertResponse; +import com.cloud.network.lb.CertService; +import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.AccountResponse; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.log4j.Logger; + +import javax.inject.Inject; +import java.util.List; + +@APICommand(name = "listSslCerts", description="Lists SSL certificates", responseObject=SslCertResponse.class) +public class ListSslCertsCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(DeleteSslCertCmd.class.getName()); + + private static final String s_name = "listsslcertsresponse"; + + @Inject + CertService _certService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name= ApiConstants.CERTIFICATE_ID, type=CommandType.UUID, entityType = SslCertResponse.class, required=false, description="Id of SSL certificate") + private Long certId; + + @Parameter(name= ApiConstants.ACCOUNT_ID, type=CommandType.UUID, entityType = AccountResponse.class, required=false, description="Account Id") + private Long accountId; + + @Parameter(name= ApiConstants.LBID, type=CommandType.UUID, entityType = FirewallRuleResponse.class, required=false, description="Loadbalancer Rule Id") + private Long lbId; + + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getCertId() { + return certId; + } + + public Long getAccountId() { + return accountId; + } + + public Long getLbId(){ + return lbId; + } + + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public void execute(){ + + + try { + List certResponseList = _certService.listSslCerts(this); + ListResponse response = new ListResponse(); + + response.setResponses(certResponseList); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + + } catch (Exception e) { + throw new CloudRuntimeException(e); + } + } + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + return CallContext.current().getCallingAccount().getId(); + } +} \ No newline at end of file diff --git a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/RemoveCertFromLoadBalancerCmd.java b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/RemoveCertFromLoadBalancerCmd.java new file mode 100644 index 00000000000..059d16320f6 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/RemoveCertFromLoadBalancerCmd.java @@ -0,0 +1,82 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.user.loadbalancer; + + +import com.cloud.event.EventTypes; +import com.cloud.exception.*; +import com.cloud.network.rules.LoadBalancer; +import com.cloud.user.Account; +import org.apache.cloudstack.api.*; +import org.apache.cloudstack.api.response.FirewallRuleResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.log4j.Logger; + + +@APICommand(name = "removeCertFromLoadBalancer", description = "Removes a certificate from a Load Balancer Rule", responseObject = SuccessResponse.class) +public class RemoveCertFromLoadBalancerCmd extends BaseAsyncCmd{ + + public static final Logger s_logger = Logger.getLogger(RemoveCertFromLoadBalancerCmd.class.getName()); + + private static final String s_name = "removeCertFromLoadBalancer"; + + + @Parameter(name = ApiConstants.LBID, type = CommandType.UUID, entityType = FirewallRuleResponse.class, + required = true, description = "the ID of the load balancer rule") + Long lbRuleId; + + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + boolean result = _lbService.removeCertFromLoadBalancer(getLbRuleId()); + if (result) { + SuccessResponse response = new SuccessResponse(getCommandName()); + this.setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to remove certificate from load balancer rule"); + } + } + + @Override + public String getEventType() { + return EventTypes.EVENT_LB_CERT_REMOVE; + } + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public String getEventDescription() { + return "Removing a certificate from a loadbalancer with ID " + getLbRuleId(); + } + + + @Override + public long getEntityOwnerId() { + LoadBalancer lb = _entityMgr.findById(LoadBalancer.class, getLbRuleId()); + if (lb == null) { + return Account.ACCOUNT_ID_SYSTEM; // bad id given, parent this command to SYSTEM so ERROR events are tracked + } + return lb.getAccountId(); + } + + public Long getLbRuleId(){ + return this.lbRuleId; + } +} diff --git a/api/src/org/apache/cloudstack/api/command/user/loadbalancer/UploadSslCertCmd.java b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/UploadSslCertCmd.java new file mode 100644 index 00000000000..897d66b73c1 --- /dev/null +++ b/api/src/org/apache/cloudstack/api/command/user/loadbalancer/UploadSslCertCmd.java @@ -0,0 +1,103 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.user.loadbalancer; + + +import org.apache.cloudstack.api.response.SslCertResponse; +import com.cloud.exception.*; +import com.cloud.network.lb.CertService; +import org.apache.cloudstack.api.*; +import org.apache.cloudstack.context.CallContext; +import org.apache.log4j.Logger; + +import javax.inject.Inject; + +@APICommand(name = "uploadSslCert", description="Upload a certificate to cloudstack", responseObject=SslCertResponse.class) +public class UploadSslCertCmd extends BaseCmd { + public static final Logger s_logger = Logger.getLogger(UploadSslCertCmd.class.getName()); + + private static final String s_name = "uploadsslcertresponse"; + + @Inject CertService _certService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name= ApiConstants.CERTIFICATE, type=CommandType.STRING, required=true, description="SSL certificate",length=16384) + private String cert; + + @Parameter(name=ApiConstants.PRIVATE_KEY, type=CommandType.STRING, required=true, description="Private key", length=16384) + private String key; + + @Parameter(name=ApiConstants.CERTIFICATE_CHAIN, type=CommandType.STRING, description="Certificate chain of trust", length=2097152) + private String chain; + + @Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, description="Password for the private key") + private String password; + + + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public String getCert() { + return cert; + } + + public String getKey() { + return key; + } + + public String getChain() { + return chain; + } + + public String getPassword() { + return password; + } + + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + + try{ + SslCertResponse response = _certService.uploadSslCert(this); + setResponseObject(response); + response.setResponseName(getCommandName()); + } catch (Exception e){ + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage()); + } + + } + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + return CallContext.current().getCallingAccount().getId(); + } + +} \ No newline at end of file diff --git a/api/src/org/apache/cloudstack/api/response/SslCertResponse.java b/api/src/org/apache/cloudstack/api/response/SslCertResponse.java new file mode 100644 index 00000000000..3e8b7ae559d --- /dev/null +++ b/api/src/org/apache/cloudstack/api/response/SslCertResponse.java @@ -0,0 +1,90 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.response; + +import com.cloud.network.lb.SslCert; +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; + +import java.util.List; +//import org.apache.cloudstack.api.EntityReference; + +@EntityReference(value= SslCert.class) +public class SslCertResponse extends BaseResponse { + + @SerializedName(ApiConstants.ID) + @Param(description = "SSL certificate ID") + private String id; + + @SerializedName(ApiConstants.CERTIFICATE) + @Param(description = "certificate") + private String certificate; + + @SerializedName(ApiConstants.PRIVATE_KEY) + @Param(description = "private key") + private String privatekey; + + @SerializedName(ApiConstants.ACCOUNT) + @Param(description = "account for the certificate") + private String accountName; + + @SerializedName(ApiConstants.CERTIFICATE_CHAIN) + @Param(description = "certificate chain") + private String certchain; + + @SerializedName(ApiConstants.CERTIFICATE_FINGERPRINT) + @Param(description = "certificate fingerprint") + private String fingerprint; + + @SerializedName(ApiConstants.LOAD_BALANCER_RULE_LIST) + @Param(description = "List of loabalancers this certificate is bound to") + List lbIds; + + public SslCertResponse() { + } + + public void setId(String id) { + this.id = id; + } + + public void setCertificate(String cert) { + this.certificate = cert; + } + + public void setPrivatekey(String key) { + this.privatekey = key; + } + + public void setAccountName(String accountName) { + this.accountName = accountName; + } + + public void setCertchain(String chain) { + this.certchain = chain; + } + + public void setFingerprint(String fingerprint){ + this.fingerprint = fingerprint; + } + + public void setLbIds(List lbIds){ + this.lbIds = lbIds; + } +} diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in index 68d7303d0a7..cb9dcf0b071 100644 --- a/client/tomcatconf/commands.properties.in +++ b/client/tomcatconf/commands.properties.in @@ -165,6 +165,14 @@ deleteLBHealthCheckPolicy=15 listLoadBalancerRuleInstances=15 updateLoadBalancerRule=15 +##### SSL offload commands + +uploadSslCert=15 +deleteSslCert=15 +listSslCerts=15 +assignCertToLoadBalancer=15 +removeCertFromLoadBalancer=15 + #### autoscale commands createCounter=1 createCondition=15 diff --git a/core/src/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java b/core/src/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java index 3a51e8ad6be..a6a46d55665 100644 --- a/core/src/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java +++ b/core/src/com/cloud/agent/api/routing/LoadBalancerConfigCommand.java @@ -33,6 +33,7 @@ public class LoadBalancerConfigCommand extends NetworkElementCommand { public String lbStatsAuth = "admin1:AdMiN123"; public String lbStatsUri = "/admin?stats"; public String maxconn =""; + public String lbProtocol; public boolean keepAliveEnabled = false; NicTO nic; Long vpcId; diff --git a/engine/components-api/src/com/cloud/network/lb/LoadBalancingRulesManager.java b/engine/components-api/src/com/cloud/network/lb/LoadBalancingRulesManager.java index 3e325859a9a..22830d5a06a 100644 --- a/engine/components-api/src/com/cloud/network/lb/LoadBalancingRulesManager.java +++ b/engine/components-api/src/com/cloud/network/lb/LoadBalancingRulesManager.java @@ -25,6 +25,7 @@ import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.lb.LoadBalancingRule.LbDestination; import com.cloud.network.lb.LoadBalancingRule.LbHealthCheckPolicy; import com.cloud.network.lb.LoadBalancingRule.LbStickinessPolicy; +import com.cloud.network.lb.LoadBalancingRule.LbSslCert; import com.cloud.network.rules.LbStickinessMethod; import com.cloud.network.rules.LoadBalancer; import com.cloud.network.rules.LoadBalancerContainer.Scheme; @@ -33,7 +34,8 @@ import com.cloud.user.Account; public interface LoadBalancingRulesManager { LoadBalancer createPublicLoadBalancer(String xId, String name, String description, - int srcPort, int destPort, long sourceIpId, String protocol, String algorithm, boolean openFirewall, CallContext caller) + int srcPort, int destPort, long sourceIpId, String protocol, String algorithm, + boolean openFirewall, CallContext caller, String lbProtocol) throws NetworkRuleConflictException; boolean removeAllLoadBalanacersForIp(long ipId, Account caller, long callerUserId); @@ -42,6 +44,7 @@ public interface LoadBalancingRulesManager { List getStickinessPolicies(long lbId); List getStickinessMethods(long networkid); List getHealthCheckPolicies(long lbId); + LbSslCert getLbSslCert(long lbId); /** * Remove vm from all load balancers diff --git a/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml b/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml index a64e5c06e7c..c71190b5cf5 100644 --- a/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml +++ b/engine/schema/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml @@ -189,6 +189,7 @@ + @@ -252,6 +253,7 @@ + diff --git a/engine/schema/src/com/cloud/network/dao/LoadBalancerCertMapDao.java b/engine/schema/src/com/cloud/network/dao/LoadBalancerCertMapDao.java new file mode 100644 index 00000000000..21c01d9c15e --- /dev/null +++ b/engine/schema/src/com/cloud/network/dao/LoadBalancerCertMapDao.java @@ -0,0 +1,29 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.dao; + +import com.cloud.network.LBHealthCheckPolicyVO; +import com.cloud.utils.db.GenericDao; + +import java.util.List; + + +public interface LoadBalancerCertMapDao extends GenericDao { + List listByCertId(Long certId); + List listByAccountId(Long accountId); + LoadBalancerCertMapVO findByLbRuleId(Long id); +} diff --git a/engine/schema/src/com/cloud/network/dao/LoadBalancerCertMapDaoImpl.java b/engine/schema/src/com/cloud/network/dao/LoadBalancerCertMapDaoImpl.java new file mode 100644 index 00000000000..57506f9a6f0 --- /dev/null +++ b/engine/schema/src/com/cloud/network/dao/LoadBalancerCertMapDaoImpl.java @@ -0,0 +1,79 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.dao; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.JoinBuilder; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; + +import javax.ejb.Local; +import javax.inject.Inject; +import java.util.List; + +@Local(value = {LoadBalancerCertMapDao.class}) +public class LoadBalancerCertMapDaoImpl extends GenericDaoBase implements LoadBalancerCertMapDao { + + private final SearchBuilder listByCertId; + private final SearchBuilder findByLbRuleId; + + + @Inject SslCertDao _sslCertDao; + + public LoadBalancerCertMapDaoImpl() { + + listByCertId = createSearchBuilder(); + listByCertId.and("certificateId", listByCertId.entity().getCertId(), SearchCriteria.Op.EQ); + listByCertId.done(); + + findByLbRuleId = createSearchBuilder(); + findByLbRuleId.and("loadBalancerId", findByLbRuleId.entity().getLbId(), SearchCriteria.Op.EQ); + findByLbRuleId.done(); + + } + + @Override + public List listByCertId(Long certId) { + SearchCriteria sc = listByCertId.create(); + sc.setParameters("certificateId", certId); + return listBy(sc); + } + + @Override + public LoadBalancerCertMapVO findByLbRuleId(Long LbId) { + SearchCriteria sc = findByLbRuleId.create(); + sc.setParameters("loadBalancerId", LbId); + return findOneBy(sc); + } + + @Override + public List listByAccountId(Long accountId) { + + SearchBuilder listByAccountId; + SearchBuilder certsForAccount; + + listByAccountId = createSearchBuilder(); + certsForAccount = _sslCertDao.createSearchBuilder(); + certsForAccount.and("accountId", certsForAccount.entity().getAccountId(), SearchCriteria.Op.EQ); + listByAccountId.join("certsForAccount", certsForAccount, certsForAccount.entity().getId(), listByAccountId.entity().getLbId(), JoinBuilder.JoinType.INNER); + certsForAccount.done(); + listByAccountId.done(); + + SearchCriteria sc = listByAccountId.create(); + sc.setParameters("accountId", accountId); + return listBy(sc); + } +} diff --git a/engine/schema/src/com/cloud/network/dao/LoadBalancerCertMapVO.java b/engine/schema/src/com/cloud/network/dao/LoadBalancerCertMapVO.java new file mode 100644 index 00000000000..535964757ec --- /dev/null +++ b/engine/schema/src/com/cloud/network/dao/LoadBalancerCertMapVO.java @@ -0,0 +1,96 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.dao; + + +import org.apache.cloudstack.api.InternalIdentity; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import java.util.UUID; + + +@Entity +@Table(name="load_balancer_cert_map") +public class LoadBalancerCertMapVO implements InternalIdentity { + + @Id + @Column(name="id") + private Long id; + + @Column(name="uuid") + private String uuid; + + @Column(name="load_balancer_id") + private Long lbId; + + @Column(name="certificate_id") + private Long certId; + + @Column(name="revoke") + private boolean revoke = false; + + + public LoadBalancerCertMapVO() { + this.uuid = UUID.randomUUID().toString(); + } + + public LoadBalancerCertMapVO(Long lbId, Long certId, boolean revoke) { + + this.lbId = lbId; + this.certId = certId; + this.revoke = revoke; + this.uuid = UUID.randomUUID().toString(); + } + + // Getters + @Override + public long getId() { + return id; + } + + public String getUuid() { + return uuid; + } + + public Long getLbId() { + return lbId; + } + + public Long getCertId() { + return certId; + } + + public boolean isRevoke() { + return revoke; + } + + //Setters + public void setLbId(Long lbId) { + this.lbId = lbId; + } + + public void setCertId(Long certId) { + this.certId = certId; + } + + public void setRevoke(boolean revoke) { + this.revoke = revoke; + } +} diff --git a/engine/schema/src/com/cloud/network/dao/LoadBalancerVO.java b/engine/schema/src/com/cloud/network/dao/LoadBalancerVO.java index fee88cf7b0a..625eb6f651a 100644 --- a/engine/schema/src/com/cloud/network/dao/LoadBalancerVO.java +++ b/engine/schema/src/com/cloud/network/dao/LoadBalancerVO.java @@ -59,10 +59,15 @@ public class LoadBalancerVO extends FirewallRuleVO implements LoadBalancer { @Column(name="scheme") Scheme scheme = Scheme.Public; + @Column(name="lb_protocol") + String lbProtocol; + + public LoadBalancerVO() { } - public LoadBalancerVO(String xId, String name, String description, long srcIpId, int srcPort, int dstPort, String algorithm, long networkId, long accountId, long domainId) { + public LoadBalancerVO(String xId, String name, String description, long srcIpId, int srcPort, int dstPort, String algorithm, long networkId, + long accountId, long domainId, String lbProtocol) { super(xId, srcIpId, srcPort, NetUtils.TCP_PROTO, networkId, accountId, domainId, Purpose.LoadBalancing, null, null, null, null); this.name = name; this.description = description; @@ -70,6 +75,7 @@ public class LoadBalancerVO extends FirewallRuleVO implements LoadBalancer { this.defaultPortStart = dstPort; this.defaultPortEnd = dstPort; this.scheme = Scheme.Public; + this.lbProtocol = lbProtocol; } @Override @@ -101,6 +107,14 @@ public class LoadBalancerVO extends FirewallRuleVO implements LoadBalancer { this.name = name; } + public String getLbProtocol(){ + return lbProtocol; + } + + public void setLbProtocol(String lbProtocol){ + this.lbProtocol = lbProtocol; + } + public void setAlgorithm(String algorithm) { this.algorithm = algorithm; } diff --git a/engine/schema/src/com/cloud/network/dao/SslCertDao.java b/engine/schema/src/com/cloud/network/dao/SslCertDao.java new file mode 100644 index 00000000000..37520bbcb90 --- /dev/null +++ b/engine/schema/src/com/cloud/network/dao/SslCertDao.java @@ -0,0 +1,27 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.dao; + + +import com.cloud.utils.db.GenericDao; + +import java.util.List; + + +public interface SslCertDao extends GenericDao { + List listByAccountId(Long id); +} \ No newline at end of file diff --git a/engine/schema/src/com/cloud/network/dao/SslCertDaoImpl.java b/engine/schema/src/com/cloud/network/dao/SslCertDaoImpl.java new file mode 100644 index 00000000000..483c28d295b --- /dev/null +++ b/engine/schema/src/com/cloud/network/dao/SslCertDaoImpl.java @@ -0,0 +1,31 @@ +package com.cloud.network.dao; + +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; + +import javax.ejb.Local; +import java.util.List; + + + +@Local(value = {SslCertDao.class}) +public class SslCertDaoImpl extends GenericDaoBase implements SslCertDao { + + private final SearchBuilder listByAccountId; + + public SslCertDaoImpl() { + listByAccountId = createSearchBuilder(); + listByAccountId.and("accountId", listByAccountId.entity().getAccountId(), SearchCriteria.Op.EQ); + listByAccountId.done(); + } + + @Override + public List listByAccountId(Long accountId) { + SearchCriteria sc = listByAccountId.create(); + sc.setParameters("accountId", accountId); + return listBy(sc); + } + + +} diff --git a/engine/schema/src/com/cloud/network/dao/SslCertVO.java b/engine/schema/src/com/cloud/network/dao/SslCertVO.java new file mode 100644 index 00000000000..c26c2aa2740 --- /dev/null +++ b/engine/schema/src/com/cloud/network/dao/SslCertVO.java @@ -0,0 +1,132 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.network.dao; + + +import com.cloud.network.lb.SslCert; +import com.cloud.utils.db.Encrypt; +import org.apache.cloudstack.acl.ControlledEntity; +import org.apache.cloudstack.api.InternalIdentity; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import java.util.UUID; + +@Entity +@Table(name="sslcerts") +public class SslCertVO implements SslCert { + + @Id + @Column(name="id") + private Long id; + + @Column(name="uuid") + private String uuid; + + @Column(name="certificate",length=16384) + private String certificate; + + + @Column(name="chain",length=2097152) + private String chain; + + @Encrypt + @Column(name="key",length=16384) + private String key; + + @Encrypt + @Column(name="password") + private String password; + + @Column(name="account_id") + private Long accountId; + + @Column(name = "domain_id") + long domainId; + + @Column(name = "fingerprint") + String fingerPrint; + + + + + public SslCertVO() { + this.uuid = UUID.randomUUID().toString(); + } + + public SslCertVO(String cert, String key, String password, String chain, Long accountId, Long domainId, String fingerPrint) { + this.certificate = cert; + this.key = key; + this.chain = chain; + this.password = password; + this.accountId = accountId; + this.domainId = domainId; + this.fingerPrint = fingerPrint; + this.uuid = UUID.randomUUID().toString(); + } + + + // Getters + @Override + public long getId() { + return id; + } + + @Override + public String getUuid() { + return uuid; + } + + @Override + public String getCertificate() { + return certificate; + } + + + @Override + public String getKey() { + return key; + } + + + @Override + public String getChain() { + return chain; + } + + @Override + public long getAccountId() { + return accountId; + } + + @Override + public String getPassword() { + return password; + } + + @Override + public long getDomainId() { + return domainId; + } + + @Override + public String getFingerPrint() { + return fingerPrint; + } +} \ No newline at end of file diff --git a/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java b/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java index 5c6f2e7dd63..e049cece058 100644 --- a/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java +++ b/plugins/network-elements/elastic-loadbalancer/src/com/cloud/network/lb/ElasticLoadBalancerManagerImpl.java @@ -98,6 +98,7 @@ import com.cloud.network.dao.VirtualRouterProviderDao; import com.cloud.network.lb.LoadBalancingRule.LbDestination; import com.cloud.network.lb.LoadBalancingRule.LbHealthCheckPolicy; import com.cloud.network.lb.LoadBalancingRule.LbStickinessPolicy; +import com.cloud.network.lb.LoadBalancingRule.LbSslCert; import com.cloud.network.lb.dao.ElasticLbVmMapDao; import com.cloud.network.router.VirtualRouter; import com.cloud.network.router.VirtualRouter.RedundantState; @@ -290,6 +291,7 @@ public class ElasticLoadBalancerManagerImpl extends ManagerBase implements Elast private void createApplyLoadBalancingRulesCommands( List rules, DomainRouterVO elbVm, Commands cmds, long guestNetworkId) { + /* XXX: cert */ LoadBalancerTO[] lbs = new LoadBalancerTO[rules.size()]; int i = 0; for (LoadBalancingRule rule : rules) { @@ -302,7 +304,8 @@ public class ElasticLoadBalancerManagerImpl extends ManagerBase implements Elast int srcPort = rule.getSourcePortStart(); String uuid = rule.getUuid(); List destinations = rule.getDestinations(); - LoadBalancerTO lb = new LoadBalancerTO(uuid, elbIp, srcPort, protocol, algorithm, revoked, false, false, destinations); + LoadBalancerTO lb = new LoadBalancerTO(uuid, elbIp, srcPort, protocol, algorithm, revoked, + false, false, destinations); lbs[i++] = lb; } @@ -377,8 +380,9 @@ public class ElasticLoadBalancerManagerImpl extends ManagerBase implements Elast List policyList = _lbMgr.getStickinessPolicies(lb.getId()); List hcPolicyList = _lbMgr.getHealthCheckPolicies(lb.getId()); Ip sourceIp = _networkModel.getPublicIpAddress(lb.getSourceIpAddressId()).getAddress(); + LbSslCert sslCert = _lbMgr.getLbSslCert(lb.getId()); LoadBalancingRule loadBalancing = new LoadBalancingRule( - lb, dstList, policyList, hcPolicyList, sourceIp); + lb, dstList, policyList, hcPolicyList, sourceIp, sslCert, lb.getLbProtocol()); lbRules.add(loadBalancing); } return applyLBRules(elbVm, lbRules, network.getId()); @@ -664,7 +668,7 @@ public class ElasticLoadBalancerManagerImpl extends ManagerBase implements Elast result = _lbMgr.createPublicLoadBalancer(lb.getXid(), lb.getName(), lb.getDescription(), lb.getSourcePortStart(), lb.getDefaultPortStart(), ipId.longValue(), lb.getProtocol(), - lb.getAlgorithm(), false, CallContext.current()); + lb.getAlgorithm(), false, CallContext.current(), lb.getLbProtocol()); } catch (NetworkRuleConflictException e) { s_logger.warn("Failed to create LB rule, not continuing with ELB deployment"); if (newIp) { diff --git a/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManagerImpl.java b/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManagerImpl.java index b6269ebae9d..b9482b5a490 100644 --- a/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManagerImpl.java +++ b/plugins/network-elements/internal-loadbalancer/src/org/apache/cloudstack/network/lb/InternalLoadBalancerVMManagerImpl.java @@ -77,6 +77,7 @@ import com.cloud.network.lb.LoadBalancingRule; import com.cloud.network.lb.LoadBalancingRule.LbDestination; import com.cloud.network.lb.LoadBalancingRule.LbHealthCheckPolicy; import com.cloud.network.lb.LoadBalancingRule.LbStickinessPolicy; +import com.cloud.network.lb.LoadBalancingRule.LbSslCert; import com.cloud.network.lb.LoadBalancingRulesManager; import com.cloud.network.router.VirtualNetworkApplianceManager; import com.cloud.network.router.VirtualRouter; diff --git a/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbvmmgr/InternalLBVMManagerTest.java b/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbvmmgr/InternalLBVMManagerTest.java index 82f90fb9dbf..90d6a183eb2 100644 --- a/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbvmmgr/InternalLBVMManagerTest.java +++ b/plugins/network-elements/internal-loadbalancer/test/org/apache/cloudstack/internallbvmmgr/InternalLBVMManagerTest.java @@ -212,7 +212,7 @@ public class InternalLBVMManagerTest extends TestCase { List vms = new ArrayList(); List rules = new ArrayList(); LoadBalancingRule rule = new LoadBalancingRule(null, null, - null, null, null); + null, null, null, null, null); rules.add(rule); try { @@ -232,7 +232,7 @@ public class InternalLBVMManagerTest extends TestCase { List rules = new ArrayList(); LoadBalancingRule rule = new LoadBalancingRule(null, null, - null, null, null); + null, null, null, null, null); rules.add(rule); try { @@ -252,7 +252,7 @@ public class InternalLBVMManagerTest extends TestCase { List rules = new ArrayList(); LoadBalancingRule rule = new LoadBalancingRule(null, null, - null, null, null); + null, null, null, null, null); rules.add(rule); try { @@ -272,7 +272,7 @@ public class InternalLBVMManagerTest extends TestCase { List rules = new ArrayList(); LoadBalancingRule rule = new LoadBalancingRule(null, null, - null, null, null); + null, null, null, null, null); rules.add(rule); try { diff --git a/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java b/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java index 8101864840b..de3d7e86665 100644 --- a/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java +++ b/plugins/network-elements/netscaler/src/com/cloud/network/element/NetscalerElement.java @@ -161,6 +161,7 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl @Inject ExternalLoadBalancerDeviceDao _externalLoadBalancerDeviceDao; + private boolean canHandle(Network config, Service service) { DataCenter zone = _dcDao.findById(config.getDataCenterId()); boolean handleInAdvanceZone = (zone.getNetworkType() == NetworkType.Advanced && @@ -277,7 +278,7 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl // Supports only Public load balancing lbCapabilities.put(Capability.LbSchemes, LoadBalancerContainer.Scheme.Public.toString()); - + // Specifies that load balancing rules can support autoscaling and the list of counters it supports AutoScaleCounter counter; List counterList = new ArrayList(); @@ -319,6 +320,10 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl staticNatCapabilities.put(Capability.ElasticIp, "true"); capabilities.put(Service.StaticNat, staticNatCapabilities); + // Supports SSL offloading + lbCapabilities.put(Capability.SslTermination, "true"); + + // TODO - Murali, please put correct capabilities here Map firewallCapabilities = new HashMap(); firewallCapabilities.put(Capability.TrafficStatistics, "per public ip"); @@ -516,6 +521,7 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl cmdList.add(DeleteNetscalerLoadBalancerCmd.class); cmdList.add(ListNetscalerLoadBalancerNetworksCmd.class); cmdList.add(ListNetscalerLoadBalancersCmd.class); + return cmdList; } @@ -732,7 +738,8 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl List destinations = rule.getDestinations(); if ((destinations != null && !destinations.isEmpty()) || rule.isAutoScaleConfig()) { - LoadBalancerTO loadBalancer = new LoadBalancerTO(lbUuid, srcIp, srcPort, protocol, algorithm, revoked, false, false, destinations, rule.getStickinessPolicies(), rule.getHealthCheckPolicies()); + LoadBalancerTO loadBalancer = new LoadBalancerTO(lbUuid, srcIp, srcPort, protocol, algorithm, revoked, false, false, destinations, + rule.getStickinessPolicies(), rule.getHealthCheckPolicies(), rule.getLbSslCert(), rule.getLbProtocol()); if (rule.isAutoScaleConfig()) { loadBalancer.setAutoScaleVmGroup(rule.getAutoScaleVmGroup()); } @@ -894,7 +901,7 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl if ((destinations != null && !destinations.isEmpty()) || rule.isAutoScaleConfig()) { LoadBalancerTO loadBalancer = new LoadBalancerTO(lbUuid, srcIp, srcPort, protocol, algorithm, revoked, - false, false, destinations, null, rule.getHealthCheckPolicies()); + false, false, destinations, null, rule.getHealthCheckPolicies(), rule.getLbSslCert(), rule.getLbProtocol()); loadBalancersToApply.add(loadBalancer); } } @@ -1024,5 +1031,4 @@ public class NetscalerElement extends ExternalLoadBalancerDeviceManagerImpl impl } return true; } - } diff --git a/plugins/network-elements/netscaler/src/com/cloud/network/resource/NetscalerResource.java b/plugins/network-elements/netscaler/src/com/cloud/network/resource/NetscalerResource.java index fe072e13718..e48d31d3f0a 100644 --- a/plugins/network-elements/netscaler/src/com/cloud/network/resource/NetscalerResource.java +++ b/plugins/network-elements/netscaler/src/com/cloud/network/resource/NetscalerResource.java @@ -25,6 +25,10 @@ import java.util.Map; import javax.naming.ConfigurationException; +import com.citrix.netscaler.nitro.resource.config.ssl.sslcertkey; +import com.citrix.netscaler.nitro.resource.config.ssl.sslvserver_sslcertkey_binding; +import com.cloud.network.lb.LoadBalancingRule.LbSslCert; +import com.cloud.utils.ssh.SshHelper; import org.apache.log4j.Logger; import com.citrix.netscaler.nitro.exception.nitro_exception; @@ -235,6 +239,7 @@ public class NetscalerResource implements ServerResource { //enable load balancing feature enableLoadBalancingFeature(); + SSL.enableSslFeature(_netscalerService); //if the the device is cloud stack provisioned then make it part of the public network if (_cloudManaged) { @@ -550,6 +555,8 @@ public class NetscalerResource implements ServerResource { String lbAlgorithm = loadBalancer.getAlgorithm(); String nsVirtualServerName = generateNSVirtualServerName(srcIp, srcPort); String nsMonitorName = generateNSMonitorName(srcIp, srcPort); + LbSslCert sslCert = loadBalancer.getSslCert(); + if(loadBalancer.isAutoScaleVmGroupTO()) { applyAutoScaleConfig(loadBalancer); // Continue to process all the rules. @@ -558,6 +565,7 @@ public class NetscalerResource implements ServerResource { boolean hasMonitor = false; boolean deleteMonitor = false; boolean destinationsToAdd = false; + boolean deleteCert = false; for (DestinationTO destination : loadBalancer.getDestinations()) { if (!destination.isRevoked()) { destinationsToAdd = true; @@ -655,9 +663,35 @@ public class NetscalerResource implements ServerResource { } } + + + if(sslCert != null && lbProtocol.equals(NetUtils.SSL_PROTO)) { + if ( sslCert.isRevoked() ){ + deleteCert = true; + } else{ + + String certName = generateSslCertName(srcIp, srcPort); + String keyName = generateSslKeyName(srcIp, srcPort); + String certKeyName = generateSslCertKeyName(srcIp, srcPort); + + if ( SSL.isSslCertKeyPresent(_netscalerService, certKeyName)){ + SSL.deleteSslCertKey(_netscalerService, certKeyName); + } + + + SSL.uploadCert(_ip, _username, _password, certName, sslCert.getCert().getBytes()); + SSL.uploadKey(_ip, _username, _password, keyName, sslCert.getKey().getBytes()); + + SSL.createSslCertKey(_netscalerService, certName, keyName, certKeyName, sslCert.getPassword()); + SSL.bindCertKeyToVserver(_netscalerService, certKeyName, nsVirtualServerName); + } + + } + if (s_logger.isDebugEnabled()) { s_logger.debug("Successfully added LB destination: " + destination.getDestIp() + ":" + destination.getDestPort() + " to load balancer " + srcIp + ":" + srcPort); } + } else { // remove a destination from the deployed load balancing rule com.citrix.netscaler.nitro.resource.config.lb.lbvserver_service_binding[] serviceBindings = com.citrix.netscaler.nitro.resource.config.lb.lbvserver_service_binding.get(_netscalerService, nsVirtualServerName); @@ -731,11 +765,27 @@ public class NetscalerResource implements ServerResource { } removeLBVirtualServer(nsVirtualServerName); deleteMonitor = true; + deleteCert = true; } } if(deleteMonitor) { removeLBMonitor(nsMonitorName); } + if ( sslCert != null && deleteCert){ + + String certName = generateSslCertName(srcIp, srcPort); + String keyName = generateSslKeyName(srcIp, srcPort); + String certKeyName = generateSslCertKeyName(srcIp, srcPort); + + // unbind before deleting + if ( nsVirtualServerExists(nsVirtualServerName) ){ + SSL.unbindCertKeyFromVserver(_netscalerService, certKeyName, nsVirtualServerName); + } + + SSL.deleteSslCertKey(_netscalerService, certKeyName); + SSL.deleteCertFile(_ip, _username, _password, certName); + SSL.deleteKeyFile(_ip, _username, _password, keyName); + } } @@ -1666,6 +1716,173 @@ public class NetscalerResource implements ServerResource { } } + /* SSL Termination */ + private static class SSL { + + private static final String SSL_CERT_PATH = "/nsconfig/ssl/"; + private static final int SSH_PORT = 22; + + private static boolean isSslCertKeyPresent(nitro_service ns, String certKeyName) throws ExecutionException { + + String filter = "certkey:" + certKeyName; + + try { + if (sslcertkey.count_filtered(ns, filter) > 0) return true; + } catch (nitro_exception e){ + throw new ExecutionException("Failed to get certkey " + e.getMessage()); + } catch (Exception e){ + throw new ExecutionException("Failed to get certkey " + e.getMessage()); + } + + return false; + } + + private static void deleteSslCertKey(nitro_service ns, String certKeyName) throws ExecutionException { + try { + + sslcertkey certkey = new sslcertkey(); + certkey.set_certkey(certKeyName); + sslcertkey.delete(ns, certkey); + + } catch (nitro_exception e){ + throw new ExecutionException("Failed to delete certkey " + e.getMessage()); + } catch (Exception e){ + throw new ExecutionException("Failed to delete certkey " + e.getMessage()); + } + + } + + private static void deleteCertFile(String nsIp, String username, String password, String certName) throws Exception { + SshHelper.sshExecute(nsIp,SSH_PORT,username,null,password,"shell rm " + SSL_CERT_PATH + certName); + } + + private static void deleteKeyFile(String nsIp, String username, String password, String keyName) throws Exception { + SshHelper.sshExecute(nsIp,SSH_PORT,username,null,password,"shell rm " + SSL_CERT_PATH + keyName); + } + + private static void createSslCertKey(nitro_service ns, String certName, String keyName, String certKeyName, String password) throws ExecutionException { + s_logger.debug("Adding cert to netscaler"); + try { + sslcertkey certkey = new sslcertkey(); + certkey.set_certkey(certKeyName); + certkey.set_cert(SSL_CERT_PATH + certName); + certkey.set_key(SSL_CERT_PATH + keyName); + + if( password != null ) { + certkey.set_passplain(password); + } + + certkey.perform_operation(ns); + + } catch (nitro_exception e){ + throw new ExecutionException("Failed to add certkey binding " + e.getMessage()); + } catch (Exception e){ + throw new ExecutionException("Failed to add certkey binding " + e.getMessage()); + } + + } + + public static void updateCertKey(nitro_service ns, String certKeyName, String cert, String key, String password) throws ExecutionException { + try{ + sslcertkey certkey = sslcertkey.get(ns, certKeyName); + if ( cert != null ) + certkey.set_cert(cert); + if ( key != null ) + certkey.set_key(cert); + if ( password != null ) + certkey.set_passplain(cert); + + sslcertkey.change(ns,certkey); + + } catch (nitro_exception e){ + throw new ExecutionException("Failed to update ssl on load balancer due to " + e.getMessage()); + } catch (Exception e){ + throw new ExecutionException("Failed to update ssl on load balancer due to " + e.getMessage()); + } + } + + private static void bindCertKeyToVserver(nitro_service ns, String certKeyName, String vserver) throws ExecutionException { + s_logger.debug("Adding cert to netscaler"); + + try { + sslvserver_sslcertkey_binding cert_binding = new sslvserver_sslcertkey_binding(); + cert_binding.set_certkeyname(certKeyName); + cert_binding.set_vservername(vserver); + cert_binding.perform_operation(ns); + } catch (nitro_exception e){ + throw new ExecutionException("Failed to bind certkey to vserver due to " + e.getMessage()); + } catch (Exception e){ + throw new ExecutionException("Failed to bind certkey to vserver due to " + e.getMessage()); + } + } + + private static void unbindCertKeyFromVserver(nitro_service ns, String certKeyName, String vserver) throws ExecutionException { + try { + + sslvserver_sslcertkey_binding cert_binding = new sslvserver_sslcertkey_binding(); + cert_binding.set_certkeyname(certKeyName); + cert_binding.set_vservername(vserver); + sslvserver_sslcertkey_binding.delete(ns,cert_binding); + + } catch (nitro_exception e){ + throw new ExecutionException("Failed to unbind certkey to vserver due to " + e.getMessage()); + } catch (Exception e){ + throw new ExecutionException("Failed to unbind certkey to vserver due to " + e.getMessage()); + } + + } + + + private static void uploadCert(String nsIp, String user, String password, String certName, byte[] certData) throws ExecutionException { + try { + SshHelper.scpTo(nsIp,SSH_PORT,user,null,password, SSL_CERT_PATH, certData, certName, null); + } catch (Exception e){ + throw new ExecutionException("Failed to copy private key to device " + e.getMessage()); + } + } + + private static void uploadKey(String nsIp, String user, String password, String keyName, byte[] keyData) throws ExecutionException { + try { + SshHelper.scpTo(nsIp, SSH_PORT, user, null, password, SSL_CERT_PATH, keyData, keyName, null); + } catch (Exception e){ + throw new ExecutionException("Failed to copy private key to device " + e.getMessage()); + } + } + + + private static void enableSslFeature(nitro_service ns) throws ExecutionException { + try { + base_response result = ns.enable_features(new String[]{"SSL"}); + if( result.errorcode != 0 ) + throw new ExecutionException("Unable to enable SSL on LB"); + } catch (nitro_exception e){ + throw new ExecutionException("Failed to enable ssl feature on load balancer due to " + e.getMessage()); + } catch (Exception e){ + throw new ExecutionException("Failed to enable ssl feature on load balancer due to " + e.getMessage()); + } + } + + public static boolean checkSslFeature(nitro_service ns) throws ExecutionException { + try { + String[] features = ns.get_enabled_features(); + if (features != null) { + for (String feature : features) { + if (feature.equalsIgnoreCase("SSL")) { + return true; + } + } + } + return false; + } catch (nitro_exception e){ + throw new ExecutionException("Failed to check ssl feature on load balancer due to " + e.getMessage()); + } catch (Exception e){ + throw new ExecutionException("Failed to check ssl feature on load balancer due to " + e.getMessage()); + } + } + + + } + private void enableVPXInterfaces(String publicIf, String privateIf, ns ns_obj) { // enable VPX to use 10 gigabit Ethernet interfaces if public/private interface @@ -2110,6 +2327,25 @@ public class NetscalerResource implements ServerResource { } } + private boolean nsVirtualServerExists(String vserverName) throws ExecutionException { + try { + if (com.citrix.netscaler.nitro.resource.config.lb.lbvserver.get(_netscalerService, vserverName) != null) { + return true; + } else { + return false; + } + } catch (nitro_exception e) { + if (e.getErrorCode() == NitroError.NS_RESOURCE_NOT_EXISTS) { + return false; + } else { + throw new ExecutionException("Failed to verify VServer " + vserverName + " exists on the NetScaler device due to " + e.getMessage()); + } + } catch (Exception e) { + throw new ExecutionException("Failed to verify VServer " + vserverName + " exists on the NetScaler device due to " + e.getMessage()); + } + } + + private boolean nsVlanNsipBindingExists(long vlanTag, String vlanSelfIp) throws ExecutionException { try { vlan_nsip_binding[] vlanNsipBindings = vlan_nsip_binding.get(_netscalerService, vlanTag); @@ -2308,11 +2544,14 @@ public class NetscalerResource implements ServerResource { private String getNetScalerProtocol(LoadBalancerTO loadBalancer) throws ExecutionException { String port = Integer.toString(loadBalancer.getSrcPort()); - String lbProtocol = loadBalancer.getProtocol(); + String lbProtocol = loadBalancer.getLbProtocol(); StickinessPolicyTO[] stickyPolicies = loadBalancer.getStickinessPolicies(); String nsProtocol = "TCP"; - if ((stickyPolicies != null) && (stickyPolicies.length > 0) && (stickyPolicies[0] != null)){ + if(lbProtocol == null) + lbProtocol = loadBalancer.getProtocol(); + + if ((stickyPolicies != null) && (stickyPolicies.length > 0) && (stickyPolicies[0] != null)){ StickinessPolicyTO stickinessPolicy = stickyPolicies[0]; if (StickinessMethodType.LBCookieBased.getName().equalsIgnoreCase(stickinessPolicy.getMethodName()) || (StickinessMethodType.AppCookieBased.getName().equalsIgnoreCase(stickinessPolicy.getMethodName()))) { @@ -2321,6 +2560,10 @@ public class NetscalerResource implements ServerResource { } } + + if( lbProtocol.equalsIgnoreCase(NetUtils.SSL_PROTO) || lbProtocol.equalsIgnoreCase(NetUtils.HTTP_PROTO)) + return lbProtocol.toUpperCase(); + if (port.equals(NetUtils.HTTP_PORT)) { nsProtocol = "HTTP"; } else if (NetUtils.TCP_PROTO.equalsIgnoreCase(lbProtocol)) { @@ -3381,6 +3624,18 @@ public class NetscalerResource implements ServerResource { return counterName.replace(' ', '_'); } + private String generateSslCertName(String srcIp, long srcPort) { + // maximum length supported by NS is 31 + return genObjectName("Cloud-Cert", srcIp, srcPort); + } + + private String generateSslKeyName(String srcIp, long srcPort) { + return genObjectName("Cloud-Key", srcIp, srcPort); + } + private String generateSslCertKeyName(String srcIp, long srcPort) { + return genObjectName("Cloud-CertKey", srcIp, srcPort); + } + private String genObjectName(Object... args) { String objectName = ""; for (int i = 0; i < args.length; i++) { diff --git a/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml b/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml index 5e3790825cb..f7a8d6795cd 100644 --- a/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml +++ b/server/resources/META-INF/cloudstack/core/spring-server-core-managers-context.xml @@ -223,4 +223,6 @@ + + diff --git a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java index 6ca40c01e98..8d54541dd62 100644 --- a/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java +++ b/server/src/com/cloud/network/ExternalLoadBalancerDeviceManagerImpl.java @@ -899,7 +899,7 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase if ((destinations != null && !destinations.isEmpty()) || rule.isAutoScaleConfig()) { boolean inline = _networkMgr.isNetworkInlineMode(network); LoadBalancerTO loadBalancer = new LoadBalancerTO(uuid, srcIp, srcPort, protocol, algorithm, revoked, false, inline, destinations, rule.getStickinessPolicies(), - rule.getHealthCheckPolicies()); + rule.getHealthCheckPolicies(), rule.getLbSslCert(), rule.getLbProtocol()); if (rule.isAutoScaleConfig()) { loadBalancer.setAutoScaleVmGroup(rule.getAutoScaleVmGroup()); } @@ -1184,7 +1184,7 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase if ((destinations != null && !destinations.isEmpty()) || !rule.isAutoScaleConfig()) { boolean inline = _networkMgr.isNetworkInlineMode(network); LoadBalancerTO loadBalancer = new LoadBalancerTO(uuid, srcIp, srcPort, protocol, algorithm, revoked, - false, inline, destinations, rule.getStickinessPolicies(), rule.getHealthCheckPolicies()); + false, inline, destinations, rule.getStickinessPolicies(), rule.getHealthCheckPolicies(), rule.getLbSslCert(), rule.getLbProtocol()); loadBalancersToApply.add(loadBalancer); } } @@ -1218,5 +1218,5 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase } } return null; - } + } } diff --git a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java index 0d434784505..a1650e07109 100755 --- a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java +++ b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java @@ -107,6 +107,9 @@ import com.cloud.network.dao.LoadBalancerVO; import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkServiceMapDao; import com.cloud.network.dao.NetworkVO; +import com.cloud.network.dao.LoadBalancerCertMapDao; +import com.cloud.network.dao.LoadBalancerCertMapVO; +import com.cloud.network.dao.SslCertVO; import com.cloud.network.element.LoadBalancingServiceProvider; import com.cloud.network.lb.LoadBalancingRule.LbAutoScalePolicy; import com.cloud.network.lb.LoadBalancingRule.LbAutoScaleVmGroup; @@ -115,6 +118,7 @@ import com.cloud.network.lb.LoadBalancingRule.LbCondition; import com.cloud.network.lb.LoadBalancingRule.LbDestination; import com.cloud.network.lb.LoadBalancingRule.LbHealthCheckPolicy; import com.cloud.network.lb.LoadBalancingRule.LbStickinessPolicy; +import com.cloud.network.lb.LoadBalancingRule.LbSslCert; import com.cloud.network.rules.FirewallManager; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRule.FirewallRuleType; @@ -253,6 +257,9 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements IpAddressManager _ipAddrMgr; @Inject EntityManager _entityMgr; + @Inject + LoadBalancerCertMapDao _lbCertMapDao; + // Will return a string. For LB Stickiness this will be a json, for // autoscale this will be "," separated values @@ -350,7 +357,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements */ List policyList = getStickinessPolicies(lb.getId()); Ip sourceIp = getSourceIp(lb); - LoadBalancingRule rule = new LoadBalancingRule(lb, null, policyList, null, sourceIp); + LoadBalancingRule rule = new LoadBalancingRule(lb, null, policyList, null, sourceIp, null, lb.getLbProtocol()); rule.setAutoScaleVmGroup(lbAutoScaleVmGroup); if (!isRollBackAllowedForProvider(lb)) { @@ -558,7 +565,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements policyList.add(new LbStickinessPolicy(cmd.getStickinessMethodName(), lbpolicy.getParams())); Ip sourceIp = getSourceIp(loadBalancer); LoadBalancingRule lbRule = new LoadBalancingRule(loadBalancer, getExistingDestinations(lbpolicy.getId()), - policyList, null, sourceIp); + policyList, null, sourceIp,null, loadBalancer.getLbProtocol()); if (!validateLbRule(lbRule)) { throw new InvalidParameterValueException("Failed to create Stickiness policy: Validation Failed " + cmd.getLbRuleId()); @@ -905,7 +912,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements // hashealtChecks if (hcPolicyList != null && hcPolicyList.size() > 0) { Ip sourceIp = getSourceIp(lb); - LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList, null, hcPolicyList, sourceIp); + LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList, null, hcPolicyList, sourceIp, null, lb.getLbProtocol()); lbrules.add(loadBalancing); } } @@ -1087,12 +1094,161 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements return success; } + @Override + public boolean assignSSLCertToLoadBalancerRule(Long lbId, String certName, String publicCert, String privateKey) { + s_logger.error("Calling the manager for LB"); + LoadBalancerVO loadBalancer = _lbDao.findById(lbId); + + return false; //TODO + } + @Override @ActionEvent(eventType = EventTypes.EVENT_REMOVE_FROM_LOAD_BALANCER_RULE, eventDescription = "removing from load balancer", async = true) public boolean removeFromLoadBalancer(long loadBalancerId, List instanceIds) { return removeFromLoadBalancerInternal(loadBalancerId, instanceIds, true); } + @Override + public LbSslCert getLbSslCert(long lbRuleId) { + LoadBalancerCertMapVO lbCertMap = _lbCertMapDao.findByLbRuleId(lbRuleId); + + if ( lbCertMap == null) + return null; + + SslCertVO certVO = _entityMgr.findById(SslCertVO.class, lbCertMap.getCertId()); + if ( certVO == null) { + s_logger.warn("Cert rule with cert ID " + lbCertMap.getCertId() + " but Cert is not found"); + return null; + } + + return new LbSslCert(certVO.getCertificate(), certVO.getKey(), + certVO.getChain(), certVO.getPassword(), lbCertMap.isRevoke()); + } + + @Override + @DB + @ActionEvent(eventType = EventTypes.EVENT_LB_CERT_ASSIGN, eventDescription = "assigning certificate to load balancer", async = true) + public boolean assignCertToLoadBalancer(long lbRuleId, Long certId) { + CallContext caller = CallContext.current(); + + LoadBalancerVO loadBalancer = _lbDao.findById(Long.valueOf(lbRuleId)); + if (loadBalancer == null) { + throw new InvalidParameterException("Invalid load balancer id: " + lbRuleId); + } + + SslCertVO certVO = _entityMgr.findById(SslCertVO.class,certId); + if (certVO == null) { + throw new InvalidParameterException("Invalid certificate id: " + certId); + } + + _accountMgr.checkAccess(caller.getCallingAccount(), null, true, loadBalancer); + + // check if LB and Cert belong to the same account + if( loadBalancer.getAccountId() != certVO.getAccountId() ){ + throw new InvalidParameterValueException("Access denied for account " + certVO.getAccountId()); + } + + + String capability = getLBCapability(loadBalancer.getNetworkId(), Capability.SslTermination.getName()); + if ( capability == null){ + throw new InvalidParameterValueException("Ssl termination not supported by the loadbalancer"); + } + + //check if the lb is already bound + LoadBalancerCertMapVO certMapRule = _lbCertMapDao.findByLbRuleId(loadBalancer.getId()); + if (certMapRule != null) + throw new InvalidParameterValueException("Another certificate is already bound to the LB"); + + //check for correct port + if ( loadBalancer.getLbProtocol() == null || !(loadBalancer.getLbProtocol().equals(NetUtils.SSL_PROTO))) + throw new InvalidParameterValueException("Bad LB protocol: Expected ssl got " + loadBalancer.getLbProtocol()); + + + boolean success = false; + FirewallRule.State backupState = loadBalancer.getState(); + + try { + + loadBalancer.setState(FirewallRule.State.Add); + _lbDao.persist(loadBalancer); + LoadBalancerCertMapVO certMap = new LoadBalancerCertMapVO(lbRuleId,certId,false); + _lbCertMapDao.persist(certMap); + applyLoadBalancerConfig(loadBalancer.getId()); + /*s_logger.warn("Failed to apply Ssl Cert to LB " + loadBalancer.getId()); + CloudRuntimeException ex = new CloudRuntimeException( + "Failed to apply Ssl Cert to LB " + loadBalancer.getId()); + ex.addProxyObject(loadBalancer.getUuid(), "loadBalancerId"); + throw ex;*/ + success = true; + } catch (ResourceUnavailableException e) { + if (isRollBackAllowedForProvider(loadBalancer)) { + + loadBalancer.setState(backupState); + _lbDao.persist(loadBalancer); + LoadBalancerCertMapVO certMap = _lbCertMapDao.findByLbRuleId(lbRuleId); + _lbCertMapDao.remove(certMap.getId()); + s_logger.debug("LB Rollback rule id: " + loadBalancer.getId() + " while adding cert"); + } + s_logger.warn("Unable to apply the load balancer config because resource is unavaliable.", e); + } + return success; + } + + @Override + @DB + @ActionEvent(eventType = EventTypes.EVENT_LB_CERT_REMOVE, eventDescription = "removing certificate from load balancer", async = true) + public boolean removeCertFromLoadBalancer(long lbRuleId) { + CallContext caller = CallContext.current(); + + LoadBalancerVO loadBalancer = _lbDao.findById(lbRuleId); + LoadBalancerCertMapVO lbCertMap = _lbCertMapDao.findByLbRuleId(lbRuleId); + + if (loadBalancer == null) { + throw new InvalidParameterException("Invalid load balancer value: " + lbRuleId); + } + + if( lbCertMap == null ) { + throw new InvalidParameterException("No certificate is bound to lb with id: " + lbRuleId); + } + + _accountMgr.checkAccess(caller.getCallingAccount(), null, true, loadBalancer); + + boolean success = false; + FirewallRule.State backupState = loadBalancer.getState(); + try { + + loadBalancer.setState(FirewallRule.State.Add); + _lbDao.persist(loadBalancer); + lbCertMap.setRevoke(true); + _lbCertMapDao.persist(lbCertMap); + + if (!applyLoadBalancerConfig(lbRuleId)) { + s_logger.warn("Failed to remove cert from load balancer rule id " + lbRuleId); + CloudRuntimeException ex = new CloudRuntimeException( + "Failed to remove certificate load balancer rule id " + lbRuleId); + ex.addProxyObject(loadBalancer.getUuid(), "loadBalancerId"); + throw ex; + } + success = true; + } catch (ResourceUnavailableException e) { + if (isRollBackAllowedForProvider(loadBalancer)) { + lbCertMap.setRevoke(false); + _lbCertMapDao.persist(lbCertMap); + loadBalancer.setState(backupState); + _lbDao.persist(loadBalancer); + s_logger.debug("Rolled back certificate removal lb id " + lbRuleId); + } + s_logger.warn("Unable to apply the load balancer config because resource is unavaliable.", e); + if (!success) { + CloudRuntimeException ex = new CloudRuntimeException( + "Failed to remove certificate from load balancer rule id " + lbRuleId); + ex.addProxyObject(loadBalancer.getUuid(), "loadBalancerId"); + throw ex; + } + } + return success; + } + private boolean removeFromLoadBalancerInternal(long loadBalancerId, List instanceIds, boolean rollBack) { CallContext caller = CallContext.current(); @@ -1317,7 +1473,8 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements @Override @ActionEvent(eventType = EventTypes.EVENT_LOAD_BALANCER_CREATE, eventDescription = "creating load balancer") public LoadBalancer createPublicLoadBalancerRule(String xId, String name, String description, - int srcPortStart, int srcPortEnd, int defPortStart, int defPortEnd, Long ipAddrId, String protocol, String algorithm, long networkId, long lbOwnerId, boolean openFirewall) + int srcPortStart, int srcPortEnd, int defPortStart, int defPortEnd, Long ipAddrId, String protocol, String algorithm, + long networkId, long lbOwnerId, boolean openFirewall, String lbProtocol) throws NetworkRuleConflictException, InsufficientAddressCapacityException { Account lbOwner = _accountMgr.getAccount(lbOwnerId); @@ -1377,7 +1534,8 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements + network); } - result = createPublicLoadBalancer(xId, name, description, srcPortStart, defPortStart, ipVO.getId(), protocol, algorithm, openFirewall, CallContext.current()); + result = createPublicLoadBalancer(xId, name, description, srcPortStart, defPortStart, ipVO.getId(), protocol, + algorithm, openFirewall, CallContext.current(), lbProtocol); } catch (Exception ex) { s_logger.warn("Failed to create load balancer due to ", ex); if (ex instanceof NetworkRuleConflictException) { @@ -1407,13 +1565,14 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements @DB @Override public LoadBalancer createPublicLoadBalancer(final String xId, final String name, final String description, - final int srcPort, final int destPort, final long sourceIpId, final String protocol, final String algorithm, final boolean openFirewall, final CallContext caller) + final int srcPort, final int destPort, final long sourceIpId, final String protocol, + final String algorithm, final boolean openFirewall, final CallContext caller, final String lbProtocol) throws NetworkRuleConflictException { if (!NetUtils.isValidPort(destPort)) { throw new InvalidParameterValueException("privatePort is an invalid value: " + destPort); } - + if ((algorithm == null) || !NetUtils.isValidAlgorithm(algorithm)) { throw new InvalidParameterValueException("Invalid algorithm: " + algorithm); } @@ -1454,18 +1613,29 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements _firewallMgr.validateFirewallRule(caller.getCallingAccount(), ipAddr, srcPort, srcPort, protocol, Purpose.LoadBalancing, FirewallRuleType.User, networkId, null); + LoadBalancerVO newRule = new LoadBalancerVO(xId, name, description, + sourceIpId, srcPort, destPort, algorithm, + networkId, ipAddr.getAllocatedToAccountId(), ipAddr.getAllocatedInDomainId(), lbProtocol); + + // verify rule is supported by Lb provider of the network + Ip sourceIp = getSourceIp(newRule); + LoadBalancingRule loadBalancing = new LoadBalancingRule(newRule, new ArrayList(), + new ArrayList(), new ArrayList(), sourceIp, null, lbProtocol); + if (!validateLbRule(loadBalancing)) { + throw new InvalidParameterValueException("LB service provider cannot support this rule"); + } return Transaction.execute(new TransactionCallbackWithException() { @Override public LoadBalancerVO doInTransaction(TransactionStatus status) throws NetworkRuleConflictException { LoadBalancerVO newRule = new LoadBalancerVO(xId, name, description, sourceIpId, srcPort, destPort, algorithm, - networkId, ipAddr.getAllocatedToAccountId(), ipAddr.getAllocatedInDomainId()); + networkId, ipAddr.getAllocatedToAccountId(), ipAddr.getAllocatedInDomainId(), lbProtocol); // verify rule is supported by Lb provider of the network Ip sourceIp = getSourceIp(newRule); LoadBalancingRule loadBalancing = new LoadBalancingRule(newRule, new ArrayList(), - new ArrayList(), new ArrayList(), sourceIp); + new ArrayList(), new ArrayList(), sourceIp, null, lbProtocol); if (!validateLbRule(loadBalancing)) { throw new InvalidParameterValueException("LB service provider cannot support this rule"); } @@ -1510,7 +1680,6 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements } - @Override public boolean applyLoadBalancerConfig(long lbRuleId) throws ResourceUnavailableException { LoadBalancerVO lb = _lbDao.findById(lbRuleId); List lbs; @@ -1576,7 +1745,8 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements List policyList = getStickinessPolicies(lb.getId()); Ip sourceIp = getSourceIp(lb); - LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, null, policyList, null, sourceIp); + LbSslCert sslCert = getLbSslCert(lb.getId()); + LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, null, policyList, null, sourceIp, sslCert, lb.getLbProtocol()); if (_autoScaleVmGroupDao.isAutoScaleLoadBalancer(lb.getId())) { // Get the associated VmGroup @@ -1659,7 +1829,13 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements _lb2healthcheckDao.remove(lb.getId(), true); s_logger.debug("Load balancer rule id " + lb.getId() + " is removed health check monitors policies"); } - + + LoadBalancerCertMapVO lbCertMap = _lbCertMapDao.findByLbRuleId(lb.getId()); + if (lbCertMap != null && lbCertMap.isRevoke()) { + _lbCertMapDao.remove(lbCertMap.getId()); + s_logger.debug("Load balancer rule id " + lb.getId() + " removed certificate mapping"); + } + return checkForReleaseElasticIp; } }); diff --git a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index 617d6ac8f3e..b8d0babe3f9 100755 --- a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -187,6 +187,7 @@ import com.cloud.network.lb.LoadBalancingRule; import com.cloud.network.lb.LoadBalancingRule.LbDestination; import com.cloud.network.lb.LoadBalancingRule.LbHealthCheckPolicy; import com.cloud.network.lb.LoadBalancingRule.LbStickinessPolicy; +import com.cloud.network.lb.LoadBalancingRule.LbSslCert; import com.cloud.network.lb.LoadBalancingRulesManager; import com.cloud.network.router.VirtualRouter.RedundantState; import com.cloud.network.router.VirtualRouter.Role; @@ -2544,7 +2545,8 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V List policyList = _lbMgr.getStickinessPolicies(lb.getId()); List hcPolicyList = _lbMgr.getHealthCheckPolicies(lb.getId()); Ip sourceIp = _networkModel.getPublicIpAddress(lb.getSourceIpAddressId()).getAddress(); - LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList, policyList, hcPolicyList, sourceIp); + LbSslCert sslCert = _lbMgr.getLbSslCert(lb.getId()); + LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList, policyList, hcPolicyList, sourceIp, sslCert, lb.getLbProtocol()); lbRules.add(loadBalancing); } } @@ -3680,8 +3682,11 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V List dstList = _lbMgr.getExistingDestinations(lb.getId()); List policyList = _lbMgr.getStickinessPolicies(lb.getId()); List hcPolicyList = _lbMgr.getHealthCheckPolicies(lb.getId()); + LbSslCert sslCert = _lbMgr.getLbSslCert(lb.getId()); Ip sourceIp = _networkModel.getPublicIpAddress(lb.getSourceIpAddressId()).getAddress(); - LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList, policyList, hcPolicyList, sourceIp); + LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList, policyList, hcPolicyList, sourceIp, + sslCert, lb.getLbProtocol()); + lbRules.add(loadBalancing); } return sendLBRules(router, lbRules, network.getId()); @@ -3716,8 +3721,9 @@ public class VirtualNetworkApplianceManagerImpl extends ManagerBase implements V List dstList = _lbMgr.getExistingDestinations(lb.getId()); List policyList = _lbMgr.getStickinessPolicies(lb.getId()); List hcPolicyList = _lbMgr.getHealthCheckPolicies(lb.getId()); + LbSslCert sslCert = _lbMgr.getLbSslCert(lb.getId()); Ip sourceIp = _networkModel.getPublicIpAddress(lb.getSourceIpAddressId()).getAddress(); - LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList, policyList, hcPolicyList, sourceIp); + LoadBalancingRule loadBalancing = new LoadBalancingRule(lb, dstList, policyList, hcPolicyList, sourceIp, sslCert, lb.getLbProtocol()); lbRules.add(loadBalancing); } return sendLBRules(router, lbRules, network.getId()); diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 35bc6813c03..d083c11eceb 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -287,6 +287,11 @@ import org.apache.cloudstack.api.command.user.loadbalancer.ListLoadBalancerRuleI import org.apache.cloudstack.api.command.user.loadbalancer.ListLoadBalancerRulesCmd; import org.apache.cloudstack.api.command.user.loadbalancer.RemoveFromLoadBalancerRuleCmd; import org.apache.cloudstack.api.command.user.loadbalancer.UpdateLoadBalancerRuleCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.UploadSslCertCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.DeleteSslCertCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.ListSslCertsCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.AssignCertToLoadBalancerCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.RemoveCertFromLoadBalancerCmd; import org.apache.cloudstack.api.command.user.nat.CreateIpForwardingRuleCmd; import org.apache.cloudstack.api.command.user.nat.DeleteIpForwardingRuleCmd; import org.apache.cloudstack.api.command.user.nat.DisableStaticNatCmd; @@ -2876,6 +2881,11 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe cmdList.add(UpdateNetworkACLItemCmd.class); cmdList.add(CleanVMReservationsCmd.class); cmdList.add(UpgradeRouterTemplateCmd.class); + cmdList.add(UploadSslCertCmd.class); + cmdList.add(DeleteSslCertCmd.class); + cmdList.add(ListSslCertsCmd.class); + cmdList.add(AssignCertToLoadBalancerCmd.class); + cmdList.add(RemoveCertFromLoadBalancerCmd.class); return cmdList; } diff --git a/server/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerManagerImpl.java b/server/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerManagerImpl.java index b7cd231831c..f0f0a6efbf2 100644 --- a/server/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerManagerImpl.java +++ b/server/src/org/apache/cloudstack/network/lb/ApplicationLoadBalancerManagerImpl.java @@ -146,7 +146,7 @@ public class ApplicationLoadBalancerManagerImpl extends ManagerBase implements A //4) Validate Load Balancing rule on the providers LoadBalancingRule loadBalancing = new LoadBalancingRule(newRule, new ArrayList(), - new ArrayList(), new ArrayList(), sourceIpAddr); + new ArrayList(), new ArrayList(), sourceIpAddr, null, null); if (!_lbMgr.validateLbRule(loadBalancing)) { throw new InvalidParameterValueException("LB service provider cannot support this rule"); } diff --git a/server/src/org/apache/cloudstack/network/lb/CertServiceImpl.java b/server/src/org/apache/cloudstack/network/lb/CertServiceImpl.java new file mode 100644 index 00000000000..53dae507bbb --- /dev/null +++ b/server/src/org/apache/cloudstack/network/lb/CertServiceImpl.java @@ -0,0 +1,477 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.network.lb; + +import com.cloud.event.ActionEvent; +import com.cloud.event.EventTypes; +import com.cloud.network.dao.*; +import com.cloud.network.lb.CertService; +import com.cloud.network.rules.LoadBalancer; +import com.cloud.user.dao.AccountDao; +import com.cloud.utils.db.EntityManager; +import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.cloudstack.api.command.user.loadbalancer.DeleteSslCertCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.ListSslCertsCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.UploadSslCertCmd; +import org.apache.cloudstack.api.response.SslCertResponse; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.utils.db.DB; +import org.apache.cloudstack.acl.SecurityChecker; +import org.apache.cloudstack.context.CallContext; +import org.apache.log4j.Logger; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.openssl.PEMReader; +import org.bouncycastle.openssl.PasswordFinder; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.ejb.Local; +import javax.inject.Inject; +import java.io.IOException; +import java.io.StringReader; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.security.*; +import java.security.cert.*; +import java.security.cert.Certificate; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +@Local(value = {CertService.class}) +public class CertServiceImpl implements CertService { + + private static final Logger s_logger = Logger.getLogger(CertServiceImpl.class); + + @Inject AccountManager _accountMgr; + @Inject AccountDao _accountDao; + @Inject SslCertDao _sslCertDao; + @Inject LoadBalancerCertMapDao _lbCertDao; + @Inject EntityManager _entityMgr; + + + + public CertServiceImpl() { + Security.addProvider(new BouncyCastleProvider()); + } + + @DB + @Override + @ActionEvent(eventType = EventTypes.EVENT_LB_CERT_UPLOAD, eventDescription = "Uploading a certificate to cloudstack", async = false) + public SslCertResponse uploadSslCert(UploadSslCertCmd certCmd) { + try { + + String cert = URLDecoder.decode(certCmd.getCert(), "UTF-8"); + String key = URLDecoder.decode(certCmd.getKey(), "UTF-8"); + String password = certCmd.getPassword(); + String chain = certCmd.getChain() == null ? null: URLDecoder.decode(certCmd.getChain(), "UTF-8"); + + validate(cert, key, password, chain); + s_logger.debug("Certificate Validation succeeded"); + String fingerPrint = generateFingerPrint(parseCertificate(cert)); + + Long accountId = CallContext.current().getCallingAccount().getId(); + Long domainId = CallContext.current().getCallingAccount().getDomainId(); + + + SslCertVO certVO = new SslCertVO(cert, key, password, chain, accountId, domainId, fingerPrint); + _sslCertDao.persist(certVO); + + + return createCertResponse(certVO, null); + + } catch (UnsupportedEncodingException e) { + throw new CloudRuntimeException("Error decoding certificate data"); + } + + } + + @DB + @Override + @ActionEvent(eventType = EventTypes.EVENT_LB_CERT_DELETE, eventDescription = "Deleting a certificate to cloudstack", async = false) + public void deleteSslCert(DeleteSslCertCmd deleteSslCertCmd) { + + CallContext ctx = CallContext.current(); + Account caller = ctx.getCallingAccount(); + + Long certId = deleteSslCertCmd.getId(); + SslCertVO certVO = _sslCertDao.findById(certId); + + if (certVO == null) { + throw new InvalidParameterValueException("Invalid certificate id: " + certId); + } + _accountMgr.checkAccess(caller, SecurityChecker.AccessType.ModifyEntry, true, certVO); + + List lbCertRule = _lbCertDao.listByCertId(certId); + + if ( (lbCertRule != null) && (!lbCertRule.isEmpty()) ){ + String lbUuids = ""; + + for( LoadBalancerCertMapVO rule : lbCertRule ){ + LoadBalancerVO lb = _entityMgr.findById(LoadBalancerVO.class, rule.getLbId()); + lbUuids += " " + lb.getUuid(); + } + + throw new CloudRuntimeException("Certificate in use by a loadbalancer(s)" + lbUuids); + } + + _sslCertDao.remove(certId); + } + + @Override + public List listSslCerts(ListSslCertsCmd listSslCertCmd) { + CallContext ctx = CallContext.current(); + Account caller = ctx.getCallingAccount(); + + Long certId= listSslCertCmd.getCertId(); + Long accountId = listSslCertCmd.getAccountId(); + Long lbRuleId = listSslCertCmd.getLbId(); + + List certResponseList = new ArrayList(); + + if (certId == null && accountId == null && lbRuleId == null ) { + throw new InvalidParameterValueException("Invalid parameters either certificate ID or Account ID or Loadbalancer ID required"); + } + + List certLbMap = null; + SslCertVO certVO = null; + + + if(certId != null) { + + certVO = _sslCertDao.findById(certId); + + if (certVO == null) { + throw new InvalidParameterValueException("Invalid certificate id: " + certId); + } + + + _accountMgr.checkAccess(caller, SecurityChecker.AccessType.ListEntry, true, certVO); + + certLbMap = _lbCertDao.listByCertId(certId); + + certResponseList.add(createCertResponse(certVO, certLbMap)); + return certResponseList; + } + + if ( lbRuleId != null) { + LoadBalancer lb = _entityMgr.findById(LoadBalancerVO.class, lbRuleId); + + if ( lb == null ){ + throw new InvalidParameterValueException("found no loadbalancer wth id: " + lbRuleId); + } + + _accountMgr.checkAccess(caller, SecurityChecker.AccessType.ListEntry, true, lb); + + // get the cert id + LoadBalancerCertMapVO lbCertMapRule; + lbCertMapRule = _lbCertDao.findByLbRuleId(lbRuleId); + + if (lbCertMapRule == null) { + throw new InvalidParameterValueException("No certificate bound to loadbalancer id: " + lbRuleId); + } + + certVO = _sslCertDao.findById(lbCertMapRule.getCertId()); + certLbMap = _lbCertDao.listByCertId(lbCertMapRule.getCertId()); + + certResponseList.add(createCertResponse(certVO, certLbMap)); + return certResponseList; + + } + + //reached here look by accountId + List certVOList = _sslCertDao.listByAccountId(accountId); + if ( certVOList == null || certVOList.isEmpty()) + return certResponseList; + _accountMgr.checkAccess(caller, SecurityChecker.AccessType.ListEntry, true, certVOList.get(0)); + + for( SslCertVO cert : certVOList ){ + certLbMap = _lbCertDao.listByCertId(cert.getId()); + certResponseList.add(createCertResponse(cert, certLbMap)); + } + + return certResponseList; + } + + + private void validate(String _cert, String _key, String _password, String _chain) { + Certificate cert; + PrivateKey key; + List chain=null; + + + try { + cert = parseCertificate(_cert); + key = parsePrivateKey(_key, _password); + + if ( _chain != null) { + chain = parseChain(_chain); + } + + } catch (IOException e) { + throw new IllegalArgumentException("Parsing certificate/key failed: " + e.getMessage()); + } + + validateCert(cert, _chain != null? true: false); + validateKeys(cert.getPublicKey(), key); + + if ( _chain != null ) + validateChain(chain, cert); + } + + public SslCertResponse createCertResponse(SslCertVO cert, List lbCertMap) { + SslCertResponse response = new SslCertResponse(); + + Account account = _accountDao.findByIdIncludingRemoved(cert.getAccountId()); + + 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()); + + if ( lbCertMap != null && !lbCertMap.isEmpty()){ + List lbIds = new ArrayList(); + for ( LoadBalancerCertMapVO mapVO : lbCertMap ) { + LoadBalancer lb = _entityMgr.findById(LoadBalancerVO.class, mapVO.getLbId()); + lbIds.add(lb.getUuid()); + } + response.setLbIds(lbIds); + } + + return response; + } + + private void validateCert(Certificate cert, boolean chain_present) { + + if ( !( cert instanceof X509Certificate)) + throw new IllegalArgumentException("Invalid certificate format. Expected X509 certificate"); + + try { + ((X509Certificate)cert).checkValidity(); + } catch (Exception e) { + throw new IllegalArgumentException("Certificate expired or not valid"); + } + + if( !chain_present ) { + PublicKey pubKey = cert.getPublicKey(); + try { + cert.verify(pubKey); + } catch (Exception e) { + throw new IllegalArgumentException("No chain given and certificate not self signed"); + } + } + } + + private void validateKeys(PublicKey pubKey, PrivateKey privKey) { + + if (pubKey.getAlgorithm() != privKey.getAlgorithm()) + throw new IllegalArgumentException("Public and private key have different algorithms"); + + // No encryption for DSA + if ( pubKey.getAlgorithm() != "RSA") + return; + + try { + + String data = "ENCRYPT_DATA"; + SecureRandom random = new SecureRandom(); + Cipher cipher = Cipher.getInstance(pubKey.getAlgorithm()); + cipher.init(Cipher.ENCRYPT_MODE,privKey,random); + byte[] encryptedData = cipher.doFinal(data.getBytes()); + + cipher.init(Cipher.DECRYPT_MODE,pubKey,random); + String decreptedData = new String(cipher.doFinal(encryptedData)); + if (!decreptedData.equals(data)) + throw new IllegalArgumentException("Bad public-private key"); + + } catch (BadPaddingException e) { + throw new IllegalArgumentException("Bad public-private key"); + } catch (IllegalBlockSizeException e) { + throw new IllegalArgumentException("Bad public-private key"); + } catch (NoSuchPaddingException e) { + throw new IllegalArgumentException("Bad public-private key"); + } catch (InvalidKeyException e) { + throw new IllegalArgumentException("Invalid public-private key"); + } catch (NoSuchAlgorithmException e) { + throw new IllegalArgumentException("Invalid algorithm for public-private key"); + } + } + + + private void validateChain(List chain, Certificate cert) { + + List certs = new ArrayList(); + List root = new ArrayList(); + + Set anchors = new HashSet(); + + + certs.add(cert); // adding for self signed certs + certs.addAll(chain); + + for( Certificate c : certs) { + if ( !( c instanceof X509Certificate)) + throw new IllegalArgumentException("Invalid chain format. Expected X509 certificate"); + + X509Certificate xCert = (X509Certificate)c; + + Principal subject = xCert.getSubjectDN(); + Principal issuer = xCert.getIssuerDN(); + + if( issuer != null && subject.equals(issuer) ) { + root.add(c); + anchors.add(new TrustAnchor(xCert,null)); + } + } + + if ( root.size() == 0 ) + throw new IllegalArgumentException("No root certificates found for certificate chain",null); + + + X509CertSelector target = new X509CertSelector(); + target.setCertificate((X509Certificate)cert); + + PKIXBuilderParameters params = null; + try { + params = new PKIXBuilderParameters(anchors, target); + params.setRevocationEnabled(false); + params.addCertStore(CertStore.getInstance("Collection", new CollectionCertStoreParameters(certs))); + CertPathBuilder builder = CertPathBuilder.getInstance("PKIX"); + builder.build(params); + } catch (InvalidAlgorithmParameterException e) { + throw new IllegalArgumentException("Invalid certificate chain",null); + } catch (CertPathBuilderException e) { + throw new IllegalArgumentException("Invalid certificate chain",null); + } catch (NoSuchAlgorithmException e) { + throw new IllegalArgumentException("Invalid certificate chain",null); + } + + } + + public PrivateKey parsePrivateKey(String key, String password) throws IOException { + + PasswordFinder pGet = null; + + if( password != null ) + pGet = new KeyPassword(password.toCharArray()); + + PEMReader privateKey = new PEMReader(new StringReader(key), pGet); + Object obj = privateKey.readObject(); + + try { + + if ( obj instanceof KeyPair ) + return ((KeyPair)obj).getPrivate(); + + return (PrivateKey) obj; + + }catch (Exception e){ + e.printStackTrace(); + throw new IOException("Invalid Key format or invalid password."); + } + } + + + public Certificate parseCertificate(String cert) { + PEMReader certPem = new PEMReader(new StringReader(cert)); + try { + return (Certificate) certPem.readObject(); + } catch (Exception e) { + throw new InvalidParameterValueException("Invalid Certificate format. Expected X509 certificate"); + } + } + + + public List parseChain(String chain) throws IOException { + + List certs = new ArrayList(); + PEMReader reader = new PEMReader(new StringReader(chain)); + + Certificate crt = null; + + while ( ( crt = (Certificate) reader.readObject()) != null ) { + if ( crt instanceof X509Certificate) { + certs.add(crt); + } + } + if ( certs.size() == 0 ) + throw new IllegalArgumentException("Unable to decode certificate chain",null); + + return certs; + } + + + String generateFingerPrint(Certificate cert) { + + final char[] HEX = + {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + + StringBuilder buffer = new StringBuilder(60); + try { + + MessageDigest md = MessageDigest.getInstance("SHA-1"); + byte[] data = md.digest(cert.getEncoded()); + + for ( int i = 0 ; i < data.length ; i++ ) { + if ( buffer.length() > 0 ) { + buffer.append(":"); + } + + buffer.append(HEX[(0xF0 & data[i]) >>> 4]); + buffer.append(HEX[0x0F & data[i]]); + } + + } catch (CertificateEncodingException e) { + throw new InvalidParameterValueException("Bad certificate encoding"); + } catch (NoSuchAlgorithmException e) { + throw new InvalidParameterValueException("Bad certificate algorithm"); + } + + return buffer.toString(); + } + + + public static class KeyPassword implements PasswordFinder { + + boolean password_requested=false; + char[] password; + + + KeyPassword(char[] word){ + this.password = word; + } + + public char[] getPassword() { + password_requested=true; + return password; + } + + public boolean getPasswordRequested(){ + return password_requested; + } + } +} \ No newline at end of file diff --git a/server/test/org/apache/cloudstack/lb/ApplicationLoadBalancerTest.java b/server/test/org/apache/cloudstack/network/lb/ApplicationLoadBalancerTest.java similarity index 99% rename from server/test/org/apache/cloudstack/lb/ApplicationLoadBalancerTest.java rename to server/test/org/apache/cloudstack/network/lb/ApplicationLoadBalancerTest.java index 9b46e683113..82b11817948 100644 --- a/server/test/org/apache/cloudstack/lb/ApplicationLoadBalancerTest.java +++ b/server/test/org/apache/cloudstack/network/lb/ApplicationLoadBalancerTest.java @@ -14,7 +14,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package org.apache.cloudstack.lb; +package org.apache.cloudstack.network.lb; import java.io.IOException; import java.lang.reflect.Field; @@ -25,6 +25,7 @@ import javax.inject.Inject; import junit.framework.TestCase; +import org.apache.cloudstack.lb.ApplicationLoadBalancerRuleVO; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -335,7 +336,7 @@ public class ApplicationLoadBalancerTest extends TestCase { public AccountManager accountManager() { return Mockito.mock(AccountManager.class); } - + @Bean public LoadBalancingRulesManager loadBalancingRulesManager() { diff --git a/server/test/org/apache/cloudstack/network/lb/CertServiceTest.java b/server/test/org/apache/cloudstack/network/lb/CertServiceTest.java new file mode 100644 index 00000000000..e47fc013f05 --- /dev/null +++ b/server/test/org/apache/cloudstack/network/lb/CertServiceTest.java @@ -0,0 +1,791 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.network.lb; + +import com.cloud.network.dao.*; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.AccountVO; +import com.cloud.user.UserVO; +import com.cloud.user.dao.AccountDao; +import com.cloud.utils.db.EntityManager; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.TransactionLegacy; +import junit.framework.TestCase; +import org.apache.cloudstack.api.command.user.loadbalancer.DeleteSslCertCmd; +import org.apache.cloudstack.api.command.user.loadbalancer.UploadSslCertCmd; +import org.apache.cloudstack.context.CallContext; +import org.apache.log4j.Logger; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Field; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +import static org.apache.commons.io.FileUtils.readFileToString; +import static org.mockito.Matchers.*; +import static org.mockito.Mockito.when; + +public class CertServiceTest extends TestCase { + + private static final Logger s_logger = Logger.getLogger( CertServiceTest.class); + + @Override + @Before + public void setUp() { + Account account = new AccountVO("testaccount", 1, "networkdomain", (short)0, UUID.randomUUID().toString()); + UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString()); + CallContext.register(user, account); + } + + @Override + @After + public void tearDown() { + CallContext.unregister(); + } + + @Test + public void testUploadSslCert() throws Exception { + + /* Test1 : Given a Certificate in bad format (Not PEM), upload should fail */ + runUploadSslCertBadFormat(); + + /* Test2: Given a Certificate which is not X509, upload should fail */ + runUploadSslCertNotX509(); + + /* Test3: Given an expired certificate, upload should fail */ + runUploadSslCertExpiredCert(); + + /* Test4: Given a private key which has a different algorithm than the certificate, + upload should fail. + */ + runUploadSslCertBadkeyAlgo(); + + /* Test5: Given a private key which does not match the public key in the certificate, + upload should fail + */ + runUploadSslCertBadkeyPair(); + + /* Test6: Given an encrypted private key with a bad password. Upload should fail. */ + runUploadSslCertBadPassword(); + + /* Test7: If no chain is given, the certificate should be self signed. Else, uploadShould Fail */ + runUploadSslCertNoChain(); + + /* Test8: Chain is given but does not have root certificate */ + runUploadSslCertNoRootCert(); + + /* Test9: The chain given is not the correct chain for the certificate */ + runUploadSslCertBadChain(); + + /* Test10: Given a Self-signed Certificate with encrypted key, upload should succeed */ + runUploadSslCertSelfSignedNoPassword(); + + /* Test11: Given a Self-signed Certificate with non-encrypted key, upload should succeed */ + runUploadSslCertSelfSignedWithPassword(); + + /* Test12: Given a certificate signed by a CA and a valid CA chain, upload should succeed */ + runUploadSslCertWithCAChain(); + + } + + private void runUploadSslCertWithCAChain() throws Exception { + //To change body of created methods use File | Settings | File Templates. + + TransactionLegacy txn = TransactionLegacy.open("runUploadSslCertWithCAChain"); + + String certFile = getClass().getResource("/certs/rsa_ca_signed.crt").getFile(); + String keyFile = getClass().getResource("/certs/rsa_ca_signed.key").getFile(); + String chainFile = getClass().getResource("/certs/root_chain.crt").getFile(); + String password = "user"; + + + String cert = URLEncoder.encode(readFileToString(new File(certFile)), "UTF-8"); + String key = URLEncoder.encode(readFileToString(new File(keyFile)), "UTF-8"); + String chain = URLEncoder.encode(readFileToString(new File(chainFile)), "UTF-8"); + + CertServiceImpl certService = new CertServiceImpl(); + + //setting mock objects + certService._accountMgr = Mockito.mock(AccountManager.class); + Account account = new AccountVO("testaccount", 1, + "networkdomain", (short) 0, UUID.randomUUID().toString()); + when(certService._accountMgr.getAccount(anyLong())).thenReturn(account); + + certService._sslCertDao = Mockito.mock(SslCertDao.class); + when(certService._sslCertDao.persist(any(SslCertVO.class))).thenReturn(new SslCertVO()); + + + certService._accountDao = Mockito.mock(AccountDao.class); + when(certService._accountDao.findByIdIncludingRemoved(anyLong())).thenReturn((AccountVO)account); + + + //creating the command + UploadSslCertCmd uploadCmd = new UploadSslCertCmdExtn(); + Class _class = uploadCmd.getClass().getSuperclass(); + + Field certField = _class.getDeclaredField("cert"); + certField.setAccessible(true); + certField.set(uploadCmd, cert); + + Field keyField = _class.getDeclaredField("key"); + keyField.setAccessible(true); + keyField.set(uploadCmd, key); + + Field passField = _class.getDeclaredField("password"); + passField.setAccessible(true); + passField.set(uploadCmd, password); + + Field chainField = _class.getDeclaredField("chain"); + chainField.setAccessible(true); + chainField.set(uploadCmd, chain); + + certService.uploadSslCert(uploadCmd); + } + + private void runUploadSslCertSelfSignedWithPassword() throws Exception { + + TransactionLegacy txn = TransactionLegacy.open("runUploadSslCertSelfSignedWithPassword"); + + String certFile = getClass().getResource("/certs/rsa_self_signed_with_pwd.crt").getFile(); + String keyFile = getClass().getResource("/certs/rsa_self_signed_with_pwd.key").getFile(); + String password = "test"; + + + String cert = URLEncoder.encode(readFileToString(new File(certFile)), "UTF-8"); + String key = URLEncoder.encode(readFileToString(new File(keyFile)), "UTF-8"); + + CertServiceImpl certService = new CertServiceImpl(); + + //setting mock objects + certService._accountMgr = Mockito.mock(AccountManager.class); + Account account = new AccountVO("testaccount", 1, + "networkdomain", (short) 0, UUID.randomUUID().toString()); + when(certService._accountMgr.getAccount(anyLong())).thenReturn(account); + + certService._sslCertDao = Mockito.mock(SslCertDao.class); + when(certService._sslCertDao.persist(any(SslCertVO.class))).thenReturn(new SslCertVO()); + + + certService._accountDao = Mockito.mock(AccountDao.class); + when(certService._accountDao.findByIdIncludingRemoved(anyLong())).thenReturn((AccountVO)account); + + + //creating the command + UploadSslCertCmd uploadCmd = new UploadSslCertCmdExtn(); + Class _class = uploadCmd.getClass().getSuperclass(); + + Field certField = _class.getDeclaredField("cert"); + certField.setAccessible(true); + certField.set(uploadCmd, cert); + + Field keyField = _class.getDeclaredField("key"); + keyField.setAccessible(true); + keyField.set(uploadCmd, key); + + Field passField = _class.getDeclaredField("password"); + passField.setAccessible(true); + passField.set(uploadCmd, password); + + certService.uploadSslCert(uploadCmd); + } + + private void runUploadSslCertSelfSignedNoPassword() throws Exception { + + TransactionLegacy txn = TransactionLegacy.open("runUploadSslCertSelfSignedNoPassword"); + + String certFile = getClass().getResource("/certs/rsa_self_signed.crt").getFile(); + String keyFile = getClass().getResource("/certs/rsa_self_signed.key").getFile(); + + + String cert = URLEncoder.encode(readFileToString(new File(certFile)), "UTF-8"); + String key = URLEncoder.encode(readFileToString(new File(keyFile)), "UTF-8"); + + CertServiceImpl certService = new CertServiceImpl(); + + //setting mock objects + certService._accountMgr = Mockito.mock(AccountManager.class); + Account account = new AccountVO("testaccount", 1, + "networkdomain", (short) 0, UUID.randomUUID().toString()); + when(certService._accountMgr.getAccount(anyLong())).thenReturn(account); + + certService._sslCertDao = Mockito.mock(SslCertDao.class); + when(certService._sslCertDao.persist(any(SslCertVO.class))).thenReturn(new SslCertVO()); + + + certService._accountDao = Mockito.mock(AccountDao.class); + when(certService._accountDao.findByIdIncludingRemoved(anyLong())).thenReturn((AccountVO)account); + + + //creating the command + UploadSslCertCmd uploadCmd = new UploadSslCertCmdExtn(); + Class _class = uploadCmd.getClass().getSuperclass(); + + Field certField = _class.getDeclaredField("cert"); + certField.setAccessible(true); + certField.set(uploadCmd, cert); + + Field keyField = _class.getDeclaredField("key"); + keyField.setAccessible(true); + keyField.set(uploadCmd, key); + + certService.uploadSslCert(uploadCmd); + } + + + private void runUploadSslCertBadChain() throws IOException, IllegalAccessException, NoSuchFieldException { + //To change body of created methods use File | Settings | File Templates. + String certFile = getClass().getResource("/certs/rsa_ca_signed.crt").getFile(); + String keyFile = getClass().getResource("/certs/rsa_ca_signed.key").getFile(); + String chainFile = getClass().getResource("/certs/rsa_self_signed.crt").getFile(); + String password = "user"; + + + String cert = URLEncoder.encode(readFileToString(new File(certFile)), "UTF-8"); + String key = URLEncoder.encode(readFileToString(new File(keyFile)), "UTF-8"); + String chain = URLEncoder.encode(readFileToString(new File(chainFile)), "UTF-8"); + + CertServiceImpl certService = new CertServiceImpl(); + + //setting mock objects + certService._accountMgr = Mockito.mock(AccountManager.class); + Account account = new AccountVO("testaccount", 1, + "networkdomain", (short) 0, UUID.randomUUID().toString()); + when(certService._accountMgr.getAccount(anyLong())).thenReturn(account); + + certService._sslCertDao = Mockito.mock(SslCertDao.class); + when(certService._sslCertDao.persist(any(SslCertVO.class))).thenReturn(new SslCertVO()); + + //creating the command + UploadSslCertCmd uploadCmd = new UploadSslCertCmdExtn(); + Class _class = uploadCmd.getClass().getSuperclass(); + + Field certField = _class.getDeclaredField("cert"); + certField.setAccessible(true); + certField.set(uploadCmd, cert); + + Field keyField = _class.getDeclaredField("key"); + keyField.setAccessible(true); + keyField.set(uploadCmd, key); + + Field passField = _class.getDeclaredField("password"); + passField.setAccessible(true); + passField.set(uploadCmd, password); + + Field chainField = _class.getDeclaredField("chain"); + chainField.setAccessible(true); + chainField.set(uploadCmd, chain); + + try { + certService.uploadSslCert(uploadCmd); + } catch (Exception e) { + assertTrue(e.getMessage().contains("Invalid certificate chain")); + } + } + + private void runUploadSslCertNoRootCert() throws IOException, IllegalAccessException, NoSuchFieldException { + + //To change body of created methods use File | Settings | File Templates. + String certFile = getClass().getResource("/certs/rsa_ca_signed.crt").getFile(); + String keyFile = getClass().getResource("/certs/rsa_ca_signed.key").getFile(); + String chainFile = getClass().getResource("/certs/rsa_ca_signed2.crt").getFile(); + String password = "user"; + + + String cert = URLEncoder.encode(readFileToString(new File(certFile)), "UTF-8"); + String key = URLEncoder.encode(readFileToString(new File(keyFile)), "UTF-8"); + String chain = URLEncoder.encode(readFileToString(new File(chainFile)), "UTF-8"); + + CertServiceImpl certService = new CertServiceImpl(); + + //setting mock objects + certService._accountMgr = Mockito.mock(AccountManager.class); + Account account = new AccountVO("testaccount", 1, + "networkdomain", (short) 0, UUID.randomUUID().toString()); + when(certService._accountMgr.getAccount(anyLong())).thenReturn(account); + + certService._sslCertDao = Mockito.mock(SslCertDao.class); + when(certService._sslCertDao.persist(any(SslCertVO.class))).thenReturn(new SslCertVO()); + + //creating the command + UploadSslCertCmd uploadCmd = new UploadSslCertCmdExtn(); + Class _class = uploadCmd.getClass().getSuperclass(); + + Field certField = _class.getDeclaredField("cert"); + certField.setAccessible(true); + certField.set(uploadCmd, cert); + + Field keyField = _class.getDeclaredField("key"); + keyField.setAccessible(true); + keyField.set(uploadCmd, key); + + Field passField = _class.getDeclaredField("password"); + passField.setAccessible(true); + passField.set(uploadCmd, password); + + Field chainField = _class.getDeclaredField("chain"); + chainField.setAccessible(true); + chainField.set(uploadCmd, chain); + + try { + certService.uploadSslCert(uploadCmd); + } catch (Exception e) { + assertTrue(e.getMessage().contains("No root certificates found")); + } + + } + + private void runUploadSslCertNoChain() throws IOException, IllegalAccessException, NoSuchFieldException { + + String certFile = getClass().getResource("/certs/rsa_ca_signed.crt").getFile(); + String keyFile = getClass().getResource("/certs/rsa_ca_signed.key").getFile(); + String password = "user"; + + + String cert = URLEncoder.encode(readFileToString(new File(certFile)), "UTF-8"); + String key = URLEncoder.encode(readFileToString(new File(keyFile)), "UTF-8"); + + CertServiceImpl certService = new CertServiceImpl(); + + //setting mock objects + certService._accountMgr = Mockito.mock(AccountManager.class); + Account account = new AccountVO("testaccount", 1, + "networkdomain", (short) 0, UUID.randomUUID().toString()); + when(certService._accountMgr.getAccount(anyLong())).thenReturn(account); + + certService._sslCertDao = Mockito.mock(SslCertDao.class); + when(certService._sslCertDao.persist(any(SslCertVO.class))).thenReturn(new SslCertVO()); + + //creating the command + UploadSslCertCmd uploadCmd = new UploadSslCertCmdExtn(); + Class _class = uploadCmd.getClass().getSuperclass(); + + Field certField = _class.getDeclaredField("cert"); + certField.setAccessible(true); + certField.set(uploadCmd, cert); + + Field keyField = _class.getDeclaredField("key"); + keyField.setAccessible(true); + keyField.set(uploadCmd, key); + + Field passField = _class.getDeclaredField("password"); + passField.setAccessible(true); + passField.set(uploadCmd, password); + + + try { + certService.uploadSslCert(uploadCmd); + } catch (Exception e) { + assertTrue(e.getMessage().contains("No chain given and certificate not self signed")); + } + + } + + private void runUploadSslCertBadPassword() throws IOException, IllegalAccessException, NoSuchFieldException { + + String certFile = getClass().getResource("/certs/rsa_self_signed_with_pwd.crt").getFile(); + String keyFile = getClass().getResource("/certs/rsa_self_signed_with_pwd.key").getFile(); + String password = "bad_password"; + + + String cert = URLEncoder.encode(readFileToString(new File(certFile)), "UTF-8"); + String key = URLEncoder.encode(readFileToString(new File(keyFile)), "UTF-8"); + + CertServiceImpl certService = new CertServiceImpl(); + + //setting mock objects + certService._accountMgr = Mockito.mock(AccountManager.class); + Account account = new AccountVO("testaccount", 1, + "networkdomain", (short) 0, UUID.randomUUID().toString()); + when(certService._accountMgr.getAccount(anyLong())).thenReturn(account); + + certService._sslCertDao = Mockito.mock(SslCertDao.class); + when(certService._sslCertDao.persist(any(SslCertVO.class))).thenReturn(new SslCertVO()); + + //creating the command + UploadSslCertCmd uploadCmd = new UploadSslCertCmdExtn(); + Class _class = uploadCmd.getClass().getSuperclass(); + + Field certField = _class.getDeclaredField("cert"); + certField.setAccessible(true); + certField.set(uploadCmd, cert); + + Field keyField = _class.getDeclaredField("key"); + keyField.setAccessible(true); + keyField.set(uploadCmd, key); + + Field passField = _class.getDeclaredField("password"); + passField.setAccessible(true); + passField.set(uploadCmd, password); + + + try { + certService.uploadSslCert(uploadCmd); + } catch (Exception e) { + assertTrue(e.getMessage().contains("please check password and data")); + } + + } + + private void runUploadSslCertBadkeyPair() throws IOException, IllegalAccessException, NoSuchFieldException { + // Reading appropritate files + String certFile = getClass().getResource("/certs/rsa_self_signed.crt").getFile(); + String keyFile = getClass().getResource("/certs/rsa_random_pkey.key").getFile(); + + String cert = URLEncoder.encode(readFileToString(new File(certFile)), "UTF-8"); + String key = URLEncoder.encode(readFileToString(new File(keyFile)), "UTF-8"); + + CertServiceImpl certService = new CertServiceImpl(); + + //setting mock objects + certService._accountMgr = Mockito.mock(AccountManager.class); + Account account = new AccountVO("testaccount", 1, + "networkdomain", (short) 0, UUID.randomUUID().toString()); + when(certService._accountMgr.getAccount(anyLong())).thenReturn(account); + + certService._sslCertDao = Mockito.mock(SslCertDao.class); + when(certService._sslCertDao.persist(any(SslCertVO.class))).thenReturn(new SslCertVO()); + + //creating the command + UploadSslCertCmd uploadCmd = new UploadSslCertCmdExtn(); + Class _class = uploadCmd.getClass().getSuperclass(); + + Field certField = _class.getDeclaredField("cert"); + certField.setAccessible(true); + certField.set(uploadCmd, cert); + + Field keyField = _class.getDeclaredField("key"); + keyField.setAccessible(true); + keyField.set(uploadCmd, key); + + try { + certService.uploadSslCert(uploadCmd); + } catch (Exception e) { + assertTrue(e.getMessage().contains("Bad public-private key")); + } + } + + private void runUploadSslCertBadkeyAlgo() throws IOException, IllegalAccessException, NoSuchFieldException { + + // Reading appropritate files + String certFile = getClass().getResource("/certs/rsa_self_signed.crt").getFile(); + String keyFile = getClass().getResource("/certs/dsa_self_signed.key").getFile(); + + String cert = URLEncoder.encode(readFileToString(new File(certFile)), "UTF-8"); + String key = URLEncoder.encode(readFileToString(new File(keyFile)), "UTF-8"); + + CertServiceImpl certService = new CertServiceImpl(); + + //setting mock objects + certService._accountMgr = Mockito.mock(AccountManager.class); + Account account = new AccountVO("testaccount", 1, + "networkdomain", (short) 0, UUID.randomUUID().toString()); + when(certService._accountMgr.getAccount(anyLong())).thenReturn(account); + + certService._sslCertDao = Mockito.mock(SslCertDao.class); + when(certService._sslCertDao.persist(any(SslCertVO.class))).thenReturn(new SslCertVO()); + + //creating the command + UploadSslCertCmd uploadCmd = new UploadSslCertCmdExtn(); + Class _class = uploadCmd.getClass().getSuperclass(); + + Field certField = _class.getDeclaredField("cert"); + certField.setAccessible(true); + certField.set(uploadCmd, cert); + + Field keyField = _class.getDeclaredField("key"); + keyField.setAccessible(true); + keyField.set(uploadCmd, key); + + try { + certService.uploadSslCert(uploadCmd); + } catch (Exception e) { + assertTrue(e.getMessage().contains("Public and private key have different algorithms")); + } + } + + private void runUploadSslCertExpiredCert() throws IOException, IllegalAccessException, NoSuchFieldException { + + // Reading appropritate files + String certFile = getClass().getResource("/certs/expired_cert.crt").getFile(); + String keyFile = getClass().getResource("/certs/rsa_self_signed.key").getFile(); + + String cert = URLEncoder.encode(readFileToString(new File(certFile)), "UTF-8"); + String key = URLEncoder.encode(readFileToString(new File(keyFile)), "UTF-8"); + + CertServiceImpl certService = new CertServiceImpl(); + + //setting mock objects + certService._accountMgr = Mockito.mock(AccountManager.class); + Account account = new AccountVO("testaccount", 1, + "networkdomain", (short) 0, UUID.randomUUID().toString()); + when(certService._accountMgr.getAccount(anyLong())).thenReturn(account); + + certService._sslCertDao = Mockito.mock(SslCertDao.class); + when(certService._sslCertDao.persist(any(SslCertVO.class))).thenReturn(new SslCertVO()); + + //creating the command + UploadSslCertCmd uploadCmd = new UploadSslCertCmdExtn(); + Class _class = uploadCmd.getClass().getSuperclass(); + + Field certField = _class.getDeclaredField("cert"); + certField.setAccessible(true); + certField.set(uploadCmd, cert); + + Field keyField = _class.getDeclaredField("key"); + keyField.setAccessible(true); + keyField.set(uploadCmd, key); + + try { + certService.uploadSslCert(uploadCmd); + } catch (Exception e) { + assertTrue(e.getMessage().contains("Certificate expired")); + } + } + + private void runUploadSslCertNotX509() throws IOException, IllegalAccessException, NoSuchFieldException { + // Reading appropritate files + String certFile = getClass().getResource("/certs/non_x509_pem.crt").getFile(); + String keyFile = getClass().getResource("/certs/rsa_self_signed.key").getFile(); + + String cert = URLEncoder.encode(readFileToString(new File(certFile)), "UTF-8"); + String key = URLEncoder.encode(readFileToString(new File(keyFile)), "UTF-8"); + + CertServiceImpl certService = new CertServiceImpl(); + + //setting mock objects + certService._accountMgr = Mockito.mock(AccountManager.class); + Account account = new AccountVO("testaccount", 1, + "networkdomain", (short) 0, UUID.randomUUID().toString()); + when(certService._accountMgr.getAccount(anyLong())).thenReturn(account); + + certService._sslCertDao = Mockito.mock(SslCertDao.class); + when(certService._sslCertDao.persist(any(SslCertVO.class))).thenReturn(new SslCertVO()); + + //creating the command + UploadSslCertCmd uploadCmd = new UploadSslCertCmdExtn(); + Class _class = uploadCmd.getClass().getSuperclass(); + + Field certField = _class.getDeclaredField("cert"); + certField.setAccessible(true); + certField.set(uploadCmd, cert); + + Field keyField = _class.getDeclaredField("key"); + keyField.setAccessible(true); + keyField.set(uploadCmd, key); + + try { + certService.uploadSslCert(uploadCmd); + } catch (Exception e) { + assertTrue(e.getMessage().contains("Expected X509 certificate")); + } + } + + private void runUploadSslCertBadFormat() throws IOException, IllegalAccessException, NoSuchFieldException { + + // Reading appropritate files + String certFile = getClass().getResource("/certs/bad_format_cert.crt").getFile(); + String keyFile = getClass().getResource("/certs/rsa_self_signed.key").getFile(); + + String cert = URLEncoder.encode(readFileToString(new File(certFile)), "UTF-8"); + String key = URLEncoder.encode(readFileToString(new File(keyFile)), "UTF-8"); + + CertServiceImpl certService = new CertServiceImpl(); + + //setting mock objects + certService._accountMgr = Mockito.mock(AccountManager.class); + Account account = new AccountVO("testaccount", 1, + "networkdomain", (short) 0, UUID.randomUUID().toString()); + when(certService._accountMgr.getAccount(anyLong())).thenReturn(account); + + certService._sslCertDao = Mockito.mock(SslCertDao.class); + when(certService._sslCertDao.persist(any(SslCertVO.class))).thenReturn(new SslCertVO()); + + //creating the command + UploadSslCertCmd uploadCmd = new UploadSslCertCmdExtn(); + Class _class = uploadCmd.getClass().getSuperclass(); + + Field certField = _class.getDeclaredField("cert"); + certField.setAccessible(true); + certField.set(uploadCmd, cert); + + Field keyField = _class.getDeclaredField("key"); + keyField.setAccessible(true); + keyField.set(uploadCmd, key); + + try { + certService.uploadSslCert(uploadCmd); + } catch (Exception e) { + assertTrue(e.getMessage().contains("Invalid certificate format")); + } + } + + + @Test + public void testDeleteSslCert() throws Exception { + /* Test1: Delete with an invalid ID should fail */ + runDeleteSslCertInvalidId(); + + /* Test2: Delete with a cert id bound to a lb should fail */ + runDeleteSslCertBoundCert(); + + /* Test3: Delete with a valid Id should succeed */ + runDeleteSslCertValid(); + + + } + + private void runDeleteSslCertValid() throws Exception { + + TransactionLegacy txn = TransactionLegacy.open("runDeleteSslCertValid"); + + CertServiceImpl certService = new CertServiceImpl(); + long certId = 1; + + //setting mock objects + certService._accountMgr = Mockito.mock(AccountManager.class); + Account account = new AccountVO("testaccount", 1, + "networkdomain", (short) 0, UUID.randomUUID().toString()); + when(certService._accountMgr.getAccount(anyLong())).thenReturn(account); + + certService._sslCertDao = Mockito.mock(SslCertDao.class); + when(certService._sslCertDao.remove(anyLong())).thenReturn(true); + when(certService._sslCertDao.findById(anyLong())).thenReturn(new SslCertVO()); + + // a rule holding the cert + + certService._lbCertDao = Mockito.mock(LoadBalancerCertMapDao.class); + when(certService._lbCertDao.listByCertId(anyLong())).thenReturn(null); + + //creating the command + DeleteSslCertCmd deleteCmd = new DeleteSslCertCmdExtn(); + Class _class = deleteCmd.getClass().getSuperclass(); + + Field certField = _class.getDeclaredField("id"); + certField.setAccessible(true); + certField.set(deleteCmd, certId); + + certService.deleteSslCert(deleteCmd); + } + + private void runDeleteSslCertBoundCert() throws NoSuchFieldException, IllegalAccessException { + + TransactionLegacy txn = TransactionLegacy.open("runDeleteSslCertBoundCert"); + + CertServiceImpl certService = new CertServiceImpl(); + + //setting mock objects + long certId = 1; + + certService._accountMgr = Mockito.mock(AccountManager.class); + Account account = new AccountVO("testaccount", 1, + "networkdomain", (short) 0, UUID.randomUUID().toString()); + when(certService._accountMgr.getAccount(anyLong())).thenReturn(account); + + certService._sslCertDao = Mockito.mock(SslCertDao.class); + when(certService._sslCertDao.remove(anyLong())).thenReturn(true); + when(certService._sslCertDao.findById(anyLong())).thenReturn(new SslCertVO()); + + // rule holding the cert + certService._lbCertDao = Mockito.mock(LoadBalancerCertMapDao.class); + + List lbMapList = new ArrayList(); + lbMapList.add(new LoadBalancerCertMapVO()); + + certService._lbCertDao = Mockito.mock(LoadBalancerCertMapDao.class); + when(certService._lbCertDao.listByCertId(anyLong())).thenReturn(lbMapList); + + + certService._entityMgr = Mockito.mock(EntityManager.class); + when(certService._entityMgr.findById(eq(LoadBalancerVO.class), anyLong())).thenReturn(new LoadBalancerVO()); + + //creating the command + DeleteSslCertCmd deleteCmd = new DeleteSslCertCmdExtn(); + Class _class = deleteCmd.getClass().getSuperclass(); + + Field certField = _class.getDeclaredField("id"); + certField.setAccessible(true); + certField.set(deleteCmd, certId); + + try { + certService.deleteSslCert(deleteCmd); + }catch (Exception e){ + assertTrue(e.getMessage().contains("Certificate in use by a loadbalancer")); + } + + + } + + private void runDeleteSslCertInvalidId() throws NoSuchFieldException, IllegalAccessException { + + TransactionLegacy txn = TransactionLegacy.open("runDeleteSslCertInvalidId"); + + long certId = 1; + CertServiceImpl certService = new CertServiceImpl(); + + certService._accountMgr = Mockito.mock(AccountManager.class); + Account account = new AccountVO("testaccount", 1, + "networkdomain", (short) 0, UUID.randomUUID().toString()); + when(certService._accountMgr.getAccount(anyLong())).thenReturn(account); + + certService._sslCertDao = Mockito.mock(SslCertDao.class); + when(certService._sslCertDao.remove(anyLong())).thenReturn(true); + when(certService._sslCertDao.findById(anyLong())).thenReturn(null); + + // no rule holding the cert + certService._lbCertDao = Mockito.mock(LoadBalancerCertMapDao.class); + when(certService._lbCertDao.listByCertId(anyLong())).thenReturn(null); + + //creating the command + DeleteSslCertCmd deleteCmd = new DeleteSslCertCmdExtn(); + Class _class = deleteCmd.getClass().getSuperclass(); + + Field certField = _class.getDeclaredField("id"); + certField.setAccessible(true); + certField.set(deleteCmd, certId); + + try { + certService.deleteSslCert(deleteCmd); + }catch (Exception e){ + assertTrue(e.getMessage().contains("Invalid certificate id")); + } + + } + + + public class UploadSslCertCmdExtn extends UploadSslCertCmd { + @Override + public long getEntityOwnerId() { + return 1; + } + } + + public class DeleteSslCertCmdExtn extends DeleteSslCertCmd { + @Override + public long getEntityOwnerId() { + return 1; + } + } +} diff --git a/server/test/resources/certs/bad_format_cert.crt b/server/test/resources/certs/bad_format_cert.crt new file mode 100644 index 00000000000..bab377a1720 --- /dev/null +++ b/server/test/resources/certs/bad_format_cert.crt @@ -0,0 +1 @@ +BAD FORMAT CERT diff --git a/server/test/resources/certs/dsa_self_signed.crt b/server/test/resources/certs/dsa_self_signed.crt new file mode 100644 index 00000000000..9ee3dc8e5dc --- /dev/null +++ b/server/test/resources/certs/dsa_self_signed.crt @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEaDCCBBACCQDB6QTHSA74AzAJBgcqhkjOOAQDMEUxCzAJBgNVBAYTAkFVMRMw +EQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0 +eSBMdGQwHhcNMTMxMDIxMTUxMzE1WhcNMTQxMDIxMTUxMzE1WjBFMQswCQYDVQQG +EwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lk +Z2l0cyBQdHkgTHRkMIIDSDCCAjoGByqGSM44BAEwggItAoIBAQD1cLkWeTvzloom +uaHmB0ANyrmHTum6bVVMyN2V/it8BAErugqQBIaNtF2EOmJ3baxsxIROOqJ5uVx0 +pymYVr4BcS3R6H2G7lSWHa5iA/UMfVp9yHroK+WYdN5ZVKGYcUTvKZXtyr2OX3Rc +KJJ2yp4qbcQTB2GlV6eZdpX3l38G/03n/Wi5yjU2/p56R80FAaLtCr4wJoS2aXxU +Iytps+msEn0LRZuFHpW1sLIKPLRCnjFXWeWKdJu6bggUVB0GjfsZR67XzFY5nRvX +7/vW2XS5Vo4X6gSOym0O/8/vzUp1gQSwHiMQQRAoRYoZPxWo8ACMsqdj0MTbN32y +b11//OlXAiEAoR8xDStCDTaQ2Ale9swNzLB8vWFzmSLQXXOM1PY10fMCggEBAO1p +RV1kluxjYCKec12MKdTBqO2QZnOOVFsY2vpIavgqpxyGaHRwY8Cm7BGosV2chMZw +G6xMz5CRnR55KasaX1Vz2xAz7PwczXWDQA59Il5tQbQdewitm1S3NRb1n9u+cNkQ +E6ZekjdW9tRykvaNQHH8EBzgQ9KXCYzJ8nFLk2DMt2Mor/paXfobNzO/vi2UgL+B +5/E8BXoMtBFPhiz72CsCiXp/usROe/UAejow/CTHYC2mfcPhKt2jIVelXx7Baf0n +K1SWKBpNI4ucBj+/4L3Be0ldqDGmeTRUNTNpJIzmAyplUvnpOiqCbzKst57+l4ZE +xdVgv2LiIrTaqTn1L4sDggEGAAKCAQEAv0hyFYj8IMEaOCk9+6wb32NGEGoEz4re +YW1O02Kij2/0YJk0CPyg0ozIpJq9FiHvOzE+2/Eg5jLVTLlAJbjnGjSnzZJ6pJHw +zhwnJ9wT4to51jLvG1v82iL2FfFKOZFjABxC+kND9cAUXu3URIGfdYJl1rBxvOD1 +WZ03Gk90GMCLUIMqqUYBQg7XRNVf0k1AgiRgDWpdLkKOGiDntAj/unXdFrbse2xD +IbqBGhCNtPVx34CZ3bUWrvYBoj+BUinfItRK4rkZTEGJinoxbKDvdqoewgk2nSty +7CH40wFS4ni4DCvYTEwUoUuciQaU4XUOOSYFS9IjNWOR8uGBtORteTAJBgcqhkjO +OAQDA0cAMEQCIHqfrNbyMadxZ3uCPr8QPj+17XZZod8B7F8VgZW3R5vSAiAV/WMF +vQ1Dwpr4wJOjNELDe5AEH9WGvevfuc54vmdAdg== +-----END CERTIFICATE----- diff --git a/server/test/resources/certs/dsa_self_signed.key b/server/test/resources/certs/dsa_self_signed.key new file mode 100644 index 00000000000..9a9d6675d5d --- /dev/null +++ b/server/test/resources/certs/dsa_self_signed.key @@ -0,0 +1,20 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIDVwIBAAKCAQEA9XC5Fnk785aKJrmh5gdADcq5h07pum1VTMjdlf4rfAQBK7oK +kASGjbRdhDpid22sbMSETjqieblcdKcpmFa+AXEt0eh9hu5Ulh2uYgP1DH1afch6 +6CvlmHTeWVShmHFE7ymV7cq9jl90XCiSdsqeKm3EEwdhpVenmXaV95d/Bv9N5/1o +uco1Nv6eekfNBQGi7Qq+MCaEtml8VCMrabPprBJ9C0WbhR6VtbCyCjy0Qp4xV1nl +inSbum4IFFQdBo37GUeu18xWOZ0b1+/71tl0uVaOF+oEjsptDv/P781KdYEEsB4j +EEEQKEWKGT8VqPAAjLKnY9DE2zd9sm9df/zpVwIhAKEfMQ0rQg02kNgJXvbMDcyw +fL1hc5ki0F1zjNT2NdHzAoIBAQDtaUVdZJbsY2AinnNdjCnUwajtkGZzjlRbGNr6 +SGr4Kqcchmh0cGPApuwRqLFdnITGcBusTM+QkZ0eeSmrGl9Vc9sQM+z8HM11g0AO +fSJebUG0HXsIrZtUtzUW9Z/bvnDZEBOmXpI3VvbUcpL2jUBx/BAc4EPSlwmMyfJx +S5NgzLdjKK/6Wl36Gzczv74tlIC/gefxPAV6DLQRT4Ys+9grAol6f7rETnv1AHo6 +MPwkx2Atpn3D4SrdoyFXpV8ewWn9JytUligaTSOLnAY/v+C9wXtJXagxpnk0VDUz +aSSM5gMqZVL56Toqgm8yrLee/peGRMXVYL9i4iK02qk59S+LAoIBAQC/SHIViPwg +wRo4KT37rBvfY0YQagTPit5hbU7TYqKPb/RgmTQI/KDSjMikmr0WIe87MT7b8SDm +MtVMuUAluOcaNKfNknqkkfDOHCcn3BPi2jnWMu8bW/zaIvYV8Uo5kWMAHEL6Q0P1 +wBRe7dREgZ91gmXWsHG84PVZnTcaT3QYwItQgyqpRgFCDtdE1V/STUCCJGANal0u +Qo4aIOe0CP+6dd0Wtux7bEMhuoEaEI209XHfgJndtRau9gGiP4FSKd8i1EriuRlM +QYmKejFsoO92qh7CCTadK3LsIfjTAVLieLgMK9hMTBShS5yJBpThdQ45JgVL0iM1 +Y5Hy4YG05G15AiBO/b8wvyKsJJAInNbsLH7OPitH3qKsI18IxykJSl9lTw== +-----END DSA PRIVATE KEY----- diff --git a/server/test/resources/certs/expired_cert.crt b/server/test/resources/certs/expired_cert.crt new file mode 100644 index 00000000000..d133f24bb74 --- /dev/null +++ b/server/test/resources/certs/expired_cert.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDVzCCAj+gAwIBAgIJAJRInPvOqxbXMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNV +BAYTAlhYMRUwEwYDVQQHDAxEZWZhdWx0IENpdHkxHDAaBgNVBAoME0RlZmF1bHQg +Q29tcGFueSBMdGQwHhcNMTMxMDIxMjAwNjA5WhcNMTMxMDIwMjAwNjA5WjBCMQsw +CQYDVQQGEwJYWDEVMBMGA1UEBwwMRGVmYXVsdCBDaXR5MRwwGgYDVQQKDBNEZWZh +dWx0IENvbXBhbnkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +3rASFvBmAF+CHn58TU5ib0HuMD4gxutohjzQjJXYRFs1cmiLb9esO0Cvk0DFaQuq +lpxw4Dhe6kxRbNQKkPFr0zsv9B8I/o8UQmclnZ0I++ixlAq4VyP6H0sewrmdVbrV +mSH0eG1t0hLqXUmxX/XX1kkbHOgZQQk90Sew23VwTVxbywq8yjkYLa2hlBXh33rX +siky7JFiF0TJE2r6wNB60BQMdi2EErtBUPL/1LD7+VuB/Y6xZpwivKwMIXeFdzSr +I2gGCn+zf01kNfHj0YrA2bH0i5FX4/9YSpd8PFIOYc/gA+3MNO0xMWchbz6AfjPQ +aR4tGLsRBjjwvLIZwHzyWQIDAQABo1AwTjAdBgNVHQ4EFgQUo/kIdWN+yxvnWUoK +/ZJYNl2wY9cwHwYDVR0jBBgwFoAUo/kIdWN+yxvnWUoK/ZJYNl2wY9cwDAYDVR0T +BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAJ/LwjkhXQFOcfUmAoIeBIDAMayy7 +HEJusMOA+uUPPuEemgU7DTbwABCaavfBza7QvG171LsTGtvgnvwDg7rdScUOcoX8 +w0XZbhr+dZzvashVmMz4oY6hGw29eGo7M01Rm4msX7bW1IXmdWmDcqcNT6/dKOgj +tjMR2JvN9I4qwZ41xXAeUHDUqKjgsKlhflBbOX7K07tbpHFMQZcoOs19Jqve8Gfm +MbH0hZw3LC2YNed8ne/3/lXKNZIhbyZp1IJ/rjgruEZ0ObOwqB1IGR0UjQbAw102 +1D4L8FOzmDi4LfhKPgGc/BMeuPRozxQi60TzrnXN5eQSb0ukFvScMhAIrQ== +-----END CERTIFICATE----- diff --git a/server/test/resources/certs/non_x509_pem.crt b/server/test/resources/certs/non_x509_pem.crt new file mode 100644 index 00000000000..fbbae8ed75f --- /dev/null +++ b/server/test/resources/certs/non_x509_pem.crt @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICtzCCAZ8CAQAwcjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx +ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDENMAsGA1UEAwwEU3ll +ZDEcMBoGCSqGSIb3DQEJARYNc3llZEB0ZXN0LmNvbTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAKmQeRXpkeGRhzdj3aJiWUcZtKdcjPCdtphx8gHk1GV1 +vHK2zYenwe23EbSsfkOAQx2p86jCpghN7b+ECilmou4C7ASPS2U8n+GhWdl4eUK4 +Gmz7+daRqcDQOCTCJWSybtShYzvfp2SaEt/TcUgDT+k6xRitqcIkAY7boGY1Cehy +O6hYdlFkg0oU1XCA0usIaSEi7gOTijpGe2jSh7CTBRRWiClQnqE8VT7x4hXQEDF6 +u26K/ptAL90bgyFUuX2dEH5dKd/5QAyAfdrLV6a3wIvikCUGZy23Twtxot4kFVYf +S2x3H9BS6j/mIvrUj95CLi2Eu6t4z5uHMOrf8k0NjN8CAwEAAaAAMA0GCSqGSIb3 +DQEBBQUAA4IBAQBa5B6xzAkx3OtJEgOkTJ0nID2TsTt6eQBrp+//jhT/9yKLHmd5 +SeNcLzMWDlTQ+zNlLf9+lreO+CmlolaOKDRXh9eXbyNq0/I2QxOEsIlXqH4dVoCB +6UkV8eA0lFeNdFJaCla5/QTKmv4f0eUakbI5Scd1PlBr+YOplvI9fpLaxHGmVzCX +s3WQ7m7SN5hZav7dO8krheZL7N3AYZoCY0QbQ3JTeoakLenmFXqvsckP6in5NQJh +ECaJprYxrxR+5GPjpUkxu7YGLloXHvnnINeZGJG0TB7kPDO+axDxloiI2eYlT/mp +HxdgL9BvDYNfI+0NcZYHguz8GWuWiTZC7F26 +-----END CERTIFICATE REQUEST----- diff --git a/server/test/resources/certs/root_chain.crt b/server/test/resources/certs/root_chain.crt new file mode 100644 index 00000000000..2ed80858532 --- /dev/null +++ b/server/test/resources/certs/root_chain.crt @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDnTCCAoWgAwIBAgIJALXV1B5/vewgMA0GCSqGSIb3DQEBBQUAMGUxCzAJBgNV +BAYTAkFVMQ0wCwYDVQQIDARTb21lMQwwCgYDVQQKDANPcmcxDDAKBgNVBAsMA0Rl +djENMAsGA1UEAwwETmFtZTEcMBoGCSqGSIb3DQEJARYNdGVzdEBtYWlsLmNvbTAe +Fw0xMzEwMjExNjAxMDdaFw0xNjEwMjAxNjAxMDdaMGUxCzAJBgNVBAYTAkFVMQ0w +CwYDVQQIDARTb21lMQwwCgYDVQQKDANPcmcxDDAKBgNVBAsMA0RldjENMAsGA1UE +AwwETmFtZTEcMBoGCSqGSIb3DQEJARYNdGVzdEBtYWlsLmNvbTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBALQZLQa2R64GRCuoh59VFvKoXnAM+4H4sW9E +jiURT/CeH6rbD0IbEMZZ3o84VfQw1zDsVXN/GXq3IEMp8uBBpWJuZRBF1UeDMYlB +bouMqUGL05Ov51zK2aQK/83S8MoQI7KV1FGJNti4iwUzemG1fClrBqjCFJQKmv8y +0z1UaeniAR7ygedIB4I2Y4a/DxtI0e2EsS0TcViwKHGrLArO0GfvNbH+tXqTaotF +X5eyinUFqQxT3JvnlIIernk0ly8c07mqOFbFqHrhFXxddD4pZrUetHXM2MKLdCMu +fvXsmMXSAgQ5F97GWmiDEJ9zMDxGoSmhTIN96FwPCRDr7e22lEsCAwEAAaNQME4w +HQYDVR0OBBYEFIxSziB7ssNqFvhV2MSf1GYvGHQYMB8GA1UdIwQYMBaAFIxSziB7 +ssNqFvhV2MSf1GYvGHQYMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB +AB1rcxZL6xGuk8PSoBQ0imREcVf9BcEvGIC6uubPSXuoJ/gr584vo3pRJpTpHQyK +xUUwG6gCaDgAMYX177GBamGCt056ThSLKFROIPVrigZ5yY1NWznNq3zjWS4jIHkV +vGd+Gx8t3qYBhsn+v6Y6gRTjMOVQum+rvxvixG7n97DaxBnrwNWXbzZQ9spHrQsT +dsSF/kf9NKkWM0zKh+f/FSNmveJKKvZ+WQZC/MKUfc5VHjyLldXhrffcxzek/dOc +8YADSICSizvXCP/QjyVVl8dpKr/3c00r16Ei3QQaFhHES0bv/sKLnTwQwKDfJthu +bQj7M/XGWi33JQgoMHktYhI= +-----END CERTIFICATE----- diff --git a/server/test/resources/certs/rsa_ca_signed.crt b/server/test/resources/certs/rsa_ca_signed.crt new file mode 100644 index 00000000000..fb74f17574b --- /dev/null +++ b/server/test/resources/certs/rsa_ca_signed.crt @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID1TCCAr2gAwIBAgIJALXV1B5/vewhMA0GCSqGSIb3DQEBBQUAMGUxCzAJBgNV +BAYTAkFVMQ0wCwYDVQQIDARTb21lMQwwCgYDVQQKDANPcmcxDDAKBgNVBAsMA0Rl +djENMAsGA1UEAwwETmFtZTEcMBoGCSqGSIb3DQEJARYNdGVzdEBtYWlsLmNvbTAe +Fw0xMzEwMjExNjE4MjJaFw0xNDEwMjExNjE4MjJaMHIxCzAJBgNVBAYTAkFVMRMw +EQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0 +eSBMdGQxDTALBgNVBAMMBFN5ZWQxHDAaBgkqhkiG9w0BCQEWDXN5ZWRAdGVzdC5j +b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpkHkV6ZHhkYc3Y92i +YllHGbSnXIzwnbaYcfIB5NRldbxyts2Hp8HttxG0rH5DgEMdqfOowqYITe2/hAop +ZqLuAuwEj0tlPJ/hoVnZeHlCuBps+/nWkanA0DgkwiVksm7UoWM736dkmhLf03FI +A0/pOsUYranCJAGO26BmNQnocjuoWHZRZINKFNVwgNLrCGkhIu4Dk4o6Rnto0oew +kwUUVogpUJ6hPFU+8eIV0BAxertuiv6bQC/dG4MhVLl9nRB+XSnf+UAMgH3ay1em +t8CL4pAlBmctt08LcaLeJBVWH0tsdx/QUuo/5iL61I/eQi4thLureM+bhzDq3/JN +DYzfAgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wg +R2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBR2LIRfVveDgQB3dC7TOYhX +BEv71DAfBgNVHSMEGDAWgBSMUs4ge7LDahb4VdjEn9RmLxh0GDANBgkqhkiG9w0B +AQUFAAOCAQEAPjN/sdLcPfMh5ep29vp/7JTh6dUYnBNATYaXxx8j2XdnMCKeRfgP +WOJur8HDPSayWWKKlztiQbJV5jDS5vyuMWI1a5/KIAQlOJep+anpR1QnQaX4/M4Z +YUJo1fPs6tg47dXRpZZaJ+Hqwh0ZftCQoUq/sBxawXf6sbxsjoUmzxQLBqzYo1LJ +jwxBs6C9aM8LDHFz4TVlyclSFQXiLMosj1jLBQ+TqzCxS6qOfJeMM9STXI9W3F2k +duXeceqOwEkh8aeSUIztYFpX34d4SA4DDX5GUEaOeOR/abnXjH52vE6tM/m7NOve +5+I/BrlT3heRqiD6Z2ofSsFhG86YeF9Q3w== +-----END CERTIFICATE----- diff --git a/server/test/resources/certs/rsa_ca_signed.key b/server/test/resources/certs/rsa_ca_signed.key new file mode 100644 index 00000000000..d30dd8e8e99 --- /dev/null +++ b/server/test/resources/certs/rsa_ca_signed.key @@ -0,0 +1,30 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIN4x8YHLIb60CAggA +MBQGCCqGSIb3DQMHBAiuWe+C2SitUgSCBMhVxMKivNaQh9SQedh2GQ8vlhI2/mKf +r6zVUgODOdmFRj/PAlQu6B+VH8u2Ef5tr74O9UyZUQpC6oI0npvQOGqnhIxECR8D +zepFlC0s+6kNRqfzXiMhGTsfbs3xUE1TZK1z5556OS4GlihIB0E5F7GdlulHELeA +dnEItqDffWPQczTmSmFqtH7G/ksGQhSA2reBIDNgxWreBh9x9h2TftEvhhogdkr2 +XQpzxcby2v2z6Hut1lfVkLQNdvdHYdDG751NQltOmGvncXkTNJ+tSByXuY9ITtYz +XqwY/vAEX+YYjCrWcvMmhU1t6B9cZ3viFzIIIltqtvDo3rybicpM3xvmnYnTF35j +sGebcynzZedrLUHwD6/o0jBzFJN26QBxDGrlmn9E8HBhmjMCeSyZTXtSkwN0dAhu +EHT2NgdC/4G4+JHsb3Oetl6AbUyYs2eWTRgr6bgBezbiDqKMj1QtGECkPQE9tFFP +Jtma6lGJ1/u8zLFYNjigKZgXaNbtlMpslk+KDTGaTSbbVEaaxWSc0YlHz329ovQC +1btrTE71FoNjRsTRaDRXC7BfrrMtnLhG2SmROKzyBtoxFymfEmASpdGERO+c2712 +Z0NLpHJL5ocsRr/onVi0auFC/nuaq6QqYF5OPtZhYh3+IDd193LP3xo8hnFjTq90 +9zV1QI2uHfTfijI4OABYSSZLxrl2IFF7Z/e4XkWSXrneR2Ne5GoYX7w6wshiuubQ +bDPUHODsy7uQJ3ZEmmmd5xWvA3h3F5Yyls3WEuz8+jYR4iPKdjt8DJuz9j+7IP3C +LoRa3KhxIPAzziQw+tMFVCozLLfS1kN8mg5SwU9Dp4HUPY/n3KnjVSjUJ347KAgW ++ykPlz4S1H0A2GyGWhdyX3J839UOdXfCsfKQQ1FLOBvhQgBNGzoRIgDrsZdrxgWa +XtF+Ct2/2/O+503I6X90maXzhshmGw/NKsiNx7YOdUiu6w3N4LajIWE689UUU7Dr +EtM8HcfmBnE/cZTbeWbQBfl1GqigMp+YOAY2sw0rZdF4ocmnqoCWLVN2j8O/re5g +20y5eHkztPOZ+NNczo5PP96ng1XEMVzs/h6xDHzsak6osZb5b+Hs9kcYuqBEqr16 +3DVwaZ45dGwNN90Q9YmrgEdCqtCAU12w/YYVB/aB701Ijg0NhVsh7PgWaJIOJD56 +YTaiWIzQaZ/uM0KlgLz2eI9VXcuv24gUMAUMaI84mInnIrax1zFMrlCjEcR8Zxvk +jCCY6Uq9WH30cUo7cMHWLWMzsl7PC7xpYSHPClqzCUluUgQwqoOs5Ux4nYl+JI7C +ZfJ8BUMCD2RJtjvJhkE6LEkcrCjwnvappRaXbN54IVXpuMl2XYtp44T117QulEj1 +I/jk1mrpkXRKi9ZsKsjDH9VMy1hcKHn4CgTxmtRYN6LPA4tamxzVLxIi6YDU0142 +l1u763cT7cH14lvzUvEQMFbk/s0AUl8zeZAwjDayNlD/ljz7nZnJ3NToMlxeoK0a +F6c/RgQBwxR8NMdo19Irv8stxo9WGB2/0Q8WCxW7ENHlBpvX5zXKRJMswFKp0ft6 +dT7hOBPgJlD7C1eX5jVcSz6kDRM6gQ7K/c5QcJa6qNAC2Jw6yBBYltqiRalFWX46 +VcM= +-----END ENCRYPTED PRIVATE KEY----- diff --git a/server/test/resources/certs/rsa_ca_signed2.crt b/server/test/resources/certs/rsa_ca_signed2.crt new file mode 100644 index 00000000000..fb74f17574b --- /dev/null +++ b/server/test/resources/certs/rsa_ca_signed2.crt @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIID1TCCAr2gAwIBAgIJALXV1B5/vewhMA0GCSqGSIb3DQEBBQUAMGUxCzAJBgNV +BAYTAkFVMQ0wCwYDVQQIDARTb21lMQwwCgYDVQQKDANPcmcxDDAKBgNVBAsMA0Rl +djENMAsGA1UEAwwETmFtZTEcMBoGCSqGSIb3DQEJARYNdGVzdEBtYWlsLmNvbTAe +Fw0xMzEwMjExNjE4MjJaFw0xNDEwMjExNjE4MjJaMHIxCzAJBgNVBAYTAkFVMRMw +EQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0 +eSBMdGQxDTALBgNVBAMMBFN5ZWQxHDAaBgkqhkiG9w0BCQEWDXN5ZWRAdGVzdC5j +b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpkHkV6ZHhkYc3Y92i +YllHGbSnXIzwnbaYcfIB5NRldbxyts2Hp8HttxG0rH5DgEMdqfOowqYITe2/hAop +ZqLuAuwEj0tlPJ/hoVnZeHlCuBps+/nWkanA0DgkwiVksm7UoWM736dkmhLf03FI +A0/pOsUYranCJAGO26BmNQnocjuoWHZRZINKFNVwgNLrCGkhIu4Dk4o6Rnto0oew +kwUUVogpUJ6hPFU+8eIV0BAxertuiv6bQC/dG4MhVLl9nRB+XSnf+UAMgH3ay1em +t8CL4pAlBmctt08LcaLeJBVWH0tsdx/QUuo/5iL61I/eQi4thLureM+bhzDq3/JN +DYzfAgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wg +R2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBR2LIRfVveDgQB3dC7TOYhX +BEv71DAfBgNVHSMEGDAWgBSMUs4ge7LDahb4VdjEn9RmLxh0GDANBgkqhkiG9w0B +AQUFAAOCAQEAPjN/sdLcPfMh5ep29vp/7JTh6dUYnBNATYaXxx8j2XdnMCKeRfgP +WOJur8HDPSayWWKKlztiQbJV5jDS5vyuMWI1a5/KIAQlOJep+anpR1QnQaX4/M4Z +YUJo1fPs6tg47dXRpZZaJ+Hqwh0ZftCQoUq/sBxawXf6sbxsjoUmzxQLBqzYo1LJ +jwxBs6C9aM8LDHFz4TVlyclSFQXiLMosj1jLBQ+TqzCxS6qOfJeMM9STXI9W3F2k +duXeceqOwEkh8aeSUIztYFpX34d4SA4DDX5GUEaOeOR/abnXjH52vE6tM/m7NOve +5+I/BrlT3heRqiD6Z2ofSsFhG86YeF9Q3w== +-----END CERTIFICATE----- diff --git a/server/test/resources/certs/rsa_ca_signed2.key b/server/test/resources/certs/rsa_ca_signed2.key new file mode 100644 index 00000000000..d30dd8e8e99 --- /dev/null +++ b/server/test/resources/certs/rsa_ca_signed2.key @@ -0,0 +1,30 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIN4x8YHLIb60CAggA +MBQGCCqGSIb3DQMHBAiuWe+C2SitUgSCBMhVxMKivNaQh9SQedh2GQ8vlhI2/mKf +r6zVUgODOdmFRj/PAlQu6B+VH8u2Ef5tr74O9UyZUQpC6oI0npvQOGqnhIxECR8D +zepFlC0s+6kNRqfzXiMhGTsfbs3xUE1TZK1z5556OS4GlihIB0E5F7GdlulHELeA +dnEItqDffWPQczTmSmFqtH7G/ksGQhSA2reBIDNgxWreBh9x9h2TftEvhhogdkr2 +XQpzxcby2v2z6Hut1lfVkLQNdvdHYdDG751NQltOmGvncXkTNJ+tSByXuY9ITtYz +XqwY/vAEX+YYjCrWcvMmhU1t6B9cZ3viFzIIIltqtvDo3rybicpM3xvmnYnTF35j +sGebcynzZedrLUHwD6/o0jBzFJN26QBxDGrlmn9E8HBhmjMCeSyZTXtSkwN0dAhu +EHT2NgdC/4G4+JHsb3Oetl6AbUyYs2eWTRgr6bgBezbiDqKMj1QtGECkPQE9tFFP +Jtma6lGJ1/u8zLFYNjigKZgXaNbtlMpslk+KDTGaTSbbVEaaxWSc0YlHz329ovQC +1btrTE71FoNjRsTRaDRXC7BfrrMtnLhG2SmROKzyBtoxFymfEmASpdGERO+c2712 +Z0NLpHJL5ocsRr/onVi0auFC/nuaq6QqYF5OPtZhYh3+IDd193LP3xo8hnFjTq90 +9zV1QI2uHfTfijI4OABYSSZLxrl2IFF7Z/e4XkWSXrneR2Ne5GoYX7w6wshiuubQ +bDPUHODsy7uQJ3ZEmmmd5xWvA3h3F5Yyls3WEuz8+jYR4iPKdjt8DJuz9j+7IP3C +LoRa3KhxIPAzziQw+tMFVCozLLfS1kN8mg5SwU9Dp4HUPY/n3KnjVSjUJ347KAgW ++ykPlz4S1H0A2GyGWhdyX3J839UOdXfCsfKQQ1FLOBvhQgBNGzoRIgDrsZdrxgWa +XtF+Ct2/2/O+503I6X90maXzhshmGw/NKsiNx7YOdUiu6w3N4LajIWE689UUU7Dr +EtM8HcfmBnE/cZTbeWbQBfl1GqigMp+YOAY2sw0rZdF4ocmnqoCWLVN2j8O/re5g +20y5eHkztPOZ+NNczo5PP96ng1XEMVzs/h6xDHzsak6osZb5b+Hs9kcYuqBEqr16 +3DVwaZ45dGwNN90Q9YmrgEdCqtCAU12w/YYVB/aB701Ijg0NhVsh7PgWaJIOJD56 +YTaiWIzQaZ/uM0KlgLz2eI9VXcuv24gUMAUMaI84mInnIrax1zFMrlCjEcR8Zxvk +jCCY6Uq9WH30cUo7cMHWLWMzsl7PC7xpYSHPClqzCUluUgQwqoOs5Ux4nYl+JI7C +ZfJ8BUMCD2RJtjvJhkE6LEkcrCjwnvappRaXbN54IVXpuMl2XYtp44T117QulEj1 +I/jk1mrpkXRKi9ZsKsjDH9VMy1hcKHn4CgTxmtRYN6LPA4tamxzVLxIi6YDU0142 +l1u763cT7cH14lvzUvEQMFbk/s0AUl8zeZAwjDayNlD/ljz7nZnJ3NToMlxeoK0a +F6c/RgQBwxR8NMdo19Irv8stxo9WGB2/0Q8WCxW7ENHlBpvX5zXKRJMswFKp0ft6 +dT7hOBPgJlD7C1eX5jVcSz6kDRM6gQ7K/c5QcJa6qNAC2Jw6yBBYltqiRalFWX46 +VcM= +-----END ENCRYPTED PRIVATE KEY----- diff --git a/server/test/resources/certs/rsa_random_pkey.key b/server/test/resources/certs/rsa_random_pkey.key new file mode 100644 index 00000000000..8c29b3e20de --- /dev/null +++ b/server/test/resources/certs/rsa_random_pkey.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQD2ZYOSvqPjro7k +JKWggB0FJL45mz3pfvBR0NcHTGgHKdh5hml1GiHHPanYnWqRuKFI7UPWLq3xllvJ +jolMjX6FGzPFuh4wHQ3gHMFlmpi6o1gUkk5QxAeCWmsA77qJAAiLVbm27sqfpvSG +ec6KJOcePDDN/6Jp363Gf8JuSssafg6fAbfwLp7Cm1cxFM3RKN13fUdy50+OcXv7 +uvUlzHZ2ZIVK7FnlFoXOfhFHoyfdZL2Qm8xV3SuUllNPGl7aCM59Y6xR743Rq01j +3E6hHNZ82GlJGaOL413oVsp5J9ZmKV+WM7plFIn86p2JGMoA2xjtON+X6BZdz3YT +ymp7ic+7AgMBAAECggEBAKvkNd3x0TPNWzIdvs4xkg08jNhzTMXQIKdzIg+dZhVZ +RAPDmV5wVJBCnHLZnrb6LspJe8G33vFjC7WZEn+tVk5Vo9CU/uph2oQ2i1TufQ33 +VkNDrg76MqLloTCODXv14gASVfUgsYqfVodaApStGe8l3oZXiF6EBR8tkd6PnxFi +8TPAalFS/0mfjj/dA9zHXoZ0iyl+h6had6kqJNNbP8zgD+TbnfJZVkURNB0cyGVI +8/8d/eO05oQ1DpuvTJ+Q5i8wTDjikUzc4btt6coA/ho4QuOvfsZGsgCzCYsUn0+W +GA+Vn2PVEFV5hJ+MZ9gGmQ5ouC/IVAYkBBC7HlNX70ECgYEA+3DC6rTvXqdrjZz1 +TFWcITfAt7WzfGlHi2LBZ/JNmyIetXmF/sHpqGKkvp7iHDMJ4NeEBXSN9tbbEfhc +1yU+HXYlKkeaZAGaNiCSvqlr/Bouy7dX3jG8xgPGQ1o2gyluaoTEwORf2LgmApYA +q/eQyWTKHLxatTnjlqLULerxqv8CgYEA+t1Wa00XHHgB1D4was59qnpPemIUxpvm +4e3wjyQs6P2kH0F0rKyytQaSXKhkBYRcmh0EnyNSGu7wxM5l3aDTzCDgBHmb1i9P +UXLzWUYnsSgUpUB8jL6YDlUmQ1AMMDqvLagLlOLqPkRmNjN1P4/+6mdoxD5SL0rv +5FeRaOAGR0UCgYEAjWEgGDzYg058CUqCGwPgIEVrFWETpRbFZbiHq1zxChOrVLsZ +/t8l9MpSe+R2mwiPu18zGqYo1OyGjZorCcYlIQe3agiM5UKJZXn3SUGWOFC4k09q +FsO8s1KX/nMRR7raHQa+Yv+GbSNOLBIQGqG/RZ5ojrPSBSihsaeoypDahh0CgYEA ++OK3ZmVpVHlLd0LrzktnKceHKqg8bH8oJWZnj9wYIl/igI/0LYx5EFigxQTblw2m +wc+gUjI8tzPv85HCRovVFWRYXJg6H9l4HBqrjBqqLnzRXtIHv6soOLAJ8iZssTzH +p8hdFS27sGMz9PpAjPtTsUM/EdOyvfDe5/Bo91+rWvECgYEAxgvptntWbXc8QI9n +DFYGigeza0sQTmFtSsob5cux9dtPORChdb6EPNTgOPOfKD4QMkmar/VWedeXOHb9 +Cy1Qz7bgOhIUSMdXzw4hPOmLrT7IbhG5CHawwHanGycrQ/bJcV00lsv0BEj3N/NJ +PW/vxADWc9H3AcVeMi5So6gTBt4= +-----END PRIVATE KEY----- diff --git a/server/test/resources/certs/rsa_self_signed.crt b/server/test/resources/certs/rsa_self_signed.crt new file mode 100644 index 00000000000..710326ef8e5 --- /dev/null +++ b/server/test/resources/certs/rsa_self_signed.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDBjCCAe4CCQCEkqahWR0hjjANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB +VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMB4XDTEzMTAyMTEzNTIyMFoXDTE0MTAyMTEzNTIyMFowRTELMAkG +A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 +IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AN6wEhbwZgBfgh5+fE1OYm9B7jA+IMbraIY80IyV2ERbNXJoi2/XrDtAr5NAxWkL +qpaccOA4XupMUWzUCpDxa9M7L/QfCP6PFEJnJZ2dCPvosZQKuFcj+h9LHsK5nVW6 +1Zkh9HhtbdIS6l1JsV/119ZJGxzoGUEJPdEnsNt1cE1cW8sKvMo5GC2toZQV4d96 +17IpMuyRYhdEyRNq+sDQetAUDHYthBK7QVDy/9Sw+/lbgf2OsWacIrysDCF3hXc0 +qyNoBgp/s39NZDXx49GKwNmx9IuRV+P/WEqXfDxSDmHP4APtzDTtMTFnIW8+gH4z +0GkeLRi7EQY48LyyGcB88lkCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAlgx04bvU +/EE5z7lJsYmUM2oi8FjqZcZkD4F1ku7zvdAXaDNhOHjrR5LxGL+iI/N9S8lKVeSV +xZv+EXAT0NqkTidNFjvP7coctDrrM+JHSNTRlr2GnnYjCnjEph4+ZXNppx8vnhXe +7jDnHoXL/C5GIPOm0+LQaH1AlGTPF0lnBrtQaz1UG34vCr8SSUtRbTDDxH/liXfc +hfvVnf4OV5Duj0oUXsmB3YzITYZnZ/xvZ4Dw6rOU/U5Vetng+msOOt8momeTCnWB +/d1clA7rulJTCNZXb0YyaUNaC6eQX7S9JHnluB67b9yp4yg8f00qz4xR165eTQmq +mLiuE/U5fTODvA== +-----END CERTIFICATE----- diff --git a/server/test/resources/certs/rsa_self_signed.key b/server/test/resources/certs/rsa_self_signed.key new file mode 100644 index 00000000000..14b95e6ea1f --- /dev/null +++ b/server/test/resources/certs/rsa_self_signed.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA3rASFvBmAF+CHn58TU5ib0HuMD4gxutohjzQjJXYRFs1cmiL +b9esO0Cvk0DFaQuqlpxw4Dhe6kxRbNQKkPFr0zsv9B8I/o8UQmclnZ0I++ixlAq4 +VyP6H0sewrmdVbrVmSH0eG1t0hLqXUmxX/XX1kkbHOgZQQk90Sew23VwTVxbywq8 +yjkYLa2hlBXh33rXsiky7JFiF0TJE2r6wNB60BQMdi2EErtBUPL/1LD7+VuB/Y6x +ZpwivKwMIXeFdzSrI2gGCn+zf01kNfHj0YrA2bH0i5FX4/9YSpd8PFIOYc/gA+3M +NO0xMWchbz6AfjPQaR4tGLsRBjjwvLIZwHzyWQIDAQABAoIBAFBYus4oAsWTsEEM +ZhEGfSGjaith3zWmblowyxZOYm+XcRtMeTLrYCso1bCNqCyUlwIsg9WCwUxMKPzZ +LM7LLJpUOqMcJ4ShXy/uQ3Yw2LL7bEb77zMRugdcdUbQ7eGmvba4t5pT8VHgnUr3 +cdYrv6qDShMN8z6x9OnoJjmoj9J5Ggda6DhsXsvl5Ox85XMOJKd9yyaUfa/qy8b6 +wIyixGQ/9l/GwGONgtrF7yKW3YUE+uhoEp4pqgKsGUIke3l7aWug6dCDjKDMdbX5 +jwSSiw2ilTpQJhi1r8JIMOfMea3addf39VySK7e6cSWhsf1VTVwneJbka13xS6uR +SSdvs7kCgYEA9ynOXh/1+VkpCHJBAPWEIUtPn16KGJB6YEsEf7cfaAQfzQCwJ8E4 +I7/WsHveHXs80HLS/ZJQlIXXsdeMiWdu1rnsQiVBZMmSNOpOD8iP/6mv8eqeeNr+ +3e3JG+j+l3w+/RzX516WC5JPMIsNSIzSlyx8Yht4IYA2uvpJcLdMW2MCgYEA5qY/ +xht6UlbLevGzFFFnM5R9LWSs+Ip88HCBmEwbow7FQTc0TXYbOKxGtPqn88dM91XT +NMpPaGenuioRz+P1sbEFOP/iE4Hyob8643NMkAiwwoxzSf2Bsj+ebJ/U7oC0xKYx +yjLeFWINhDy+I3LDLEXTTfv5GNrFlitqBEA+ThMCgYEAmOrJnhyCD4JlS698nj5I +QF0a5wwTvnzs6dSf9PB0QuOCVVBerEn0FNIk3s3UL0NG7eSMu4uhxTJFr+cfMQfI +YJtpG8d2/QdlKM3p/APna5Mtoyu4XieH1gC/E0CE+25IfksxHRm9FW2xBuSRFFjk +FdnVHtHF8lwkAGzHsTAG0ucCgYEAigFdVT7psMyoEZb+7KBMXKtzPq7nZAsQ+JiI +okSfoK/czMmoLNUHMqC56d20koNkhPVAW2zVmIW08QntAHPIdZqSomlQrxVoxOjz +5lX9sIzSnoWFEfdyG+I++4Wi1VYDU0qRrgdDpI23wrDJn9Ix/5KD/TxP7lQwN0sg +swxxeysCgYBBXGBBJR7+AbreFpOHitw0h32Qdmy6zHTEF8e0SjmEgDv3uwGDdsYO +QQ7g9QPPPUsYtl0+mUmCwDrw1sJeVFtp86AQlQMV89pR2yXZLf0xwT7IN6RAH5Bi +WlV2/pmiMuWB1qSUKgdPzVEd6aqtjD0TIjtryDBHp76YHJR6SzdCCA== +-----END RSA PRIVATE KEY----- diff --git a/server/test/resources/certs/rsa_self_signed_with_pwd.crt b/server/test/resources/certs/rsa_self_signed_with_pwd.crt new file mode 100644 index 00000000000..de5e5c9ac0b --- /dev/null +++ b/server/test/resources/certs/rsa_self_signed_with_pwd.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDBjCCAe4CCQD5Q6qF5dVV0jANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB +VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMB4XDTEzMTAyMTEzNTgwNFoXDTE0MTAyMTEzNTgwNFowRTELMAkG +A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 +IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AN/7lJtiEs68IC1ZPxY9NA34z9T4AU4LPS/kbQtuxx4X72XOBy+y0cB/qdMD7JNV +h8Mq4URDljhSDyVPdH/+jQr+7kWx2gNe2R/DCnd/meVwwU30JJvpGVZXt+MTef5N +QAbSfDMsuT4FaUY80InbDd24HelrjwunPdY9wwKXO6zL2fLjyDRediiydxcx18Vb +Dq1cm7DRi4mNkmA3RwBQMhxGp3VsfXJ4Hy2WTRCCCxWHZphAh3EUJGK3idum6/7j +HbAwpM/t1kNWN8PZiYDZ1HbccgjmqB7Cub10BfB9g1RByiQ/C87o5cKtQha3uuXR +iBcHISoDydQrgxKgUpiqEF0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEASvulIaVb +zh8z2TysE6RFoYTAYIRXghFrmqCUyyQmUVTvs6vN8iaSXr+WMQJcpgXewWcFrDhr +mIcyRCvF91ZYb7q6lMZFSpE6u/SUGIEtxGUDAfbkbQdKYmrMcbggUUIvSzgUFisO +Kr0H9PEO4AWtCCrtOJFc7jgu03Sv06wDxn9ghkyiBRnVkbAhoKfKnI179yKruJWR +A3ieEj0eFoUbeSH8hDkToj4ynpkAvEGoHjHG9j+8FJxy/PTjkyVPl1ykTs+2Jc1B +Snx8f2afdTenPWyyBm3wFuRZjEAJJLUO0kxM7E8hAwhGsr+XYanwcr1oA1dz6M3f +cq26lpjTH5ITwQ== +-----END CERTIFICATE----- diff --git a/server/test/resources/certs/rsa_self_signed_with_pwd.key b/server/test/resources/certs/rsa_self_signed_with_pwd.key new file mode 100644 index 00000000000..d645a716632 --- /dev/null +++ b/server/test/resources/certs/rsa_self_signed_with_pwd.key @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,CCA6E4CB4C4039DD + +TaVCJtB0dE9xTZbX7GOaGJwwGHVAMjU1GbRIHf0jODdP+quZvbjklNqsw8Ozlia9 +q/G+UqtRJGlIPPLpce0YCrTo0P3eixZdMs0+hioAEJ4OLtL0SAC6b8q/gB6HRfAx +BvNg+umTqeF9YB68Tcuv/2g4VGKiaePQACyOzMdf7lGY7ojxoJCYZa1mfKb7jWrg +FLwmTtLLhNjb6CnOKo3klIef3A6zdutpgxF1gARzdRyXg4qCA3boYnwEptTOlJFu +ovxbhDG9iuYYr4gXYSs1pLYptEC8J6iWpG/qzkwfr4l5Cfg5uF00bbxQE5+WeRaj +YFicvXjB/kcoFZuCL7M/YRXYxkJ/EZ19xI9HZNBQ4L738StkSBKL4OhpF/qgYZ2y +ZLRV6XT4AijUA0Ef7YTuUsTL7Qt9drj09gCtAzXTA7gpZBn5SqT9kWhuwSzY302l +KF8DIC6A52igk2QKPLbleM/V8eCu6n+J4uF+0GwVRROuG7ThxAQiUlJKhoEYrndL +nzT7jHVLftjilhVWFu2On62bRf5t1QZuob+1AdK0ukvEIVsYnN4bnlAkc99Wi6C0 +ZJd9qW5L4A9XAC2gcjr3m0Rzw3RO+k17faR8YfmTuJvGyBf5fnrSFoNkrninXQXp +sk0ajRi4PJ4XTswLyxjWRSt3egNsZBSKnVCibca/QoDEdZHSKXo2FlYiUYx8JHQX +SPUsLl9OQKC1W8/+ReryqBLHCkiGEsvT8gVaXga0uhVaqe+PaVur2tbOHl4yCysC ++ZlnKwsC84LQsUvpENdCh+D7E1I1Rao9IJMR6q9azKq8Ck63cOJ1fA9xSnxJGoCA +IlGLttlXrR32EtzYwEnlqf1nI/IqNQrAXQKrP5VPzHsgMFu5uD4OEZa92Q5cVTsz +ap/1UEqiJVYUt6nuA+aqOUlyjC0oNtYL/VO4DbHTFcHa8SI2cPSS6ebPMWPGHjUm +l9bWa6Q9iyplCYS6hinAVsAaLVjPi1Eu9Pc8rxFCmoiJYJju5NZuGI5UBK64dqcX +T6trWl0kB8QY63JtnrZaoStoSPImV5KVseUKDV8TM3Y76h1nLV3MSmAD1ivk9oKs +VKeVrDhZBWUq9Dqre/+lVGO0a2wo5VTR8hfpf8QkODPLeyNZNdfGKzkkFLuXa8V5 +ELhLQJ3FnbEU3NEvMwikV9MhP/ELPTkZwJr/NKv+9JLs9eXtwz29I/Q8byQVrCCs +hAuDl0zHGRnqdpdSImeS2EXGx631zGMwSe8fhKelni5h6hXrXz52asr0k30BxWjf +WUn1uTInwVjWGy9B5j3mZlVDotFbvVAZgtR0IoFwihPl4VZd9oS13l+hMfrTy1YZ +8xFNg8ZqUQ0lSmKfOVqSBT0lP8tM8LuGxgY4cWluhsAQxR5Nl7wkundnqjcwEDDu +Jz2rD54St1EZYGLDJZSfC7mpG2PgodsdeopQCTyFhHWa8s3caZ40GFOwaR+/5+YF +1oRvkR1Yr4qIS7KbX4xsaFfAA5b8QfLA74L05PAgDwKofam2GFAlAKHOcI6mexPq +aySON9MNdnXBNxs16mBJLzCX5ljQb0ilJildVEI3aVmABptM4ehEiw== +-----END RSA PRIVATE KEY----- diff --git a/setup/db/db/schema-421to430.sql b/setup/db/db/schema-421to430.sql index 7bacefe31b0..53cd0bf594f 100644 --- a/setup/db/db/schema-421to430.sql +++ b/setup/db/db/schema-421to430.sql @@ -41,6 +41,8 @@ ALTER TABLE `cloud`.`vm_instance` ADD COLUMN `power_state_update_count` INT DEFA ALTER TABLE `cloud`.`vm_instance` ADD COLUMN `power_host` bigint unsigned; ALTER TABLE `cloud`.`vm_instance` ADD CONSTRAINT `fk_vm_instance__power_host` FOREIGN KEY (`power_host`) REFERENCES `cloud`.`host`(`id`); +ALTER TABLE `cloud`.`load_balancing_rules` ADD COLUMN `lb_protocol` VARCHAR(40); + DROP TABLE IF EXISTS `cloud`.`vm_snapshot_details`; CREATE TABLE `cloud`.`vm_snapshot_details` ( `id` bigint unsigned UNIQUE NOT NULL, @@ -464,6 +466,32 @@ CREATE VIEW `cloud`.`storage_pool_view` AS and async_job.instance_type = 'StoragePool' and async_job.job_status = 0; + +CREATE TABLE `sslcerts` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `uuid` varchar(40) DEFAULT NULL, + `account_id` bigint(20) unsigned NOT NULL, + `domain_id` bigint(20) unsigned NOT NULL, + `certificate` text NOT NULL, + `fingerprint` varchar(62) NOT NULL, + `key` text NOT NULL, + `chain` text, + `password` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`), + CONSTRAINT `fk_sslcert__account_id` FOREIGN KEY (`account_id`) REFERENCES `account` (`id`) ON DELETE CASCADE, + CONSTRAINT `fk_sslcert__domain_id` FOREIGN KEY (`domain_id`) REFERENCES `domain` (`id`) ON DELETE CASCADE +); + +CREATE TABLE `load_balancer_cert_map` ( + `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, + `uuid` varchar(40) DEFAULT NULL, + `load_balancer_id` bigint(20) unsigned NOT NULL, + `certificate_id` bigint(20) unsigned NOT NULL, + `revoke` tinyint(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`id`), + CONSTRAINT `fk_load_balancer_cert_map__certificate_id` FOREIGN KEY (`certificate_id`) REFERENCES `sslcerts` (`id`) ON DELETE CASCADE, + CONSTRAINT `fk_load_balancer_cert_map__load_balancer_id` FOREIGN KEY (`load_balancer_id`) REFERENCES `load_balancing_rules` (`id`) ON DELETE CASCADE); + ALTER TABLE `cloud`.`host` ADD COLUMN `cpu_sockets` int(10) unsigned DEFAULT NULL COMMENT "the number of CPU sockets on the host" AFTER pod_id; DROP VIEW IF EXISTS `cloud`.`host_view`; diff --git a/utils/src/com/cloud/utils/net/NetUtils.java b/utils/src/com/cloud/utils/net/NetUtils.java index f5904250bb4..8a351097845 100755 --- a/utils/src/com/cloud/utils/net/NetUtils.java +++ b/utils/src/com/cloud/utils/net/NetUtils.java @@ -52,6 +52,7 @@ import com.cloud.utils.script.Script; public class NetUtils { protected final static Logger s_logger = Logger.getLogger(NetUtils.class); public final static String HTTP_PORT = "80"; + public final static String HTTPS_PORT = "443"; public final static int VPN_PORT = 500; public final static int VPN_NATT_PORT = 4500; public final static int VPN_L2TP_PORT = 1701; @@ -61,6 +62,8 @@ public class NetUtils { public final static String ANY_PROTO = "any"; public final static String ICMP_PROTO = "icmp"; public final static String ALL_PROTO = "all"; + public final static String HTTP_PROTO = "http"; + public final static String SSL_PROTO = "ssl"; public final static String ALL_CIDRS = "0.0.0.0/0"; public final static int PORT_RANGE_MIN = 0;