mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
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.
This commit is contained in:
parent
ad74948480
commit
9f7b4884a7
@ -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 {};
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user