You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by mc...@apache.org on 2013/10/01 02:04:53 UTC

git commit: updated refs/heads/rbac to 5583506

Updated Branches:
  refs/heads/rbac de0904ba6 -> 5583506c0


Add entity permission grant and revoke API.

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

Branch: refs/heads/rbac
Commit: 5583506c0ca5c2eb30073ab1e6d9e035b13ba98a
Parents: de0904b
Author: Min Chen <mi...@citrix.com>
Authored: Mon Sep 30 17:03:34 2013 -0700
Committer: Min Chen <mi...@citrix.com>
Committed: Mon Sep 30 17:03:34 2013 -0700

----------------------------------------------------------------------
 api/src/com/cloud/event/EventTypes.java         |   2 +
 .../org/apache/cloudstack/acl/AclService.java   |   6 +
 .../apache/cloudstack/acl/SecurityChecker.java  |   4 +-
 .../org/apache/cloudstack/api/ApiConstants.java |   4 +
 .../admin/acl/GrantPermissionToAclGroupCmd.java | 131 +++++++++++++++++++
 .../acl/RevokePermissionFromAclGroupCmd.java    | 131 +++++++++++++++++++
 .../response/AclEntityPermissionResponse.java   | 112 ++++++++++++++++
 .../api/response/AclGroupResponse.java          |  17 +++
 client/tomcatconf/commands.properties.in        |   2 +
 .../cloudstack/acl/AclEntityPermissionVO.java   |  42 +++++-
 .../acl/dao/AclEntityPermissionDaoImpl.java     |   5 +
 server/src/com/cloud/api/ApiResponseHelper.java |  18 +--
 .../api/query/dao/AclGroupJoinDaoImpl.java      |  15 +++
 .../com/cloud/api/query/vo/AclGroupJoinVO.java  |  32 +++++
 .../com/cloud/server/ManagementServerImpl.java  |   4 +
 .../apache/cloudstack/acl/AclServiceImpl.java   |  98 +++++++++++++-
 setup/db/db/schema-420to430.sql                 |  11 +-
 17 files changed, 615 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5583506c/api/src/com/cloud/event/EventTypes.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java
index 5b7bf59..076a7c5 100755
--- a/api/src/com/cloud/event/EventTypes.java
+++ b/api/src/com/cloud/event/EventTypes.java
@@ -453,6 +453,8 @@ public class EventTypes {
     public static final String EVENT_ACL_GROUP_UPDATE = "ACLGROUP.UPDATE";
     public static final String EVENT_ACL_GROUP_CREATE = "ACLGROUP.CREATE";
     public static final String EVENT_ACL_GROUP_DELETE = "ACLGROUP.DELETE";
+    public static final String EVENT_ACL_GROUP_GRANT = "ACLGROUP.GRANT";
+    public static final String EVENT_ACL_GROUP_REVOKE = "ACLGROUP.REVOKE";
 
     static {
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5583506c/api/src/org/apache/cloudstack/acl/AclService.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/acl/AclService.java b/api/src/org/apache/cloudstack/acl/AclService.java
index 1f4d620..e01c3b6 100644
--- a/api/src/org/apache/cloudstack/acl/AclService.java
+++ b/api/src/org/apache/cloudstack/acl/AclService.java
@@ -18,6 +18,8 @@ package org.apache.cloudstack.acl;
 
 import java.util.List;
 
+import org.apache.cloudstack.acl.SecurityChecker.AccessType;
+
 public interface AclService {
 
     /**
@@ -50,6 +52,10 @@ public interface AclService {
 
     AclGroup removeAccountsFromGroup(List<Long> acctIds, Long groupId);
 
+    AclGroup grantEntityPermissionToAclGroup(long aclGroupId, String entityType, long entityId, AccessType accessType);
+
+    AclGroup revokeEntityPermissionFromAclGroup(long aclGroupId, String entityType, long entityId, AccessType accessType);
+
     /**
      * Creates an acl group for the given domain.
      *

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5583506c/api/src/org/apache/cloudstack/acl/SecurityChecker.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/acl/SecurityChecker.java b/api/src/org/apache/cloudstack/acl/SecurityChecker.java
index 3a721fe..9943f6b 100644
--- a/api/src/org/apache/cloudstack/acl/SecurityChecker.java
+++ b/api/src/org/apache/cloudstack/acl/SecurityChecker.java
@@ -34,7 +34,9 @@ public interface SecurityChecker extends Adapter {
         ListEntry,
         ModifyEntry,
         ModifyProject,
-        UseNetwork
+        UseNetwork,
+        DeleteEntry,
+        OperationOnEntry
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5583506c/api/src/org/apache/cloudstack/api/ApiConstants.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java
index cd8479f..78200e5 100755
--- a/api/src/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/org/apache/cloudstack/api/ApiConstants.java
@@ -525,6 +525,10 @@ public class ApiConstants {
     public static final String ACL_ROLE_IDS = "roleids";
     public static final String ACL_APIS = "apis";
     public static final String ACL_GROUPS = "groups";
+    public static final String ACL_PERMISSIONS = "permission";
+    public static final String ENTITY_TYPE = "entitytype";
+    public static final String ENTITY_ID = "entityid";
+    public static final String ACCESS_TYPE = "accesstype";
 
     public enum HostDetails {
         all, capacity, events, stats, min;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5583506c/api/src/org/apache/cloudstack/api/command/admin/acl/GrantPermissionToAclGroupCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/GrantPermissionToAclGroupCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/GrantPermissionToAclGroupCmd.java
new file mode 100644
index 0000000..9fefa75
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/acl/GrantPermissionToAclGroupCmd.java
@@ -0,0 +1,131 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.admin.acl;
+
+
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.acl.AclGroup;
+import org.apache.cloudstack.acl.SecurityChecker.AccessType;
+import org.apache.cloudstack.api.ACL;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiCommandJobType;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.AclGroupResponse;
+import org.apache.cloudstack.context.CallContext;
+
+import com.cloud.event.EventTypes;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.user.Account;
+
+
+@APICommand(name = "grantPermissionToAclGroup", description = "grant entity permission to an acl group", responseObject = AclGroupResponse.class)
+public class GrantPermissionToAclGroupCmd extends BaseAsyncCmd {
+    public static final Logger s_logger = Logger.getLogger(GrantPermissionToAclGroupCmd.class.getName());
+    private static final String s_name = "grantpermissiontoaclgroupresponse";
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+
+
+    @ACL
+    @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = AclGroupResponse.class,
+            required = true, description = "The ID of the acl group")
+    private Long id;
+
+    @Parameter(name = ApiConstants.ENTITY_TYPE, type = CommandType.STRING, required = true, description = "entity class simple name.")
+    private String entityType;
+
+    @Parameter(name = ApiConstants.ENTITY_ID, type = CommandType.UUID, required = true, description = "The ID of the entity")
+    private Long entityId;
+
+    @Parameter(name = ApiConstants.ACCESS_TYPE, type = CommandType.STRING, required = true, description = "access type for the entity")
+    private String accessType;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+
+    public Long getId() {
+        return id;
+    }
+
+    public String getEntityType() {
+        return entityType;
+    }
+
+    public Long getEntityId() {
+        return entityId;
+    }
+
+    public AccessType getAccessType() {
+        return AccessType.valueOf(accessType);
+    }
+
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+
+
+    @Override
+    public long getEntityOwnerId() {
+        return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked
+    }
+
+    @Override
+    public void execute() throws ResourceUnavailableException,
+            InsufficientCapacityException, ServerApiException {
+        CallContext.current().setEventDetails("Acl group Id: " + getId());
+        AclGroup result = _aclService.grantEntityPermissionToAclGroup(id, entityType, entityId, getAccessType());
+        if (result != null){
+            AclGroupResponse response = _responseGenerator.createAclGroupResponse(result);
+            response.setResponseName(getCommandName());
+            setResponseObject(response);
+        } else {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to grant permission to acl group");
+        }
+    }
+
+    @Override
+    public String getEventType() {
+        return EventTypes.EVENT_ACL_GROUP_GRANT;
+    }
+
+    @Override
+    public String getEventDescription() {
+        return "granting permission to acl group";
+    }
+
+    @Override
+    public ApiCommandJobType getInstanceType() {
+        return ApiCommandJobType.AclGroup;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5583506c/api/src/org/apache/cloudstack/api/command/admin/acl/RevokePermissionFromAclGroupCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/acl/RevokePermissionFromAclGroupCmd.java b/api/src/org/apache/cloudstack/api/command/admin/acl/RevokePermissionFromAclGroupCmd.java
new file mode 100644
index 0000000..b9a75d7
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/command/admin/acl/RevokePermissionFromAclGroupCmd.java
@@ -0,0 +1,131 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.admin.acl;
+
+
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.acl.AclGroup;
+import org.apache.cloudstack.acl.SecurityChecker.AccessType;
+import org.apache.cloudstack.api.ACL;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiCommandJobType;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.AclGroupResponse;
+import org.apache.cloudstack.context.CallContext;
+
+import com.cloud.event.EventTypes;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.user.Account;
+
+
+@APICommand(name = "revokePermissionFromAclGroup", description = "revoke entity permission from an acl group", responseObject = AclGroupResponse.class)
+public class RevokePermissionFromAclGroupCmd extends BaseAsyncCmd {
+    public static final Logger s_logger = Logger.getLogger(RevokePermissionFromAclGroupCmd.class.getName());
+    private static final String s_name = "revokepermissiontoaclgroupresponse";
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+
+
+    @ACL
+    @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = AclGroupResponse.class,
+            required = true, description = "The ID of the acl group")
+    private Long id;
+
+    @Parameter(name = ApiConstants.ENTITY_TYPE, type = CommandType.STRING, required = true, description = "entity class simple name.")
+    private String entityType;
+
+    @Parameter(name = ApiConstants.ENTITY_ID, type = CommandType.UUID, required = true, description = "The ID of the entity")
+    private Long entityId;
+
+    @Parameter(name = ApiConstants.ACCESS_TYPE, type = CommandType.STRING, required = true, description = "access type for the entity")
+    private String accessType;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+
+    public Long getId() {
+        return id;
+    }
+
+    public String getEntityType() {
+        return entityType;
+    }
+
+    public Long getEntityId() {
+        return entityId;
+    }
+
+    public AccessType getAccessType() {
+        return AccessType.valueOf(accessType);
+    }
+
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+
+
+    @Override
+    public long getEntityOwnerId() {
+        return Account.ACCOUNT_ID_SYSTEM; // no account info given, parent this command to SYSTEM so ERROR events are tracked
+    }
+
+    @Override
+    public void execute() throws ResourceUnavailableException,
+            InsufficientCapacityException, ServerApiException {
+        CallContext.current().setEventDetails("Acl group Id: " + getId());
+        AclGroup result = _aclService.revokeEntityPermissionFromAclGroup(id, entityType, entityId, getAccessType());
+        if (result != null){
+            AclGroupResponse response = _responseGenerator.createAclGroupResponse(result);
+            response.setResponseName(getCommandName());
+            setResponseObject(response);
+        } else {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to grant permission to acl group");
+        }
+    }
+
+    @Override
+    public String getEventType() {
+        return EventTypes.EVENT_ACL_GROUP_GRANT;
+    }
+
+    @Override
+    public String getEventDescription() {
+        return "granting permission to acl group";
+    }
+
+    @Override
+    public ApiCommandJobType getInstanceType() {
+        return ApiCommandJobType.AclGroup;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5583506c/api/src/org/apache/cloudstack/api/response/AclEntityPermissionResponse.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/response/AclEntityPermissionResponse.java b/api/src/org/apache/cloudstack/api/response/AclEntityPermissionResponse.java
new file mode 100644
index 0000000..da3b4b2
--- /dev/null
+++ b/api/src/org/apache/cloudstack/api/response/AclEntityPermissionResponse.java
@@ -0,0 +1,112 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.response;
+
+import com.google.gson.annotations.SerializedName;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseResponse;
+
+import com.cloud.serializer.Param;
+
+public class AclEntityPermissionResponse extends BaseResponse {
+
+    @SerializedName(ApiConstants.GROUP_ID)
+    @Param(description = "the ID of the acl group")
+    private String groupId;
+
+    @SerializedName(ApiConstants.ENTITY_TYPE)
+    @Param(description = "the entity type of this permission")
+    private String entityType;
+
+    @SerializedName(ApiConstants.ENTITY_ID)
+    @Param(description = "the uuid of the entity involved in this permission")
+    private String entityId;
+
+    @SerializedName(ApiConstants.ACCESS_TYPE)
+    @Param(description = "access type involved in this permission")
+    private String accessType;
+
+
+
+    public String getGroupId() {
+        return groupId;
+    }
+
+    public void setGroupId(String groupId) {
+        this.groupId = groupId;
+    }
+
+    public String getEntityType() {
+        return entityType;
+    }
+
+    public void setEntityType(String entityType) {
+        this.entityType = entityType;
+    }
+
+    public String getEntityId() {
+        return entityId;
+    }
+
+    public void setEntityId(String entityId) {
+        this.entityId = entityId;
+    }
+
+    public String getAccessType() {
+        return accessType;
+    }
+
+    public void setAccessType(String accessType) {
+        this.accessType = accessType;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((entityType == null) ? 0 : entityType.hashCode());
+        result = prime * result + ((entityId == null) ? 0 : entityId.hashCode());
+        result = prime * result + ((accessType == null) ? 0 : accessType.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        AclEntityPermissionResponse other = (AclEntityPermissionResponse) obj;
+        if (entityType == null) {
+            if (other.entityType != null)
+                return false;
+        } else if (!entityType.equals(other.entityType)) {
+            return false;
+        } else if ((entityId == null && other.entityId != null) || !entityId.equals(other.entityId)) {
+            return false;
+        } else if ((accessType == null && other.accessType != null) || !accessType.equals(other.accessType)) {
+            return false;
+        }
+        return true;
+    }
+
+
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5583506c/api/src/org/apache/cloudstack/api/response/AclGroupResponse.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/response/AclGroupResponse.java b/api/src/org/apache/cloudstack/api/response/AclGroupResponse.java
index 94fe8b5..e531504 100644
--- a/api/src/org/apache/cloudstack/api/response/AclGroupResponse.java
+++ b/api/src/org/apache/cloudstack/api/response/AclGroupResponse.java
@@ -60,9 +60,14 @@ public class AclGroupResponse extends BaseResponse {
     @Param(description = "acl roles granted to this acl group ")
     private Set<AclRoleResponse> roleList;
 
+    @SerializedName(ApiConstants.ACL_PERMISSIONS)
+    @Param(description = "permissions granted to this acl group ")
+    private Set<AclEntityPermissionResponse> permList;
+
     public AclGroupResponse() {
         accountIdList = new LinkedHashSet<String>();
         roleList = new LinkedHashSet<AclRoleResponse>();
+        permList = new LinkedHashSet<AclEntityPermissionResponse>();
     }
 
     @Override
@@ -116,6 +121,18 @@ public class AclGroupResponse extends BaseResponse {
         return roleList;
     }
 
+    public Set<AclEntityPermissionResponse> getPermissionList() {
+        return permList;
+    }
+
+    public void setPermissionList(Set<AclEntityPermissionResponse> perms) {
+        permList = perms;
+    }
+
+    public void addPermission(AclEntityPermissionResponse perm) {
+        permList.add(perm);
+    }
+
     @Override
     public int hashCode() {
         final int prime = 31;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5583506c/client/tomcatconf/commands.properties.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in
index 8aad3a7..9bb0ea2 100644
--- a/client/tomcatconf/commands.properties.in
+++ b/client/tomcatconf/commands.properties.in
@@ -692,4 +692,6 @@ addAclRoleToAclGroup=7
 removeAclRoleFromAclGroup=7
 addAccountToAclGroup=7
 removeAccountFromAclGroup=7
+grantPermissionToAclGroup=7
+revokePermissionFromAclGroup=7
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5583506c/engine/schema/src/org/apache/cloudstack/acl/AclEntityPermissionVO.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/org/apache/cloudstack/acl/AclEntityPermissionVO.java b/engine/schema/src/org/apache/cloudstack/acl/AclEntityPermissionVO.java
index b9e9174..a394516 100644
--- a/engine/schema/src/org/apache/cloudstack/acl/AclEntityPermissionVO.java
+++ b/engine/schema/src/org/apache/cloudstack/acl/AclEntityPermissionVO.java
@@ -31,7 +31,10 @@ public class AclEntityPermissionVO implements AclEntityPermission {
     private String entityType;
 
     @Column(name = "entity_id")
-    private Long entityId;
+    private long entityId;
+    
+    @Column(name = "entity_uuid")
+    private String entityUuid;
 
     @Column(name = "access_type")
     @Enumerated(value = EnumType.STRING)
@@ -43,6 +46,18 @@ public class AclEntityPermissionVO implements AclEntityPermission {
     @Column(name = GenericDao.CREATED_COLUMN)
     private Date created;
 
+    public AclEntityPermissionVO() {
+
+    }
+
+    public AclEntityPermissionVO(long groupId, String entityType, long entityId, String entityUuid, AccessType atype) {
+        aclGroupId = groupId;
+        this.entityType = entityType;
+        this.entityId = entityId;
+        this.entityUuid = entityUuid;
+        accessType = atype;
+    }
+    
     @Override
     public long getId() {
         return id;
@@ -63,11 +78,36 @@ public class AclEntityPermissionVO implements AclEntityPermission {
         return entityId;
     }
 
+    public String getEntityUuid() {
+        return entityUuid;
+    }
+
     @Override
     public AccessType getAccessType() {
         return accessType;
     }
 
+
+    public void setAclGroupId(long aclGroupId) {
+        this.aclGroupId = aclGroupId;
+    }
+
+    public void setEntityType(String entityType) {
+        this.entityType = entityType;
+    }
+
+    public void setEntityId(long entityId) {
+        this.entityId = entityId;
+    }
+
+    public void setEntityUuid(String entityUuid) {
+        this.entityUuid = entityUuid;
+    }
+
+    public void setAccessType(AccessType accessType) {
+        this.accessType = accessType;
+    }
+
     public Date getRemoved() {
         return removed;
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5583506c/engine/schema/src/org/apache/cloudstack/acl/dao/AclEntityPermissionDaoImpl.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/org/apache/cloudstack/acl/dao/AclEntityPermissionDaoImpl.java b/engine/schema/src/org/apache/cloudstack/acl/dao/AclEntityPermissionDaoImpl.java
index 71c6e64..482c9f3 100644
--- a/engine/schema/src/org/apache/cloudstack/acl/dao/AclEntityPermissionDaoImpl.java
+++ b/engine/schema/src/org/apache/cloudstack/acl/dao/AclEntityPermissionDaoImpl.java
@@ -33,6 +33,11 @@ import com.cloud.utils.db.SearchCriteria;
 public class AclEntityPermissionDaoImpl extends GenericDaoBase<AclEntityPermissionVO, Long> implements AclEntityPermissionDao {
     private SearchBuilder<AclEntityPermissionVO> findByGroupEntity;
 
+    public AclEntityPermissionDaoImpl()
+    {
+
+    }
+
     @Override
     public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
         super.configure(name, params);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5583506c/server/src/com/cloud/api/ApiResponseHelper.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java
index c4ab6b8..b19d6ef 100755
--- a/server/src/com/cloud/api/ApiResponseHelper.java
+++ b/server/src/com/cloud/api/ApiResponseHelper.java
@@ -151,6 +151,7 @@ import org.apache.cloudstack.usage.UsageTypes;
 
 import com.cloud.api.query.ViewResponseHelper;
 import com.cloud.api.query.vo.AccountJoinVO;
+import com.cloud.api.query.vo.AclGroupJoinVO;
 import com.cloud.api.query.vo.AclRoleJoinVO;
 import com.cloud.api.query.vo.AsyncJobJoinVO;
 import com.cloud.api.query.vo.ControlledViewEntity;
@@ -3683,19 +3684,10 @@ public class ApiResponseHelper implements ResponseGenerator {
 
     @Override
     public AclGroupResponse createAclGroupResponse(AclGroup group) {
-        AclGroupResponse response = new AclGroupResponse();
-
-        response.setId(group.getUuid());
-        response.setName(group.getName());
-        response.setDescription(group.getDescription());
-        Domain domain = _entityMgr.findById(Domain.class, group.getDomainId());
-        if (domain != null) {
-            response.setDomainId(domain.getUuid());
-            response.setDomainName(domain.getName());
-        }
-
-        response.setObjectName("aclgroup");
-        return response;
+        List<AclGroupJoinVO> viewGroups = ApiDBUtils.newAclGroupView(group);
+        List<AclGroupResponse> listGroups = ViewResponseHelper.createAclGroupResponses(viewGroups);
+        assert listGroups != null && listGroups.size() == 1 : "There should be one acl role returned";
+        return listGroups.get(0);
     }
 
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5583506c/server/src/com/cloud/api/query/dao/AclGroupJoinDaoImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/query/dao/AclGroupJoinDaoImpl.java b/server/src/com/cloud/api/query/dao/AclGroupJoinDaoImpl.java
index 9b70542..a1ffad2 100644
--- a/server/src/com/cloud/api/query/dao/AclGroupJoinDaoImpl.java
+++ b/server/src/com/cloud/api/query/dao/AclGroupJoinDaoImpl.java
@@ -30,6 +30,7 @@ import org.springframework.stereotype.Component;
 import org.apache.cloudstack.acl.AclGroup;
 import org.apache.cloudstack.acl.AclGroupAccountMapVO;
 import org.apache.cloudstack.acl.dao.AclGroupAccountMapDao;
+import org.apache.cloudstack.api.response.AclEntityPermissionResponse;
 import org.apache.cloudstack.api.response.AclGroupResponse;
 import org.apache.cloudstack.api.response.AclRoleResponse;
 import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
@@ -88,6 +89,13 @@ public class AclGroupJoinDaoImpl extends GenericDaoBase<AclGroupJoinVO, Long> im
             roleResp.setName(group.getRoleName());
             response.addRole(roleResp);
         }
+        if (group.getEntityId() > 0) {
+            AclEntityPermissionResponse permResp = new AclEntityPermissionResponse();
+            permResp.setEntityId(group.getEntityUuid());
+            permResp.setEntityType(group.getEntityType());
+            permResp.setAccessType(group.getAccessType().toString());
+            response.addPermission(permResp);
+        }
         response.setObjectName("aclgroup");
         
 
@@ -105,6 +113,13 @@ public class AclGroupJoinDaoImpl extends GenericDaoBase<AclGroupJoinVO, Long> im
             roleResp.setName(group.getRoleName());
             response.addRole(roleResp);
         }
+        if (group.getEntityId() > 0) {
+            AclEntityPermissionResponse permResp = new AclEntityPermissionResponse();
+            permResp.setEntityId(group.getEntityUuid());
+            permResp.setEntityType(group.getEntityType());
+            permResp.setAccessType(group.getAccessType().toString());
+            response.addPermission(permResp);
+        }
         return response;
     }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5583506c/server/src/com/cloud/api/query/vo/AclGroupJoinVO.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/query/vo/AclGroupJoinVO.java b/server/src/com/cloud/api/query/vo/AclGroupJoinVO.java
index dd8e20e..0a32f4d 100644
--- a/server/src/com/cloud/api/query/vo/AclGroupJoinVO.java
+++ b/server/src/com/cloud/api/query/vo/AclGroupJoinVO.java
@@ -20,11 +20,15 @@ import java.util.Date;
 
 import javax.persistence.Column;
 import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
 import javax.persistence.GeneratedValue;
 import javax.persistence.GenerationType;
 import javax.persistence.Id;
 import javax.persistence.Table;
 
+import org.apache.cloudstack.acl.SecurityChecker.AccessType;
+
 import com.cloud.utils.db.GenericDao;
 
 @Entity
@@ -80,6 +84,19 @@ public class AclGroupJoinVO extends BaseViewVO {
     @Column(name = "account_name")
     private String accountName;
 
+    @Column(name = "entity_type")
+    private String entityType;
+
+    @Column(name = "entity_id")
+    private long entityId;
+
+    @Column(name = "entity_uuid")
+    private String entityUuid;
+
+    @Column(name = "access_type")
+    @Enumerated(value = EnumType.STRING)
+    AccessType accessType;
+
     public AclGroupJoinVO() {
     }
 
@@ -154,5 +171,20 @@ public class AclGroupJoinVO extends BaseViewVO {
         return accountName;
     }
 
+    public String getEntityType() {
+        return entityType;
+    }
+
+    public long getEntityId() {
+        return entityId;
+    }
+
+    public String getEntityUuid() {
+        return entityUuid;
+    }
+
+    public AccessType getAccessType() {
+        return accessType;
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5583506c/server/src/com/cloud/server/ManagementServerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java
index 3a4fd31..ae06643 100755
--- a/server/src/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/com/cloud/server/ManagementServerImpl.java
@@ -63,11 +63,13 @@ import org.apache.cloudstack.api.command.admin.acl.CreateAclGroupCmd;
 import org.apache.cloudstack.api.command.admin.acl.CreateAclRoleCmd;
 import org.apache.cloudstack.api.command.admin.acl.DeleteAclGroupCmd;
 import org.apache.cloudstack.api.command.admin.acl.DeleteAclRoleCmd;
+import org.apache.cloudstack.api.command.admin.acl.GrantPermissionToAclGroupCmd;
 import org.apache.cloudstack.api.command.admin.acl.GrantPermissionToAclRoleCmd;
 import org.apache.cloudstack.api.command.admin.acl.ListAclGroupsCmd;
 import org.apache.cloudstack.api.command.admin.acl.ListAclRolesCmd;
 import org.apache.cloudstack.api.command.admin.acl.RemoveAccountFromAclGroupCmd;
 import org.apache.cloudstack.api.command.admin.acl.RemoveAclRoleFromAclGroupCmd;
+import org.apache.cloudstack.api.command.admin.acl.RevokePermissionFromAclGroupCmd;
 import org.apache.cloudstack.api.command.admin.acl.RevokePermissionFromAclRoleCmd;
 import org.apache.cloudstack.api.command.admin.autoscale.CreateCounterCmd;
 import org.apache.cloudstack.api.command.admin.autoscale.DeleteCounterCmd;
@@ -2877,6 +2879,8 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
         cmdList.add(ListAclGroupsCmd.class);
         cmdList.add(AddAccountToAclGroupCmd.class);
         cmdList.add(RemoveAccountFromAclGroupCmd.class);
+        cmdList.add(GrantPermissionToAclGroupCmd.class);
+        cmdList.add(RevokePermissionFromAclGroupCmd.class);
         return cmdList;
     }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5583506c/server/src/org/apache/cloudstack/acl/AclServiceImpl.java
----------------------------------------------------------------------
diff --git a/server/src/org/apache/cloudstack/acl/AclServiceImpl.java b/server/src/org/apache/cloudstack/acl/AclServiceImpl.java
index 00d15db..1e5ad15 100644
--- a/server/src/org/apache/cloudstack/acl/AclServiceImpl.java
+++ b/server/src/org/apache/cloudstack/acl/AclServiceImpl.java
@@ -16,6 +16,7 @@
 // under the License.
 package org.apache.cloudstack.acl;
 
+import java.util.HashMap;
 import java.util.List;
 
 import javax.ejb.Local;
@@ -23,24 +24,31 @@ import javax.inject.Inject;
 
 import org.apache.log4j.Logger;
 
+import org.apache.cloudstack.acl.SecurityChecker.AccessType;
 import org.apache.cloudstack.acl.dao.AclApiPermissionDao;
 import org.apache.cloudstack.acl.dao.AclEntityPermissionDao;
 import org.apache.cloudstack.acl.dao.AclGroupAccountMapDao;
 import org.apache.cloudstack.acl.dao.AclGroupDao;
 import org.apache.cloudstack.acl.dao.AclGroupRoleMapDao;
 import org.apache.cloudstack.acl.dao.AclRoleDao;
+import org.apache.cloudstack.api.Identity;
 import org.apache.cloudstack.context.CallContext;
 
 import com.cloud.event.ActionEvent;
 import com.cloud.event.EventTypes;
 import com.cloud.exception.InvalidParameterValueException;
 import com.cloud.exception.PermissionDeniedException;
+import com.cloud.storage.Snapshot;
+import com.cloud.storage.Volume;
+import com.cloud.template.VirtualMachineTemplate;
 import com.cloud.user.Account;
 import com.cloud.user.AccountManager;
 import com.cloud.user.dao.AccountDao;
+import com.cloud.uservm.UserVm;
 import com.cloud.utils.component.Manager;
 import com.cloud.utils.component.ManagerBase;
 import com.cloud.utils.db.DB;
+import com.cloud.utils.db.EntityManager;
 import com.cloud.utils.db.Transaction;
 
 @Local(value = {AclService.class})
@@ -62,6 +70,9 @@ public class AclServiceImpl extends ManagerBase implements AclService, Manager {
     AclGroupDao _aclGroupDao;
 
     @Inject
+    EntityManager _entityMgr;
+
+    @Inject
     AclGroupRoleMapDao _aclGroupRoleMapDao;
 
     @Inject
@@ -73,6 +84,15 @@ public class AclServiceImpl extends ManagerBase implements AclService, Manager {
     @Inject
     AclEntityPermissionDao _entityPermissionDao;
 
+    public static HashMap<String, Class> entityClassMap = new HashMap<String, Class>();
+
+    static {
+        entityClassMap.put("VirtualMachine", UserVm.class);
+        entityClassMap.put("Volume", Volume.class);
+        entityClassMap.put("Template", VirtualMachineTemplate.class);
+        entityClassMap.put("Snapshot", Snapshot.class);
+        // To be filled in later depending on the entity permission grant scope
+    }
 
     @DB
     @Override
@@ -188,7 +208,7 @@ public class AclServiceImpl extends ManagerBase implements AclService, Manager {
 
         Transaction txn = Transaction.currentTxn();
         txn.start();
-        // add entries in acl_api_permission table
+        // remove entries from acl_api_permission table
         for (String api : apiNames) {
             AclApiPermissionVO perm = _apiPermissionDao.findByRoleAndApi(aclRoleId, api);
             if (perm != null) {
@@ -202,6 +222,80 @@ public class AclServiceImpl extends ManagerBase implements AclService, Manager {
 
     @DB
     @Override
+    @ActionEvent(eventType = EventTypes.EVENT_ACL_GROUP_GRANT, eventDescription = "Granting entity permission to Acl Group")
+    public AclGroup grantEntityPermissionToAclGroup(long aclGroupId, String entityType, long entityId, AccessType accessType) {
+        Account caller = CallContext.current().getCallingAccount();
+        // get the Acl Group entity
+        AclGroup group = _aclGroupDao.findById(aclGroupId);
+        if (group == null) {
+            throw new InvalidParameterValueException("Unable to find acl group: " + aclGroupId
+                    + "; failed to grant permission to group.");
+        }
+        // check permissions
+        _accountMgr.checkAccess(caller, null, true, group);
+
+        // get the entity and check permission
+        Class entityClass = entityClassMap.get(entityType);
+        if (entityClass == null) {
+            throw new InvalidParameterValueException("Entity type " + entityType + " permission granting is not supported yet");
+        }
+        ControlledEntity entity = (ControlledEntity)_entityMgr.findById(entityClass, entityId);
+        if (entity == null) {
+            throw new InvalidParameterValueException("Unable to find entity " + entityType + " by id: " + entityId);
+        }
+        _accountMgr.checkAccess(caller,null, true, entity);
+        
+        // add entry in acl_entity_permission table
+        AclEntityPermissionVO perm = _entityPermissionDao.findByGroupAndEntity(aclGroupId, entityType, entityId, accessType);
+        if (perm == null) {
+            // not there already
+            String entityUuid = String.valueOf(entityId);
+            if (entity instanceof Identity) {
+                entityUuid = ((Identity)entity).getUuid();
+            }
+            perm = new AclEntityPermissionVO(aclGroupId, entityType, entityId, entityUuid, accessType);
+            _entityPermissionDao.persist(perm);
+        }
+        return group;
+
+    }
+
+    @DB
+    @Override
+    @ActionEvent(eventType = EventTypes.EVENT_ACL_GROUP_REVOKE, eventDescription = "Revoking entity permission from Acl Group")
+    public AclGroup revokeEntityPermissionFromAclGroup(long aclGroupId, String entityType, long entityId, AccessType accessType) {
+        Account caller = CallContext.current().getCallingAccount();
+        // get the Acl Group entity
+        AclGroup group = _aclGroupDao.findById(aclGroupId);
+        if (group == null) {
+            throw new InvalidParameterValueException("Unable to find acl group: " + aclGroupId
+                    + "; failed to revoke permission from group.");
+        }
+        // check permissions
+        _accountMgr.checkAccess(caller, null, true, group);
+
+        // get the entity and check permission
+        Class entityClass = entityClassMap.get(entityType);
+        if (entityClass == null) {
+            throw new InvalidParameterValueException("Entity type " + entityType + " permission revoke is not supported yet");
+        }
+        ControlledEntity entity = (ControlledEntity)_entityMgr.findById(entityClass, entityId);
+        if (entity == null) {
+            throw new InvalidParameterValueException("Unable to find entity " + entityType + " by id: " + entityId);
+        }
+        _accountMgr.checkAccess(caller, null, true, entity);
+
+        // remove entry from acl_entity_permission table
+        AclEntityPermissionVO perm = _entityPermissionDao.findByGroupAndEntity(aclGroupId, entityType, entityId, accessType);
+        if (perm != null) {
+            // not removed yet
+            _entityPermissionDao.remove(perm.getId());
+        }
+        return group;
+    }
+
+    @DB
+    @Override
     @ActionEvent(eventType = EventTypes.EVENT_ACL_GROUP_UPDATE, eventDescription = "Adding roles to acl group")
     public AclGroup addAclRolesToGroup(List<Long> roleIds, Long groupId) {
         Account caller = CallContext.current().getCallingAccount();
@@ -326,7 +420,7 @@ public class AclServiceImpl extends ManagerBase implements AclService, Manager {
 
         Transaction txn = Transaction.currentTxn();
         txn.start();
-        // add entries in acl_group_account_map table
+        // remove entries from acl_group_account_map table
         for (Long acctId : acctIds) {
             // check account permissions
             Account account = _accountDao.findById(acctId);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/5583506c/setup/db/db/schema-420to430.sql
----------------------------------------------------------------------
diff --git a/setup/db/db/schema-420to430.sql b/setup/db/db/schema-420to430.sql
index 78c2afe..c23c498 100644
--- a/setup/db/db/schema-420to430.sql
+++ b/setup/db/db/schema-420to430.sql
@@ -361,6 +361,7 @@ CREATE TABLE `cloud`.`acl_entity_permission` (
   `group_id` bigint unsigned NOT NULL,
   `entity_type` varchar(100) NOT NULL,
   `entity_id` bigint unsigned NOT NULL,
+  `entity_uuid` varchar(40),  
   `access_type` varchar(40) NOT NULL,  
   `removed` datetime COMMENT 'date the permission was revoked',
   `created` datetime COMMENT 'date the permission was granted',   
@@ -414,7 +415,11 @@ CREATE VIEW `cloud`.`acl_group_view` AS
         acl_role.name role_name,
         account.id account_id,
         account.uuid account_uuid,
-        account.account_name account_name
+        account.account_name account_name,
+        acl_entity_permission.entity_id entity_id,
+        acl_entity_permission.entity_uuid entity_uuid,
+        acl_entity_permission.entity_type entity_type,
+        acl_entity_permission.access_type access_type
     from
         `cloud`.`acl_group`
             inner join
@@ -426,5 +431,7 @@ CREATE VIEW `cloud`.`acl_group_view` AS
             left join
         `cloud`.`acl_group_account_map` ON acl_group.id = acl_group_account_map.group_id
             left join
-        `cloud`.`account` ON acl_group_account_map.account_id = account.id;                   
+        `cloud`.`account` ON acl_group_account_map.account_id = account.id
+            left join
+         `cloud`.`acl_entity_permission` ON acl_group.id = acl_entity_permission.group_id;                         
  
\ No newline at end of file