You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by pr...@apache.org on 2012/10/24 23:11:19 UTC

git commit: Some ACL POC work

Updated Branches:
  refs/heads/acl f16b5103d -> 3058520ab


Some ACL POC work


Project: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/commit/3058520a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/tree/3058520a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/diff/3058520a

Branch: refs/heads/acl
Commit: 3058520ab3f09c31c142b41e37912e5ddd8d074a
Parents: f16b510
Author: Prachi Damle <pr...@cloud.com>
Authored: Thu Oct 18 13:32:45 2012 -0700
Committer: Prachi Damle <pr...@cloud.com>
Committed: Thu Oct 18 13:32:45 2012 -0700

----------------------------------------------------------------------
 api/src/com/cloud/api/ACL.java                  |   31 +++++
 api/src/com/cloud/api/commands/DeployVMCmd.java |    9 ++
 server/src/com/cloud/api/ApiDispatcher.java     |  126 +++++++++++++++++-
 server/src/com/cloud/api/ApiServer.java         |   11 ++-
 4 files changed, 172 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/3058520a/api/src/com/cloud/api/ACL.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/api/ACL.java b/api/src/com/cloud/api/ACL.java
new file mode 100644
index 0000000..1f376e9
--- /dev/null
+++ b/api/src/com/cloud/api/ACL.java
@@ -0,0 +1,31 @@
+// 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.api;
+
+import static java.lang.annotation.ElementType.FIELD;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ FIELD })
+public @interface ACL {
+	
+
+	Class<?> resourceType();
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/3058520a/api/src/com/cloud/api/commands/DeployVMCmd.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/api/commands/DeployVMCmd.java b/api/src/com/cloud/api/commands/DeployVMCmd.java
index f67ee8f..da9f3ea 100644
--- a/api/src/com/cloud/api/commands/DeployVMCmd.java
+++ b/api/src/com/cloud/api/commands/DeployVMCmd.java
@@ -26,6 +26,7 @@ import java.util.Map;
 
 import org.apache.log4j.Logger;
 
+import com.cloud.api.ACL;
 import com.cloud.api.ApiConstants;
 import com.cloud.api.BaseAsyncCreateCmd;
 import com.cloud.api.BaseCmd;
@@ -43,7 +44,10 @@ import com.cloud.exception.InsufficientCapacityException;
 import com.cloud.exception.InvalidParameterValueException;
 import com.cloud.exception.ResourceAllocationException;
 import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.host.Host;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.network.Network;
+import com.cloud.network.security.SecurityGroup;
 import com.cloud.offering.DiskOffering;
 import com.cloud.offering.ServiceOffering;
 import com.cloud.template.VirtualMachineTemplate;
@@ -69,6 +73,7 @@ public class DeployVMCmd extends BaseAsyncCreateCmd {
     @Parameter(name=ApiConstants.SERVICE_OFFERING_ID, type=CommandType.LONG, required=true, description="the ID of the service offering for the virtual machine")
     private Long serviceOfferingId;
 
+    @ACL(resourceType=VirtualMachineTemplate.class)
     @IdentityMapper(entityTableName="vm_template")
     @Parameter(name=ApiConstants.TEMPLATE_ID, type=CommandType.LONG, required=true, description="the ID of the template for the virtual machine")
     private Long templateId;
@@ -88,6 +93,7 @@ public class DeployVMCmd extends BaseAsyncCreateCmd {
     private Long domainId;
 
     //Network information
+    @ACL(resourceType=Network.class)
     @IdentityMapper(entityTableName="networks")
     @Parameter(name=ApiConstants.NETWORK_IDS, type=CommandType.LIST, collectionType=CommandType.LONG, description="list of network ids used by virtual machine. Can't be specified with ipToNetworkList parameter")
     private List<Long> networkIds;
@@ -112,14 +118,17 @@ public class DeployVMCmd extends BaseAsyncCreateCmd {
     @Parameter(name=ApiConstants.SSH_KEYPAIR, type=CommandType.STRING, description="name of the ssh key pair used to login to the virtual machine")
     private String sshKeyPairName;
 
+    //@ACL(resourceType=Host.class)
     @IdentityMapper(entityTableName="host")
     @Parameter(name=ApiConstants.HOST_ID, type=CommandType.LONG, description="destination Host ID to deploy the VM to - parameter available for root admin only")
     private Long hostId;
     
+    //@ACL(resourceType=SecurityGroup.class)
     @IdentityMapper(entityTableName="security_group")
     @Parameter(name=ApiConstants.SECURITY_GROUP_IDS, type=CommandType.LIST, collectionType=CommandType.LONG, description="comma separated list of security groups id that going to be applied to the virtual machine. Should be passed only when vm is created from a zone with Basic Network support. Mutually exclusive with securitygroupnames parameter")
     private List<Long> securityGroupIdList;
     
+    //@ACL(resourceType=SecurityGroup.class)
     @Parameter(name=ApiConstants.SECURITY_GROUP_NAMES, type=CommandType.LIST, collectionType=CommandType.STRING, description="comma separated list of security groups names that going to be applied to the virtual machine. Should be passed only when vm is created from a zone with Basic Network support. Mutually exclusive with securitygroupids parameter")
     private List<String> securityGroupNameList;
     

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/3058520a/server/src/com/cloud/api/ApiDispatcher.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/ApiDispatcher.java b/server/src/com/cloud/api/ApiDispatcher.java
index 8eade00..de7bdc6 100755
--- a/server/src/com/cloud/api/ApiDispatcher.java
+++ b/server/src/com/cloud/api/ApiDispatcher.java
@@ -22,6 +22,7 @@ import java.text.ParseException;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.StringTokenizer;
@@ -29,6 +30,7 @@ import java.util.regex.Matcher;
 
 import org.apache.log4j.Logger;
 
+import com.cloud.acl.ControlledEntity;
 import com.cloud.api.BaseCmd.CommandType;
 import com.cloud.api.commands.ListEventsCmd;
 import com.cloud.async.AsyncCommandQueued;
@@ -40,12 +42,17 @@ import com.cloud.exception.PermissionDeniedException;
 import com.cloud.exception.ResourceAllocationException;
 import com.cloud.exception.ResourceUnavailableException;
 import com.cloud.utils.IdentityProxy;
+import com.cloud.network.dao.NetworkDao;
 import com.cloud.server.ManagementServer;
+import com.cloud.storage.dao.VMTemplateDao;
 import com.cloud.user.Account;
+import com.cloud.user.AccountManager;
+import com.cloud.user.AccountService;
 import com.cloud.user.UserContext;
 import com.cloud.utils.DateUtil;
 import com.cloud.utils.component.ComponentLocator;
 import com.cloud.utils.component.PluggableService;
+import com.cloud.utils.db.GenericDao;
 import com.cloud.utils.exception.CSExceptionErrorCode;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.uuididentity.dao.IdentityDao;
@@ -59,7 +66,10 @@ public class ApiDispatcher {
     ComponentLocator _locator;
     AsyncJobManager _asyncMgr;
     IdentityDao _identityDao;
+    AccountManager _accountMgr;
 
+
+    Map<String, Class<? extends GenericDao>> _daoNameMap = new HashMap<String, Class<? extends GenericDao>>();
     // singleton class
     private static ApiDispatcher s_instance = new ApiDispatcher();
 
@@ -71,13 +81,30 @@ public class ApiDispatcher {
         _locator = ComponentLocator.getLocator(ManagementServer.Name);
         _asyncMgr = _locator.getManager(AsyncJobManager.class);
         _identityDao = _locator.getDao(IdentityDao.class);
+        _accountMgr = _locator.getManager(AccountManager.class);
+        
+        _daoNameMap.put("com.cloud.network.Network", NetworkDao.class);
+        _daoNameMap.put("com.cloud.template.VirtualMachineTemplate", VMTemplateDao.class);
+        
+        
     }
 
     public void dispatchCreateCmd(BaseAsyncCreateCmd cmd, Map<String, String> params) {
 
-        setupParameters(cmd, params);
+    	List<ControlledEntity> entitiesToAccess = new ArrayList<ControlledEntity>();
+    	setupParameters(cmd, params, entitiesToAccess);
         plugService(cmd);
 
+        if(!entitiesToAccess.isEmpty()){
+			 //owner
+			Account caller = UserContext.current().getCaller();
+			Account owner = s_instance._accountMgr.getActiveAccountById(cmd.getEntityOwnerId());
+			s_instance._accountMgr.checkAccess(caller, null, true, owner);
+			 
+			for(ControlledEntity entity : entitiesToAccess)
+			s_instance._accountMgr.checkAccess(caller, null, true, entity);
+        }
+        
         try {
             UserContext ctx = UserContext.current();
             ctx.setAccountId(cmd.getEntityOwnerId());
@@ -118,8 +145,19 @@ public class ApiDispatcher {
     }
 
     public void dispatch(BaseCmd cmd, Map<String, String> params) {
-        setupParameters(cmd, params);
+    	List<ControlledEntity> entitiesToAccess = new ArrayList<ControlledEntity>();
+    	setupParameters(cmd, params, entitiesToAccess);
         ApiDispatcher.plugService(cmd);
+        
+        if(!entitiesToAccess.isEmpty()){
+			 //owner
+			Account caller = UserContext.current().getCaller();
+			Account owner = s_instance._accountMgr.getActiveAccountById(cmd.getEntityOwnerId());
+			s_instance._accountMgr.checkAccess(caller, null, true, owner);
+			for(ControlledEntity entity : entitiesToAccess)
+			s_instance._accountMgr.checkAccess(caller, null, true, entity);
+        }
+        
         try {
             UserContext ctx = UserContext.current();
             ctx.setAccountId(cmd.getEntityOwnerId());
@@ -270,8 +308,10 @@ public class ApiDispatcher {
         }
     }
 
-    public static void setupParameters(BaseCmd cmd, Map<String, String> params) {
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+	public static void setupParameters(BaseCmd cmd, Map<String, String> params, List<ControlledEntity> entitiesToAccess) {
         Map<String, Object> unpackedParams = cmd.unpackParams(params);
+        
 
         if (cmd instanceof BaseListCmd) {
             Object pageSizeObj = unpackedParams.get(ApiConstants.PAGE_SIZE);
@@ -339,12 +379,90 @@ public class ApiDispatcher {
                 throw new ServerApiException(BaseCmd.PARAM_ERROR, "Unable to execute API command " + cmd.getCommandName().substring(0, cmd.getCommandName().length() - 8) + " due to invalid value. " + invEx.getMessage());
             } catch (CloudRuntimeException cloudEx) {
                 // FIXME: Better error message? This only happens if the API command is not executable, which typically
-// means
+            	//means
                 // there was
                 // and IllegalAccessException setting one of the parameters.
                 throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Internal error executing API command " + cmd.getCommandName().substring(0, cmd.getCommandName().length() - 8));
             }
+            
+            
+            //check access on the resource this field points to
+	        try {
+	            ACL checkAccess = field.getAnnotation(ACL.class);
+	            CommandType fieldType = parameterAnnotation.type();
+	            
+	            
+	            if(checkAccess != null){
+	            	// Verify that caller can perform actions in behalf of vm owner
+	            	//acumulate all Controlled Entities together.
+	            	if(checkAccess.resourceType() != null){
+	            		 Class<?> entity = checkAccess.resourceType();
+	            				 
+	            		 if(ControlledEntity.class.isAssignableFrom(entity)){
+	                         if (s_logger.isDebugEnabled()) {
+	                             s_logger.debug("entity name is:" + entity.getName());
+	                         }
+	                         
+	                         if(s_instance._daoNameMap.containsKey(entity.getName())){
+	                        	 Class<? extends GenericDao> daoClass = s_instance._daoNameMap.get(entity.getName());
+	                        	 GenericDao daoClassInstance =  s_instance._locator.getDao(daoClass);
+	                        	 
+	                        	 //Check if the parameter type is a single Id or list of id's/name's
+	                        	 switch (fieldType) {                        	 
+			                         case LIST:
+		                                 CommandType listType = parameterAnnotation.collectionType();
+		                                 switch (listType) {
+    		                                 case LONG: 
+    		                                	 List<Long> listParam = new ArrayList<Long>();
+     											 listParam = (List)field.get(cmd);
+    
+    		                                	 for(Long entityId : listParam){
+    			    	                        	 ControlledEntity entityObj = (ControlledEntity)daoClassInstance.findById(entityId);
+    			    	                        	 entitiesToAccess.add(entityObj);
+    		                                	 }
+    			    	                     break;
+    		                                 /*case STRING:
+    		                                	 List<String> listParam = new ArrayList<String>();
+    		                                	 listParam = (List)field.get(cmd);
+    		                                	 for(String entityName: listParam){
+    			    	                        	 ControlledEntity entityObj = (ControlledEntity)daoClassInstance(entityId);
+    			    	                        	 entitiesToAccess.add(entityObj);
+    		                                	 }
+    		                                     break;
+    		                                  */
+    		                                 default:
+    		                                 break;
+		                                 }
+			                             break;
+			                         case LONG:
+			                        	 Long entityId = (Long)field.get(cmd);
+			                        	 ControlledEntity entityObj = (ControlledEntity)daoClassInstance.findById(entityId);
+			                        	 entitiesToAccess.add(entityObj);
+			                        	 break;
+			                         default:
+			                        	 break;
+	                        	 }
+	                             
+	                        	 
+	                         }
+	            			 
+	            		 }
+	            		 
+	            	}
+	            	
+	            }
+	
+			} catch (IllegalArgumentException e) {
+	            s_logger.error("Error initializing command " + cmd.getCommandName() + ", field " + field.getName() + " is not accessible.");
+	            throw new CloudRuntimeException("Internal error initializing parameters for command " + cmd.getCommandName() + " [field " + field.getName() + " is not accessible]");
+			} catch (IllegalAccessException e) {
+	            s_logger.error("Error initializing command " + cmd.getCommandName() + ", field " + field.getName() + " is not accessible.");
+	            throw new CloudRuntimeException("Internal error initializing parameters for command " + cmd.getCommandName() + " [field " + field.getName() + " is not accessible]");
+			}
+            
         }
+        
+        //check access on the entities.
     }
 
     @SuppressWarnings({ "unchecked", "rawtypes" })

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/3058520a/server/src/com/cloud/api/ApiServer.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/ApiServer.java b/server/src/com/cloud/api/ApiServer.java
index eb5e770..3186d95 100755
--- a/server/src/com/cloud/api/ApiServer.java
+++ b/server/src/com/cloud/api/ApiServer.java
@@ -81,6 +81,7 @@ import org.apache.http.protocol.ResponseDate;
 import org.apache.http.protocol.ResponseServer;
 import org.apache.log4j.Logger;
 
+import com.cloud.acl.ControlledEntity;
 import com.cloud.api.response.ApiResponseSerializer;
 import com.cloud.api.response.ExceptionResponse;
 import com.cloud.api.response.ListResponse;
@@ -486,8 +487,16 @@ public class ApiServer implements HttpRequestHandler {
                 objectEntityTable = createCmd.getEntityTable();
                 params.put("id", objectId.toString());
             } else {
-                ApiDispatcher.setupParameters(cmdObj, params);
+            	List<ControlledEntity> entitiesToAccess = new ArrayList<ControlledEntity>();
+                ApiDispatcher.setupParameters(cmdObj, params, entitiesToAccess);
                 ApiDispatcher.plugService(cmdObj);
+                
+                if(!entitiesToAccess.isEmpty()){
+	                Account owner = s_instance._accountMgr.getActiveAccountById(cmdObj.getEntityOwnerId());
+	        		s_instance._accountMgr.checkAccess(caller, null, true, owner);
+	        		 
+	        		s_instance._accountMgr.checkAccess(caller, null, true, (ControlledEntity[])entitiesToAccess.toArray());
+                }
             }
 
             BaseAsyncCmd asyncCmd = (BaseAsyncCmd) cmdObj;


RE: git commit: Some ACL POC work

Posted by Prachi Damle <Pr...@citrix.com>.
Hi David,

I am putting together the ideas currently and will provide a link to a document soon describing them.

Thanks,
Prachi
-----Original Message-----
From: David Nalley [mailto:david@gnsa.us]
Sent: Saturday, November 10, 2012 3:22 AM
To: cloudstack-dev@incubator.apache.org
Subject: Re: git commit: Some ACL POC work

Hi Prachi:

I am still trying to get caught up on my backlog of mail, is there a place where you've discussed some of these ACL ideas?

--David

On Wed, Oct 24, 2012 at 5:11 PM,  <pr...@apache.org> wrote:
> Updated Branches:
>   refs/heads/acl f16b5103d -> 3058520ab
>
>
> Some ACL POC work
>
>
> Project:
> http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/repo
> Commit:
> http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/commit/305
> 8520a
> Tree:
> http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/tree/30585
> 20a
> Diff:
> http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/diff/30585
> 20a
>
> Branch: refs/heads/acl
> Commit: 3058520ab3f09c31c142b41e37912e5ddd8d074a
> Parents: f16b510
> Author: Prachi Damle <pr...@cloud.com>
> Authored: Thu Oct 18 13:32:45 2012 -0700
> Committer: Prachi Damle <pr...@cloud.com>
> Committed: Thu Oct 18 13:32:45 2012 -0700
>
> ----------------------------------------------------------------------
>  api/src/com/cloud/api/ACL.java                  |   31 +++++
>  api/src/com/cloud/api/commands/DeployVMCmd.java |    9 ++
>  server/src/com/cloud/api/ApiDispatcher.java     |  126 +++++++++++++++++-
>  server/src/com/cloud/api/ApiServer.java         |   11 ++-
>  4 files changed, 172 insertions(+), 5 deletions(-)
> ----------------------------------------------------------------------
>
>
> http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/30585
> 20a/api/src/com/cloud/api/ACL.java
> ----------------------------------------------------------------------
> diff --git a/api/src/com/cloud/api/ACL.java
> b/api/src/com/cloud/api/ACL.java new file mode 100644 index
> 0000000..1f376e9
> --- /dev/null
> +++ b/api/src/com/cloud/api/ACL.java
> @@ -0,0 +1,31 @@
> +// 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.api;
> +
> +import static java.lang.annotation.ElementType.FIELD;
> +
> +import java.lang.annotation.Retention; import
> +java.lang.annotation.RetentionPolicy;
> +import java.lang.annotation.Target;
> +
> +@Retention(RetentionPolicy.RUNTIME)
> +@Target({ FIELD })
> +public @interface ACL {
> +
> +
> +       Class<?> resourceType();
> +}
>
> http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/30585
> 20a/api/src/com/cloud/api/commands/DeployVMCmd.java
> ----------------------------------------------------------------------
> diff --git a/api/src/com/cloud/api/commands/DeployVMCmd.java
> b/api/src/com/cloud/api/commands/DeployVMCmd.java
> index f67ee8f..da9f3ea 100644
> --- a/api/src/com/cloud/api/commands/DeployVMCmd.java
> +++ b/api/src/com/cloud/api/commands/DeployVMCmd.java
> @@ -26,6 +26,7 @@ import java.util.Map;
>
>  import org.apache.log4j.Logger;
>
> +import com.cloud.api.ACL;
>  import com.cloud.api.ApiConstants;
>  import com.cloud.api.BaseAsyncCreateCmd;  import
> com.cloud.api.BaseCmd; @@ -43,7 +44,10 @@ import
> com.cloud.exception.InsufficientCapacityException;
>  import com.cloud.exception.InvalidParameterValueException;
>  import com.cloud.exception.ResourceAllocationException;
>  import com.cloud.exception.ResourceUnavailableException;
> +import com.cloud.host.Host;
>  import com.cloud.hypervisor.Hypervisor.HypervisorType;
> +import com.cloud.network.Network;
> +import com.cloud.network.security.SecurityGroup;
>  import com.cloud.offering.DiskOffering;  import
> com.cloud.offering.ServiceOffering;
>  import com.cloud.template.VirtualMachineTemplate;
> @@ -69,6 +73,7 @@ public class DeployVMCmd extends BaseAsyncCreateCmd {
>      @Parameter(name=ApiConstants.SERVICE_OFFERING_ID, type=CommandType.LONG, required=true, description="the ID of the service offering for the virtual machine")
>      private Long serviceOfferingId;
>
> +    @ACL(resourceType=VirtualMachineTemplate.class)
>      @IdentityMapper(entityTableName="vm_template")
>      @Parameter(name=ApiConstants.TEMPLATE_ID, type=CommandType.LONG, required=true, description="the ID of the template for the virtual machine")
>      private Long templateId;
> @@ -88,6 +93,7 @@ public class DeployVMCmd extends BaseAsyncCreateCmd {
>      private Long domainId;
>
>      //Network information
> +    @ACL(resourceType=Network.class)
>      @IdentityMapper(entityTableName="networks")
>      @Parameter(name=ApiConstants.NETWORK_IDS, type=CommandType.LIST, collectionType=CommandType.LONG, description="list of network ids used by virtual machine. Can't be specified with ipToNetworkList parameter")
>      private List<Long> networkIds;
> @@ -112,14 +118,17 @@ public class DeployVMCmd extends BaseAsyncCreateCmd {
>      @Parameter(name=ApiConstants.SSH_KEYPAIR, type=CommandType.STRING, description="name of the ssh key pair used to login to the virtual machine")
>      private String sshKeyPairName;
>
> +    //@ACL(resourceType=Host.class)
>      @IdentityMapper(entityTableName="host")
>      @Parameter(name=ApiConstants.HOST_ID, type=CommandType.LONG, description="destination Host ID to deploy the VM to - parameter available for root admin only")
>      private Long hostId;
>
> +    //@ACL(resourceType=SecurityGroup.class)
>      @IdentityMapper(entityTableName="security_group")
>      @Parameter(name=ApiConstants.SECURITY_GROUP_IDS, type=CommandType.LIST, collectionType=CommandType.LONG, description="comma separated list of security groups id that going to be applied to the virtual machine. Should be passed only when vm is created from a zone with Basic Network support. Mutually exclusive with securitygroupnames parameter")
>      private List<Long> securityGroupIdList;
>
> +    //@ACL(resourceType=SecurityGroup.class)
>      @Parameter(name=ApiConstants.SECURITY_GROUP_NAMES, type=CommandType.LIST, collectionType=CommandType.STRING, description="comma separated list of security groups names that going to be applied to the virtual machine. Should be passed only when vm is created from a zone with Basic Network support. Mutually exclusive with securitygroupids parameter")
>      private List<String> securityGroupNameList;
>
>
> http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/30585
> 20a/server/src/com/cloud/api/ApiDispatcher.java
> ----------------------------------------------------------------------
> diff --git a/server/src/com/cloud/api/ApiDispatcher.java
> b/server/src/com/cloud/api/ApiDispatcher.java
> index 8eade00..de7bdc6 100755
> --- a/server/src/com/cloud/api/ApiDispatcher.java
> +++ b/server/src/com/cloud/api/ApiDispatcher.java
> @@ -22,6 +22,7 @@ import java.text.ParseException;  import
> java.util.ArrayList;  import java.util.Calendar;  import
> java.util.Date;
> +import java.util.HashMap;
>  import java.util.List;
>  import java.util.Map;
>  import java.util.StringTokenizer;
> @@ -29,6 +30,7 @@ import java.util.regex.Matcher;
>
>  import org.apache.log4j.Logger;
>
> +import com.cloud.acl.ControlledEntity;
>  import com.cloud.api.BaseCmd.CommandType;
>  import com.cloud.api.commands.ListEventsCmd;
>  import com.cloud.async.AsyncCommandQueued;
> @@ -40,12 +42,17 @@ import
> com.cloud.exception.PermissionDeniedException;
>  import com.cloud.exception.ResourceAllocationException;
>  import com.cloud.exception.ResourceUnavailableException;
>  import com.cloud.utils.IdentityProxy;
> +import com.cloud.network.dao.NetworkDao;
>  import com.cloud.server.ManagementServer;
> +import com.cloud.storage.dao.VMTemplateDao;
>  import com.cloud.user.Account;
> +import com.cloud.user.AccountManager; import
> +com.cloud.user.AccountService;
>  import com.cloud.user.UserContext;
>  import com.cloud.utils.DateUtil;
>  import com.cloud.utils.component.ComponentLocator;
>  import com.cloud.utils.component.PluggableService;
> +import com.cloud.utils.db.GenericDao;
>  import com.cloud.utils.exception.CSExceptionErrorCode;
>  import com.cloud.utils.exception.CloudRuntimeException;
>  import com.cloud.uuididentity.dao.IdentityDao;
> @@ -59,7 +66,10 @@ public class ApiDispatcher {
>      ComponentLocator _locator;
>      AsyncJobManager _asyncMgr;
>      IdentityDao _identityDao;
> +    AccountManager _accountMgr;
>
> +
> +    Map<String, Class<? extends GenericDao>> _daoNameMap = new
> + HashMap<String, Class<? extends GenericDao>>();
>      // singleton class
>      private static ApiDispatcher s_instance = new ApiDispatcher();
>
> @@ -71,13 +81,30 @@ public class ApiDispatcher {
>          _locator = ComponentLocator.getLocator(ManagementServer.Name);
>          _asyncMgr = _locator.getManager(AsyncJobManager.class);
>          _identityDao = _locator.getDao(IdentityDao.class);
> +        _accountMgr = _locator.getManager(AccountManager.class);
> +
> +        _daoNameMap.put("com.cloud.network.Network", NetworkDao.class);
> +        _daoNameMap.put("com.cloud.template.VirtualMachineTemplate",
> + VMTemplateDao.class);
> +
> +
>      }
>
>      public void dispatchCreateCmd(BaseAsyncCreateCmd cmd, Map<String,
> String> params) {
>
> -        setupParameters(cmd, params);
> +       List<ControlledEntity> entitiesToAccess = new ArrayList<ControlledEntity>();
> +       setupParameters(cmd, params, entitiesToAccess);
>          plugService(cmd);
>
> +        if(!entitiesToAccess.isEmpty()){
> +                        //owner
> +                       Account caller = UserContext.current().getCaller();
> +                       Account owner = s_instance._accountMgr.getActiveAccountById(cmd.getEntityOwnerId());
> +                       s_instance._accountMgr.checkAccess(caller,
> + null, true, owner);
> +
> +                       for(ControlledEntity entity : entitiesToAccess)
> +                       s_instance._accountMgr.checkAccess(caller, null, true, entity);
> +        }
> +
>          try {
>              UserContext ctx = UserContext.current();
>              ctx.setAccountId(cmd.getEntityOwnerId());
> @@ -118,8 +145,19 @@ public class ApiDispatcher {
>      }
>
>      public void dispatch(BaseCmd cmd, Map<String, String> params) {
> -        setupParameters(cmd, params);
> +       List<ControlledEntity> entitiesToAccess = new ArrayList<ControlledEntity>();
> +       setupParameters(cmd, params, entitiesToAccess);
>          ApiDispatcher.plugService(cmd);
> +
> +        if(!entitiesToAccess.isEmpty()){
> +                        //owner
> +                       Account caller = UserContext.current().getCaller();
> +                       Account owner = s_instance._accountMgr.getActiveAccountById(cmd.getEntityOwnerId());
> +                       s_instance._accountMgr.checkAccess(caller, null, true, owner);
> +                       for(ControlledEntity entity : entitiesToAccess)
> +                       s_instance._accountMgr.checkAccess(caller, null, true, entity);
> +        }
> +
>          try {
>              UserContext ctx = UserContext.current();
>              ctx.setAccountId(cmd.getEntityOwnerId());
> @@ -270,8 +308,10 @@ public class ApiDispatcher {
>          }
>      }
>
> -    public static void setupParameters(BaseCmd cmd, Map<String, String> params) {
> +    @SuppressWarnings({ "unchecked", "rawtypes" })
> +       public static void setupParameters(BaseCmd cmd, Map<String,
> + String> params, List<ControlledEntity> entitiesToAccess) {
>          Map<String, Object> unpackedParams =
> cmd.unpackParams(params);
> +
>
>          if (cmd instanceof BaseListCmd) {
>              Object pageSizeObj =
> unpackedParams.get(ApiConstants.PAGE_SIZE);
> @@ -339,12 +379,90 @@ public class ApiDispatcher {
>                  throw new ServerApiException(BaseCmd.PARAM_ERROR, "Unable to execute API command " + cmd.getCommandName().substring(0, cmd.getCommandName().length() - 8) + " due to invalid value. " + invEx.getMessage());
>              } catch (CloudRuntimeException cloudEx) {
>                  // FIXME: Better error message? This only happens if
> the API command is not executable, which typically -// means
> +               //means
>                  // there was
>                  // and IllegalAccessException setting one of the parameters.
>                  throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Internal error executing API command " + cmd.getCommandName().substring(0, cmd.getCommandName().length() - 8));
>              }
> +
> +
> +            //check access on the resource this field points to
> +               try {
> +                   ACL checkAccess = field.getAnnotation(ACL.class);
> +                   CommandType fieldType =
> + parameterAnnotation.type();
> +
> +
> +                   if(checkAccess != null){
> +                       // Verify that caller can perform actions in behalf of vm owner
> +                       //acumulate all Controlled Entities together.
> +                       if(checkAccess.resourceType() != null){
> +                                Class<?> entity =
> + checkAccess.resourceType();
> +
> +                                if(ControlledEntity.class.isAssignableFrom(entity)){
> +                                if (s_logger.isDebugEnabled()) {
> +                                    s_logger.debug("entity name is:" + entity.getName());
> +                                }
> +
> +                                if(s_instance._daoNameMap.containsKey(entity.getName())){
> +                                        Class<? extends GenericDao> daoClass = s_instance._daoNameMap.get(entity.getName());
> +                                        GenericDao daoClassInstance =
> + s_instance._locator.getDao(daoClass);
> +
> +                                        //Check if the parameter type is a single Id or list of id's/name's
> +                                        switch (fieldType) {
> +                                                case LIST:
> +                                                CommandType listType = parameterAnnotation.collectionType();
> +                                                switch (listType) {
> +                                                case LONG:
> +                                                        List<Long> listParam = new ArrayList<Long>();
> +
> + listParam = (List)field.get(cmd);
> +
> +                                                        for(Long entityId : listParam){
> +                                                                ControlledEntity entityObj = (ControlledEntity)daoClassInstance.findById(entityId);
> +                                                                entitiesToAccess.add(entityObj);
> +                                                        }
> +                                                    break;
> +                                                /*case STRING:
> +                                                        List<String> listParam = new ArrayList<String>();
> +                                                        listParam = (List)field.get(cmd);
> +                                                        for(String entityName: listParam){
> +                                                                ControlledEntity entityObj = (ControlledEntity)daoClassInstance(entityId);
> +                                                                entitiesToAccess.add(entityObj);
> +                                                        }
> +                                                    break;
> +                                                 */
> +                                                default:
> +                                                break;
> +                                                }
> +                                                    break;
> +                                                case LONG:
> +                                                        Long entityId = (Long)field.get(cmd);
> +                                                        ControlledEntity entityObj = (ControlledEntity)daoClassInstance.findById(entityId);
> +                                                        entitiesToAccess.add(entityObj);
> +                                                        break;
> +                                                default:
> +                                                        break;
> +                                        }
> +
> +
> +                                }
> +
> +                                }
> +
> +                       }
> +
> +                   }
> +
> +                       } catch (IllegalArgumentException e) {
> +                   s_logger.error("Error initializing command " + cmd.getCommandName() + ", field " + field.getName() + " is not accessible.");
> +                   throw new CloudRuntimeException("Internal error initializing parameters for command " + cmd.getCommandName() + " [field " + field.getName() + " is not accessible]");
> +                       } catch (IllegalAccessException e) {
> +                   s_logger.error("Error initializing command " + cmd.getCommandName() + ", field " + field.getName() + " is not accessible.");
> +                   throw new CloudRuntimeException("Internal error initializing parameters for command " + cmd.getCommandName() + " [field " + field.getName() + " is not accessible]");
> +                       }
> +
>          }
> +
> +        //check access on the entities.
>      }
>
>      @SuppressWarnings({ "unchecked", "rawtypes" })
>
> http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/30585
> 20a/server/src/com/cloud/api/ApiServer.java
> ----------------------------------------------------------------------
> diff --git a/server/src/com/cloud/api/ApiServer.java
> b/server/src/com/cloud/api/ApiServer.java
> index eb5e770..3186d95 100755
> --- a/server/src/com/cloud/api/ApiServer.java
> +++ b/server/src/com/cloud/api/ApiServer.java
> @@ -81,6 +81,7 @@ import org.apache.http.protocol.ResponseDate;
>  import org.apache.http.protocol.ResponseServer;
>  import org.apache.log4j.Logger;
>
> +import com.cloud.acl.ControlledEntity;
>  import com.cloud.api.response.ApiResponseSerializer;
>  import com.cloud.api.response.ExceptionResponse;
>  import com.cloud.api.response.ListResponse;
> @@ -486,8 +487,16 @@ public class ApiServer implements HttpRequestHandler {
>                  objectEntityTable = createCmd.getEntityTable();
>                  params.put("id", objectId.toString());
>              } else {
> -                ApiDispatcher.setupParameters(cmdObj, params);
> +               List<ControlledEntity> entitiesToAccess = new ArrayList<ControlledEntity>();
> +                ApiDispatcher.setupParameters(cmdObj, params,
> + entitiesToAccess);
>                  ApiDispatcher.plugService(cmdObj);
> +
> +                if(!entitiesToAccess.isEmpty()){
> +                       Account owner = s_instance._accountMgr.getActiveAccountById(cmdObj.getEntityOwnerId());
> +
> + s_instance._accountMgr.checkAccess(caller, null, true, owner);
> +
> +                               s_instance._accountMgr.checkAccess(caller, null, true, (ControlledEntity[])entitiesToAccess.toArray());
> +                }
>              }
>
>              BaseAsyncCmd asyncCmd = (BaseAsyncCmd) cmdObj;
>

Re: git commit: Some ACL POC work

Posted by David Nalley <da...@gnsa.us>.
Hi Prachi:

I am still trying to get caught up on my backlog of mail, is there a
place where you've discussed some of these ACL ideas?

--David

On Wed, Oct 24, 2012 at 5:11 PM,  <pr...@apache.org> wrote:
> Updated Branches:
>   refs/heads/acl f16b5103d -> 3058520ab
>
>
> Some ACL POC work
>
>
> Project: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/repo
> Commit: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/commit/3058520a
> Tree: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/tree/3058520a
> Diff: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/diff/3058520a
>
> Branch: refs/heads/acl
> Commit: 3058520ab3f09c31c142b41e37912e5ddd8d074a
> Parents: f16b510
> Author: Prachi Damle <pr...@cloud.com>
> Authored: Thu Oct 18 13:32:45 2012 -0700
> Committer: Prachi Damle <pr...@cloud.com>
> Committed: Thu Oct 18 13:32:45 2012 -0700
>
> ----------------------------------------------------------------------
>  api/src/com/cloud/api/ACL.java                  |   31 +++++
>  api/src/com/cloud/api/commands/DeployVMCmd.java |    9 ++
>  server/src/com/cloud/api/ApiDispatcher.java     |  126 +++++++++++++++++-
>  server/src/com/cloud/api/ApiServer.java         |   11 ++-
>  4 files changed, 172 insertions(+), 5 deletions(-)
> ----------------------------------------------------------------------
>
>
> http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/3058520a/api/src/com/cloud/api/ACL.java
> ----------------------------------------------------------------------
> diff --git a/api/src/com/cloud/api/ACL.java b/api/src/com/cloud/api/ACL.java
> new file mode 100644
> index 0000000..1f376e9
> --- /dev/null
> +++ b/api/src/com/cloud/api/ACL.java
> @@ -0,0 +1,31 @@
> +// 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.api;
> +
> +import static java.lang.annotation.ElementType.FIELD;
> +
> +import java.lang.annotation.Retention;
> +import java.lang.annotation.RetentionPolicy;
> +import java.lang.annotation.Target;
> +
> +@Retention(RetentionPolicy.RUNTIME)
> +@Target({ FIELD })
> +public @interface ACL {
> +
> +
> +       Class<?> resourceType();
> +}
>
> http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/3058520a/api/src/com/cloud/api/commands/DeployVMCmd.java
> ----------------------------------------------------------------------
> diff --git a/api/src/com/cloud/api/commands/DeployVMCmd.java b/api/src/com/cloud/api/commands/DeployVMCmd.java
> index f67ee8f..da9f3ea 100644
> --- a/api/src/com/cloud/api/commands/DeployVMCmd.java
> +++ b/api/src/com/cloud/api/commands/DeployVMCmd.java
> @@ -26,6 +26,7 @@ import java.util.Map;
>
>  import org.apache.log4j.Logger;
>
> +import com.cloud.api.ACL;
>  import com.cloud.api.ApiConstants;
>  import com.cloud.api.BaseAsyncCreateCmd;
>  import com.cloud.api.BaseCmd;
> @@ -43,7 +44,10 @@ import com.cloud.exception.InsufficientCapacityException;
>  import com.cloud.exception.InvalidParameterValueException;
>  import com.cloud.exception.ResourceAllocationException;
>  import com.cloud.exception.ResourceUnavailableException;
> +import com.cloud.host.Host;
>  import com.cloud.hypervisor.Hypervisor.HypervisorType;
> +import com.cloud.network.Network;
> +import com.cloud.network.security.SecurityGroup;
>  import com.cloud.offering.DiskOffering;
>  import com.cloud.offering.ServiceOffering;
>  import com.cloud.template.VirtualMachineTemplate;
> @@ -69,6 +73,7 @@ public class DeployVMCmd extends BaseAsyncCreateCmd {
>      @Parameter(name=ApiConstants.SERVICE_OFFERING_ID, type=CommandType.LONG, required=true, description="the ID of the service offering for the virtual machine")
>      private Long serviceOfferingId;
>
> +    @ACL(resourceType=VirtualMachineTemplate.class)
>      @IdentityMapper(entityTableName="vm_template")
>      @Parameter(name=ApiConstants.TEMPLATE_ID, type=CommandType.LONG, required=true, description="the ID of the template for the virtual machine")
>      private Long templateId;
> @@ -88,6 +93,7 @@ public class DeployVMCmd extends BaseAsyncCreateCmd {
>      private Long domainId;
>
>      //Network information
> +    @ACL(resourceType=Network.class)
>      @IdentityMapper(entityTableName="networks")
>      @Parameter(name=ApiConstants.NETWORK_IDS, type=CommandType.LIST, collectionType=CommandType.LONG, description="list of network ids used by virtual machine. Can't be specified with ipToNetworkList parameter")
>      private List<Long> networkIds;
> @@ -112,14 +118,17 @@ public class DeployVMCmd extends BaseAsyncCreateCmd {
>      @Parameter(name=ApiConstants.SSH_KEYPAIR, type=CommandType.STRING, description="name of the ssh key pair used to login to the virtual machine")
>      private String sshKeyPairName;
>
> +    //@ACL(resourceType=Host.class)
>      @IdentityMapper(entityTableName="host")
>      @Parameter(name=ApiConstants.HOST_ID, type=CommandType.LONG, description="destination Host ID to deploy the VM to - parameter available for root admin only")
>      private Long hostId;
>
> +    //@ACL(resourceType=SecurityGroup.class)
>      @IdentityMapper(entityTableName="security_group")
>      @Parameter(name=ApiConstants.SECURITY_GROUP_IDS, type=CommandType.LIST, collectionType=CommandType.LONG, description="comma separated list of security groups id that going to be applied to the virtual machine. Should be passed only when vm is created from a zone with Basic Network support. Mutually exclusive with securitygroupnames parameter")
>      private List<Long> securityGroupIdList;
>
> +    //@ACL(resourceType=SecurityGroup.class)
>      @Parameter(name=ApiConstants.SECURITY_GROUP_NAMES, type=CommandType.LIST, collectionType=CommandType.STRING, description="comma separated list of security groups names that going to be applied to the virtual machine. Should be passed only when vm is created from a zone with Basic Network support. Mutually exclusive with securitygroupids parameter")
>      private List<String> securityGroupNameList;
>
>
> http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/3058520a/server/src/com/cloud/api/ApiDispatcher.java
> ----------------------------------------------------------------------
> diff --git a/server/src/com/cloud/api/ApiDispatcher.java b/server/src/com/cloud/api/ApiDispatcher.java
> index 8eade00..de7bdc6 100755
> --- a/server/src/com/cloud/api/ApiDispatcher.java
> +++ b/server/src/com/cloud/api/ApiDispatcher.java
> @@ -22,6 +22,7 @@ import java.text.ParseException;
>  import java.util.ArrayList;
>  import java.util.Calendar;
>  import java.util.Date;
> +import java.util.HashMap;
>  import java.util.List;
>  import java.util.Map;
>  import java.util.StringTokenizer;
> @@ -29,6 +30,7 @@ import java.util.regex.Matcher;
>
>  import org.apache.log4j.Logger;
>
> +import com.cloud.acl.ControlledEntity;
>  import com.cloud.api.BaseCmd.CommandType;
>  import com.cloud.api.commands.ListEventsCmd;
>  import com.cloud.async.AsyncCommandQueued;
> @@ -40,12 +42,17 @@ import com.cloud.exception.PermissionDeniedException;
>  import com.cloud.exception.ResourceAllocationException;
>  import com.cloud.exception.ResourceUnavailableException;
>  import com.cloud.utils.IdentityProxy;
> +import com.cloud.network.dao.NetworkDao;
>  import com.cloud.server.ManagementServer;
> +import com.cloud.storage.dao.VMTemplateDao;
>  import com.cloud.user.Account;
> +import com.cloud.user.AccountManager;
> +import com.cloud.user.AccountService;
>  import com.cloud.user.UserContext;
>  import com.cloud.utils.DateUtil;
>  import com.cloud.utils.component.ComponentLocator;
>  import com.cloud.utils.component.PluggableService;
> +import com.cloud.utils.db.GenericDao;
>  import com.cloud.utils.exception.CSExceptionErrorCode;
>  import com.cloud.utils.exception.CloudRuntimeException;
>  import com.cloud.uuididentity.dao.IdentityDao;
> @@ -59,7 +66,10 @@ public class ApiDispatcher {
>      ComponentLocator _locator;
>      AsyncJobManager _asyncMgr;
>      IdentityDao _identityDao;
> +    AccountManager _accountMgr;
>
> +
> +    Map<String, Class<? extends GenericDao>> _daoNameMap = new HashMap<String, Class<? extends GenericDao>>();
>      // singleton class
>      private static ApiDispatcher s_instance = new ApiDispatcher();
>
> @@ -71,13 +81,30 @@ public class ApiDispatcher {
>          _locator = ComponentLocator.getLocator(ManagementServer.Name);
>          _asyncMgr = _locator.getManager(AsyncJobManager.class);
>          _identityDao = _locator.getDao(IdentityDao.class);
> +        _accountMgr = _locator.getManager(AccountManager.class);
> +
> +        _daoNameMap.put("com.cloud.network.Network", NetworkDao.class);
> +        _daoNameMap.put("com.cloud.template.VirtualMachineTemplate", VMTemplateDao.class);
> +
> +
>      }
>
>      public void dispatchCreateCmd(BaseAsyncCreateCmd cmd, Map<String, String> params) {
>
> -        setupParameters(cmd, params);
> +       List<ControlledEntity> entitiesToAccess = new ArrayList<ControlledEntity>();
> +       setupParameters(cmd, params, entitiesToAccess);
>          plugService(cmd);
>
> +        if(!entitiesToAccess.isEmpty()){
> +                        //owner
> +                       Account caller = UserContext.current().getCaller();
> +                       Account owner = s_instance._accountMgr.getActiveAccountById(cmd.getEntityOwnerId());
> +                       s_instance._accountMgr.checkAccess(caller, null, true, owner);
> +
> +                       for(ControlledEntity entity : entitiesToAccess)
> +                       s_instance._accountMgr.checkAccess(caller, null, true, entity);
> +        }
> +
>          try {
>              UserContext ctx = UserContext.current();
>              ctx.setAccountId(cmd.getEntityOwnerId());
> @@ -118,8 +145,19 @@ public class ApiDispatcher {
>      }
>
>      public void dispatch(BaseCmd cmd, Map<String, String> params) {
> -        setupParameters(cmd, params);
> +       List<ControlledEntity> entitiesToAccess = new ArrayList<ControlledEntity>();
> +       setupParameters(cmd, params, entitiesToAccess);
>          ApiDispatcher.plugService(cmd);
> +
> +        if(!entitiesToAccess.isEmpty()){
> +                        //owner
> +                       Account caller = UserContext.current().getCaller();
> +                       Account owner = s_instance._accountMgr.getActiveAccountById(cmd.getEntityOwnerId());
> +                       s_instance._accountMgr.checkAccess(caller, null, true, owner);
> +                       for(ControlledEntity entity : entitiesToAccess)
> +                       s_instance._accountMgr.checkAccess(caller, null, true, entity);
> +        }
> +
>          try {
>              UserContext ctx = UserContext.current();
>              ctx.setAccountId(cmd.getEntityOwnerId());
> @@ -270,8 +308,10 @@ public class ApiDispatcher {
>          }
>      }
>
> -    public static void setupParameters(BaseCmd cmd, Map<String, String> params) {
> +    @SuppressWarnings({ "unchecked", "rawtypes" })
> +       public static void setupParameters(BaseCmd cmd, Map<String, String> params, List<ControlledEntity> entitiesToAccess) {
>          Map<String, Object> unpackedParams = cmd.unpackParams(params);
> +
>
>          if (cmd instanceof BaseListCmd) {
>              Object pageSizeObj = unpackedParams.get(ApiConstants.PAGE_SIZE);
> @@ -339,12 +379,90 @@ public class ApiDispatcher {
>                  throw new ServerApiException(BaseCmd.PARAM_ERROR, "Unable to execute API command " + cmd.getCommandName().substring(0, cmd.getCommandName().length() - 8) + " due to invalid value. " + invEx.getMessage());
>              } catch (CloudRuntimeException cloudEx) {
>                  // FIXME: Better error message? This only happens if the API command is not executable, which typically
> -// means
> +               //means
>                  // there was
>                  // and IllegalAccessException setting one of the parameters.
>                  throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Internal error executing API command " + cmd.getCommandName().substring(0, cmd.getCommandName().length() - 8));
>              }
> +
> +
> +            //check access on the resource this field points to
> +               try {
> +                   ACL checkAccess = field.getAnnotation(ACL.class);
> +                   CommandType fieldType = parameterAnnotation.type();
> +
> +
> +                   if(checkAccess != null){
> +                       // Verify that caller can perform actions in behalf of vm owner
> +                       //acumulate all Controlled Entities together.
> +                       if(checkAccess.resourceType() != null){
> +                                Class<?> entity = checkAccess.resourceType();
> +
> +                                if(ControlledEntity.class.isAssignableFrom(entity)){
> +                                if (s_logger.isDebugEnabled()) {
> +                                    s_logger.debug("entity name is:" + entity.getName());
> +                                }
> +
> +                                if(s_instance._daoNameMap.containsKey(entity.getName())){
> +                                        Class<? extends GenericDao> daoClass = s_instance._daoNameMap.get(entity.getName());
> +                                        GenericDao daoClassInstance =  s_instance._locator.getDao(daoClass);
> +
> +                                        //Check if the parameter type is a single Id or list of id's/name's
> +                                        switch (fieldType) {
> +                                                case LIST:
> +                                                CommandType listType = parameterAnnotation.collectionType();
> +                                                switch (listType) {
> +                                                case LONG:
> +                                                        List<Long> listParam = new ArrayList<Long>();
> +                                                                                        listParam = (List)field.get(cmd);
> +
> +                                                        for(Long entityId : listParam){
> +                                                                ControlledEntity entityObj = (ControlledEntity)daoClassInstance.findById(entityId);
> +                                                                entitiesToAccess.add(entityObj);
> +                                                        }
> +                                                    break;
> +                                                /*case STRING:
> +                                                        List<String> listParam = new ArrayList<String>();
> +                                                        listParam = (List)field.get(cmd);
> +                                                        for(String entityName: listParam){
> +                                                                ControlledEntity entityObj = (ControlledEntity)daoClassInstance(entityId);
> +                                                                entitiesToAccess.add(entityObj);
> +                                                        }
> +                                                    break;
> +                                                 */
> +                                                default:
> +                                                break;
> +                                                }
> +                                                    break;
> +                                                case LONG:
> +                                                        Long entityId = (Long)field.get(cmd);
> +                                                        ControlledEntity entityObj = (ControlledEntity)daoClassInstance.findById(entityId);
> +                                                        entitiesToAccess.add(entityObj);
> +                                                        break;
> +                                                default:
> +                                                        break;
> +                                        }
> +
> +
> +                                }
> +
> +                                }
> +
> +                       }
> +
> +                   }
> +
> +                       } catch (IllegalArgumentException e) {
> +                   s_logger.error("Error initializing command " + cmd.getCommandName() + ", field " + field.getName() + " is not accessible.");
> +                   throw new CloudRuntimeException("Internal error initializing parameters for command " + cmd.getCommandName() + " [field " + field.getName() + " is not accessible]");
> +                       } catch (IllegalAccessException e) {
> +                   s_logger.error("Error initializing command " + cmd.getCommandName() + ", field " + field.getName() + " is not accessible.");
> +                   throw new CloudRuntimeException("Internal error initializing parameters for command " + cmd.getCommandName() + " [field " + field.getName() + " is not accessible]");
> +                       }
> +
>          }
> +
> +        //check access on the entities.
>      }
>
>      @SuppressWarnings({ "unchecked", "rawtypes" })
>
> http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/3058520a/server/src/com/cloud/api/ApiServer.java
> ----------------------------------------------------------------------
> diff --git a/server/src/com/cloud/api/ApiServer.java b/server/src/com/cloud/api/ApiServer.java
> index eb5e770..3186d95 100755
> --- a/server/src/com/cloud/api/ApiServer.java
> +++ b/server/src/com/cloud/api/ApiServer.java
> @@ -81,6 +81,7 @@ import org.apache.http.protocol.ResponseDate;
>  import org.apache.http.protocol.ResponseServer;
>  import org.apache.log4j.Logger;
>
> +import com.cloud.acl.ControlledEntity;
>  import com.cloud.api.response.ApiResponseSerializer;
>  import com.cloud.api.response.ExceptionResponse;
>  import com.cloud.api.response.ListResponse;
> @@ -486,8 +487,16 @@ public class ApiServer implements HttpRequestHandler {
>                  objectEntityTable = createCmd.getEntityTable();
>                  params.put("id", objectId.toString());
>              } else {
> -                ApiDispatcher.setupParameters(cmdObj, params);
> +               List<ControlledEntity> entitiesToAccess = new ArrayList<ControlledEntity>();
> +                ApiDispatcher.setupParameters(cmdObj, params, entitiesToAccess);
>                  ApiDispatcher.plugService(cmdObj);
> +
> +                if(!entitiesToAccess.isEmpty()){
> +                       Account owner = s_instance._accountMgr.getActiveAccountById(cmdObj.getEntityOwnerId());
> +                               s_instance._accountMgr.checkAccess(caller, null, true, owner);
> +
> +                               s_instance._accountMgr.checkAccess(caller, null, true, (ControlledEntity[])entitiesToAccess.toArray());
> +                }
>              }
>
>              BaseAsyncCmd asyncCmd = (BaseAsyncCmd) cmdObj;
>