DaanHoogland closed pull request #2357: CLOUDSTACK-10182 Restrict volumes and
templates download per user for security purposes
URL: https://github.com/apache/cloudstack/pull/2357
This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:
As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):
diff --git
a/api/src/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java
b/api/src/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java
index 9c526563d44..c82c291e9c2 100644
---
a/api/src/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java
+++
b/api/src/org/apache/cloudstack/api/command/user/config/ListCapabilitiesCmd.java
@@ -59,6 +59,7 @@ public void execute() {
response.setKVMSnapshotEnabled((Boolean)capabilities.get("KVMSnapshotEnabled"));
response.setAllowUserViewDestroyedVM((Boolean)capabilities.get("allowUserViewDestroyedVM"));
response.setAllowUserExpungeRecoverVM((Boolean)capabilities.get("allowUserExpungeRecoverVM"));
+
response.setAllowVolumeExtraction((Boolean)capabilities.get("allowVolumeExtraction"));
if (capabilities.containsKey("apiLimitInterval")) {
response.setApiLimitInterval((Integer)capabilities.get("apiLimitInterval"));
}
diff --git
a/api/src/org/apache/cloudstack/api/response/CapabilitiesResponse.java
b/api/src/org/apache/cloudstack/api/response/CapabilitiesResponse.java
index bcdad468fac..5dcf22e5875 100644
--- a/api/src/org/apache/cloudstack/api/response/CapabilitiesResponse.java
+++ b/api/src/org/apache/cloudstack/api/response/CapabilitiesResponse.java
@@ -84,6 +84,10 @@
@Param(description = "true if the user can recover and expunge
virtualmachines, false otherwise", since = "4.6.0")
private boolean allowUserExpungeRecoverVM;
+ @SerializedName("allowvolumeextraction")
+ @Param(description = "If false, users will not be able to extract volumes
and templates")
+ private boolean allowVolumeExtraction;
+
public void setSecurityGroupsEnabled(boolean securityGroupsEnabled) {
this.securityGroupsEnabled = securityGroupsEnabled;
}
@@ -143,4 +147,8 @@ public void setAllowUserViewDestroyedVM(boolean
allowUserViewDestroyedVM) {
public void setAllowUserExpungeRecoverVM(boolean
allowUserExpungeRecoverVM) {
this.allowUserExpungeRecoverVM = allowUserExpungeRecoverVM;
}
+
+ public void setAllowVolumeExtraction(boolean allowVolumeExtraction) {
+ this.allowVolumeExtraction = allowVolumeExtraction;
+ }
}
\ No newline at end of file
diff --git a/engine/components-api/src/com/cloud/template/TemplateManager.java
b/engine/components-api/src/com/cloud/template/TemplateManager.java
index 68c3b585692..38f6fedd0f4 100644
--- a/engine/components-api/src/com/cloud/template/TemplateManager.java
+++ b/engine/components-api/src/com/cloud/template/TemplateManager.java
@@ -39,6 +39,7 @@
public interface TemplateManager {
static final String AllowPublicUserTemplatesCK =
"allow.public.user.templates";
static final String TemplatePreloaderPoolSizeCK =
"template.preloader.pool.size";
+ static final String AllowVolumeExtractionCK = "allow.volume.extraction";
static final ConfigKey<Boolean> AllowPublicUserTemplates = new
ConfigKey<Boolean>("Advanced", Boolean.class, AllowPublicUserTemplatesCK,
"true",
"If false, users will not be able to create public templates.", true,
ConfigKey.Scope.Account);
@@ -46,6 +47,8 @@
static final ConfigKey<Integer> TemplatePreloaderPoolSize = new
ConfigKey<Integer>("Advanced", Integer.class, TemplatePreloaderPoolSizeCK, "8",
"Size of the TemplateManager threadpool", false,
ConfigKey.Scope.Global);
+ static final ConfigKey<Boolean> AllowVolumeExtraction = new
ConfigKey<Boolean>("Advanced", Boolean.class, AllowVolumeExtractionCK, "true",
+ "If false, users will not be able to extract volumes and
templates", true, ConfigKey.Scope.Account);
/**
diff --git a/server/src/com/cloud/server/ManagementServerImpl.java
b/server/src/com/cloud/server/ManagementServerImpl.java
index da987ca1330..20f7fdcf708 100644
--- a/server/src/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/com/cloud/server/ManagementServerImpl.java
@@ -3370,6 +3370,7 @@ private String signRequest(final String request, final
String key) {
boolean securityGroupsEnabled = false;
boolean elasticLoadBalancerEnabled = false;
boolean KVMSnapshotEnabled = false;
+ boolean allowVolumeExtraction = false;
String supportELB = "false";
final List<NetworkVO> networks =
_networkDao.listSecurityGroupEnabledNetworks();
if (networks != null && !networks.isEmpty()) {
@@ -3388,6 +3389,9 @@ private String signRequest(final String request, final
String key) {
final long diskOffMaxSize =
VolumeOrchestrationService.CustomDiskOfferingMaxSize.value();
KVMSnapshotEnabled =
Boolean.parseBoolean(_configDao.getValue("KVM.snapshot.enabled"));
+ Account account = CallContext.current().getCallingAccount();
+ allowVolumeExtraction =
TemplateManager.AllowVolumeExtraction.valueIn(account.getId());
+
final boolean userPublicTemplateEnabled =
TemplateManager.AllowPublicUserTemplates.valueIn(caller.getId());
// add some parameters UI needs to handle API throttling
@@ -3417,6 +3421,7 @@ private String signRequest(final String request, final
String key) {
capabilities.put("KVMSnapshotEnabled", KVMSnapshotEnabled);
capabilities.put("allowUserViewDestroyedVM", allowUserViewDestroyedVM);
capabilities.put("allowUserExpungeRecoverVM",
allowUserExpungeRecoverVM);
+ capabilities.put("allowVolumeExtraction", allowVolumeExtraction);
if (apiLimitEnabled) {
capabilities.put("apiLimitInterval", apiLimitInterval);
capabilities.put("apiLimitMax", apiLimitMax);
diff --git a/server/src/com/cloud/storage/VolumeApiServiceImpl.java
b/server/src/com/cloud/storage/VolumeApiServiceImpl.java
index 37b72a68d14..0c4eff7f6d2 100644
--- a/server/src/com/cloud/storage/VolumeApiServiceImpl.java
+++ b/server/src/com/cloud/storage/VolumeApiServiceImpl.java
@@ -2279,6 +2279,12 @@ public String extractVolume(ExtractVolumeCmd cmd) {
throw new PermissionDeniedException("Extraction has been disabled
by admin");
}
+ boolean VolumeExtractionEnabled =
TemplateManager.AllowVolumeExtraction.valueIn(account.getId());
+ //AccountDetailVO accountDetailVO =
_accountDetailsDao.findDetail(account.getId(), "allow.volume.extraction");
+ if (!VolumeExtractionEnabled) {
+ throw new PermissionDeniedException("Extraction has been disabled
in user properties");
+ }
+
VolumeVO volume = _volsDao.findById(volumeId);
if (volume == null) {
InvalidParameterValueException ex = new
InvalidParameterValueException("Unable to find volume with specified volumeId");
diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java
b/server/src/com/cloud/template/TemplateManagerImpl.java
index f6494c3b77e..9a3cb7ec417 100644
--- a/server/src/com/cloud/template/TemplateManagerImpl.java
+++ b/server/src/com/cloud/template/TemplateManagerImpl.java
@@ -2095,7 +2095,7 @@ public String getConfigComponentName() {
@Override
public ConfigKey<?>[] getConfigKeys() {
- return new ConfigKey<?>[] {AllowPublicUserTemplates,
TemplatePreloaderPoolSize};
+ return new ConfigKey<?>[] {AllowPublicUserTemplates,
TemplatePreloaderPoolSize, AllowVolumeExtraction};
}
public List<TemplateAdapter> getTemplateAdapters() {
diff --git a/ui/scripts/cloudStack.js b/ui/scripts/cloudStack.js
index 119013326fb..bf948255886 100644
--- a/ui/scripts/cloudStack.js
+++ b/ui/scripts/cloudStack.js
@@ -149,6 +149,7 @@
g_allowUserExpungeRecoverVm =
json.listcapabilitiesresponse.capability.allowuserexpungerecovervm;
g_userProjectsEnabled =
json.listcapabilitiesresponse.capability.allowusercreateprojects;
+ g_allowvolumeextraction =
json.listcapabilitiesresponse.capability.allowvolumeextraction;
g_cloudstackversion =
json.listcapabilitiesresponse.capability.cloudstackversion;
@@ -302,6 +303,7 @@
}
g_allowUserExpungeRecoverVm =
json.listcapabilitiesresponse.capability.allowuserexpungerecovervm;
g_userProjectsEnabled =
json.listcapabilitiesresponse.capability.allowusercreateprojects;
+ g_allowvolumeextraction =
json.listcapabilitiesresponse.capability.allowvolumeextraction;
g_cloudstackversion =
json.listcapabilitiesresponse.capability.cloudstackversion;
@@ -360,6 +362,7 @@
g_kvmsnapshotenabled = null;
g_regionsecondaryenabled = null;
g_loginCmdText = null;
+ g_allowvolumeextraction = null;
// Remove any cookies
var cookies = document.cookie.split(";");
@@ -396,6 +399,7 @@
g_kvmsnapshotenabled = null;
g_regionsecondaryenabled = null;
g_loginCmdText = null;
+ g_allowvolumeextraction = null;
// Remove any cookies
var cookies = document.cookie.split(";");
diff --git a/ui/scripts/sharedFunctions.js b/ui/scripts/sharedFunctions.js
index 655aee9fb93..37af41d7eff 100644
--- a/ui/scripts/sharedFunctions.js
+++ b/ui/scripts/sharedFunctions.js
@@ -35,6 +35,7 @@ var g_cloudstackversion = null;
var g_queryAsyncJobResultInterval = 3000;
var g_idpList = null;
var g_appendIdpDomain = false;
+var g_allowvolumeextraction = true;
//keyboard keycode
var keycode_Enter = 13;
diff --git a/ui/scripts/storage.js b/ui/scripts/storage.js
index 9c017b1025b..14f13bff633 100644
--- a/ui/scripts/storage.js
+++ b/ui/scripts/storage.js
@@ -2767,7 +2767,7 @@
}
if (jsonObj.state != "Allocated") {
- if ((jsonObj.vmstate == "Stopped" || jsonObj.virtualmachineid ==
null) && jsonObj.state == "Ready") {
+ if ((jsonObj.vmstate == "Stopped" || jsonObj.virtualmachineid ==
null) && jsonObj.state == "Ready" && g_allowvolumeextraction == true) {
allowedActions.push("downloadVolume");
}
}
diff --git a/ui/scripts/templates.js b/ui/scripts/templates.js
index 1ab1b9b09dd..da816755bd3 100755
--- a/ui/scripts/templates.js
+++ b/ui/scripts/templates.js
@@ -2959,7 +2959,7 @@
// "Download Template"
if (((isAdmin() == false && !(jsonObj.domainid == g_domainid &&
jsonObj.account == g_account) && !(jsonObj.domainid == g_domainid &&
cloudStack.context.projects && jsonObj.projectid ==
cloudStack.context.projects[0].id))) //if neither root-admin, nor the same
account, nor the same project
- || (jsonObj.isready == false) || jsonObj.templatetype == "SYSTEM")
{
+ || (jsonObj.isready == false) || jsonObj.templatetype == "SYSTEM"
|| g_allowvolumeextraction == false) {
//do nothing
} else {
allowedActions.push("downloadTemplate");
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]
With regards,
Apache Git Services