Repository: incubator-ranger Updated Branches: refs/heads/stack c4d066b6b -> dc0b2c8eb
RANGER-203: 1) Grant/Revoke implementation in HBase. 2) Fixes in grant/revoke REST API on policy update logic. 3) Updated PolicyRefresher to use thread-interrupt to stop the refresher thread (instead of shutdown flag). 4) Fix in HBase Ranger co-processor to ensure a single instance of plugin object, and there by a single instance of PolicyRefresher and PolicyEngine objects 5) Updated singleton plugin instantiation in HDFS/HBase/Hive to use volatile, instead of relying on double-checked locking Project: http://git-wip-us.apache.org/repos/asf/incubator-ranger/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ranger/commit/b8ebee5b Tree: http://git-wip-us.apache.org/repos/asf/incubator-ranger/tree/b8ebee5b Diff: http://git-wip-us.apache.org/repos/asf/incubator-ranger/diff/b8ebee5b Branch: refs/heads/stack Commit: b8ebee5b0924368dc131a1f0b78d1fd684e8cbda Parents: a6f8050 Author: Madhan Neethiraj <[email protected]> Authored: Tue Feb 10 17:07:50 2015 -0800 Committer: Madhan Neethiraj <[email protected]> Committed: Tue Feb 10 17:07:50 2015 -0800 ---------------------------------------------------------------------- .../admin/client/RangerAdminRESTClient.java | 25 +- .../admin/client/datatype/RESTResponse.java | 11 + .../RangerAbstractResourceMatcher.java | 4 + .../ranger/plugin/service/RangerBasePlugin.java | 47 +-- .../ranger/plugin/util/PolicyRefresher.java | 19 +- .../authorization/hbase/HbaseAuthUtils.java | 4 + .../authorization/hbase/HbaseAuthUtilsImpl.java | 13 +- .../hbase/RangerAuthorizationCoprocessor.java | 179 +++++--- .../namenode/RangerFSPermissionChecker.java | 19 +- .../hive/authorizer/RangerHiveAuthorizer.java | 19 +- .../org/apache/ranger/common/package-info.java | 6 +- .../org/apache/ranger/rest/ServiceREST.java | 403 +++++++++++-------- 12 files changed, 470 insertions(+), 279 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/b8ebee5b/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminRESTClient.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminRESTClient.java b/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminRESTClient.java index 8101250..f6bbebc 100644 --- a/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminRESTClient.java +++ b/agents-common/src/main/java/org/apache/ranger/admin/client/RangerAdminRESTClient.java @@ -24,6 +24,7 @@ import com.sun.jersey.api.client.WebResource; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.security.AccessControlException; import org.apache.ranger.admin.client.datatype.RESTResponse; import org.apache.ranger.authorization.hadoop.config.RangerConfiguration; import org.apache.ranger.plugin.util.GrantRevokeRequest; @@ -91,10 +92,16 @@ public class RangerAdminRESTClient implements RangerAdminClient { WebResource webResource = createWebResource(REST_URL_SERVICE_GRANT_ACCESS + serviceName); ClientResponse response = webResource.accept(REST_EXPECTED_MIME_TYPE).type(REST_EXPECTED_MIME_TYPE).post(ClientResponse.class, restClient.toJson(request)); - if(response == null || response.getStatus() != 200) { - RESTResponse resp = RESTResponse.fromClientResponse(response); + if(response != null && response.getStatus() != 200) { + LOG.error("grantAccess() failed: HTTP status=" + response.getStatus()); - throw new Exception(resp.getMessage()); + if(response.getStatus() == 401) { + throw new AccessControlException(); + } + + throw new Exception("HTTP " + response.getStatus()); + } else if(response == null) { + throw new Exception("unknown error"); } if(LOG.isDebugEnabled()) { @@ -111,10 +118,16 @@ public class RangerAdminRESTClient implements RangerAdminClient { WebResource webResource = createWebResource(REST_URL_SERVICE_REVOKE_ACCESS + serviceName); ClientResponse response = webResource.accept(REST_EXPECTED_MIME_TYPE).type(REST_EXPECTED_MIME_TYPE).post(ClientResponse.class, restClient.toJson(request)); - if(response == null || response.getStatus() != 200) { - RESTResponse resp = RESTResponse.fromClientResponse(response); + if(response != null && response.getStatus() != 200) { + LOG.error("revokeAccess() failed: HTTP status=" + response.getStatus()); - throw new Exception(resp.getMessage()); + if(response.getStatus() == 401) { + throw new AccessControlException(); + } + + throw new Exception("HTTP " + response.getStatus()); + } else if(response == null) { + throw new Exception("unknown error"); } if(LOG.isDebugEnabled()) { http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/b8ebee5b/agents-common/src/main/java/org/apache/ranger/admin/client/datatype/RESTResponse.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/admin/client/datatype/RESTResponse.java b/agents-common/src/main/java/org/apache/ranger/admin/client/datatype/RESTResponse.java index 6f0547f..d5b4524 100644 --- a/agents-common/src/main/java/org/apache/ranger/admin/client/datatype/RESTResponse.java +++ b/agents-common/src/main/java/org/apache/ranger/admin/client/datatype/RESTResponse.java @@ -37,6 +37,17 @@ import com.sun.jersey.api.client.ClientResponse; public class RESTResponse { private static Logger LOG = Logger.getLogger(RESTResponse.class); + /** + * values for statusCode + */ + public static final int STATUS_SUCCESS = 0; + public static final int STATUS_ERROR = 1; + public static final int STATUS_VALIDATION = 2; + public static final int STATUS_WARN = 3; + public static final int STATUS_INFO = 4; + public static final int STATUS_PARTIAL_SUCCESS = 5; + public static final int ResponseStatus_MAX = 5; + private int httpStatusCode; private int statusCode; private String msgDesc; http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/b8ebee5b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerAbstractResourceMatcher.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerAbstractResourceMatcher.java b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerAbstractResourceMatcher.java index 81f2412..79a878f 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerAbstractResourceMatcher.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/resourcematcher/RangerAbstractResourceMatcher.java @@ -155,6 +155,10 @@ public abstract class RangerAbstractResourceMatcher implements RangerResourceMat } else { ret = optIgnoreCase ? StringUtils.equalsIgnoreCase(resource, policyValue) : StringUtils.equals(resource, policyValue); } + + if(policyIsExcludes) { + ret = !ret; + } } if(LOG.isDebugEnabled()) { http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/b8ebee5b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java index 3dbbe81..d4f4c7f 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/service/RangerBasePlugin.java @@ -89,7 +89,7 @@ public class RangerBasePlugin { serviceName = RangerConfiguration.getInstance().get(propertyPrefix + ".service.name"); - RangerAdminClient admin = getAdminClient(propertyPrefix); + RangerAdminClient admin = createAdminClient(propertyPrefix); refresher = new PolicyRefresher(policyEngine, serviceType, serviceName, admin, pollingIntervalMs, cacheDir); refresher.startRefresher(); @@ -170,47 +170,30 @@ public class RangerBasePlugin { return null; } - public boolean grantAccess(GrantRevokeRequest request, RangerAuditHandler auditHandler) { - boolean ret = false; + public void grantAccess(GrantRevokeRequest request, RangerAuditHandler auditHandler) throws Exception { + PolicyRefresher refresher = this.refresher; + RangerAdminClient admin = refresher == null ? null : refresher.getRangerAdminClient(); - PolicyRefresher refresher = this.refresher; - - if(refresher != null) { - RangerAdminClient admin = refresher.getRangerAdminClient(); - - if(admin != null) { - try { - admin.grantAccess(serviceName, request); - } catch(Exception excp) { - LOG.error("grantAccess() failed", excp); - } - } + if(admin == null) { + throw new Exception("ranger-admin client is null"); } - return ret; + admin.grantAccess(serviceName, request); } - public boolean revokeAccess(GrantRevokeRequest request, RangerAuditHandler auditHandler) { - boolean ret = false; + public void revokeAccess(GrantRevokeRequest request, RangerAuditHandler auditHandler) throws Exception { + PolicyRefresher refresher = this.refresher; + RangerAdminClient admin = refresher == null ? null : refresher.getRangerAdminClient(); - PolicyRefresher refresher = this.refresher; - - if(refresher != null) { - RangerAdminClient admin = refresher.getRangerAdminClient(); - - if(admin != null) { - try { - admin.revokeAccess(serviceName, request); - } catch(Exception excp) { - LOG.error("revokeAccess() failed", excp); - } - } + if(admin == null) { + throw new Exception("ranger-admin client is null"); } - return ret; + admin.revokeAccess(serviceName, request); } - private RangerAdminClient getAdminClient(String propertyPrefix) { + + private RangerAdminClient createAdminClient(String propertyPrefix) { RangerAdminClient ret = null; String policySourceImpl = RangerConfiguration.getInstance().get(propertyPrefix + ".source.impl"); http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/b8ebee5b/agents-common/src/main/java/org/apache/ranger/plugin/util/PolicyRefresher.java ---------------------------------------------------------------------- diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/util/PolicyRefresher.java b/agents-common/src/main/java/org/apache/ranger/plugin/util/PolicyRefresher.java index 4974a10..eaccf7a 100644 --- a/agents-common/src/main/java/org/apache/ranger/plugin/util/PolicyRefresher.java +++ b/agents-common/src/main/java/org/apache/ranger/plugin/util/PolicyRefresher.java @@ -45,7 +45,6 @@ public class PolicyRefresher extends Thread { private long pollingIntervalMs = 30 * 1000; private String cacheFile = null; - private boolean shutdownFlag = false; private long lastKnownVersion = -1; private Gson gson = null; @@ -120,13 +119,17 @@ public class PolicyRefresher extends Thread { public void startRefresher() { loadFromCache(); - shutdownFlag = false; - super.start(); } public void stopRefresher() { - shutdownFlag = true; + super.interrupt(); + + try { + super.join(); + } catch (InterruptedException excp) { + LOG.warn("PolicyRefresher(serviceName=" + serviceName + "): error while waiting for thread to exit", excp); + } } public void run() { @@ -134,7 +137,7 @@ public class PolicyRefresher extends Thread { LOG.debug("==> PolicyRefresher(serviceName=" + serviceName + ").run()"); } - while(! shutdownFlag) { + while(true) { try { ServicePolicies svcPolicies = rangerAdmin.getServicePoliciesIfUpdated(serviceName, lastKnownVersion); @@ -167,10 +170,10 @@ public class PolicyRefresher extends Thread { try { Thread.sleep(pollingIntervalMs); - } catch(Exception excp) { - LOG.error("PolicyRefresher(serviceName=" + serviceName + ").run(): error while sleep. exiting thread", excp); + } catch(InterruptedException excp) { + LOG.info("PolicyRefresher(serviceName=" + serviceName + ").run(): interrupted! Exiting thread", excp); - throw new RuntimeException(excp); + break; } } http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/b8ebee5b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuthUtils.java ---------------------------------------------------------------------- diff --git a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuthUtils.java b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuthUtils.java index 45d4cb4..1d487e5 100644 --- a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuthUtils.java +++ b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuthUtils.java @@ -22,6 +22,10 @@ import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment; import org.apache.hadoop.hbase.security.access.Permission.Action; public interface HbaseAuthUtils { + public static final String ACCESS_TYPE_READ = "read"; + public static final String ACCESS_TYPE_WRITE = "write"; + public static final String ACCESS_TYPE_CREATE = "create"; + public static final String ACCESS_TYPE_ADMIN = "admin"; String getAccess(Action action); http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/b8ebee5b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuthUtilsImpl.java ---------------------------------------------------------------------- diff --git a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuthUtilsImpl.java b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuthUtilsImpl.java index 955a85c..e42d096 100644 --- a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuthUtilsImpl.java +++ b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/HbaseAuthUtilsImpl.java @@ -39,7 +39,18 @@ public class HbaseAuthUtilsImpl implements HbaseAuthUtils { @Override public String getAccess(Action action) { - return action.toString().toLowerCase(); + switch(action) { + case READ: + return ACCESS_TYPE_READ; + case WRITE: + return ACCESS_TYPE_WRITE; + case CREATE: + return ACCESS_TYPE_CREATE; + case ADMIN: + return ACCESS_TYPE_ADMIN; + default: + return action.name().toLowerCase(); + } } @Override http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/b8ebee5b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/RangerAuthorizationCoprocessor.java ---------------------------------------------------------------------- diff --git a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/RangerAuthorizationCoprocessor.java b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/RangerAuthorizationCoprocessor.java index 828ab7a..1dabb90 100644 --- a/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/RangerAuthorizationCoprocessor.java +++ b/hbase-agent/src/main/java/org/apache/ranger/authorization/hbase/RangerAuthorizationCoprocessor.java @@ -90,16 +90,15 @@ import org.apache.hadoop.hbase.security.access.TablePermission; import org.apache.hadoop.hbase.security.access.UserPermission; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Pair; -import org.apache.ranger.admin.client.RangerAdminRESTClient; -import org.apache.ranger.admin.client.datatype.GrantRevokeData; -import org.apache.ranger.admin.client.datatype.GrantRevokeData.PermMap; +import org.apache.ranger.admin.client.RangerAdminClient; import org.apache.ranger.audit.model.AuthzAuditEvent; import org.apache.ranger.authorization.hadoop.config.RangerConfiguration; import org.apache.ranger.authorization.hadoop.constants.RangerHadoopConstants; import org.apache.ranger.authorization.utils.StringUtil; import org.apache.ranger.plugin.audit.RangerDefaultAuditHandler; -import org.apache.ranger.plugin.policyengine.RangerPolicyEngine; import org.apache.ranger.plugin.service.RangerBasePlugin; +import org.apache.ranger.plugin.util.GrantRevokeRequest; +import org.apache.ranger.plugin.util.PolicyRefresher; import com.google.common.base.Objects; import com.google.common.collect.Lists; @@ -112,8 +111,7 @@ import com.google.protobuf.Service; public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocessorBase implements AccessControlService.Interface, CoprocessorService { private static final Log LOG = LogFactory.getLog(RangerAuthorizationCoprocessor.class.getName()); - private static final String repositoryName = RangerConfiguration.getInstance().get(RangerHadoopConstants.AUDITLOG_REPOSITORY_NAME_PROP); - private static final boolean UpdateRangerPoliciesOnGrantRevoke = RangerConfiguration.getInstance().getBoolean(RangerHadoopConstants.HBASE_UPDATE_RANGER_POLICIES_ON_GRANT_REVOKE_PROP, RangerHadoopConstants.HBASE_UPDATE_RANGER_POLICIES_ON_GRANT_REVOKE_DEFAULT_VALUE); + private static boolean UpdateRangerPoliciesOnGrantRevoke = RangerHadoopConstants.HBASE_UPDATE_RANGER_POLICIES_ON_GRANT_REVOKE_DEFAULT_VALUE; private static final String GROUP_PREFIX = "@"; private static final String SUPERUSER_CONFIG_PROP = "hbase.superuser"; @@ -130,9 +128,9 @@ public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocess * These are package level only for testability and aren't meant to be exposed outside via getters/setters or made available to derived classes. */ final HbaseFactory _factory = HbaseFactory.getInstance(); - final RangerPolicyEngine _authorizer = _factory.getPolicyEngine(); final HbaseUserUtils _userUtils = _factory.getUserUtils(); final HbaseAuthUtils _authUtils = _factory.getAuthUtils(); + private static volatile RangerHBasePlugin hbasePlugin = null; // Utilities Methods protected byte[] getTableName(RegionCoprocessorEnvironment e) { @@ -323,7 +321,7 @@ public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocess User user = getActiveUser(); // let's create a session that would be reused. Set things on it that won't change. HbaseAuditHandler auditHandler = _factory.getAuditHandler(); - AuthorizationSession session = new AuthorizationSession(_authorizer) + AuthorizationSession session = new AuthorizationSession(hbasePlugin.getPolicyEngine()) .operation(operation) .remoteAddress(getRemoteAddress()) .auditHandler(auditHandler) @@ -506,7 +504,7 @@ public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocess User user = getActiveUser(); HbaseAuditHandler auditHandler = _factory.getAuditHandler(); - AuthorizationSession session = new AuthorizationSession(_authorizer) + AuthorizationSession session = new AuthorizationSession(hbasePlugin.getPolicyEngine()) .operation(operation) .otherInformation(otherInformation) .remoteAddress(getRemoteAddress()) @@ -562,7 +560,7 @@ public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocess // if write access is desired to metatables then global create access is sufficient if (_authUtils.isWriteAccess(access) && isAccessForMetaTables(regionServerEnv)) { String createAccess = _authUtils.getAccess(Action.CREATE); - AuthorizationSession session = new AuthorizationSession(_authorizer) + AuthorizationSession session = new AuthorizationSession(hbasePlugin.getPolicyEngine()) .operation(operation) .remoteAddress(getRemoteAddress()) .user(user) @@ -870,6 +868,7 @@ public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocess private static final String MASTER_COPROCESSOR_TYPE = "master"; private static final String REGIONAL_COPROCESSOR_TYPE = "regional"; private static final String REGIONAL_SERVER_COPROCESSOR_TYPE = "regionalServer"; + @Override public void start(CoprocessorEnvironment env) throws IOException { String appType = "unknown"; @@ -898,9 +897,26 @@ public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocess } } } + // create and initialize the plugin class - new RangerBasePlugin("hbase", appType) {} - .init(_authorizer); + RangerHBasePlugin plugin = hbasePlugin; + + if(plugin == null) { + synchronized(RangerAuthorizationCoprocessor.class) { + plugin = hbasePlugin; + + if(plugin == null) { + plugin = new RangerHBasePlugin(appType); + + plugin.init(); + + UpdateRangerPoliciesOnGrantRevoke = RangerConfiguration.getInstance().getBoolean(RangerHadoopConstants.HBASE_UPDATE_RANGER_POLICIES_ON_GRANT_REVOKE_PROP, RangerHadoopConstants.HBASE_UPDATE_RANGER_POLICIES_ON_GRANT_REVOKE_DEFAULT_VALUE); + + hbasePlugin = plugin; + } + } + } + if (LOG.isDebugEnabled()) { LOG.debug("Start of Coprocessor: [" + coprocessorType + "] with superUserList [" + superUserList + "]"); } @@ -985,16 +1001,20 @@ public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocess boolean isSuccess = false; if(UpdateRangerPoliciesOnGrantRevoke) { - GrantRevokeData grData = null; + GrantRevokeRequest grData = null; try { grData = createGrantData(request); - - RangerAdminRESTClient xaAdmin = new RangerAdminRESTClient(); - - // TODO: xaAdmin.grantPrivilege(grData); - - isSuccess = true; + + RangerHBasePlugin plugin = hbasePlugin; + PolicyRefresher refresher = plugin == null ? null : plugin.getPolicyRefresher(); + RangerAdminClient admin = refresher == null ? null : refresher.getRangerAdminClient(); + + if(admin != null) { + admin.grantAccess(plugin.getServiceName(), grData); + + isSuccess = true; + } } catch(IOException excp) { LOG.warn("grant() failed", excp); @@ -1004,7 +1024,7 @@ public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocess ResponseConverter.setControllerException(controller, new CoprocessorException(excp.getMessage())); } finally { - byte[] tableName = grData == null ? null : StringUtil.getBytes(grData.getTables()); +// byte[] tableName = grData == null ? null : StringUtil.getBytes(grData.getTables()); // TODO - Auditing of grant-revoke to be sorted out. // if(accessController.isAudited(tableName)) { @@ -1027,16 +1047,20 @@ public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocess boolean isSuccess = false; if(UpdateRangerPoliciesOnGrantRevoke) { - GrantRevokeData grData = null; + GrantRevokeRequest grData = null; try { grData = createRevokeData(request); - RangerAdminRESTClient xaAdmin = new RangerAdminRESTClient(); - - // TODO: xaAdmin.revokePrivilege(grData); - - isSuccess = true; + RangerHBasePlugin plugin = hbasePlugin; + PolicyRefresher refresher = plugin == null ? null : plugin.getPolicyRefresher(); + RangerAdminClient admin = refresher == null ? null : refresher.getRangerAdminClient(); + + if(admin != null) { + admin.revokeAccess(plugin.getServiceName(), grData); + + isSuccess = true; + } } catch(IOException excp) { LOG.warn("revoke() failed", excp); @@ -1046,7 +1070,7 @@ public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocess ResponseConverter.setControllerException(controller, new CoprocessorException(excp.getMessage())); } finally { - byte[] tableName = grData == null ? null : StringUtil.getBytes(grData.getTables()); +// byte[] tableName = grData == null ? null : StringUtil.getBytes(grData.getTables()); // TODO Audit of grant revoke to be sorted out // if(accessController.isAudited(tableName)) { @@ -1079,7 +1103,7 @@ public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocess return AccessControlProtos.AccessControlService.newReflectiveService(this); } - private GrantRevokeData createGrantData(AccessControlProtos.GrantRequest request) throws Exception { + private GrantRevokeRequest createGrantData(AccessControlProtos.GrantRequest request) throws Exception { org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.UserPermission up = request.getUserPermission(); org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.Permission perm = up == null ? null : up.getPermission(); @@ -1104,7 +1128,7 @@ public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocess switch(perm.getType()) { case Global: - tableName = colFamily = qualifier = "*"; + tableName = colFamily = qualifier = WILDCARD; break; case Table: @@ -1123,21 +1147,49 @@ public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocess throw new Exception("grant(): table/columnFamily/columnQualifier not specified"); } - PermMap permMap = new PermMap(); + tableName = StringUtil.isEmpty(tableName) ? WILDCARD : tableName; + colFamily = StringUtil.isEmpty(colFamily) ? WILDCARD : colFamily; + qualifier = StringUtil.isEmpty(qualifier) ? WILDCARD : qualifier; + + User activeUser = getActiveUser(); + String grantor = activeUser != null ? activeUser.getShortName() : null; + + Map<String, String> mapResource = new HashMap<String, String>(); + mapResource.put("table", tableName); + mapResource.put("column-family", colFamily); + mapResource.put("column", qualifier); + + GrantRevokeRequest ret = new GrantRevokeRequest(); + + ret.setGrantor(grantor); + ret.setDelegateAdmin(Boolean.FALSE); + ret.setEnableAudit(Boolean.TRUE); + ret.setReplaceExistingPermissions(Boolean.TRUE); + ret.setResource(mapResource); if(userName.startsWith(GROUP_PREFIX)) { - permMap.addGroup(userName.substring(GROUP_PREFIX.length())); + ret.getGroups().add(userName.substring(GROUP_PREFIX.length())); } else { - permMap.addUser(userName); + ret.getUsers().add(userName); } for (int i = 0; i < actions.length; i++) { switch(actions[i].code()) { case 'R': + ret.getAccessTypes().add(HbaseAuthUtils.ACCESS_TYPE_READ); + break; + case 'W': + ret.getAccessTypes().add(HbaseAuthUtils.ACCESS_TYPE_WRITE); + break; + case 'C': + ret.getAccessTypes().add(HbaseAuthUtils.ACCESS_TYPE_CREATE); + break; + case 'A': - permMap.addPerm(actions[i].name()); + ret.getAccessTypes().add(HbaseAuthUtils.ACCESS_TYPE_ADMIN); + ret.setDelegateAdmin(Boolean.TRUE); break; default: @@ -1145,17 +1197,10 @@ public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocess } } - User activeUser = getActiveUser(); - String grantor = activeUser != null ? activeUser.getShortName() : null; - - GrantRevokeData grData = new GrantRevokeData(); - - grData.setHBaseData(grantor, repositoryName, tableName, qualifier, colFamily, permMap); - - return grData; + return ret; } - private GrantRevokeData createRevokeData(AccessControlProtos.RevokeRequest request) throws Exception { + private GrantRevokeRequest createRevokeData(AccessControlProtos.RevokeRequest request) throws Exception { org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.UserPermission up = request.getUserPermission(); org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.Permission perm = up == null ? null : up.getPermission(); @@ -1175,7 +1220,7 @@ public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocess switch(perm.getType()) { case Global : - tableName = colFamily = qualifier = "*"; + tableName = colFamily = qualifier = WILDCARD; break; case Table : @@ -1194,27 +1239,51 @@ public class RangerAuthorizationCoprocessor extends RangerAuthorizationCoprocess throw new Exception("revoke(): table/columnFamily/columnQualifier not specified"); } - PermMap permMap = new PermMap(); + tableName = StringUtil.isEmpty(tableName) ? WILDCARD : tableName; + colFamily = StringUtil.isEmpty(colFamily) ? WILDCARD : colFamily; + qualifier = StringUtil.isEmpty(qualifier) ? WILDCARD : qualifier; + + User activeUser = getActiveUser(); + String grantor = activeUser != null ? activeUser.getShortName() : null; + + Map<String, String> mapResource = new HashMap<String, String>(); + mapResource.put("table", tableName); + mapResource.put("column-family", colFamily); + mapResource.put("column", qualifier); + + GrantRevokeRequest ret = new GrantRevokeRequest(); + + ret.setGrantor(grantor); + ret.setDelegateAdmin(Boolean.FALSE); + ret.setEnableAudit(Boolean.TRUE); + ret.setReplaceExistingPermissions(Boolean.TRUE); + ret.setResource(mapResource); if(userName.startsWith(GROUP_PREFIX)) { - permMap.addGroup(userName.substring(GROUP_PREFIX.length())); + ret.getGroups().add(userName.substring(GROUP_PREFIX.length())); } else { - permMap.addUser(userName); + ret.getUsers().add(userName); } // revoke removes all permissions - permMap.addPerm(Permission.Action.READ.name()); - permMap.addPerm(Permission.Action.WRITE.name()); - permMap.addPerm(Permission.Action.CREATE.name()); - permMap.addPerm(Permission.Action.ADMIN.name()); + ret.getAccessTypes().add(HbaseAuthUtils.ACCESS_TYPE_READ); + ret.getAccessTypes().add(HbaseAuthUtils.ACCESS_TYPE_WRITE); + ret.getAccessTypes().add(HbaseAuthUtils.ACCESS_TYPE_CREATE); + ret.getAccessTypes().add(HbaseAuthUtils.ACCESS_TYPE_ADMIN); - User activeUser = getActiveUser(); - String grantor = activeUser != null ? activeUser.getShortName() : null; + return ret; + } +} - GrantRevokeData grData = new GrantRevokeData(); - grData.setHBaseData(grantor, repositoryName, tableName, qualifier, colFamily, permMap); +class RangerHBasePlugin extends RangerBasePlugin { + public RangerHBasePlugin(String appType) { + super("hbase", appType); + } - return grData; + public void init() { + super.init(); } } + + http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/b8ebee5b/hdfs-agent/src/main/java/org/apache/hadoop/hdfs/server/namenode/RangerFSPermissionChecker.java ---------------------------------------------------------------------- diff --git a/hdfs-agent/src/main/java/org/apache/hadoop/hdfs/server/namenode/RangerFSPermissionChecker.java b/hdfs-agent/src/main/java/org/apache/hadoop/hdfs/server/namenode/RangerFSPermissionChecker.java index 58c1102..151360f 100644 --- a/hdfs-agent/src/main/java/org/apache/hadoop/hdfs/server/namenode/RangerFSPermissionChecker.java +++ b/hdfs-agent/src/main/java/org/apache/hadoop/hdfs/server/namenode/RangerFSPermissionChecker.java @@ -66,7 +66,7 @@ public class RangerFSPermissionChecker { access2ActionListMapper.put(FsAction.EXECUTE, Sets.newHashSet(EXECUTE_ACCCESS_TYPE)); } - private static RangerHdfsPlugin rangerPlugin = null; + private static volatile RangerHdfsPlugin rangerPlugin = null; private static ThreadLocal<RangerHdfsAuditHandler> currentAuditHandler = new ThreadLocal<RangerHdfsAuditHandler>(); @@ -98,15 +98,18 @@ public class RangerFSPermissionChecker { aPathName = RangerHadoopConstants.HDFS_ROOT_FOLDER_PATH; } - if (rangerPlugin == null) { + RangerHdfsPlugin plugin = rangerPlugin; + + if (plugin == null) { synchronized(RangerFSPermissionChecker.class) { - RangerHdfsPlugin temp = rangerPlugin ; - if (temp == null) { + plugin = rangerPlugin ; + + if (plugin == null) { try { - temp = new RangerHdfsPlugin(); - temp.init(); + plugin = new RangerHdfsPlugin(); + plugin.init(); - rangerPlugin = temp; + rangerPlugin = plugin; } catch(Throwable t) { LOG.error("Unable to create Authorizer", t); @@ -172,7 +175,7 @@ public class RangerFSPermissionChecker { } class RangerHdfsPlugin extends RangerBasePlugin { - private static boolean hadoopAuthEnabled = false; + private static boolean hadoopAuthEnabled = RangerHadoopConstants.RANGER_ADD_HDFS_PERMISSION_DEFAULT; public RangerHdfsPlugin() { super("hdfs", "hdfs"); http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/b8ebee5b/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAuthorizer.java ---------------------------------------------------------------------- diff --git a/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAuthorizer.java b/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAuthorizer.java index e862943..d7d7a34 100644 --- a/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAuthorizer.java +++ b/hive-agent/src/main/java/org/apache/ranger/authorization/hive/authorizer/RangerHiveAuthorizer.java @@ -26,7 +26,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -64,7 +63,7 @@ public class RangerHiveAuthorizer extends RangerHiveAuthorizerBase { private static final char COLUMN_SEP = ','; - private static RangerHivePlugin hivePlugin = null ; + private static volatile RangerHivePlugin hivePlugin = null ; public RangerHiveAuthorizer(HiveMetastoreClientFactory metastoreClientFactory, @@ -75,9 +74,13 @@ public class RangerHiveAuthorizer extends RangerHiveAuthorizerBase { LOG.debug("RangerHiveAuthorizer.RangerHiveAuthorizer()"); - if(hivePlugin == null) { + RangerHivePlugin plugin = hivePlugin; + + if(plugin == null) { synchronized(RangerHiveAuthorizer.class) { - if(hivePlugin == null) { + plugin = hivePlugin; + + if(plugin == null) { String appType = "unknown"; if(sessionContext != null) { @@ -92,10 +95,10 @@ public class RangerHiveAuthorizer extends RangerHiveAuthorizerBase { } } - RangerHivePlugin temp = new RangerHivePlugin(appType); - temp.init(); + plugin = new RangerHivePlugin(appType); + plugin.init(); - hivePlugin = temp; + hivePlugin = plugin; } } } @@ -535,7 +538,7 @@ public class RangerHiveAuthorizer extends RangerHiveAuthorizerBase { case GRANT_PRIVILEGE: case REVOKE_PRIVILEGE: - accessType = HiveAccessType.ADMIN; + accessType = HiveAccessType.NONE; // access check will be performed at the ranger-admin side break; case ADD: http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/b8ebee5b/ranger-util/src/gen/org/apache/ranger/common/package-info.java ---------------------------------------------------------------------- diff --git a/ranger-util/src/gen/org/apache/ranger/common/package-info.java b/ranger-util/src/gen/org/apache/ranger/common/package-info.java index 5e8bd27..233f419 100644 --- a/ranger-util/src/gen/org/apache/ranger/common/package-info.java +++ b/ranger-util/src/gen/org/apache/ranger/common/package-info.java @@ -20,7 +20,7 @@ * Generated by saveVersion.sh */ @RangerVersionAnnotation(version="0.4.0", shortVersion="${ranger.version.shortname}", - revision="25517f0b1ff57e2da4a0844f4559390508ecb57e", branch="BUG-210", - user="gautam", date="Mon Feb 2 11:40:14 IST 2015", url="git://Gautams-MacBook-Pro.local/Users/gautam/Code/javaWorkspace/XASecure/Repos/incubator-ranger-patch", - srcChecksum="b46cebc9c7edc45bd3bcc6193ff245ca") + revision="a6f8050b54206dfa61d87a756d7434ec70131d88", branch="stack", + user="mneethiraj", date="Tue Feb 10 17:06:21 PST 2015", url="git://HW10963.local/Users/mneethiraj/Apache/git-commit2/incubator-ranger", + srcChecksum="c0d896b805fcb51d32f80227c393ce33") package org.apache.ranger.common; http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/b8ebee5b/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java ---------------------------------------------------------------------- diff --git a/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java b/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java index 922d174..971f6ac 100644 --- a/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java +++ b/security-admin/src/main/java/org/apache/ranger/rest/ServiceREST.java @@ -20,9 +20,8 @@ package org.apache.ranger.rest; import java.util.ArrayList; -import java.util.Collection; +import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -36,12 +35,12 @@ import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Context; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.ArrayUtils; -import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -51,6 +50,7 @@ import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemAccess; import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource; import org.apache.ranger.plugin.model.RangerService; import org.apache.ranger.plugin.model.RangerServiceDef; +import org.apache.ranger.plugin.policyengine.RangerPolicyEngine; import org.apache.ranger.plugin.policyengine.RangerResource; import org.apache.ranger.plugin.policyengine.RangerResourceImpl; import org.apache.ranger.plugin.policyevaluator.RangerDefaultPolicyEvaluator; @@ -66,6 +66,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Component; +import org.apache.ranger.admin.client.datatype.RESTResponse; import org.apache.ranger.biz.AssetMgr; import org.apache.ranger.biz.ServiceMgr; import org.apache.ranger.common.RESTErrorUtil; @@ -465,16 +466,19 @@ public class ServiceREST { @POST @Path("/services/grant/{serviceName}") @Produces({ "application/json", "application/xml" }) - public void grantAccess(@PathParam("serviceName") String serviceName, GrantRevokeRequest grantRequest, @Context HttpServletRequest request) throws Exception { + public RESTResponse grantAccess(@PathParam("serviceName") String serviceName, GrantRevokeRequest grantRequest, @Context HttpServletRequest request) throws Exception { if(LOG.isDebugEnabled()) { LOG.debug("==> ServiceREST.grantAccess(" + serviceName + ", " + grantRequest + ")"); } + RESTResponse ret = new RESTResponse(); + try { - String userName = grantRequest.getGrantor(); - RangerResource resource = new RangerResourceImpl(grantRequest.getResource()); + String userName = grantRequest.getGrantor(); + Set<String> userGroups = Collections.<String>emptySet(); // TODO: get groups for the grantor from Ranger database + RangerResource resource = new RangerResourceImpl(grantRequest.getResource()); - boolean isAdmin = isAdminForResource(userName, serviceName, resource); + boolean isAdmin = isAdminForResource(userName, userGroups, serviceName, resource); if(!isAdmin) { throw restErrorUtil.createRESTException(HttpServletResponse.SC_UNAUTHORIZED, "", true); @@ -483,79 +487,98 @@ public class ServiceREST { RangerPolicy policy = getExactMatchPolicyForResource(serviceName, resource); if(policy != null) { + boolean policyUpdated = false; + // replace all existing privileges for users and groups if(grantRequest.getReplaceExistingPermissions()) { - int numOfItems = CollectionUtils.isEmpty(policy.getPolicyItems()) ? 0 : policy.getPolicyItems().size(); + List<RangerPolicyItem> policyItems = policy.getPolicyItems(); + + int numOfItems = policyItems.size(); for(int i = 0; i < numOfItems; i++) { - RangerPolicyItem policyItem = policy.getPolicyItems().get(i); + RangerPolicyItem policyItem = policyItems.get(i); - CollectionUtils.removeAll(policyItem.getUsers(), grantRequest.getUsers()); - CollectionUtils.removeAll(policyItem.getGroups(), grantRequest.getGroups()); + if(CollectionUtils.containsAny(policyItem.getUsers(), grantRequest.getUsers())) { + policyItem.getUsers().removeAll(grantRequest.getUsers()); + + policyUpdated = true; + } + + if(CollectionUtils.containsAny(policyItem.getGroups(), grantRequest.getGroups())) { + policyItem.getGroups().removeAll(grantRequest.getGroups()); + + policyUpdated = true; + } if(CollectionUtils.isEmpty(policyItem.getUsers()) && CollectionUtils.isEmpty(policyItem.getGroups())) { - policy.getPolicyItems().remove(i); + policyItems.remove(i); numOfItems--; i--; + + policyUpdated = true; } } + + if(compactPolicy(policy)) { + policyUpdated = true; + } } - - // update policy with granted accesses for users and groups - int numOfItems = CollectionUtils.isEmpty(policy.getPolicyItems()) ? 0 : policy.getPolicyItems().size(); - - boolean policyUpdated = false; - for(int i = 0; i < numOfItems; i++) { - RangerPolicyItem policyItem = policy.getPolicyItems().get(i); - - // if policyItem matches the users and groups in the request, update the policyItem - if(isMatchForUsersGroups(policyItem, grantRequest.getUsers(), grantRequest.getGroups())) { - for(String accessType : grantRequest.getAccessTypes()) { - boolean foundAccessType = false; - - for(RangerPolicyItemAccess policyItemAccess : policyItem.getAccesses()) { - if(StringUtils.equals(policyItemAccess.getType(), accessType)) { - policyItemAccess.setIsAllowed(Boolean.TRUE); - foundAccessType = true; - break; - } - } - - if(! foundAccessType) { - policyItem.getAccesses().add(new RangerPolicyItemAccess(accessType, Boolean.TRUE)); - } + + for(String user : grantRequest.getUsers()) { + RangerPolicyItem policyItem = getPolicyItemForUser(policy, user); + + if(policyItem != null) { + if(addAccesses(policyItem, grantRequest.getAccessTypes())) { + policyUpdated = true; } - policyItem.setDelegateAdmin(grantRequest.getDelegateAdmin()); - + } else { + policyItem = new RangerPolicyItem(); + + policyItem.getUsers().add(user); + addAccesses(policyItem, grantRequest.getAccessTypes()); + policy.getPolicyItems().add(policyItem); + policyUpdated = true; - } else if(ObjectUtils.equals(policyItem.getDelegateAdmin(), grantRequest.getDelegateAdmin()) && - isMatchForAccessTypes(policyItem, grantRequest.getAccessTypes())) { // if policyItem matches the accessTypes in the request - policyItem.getUsers().addAll(grantRequest.getUsers()); - policyItem.getGroups().addAll(grantRequest.getGroups()); + } + + if(grantRequest.getDelegateAdmin()) { + if(!policyItem.getDelegateAdmin()) { + policyItem.setDelegateAdmin(Boolean.TRUE); - policyUpdated = true; + policyUpdated = true; + } } + } + + for(String group : grantRequest.getGroups()) { + RangerPolicyItem policyItem = getPolicyItemForGroup(policy, group); - if(policyUpdated) { - break; + if(policyItem != null) { + if(addAccesses(policyItem, grantRequest.getAccessTypes())) { + policyUpdated = true; + } + } else { + policyItem = new RangerPolicyItem(); + + policyItem.getGroups().add(group); + addAccesses(policyItem, grantRequest.getAccessTypes()); + policy.getPolicyItems().add(policyItem); + + policyUpdated = true; } - } + + if(grantRequest.getDelegateAdmin()) { + if(!policyItem.getDelegateAdmin()) { + policyItem.setDelegateAdmin(Boolean.TRUE); - if(!policyUpdated) { - RangerPolicyItem policyItem = new RangerPolicyItem(); - - policyItem.getUsers().addAll(grantRequest.getUsers()); - policyItem.getGroups().addAll(grantRequest.getGroups()); - for(String accessType : grantRequest.getAccessTypes()) { - RangerPolicyItemAccess access = new RangerPolicyItemAccess(accessType, Boolean.TRUE); - - policyItem.getAccesses().add(access); + policyUpdated = true; + } } - policyItem.setDelegateAdmin(grantRequest.getDelegateAdmin()); - policy.getPolicyItems().add(policyItem); } - - updatePolicy(policy); + + if(policyUpdated) { + updatePolicy(policy); + } } else { policy = new RangerPolicy(); policy.setService(serviceName); @@ -574,101 +597,132 @@ public class ServiceREST { } policy.setResources(policyResources); - RangerPolicyItem policyItem = new RangerPolicyItem(); - - policyItem.getUsers().addAll(grantRequest.getUsers()); - policyItem.getGroups().addAll(grantRequest.getGroups()); - for(String accessType : grantRequest.getAccessTypes()) { - policyItem.getAccesses().add(new RangerPolicyItemAccess(accessType, Boolean.TRUE)); + for(String user : grantRequest.getUsers()) { + RangerPolicyItem policyItem = new RangerPolicyItem(); + + policyItem.getUsers().add(user); + for(String accessType : grantRequest.getAccessTypes()) { + policyItem.getAccesses().add(new RangerPolicyItemAccess(accessType, Boolean.TRUE)); + } + policyItem.setDelegateAdmin(grantRequest.getDelegateAdmin()); + policy.getPolicyItems().add(policyItem); + } + + for(String group : grantRequest.getGroups()) { + RangerPolicyItem policyItem = new RangerPolicyItem(); + + policyItem.getGroups().add(group); + for(String accessType : grantRequest.getAccessTypes()) { + policyItem.getAccesses().add(new RangerPolicyItemAccess(accessType, Boolean.TRUE)); + } + policyItem.setDelegateAdmin(grantRequest.getDelegateAdmin()); + policy.getPolicyItems().add(policyItem); } - policyItem.setDelegateAdmin(grantRequest.getDelegateAdmin()); - policy.getPolicyItems().add(policyItem); createPolicy(policy); } + } catch(WebApplicationException excp) { + throw excp; } catch(Exception excp) { + LOG.error("grantAccess() failed", excp); + throw restErrorUtil.createRESTException(HttpServletResponse.SC_BAD_REQUEST, excp.getMessage(), true); } + ret.setStatusCode(RESTResponse.STATUS_SUCCESS); + if(LOG.isDebugEnabled()) { - LOG.debug("<== ServiceREST.grantAccess(" + serviceName + ", " + grantRequest + ")"); + LOG.debug("<== ServiceREST.grantAccess(" + serviceName + ", " + grantRequest + "): " + ret); } + + return ret; } @POST @Path("/services/revoke/{serviceName}") @Produces({ "application/json", "application/xml" }) - public void revokeAccess(@PathParam("serviceName") String serviceName, GrantRevokeRequest revokeRequest, @Context HttpServletRequest request) throws Exception { + public RESTResponse revokeAccess(@PathParam("serviceName") String serviceName, GrantRevokeRequest revokeRequest, @Context HttpServletRequest request) throws Exception { if(LOG.isDebugEnabled()) { LOG.debug("==> ServiceREST.revokeAccess(" + serviceName + ", " + revokeRequest + ")"); } + RESTResponse ret = new RESTResponse(); + try { - String userName = revokeRequest.getGrantor(); - RangerResource resource = new RangerResourceImpl(revokeRequest.getResource()); + String userName = revokeRequest.getGrantor(); + Set<String> userGroups = Collections.<String>emptySet(); // TODO: get groups for the grantor from Ranger databas + RangerResource resource = new RangerResourceImpl(revokeRequest.getResource()); - boolean isAdmin = isAdminForResource(userName, serviceName, resource); + boolean isAdmin = isAdminForResource(userName, userGroups, serviceName, resource); if(!isAdmin) { - throw new Exception("Access denied"); + throw restErrorUtil.createRESTException(HttpServletResponse.SC_UNAUTHORIZED, "", true); } RangerPolicy policy = getExactMatchPolicyForResource(serviceName, resource); - - if(policy != null && !CollectionUtils.isEmpty(policy.getPolicyItems())) { + + if(policy != null) { boolean policyUpdated = false; - for(int i = 0; i < policy.getPolicyItems().size(); i++) { - RangerPolicyItem policyItem = policy.getPolicyItems().get(i); + for(String user : revokeRequest.getUsers()) { + RangerPolicyItem policyItem = getPolicyItemForUser(policy, user); + + if(policyItem != null) { + if(removeAccesses(policyItem, revokeRequest.getAccessTypes())) { + policyUpdated = true; + } + } - // if users and groups of policyItem are a subset of request, update the policyItem - if(isSubsetOfUsersGroups(policyItem, revokeRequest.getUsers(), revokeRequest.getGroups())) { - for(String accessType : revokeRequest.getAccessTypes()) { - for(int j = 0; j < policyItem.getAccesses().size(); j++) { - RangerPolicyItemAccess policyItemAccess = policyItem.getAccesses().get(j); + if(revokeRequest.getDelegateAdmin()) { // remove delegate? + if(policyItem.getDelegateAdmin()) { + policyItem.setDelegateAdmin(Boolean.FALSE); + policyUpdated = true; + } + } + } - if(StringUtils.equals(policyItemAccess.getType(), accessType)) { - policyItem.getAccesses().remove(j); - j--; + for(String group : revokeRequest.getGroups()) { + RangerPolicyItem policyItem = getPolicyItemForGroup(policy, group); + + if(policyItem != null) { + if(removeAccesses(policyItem, revokeRequest.getAccessTypes())) { + policyUpdated = true; + } - policyUpdated = true; - } + if(revokeRequest.getDelegateAdmin()) { // remove delegate? + if(policyItem.getDelegateAdmin()) { + policyItem.setDelegateAdmin(Boolean.FALSE); + policyUpdated = true; } } - } else if(ObjectUtils.equals(policyItem.getDelegateAdmin(), revokeRequest.getDelegateAdmin()) && - isSubsetOfAccessTypes(policyItem, revokeRequest.getAccessTypes())) { // if policyItem matches the accessTypes in the request - policyItem.getUsers().removeAll(revokeRequest.getUsers()); - policyItem.getGroups().removeAll(revokeRequest.getGroups()); - - policyUpdated = true; } + } - if(CollectionUtils.isEmpty(policyItem.getAccesses()) || - (CollectionUtils.isEmpty(policyItem.getUsers()) && CollectionUtils.isEmpty(policyItem.getGroups()))) { - policy.getPolicyItems().remove(i); - i--; - - policyUpdated = true; - } + if(compactPolicy(policy)) { + policyUpdated = true; } if(policyUpdated) { - if(CollectionUtils.isEmpty(policy.getPolicyItems())) { - deletePolicy(policy.getId()); - } else { - updatePolicy(policy); - } + updatePolicy(policy); } } else { // nothing to revoke! } + } catch(WebApplicationException excp) { + throw excp; } catch(Exception excp) { + LOG.error("revokeAccess() failed", excp); + throw restErrorUtil.createRESTException(HttpServletResponse.SC_BAD_REQUEST, excp.getMessage(), true); } + ret.setStatusCode(RESTResponse.STATUS_SUCCESS); + if(LOG.isDebugEnabled()) { - LOG.debug("<== ServiceREST.revokeAccess(" + serviceName + ", " + revokeRequest + ")"); + LOG.debug("<== ServiceREST.revokeAccess(" + serviceName + ", " + revokeRequest + "): " + ret); } + + return ret; } @@ -968,7 +1022,7 @@ public class ServiceREST { } } - private boolean isAdminForResource(String userName, String serviceName, RangerResource resource) throws Exception { + private boolean isAdminForResource(String userName, Set<String> userGroups, String serviceName, RangerResource resource) throws Exception { if(LOG.isDebugEnabled()) { LOG.debug("==> ServiceREST.isAdminForResource(" + userName + ", " + serviceName + ", " + resource + ")"); } @@ -992,12 +1046,12 @@ public class ServiceREST { continue; } - if(! policyItem.getUsers().contains(userName)) { // TODO: check group membership as well - continue; + if(policyItem.getUsers().contains(userName) || + policyItem.getGroups().contains(RangerPolicyEngine.GROUP_PUBLIC) || + CollectionUtils.containsAny(policyItem.getGroups(), userGroups)) { + ret = true; + break; } - - ret = true; - break; } if(ret) { @@ -1089,77 +1143,110 @@ public class ServiceREST { return ret; } - private boolean isEqualCollection(Collection<?> col1, Collection<?> col2) { - if(col1 == null) { - return CollectionUtils.isEmpty(col2); - } else if(col2 != null) { - return CollectionUtils.isEqualCollection(col1, col2); - } else { - return false; - } - } + private boolean compactPolicy(RangerPolicy policy) { + boolean ret = false; - private boolean isSubCollection(Collection<?> col1, Collection<?> col2) { - if(col1 == null) { - return CollectionUtils.isEmpty(col2); - } else if(col2 != null) { - return CollectionUtils.isSubCollection(col1, col2); - } else { - return false; + List<RangerPolicyItem> policyItems = policy.getPolicyItems(); + + int numOfItems = policyItems.size(); + + for(int i = 0; i < numOfItems; i++) { + RangerPolicyItem policyItem = policyItems.get(i); + + // remove the policy item if 1) there are no users and groups OR 2) if there are no accessTypes and not a delegate-admin + if((CollectionUtils.isEmpty(policyItem.getUsers()) && CollectionUtils.isEmpty(policyItem.getGroups())) || + (CollectionUtils.isEmpty(policyItem.getAccesses()) && !policyItem.getDelegateAdmin())) { + policyItems.remove(i); + numOfItems--; + i--; + + ret = true; + } } + + return ret; } - private boolean isMatchForUsersGroups(RangerPolicyItem policyItem, Set<String> users, Set<String> groups) { - if(policyItem == null) { - return false; + private RangerPolicyItem getPolicyItemForUser(RangerPolicy policy, String userName) { + RangerPolicyItem ret = null; + + for(RangerPolicyItem policyItem : policy.getPolicyItems()) { + if(policyItem.getUsers().size() != 1) { + continue; + } + + if(policyItem.getUsers().contains(userName)) { + ret = policyItem; + break; + } } - return isEqualCollection(policyItem.getUsers(), users) && - isEqualCollection(policyItem.getGroups(), groups); + return ret; } - private boolean isSubsetOfUsersGroups(RangerPolicyItem policyItem, Set<String> users, Set<String> groups) { - if(policyItem == null) { - return false; + private RangerPolicyItem getPolicyItemForGroup(RangerPolicy policy, String groupName) { + RangerPolicyItem ret = null; + + for(RangerPolicyItem policyItem : policy.getPolicyItems()) { + if(policyItem.getGroups().size() != 1) { + continue; + } + + if(policyItem.getGroups().contains(groupName)) { + ret = policyItem; + break; + } } - return isSubCollection(policyItem.getUsers(), users) && - isSubCollection(policyItem.getGroups(), groups); + return ret; } - private boolean isMatchForAccessTypes(RangerPolicyItem policyItem, Set<String> accessTypes) { - if(policyItem == null) { - return false; - } + private boolean addAccesses(RangerPolicyItem policyItem, Set<String> accessTypes) { + boolean ret = false; - Set<String> policyAccessTypes = new HashSet<String>(); + for(String accessType : accessTypes) { + RangerPolicyItemAccess policyItemAccess = null; + + for(RangerPolicyItemAccess itemAccess : policyItem.getAccesses()) { + if(StringUtils.equals(itemAccess.getType(), accessType)) { + policyItemAccess = itemAccess; + break; + } + } - if(!CollectionUtils.isEmpty(policyItem.getAccesses())) { - for(RangerPolicyItemAccess policyItemAccess : policyItem.getAccesses()) { - if(policyItemAccess.getIsAllowed()) { - policyAccessTypes.add(policyItemAccess.getType()); + if(policyItemAccess != null) { + if(!policyItemAccess.getIsAllowed()) { + policyItemAccess.setIsAllowed(Boolean.TRUE); + ret = true; } + } else { + policyItem.getAccesses().add(new RangerPolicyItemAccess(accessType, Boolean.TRUE)); + ret = true; } } - return isEqualCollection(policyAccessTypes, accessTypes); + return ret; } - private boolean isSubsetOfAccessTypes(RangerPolicyItem policyItem, Set<String> accessTypes) { - if(policyItem == null) { - return false; - } + private boolean removeAccesses(RangerPolicyItem policyItem, Set<String> accessTypes) { + boolean ret = false; + + for(String accessType : accessTypes) { + int numOfItems = policyItem.getAccesses().size(); - Set<String> policyAccessTypes = new HashSet<String>(); + for(int i = 0; i < numOfItems; i++) { + RangerPolicyItemAccess itemAccess = policyItem.getAccesses().get(i); + + if(StringUtils.equals(itemAccess.getType(), accessType)) { + policyItem.getAccesses().remove(i); + numOfItems--; + i--; - if(!CollectionUtils.isEmpty(policyItem.getAccesses())) { - for(RangerPolicyItemAccess policyItemAccess : policyItem.getAccesses()) { - if(policyItemAccess.getIsAllowed()) { - policyAccessTypes.add(policyItemAccess.getType()); + ret = true; } } } - return isSubCollection(policyAccessTypes, accessTypes); + return ret; } }
