incubator-cloudstack-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From David Nalley <da...@gnsa.us>
Subject Re: git commit: Some ACL POC work
Date Sat, 10 Nov 2012 11:22:03 GMT
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,  <prachidamle@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 <prachi@cloud.com>
> Authored: Thu Oct 18 13:32:45 2012 -0700
> Committer: Prachi Damle <prachi@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;
>

Mime
View raw message