/*
* Copyright (c) 2008-2013 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.security.authorization;
import java.net.URI;
import java.security.Principal;
import java.text.CollationElementIterator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import javax.ws.rs.core.UriInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.emc.storageos.db.exceptions.DatabaseException;
import com.emc.storageos.security.authentication.StorageOSUser;
import com.emc.storageos.svcs.errorhandling.resources.APIException;
import com.sun.jersey.spi.container.ContainerRequest;
import com.sun.jersey.spi.container.ContainerRequestFilter;
import com.sun.jersey.spi.container.ContainerResponseFilter;
import com.sun.jersey.spi.container.ResourceFilter;
import org.springframework.util.CollectionUtils;
/**
* Abstract filter class for permission checker, implements filter method
*/
public abstract class AbstractPermissionFilter implements ResourceFilter, ContainerRequestFilter {
private static final Logger _log = LoggerFactory.getLogger(AbstractPermissionFilter.class);
protected final Role[] _roles;
protected final ACL[] _acls;
protected final boolean _blockProxies;
protected Class<?> _resourceClazz;
protected BasePermissionsHelper _permissionsHelper;
protected AbstractPermissionFilter(Role[] roles, ACL[] acls, boolean blockProxies,
Class resourceClazz, BasePermissionsHelper helper) {
// To Do - sort permissions
_roles = (roles != null) ? roles : new Role[] {};
_acls = (acls != null) ? acls : new ACL[] {};
_blockProxies = blockProxies;
_resourceClazz = resourceClazz;
_permissionsHelper = helper;
}
@Override
public ContainerRequestFilter getRequestFilter() {
return this;
}
@Override
public ContainerResponseFilter getResponseFilter() {
return null;
}
/**
* Get tenant id from the uri
*
* @return
*/
protected abstract URI getTenantIdFromURI(final UriInfo uriInfo);
/**
* Get project id from the uri
*
* @return
*/
protected abstract URI getProjectIdFromURI(final UriInfo uriInfo);
/**
* Get usage acls for the given tenant on the resource
*
* @param tenantId
* @return
*/
protected abstract Set<String> getUsageAclsFromURI(String tenantId, final UriInfo uriInfo);
/**
* Get UriInfo from the context
*
* @return
*/
protected abstract UriInfo getUriInfo();
/**
* Get tenant ids from the uri
*
* @return
*/
protected abstract Set<URI> getTenantIdsFromURI(UriInfo uriInfo);
/**
* ContainerRequestFilter - checks to see if one of the specified
* permissions exists for the user, if not throws
* APIException.forbidden.insufficientPermissionsForUser
*
* @param request
* @return ContainerRequest
*/
@Override
public ContainerRequest filter(ContainerRequest request) {
Principal p = request.getUserPrincipal();
if (!(p instanceof StorageOSUser)) {
throw APIException.forbidden.invalidSecurityContext();
}
StorageOSUser user = (StorageOSUser) p;
if (_blockProxies && user.isProxied()) {
throw APIException.forbidden.insufficientPermissionsForUser(user.getName());
}
boolean good = false;
// Step 1: Roles check - see if the user has one of the allowed roles
Set<String> tenantRoles = null;
for (Role role : _roles) {
if (user.getRoles().contains(role.toString())) {
good = true;
break;
}
if (_permissionsHelper.isRoleTenantLevel(role.toString())) {
if (tenantRoles == null) {
try {
URI tenantId = getTenantIdFromURI(getUriInfo());
tenantRoles = _permissionsHelper.getTenantRolesForUser(user, tenantId,
isIdEmbeddedInURL(tenantId));
if (CollectionUtils.isEmpty(tenantRoles)) {
tenantRoles = getTenantRolesFromResource(user);
}
} catch (DatabaseException ex) {
throw APIException.forbidden.failedReadingTenantRoles(ex);
}
}
if (tenantRoles != null && tenantRoles.contains(role.toString())) {
good = true;
break;
}
}
}
// Step 2: if we are still not good, start checking for acls
if (!good && _acls.length > 0) {
// grab all acls from the resource
Set<String> acls = new HashSet<String>();
URI projectId = getProjectIdFromURI(getUriInfo());
if (projectId != null) {
try {
acls = _permissionsHelper.getProjectACLsForUser(user, projectId,
isIdEmbeddedInURL(projectId));
} catch (DatabaseException ex) {
throw APIException.forbidden.failedReadingProjectACLs(ex);
}
} else { /* other resource acls */
// these acls are assigned to tenant, so enhanced to check not only user's home tenant,
// but also need to take into consideration of subtenants, which user has tenant roles.
acls = getUsageAclsFromURI(user.getTenantId(), getUriInfo());
for (String subtenantId : _permissionsHelper.getSubtenantsForUser(user)) {
Set<String> subTenantAcls = getUsageAclsFromURI(subtenantId, getUriInfo());
if (acls == null) {
acls = subTenantAcls;
} else if (subTenantAcls != null) {
acls.addAll(subTenantAcls);
}
}
}
// see if we got any and we got a hit
if (acls != null) {
for (ACL acl : _acls) {
if (acl.equals(ACL.ANY) &&
(acls.contains(ACL.OWN.toString()) ||
acls.contains(ACL.BACKUP.toString()) ||
acls.contains(ACL.ALL.toString()))) {
good = true;
break;
} else if (acls.contains(acl.toString())) {
good = true;
break;
}
}
}
}
// still not good, its not allowed
if (!good) {
throw APIException.forbidden.insufficientPermissionsForUser(user.getName());
}
return request;
}
private Set<String> getTenantRolesFromResource(StorageOSUser user) {
Set<String> tenantRoles = null;
Set<URI> tenantIds = getTenantIdsFromURI(getUriInfo());
if (CollectionUtils.isEmpty(tenantIds)) {
return tenantRoles;
}
Iterator<URI> tenantIdIterator = tenantIds.iterator();
while (tenantIdIterator.hasNext()) {
URI tenantId = tenantIdIterator.next();
Set<String> localTenantRoles = _permissionsHelper.getTenantRolesForUser(user, tenantId,
isIdEmbeddedInURL(tenantId));
if(CollectionUtils.isEmpty(localTenantRoles)) {
continue;
}
if (tenantRoles == null) {
tenantRoles = localTenantRoles;
} else {
tenantRoles.addAll(localTenantRoles);
}
}
return tenantRoles;
}
protected boolean isIdEmbeddedInURL(URI id) {
if (id == null) {
return false;
}
return isIdEmbeddedInURL(id.toString());
}
protected boolean isIdEmbeddedInURL(String id) {
boolean idEmbeddedInURL = false;
try {
String uriStr = getUriInfo().getPathParameters().getFirst("id");
if (uriStr.equals(id)) {
idEmbeddedInURL = true;
}
} catch (Exception ex) {
idEmbeddedInURL = false;
}
return idEmbeddedInURL;
}
}