/*
* Copyright (c) 2008-2013 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.security.authorization;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import javax.xml.bind.annotation.XmlElement;
import org.apache.commons.lang.StringUtils;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import com.emc.storageos.coordinator.client.service.CoordinatorClient;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.URIUtil;
import com.emc.storageos.db.client.constraint.AlternateIdConstraint;
import com.emc.storageos.db.client.constraint.ContainmentConstraint;
import com.emc.storageos.db.client.constraint.ContainmentPermissionsConstraint;
import com.emc.storageos.db.client.constraint.NamedElementQueryResultList;
import com.emc.storageos.db.client.constraint.NamedElementQueryResultList.NamedElement;
import com.emc.storageos.db.client.constraint.PrefixConstraint;
import com.emc.storageos.db.client.constraint.QueryResultList;
import com.emc.storageos.db.client.constraint.URIQueryResultList;
import com.emc.storageos.db.client.model.AbstractChangeTrackingSet;
import com.emc.storageos.db.client.model.Cluster;
import com.emc.storageos.db.client.model.ComputeVirtualPool;
import com.emc.storageos.db.client.model.DataObject;
import com.emc.storageos.db.client.model.FilePolicy;
import com.emc.storageos.db.client.model.Host;
import com.emc.storageos.db.client.model.Initiator;
import com.emc.storageos.db.client.model.IpInterface;
import com.emc.storageos.db.client.model.NamedURI;
import com.emc.storageos.db.client.model.Project;
import com.emc.storageos.db.client.model.StorageOSUserDAO;
import com.emc.storageos.db.client.model.StringSet;
import com.emc.storageos.db.client.model.StringSetMap;
import com.emc.storageos.db.client.model.TenantOrg;
import com.emc.storageos.db.client.model.TenantResource;
import com.emc.storageos.db.client.model.UserGroup;
import com.emc.storageos.db.client.model.Vcenter;
import com.emc.storageos.db.client.model.VcenterDataCenter;
import com.emc.storageos.db.client.model.VirtualArray;
import com.emc.storageos.db.client.model.VirtualDataCenter;
import com.emc.storageos.db.client.model.VirtualPool;
import com.emc.storageos.db.client.model.Volume;
import com.emc.storageos.db.client.model.uimodels.CatalogCategory;
import com.emc.storageos.db.client.model.uimodels.CatalogService;
import com.emc.storageos.db.client.util.CustomQueryUtility;
import com.emc.storageos.db.client.util.NullColumnValueGetter;
import com.emc.storageos.db.common.VdcUtil;
import com.emc.storageos.db.exceptions.DatabaseException;
import com.emc.storageos.db.exceptions.FatalDatabaseException;
import com.emc.storageos.model.auth.ACLEntry;
import com.emc.storageos.model.tenant.UserMappingAttributeParam;
import com.emc.storageos.model.tenant.UserMappingParam;
import com.emc.storageos.model.usergroup.UserAttributeParam;
import com.emc.storageos.security.SecurityDisabler;
import com.emc.storageos.security.authentication.StorageOSUser;
import com.emc.storageos.security.exceptions.SecurityException;
import com.emc.storageos.svcs.errorhandling.resources.APIException;
/**
* Class provides helper methods for accessing roles and acls from db
*/
public class BasePermissionsHelper {
private static final Logger _log = LoggerFactory.getLogger(BasePermissionsHelper.class);
private static final String ROOT = "root";
private DbClient _dbClient = null;
private boolean _usingCache = true;
private Map<CoordinatorClient.LicenseType, Boolean> licensedCache = new HashMap<CoordinatorClient.LicenseType, Boolean>();
@Autowired(required = false)
private SecurityDisabler _disabler;
@Autowired
private CoordinatorClient _coordinatorClient;
/**
* Determines if the specific license type is enabled.
*
* @param type
* the type of the license.
* @return true if the license is found.
*/
public boolean isLicensed(CoordinatorClient.LicenseType type) {
boolean licensed = Boolean.TRUE.equals(licensedCache.get(type));
if (!licensed) {
licensed = _coordinatorClient.isStorageProductLicensed(type);
licensedCache.put(type, licensed);
}
return licensed;
}
/**
* Determines if any of the provided licenses are enabled.
*
* @param types
* the license types.
* @return true if any of the provided licenses are found.
*/
public boolean isAnyLicensed(CoordinatorClient.LicenseType... types) {
for (CoordinatorClient.LicenseType type : types) {
if (isLicensed(type)) {
return true;
}
}
return false;
}
/**
* Determines if there are any licenses enabled.
*
* @return true if any license is found.
*/
public boolean hasAnyLicense() {
return isAnyLicensed(CoordinatorClient.LicenseType.values());
}
private static boolean containsAllIgnoreCase(List<String> left, List<String> right) {
for (String rightString : right) {
if (!containsIgnoreCase(left, rightString)) {
return false;
}
}
return true;
}
/**
* Check if the two lists contain the same string values
* ignoring case
*
* @param left
* @param right
* @return true if left and right lists are equal ignoring case
* and list position
*/
private static boolean listEqualsIgnoreCase(List<String> left, List<String> right) {
if (left == null) {
if (right != null) {
return false;
}
} else if (right == null) {
return false;
} else if (left.size() != right.size()) {
return false;
}
return containsAllIgnoreCase(left, right);
}
private static boolean containsIgnoreCase(List<String> left, String rightString) {
for (String leftString : left) {
if (leftString.equalsIgnoreCase(rightString)) {
return true;
}
}
return false;
}
public static class UserMapping {
private String _domain;
private List<UserMappingAttribute> _attributes;
private List<String> _groups;
public String getDomain() {
return _domain == null ? null : _domain.toLowerCase();
}
public void setDomain(String domain) {
_domain = domain;
}
public List<UserMappingAttribute> getAttributes() {
return _attributes;
}
public void setAttributes(List<UserMappingAttribute> attributes) {
_attributes = attributes;
}
public List<String> getGroups() {
return _groups;
}
public void setGroups(List<String> groups) {
_groups = groups;
}
public UserMapping() {
_attributes = new ArrayList<UserMappingAttribute>();
_groups = new ArrayList<String>();
}
public UserMapping(UserMappingParam param) {
_domain = param.getDomain();
_groups = param.getGroups() == null ? new ArrayList<String>() : param.getGroups();
if (param.getAttributes() != null) {
_attributes = new ArrayList<UserMappingAttribute>();
for (UserMappingAttributeParam attribute : param.getAttributes()) {
_attributes.add(new UserMappingAttribute(attribute));
}
} else {
_attributes = new ArrayList<UserMappingAttribute>();
}
}
public static List<UserMapping> fromParamList(List<UserMappingParam> params) {
if (params == null) {
return null;
}
List<UserMapping> userMappings = new ArrayList<UserMapping>();
for (UserMappingParam param : params) {
userMappings.add(new UserMapping(param));
}
return userMappings;
}
public static UserMappingParam toParam(UserMapping mapping) {
UserMappingParam param = new UserMappingParam();
param.setDomain(mapping.getDomain());
param.setGroups(mapping.getGroups());
if (mapping.getAttributes() != null) {
List<UserMappingAttributeParam> attrList = new ArrayList<UserMappingAttributeParam>();
for (UserMappingAttribute attribute : mapping.getAttributes()) {
attrList.add(UserMappingAttribute.toParam(attribute));
}
param.setAttributes(attrList);
} else {
param.setAttributes(new ArrayList<UserMappingAttributeParam>());
}
return param;
}
/**
* Check if this mapping conflicts with the other mapping
*
* @param other
* @return
*/
public boolean isMatch(UserMapping other) {
// return true if users with this mapping would match the other mapping or
// users with the other mapping would match this mapping
return isMatch(other.getDomain(), other.getAttributes(), other.getGroups())
|| other.isMatch(getDomain(), getAttributes(), getGroups());
}
/**
* Check if the domain, attributes, and groups results in a match with this UserMapping object
*
* @param domain
* @param attributes
* @param groups
* @return true if there is a match with this mapping
*/
public boolean isMatch(String domain, List<UserMappingAttribute> attributes, List<String> groups) {
return _domain.equalsIgnoreCase(domain) && attributesMatch(attributes) && groupsMatch(groups);
}
/**
* check if the other mapping contains all of this mapping's groups
*
* @param groups the other mapping to compare to
* @return true if this mapping's groups are a sublist of the other mapping
*/
private boolean groupsMatch(List<String> groups) {
// If there are no groups in this mapping then they match inherently
// if there are groups then check if the groups passed in contain all of the
// groups in the mapping
return !hasGroups() || (groups != null && containsAllIgnoreCase(groups, _groups));
}
/**
* Check if this mapping has groups
*
* @return true if the groups list is not null and not empty
*/
private boolean hasGroups() {
return getGroups() != null && !getGroups().isEmpty();
}
/**
* Check if this mapping's attributes conflicts with the
* other mappings attributes
*
* @param attributes The other mapping to compare this mapping to
* @return true if the mapping's attributes conflict with the other
*/
private boolean attributesMatch(List<UserMappingAttribute> attributes) {
return !hasAttributes() || (attributes != null && containsAllAttributes(attributes, getAttributes()));
}
/**
* Check if this user mappings attributes are equal to a list of
* user mapping attributes
*
* @param right list of attributes to compare to
* @return true if the attribute lists are equal
*/
private boolean equalsAttributes(List<UserMappingAttribute> right) {
if (_attributes == null) {
if (right != null) {
return false;
}
} else if (right == null) {
return false;
}
if (_attributes.size() != right.size()) {
return false;
} else {
return _attributes.containsAll(right);
}
}
private boolean containsAllAttributes(
List<UserMappingAttribute> leftAttributes,
List<UserMappingAttribute> rightAttributes) {
for (UserMappingAttribute rightAttribute : rightAttributes) {
if (!containsAttribute(leftAttributes, rightAttribute)) {
return false;
}
}
return true;
}
private boolean containsAttribute(
List<UserMappingAttribute> leftAttributes,
UserMappingAttribute rightAttribute) {
for (UserMappingAttribute leftAttribute : leftAttributes) {
if (leftAttribute.getKey().equalsIgnoreCase(rightAttribute.getKey())
&& containsAllIgnoreCase(leftAttribute.getValues(), rightAttribute.getValues())) {
return true;
}
}
return false;
}
/**
* Check if the mapping has attributes
*
* @return true if the list of attributes is not null and is not empty
*/
private boolean hasAttributes() {
return getAttributes() != null && !getAttributes().isEmpty();
}
@Override
public String toString() {
ObjectMapper mapper = new ObjectMapper();
try {
_domain = _domain.toLowerCase();
return mapper.writeValueAsString(this);
} catch (JsonGenerationException e) {
_log.error("Failed to convert mapping to string.", e);
} catch (JsonMappingException e) {
_log.error("Failed to convert mapping to string.", e);
} catch (IOException e) {
_log.error("Failed to convert mapping to string.", e);
}
return null;
}
public static UserMapping fromString(String userMappingString) {
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.readValue(userMappingString, UserMapping.class);
} catch (JsonParseException e) {
_log.error("Failed to convert mapping to string.", e);
} catch (JsonMappingException e) {
_log.error("Failed to convert mapping to string.", e);
} catch (IOException e) {
_log.error("Failed to convert mapping to string.", e);
}
return null;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((_attributes == null) ? 0 : _attributes.hashCode());
result = prime * result
+ ((_domain == null) ? 0 : _domain.hashCode());
result = prime * result
+ ((_groups == null) ? 0 : _groups.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;
}
UserMapping other = (UserMapping) obj;
if (_domain == null) {
if (other._domain != null) {
return false;
}
} else if (!_domain.equalsIgnoreCase(other._domain)) {
return false;
}
if (!listEqualsIgnoreCase(_groups, other._groups)) {
return false;
}
return equalsAttributes(other._attributes);
}
}
public static class UserMappingAttribute {
private String _key;
private List<String> _values;
public UserMappingAttribute() {
_values = new ArrayList<String>();
}
public UserMappingAttribute(UserMappingAttributeParam param) {
_key = param.getKey();
_values = param.getValues();
}
public static UserMappingAttributeParam toParam(UserMappingAttribute attribute) {
UserMappingAttributeParam param = new UserMappingAttributeParam();
param.setKey(attribute.getKey());
param.setValues(attribute.getValues());
return param;
}
@XmlElement(required = true, name = "key")
public String getKey() {
return _key;
}
public void setKey(String key) {
_key = key;
}
@XmlElement(required = true, name = "value")
public List<String> getValues() {
return _values;
}
public void setValues(List<String> values) {
_values = values;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((_key == null) ? 0 : _key.hashCode());
result = prime * result
+ ((_values == null) ? 0 : _values.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;
}
UserMappingAttribute other = (UserMappingAttribute) obj;
if (_key == null) {
if (other._key != null) {
return false;
}
} else if (!_key.equalsIgnoreCase(other._key)) {
return false;
}
return listEqualsIgnoreCase(_values, other._values);
}
}
/**
* Constructor - takes db client
*
* @param dbClient
*/
public BasePermissionsHelper(DbClient dbClient) {
_dbClient = dbClient;
}
/**
* Constructor - takes db client, using cache
*
* @param dbClient
* @param usingCache
*/
public BasePermissionsHelper(DbClient dbClient, boolean usingCache) {
_dbClient = dbClient;
_usingCache = usingCache;
}
public void setUsingCache(boolean usingCache) {
_usingCache = usingCache;
}
/**
* Find the tenant for a user based on the attribute (key=value) string
*
* @param userMapping
* @return URI of the tenant
*/
public URI lookupTenant(final UserMapping userMapping) {
if (userMapping == null) {
_log.warn("user mapping is empty");
return null;
}
try {
final List<URI> tenantIds = new ArrayList<URI>();
QueryResultList<URI> results = new QueryResultList<URI>() {
@Override
public URI createQueryHit(URI uri) {
// none
return uri;
}
@Override
public URI createQueryHit(URI uri, String queryUserMapping, UUID timestamp) {
if (userMapping.isMatch(UserMapping.fromString(queryUserMapping))) {
tenantIds.add(uri);
}
return uri;
}
@Override
public URI createQueryHit(URI uri, Object entry) {
if (entry instanceof String) {
return createQueryHit(uri, (String) entry, null);
} else {
return createQueryHit(uri);
}
}
};
_dbClient.queryByConstraint(ContainmentPermissionsConstraint.Factory.getUserMappingsWithDomain(userMapping.getDomain()),
results);
for (Iterator<URI> iterator = results.iterator(); iterator.hasNext(); iterator.next()) {
;
}
if (tenantIds.isEmpty()) {
_log.warn("Tenant lookup returned empty for mapping: {}", userMapping.toString());
return null;
} else if (tenantIds.size() > 1) {
_log.warn("Tenant lookup returned {} tenants for mapping: {}", userMapping.toString());
return null;
} else {
return tenantIds.get(0);
}
} catch (DatabaseException ex) {
_log.error("tenant user mapping query failed", ex);
}
return null;
}
/**
* Returns root TenantOrg
*
* @return
*/
public TenantOrg getRootTenant() {
if (_usingCache && QueriedObjectCache.getRootTenantOrgObject() != null) {
return QueriedObjectCache.getRootTenantOrgObject();
}
URIQueryResultList tenants = new URIQueryResultList();
try {
_dbClient.queryByConstraint(
ContainmentConstraint.Factory.getTenantOrgSubTenantConstraint(URI.create(TenantOrg.NO_PARENT)),
tenants);
if (tenants.iterator().hasNext()) {
URI root = tenants.iterator().next();
TenantOrg rootTenant = _dbClient.queryObject(TenantOrg.class, root);
QueriedObjectCache.setRootTenantObject(rootTenant);
// safety check to prevent further operations when root tenant is messed up
// It is possible have multiple index entries for the same root tenant at a certain period (CQ610571)
while (tenants.iterator().hasNext()) {
URI mulRoot = tenants.iterator().next();
if (!mulRoot.equals(root)) {
_log.error("multiple entries found for root tenant. Stop.");
throw SecurityException.fatals.rootTenantQueryReturnedDuplicates();
}
}
return rootTenant;
} else {
_log.error("root tenant query returned no results");
}
} catch (DatabaseException ex) {
throw SecurityException.fatals.tenantQueryFailed(TenantOrg.NO_PARENT, ex);
}
throw SecurityException.fatals.tenantQueryFailed(TenantOrg.NO_PARENT);
}
/**
* Get object from id
*
* @param id
* @return
*/
public <T extends DataObject> T getObjectById(URI id, Class<T> clazz) {
return getObjectById(id, clazz, false);
}
public <T extends DataObject> T getObjectById(URI id, Class<T> clazz,
boolean bypassCache) {
T ret = null;
boolean usingCache = _usingCache && !bypassCache;
if (usingCache) {
ret = QueriedObjectCache.getObject(id, clazz);
}
if (ret == null) {
ret = _dbClient.queryObject(clazz, id);
if (ret != null && usingCache) {
QueriedObjectCache.setObject(ret);
}
}
return ret;
}
/**
* Same as queryObjectById(URI, Class). Takes NamedURI instead.
*/
public <T extends DataObject> T getObjectById(NamedURI id, Class<T> clazz) {
return getObjectById(id.getURI(), clazz, false);
}
/**
* Get parent of of the object. Now Vplex volume is the only supported case, return null for other types of object
*
* @param obj
* @return
*/
public Volume getParentObject(DataObject obj) {
final List<Volume> vplexVolumes = CustomQueryUtility.queryActiveResourcesByConstraint(
_dbClient, Volume.class,
AlternateIdConstraint.Factory.getVolumesByAssociatedId(obj.getId().toString()));
if (vplexVolumes == null || vplexVolumes.isEmpty()) {
return null;
}
return vplexVolumes.get(0); // Assuming there is only parent
}
/**
* adds user's roles on root tenant to user object
*
* @param user
*/
public void populateZoneRoles(StorageOSUser user, VirtualDataCenter vdc) {
if (_disabler != null) {
return;
}
// from upn
Set<String> userRoles = vdc.getRoleSet(
new PermissionsKey(PermissionsKey.Type.SID, user.getName()).toString());
// in case db migration haven't finished yet, read vdc roles from root tenant.
TenantOrg root = getRootTenant();
if (CollectionUtils.isEmpty(userRoles)) {
userRoles = root.getRoleSet(
new PermissionsKey(PermissionsKey.Type.SID, user.getName()).toString());
}
if (userRoles != null) {
for (String role : userRoles) {
if (isRoleZoneLevel(role)) {
user.addRole(role);
}
}
}
// from groups
Set<String> groups = user.getGroups();
if (!CollectionUtils.isEmpty(groups)) {
for (String group : groups) {
// add if any roles for the groups, from the vdc
Set<String> roleSet = vdc.getRoleSet(
new PermissionsKey(PermissionsKey.Type.GROUP, group).toString());
// in case db migration haven't finished yet, read vdc roles from root tenant.
if (CollectionUtils.isEmpty(roleSet)) {
roleSet = root.getRoleSet(
new PermissionsKey(PermissionsKey.Type.GROUP, group).toString());
}
if (null != roleSet) {
for (String role : roleSet) {
if (isRoleZoneLevel(role)) {
user.addRole(role);
}
}
}
}
}
// Now based on userGroup role assignments.
updateUserVdcRolesBasedOnUserGroup(user, vdc);
}
/**
* Get tenant id from a project id retrieved from uri
*
* @param projectId
* @return
*/
public URI getTenantIdFromProjectId(String projectId, boolean idEmbeddedInURL) {
if (projectId == null) {
return null;
}
try {
URI id = URI.create(projectId);
Project ret = getObjectById(id, Project.class);
if (ret == null) {
if (idEmbeddedInURL) {
throw APIException.notFound.unableToFindEntityInURL(id);
} else {
throw APIException.badRequests.unableToFindEntity(id);
}
}
return ret.getTenantOrg().getURI();
} catch (DatabaseException ex) {
throw SecurityException.fatals.failedGettingTenant(ex);
}
}
/**
* Get tenant id from a project id retrieved from uri
*
* @param childId
* @return
*/
public URI getTenantResourceTenantId(String childId) {
if (childId == null) {
return null;
}
try {
URI id = URI.create(childId);
TenantResource ret = null;
if (URIUtil.isType(id, Host.class)) {
ret = getObjectById(id, Host.class);
} else if (URIUtil.isType(id, VcenterDataCenter.class)) {
ret = getObjectById(id, VcenterDataCenter.class);
} else if (URIUtil.isType(id, Cluster.class)) {
ret = getObjectById(id, Cluster.class);
} else if (URIUtil.isType(id, Initiator.class)) {
Initiator ini = getObjectById(id, Initiator.class);
if (ini.getHost() != null) {
ret = getObjectById(ini.getHost(), Host.class);
}
} else if (URIUtil.isType(id, IpInterface.class)) {
IpInterface hostIf = getObjectById(id, IpInterface.class);
if (hostIf.getHost() != null) {
ret = getObjectById(hostIf.getHost(), Host.class);
}
} else {
throw APIException.badRequests.theURIIsNotOfType(id,
TenantResource.class.getName());
}
if (ret == null) {
throw FatalDatabaseException.fatals.unableToFindEntity(id);
}
return ret.getTenant();
} catch (DatabaseException ex) {
throw SecurityException.fatals.failedGettingTenant(ex);
}
}
/**
* get the set of tenant roles assigned to a user
*
* @param user StorageOSUser representing the logged in user
* @param tenantId URI of the tenant, if null, user's tenant is used if one exists
* @return unmodifiable instance of Set<StorageOSUser.TenantRole>
*/
public Set<String> getTenantRolesForUser(StorageOSUser user, URI tenantId,
boolean idEmbeddedInURL) {
if (tenantId == null) {
tenantId = URI.create(user.getTenantId());
}
if (tenantId == null) {
return Collections.emptySet();
}
Set<String> tenantRoles = new HashSet<String>();
TenantOrg tenant = getObjectById(tenantId, TenantOrg.class);
if (tenant == null) {
if (idEmbeddedInURL) {
throw APIException.notFound.unableToFindEntityInURL(tenantId);
} else {
throw APIException.badRequests.unableToFindTenant(tenantId);
}
}
// The three scenarios that allow us to look up roles in this tenant:
// 1 user tenant is the same tenant as the one we're after for role lookups,
// 2 or user tenant is root tenant (parent of all)
// 3 or user tenant is parent of the tenant we are after (technically same as 2 today since
// there is only one level of subtenancy but in the future this may change)
// If all are false, return no role.
URI userTenantId = URI.create(user.getTenantId());
TenantOrg userTenant = getObjectById(userTenantId, TenantOrg.class);
if (!tenantId.equals(userTenantId) &&
!TenantOrg.isRootTenant(userTenant) &&
!tenant.getParentTenant().getURI().equals(userTenantId)) {
return Collections.emptySet();
}
// for upn
Set<String> userRoles = tenant.getRoleSet(
new PermissionsKey(PermissionsKey.Type.SID, user.getName()).toString());
if (userRoles != null) {
for (String role : userRoles) {
if (isRoleTenantLevel(role)) {
tenantRoles.add(role);
}
}
}
// from groups
Set<String> groups = user.getGroups();
if (!CollectionUtils.isEmpty(groups)) {
for (String group : groups) {
// add if any roles for the groups, from root tenant/zone roles
Set<String> roleSet = tenant.getRoleSet(
new PermissionsKey(PermissionsKey.Type.GROUP, group).toString());
if (null != roleSet) {
for (String role : roleSet) {
if (isRoleTenantLevel(role)) {
tenantRoles.add(role);
}
}
}
}
}
// Now based on userGroup role assignments.
updateUserTenantRolesBasedOnUserGroup(user, tenant, tenantRoles);
return Collections.unmodifiableSet(tenantRoles);
}
/**
* get the set of project ACLs assigned to a user
*
* @param user StorageOSUser representing the logged in user
* @param projectId URI of the project
* @return unmodifiable instance of Set<String>
*/
public Set<String> getProjectACLsForUser(StorageOSUser user, URI projectId,
boolean idEmbeddedInURL) {
if (projectId == null) {
return Collections.emptySet();
}
Set<String> projectACLs = new HashSet<String>();
Project project = getObjectById(projectId, Project.class);
if (project == null) {
if (idEmbeddedInURL) {
throw APIException.notFound.unableToFindEntityInURL(projectId);
} else {
throw APIException.badRequests.unableToFindEntity(projectId);
}
}
// for upn
Set<String> acls = project.getAclSet(
new PermissionsKey(PermissionsKey.Type.SID, user.getName(),
user.getTenantId()).toString());
if (acls != null) {
for (String acl : acls) {
if (isProjectACL(acl)) {
projectACLs.add(acl);
}
}
}
// from groups
Set<String> groups = user.getGroups();
if (!CollectionUtils.isEmpty(groups)) {
for (String group : groups) {
// add if any roles for the groups, from root tenant/zone roles
acls = project.getAclSet(
new PermissionsKey(PermissionsKey.Type.GROUP, group,
user.getTenantId()).toString());
if (null != acls) {
for (String acl : acls) {
if (isProjectACL(acl)) {
projectACLs.add(acl);
}
}
}
}
}
// Now based on userGroup acl assignments.
updateUserProjectAclBasedOnUserGroup(user, project, projectACLs);
return Collections.unmodifiableSet(projectACLs);
}
/**
* Returns true if the user has any role from the given list, false otherwise
*
* @param user
* @param tenantId tenant id
* @param roles
* @return
*/
public boolean userHasGivenRole(StorageOSUser user, URI tenantId, Role... roles) {
if (_disabler != null) {
return true;
}
Set<String> tenantRoles = null;
for (Role role : roles) {
if (user.getRoles().contains(role.toString())) {
return true;
} else if (isRoleTenantLevel(role.toString())) {
if (tenantRoles == null) {
tenantRoles = getTenantRolesForUser(user, tenantId, false);
}
if (tenantRoles.contains(role.toString())) {
return true;
}
}
}
return false;
}
/**
* Returns true if the user has any role from the given list in their home tenant or any subtenant. false otherwise.
*
* @param user StorageOSUser representing the logged in user
* @param roles Roles to test against
* @return whether or not the user has any of the given roles
*/
public boolean userHasGivenRoleInAnyTenant(StorageOSUser user, Role... roles) {
if (userHasGivenRole(user, URI.create(user.getTenantId()), roles)) {
return true;
}
Map<String, Collection<String>> allSubtenantRoles = null;
for (Role role : roles) {
if (isRoleTenantLevel(role.toString())) {
if (allSubtenantRoles == null) {
// don't initialize allSubtenantRoles unless we need to.
// API can't return null, so this will only run once.
allSubtenantRoles = getSubtenantRolesForUser(user);
}
for (Collection<String> subtenantRoles : allSubtenantRoles.values()) {
if (subtenantRoles.contains(role.toString())) {
return true;
}
}
}
}
return false;
}
/**
* Returns true if the user has any acl from the given list, false otherwise
*
* @param user
* @param projectId Project uri to check acls on
* @param acls
* @return
*/
public boolean userHasGivenACL(StorageOSUser user, URI projectId, ACL... acls) {
if (_disabler != null) {
return true;
}
Set<String> projectAcls = getProjectACLsForUser(user, projectId, false);
for (ACL acl : acls) {
if (acl.equals(ACL.ANY) && !projectAcls.isEmpty()) {
return true;
}
if (projectAcls.contains(acl.toString())) {
return true;
}
}
return false;
}
/**
* Returns true if the user's tenant has a usage acl on the VirtualPool
*
* @param tenantUri
* @param virtualPool
* @return
*/
public boolean tenantHasUsageACL(URI tenantUri, VirtualPool virtualPool) {
if (_disabler != null) {
return true;
}
// Make CoS open to all by default, restriction kicks in once a acl assignment is done
if (CollectionUtils.isEmpty(virtualPool.getAcls())) {
return true;
}
Set<String> acls = virtualPool.getAclSet(new PermissionsKey(PermissionsKey.Type.TENANT,
tenantUri.toString(), virtualPool.getType()).toString());
if (acls != null && acls.contains(ACL.USE.toString())) {
return true;
}
return false;
}
/**
* Returns true if the user's tenant has a usage acl on the FilePolicy
*
* @param tenantUri
* @param filePolicy
* @return
*/
public boolean tenantHasUsageACL(URI tenantUri, FilePolicy filePolicy) {
if (_disabler != null) {
return true;
}
// Make CoS open to all by default, restriction kicks in once a acl assignment is done
if (CollectionUtils.isEmpty(filePolicy.getAcls())) {
return true;
}
Set<String> acls = filePolicy.getAclSet(new PermissionsKey(PermissionsKey.Type.TENANT,
tenantUri.toString()).toString());
if (acls != null && acls.contains(ACL.USE.toString())) {
return true;
}
return false;
}
/**
* Returns true if any tenant in the list has a usage acl on the FilePolicy
*
* @param tenantUris
* @param filePolicy
* @return
*/
public boolean tenantHasUsageACL(List<URI> tenantUris, FilePolicy filePolicy) {
for (URI tenantUri : tenantUris) {
if (tenantHasUsageACL(tenantUri, filePolicy)) {
return true;
}
}
return false;
}
/**
* Returns true if any tenant in the list has a usage acl on the VirtualPool
*
* @param tenantUris
* @param virtualPool
* @return
*/
public boolean tenantHasUsageACL(List<URI> tenantUris, VirtualPool virtualPool) {
for (URI tenantUri : tenantUris) {
if (tenantHasUsageACL(tenantUri, virtualPool)) {
return true;
}
}
return false;
}
/**
* Returns true if the user's tenant has a usage acl on the ComputeVirtualPool
*
* @param tenantUri
* @param computeVirtualPool
* @return
*/
public boolean tenantHasUsageACL(URI tenantUri, ComputeVirtualPool computeVirtualPool) {
if (_disabler != null) {
return true;
}
// Make CoS open to all by default, restriction kicks in once a acl assignment is done
if (CollectionUtils.isEmpty(computeVirtualPool.getAcls())) {
return true;
}
Set<String> acls = computeVirtualPool.getAclSet(new PermissionsKey(PermissionsKey.Type.TENANT,
tenantUri.toString(), computeVirtualPool.getSystemType()).toString());
if (acls != null && acls.contains(ACL.USE.toString())) {
return true;
}
return false;
}
public boolean tenantHasUsageACL(List<URI> tenantUris, ComputeVirtualPool computeVirtualPool) {
for (URI tenantUri : tenantUris) {
if (tenantHasUsageACL(tenantUri, computeVirtualPool)) {
return true;
}
}
return false;
}
/**
* Returns true if the user's tenant has a usage acl on the VirtualArray
*
* @param tenantUri
* @param virtualArray
* @return
*/
public boolean tenantHasUsageACL(URI tenantUri, VirtualArray virtualArray) {
if (_disabler != null) {
return true;
}
// Make Neighborhood open to all by default, restriction kicks in once a acl assignment is done
if (CollectionUtils.isEmpty(virtualArray.getAcls())) {
return true;
}
Set<String> acls = virtualArray.getAclSet(new PermissionsKey(PermissionsKey.Type.TENANT,
tenantUri.toString()).toString());
if (acls != null && acls.contains(ACL.USE.toString())) {
return true;
}
return false;
}
/**
* Returns true if any tenant in the list has a usage acl on the VirtualArray
*
* @param tenantUris
* @param virtualArray
* @return
*/
public boolean tenantHasUsageACL(List<URI> tenantUris, VirtualArray virtualArray) {
for (URI tenantUri : tenantUris) {
if (tenantHasUsageACL(tenantUri, virtualArray)) {
return true;
}
}
return false;
}
/**
* return a list of tenant URI the specified user has tenant role over it.
*
* @param user
* @return
*/
public List<URI> getSubtenantsWithRoles(StorageOSUser user) {
Map<String, Collection<String>> subTenantRoles = getSubtenantRolesForUser(user);
List<URI> subtenants = new ArrayList<URI>();
for (String subtenant : subTenantRoles.keySet()) {
subtenants.add(URI.create(subtenant));
}
return subtenants;
}
/**
* Check if the string is zone level role
*
* @param role
* @return true if the string is zone level role, false otherwise
*/
public boolean isRoleZoneLevel(String role) {
return (role.equalsIgnoreCase(Role.SYSTEM_ADMIN.toString()) ||
role.equalsIgnoreCase(Role.SECURITY_ADMIN.toString()) ||
role.equalsIgnoreCase(Role.SYSTEM_MONITOR.toString()) ||
role.equalsIgnoreCase(Role.SYSTEM_AUDITOR.toString()) ||
role.equalsIgnoreCase(Role.RESTRICTED_SECURITY_ADMIN.toString()) || role.equalsIgnoreCase(Role.RESTRICTED_SYSTEM_ADMIN
.toString()));
}
/**
* Check if the string is external zone level role
*
* @param role
* @return true if the string is zone level role, false otherwise
*/
public boolean isExternalRoleZoneLevel(String role) {
return (role.equalsIgnoreCase(Role.SYSTEM_ADMIN.toString()) ||
role.equalsIgnoreCase(Role.SECURITY_ADMIN.toString()) ||
role.equalsIgnoreCase(Role.SYSTEM_MONITOR.toString()) || role.equalsIgnoreCase(Role.SYSTEM_AUDITOR.toString()));
}
/**
* Check if the string is a tenant level role
*
* @param role
* @return true if string is tenant level role, false otherwise
*/
public boolean isRoleTenantLevel(String role) {
return (role.equalsIgnoreCase(Role.TENANT_ADMIN.toString()) ||
role.equalsIgnoreCase(Role.PROJECT_ADMIN.toString()) || role.equalsIgnoreCase(Role.TENANT_APPROVER.toString()));
}
/**
* Check if the string is a valid project acl string
*
* @param acl
* @return true if a valid project acl, false otherwise
*/
public boolean isProjectACL(String acl) {
return (acl.equalsIgnoreCase(ACL.OWN.toString()) ||
acl.equalsIgnoreCase(ACL.ALL.toString()) || acl.equalsIgnoreCase(ACL.BACKUP.toString()));
}
/**
* Check if the string is a usage acl string
*
* @param acl
* @return true if a its usage acl, false otherwise
*/
public static boolean isUsageACL(String acl) {
return (acl.equalsIgnoreCase(ACL.USE.toString()));
}
/**
* Get all tenants with roles for the given user
*
* @param user
* @param filterBy if not null, set of roles that the resulting columns will be filtered by
* @param onTenant if true, queries for tenant columns, otherwise, project columns
* @return
*/
public Map<URI, Set<String>> getAllPermissionsForUser(StorageOSUser user,
URI tenantId, final Set<String> filterBy, boolean onTenant) {
try {
final Map<URI, Set<String>> permissionsMap = new HashMap<URI, Set<String>>();
QueryResultList<URI> results = new QueryResultList<URI>() {
@Override
public URI createQueryHit(URI uri) {
// none
return uri;
}
@Override
public URI createQueryHit(URI uri, String permission, UUID timestamp) {
if (filterBy == null ||
filterBy.contains(permission)) {
if (!permissionsMap.containsKey(uri)) {
permissionsMap.put(uri, new HashSet<String>());
}
permissionsMap.get(uri).add(permission);
}
return uri;
}
@Override
public URI createQueryHit(URI uri, Object entry) {
return createQueryHit(uri);
}
};
// To do - fix up ContainmentPermissionsConstraint to query multiple row keys at a time.
if (onTenant) {
_dbClient.queryByConstraint(
ContainmentPermissionsConstraint.Factory.getTenantsWithPermissionsConstraint(
new PermissionsKey(PermissionsKey.Type.SID, user.getName()).toString()),
results);
for (Iterator<URI> iterator = results.iterator(); iterator.hasNext(); iterator.next()) {
;
}
if (user.getGroups() != null) {
for (String group : user.getGroups()) {
_dbClient.queryByConstraint(
ContainmentPermissionsConstraint.Factory.getTenantsWithPermissionsConstraint(
new PermissionsKey(PermissionsKey.Type.GROUP, group).toString()),
results);
for (Iterator<URI> iterator = results.iterator(); iterator.hasNext(); iterator.next()) {
;
}
}
}
// Now get the user's permissions based on the userGroup
getUserPermissionsForTenantBasedOnUserGroup(user, filterBy, permissionsMap);
} else {/* project */
_dbClient.queryByConstraint(
ContainmentPermissionsConstraint.Factory.getObjsWithPermissionsConstraint(
new PermissionsKey(PermissionsKey.Type.SID, user.getName(), tenantId).toString(),
Project.class),
results);
for (Iterator<URI> iterator = results.iterator(); iterator.hasNext(); iterator.next()) {
;
}
if (user.getGroups() != null) {
for (String group : user.getGroups()) {
_dbClient.queryByConstraint(
ContainmentPermissionsConstraint.Factory.getObjsWithPermissionsConstraint(
new PermissionsKey(PermissionsKey.Type.GROUP, group, tenantId).toString(),
Project.class),
results);
for (Iterator<URI> iterator = results.iterator(); iterator.hasNext(); iterator.next()) {
;
}
}
}
// Now get the user's permissions based on the userGroup
getUserPermissionsForProjectBasedOnUserGroup(user, filterBy, permissionsMap);
}
return permissionsMap;
} catch (DatabaseException ex) {
_log.error("permissions index query failed", ex);
}
throw SecurityException.fatals.permissionsIndexQueryFailed();
}
/**
* Given a domain get a map of tenant IDs to a list of user mappings with the domain
*
* @param domain domain to search for
* @return a map of tenant ID to mappings
*/
public Map<URI, List<UserMapping>> getAllUserMappingsForDomain(String domain) {
try {
final Map<URI, List<UserMapping>> tenantUserMappingMap = new HashMap<URI, List<UserMapping>>();
QueryResultList<URI> results = new QueryResultList<URI>() {
@Override
public URI createQueryHit(URI uri) {
// none
return uri;
}
@Override
public URI createQueryHit(URI uri, String userMapping, UUID timestamp) {
if (!tenantUserMappingMap.containsKey(uri)) {
tenantUserMappingMap.put(uri, new ArrayList<UserMapping>());
}
tenantUserMappingMap.get(uri).add(UserMapping.fromString(userMapping));
return uri;
}
@Override
public URI createQueryHit(URI uri, Object entry) {
return createQueryHit(uri);
}
};
_dbClient.queryByConstraint(ContainmentPermissionsConstraint.Factory.getUserMappingsWithDomain(domain), results);
for (Iterator<URI> iterator = results.iterator(); iterator.hasNext(); iterator.next()) {
;
}
return tenantUserMappingMap;
} catch (DatabaseException ex) {
_log.error("tenant user mapping query failed", ex);
}
throw SecurityException.fatals.tenantUserMappingQueryFailed();
}
public Map<String, Collection<String>> getSubtenantRolesForUser(StorageOSUser user) {
Map<String, Collection<String>> subTenantRoles = new HashMap<String, Collection<String>>();
URI userHomeTenant = URI.create(user.getTenantId());
NamedElementQueryResultList subtenants = new NamedElementQueryResultList();
_dbClient.queryByConstraint(ContainmentConstraint.Factory
.getTenantOrgSubTenantConstraint(userHomeTenant), subtenants);
for (NamedElement sub : subtenants) {
Collection<String> roles = getTenantRolesForUser(user, sub.getId(), false);
if (!CollectionUtils.isEmpty(roles)) {
subTenantRoles.put(sub.getId().toString(), roles);
}
}
return subTenantRoles;
}
/**
* return all subtenants the user has any tenant role over them.
*
* @param user
* @return
*/
public Set<String> getSubtenantsForUser(StorageOSUser user) {
return getSubtenantRolesForUser(user).keySet();
}
public void removeRootRoleAssignmentOnTenantAndProject() throws DatabaseException {
String keyForRoot = new PermissionsKey(PermissionsKey.Type.SID, ROOT).toString();
StringBuffer tenantRolesRemoved = new StringBuffer("Tenant roles removed: ");
StringBuffer projectOwnerRemoved = new StringBuffer("Project owner removed: ");
List<URI> uriQueryResultList = _dbClient.queryByType(TenantOrg.class, true);
Iterator<TenantOrg> tenantOrgIterator = _dbClient.queryIterativeObjects(
TenantOrg.class, uriQueryResultList);
while (tenantOrgIterator.hasNext()) {
boolean bNeedPersistent = false;
TenantOrg tenantOrg = tenantOrgIterator.next();
Set<String> rootRoles = tenantOrg.getRoleSet(keyForRoot);
if (!CollectionUtils.isEmpty(rootRoles)) {
for (String role : rootRoles) {
_log.info("removing root's " + role + " from Tenant: " + tenantOrg.getLabel());
tenantOrg.removeRole(keyForRoot, role);
bNeedPersistent = true;
}
}
if (bNeedPersistent) {
_dbClient.updateAndReindexObject(tenantOrg);
tenantRolesRemoved.append(tenantOrg.getLabel()).append(" ");
}
}
uriQueryResultList = _dbClient.queryByType(Project.class, true);
Iterator<Project> projectIterator = _dbClient.queryIterativeObjects(
Project.class, uriQueryResultList);
while (projectIterator.hasNext()) {
Project project = projectIterator.next();
if (project.getOwner().equalsIgnoreCase(ROOT)) {
_log.info("removing root's ownership from project: " + project.getLabel());
project.setOwner("");
_dbClient.updateAndReindexObject(project);
projectOwnerRemoved.append(project.getLabel()).append(" ");
}
}
_log.info(tenantRolesRemoved.toString());
_log.info(projectOwnerRemoved.toString());
}
/***
* Gets all the user group that has the domain matching with
* the param domain.
*
* @param domain to be matched.
* @return list of active UserGroup.
*/
public List<UserGroup> getAllUserGroupForDomain(String domain) {
List<UserGroup> userGroupList = null;
try {
userGroupList = CustomQueryUtility.queryActiveResourcesByConstraint(_dbClient, UserGroup.class,
PrefixConstraint.Factory.getFullMatchConstraint(UserGroup.class, "domain", domain));
} catch (DatabaseException ex) {
_log.error("User group query failed", ex);
}
return userGroupList;
}
/***
* Gets all the user group that has the label matching with
* the param label.
*
* @param label to be matched.
* @return list of active UserGroup.
*/
public List<UserGroup> getAllUserGroupByLabel(String label) {
List<UserGroup> userGroupList = null;
try {
userGroupList = CustomQueryUtility.queryActiveResourcesByConstraint(_dbClient, UserGroup.class,
PrefixConstraint.Factory.getFullMatchConstraint(UserGroup.class, "label", label));
} catch (DatabaseException ex) {
_log.error("User group query failed", ex);
}
return userGroupList;
}
/***
* Get all the configured user group from the given
* role assignments or acls.
*
* @param roleAssignments to used to find the user group based in its keyset.
* @return a map of user group and its corresponding roles.
*/
public Map<UserGroup, StringSet> getUserGroupsFromRoleAssignments(StringSetMap roleAssignments) {
Map<UserGroup, StringSet> userGroupsWithRoles = null;
if (CollectionUtils.isEmpty(roleAssignments)) {
_log.warn("Invalid or Empty role-assignments");
return userGroupsWithRoles;
}
userGroupsWithRoles = new HashMap<UserGroup, StringSet>();
Set<String> keys = roleAssignments.keySet();
for (String key : keys) {
if (StringUtils.isBlank(key)) {
_log.debug("Invalid entry in the role-assignments");
continue;
}
PermissionsKey permissionsKey = new PermissionsKey();
permissionsKey.parseFromString(key);
List<UserGroup> userGroupListList = getAllUserGroupByLabel(permissionsKey.getValue());
if (CollectionUtils.isEmpty(userGroupListList)) {
_log.debug("Could not find any user group with label {}", permissionsKey.getValue());
continue;
}
if (userGroupListList.size() > 1) {
_log.warn("Found more than one user group with label {} in DB. " +
"Using the first object in the returned list", permissionsKey.getValue());
}
StringSet roleSet = roleAssignments.get(key);
_log.debug("Adding user group {} with roles", userGroupListList.get(0).getLabel(), roleSet.toString());
userGroupsWithRoles.put(userGroupListList.get(0), roleSet);
}
return userGroupsWithRoles;
}
/***
* Compare the user group with the list of user's attributes.
*
* @param user who's attributes list to be compared with user group.
* @param roleAssignmentUserGroup to be compared with the user's attributes list.
* @return true if user's attributes contains all the all attributes and its values of
* user group otherwise false.
*/
public boolean matchUserAttributesToUserGroup(StorageOSUserDAO user,
UserGroup roleAssignmentUserGroup) {
boolean isUserGroupMatchesUserAttributes = false;
if (roleAssignmentUserGroup == null ||
user == null) {
_log.error("Invalid user {} or user group {}", user, roleAssignmentUserGroup);
return isUserGroupMatchesUserAttributes;
}
Set<String> userGroupDoNotMatch = new HashSet<String>();
for (String roleAssignmentUserAttributeString : roleAssignmentUserGroup.getAttributes()) {
if (StringUtils.isBlank(roleAssignmentUserAttributeString)) {
_log.debug("Invalid user attributes param string");
continue;
}
boolean isUserGroupMatchesUserAttribute = false;
UserAttributeParam roleAssignmentUserAttribute = UserAttributeParam.fromString(roleAssignmentUserAttributeString);
if (roleAssignmentUserAttribute == null) {
_log.warn("Failed to convert user attributes param string {} to object.", roleAssignmentUserAttributeString);
continue;
}
for (String userAttributeString : user.getAttributes()) {
UserAttributeParam userAttribute = UserAttributeParam.fromString(userAttributeString);
if (userAttribute == null) {
_log.info("Failed to convert user attributes param string {} to object.", userAttributeString);
continue;
}
_log.debug("Comparing user attributes {} with user group attribute {}",
userAttributeString, roleAssignmentUserAttributeString);
if (userAttribute.containsAllAttributeValues(roleAssignmentUserAttribute)) {
_log.debug("Found user attributes {} matching with user group attributes {}",
userAttributeString, roleAssignmentUserAttributeString);
isUserGroupMatchesUserAttribute = true;
break;
}
}
if (isUserGroupMatchesUserAttribute == false) {
_log.debug("Adding user group {} to the do not match list", roleAssignmentUserAttributeString);
userGroupDoNotMatch.add(roleAssignmentUserAttributeString);
}
}
if (CollectionUtils.isEmpty(userGroupDoNotMatch)) {
isUserGroupMatchesUserAttributes = true;
}
return isUserGroupMatchesUserAttributes;
}
/***
* Compares all the AD/LDAP attributes of user with configured user group
* to find if the user's attaches matches with any of the user attributes and
* get the role associated with that user group to add the user or
* tenant.
*
* @param user attributes of the user to be compared with the user group.
* @param userGroupsWithRoles a map contains all the user group
* and the all the roles associated with that groups.
* @return returns all the roles of the user group that matches with the
* user's attributes.
*/
private StringSet findAllRolesToAdd(StorageOSUser user, Map<UserGroup, StringSet> userGroupsWithRoles) {
StringSet rolesToAdd = null;
if (CollectionUtils.isEmpty(userGroupsWithRoles)) {
_log.error("Invalid user group and roles.");
return rolesToAdd;
}
rolesToAdd = new StringSet();
for (Map.Entry<UserGroup, StringSet> userGroupEntry : userGroupsWithRoles.entrySet()) {
if (CollectionUtils.isEmpty(userGroupEntry.getValue())) {
continue;
}
if (matchUserAttributesToUserGroup(user, userGroupEntry.getKey())) {
rolesToAdd.addAll(userGroupEntry.getValue());
;
}
}
return rolesToAdd;
}
/***
* Add the vdc roles to the user based on the user group in the
* vdc role-assignments.
*
* @param user who's roles to be updated based on the user group in the
* vdc role-assignments.
* @param vdc to get its role-assignments.
*/
private void updateUserVdcRolesBasedOnUserGroup(StorageOSUser user, VirtualDataCenter vdc) {
if (user == null || vdc == null) {
_log.error("Invalid user {} or vdc {}", user, vdc);
return;
}
StringSetMap roleAssignments = vdc.getRoleAssignments();
Map<UserGroup, StringSet> userGroupsWithRoles = getUserGroupsFromRoleAssignments(roleAssignments);
if (CollectionUtils.isEmpty(userGroupsWithRoles)) {
_log.info("There are no role assignments for VDC {} with user group", vdc.getLabel());
return;
}
StringSet roleSet = findAllRolesToAdd(user, userGroupsWithRoles);
if (CollectionUtils.isEmpty(roleSet)) {
_log.debug("There are no roles found for user group in the vdc {}", vdc.getLabel());
return;
}
for (String role : roleSet) {
if (isRoleZoneLevel(role)) {
_log.debug("Adding the vdc role {} to the user {}", role, user.getDistinguishedName());
user.addRole(role);
}
}
}
/***
* Update the user's tenants roles based on the tenant's role-assignments.
*
* @param user who's role to be found based the attributes and tenant's role-assignments.
* @param tenant to get its role-assignments.
* @param tenantRoles out param, to be updated all the user's roles for this tenant.
*/
private void updateUserTenantRolesBasedOnUserGroup(StorageOSUser user, TenantOrg tenant, Set<String> tenantRoles) {
if (user == null || tenant == null) {
_log.error("Invalid user {} or tenant {}", user, tenant);
return;
}
StringSetMap roleAssignments = tenant.getRoleAssignments();
Map<UserGroup, StringSet> userGroupsWithRoles = getUserGroupsFromRoleAssignments(roleAssignments);
if (CollectionUtils.isEmpty(userGroupsWithRoles)) {
_log.debug("There are no role assignments for tenant {} with user group", tenant.getLabel());
return;
}
StringSet roleSet = findAllRolesToAdd(user, userGroupsWithRoles);
if (CollectionUtils.isEmpty(roleSet)) {
_log.debug("There are no roles found for user group in the tenant {}", tenant.getLabel());
return;
}
for (String role : roleSet) {
if (isRoleTenantLevel(role)) {
_log.debug("Adding the tenant role {} to the user {}", role, user.getDistinguishedName());
tenantRoles.add(role);
}
}
}
/***
* Update the user's project roles based on the project's acls.
*
* @param user who's roles to be found based the attributes and project's acls.
* @param project to get its acls.
* @param projectAcls out param, to be updated all the user's roles for this project.
*/
private void updateUserProjectAclBasedOnUserGroup(StorageOSUser user, Project project, Set<String> projectAcls) {
if (user == null || project == null) {
_log.error("Invalid user or project", user, project);
return;
}
StringSetMap roleAssignments = project.getAcls();
Map<UserGroup, StringSet> userGroupsWithRoles = getUserGroupsFromRoleAssignments(roleAssignments);
if (CollectionUtils.isEmpty(userGroupsWithRoles)) {
_log.debug("There are no role assignments for project {} with user group", project.getLabel());
return;
}
StringSet roleSet = findAllRolesToAdd(user, userGroupsWithRoles);
if (CollectionUtils.isEmpty(roleSet)) {
_log.debug("There are no roles found for user group in the project {}", project.getLabel());
return;
}
for (String role : roleSet) {
if (isProjectACL(role)) {
_log.debug("Adding the project acl {} to the user {}", role, user.getDistinguishedName());
projectAcls.add(role);
}
}
}
/***
* Add all the allowed permissions to the user.
*
* @param filterBy if not null, set of roles that the resulting columns will be filtered by
* @param id tenant's id
* @param roles roles to be checked.
* @param permissionsMap out param, to updated with list of permissions.
*/
private void addUserPermissions(Set<String> filterBy, URI id, Set<String> roles, Map<URI, Set<String>> permissionsMap) {
if (CollectionUtils.isEmpty(roles)) {
_log.error("Invalid roles set");
return;
}
if (permissionsMap == null) {
permissionsMap = new HashMap<URI, Set<String>>();
}
for (String role : roles) {
if (StringUtils.isBlank(role)) {
continue;
}
if (filterBy == null || filterBy.contains(role)) {
if (!permissionsMap.containsKey(id)) {
permissionsMap.put(id, new HashSet<String>());
}
_log.debug("Adding the role {} to the resource {}", role, id);
permissionsMap.get(id).add(role);
}
}
}
/***
* Update the user's permissions for the tenant based on the user group.
*
* @param user who's permissions to be updated.
* @param filterBy if not null, set of roles that the resulting columns will be filtered by
* @param permissionsMap out param, to be updated with list of permissions.
*/
private void
getUserPermissionsForTenantBasedOnUserGroup(StorageOSUser user, Set<String> filterBy, Map<URI, Set<String>> permissionsMap) {
if (user == null || CollectionUtils.isEmpty(user.getAttributes())) {
_log.error("Invalid user or user attributes");
return;
}
TenantOrg userTenant = (TenantOrg) _dbClient.queryObject(URI.create(user.getTenantId()));
if (userTenant == null) {
_log.error("Could not find user's {} tenant {}", user.getDistinguishedName(), user.getTenantId());
return;
}
Set<String> tenantRoles = new HashSet<String>();
updateUserTenantRolesBasedOnUserGroup(user, userTenant, tenantRoles);
if (!CollectionUtils.isEmpty(tenantRoles)) {
addUserPermissions(filterBy, userTenant.getId(), tenantRoles, permissionsMap);
}
}
/***
* Update the user's permissions for the project based on the user group.
*
* @param user who's permissions to be updated.
* @param filterBy if not null, set of roles that the resulting columns will be filtered by
* @param permissionsMap out param, to be updated with list of permissions.
*/
private void
getUserPermissionsForProjectBasedOnUserGroup(StorageOSUser user, Set<String> filterBy, Map<URI, Set<String>> permissionsMap) {
if (user == null || CollectionUtils.isEmpty(user.getAttributes())) {
_log.error("Invalid user or user attributes");
return;
}
List<URI> projectsURIList = _dbClient.queryByType(Project.class, true);
if (projectsURIList == null || !projectsURIList.iterator().hasNext()) {
_log.warn("There are no projects configured.");
return;
}
List<Project> projects = _dbClient.queryObject(Project.class, projectsURIList);
if (CollectionUtils.isEmpty(projects)) {
_log.error("Could not find the project objects for the Ids {}", projectsURIList.toString());
return;
}
for (Project project : projects) {
if (project == null) {
_log.debug("Invalid project");
continue;
}
Set<String> projectACLs = new HashSet<String>();
updateUserProjectAclBasedOnUserGroup(user, project, projectACLs);
if (!CollectionUtils.isEmpty(projectACLs)) {
addUserPermissions(filterBy, project.getId(), projectACLs, permissionsMap);
}
}
}
/***
* Check if any active user mapping for the domain that uses the user group.
*
* @param domain to find all the active user mappings for the domain.
* @param label to check if the user mapping uses this user group or not.
* @return Set of URI of the tenant that has the user mappings references to the
* user group.
*/
public Set<URI> checkForActiveUserMappingUsingGroup(String domain, String label) {
Set<URI> tenantsUsingUserGroup = null;
Map<URI, List<UserMapping>> mappings = getAllUserMappingsForDomain(domain);
if (CollectionUtils.isEmpty(mappings)) {
_log.debug("Could not find any user mappings from domain {}", domain);
return tenantsUsingUserGroup;
}
tenantsUsingUserGroup = new HashSet<URI>();
for (Map.Entry<URI, List<BasePermissionsHelper.UserMapping>> entry : mappings.entrySet()) {
if (CollectionUtils.isEmpty(entry.getValue())) {
continue;
}
for (UserMapping userMapping : entry.getValue()) {
if (userMapping == null || CollectionUtils.isEmpty(userMapping.getGroups())) {
continue;
}
for (String group : userMapping.getGroups()) {
if (StringUtils.isNotBlank(group) && group.equalsIgnoreCase(label)) {
tenantsUsingUserGroup.add(entry.getKey());
}
}
}
}
return tenantsUsingUserGroup;
}
/***
* Checks whether the given the user group is present in the given
* acls or role-assignment set.
*
* @param label to check if the acls or role-assignments uses user group or not.
* @param acls set or acls or role-assignments to be checked.
* @return true if the acls or role-assignments contains the user group
* otherwise false.
*/
private boolean checkUserGroupWithPermissionKeys(String label, Set<String> acls) {
boolean resourceUsingUserGroup = false;
if (CollectionUtils.isEmpty(acls)) {
_log.warn("Invalid acls");
return resourceUsingUserGroup;
}
for (String acl : acls) {
if (StringUtils.isBlank(acl)) {
_log.debug("Invalid acl entry");
continue;
}
PermissionsKey permissionsKey = new PermissionsKey();
permissionsKey.parseFromString(acl);
if (permissionsKey.getType() == PermissionsKey.Type.GROUP &&
permissionsKey.getValue().equalsIgnoreCase(label)) {
resourceUsingUserGroup = true;
}
}
return resourceUsingUserGroup;
}
/***
* Checks whether the given the user group is present in any of the
* project's acls or not
*
* @param label to check if any project acls uses user group or not.
* @return set of URI's Projects that uses the user group.
*/
public Set<URI> checkForActiveProjectAclsUsingUserGroup(String label) {
Set<URI> projectsUsingUserGroup = null;
// Find all the configured project IDs based on the type.
List<URI> projectURIList = _dbClient.queryByType(Project.class, true);
if (projectURIList == null || !projectURIList.iterator().hasNext()) {
_log.warn("There are no projects configured.");
return projectsUsingUserGroup;
}
// Find all the configured project objects based on the given list of IDs.
List<Project> projects = _dbClient.queryObject(Project.class, projectURIList);
if (CollectionUtils.isEmpty(projects)) {
_log.error("Could not find the project objects for the Ids {}", projectURIList.toString());
return projectsUsingUserGroup;
}
projectsUsingUserGroup = new HashSet<URI>();
for (Project project : projects) {
if (project == null) {
_log.debug("Invalid project");
continue;
}
if (CollectionUtils.isEmpty(project.getAcls())) {
_log.debug("ACLs are not configured for project {}", project.getLabel());
continue;
}
Set<String> aclKeys = project.getAcls().keySet();
if (checkUserGroupWithPermissionKeys(label, aclKeys)) {
projectsUsingUserGroup.add(project.getId());
}
}
return projectsUsingUserGroup;
}
/***
* Checks whether the given the user group is present in the local vdc's
* role-assignment or not
*
* @param label to check if any vdc role-assignments uses user group or not.
* @return set of URI's VDCs that uses the user group.
*/
public Set<URI> checkForActiveVDCRoleAssignmentsUsingUserGroup(String label) {
Set<URI> vdcUsingUserGroup = null;
VirtualDataCenter vdc = VdcUtil.getLocalVdc();
if (vdc == null) {
_log.error("Could not find local VDC");
return vdcUsingUserGroup;
}
if (CollectionUtils.isEmpty(vdc.getRoleAssignments())) {
_log.debug("Role assignments are not configured for vdc {}", vdc.getLabel());
return vdcUsingUserGroup;
}
vdcUsingUserGroup = new HashSet<URI>();
Set<String> roleAssignmentKeys = vdc.getRoleAssignments().keySet();
if (checkUserGroupWithPermissionKeys(label, roleAssignmentKeys)) {
vdcUsingUserGroup.add(vdc.getId());
}
return vdcUsingUserGroup;
}
/***
* Checks whether the given the user group is present the any of the
* tenants role-assignments or not
*
* @param label to check if any tenants role-assignments uses user group or not.
* @return set of URI's tenants that uses the user group.
*/
public Set<URI> checkForActiveTenantRoleAssignmentsUsingUserGroup(String label) {
Set<URI> tenantsUsingUserGroup = null;
// Find all the configured tenant IDs based on the type.
List<URI> tenantURIList = _dbClient.queryByType(TenantOrg.class, true);
if (tenantURIList == null || !tenantURIList.iterator().hasNext()) {
_log.error("There are no tenants configured.");
return tenantsUsingUserGroup;
}
// Find all the configured tenant objects based on the given list of IDs.
List<TenantOrg> tenants = _dbClient.queryObject(TenantOrg.class, tenantURIList);
if (CollectionUtils.isEmpty(tenants)) {
_log.error("Could not find the tenant objects for the Ids {}", tenantURIList.toString());
return tenantsUsingUserGroup;
}
tenantsUsingUserGroup = new HashSet<URI>();
for (TenantOrg tenant : tenants) {
if (tenant == null) {
_log.debug("Invalid tenant");
continue;
}
if (CollectionUtils.isEmpty(tenant.getRoleAssignments())) {
_log.debug("Role assignments are not configured for tenant {}", tenant.getLabel());
continue;
}
Set<String> roleAssignmentKeys = tenant.getRoleAssignments().keySet();
if (checkUserGroupWithPermissionKeys(label, roleAssignmentKeys)) {
tenantsUsingUserGroup.add(tenant.getId());
}
}
return tenantsUsingUserGroup;
}
/***
* Checks whether the given the user group is present the any of the
* catalog category acls or not
*
* @param label to check if any tenants role-assignments uses user group or not.
* @return set of URI's catalog category that uses the user group.
*/
public Set<URI> checkForActiveCatalogCategoryAclsUsingUserGroup(String label) {
Set<URI> catalogCategoryUsingUserGroup = null;
// Find all the configured Catalog category IDs based on the type.
List<URI> catalogCategoryURIList = _dbClient.queryByType(CatalogCategory.class, true);
if (catalogCategoryURIList == null || !catalogCategoryURIList.iterator().hasNext()) {
_log.warn("There are no catalog category configured.");
return catalogCategoryUsingUserGroup;
}
// Find all the configured Catalog category objects based on the given list of IDs.
List<CatalogCategory> catalogCategories = _dbClient.queryObject(CatalogCategory.class, catalogCategoryURIList);
if (CollectionUtils.isEmpty(catalogCategories)) {
_log.error("Could not find the Catalog category objects for the Ids {}", catalogCategoryURIList.toString());
return catalogCategoryUsingUserGroup;
}
catalogCategoryUsingUserGroup = new HashSet<URI>();
for (CatalogCategory catalogCategory : catalogCategories) {
if (catalogCategory == null) {
_log.info("Invalid catalog category");
continue;
}
if (CollectionUtils.isEmpty(catalogCategory.getAcls())) {
_log.debug("ACLs not configured for Catalog category {}", catalogCategory.getLabel());
continue;
}
Set<String> aclKeys = catalogCategory.getAcls().keySet();
if (checkUserGroupWithPermissionKeys(label, aclKeys)) {
catalogCategoryUsingUserGroup.add(catalogCategory.getId());
}
}
return catalogCategoryUsingUserGroup;
}
/***
* Checks whether the given the user group is present the any of the
* catalog service acls or not
*
* @param label to check if any tenants role-assignments uses user group or not.
* @return set of URI's catalog services that uses the user group.
*/
public Set<URI> checkForActiveCatalogServiceAclsUsingUserGroup(String label) {
Set<URI> catalogServiceUsingUserGroup = null;
// Find all the configured Catalog service IDs based on the type.
List<URI> catalogServiceURIList = _dbClient.queryByType(CatalogService.class, true);
if (catalogServiceURIList == null || !catalogServiceURIList.iterator().hasNext()) {
_log.warn("There are no catalog service configured.");
return catalogServiceUsingUserGroup;
}
// Find all the configured Catalog service objects based on the given list of IDs.
List<CatalogService> catalogServices = _dbClient.queryObject(CatalogService.class, catalogServiceURIList);
if (CollectionUtils.isEmpty(catalogServices)) {
_log.error("Could not find the Catalog service objects for the Ids {}", catalogServiceURIList.toString());
return catalogServiceUsingUserGroup;
}
catalogServiceUsingUserGroup = new HashSet<URI>();
for (CatalogService catalogService : catalogServices) {
if (catalogService == null) {
_log.info("Invalid catalog service");
continue;
}
if (CollectionUtils.isEmpty(catalogService.getAcls())) {
_log.debug("ACLs not configured for Catalog service {}", catalogService.getLabel());
continue;
}
Set<String> aclKeys = catalogService.getAcls().keySet();
if (checkUserGroupWithPermissionKeys(label, aclKeys)) {
catalogServiceUsingUserGroup.add(catalogService.getId());
}
}
return catalogServiceUsingUserGroup;
}
/**
* Returns true if the user has any acl from the given list, false otherwise
*
* @param user
* @param acls
* @return
*/
public boolean userHasGivenProjectACL(StorageOSUser user, ACL... acls) {
List<URI> projectIds = _dbClient.queryByType(Project.class, true);
if (projectIds == null || !projectIds.iterator().hasNext()) {
_log.warn("There are no projects configured.");
return false;
}
for (URI projectId : projectIds) {
if (userHasGivenACL(user, projectId, acls)) {
return true;
} else {
continue;
}
}
return false;
}
/**
* given tenant id, find its name
*/
public String getTenantNameByID(String tenantID) {
if (StringUtils.isEmpty(tenantID)) {
return null;
}
TenantOrg tenantOrg = _dbClient.queryObject(TenantOrg.class, URI.create(tenantID));
return tenantOrg != null ? tenantOrg.getLabel() : null;
}
/**
* Converts StringSetMap of acls into a list of ACLEntry as used by the API
*
* @param acls to be converted into the ACLEntry list.
* @return the converted ACLEntry list.
*/
public static List<ACLEntry> convertToACLEntries(StringSetMap acls) {
List<ACLEntry> assignments = new ArrayList<ACLEntry>();
if (CollectionUtils.isEmpty(acls)) {
return assignments;
}
for (Map.Entry<String, AbstractChangeTrackingSet<String>> ace : acls.entrySet()) {
PermissionsKey rowKey = new PermissionsKey();
rowKey.parseFromString(ace.getKey());
ACLEntry entry = new ACLEntry();
if (rowKey.getType().equals(PermissionsKey.Type.GROUP)) {
entry.setGroup(rowKey.getValue());
} else if (rowKey.getType().equals(PermissionsKey.Type.SID)) {
entry.setSubjectId(rowKey.getValue());
} else if (rowKey.getType().equals(PermissionsKey.Type.TENANT)) {
entry.setTenant(rowKey.getValue());
}
for (String priv : ace.getValue()) {
// skip owner
if (priv.equalsIgnoreCase(ACL.OWN.toString())) {
continue;
}
entry.getAces().add(priv);
}
if (!entry.getAces().isEmpty()) {
assignments.add(entry);
}
}
return assignments;
}
/**
* Gets the USE URIs from the acl string set map. It converts
* the acls string set map to the list of ACLEntry and then
* fetches the URI list from the ACLEntry list.
*
* @param acls to be used to fetch the usage URIs.
* @return a set of URIs retrived from the acls.
*/
public static Set<URI> getUsageURIsFromAcls(StringSetMap acls) {
Set<URI> tenantUris = new HashSet<URI>();
if (CollectionUtils.isEmpty(acls)) {
return tenantUris;
}
List<ACLEntry> aclEntries = convertToACLEntries(acls);
tenantUris = getUsageURIsFromAclEntries(aclEntries);
return tenantUris;
}
/**
* Gets the USE URIs from the list of ACLEntry.
*
* @param aclEntries to be used to fetch the usage URIs.
* @return a set of URIs retrived from the acls.
*/
public static Set<URI> getUsageURIsFromAclEntries(List<ACLEntry> aclEntries) {
Set<URI> tenantUris = new HashSet<URI>();
if (CollectionUtils.isEmpty(aclEntries)) {
return tenantUris;
}
Iterator<ACLEntry> aclEntryIt = aclEntries.iterator();
while (aclEntryIt.hasNext()) {
ACLEntry aclEntry = aclEntryIt.next();
if (!CollectionUtils.isEmpty(aclEntry.getAces())) {
tenantUris.add(URI.create(aclEntry.getTenant()));
}
}
return tenantUris;
}
/**
* Get the USE permission key for the provided tenant.
*
* @param tenantId to which a permission key to be created.
* @return a string format of a permission key.
*/
public static String getTenantUsePermissionKey(String tenantId) {
if (StringUtils.isBlank(tenantId)) {
throw APIException.badRequests.invalidEntryACLEntryMissingTenant();
}
PermissionsKey key = new PermissionsKey(PermissionsKey.Type.TENANT, tenantId);
return key.toString();
}
/**
* Get the vCenter tenant based on its acls. Basically
* if there is only one acl entry configured for the vCenter
* it returns the tenant of that acl entry and if there are
* more than one acl entry configured for the system, it returns
* null uri.
*
* @param acls to be used to find out the tenant of the resource.
* @return the URI of the resource if the resource contains only
* one acl entry otherwise null URI.
*/
public static URI getTenant(StringSetMap acls) {
Set<URI> usageUris = getUsageURIsFromAcls(acls);
if (CollectionUtils.isEmpty(usageUris) ||
usageUris.size() != 1) {
return NullColumnValueGetter.getNullURI();
}
return usageUris.iterator().next();
}
/**
* Get the USE ACLEntry for the tenant.
*
* @param tenantId to be used in the USE ACLEntry.
* @return the ACLEntry.
*/
public ACLEntry getUseAclEntry(String tenantId) {
ACLEntry aclEntry = new ACLEntry();
aclEntry.setTenant(tenantId);
aclEntry.getAces().add(ACL.USE.name());
return aclEntry;
}
/**
* Get tenant id from a project id retrieved from uri
*
* @param childId
* @return
*/
public Set<URI> getTenantResourceTenantIds(String childId) {
if (childId == null) {
return null;
}
try {
URI id = URI.create(childId);
Vcenter ret = null;
if (URIUtil.isType(id, Vcenter.class)) {
ret = getObjectById(id, Vcenter.class);
}
return getUsageURIsFromAcls(ret.getAcls());
} catch (DatabaseException ex) {
throw SecurityException.fatals.failedGettingTenant(ex);
}
}
/**
* Gets the user mappings of the all the domains.
*
* @param domains to get all the user mappings.
* @return returns the map of tenantID to user mappings
* of the domains.
*/
public Map<URI, List<UserMapping>> getAllUserMappingsForDomain(StringSet domains) {
Map<URI, List<UserMapping>> tenantUserMappingMap = new HashMap<URI, List<UserMapping>>();
if (CollectionUtils.isEmpty(domains)) {
return tenantUserMappingMap;
}
Iterator<String> domainsIterator = domains.iterator();
while (domainsIterator.hasNext()) {
Map<URI, List<UserMapping>> singleTenantUserMappingMap = getAllUserMappingsForDomain(domainsIterator.next());
if (!CollectionUtils.isEmpty(singleTenantUserMappingMap)) {
tenantUserMappingMap.putAll(singleTenantUserMappingMap);
}
}
return tenantUserMappingMap;
}
}