blob: d85ee2be06790da6dd2be902b7fae4bd66cbc419 [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.authorization.hive.udf;
import java.sql.Date;
import org.apache.hadoop.hive.ql.exec.Description;
import org.apache.hadoop.hive.serde2.io.ShortWritable;
import org.apache.hadoop.hive.serde2.objectinspector.ConstantObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.*;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
@Description(name = "mask",
value = "masks the given value",
extended = "Examples:\n "
+ " mask(ccn)\n "
+ " mask(ccn, 'X', 'x', '0')\n "
+ " mask(ccn, 'x', 'x', 'x')\n "
+ "Arguments:\n "
+ " mask(value, upperChar, lowerChar, digitChar, otherChar, numberChar, dayValue, monthValue, yearValue)\n "
+ " value - value to mask. Supported types: TINYINT, SMALLINT, INT, BIGINT, STRING, VARCHAR, CHAR, DATE\n "
+ " upperChar - character to replace upper-case characters with. Specify -1 to retain original character. Default value: 'X'\n "
+ " lowerChar - character to replace lower-case characters with. Specify -1 to retain original character. Default value: 'x'\n "
+ " digitChar - character to replace digit characters with. Specify -1 to retain original character. Default value: 'n'\n "
+ " otherChar - character to replace all other characters with. Specify -1 to retain original character. Default value: -1\n "
+ " numberChar - character to replace digits in a number with. Valid values: 0-9. Default value: '1'\n "
+ " dayValue - value to replace day field in a date with. Specify -1 to retain original value. Valid values: 1-31. Default value: 1\n "
+ " monthValue - value to replace month field in a date with. Specify -1 to retain original value. Valid values: 0-11. Default value: 0\n "
+ " yearValue - value to replace year field in a date with. Specify -1 to retain original value. Default value: 0\n "
)
public class RangerUdfMask extends RangerBaseUdf {
public static final String UDF_NAME = "mask";
public RangerUdfMask() {
super(new MaskTransformer(), UDF_NAME);
}
}
class MaskTransformer extends AbstractTransformer {
final static int MASKED_UPPERCASE = 'X';
final static int MASKED_LOWERCASE = 'x';
final static int MASKED_DIGIT = 'n';
final static int MASKED_OTHER_CHAR = -1;
final static int MASKED_NUMBER = 1;
final static int MASKED_DAY_COMPONENT_VAL = 1;
final static int MASKED_MONTH_COMPONENT_VAL = 0;
final static int MASKED_YEAR_COMPONENT_VAL = 0;
final static int UNMASKED_VAL = -1;
int maskedUpperChar = MASKED_UPPERCASE;
int maskedLowerChar = MASKED_LOWERCASE;
int maskedDigitChar = MASKED_DIGIT;
int maskedOtherChar = MASKED_OTHER_CHAR;
int maskedNumber = MASKED_NUMBER;
int maskedDayValue = MASKED_DAY_COMPONENT_VAL;
int maskedMonthValue = MASKED_MONTH_COMPONENT_VAL;
int maskedYearValue = MASKED_YEAR_COMPONENT_VAL;
public MaskTransformer() {
}
@Override
public void init(ObjectInspector[] arguments, int startIdx) {
int idx = startIdx;
maskedUpperChar = getCharArg(arguments, idx++, MASKED_UPPERCASE);
maskedLowerChar = getCharArg(arguments, idx++, MASKED_LOWERCASE);
maskedDigitChar = getCharArg(arguments, idx++, MASKED_DIGIT);
maskedOtherChar = getCharArg(arguments, idx++, MASKED_OTHER_CHAR);
maskedNumber = getIntArg(arguments, idx++, MASKED_NUMBER);
maskedDayValue = getIntArg(arguments, idx++, MASKED_DAY_COMPONENT_VAL);
maskedMonthValue = getIntArg(arguments, idx++, MASKED_MONTH_COMPONENT_VAL);
maskedYearValue = getIntArg(arguments, idx++, MASKED_YEAR_COMPONENT_VAL);
if(maskedNumber < 0 || maskedNumber > 9) {
maskedNumber = MASKED_NUMBER;
}
if(maskedDayValue < 1 || maskedDayValue > 31) {
maskedDayValue = MASKED_DAY_COMPONENT_VAL;
}
if(maskedMonthValue < 0 || maskedMonthValue > 11) {
maskedMonthValue = MASKED_MONTH_COMPONENT_VAL;
}
}
@Override
String transform(final String val) {
StringBuilder ret = new StringBuilder(val.length());
for(int i = 0; i < val.length(); i++) {
ret.appendCodePoint(transformChar(val.charAt(i)));
}
return ret.toString();
}
@Override
Byte transform(final Byte value) {
byte val = value;
if(value < 0) {
val *= -1;
}
byte ret = 0;
int pos = 1;
while(val != 0) {
ret += maskedNumber * pos;
val /= 10;
pos *= 10;
}
if(value < 0) {
ret *= -1;
}
return ret;
}
@Override
Short transform(final Short value) {
short val = value;
if(value < 0) {
val *= -1;
}
short ret = 0;
int pos = 1;
while(val != 0) {
ret += maskedNumber * pos;
val /= 10;
pos *= 10;
}
if(value < 0) {
ret *= -1;
}
return ret;
}
@Override
Integer transform(final Integer value) {
int val = value;
if(value < 0) {
val *= -1;
}
int ret = 0;
int pos = 1;
while(val != 0) {
ret += maskedNumber * pos;
val /= 10;
pos *= 10;
}
if(value < 0) {
ret *= -1;
}
return ret;
}
@Override
Long transform(final Long value) {
long val = value;
if(value < 0) {
val *= -1;
}
long ret = 0;
long pos = 1;
while (val != 0) {
ret += maskedNumber * pos;
val /= 10;
pos *= 10;
}
if(value < 0) {
ret *= -1;
}
return ret;
}
@Override
Date transform(final Date value) {
int year = maskedYearValue == UNMASKED_VAL ? value.getYear() : maskedYearValue;
int month = maskedMonthValue == UNMASKED_VAL ? value.getMonth() : maskedMonthValue;
int day = maskedDayValue == UNMASKED_VAL ? value.getDate() : maskedDayValue;
return new Date(year, month, day);
}
protected int transformChar(final int c) {
switch(Character.getType(c)) {
case Character.UPPERCASE_LETTER:
if(maskedUpperChar != UNMASKED_VAL) {
return maskedUpperChar;
}
break;
case Character.LOWERCASE_LETTER:
if(maskedLowerChar != UNMASKED_VAL) {
return maskedLowerChar;
}
break;
case Character.DECIMAL_DIGIT_NUMBER:
if(maskedDigitChar != UNMASKED_VAL) {
return maskedDigitChar;
}
break;
default:
if(maskedOtherChar != UNMASKED_VAL) {
return maskedOtherChar;
}
break;
}
return c;
}
int getCharArg(ObjectInspector[] arguments, int index, int defaultValue) {
int ret = defaultValue;
ObjectInspector arg = (arguments != null && arguments.length > index) ? arguments[index] : null;
if (arg != null) {
if(arg instanceof WritableConstantIntObjectInspector) {
IntWritable value = ((WritableConstantIntObjectInspector)arg).getWritableConstantValue();
if(value != null) {
ret = value.get();
}
} else if(arg instanceof WritableConstantLongObjectInspector) {
LongWritable value = ((WritableConstantLongObjectInspector)arg).getWritableConstantValue();
if(value != null) {
ret = (int)value.get();
}
} else if(arg instanceof WritableConstantShortObjectInspector) {
ShortWritable value = ((WritableConstantShortObjectInspector)arg).getWritableConstantValue();
if(value != null) {
ret = value.get();
}
} else if(arg instanceof ConstantObjectInspector) {
Object value = ((ConstantObjectInspector) arg).getWritableConstantValue();
if (value != null) {
String strValue = value.toString();
if (strValue != null && strValue.length() > 0) {
ret = strValue.charAt(0);
}
}
}
}
return ret;
}
int getIntArg(ObjectInspector[] arguments, int index, int defaultValue) {
int ret = defaultValue;
ObjectInspector arg = (arguments != null && arguments.length > index) ? arguments[index] : null;
if (arg != null) {
if (arg instanceof WritableConstantIntObjectInspector) {
IntWritable value = ((WritableConstantIntObjectInspector) arg).getWritableConstantValue();
if (value != null) {
ret = value.get();
}
} else if (arg instanceof WritableConstantLongObjectInspector) {
LongWritable value = ((WritableConstantLongObjectInspector) arg).getWritableConstantValue();
if (value != null) {
ret = (int) value.get();
}
} else if (arg instanceof WritableConstantShortObjectInspector) {
ShortWritable value = ((WritableConstantShortObjectInspector) arg).getWritableConstantValue();
if (value != null) {
ret = value.get();
}
} else if (arg instanceof ConstantObjectInspector) {
Object value = ((ConstantObjectInspector) arg).getWritableConstantValue();
if (value != null) {
String strValue = value.toString();
if (strValue != null && strValue.length() > 0) {
ret = Integer.parseInt(value.toString());
}
}
}
}
return ret;
}
}