http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/92cde111/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java index 81adec2..fbb611e 100644 --- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java @@ -65,6 +65,7 @@ import org.apache.sentry.provider.db.service.thrift.TSentryActiveRoleSet; import org.apache.sentry.provider.db.service.thrift.TSentryAuthorizable; import org.apache.sentry.provider.db.service.thrift.TSentryGrantOption; import org.apache.sentry.provider.db.service.thrift.TSentryGroup; +import org.apache.sentry.provider.db.service.thrift.TSentryMappingData; import org.apache.sentry.provider.db.service.thrift.TSentryPrivilege; import org.apache.sentry.provider.db.service.thrift.TSentryPrivilegeMap; import org.apache.sentry.provider.db.service.thrift.TSentryRole; @@ -76,9 +77,11 @@ import org.slf4j.LoggerFactory; import com.codahale.metrics.Gauge; import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Function; import com.google.common.base.Joiner; import com.google.common.base.Preconditions; import com.google.common.base.Strings; +import com.google.common.collect.Collections2; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -310,16 +313,10 @@ public class SentryStore { PersistenceManager pm = null; try { pm = openTransaction(); - MSentryRole mSentryRole = getMSentryRole(pm, roleName); - if (mSentryRole == null) { - MSentryRole mRole = new MSentryRole(roleName, System.currentTimeMillis()); - pm.makePersistent(mRole); - CommitContext commit = commitUpdateTransaction(pm); - rollbackTransaction = false; - return commit; - } else { - throw new SentryAlreadyExistsException("Role: " + roleName); - } + createSentryRoleCore(pm, roleName); + CommitContext commit = commitUpdateTransaction(pm); + rollbackTransaction = false; + return commit; } finally { if (rollbackTransaction) { rollbackTransaction(pm); @@ -327,6 +324,17 @@ public class SentryStore { } } + private void createSentryRoleCore(PersistenceManager pm, String roleName) + throws SentryAlreadyExistsException { + MSentryRole mSentryRole = getMSentryRole(pm, roleName); + if (mSentryRole == null) { + MSentryRole mRole = new MSentryRole(roleName, System.currentTimeMillis()); + pm.makePersistent(mRole); + } else { + throw new SentryAlreadyExistsException("Role: " + roleName); + } + } + private <T> Long getCount(Class<T> tClass) { PersistenceManager pm = null; Long size = new Long(-1); @@ -444,7 +452,8 @@ public class SentryStore { || (!isNULL(privilege.getDbName()))) { // If Grant is for ALL and Either INSERT/SELECT already exists.. // need to remove it and GRANT ALL.. - if (privilege.getAction().equalsIgnoreCase("*")) { + if (AccessConstants.ALL.equalsIgnoreCase(privilege.getAction()) + || AccessConstants.ACTION_ALL.equalsIgnoreCase(privilege.getAction())) { TSentryPrivilege tNotAll = new TSentryPrivilege(privilege); tNotAll.setAction(AccessConstants.SELECT); MSentryPrivilege mSelect = getMSentryPrivilege(tNotAll, pm); @@ -465,8 +474,13 @@ public class SentryStore { // do nothing.. TSentryPrivilege tAll = new TSentryPrivilege(privilege); tAll.setAction(AccessConstants.ALL); - MSentryPrivilege mAll = getMSentryPrivilege(tAll, pm); - if ((mAll != null) && (mRole.getPrivileges().contains(mAll))) { + MSentryPrivilege mAll1 = getMSentryPrivilege(tAll, pm); + tAll.setAction(AccessConstants.ACTION_ALL); + MSentryPrivilege mAll2 = getMSentryPrivilege(tAll, pm); + if ((mAll1 != null) && (mRole.getPrivileges().contains(mAll1))) { + return null; + } + if ((mAll2 != null) && (mRole.getPrivileges().contains(mAll2))) { return null; } } @@ -763,25 +777,9 @@ public class SentryStore { throws SentryNoSuchObjectException { boolean rollbackTransaction = true; PersistenceManager pm = null; - roleName = roleName.trim().toLowerCase(); try { pm = openTransaction(); - Query query = pm.newQuery(MSentryRole.class); - query.setFilter("this.roleName == t"); - query.declareParameters("java.lang.String t"); - query.setUnique(true); - MSentryRole sentryRole = (MSentryRole) query.execute(roleName); - if (sentryRole == null) { - throw new SentryNoSuchObjectException("Role " + roleName); - } else { - pm.retrieve(sentryRole); - int numPrivs = sentryRole.getPrivileges().size(); - sentryRole.removePrivileges(); - //with SENTRY-398 generic model - sentryRole.removeGMPrivileges(); - privCleaner.incPrivRemoval(numPrivs); - pm.deletePersistent(sentryRole); - } + dropSentryRoleCore(pm, roleName); CommitContext commit = commitUpdateTransaction(pm); rollbackTransaction = false; return commit; @@ -792,42 +790,38 @@ public class SentryStore { } } + private void dropSentryRoleCore(PersistenceManager pm, String roleName) + throws SentryNoSuchObjectException { + String lRoleName = roleName.trim().toLowerCase(); + Query query = pm.newQuery(MSentryRole.class); + query.setFilter("this.roleName == t"); + query.declareParameters("java.lang.String t"); + query.setUnique(true); + MSentryRole sentryRole = (MSentryRole) query.execute(lRoleName); + if (sentryRole == null) { + throw new SentryNoSuchObjectException("Role " + lRoleName); + } else { + pm.retrieve(sentryRole); + int numPrivs = sentryRole.getPrivileges().size(); + sentryRole.removePrivileges(); + // with SENTRY-398 generic model + sentryRole.removeGMPrivileges(); + privCleaner.incPrivRemoval(numPrivs); + pm.deletePersistent(sentryRole); + } + } + public CommitContext alterSentryRoleAddGroups( String grantorPrincipal, String roleName, Set<TSentryGroup> groupNames) throws SentryNoSuchObjectException { boolean rollbackTransaction = true; PersistenceManager pm = null; - roleName = roleName.trim().toLowerCase(); try { pm = openTransaction(); - Query query = pm.newQuery(MSentryRole.class); - query.setFilter("this.roleName == t"); - query.declareParameters("java.lang.String t"); - query.setUnique(true); - MSentryRole role = (MSentryRole) query.execute(roleName); - if (role == null) { - throw new SentryNoSuchObjectException("Role: " + roleName); - } else { - query = pm.newQuery(MSentryGroup.class); - query.setFilter("this.groupName == t"); - query.declareParameters("java.lang.String t"); - query.setUnique(true); - List<MSentryGroup> groups = Lists.newArrayList(); - for (TSentryGroup tGroup : groupNames) { - String groupName = tGroup.getGroupName().trim(); - MSentryGroup group = (MSentryGroup) query.execute(groupName); - if (group == null) { - group = new MSentryGroup(groupName, System.currentTimeMillis(), - Sets.newHashSet(role)); - } - group.appendRole(role); - groups.add(group); - } - pm.makePersistentAll(groups); - CommitContext commit = commitUpdateTransaction(pm); - rollbackTransaction = false; - return commit; - } + alterSentryRoleAddGroupsCore(pm, roleName, groupNames); + CommitContext commit = commitUpdateTransaction(pm); + rollbackTransaction = false; + return commit; } finally { if (rollbackTransaction) { rollbackTransaction(pm); @@ -835,6 +829,35 @@ public class SentryStore { } } + private void alterSentryRoleAddGroupsCore(PersistenceManager pm, String roleName, + Set<TSentryGroup> groupNames) throws SentryNoSuchObjectException { + String lRoleName = roleName.trim().toLowerCase(); + Query query = pm.newQuery(MSentryRole.class); + query.setFilter("this.roleName == t"); + query.declareParameters("java.lang.String t"); + query.setUnique(true); + MSentryRole role = (MSentryRole) query.execute(lRoleName); + if (role == null) { + throw new SentryNoSuchObjectException("Role: " + lRoleName); + } else { + query = pm.newQuery(MSentryGroup.class); + query.setFilter("this.groupName == t"); + query.declareParameters("java.lang.String t"); + query.setUnique(true); + List<MSentryGroup> groups = Lists.newArrayList(); + for (TSentryGroup tGroup : groupNames) { + String groupName = tGroup.getGroupName().trim(); + MSentryGroup group = (MSentryGroup) query.execute(groupName); + if (group == null) { + group = new MSentryGroup(groupName, System.currentTimeMillis(), Sets.newHashSet(role)); + } + group.appendRole(role); + groups.add(group); + } + pm.makePersistentAll(groups); + } + } + public CommitContext alterSentryRoleDeleteGroups(String roleName, Set<TSentryGroup> groupNames) throws SentryNoSuchObjectException { @@ -1341,7 +1364,7 @@ public class SentryStore { return group; } - private TSentryPrivilege convertToTSentryPrivilege(MSentryPrivilege mSentryPrivilege) { + protected TSentryPrivilege convertToTSentryPrivilege(MSentryPrivilege mSentryPrivilege) { TSentryPrivilege privilege = new TSentryPrivilege(); convertToTSentryPrivilege(mSentryPrivilege, privilege); return privilege; @@ -1979,4 +2002,319 @@ public class SentryStore { } } } + + // get all mapping data for [group,role] + public Map<String, Set<String>> getGroupNameRoleNamesMap() { + boolean rollbackTransaction = true; + PersistenceManager pm = null; + try { + pm = openTransaction(); + Query query = pm.newQuery(MSentryGroup.class); + List<MSentryGroup> mSentryGroups = (List<MSentryGroup>) query.execute(); + Map<String, Set<String>> sentryGroupNameRoleNamesMap = Maps.newHashMap(); + if (mSentryGroups != null) { + // change the List<MSentryGroup> -> Map<groupName, Set<roleName>> + for (MSentryGroup mSentryGroup : mSentryGroups) { + String groupName = mSentryGroup.getGroupName(); + Set<String> roleNames = Sets.newHashSet(); + for (MSentryRole mSentryRole : mSentryGroup.getRoles()) { + roleNames.add(mSentryRole.getRoleName()); + } + if (roleNames.size() > 0) { + sentryGroupNameRoleNamesMap.put(groupName, roleNames); + } + } + } + commitTransaction(pm); + rollbackTransaction = false; + return sentryGroupNameRoleNamesMap; + } finally { + if (rollbackTransaction) { + rollbackTransaction(pm); + } + } + } + + // get all mapping data for [role,privilege] + public Map<String, Set<TSentryPrivilege>> getRoleNameTPrivilegesMap() throws Exception { + boolean rollbackTransaction = true; + PersistenceManager pm = null; + try { + pm = openTransaction(); + Query query = pm.newQuery(MSentryRole.class); + List<MSentryRole> mSentryRoles = (List<MSentryRole>) query.execute(); + Map<String, Set<TSentryPrivilege>> sentryRolePrivilegesMap = Maps.newHashMap(); + if (mSentryRoles != null) { + // change the List<MSentryRole> -> Map<roleName, Set<TSentryPrivilege>> + for (MSentryRole mSentryRole : mSentryRoles) { + Set<TSentryPrivilege> privilegeSet = convertToTSentryPrivileges(mSentryRole + .getPrivileges()); + if (privilegeSet != null && !privilegeSet.isEmpty()) { + sentryRolePrivilegesMap.put(mSentryRole.getRoleName(), privilegeSet); + } + } + } + commitTransaction(pm); + rollbackTransaction = false; + return sentryRolePrivilegesMap; + } finally { + if (rollbackTransaction) { + rollbackTransaction(pm); + } + } + } + + // get the all exist role names + private Set<String> getAllRoleNames(PersistenceManager pm) { + Query query = pm.newQuery(MSentryRole.class); + List<MSentryRole> mSentryRoles = (List<MSentryRole>) query.execute(); + Set<String> existRoleNames = Sets.newHashSet(); + if (mSentryRoles != null) { + for (MSentryRole mSentryRole : mSentryRoles) { + existRoleNames.add(mSentryRole.getRoleName()); + } + } + return existRoleNames; + } + + // get the all exist groups + private Map<String, MSentryGroup> getGroupNameTGroupMap(PersistenceManager pm) { + Query query = pm.newQuery(MSentryGroup.class); + List<MSentryGroup> mSentryGroups = (List<MSentryGroup>) query.execute(); + Map<String, MSentryGroup> existGroupsMap = Maps.newHashMap(); + if (mSentryGroups != null) { + // change the List<MSentryGroup> -> Map<roleName, Set<MSentryGroup>> + for (MSentryGroup mSentryGroup : mSentryGroups) { + existGroupsMap.put(mSentryGroup.getGroupName(), mSentryGroup); + } + } + return existGroupsMap; + } + + // get the all exist privileges + private List<MSentryPrivilege> getPrivilegesList(PersistenceManager pm) { + Query query = pm.newQuery(MSentryPrivilege.class); + List<MSentryPrivilege> resultList = (List<MSentryPrivilege>) query.execute(); + if (resultList == null) { + resultList = Lists.newArrayList(); + } + return resultList; + } + + @VisibleForTesting + protected Map<String, MSentryRole> getRolesMap() { + boolean rollbackTransaction = true; + PersistenceManager pm = null; + try { + pm = openTransaction(); + + Query query = pm.newQuery(MSentryRole.class); + List<MSentryRole> mSentryRoles = (List<MSentryRole>) query.execute(); + Map<String, MSentryRole> existRolesMap = Maps.newHashMap(); + if (mSentryRoles != null) { + // change the List<MSentryRole> -> Map<roleName, Set<MSentryRole>> + for (MSentryRole mSentryRole : mSentryRoles) { + existRolesMap.put(mSentryRole.getRoleName(), mSentryRole); + } + } + + commitTransaction(pm); + rollbackTransaction = false; + return existRolesMap; + } finally { + if (rollbackTransaction) { + rollbackTransaction(pm); + } + } + } + + @VisibleForTesting + protected Map<String, MSentryGroup> getGroupNameTGroupMap() { + boolean rollbackTransaction = true; + PersistenceManager pm = null; + try { + pm = openTransaction(); + Map<String, MSentryGroup> resultMap = getGroupNameTGroupMap(pm); + commitTransaction(pm); + rollbackTransaction = false; + return resultMap; + } finally { + if (rollbackTransaction) { + rollbackTransaction(pm); + } + } + } + + @VisibleForTesting + protected List<MSentryPrivilege> getPrivilegesList() { + boolean rollbackTransaction = true; + PersistenceManager pm = null; + try { + pm = openTransaction(); + List<MSentryPrivilege> resultList = getPrivilegesList(pm); + commitTransaction(pm); + rollbackTransaction = false; + return resultList; + } finally { + if (rollbackTransaction) { + rollbackTransaction(pm); + } + } + } + + /** + * Import the sentry mapping data. + * + * @param tSentryMappingData + * Include 2 maps to save the mapping data, the following is the example of the data + * structure: + * for the following mapping data: + * group1=role1,role2 + * group2=role2,role3 + * role1=server=server1->db=db1 + * role2=server=server1->db=db1->table=tbl1,server=server1->db=db1->table=tbl2 + * role3=server=server1->url=hdfs://localhost/path + * + * The GroupRolesMap in TSentryMappingData will be saved as: + * { + * TSentryGroup(group1)={role1, role2}, + * TSentryGroup(group2)={role2, role3} + * } + * The RolePrivilegesMap in TSentryMappingData will be saved as: + * { + * role1={TSentryPrivilege(server=server1->db=db1)}, + * role2={TSentryPrivilege(server=server1->db=db1->table=tbl1), + * TSentryPrivilege(server=server1->db=db1->table=tbl2)}, + * role3={TSentryPrivilege(server=server1->url=hdfs://localhost/path)} + * } + * @param isOverwriteForRole + * The option for merging or overwriting the existing data during import, true for + * overwriting, false for merging + */ + public void importSentryMetaData(TSentryMappingData tSentryMappingData, boolean isOverwriteForRole) + throws Exception { + boolean rollbackTransaction = true; + PersistenceManager pm = null; + // change all role name in lowercase + TSentryMappingData mappingData = lowercaseRoleName(tSentryMappingData); + try { + pm = openTransaction(); + Set<String> existRoleNames = getAllRoleNames(pm); + // + Map<String, Set<TSentryGroup>> importedRoleGroupsMap = covertToRoleNameTGroupsMap(mappingData + .getGroupRolesMap()); + Set<String> importedRoleNames = importedRoleGroupsMap.keySet(); + // if import with overwrite role, drop the duplicated roles in current DB first. + if (isOverwriteForRole) { + dropDuplicatedRoleForImport(pm, existRoleNames, importedRoleNames); + // refresh the existRoleNames for the drop role + existRoleNames = getAllRoleNames(pm); + } + + // import the mapping data for [role,privilege], the existRoleNames will be updated + importSentryRolePrivilegeMapping(pm, existRoleNames, mappingData.getRolePrivilegesMap()); + + importSentryGroupRoleMapping(pm, existRoleNames, importedRoleGroupsMap); + + commitTransaction(pm); + rollbackTransaction = false; + } finally { + if (rollbackTransaction) { + rollbackTransaction(pm); + } + } + } + + // covert the Map[group->roles] to Map[role->groups] + private Map<String, Set<TSentryGroup>> covertToRoleNameTGroupsMap( + Map<String, Set<String>> groupRolesMap) { + Map<String, Set<TSentryGroup>> roleGroupsMap = Maps.newHashMap(); + if (groupRolesMap != null) { + for (String groupName : groupRolesMap.keySet()) { + Set<String> roleNames = groupRolesMap.get(groupName); + if (roleNames != null) { + for (String roleName : roleNames) { + Set<TSentryGroup> tSentryGroups = roleGroupsMap.get(roleName); + if (tSentryGroups == null) { + tSentryGroups = Sets.newHashSet(); + } + tSentryGroups.add(new TSentryGroup(groupName)); + roleGroupsMap.put(roleName, tSentryGroups); + } + } + } + } + return roleGroupsMap; + } + + private void importSentryGroupRoleMapping(PersistenceManager pm, Set<String> existRoleNames, + Map<String, Set<TSentryGroup>> importedRoleGroupsMap) throws Exception { + if (importedRoleGroupsMap == null || importedRoleGroupsMap.keySet() == null) { + return; + } + for (String roleName : importedRoleGroupsMap.keySet()) { + if (!existRoleNames.contains(roleName)) { + createSentryRoleCore(pm, roleName); + } + alterSentryRoleAddGroupsCore(pm, roleName, importedRoleGroupsMap.get(roleName)); + } + } + + // drop all duplicated with the imported role + private void dropDuplicatedRoleForImport(PersistenceManager pm, Set<String> existRoleNames, + Set<String> importedRoleNames) throws Exception { + Set<String> duplicatedRoleNames = Sets.intersection(existRoleNames, importedRoleNames); + for (String droppedRoleName : duplicatedRoleNames) { + dropSentryRoleCore(pm, droppedRoleName); + } + } + + // change all role name in lowercase + private TSentryMappingData lowercaseRoleName(TSentryMappingData tSentryMappingData) { + Map<String, Set<String>> sentryGroupRolesMap = tSentryMappingData.getGroupRolesMap(); + Map<String, Set<TSentryPrivilege>> sentryRolePrivilegesMap = tSentryMappingData + .getRolePrivilegesMap(); + + Map<String, Set<String>> newSentryGroupRolesMap = Maps.newHashMap(); + Map<String, Set<TSentryPrivilege>> newSentryRolePrivilegesMap = Maps.newHashMap(); + // for mapping data [group,role] + for (String groupName : sentryGroupRolesMap.keySet()) { + Collection<String> lowcaseRoles = Collections2.transform(sentryGroupRolesMap.get(groupName), + new Function<String, String>() { + @Override + public String apply(String input) { + return input.toString().toLowerCase(); + } + }); + newSentryGroupRolesMap.put(groupName, Sets.newHashSet(lowcaseRoles)); + } + + // for mapping data [role,privilege] + for (String roleName : sentryRolePrivilegesMap.keySet()) { + newSentryRolePrivilegesMap.put(roleName.toLowerCase(), sentryRolePrivilegesMap.get(roleName)); + } + + tSentryMappingData.setGroupRolesMap(newSentryGroupRolesMap); + tSentryMappingData.setRolePrivilegesMap(newSentryRolePrivilegesMap); + return tSentryMappingData; + } + + // import the mapping data for [role,privilege] + private void importSentryRolePrivilegeMapping(PersistenceManager pm, Set<String> existRoleNames, + Map<String, Set<TSentryPrivilege>> sentryRolePrivilegesMap) throws Exception { + if (sentryRolePrivilegesMap != null) { + for (String roleName : sentryRolePrivilegesMap.keySet()) { + // if the rolenName doesn't exist, create it. + if (!existRoleNames.contains(roleName)) { + createSentryRoleCore(pm, roleName); + existRoleNames.add(roleName); + } + // get the privileges for the role + Set<TSentryPrivilege> tSentryPrivileges = sentryRolePrivilegesMap.get(roleName); + for (TSentryPrivilege tSentryPrivilege : tSentryPrivileges) { + alterSentryRoleGrantPrivilegeCore(pm, roleName, tSentryPrivilege); + } + } + } + } }
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/92cde111/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryPolicyServiceClient.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryPolicyServiceClient.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryPolicyServiceClient.java index 05cbfb6..9c2d384 100644 --- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryPolicyServiceClient.java +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryPolicyServiceClient.java @@ -178,4 +178,12 @@ public interface SentryPolicyServiceClient { public String getConfigValue(String propertyName, String defaultValue) throws SentryUserException; public void close(); + + // Import the sentry mapping data with map structure + public void importPolicy(Map<String, Map<String, Set<String>>> policyFileMappingData, + String requestorUserName, boolean isOverwriteRole) throws SentryUserException; + + // export the sentry mapping data with map structure + public Map<String, Map<String, Set<String>>> exportPolicy(String requestorUserName) + throws SentryUserException; } http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/92cde111/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryPolicyServiceClientDefaultImpl.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryPolicyServiceClientDefaultImpl.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryPolicyServiceClientDefaultImpl.java index 533a28c..09b3d99 100644 --- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryPolicyServiceClientDefaultImpl.java +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryPolicyServiceClientDefaultImpl.java @@ -27,6 +27,7 @@ import java.util.Set; import javax.security.auth.callback.CallbackHandler; +import org.apache.commons.lang.StringUtils; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.net.NetUtils; import org.apache.hadoop.security.SaslRpcServer; @@ -38,6 +39,8 @@ import org.apache.sentry.core.common.ActiveRoleSet; import org.apache.sentry.core.common.Authorizable; import org.apache.sentry.core.model.db.AccessConstants; import org.apache.sentry.core.model.db.DBModelAuthorizable; +import org.apache.sentry.provider.common.PolicyFileConstants; +import org.apache.sentry.service.thrift.SentryServiceUtil; import org.apache.sentry.service.thrift.ServiceConstants.ClientConfig; import org.apache.sentry.service.thrift.ServiceConstants.PrivilegeScope; import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig; @@ -58,6 +61,7 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import com.google.common.collect.Sets; public class SentryPolicyServiceClientDefaultImpl implements SentryPolicyServiceClient { @@ -816,4 +820,111 @@ public class SentryPolicyServiceClientDefaultImpl implements SentryPolicyService transport.close(); } } + + /** + * Import the sentry mapping data, convert the mapping data from map structure to + * TSentryMappingData, and call the import API. + * + * @param policyFileMappingData + * Include 2 maps to save the mapping data, the following is the example of the data + * structure: + * for the following mapping data: + * group1=role1,role2 + * group2=role2,role3 + * role1=server=server1->db=db1 + * role2=server=server1->db=db1->table=tbl1,server=server1->db=db1->table=tbl2 + * role3=server=server1->url=hdfs://localhost/path + * + * The policyFileMappingData will be inputed as: + * { + * groups={[group1={role1, role2}], group2=[role2, role3]}, + * roles={role1=[server=server1->db=db1], + * role2=[server=server1->db=db1->table=tbl1,server=server1->db=db1->table=tbl2], + * role3=[server=server1->url=hdfs://localhost/path] + * } + * } + * @param requestorUserName + * The name of the request user + */ + public void importPolicy(Map<String, Map<String, Set<String>>> policyFileMappingData, + String requestorUserName, boolean isOverwriteRole) + throws SentryUserException { + try { + TSentryMappingData tSentryMappingData = new TSentryMappingData(); + // convert the mapping data for [group,role] from map structure to + // TSentryMappingData.GroupRolesMap + tSentryMappingData.setGroupRolesMap(policyFileMappingData.get(PolicyFileConstants.GROUPS)); + // convert the mapping data for [role,privilege] from map structure to + // TSentryMappingData.RolePrivilegesMap + tSentryMappingData + .setRolePrivilegesMap(convertRolePrivilegesMapForSentryDB(policyFileMappingData + .get(PolicyFileConstants.ROLES))); + TSentryImportMappingDataRequest request = new TSentryImportMappingDataRequest( + ThriftConstants.TSENTRY_SERVICE_VERSION_CURRENT, requestorUserName, isOverwriteRole, + tSentryMappingData); + TSentryImportMappingDataResponse response = client.import_sentry_mapping_data(request); + Status.throwIfNotOk(response.getStatus()); + } catch (TException e) { + throw new SentryUserException(THRIFT_EXCEPTION_MESSAGE, e); + } + } + + // convert the mapping data for [role,privilege] from map structure to + // TSentryMappingData.RolePrivilegesMap + private Map<String, Set<TSentryPrivilege>> convertRolePrivilegesMapForSentryDB( + Map<String, Set<String>> rolePrivilegesMap) { + Map<String, Set<TSentryPrivilege>> rolePrivilegesMapResult = Maps.newHashMap(); + if (rolePrivilegesMap != null) { + for (String tempRoleName : rolePrivilegesMap.keySet()) { + Set<TSentryPrivilege> tempTSentryPrivileges = Sets.newHashSet(); + Set<String> tempPrivileges = rolePrivilegesMap.get(tempRoleName); + for (String tempPrivilege : tempPrivileges) { + tempTSentryPrivileges.add(SentryServiceUtil.convertToTSentryPrivilege(tempPrivilege)); + } + rolePrivilegesMapResult.put(tempRoleName, tempTSentryPrivileges); + } + } + return rolePrivilegesMapResult; + } + + // export the sentry mapping data with map structure + public Map<String, Map<String, Set<String>>> exportPolicy(String requestorUserName) + throws SentryUserException { + TSentryExportMappingDataRequest request = new TSentryExportMappingDataRequest( + ThriftConstants.TSENTRY_SERVICE_VERSION_CURRENT, requestorUserName); + try { + TSentryExportMappingDataResponse response = client.export_sentry_mapping_data(request); + Status.throwIfNotOk(response.getStatus()); + TSentryMappingData tSentryMappingData = response.getMappingData(); + Map<String, Map<String, Set<String>>> resultMap = Maps.newHashMap(); + resultMap.put(PolicyFileConstants.GROUPS, tSentryMappingData.getGroupRolesMap()); + resultMap.put(PolicyFileConstants.ROLES, + convertRolePrivilegesMapForPolicyFile(tSentryMappingData.getRolePrivilegesMap())); + return resultMap; + } catch (TException e) { + throw new SentryUserException(THRIFT_EXCEPTION_MESSAGE, e); + } + } + + // convert the mapping data for [roleName,privilege] from TSentryMappingData.RolePrivilegesMap to + // map structure + private Map<String, Set<String>> convertRolePrivilegesMapForPolicyFile( + Map<String, Set<TSentryPrivilege>> rolePrivilegesMap) { + Map<String, Set<String>> rolePrivilegesMapForFile = Maps.newHashMap(); + if (rolePrivilegesMap != null) { + for (String tempRoleName : rolePrivilegesMap.keySet()) { + Set<TSentryPrivilege> tempSentryPrivileges = rolePrivilegesMap.get(tempRoleName); + Set<String> tempStrPrivileges = Sets.newHashSet(); + for (TSentryPrivilege tSentryPrivilege : tempSentryPrivileges) { + // convert TSentryPrivilege to privilege in string + String privilegeStr = SentryServiceUtil.convertTSentryPrivilegeToStr(tSentryPrivilege); + if (!StringUtils.isEmpty(privilegeStr)) { + tempStrPrivileges.add(privilegeStr); + } + } + rolePrivilegesMapForFile.put(tempRoleName, tempStrPrivileges); + } + } + return rolePrivilegesMapForFile; + } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/92cde111/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryPolicyStoreProcessor.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryPolicyStoreProcessor.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryPolicyStoreProcessor.java index 406daa0..ea9fae9 100644 --- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryPolicyStoreProcessor.java +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/thrift/SentryPolicyStoreProcessor.java @@ -857,4 +857,57 @@ public class SentryPolicyStoreProcessor implements SentryPolicyService.Iface { } } + // get the sentry mapping data and return the data with map structure + @Override + public TSentryExportMappingDataResponse export_sentry_mapping_data( + TSentryExportMappingDataRequest request) throws TException { + TSentryExportMappingDataResponse response = new TSentryExportMappingDataResponse(); + try { + String requestor = request.getRequestorUserName(); + Set<String> memberGroups = getRequestorGroups(requestor); + if (!inAdminGroups(memberGroups)) { + // disallow non-admin to import the metadata of sentry + throw new SentryAccessDeniedException("Access denied to " + requestor + + " for export the metadata of sentry."); + } + TSentryMappingData tSentryMappingData = new TSentryMappingData(); + tSentryMappingData.setGroupRolesMap(sentryStore.getGroupNameRoleNamesMap()); + tSentryMappingData.setRolePrivilegesMap(sentryStore.getRoleNameTPrivilegesMap()); + response.setMappingData(tSentryMappingData); + response.setStatus(Status.OK()); + } catch (Exception e) { + String msg = "Unknown error for request: " + request + ", message: " + e.getMessage(); + LOGGER.error(msg, e); + response.setMappingData(new TSentryMappingData()); + response.setStatus(Status.RuntimeError(msg, e)); + } + return response; + } + + // import the sentry mapping data + @Override + public TSentryImportMappingDataResponse import_sentry_mapping_data( + TSentryImportMappingDataRequest request) throws TException { + TSentryImportMappingDataResponse response = new TSentryImportMappingDataResponse(); + try { + String requestor = request.getRequestorUserName(); + Set<String> memberGroups = getRequestorGroups(requestor); + if (!inAdminGroups(memberGroups)) { + // disallow non-admin to import the metadata of sentry + throw new SentryAccessDeniedException("Access denied to " + requestor + + " for import the metadata of sentry."); + } + sentryStore.importSentryMetaData(request.getMappingData(), request.isOverwriteRole()); + response.setStatus(Status.OK()); + } catch (SentryInvalidInputException e) { + String msg = "Invalid input privilege object"; + LOGGER.error(msg, e); + response.setStatus(Status.InvalidInput(msg, e)); + } catch (Exception e) { + String msg = "Unknown error for request: " + request + ", message: " + e.getMessage(); + LOGGER.error(msg, e); + response.setStatus(Status.RuntimeError(msg, e)); + } + return response; + } } http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/92cde111/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/SentryServiceUtil.java ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/SentryServiceUtil.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/SentryServiceUtil.java new file mode 100644 index 0000000..46798a0 --- /dev/null +++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/SentryServiceUtil.java @@ -0,0 +1,127 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.sentry.service.thrift; + +import java.util.List; + +import org.apache.commons.lang.StringUtils; +import org.apache.sentry.provider.common.KeyValue; +import org.apache.sentry.provider.common.PolicyFileConstants; +import org.apache.sentry.provider.common.ProviderConstants; +import org.apache.sentry.provider.db.service.thrift.TSentryGrantOption; +import org.apache.sentry.provider.db.service.thrift.TSentryPrivilege; +import org.apache.sentry.service.thrift.ServiceConstants.PrivilegeScope; + +import com.google.common.collect.Lists; + +public class SentryServiceUtil { + + // parse the privilege in String and get the TSentryPrivilege as result + public static TSentryPrivilege convertToTSentryPrivilege(String privilegeStr) { + TSentryPrivilege tSentryPrivilege = new TSentryPrivilege(); + for (String authorizable : ProviderConstants.AUTHORIZABLE_SPLITTER.split(privilegeStr)) { + KeyValue tempKV = new KeyValue(authorizable); + String key = tempKV.getKey(); + String value = tempKV.getValue(); + + if (PolicyFileConstants.PRIVILEGE_SERVER_NAME.equalsIgnoreCase(key)) { + tSentryPrivilege.setServerName(value); + } else if (PolicyFileConstants.PRIVILEGE_DATABASE_NAME.equalsIgnoreCase(key)) { + tSentryPrivilege.setDbName(value); + } else if (PolicyFileConstants.PRIVILEGE_TABLE_NAME.equalsIgnoreCase(key)) { + tSentryPrivilege.setTableName(value); + } else if (PolicyFileConstants.PRIVILEGE_COLUMN_NAME.equalsIgnoreCase(key)) { + tSentryPrivilege.setColumnName(value); + } else if (PolicyFileConstants.PRIVILEGE_URI_NAME.equalsIgnoreCase(key)) { + tSentryPrivilege.setURI(value); + } else if (PolicyFileConstants.PRIVILEGE_ACTION_NAME.equalsIgnoreCase(key)) { + tSentryPrivilege.setAction(value); + } else if (PolicyFileConstants.PRIVILEGE_GRANT_OPTION_NAME.equalsIgnoreCase(key)) { + TSentryGrantOption grantOption = "true".equalsIgnoreCase(value) ? TSentryGrantOption.TRUE + : TSentryGrantOption.FALSE; + tSentryPrivilege.setGrantOption(grantOption); + } + } + tSentryPrivilege.setPrivilegeScope(getPrivilegeScope(tSentryPrivilege)); + return tSentryPrivilege; + } + + // for the different hierarchy for hive: + // 1: server->url + // 2: server->database->table->column + // if both of them are found in the privilege string, the privilege scope will be set as + // PrivilegeScope.URI + public static String getPrivilegeScope(TSentryPrivilege tSentryPrivilege) { + PrivilegeScope privilegeScope = PrivilegeScope.SERVER; + if (!StringUtils.isEmpty(tSentryPrivilege.getURI())) { + privilegeScope = PrivilegeScope.URI; + } else if (!StringUtils.isEmpty(tSentryPrivilege.getColumnName())) { + privilegeScope = PrivilegeScope.COLUMN; + } else if (!StringUtils.isEmpty(tSentryPrivilege.getTableName())) { + privilegeScope = PrivilegeScope.TABLE; + } else if (!StringUtils.isEmpty(tSentryPrivilege.getDbName())) { + privilegeScope = PrivilegeScope.DATABASE; + } + return privilegeScope.toString(); + } + + // convert TSentryPrivilege to privilege in string + public static String convertTSentryPrivilegeToStr(TSentryPrivilege tSentryPrivilege) { + List<String> privileges = Lists.newArrayList(); + if (tSentryPrivilege != null) { + String serverName = tSentryPrivilege.getServerName(); + String dbName = tSentryPrivilege.getDbName(); + String tableName = tSentryPrivilege.getTableName(); + String columnName = tSentryPrivilege.getColumnName(); + String uri = tSentryPrivilege.getURI(); + String action = tSentryPrivilege.getAction(); + String grantOption = (tSentryPrivilege.getGrantOption() == TSentryGrantOption.TRUE ? "true" + : "false"); + if (!StringUtils.isEmpty(serverName)) { + privileges.add(ProviderConstants.KV_JOINER.join(PolicyFileConstants.PRIVILEGE_SERVER_NAME, + serverName)); + if (!StringUtils.isEmpty(uri)) { + privileges.add(ProviderConstants.KV_JOINER.join(PolicyFileConstants.PRIVILEGE_URI_NAME, + uri)); + } else if (!StringUtils.isEmpty(dbName)) { + privileges.add(ProviderConstants.KV_JOINER.join( + PolicyFileConstants.PRIVILEGE_DATABASE_NAME, dbName)); + if (!StringUtils.isEmpty(tableName)) { + privileges.add(ProviderConstants.KV_JOINER.join( + PolicyFileConstants.PRIVILEGE_TABLE_NAME, tableName)); + if (!StringUtils.isEmpty(columnName)) { + privileges.add(ProviderConstants.KV_JOINER.join( + PolicyFileConstants.PRIVILEGE_COLUMN_NAME, columnName)); + } + } + } + if (!StringUtils.isEmpty(action)) { + privileges.add(ProviderConstants.KV_JOINER.join( + PolicyFileConstants.PRIVILEGE_ACTION_NAME, action)); + } + } + // only append the grant option to privilege string if it's true + if ("true".equals(grantOption)) { + privileges.add(ProviderConstants.KV_JOINER.join( + PolicyFileConstants.PRIVILEGE_GRANT_OPTION_NAME, grantOption)); + } + } + return ProviderConstants.AUTHORIZABLE_JOINER.join(privileges); + } +} http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/92cde111/sentry-provider/sentry-provider-db/src/main/resources/sentry_policy_service.thrift ---------------------------------------------------------------------- diff --git a/sentry-provider/sentry-provider-db/src/main/resources/sentry_policy_service.thrift b/sentry-provider/sentry-provider-db/src/main/resources/sentry_policy_service.thrift index 5803cc4..40889e8 100644 --- a/sentry-provider/sentry-provider-db/src/main/resources/sentry_policy_service.thrift +++ b/sentry-provider/sentry-provider-db/src/main/resources/sentry_policy_service.thrift @@ -232,6 +232,33 @@ struct TSentryConfigValueResponse { 2: optional string value } +# struct for the mapping data like group to role, role to privilege +struct TSentryMappingData { +1: optional map<string, set<string>> groupRolesMap, # for the groupName -> role mapping +2: optional map<string, set<TSentryPrivilege>> rolePrivilegesMap # for the roleName -> privilege mapping +} + +struct TSentryExportMappingDataRequest { +1: required i32 protocol_version = sentry_common_service.TSENTRY_SERVICE_V1, +2: required string requestorUserName # user on whose behalf the request is issued +} + +struct TSentryExportMappingDataResponse { +1: required sentry_common_service.TSentryResponseStatus status, +2: required TSentryMappingData mappingData +} + +struct TSentryImportMappingDataRequest { +1: required i32 protocol_version = sentry_common_service.TSENTRY_SERVICE_V1, +2: required string requestorUserName, # user on whose behalf the request is issued +3: required bool overwriteRole = false, # if overwrite the exist role with the imported privileges, default is false +4: required TSentryMappingData mappingData +} + +struct TSentryImportMappingDataResponse { +1: required sentry_common_service.TSentryResponseStatus status +} + service SentryPolicyService { TCreateSentryRoleResponse create_sentry_role(1:TCreateSentryRoleRequest request) @@ -250,11 +277,17 @@ service SentryPolicyService # For use with ProviderBackend.getPrivileges only TListSentryPrivilegesForProviderResponse list_sentry_privileges_for_provider(1:TListSentryPrivilegesForProviderRequest request) - TDropPrivilegesResponse drop_sentry_privilege(1:TDropPrivilegesRequest request); + TDropPrivilegesResponse drop_sentry_privilege(1:TDropPrivilegesRequest request); + + TRenamePrivilegesResponse rename_sentry_privilege(1:TRenamePrivilegesRequest request); + + TListSentryPrivilegesByAuthResponse list_sentry_privileges_by_authorizable(1:TListSentryPrivilegesByAuthRequest request); - TRenamePrivilegesResponse rename_sentry_privilege(1:TRenamePrivilegesRequest request); + TSentryConfigValueResponse get_sentry_config_value(1:TSentryConfigValueRequest request); - TListSentryPrivilegesByAuthResponse list_sentry_privileges_by_authorizable(1:TListSentryPrivilegesByAuthRequest request); + # export the mapping data in sentry + TSentryExportMappingDataResponse export_sentry_mapping_data(1:TSentryExportMappingDataRequest request); - TSentryConfigValueResponse get_sentry_config_value(1:TSentryConfigValueRequest request) + # import the mapping data in sentry + TSentryImportMappingDataResponse import_sentry_mapping_data(1:TSentryImportMappingDataRequest request); }
