diff --git a/api/src/main/java/com/cloud/event/EventTypes.java b/api/src/main/java/com/cloud/event/EventTypes.java index 38e601c790a7..d2989a8ffdc9 100644 --- a/api/src/main/java/com/cloud/event/EventTypes.java +++ b/api/src/main/java/com/cloud/event/EventTypes.java @@ -503,6 +503,7 @@ public class EventTypes { public static final String EVENT_S2S_VPN_CUSTOMER_GATEWAY_CREATE = "VPN.S2S.CUSTOMER.GATEWAY.CREATE"; public static final String EVENT_S2S_VPN_CUSTOMER_GATEWAY_DELETE = "VPN.S2S.CUSTOMER.GATEWAY.DELETE"; public static final String EVENT_S2S_VPN_CUSTOMER_GATEWAY_UPDATE = "VPN.S2S.CUSTOMER.GATEWAY.UPDATE"; + public static final String EVENT_S2S_VPN_GATEWAY_OBSOLETE_PARAMS = "VPN.S2S.GATEWAY.OBSOLETE.PARAMS"; public static final String EVENT_S2S_VPN_CONNECTION_CREATE = "VPN.S2S.CONNECTION.CREATE"; public static final String EVENT_S2S_VPN_CONNECTION_DELETE = "VPN.S2S.CONNECTION.DELETE"; public static final String EVENT_S2S_VPN_CONNECTION_RESET = "VPN.S2S.CONNECTION.RESET"; @@ -1151,6 +1152,7 @@ public class EventTypes { entityEventDetails.put(EVENT_S2S_VPN_CUSTOMER_GATEWAY_CREATE, Site2SiteCustomerGateway.class); entityEventDetails.put(EVENT_S2S_VPN_CUSTOMER_GATEWAY_DELETE, Site2SiteCustomerGateway.class); entityEventDetails.put(EVENT_S2S_VPN_CUSTOMER_GATEWAY_UPDATE, Site2SiteCustomerGateway.class); + entityEventDetails.put(EVENT_S2S_VPN_GATEWAY_OBSOLETE_PARAMS, Site2SiteCustomerGateway.class); entityEventDetails.put(EVENT_S2S_VPN_CONNECTION_CREATE, Site2SiteVpnConnection.class); entityEventDetails.put(EVENT_S2S_VPN_CONNECTION_DELETE, Site2SiteVpnConnection.class); entityEventDetails.put(EVENT_S2S_VPN_CONNECTION_RESET, Site2SiteVpnConnection.class); diff --git a/api/src/main/java/org/apache/cloudstack/alert/AlertService.java b/api/src/main/java/org/apache/cloudstack/alert/AlertService.java index d8e471756a02..cc3188feeca5 100644 --- a/api/src/main/java/org/apache/cloudstack/alert/AlertService.java +++ b/api/src/main/java/org/apache/cloudstack/alert/AlertService.java @@ -74,6 +74,7 @@ private AlertType(short type, String name, boolean isDefault) { public static final AlertType ALERT_TYPE_VR_PUBLIC_IFACE_MTU = new AlertType((short)32, "ALERT.VR.PUBLIC.IFACE.MTU", true); public static final AlertType ALERT_TYPE_VR_PRIVATE_IFACE_MTU = new AlertType((short)32, "ALERT.VR.PRIVATE.IFACE.MTU", true); public static final AlertType ALERT_TYPE_EXTENSION_PATH_NOT_READY = new AlertType((short)33, "ALERT.TYPE.EXTENSION.PATH.NOT.READY", true); + public static final AlertType ALERT_TYPE_VPN_GATEWAY_OBSOLETE_PARAMETERS = new AlertType((short)34, "ALERT.S2S.VPN.GATEWAY.OBSOLETE.PARAMETERS", true); public static final AlertType ALERT_TYPE_BACKUP_STORAGE = new AlertType(Capacity.CAPACITY_TYPE_BACKUP_STORAGE, "ALERT.STORAGE.BACKUP", true); public static final AlertType ALERT_TYPE_OBJECT_STORAGE = new AlertType(Capacity.CAPACITY_TYPE_OBJECT_STORAGE, "ALERT.STORAGE.OBJECT", true); diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java index 8fca652518f2..0e4a5a030aa8 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -1363,6 +1363,10 @@ public class ApiConstants { public static final String RECURSIVE_DOMAINS = "recursivedomains"; + public static final String VPN_CUSTOMER_GATEWAY_PARAMETERS = "vpncustomergatewayparameters"; + public static final String OBSOLETE_PARAMETERS = "obsoleteparameters"; + public static final String EXCLUDED_PARAMETERS = "excludedparameters"; + /** * This enum specifies IO Drivers, each option controls specific policies on I/O. * Qemu guests support "threads" and "native" options Since 0.8.8 ; "io_uring" is supported Since 6.3.0 (QEMU 5.0). diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java index ed1bd7b063b2..4f2bbb8add37 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java @@ -76,6 +76,10 @@ public void execute() { response.setExtensionsPath((String)capabilities.get(ApiConstants.EXTENSIONS_PATH)); response.setDynamicScalingEnabled((Boolean) capabilities.get(ApiConstants.DYNAMIC_SCALING_ENABLED)); response.setAdditionalConfigEnabled((Boolean) capabilities.get(ApiConstants.ADDITONAL_CONFIG_ENABLED)); + if (capabilities.containsKey(ApiConstants.VPN_CUSTOMER_GATEWAY_PARAMETERS)) { + Map vpnCustomerGatewayParameters = (Map) capabilities.get(ApiConstants.VPN_CUSTOMER_GATEWAY_PARAMETERS); + response.setVpnCustomerGatewayParameters(vpnCustomerGatewayParameters); + } response.setObjectName("capability"); response.setResponseName(getCommandName()); this.setResponseObject(response); diff --git a/api/src/main/java/org/apache/cloudstack/api/response/CapabilitiesResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/CapabilitiesResponse.java index d2c71b5f3525..a37f3d3d16ec 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/CapabilitiesResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/CapabilitiesResponse.java @@ -16,6 +16,8 @@ // under the License. package org.apache.cloudstack.api.response; +import java.util.Map; + import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; @@ -153,6 +155,10 @@ public class CapabilitiesResponse extends BaseResponse { @Param(description = "true if additional configurations or extraconfig can be passed to Instances", since = "4.20.2") private Boolean additionalConfigEnabled; + @SerializedName(ApiConstants.VPN_CUSTOMER_GATEWAY_PARAMETERS) + @Param(description = "Excluded and obsolete VPN customer gateway cryptographic parameters") + private Map vpnCustomerGatewayParameters; + public void setSecurityGroupsEnabled(boolean securityGroupsEnabled) { this.securityGroupsEnabled = securityGroupsEnabled; } @@ -280,4 +286,8 @@ public void setDynamicScalingEnabled(Boolean dynamicScalingEnabled) { public void setAdditionalConfigEnabled(Boolean additionalConfigEnabled) { this.additionalConfigEnabled = additionalConfigEnabled; } + + public void setVpnCustomerGatewayParameters(Map vpnCustomerGatewayParameters) { + this.vpnCustomerGatewayParameters = vpnCustomerGatewayParameters; + } } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/Site2SiteCustomerGatewayResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/Site2SiteCustomerGatewayResponse.java index 4ae140ec573d..8de74cfd3c16 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/Site2SiteCustomerGatewayResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/Site2SiteCustomerGatewayResponse.java @@ -114,6 +114,14 @@ public class Site2SiteCustomerGatewayResponse extends BaseResponseWithAnnotation @Param(description = "Which IKE Version to use, one of ike (autoselect), ikev1, or ikev2. Defaults to ike") private String ikeVersion; + @SerializedName(ApiConstants.OBSOLETE_PARAMETERS) + @Param(description = "Contains the list of obsolete/insecure cryptographic parameters that the vpn customer gateway is using.", since = "4.23.0") + private String obsoleteParameters; + + @SerializedName(ApiConstants.EXCLUDED_PARAMETERS) + @Param(description = "Contains the list of excluded/not allowed cryptographic parameters that the vpn customer gateway is using.", since = "4.23.0") + private String excludedParameters; + public void setId(String id) { this.id = id; } @@ -202,4 +210,12 @@ public void setDomainPath(String domainPath) { this.domainPath = domainPath; } + public void setContainsObsoleteParameters(String obsoleteParameters) { + this.obsoleteParameters = obsoleteParameters; + } + + public void setContainsExcludedParameters(String excludedParameters) { + this.excludedParameters = excludedParameters; + } + } diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java index 8cc10ce41673..11f49f85dd79 100644 --- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java +++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java @@ -50,6 +50,7 @@ import com.cloud.dc.dao.VlanDetailsDao; import com.cloud.hypervisor.Hypervisor; import com.cloud.network.vpc.VpcGateway; +import com.cloud.network.vpn.Site2SiteVpnManager; import com.cloud.storage.BucketVO; import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.ControlledEntity.ACLType; @@ -528,6 +529,8 @@ public class ApiResponseHelper implements ResponseGenerator { @Inject RoutedIpv4Manager routedIpv4Manager; @Inject + Site2SiteVpnManager site2SiteVpnManager; + @Inject ResourceIconManager resourceIconManager; public static String getPrettyDomainPath(String path) { @@ -3884,6 +3887,16 @@ public Site2SiteCustomerGatewayResponse createSite2SiteCustomerGatewayResponse(S response.setRemoved(result.getRemoved()); response.setIkeVersion(result.getIkeVersion()); response.setSplitConnections(result.getSplitConnections()); + + Set obsoleteParameters = site2SiteVpnManager.getObsoleteVpnGatewayParameters(result); + if (!obsoleteParameters.isEmpty()) { + response.setContainsObsoleteParameters(obsoleteParameters.toString()); + } + Set excludedParameters = site2SiteVpnManager.getExcludedVpnGatewayParameters(result); + if (!excludedParameters.isEmpty()) { + response.setContainsExcludedParameters(excludedParameters.toString()); + } + response.setObjectName("vpncustomergateway"); response.setHasAnnotation(annotationDao.hasAnnotations(result.getUuid(), AnnotationService.EntityType.VPN_CUSTOMER_GATEWAY.name(), _accountMgr.isRootAdmin(CallContext.current().getCallingAccount().getId()))); diff --git a/server/src/main/java/com/cloud/network/vpn/Site2SiteVpnManager.java b/server/src/main/java/com/cloud/network/vpn/Site2SiteVpnManager.java index 25c84d6d956b..9cf604f85070 100644 --- a/server/src/main/java/com/cloud/network/vpn/Site2SiteVpnManager.java +++ b/server/src/main/java/com/cloud/network/vpn/Site2SiteVpnManager.java @@ -17,11 +17,17 @@ package com.cloud.network.vpn; import java.util.List; +import java.util.Set; +import com.cloud.network.Site2SiteCustomerGateway; import com.cloud.network.dao.Site2SiteVpnConnectionVO; import com.cloud.vm.DomainRouterVO; public interface Site2SiteVpnManager extends Site2SiteVpnService { + Set getExcludedVpnGatewayParameters(Site2SiteCustomerGateway customerGw); + + Set getObsoleteVpnGatewayParameters(Site2SiteCustomerGateway customerGw); + boolean cleanupVpnConnectionByVpc(long vpcId); boolean cleanupVpnGatewayByVpc(long vpcId); diff --git a/server/src/main/java/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java b/server/src/main/java/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java index ad1d1f02682e..5d32226e077d 100644 --- a/server/src/main/java/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java +++ b/server/src/main/java/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java @@ -17,15 +17,21 @@ package com.cloud.network.vpn; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.Timer; +import java.util.TimerTask; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.framework.config.Configurable; import org.apache.commons.collections.CollectionUtils; import org.springframework.stereotype.Component; +import org.apache.cloudstack.alert.AlertService; import org.apache.cloudstack.annotation.AnnotationService; import org.apache.cloudstack.annotation.dao.AnnotationDao; import org.apache.cloudstack.api.command.user.vpn.CreateVpnConnectionCmd; @@ -41,9 +47,13 @@ import org.apache.cloudstack.api.command.user.vpn.UpdateVpnCustomerGatewayCmd; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.cloudstack.managed.context.ManagedContextTimerTask; +import com.cloud.alert.AlertManager; import com.cloud.configuration.Config; import com.cloud.event.ActionEvent; +import com.cloud.event.ActionEventUtils; import com.cloud.event.EventTypes; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.PermissionDeniedException; @@ -72,9 +82,11 @@ import com.cloud.projects.Project.ListProjectResourcesCriteria; import com.cloud.user.Account; import com.cloud.user.AccountManager; +import com.cloud.user.User; import com.cloud.user.dao.AccountDao; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; +import com.cloud.utils.StringUtils; import com.cloud.utils.Ternary; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.db.DB; @@ -88,7 +100,52 @@ import com.cloud.vm.dao.DomainRouterDao; @Component -public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpnManager { +public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpnManager, Configurable { + + // Configuration keys for VPN gateway cryptographic parameter controls + public static final ConfigKey VpnCustomerGatewayExcludedEncryptionAlgorithms = new ConfigKey( + ConfigKey.CATEGORY_NETWORK, String.class, "vpn.customer.gateway.excluded.encryption.algorithms", "", + "Comma-separated list of encryption algorithms that are excluded and cannot be selected by end users for VPN Customer Gateways." + + "Applies to both IKE and ESP phases. Allowed values are aes128, aes192 and aes256 and 3des.", + true, ConfigKey.Scope.Domain); + public static final ConfigKey VpnCustomerGatewayExcludedHashingAlgorithms = new ConfigKey( + ConfigKey.CATEGORY_NETWORK, String.class, "vpn.customer.gateway.excluded.hashing.algorithms", "", + "Comma-separated list of hashing algorithms that are excluded and cannot be selected by end users for VPN Customer Gateways." + + "Applies to both IKE and ESP phases. Allowed values are sha1, sha256, sha384 and sha512 and md5.", + true, ConfigKey.Scope.Domain); + public static final ConfigKey VpnCustomerGatewayExcludedIkeVersions = new ConfigKey( + ConfigKey.CATEGORY_NETWORK, String.class, "vpn.customer.gateway.excluded.ike.versions", "", + "Comma-separated list of IKE versions that are excluded and cannot be selected by end users for VPN Customer Gateways. Allowed values are ikev, ikev1 and ikev2.", + true, ConfigKey.Scope.Domain); + public static final ConfigKey VpnCustomerGatewayExcludedDhGroup = new ConfigKey( + ConfigKey.CATEGORY_NETWORK, String.class, "vpn.customer.gateway.excluded.dh.group", "", + "Comma-separated list of Diffie-Hellman groups that are excluded and cannot be selected by end users for VPN Customer Gateways." + + "Applies to both IKE and ESP phases. Allowed values are modp1024, modp1536, modp2048, modp3072, modp4096, modp6144 and modp8192.", + true, ConfigKey.Scope.Domain); + public static final ConfigKey VpnCustomerGatewayObsoleteEncryptionAlgorithms = new ConfigKey( + ConfigKey.CATEGORY_NETWORK, String.class, "vpn.customer.gateway.obsolete.encryption.algorithms", "", + "Comma-separated list of encryption algorithms that are marked as obsolete/insecure for VPN Customer Gateways." + + "Applies to both IKE and ESP phases. Allowed values are aes128, aes192 and aes256 and 3des.", + true, ConfigKey.Scope.Domain); + public static final ConfigKey VpnCustomerGatewayObsoleteHashingAlgorithms = new ConfigKey( + ConfigKey.CATEGORY_NETWORK, String.class, "vpn.customer.gateway.obsolete.hashing.algorithms", "", + "Comma-separated list of hashing algorithms that are marked as obsolete/insecure for VPN Customer Gateways." + + "Applies to both IKE and ESP phases. Allowed values are sha1, sha256, sha384 and sha512 and md5.", + true, ConfigKey.Scope.Domain); + public static final ConfigKey VpnCustomerGatewayObsoleteIkeVersions = new ConfigKey( + ConfigKey.CATEGORY_NETWORK, String.class, "vpn.customer.gateway.obsolete.ike.versions", "", + "Comma-separated list of IKE versions that are marked as obsolete/insecure for VPN Customer Gateways. Allowed values are ikev, ikev1 and ikev2.", + true, ConfigKey.Scope.Domain); + public static final ConfigKey VpnCustomerGatewayObsoleteDhGroup = new ConfigKey( + ConfigKey.CATEGORY_NETWORK, String.class, "vpn.customer.gateway.obsolete.dh.group", "", + "Comma-separated list of Diffie-Hellman groups that are marked as obsolete/insecure for VPN Customer Gateways." + + "Applies to both IKE and ESP phases. Allowed values are modp1024, modp1536, modp2048, modp3072, modp4096, modp6144 and modp8192.", + true, ConfigKey.Scope.Domain); + public static final ConfigKey VpnCustomerGatewayObsoleteCheckInterval = new ConfigKey( + ConfigKey.CATEGORY_NETWORK, Long.class, "vpn.customer.gateway.obsolete.check.interval", "0", + "Interval in minutes to periodically check VPN customer gateways for obsolete/excluded parameters and generate events and alerts. " + + "Set to 0 to disable. Default: 0 (disabled).", + true, ConfigKey.Scope.Global); List _s2sProviders; @Inject @@ -117,9 +174,12 @@ public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpn private IpAddressManager ipAddressManager; @Inject private VpcManager vpcManager; + @Inject + private AlertManager _alertMgr; int _connLimit; int _subnetsLimit; + private Timer _vpnCheckTimer; @Override public boolean configure(String name, Map params) throws ConfigurationException { @@ -127,6 +187,7 @@ public boolean configure(String name, Map params) throws Configu _connLimit = NumbersUtil.parseInt(configs.get(Config.Site2SiteVpnConnectionPerVpnGatewayLimit.key()), 4); _subnetsLimit = NumbersUtil.parseInt(configs.get(Config.Site2SiteVpnSubnetsPerCustomerGatewayLimit.key()), 10); assert (_s2sProviders.iterator().hasNext()) : "Did not get injected with a list of S2S providers!"; + _vpnCheckTimer = new Timer("VpnCustomerGateway-ObsoleteCheck", true); return true; } @@ -146,7 +207,7 @@ public Site2SiteVpnGateway createVpnGateway(CreateVpnGatewayCmd cmd) { } Site2SiteVpnGatewayVO gws = _vpnGatewayDao.findByVpcId(vpcId); if (gws != null) { - throw new InvalidParameterValueException(String.format("The VPN gateway of VPC %s already existed!", vpc)); + throw new InvalidParameterValueException(String.format("The VPN gateway of VPC %s already exists!", vpc)); } IPAddressVO requestedIp = _ipAddressDao.findById(cmd.getIpAddressId()); @@ -187,6 +248,113 @@ private IPAddressVO getIpAddressIdForVpn(Long vpcId, Long vpcOferingId, IPAddres } } + private void validateVpnCryptographicParameters(String ikePolicy, String espPolicy, String ikeVersion, Long domainId) { + String excludedEncryption = VpnCustomerGatewayExcludedEncryptionAlgorithms.valueIn(domainId); + String excludedHashing = VpnCustomerGatewayExcludedHashingAlgorithms.valueIn(domainId); + String excludedIkeVersions = VpnCustomerGatewayExcludedIkeVersions.valueIn(domainId); + String excludedDhGroup = VpnCustomerGatewayExcludedDhGroup.valueIn(domainId); + + Set excludedParameters = getVpnGatewayParametersInBlockedList(ikePolicy, espPolicy, ikeVersion, + excludedEncryption, excludedHashing, excludedIkeVersions, excludedDhGroup); + if (!excludedParameters.isEmpty()) { + throw new InvalidParameterValueException("The following excluded cryptographic parameter(s) cannot be used in a VPN Customer Gateway: " + excludedParameters.toString()); + } + } + + @Override + public Set getExcludedVpnGatewayParameters(Site2SiteCustomerGateway customerGw) { + Long domainId = customerGw.getDomainId(); + String excludedEncryption = VpnCustomerGatewayExcludedEncryptionAlgorithms.valueIn(domainId); + String excludedHashing = VpnCustomerGatewayExcludedHashingAlgorithms.valueIn(domainId); + String excludedIkeVersions = VpnCustomerGatewayExcludedIkeVersions.valueIn(domainId); + String excludedDhGroup = VpnCustomerGatewayExcludedDhGroup.valueIn(domainId); + + return getVpnGatewayParametersInBlockedList(customerGw.getIkePolicy(), customerGw.getEspPolicy(), customerGw.getIkeVersion(), + excludedEncryption, excludedHashing, excludedIkeVersions, excludedDhGroup); + } + + @Override + public Set getObsoleteVpnGatewayParameters(Site2SiteCustomerGateway customerGw) { + Long domainId = customerGw.getDomainId(); + String obsoleteEncryption = VpnCustomerGatewayObsoleteEncryptionAlgorithms.valueIn(domainId); + String obsoleteHashing = VpnCustomerGatewayObsoleteHashingAlgorithms.valueIn(domainId); + String obsoleteIkeVersions = VpnCustomerGatewayObsoleteIkeVersions.valueIn(domainId); + String obsoleteDhGroup = VpnCustomerGatewayObsoleteDhGroup.valueIn(domainId); + + return getVpnGatewayParametersInBlockedList(customerGw.getIkePolicy(), customerGw.getEspPolicy(), customerGw.getIkeVersion(), + obsoleteEncryption, obsoleteHashing, obsoleteIkeVersions, obsoleteDhGroup); + } + + private Set getVpnGatewayParametersInBlockedList(String ikePolicy, String espPolicy, String ikeVersion, + String blockedEncryptionList, String blockedHashingList, + String blockedIkeVersionList, String blockedDhGroupList) { + + Set blockedParameters = new HashSet<>(); + if (StringUtils.isEmpty(blockedEncryptionList) + && StringUtils.isEmpty(blockedHashingList) + && StringUtils.isEmpty(blockedIkeVersionList) + && StringUtils.isEmpty(blockedDhGroupList)) { + return blockedParameters; + } + + if (isParameterInList(ikeVersion, blockedIkeVersionList)) { + blockedParameters.add(ikeVersion); + } + + Set ikePolicyResult = getVpnGatewayPolicyParametersInBlockedList(ikePolicy, "IKE", blockedEncryptionList, blockedHashingList, blockedDhGroupList); + if (!ikePolicyResult.isEmpty()) { + blockedParameters.addAll(ikePolicyResult); + } + + Set espPolicyResult = getVpnGatewayPolicyParametersInBlockedList(espPolicy, "ESP", blockedEncryptionList, blockedHashingList, blockedDhGroupList); + if (!espPolicyResult.isEmpty()) { + blockedParameters.addAll(espPolicyResult); + } + + return blockedParameters; + } + + private Set getVpnGatewayPolicyParametersInBlockedList(String policy, String policyType, String blockedEncryptionList, String blockedHashingList, String blockedDhGroupList) { + + String trimmedPolicy = policy.trim(); + String cipherHash = trimmedPolicy.split(";")[0]; + String[] parts = cipherHash.split("-"); + + String encryption = parts[0].trim(); + String hashing = parts.length > 1 ? parts[1].trim() : ""; + + Set blockedParameters = new HashSet<>(); + if (isParameterInList(encryption, blockedEncryptionList)) { + blockedParameters.add(encryption); + } + + if (isParameterInList(hashing, blockedHashingList)) { + blockedParameters.add(hashing); + } + + if (!trimmedPolicy.equals(cipherHash)) { + String dhGroup = trimmedPolicy.split(";")[1].trim(); + if (isParameterInList(dhGroup, blockedDhGroupList)) { + blockedParameters.add(dhGroup); + } + } + return blockedParameters; + } + + private boolean isParameterInList(String parameter, String list) { + if (StringUtils.isEmpty(list) || StringUtils.isEmpty(parameter)) { + return false; + } + + String[] entries = list.split(","); + for (String item : entries) { + if (item != null && item.trim().equalsIgnoreCase(parameter.trim())) { + return true; + } + } + return false; + } + protected void checkCustomerGatewayCidrList(String guestCidrList) { String[] cidrList = guestCidrList.split(","); if (cidrList.length > _subnetsLimit) { @@ -235,6 +403,13 @@ public Site2SiteCustomerGateway createCustomerGateway(CreateVpnCustomerGatewayCm if (!NetUtils.isValidS2SVpnPolicy("esp", espPolicy)) { throw new InvalidParameterValueException("The customer gateway ESP policy " + espPolicy + " is invalid!"); } + + String ikeVersion = cmd.getIkeVersion(); + if (ikeVersion == null) { + ikeVersion = "ike"; + } + validateVpnCryptographicParameters(ikePolicy, espPolicy, ikeVersion, owner.getDomainId()); + Long ikeLifetime = cmd.getIkeLifetime(); if (ikeLifetime == null) { // Default value of lifetime is 1 day @@ -264,7 +439,7 @@ public Site2SiteCustomerGateway createCustomerGateway(CreateVpnCustomerGatewayCm long accountId = owner.getAccountId(); if (_customerGatewayDao.findByNameAndAccountId(name, accountId) != null) { - throw new InvalidParameterValueException("The customer gateway with name " + name + " already existed!"); + throw new InvalidParameterValueException("The customer gateway with name " + name + " already exists!"); } Boolean splitConnections = cmd.getSplitConnections(); @@ -272,11 +447,6 @@ public Site2SiteCustomerGateway createCustomerGateway(CreateVpnCustomerGatewayCm splitConnections = false; } - String ikeVersion = cmd.getIkeVersion(); - if (ikeVersion == null) { - ikeVersion = "ike"; - } - checkCustomerGatewayCidrList(peerCidrList); Site2SiteCustomerGatewayVO gw = @@ -374,7 +544,7 @@ private void validateVpnConnectionOfTheRightAccount(Site2SiteCustomerGateway cus private void validateVpnConnectionDoesntExist(Site2SiteCustomerGateway customerGateway, Site2SiteVpnGateway vpnGateway) { if (_vpnConnectionDao.findByVpnGatewayIdAndCustomerGatewayId(vpnGateway.getId(), customerGateway.getId()) != null) { - throw new InvalidParameterValueException(String.format("The vpn connection with customer gateway %s and vpn gateway %s already existed!", customerGateway, vpnGateway)); + throw new InvalidParameterValueException(String.format("The vpn connection with customer gateway %s and vpn gateway %s already exists!", customerGateway, vpnGateway)); } } @@ -521,6 +691,10 @@ public Site2SiteCustomerGateway updateCustomerGateway(UpdateVpnCustomerGatewayCm if (!NetUtils.isValidS2SVpnPolicy("esp", espPolicy)) { throw new InvalidParameterValueException("The customer gateway ESP policy" + espPolicy + " is invalid!"); } + + String ikeVersion = cmd.getIkeVersion(); + validateVpnCryptographicParameters(ikePolicy, espPolicy, ikeVersion, gw.getDomainId()); + Long ikeLifetime = cmd.getIkeLifetime(); if (ikeLifetime == null) { // Default value of lifetime is 1 day @@ -550,14 +724,12 @@ public Site2SiteCustomerGateway updateCustomerGateway(UpdateVpnCustomerGatewayCm Boolean splitConnections = cmd.getSplitConnections(); - String ikeVersion = cmd.getIkeVersion(); - checkCustomerGatewayCidrList(guestCidrList); long accountId = gw.getAccountId(); Site2SiteCustomerGatewayVO existedGw = _customerGatewayDao.findByNameAndAccountId(name, accountId); if (existedGw != null && existedGw.getId() != gw.getId()) { - throw new InvalidParameterValueException("The customer gateway with name " + name + " already existed!"); + throw new InvalidParameterValueException("The customer gateway with name " + name + " already exists!"); } gw.setName(name); @@ -977,4 +1149,89 @@ public Site2SiteVpnGateway updateVpnGateway(Long id, String customId, Boolean fo return _vpnGatewayDao.findById(id); } + + @Override + public boolean start() { + final long checkInterval = VpnCustomerGatewayObsoleteCheckInterval.value(); + if (checkInterval > 0) { + TimerTask task = new CheckVpnCustomerGatewayObsoleteParametersTask(); + _vpnCheckTimer.schedule(task, checkInterval * 60 * 1000L, checkInterval * 60 * 1000L); + logger.info("Scheduled VPN customer gateway obsolete parameters check with interval: " + checkInterval + " minutes"); + } else { + logger.debug("VPN customer gateway obsolete check is disabled (interval = 0)"); + } + return true; + } + + @Override + public boolean stop() { + if (_vpnCheckTimer != null) { + _vpnCheckTimer.cancel(); + } + return true; + } + + @Override + public String getConfigComponentName() { + return Site2SiteVpnManager.class.getSimpleName(); + } + + @Override + public ConfigKey[] getConfigKeys() { + return new ConfigKey[] { VpnCustomerGatewayExcludedEncryptionAlgorithms, VpnCustomerGatewayExcludedHashingAlgorithms, + VpnCustomerGatewayExcludedIkeVersions, VpnCustomerGatewayExcludedDhGroup, VpnCustomerGatewayObsoleteEncryptionAlgorithms, + VpnCustomerGatewayObsoleteHashingAlgorithms, VpnCustomerGatewayObsoleteIkeVersions, VpnCustomerGatewayObsoleteDhGroup, + VpnCustomerGatewayObsoleteCheckInterval}; + } + + protected class CheckVpnCustomerGatewayObsoleteParametersTask extends ManagedContextTimerTask { + + @Override + protected void runInContext() { + List allGateways = _customerGatewayDao.listAll(); + int obsoleteCount = 0; + int excludedCount = 0; + + for (Site2SiteCustomerGatewayVO gateway : allGateways) { + Set excludedParameters = getExcludedVpnGatewayParameters(gateway); + Set obsoleteParameters = getObsoleteVpnGatewayParameters(gateway); + + String message = ""; + if (!excludedParameters.isEmpty()) { + excludedCount++; + message += "excluded parameter(s) " + excludedParameters.toString(); + } + if (!obsoleteParameters.isEmpty()) { + obsoleteCount++; + if (StringUtils.isNotEmpty(message)) { + message += " and "; + } + message += "obsolete parameter(s) " + obsoleteParameters.toString(); + } + + if (StringUtils.isNotEmpty(message)) { + Account account = _accountDao.findById(gateway.getAccountId()); + String description = String.format("VPN customer gateway '%s' (Account: %s) contains %s.", gateway.getName(), account.getAccountName(), message); + ActionEventUtils.onActionEvent(User.UID_SYSTEM, gateway.getAccountId(), gateway.getDomainId(), + EventTypes.EVENT_S2S_VPN_GATEWAY_OBSOLETE_PARAMS, description, + gateway.getId(), Site2SiteCustomerGateway.class.getSimpleName()); + } + } + + String message = ""; + if (obsoleteCount > 0) { + message += "VPN Customer Gateways with obsolete parameters: " + obsoleteCount; + } + if (excludedCount > 0) { + if (StringUtils.isNotEmpty(message)) { + message += " and "; + } + message += "VPN Customer Gateways with excluded parameters: " + excludedCount; + } + if (StringUtils.isNotEmpty(message)) { + _alertMgr.clearAlert(AlertService.AlertType.ALERT_TYPE_VPN_GATEWAY_OBSOLETE_PARAMETERS, 0L, 0L); + _alertMgr.sendAlert(AlertService.AlertType.ALERT_TYPE_VPN_GATEWAY_OBSOLETE_PARAMETERS, 0L, 0L, message, null); + } + } + } } diff --git a/server/src/main/java/com/cloud/server/ManagementServerImpl.java b/server/src/main/java/com/cloud/server/ManagementServerImpl.java index e6032662e926..db7879c65892 100644 --- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java +++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java @@ -760,6 +760,7 @@ import com.cloud.network.Network; import com.cloud.network.NetworkModel; import com.cloud.network.Networks; +import com.cloud.network.vpn.Site2SiteVpnManagerImpl; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.IPAddressVO; import com.cloud.network.dao.LoadBalancerDao; @@ -4778,9 +4779,54 @@ public Map listCapabilities(final ListCapabilitiesCmd cmd) { } capabilities.put(ApiConstants.ADDITONAL_CONFIG_ENABLED, UserVmManager.EnableAdditionalVmConfig.valueIn(caller.getId())); + Long domainId = caller.getDomainId(); + Map vpnParams = getVpnCustomerGatewayParameters(domainId); + if (!vpnParams.isEmpty()) { + capabilities.put(ApiConstants.VPN_CUSTOMER_GATEWAY_PARAMETERS, vpnParams); + } + return capabilities; } + private Map getVpnCustomerGatewayParameters(Long domainId) { + Map vpnParams = new HashMap<>(); + + String excludedEncryption = Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedEncryptionAlgorithms.valueIn(domainId); + String excludedHashing = Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedHashingAlgorithms.valueIn(domainId); + String excludedIkeVersions = Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedIkeVersions.valueIn(domainId); + String excludedDhGroup = Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedDhGroup.valueIn(domainId); + String obsoleteEncryption = Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteEncryptionAlgorithms.valueIn(domainId); + String obsoleteHashing = Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteHashingAlgorithms.valueIn(domainId); + String obsoleteIkeVersions = Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteIkeVersions.valueIn(domainId); + String obsoleteDhGroup = Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteDhGroup.valueIn(domainId); + + if (!excludedEncryption.isEmpty()) { + vpnParams.put("excludedencryptionalgorithms", excludedEncryption); + } + if (!obsoleteEncryption.isEmpty()) { + vpnParams.put("obsoleteencryptionalgorithms", obsoleteEncryption); + } + if (!excludedHashing.isEmpty()) { + vpnParams.put("excludedhashingalgorithms", excludedHashing); + } + if (!obsoleteHashing.isEmpty()) { + vpnParams.put("obsoletehashingalgorithms", obsoleteHashing); + } + if (!excludedIkeVersions.isEmpty()) { + vpnParams.put("excludedikeversions", excludedIkeVersions); + } + if (!obsoleteIkeVersions.isEmpty()) { + vpnParams.put("obsoleteikeversions", obsoleteIkeVersions); + } + if (!excludedDhGroup.isEmpty()) { + vpnParams.put("excludeddhgroups", excludedDhGroup); + } + if (!obsoleteDhGroup.isEmpty()) { + vpnParams.put("obsoletedhgroups", obsoleteDhGroup); + } + return vpnParams; + } + @Override public GuestOSVO getGuestOs(final Long guestOsId) { return _guestOSDao.findById(guestOsId); diff --git a/server/src/test/java/com/cloud/network/vpn/Site2SiteVpnManagerImplTest.java b/server/src/test/java/com/cloud/network/vpn/Site2SiteVpnManagerImplTest.java new file mode 100644 index 000000000000..291d3a4aa812 --- /dev/null +++ b/server/src/test/java/com/cloud/network/vpn/Site2SiteVpnManagerImplTest.java @@ -0,0 +1,944 @@ +/* + * 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.vpn; + +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.Site2SiteVpnConnection; +import com.cloud.network.Site2SiteVpnConnection.State; +import com.cloud.network.Site2SiteVpnGateway; +import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.dao.Site2SiteCustomerGatewayDao; +import com.cloud.network.dao.Site2SiteCustomerGatewayVO; +import com.cloud.network.dao.Site2SiteVpnConnectionDao; +import com.cloud.network.dao.Site2SiteVpnConnectionVO; +import com.cloud.network.dao.Site2SiteVpnGatewayDao; +import com.cloud.network.dao.Site2SiteVpnGatewayVO; +import com.cloud.network.element.Site2SiteVpnServiceProvider; +import com.cloud.network.vpc.VpcManager; +import com.cloud.network.vpc.VpcVO; +import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.AccountVO; +import com.cloud.user.User; +import com.cloud.user.UserVO; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.NetUtils; +import com.cloud.vm.DomainRouterVO; +import org.apache.cloudstack.acl.SecurityChecker; +import org.apache.cloudstack.annotation.dao.AnnotationDao; +import org.apache.cloudstack.api.command.user.vpn.CreateVpnConnectionCmd; +import org.apache.cloudstack.api.command.user.vpn.CreateVpnCustomerGatewayCmd; +import org.apache.cloudstack.api.command.user.vpn.CreateVpnGatewayCmd; +import org.apache.cloudstack.api.command.user.vpn.DeleteVpnConnectionCmd; +import org.apache.cloudstack.api.command.user.vpn.DeleteVpnCustomerGatewayCmd; +import org.apache.cloudstack.api.command.user.vpn.DeleteVpnGatewayCmd; +import org.apache.cloudstack.api.command.user.vpn.ResetVpnConnectionCmd; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.framework.config.ConfigKey; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.Silent.class) +public class Site2SiteVpnManagerImplTest { + + @Mock + private Site2SiteCustomerGatewayDao _customerGatewayDao; + @Mock + private Site2SiteVpnGatewayDao _vpnGatewayDao; + @Mock + private Site2SiteVpnConnectionDao _vpnConnectionDao; + @Mock + private VpcDao _vpcDao; + @Mock + private IPAddressDao _ipAddressDao; + @Mock + private VpcManager _vpcMgr; + @Mock + private AccountManager _accountMgr; + @Mock + private AnnotationDao annotationDao; + @Mock + private List _s2sProviders; + @Mock + VpcOfferingServiceMapDao vpcOfferingServiceMapDao; + + @InjectMocks + private Site2SiteVpnManagerImpl site2SiteVpnManager; + + private AccountVO account; + private UserVO user; + private VpcVO vpc; + private IPAddressVO ipAddress; + private Site2SiteVpnGatewayVO vpnGateway; + private Site2SiteCustomerGatewayVO customerGateway; + private Site2SiteVpnConnectionVO vpnConnection; + + private static final Long ACCOUNT_ID = 1L; + private static final Long DOMAIN_ID = 2L; + private static final Long VPC_ID = 3L; + private static final Long VPN_GATEWAY_ID = 4L; + private static final Long CUSTOMER_GATEWAY_ID = 5L; + private static final Long VPN_CONNECTION_ID = 6L; + private static final Long IP_ADDRESS_ID = 7L; + + @Before + public void setUp() throws Exception { + account = new AccountVO("testaccount", DOMAIN_ID, "networkdomain", Account.Type.NORMAL, UUID.randomUUID().toString()); + account.setId(ACCOUNT_ID); + user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", + UUID.randomUUID().toString(), User.Source.UNKNOWN); + CallContext.register(user, account); + + vpc = mock(VpcVO.class); + when(vpc.getId()).thenReturn(VPC_ID); + when(vpc.getAccountId()).thenReturn(ACCOUNT_ID); + when(vpc.getDomainId()).thenReturn(DOMAIN_ID); + when(vpc.getCidr()).thenReturn("10.0.0.0/16"); + + ipAddress = mock(IPAddressVO.class); + when(ipAddress.getId()).thenReturn(IP_ADDRESS_ID); + when(ipAddress.getVpcId()).thenReturn(VPC_ID); + + vpnGateway = mock(Site2SiteVpnGatewayVO.class); + when(vpnGateway.getId()).thenReturn(VPN_GATEWAY_ID); + when(vpnGateway.getVpcId()).thenReturn(VPC_ID); + when(vpnGateway.getAccountId()).thenReturn(ACCOUNT_ID); + when(vpnGateway.getDomainId()).thenReturn(DOMAIN_ID); + + customerGateway = mock(Site2SiteCustomerGatewayVO.class); + when(customerGateway.getId()).thenReturn(CUSTOMER_GATEWAY_ID); + when(customerGateway.getAccountId()).thenReturn(ACCOUNT_ID); + when(customerGateway.getDomainId()).thenReturn(DOMAIN_ID); + when(customerGateway.getGuestCidrList()).thenReturn("192.168.1.0/24"); + when(customerGateway.getIkePolicy()).thenReturn("aes128-sha256;modp2048"); + when(customerGateway.getEspPolicy()).thenReturn("aes128-sha256;modp2048"); + when(customerGateway.getIkeVersion()).thenReturn("ike"); + + vpnConnection = new Site2SiteVpnConnectionVO(ACCOUNT_ID, DOMAIN_ID, VPN_GATEWAY_ID, CUSTOMER_GATEWAY_ID, false); + vpnConnection.setState(State.Pending); + + when(_accountMgr.getAccount(ACCOUNT_ID)).thenReturn(account); + doNothing().when(_accountMgr).checkAccess(any(Account.class), nullable(SecurityChecker.AccessType.class), anyBoolean(), any()); + } + + @After + public void tearDown() throws Exception { + resetConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedIkeVersions); + resetConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedEncryptionAlgorithms); + resetConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedHashingAlgorithms); + resetConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedDhGroup); + resetConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteIkeVersions); + resetConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteEncryptionAlgorithms); + resetConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteHashingAlgorithms); + resetConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteDhGroup); + CallContext.unregister(); + } + + private void setConfigKeyValue(ConfigKey configKey, String value) { + try { + Field valueField = ConfigKey.class.getDeclaredField("_value"); + valueField.setAccessible(true); + valueField.set(configKey, value); + + Field dynamicField = ConfigKey.class.getDeclaredField("_isDynamic"); + dynamicField.setAccessible(true); + dynamicField.setBoolean(configKey, false); + } catch (IllegalAccessException | NoSuchFieldException e) { + throw new RuntimeException("Failed to set ConfigKey value", e); + } + } + + private void resetConfigKeyValue(ConfigKey configKey) { + try { + Field valueField = ConfigKey.class.getDeclaredField("_value"); + valueField.setAccessible(true); + valueField.set(configKey, null); + + Field dynamicField = ConfigKey.class.getDeclaredField("_isDynamic"); + dynamicField.setAccessible(true); + dynamicField.setBoolean(configKey, true); + } catch (IllegalAccessException | NoSuchFieldException e) { + throw new RuntimeException("Failed to reset ConfigKey value", e); + } + } + + @Test + public void testCreateVpnGatewaySuccess() { + CreateVpnGatewayCmd cmd = mock(CreateVpnGatewayCmd.class); + when(cmd.getVpcId()).thenReturn(VPC_ID); + when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID); + when(cmd.isDisplay()).thenReturn(true); + + when(_vpcDao.findById(VPC_ID)).thenReturn(vpc); + when(_vpnGatewayDao.findByVpcId(VPC_ID)).thenReturn(null); + when(_ipAddressDao.listByAssociatedVpc(VPC_ID, true)).thenReturn(List.of(ipAddress)); + when(_vpnGatewayDao.persist(any(Site2SiteVpnGatewayVO.class))).thenReturn(vpnGateway); + + Site2SiteVpnGateway result = site2SiteVpnManager.createVpnGateway(cmd); + + assertNotNull(result); + verify(_vpnGatewayDao).persist(any(Site2SiteVpnGatewayVO.class)); + } + + @Test(expected = InvalidParameterValueException.class) + public void testCreateVpnGatewayInvalidVpc() { + CreateVpnGatewayCmd cmd = mock(CreateVpnGatewayCmd.class); + when(cmd.getVpcId()).thenReturn(VPC_ID); + when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID); + + when(_vpcDao.findById(VPC_ID)).thenReturn(null); + + site2SiteVpnManager.createVpnGateway(cmd); + } + + @Test(expected = InvalidParameterValueException.class) + public void testCreateVpnGatewayAlreadyExists() { + CreateVpnGatewayCmd cmd = mock(CreateVpnGatewayCmd.class); + when(cmd.getVpcId()).thenReturn(VPC_ID); + when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID); + + when(_vpcDao.findById(VPC_ID)).thenReturn(vpc); + when(_vpnGatewayDao.findByVpcId(VPC_ID)).thenReturn(vpnGateway); + + site2SiteVpnManager.createVpnGateway(cmd); + } + + @Test(expected = CloudRuntimeException.class) + public void testCreateVpnGatewayNoSourceNatIp() { + CreateVpnGatewayCmd cmd = mock(CreateVpnGatewayCmd.class); + when(cmd.getVpcId()).thenReturn(VPC_ID); + when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID); + + when(_vpcDao.findById(VPC_ID)).thenReturn(vpc); + when(_vpnGatewayDao.findByVpcId(VPC_ID)).thenReturn(null); + when(_ipAddressDao.listByAssociatedVpc(VPC_ID, true)).thenReturn(new ArrayList<>()); + + site2SiteVpnManager.createVpnGateway(cmd); + } + + @Test(expected = InvalidParameterValueException.class) + public void testCreateCustomerGatewayInvalidIp() { + CreateVpnCustomerGatewayCmd cmd = mock(CreateVpnCustomerGatewayCmd.class); + when(cmd.getGatewayIp()).thenReturn("invalid-ip"); + when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID); + + try (MockedStatic netUtilsMock = Mockito.mockStatic(NetUtils.class)) { + netUtilsMock.when(() -> NetUtils.isValidIp4("invalid-ip")).thenReturn(false); + netUtilsMock.when(() -> NetUtils.verifyDomainName("invalid-ip")).thenReturn(false); + + site2SiteVpnManager.createCustomerGateway(cmd); + } + } + + @Test(expected = InvalidParameterValueException.class) + public void testCreateCustomerGatewayInvalidCidrList() { + CreateVpnCustomerGatewayCmd cmd = mock(CreateVpnCustomerGatewayCmd.class); + when(cmd.getGatewayIp()).thenReturn("1.2.3.4"); + when(cmd.getGuestCidrList()).thenReturn("invalid-cidr"); + when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID); + + try (MockedStatic netUtilsMock = Mockito.mockStatic(NetUtils.class)) { + netUtilsMock.when(() -> NetUtils.isValidIp4("1.2.3.4")).thenReturn(true); + netUtilsMock.when(() -> NetUtils.isValidCidrList("invalid-cidr")).thenReturn(false); + + site2SiteVpnManager.createCustomerGateway(cmd); + } + } + + @Test(expected = InvalidParameterValueException.class) + public void testCreateCustomerGatewayInvalidIkePolicy() { + CreateVpnCustomerGatewayCmd cmd = mock(CreateVpnCustomerGatewayCmd.class); + when(cmd.getGatewayIp()).thenReturn("1.2.3.4"); + when(cmd.getGuestCidrList()).thenReturn("192.168.1.0/24"); + when(cmd.getIkePolicy()).thenReturn("invalid-policy"); + when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID); + + try (MockedStatic netUtilsMock = Mockito.mockStatic(NetUtils.class)) { + netUtilsMock.when(() -> NetUtils.isValidIp4("1.2.3.4")).thenReturn(true); + netUtilsMock.when(() -> NetUtils.isValidCidrList("192.168.1.0/24")).thenReturn(true); + netUtilsMock.when(() -> NetUtils.isValidS2SVpnPolicy("ike", "invalid-policy")).thenReturn(false); + + site2SiteVpnManager.createCustomerGateway(cmd); + } + } + + @Test(expected = InvalidParameterValueException.class) + public void testCreateCustomerGatewayInvalidEspPolicy() { + CreateVpnCustomerGatewayCmd cmd = mock(CreateVpnCustomerGatewayCmd.class); + when(cmd.getGatewayIp()).thenReturn("1.2.3.4"); + when(cmd.getGuestCidrList()).thenReturn("192.168.1.0/24"); + when(cmd.getIkePolicy()).thenReturn("aes128-sha256;modp2048"); + when(cmd.getEspPolicy()).thenReturn("invalid-policy"); + when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID); + + try (MockedStatic netUtilsMock = Mockito.mockStatic(NetUtils.class)) { + netUtilsMock.when(() -> NetUtils.isValidIp4("1.2.3.4")).thenReturn(true); + netUtilsMock.when(() -> NetUtils.isValidCidrList("192.168.1.0/24")).thenReturn(true); + netUtilsMock.when(() -> NetUtils.isValidS2SVpnPolicy("ike", "aes128-sha256;modp2048")).thenReturn(true); + netUtilsMock.when(() -> NetUtils.isValidS2SVpnPolicy("esp", "invalid-policy")).thenReturn(false); + + site2SiteVpnManager.createCustomerGateway(cmd); + } + } + + @Test(expected = InvalidParameterValueException.class) + public void testCreateCustomerGatewayWithExcludedParameters() throws Exception { + CreateVpnCustomerGatewayCmd cmd = mock(CreateVpnCustomerGatewayCmd.class); + when(cmd.getName()).thenReturn("test-gateway"); + when(cmd.getGatewayIp()).thenReturn("1.2.3.4"); + when(cmd.getGuestCidrList()).thenReturn("192.168.1.0/24"); + when(cmd.getIpsecPsk()).thenReturn("test-psk"); + when(cmd.getIkePolicy()).thenReturn("3des-sha256;modp2048"); + when(cmd.getEspPolicy()).thenReturn("aes128-sha256;modp2048"); + when(cmd.getIkeVersion()).thenReturn("ike"); + when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID); + + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedEncryptionAlgorithms, "3des"); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedHashingAlgorithms, ""); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedIkeVersions, ""); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedDhGroup, ""); + + try (MockedStatic netUtilsMock = Mockito.mockStatic(NetUtils.class)) { + netUtilsMock.when(() -> NetUtils.isValidIp4("1.2.3.4")).thenReturn(true); + netUtilsMock.when(() -> NetUtils.isValidCidrList("192.168.1.0/24")).thenReturn(true); + netUtilsMock.when(() -> NetUtils.isValidS2SVpnPolicy("ike", "3des-sha256;modp2048")).thenReturn(true); + netUtilsMock.when(() -> NetUtils.isValidS2SVpnPolicy("esp", "aes128-sha256;modp2048")).thenReturn(true); + + site2SiteVpnManager.createCustomerGateway(cmd); + } + } + + @Test(expected = InvalidParameterValueException.class) + public void testCreateCustomerGatewayDuplicateName() { + CreateVpnCustomerGatewayCmd cmd = mock(CreateVpnCustomerGatewayCmd.class); + when(cmd.getName()).thenReturn("test-gateway"); + when(cmd.getGatewayIp()).thenReturn("1.2.3.4"); + when(cmd.getGuestCidrList()).thenReturn("192.168.1.0/24"); + when(cmd.getIkePolicy()).thenReturn("aes128-sha256;modp2048"); + when(cmd.getEspPolicy()).thenReturn("aes128-sha256;modp2048"); + when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID); + + try (MockedStatic netUtilsMock = Mockito.mockStatic(NetUtils.class)) { + netUtilsMock.when(() -> NetUtils.isValidIp4("1.2.3.4")).thenReturn(true); + netUtilsMock.when(() -> NetUtils.isValidCidrList("192.168.1.0/24")).thenReturn(true); + netUtilsMock.when(() -> NetUtils.isValidS2SVpnPolicy("ike", "aes128-sha256;modp2048")).thenReturn(true); + netUtilsMock.when(() -> NetUtils.isValidS2SVpnPolicy("esp", "aes128-sha256;modp2048")).thenReturn(true); + + when(_customerGatewayDao.findByNameAndAccountId("test-gateway", ACCOUNT_ID)).thenReturn(customerGateway); + + site2SiteVpnManager.createCustomerGateway(cmd); + } + } + + @Test(expected = InvalidParameterValueException.class) + public void testCreateCustomerGatewayInvalidIkeLifetime() { + CreateVpnCustomerGatewayCmd cmd = mock(CreateVpnCustomerGatewayCmd.class); + when(cmd.getGatewayIp()).thenReturn("1.2.3.4"); + when(cmd.getGuestCidrList()).thenReturn("192.168.1.0/24"); + when(cmd.getIkePolicy()).thenReturn("aes128-sha256;modp2048"); + when(cmd.getEspPolicy()).thenReturn("aes128-sha256;modp2048"); + when(cmd.getIkeLifetime()).thenReturn(86401L); + when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID); + + try (MockedStatic netUtilsMock = Mockito.mockStatic(NetUtils.class)) { + netUtilsMock.when(() -> NetUtils.isValidIp4("1.2.3.4")).thenReturn(true); + netUtilsMock.when(() -> NetUtils.isValidCidrList("192.168.1.0/24")).thenReturn(true); + netUtilsMock.when(() -> NetUtils.isValidS2SVpnPolicy("ike", "aes128-sha256;modp2048")).thenReturn(true); + netUtilsMock.when(() -> NetUtils.isValidS2SVpnPolicy("esp", "aes128-sha256;modp2048")).thenReturn(true); + + site2SiteVpnManager.createCustomerGateway(cmd); + } + } + + @Test(expected = InvalidParameterValueException.class) + public void testCreateCustomerGatewayInvalidEspLifetime() { + CreateVpnCustomerGatewayCmd cmd = mock(CreateVpnCustomerGatewayCmd.class); + when(cmd.getGatewayIp()).thenReturn("1.2.3.4"); + when(cmd.getGuestCidrList()).thenReturn("192.168.1.0/24"); + when(cmd.getIkePolicy()).thenReturn("aes128-sha256;modp2048"); + when(cmd.getEspPolicy()).thenReturn("aes128-sha256;modp2048"); + when(cmd.getEspLifetime()).thenReturn(86401L); + when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID); + + try (MockedStatic netUtilsMock = Mockito.mockStatic(NetUtils.class)) { + netUtilsMock.when(() -> NetUtils.isValidIp4("1.2.3.4")).thenReturn(true); + netUtilsMock.when(() -> NetUtils.isValidCidrList("192.168.1.0/24")).thenReturn(true); + netUtilsMock.when(() -> NetUtils.isValidS2SVpnPolicy("ike", "aes128-sha256;modp2048")).thenReturn(true); + netUtilsMock.when(() -> NetUtils.isValidS2SVpnPolicy("esp", "aes128-sha256;modp2048")).thenReturn(true); + + site2SiteVpnManager.createCustomerGateway(cmd); + } + } + + @Test(expected = InvalidParameterValueException.class) + public void testCreateCustomerGatewayTooManySubnets() { + CreateVpnCustomerGatewayCmd cmd = mock(CreateVpnCustomerGatewayCmd.class); + when(cmd.getGatewayIp()).thenReturn("1.2.3.4"); + String tooManyCidrs = "192.168.1.0/24,192.168.2.0/24,192.168.3.0/24,192.168.4.0/24,192.168.5.0/24," + + "192.168.6.0/24,192.168.7.0/24,192.168.8.0/24,192.168.9.0/24,192.168.10.0/24,192.168.11.0/24"; + when(cmd.getGuestCidrList()).thenReturn(tooManyCidrs); + when(cmd.getIkePolicy()).thenReturn("aes128-sha256;modp2048"); + when(cmd.getEspPolicy()).thenReturn("aes128-sha256;modp2048"); + when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID); + + try (MockedStatic netUtilsMock = Mockito.mockStatic(NetUtils.class)) { + netUtilsMock.when(() -> NetUtils.isValidIp4("1.2.3.4")).thenReturn(true); + netUtilsMock.when(() -> NetUtils.isValidCidrList(tooManyCidrs)).thenReturn(true); + netUtilsMock.when(() -> NetUtils.getCleanIp4CidrList(tooManyCidrs)).thenReturn(tooManyCidrs); + netUtilsMock.when(() -> NetUtils.isValidS2SVpnPolicy("ike", "aes128-sha256;modp2048")).thenReturn(true); + netUtilsMock.when(() -> NetUtils.isValidS2SVpnPolicy("esp", "aes128-sha256;modp2048")).thenReturn(true); + + site2SiteVpnManager.createCustomerGateway(cmd); + } + } + + @Test(expected = InvalidParameterValueException.class) + public void testCreateCustomerGatewayOverlappingSubnets() { + CreateVpnCustomerGatewayCmd cmd = mock(CreateVpnCustomerGatewayCmd.class); + when(cmd.getGatewayIp()).thenReturn("1.2.3.4"); + when(cmd.getGuestCidrList()).thenReturn("192.168.1.0/24,192.168.1.0/25"); + when(cmd.getIkePolicy()).thenReturn("aes128-sha256;modp2048"); + when(cmd.getEspPolicy()).thenReturn("aes128-sha256;modp2048"); + when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID); + + try (MockedStatic netUtilsMock = Mockito.mockStatic(NetUtils.class)) { + String cidrList = "192.168.1.0/24,192.168.1.0/25"; + netUtilsMock.when(() -> NetUtils.isValidIp4("1.2.3.4")).thenReturn(true); + netUtilsMock.when(() -> NetUtils.isValidCidrList(cidrList)).thenReturn(true); + netUtilsMock.when(() -> NetUtils.getCleanIp4CidrList(cidrList)).thenReturn(cidrList); + netUtilsMock.when(() -> NetUtils.isValidS2SVpnPolicy("ike", "aes128-sha256;modp2048")).thenReturn(true); + netUtilsMock.when(() -> NetUtils.isValidS2SVpnPolicy("esp", "aes128-sha256;modp2048")).thenReturn(true); + netUtilsMock.when(() -> NetUtils.isNetworksOverlap("192.168.1.0/24", "192.168.1.0/25")).thenReturn(true); + + site2SiteVpnManager.createCustomerGateway(cmd); + } + } + + @Test(expected = InvalidParameterValueException.class) + public void testCreateVpnConnectionCidrOverlapWithVpc() { + CreateVpnConnectionCmd cmd = mock(CreateVpnConnectionCmd.class); + when(cmd.getVpnGatewayId()).thenReturn(VPN_GATEWAY_ID); + when(cmd.getCustomerGatewayId()).thenReturn(CUSTOMER_GATEWAY_ID); + when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID); + + Site2SiteCustomerGatewayVO customerGw = mock(Site2SiteCustomerGatewayVO.class); + when(customerGw.getGuestCidrList()).thenReturn("10.0.0.0/24"); + when(customerGw.getAccountId()).thenReturn(ACCOUNT_ID); + when(customerGw.getDomainId()).thenReturn(DOMAIN_ID); + + when(_customerGatewayDao.findById(CUSTOMER_GATEWAY_ID)).thenReturn(customerGw); + when(_vpnGatewayDao.findById(VPN_GATEWAY_ID)).thenReturn(vpnGateway); + when(_vpnConnectionDao.findByVpnGatewayIdAndCustomerGatewayId(VPN_GATEWAY_ID, CUSTOMER_GATEWAY_ID)).thenReturn(null); + when(_vpnGatewayDao.findByVpcId(VPC_ID)).thenReturn(vpnGateway); + when(_vpcDao.findById(VPC_ID)).thenReturn(vpc); + + try (MockedStatic netUtilsMock = Mockito.mockStatic(NetUtils.class)) { + netUtilsMock.when(() -> NetUtils.isNetworksOverlap("10.0.0.0/16", "10.0.0.0/24")).thenReturn(true); + + site2SiteVpnManager.createVpnConnection(cmd); + } + } + + @Test(expected = InvalidParameterValueException.class) + public void testCreateVpnConnectionExceedsLimit() { + CreateVpnConnectionCmd cmd = mock(CreateVpnConnectionCmd.class); + when(cmd.getVpnGatewayId()).thenReturn(VPN_GATEWAY_ID); + when(cmd.getCustomerGatewayId()).thenReturn(CUSTOMER_GATEWAY_ID); + when(cmd.getEntityOwnerId()).thenReturn(ACCOUNT_ID); + + when(_customerGatewayDao.findById(CUSTOMER_GATEWAY_ID)).thenReturn(customerGateway); + when(_vpnGatewayDao.findById(VPN_GATEWAY_ID)).thenReturn(vpnGateway); + when(_vpnConnectionDao.findByVpnGatewayIdAndCustomerGatewayId(VPN_GATEWAY_ID, CUSTOMER_GATEWAY_ID)).thenReturn(null); + when(_vpnGatewayDao.findByVpcId(VPC_ID)).thenReturn(vpnGateway); + when(_vpcDao.findById(VPC_ID)).thenReturn(vpc); + + List existingConns = new ArrayList<>(); + for (int i = 0; i < 4; i++) { + existingConns.add(mock(Site2SiteVpnConnectionVO.class)); + } + when(_vpnConnectionDao.listByVpnGatewayId(VPN_GATEWAY_ID)).thenReturn(existingConns); + + site2SiteVpnManager.createVpnConnection(cmd); + } + + @Test + public void testDeleteCustomerGatewaySuccess() { + DeleteVpnCustomerGatewayCmd cmd = mock(DeleteVpnCustomerGatewayCmd.class); + when(cmd.getId()).thenReturn(CUSTOMER_GATEWAY_ID); + + when(_customerGatewayDao.findById(CUSTOMER_GATEWAY_ID)).thenReturn(customerGateway); + when(_vpnConnectionDao.listByCustomerGatewayId(CUSTOMER_GATEWAY_ID)).thenReturn(new ArrayList<>()); + + boolean result = site2SiteVpnManager.deleteCustomerGateway(cmd); + + assertTrue(result); + verify(_customerGatewayDao).remove(CUSTOMER_GATEWAY_ID); + } + + @Test(expected = InvalidParameterValueException.class) + public void testDeleteCustomerGatewayWithConnections() { + DeleteVpnCustomerGatewayCmd cmd = mock(DeleteVpnCustomerGatewayCmd.class); + when(cmd.getId()).thenReturn(CUSTOMER_GATEWAY_ID); + + when(_customerGatewayDao.findById(CUSTOMER_GATEWAY_ID)).thenReturn(customerGateway); + when(_vpnConnectionDao.listByCustomerGatewayId(CUSTOMER_GATEWAY_ID)).thenReturn(List.of(vpnConnection)); + + site2SiteVpnManager.deleteCustomerGateway(cmd); + } + + @Test + public void testDeleteVpnGatewaySuccess() { + DeleteVpnGatewayCmd cmd = mock(DeleteVpnGatewayCmd.class); + when(cmd.getId()).thenReturn(VPN_GATEWAY_ID); + + when(_vpnGatewayDao.findById(VPN_GATEWAY_ID)).thenReturn(vpnGateway); + when(_vpnConnectionDao.listByVpnGatewayId(VPN_GATEWAY_ID)).thenReturn(new ArrayList<>()); + + boolean result = site2SiteVpnManager.deleteVpnGateway(cmd); + + assertTrue(result); + verify(_vpnGatewayDao).remove(VPN_GATEWAY_ID); + } + + @Test(expected = InvalidParameterValueException.class) + public void testDeleteVpnGatewayWithConnections() { + DeleteVpnGatewayCmd cmd = mock(DeleteVpnGatewayCmd.class); + when(cmd.getId()).thenReturn(VPN_GATEWAY_ID); + + when(_vpnGatewayDao.findById(VPN_GATEWAY_ID)).thenReturn(vpnGateway); + when(_vpnConnectionDao.listByVpnGatewayId(VPN_GATEWAY_ID)).thenReturn(List.of(vpnConnection)); + + site2SiteVpnManager.deleteVpnGateway(cmd); + } + + @Test + public void testDeleteVpnConnectionSuccess() throws ResourceUnavailableException { + DeleteVpnConnectionCmd cmd = mock(DeleteVpnConnectionCmd.class); + when(cmd.getId()).thenReturn(VPN_CONNECTION_ID); + + when(_vpnConnectionDao.findById(VPN_CONNECTION_ID)).thenReturn(vpnConnection); + vpnConnection.setState(State.Pending); + when(_vpnGatewayDao.findById(VPN_GATEWAY_ID)).thenReturn(vpnGateway); + when(_vpcMgr.applyStaticRouteForVpcVpnIfNeeded(anyLong(), anyBoolean())).thenReturn(true); + + boolean result = site2SiteVpnManager.deleteVpnConnection(cmd); + + assertTrue(result); + verify(_vpnConnectionDao).remove(VPN_CONNECTION_ID); + } + + @Test + public void testStartVpnConnectionSuccess() throws ResourceUnavailableException { + when(_vpnConnectionDao.acquireInLockTable(VPN_CONNECTION_ID)).thenReturn(vpnConnection); + vpnConnection.setState(State.Pending); + when(_vpnGatewayDao.findById(VPN_GATEWAY_ID)).thenReturn(vpnGateway); + Site2SiteVpnServiceProvider provider = mock(Site2SiteVpnServiceProvider.class); + when(provider.startSite2SiteVpn(any(Site2SiteVpnConnection.class))).thenReturn(true); + when(_s2sProviders.iterator()).thenReturn(List.of(provider).iterator()); + when(_vpnConnectionDao.persist(any(Site2SiteVpnConnectionVO.class))).thenReturn(vpnConnection); + when(_vpcMgr.applyStaticRouteForVpcVpnIfNeeded(anyLong(), anyBoolean())).thenReturn(true); + + Site2SiteVpnConnection result = site2SiteVpnManager.startVpnConnection(VPN_CONNECTION_ID); + + assertNotNull(result); + verify(_vpnConnectionDao, org.mockito.Mockito.atLeastOnce()).persist(any(Site2SiteVpnConnectionVO.class)); + } + + @Test(expected = InvalidParameterValueException.class) + public void testStartVpnConnectionWrongState() throws ResourceUnavailableException { + when(_vpnConnectionDao.acquireInLockTable(VPN_CONNECTION_ID)).thenReturn(vpnConnection); + vpnConnection.setState(State.Connected); + + site2SiteVpnManager.startVpnConnection(VPN_CONNECTION_ID); + } + + @Test + public void testResetVpnConnectionSuccess() throws ResourceUnavailableException { + ResetVpnConnectionCmd cmd = mock(ResetVpnConnectionCmd.class); + when(cmd.getId()).thenReturn(VPN_CONNECTION_ID); + + when(_vpnConnectionDao.findById(VPN_CONNECTION_ID)).thenReturn(vpnConnection); + vpnConnection.setState(State.Connected); + when(_vpnConnectionDao.acquireInLockTable(VPN_CONNECTION_ID)).thenReturn(vpnConnection); + when(_vpnGatewayDao.findById(VPN_GATEWAY_ID)).thenReturn(vpnGateway); + Site2SiteVpnServiceProvider provider = mock(Site2SiteVpnServiceProvider.class); + when(provider.stopSite2SiteVpn(any(Site2SiteVpnConnection.class))).thenReturn(true); + when(provider.startSite2SiteVpn(any(Site2SiteVpnConnection.class))).thenReturn(true); + when(_s2sProviders.iterator()).thenReturn(List.of(provider).iterator()); + when(_vpnConnectionDao.persist(any(Site2SiteVpnConnectionVO.class))).thenReturn(vpnConnection); + when(_vpcMgr.applyStaticRouteForVpcVpnIfNeeded(anyLong(), anyBoolean())).thenReturn(true); + + Site2SiteVpnConnection result = site2SiteVpnManager.resetVpnConnection(cmd); + + assertNotNull(result); + } + + @Test + public void testCleanupVpnConnectionByVpc() { + when(_vpnConnectionDao.listByVpcId(VPC_ID)).thenReturn(List.of(vpnConnection)); + + boolean result = site2SiteVpnManager.cleanupVpnConnectionByVpc(VPC_ID); + + assertTrue(result); + verify(_vpnConnectionDao).remove(vpnConnection.getId()); + } + + @Test + public void testCleanupVpnGatewayByVpc() { + when(_vpnGatewayDao.findByVpcId(VPC_ID)).thenReturn(vpnGateway); + when(_vpnConnectionDao.listByVpnGatewayId(VPN_GATEWAY_ID)).thenReturn(new ArrayList<>()); + + boolean result = site2SiteVpnManager.cleanupVpnGatewayByVpc(VPC_ID); + + assertTrue(result); + verify(_vpnGatewayDao).remove(VPN_GATEWAY_ID); + } + + @Test + public void testCleanupVpnGatewayByVpcNotFound() { + when(_vpnGatewayDao.findByVpcId(VPC_ID)).thenReturn(null); + + boolean result = site2SiteVpnManager.cleanupVpnGatewayByVpc(VPC_ID); + + assertTrue(result); + verify(_vpnGatewayDao, never()).remove(anyLong()); + } + + @Test + public void testGetConnectionsForRouter() { + DomainRouterVO router = mock(DomainRouterVO.class); + when(router.getVpcId()).thenReturn(VPC_ID); + when(_vpnConnectionDao.listByVpcId(VPC_ID)).thenReturn(List.of(vpnConnection)); + + List result = site2SiteVpnManager.getConnectionsForRouter(router); + + assertNotNull(result); + assertEquals(1, result.size()); + } + + @Test + public void testGetConnectionsForRouterNoVpc() { + DomainRouterVO router = mock(DomainRouterVO.class); + when(router.getVpcId()).thenReturn(null); + + List result = site2SiteVpnManager.getConnectionsForRouter(router); + + assertNotNull(result); + assertTrue(result.isEmpty()); + } + + @Test + public void testDeleteCustomerGatewayByAccount() { + when(_customerGatewayDao.listByAccountId(ACCOUNT_ID)).thenReturn(List.of(customerGateway)); + when(_vpnConnectionDao.listByCustomerGatewayId(CUSTOMER_GATEWAY_ID)).thenReturn(new ArrayList<>()); + + boolean result = site2SiteVpnManager.deleteCustomerGatewayByAccount(ACCOUNT_ID); + + assertTrue(result); + verify(_customerGatewayDao).remove(CUSTOMER_GATEWAY_ID); + } + + @Test + public void testReconnectDisconnectedVpnByVpc() throws ResourceUnavailableException { + Site2SiteVpnConnectionVO conn = mock(Site2SiteVpnConnectionVO.class); + when(conn.getId()).thenReturn(VPN_CONNECTION_ID); + when(conn.getState()).thenReturn(State.Disconnected); + when(conn.getCustomerGatewayId()).thenReturn(CUSTOMER_GATEWAY_ID); + when(conn.getVpnGatewayId()).thenReturn(VPN_GATEWAY_ID); + when(_vpnConnectionDao.listByVpcId(VPC_ID)).thenReturn(List.of(conn)); + when(_customerGatewayDao.findById(CUSTOMER_GATEWAY_ID)).thenReturn(customerGateway); + when(_vpnConnectionDao.acquireInLockTable(VPN_CONNECTION_ID)).thenReturn(conn); + when(_vpnGatewayDao.findById(VPN_GATEWAY_ID)).thenReturn(vpnGateway); + Site2SiteVpnServiceProvider provider = mock(Site2SiteVpnServiceProvider.class); + when(provider.startSite2SiteVpn(any(Site2SiteVpnConnection.class))).thenReturn(true); + when(_s2sProviders.iterator()).thenReturn(List.of(provider).iterator()); + when(_vpnConnectionDao.persist(any(Site2SiteVpnConnectionVO.class))).thenReturn(conn); + when(_vpcMgr.applyStaticRouteForVpcVpnIfNeeded(anyLong(), anyBoolean())).thenReturn(true); + + site2SiteVpnManager.reconnectDisconnectedVpnByVpc(VPC_ID); + + verify(_vpnConnectionDao, org.mockito.Mockito.atLeastOnce()).persist(any(Site2SiteVpnConnectionVO.class)); + } + + @Test + public void testUpdateVpnConnection() { + when(_vpnConnectionDao.findById(VPN_CONNECTION_ID)).thenReturn(vpnConnection); + when(_vpnConnectionDao.update(anyLong(), any(Site2SiteVpnConnectionVO.class))).thenReturn(true); + when(_vpnConnectionDao.findById(VPN_CONNECTION_ID)).thenReturn(vpnConnection); + + Site2SiteVpnConnection result = site2SiteVpnManager.updateVpnConnection(VPN_CONNECTION_ID, "custom-id", true); + + assertNotNull(result); + } + + @Test + public void testUpdateVpnGateway() { + when(_vpnGatewayDao.findById(VPN_GATEWAY_ID)).thenReturn(vpnGateway); + when(_vpnGatewayDao.update(anyLong(), any(Site2SiteVpnGatewayVO.class))).thenReturn(true); + when(_vpnGatewayDao.findById(VPN_GATEWAY_ID)).thenReturn(vpnGateway); + + Site2SiteVpnGateway result = site2SiteVpnManager.updateVpnGateway(VPN_GATEWAY_ID, "custom-id", true); + + assertNotNull(result); + } + + @Test + public void testVpnGatewayContainsExcludedParametersWithExcludedIkeVersion() throws Exception { + Site2SiteCustomerGatewayVO gw = mock(Site2SiteCustomerGatewayVO.class); + when(gw.getIkePolicy()).thenReturn("aes128-sha256;modp2048"); + when(gw.getEspPolicy()).thenReturn("aes128-sha256;modp2048"); + when(gw.getIkeVersion()).thenReturn("ikev1"); + when(gw.getDomainId()).thenReturn(DOMAIN_ID); + + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedIkeVersions, "ikev1"); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedEncryptionAlgorithms, ""); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedHashingAlgorithms, ""); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedDhGroup, ""); + + java.util.Set result = site2SiteVpnManager.getExcludedVpnGatewayParameters(gw); + assertFalse("Should detect excluded IKE version", result.isEmpty()); + assertEquals("Should detect excluded IKE version", "[ikev1]", result.toString()); + } + + @Test + public void testVpnGatewayContainsExcludedParametersWithExcludedEncryption() throws Exception { + Site2SiteCustomerGatewayVO gw = mock(Site2SiteCustomerGatewayVO.class); + when(gw.getIkePolicy()).thenReturn("3des-sha256;modp2048"); + when(gw.getEspPolicy()).thenReturn("aes128-sha256;modp2048"); + when(gw.getIkeVersion()).thenReturn("ike"); + when(gw.getDomainId()).thenReturn(DOMAIN_ID); + + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedIkeVersions, ""); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedEncryptionAlgorithms, "3des"); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedHashingAlgorithms, ""); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedDhGroup, ""); + + java.util.Set result = site2SiteVpnManager.getExcludedVpnGatewayParameters(gw); + assertFalse("Should detect excluded encryption algorithm", result.isEmpty()); + assertEquals("Should detect excluded encryption algorithm", "[3des]", result.toString()); + } + + @Test + public void testVpnGatewayContainsExcludedParametersWithExcludedHashing() throws Exception { + Site2SiteCustomerGatewayVO gw = mock(Site2SiteCustomerGatewayVO.class); + when(gw.getIkePolicy()).thenReturn("aes128-md5;modp2048"); + when(gw.getEspPolicy()).thenReturn("aes128-sha256;modp2048"); + when(gw.getIkeVersion()).thenReturn("ike"); + when(gw.getDomainId()).thenReturn(DOMAIN_ID); + + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedIkeVersions, ""); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedEncryptionAlgorithms, "aes128"); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedHashingAlgorithms, "md5"); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedDhGroup, ""); + + java.util.Set result = site2SiteVpnManager.getExcludedVpnGatewayParameters(gw); + assertFalse("Should detect excluded algorithms", result.isEmpty()); + assertEquals("Should detect excluded algorithms", "[aes128, md5]", result.toString()); + } + + @Test + public void testVpnGatewayContainsExcludedParametersWithExcludedDhGroup() { + Site2SiteCustomerGatewayVO gw = mock(Site2SiteCustomerGatewayVO.class); + when(gw.getIkePolicy()).thenReturn("aes128-sha256;modp1024"); + when(gw.getEspPolicy()).thenReturn("aes128-sha256;modp2048"); + when(gw.getIkeVersion()).thenReturn("ike"); + when(gw.getDomainId()).thenReturn(DOMAIN_ID); + + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedIkeVersions, ""); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedEncryptionAlgorithms, ""); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedHashingAlgorithms, ""); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedDhGroup, "modp1024"); + + java.util.Set result = site2SiteVpnManager.getExcludedVpnGatewayParameters(gw); + assertFalse("Should detect excluded DH group", result.isEmpty()); + assertEquals("Should detect excluded DH group", "[modp1024]", result.toString()); + } + + @Test + public void testVpnGatewayContainsExcludedParametersNoExcludedParameters() { + Site2SiteCustomerGatewayVO gw = mock(Site2SiteCustomerGatewayVO.class); + when(gw.getIkePolicy()).thenReturn("aes128-sha256;modp2048"); + when(gw.getEspPolicy()).thenReturn("aes128-sha256;modp2048"); + when(gw.getIkeVersion()).thenReturn("ike"); + when(gw.getDomainId()).thenReturn(DOMAIN_ID); + + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedIkeVersions, ""); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedEncryptionAlgorithms, ""); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedHashingAlgorithms, ""); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedDhGroup, ""); + + java.util.Set result = site2SiteVpnManager.getExcludedVpnGatewayParameters(gw); + assertTrue("Should not detect excluded parameters when none are configured", result.isEmpty()); + } + + @Test + public void testVpnGatewayContainsExcludedParametersWithExcludedEspPolicy() { + Site2SiteCustomerGatewayVO gw = mock(Site2SiteCustomerGatewayVO.class); + when(gw.getIkePolicy()).thenReturn("aes128-sha256;modp2048"); + when(gw.getEspPolicy()).thenReturn("3des-sha256;modp2048"); + when(gw.getIkeVersion()).thenReturn("ike"); + when(gw.getDomainId()).thenReturn(DOMAIN_ID); + + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedIkeVersions, ""); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedEncryptionAlgorithms, "3des"); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedHashingAlgorithms, ""); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayExcludedDhGroup, ""); + + java.util.Set result = site2SiteVpnManager.getExcludedVpnGatewayParameters(gw); + assertFalse("Should detect excluded encryption in ESP policy", result.isEmpty()); + assertEquals("Should detect excluded encryption in ESP policy", "[3des]", result.toString()); + } + + @Test + public void testVpnGatewayContainsObsoleteParametersWithObsoleteIkeVersion() { + Site2SiteCustomerGatewayVO gw = mock(Site2SiteCustomerGatewayVO.class); + when(gw.getIkePolicy()).thenReturn("aes128-sha256;modp2048"); + when(gw.getEspPolicy()).thenReturn("aes128-sha256;modp2048"); + when(gw.getIkeVersion()).thenReturn("ikev1"); + when(gw.getDomainId()).thenReturn(DOMAIN_ID); + + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteIkeVersions, "ikev1"); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteEncryptionAlgorithms, ""); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteHashingAlgorithms, ""); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteDhGroup, ""); + + java.util.Set result = site2SiteVpnManager.getObsoleteVpnGatewayParameters(gw); + assertFalse("Should detect obsolete IKE version", result.isEmpty()); + assertEquals("Should detect obsolete IKE version", "[ikev1]", result.toString()); + } + + @Test + public void testVpnGatewayContainsObsoleteParametersWithObsoleteEncryption() { + Site2SiteCustomerGatewayVO gw = mock(Site2SiteCustomerGatewayVO.class); + when(gw.getIkePolicy()).thenReturn("3des-sha256;modp2048"); + when(gw.getEspPolicy()).thenReturn("aes128-sha256;modp2048"); + when(gw.getIkeVersion()).thenReturn("ike"); + when(gw.getDomainId()).thenReturn(DOMAIN_ID); + + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteIkeVersions, ""); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteEncryptionAlgorithms, "3des"); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteHashingAlgorithms, ""); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteDhGroup, ""); + + java.util.Set result = site2SiteVpnManager.getObsoleteVpnGatewayParameters(gw); + assertFalse("Should detect obsolete encryption algorithm", result.isEmpty()); + assertEquals("Should detect obsolete encryption algorithm", "[3des]", result.toString()); + } + + @Test + public void testVpnGatewayContainsObsoleteParametersWithObsoleteHashing() { + Site2SiteCustomerGatewayVO gw = mock(Site2SiteCustomerGatewayVO.class); + when(gw.getIkePolicy()).thenReturn("aes128-md5;modp2048"); + when(gw.getEspPolicy()).thenReturn("aes128-sha256;modp2048"); + when(gw.getIkeVersion()).thenReturn("ike"); + when(gw.getDomainId()).thenReturn(DOMAIN_ID); + + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteIkeVersions, ""); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteEncryptionAlgorithms, ""); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteHashingAlgorithms, "md5"); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteDhGroup, ""); + + java.util.Set result = site2SiteVpnManager.getObsoleteVpnGatewayParameters(gw); + assertFalse("Should detect obsolete hashing algorithm", result.isEmpty()); + assertEquals("Should detect obsolete hashing algorithm", "[md5]", result.toString()); + } + + @Test + public void testVpnGatewayContainsObsoleteParametersWithObsoleteDhGroup() { + Site2SiteCustomerGatewayVO gw = mock(Site2SiteCustomerGatewayVO.class); + when(gw.getIkePolicy()).thenReturn("aes128-sha256;modp1024"); + when(gw.getEspPolicy()).thenReturn("aes128-sha256;modp2048"); + when(gw.getIkeVersion()).thenReturn("ike"); + when(gw.getDomainId()).thenReturn(DOMAIN_ID); + + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteIkeVersions, ""); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteEncryptionAlgorithms, ""); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteHashingAlgorithms, ""); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteDhGroup, "modp1024"); + + java.util.Set result = site2SiteVpnManager.getObsoleteVpnGatewayParameters(gw); + assertFalse("Should detect obsolete DH group", result.isEmpty()); + assertEquals("Should detect obsolete DH group", "[modp1024]", result.toString()); + } + + @Test + public void testVpnGatewayContainsObsoleteParametersNoObsoleteParameters() { + Site2SiteCustomerGatewayVO gw = mock(Site2SiteCustomerGatewayVO.class); + when(gw.getIkePolicy()).thenReturn("aes128-sha256;modp2048"); + when(gw.getEspPolicy()).thenReturn("aes128-sha256;modp2048"); + when(gw.getIkeVersion()).thenReturn("ike"); + when(gw.getDomainId()).thenReturn(DOMAIN_ID); + + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteIkeVersions, ""); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteEncryptionAlgorithms, ""); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteHashingAlgorithms, ""); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteDhGroup, ""); + + java.util.Set result = site2SiteVpnManager.getObsoleteVpnGatewayParameters(gw); + assertTrue("Should not detect obsolete parameters when none are configured", result.isEmpty()); + } + + @Test + public void testVpnGatewayContainsObsoleteParametersWithObsoleteEspPolicy() { + Site2SiteCustomerGatewayVO gw = mock(Site2SiteCustomerGatewayVO.class); + when(gw.getIkePolicy()).thenReturn("aes128-sha256;modp2048"); + when(gw.getEspPolicy()).thenReturn("3des-sha256;modp2048"); + when(gw.getIkeVersion()).thenReturn("ike"); + when(gw.getDomainId()).thenReturn(DOMAIN_ID); + + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteIkeVersions, ""); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteEncryptionAlgorithms, "3des"); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteHashingAlgorithms, ""); + setConfigKeyValue(Site2SiteVpnManagerImpl.VpnCustomerGatewayObsoleteDhGroup, ""); + + java.util.Set result = site2SiteVpnManager.getObsoleteVpnGatewayParameters(gw); + assertFalse("Should detect obsolete encryption in ESP policy", result.isEmpty()); + assertEquals("Should detect obsolete encryption in ESP policy", "[3des]", result.toString()); + } +} diff --git a/server/src/test/java/com/cloud/vpc/MockSite2SiteVpnManagerImpl.java b/server/src/test/java/com/cloud/vpc/MockSite2SiteVpnManagerImpl.java index 3558eed1cfa1..af6c1c599aab 100644 --- a/server/src/test/java/com/cloud/vpc/MockSite2SiteVpnManagerImpl.java +++ b/server/src/test/java/com/cloud/vpc/MockSite2SiteVpnManagerImpl.java @@ -23,7 +23,6 @@ import com.cloud.network.Site2SiteVpnGateway; import com.cloud.network.dao.Site2SiteVpnConnectionVO; import com.cloud.network.vpn.Site2SiteVpnManager; -import com.cloud.network.vpn.Site2SiteVpnService; import com.cloud.utils.Pair; import com.cloud.utils.component.ManagerBase; import com.cloud.vm.DomainRouterVO; @@ -41,11 +40,13 @@ import org.springframework.stereotype.Component; import javax.naming.ConfigurationException; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; @Component -public class MockSite2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpnManager, Site2SiteVpnService { +public class MockSite2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpnManager { /* (non-Javadoc) * @see com.cloud.network.vpn.Site2SiteVpnService#createVpnGateway(org.apache.cloudstack.api.commands.CreateVpnGatewayCmd) @@ -275,4 +276,16 @@ public Site2SiteVpnGateway updateVpnGateway(Long id, String customId, Boolean fo return null; } + @Override + public Set getExcludedVpnGatewayParameters(Site2SiteCustomerGateway customerGw) { + // TODO Auto-generated method stub + return new HashSet<>(); + } + + @Override + public Set getObsoleteVpnGatewayParameters(Site2SiteCustomerGateway customerGw) { + // TODO Auto-generated method stub + return new HashSet<>(); + } + } diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index 028406bbc682..942a605650bb 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -2613,6 +2613,7 @@ "label.update.to": "updated to", "label.update.traffic.label": "Update traffic labels", "label.update.vmware.datacenter": "Update VMWare datacenter", +"label.update.vpn.customer.gateway": "Update VPN Customer Gateway", "label.update.webhook": "Update Webhook", "label.updating": "Updating", "label.upgrade.router.newer.template": "Upgrade router to use newer Template", @@ -3939,6 +3940,7 @@ "message.success.update.network": "Successfully updated Network", "message.success.update.template": "Successfully updated Template", "message.success.update.user": "Successfully updated User", +"message.success.update.vpn.customer.gateway": "Successfully updated VPN customer gateway", "message.success.upgrade.kubernetes": "Successfully upgraded Kubernetes Cluster", "message.success.upload": "Successfully uploaded", "message.success.upload.description": "This ISO file has been uploaded. Please check its status in the Templates menu.", @@ -3966,6 +3968,9 @@ "message.update.condition.failed": "Failed to update condition", "message.update.condition.processing": "Updating condition...", "message.update.failed": "Update failed", +"message.update.vpn.customer.gateway": "Update VPN customer gateway", +"message.update.vpn.customer.gateway.failed": "Updating the VPN customer gateway failed", +"message.update.vpn.customer.gateway.processing": "Updating VPN customer gateway...", "message.test.webhook.delivery": "Test delivery to the Webhook with an optional payload", "message.two.factor.authorization.failed": "Unable to verify 2FA with provided code, please retry.", "message.two.fa.auth": "Open the two-factor authentication app on your mobile device to view your authentication code.", @@ -4052,6 +4057,11 @@ "message.volumes.managed": "Volumes controlled by CloudStack.", "message.volumes.unmanaged": "Volumes not controlled by CloudStack.", "message.vpc.restart.required": "Restart is required for VPC(s). Click here to view VPC(s) which require restart.", +"message.vpn.customer.gateway.contains.obsolete.parameters": "The VPN Customer Gateway is configured with parameters marked as obsolete. Consider changing the parameters using Update VPN Customer Gateway.", +"message.vpn.customer.gateway.excluded.parameter": " is marked as excluded. Please choose another value.", +"message.vpn.customer.gateway.obsolete.parameter": " is marked as obsolete/insecure. Please choose another value.", +"message.vpn.customer.gateway.obsolete.parameter.tooltip": "This parameter value is marked as obsolete/insecure.", +"message.vr.alert.upon.network.offering.creation.l2": "As virtual routers are not created for L2 Networks, the compute offering will not be used.", "message.vr.alert.upon.network.offering.creation.others": "As none of the obligatory services for creating a virtual router (VPN, DHCP, DNS, Firewall, LB, UserData, SourceNat, StaticNat, PortForwarding) are enabled, the virtual router will not be created and the compute offering will not be used.", "message.warn.change.primary.storage.scope": "This feature is tested and supported for the following configurations:
KVM - NFS/Ceph - DefaultPrimary
VMware - NFS - DefaultPrimary
*There might be extra steps involved to make it work for other configurations.", "message.warn.filetype": "jpg, jpeg, png, bmp and svg are the only supported image formats.", diff --git a/ui/src/components/view/ListView.vue b/ui/src/components/view/ListView.vue index 47aa3d2ddef1..e0af9140164c 100644 --- a/ui/src/components/view/ListView.vue +++ b/ui/src/components/view/ListView.vue @@ -178,6 +178,12 @@ + +   + + + + import('@/views/network/UpdateVpnCustomerGateway.vue'))) }, { api: 'deleteVpnCustomerGateway', diff --git a/ui/src/views/network/CreateVpnCustomerGateway.vue b/ui/src/views/network/CreateVpnCustomerGateway.vue index f71fc4709e8d..155765a276f5 100644 --- a/ui/src/views/network/CreateVpnCustomerGateway.vue +++ b/ui/src/views/network/CreateVpnCustomerGateway.vue @@ -15,352 +15,58 @@ // specific language governing permissions and limitations // under the License. + - diff --git a/ui/src/views/network/UpdateVpnCustomerGateway.vue b/ui/src/views/network/UpdateVpnCustomerGateway.vue new file mode 100644 index 000000000000..81a390436f4e --- /dev/null +++ b/ui/src/views/network/UpdateVpnCustomerGateway.vue @@ -0,0 +1,128 @@ +// 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. + + + diff --git a/ui/src/views/network/VpnCustomerGateway.vue b/ui/src/views/network/VpnCustomerGateway.vue new file mode 100644 index 000000000000..7331c0b82d7c --- /dev/null +++ b/ui/src/views/network/VpnCustomerGateway.vue @@ -0,0 +1,581 @@ +// 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. + + + +