blob: 81c720d3f894e30543473bd18c9689b8784276a0 [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.service;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.ranger.common.AppConstants;
import org.apache.ranger.common.JSONUtil;
import org.apache.ranger.common.MessageEnums;
import org.apache.ranger.plugin.util.PasswordUtils;
import org.apache.ranger.common.PropertiesUtil;
import org.apache.ranger.common.SearchField;
import org.apache.ranger.common.SearchField.DATA_TYPE;
import org.apache.ranger.common.SearchField.SEARCH_TYPE;
import org.apache.ranger.common.StringUtil;
import org.apache.ranger.common.view.VTrxLogAttr;
import org.apache.ranger.db.RangerDaoManager;
import org.apache.ranger.entity.XXAsset;
import org.apache.ranger.entity.XXTrxLog;
import org.apache.ranger.util.RangerEnumUtil;
import org.apache.ranger.view.VXAsset;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
@Service
@Scope("singleton")
public class XAssetService extends XAssetServiceBase<XXAsset, VXAsset> {
@Autowired
JSONUtil jsonUtil;
@Autowired
RangerDaoManager appDaoMgr;
@Autowired
StringUtil stringUtil;
static HashMap<String, VTrxLogAttr> trxLogAttrs = new HashMap<String, VTrxLogAttr>();
static {
trxLogAttrs.put("name", new VTrxLogAttr("name", "Repository Name", false));
trxLogAttrs.put("description", new VTrxLogAttr("description", "Repository Description", false));
trxLogAttrs.put("activeStatus", new VTrxLogAttr("activeStatus", "Repository Status", true));
trxLogAttrs.put("config", new VTrxLogAttr("config", "Connection Configurations", false));
}
private String hiddenPasswordString;
@Autowired
RangerEnumUtil xaEnumUtil;
public XAssetService(){
super();
hiddenPasswordString = PropertiesUtil.getProperty("ranger.password.hidden", "*****");
searchFields.add(new SearchField("status", "obj.activeStatus",
SearchField.DATA_TYPE.INT_LIST, SearchField.SEARCH_TYPE.FULL));
searchFields.add(new SearchField("name", "obj.name", DATA_TYPE.STRING,
SEARCH_TYPE.PARTIAL));
searchFields.add(new SearchField("type", "obj.assetType",
DATA_TYPE.INTEGER, SEARCH_TYPE.FULL));
}
@Override
protected void validateForCreate(VXAsset vObj) {
XXAsset xxAsset = appDaoMgr.getXXAsset()
.findByAssetName(vObj.getName());
if (xxAsset != null) {
String errorMessage = "Repository Name already exists";
throw restErrorUtil.createRESTException(errorMessage,
MessageEnums.INVALID_INPUT_DATA, null, null,
vObj.toString());
}
if(vObj.getName()==null || vObj.getName().trim().length()==0){
String errorMessage = "Repository Name can't be empty";
throw restErrorUtil.createRESTException(errorMessage,
MessageEnums.INVALID_INPUT_DATA, null, null,
vObj.toString());
}
validateConfig(vObj);
}
@Override
protected void validateForUpdate(VXAsset vObj, XXAsset mObj) {
if (!vObj.getName().equalsIgnoreCase(mObj.getName())) {
validateForCreate(vObj);
}else{
validateConfig(vObj);
}
}
@Override
protected XXAsset mapViewToEntityBean(VXAsset vObj, XXAsset mObj,
int OPERATION_CONTEXT) {
if (vObj != null && mObj != null) {
String oldConfig = mObj.getConfig();
super.mapViewToEntityBean(vObj, mObj, OPERATION_CONTEXT);
String config = vObj.getConfig();
if (config != null && !config.isEmpty()) {
Map<String, String> configMap = jsonUtil.jsonToMap(config);
Entry<String, String> passwordEntry = getPasswordEntry(configMap);
if (passwordEntry != null) {
// If "*****" then get password from db and update
String password = passwordEntry.getValue();
if (password != null) {
if (password.equals(hiddenPasswordString)) {
if (oldConfig != null && !oldConfig.isEmpty()) {
Map<String, String> oldConfigMap = jsonUtil
.jsonToMap(oldConfig);
Entry<String, String> oldPasswordEntry
= getPasswordEntry(oldConfigMap);
if (oldPasswordEntry != null) {
configMap.put(oldPasswordEntry.getKey(),
oldPasswordEntry.getValue());
}
}
}
config = jsonUtil.readMapToString(configMap);
}
}
}
mObj.setConfig(config);
}
return mObj;
}
@Override
protected VXAsset mapEntityToViewBean(VXAsset vObj, XXAsset mObj) {
vObj = super.mapEntityToViewBean(vObj, mObj);
String config = vObj.getConfig();
if (config != null && !config.isEmpty()) {
Map<String, String> configMap = jsonUtil.jsonToMap(config);
Entry<String, String> passwordEntry = getPasswordEntry(configMap);
if (passwordEntry != null) {
configMap.put(passwordEntry.getKey(), hiddenPasswordString);
}
config = jsonUtil.readMapToString(configMap);
}
vObj.setConfig(config);
return vObj;
}
private Entry<String, String> getPasswordEntry(Map<String, String> configMap) {
Entry<String, String> entry = null;
for(Entry<String, String> e : configMap.entrySet()) {
if(e.getKey().toLowerCase().contains("password")){
entry = e;
break;
}
}
return entry;
}
private Entry<String, String> getIsEncryptedEntry(Map<String, String> configMap){
Entry<String, String> entry = null;
for(Entry<String, String> e : configMap.entrySet()) {
if(e.getKey().toLowerCase().contains("isencrypted")){
entry = e;
break;
}
}
return entry;
}
public void validateConfig(VXAsset vObj) {
HashMap<String, Object> configrationMap = null;
if (vObj.getAssetType() == AppConstants.ASSET_HDFS) {
ObjectMapper objectMapper = new ObjectMapper();
TypeReference<HashMap<String, Object>> typeRef = new TypeReference
<HashMap<String, Object>>() {};
try {
configrationMap = objectMapper.readValue(vObj.getConfig(),
typeRef);
} catch (Exception e) {
logger.error("Error in config json", e);
}
if (configrationMap != null) {
String fs_default_name = configrationMap.get("fs.default.name")
.toString();
if (fs_default_name.isEmpty()) {
throw restErrorUtil.createRESTException(
"serverMsg.fsDefaultNameEmptyError",
MessageEnums.INVALID_INPUT_DATA, null, "fs.default.name",
vObj.toString());
}
/*String expression="^+(hdfs://)\\s*(.*?):[0-9]{1,5}";
// String expression = "^+(hdfs://)[a-z,A-Z,0-9,.]*+:[0-9]{1,5}";
Pattern pattern = Pattern.compile(expression,
Pattern.CASE_INSENSITIVE);
// String inputStr = "hdfs://192.168.1.16:2";
Matcher matcher = pattern.matcher(fs_default_name);
if (!matcher.matches()) {
throw restErrorUtil.createRESTException(
"serverMsg.fsDefaultNameValidationError",
MessageEnums.INVALID_INPUT_DATA, null, "fs.default.name",
vObj.toString());
}*/
}
}
}
public List<XXTrxLog> getTransactionLog(VXAsset vResource, String action){
return getTransactionLog(vResource, null, action);
}
public List<XXTrxLog> getTransactionLog(VXAsset vObj, XXAsset mObj, String action){
if(vObj == null ||action == null || (action.equalsIgnoreCase("update") && mObj == null)){
return null;
}
List<XXTrxLog> trxLogList = new ArrayList<XXTrxLog>();
Field[] fields = vObj.getClass().getDeclaredFields();
try {
Field nameField = vObj.getClass().getDeclaredField("name");
nameField.setAccessible(true);
String objectName = ""+nameField.get(vObj);
for(Field field : fields){
field.setAccessible(true);
String fieldName = field.getName();
if(!trxLogAttrs.containsKey(fieldName)){
continue;
}
VTrxLogAttr vTrxLogAttr = trxLogAttrs.get(fieldName);
XXTrxLog xTrxLog = new XXTrxLog();
xTrxLog.setAttributeName(vTrxLogAttr.getAttribUserFriendlyName());
String value = null;
boolean isEnum = vTrxLogAttr.isEnum();
if(isEnum){
String enumName = XXAsset.getEnumName(fieldName);
int enumValue = field.get(vObj) == null ? 0 : Integer.parseInt(""+field.get(vObj));
value = xaEnumUtil.getLabel(enumName, enumValue);
} else {
value = ""+field.get(vObj);
}
if(action.equalsIgnoreCase("create")){
if(stringUtil.isEmpty(value)){
continue;
}
xTrxLog.setNewValue(value);
} else if(action.equalsIgnoreCase("delete")){
xTrxLog.setPreviousValue(value);
} else if(action.equalsIgnoreCase("update")){
String oldValue = null;
Field[] mFields = mObj.getClass().getDeclaredFields();
for(Field mField : mFields){
mField.setAccessible(true);
String mFieldName = mField.getName();
if(fieldName.equalsIgnoreCase(mFieldName)){
if(isEnum){
String enumName = XXAsset.getEnumName(mFieldName);
int enumValue = mField.get(mObj) == null ? 0 : Integer.parseInt(""+mField.get(mObj));
oldValue = xaEnumUtil.getLabel(enumName, enumValue);
} else {
oldValue = mField.get(mObj)+"";
}
break;
}
}
if(fieldName.equalsIgnoreCase("config")){
Map<String, String> vConfig = jsonUtil.jsonToMap(value);
Map<String, String> xConfig = jsonUtil.jsonToMap(oldValue);
Map<String, String> newConfig = new HashMap<String, String>();
Map<String, String> oldConfig = new HashMap<String, String>();
for (Entry<String, String> entry: vConfig.entrySet()) {
String key = entry.getKey();
if (!xConfig.containsKey(key)) {
newConfig.put(key, entry.getValue());
} else if(!entry.getValue().equalsIgnoreCase(xConfig.get(key))){
if(key.equalsIgnoreCase("password") && entry
.getValue().equalsIgnoreCase(hiddenPasswordString)){
continue;
}
newConfig.put(key, entry.getValue());
oldConfig.put(key, xConfig.get(key));
}
}
oldValue = jsonUtil.readMapToString(oldConfig);
value = jsonUtil.readMapToString(newConfig);
}
if(value.equalsIgnoreCase(oldValue)){
continue;
}
xTrxLog.setPreviousValue(oldValue);
xTrxLog.setNewValue(value);
}
xTrxLog.setAction(action);
xTrxLog.setObjectClassType(AppConstants.CLASS_TYPE_XA_ASSET);
xTrxLog.setObjectId(vObj.getId());
xTrxLog.setObjectName(objectName);
trxLogList.add(xTrxLog);
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
}
return trxLogList;
}
public String getConfigWithEncryptedPassword(String config,boolean isForced){
try {
if (config != null && !config.isEmpty()) {
Map<String, String> configMap = jsonUtil.jsonToMap(config);
Entry<String, String> passwordEntry = getPasswordEntry(configMap);
Entry<String, String> isEncryptedEntry = getIsEncryptedEntry(configMap);
if (passwordEntry != null){
if(isEncryptedEntry==null || !isEncryptedEntry.getValue().equalsIgnoreCase("true")||isForced==true){
String password=passwordEntry.getValue();
String encryptPassword=PasswordUtils.encryptPassword(password);
String decryptPassword=PasswordUtils.decryptPassword(encryptPassword);
if(decryptPassword != null && decryptPassword.equalsIgnoreCase(password)){
configMap.put(passwordEntry.getKey(),
encryptPassword);
configMap.put("isencrypted", "true");
}
}
}
config = jsonUtil.readMapToString(configMap);
}
} catch (IOException e) {
String errorMessage = "Password encryption error";
throw restErrorUtil.createRESTException(errorMessage,
MessageEnums.INVALID_INPUT_DATA, null, null,
e.getMessage());
}
return config;
}
public String getConfigWithDecryptedPassword(String config){
try {
if (config != null && !config.isEmpty()) {
Map<String, String> configMap = jsonUtil.jsonToMap(config);
Entry<String, String> passwordEntry = getPasswordEntry(configMap);
Entry<String, String> isEncryptedEntry = getIsEncryptedEntry(configMap);
if (isEncryptedEntry!=null && passwordEntry != null){
if (!stringUtil.isEmpty(isEncryptedEntry.getValue())
&& isEncryptedEntry.getValue().equalsIgnoreCase(
"true")) {
String encryptPassword = passwordEntry.getValue();
String decryptPassword = PasswordUtils
.decryptPassword(encryptPassword);
configMap.put(passwordEntry.getKey(), decryptPassword);
}
}
config = jsonUtil.readMapToString(configMap);
}
} catch (IOException e) {
String errorMessage = "Password decryption error";
throw restErrorUtil.createRESTException(errorMessage,
MessageEnums.INVALID_INPUT_DATA, null, null,
e.getMessage());
}
return config;
}
}