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

git commit: updated refs/heads/master to 9f7b488

Updated Branches:
  refs/heads/master ad7494848 -> 9f7b4884a


Make commands.properties optional for non-ACS code

Currently any new API extension to CloudStack must edit
commands.properties to add the appropriate ACLs.  This generally works
fine for ACS as we control the contents of that file and distribute
all the code ourself.  The hang up comes when somebody develops code
outside of ACS and want to add their code to an existing ACS
installation.  The Spring work that has been done has made this much
easier, but you are still required to manually edit
commands.properties.  This change introduces the following logic.

First check commands.properties for ACL info.  If ACL info exists, use
that to authorize the command.  If no ACL information exists (ie
null), then look at the @APICommand annotation.  The defaults of
@APICommand will provide no ACL info.  If the @APICommand annotation
provides no ACL info, use that.


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

Branch: refs/heads/master
Commit: 9f7b4884a7a0bf0b15d94777cff449fde4664af2
Parents: ad74948
Author: Darren Shepherd <da...@gmail.com>
Authored: Thu Oct 24 15:05:05 2013 -0700
Committer: Darren Shepherd <da...@gmail.com>
Committed: Fri Oct 25 16:31:55 2013 -0700

----------------------------------------------------------------------
 .../org/apache/cloudstack/api/APICommand.java   |  4 +++
 .../acl/StaticRoleBasedAPIAccessChecker.java    | 37 +++++++++++++++++---
 2 files changed, 36 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/9f7b4884/api/src/org/apache/cloudstack/api/APICommand.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/APICommand.java b/api/src/org/apache/cloudstack/api/APICommand.java
index 4d024c1..7c9e6fe 100644
--- a/api/src/org/apache/cloudstack/api/APICommand.java
+++ b/api/src/org/apache/cloudstack/api/APICommand.java
@@ -22,6 +22,8 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+import org.apache.cloudstack.acl.RoleType;
+
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ TYPE })
 public @interface APICommand {
@@ -36,4 +38,6 @@ public @interface APICommand {
     boolean includeInApiDoc() default true;
 
     String since() default "";
+
+    RoleType[] authorized() default {};
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/9f7b4884/plugins/acl/static-role-based/src/org/apache/cloudstack/acl/StaticRoleBasedAPIAccessChecker.java
----------------------------------------------------------------------
diff --git a/plugins/acl/static-role-based/src/org/apache/cloudstack/acl/StaticRoleBasedAPIAccessChecker.java b/plugins/acl/static-role-based/src/org/apache/cloudstack/acl/StaticRoleBasedAPIAccessChecker.java
index affcf91..bf3acf5 100644
--- a/plugins/acl/static-role-based/src/org/apache/cloudstack/acl/StaticRoleBasedAPIAccessChecker.java
+++ b/plugins/acl/static-role-based/src/org/apache/cloudstack/acl/StaticRoleBasedAPIAccessChecker.java
@@ -26,6 +26,7 @@ import javax.ejb.Local;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
+import org.apache.cloudstack.api.APICommand;
 import org.apache.log4j.Logger;
 
 import com.cloud.exception.PermissionDeniedException;
@@ -43,7 +44,10 @@ public class StaticRoleBasedAPIAccessChecker extends AdapterBase implements APIC
 
     protected static final Logger s_logger = Logger.getLogger(StaticRoleBasedAPIAccessChecker.class);
 
-    private static Map<RoleType, Set<String>> s_roleBasedApisMap =
+    Set<String> commandsPropertiesOverrides = new HashSet<String>();
+    Map<RoleType, Set<String>> commandsPropertiesRoleBasedApisMap =
+            new HashMap<RoleType, Set<String>>();
+    Map<RoleType, Set<String>> annotationRoleBasedApisMap =
             new HashMap<RoleType, Set<String>>();
 
     List<PluggableService> _services;
@@ -51,8 +55,10 @@ public class StaticRoleBasedAPIAccessChecker extends AdapterBase implements APIC
 
     protected StaticRoleBasedAPIAccessChecker() {
         super();
-        for (RoleType roleType: RoleType.values())
-            s_roleBasedApisMap.put(roleType, new HashSet<String>());
+        for (RoleType roleType: RoleType.values()) {
+            commandsPropertiesRoleBasedApisMap.put(roleType, new HashSet<String>());
+            annotationRoleBasedApisMap.put(roleType, new HashSet<String>());
+        }
     }
 
     @Override
@@ -64,7 +70,10 @@ public class StaticRoleBasedAPIAccessChecker extends AdapterBase implements APIC
         }
 
         RoleType roleType = _accountService.getRoleType(account);
-        boolean isAllowed = s_roleBasedApisMap.get(roleType).contains(commandName);
+        boolean isAllowed = commandsPropertiesOverrides.contains(commandName) ?
+                commandsPropertiesRoleBasedApisMap.get(roleType).contains(commandName) :
+                    annotationRoleBasedApisMap.get(roleType).contains(commandName);
+
         if (!isAllowed) {
             throw new PermissionDeniedException("The API does not exist or is blacklisted. Role type=" + roleType.toString() + " is not allowed to request the api: " + commandName);
         }
@@ -80,15 +89,32 @@ public class StaticRoleBasedAPIAccessChecker extends AdapterBase implements APIC
         return true;
     }
 
+
+    @Override
+    public boolean start() {
+        for ( PluggableService service : _services ) {
+            for ( Class<?> clz : service.getCommands() ) {
+                APICommand command = clz.getAnnotation(APICommand.class);
+                for ( RoleType role : command.authorized() ) {
+                    Set<String> commands = annotationRoleBasedApisMap.get(role);
+                    if (!commands.contains(command.name()))
+                        commands.add(command.name());
+                }
+            }
+        }
+        return super.start();
+    }
+
     private void processMapping(Map<String, String> configMap) {
         for (Map.Entry<String, String> entry: configMap.entrySet()) {
             String apiName = entry.getKey();
             String roleMask = entry.getValue();
+            commandsPropertiesOverrides.add(apiName);
             try {
                 short cmdPermissions = Short.parseShort(roleMask);
                 for (RoleType roleType: RoleType.values()) {
                     if ((cmdPermissions & roleType.getValue()) != 0)
-                        s_roleBasedApisMap.get(roleType).add(apiName);
+                        commandsPropertiesRoleBasedApisMap.get(roleType).add(apiName);
                 }
             } catch (NumberFormatException nfe) {
                 s_logger.info("Malformed key=value pair for entry: " + entry.toString());
@@ -104,4 +130,5 @@ public class StaticRoleBasedAPIAccessChecker extends AdapterBase implements APIC
     public void setServices(List<PluggableService> _services) {
         this._services = _services;
     }
+
 }