mirror of
https://github.com/apache/cloudstack.git
synced 2025-11-02 11:52:28 +01:00
Moved the loading of commands.properties to the IAM plugin
This commit is contained in:
parent
dd8dcd9492
commit
e5b4a1d869
@ -190,10 +190,6 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
|
||||
private static final DateFormat _dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
|
||||
private static Map<String, List<Class<?>>> _apiNameCmdClassMap = new HashMap<String, List<Class<?>>>();
|
||||
|
||||
private static Set<String> commandsPropertiesOverrides = new HashSet<String>();
|
||||
private static Map<RoleType, Set<String>> commandsPropertiesRoleBasedApisMap = new HashMap<RoleType, Set<String>>();
|
||||
|
||||
|
||||
private static ExecutorService _executor = new ThreadPoolExecutor(10, 150, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new NamedThreadFactory("ApiServer"));
|
||||
|
||||
public ApiServer() {
|
||||
@ -201,7 +197,6 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
|
||||
|
||||
@Override
|
||||
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
|
||||
processMapping(PropertiesUtil.processConfigFile(new String[] { "commands.properties" }));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -238,39 +233,6 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
|
||||
}
|
||||
}
|
||||
|
||||
// drop all default policy api permissions - we reload them every time
|
||||
// to include any chanegs done to the @APICommand or
|
||||
// commands.properties.
|
||||
SearchBuilder<AclPolicyPermissionVO> sb = _aclPermissionDao.createSearchBuilder();
|
||||
sb.and("policyId", sb.entity().getAclPolicyId(), SearchCriteria.Op.EQ);
|
||||
sb.and("scope", sb.entity().getScope(), SearchCriteria.Op.EQ);
|
||||
sb.done();
|
||||
|
||||
SearchCriteria<AclPolicyPermissionVO> permissionSC = sb.create();
|
||||
|
||||
for (RoleType role : RoleType.values()) {
|
||||
permissionSC.setParameters("policyId", role.ordinal() + 1);
|
||||
switch (role) {
|
||||
case User:
|
||||
permissionSC.setParameters("scope", PermissionScope.ACCOUNT.toString());
|
||||
break;
|
||||
|
||||
case Admin:
|
||||
permissionSC.setParameters("scope", PermissionScope.ALL.toString());
|
||||
break;
|
||||
|
||||
case DomainAdmin:
|
||||
permissionSC.setParameters("scope", PermissionScope.DOMAIN.toString());
|
||||
break;
|
||||
|
||||
case ResourceAdmin:
|
||||
permissionSC.setParameters("scope", PermissionScope.DOMAIN.toString());
|
||||
break;
|
||||
}
|
||||
_aclPermissionDao.expunge(permissionSC);
|
||||
|
||||
}
|
||||
|
||||
for(Class<?> cmdClass: cmdClasses) {
|
||||
APICommand at = cmdClass.getAnnotation(APICommand.class);
|
||||
if (at == null) {
|
||||
@ -283,28 +245,8 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
|
||||
_apiNameCmdClassMap.put(apiName, apiCmdList);
|
||||
}
|
||||
apiCmdList.add(cmdClass);
|
||||
|
||||
if (!commandsPropertiesOverrides.contains(apiName)) {
|
||||
for (RoleType role : at.authorized()) {
|
||||
addDefaultAclPolicyPermission(apiName, cmdClass, role);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// read commands.properties and load api acl permissions -
|
||||
// commands.properties overrides any @APICommand authorization
|
||||
|
||||
for (String apiName : commandsPropertiesOverrides) {
|
||||
Class<?> cmdClass = getCmdClass(apiName);
|
||||
for (RoleType role : RoleType.values()) {
|
||||
if (commandsPropertiesRoleBasedApisMap.get(role).contains(apiName)) {
|
||||
// insert permission for this role for this api
|
||||
addDefaultAclPolicyPermission(apiName, cmdClass, role);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
encodeApiResponse = Boolean.valueOf(_configDao.getValue(Config.EncodeApiResponse.key()));
|
||||
String jsonType = _configDao.getValue(Config.JavaScriptDefaultContentType.key());
|
||||
if (jsonType != null) {
|
||||
@ -319,92 +261,6 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
|
||||
return true;
|
||||
}
|
||||
|
||||
private void processMapping(Map<String, String> configMap) {
|
||||
for (RoleType roleType : RoleType.values()) {
|
||||
commandsPropertiesRoleBasedApisMap.put(roleType, new HashSet<String>());
|
||||
}
|
||||
|
||||
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)
|
||||
commandsPropertiesRoleBasedApisMap.get(roleType).add(apiName);
|
||||
}
|
||||
} catch (NumberFormatException nfe) {
|
||||
s_logger.info("Malformed key=value pair for entry: " + entry.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addDefaultAclPolicyPermission(String apiName, Class<?> cmdClass, RoleType role) {
|
||||
|
||||
boolean isReadCommand = false;
|
||||
AclEntityType[] entityTypes = null;
|
||||
if (cmdClass != null) {
|
||||
BaseCmd cmdObj;
|
||||
try {
|
||||
cmdObj = (BaseCmd) cmdClass.newInstance();
|
||||
if (cmdObj instanceof BaseListCmd) {
|
||||
isReadCommand = true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new CloudRuntimeException(String.format(
|
||||
"%s is claimed as an API command, but it cannot be instantiated", cmdClass.getName()));
|
||||
}
|
||||
|
||||
APICommand at = cmdClass.getAnnotation(APICommand.class);
|
||||
entityTypes = at.entityType();
|
||||
}
|
||||
|
||||
AclPolicyPermissionVO apiPermission = null;
|
||||
PermissionScope permissionScope = PermissionScope.ACCOUNT;
|
||||
switch (role) {
|
||||
case User:
|
||||
permissionScope = PermissionScope.ACCOUNT;
|
||||
break;
|
||||
|
||||
case Admin:
|
||||
permissionScope = PermissionScope.ALL;
|
||||
break;
|
||||
|
||||
case DomainAdmin:
|
||||
permissionScope = PermissionScope.DOMAIN;
|
||||
break;
|
||||
|
||||
case ResourceAdmin:
|
||||
permissionScope = PermissionScope.DOMAIN;
|
||||
break;
|
||||
}
|
||||
|
||||
if (entityTypes == null || entityTypes.length == 0) {
|
||||
apiPermission = new AclPolicyPermissionVO(role.ordinal() + 1, apiName, null, null, permissionScope,
|
||||
new Long(-1), Permission.Allow);
|
||||
if (apiPermission != null) {
|
||||
if (isReadCommand) {
|
||||
apiPermission.setAccessType(AccessType.ListEntry);
|
||||
}
|
||||
_aclPermissionDao.persist(apiPermission);
|
||||
}
|
||||
} else {
|
||||
|
||||
for (AclEntityType entityType : entityTypes) {
|
||||
apiPermission = new AclPolicyPermissionVO(role.ordinal() + 1, apiName, entityType.toString(), null,
|
||||
permissionScope, new Long(-1), Permission.Allow);
|
||||
if (apiPermission != null) {
|
||||
if (isReadCommand) {
|
||||
apiPermission.setAccessType(AccessType.ListEntry);
|
||||
}
|
||||
_aclPermissionDao.persist(apiPermission);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// NOTE: handle() only handles over the wire (OTW) requests from integration.api.port 8096
|
||||
// If integration api port is not configured, actual OTW requests will be received by ApiServlet
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
|
||||
@ -16,52 +16,205 @@
|
||||
// under the License.
|
||||
package org.apache.cloudstack.acl;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.ejb.Local;
|
||||
import javax.inject.Inject;
|
||||
import javax.naming.ConfigurationException;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import org.apache.cloudstack.acl.api.AclApiService;
|
||||
import org.apache.cloudstack.acl.APIChecker;
|
||||
import org.apache.cloudstack.acl.AclEntityType;
|
||||
import org.apache.cloudstack.acl.PermissionScope;
|
||||
import org.apache.cloudstack.acl.RoleType;
|
||||
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
|
||||
import org.apache.cloudstack.api.APICommand;
|
||||
import org.apache.cloudstack.api.BaseCmd;
|
||||
import org.apache.cloudstack.api.BaseListCmd;
|
||||
import org.apache.cloudstack.iam.api.AclPolicy;
|
||||
import org.apache.cloudstack.iam.api.AclPolicyPermission.Permission;
|
||||
import org.apache.cloudstack.iam.api.IAMService;
|
||||
|
||||
import com.cloud.api.ApiServerService;
|
||||
import com.cloud.exception.PermissionDeniedException;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.user.AccountService;
|
||||
import com.cloud.user.User;
|
||||
import com.cloud.utils.PropertiesUtil;
|
||||
import com.cloud.utils.component.AdapterBase;
|
||||
import com.cloud.utils.component.PluggableService;
|
||||
import com.cloud.utils.exception.CloudRuntimeException;
|
||||
|
||||
// This is the Role Based API access checker that grab's the account's roles
|
||||
// based on the set of roles, access is granted if any of the role has access to the api
|
||||
//This is the Role Based API access checker that grab's the account's roles
|
||||
//based on the set of roles, access is granted if any of the role has access to the api
|
||||
@Local(value=APIChecker.class)
|
||||
public class RoleBasedAPIAccessChecker extends AdapterBase implements APIChecker {
|
||||
|
||||
protected static final Logger s_logger = Logger.getLogger(RoleBasedAPIAccessChecker.class);
|
||||
|
||||
@Inject AccountService _accountService;
|
||||
@Inject AclApiService _aclService;
|
||||
@Inject
|
||||
AccountService _accountService;
|
||||
@Inject
|
||||
ApiServerService _apiServer;
|
||||
@Inject
|
||||
IAMService _iamSrv;
|
||||
|
||||
Set<String> commandsPropertiesOverrides = new HashSet<String>();
|
||||
Map<RoleType, Set<String>> commandsPropertiesRoleBasedApisMap = new HashMap<RoleType, Set<String>>();
|
||||
|
||||
List<PluggableService> _services;
|
||||
|
||||
protected RoleBasedAPIAccessChecker() {
|
||||
super();
|
||||
}
|
||||
for (RoleType roleType : RoleType.values()) {
|
||||
commandsPropertiesRoleBasedApisMap.put(roleType, new HashSet<String>());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkAccess(User user, String commandName)
|
||||
throws PermissionDeniedException {
|
||||
public boolean checkAccess(User user, String commandName) throws PermissionDeniedException {
|
||||
Account account = _accountService.getAccount(user.getAccountId());
|
||||
if (account == null) {
|
||||
throw new PermissionDeniedException("The account id=" + user.getAccountId() + "for user id=" + user.getId() + "is null");
|
||||
throw new PermissionDeniedException("The account id=" + user.getAccountId() + "for user id=" + user.getId()
|
||||
+ "is null");
|
||||
}
|
||||
|
||||
List<AclPolicy> policies = _aclService.listAclPolicies(account.getAccountId());
|
||||
List<AclPolicy> policies = _iamSrv.listAclPolicies(account.getAccountId());
|
||||
|
||||
|
||||
boolean isAllowed = _aclService.isAPIAccessibleForPolicies(commandName, policies);
|
||||
boolean isAllowed = _iamSrv.isAPIAccessibleForPolicies(commandName, policies);
|
||||
if (!isAllowed) {
|
||||
throw new PermissionDeniedException("The API does not exist or is blacklisted. api: " + commandName);
|
||||
}
|
||||
return isAllowed;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
|
||||
super.configure(name, params);
|
||||
|
||||
processMapping(PropertiesUtil.processConfigFile(new String[] { "commands.properties" }));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean start() {
|
||||
|
||||
// drop all default policy api permissions - we reload them every time
|
||||
// to include any changes done to the @APICommand or
|
||||
// commands.properties.
|
||||
|
||||
for (RoleType role : RoleType.values()) {
|
||||
_iamSrv.resetAclPolicy(role.ordinal() + 1);
|
||||
}
|
||||
|
||||
for (PluggableService service : _services) {
|
||||
for (Class<?> cmdClass : service.getCommands()) {
|
||||
APICommand command = cmdClass.getAnnotation(APICommand.class);
|
||||
if (!commandsPropertiesOverrides.contains(command.name())) {
|
||||
for (RoleType role : command.authorized()) {
|
||||
addDefaultAclPolicyPermission(command.name(), cmdClass, role);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// read commands.properties and load api acl permissions -
|
||||
// commands.properties overrides any @APICommand authorization
|
||||
|
||||
for (String apiName : commandsPropertiesOverrides) {
|
||||
Class<?> cmdClass = _apiServer.getCmdClass(apiName);
|
||||
for (RoleType role : RoleType.values()) {
|
||||
if (commandsPropertiesRoleBasedApisMap.get(role).contains(apiName)) {
|
||||
// insert permission for this role for this api
|
||||
addDefaultAclPolicyPermission(apiName, cmdClass, role);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
commandsPropertiesRoleBasedApisMap.get(roleType).add(apiName);
|
||||
}
|
||||
} catch (NumberFormatException nfe) {
|
||||
s_logger.info("Malformed key=value pair for entry: " + entry.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<PluggableService> getServices() {
|
||||
return _services;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setServices(List<PluggableService> _services) {
|
||||
this._services = _services;
|
||||
}
|
||||
|
||||
private void addDefaultAclPolicyPermission(String apiName, Class<?> cmdClass, RoleType role) {
|
||||
|
||||
AccessType accessType = null;
|
||||
AclEntityType[] entityTypes = null;
|
||||
if (cmdClass != null) {
|
||||
BaseCmd cmdObj;
|
||||
try {
|
||||
cmdObj = (BaseCmd) cmdClass.newInstance();
|
||||
if (cmdObj instanceof BaseListCmd) {
|
||||
accessType = AccessType.ListEntry;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new CloudRuntimeException(String.format(
|
||||
"%s is claimed as an API command, but it cannot be instantiated", cmdClass.getName()));
|
||||
}
|
||||
|
||||
APICommand at = cmdClass.getAnnotation(APICommand.class);
|
||||
entityTypes = at.entityType();
|
||||
}
|
||||
|
||||
PermissionScope permissionScope = PermissionScope.ACCOUNT;
|
||||
switch (role) {
|
||||
case User:
|
||||
permissionScope = PermissionScope.ACCOUNT;
|
||||
break;
|
||||
|
||||
case Admin:
|
||||
permissionScope = PermissionScope.ALL;
|
||||
break;
|
||||
|
||||
case DomainAdmin:
|
||||
permissionScope = PermissionScope.DOMAIN;
|
||||
break;
|
||||
|
||||
case ResourceAdmin:
|
||||
permissionScope = PermissionScope.DOMAIN;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (entityTypes == null || entityTypes.length == 0) {
|
||||
_iamSrv.addAclPermissionToAclPolicy(new Long(role.ordinal()) + 1, null, permissionScope.toString(), new Long(-1),
|
||||
apiName, accessType.toString(), Permission.Allow);
|
||||
} else {
|
||||
for (AclEntityType entityType : entityTypes) {
|
||||
_iamSrv.addAclPermissionToAclPolicy(new Long(role.ordinal()) + 1, entityType.toString(), permissionScope.toString(), new Long(-1),
|
||||
apiName, accessType.toString(), Permission.Allow);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -34,4 +34,24 @@
|
||||
<module>plugin</module>
|
||||
<module>server</module>
|
||||
</modules>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.cloudstack</groupId>
|
||||
<artifactId>cloud-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.cloudstack</groupId>
|
||||
<artifactId>cloud-utils</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.cloudstack</groupId>
|
||||
<artifactId>cloud-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
||||
@ -27,18 +27,6 @@
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.cloudstack</groupId>
|
||||
<artifactId>cloud-utils</artifactId>
|
||||
|
||||
@ -72,5 +72,6 @@ public interface IAMService {
|
||||
|
||||
List<Long> getGrantedEntities(long accountId, String action, String scope);
|
||||
|
||||
AclPolicy resetAclPolicy(long aclPolicyId);
|
||||
|
||||
}
|
||||
|
||||
@ -579,6 +579,26 @@ public class IAMServiceImpl extends ManagerBase implements IAMService, Manager {
|
||||
}
|
||||
|
||||
|
||||
@DB
|
||||
@Override
|
||||
public AclPolicy resetAclPolicy(long aclPolicyId) {
|
||||
// get the Acl Policy entity
|
||||
AclPolicy policy = _aclPolicyDao.findById(aclPolicyId);
|
||||
if (policy == null) {
|
||||
throw new InvalidParameterValueException("Unable to find acl policy: " + aclPolicyId
|
||||
+ "; failed to reset the policy.");
|
||||
}
|
||||
|
||||
SearchBuilder<AclPolicyPermissionVO> sb = _policyPermissionDao.createSearchBuilder();
|
||||
sb.and("policyId", sb.entity().getAclPolicyId(), SearchCriteria.Op.EQ);
|
||||
sb.and("scope", sb.entity().getScope(), SearchCriteria.Op.EQ);
|
||||
sb.done();
|
||||
SearchCriteria<AclPolicyPermissionVO> permissionSC = sb.create();
|
||||
permissionSC.setParameters("policyId", aclPolicyId);
|
||||
_policyPermissionDao.expunge(permissionSC);
|
||||
|
||||
return policy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAPIAccessibleForPolicies(String apiName, List<AclPolicy> policies) {
|
||||
|
||||
@ -17,7 +17,6 @@
|
||||
package org.apache.cloudstack.iam;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.mockito.Matchers.anyLong;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user