/*
* Copyright (c) 2008-2011 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.systemservices.impl.security;
import com.emc.storageos.coordinator.client.model.Site;
import com.emc.storageos.coordinator.client.model.SiteState;
import com.emc.storageos.coordinator.client.service.DrUtil;
import com.emc.storageos.security.SecurityDisabler;
import com.emc.storageos.security.authorization.*;
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.beans.factory.annotation.Autowired;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo;
import java.net.URI;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
/**
* Class implements ResourceFilterFactory to add permissions filter where needed
*/
public class SyssvcPermissionsFilterFactory extends AbstractPermissionsFilterFactory {
private static final List<String> FORBIDDEN_PATHS = Arrays.asList("backupset", "control/cluster/recovery",
"control/cluster/ipreconfig", "upgrade/image/upload", "storagedriver");
private static final List<String> READ_ONLY_PATHS = Arrays.asList("ipsec");
private static final List<String> CONFIG_PATHS = Arrays.asList("config");
private static final List<String> WRITE_METHODS = Arrays.asList("PUT", "POST");
private BasePermissionsHelper _permissionsHelper;
@Autowired(required = false)
private SecurityDisabler _disabler;
private @Context
UriInfo uriInfo;
private boolean isStandby = false; // default to false
public void setIsStandby(boolean isStandby) {
this.isStandby = isStandby;
}
@Autowired
private DrUtil drUtil;
/**
* PermissionsFilter for apisvc
*/
private class SyssvcPermissionFilter extends AbstractPermissionFilter {
SyssvcPermissionFilter(Role[] roles, ACL[] acls, boolean proxiedUser, Class resourceClazz, BasePermissionsHelper helper) {
super(roles, acls, proxiedUser, resourceClazz, helper);
}
@Override
protected UriInfo getUriInfo() {
return uriInfo;
}
/**
* Get tenant id from the uri
*
* @return
*/
@Override
protected URI getTenantIdFromURI(UriInfo uriInfo) {
return null;
}
@Override
protected URI getProjectIdFromURI(UriInfo uriInfo) {
return null;
}
@Override
protected Set<String> getUsageAclsFromURI(String tenantId, UriInfo uriInfo) {
return null;
}
/**
* Get tenant ids from the uri
*
* @return
*/
@Override
protected Set<URI> getTenantIdsFromURI(UriInfo uriInfo) {
return null;
}
}
/**
* Setter for permissions helper object
*
* @param permissionsHelper
*/
public void setPermissionsHelper(BasePermissionsHelper permissionsHelper) {
_permissionsHelper = permissionsHelper;
}
@Override
protected boolean isSecurityDisabled() {
return (_disabler != null);
}
@Override
protected ResourceFilter getPreFilter() {
return new StandbySyssvcFilter();
}
@Override
protected ResourceFilter getPostFilter() {
return null;
}
@Override
protected AbstractPermissionFilter getPermissionsFilter(Role[] roles, ACL[] acls, boolean blockProxies, Class resourceClazz) {
return new SyssvcPermissionFilter(roles, acls, blockProxies, resourceClazz, _permissionsHelper);
}
@Override
protected boolean isLicenseCheckDisabled() {
// Check - always true for syssvc, since syssvc api doesn't need any license
return true;
}
@Override
protected AbstractLicenseFilter getLicenseFilter() {
return null;
}
/**
* Request filter for syssvc on standby node. We disable backup reuquests on standby.
*/
private class StandbySyssvcFilter implements ResourceFilter, ContainerRequestFilter {
@Override
public ContainerRequest filter(ContainerRequest request) {
// allow all request on active site
// use a injected variable rather than querying with DrUtil every time
// because if a ZK quorum is lost on the active site all the ZK accesses will fail
// note that readonly mode is not enabled on the active site.
if (!isStandby) {
return request;
}
String path = request.getPath();
if (isForbidden(request)) {
throw APIException.forbidden.disallowOperationOnDrStandby(drUtil.getActiveSite().getVipEndPoint());
}
return request;
}
private boolean isForbidden(ContainerRequest request) {
if (isPathForbidden(request.getPath())) {
return true;
}
if (isPathInReadOnly(request.getPath()) && isWrite(request.getMethod())) {
return true;
}
if (isConfigurationPath(request.getPath()) &&
!drUtil.getLocalSite().getState().equals(SiteState.STANDBY_SYNCED)) {
return true;
}
return false;
}
private boolean isWrite(String method) {
for (String m : WRITE_METHODS) {
if (m.equalsIgnoreCase(method)) {
return true;
}
}
return false;
}
private boolean isPathInReadOnly(String path) {
for (String forbid : READ_ONLY_PATHS) {
if (path.startsWith(forbid)) {
return true;
}
}
return false;
}
private boolean isConfigurationPath(String path) {
for (String forbid : CONFIG_PATHS) {
if (path.startsWith(forbid)) {
return true;
}
}
return false;
}
private boolean isPathForbidden(String path) {
for (String forbid : FORBIDDEN_PATHS) {
if (path.startsWith(forbid)) {
return true;
}
}
return false;
}
@Override
public ContainerRequestFilter getRequestFilter() {
return this;
}
@Override
public ContainerResponseFilter getResponseFilter() {
return null;
}
}
}