blob: 4dfe72aed35a8e51766ca94c6271625a8124dd8b [file] [log] [blame]
/*
* 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.ranger.patch;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.ranger.authorization.utils.JsonUtils;
import org.apache.ranger.biz.PolicyRefUpdater;
import org.apache.ranger.biz.ServiceDBStore;
import org.apache.ranger.biz.XUserMgr;
import org.apache.ranger.db.RangerDaoManager;
import org.apache.ranger.db.XXGroupDao;
import org.apache.ranger.db.XXPolicyDao;
import org.apache.ranger.db.XXPolicyRefAccessTypeDao;
import org.apache.ranger.db.XXPolicyRefConditionDao;
import org.apache.ranger.db.XXPolicyRefDataMaskTypeDao;
import org.apache.ranger.db.XXPolicyRefGroupDao;
import org.apache.ranger.db.XXPolicyRefResourceDao;
import org.apache.ranger.db.XXPolicyRefUserDao;
import org.apache.ranger.db.XXUserDao;
import org.apache.ranger.entity.XXAccessTypeDef;
import org.apache.ranger.entity.XXDataMaskTypeDef;
import org.apache.ranger.entity.XXGroup;
import org.apache.ranger.entity.XXPolicy;
import org.apache.ranger.entity.XXPolicyConditionDef;
import org.apache.ranger.entity.XXPolicyRefAccessType;
import org.apache.ranger.entity.XXPolicyRefCondition;
import org.apache.ranger.entity.XXPolicyRefDataMaskType;
import org.apache.ranger.entity.XXPolicyRefGroup;
import org.apache.ranger.entity.XXPolicyRefResource;
import org.apache.ranger.entity.XXPolicyRefUser;
import org.apache.ranger.entity.XXResourceDef;
import org.apache.ranger.entity.XXServiceDef;
import org.apache.ranger.entity.XXUser;
import org.apache.ranger.plugin.model.RangerPolicy;
import org.apache.ranger.plugin.model.RangerPolicy.RangerDataMaskPolicyItem;
import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItem;
import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemAccess;
import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemCondition;
import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyResource;
import org.apache.ranger.plugin.model.RangerService;
import org.apache.ranger.util.CLIUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
/**
* Consolidates Ranger policy details into a JSON string and stores it into a
* column in x_policy table After running this patch Ranger policy can be
* completely read/saved into x_policy table and some related Ref tables (which
* maintain ID->String mapping for each policy).
*
*/
@Component
public class PatchForMigratingOldRegimePolicyJson_J10046 extends BaseLoader {
private static final Logger logger = LoggerFactory.getLogger(PatchForMigratingOldRegimePolicyJson_J10046.class);
@Autowired
RangerDaoManager daoMgr;
@Autowired
ServiceDBStore svcStore;
@Autowired
@Qualifier(value = "transactionManager")
PlatformTransactionManager txManager;
@Autowired
PolicyRefUpdater policyRefUpdater;
@Autowired
XUserMgr xUserMgr;
private final Map<String, Long> groupIdMap = new HashMap<>();
private final Map<String, Long> userIdMap = new HashMap<>();
private final Map<String, Map<String, Long>> resourceNameIdMap = new HashMap<>();
private final Map<String, Map<String, Long>> accessTypeIdMap = new HashMap<>();
private final Map<String, Map<String, Long>> conditionNameIdMap = new HashMap<>();
private final Map<String, Map<String, Long>> dataMaskTypeIdMap = new HashMap<>();
public static void main(String[] args) {
logger.info("main()");
try {
PatchForMigratingOldRegimePolicyJson_J10046 loader = (PatchForMigratingOldRegimePolicyJson_J10046) CLIUtil.getBean(PatchForMigratingOldRegimePolicyJson_J10046.class);
loader.init();
while (loader.isMoreToProcess()) {
loader.load();
}
logger.info("Load complete. Exiting!!!");
System.exit(0);
} catch (Exception e) {
logger.error("Error loading", e);
System.exit(1);
}
}
@Override
public void init() throws Exception {
// Do Nothing
}
@Override
public void execLoad() {
logger.info("==> PatchForMigratingOldRegimePolicyJson.execLoad()");
try {
migrateRangerPolicyTableWithPolicyJson();
} catch (Exception e) {
logger.error("Error while PatchForMigratingOldRegimePolicyJson()", e);
System.exit(1);
}
logger.info("<== PatchForMigratingOldRegimePolicyJson.execLoad()");
}
@Override
public void printStats() {
logger.info("Migrating OldRegimePolicyJson data ");
}
private void migrateRangerPolicyTableWithPolicyJson() throws Exception {
logger.info("==> updateRangerPolicyTableWithPolicyJson() ");
List<XXPolicy> xxPolicyList = daoMgr.getXXPolicy().getAllByPolicyItem();
if (CollectionUtils.isNotEmpty(xxPolicyList)) {
for (XXPolicy xxPolicy : xxPolicyList) {
logger.info("XXPolicy : " + xxPolicy);
RangerPolicy policy = svcStore.getPolicy(xxPolicy.getId());
if (policy != null) {
TransactionTemplate txTemplate = new TransactionTemplate(txManager);
RangerService service = svcStore.getServiceByName(policy.getService());
PolicyUpdaterThread updaterThread = new PolicyUpdaterThread(txTemplate, service, policy);
updaterThread.setDaemon(true);
updaterThread.start();
updaterThread.join();
String errorMsg = updaterThread.getErrorMsg();
if (StringUtils.isNotEmpty(errorMsg)) {
throw new Exception(errorMsg);
}
}
}
} else {
logger.info("no old XXPolicyItems found ");
}
logger.info("<== updateRangerPolicyTableWithPolicyJson() ");
}
public Boolean cleanupOldRefTables(RangerPolicy policy) {
final Long policyId = policy == null ? null : policy.getId();
if (policyId == null) {
return false;
}
logger.info("==> cleanupOldRefTables() ");
daoMgr.getXXPolicyItemGroupPerm().deleteByPolicyId(policyId);
daoMgr.getXXPolicyItemUserPerm().deleteByPolicyId(policyId);
daoMgr.getXXPolicyItemAccess().deleteByPolicyId(policyId);
daoMgr.getXXPolicyItemCondition().deleteByPolicyId(policyId);
daoMgr.getXXPolicyItemDataMaskInfo().deleteByPolicyId(policyId);
daoMgr.getXXPolicyItemRowFilterInfo().deleteByPolicyId(policyId);
daoMgr.getXXPolicyItem().deleteByPolicyId(policyId);
daoMgr.getXXPolicyResourceMap().deleteByPolicyId(policyId);
daoMgr.getXXPolicyResource().deleteByPolicyId(policyId);
logger.info("<== cleanupOldRefTables() ");
return true;
}
private class PolicyUpdaterThread extends Thread {
final TransactionTemplate txTemplate;
final RangerService service;
final RangerPolicy policy;
String errorMsg;
PolicyUpdaterThread(TransactionTemplate txTemplate, final RangerService service, final RangerPolicy policy) {
this.txTemplate = txTemplate;
this.service = service;
this.policy = policy;
this.errorMsg = null;
}
public String getErrorMsg() {
return errorMsg;
}
@Override
public void run() {
errorMsg = txTemplate.execute(new TransactionCallback<String>() {
@Override
public String doInTransaction(TransactionStatus status) {
String ret = null;
try {
policyRefUpdater.cleanupRefTables(policy);
portPolicy(service.getType(), policy);
cleanupOldRefTables(policy);
} catch (Throwable e) {
logger.error("PortPolicy failed for policy:[" + policy + "]", e);
ret = e.toString();
}
return ret;
}
});
}
}
private void portPolicy(String serviceType, RangerPolicy policy) throws Exception {
logger.info("==> portPolicy(id=" + policy.getId() + ")");
String policyText = JsonUtils.objectToJson(policy);
if (StringUtils.isEmpty(policyText)) {
throw new Exception("Failed to convert policy to json string. Policy: [id=" + policy.getId() + "; name=" + policy.getName() + "; serviceType=" + serviceType + "]");
}
XXPolicyDao policyDao = daoMgr.getXXPolicy();
XXPolicy dbBean = policyDao.getById(policy.getId());
dbBean.setPolicyText(policyText);
policyDao.update(dbBean);
try {
Set<String> accesses = new HashSet<>();
Set<String> users = new HashSet<>();
Set<String> groups = new HashSet<>();
Set<String> conditions = new HashSet<>();
Set<String> dataMasks = new HashSet<>();
buildLists(policy.getPolicyItems(), accesses, conditions, users, groups);
buildLists(policy.getDenyPolicyItems(), accesses, conditions, users, groups);
buildLists(policy.getAllowExceptions(), accesses, conditions, users, groups);
buildLists(policy.getDenyExceptions(), accesses, conditions, users, groups);
buildLists(policy.getDataMaskPolicyItems(), accesses, conditions, users, groups);
buildLists(policy.getRowFilterPolicyItems(), accesses, conditions, users, groups);
buildList(policy.getDataMaskPolicyItems(), dataMasks);
addResourceDefRef(serviceType, policy);
addUserNameRef(policy.getId(), users);
addGroupNameRef(policy.getId(), groups);
addAccessDefRef(serviceType, policy.getId(), accesses);
addPolicyConditionDefRef(serviceType, policy.getId(), conditions);
addDataMaskDefRef(serviceType, policy.getId(), dataMasks);
} catch (Exception e) {
logger.error("portPoliry(id=" + policy.getId() +") failed!!");
logger.error("Offending policy:" + policyText);
throw e;
}
logger.info("<== portPolicy(id=" + policy.getId() + ")");
}
private void addResourceDefRef(String serviceType, RangerPolicy policy) throws Exception {
logger.info("==> addResourceDefRef(id=" + policy.getId() + ")");
Map<String, Long> serviceDefResourceNameIDMap = resourceNameIdMap.get(serviceType);
if (serviceDefResourceNameIDMap == null) {
serviceDefResourceNameIDMap = new HashMap<>();
resourceNameIdMap.put(serviceType, serviceDefResourceNameIDMap);
XXServiceDef dbServiceDef = daoMgr.getXXServiceDef().findByName(serviceType);
if (dbServiceDef != null) {
for (XXResourceDef resourceDef : daoMgr.getXXResourceDef().findByServiceDefId(dbServiceDef.getId())) {
serviceDefResourceNameIDMap.put(resourceDef.getName(), resourceDef.getId());
}
}
}
Map<String, RangerPolicyResource> policyResources = policy.getResources();
if (MapUtils.isNotEmpty(policyResources)) {
XXPolicyRefResourceDao policyRefResourceDao = daoMgr.getXXPolicyRefResource();
Set<String> resourceNames = policyResources.keySet();
for (String resourceName : resourceNames) {
Long resourceDefId = serviceDefResourceNameIDMap.get(resourceName);
if (resourceDefId == null) {
throw new Exception(resourceName + ": unknown resource in policy [id=" + policy.getId() + "; name=" + policy.getName() + "; serviceType=" + serviceType + "]. Known resources: " + serviceDefResourceNameIDMap.keySet());
}
// insert policy-id, resourceDefId, resourceName into Ref table
XXPolicyRefResource policyRefResource = new XXPolicyRefResource();
policyRefResource.setPolicyId(policy.getId());
policyRefResource.setResourceDefId(resourceDefId);
policyRefResource.setResourceName(resourceName);
policyRefResourceDao.create(policyRefResource);
}
}
logger.info("<== addResourceDefRef(id=" + policy.getId() + ")");
}
private void addUserNameRef(Long policyId, Set<String> users) throws Exception {
logger.info("==> addUserNameRef(id=" + policyId + ")");
XXPolicyRefUserDao policyRefUserDao = daoMgr.getXXPolicyRefUser();
XXUserDao userDao = daoMgr.getXXUser();
// insert policy-id, userName into Ref table
for (String user : users) {
Long userId = userIdMap.get(user);
if (userId == null) {
XXUser userObject = userDao.findByUserName(user);
if (userObject == null) {
logger.info(user +" user is not found, adding user: "+user);
TransactionTemplate txTemplate = new TransactionTemplate(txManager);
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
try {
txTemplate.execute(new TransactionCallback<Object>() {
@Override
public Object doInTransaction(TransactionStatus status) {
xUserMgr.createServiceConfigUserSynchronously(user);
return null;
}
});
} catch(Exception exception) {
logger.error("Cannot create ServiceConfigUser(" + user + ")", exception);
}
userObject = userDao.findByUserName(user);
if (userObject == null) {
throw new Exception(user + ": unknown user in policy [id=" + policyId + "]");
}
}
userId = userObject.getId();
logger.info("userId:"+userId);
userIdMap.put(user, userId);
}
XXPolicyRefUser policyRefUser = new XXPolicyRefUser();
policyRefUser.setPolicyId(policyId);
policyRefUser.setUserName(user);
policyRefUser.setUserId(userId);
policyRefUserDao.create(policyRefUser);
}
logger.info("<== addUserNameRef(id=" + policyId + ")");
}
private void addGroupNameRef(Long policyId, Set<String> groups) throws Exception {
logger.info("==> addGroupNameRef(id=" + policyId + ")");
// insert policy-id, groupName into Ref table
XXPolicyRefGroupDao policyRefGroupDao = daoMgr.getXXPolicyRefGroup();
XXGroupDao groupDao = daoMgr.getXXGroup();
for (String group : groups) {
Long groupId = groupIdMap.get(group);
if (groupId == null) {
XXGroup groupObject = groupDao.findByGroupName(group);
if (groupObject == null) {
throw new Exception(group + ": unknown group in policy [id=" + policyId + "]");
}
groupId = groupObject.getId();
groupIdMap.put(group, groupId);
}
XXPolicyRefGroup policyRefGroup = new XXPolicyRefGroup();
policyRefGroup.setPolicyId(policyId);
policyRefGroup.setGroupName(group);
policyRefGroup.setGroupId(groupId);
policyRefGroupDao.create(policyRefGroup);
}
logger.info("<== addGroupNameRef(id=" + policyId + ")");
}
private void addAccessDefRef(String serviceType, Long policyId, Set<String> accesses) throws Exception {
logger.info("==> addAccessDefRef(id=" + policyId + ")");
// insert policy-id, accessName into Ref table
Map<String, Long> serviceDefAccessTypeIDMap = accessTypeIdMap.get(serviceType);
if (serviceDefAccessTypeIDMap == null) {
serviceDefAccessTypeIDMap = new HashMap<>();
accessTypeIdMap.put(serviceType, serviceDefAccessTypeIDMap);
XXServiceDef dbServiceDef = daoMgr.getXXServiceDef().findByName(serviceType);
if (dbServiceDef != null) {
for (XXAccessTypeDef accessTypeDef : daoMgr.getXXAccessTypeDef().findByServiceDefId(dbServiceDef.getId())) {
serviceDefAccessTypeIDMap.put(accessTypeDef.getName(), accessTypeDef.getId());
}
}
}
XXPolicyRefAccessTypeDao policyRefAccessTypeDao = daoMgr.getXXPolicyRefAccessType();
for (String access : accesses) {
Long accessTypeDefId = serviceDefAccessTypeIDMap.get(access);
if (accessTypeDefId == null) {
throw new Exception(access + ": unknown accessType in policy [id=" + policyId + "; serviceType=" + serviceType + "]. Known accessTypes: " + serviceDefAccessTypeIDMap.keySet());
}
XXPolicyRefAccessType policyRefAccessType = new XXPolicyRefAccessType();
policyRefAccessType.setPolicyId(policyId);
policyRefAccessType.setAccessTypeName(access);
policyRefAccessType.setAccessDefId(accessTypeDefId);
policyRefAccessTypeDao.create(policyRefAccessType);
}
logger.info("<== addAccessDefRef(id=" + policyId + ")");
}
private void addPolicyConditionDefRef(String serviceType, Long policyId, Set<String> conditions) throws Exception {
logger.info("==> addPolicyConditionDefRef(id=" + policyId + ")");
// insert policy-id, conditionName into Ref table
Map<String, Long> serviceDefConditionNameIDMap = conditionNameIdMap.get(serviceType);
if (serviceDefConditionNameIDMap == null) {
serviceDefConditionNameIDMap = new HashMap<>();
conditionNameIdMap.put(serviceType, serviceDefConditionNameIDMap);
XXServiceDef dbServiceDef = daoMgr.getXXServiceDef().findByName(serviceType);
if (dbServiceDef != null) {
for (XXPolicyConditionDef conditionDef : daoMgr.getXXPolicyConditionDef().findByServiceDefId(dbServiceDef.getId())) {
serviceDefConditionNameIDMap.put(conditionDef.getName(), conditionDef.getId());
}
}
}
XXPolicyRefConditionDao policyRefConditionDao = daoMgr.getXXPolicyRefCondition();
for (String condition : conditions) {
Long conditionDefId = serviceDefConditionNameIDMap.get(condition);
if (conditionDefId == null) {
throw new Exception(condition + ": unknown condition in policy [id=" + policyId + "; serviceType=" + serviceType + "]. Known conditions are: " + serviceDefConditionNameIDMap.keySet());
}
XXPolicyRefCondition policyRefCondition = new XXPolicyRefCondition();
policyRefCondition.setPolicyId(policyId);
policyRefCondition.setConditionName(condition);
policyRefCondition.setConditionDefId(conditionDefId);
policyRefConditionDao.create(policyRefCondition);
}
logger.info("<== addPolicyConditionDefRef(id=" + policyId + ")");
}
private void addDataMaskDefRef(String serviceType, Long policyId, Set<String> datamasks) throws Exception {
logger.info("==> addDataMaskDefRef(id=" + policyId + ")");
// insert policy-id, datamaskName into Ref table
Map<String, Long> serviceDefDataMaskTypeIDMap = dataMaskTypeIdMap.get(serviceType);
if (serviceDefDataMaskTypeIDMap == null) {
serviceDefDataMaskTypeIDMap = new HashMap<>();
dataMaskTypeIdMap.put(serviceType, serviceDefDataMaskTypeIDMap);
XXServiceDef dbServiceDef = daoMgr.getXXServiceDef().findByName(serviceType);
if (dbServiceDef != null) {
for (XXDataMaskTypeDef dataMaskTypeDef : daoMgr.getXXDataMaskTypeDef().findByServiceDefId(dbServiceDef.getId())) {
serviceDefDataMaskTypeIDMap.put(dataMaskTypeDef.getName(), dataMaskTypeDef.getId());
}
}
}
XXPolicyRefDataMaskTypeDao policyRefDataMaskTypeDao = daoMgr.getXXPolicyRefDataMaskType();
for (String datamask : datamasks) {
Long dataMaskTypeId = serviceDefDataMaskTypeIDMap.get(datamask);
if (dataMaskTypeId == null) {
throw new Exception(datamask + ": unknown dataMaskType in policy [id=" + policyId + "; serviceType=" + serviceType + "]. Known dataMaskTypes " + serviceDefDataMaskTypeIDMap.keySet());
}
XXPolicyRefDataMaskType policyRefDataMaskType = new XXPolicyRefDataMaskType();
policyRefDataMaskType.setPolicyId(policyId);
policyRefDataMaskType.setDataMaskTypeName(datamask);
policyRefDataMaskType.setDataMaskDefId(dataMaskTypeId);
policyRefDataMaskTypeDao.create(policyRefDataMaskType);
}
logger.info("<== addDataMaskDefRef(id=" + policyId + ")");
}
private void buildLists(List<? extends RangerPolicyItem> policyItems, Set<String> accesses, Set<String> conditions, Set<String> users, Set<String> groups) {
for (RangerPolicyItem item : policyItems) {
for (RangerPolicyItemAccess policyAccess : item.getAccesses()) {
accesses.add(policyAccess.getType());
}
for (RangerPolicyItemCondition policyCondition : item.getConditions()) {
conditions.add(policyCondition.getType());
}
users.addAll(item.getUsers());
groups.addAll(item.getGroups());
}
}
private void buildList(List<RangerDataMaskPolicyItem> dataMaskPolicyItems, Set<String> dataMasks) {
for (RangerDataMaskPolicyItem datMaskPolicyItem : dataMaskPolicyItems) {
dataMasks.add(datMaskPolicyItem.getDataMaskInfo().getDataMaskType());
}
}
}