mirror of
https://github.com/NationalSecurityAgency/datawave.git
synced 2026-11-07 05:56:25 -10:00
Replace Markings Map with POJO (#3469)
update accumulo-utils to use a POJO for storing markings and then updated the rest of the codebase that referenced it. replaced some of the ColumnVisibility usage with AccessExpression to improve performance. --------- Co-authored-by: Joe Alphonso <[email protected]>
This commit is contained in:
1 parent
8b044420ec
commit
336293cafc
210 files changed
+2694
-1820
No files matched your search
+18
-47
@@ -1,8 +1,7 @@
|
||||
package datawave.marking;
|
||||
|
||||
import static com.google.common.base.Charsets.UTF_8;
|
||||
import static datawave.marking.AccessExpressionMarkings.ACCESS;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -12,7 +11,7 @@ import javax.xml.bind.annotation.XmlAccessorOrder;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
|
||||
import org.apache.accumulo.core.security.ColumnVisibility;
|
||||
import org.apache.accumulo.access.AccessExpression;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
@@ -31,7 +30,7 @@ public class ColumnVisibilitySecurityMarking implements SecurityMarking {
|
||||
if (null == values) {
|
||||
throw new IllegalArgumentException("Required parameter " + VISIBILITY_MARKING + " not found");
|
||||
}
|
||||
if (values.isEmpty() || values.size() > 1) {
|
||||
if (values.size() != 1) {
|
||||
throw new IllegalArgumentException("Required parameter " + VISIBILITY_MARKING + " only accepts one value");
|
||||
}
|
||||
columnVisibility = values.get(0);
|
||||
@@ -47,8 +46,16 @@ public class ColumnVisibilitySecurityMarking implements SecurityMarking {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColumnVisibility toColumnVisibility() {
|
||||
return new ColumnVisibility(columnVisibility);
|
||||
public AccessExpression toAccessExpression() {
|
||||
if (columnVisibility == null || columnVisibility.isEmpty()) {
|
||||
return ACCESS.newExpression("");
|
||||
}
|
||||
return ACCESS.newExpression(columnVisibility);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Markings<?> toMarkings() {
|
||||
return AccessExpressionMarkings.builder().accessExpression(toAccessExpression()).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -72,65 +79,29 @@ public class ColumnVisibilitySecurityMarking implements SecurityMarking {
|
||||
if (this.columnVisibility == null && other.columnVisibility != null) {
|
||||
return false;
|
||||
}
|
||||
if (this.columnVisibility == null && other.columnVisibility == null) {
|
||||
if (this.columnVisibility == null) {
|
||||
return true;
|
||||
}
|
||||
if (this.columnVisibility.equals(other.columnVisibility)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return this.columnVisibility.equals(other.columnVisibility);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toColumnVisibilityString();
|
||||
return toAccessExpressionString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toColumnVisibilityString() {
|
||||
public String toAccessExpressionString() {
|
||||
if (null == this.columnVisibility) {
|
||||
return null;
|
||||
}
|
||||
return new String(toColumnVisibility().flatten(), UTF_8);
|
||||
return AccessExpressionUtil.normalize(columnVisibility).getExpression();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
this.columnVisibility = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String,String> toMap() {
|
||||
return Collections.singletonMap(VISIBILITY_MARKING, this.columnVisibility);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromMap(Map<String,String> map) {
|
||||
this.columnVisibility = map.get(VISIBILITY_MARKING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn this set of markings into a serializable string
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
@Override
|
||||
public String mapToString() {
|
||||
return MarkingFunctions.Encoding.toString(toMap());
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill this security markings given an encoded string
|
||||
*
|
||||
* @param encodedMarkings
|
||||
*/
|
||||
@Override
|
||||
public void fromString(String encodedMarkings) {
|
||||
Map<String,String> markings = MarkingFunctions.Encoding.fromString(encodedMarkings);
|
||||
this.columnVisibility = markings.get(VISIBILITY_MARKING);
|
||||
Preconditions.checkNotNull(columnVisibility);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,24 +1,16 @@
|
||||
package datawave.marking;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.accumulo.core.security.ColumnVisibility;
|
||||
import org.apache.accumulo.access.AccessExpression;
|
||||
|
||||
import datawave.validation.ParameterValidator;
|
||||
|
||||
public interface SecurityMarking extends ParameterValidator {
|
||||
|
||||
ColumnVisibility toColumnVisibility() throws MarkingFunctions.Exception;
|
||||
AccessExpression toAccessExpression() throws MarkingFunctions.Exception;
|
||||
|
||||
String toColumnVisibilityString();
|
||||
String toAccessExpressionString();
|
||||
|
||||
Map<String,String> toMap();
|
||||
|
||||
void fromMap(Map<String,String> map);
|
||||
|
||||
String mapToString();
|
||||
|
||||
void fromString(String xmlString);
|
||||
Markings<?> toMarkings() throws MarkingFunctions.Exception;
|
||||
|
||||
void clear();
|
||||
}
|
||||
+3
-3
@@ -1,10 +1,10 @@
|
||||
package datawave.webservice.query.result.event;
|
||||
|
||||
import java.util.Map;
|
||||
import datawave.marking.Markings;
|
||||
|
||||
public interface HasMarkings {
|
||||
|
||||
void setMarkings(Map<String,String> markings);
|
||||
void setMarkings(Markings<?> markings);
|
||||
|
||||
Map<String,String> getMarkings();
|
||||
Markings<?> getMarkings();
|
||||
}
|
||||
+54
-101
@@ -7,26 +7,24 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.apache.accumulo.core.security.ColumnVisibility;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import datawave.data.type.Type;
|
||||
import datawave.marking.MarkingFunctions;
|
||||
import datawave.marking.Markings;
|
||||
import datawave.webservice.query.cachedresults.CacheableQueryRow;
|
||||
import datawave.webservice.query.data.ObjectSizeOf;
|
||||
import datawave.webservice.query.util.TypedValue;
|
||||
|
||||
public class CacheableQueryRowImpl extends CacheableQueryRow implements ObjectSizeOf {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(CacheableQueryRowImpl.class);
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(CacheableQueryRowImpl.class);
|
||||
|
||||
private String user = null;
|
||||
private String queryId = null;
|
||||
@@ -35,77 +33,52 @@ public class CacheableQueryRowImpl extends CacheableQueryRow implements ObjectSi
|
||||
private String eventId = null;
|
||||
private String row = null;
|
||||
private String colFam = null;
|
||||
private Map<String,String> markings = new HashMap<>();
|
||||
private Map<String,Map<String,String>> columnMarkingsMap = new HashMap<>();
|
||||
private Markings<?> markings = null;
|
||||
private Map<String,Markings<?>> columnMarkingsMap = new HashMap<>();
|
||||
private Map<String,String> columnColumnVisibilityMap = new HashMap<>();
|
||||
private Map<String,String> columnTypeMap = Maps.newHashMap();
|
||||
private Map<String,String> columnTypeMap = new HashMap<>();
|
||||
private Map<String,Long> columnTimestampMap = new HashMap<>();
|
||||
private Map<String,Set<String>> columnValues = new HashMap<>();
|
||||
private Set<String> variableColumnNames = new TreeSet<>();
|
||||
private String queryOrigin = null;
|
||||
private String resultOrigin = null;
|
||||
|
||||
public void addColumn(String columnName, String columnValueString, Map<String,String> markings, String columnVisibility, Long timestamp) {
|
||||
public void addColumn(String columnName, String columnValueString, Markings<?> markings, String columnVisibility, Long timestamp) {
|
||||
addColumn(columnName, new TypedValue(columnValueString), markings, columnVisibility, timestamp);
|
||||
}
|
||||
|
||||
public void addColumn(String columnName, TypedValue columnTypedValue, Map<String,String> markings, String columnVisibility, Long timestamp) {
|
||||
public void addColumn(String columnName, TypedValue columnTypedValue, Markings<?> markings, String columnVisibility, Long timestamp) {
|
||||
|
||||
columnName = columnName.replaceAll(" ", "_");
|
||||
final String cleanColumnName = columnName.replace(' ', '_');
|
||||
|
||||
// if new markings are the same as the old markings, skip all of this
|
||||
// they are the same and the markings value has already been validated
|
||||
if (this.markings.equals(markings) == false) {
|
||||
if (this.markings.isEmpty()) {
|
||||
// validate the markings
|
||||
try {
|
||||
markingFunctions.translateToColumnVisibility(markings);
|
||||
if (this.markings.isEmpty()) {
|
||||
// markings were empty, so use the one passed in.
|
||||
this.markings = markings;
|
||||
}
|
||||
} catch (MarkingFunctions.Exception e) {
|
||||
log.error("Invalid markings {} skipping column {} = {}", markings, columnName, columnTypedValue, e);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
Set<ColumnVisibility> columnVisibilities = Sets.newHashSet();
|
||||
columnVisibilities.add(markingFunctions.translateToColumnVisibility(this.markings));
|
||||
columnVisibilities.add(markingFunctions.translateToColumnVisibility(markings));
|
||||
ColumnVisibility combinedVisibility = markingFunctions.combine(columnVisibilities);
|
||||
|
||||
// use combined marking as new markings
|
||||
this.markings = markingFunctions.translateFromColumnVisibility(combinedVisibility);
|
||||
} catch (MarkingFunctions.Exception e) {
|
||||
log.error("Invalid markings {} skipping column {} = {}", markings, columnName, columnTypedValue, e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
try {
|
||||
this.markings = markingFunctions.combine(this.markings, markings);
|
||||
} catch (MarkingFunctions.Exception e) {
|
||||
LOGGER.error("Invalid markings {} skipping column {} = {}", markings, cleanColumnName, columnTypedValue, e);
|
||||
return;
|
||||
}
|
||||
|
||||
Long currTimestamp = columnTimestampMap.get(columnName);
|
||||
Long currTimestamp = columnTimestampMap.get(cleanColumnName);
|
||||
if (currTimestamp == null || timestamp > currTimestamp) {
|
||||
columnTimestampMap.put(columnName, timestamp);
|
||||
columnTimestampMap.put(cleanColumnName, timestamp);
|
||||
}
|
||||
|
||||
Type<?> datawaveType = null;
|
||||
String typedColumnName = "";
|
||||
if (columnTypedValue.getValue() instanceof Type<?>) {
|
||||
datawaveType = (Type<?>) columnTypedValue.getValue();
|
||||
typedColumnName = columnTypedValue.getType().replaceAll(":", "_").toUpperCase();
|
||||
typedColumnName += "_" + columnName;
|
||||
typedColumnName = columnTypedValue.getType().replace(':', '_').toUpperCase();
|
||||
typedColumnName += "_" + cleanColumnName;
|
||||
}
|
||||
|
||||
manageColumnInsert(datawaveType, columnName, columnTypedValue, markings, columnVisibility);
|
||||
if (!typedColumnName.isEmpty() && typedColumnName.startsWith("XS_STRING") == false) {
|
||||
manageColumnInsert(datawaveType, cleanColumnName, columnTypedValue, markings, columnVisibility);
|
||||
if (!typedColumnName.isEmpty() && !typedColumnName.startsWith("XS_STRING")) {
|
||||
manageColumnInsert(datawaveType, typedColumnName, columnTypedValue, markings, columnVisibility);
|
||||
}
|
||||
}
|
||||
|
||||
private void manageColumnInsert(Type<?> datawaveType, String columnName, TypedValue columnTypedValue, Map<String,String> markings,
|
||||
String columnVisibility) {
|
||||
if (this.columnValues.containsKey(columnName) == false) {
|
||||
private void manageColumnInsert(Type<?> datawaveType, String columnName, TypedValue columnTypedValue, Markings<?> markings, String columnVisibility) {
|
||||
if (!this.columnValues.containsKey(columnName)) {
|
||||
|
||||
Set<String> valuesSet = Sets.newLinkedHashSet();
|
||||
if (datawaveType != null) {
|
||||
@@ -121,8 +94,8 @@ public class CacheableQueryRowImpl extends CacheableQueryRow implements ObjectSi
|
||||
this.columnValues.put(columnName, valuesSet);
|
||||
this.columnMarkingsMap.put(columnName, markings);
|
||||
this.columnColumnVisibilityMap.put(columnName, columnVisibility);
|
||||
} else {
|
||||
|
||||
} else {
|
||||
if (datawaveType != null) {
|
||||
if (columnName.startsWith("XS")) {
|
||||
columnValues.get(columnName).add(datawaveType.getNormalizedValue());
|
||||
@@ -133,18 +106,18 @@ public class CacheableQueryRowImpl extends CacheableQueryRow implements ObjectSi
|
||||
} else {
|
||||
columnValues.get(columnName).add(columnTypedValue.getValue().toString());
|
||||
}
|
||||
Map<String,String> currMarkings = columnMarkingsMap.get(columnName);
|
||||
Markings<?> currMarkings = columnMarkingsMap.get(columnName);
|
||||
|
||||
if (currMarkings.equals(markings) == false) {
|
||||
if (currMarkings == null) {
|
||||
// existing marking was null so we update with new one
|
||||
columnMarkingsMap.put(columnName, markings);
|
||||
columnColumnVisibilityMap.put(columnName, columnVisibility);
|
||||
} else if (!currMarkings.equals(markings)) {
|
||||
try {
|
||||
Set<ColumnVisibility> columnVisibilities = Sets.newHashSet();
|
||||
columnVisibilities.add(markingFunctions.translateToColumnVisibility(currMarkings));
|
||||
columnVisibilities.add(markingFunctions.translateToColumnVisibility(markings));
|
||||
ColumnVisibility combinedVisibility = markingFunctions.combine(columnVisibilities);
|
||||
Map<String,String> minMarkings = markingFunctions.translateFromColumnVisibility(combinedVisibility);
|
||||
Markings<?> combinedMarkings = markingFunctions.combine(currMarkings, markings);
|
||||
|
||||
// use combined marking as new markings
|
||||
columnMarkingsMap.put(columnName, minMarkings);
|
||||
columnMarkingsMap.put(columnName, combinedMarkings);
|
||||
// new combined marking means that this colVis is greater than old colVis
|
||||
columnColumnVisibilityMap.put(columnName, columnVisibility);
|
||||
} catch (MarkingFunctions.Exception e) {
|
||||
@@ -183,21 +156,19 @@ public class CacheableQueryRowImpl extends CacheableQueryRow implements ObjectSi
|
||||
return colFam;
|
||||
}
|
||||
|
||||
public Map<String,String> getMarkings() {
|
||||
return Maps.newHashMap(markings);
|
||||
public Markings<?> getMarkings() {
|
||||
return markings;
|
||||
}
|
||||
|
||||
public Map<String,String> getColumnMarkings(String columnName) {
|
||||
columnName = columnName.replaceAll(" ", "_");
|
||||
Map<String,String> markings = null;
|
||||
if (this.columnMarkingsMap.containsKey(columnName)) {
|
||||
markings = this.columnMarkingsMap.get(columnName);
|
||||
public Markings<?> getColumnMarkings(String columnName) {
|
||||
final String cleanColumnName = columnName.replace(' ', '_');
|
||||
Markings<?> markings;
|
||||
if (this.columnMarkingsMap.containsKey(cleanColumnName)) {
|
||||
markings = this.columnMarkingsMap.get(cleanColumnName);
|
||||
} else {
|
||||
markings = this.columnMarkingsMap.get("_DEFAULT_");
|
||||
}
|
||||
|
||||
if (markings == null)
|
||||
markings = Maps.newHashMap();
|
||||
return markings;
|
||||
}
|
||||
|
||||
@@ -209,11 +180,7 @@ public class CacheableQueryRowImpl extends CacheableQueryRow implements ObjectSi
|
||||
Integer currColumnNumber = columnMap.get(currColumnName);
|
||||
if (currColumnNumber != null) {
|
||||
Long currLong = entry.getValue();
|
||||
Set<String> columnSet = timestampMap.get(currLong);
|
||||
if (columnSet == null) {
|
||||
columnSet = new TreeSet<>();
|
||||
timestampMap.put(currLong, columnSet);
|
||||
}
|
||||
Set<String> columnSet = timestampMap.computeIfAbsent(currLong, k -> new TreeSet<>());
|
||||
columnSet.add(currColumnName);
|
||||
}
|
||||
}
|
||||
@@ -243,10 +210,10 @@ public class CacheableQueryRowImpl extends CacheableQueryRow implements ObjectSi
|
||||
}
|
||||
|
||||
public String getColumnVisibility(String columnName) {
|
||||
columnName = columnName.replaceAll(" ", "_");
|
||||
String columnVisibility = null;
|
||||
if (this.columnColumnVisibilityMap.containsKey(columnName)) {
|
||||
columnVisibility = this.columnColumnVisibilityMap.get(columnName);
|
||||
final String cleanColumnName = columnName.replace(' ', '_');
|
||||
String columnVisibility;
|
||||
if (this.columnColumnVisibilityMap.containsKey(cleanColumnName)) {
|
||||
columnVisibility = this.columnColumnVisibilityMap.get(cleanColumnName);
|
||||
} else {
|
||||
columnVisibility = this.columnColumnVisibilityMap.get("_DEFAULT_");
|
||||
}
|
||||
@@ -255,10 +222,10 @@ public class CacheableQueryRowImpl extends CacheableQueryRow implements ObjectSi
|
||||
|
||||
public Long getColumnTimestamp(String columnName) {
|
||||
|
||||
columnName = columnName.replaceAll(" ", "_");
|
||||
final String cleanColumnName = columnName.replace(' ', '_');
|
||||
Long timestamp = null;
|
||||
if (this.columnTimestampMap.containsKey(columnName)) {
|
||||
timestamp = this.columnTimestampMap.get(columnName);
|
||||
if (this.columnTimestampMap.containsKey(cleanColumnName)) {
|
||||
timestamp = this.columnTimestampMap.get(cleanColumnName);
|
||||
} else {
|
||||
timestamp = this.columnTimestampMap.get("_DEFAULT_");
|
||||
}
|
||||
@@ -289,17 +256,11 @@ public class CacheableQueryRowImpl extends CacheableQueryRow implements ObjectSi
|
||||
this.colFam = colFam;
|
||||
}
|
||||
|
||||
public void setMarkings(Map<String,String> markings) {
|
||||
// validate the markings
|
||||
try {
|
||||
markingFunctions.translateToColumnVisibility(markings);
|
||||
this.markings = markings;
|
||||
} catch (MarkingFunctions.Exception e) {
|
||||
log.error("Invalid markings {}", markings, e);
|
||||
}
|
||||
public void setMarkings(Markings<?> markings) {
|
||||
this.markings = markings;
|
||||
}
|
||||
|
||||
public void setColumnMarkingsMap(Map<String,Map<String,String>> columnMarkingsMap) {
|
||||
public void setColumnMarkingsMap(Map<String,Markings<?>> columnMarkingsMap) {
|
||||
this.columnMarkingsMap = columnMarkingsMap;
|
||||
}
|
||||
|
||||
@@ -317,14 +278,12 @@ public class CacheableQueryRowImpl extends CacheableQueryRow implements ObjectSi
|
||||
|
||||
for (String field : columnMarkingsMap.keySet()) {
|
||||
|
||||
// sort the map
|
||||
Map<String,String> m = columnMarkingsMap.get(field);
|
||||
Markings<?> m = columnMarkingsMap.get(field);
|
||||
String v = columnColumnVisibilityMap.get(field);
|
||||
if (m == null) {
|
||||
m = new HashMap<>();
|
||||
String mStr = "";
|
||||
if (m != null && !m.isEmpty()) {
|
||||
mStr = m.toAccessExpression().getExpression();
|
||||
}
|
||||
// use TreeMap to sort the map
|
||||
String mStr = MarkingFunctions.Encoding.toString(new TreeMap<>(m));
|
||||
if (v == null) {
|
||||
combinedMap.put(field, mStr);
|
||||
} else {
|
||||
@@ -338,11 +297,7 @@ public class CacheableQueryRowImpl extends CacheableQueryRow implements ObjectSi
|
||||
Map<String,Set<String>> markingToField = new HashMap<>();
|
||||
for (Map.Entry<String,String> entry : combinedMap.entrySet()) {
|
||||
String combinedMarking = entry.getValue();
|
||||
Set<String> fields = markingToField.get(combinedMarking);
|
||||
if (fields == null) {
|
||||
fields = new HashSet<>();
|
||||
markingToField.put(combinedMarking, fields);
|
||||
}
|
||||
Set<String> fields = markingToField.computeIfAbsent(combinedMarking, k -> new HashSet<>());
|
||||
fields.add(entry.getKey());
|
||||
if (fields.size() > largestSetCount) {
|
||||
largestSetCount = fields.size();
|
||||
@@ -377,9 +332,7 @@ public class CacheableQueryRowImpl extends CacheableQueryRow implements ObjectSi
|
||||
}
|
||||
|
||||
public List<String> getVariableColumnNames() {
|
||||
List<String> l = new ArrayList<>();
|
||||
l.addAll(variableColumnNames);
|
||||
return l;
|
||||
return new ArrayList<>(variableColumnNames);
|
||||
}
|
||||
|
||||
public void setVariableColumnNames(Collection<String> c) {
|
||||
|
||||
+13
-5
@@ -9,10 +9,12 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.apache.accumulo.core.security.ColumnVisibility;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import datawave.marking.MarkingFunctions;
|
||||
import datawave.marking.Markings;
|
||||
import datawave.webservice.query.cachedresults.CacheableQueryRow;
|
||||
import datawave.webservice.query.result.event.ResponseObjectFactory;
|
||||
|
||||
@@ -20,8 +22,9 @@ public class CacheableQueryRowReader {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(CacheableQueryRowReader.class);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static CacheableQueryRow createRow(ResultSet cachedRowSet, Set<String> fixedFieldsInEvent, ResponseObjectFactory responseObjectFactory,
|
||||
MarkingFunctions markingFunctions) {
|
||||
MarkingFunctions<?> markingFunctions) {
|
||||
|
||||
CacheableQueryRow cqfc = responseObjectFactory.getCacheableQueryRow();
|
||||
cqfc.setMarkingFunctions(markingFunctions);
|
||||
@@ -86,22 +89,25 @@ public class CacheableQueryRowReader {
|
||||
}
|
||||
if (columnToIndexMap.get("_markings_") != null) {
|
||||
String mStr = cachedRowSet.getString(columnToIndexMap.get("_markings_"));
|
||||
cqfc.setMarkings(MarkingFunctions.Encoding.fromString(mStr));
|
||||
if (mStr != null && !mStr.isEmpty()) {
|
||||
cqfc.setMarkings(markingFunctions.translateFromColumnVisibility(new ColumnVisibility(mStr)));
|
||||
}
|
||||
}
|
||||
if (columnToIndexMap.get("_column_markings_") != null) {
|
||||
String columnMarkings = cachedRowSet.getString(columnToIndexMap.get("_column_markings_"));
|
||||
Map<String,String> combinedColumnMarkings = parseColumnMarkings(columnMarkings, columnToIndexMap);
|
||||
Map<String,Map<String,String>> columnMarkingsMap = new HashMap<>();
|
||||
Map<String,Markings<?>> columnMarkingsMap = new HashMap<>();
|
||||
Map<String,String> columnVisibilityMap = new HashMap<>();
|
||||
for (Map.Entry<String,String> entry : combinedColumnMarkings.entrySet()) {
|
||||
String columnName = entry.getKey();
|
||||
String combinedString = entry.getValue();
|
||||
int x = combinedString.lastIndexOf(':');
|
||||
if (x >= 0) {
|
||||
columnMarkingsMap.put(columnName, MarkingFunctions.Encoding.fromString(combinedString.substring(0, x)));
|
||||
String markingStr = combinedString.substring(0, x);
|
||||
columnMarkingsMap.put(columnName, markingFunctions.translateFromColumnVisibility(new ColumnVisibility(markingStr)));
|
||||
columnVisibilityMap.put(columnName, combinedString.substring(x + 1));
|
||||
} else {
|
||||
columnMarkingsMap.put(columnName, MarkingFunctions.Encoding.fromString(combinedString));
|
||||
columnMarkingsMap.put(columnName, markingFunctions.translateFromColumnVisibility(new ColumnVisibility(combinedString)));
|
||||
columnVisibilityMap.put(columnName, "");
|
||||
}
|
||||
}
|
||||
@@ -115,6 +121,8 @@ public class CacheableQueryRowReader {
|
||||
|
||||
} catch (SQLException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
} catch (MarkingFunctions.Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return cqfc;
|
||||
|
||||
@@ -13,10 +13,6 @@
|
||||
<dependencies />
|
||||
</dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>gov.nsa.datawave.core</groupId>
|
||||
<artifactId>accumulo-utils</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>gov.nsa.datawave.core</groupId>
|
||||
<artifactId>datawave-core-connection-pool</artifactId>
|
||||
|
||||
@@ -27,6 +27,9 @@ public interface ClassCache {
|
||||
* @param name
|
||||
* the class name
|
||||
* @return a {@link Class}
|
||||
*
|
||||
* @throws ClassNotFoundException
|
||||
* if class not found
|
||||
*/
|
||||
Class<?> get(String name) throws ClassNotFoundException;
|
||||
}
|
||||
@@ -50,7 +50,9 @@ import datawave.data.ColumnFamilyConstants;
|
||||
import datawave.data.type.Type;
|
||||
import datawave.ingest.protobuf.Uid;
|
||||
import datawave.ingest.protobuf.Uid.List.Builder;
|
||||
import datawave.marking.AccessExpressionUtil;
|
||||
import datawave.marking.MarkingFunctions;
|
||||
import datawave.marking.Markings;
|
||||
import datawave.microservice.query.DefaultQueryParameters;
|
||||
import datawave.microservice.query.QueryPersistence;
|
||||
import datawave.modification.configuration.ModificationServiceConfiguration;
|
||||
@@ -204,7 +206,7 @@ public class MutableMetadataHandler extends ModificationServiceConfiguration {
|
||||
protected String reverseIndexTableName = null;
|
||||
protected String metadataTableName = null;
|
||||
protected MetadataHelperFactory metadataHelperFactory;
|
||||
protected MarkingFunctions markingFunctions = null;
|
||||
protected MarkingFunctions<?> markingFunctions = null;
|
||||
|
||||
// a map of event fields to index only/derived fields to enable appropriate deleting of event fields and all derivatives
|
||||
protected Multimap<String,String> indexOnlyMap = null;
|
||||
@@ -247,11 +249,11 @@ public class MutableMetadataHandler extends ModificationServiceConfiguration {
|
||||
this.metadataTableName = metadataTableName;
|
||||
}
|
||||
|
||||
public MarkingFunctions getMarkingFunctions() {
|
||||
public MarkingFunctions<?> getMarkingFunctions() {
|
||||
return markingFunctions;
|
||||
}
|
||||
|
||||
public void setMarkingFunctions(MarkingFunctions markingFunctions) {
|
||||
public void setMarkingFunctions(MarkingFunctions<?> markingFunctions) {
|
||||
this.markingFunctions = markingFunctions;
|
||||
}
|
||||
|
||||
@@ -310,6 +312,24 @@ public class MutableMetadataHandler extends ModificationServiceConfiguration {
|
||||
this.process(client, request, mutableFieldList, userAuths, userDetails, false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert legacy Map<String,String> field markings (from DefaultModificationRequest) to Markings<?>.
|
||||
*/
|
||||
private Markings<?> convertFieldMarkings(Map<String,String> rawMarkings) {
|
||||
if (rawMarkings == null || rawMarkings.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
String vis = rawMarkings.getOrDefault("columnVisibility", "");
|
||||
if (vis.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return markingFunctions.translateFromColumnVisibility(new ColumnVisibility(vis));
|
||||
} catch (MarkingFunctions.Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void process(AccumuloClient client, ModificationRequestBase request, Map<String,Set<String>> mutableFieldList, Set<Authorizations> userAuths,
|
||||
ProxiedUserDetails userDetails, boolean purgeIndex, boolean insertHistory) throws Exception {
|
||||
|
||||
@@ -334,7 +354,7 @@ public class MutableMetadataHandler extends ModificationServiceConfiguration {
|
||||
String eventUid = e.getEventUid();
|
||||
|
||||
String oldFieldValue = null;
|
||||
Map<String,String> oldFieldMarkings = null;
|
||||
Markings<?> oldFieldMarkings = null;
|
||||
String oldColumnVisibility = null;
|
||||
List<Pair<Key,Value>> currentEntryList = null;
|
||||
int valHistoryCount = 0;
|
||||
@@ -358,8 +378,7 @@ public class MutableMetadataHandler extends ModificationServiceConfiguration {
|
||||
|
||||
// Count the history entries if history is going to be inserted.
|
||||
if (insertHistory && (MODE.INSERT.equals(mode) || MODE.UPDATE.equals(mode))) {
|
||||
List<Pair<Key,Value>> fieldHistoryList = getField(client, userAuths, shardId, datatype, eventUid, "HISTORY_" + fieldName, null,
|
||||
new HashMap<>(), null);
|
||||
List<Pair<Key,Value>> fieldHistoryList = getField(client, userAuths, shardId, datatype, eventUid, "HISTORY_" + fieldName, null, null, null);
|
||||
|
||||
for (Pair<Key,Value> p : fieldHistoryList) {
|
||||
if (p.getLeft().getColumnQualifier().find(mr.getFieldValue()) > -1) {
|
||||
@@ -371,13 +390,13 @@ public class MutableMetadataHandler extends ModificationServiceConfiguration {
|
||||
if (MODE.UPDATE.equals(mode) || MODE.DELETE.equals(mode)) {
|
||||
if (MODE.UPDATE.equals(mode)) {
|
||||
oldFieldValue = mr.getOldFieldValue();
|
||||
oldFieldMarkings = mr.getOldFieldMarkings();
|
||||
oldFieldMarkings = convertFieldMarkings(mr.getOldFieldMarkings());
|
||||
oldColumnVisibility = mr.getOldColumnVisibility();
|
||||
if (null == oldFieldValue)
|
||||
throw new IllegalArgumentException("fieldValue parameter required for update");
|
||||
} else {
|
||||
oldFieldValue = mr.getFieldValue();
|
||||
oldFieldMarkings = mr.getFieldMarkings();
|
||||
oldFieldMarkings = convertFieldMarkings(mr.getFieldMarkings());
|
||||
oldColumnVisibility = mr.getColumnVisibility();
|
||||
if (null == oldFieldValue)
|
||||
throw new IllegalArgumentException("fieldValue parameter required for delete");
|
||||
@@ -399,7 +418,7 @@ public class MutableMetadataHandler extends ModificationServiceConfiguration {
|
||||
|
||||
if (MODE.INSERT.equals(mode)) {
|
||||
String fieldValue = mr.getFieldValue();
|
||||
Map<String,String> fieldMarkings = mr.getFieldMarkings();
|
||||
Markings<?> fieldMarkings = convertFieldMarkings(mr.getFieldMarkings());
|
||||
String columnVisibility = mr.getColumnVisibility();
|
||||
ColumnVisibility colviz = null;
|
||||
if (null != columnVisibility) {
|
||||
@@ -414,7 +433,7 @@ public class MutableMetadataHandler extends ModificationServiceConfiguration {
|
||||
delete(writer, client, userAuths, currentEntryList, isIndexOnly, isIndexed, isReverseIndexed, isContent, dataTypes, user, MODE.UPDATE,
|
||||
origTimestamp + valHistoryCount, purgeIndex, insertHistory);
|
||||
String fieldValue = mr.getFieldValue();
|
||||
Map<String,String> fieldMarkings = mr.getFieldMarkings();
|
||||
Markings<?> fieldMarkings = convertFieldMarkings(mr.getFieldMarkings());
|
||||
String columnVisibility = mr.getColumnVisibility();
|
||||
ColumnVisibility colviz = null;
|
||||
if (null != columnVisibility) {
|
||||
@@ -636,7 +655,7 @@ public class MutableMetadataHandler extends ModificationServiceConfiguration {
|
||||
* @throws Exception
|
||||
* if there are issues
|
||||
*/
|
||||
protected void insert(MultiTableBatchWriter writer, String shardId, String datatype, String eventUid, Map<String,String> markings, ColumnVisibility viz,
|
||||
protected void insert(MultiTableBatchWriter writer, String shardId, String datatype, String eventUid, Markings<?> markings, ColumnVisibility viz,
|
||||
String fieldName, String fieldValue, boolean isIndexOnlyField, boolean isIndexed, boolean isReverseIndexed, Set<Type<?>> dataTypes,
|
||||
String user, MODE mode, long ts, boolean insertHistory) throws Exception {
|
||||
|
||||
@@ -644,7 +663,7 @@ public class MutableMetadataHandler extends ModificationServiceConfiguration {
|
||||
if (null == markings || markings.isEmpty())
|
||||
throw new IllegalArgumentException("No security information specified. Security markings must be supplied");
|
||||
|
||||
viz = markingFunctions.translateToColumnVisibility(markings);
|
||||
viz = markings.toColumnVisibility();
|
||||
}
|
||||
|
||||
insert(writer, shardId, datatype, eventUid, viz, fieldName, fieldValue, ts, isIndexOnlyField, isIndexed, isReverseIndexed, dataTypes, false,
|
||||
@@ -816,7 +835,7 @@ public class MutableMetadataHandler extends ModificationServiceConfiguration {
|
||||
* if there are issues
|
||||
*/
|
||||
protected List<Pair<Key,Value>> getField(AccumuloClient client, Set<Authorizations> userAuths, String shardId, String datatype, String eventUid,
|
||||
String fieldName, String oldFieldValue, Map<String,String> oldFieldMarkings, ColumnVisibility oldColumnVisibility) throws Exception {
|
||||
String fieldName, String oldFieldValue, Markings<?> oldFieldMarkings, ColumnVisibility oldColumnVisibility) throws Exception {
|
||||
|
||||
Text family = new Text(datatype);
|
||||
TextUtil.textAppend(family, eventUid);
|
||||
@@ -847,19 +866,28 @@ public class MutableMetadataHandler extends ModificationServiceConfiguration {
|
||||
}
|
||||
|
||||
if (null != oldColumnVisibility) {
|
||||
// need to compare the flattened values for equivalence. It's possible for the visibility to be in a different order
|
||||
String oldColViz = new String(oldColumnVisibility.flatten(), "UTF-8");
|
||||
String thisVis = new String(thisViz.flatten(), "UTF-8");
|
||||
// need to compare the normalized values for equivalence. It's possible for the visibility to be in a different order
|
||||
String oldColViz = AccessExpressionUtil.normalize(oldColumnVisibility).getExpression();
|
||||
String thisVis = AccessExpressionUtil.normalize(thisViz).getExpression();
|
||||
if (!oldColViz.equals(thisVis)) {
|
||||
log.trace("Skipping key that does not match with column visibility: {}", e.getKey());
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Skipping key that does not match with column visibility: {}", e.getKey());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
Map<String,String> markings = markingFunctions.translateFromColumnVisibilityForAuths(e.getKey().getColumnVisibilityParsed(), userAuths);
|
||||
if (null != oldFieldMarkings && !oldFieldMarkings.equals(markings)) {
|
||||
log.trace("Skipping key that does not match with markings: {}", e.getKey());
|
||||
continue;
|
||||
try {
|
||||
Markings<?> markings = markingFunctions.translateFromColumnVisibilityForAuths(e.getKey().getColumnVisibilityParsed(), userAuths);
|
||||
if (null != oldFieldMarkings && !oldFieldMarkings.equals(markings)) {
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Skipping key that does not match with markings: {}", e.getKey());
|
||||
}
|
||||
continue;
|
||||
}
|
||||
} catch (MarkingFunctions.Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
}
|
||||
results.add(Pair.of(e.getKey(), e.getValue()));
|
||||
}
|
||||
|
||||
+1
-1
@@ -126,7 +126,7 @@ class MutableMetadataHandlerTestSupport {
|
||||
request.setFieldName(fieldName);
|
||||
request.setFieldValue(fieldValue);
|
||||
Map<String,String> markings = new HashMap<>();
|
||||
markings.put(MarkingFunctions.Default.COLUMN_VISIBILITY, columnVisibility);
|
||||
markings.put("columnVisibility", columnVisibility);
|
||||
request.setFieldMarkings(markings);
|
||||
request.setColumnVisibility(null);
|
||||
return request;
|
||||
|
||||
@@ -47,7 +47,7 @@ public abstract class BaseQueryLogic<T> implements QueryLogic<T> {
|
||||
protected ProxiedUserDetails serverUser;
|
||||
|
||||
protected Set<String> requiredRoles;
|
||||
protected MarkingFunctions markingFunctions;
|
||||
protected MarkingFunctions<?> markingFunctions;
|
||||
protected ResponseObjectFactory responseObjectFactory;
|
||||
protected SelectorExtractor selectorExtractor;
|
||||
protected ResponseEnricherBuilder responseEnricherBuilder = null;
|
||||
@@ -100,11 +100,11 @@ public abstract class BaseQueryLogic<T> implements QueryLogic<T> {
|
||||
return settings.getQuery();
|
||||
}
|
||||
|
||||
public MarkingFunctions getMarkingFunctions() {
|
||||
public MarkingFunctions<?> getMarkingFunctions() {
|
||||
return markingFunctions;
|
||||
}
|
||||
|
||||
public void setMarkingFunctions(MarkingFunctions markingFunctions) {
|
||||
public void setMarkingFunctions(MarkingFunctions<?> markingFunctions) {
|
||||
this.markingFunctions = markingFunctions;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@ import datawave.marking.MarkingFunctions;
|
||||
|
||||
public abstract class BaseQueryLogicTransformer<I,O> extends AbstractQueryLogicTransformer<I,O> implements QueryLogicTransformer<I,O> {
|
||||
|
||||
protected MarkingFunctions markingFunctions;
|
||||
protected MarkingFunctions<?> markingFunctions;
|
||||
|
||||
public BaseQueryLogicTransformer(MarkingFunctions markingFunctions) {
|
||||
public BaseQueryLogicTransformer(MarkingFunctions<?> markingFunctions) {
|
||||
if (null == markingFunctions) {
|
||||
throw new IllegalArgumentException("MarkingFunctions must be set");
|
||||
}
|
||||
|
||||
@@ -251,12 +251,12 @@ public abstract class DelegatingQueryLogic implements QueryLogic<Object> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public MarkingFunctions getMarkingFunctions() {
|
||||
public MarkingFunctions<?> getMarkingFunctions() {
|
||||
return delegate.getMarkingFunctions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMarkingFunctions(MarkingFunctions markingFunctions) {
|
||||
public void setMarkingFunctions(MarkingFunctions<?> markingFunctions) {
|
||||
delegate.setMarkingFunctions(markingFunctions);
|
||||
}
|
||||
|
||||
|
||||
@@ -317,9 +317,9 @@ public interface QueryLogic<T> extends Iterable<T>, Cloneable, ParameterValidato
|
||||
|
||||
Set<String> getRequiredRoles();
|
||||
|
||||
MarkingFunctions getMarkingFunctions();
|
||||
MarkingFunctions<?> getMarkingFunctions();
|
||||
|
||||
void setMarkingFunctions(MarkingFunctions markingFunctions);
|
||||
void setMarkingFunctions(MarkingFunctions<?> markingFunctions);
|
||||
|
||||
ResponseObjectFactory getResponseObjectFactory();
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
<artifactId>accumulo-utils</artifactId>
|
||||
<name>${project.artifactId}</name>
|
||||
<properties>
|
||||
<datawave.webservice.namespace>http://webservice.datawave.nsa/v1</datawave.webservice.namespace>
|
||||
<version.dropwizard>4.1.2</version.dropwizard>
|
||||
<!-- snappy and dropwizard required to allow miniaccumulo to work with upgraded zookeeper -->
|
||||
<version.snappy>1.1.7</version.snappy>
|
||||
@@ -67,15 +68,14 @@
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.protostuff</groupId>
|
||||
<artifactId>protostuff-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.accumulo</groupId>
|
||||
<artifactId>accumulo-core</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<artifactId>accumulo-access-core</artifactId>
|
||||
<version>1.0.0-beta3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
@@ -85,6 +85,10 @@
|
||||
<groupId>org.apache.zookeeper</groupId>
|
||||
<artifactId>zookeeper</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
@@ -103,11 +107,22 @@
|
||||
<artifactId>spring-jcl</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.xml.bind</groupId>
|
||||
<artifactId>jaxb-impl</artifactId>
|
||||
<version>${version.jaxb-impl}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>gov.nsa.datawave</groupId>
|
||||
<artifactId>datawave-in-memory-accumulo</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.protostuff</groupId>
|
||||
<artifactId>protostuff-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
@@ -126,4 +141,56 @@
|
||||
<url>https://maven.pkg.github.com/NationalSecurityAgency/datawave</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<filtering>true</filtering>
|
||||
<directory>src/main/resources</directory>
|
||||
<excludes>
|
||||
<exclude>source-templates/**</exclude>
|
||||
</excludes>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-templated-sources</id>
|
||||
<goals>
|
||||
<goal>copy-resources</goal>
|
||||
</goals>
|
||||
<phase>validate</phase>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/generated-sources/templated-sources</outputDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources/source-templates</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-source</id>
|
||||
<goals>
|
||||
<goal>add-source</goal>
|
||||
</goals>
|
||||
<phase>generate-sources</phase>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>target/generated-sources/templated-sources</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
+185
@@ -0,0 +1,185 @@
|
||||
package datawave.marking;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlTransient;
|
||||
|
||||
import org.apache.accumulo.access.Access;
|
||||
import org.apache.accumulo.access.AccessExpression;
|
||||
import org.apache.accumulo.core.security.ColumnVisibility;
|
||||
import org.apache.hadoop.io.Text;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import io.protostuff.Input;
|
||||
import io.protostuff.Output;
|
||||
import io.protostuff.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@XmlAccessorType(XmlAccessType.NONE)
|
||||
@JsonAutoDetect(getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE)
|
||||
public class AccessExpressionMarkings implements Markings<AccessExpression> {
|
||||
public static final Access ACCESS = Access.builder().build();
|
||||
|
||||
public static final String COLUMN_VISIBILITY_KEY = "columnVisibility";
|
||||
|
||||
private AccessExpression accessExpression;
|
||||
|
||||
@Override
|
||||
public AccessExpression getMarkings() {
|
||||
return getAccessExpression();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessExpression toAccessExpression() {
|
||||
return accessExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColumnVisibility toColumnVisibility() {
|
||||
return AccessExpressionUtil.toColumnVisibility(AccessExpressionUtil.normalize(accessExpression));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return accessExpression == null || accessExpression.getExpression().isEmpty();
|
||||
}
|
||||
|
||||
@JsonProperty(COLUMN_VISIBILITY_KEY)
|
||||
@XmlElement(name = COLUMN_VISIBILITY_KEY)
|
||||
public String getColumnVisibilityString() {
|
||||
return accessExpression != null ? accessExpression.getExpression() : null;
|
||||
}
|
||||
|
||||
// required for JAXB unmarshalling
|
||||
public void setColumnVisibilityString(String ae) {
|
||||
this.accessExpression = ae != null ? ACCESS.newExpression(ae) : null;
|
||||
}
|
||||
|
||||
@JsonCreator
|
||||
public static AccessExpressionMarkings create(@JsonProperty(COLUMN_VISIBILITY_KEY) String cv) {
|
||||
if (cv != null && !cv.isEmpty()) {
|
||||
return AccessExpressionMarkings.builder().columnVisibility(cv).build();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static AccessExpressionMarkings createMarkings(ColumnVisibility cv) {
|
||||
if (null == cv) {
|
||||
return null;
|
||||
}
|
||||
return create(new String(cv.getExpression(), StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
public static AccessExpressionMarkings createMarkings(AccessExpression ae) {
|
||||
if (null == ae) {
|
||||
return null;
|
||||
}
|
||||
return create(ae.getExpression());
|
||||
}
|
||||
|
||||
public static AccessExpressionMarkings createMarkings(Text cv) {
|
||||
if (null == cv) {
|
||||
return null;
|
||||
}
|
||||
return create(cv.toString());
|
||||
}
|
||||
|
||||
public static AccessExpressionMarkings createMarkings(String cv) {
|
||||
if (null == cv) {
|
||||
return null;
|
||||
}
|
||||
return create(cv);
|
||||
}
|
||||
|
||||
public static class AccessExpressionMarkingsBuilder {
|
||||
public AccessExpressionMarkingsBuilder columnVisibility(String cv) {
|
||||
this.accessExpression = cv != null ? ACCESS.newExpression(cv) : null;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@XmlTransient
|
||||
public static final Schema<AccessExpressionMarkings> SCHEMA = new Schema<>() {
|
||||
private final HashMap<String,Integer> fieldMap = new HashMap<>();
|
||||
{
|
||||
fieldMap.put(COLUMN_VISIBILITY_KEY, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFieldName(int number) {
|
||||
if (number == 1) {
|
||||
return COLUMN_VISIBILITY_KEY;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFieldNumber(String name) {
|
||||
final Integer number = fieldMap.get(name);
|
||||
return number == null ? 0 : number;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitialized(AccessExpressionMarkings message) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessExpressionMarkings newMessage() {
|
||||
return AccessExpressionMarkings.builder().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String messageName() {
|
||||
return AccessExpressionMarkings.class.getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String messageFullName() {
|
||||
return AccessExpressionMarkings.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? super AccessExpressionMarkings> typeClass() {
|
||||
return AccessExpressionMarkings.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mergeFrom(Input input, AccessExpressionMarkings message) throws IOException {
|
||||
int number;
|
||||
while ((number = input.readFieldNumber(this)) != 0) {
|
||||
if (number == 1) {
|
||||
String expr = input.readString();
|
||||
if (expr != null && !expr.isEmpty()) {
|
||||
message.accessExpression = ACCESS.newExpression(expr);
|
||||
}
|
||||
} else {
|
||||
input.handleUnknownField(number, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(Output output, AccessExpressionMarkings message) throws IOException {
|
||||
if (message.accessExpression != null) {
|
||||
output.writeString(1, message.accessExpression.getExpression(), false);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
package datawave.marking;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import static datawave.marking.AccessExpressionMarkings.ACCESS;
|
||||
import static org.apache.accumulo.access.ParsedAccessExpression.ExpressionType.AND;
|
||||
import static org.apache.accumulo.access.ParsedAccessExpression.ExpressionType.AUTHORIZATION;
|
||||
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.apache.accumulo.access.Access;
|
||||
import org.apache.accumulo.access.AccessExpression;
|
||||
import org.apache.accumulo.access.ParsedAccessExpression;
|
||||
import org.apache.accumulo.core.security.ColumnVisibility;
|
||||
|
||||
/**
|
||||
* Utility for bridging between Accumulo's {@link ColumnVisibility} (from accumulo-core) and {@link AccessExpression} (from accumulo-access).
|
||||
* <p>
|
||||
* Many modules still require {@link ColumnVisibility} for the native Accumulo Key/Mutation API, while the marking functions layer has migrated to
|
||||
* {@link AccessExpression}. This utility provides zero-copy-where-possible conversions between the two.
|
||||
*/
|
||||
public final class AccessExpressionUtil {
|
||||
|
||||
private static final AccessExpression EMPTY_EXPRESSION = ACCESS.newExpression("");
|
||||
private static final ColumnVisibility EMPTY_VISIBILITY = new ColumnVisibility();
|
||||
|
||||
private AccessExpressionUtil() {}
|
||||
|
||||
/**
|
||||
* Convert an {@link AccessExpression} to a {@link ColumnVisibility}.
|
||||
*
|
||||
* @param ae
|
||||
* the access expression
|
||||
* @return the equivalent column visibility
|
||||
*/
|
||||
public static ColumnVisibility toColumnVisibility(AccessExpression ae) {
|
||||
if (null == ae) {
|
||||
return null;
|
||||
}
|
||||
String expr = ae.getExpression();
|
||||
if (expr.isEmpty()) {
|
||||
return EMPTY_VISIBILITY;
|
||||
}
|
||||
return new ColumnVisibility(expr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a {@link ColumnVisibility} to an {@link AccessExpression}.
|
||||
*
|
||||
* @param cv
|
||||
* the column visibility
|
||||
* @return the equivalent access expression
|
||||
*/
|
||||
public static AccessExpression toAccessExpression(ColumnVisibility cv) {
|
||||
if (null == cv) {
|
||||
return null;
|
||||
}
|
||||
byte[] expr = cv.getExpression();
|
||||
|
||||
return toAccessExpression(expr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a visibility String to an {@link AccessExpression}.
|
||||
*
|
||||
* @param visibility
|
||||
* the visibility String
|
||||
* @return the equivalent access expression
|
||||
*/
|
||||
public static AccessExpression toAccessExpression(String visibility) {
|
||||
if (visibility == null || visibility.isEmpty()) {
|
||||
return EMPTY_EXPRESSION;
|
||||
}
|
||||
return ACCESS.newExpression(visibility);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a raw visibility byte array (e.g. from {@code Key.getColumnVisibilityData()}) to an {@link AccessExpression}.
|
||||
*
|
||||
* @param visibilityBytes
|
||||
* the raw visibility bytes
|
||||
* @return the equivalent access expression
|
||||
*/
|
||||
public static AccessExpression toAccessExpression(byte[] visibilityBytes) {
|
||||
if (visibilityBytes == null || visibilityBytes.length == 0) {
|
||||
return EMPTY_EXPRESSION;
|
||||
}
|
||||
return ACCESS.newExpression(new String(visibilityBytes, UTF_8));
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize an {@link AccessExpression} by deduplicating and sorting terms. This is the replacement for the old {@code ColumnVisibility.flatten()}
|
||||
* behavior.
|
||||
*
|
||||
* @param expression
|
||||
* the expression to normalize
|
||||
* @return a normalized {@link AccessExpression}
|
||||
*/
|
||||
public static AccessExpression normalize(AccessExpression expression) {
|
||||
if (null == expression) {
|
||||
return null;
|
||||
}
|
||||
return normalize(expression.getExpression());
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a ColumnVisibility by deduplicating and sorting terms. This is the replacement for the old {@code ColumnVisibility.flatten()} behavior.
|
||||
*
|
||||
* @param cv
|
||||
* the column visibility to normalize
|
||||
* @return a normalized {@link AccessExpression}
|
||||
*/
|
||||
public static AccessExpression normalize(ColumnVisibility cv) {
|
||||
if (null == cv) {
|
||||
return null;
|
||||
}
|
||||
return normalize(new String(cv.getExpression(), UTF_8));
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a ColumnVisibility String by deduplicating and sorting terms. This is the replacement for the old {@code ColumnVisibility.flatten()} behavior.
|
||||
*
|
||||
* @param cv
|
||||
* the column visibility to normalize
|
||||
* @return a normalized {@link AccessExpression}
|
||||
*/
|
||||
public static AccessExpression normalize(String cv) {
|
||||
if (null == cv) {
|
||||
return null;
|
||||
}
|
||||
ParsedAccessExpression parsed = ACCESS.newParsedExpression(cv);
|
||||
return ACCESS.newExpression(normalize(parsed).expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the shared {@link Access} instance used by this utility
|
||||
*/
|
||||
public static Access getAccess() {
|
||||
return ACCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a cached empty {@link AccessExpression}
|
||||
*/
|
||||
public static AccessExpression emptyExpression() {
|
||||
return EMPTY_EXPRESSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* As part of normalizing access expression this class is used to sort and dedupe sub-expressions in a tree set.
|
||||
*/
|
||||
public static class NormalizedExpression implements Comparable<NormalizedExpression> {
|
||||
public final String expression;
|
||||
public final ParsedAccessExpression.ExpressionType type;
|
||||
|
||||
NormalizedExpression(String expression, ParsedAccessExpression.ExpressionType type) {
|
||||
this.expression = expression;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
// determines the sort order of different kinds of subexpressions.
|
||||
private static int typeOrder(ParsedAccessExpression.ExpressionType type) {
|
||||
switch (type) {
|
||||
case AUTHORIZATION:
|
||||
return 1;
|
||||
case OR:
|
||||
return 2;
|
||||
case AND:
|
||||
return 3;
|
||||
case EMPTY:
|
||||
default:
|
||||
throw new IllegalArgumentException("Unexpected type " + type);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(NormalizedExpression o) {
|
||||
// Changing this comparator would significantly change how expressions are normalized.
|
||||
int cmp = typeOrder(type) - typeOrder(o.type);
|
||||
if (cmp == 0) {
|
||||
if (type == AUTHORIZATION) {
|
||||
// sort based on the unquoted and unescaped form of the authorization
|
||||
cmp = ACCESS.unquote(expression).compareTo(ACCESS.unquote(o.expression));
|
||||
} else {
|
||||
cmp = expression.compareTo(o.expression);
|
||||
}
|
||||
|
||||
}
|
||||
return cmp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return this == o || (o instanceof NormalizedExpression && compareTo((NormalizedExpression) o) == 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return expression.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method helps with the flattening aspect of normalization by recursing down as far as possible the parse tree in the case when the expression type is
|
||||
* the same. As long as the type is the same in the sub expression, keep using the same set.
|
||||
*/
|
||||
private static void flatten(ParsedAccessExpression.ExpressionType parentType, ParsedAccessExpression parsed,
|
||||
SortedSet<NormalizedExpression> normalizedExpressions) {
|
||||
if (parsed.getType() == parentType) {
|
||||
for (var child : parsed.getChildren()) {
|
||||
flatten(parentType, child, normalizedExpressions);
|
||||
}
|
||||
} else {
|
||||
// The type changed, so start again on the subexpression.
|
||||
normalizedExpressions.add(normalize(parsed));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* For a given access expression this example will deduplicate, sort, flatten, and remove unneeded parentheses or quotes in the expressions. The following
|
||||
* list gives examples of what each normalization step does.
|
||||
*
|
||||
* <ul>
|
||||
* <li>As an example of flattening, the expression {@code A&(B&C)} flattens to {@code
|
||||
* A&B&C}.</li>
|
||||
* <li>As an example of sorting, the expression {@code (Z&Y)|(C&B)} sorts to {@code
|
||||
* (B&C)|(Y&Z)}</li>
|
||||
* <li>As an example of deduplication, the expression {@code X&Y&X} normalizes to {@code X&Y}</li>
|
||||
* <li>As an example of unneeded quotes, the expression {@code "ABC"&"XYZ"} normalizes to {@code ABC&XYZ}</li>
|
||||
* <li>As an example of unneeded parentheses, the expression {@code (((ABC)|(XYZ)))} normalizes to {@code ABC|XYZ}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* This algorithm attempts to have the same behavior as the one in the Accumulo 2.1 ColumnVisibility class. However the implementation is very different.
|
||||
*/
|
||||
public static NormalizedExpression normalize(ParsedAccessExpression parsed) {
|
||||
if (parsed.getType() == AUTHORIZATION) {
|
||||
// If the authorization is quoted and it does not need to be quoted then the following two
|
||||
// lines will remove the unnecessary quoting.
|
||||
String unquoted = ACCESS.unquote(parsed.getExpression());
|
||||
String quoted = ACCESS.quote(unquoted);
|
||||
return new NormalizedExpression(quoted, parsed.getType());
|
||||
} else {
|
||||
// The tree set does the work of sorting and deduplicating sub expressions.
|
||||
TreeSet<NormalizedExpression> normalizedChildren = new TreeSet<>();
|
||||
for (var child : parsed.getChildren()) {
|
||||
flatten(parsed.getType(), child, normalizedChildren);
|
||||
}
|
||||
|
||||
if (normalizedChildren.size() == 1) {
|
||||
return normalizedChildren.first();
|
||||
} else {
|
||||
StringBuilder builder = getStringBuilder(parsed, normalizedChildren);
|
||||
|
||||
return new NormalizedExpression(builder.toString(), parsed.getType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static StringBuilder getStringBuilder(ParsedAccessExpression parsed, TreeSet<NormalizedExpression> normalizedChildren) {
|
||||
String operator = parsed.getType() == AND ? "&" : "|";
|
||||
String sep = "";
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
for (var child : normalizedChildren) {
|
||||
builder.append(sep);
|
||||
if (child.type == AUTHORIZATION) {
|
||||
builder.append(child.expression);
|
||||
} else {
|
||||
builder.append("(");
|
||||
builder.append(child.expression);
|
||||
builder.append(")");
|
||||
}
|
||||
sep = operator;
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
package datawave.marking;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.accumulo.core.security.Authorizations;
|
||||
import org.apache.accumulo.core.security.ColumnVisibility;
|
||||
import org.apache.accumulo.core.security.ColumnVisibility.Node;
|
||||
import org.apache.accumulo.core.security.ColumnVisibility.NodeType;
|
||||
import org.apache.accumulo.core.security.VisibilityEvaluator;
|
||||
import org.apache.accumulo.core.security.VisibilityParseException;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import datawave.marking.MarkingFunctions.Exception;
|
||||
|
||||
public class ColumnVisibilityHelper {
|
||||
|
||||
protected static final Charset charset = StandardCharsets.UTF_8;
|
||||
private static Logger log = Logger.getLogger(ColumnVisibilityHelper.class);
|
||||
|
||||
public static ColumnVisibility simplifyColumnVisibilityForAuthorizations(ColumnVisibility columnVisibility, Collection<Authorizations> authorizations)
|
||||
throws MarkingFunctions.Exception {
|
||||
|
||||
ColumnVisibility simplifiedCV = columnVisibility;
|
||||
|
||||
Node node = columnVisibility.getParseTree();
|
||||
if (node.getType() == NodeType.OR) {
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Top level OR Node, removing unsatisfied branches from: " + columnVisibility);
|
||||
}
|
||||
byte[] expression = columnVisibility.getExpression();
|
||||
if (authorizations != null) {
|
||||
HashSet<VisibilityEvaluator> ve = new HashSet<>();
|
||||
for (Authorizations a : authorizations)
|
||||
ve.add(new VisibilityEvaluator(a));
|
||||
removeUnsatisfiedTopLevelOrNodes(ve, expression, node);
|
||||
}
|
||||
|
||||
simplifiedCV = ColumnVisibilityHelper.flatten(node, expression);
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("removed unsatisfied branches, visibility now: " + simplifiedCV);
|
||||
}
|
||||
}
|
||||
return simplifiedCV;
|
||||
}
|
||||
|
||||
public static ColumnVisibility removeUndisplayedVisibilities(ColumnVisibility columnVisibility, Set<String> undisplayedVisibilities)
|
||||
throws MarkingFunctions.Exception {
|
||||
ColumnVisibility newColumnVisibility = columnVisibility;
|
||||
if (undisplayedVisibilities != null && !undisplayedVisibilities.isEmpty()) {
|
||||
byte[] expression = columnVisibility.getExpression();
|
||||
Node node = columnVisibility.getParseTree();
|
||||
removeUndisplayedVisibilities(node, expression, undisplayedVisibilities);
|
||||
newColumnVisibility = flatten(node, expression);
|
||||
}
|
||||
return newColumnVisibility;
|
||||
}
|
||||
|
||||
private static void removeUnsatisfiedTopLevelOrNodes(Set<VisibilityEvaluator> ve, byte[] expression, Node node) throws Exception {
|
||||
if (node.getType() == NodeType.OR) {
|
||||
List<Node> children = node.getChildren();
|
||||
int lastNode = children.size() - 1;
|
||||
for (int x = lastNode; x >= 0; x--) {
|
||||
Node currNode = children.get(x);
|
||||
boolean remove = isUnsatisfied(x, ve, currNode, expression);
|
||||
if (remove == true) {
|
||||
children.remove(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isUnsatisfied(int position, Set<VisibilityEvaluator> ve, Node currNode, byte[] expression) throws Exception {
|
||||
boolean unsatisfied = false;
|
||||
try {
|
||||
ColumnVisibility currVis = ColumnVisibilityHelper.flatten(currNode, expression);
|
||||
for (VisibilityEvaluator v : ve) {
|
||||
if (!v.evaluate(currVis))
|
||||
unsatisfied = true;
|
||||
}
|
||||
} catch (VisibilityParseException e) {
|
||||
throw new MarkingFunctions.Exception(e);
|
||||
}
|
||||
return unsatisfied;
|
||||
}
|
||||
|
||||
private static String termNodeToString(Node termNode, byte[] expression) throws Exception {
|
||||
int start = termNode.getTermStart();
|
||||
int end = termNode.getTermEnd();
|
||||
|
||||
String str = "[ERROR]";
|
||||
try {
|
||||
str = new String(expression, start, end - start, charset);
|
||||
} catch (RuntimeException e) {
|
||||
log.error("Error converting term: start:" + start + " length:" + (end - start) + "of expression:" + expression + " -- " + e.getMessage());
|
||||
throw new MarkingFunctions.Exception(e);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
private static ColumnVisibility flatten(Node node, byte[] expression) {
|
||||
|
||||
Node newNode = ColumnVisibility.normalize(node, expression);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
ColumnVisibility.stringify(newNode, expression, sb);
|
||||
return new ColumnVisibility(sb.toString());
|
||||
}
|
||||
|
||||
private static void removeUndisplayedVisibilities(Node node, byte[] expression, Set<String> undisplayedVisibilities) throws MarkingFunctions.Exception {
|
||||
List<Node> children = node.getChildren();
|
||||
// walk backwards so we don't change the index that we need to remove
|
||||
int lastNode = children.size() - 1;
|
||||
for (int x = lastNode; x >= 0; x--) {
|
||||
Node currNode = children.get(x);
|
||||
if (currNode.getType() == NodeType.TERM) {
|
||||
String nodeString = termNodeToString(currNode, expression);
|
||||
if (undisplayedVisibilities.contains(nodeString)) {
|
||||
children.remove(x);
|
||||
}
|
||||
} else {
|
||||
removeUndisplayedVisibilities(currNode, expression, undisplayedVisibilities);
|
||||
// if all children of this NodeType.AND or NodeType.OR node have been removed, remove the node itself.
|
||||
if (currNode.getChildren().isEmpty()) {
|
||||
children.remove(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -13,7 +13,7 @@ import org.apache.accumulo.core.security.ColumnVisibility;
|
||||
*
|
||||
*/
|
||||
public class FlattenedVisibilityCache {
|
||||
private static Map<ColumnVisibility,byte[]> flattenedVisCache = Collections.synchronizedMap(new HashMap<>());
|
||||
private static final Map<ColumnVisibility,byte[]> flattenedVisCache = Collections.synchronizedMap(new HashMap<>());
|
||||
|
||||
/**
|
||||
* Create a flattened visibility, using the cache if possible
|
||||
|
||||
@@ -1,27 +1,23 @@
|
||||
package datawave.marking;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static datawave.marking.AccessExpressionMarkings.ACCESS;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Arrays;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.accumulo.access.AccessExpression;
|
||||
import org.apache.accumulo.access.ParsedAccessExpression;
|
||||
import org.apache.accumulo.core.security.Authorizations;
|
||||
import org.apache.accumulo.core.security.ColumnVisibility;
|
||||
import org.apache.commons.beanutils.BeanUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
/**
|
||||
* Accumulo marks all data with a columnVisibility that declares and controls access. MarkingFunctions provide a pattern for mapping a user's preferred means of
|
||||
* declaring access controls with the Accumulo columnVisibility pattern. As an example, James Bond might use MarkingFunctions to translate a the
|
||||
@@ -29,26 +25,23 @@ import com.google.common.collect.Maps;
|
||||
* human-readable marking like "Patient Privileged Information"
|
||||
*/
|
||||
|
||||
public interface MarkingFunctions {
|
||||
public interface MarkingFunctions<T extends Markings<?>> {
|
||||
|
||||
ColumnVisibility combine(Collection<ColumnVisibility> columnVisibilities) throws MarkingFunctions.Exception;
|
||||
ColumnVisibility combineVisibilities(Collection<ColumnVisibility> visibilities) throws MarkingFunctions.Exception;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String,String> combine(Map<String,String>... markings) throws MarkingFunctions.Exception;
|
||||
T combine(Collection<Markings<?>> markings) throws MarkingFunctions.Exception;
|
||||
|
||||
ColumnVisibility translateToColumnVisibility(Map<String,String> markings) throws MarkingFunctions.Exception;
|
||||
T combine(Markings<?> markings1, Markings<?> markings2) throws MarkingFunctions.Exception;
|
||||
|
||||
Map<String,String> translateFromColumnVisibility(ColumnVisibility columnVisibility) throws MarkingFunctions.Exception;
|
||||
Markings<?> translateFromColumnVisibility(ColumnVisibility columnVisibility) throws MarkingFunctions.Exception;
|
||||
|
||||
Map<String,String> translateFromColumnVisibilityForAuths(ColumnVisibility columnVisibility, Collection<Authorizations> authorizations)
|
||||
Markings<?> translateFromColumnVisibilityForAuths(ColumnVisibility columnVisibility, Collection<Authorizations> authorizations)
|
||||
throws MarkingFunctions.Exception;
|
||||
|
||||
Map<String,String> translateFromColumnVisibilityForAuths(ColumnVisibility columnVisibility, Authorizations authorizations)
|
||||
throws MarkingFunctions.Exception;
|
||||
Markings<?> translateFromColumnVisibilityForAuths(ColumnVisibility columnVisibility, Authorizations authorizations) throws MarkingFunctions.Exception;
|
||||
|
||||
byte[] flatten(ColumnVisibility vis);
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
class Exception extends java.lang.Exception {
|
||||
|
||||
public Exception() {
|
||||
@@ -72,47 +65,100 @@ public interface MarkingFunctions {
|
||||
}
|
||||
}
|
||||
|
||||
class Default implements MarkingFunctions {
|
||||
public static final String COLUMN_VISIBILITY = "columnVisibility";
|
||||
class Default implements MarkingFunctions<AccessExpressionMarkings> {
|
||||
|
||||
@Override
|
||||
public ColumnVisibility combine(Collection<ColumnVisibility> expressions) {
|
||||
public ColumnVisibility combineVisibilities(Collection<ColumnVisibility> visibilities) {
|
||||
AccessExpressionMarkings accessExpressionMarkings = combine(
|
||||
visibilities.stream().filter(Objects::nonNull).map(AccessExpressionMarkings::createMarkings).collect(Collectors.toList()));
|
||||
|
||||
// filter out any empty expressions, then flatten each one (to de-dupe) and concatenate with '&'
|
||||
// flatten the final combined ColumnVisibility and use that to make the ColumnVisibility to return
|
||||
return new ColumnVisibility(new ColumnVisibility(expressions.stream().map(ColumnVisibility::flatten).filter(b -> b.length > 0)
|
||||
.map(b -> "(" + new String(b, UTF_8) + ")").collect(Collectors.joining("&")).getBytes(UTF_8)).flatten());
|
||||
if (null == accessExpressionMarkings) {
|
||||
// is this correct behavior, does it match other implementations?
|
||||
// switching to null causes lots of NPEs so leaving this as is
|
||||
return new ColumnVisibility();
|
||||
}
|
||||
|
||||
return accessExpressionMarkings.toColumnVisibility();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SafeVarargs
|
||||
public final Map<String,String> combine(Map<String,String>... markings) {
|
||||
// translate COLUMN_VISIBILITY values to ColumnVisibility, combine them and
|
||||
// return translated back to Map
|
||||
return translateFromColumnVisibility(combine(Arrays.stream(markings).filter(m -> m.containsKey(COLUMN_VISIBILITY))
|
||||
.map(this::translateToColumnVisibility).collect(Collectors.toSet())));
|
||||
public AccessExpressionMarkings combine(Collection<Markings<?>> markings) {
|
||||
|
||||
Set<AccessExpressionMarkings> uniqueMarkings = new HashSet<>();
|
||||
|
||||
for (Markings<?> marking : markings) {
|
||||
if (null == marking) {
|
||||
continue;
|
||||
}
|
||||
if (!(marking instanceof AccessExpressionMarkings)) {
|
||||
throw new RuntimeException(String.format("Unknown markings class %s", marking.getClass().getName()));
|
||||
}
|
||||
uniqueMarkings.add((AccessExpressionMarkings) marking);
|
||||
}
|
||||
|
||||
if (uniqueMarkings.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (uniqueMarkings.size() == 1) {
|
||||
return uniqueMarkings.stream().findFirst().get();
|
||||
}
|
||||
|
||||
Set<AccessExpression> uniqueExpressions = uniqueMarkings.stream().map(AccessExpressionMarkings::getMarkings).collect(Collectors.toSet());
|
||||
|
||||
// filter out any empty expressions and concatenate with '&'
|
||||
// @formatter:off
|
||||
ParsedAccessExpression expression = ACCESS.newParsedExpression(uniqueExpressions
|
||||
.stream()
|
||||
.map(AccessExpression::getExpression)
|
||||
.filter(str -> !str.isEmpty())
|
||||
.map(str -> "(" + str + ")")
|
||||
.collect(Collectors.joining("&"))
|
||||
);
|
||||
// @formatter:on
|
||||
|
||||
// normalize the Parsed Expression and then return a copy without the parse tree
|
||||
return AccessExpressionMarkings.builder().columnVisibility(AccessExpressionUtil.normalize(expression).expression).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColumnVisibility translateToColumnVisibility(Map<String,String> markings) {
|
||||
ColumnVisibility cv = new ColumnVisibility(markings.get(COLUMN_VISIBILITY));
|
||||
return new ColumnVisibility(cv.flatten());
|
||||
public AccessExpressionMarkings combine(Markings<?> markings1, Markings<?> markings2) {
|
||||
|
||||
if (markings1 == null && markings2 == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (markings2 == null) {
|
||||
return (AccessExpressionMarkings) markings1;
|
||||
}
|
||||
|
||||
if (markings1 == null) {
|
||||
return (AccessExpressionMarkings) markings2;
|
||||
}
|
||||
|
||||
if (markings1 instanceof AccessExpressionMarkings && markings2 instanceof AccessExpressionMarkings) {
|
||||
AccessExpressionMarkings aem1 = (AccessExpressionMarkings) markings1;
|
||||
AccessExpressionMarkings aem2 = (AccessExpressionMarkings) markings2;
|
||||
return combine(List.of(aem1, aem2));
|
||||
}
|
||||
|
||||
throw new RuntimeException(String.format("Unknown markings class %s or %s", markings1.getClass().getName(), markings2.getClass().getName()));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String,String> translateFromColumnVisibility(ColumnVisibility expression) {
|
||||
Map<String,String> markings = Maps.newHashMap();
|
||||
markings.put(COLUMN_VISIBILITY, new String(expression.getExpression(), Charsets.UTF_8));
|
||||
return markings;
|
||||
public Markings<?> translateFromColumnVisibility(ColumnVisibility expression) {
|
||||
String cv = new String(expression.getExpression(), StandardCharsets.UTF_8);
|
||||
return AccessExpressionMarkings.builder().accessExpression(AccessExpressionUtil.normalize(cv)).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String,String> translateFromColumnVisibilityForAuths(ColumnVisibility columnVisibility, Collection<Authorizations> authorizations) {
|
||||
public Markings<?> translateFromColumnVisibilityForAuths(ColumnVisibility columnVisibility, Collection<Authorizations> authorizations) {
|
||||
return translateFromColumnVisibility(columnVisibility);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String,String> translateFromColumnVisibilityForAuths(ColumnVisibility columnVisibility, Authorizations authorizations) {
|
||||
public Markings<?> translateFromColumnVisibilityForAuths(ColumnVisibility columnVisibility, Authorizations authorizations) {
|
||||
return translateFromColumnVisibility(columnVisibility);
|
||||
}
|
||||
|
||||
@@ -120,58 +166,6 @@ public interface MarkingFunctions {
|
||||
public byte[] flatten(ColumnVisibility vis) {
|
||||
return FlattenedVisibilityCache.flatten(vis);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Util {
|
||||
|
||||
public static Object populate(Object obj, Map<String,String> source) {
|
||||
try {
|
||||
BeanUtils.populate(obj, source);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
throw new RuntimeException("Error populating object: " + obj.getClass().getName(), e);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
class Encoding {
|
||||
static private Logger log = LoggerFactory.getLogger(Encoding.class);
|
||||
|
||||
/**
|
||||
* Turn a set of markings into a serializable string
|
||||
*
|
||||
* @param markings
|
||||
* the markings map to convert to a string
|
||||
* @return a serialized String version of {@code markings}
|
||||
*/
|
||||
public static String toString(Map<String,String> markings) {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
try {
|
||||
return objectMapper.writeValueAsString(markings);
|
||||
} catch (JsonProcessingException e) {
|
||||
log.error("could not serialize " + markings);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn a serialized set of markings into a map
|
||||
*
|
||||
* @param encodedMarkings
|
||||
* the serialized String markings to convert back to a markings Map
|
||||
* @return a {@link Map} of the de-serialized markings from {@code encodedMarkings}
|
||||
*/
|
||||
public static Map<String,String> fromString(String encodedMarkings) {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
try {
|
||||
// noinspection unchecked
|
||||
return objectMapper.readValue(encodedMarkings, Map.class);
|
||||
} catch (IOException e) {
|
||||
log.error("could not deserialize " + encodedMarkings);
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -180,9 +174,9 @@ public interface MarkingFunctions {
|
||||
class Factory {
|
||||
public static final Logger log = LoggerFactory.getLogger(Factory.class);
|
||||
|
||||
private static MarkingFunctions markingFunctions;
|
||||
private static MarkingFunctions<?> markingFunctions;
|
||||
|
||||
public static synchronized MarkingFunctions createMarkingFunctions() {
|
||||
public static synchronized MarkingFunctions<?> createMarkingFunctions() {
|
||||
if (markingFunctions != null)
|
||||
return markingFunctions;
|
||||
ClassLoader thisClassLoader = Factory.class.getClassLoader();
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package datawave.marking;
|
||||
|
||||
import org.apache.accumulo.access.AccessExpression;
|
||||
import org.apache.accumulo.core.security.ColumnVisibility;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
|
||||
public interface Markings<T> {
|
||||
|
||||
T getMarkings();
|
||||
|
||||
AccessExpression toAccessExpression();
|
||||
|
||||
ColumnVisibility toColumnVisibility();
|
||||
|
||||
default boolean isEmpty() {
|
||||
return getMarkings() == null;
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package datawave.marking;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.apache.accumulo.core.security.ColumnVisibility;
|
||||
import org.apache.accumulo.core.security.ColumnVisibility.Node;
|
||||
import org.apache.accumulo.core.security.ColumnVisibility.NodeComparator;
|
||||
import org.apache.accumulo.core.security.ColumnVisibility.NodeType;
|
||||
import org.apache.hadoop.io.Text;
|
||||
|
||||
public class VisibilityFlattener {
|
||||
public static ColumnVisibility flatten(Node root, byte[] expression, boolean sort) {
|
||||
StringBuilder out = new StringBuilder();
|
||||
flatten(root, expression, out, sort);
|
||||
return new ColumnVisibility(out.toString());
|
||||
}
|
||||
|
||||
public static Text flattenToText(Node root, byte[] expression, boolean sort) {
|
||||
StringBuilder out = new StringBuilder();
|
||||
flatten(root, expression, out, sort);
|
||||
return new Text(out.toString());
|
||||
}
|
||||
|
||||
private static void flatten(Node root, byte[] expression, StringBuilder out, boolean sort) {
|
||||
if (root.getType() == NodeType.TERM)
|
||||
out.append(new String(expression, root.getTermStart(), root.getTermEnd() - root.getTermStart(), UTF_8));
|
||||
else {
|
||||
String sep = "";
|
||||
Node[] children = root.getChildren().toArray(new Node[] {});
|
||||
if (sort)
|
||||
Arrays.sort(children, new NodeComparator(expression));
|
||||
for (Node c : children) {
|
||||
out.append(sep);
|
||||
boolean parens = (c.getType() != NodeType.TERM && root.getType() != c.getType());
|
||||
if (parens)
|
||||
out.append("(");
|
||||
flatten(c, expression, out, sort);
|
||||
if (parens)
|
||||
out.append(")");
|
||||
sep = root.getType() == NodeType.AND ? "&" : "|";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
@XmlSchema(namespace="${datawave.webservice.namespace}", elementFormDefault=XmlNsForm.QUALIFIED, xmlns={@XmlNs(prefix = "", namespaceURI = "${datawave.webservice.namespace}")})
|
||||
package datawave.marking;
|
||||
|
||||
import javax.xml.bind.annotation.XmlNs;
|
||||
import javax.xml.bind.annotation.XmlNsForm;
|
||||
import javax.xml.bind.annotation.XmlSchema;
|
||||
+385
@@ -0,0 +1,385 @@
|
||||
package datawave.marking;
|
||||
|
||||
import static datawave.marking.AccessExpressionMarkings.ACCESS;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.JAXBElement;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.bind.Marshaller;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
|
||||
import org.apache.accumulo.access.AccessExpression;
|
||||
import org.apache.accumulo.access.InvalidAccessExpressionException;
|
||||
import org.apache.accumulo.core.security.ColumnVisibility;
|
||||
import org.apache.hadoop.io.Text;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import io.protostuff.LinkedBuffer;
|
||||
import io.protostuff.ProtostuffIOUtil;
|
||||
import io.protostuff.Schema;
|
||||
|
||||
public class AccessExpressionMarkingsTest {
|
||||
|
||||
private static final ObjectMapper MAPPER = new ObjectMapper();
|
||||
private static final Schema<AccessExpressionMarkings> SCHEMA = AccessExpressionMarkings.SCHEMA;
|
||||
|
||||
// -- getMarkings / toAccessExpression --
|
||||
|
||||
@Test
|
||||
public void testGetMarkingsReturnsAccessExpression() {
|
||||
AccessExpression ae = ACCESS.newExpression("A&B");
|
||||
AccessExpressionMarkings markings = AccessExpressionMarkings.builder().accessExpression(ae).build();
|
||||
assertEquals(ae, markings.getMarkings());
|
||||
assertEquals(ae, markings.toAccessExpression());
|
||||
}
|
||||
|
||||
// -- toColumnVisibility --
|
||||
|
||||
@Test
|
||||
public void testToColumnVisibility() {
|
||||
AccessExpressionMarkings markings = AccessExpressionMarkings.create("B&A");
|
||||
ColumnVisibility cv = markings.toColumnVisibility();
|
||||
// normalized: sorted
|
||||
assertEquals("A&B", new String(cv.getExpression()));
|
||||
}
|
||||
|
||||
// -- isEmpty --
|
||||
|
||||
@Test
|
||||
public void testIsEmptyWithNullExpression() {
|
||||
AccessExpressionMarkings markings = AccessExpressionMarkings.builder().accessExpression(null).build();
|
||||
assertTrue(markings.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsEmptyWithEmptyExpression() {
|
||||
assertNull(AccessExpressionMarkings.create(""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsEmptyWithNonEmptyExpression() {
|
||||
AccessExpressionMarkings markings = AccessExpressionMarkings.create("A");
|
||||
assertFalse(markings.isEmpty());
|
||||
}
|
||||
|
||||
// -- getColumnVisibilityString --
|
||||
|
||||
@Test
|
||||
public void testGetColumnVisibilityString() {
|
||||
AccessExpressionMarkings markings = AccessExpressionMarkings.create("X|Y");
|
||||
assertEquals("X|Y", markings.getColumnVisibilityString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetColumnVisibilityStringNull() {
|
||||
AccessExpressionMarkings markings = AccessExpressionMarkings.builder().accessExpression(null).build();
|
||||
assertNull(markings.getColumnVisibilityString());
|
||||
}
|
||||
|
||||
// -- create (JsonCreator) --
|
||||
|
||||
@Test
|
||||
public void testCreateWithNull() {
|
||||
assertNull(AccessExpressionMarkings.create(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithExpression() {
|
||||
AccessExpressionMarkings markings = AccessExpressionMarkings.create("A&B&C");
|
||||
assertEquals("A&B&C", markings.getColumnVisibilityString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateIllegalOperator1() {
|
||||
assertThrows(InvalidAccessExpressionException.class, () -> AccessExpressionMarkings.create("A&&B&C"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateIllegalOperator2() {
|
||||
assertThrows(InvalidAccessExpressionException.class, () -> AccessExpressionMarkings.create("A||B&C"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateMalformed1() {
|
||||
assertThrows(InvalidAccessExpressionException.class, () -> AccessExpressionMarkings.create("(A&B&C))"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateMalformed2() {
|
||||
assertThrows(InvalidAccessExpressionException.class, () -> AccessExpressionMarkings.create("(A&B,C))"));
|
||||
}
|
||||
|
||||
// -- createMarkings(ColumnVisibility) --
|
||||
|
||||
@Test
|
||||
public void testCreateMarkingsFromColumnVisibilityNull() {
|
||||
assertNull(AccessExpressionMarkings.createMarkings((ColumnVisibility) null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateMarkingsFromColumnVisibility() {
|
||||
ColumnVisibility cv = new ColumnVisibility("A|B");
|
||||
AccessExpressionMarkings markings = AccessExpressionMarkings.createMarkings(cv);
|
||||
assertEquals("A|B", markings.getColumnVisibilityString());
|
||||
}
|
||||
|
||||
// -- createMarkings(AccessExpression) --
|
||||
|
||||
@Test
|
||||
public void testCreateMarkingsFromAccessExpressionNull() {
|
||||
assertNull(AccessExpressionMarkings.createMarkings((AccessExpression) null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateMarkingsFromAccessExpression() {
|
||||
AccessExpression ae = ACCESS.newExpression("C&D");
|
||||
AccessExpressionMarkings markings = AccessExpressionMarkings.createMarkings(ae);
|
||||
assertEquals("C&D", markings.getColumnVisibilityString());
|
||||
}
|
||||
|
||||
// -- createMarkings(Text) --
|
||||
|
||||
@Test
|
||||
public void testCreateMarkingsFromTextNull() {
|
||||
assertNull(AccessExpressionMarkings.createMarkings((Text) null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateMarkingsFromText() {
|
||||
AccessExpressionMarkings markings = AccessExpressionMarkings.createMarkings(new Text("E|F"));
|
||||
assertEquals("E|F", markings.getColumnVisibilityString());
|
||||
}
|
||||
|
||||
// -- createMarkings(String) --
|
||||
|
||||
@Test
|
||||
public void testCreateMarkingsFromStringNull() {
|
||||
assertNull(AccessExpressionMarkings.createMarkings((String) null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateMarkingsFromString() {
|
||||
AccessExpressionMarkings markings = AccessExpressionMarkings.createMarkings("G&H");
|
||||
assertEquals("G&H", markings.getColumnVisibilityString());
|
||||
}
|
||||
|
||||
// -- JSON round-trip --
|
||||
|
||||
@Test
|
||||
public void testJsonSerialization() throws Exception {
|
||||
AccessExpressionMarkings original = AccessExpressionMarkings.create("A&B");
|
||||
String json = MAPPER.writeValueAsString(original);
|
||||
assertTrue(json.contains("\"columnVisibility\":\"A&B\""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJsonDeserialization() throws Exception {
|
||||
String json = "{\"@class\":\"datawave.marking.AccessExpressionMarkings\",\"columnVisibility\":\"X|Y\"}";
|
||||
AccessExpressionMarkings markings = MAPPER.readValue(json, AccessExpressionMarkings.class);
|
||||
assertEquals("X|Y", markings.getColumnVisibilityString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJsonRoundTrip() throws Exception {
|
||||
AccessExpressionMarkings original = AccessExpressionMarkings.create("A&B&C");
|
||||
String json = MAPPER.writeValueAsString(original);
|
||||
// round-trip through the polymorphic Markings type
|
||||
Markings<?> deserialized = MAPPER.readValue(json, Markings.class);
|
||||
assertInstanceOf(AccessExpressionMarkings.class, deserialized);
|
||||
assertEquals(original.getColumnVisibilityString(), ((AccessExpressionMarkings) deserialized).getColumnVisibilityString());
|
||||
}
|
||||
|
||||
// -- equals via Lombok @Data --
|
||||
|
||||
@Test
|
||||
public void testEquality() {
|
||||
AccessExpressionMarkings a = AccessExpressionMarkings.create("A&B");
|
||||
AccessExpressionMarkings b = AccessExpressionMarkings.create("A&B");
|
||||
assertEquals(a, b);
|
||||
assertEquals(a.hashCode(), b.hashCode());
|
||||
}
|
||||
|
||||
// -- JAXB round-trip --
|
||||
|
||||
@Test
|
||||
public void testJaxbMarshal() throws Exception {
|
||||
AccessExpressionMarkings original = AccessExpressionMarkings.create("A&B");
|
||||
String xml = makeJaxbMarshall(original);
|
||||
assertTrue(xml.contains("<columnVisibility>A&B</columnVisibility>"), "XML should contain the columnVisibility element: " + xml);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJaxbUnmarshal() throws Exception {
|
||||
String expression = "X|Y";
|
||||
AccessExpressionMarkings markings = makeJaxbUnmarshall(expression);
|
||||
assertEquals("X|Y", markings.getColumnVisibilityString());
|
||||
assertFalse(markings.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJaxbRoundTrip() throws Exception {
|
||||
AccessExpressionMarkings original = AccessExpressionMarkings.create("(A&B)|C");
|
||||
AccessExpressionMarkings result = makeJaxbRoundTrip(original);
|
||||
assertEquals(original.getColumnVisibilityString(), result.getColumnVisibilityString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJaxbRoundTripEmpty() throws Exception {
|
||||
AccessExpressionMarkings original = AccessExpressionMarkings.builder().build();
|
||||
AccessExpressionMarkings result = makeJaxbRoundTrip(original);
|
||||
|
||||
assertNull(result.getColumnVisibilityString());
|
||||
assertTrue(result.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJaxbRoundTripComplexExpression() throws Exception {
|
||||
AccessExpressionMarkings original = AccessExpressionMarkings.create("(A&B)|(C&D&E)");
|
||||
AccessExpressionMarkings result = makeJaxbRoundTrip(original);
|
||||
|
||||
assertEquals("(A&B)|(C&D&E)", result.getColumnVisibilityString());
|
||||
assertFalse(result.isEmpty());
|
||||
}
|
||||
// -- Protostuff Schema metadata --
|
||||
|
||||
@Test
|
||||
public void testSchemaGetFieldNameKnown() {
|
||||
assertEquals(AccessExpressionMarkings.COLUMN_VISIBILITY_KEY, SCHEMA.getFieldName(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSchemaGetFieldNameUnknown() {
|
||||
assertNull(SCHEMA.getFieldName(0));
|
||||
assertNull(SCHEMA.getFieldName(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSchemaGetFieldNumberKnown() {
|
||||
assertEquals(1, SCHEMA.getFieldNumber(AccessExpressionMarkings.COLUMN_VISIBILITY_KEY));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSchemaGetFieldNumberUnknown() {
|
||||
assertEquals(0, SCHEMA.getFieldNumber("nonExistentField"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSchemaIsInitialized() {
|
||||
assertTrue(SCHEMA.isInitialized(AccessExpressionMarkings.create("A")));
|
||||
assertTrue(SCHEMA.isInitialized(AccessExpressionMarkings.builder().build()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSchemaNewMessage() {
|
||||
AccessExpressionMarkings msg = SCHEMA.newMessage();
|
||||
assertNotNull(msg);
|
||||
assertTrue(msg.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSchemaMessageName() {
|
||||
assertEquals("AccessExpressionMarkings", SCHEMA.messageName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSchemaMessageFullName() {
|
||||
assertEquals("datawave.marking.AccessExpressionMarkings", SCHEMA.messageFullName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSchemaTypeClass() {
|
||||
assertEquals(AccessExpressionMarkings.class, SCHEMA.typeClass());
|
||||
}
|
||||
|
||||
// -- Protostuff Schema round-trip serialization --
|
||||
|
||||
@Test
|
||||
public void testProtostuffRoundTrip() {
|
||||
AccessExpressionMarkings original = AccessExpressionMarkings.create("(A&B)|C");
|
||||
AccessExpressionMarkings deserialized = makeProtostuffRoundTrip(original);
|
||||
assertEquals(original.getColumnVisibilityString(), deserialized.getColumnVisibilityString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProtostuffRoundTripEmpty() {
|
||||
AccessExpressionMarkings original = AccessExpressionMarkings.builder().build();
|
||||
AccessExpressionMarkings deserialized = makeProtostuffRoundTrip(original);
|
||||
assertTrue(deserialized.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProtostuffRoundTripComplexExpression() {
|
||||
AccessExpressionMarkings original = AccessExpressionMarkings.create("(A&B)|(C&D&E)");
|
||||
AccessExpressionMarkings deserialized = makeProtostuffRoundTrip(original);
|
||||
assertEquals("(A&B)|(C&D&E)", deserialized.getColumnVisibilityString());
|
||||
assertFalse(deserialized.isEmpty());
|
||||
}
|
||||
|
||||
private static String makeJaxbMarshall(AccessExpressionMarkings original) throws JAXBException {
|
||||
JAXBContext ctx = JAXBContext.newInstance(AccessExpressionMarkings.class);
|
||||
ByteArrayOutputStream out = marshal(original, ctx);
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
private static AccessExpressionMarkings makeJaxbUnmarshall(String expression) throws JAXBException, IOException {
|
||||
JAXBContext ctx = JAXBContext.newInstance(AccessExpressionMarkings.class);
|
||||
|
||||
String xml = String.format(
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
|
||||
+ "<markings xmlns=\"http://webservice.datawave.nsa/v1\"><columnVisibility>%s</columnVisibility></markings>",
|
||||
expression);
|
||||
|
||||
JAXBElement<AccessExpressionMarkings> element;
|
||||
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
|
||||
out.write(xml.getBytes());
|
||||
element = unmarshal(out, ctx);
|
||||
}
|
||||
return element.getValue();
|
||||
}
|
||||
|
||||
private static AccessExpressionMarkings makeJaxbRoundTrip(AccessExpressionMarkings original) throws JAXBException {
|
||||
JAXBContext ctx = JAXBContext.newInstance(AccessExpressionMarkings.class);
|
||||
ByteArrayOutputStream out = marshal(original, ctx);
|
||||
JAXBElement<AccessExpressionMarkings> result = unmarshal(out, ctx);
|
||||
return result.getValue();
|
||||
}
|
||||
|
||||
private static ByteArrayOutputStream marshal(AccessExpressionMarkings original, JAXBContext ctx) throws JAXBException {
|
||||
Marshaller marshaller = ctx.createMarshaller();
|
||||
JAXBElement<AccessExpressionMarkings> element = new JAXBElement<>(new QName("http://webservice.datawave.nsa/v1", "markings"),
|
||||
AccessExpressionMarkings.class, original);
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
marshaller.marshal(element, out);
|
||||
return out;
|
||||
}
|
||||
|
||||
private static JAXBElement<AccessExpressionMarkings> unmarshal(ByteArrayOutputStream out, JAXBContext ctx) throws JAXBException {
|
||||
Unmarshaller unmarshaller = ctx.createUnmarshaller();
|
||||
return unmarshaller.unmarshal(new StreamSource(new ByteArrayInputStream(out.toByteArray())), AccessExpressionMarkings.class);
|
||||
}
|
||||
|
||||
private static AccessExpressionMarkings makeProtostuffRoundTrip(AccessExpressionMarkings original) {
|
||||
LinkedBuffer buffer = LinkedBuffer.allocate();
|
||||
byte[] bytes = ProtostuffIOUtil.toByteArray(original, SCHEMA, buffer);
|
||||
|
||||
AccessExpressionMarkings deserialized = SCHEMA.newMessage();
|
||||
ProtostuffIOUtil.mergeFrom(bytes, deserialized, SCHEMA);
|
||||
return deserialized;
|
||||
}
|
||||
|
||||
}
|
||||
+215
@@ -0,0 +1,215 @@
|
||||
package datawave.marking;
|
||||
|
||||
import static datawave.marking.AccessExpressionMarkings.ACCESS;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import org.apache.accumulo.access.AccessExpression;
|
||||
import org.apache.accumulo.access.ParsedAccessExpression;
|
||||
import org.apache.accumulo.core.security.ColumnVisibility;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class AccessExpressionUtilTest {
|
||||
|
||||
// -- toColumnVisibility --
|
||||
|
||||
@Test
|
||||
public void testToColumnVisibilityNull() {
|
||||
assertNull(AccessExpressionUtil.toColumnVisibility(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToColumnVisibilityEmpty() {
|
||||
AccessExpression ae = ACCESS.newExpression("");
|
||||
ColumnVisibility cv = AccessExpressionUtil.toColumnVisibility(ae);
|
||||
assertEquals(0, cv.getExpression().length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToColumnVisibilitySimple() {
|
||||
AccessExpression ae = ACCESS.newExpression("A&B");
|
||||
ColumnVisibility cv = AccessExpressionUtil.toColumnVisibility(ae);
|
||||
assertEquals("A&B", new String(cv.getExpression()));
|
||||
}
|
||||
|
||||
// -- toAccessExpression(ColumnVisibility) --
|
||||
|
||||
@Test
|
||||
public void testToAccessExpressionFromColumnVisibilityNull() {
|
||||
assertNull(AccessExpressionUtil.toAccessExpression((ColumnVisibility) null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToAccessExpressionFromColumnVisibilityEmpty() {
|
||||
ColumnVisibility cv = new ColumnVisibility();
|
||||
AccessExpression ae = AccessExpressionUtil.toAccessExpression(cv);
|
||||
assertEquals("", ae.getExpression());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToAccessExpressionFromColumnVisibility() {
|
||||
ColumnVisibility cv = new ColumnVisibility("A|B");
|
||||
AccessExpression ae = AccessExpressionUtil.toAccessExpression(cv);
|
||||
assertEquals("A|B", ae.getExpression());
|
||||
}
|
||||
|
||||
// -- toAccessExpression(String) --
|
||||
|
||||
@Test
|
||||
public void testToAccessExpressionFromStringNull() {
|
||||
AccessExpression ae = AccessExpressionUtil.toAccessExpression((String) null);
|
||||
assertEquals("", ae.getExpression());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToAccessExpressionFromStringEmpty() {
|
||||
AccessExpression ae = AccessExpressionUtil.toAccessExpression("");
|
||||
assertEquals("", ae.getExpression());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToAccessExpressionFromString() {
|
||||
AccessExpression ae = AccessExpressionUtil.toAccessExpression("X&Y");
|
||||
assertEquals("X&Y", ae.getExpression());
|
||||
}
|
||||
|
||||
// -- toAccessExpression(byte[]) --
|
||||
|
||||
@Test
|
||||
public void testToAccessExpressionFromBytesNull() {
|
||||
AccessExpression ae = AccessExpressionUtil.toAccessExpression((byte[]) null);
|
||||
assertEquals("", ae.getExpression());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToAccessExpressionFromBytesEmpty() {
|
||||
AccessExpression ae = AccessExpressionUtil.toAccessExpression(new byte[0]);
|
||||
assertEquals("", ae.getExpression());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToAccessExpressionFromBytes() {
|
||||
AccessExpression ae = AccessExpressionUtil.toAccessExpression("C&D".getBytes());
|
||||
assertEquals("C&D", ae.getExpression());
|
||||
}
|
||||
|
||||
// -- normalize --
|
||||
|
||||
@Test
|
||||
public void testNormalizeEmpty() {
|
||||
AccessExpression ae = ACCESS.newExpression("");
|
||||
AccessExpression normalized = AccessExpressionUtil.normalize(ae);
|
||||
assertEquals("", normalized.getExpression());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalizeSortsTerms() {
|
||||
AccessExpression ae = ACCESS.newExpression("Z&Y&X");
|
||||
AccessExpression normalized = AccessExpressionUtil.normalize(ae);
|
||||
assertEquals("X&Y&Z", normalized.getExpression());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalizeDeduplicates() {
|
||||
AccessExpression ae = ACCESS.newExpression("A&B&A");
|
||||
AccessExpression normalized = AccessExpressionUtil.normalize(ae);
|
||||
assertEquals("A&B", normalized.getExpression());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalizeFlattensNestedAnds() {
|
||||
AccessExpression ae = ACCESS.newExpression("A&(B&C)");
|
||||
AccessExpression normalized = AccessExpressionUtil.normalize(ae);
|
||||
assertEquals("A&B&C", normalized.getExpression());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalizeSortsOrSubExpressions() {
|
||||
AccessExpression ae = ACCESS.newExpression("(Z&Y)|(C&B)");
|
||||
AccessExpression normalized = AccessExpressionUtil.normalize(ae);
|
||||
assertEquals("(B&C)|(Y&Z)", normalized.getExpression());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalizeRemovesUnnecessaryQuotes() {
|
||||
AccessExpression ae = ACCESS.newExpression("\"ABC\"&\"XYZ\"");
|
||||
AccessExpression normalized = AccessExpressionUtil.normalize(ae);
|
||||
assertEquals("ABC&XYZ", normalized.getExpression());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalizeRemovesUnnecessaryParentheses() {
|
||||
AccessExpression ae = ACCESS.newExpression("(((ABC)|(XYZ)))");
|
||||
AccessExpression normalized = AccessExpressionUtil.normalize(ae);
|
||||
assertEquals("ABC|XYZ", normalized.getExpression());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalizeSingleAuth() {
|
||||
AccessExpression ae = ACCESS.newExpression("ALPHA");
|
||||
AccessExpression normalized = AccessExpressionUtil.normalize(ae);
|
||||
assertEquals("ALPHA", normalized.getExpression());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalizeComplex1() {
|
||||
AccessExpression ae = ACCESS.newExpression("(A&A)|(B&B)|(A&A&A)");
|
||||
AccessExpression normalized = AccessExpressionUtil.normalize(ae);
|
||||
assertEquals("A|B", normalized.getExpression());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalizeComplex2() {
|
||||
AccessExpression ae = ACCESS.newExpression("(Y|B|Y)&(Z|A|Z)");
|
||||
AccessExpression normalized = AccessExpressionUtil.normalize(ae);
|
||||
assertEquals("(A|Z)&(B|Y)", normalized.getExpression());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalizeAlreadyOptimal() {
|
||||
AccessExpression ae = ACCESS.newExpression("(A|B|C)&(B|C|D)");
|
||||
AccessExpression normalized = AccessExpressionUtil.normalize(ae);
|
||||
assertEquals("(A|B|C)&(B|C|D)", normalized.getExpression());
|
||||
}
|
||||
|
||||
// -- emptyExpression / getAccess --
|
||||
|
||||
@Test
|
||||
public void testEmptyExpression() {
|
||||
assertEquals("", AccessExpressionUtil.emptyExpression().getExpression());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAccess() {
|
||||
assertEquals(ACCESS, AccessExpressionUtil.getAccess());
|
||||
}
|
||||
|
||||
// -- round-trip --
|
||||
|
||||
@Test
|
||||
public void testRoundTripColumnVisibilityToAccessExpression() {
|
||||
ColumnVisibility original = new ColumnVisibility("A&B&C");
|
||||
AccessExpression ae = AccessExpressionUtil.toAccessExpression(original);
|
||||
ColumnVisibility roundTripped = AccessExpressionUtil.toColumnVisibility(ae);
|
||||
assertEquals(new String(original.getExpression()), new String(roundTripped.getExpression()));
|
||||
}
|
||||
|
||||
// -- NormalizedExpression --
|
||||
|
||||
@Test
|
||||
public void testNormalizedExpressionCompareTo() {
|
||||
var a = new AccessExpressionUtil.NormalizedExpression("A", ParsedAccessExpression.ExpressionType.AUTHORIZATION);
|
||||
var b = new AccessExpressionUtil.NormalizedExpression("B", ParsedAccessExpression.ExpressionType.AUTHORIZATION);
|
||||
assertTrue(a.compareTo(b) < 0);
|
||||
assertTrue(b.compareTo(a) > 0);
|
||||
assertEquals(0, a.compareTo(a));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNormalizedExpressionEquals() {
|
||||
var a = new AccessExpressionUtil.NormalizedExpression("A", ParsedAccessExpression.ExpressionType.AUTHORIZATION);
|
||||
var aDuplicate = new AccessExpressionUtil.NormalizedExpression("A", ParsedAccessExpression.ExpressionType.AUTHORIZATION);
|
||||
assertEquals(a, aDuplicate);
|
||||
}
|
||||
}
|
||||
+64
-26
@@ -1,61 +1,99 @@
|
||||
package datawave.marking;
|
||||
|
||||
import static datawave.marking.MarkingFunctions.Default.COLUMN_VISIBILITY;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.accumulo.core.security.ColumnVisibility;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
public class MarkingFunctionsDefaultCombineTest {
|
||||
|
||||
@Test
|
||||
public void testCombineAnds() throws MarkingFunctions.Exception {
|
||||
MarkingFunctions markingFunctions = new MarkingFunctions.Default();
|
||||
MarkingFunctions<AccessExpressionMarkings> markingFunctions = new MarkingFunctions.Default();
|
||||
|
||||
ColumnVisibility oneAnna = new ColumnVisibility("A&B");
|
||||
ColumnVisibility twoAnna = new ColumnVisibility("A&C");
|
||||
AccessExpressionMarkings oneAnna = AccessExpressionMarkings.builder().columnVisibility("A&B").build();
|
||||
AccessExpressionMarkings twoAnna = AccessExpressionMarkings.builder().columnVisibility("A&C").build();
|
||||
|
||||
ColumnVisibility combined = markingFunctions.combine(Sets.newHashSet(oneAnna, twoAnna));
|
||||
assertEquals(new ColumnVisibility("A&B&C"), combined);
|
||||
AccessExpressionMarkings combined = markingFunctions.combine(List.of(oneAnna, twoAnna));
|
||||
assertEquals(AccessExpressionMarkings.builder().columnVisibility("A&B&C").build(), combined);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCombineOrs() throws MarkingFunctions.Exception {
|
||||
MarkingFunctions markingFunctions = new MarkingFunctions.Default();
|
||||
MarkingFunctions<AccessExpressionMarkings> markingFunctions = new MarkingFunctions.Default();
|
||||
|
||||
ColumnVisibility oneOr = new ColumnVisibility("A|B");
|
||||
ColumnVisibility twoOr = new ColumnVisibility("A|C");
|
||||
AccessExpressionMarkings oneOr = AccessExpressionMarkings.builder().columnVisibility("A|B").build();
|
||||
AccessExpressionMarkings twoOr = AccessExpressionMarkings.builder().columnVisibility("A|C").build();
|
||||
|
||||
ColumnVisibility combined = markingFunctions.combine(Sets.newHashSet(oneOr, twoOr));
|
||||
assertEquals(new ColumnVisibility("(A|B)&(A|C)"), combined);
|
||||
AccessExpressionMarkings combined = markingFunctions.combine(List.of(oneOr, twoOr));
|
||||
assertEquals(AccessExpressionMarkings.builder().columnVisibility("(A|B)&(A|C)").build(), combined);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCombineMapsOfAnds() throws MarkingFunctions.Exception {
|
||||
MarkingFunctions markingFunctions = new MarkingFunctions.Default();
|
||||
MarkingFunctions<AccessExpressionMarkings> markingFunctions = new MarkingFunctions.Default();
|
||||
|
||||
Map<String,String> mapOne = ImmutableMap.of(COLUMN_VISIBILITY, "A&B");
|
||||
Map<String,String> mapTwo = ImmutableMap.of(COLUMN_VISIBILITY, "A&C");
|
||||
AccessExpressionMarkings cv1 = AccessExpressionMarkings.builder().columnVisibility("A&B").build();
|
||||
AccessExpressionMarkings cv2 = AccessExpressionMarkings.builder().columnVisibility("A&C").build();
|
||||
AccessExpressionMarkings expected = AccessExpressionMarkings.builder().columnVisibility("A&B&C").build();
|
||||
|
||||
Map<String,String> expected = ImmutableMap.of(COLUMN_VISIBILITY, "A&B&C");
|
||||
|
||||
assertEquals(expected, markingFunctions.combine(mapOne, mapTwo));
|
||||
assertEquals(expected, markingFunctions.combine(List.of(cv1, cv2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCombineMapsOfOrs() throws MarkingFunctions.Exception {
|
||||
MarkingFunctions markingFunctions = new MarkingFunctions.Default();
|
||||
MarkingFunctions<AccessExpressionMarkings> markingFunctions = new MarkingFunctions.Default();
|
||||
|
||||
Map<String,String> mapOne = ImmutableMap.of(COLUMN_VISIBILITY, "A|B");
|
||||
Map<String,String> mapTwo = ImmutableMap.of(COLUMN_VISIBILITY, "A|C");
|
||||
AccessExpressionMarkings cv1 = AccessExpressionMarkings.builder().columnVisibility("A|B").build();
|
||||
AccessExpressionMarkings cv2 = AccessExpressionMarkings.builder().columnVisibility("A|C").build();
|
||||
AccessExpressionMarkings expected = AccessExpressionMarkings.builder().columnVisibility("(A|B)&(A|C)").build();
|
||||
|
||||
Map<String,String> expected = ImmutableMap.of(COLUMN_VISIBILITY, "(A|B)&(A|C)");
|
||||
assertEquals(expected, markingFunctions.combine(List.of(cv1, cv2)));
|
||||
}
|
||||
|
||||
assertEquals(expected, markingFunctions.combine(mapOne, mapTwo));
|
||||
@Test
|
||||
public void testCombineSkipsNullMarkings() throws MarkingFunctions.Exception {
|
||||
MarkingFunctions<AccessExpressionMarkings> markingFunctions = new MarkingFunctions.Default();
|
||||
|
||||
AccessExpressionMarkings aem1 = AccessExpressionMarkings.builder().columnVisibility("A&B").build();
|
||||
AccessExpressionMarkings aem2 = AccessExpressionMarkings.builder().columnVisibility("A&C").build();
|
||||
AccessExpressionMarkings expected = AccessExpressionMarkings.builder().columnVisibility("A&B&C").build();
|
||||
|
||||
Collection<Markings<?>> markings = new ArrayList<>(Arrays.asList(aem1, null, aem2, null));
|
||||
assertEquals(expected, markingFunctions.combine(markings));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCombineAllNullMarkingsReturnsNull() throws MarkingFunctions.Exception {
|
||||
MarkingFunctions<AccessExpressionMarkings> markingFunctions = new MarkingFunctions.Default();
|
||||
|
||||
Collection<Markings<?>> markings = new ArrayList<>(Arrays.asList(null, null));
|
||||
assertNull(markingFunctions.combine(markings));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCombineVisibilitiesSkipsNullElements() throws MarkingFunctions.Exception {
|
||||
MarkingFunctions<AccessExpressionMarkings> markingFunctions = new MarkingFunctions.Default();
|
||||
|
||||
ColumnVisibility vis1 = new ColumnVisibility("A&B");
|
||||
ColumnVisibility vis2 = new ColumnVisibility("A&C");
|
||||
|
||||
Collection<ColumnVisibility> visibilities = new ArrayList<>(Arrays.asList(vis1, null, vis2, null));
|
||||
ColumnVisibility combined = markingFunctions.combineVisibilities(visibilities);
|
||||
assertEquals(new ColumnVisibility("A&B&C"), combined);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCombineVisibilitiesAllNullsReturnsEmpty() throws MarkingFunctions.Exception {
|
||||
MarkingFunctions<AccessExpressionMarkings> markingFunctions = new MarkingFunctions.Default();
|
||||
|
||||
Collection<ColumnVisibility> visibilities = new ArrayList<>(Arrays.asList(null, null));
|
||||
assertEquals(new ColumnVisibility(), markingFunctions.combineVisibilities(visibilities));
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -54,7 +54,7 @@ public class FrequencyMetadataAggregator extends WrappingIterator implements Opt
|
||||
|
||||
private static final Logger log = Logger.getLogger(FrequencyMetadataAggregator.class);
|
||||
private static final String NULL_BYTE = "\0";
|
||||
private static final MarkingFunctions markingFunctions = MarkingFunctions.Factory.createMarkingFunctions();
|
||||
private final MarkingFunctions<?> markingFunctions;
|
||||
|
||||
private boolean combineVisibilities;
|
||||
private String columnsOption;
|
||||
@@ -82,6 +82,7 @@ public class FrequencyMetadataAggregator extends WrappingIterator implements Opt
|
||||
cache = new TreeMap<>();
|
||||
visibilityToDateFrequencies = new HashMap<>();
|
||||
visibilityToMaxTimestamp = new HashMap<>();
|
||||
markingFunctions = MarkingFunctions.Factory.createMarkingFunctions();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -584,9 +585,8 @@ public class FrequencyMetadataAggregator extends WrappingIterator implements Opt
|
||||
private ColumnVisibility combineAllVisibilities() {
|
||||
Set<ColumnVisibility> visibilities = visibilityToDateFrequencies.keySet();
|
||||
try {
|
||||
return markingFunctions.combine(visibilities);
|
||||
return markingFunctions.combineVisibilities(visibilities);
|
||||
} catch (MarkingFunctions.Exception e) {
|
||||
log.error("Failed to combine visibilities " + visibilities);
|
||||
throw new IllegalArgumentException("Failed to combine visibilities " + visibilities, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,6 +127,9 @@ public class ModelKeyParser {
|
||||
}
|
||||
|
||||
public static Key createKey(FieldMapping mapping, String modelName) {
|
||||
if (null == mapping.getColumnVisibility()) {
|
||||
throw new RuntimeException("ColumnVisibility was null, unable to create Accumulo mutation");
|
||||
}
|
||||
ColumnVisibility cv = new ColumnVisibility(mapping.getColumnVisibility());
|
||||
|
||||
String dataType = StringUtils.isEmpty(mapping.getDatatype()) ? "" : NULL_BYTE + mapping.getDatatype().trim();
|
||||
@@ -185,6 +188,9 @@ public class ModelKeyParser {
|
||||
}
|
||||
|
||||
public static Mutation createMutation(FieldMapping mapping, String modelName) {
|
||||
if (null == mapping.getColumnVisibility()) {
|
||||
throw new RuntimeException("ColumnVisibility was null, unable to create Accumulo mutation");
|
||||
}
|
||||
ColumnVisibility cv = new ColumnVisibility(mapping.getColumnVisibility());
|
||||
Mutation m;
|
||||
String dataType = StringUtils.isEmpty(mapping.getDatatype()) ? "" : NULL_BYTE + mapping.getDatatype().trim();
|
||||
@@ -208,6 +214,9 @@ public class ModelKeyParser {
|
||||
}
|
||||
|
||||
public static Mutation createDeleteMutation(FieldMapping mapping, String modelName) {
|
||||
if (null == mapping.getColumnVisibility()) {
|
||||
throw new RuntimeException("ColumnVisibility was null, unable to create Accumulo mutation");
|
||||
}
|
||||
ColumnVisibility cv = new ColumnVisibility(mapping.getColumnVisibility());
|
||||
Mutation m;
|
||||
String dataType = StringUtils.isEmpty(mapping.getDatatype()) ? "" : NULL_BYTE + mapping.getDatatype().trim();
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|datawave\.test.*|
|
||||
|gov.nsa.datawave.*)" regex="true" strategyOnMismatch="allowed">
|
||||
<!-- API packages -->
|
||||
<allow pkg="org.apache.accumulo.access"/>
|
||||
<allow pkg="org.apache.accumulo.core.client"/>
|
||||
<allow pkg="org.apache.accumulo.core.data"/>
|
||||
<allow pkg="org.apache.accumulo.core.security"/>
|
||||
|
||||
@@ -51,12 +51,6 @@
|
||||
<groupId>gov.nsa.datawave.core</groupId>
|
||||
<artifactId>accumulo-utils</artifactId>
|
||||
<version>${version.datawave}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>gov.nsa.datawave.core</groupId>
|
||||
|
||||
+10
-18
@@ -2,16 +2,15 @@ package datawave.webservice.response.objects;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
|
||||
import org.apache.accumulo.access.AccessExpression;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
|
||||
import datawave.marking.MarkingFunctions;
|
||||
import datawave.marking.AccessExpressionMarkings;
|
||||
import datawave.marking.Markings;
|
||||
import datawave.webservice.query.util.TypedValue;
|
||||
|
||||
@XmlAccessorType(XmlAccessType.NONE)
|
||||
@@ -87,18 +86,14 @@ public class DefaultKey extends KeyBase {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMarkings(Map<String,String> markings) {
|
||||
HashMap<String,String> markingMap = new HashMap<>();
|
||||
if (markings != null) {
|
||||
markingMap.putAll(markings);
|
||||
}
|
||||
this.markings = markingMap;
|
||||
|
||||
setColumnVisibility(markingMap.getOrDefault(MarkingFunctions.Default.COLUMN_VISIBILITY, ""));
|
||||
public void setMarkings(Markings<?> markings) {
|
||||
this.markings = markings;
|
||||
AccessExpression ae = markings.toAccessExpression();
|
||||
this.columnVisibility = new TypedValue(ae != null ? ae.getExpression() : "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String,String> getMarkings() {
|
||||
public Markings<?> getMarkings() {
|
||||
return this.markings;
|
||||
}
|
||||
|
||||
@@ -116,11 +111,8 @@ public class DefaultKey extends KeyBase {
|
||||
|
||||
public void setColumnVisibility(String colVis) {
|
||||
this.columnVisibility = (colVis == null) ? new TypedValue("") : new TypedValue(colVis);
|
||||
if (markings == null) {
|
||||
markings = new HashMap<>();
|
||||
}
|
||||
markings.put(MarkingFunctions.Default.COLUMN_VISIBILITY, this.columnVisibility.getValue().toString());
|
||||
|
||||
String expr = this.columnVisibility.getValue().toString();
|
||||
this.markings = AccessExpressionMarkings.builder().columnVisibility(expr).build();
|
||||
}
|
||||
|
||||
public void setTimestamp(long timestamp) {
|
||||
|
||||
+2
-3
@@ -1,18 +1,17 @@
|
||||
package datawave.webservice.response.objects;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlSeeAlso;
|
||||
|
||||
import datawave.marking.Markings;
|
||||
import datawave.webservice.query.result.event.HasMarkings;
|
||||
|
||||
@XmlAccessorType(XmlAccessType.NONE)
|
||||
@XmlSeeAlso(DefaultKey.class)
|
||||
public abstract class KeyBase implements HasMarkings {
|
||||
|
||||
protected Map<String,String> markings;
|
||||
protected Markings<?> markings;
|
||||
|
||||
public abstract String getRow();
|
||||
|
||||
|
||||
+7
-16
@@ -1,17 +1,13 @@
|
||||
package datawave.webservice.response.objects;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessOrder;
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorOrder;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
import javax.xml.bind.annotation.XmlTransient;
|
||||
|
||||
import datawave.webservice.xml.util.StringMapAdapter;
|
||||
import datawave.marking.Markings;
|
||||
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
@XmlAccessorOrder(XmlAccessOrder.ALPHABETICAL)
|
||||
@@ -20,9 +16,8 @@ public class Visibility {
|
||||
@XmlAttribute(name = "valid")
|
||||
private Boolean valid;
|
||||
|
||||
@XmlElement(name = "markings")
|
||||
@XmlJavaTypeAdapter(StringMapAdapter.class)
|
||||
private HashMap<String,String> markings;
|
||||
@XmlTransient
|
||||
private Markings<?> markings;
|
||||
|
||||
@XmlAttribute(name = "visibility")
|
||||
private String visibility;
|
||||
@@ -43,16 +38,12 @@ public class Visibility {
|
||||
this.visibility = visibility;
|
||||
}
|
||||
|
||||
public Map<String,String> getMarkings() {
|
||||
public Markings<?> getMarkings() {
|
||||
return markings;
|
||||
}
|
||||
|
||||
public void setMarkings(Map<String,String> markings) {
|
||||
if (this.markings == null) {
|
||||
this.markings = new HashMap<String,String>();
|
||||
}
|
||||
this.markings.clear();
|
||||
this.markings.putAll(markings);
|
||||
public void setMarkings(Markings<?> markings) {
|
||||
this.markings = markings;
|
||||
}
|
||||
|
||||
}
|
||||
+2
-4
@@ -6,9 +6,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -19,6 +17,7 @@ import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import com.fasterxml.jackson.databind.type.TypeFactory;
|
||||
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector;
|
||||
|
||||
import datawave.marking.AccessExpressionMarkings;
|
||||
import datawave.webservice.query.exception.QueryExceptionType;
|
||||
import datawave.webservice.response.objects.DefaultKey;
|
||||
import datawave.webservice.response.objects.Entry;
|
||||
@@ -39,8 +38,7 @@ public class LookupResponseTest {
|
||||
lookupResponse = new LookupResponse();
|
||||
List<Entry> entryList = new ArrayList<>();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
Map<String,String> markings = new HashMap<>();
|
||||
markings.put("columnVisibility", "A&B&C" + i);
|
||||
AccessExpressionMarkings markings = AccessExpressionMarkings.builder().columnVisibility("A&B&C" + i).build();
|
||||
KeyBase responseKey = new DefaultKey();
|
||||
responseKey.setRow("row" + i);
|
||||
responseKey.setColFam("cf" + i);
|
||||
|
||||
@@ -69,6 +69,11 @@
|
||||
<artifactId>base-rest-responses</artifactId>
|
||||
<version>${version.datawave}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>gov.nsa.datawave.core</groupId>
|
||||
<artifactId>datawave-core-common-util</artifactId>
|
||||
<version>${version.datawave}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>gov.nsa.datawave.core</groupId>
|
||||
<artifactId>type-utils</artifactId>
|
||||
@@ -229,6 +234,10 @@
|
||||
<groupId>gov.nsa.datawave.core</groupId>
|
||||
<artifactId>base-rest-responses</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>gov.nsa.datawave.core</groupId>
|
||||
<artifactId>datawave-core-common-util</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>gov.nsa.datawave.core</groupId>
|
||||
<artifactId>type-utils</artifactId>
|
||||
|
||||
+4
-3
@@ -42,6 +42,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import datawave.marking.MarkingFunctions;
|
||||
import datawave.marking.Markings;
|
||||
import datawave.webservice.query.util.OptionallyEncodedString;
|
||||
import datawave.webservice.request.UpdateRequest;
|
||||
import datawave.webservice.request.objects.MutationEntry;
|
||||
@@ -68,11 +69,11 @@ import datawave.webservice.result.VoidResponse;
|
||||
public class AdminService {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
private final MarkingFunctions markingFunctions;
|
||||
private final MarkingFunctions<?> markingFunctions;
|
||||
private final AccumuloClient warehouseAccumuloClient;
|
||||
|
||||
@Autowired
|
||||
public AdminService(@Qualifier("warehouse") AccumuloClient warehouseAccumuloClient, MarkingFunctions markingFunctions) {
|
||||
public AdminService(@Qualifier("warehouse") AccumuloClient warehouseAccumuloClient, MarkingFunctions<?> markingFunctions) {
|
||||
this.warehouseAccumuloClient = warehouseAccumuloClient;
|
||||
this.markingFunctions = markingFunctions;
|
||||
}
|
||||
@@ -569,7 +570,7 @@ public class AdminService {
|
||||
vis.setValid(false);
|
||||
visibilityList.add(vis);
|
||||
try {
|
||||
Map<String,String> markings = markingFunctions.translateFromColumnVisibilityForAuths(new ColumnVisibility(v), authorizations);
|
||||
Markings<?> markings = markingFunctions.translateFromColumnVisibilityForAuths(new ColumnVisibility(v), authorizations);
|
||||
vis.setVisibility(v);
|
||||
vis.setValid(true);
|
||||
vis.setMarkings(markings);
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ public class AccumuloConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public MarkingFunctions markingFunctions() {
|
||||
public MarkingFunctions<?> markingFunctions() {
|
||||
return new MarkingFunctions.Default();
|
||||
}
|
||||
|
||||
|
||||
+4
-8
@@ -36,6 +36,7 @@ import com.google.common.base.Preconditions;
|
||||
|
||||
import datawave.accumulo.util.security.UserAuthFunctions;
|
||||
import datawave.marking.MarkingFunctions;
|
||||
import datawave.marking.Markings;
|
||||
import datawave.marking.SecurityMarking;
|
||||
import datawave.microservice.accumulo.lookup.config.LookupAuditProperties;
|
||||
import datawave.microservice.accumulo.lookup.config.LookupProperties;
|
||||
@@ -82,7 +83,7 @@ public class LookupService {
|
||||
}
|
||||
|
||||
private final SecurityMarking auditSecurityMarking;
|
||||
private final MarkingFunctions markingFunctions;
|
||||
private final MarkingFunctions<?> markingFunctions;
|
||||
private final AccumuloClient connection;
|
||||
private final LookupAuditProperties lookupAuditProperties;
|
||||
private final LookupProperties lookupProperties;
|
||||
@@ -97,7 +98,7 @@ public class LookupService {
|
||||
public LookupService(
|
||||
@Qualifier("auditLookupSecurityMarking")
|
||||
SecurityMarking auditSecurityMarking,
|
||||
MarkingFunctions markingFunctions,
|
||||
MarkingFunctions<?> markingFunctions,
|
||||
@Qualifier("warehouse")
|
||||
AccumuloClient connection,
|
||||
LookupAuditProperties lookupAuditProperties,
|
||||
@@ -218,12 +219,7 @@ public class LookupService {
|
||||
continue;
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
final Map<String,String> markings = markingFunctions.translateFromColumnVisibilityForAuths(
|
||||
new ColumnVisibility(k.getColumnVisibility()),
|
||||
mergedAuths
|
||||
);
|
||||
//@formatter:on
|
||||
final Markings<?> markings = markingFunctions.translateFromColumnVisibilityForAuths(new ColumnVisibility(k.getColumnVisibility()), mergedAuths);
|
||||
|
||||
final KeyBase responseKey = responseObjectFactory.createKey();
|
||||
responseKey.setRow(currRow);
|
||||
|
||||
@@ -31,6 +31,11 @@
|
||||
<artifactId>guava</artifactId>
|
||||
<version>${version.guava}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>gov.nsa.datawave.core</groupId>
|
||||
<artifactId>accumulo-utils</artifactId>
|
||||
<version>${version.datawave}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>gov.nsa.datawave.core</groupId>
|
||||
<artifactId>base-rest-responses</artifactId>
|
||||
@@ -69,6 +74,10 @@
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>gov.nsa.datawave.core</groupId>
|
||||
<artifactId>accumulo-utils</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>gov.nsa.datawave.core</groupId>
|
||||
<artifactId>base-rest-responses</artifactId>
|
||||
|
||||
+15
-12
@@ -2,17 +2,17 @@ package datawave.webservice.dictionary.data;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessOrder;
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorOrder;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlTransient;
|
||||
|
||||
import datawave.webservice.query.result.event.MapSchema;
|
||||
import datawave.marking.AccessExpressionMarkings;
|
||||
import datawave.marking.Markings;
|
||||
import io.protostuff.Input;
|
||||
import io.protostuff.Message;
|
||||
import io.protostuff.Output;
|
||||
@@ -29,11 +29,12 @@ public class DefaultDescription extends DescriptionBase<DefaultDescription> impl
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public DefaultDescription(String description, Map<String,String> markings) {
|
||||
public DefaultDescription(String description, Markings<?> markings) {
|
||||
this.description = description;
|
||||
this.markings = markings;
|
||||
}
|
||||
|
||||
@XmlElement(name = "description")
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
@@ -43,12 +44,14 @@ public class DefaultDescription extends DescriptionBase<DefaultDescription> impl
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMarkings(Map<String,String> markings) {
|
||||
this.markings = markings;
|
||||
@XmlElement(name = "markings", type = AccessExpressionMarkings.class)
|
||||
public Markings<?> getMarkings() {
|
||||
return this.markings;
|
||||
}
|
||||
|
||||
public Map<String,String> getMarkings() {
|
||||
return this.markings;
|
||||
@Override
|
||||
public void setMarkings(Markings<?> markings) {
|
||||
this.markings = markings;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -86,7 +89,7 @@ public class DefaultDescription extends DescriptionBase<DefaultDescription> impl
|
||||
}
|
||||
|
||||
@XmlTransient
|
||||
private static final Schema<DefaultDescription> SCHEMA = new Schema<DefaultDescription>() {
|
||||
private static final Schema<DefaultDescription> SCHEMA = new Schema<>() {
|
||||
public DefaultDescription newMessage() {
|
||||
return new DefaultDescription();
|
||||
}
|
||||
@@ -112,7 +115,7 @@ public class DefaultDescription extends DescriptionBase<DefaultDescription> impl
|
||||
output.writeString(1, message.description, false);
|
||||
}
|
||||
if (message.markings != null)
|
||||
output.writeObject(1, message.markings, MapSchema.SCHEMA, false);
|
||||
output.writeObject(2, (AccessExpressionMarkings) message.markings, AccessExpressionMarkings.SCHEMA, false);
|
||||
}
|
||||
|
||||
public void mergeFrom(Input input, DefaultDescription message) throws IOException {
|
||||
@@ -123,8 +126,8 @@ public class DefaultDescription extends DescriptionBase<DefaultDescription> impl
|
||||
message.description = input.readString();
|
||||
break;
|
||||
case 2:
|
||||
message.markings = new HashMap<String,String>();
|
||||
input.mergeObject(message.markings, MapSchema.SCHEMA);
|
||||
message.markings = AccessExpressionMarkings.builder().build();
|
||||
input.mergeObject((AccessExpressionMarkings) message.markings, AccessExpressionMarkings.SCHEMA);
|
||||
break;
|
||||
default:
|
||||
input.handleUnknownField(number, this);
|
||||
|
||||
+2
-9
@@ -1,25 +1,18 @@
|
||||
package datawave.webservice.dictionary.data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
|
||||
import datawave.marking.Markings;
|
||||
import datawave.webservice.query.result.event.HasMarkings;
|
||||
import datawave.webservice.xml.util.StringMapAdapter;
|
||||
import io.protostuff.Message;
|
||||
|
||||
@XmlAccessorType(XmlAccessType.NONE)
|
||||
public abstract class DescriptionBase<T> implements HasMarkings, Message<T> {
|
||||
|
||||
@XmlElement(name = "description")
|
||||
protected String description;
|
||||
|
||||
@XmlElement(name = "markings")
|
||||
@XmlJavaTypeAdapter(StringMapAdapter.class)
|
||||
protected Map<String,String> markings;
|
||||
protected Markings<?> markings;
|
||||
|
||||
public abstract String getDescription();
|
||||
|
||||
|
||||
+3
-5
@@ -24,6 +24,7 @@ import io.protostuff.Input;
|
||||
import io.protostuff.Message;
|
||||
import io.protostuff.Output;
|
||||
import io.protostuff.Schema;
|
||||
import lombok.Setter;
|
||||
|
||||
@XmlRootElement(name = "EdgeDictionary")
|
||||
@XmlAccessorType(XmlAccessType.NONE)
|
||||
@@ -33,6 +34,7 @@ public class DefaultEdgeDictionary extends EdgeDictionaryBase<DefaultEdgeDiction
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final String TITLE = "Edge Dictionary", SEP = ", ";
|
||||
@Setter
|
||||
private String edgeDictionarySystem = null;
|
||||
|
||||
@XmlElementWrapper(name = "EdgeMetadata")
|
||||
@@ -64,10 +66,6 @@ public class DefaultEdgeDictionary extends EdgeDictionaryBase<DefaultEdgeDiction
|
||||
return edgeDictionarySystem == null ? null : edgeDictionarySystem;
|
||||
}
|
||||
|
||||
public void setEdgeDictionarySystem(String edgeDictionarySystem) {
|
||||
this.edgeDictionarySystem = edgeDictionarySystem;
|
||||
}
|
||||
|
||||
public static Schema<DefaultEdgeDictionary> getSchema() {
|
||||
return SCHEMA;
|
||||
}
|
||||
@@ -227,7 +225,7 @@ public class DefaultEdgeDictionary extends EdgeDictionaryBase<DefaultEdgeDiction
|
||||
fieldBuilder.append(field).append(SEP);
|
||||
}
|
||||
|
||||
String fieldNames = fieldBuilder.toString().substring(0, fieldBuilder.length() - 2);
|
||||
String fieldNames = fieldBuilder.substring(0, fieldBuilder.length() - 2);
|
||||
String date = metadata.getStartDate();
|
||||
|
||||
builder.append("<td>").append(type).append("</td>");
|
||||
|
||||
+4
-12
@@ -1,14 +1,12 @@
|
||||
package datawave.webservice.dictionary.edge;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlSeeAlso;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import datawave.marking.Markings;
|
||||
import datawave.webservice.query.result.event.HasMarkings;
|
||||
import io.protostuff.Message;
|
||||
|
||||
@@ -16,19 +14,13 @@ import io.protostuff.Message;
|
||||
@XmlSeeAlso(DefaultMetadata.class)
|
||||
public abstract class MetadataBase<T> implements HasMarkings, Message<T> {
|
||||
|
||||
protected transient Map<String,String> markings;
|
||||
protected transient Markings<?> markings;
|
||||
|
||||
public Map<String,String> getMarkings() {
|
||||
assureMarkings();
|
||||
public Markings<?> getMarkings() {
|
||||
return markings;
|
||||
}
|
||||
|
||||
protected void assureMarkings() {
|
||||
if (this.markings == null)
|
||||
this.markings = Maps.newHashMap();
|
||||
}
|
||||
|
||||
public void setMarkings(Map<String,String> markings) {
|
||||
public void setMarkings(Markings<?> markings) {
|
||||
this.markings = markings;
|
||||
}
|
||||
|
||||
|
||||
+6
-7
@@ -7,7 +7,6 @@ import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
@@ -21,9 +20,9 @@ import javax.xml.bind.annotation.XmlType;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
|
||||
import datawave.marking.AccessExpressionMarkings;
|
||||
import datawave.webservice.dictionary.data.DefaultDescription;
|
||||
import datawave.webservice.dictionary.data.DescriptionBase;
|
||||
import datawave.webservice.query.result.event.MapSchema;
|
||||
import io.protostuff.Input;
|
||||
import io.protostuff.Message;
|
||||
import io.protostuff.Output;
|
||||
@@ -73,7 +72,7 @@ public class DefaultMetadataField extends MetadataFieldBase<DefaultMetadataField
|
||||
private String lastUpdated;
|
||||
|
||||
public Boolean isIndexOnly() {
|
||||
return indexOnly == null ? false : indexOnly;
|
||||
return indexOnly != null && indexOnly;
|
||||
}
|
||||
|
||||
public Boolean isForwardIndexed() {
|
||||
@@ -137,7 +136,7 @@ public class DefaultMetadataField extends MetadataFieldBase<DefaultMetadataField
|
||||
}
|
||||
|
||||
@XmlTransient
|
||||
private static final Schema<DefaultMetadataField> SCHEMA = new Schema<DefaultMetadataField>() {
|
||||
private static final Schema<DefaultMetadataField> SCHEMA = new Schema<>() {
|
||||
private final HashMap<String,Integer> fieldMap = new HashMap<>();
|
||||
{
|
||||
fieldMap.put("fieldName", 1);
|
||||
@@ -250,8 +249,8 @@ public class DefaultMetadataField extends MetadataFieldBase<DefaultMetadataField
|
||||
int size = input.readInt32();
|
||||
message.descriptions = new HashSet<>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
Map<String,String> markings = new HashMap<>();
|
||||
input.mergeObject(markings, MapSchema.SCHEMA);
|
||||
AccessExpressionMarkings markings = AccessExpressionMarkings.builder().build();
|
||||
input.mergeObject(markings, AccessExpressionMarkings.SCHEMA);
|
||||
message.descriptions.add(new DefaultDescription(input.readString(), markings));
|
||||
}
|
||||
break;
|
||||
@@ -295,7 +294,7 @@ public class DefaultMetadataField extends MetadataFieldBase<DefaultMetadataField
|
||||
output.writeInt32(9, message.getDescriptions().size(), false);
|
||||
for (DescriptionBase desc : message.getDescriptions()) {
|
||||
output.writeString(9, desc.getDescription(), true);
|
||||
output.writeObject(9, desc.getMarkings(), MapSchema.SCHEMA, false);
|
||||
output.writeObject(9, (AccessExpressionMarkings) desc.getMarkings(), AccessExpressionMarkings.SCHEMA, false);
|
||||
}
|
||||
output.writeString(10, message.lastUpdated, false);
|
||||
output.writeBool(11, message.tokenized, false);
|
||||
|
||||
+22
-25
@@ -7,10 +7,8 @@ import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
@@ -21,17 +19,31 @@ import javax.xml.bind.annotation.XmlSchema;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import datawave.marking.AccessExpressionMarkings;
|
||||
|
||||
public class DefaultDescriptionTest {
|
||||
|
||||
@Test
|
||||
public void testMarshall() throws JAXBException {
|
||||
JAXBContext j = JAXBContext.newInstance(DefaultFields.class);
|
||||
|
||||
Map<String,String> markings = new HashMap<>();
|
||||
markings.put("columnVisibility", "PRIVATE");
|
||||
DefaultFields dicFieldsList = getDefaultFields();
|
||||
|
||||
Marshaller m = j.createMarshaller();
|
||||
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
m.marshal(dicFieldsList, out);
|
||||
|
||||
String result = out.toString();
|
||||
|
||||
assertTrue(result.contains("<columnVisibility>PRIVATE</columnVisibility>"));
|
||||
assertTrue(result.contains("<description>my description</description>"));
|
||||
}
|
||||
|
||||
private static DefaultFields getDefaultFields() {
|
||||
DefaultDescription desc = new DefaultDescription();
|
||||
desc.setMarkings(markings);
|
||||
desc.setMarkings(AccessExpressionMarkings.create("PRIVATE"));
|
||||
desc.setDescription("my description");
|
||||
|
||||
Set<DefaultDescription> descs = new HashSet<>();
|
||||
@@ -47,18 +59,7 @@ public class DefaultDescriptionTest {
|
||||
|
||||
DefaultFields dicFieldsList = new DefaultFields();
|
||||
dicFieldsList.setFields(dicFields);
|
||||
|
||||
Marshaller m = j.createMarshaller();
|
||||
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
m.marshal(dicFieldsList, out);
|
||||
|
||||
String result = out.toString();
|
||||
|
||||
assertTrue(result.contains("<key>columnVisibility</key>"));
|
||||
assertTrue(result.contains("<value>PRIVATE</value>"));
|
||||
assertTrue(result.contains("<description>my description</description>"));
|
||||
return dicFieldsList;
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -83,10 +84,7 @@ public class DefaultDescriptionTest {
|
||||
+ " <descriptions>\n"
|
||||
+ " <description>my description</description>\n"
|
||||
+ " <markings>\n"
|
||||
+ " <entry>\n"
|
||||
+ " <key>columnVisibility</key>\n"
|
||||
+ " <value>PRIVATE</value>\n"
|
||||
+ " </entry>\n"
|
||||
+ " <columnVisibility>PRIVATE</columnVisibility>\n"
|
||||
+ " </markings>\n"
|
||||
+ " </descriptions>\n"
|
||||
+ " <fieldName>myField</fieldName>\n"
|
||||
@@ -107,9 +105,9 @@ public class DefaultDescriptionTest {
|
||||
assertEquals("myType", f.getDatatype());
|
||||
for (DefaultDescription d : f.getDescriptions()) {
|
||||
assertEquals("my description", d.getDescription());
|
||||
Map<String,String> m = d.getMarkings();
|
||||
assertEquals("PRIVATE", m.get("columnVisibility"));
|
||||
markingCount = m.size();
|
||||
assertTrue(d.getMarkings() instanceof AccessExpressionMarkings);
|
||||
AccessExpressionMarkings aem = (AccessExpressionMarkings) d.getMarkings();
|
||||
assertEquals("PRIVATE", aem.getColumnVisibilityString());
|
||||
descriptionCount++;
|
||||
}
|
||||
fieldCount++;
|
||||
@@ -117,6 +115,5 @@ public class DefaultDescriptionTest {
|
||||
|
||||
assertEquals(1, fieldCount);
|
||||
assertEquals(1, descriptionCount);
|
||||
assertEquals(1, markingCount);
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -14,6 +14,8 @@ import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
import datawave.marking.AccessExpressionMarkings;
|
||||
import datawave.marking.Markings;
|
||||
import datawave.microservice.AccumuloConnectionService;
|
||||
import datawave.microservice.Connection;
|
||||
import datawave.microservice.authorization.user.DatawaveUserDetails;
|
||||
@@ -167,8 +169,7 @@ public class DataDictionaryControllerLogic<DESC extends DescriptionBase<DESC>,DI
|
||||
public VoidResponse setDescriptionPost(String fieldName, String datatype, String description, String modelName, String modelTable, String columnVisibility,
|
||||
DatawaveUserDetails currentUser) throws Exception {
|
||||
DESC desc = this.responseObjectFactory.getDescription();
|
||||
Map<String,String> markings = Maps.newHashMap();
|
||||
markings.put("columnVisibility", columnVisibility);
|
||||
Markings<?> markings = AccessExpressionMarkings.builder().columnVisibility(columnVisibility).build();
|
||||
desc.setMarkings(markings);
|
||||
desc.setDescription(description);
|
||||
|
||||
@@ -281,8 +282,7 @@ public class DataDictionaryControllerLogic<DESC extends DescriptionBase<DESC>,DI
|
||||
*/
|
||||
public VoidResponse deleteDescription(String fieldName, String datatype, String modelName, String modelTable, String columnVisibility,
|
||||
DatawaveUserDetails currentUser) throws Exception {
|
||||
Map<String,String> markings = Maps.newHashMap();
|
||||
markings.put("columnVisibility", columnVisibility);
|
||||
Markings<?> markings = AccessExpressionMarkings.builder().columnVisibility(columnVisibility).build();
|
||||
DESC desc = this.responseObjectFactory.getDescription();
|
||||
desc.setDescription("");
|
||||
desc.setMarkings(markings);
|
||||
|
||||
+2
-2
@@ -46,14 +46,14 @@ public class DictionaryServiceConfiguration {
|
||||
@Bean
|
||||
@Scope("prototype")
|
||||
@ConditionalOnMissingBean
|
||||
public MetadataDescriptionsHelper<DefaultDescription> metadataHelperWithDescriptions(MarkingFunctions markingFunctions,
|
||||
public MetadataDescriptionsHelper<DefaultDescription> metadataHelperWithDescriptions(MarkingFunctions<?> markingFunctions,
|
||||
ResponseObjectFactory<DefaultDescription,DefaultDataDictionary,DefaultMetadataField,DefaultDictionaryField,DefaultFields> responseObjectFactory) {
|
||||
return new MetadataDescriptionsHelper<>(markingFunctions, responseObjectFactory);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public DataDictionary datawaveDataDictionary(MarkingFunctions markingFunctions,
|
||||
public DataDictionary datawaveDataDictionary(MarkingFunctions<?> markingFunctions,
|
||||
ResponseObjectFactory<DefaultDescription,DefaultDataDictionary,DefaultMetadataField,DefaultDictionaryField,DefaultFields> responseObjectFactory,
|
||||
MetadataHelperFactory metadataHelperFactory, MetadataDescriptionsHelperFactory<DefaultDescription> metadataDescriptionsHelperFactory) {
|
||||
return new DataDictionaryImpl(markingFunctions, responseObjectFactory, metadataHelperFactory, metadataDescriptionsHelperFactory);
|
||||
|
||||
+2
-2
@@ -32,14 +32,14 @@ import datawave.webservice.metadata.DefaultMetadataField;
|
||||
|
||||
public class DataDictionaryImpl implements DataDictionary<DefaultMetadataField,DefaultDescription,DefaultDictionaryField> {
|
||||
|
||||
private final MarkingFunctions markingFunctions;
|
||||
private final MarkingFunctions<?> markingFunctions;
|
||||
private final ResponseObjectFactory<DefaultDescription,DefaultDataDictionary,DefaultMetadataField,DefaultDictionaryField,DefaultFields> responseObjectFactory;
|
||||
private final MetadataHelperFactory metadataHelperFactory;
|
||||
private final MetadataDescriptionsHelperFactory<DefaultDescription> metadataDescriptionsHelperFactory;
|
||||
private Map<String,String> normalizationMap = Maps.newHashMap();
|
||||
private String dataDictionarySystem = "";
|
||||
|
||||
public DataDictionaryImpl(MarkingFunctions markingFunctions,
|
||||
public DataDictionaryImpl(MarkingFunctions<?> markingFunctions,
|
||||
ResponseObjectFactory<DefaultDescription,DefaultDataDictionary,DefaultMetadataField,DefaultDictionaryField,DefaultFields> responseObjectFactory,
|
||||
MetadataHelperFactory metadataHelperFactory, MetadataDescriptionsHelperFactory<DefaultDescription> metadataDescriptionsHelperFactory) {
|
||||
this.markingFunctions = markingFunctions;
|
||||
|
||||
+2
-2
@@ -39,13 +39,13 @@ public class DefaultMetadataFieldScanner {
|
||||
private static final String TIMESTAMP_FORMAT = "yyyyMMddHHmmss";
|
||||
private static final Value EMPTY_VALUE = new Value();
|
||||
|
||||
private final MarkingFunctions markingFunctions;
|
||||
private final MarkingFunctions<?> markingFunctions;
|
||||
private final ResponseObjectFactory<DefaultDescription,?,DefaultMetadataField,?,?> responseObjectFactory;
|
||||
private final Map<String,String> normalizationMap;
|
||||
private final Connection connectionConfig;
|
||||
private final int numThreads;
|
||||
|
||||
public DefaultMetadataFieldScanner(MarkingFunctions markingFunctions,
|
||||
public DefaultMetadataFieldScanner(MarkingFunctions<?> markingFunctions,
|
||||
ResponseObjectFactory<DefaultDescription,DefaultDataDictionary,DefaultMetadataField,DefaultDictionaryField,DefaultFields> responseObjectFactory,
|
||||
Map<String,String> normalizationMap, Connection connectionConfig, int numThreads) {
|
||||
this.markingFunctions = markingFunctions;
|
||||
|
||||
+24
-19
@@ -3,10 +3,8 @@ package datawave.microservice.metadata;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.accumulo.core.client.AccumuloClient;
|
||||
@@ -34,6 +32,7 @@ import com.google.common.collect.SetMultimap;
|
||||
|
||||
import datawave.data.ColumnFamilyConstants;
|
||||
import datawave.marking.MarkingFunctions;
|
||||
import datawave.marking.Markings;
|
||||
import datawave.microservice.dictionary.config.ResponseObjectFactory;
|
||||
import datawave.query.util.MetadataEntry;
|
||||
import datawave.security.util.ScannerHelper;
|
||||
@@ -48,14 +47,14 @@ import datawave.webservice.dictionary.data.DescriptionBase;
|
||||
public class MetadataDescriptionsHelper<DESC extends DescriptionBase<DESC>> {
|
||||
private static final Logger log = LoggerFactory.getLogger(MetadataDescriptionsHelper.class);
|
||||
|
||||
private final MarkingFunctions markingFunctions;
|
||||
private final MarkingFunctions<?> markingFunctions;
|
||||
private final ResponseObjectFactory<DESC,?,?,?,?> responseObjectFactory;
|
||||
|
||||
private String metadataTableName;
|
||||
private AccumuloClient accumuloClient;
|
||||
private Set<Authorizations> fullUserAuths;
|
||||
|
||||
public MetadataDescriptionsHelper(MarkingFunctions markingFunctions, ResponseObjectFactory<DESC,?,?,?,?> responseObjectFactory) {
|
||||
public MetadataDescriptionsHelper(MarkingFunctions<?> markingFunctions, ResponseObjectFactory<DESC,?,?,?,?> responseObjectFactory) {
|
||||
this.markingFunctions = markingFunctions;
|
||||
this.responseObjectFactory = responseObjectFactory;
|
||||
}
|
||||
@@ -85,8 +84,7 @@ public class MetadataDescriptionsHelper<DESC extends DescriptionBase<DESC>> {
|
||||
return descs;
|
||||
}
|
||||
|
||||
public SetMultimap<String,DESC> getFieldDescriptions(Set<String> ingestTypeFilter)
|
||||
throws TableNotFoundException, ExecutionException, MarkingFunctions.Exception {
|
||||
public SetMultimap<String,DESC> getFieldDescriptions(Set<String> ingestTypeFilter) throws TableNotFoundException, MarkingFunctions.Exception {
|
||||
SetMultimap<MetadataEntry,DESC> descriptions = getDescriptions(ingestTypeFilter);
|
||||
SetMultimap<String,DESC> fieldDescriptions = HashMultimap.create();
|
||||
|
||||
@@ -118,16 +116,21 @@ public class MetadataDescriptionsHelper<DESC extends DescriptionBase<DESC>> {
|
||||
setDescriptions(entry, Collections.singleton(desc));
|
||||
}
|
||||
|
||||
public void setDescriptions(MetadataEntry entry, Set<? extends DescriptionBase> descs)
|
||||
throws TableNotFoundException, MutationsRejectedException, MarkingFunctions.Exception {
|
||||
public void setDescriptions(MetadataEntry entry, Set<? extends DescriptionBase> descs) throws TableNotFoundException, MutationsRejectedException {
|
||||
BatchWriter bw = null;
|
||||
try {
|
||||
BatchWriterConfig bwConfig = new BatchWriterConfig().setMaxMemory(10000L).setMaxLatency(100L, TimeUnit.MILLISECONDS).setMaxWriteThreads(1);
|
||||
bw = accumuloClient.createBatchWriter(metadataTableName, bwConfig);
|
||||
Mutation m = new Mutation(entry.getFieldName());
|
||||
for (DescriptionBase desc : descs) {
|
||||
m.put(ColumnFamilyConstants.COLF_DESC, new Text(entry.getDatatype()), markingFunctions.translateToColumnVisibility(desc.getMarkings()),
|
||||
new Value(desc.getDescription().getBytes(UTF_8)));
|
||||
ColumnVisibility cv = null;
|
||||
if (desc.getMarkings() != null) {
|
||||
cv = desc.getMarkings().toColumnVisibility();
|
||||
}
|
||||
if (null == cv || cv.getExpression().length == 0) {
|
||||
throw new IllegalArgumentException("ColumnVisibility was null or empty, unable to create Accumulo mutation");
|
||||
}
|
||||
m.put(ColumnFamilyConstants.COLF_DESC, new Text(entry.getDatatype()), cv, new Value(desc.getDescription().getBytes(UTF_8)));
|
||||
}
|
||||
bw.addMutation(m);
|
||||
} finally {
|
||||
@@ -153,14 +156,20 @@ public class MetadataDescriptionsHelper<DESC extends DescriptionBase<DESC>> {
|
||||
* @throws MutationsRejectedException
|
||||
* if writing the update to Accumulo fails
|
||||
*/
|
||||
public void removeDescription(MetadataEntry entry, DescriptionBase desc)
|
||||
throws TableNotFoundException, MutationsRejectedException, MarkingFunctions.Exception {
|
||||
public void removeDescription(MetadataEntry entry, DescriptionBase desc) throws TableNotFoundException, MutationsRejectedException {
|
||||
BatchWriter bw = null;
|
||||
try {
|
||||
BatchWriterConfig bwConfig = new BatchWriterConfig().setMaxMemory(10000L).setMaxLatency(100L, TimeUnit.MILLISECONDS).setMaxWriteThreads(1);
|
||||
bw = accumuloClient.createBatchWriter(metadataTableName, bwConfig);
|
||||
Mutation m = new Mutation(entry.getFieldName());
|
||||
m.putDelete(ColumnFamilyConstants.COLF_DESC, new Text(entry.getDatatype()), this.markingFunctions.translateToColumnVisibility(desc.getMarkings()));
|
||||
ColumnVisibility cv = null;
|
||||
if (desc.getMarkings() != null) {
|
||||
cv = desc.getMarkings().toColumnVisibility();
|
||||
}
|
||||
if (null == cv || cv.getExpression().length == 0) {
|
||||
throw new IllegalArgumentException("ColumnVisibility was null or empty, unable to create Accumulo mutation");
|
||||
}
|
||||
m.putDelete(ColumnFamilyConstants.COLF_DESC, new Text(entry.getDatatype()), cv);
|
||||
bw.addMutation(m);
|
||||
} finally {
|
||||
if (null != bw) {
|
||||
@@ -199,11 +208,7 @@ public class MetadataDescriptionsHelper<DESC extends DescriptionBase<DESC>> {
|
||||
|
||||
}
|
||||
|
||||
private Map<String,String> getMarkings(Key k) throws MarkingFunctions.Exception {
|
||||
return getMarkings(k.getColumnVisibilityParsed());
|
||||
}
|
||||
|
||||
private Map<String,String> getMarkings(ColumnVisibility visibility) throws MarkingFunctions.Exception {
|
||||
return markingFunctions.translateFromColumnVisibility(visibility);
|
||||
private Markings<?> getMarkings(Key k) throws MarkingFunctions.Exception {
|
||||
return markingFunctions.translateFromColumnVisibility(k.getColumnVisibilityParsed());
|
||||
}
|
||||
}
|
||||
+3
-7
@@ -2,8 +2,6 @@ package datawave.microservice.dictionary;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.util.AbstractMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.accumulo.core.client.AccumuloClient;
|
||||
@@ -32,7 +30,7 @@ import com.google.common.collect.Multimap;
|
||||
|
||||
import datawave.accumulo.inmemory.InMemoryAccumuloClient;
|
||||
import datawave.accumulo.inmemory.InMemoryInstance;
|
||||
import datawave.marking.MarkingFunctions;
|
||||
import datawave.marking.AccessExpressionMarkings;
|
||||
import datawave.microservice.ControllerIT;
|
||||
import datawave.microservice.dictionary.config.DataDictionaryProperties;
|
||||
import datawave.webservice.dictionary.data.DefaultDataDictionary;
|
||||
@@ -129,11 +127,9 @@ public class DataDictionaryControllerTest extends ControllerIT {
|
||||
.build();
|
||||
// @formatter:on
|
||||
|
||||
HashMap<String,String> markings = new HashMap<>();
|
||||
markings.put(MarkingFunctions.Default.COLUMN_VISIBILITY, "USER|ADMIN");
|
||||
Multimap<Map.Entry<String,String>,DefaultDescription> descriptions = HashMultimap.create();
|
||||
descriptions.put(new AbstractMap.SimpleEntry<>("fooField", "fooType"), new DefaultDescription("my foo field", markings));
|
||||
descriptions.put(new AbstractMap.SimpleEntry<>("barField", "barType"), new DefaultDescription("my bar field", markings));
|
||||
descriptions.put(Map.entry("fooField", "fooType"), new DefaultDescription("my foo field", AccessExpressionMarkings.create("USER")));
|
||||
descriptions.put(Map.entry("barField", "barType"), new DefaultDescription("my bar field", AccessExpressionMarkings.create("ADMIN")));
|
||||
DefaultFields postBody = new DefaultFields(descriptions);
|
||||
MultiValueMap<String,String> additionalHeaders = new LinkedMultiValueMap<>();
|
||||
additionalHeaders.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
|
||||
|
||||
+8
-25
@@ -28,6 +28,7 @@ import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.SetMultimap;
|
||||
|
||||
import datawave.marking.AccessExpressionMarkings;
|
||||
import datawave.marking.MarkingFunctions;
|
||||
import datawave.microservice.Connection;
|
||||
import datawave.microservice.dictionary.config.ResponseObjectFactory;
|
||||
@@ -59,7 +60,7 @@ public class DataDictionaryImplTest {
|
||||
private AccumuloClient accumuloClient;
|
||||
|
||||
@Mock
|
||||
private MarkingFunctions markingFunctions;
|
||||
private MarkingFunctions<?> markingFunctions;
|
||||
|
||||
@Mock
|
||||
private ResponseObjectFactory<DefaultDescription,DefaultDataDictionary,DefaultMetadataField,DefaultDictionaryField,DefaultFields> responseObjectFactory;
|
||||
@@ -88,11 +89,8 @@ public class DataDictionaryImplTest {
|
||||
|
||||
@Test
|
||||
public void whenSettingDescription_givenSingleDefaultDescription_shouldSetDescription() throws Exception {
|
||||
Map<String,String> markings = new HashMap<>();
|
||||
markings.put("columnVisibility", "PRIVATE");
|
||||
|
||||
DefaultDescription description = new DefaultDescription();
|
||||
description.setMarkings(markings);
|
||||
description.setMarkings(AccessExpressionMarkings.create("PRIVATE"));
|
||||
description.setDescription("my ultra cool description");
|
||||
|
||||
// Ensure no alias will be found.
|
||||
@@ -110,11 +108,8 @@ public class DataDictionaryImplTest {
|
||||
|
||||
@Test
|
||||
public void whenSettingDescription_givenDefaultDictionaryField_shouldSetDescriptionFromProperties() throws Exception {
|
||||
Map<String,String> markings = new HashMap<>();
|
||||
markings.put("columnVisibility", "PRIVATE");
|
||||
|
||||
DefaultDescription description = new DefaultDescription();
|
||||
description.setMarkings(markings);
|
||||
description.setMarkings(AccessExpressionMarkings.create("PRIVATE"));
|
||||
description.setDescription("my ultra cool description");
|
||||
|
||||
Set<DefaultDescription> descriptions = Collections.singleton(description);
|
||||
@@ -138,11 +133,8 @@ public class DataDictionaryImplTest {
|
||||
|
||||
@Test
|
||||
public void whenSettingDescription_givenNoAlias_shouldSetDescriptionWithOriginalFieldName() throws Exception {
|
||||
Map<String,String> markings = new HashMap<>();
|
||||
markings.put("columnVisibility", "PRIVATE");
|
||||
|
||||
DefaultDescription description = new DefaultDescription();
|
||||
description.setMarkings(markings);
|
||||
description.setMarkings(AccessExpressionMarkings.create("PRIVATE"));
|
||||
description.setDescription("my ultra cool description");
|
||||
|
||||
Set<DefaultDescription> descriptions = Collections.singleton(description);
|
||||
@@ -161,11 +153,8 @@ public class DataDictionaryImplTest {
|
||||
|
||||
@Test
|
||||
public void whenSettingDescription_givenAlias_shouldSetDescriptionWithAlias() throws Exception {
|
||||
Map<String,String> markings = new HashMap<>();
|
||||
markings.put("columnVisibility", "PRIVATE");
|
||||
|
||||
DefaultDescription description = new DefaultDescription();
|
||||
description.setMarkings(markings);
|
||||
description.setMarkings(AccessExpressionMarkings.create("PRIVATE"));
|
||||
description.setDescription("my ultra cool description");
|
||||
|
||||
Set<DefaultDescription> descriptions = Collections.singleton(description);
|
||||
@@ -294,11 +283,8 @@ public class DataDictionaryImplTest {
|
||||
|
||||
@Test
|
||||
public void whenDeletingDescription_givenNoAlias_shouldDeleteDescriptionWithOriginalFieldName() throws Exception {
|
||||
Map<String,String> markings = new HashMap<>();
|
||||
markings.put("columnVisibility", "PRIVATE");
|
||||
|
||||
DefaultDescription description = new DefaultDescription();
|
||||
description.setMarkings(markings);
|
||||
description.setMarkings(AccessExpressionMarkings.create("PRIVATE"));
|
||||
description.setDescription("my ultra cool description");
|
||||
|
||||
// Ensure no alias will be found.
|
||||
@@ -315,11 +301,8 @@ public class DataDictionaryImplTest {
|
||||
|
||||
@Test
|
||||
public void whenDeletingDescription_givenAlias_shouldDeleteDescriptionWithAlias() throws Exception {
|
||||
Map<String,String> markings = new HashMap<>();
|
||||
markings.put("columnVisibility", "PRIVATE");
|
||||
|
||||
DefaultDescription description = new DefaultDescription();
|
||||
description.setMarkings(markings);
|
||||
description.setMarkings(AccessExpressionMarkings.create("PRIVATE"));
|
||||
description.setDescription("my ultra cool description");
|
||||
|
||||
// Ensure an alias will be found.
|
||||
|
||||
+3
-6
@@ -31,6 +31,7 @@ import org.junit.jupiter.api.Test;
|
||||
import datawave.accumulo.inmemory.InMemoryAccumuloClient;
|
||||
import datawave.accumulo.inmemory.InMemoryInstance;
|
||||
import datawave.data.ColumnFamilyConstants;
|
||||
import datawave.marking.AccessExpressionMarkings;
|
||||
import datawave.marking.MarkingFunctions;
|
||||
import datawave.microservice.Connection;
|
||||
import datawave.microservice.dictionary.config.ResponseObjectFactory;
|
||||
@@ -50,7 +51,7 @@ public class DefaultMetadataFieldScannerTest {
|
||||
private static final String[] AUTH = {"PRIVATE"};
|
||||
private static final Set<Authorizations> AUTHS = Collections.singleton(new Authorizations(AUTH));
|
||||
|
||||
private static final ResponseObjectFactory<DefaultDescription,DefaultDataDictionary,DefaultMetadataField,DefaultDictionaryField,DefaultFields> RESPONSE_OBJECT_FACTORY = new ResponseObjectFactory<DefaultDescription,DefaultDataDictionary,DefaultMetadataField,DefaultDictionaryField,DefaultFields>() {
|
||||
private static final ResponseObjectFactory<DefaultDescription,DefaultDataDictionary,DefaultMetadataField,DefaultDictionaryField,DefaultFields> RESPONSE_OBJECT_FACTORY = new ResponseObjectFactory<>() {
|
||||
@Override
|
||||
public DefaultDataDictionary getDataDictionary() {
|
||||
return null;
|
||||
@@ -276,11 +277,7 @@ public class DefaultMetadataFieldScannerTest {
|
||||
private DefaultDescription createDescription(String descriptionText) {
|
||||
DefaultDescription description = new DefaultDescription();
|
||||
description.setDescription(descriptionText);
|
||||
|
||||
Map<String,String> markings = new HashMap<>();
|
||||
markings.put("columnVisibility", "PRIVATE}");
|
||||
description.setMarkings(markings);
|
||||
|
||||
description.setMarkings(AccessExpressionMarkings.create("PRIVATE"));
|
||||
return description;
|
||||
}
|
||||
}
|
||||
@@ -63,12 +63,6 @@
|
||||
<groupId>gov.nsa.datawave.core</groupId>
|
||||
<artifactId>accumulo-utils</artifactId>
|
||||
<version>${version.datawave}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>*</groupId>
|
||||
<artifactId>*</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>gov.nsa.datawave.core</groupId>
|
||||
|
||||
+9
-7
@@ -24,6 +24,7 @@ import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlElementWrapper;
|
||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
|
||||
import org.apache.accumulo.access.AccessExpression;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.builder.CompareToBuilder;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
@@ -34,7 +35,8 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
import datawave.marking.MarkingFunctions;
|
||||
import datawave.marking.AccessExpressionMarkings;
|
||||
import datawave.marking.Markings;
|
||||
import datawave.microservice.query.Query;
|
||||
import datawave.microservice.query.QueryImpl.Parameter;
|
||||
import datawave.webservice.query.exception.QueryException;
|
||||
@@ -1165,21 +1167,21 @@ public abstract class BaseQueryMetric implements HasMarkings, Serializable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMarkings(Map<String,String> markings) {
|
||||
public void setMarkings(Markings<?> markings) {
|
||||
if (markings == null || markings.isEmpty()) {
|
||||
this.columnVisibility = null;
|
||||
} else {
|
||||
this.columnVisibility = markings.get(MarkingFunctions.Default.COLUMN_VISIBILITY);
|
||||
AccessExpression ae = markings.toAccessExpression();
|
||||
this.columnVisibility = ae.getExpression();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String,String> getMarkings() {
|
||||
Map<String,String> markings = new HashMap<>();
|
||||
public Markings<?> getMarkings() {
|
||||
if (this.columnVisibility != null) {
|
||||
markings.put(MarkingFunctions.Default.COLUMN_VISIBILITY, this.columnVisibility);
|
||||
return AccessExpressionMarkings.builder().columnVisibility(this.columnVisibility).build();
|
||||
}
|
||||
return markings;
|
||||
return null;
|
||||
}
|
||||
|
||||
public Schema<? extends BaseQueryMetric> getSchemaInstance() {
|
||||
|
||||
+5
-10
@@ -14,9 +14,7 @@ import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.Marshaller;
|
||||
@@ -28,7 +26,7 @@ import org.junit.jupiter.api.Test;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule;
|
||||
|
||||
import datawave.marking.MarkingFunctions;
|
||||
import datawave.marking.AccessExpressionMarkings;
|
||||
import datawave.microservice.querymetric.BaseQueryMetric.Lifecycle;
|
||||
import datawave.microservice.querymetric.BaseQueryMetric.PageMetric;
|
||||
import datawave.microservice.querymetric.BaseQueryMetric.Prediction;
|
||||
@@ -43,7 +41,6 @@ import io.protostuff.Schema;
|
||||
public class QueryMetricTest {
|
||||
|
||||
private static QueryMetric queryMetric = null;
|
||||
private static Map<String,String> markings = null;
|
||||
private static List<String> negativeSelectors = null;
|
||||
private static ArrayList<PageMetric> pageTimes = null;
|
||||
private static List<String> positiveSelectors = null;
|
||||
@@ -53,9 +50,7 @@ public class QueryMetricTest {
|
||||
@BeforeAll
|
||||
public static void setup() {
|
||||
queryMetric = new QueryMetric();
|
||||
markings = new HashMap<>();
|
||||
markings.put(MarkingFunctions.Default.COLUMN_VISIBILITY, "PUBLIC");
|
||||
queryMetric.setMarkings(markings);
|
||||
queryMetric.setMarkings(AccessExpressionMarkings.builder().columnVisibility("PUBLIC").build());
|
||||
negativeSelectors = new ArrayList<>();
|
||||
negativeSelectors.add("negativeSelector1");
|
||||
positiveSelectors = new ArrayList<>();
|
||||
@@ -104,7 +99,7 @@ public class QueryMetricTest {
|
||||
queryMetric.setHost("host");
|
||||
queryMetric.setLastUpdated(d);
|
||||
queryMetric.setLifecycle(Lifecycle.INITIALIZED);
|
||||
queryMetric.setMarkings(markings);
|
||||
queryMetric.setMarkings(AccessExpressionMarkings.builder().columnVisibility("PUBLIC").build());
|
||||
queryMetric.setNegativeSelectors(negativeSelectors);
|
||||
queryMetric.setNumUpdates(0);
|
||||
queryMetric.setPageTimes(pageTimes);
|
||||
@@ -131,7 +126,7 @@ public class QueryMetricTest {
|
||||
assertEquals("host", queryMetric.getHost());
|
||||
assertEquals(d, queryMetric.getLastUpdated());
|
||||
assertEquals(Lifecycle.INITIALIZED, queryMetric.getLifecycle());
|
||||
assertEquals("PUBLIC", queryMetric.getMarkings().get(MarkingFunctions.Default.COLUMN_VISIBILITY));
|
||||
assertEquals("PUBLIC", queryMetric.getColumnVisibility());
|
||||
assertEquals("negativeSelector1", queryMetric.getNegativeSelectors().get(0));
|
||||
assertEquals(1, queryMetric.getNumPages());
|
||||
assertEquals(0, queryMetric.getNumResults());
|
||||
@@ -234,7 +229,7 @@ public class QueryMetricTest {
|
||||
qm.setHost("host");
|
||||
qm.setLastUpdated(d);
|
||||
qm.setLifecycle(BaseQueryMetric.Lifecycle.INITIALIZED);
|
||||
qm.setMarkings(markings);
|
||||
qm.setMarkings(AccessExpressionMarkings.builder().columnVisibility("PUBLIC").build());
|
||||
qm.setNegativeSelectors(negativeSelectors);
|
||||
qm.setNumUpdates(0);
|
||||
qm.setPageTimes(pageTimes);
|
||||
|
||||
@@ -135,12 +135,6 @@
|
||||
<groupId>gov.nsa.datawave.core</groupId>
|
||||
<artifactId>accumulo-utils</artifactId>
|
||||
<version>${version.datawave}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>*</groupId>
|
||||
<artifactId>*</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>gov.nsa.datawave.core</groupId>
|
||||
|
||||
+7
-4
@@ -87,7 +87,7 @@ public class QueryMetricOperations {
|
||||
private QueryGeometryHandler geometryHandler;
|
||||
private CacheManager cacheManager;
|
||||
private Cache incomingQueryMetricsCache;
|
||||
private MarkingFunctions markingFunctions;
|
||||
private MarkingFunctions<?> markingFunctions;
|
||||
private QueryMetricResponseFactory queryMetricResponseFactory;
|
||||
private MergeLockLifecycleListener mergeLock;
|
||||
private Correlator correlator;
|
||||
@@ -141,7 +141,7 @@ public class QueryMetricOperations {
|
||||
*/
|
||||
@Autowired
|
||||
public QueryMetricOperations(@Qualifier("queryMetricCacheManager") CacheManager cacheManager, ShardTableQueryMetricHandler handler,
|
||||
QueryGeometryHandler geometryHandler, MarkingFunctions markingFunctions, QueryMetricResponseFactory queryMetricResponseFactory,
|
||||
QueryGeometryHandler geometryHandler, MarkingFunctions<?> markingFunctions, QueryMetricResponseFactory queryMetricResponseFactory,
|
||||
MergeLockLifecycleListener mergeLock, Correlator correlator, MetricUpdateEntryProcessorFactory entryProcessorFactory,
|
||||
QueryMetricOperationsStats stats, QueryMetricClient queryMetricClient, DnUtils dnUtils) {
|
||||
this.handler = handler;
|
||||
@@ -478,11 +478,14 @@ public class QueryMetricOperations {
|
||||
|
||||
private boolean canViewMetric(DatawaveUserDetails currentUser, BaseQueryMetric metric) throws Exception {
|
||||
boolean userCanViewMetric = true;
|
||||
ColumnVisibility columnVisibility = this.markingFunctions.translateToColumnVisibility(metric.getMarkings());
|
||||
ColumnVisibility columnVisibility = null;
|
||||
if (null != metric.getMarkings()) {
|
||||
columnVisibility = metric.getMarkings().toColumnVisibility();
|
||||
}
|
||||
for (DatawaveUser user : currentUser.getProxiedUsers()) {
|
||||
Authorizations authorizations = new Authorizations(user.getAuths().toArray(new String[0]));
|
||||
VisibilityEvaluator visibilityEvaluator = new VisibilityEvaluator(authorizations);
|
||||
if (visibilityEvaluator.evaluate(columnVisibility) == false) {
|
||||
if (!visibilityEvaluator.evaluate(columnVisibility)) {
|
||||
userCanViewMetric = false;
|
||||
break;
|
||||
}
|
||||
|
||||
+1
-1
@@ -99,7 +99,7 @@ public class QueryMetricHandlerConfiguration {
|
||||
@ConditionalOnMissingBean
|
||||
public ShardTableQueryMetricHandler shardTableQueryMetricHandler(QueryMetricHandlerProperties queryMetricHandlerProperties,
|
||||
AccumuloConnectionFactory connectionFactory, QueryMetricQueryLogicFactory logicFactory, QueryMetricFactory metricFactory,
|
||||
MarkingFunctions markingFunctions, QueryMetricCombiner queryMetricCombiner, LuceneToJexlQueryParser luceneToJexlQueryParser,
|
||||
MarkingFunctions<?> markingFunctions, QueryMetricCombiner queryMetricCombiner, LuceneToJexlQueryParser luceneToJexlQueryParser,
|
||||
ResponseObjectFactory responseObjectFactory, WebClient.Builder webClientBuilder,
|
||||
@Autowired(required = false) JWTTokenHandler jwtTokenHandler, DnUtils dnUtils, QueryMetricResponseFactory queryMetricResponseFactory) {
|
||||
ShardTableQueryMetricHandler handler;
|
||||
|
||||
+2
-2
@@ -16,14 +16,14 @@ import datawave.webservice.query.result.event.ResponseObjectFactory;
|
||||
@Component
|
||||
public class QueryMetricQueryLogicFactory implements FactoryBean<ShardQueryLogic> {
|
||||
|
||||
private MarkingFunctions markingFunctions;
|
||||
private MarkingFunctions<?> markingFunctions;
|
||||
private ResponseObjectFactory responseObjectFactory;
|
||||
private QueryMetricHandlerProperties queryMetricHandlerProperties;
|
||||
private DateIndexHelperFactory dateIndexHelperFactory;
|
||||
private MetadataHelperFactory metadataHelperFactory;
|
||||
|
||||
@Autowired
|
||||
public QueryMetricQueryLogicFactory(MarkingFunctions markingFunctions, ResponseObjectFactory responseObjectFactory,
|
||||
public QueryMetricQueryLogicFactory(MarkingFunctions<?> markingFunctions, ResponseObjectFactory responseObjectFactory,
|
||||
DateIndexHelperFactory dateIndexHelperFactory, MetadataHelperFactory metadataHelperFactory,
|
||||
QueryMetricHandlerProperties queryMetricHandlerProperties) {
|
||||
this.markingFunctions = markingFunctions;
|
||||
|
||||
+1
-1
@@ -48,7 +48,7 @@ public class LocalShardTableQueryMetricHandler<T extends BaseQueryMetric> extend
|
||||
protected ExecutorService executorService;
|
||||
|
||||
public LocalShardTableQueryMetricHandler(QueryMetricHandlerProperties queryMetricHandlerProperties, AccumuloConnectionFactory connectionFactory,
|
||||
QueryMetricQueryLogicFactory logicFactory, QueryMetricFactory metricFactory, MarkingFunctions markingFunctions,
|
||||
QueryMetricQueryLogicFactory logicFactory, QueryMetricFactory metricFactory, MarkingFunctions<?> markingFunctions,
|
||||
QueryMetricCombiner queryMetricCombiner, LuceneToJexlQueryParser luceneToJexlQueryParser, DnUtils dnUtils) {
|
||||
super(queryMetricHandlerProperties, connectionFactory, logicFactory, metricFactory, markingFunctions, queryMetricCombiner, luceneToJexlQueryParser,
|
||||
dnUtils);
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ public class RemoteShardTableQueryMetricHandler<T extends BaseQueryMetric> exten
|
||||
private final JWTTokenHandler jwtTokenHandler;
|
||||
|
||||
public RemoteShardTableQueryMetricHandler(QueryMetricHandlerProperties queryMetricHandlerProperties, AccumuloConnectionFactory connectionFactory,
|
||||
QueryMetricQueryLogicFactory logicFactory, QueryMetricFactory metricFactory, MarkingFunctions markingFunctions,
|
||||
QueryMetricQueryLogicFactory logicFactory, QueryMetricFactory metricFactory, MarkingFunctions<?> markingFunctions,
|
||||
QueryMetricCombiner queryMetricCombiner, LuceneToJexlQueryParser luceneToJexlQueryParser, ResponseObjectFactory responseObjectFactory,
|
||||
WebClient.Builder webClientBuilder, JWTTokenHandler jwtTokenHandler, DnUtils dnUtils) {
|
||||
super(queryMetricHandlerProperties, connectionFactory, logicFactory, metricFactory, markingFunctions, queryMetricCombiner, luceneToJexlQueryParser,
|
||||
|
||||
+5
-9
@@ -63,6 +63,7 @@ import datawave.ingest.mapreduce.job.BulkIngestKey;
|
||||
import datawave.ingest.protobuf.Uid;
|
||||
import datawave.ingest.table.config.TableConfigHelper;
|
||||
import datawave.marking.MarkingFunctions;
|
||||
import datawave.marking.Markings;
|
||||
import datawave.microservice.authorization.user.DatawaveUserDetails;
|
||||
import datawave.microservice.query.Query;
|
||||
import datawave.microservice.query.QueryImpl;
|
||||
@@ -106,13 +107,13 @@ public abstract class ShardTableQueryMetricHandler<T extends BaseQueryMetric> ex
|
||||
protected QueryMetricFactory metricFactory;
|
||||
protected UIDBuilder<UID> uidBuilder = UID.builder();
|
||||
protected QueryMetricCombiner queryMetricCombiner;
|
||||
protected MarkingFunctions markingFunctions;
|
||||
protected MarkingFunctions<?> markingFunctions;
|
||||
protected DnUtils dnUtils;
|
||||
// this lock is necessary for when there is an error condition and the accumuloRecordWriter needs to be replaced
|
||||
protected ReentrantReadWriteLock accumuloRecordWriterLock = new ReentrantReadWriteLock();
|
||||
|
||||
public ShardTableQueryMetricHandler(QueryMetricHandlerProperties queryMetricHandlerProperties, AccumuloConnectionFactory connectionFactory,
|
||||
QueryMetricQueryLogicFactory logicFactory, QueryMetricFactory metricFactory, MarkingFunctions markingFunctions,
|
||||
QueryMetricQueryLogicFactory logicFactory, QueryMetricFactory metricFactory, MarkingFunctions<?> markingFunctions,
|
||||
QueryMetricCombiner queryMetricCombiner, LuceneToJexlQueryParser luceneToJexlQueryParser, DnUtils dnUtils) {
|
||||
super(luceneToJexlQueryParser);
|
||||
this.queryMetricHandlerProperties = queryMetricHandlerProperties;
|
||||
@@ -365,14 +366,9 @@ public abstract class ShardTableQueryMetricHandler<T extends BaseQueryMetric> ex
|
||||
event.setDataType(type);
|
||||
event.setTimestamp(updatedQueryMetric.getCreateDate().getTime());
|
||||
// get markings from metric, otherwise use the default markings
|
||||
Map<String,String> markings = updatedQueryMetric.getMarkings();
|
||||
Markings<?> markings = updatedQueryMetric.getMarkings();
|
||||
if (markings != null && !markings.isEmpty()) {
|
||||
try {
|
||||
event.setVisibility(this.markingFunctions.translateToColumnVisibility(updatedQueryMetric.getMarkings()));
|
||||
} catch (MarkingFunctions.Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
event.setVisibility(this.queryMetricHandlerProperties.getDefaultMetricVisibility());
|
||||
}
|
||||
event.setVisibility(markings.toColumnVisibility());
|
||||
} else {
|
||||
event.setVisibility(this.queryMetricHandlerProperties.getDefaultMetricVisibility());
|
||||
}
|
||||
|
||||
+3
-2
@@ -11,8 +11,8 @@ import java.util.TreeSet;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.accumulo.core.security.Authorizations;
|
||||
import org.junit.Assert;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
@@ -79,6 +79,7 @@ public class MetadataCachingTest extends QueryMetricTestBase {
|
||||
metadataHelper.getDatatypes(Collections.singleton("querymetrics"));
|
||||
metadataHelper.getFieldsForDatatype(LcNoDiacriticsType.class);
|
||||
metadataHelper.getFieldsToDatatypes(Collections.singleton("querymetrics"));
|
||||
metadataHelper.getHiddenFields(Collections.singleton("querymetrics"));
|
||||
metadataHelper.getContentFields(Collections.singleton("querymetrics"));
|
||||
metadataHelper.getHiddenFields(Collections.singleton("querymetrics"));
|
||||
metadataHelper.getExpansionFields(Collections.singleton("querymetrics"));
|
||||
@@ -111,7 +112,7 @@ public class MetadataCachingTest extends QueryMetricTestBase {
|
||||
expectedCacheNames.addAll(getCacheNamesForCacheableMethods(AllFieldMetadataHelper.class));
|
||||
expectedCacheNames.addAll(getCacheNamesForCacheableMethods(DateIndexHelper.class));
|
||||
|
||||
Assert.assertEquals(expectedCacheNames, cacheNames);
|
||||
Assertions.assertEquals(expectedCacheNames, cacheNames);
|
||||
}
|
||||
|
||||
private List<String> getCacheNamesForCacheableMethods(Class clazz) {
|
||||
|
||||
+2
-2
@@ -23,7 +23,7 @@ import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
import datawave.marking.MarkingFunctions;
|
||||
import datawave.marking.ColumnVisibilitySecurityMarking;
|
||||
import datawave.microservice.querymetric.config.QueryMetricTransportType;
|
||||
import datawave.microservice.querymetric.config.TimelyProperties;
|
||||
import datawave.microservice.querymetric.function.QueryMetricSupplier;
|
||||
@@ -53,7 +53,7 @@ public class NonWebApplicationMessagingTest {
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
this.metricMarkings = new HashMap<>();
|
||||
this.metricMarkings.put(MarkingFunctions.Default.COLUMN_VISIBILITY, "A&C");
|
||||
this.metricMarkings.put(ColumnVisibilitySecurityMarking.VISIBILITY_MARKING, "A&C");
|
||||
this.storedMetricUpdates.clear();
|
||||
}
|
||||
|
||||
|
||||
+7
-5
@@ -1,5 +1,6 @@
|
||||
package datawave.microservice.querymetric;
|
||||
|
||||
import static datawave.marking.AccessExpressionMarkings.ACCESS;
|
||||
import static datawave.microservice.querymetric.config.HazelcastMetricCacheConfiguration.INCOMING_METRICS;
|
||||
import static datawave.security.authorization.DatawaveUser.UserType.USER;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
@@ -12,13 +13,13 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.accumulo.access.AccessExpression;
|
||||
import org.apache.accumulo.core.client.AccumuloClient;
|
||||
import org.apache.accumulo.core.client.BatchScanner;
|
||||
import org.apache.accumulo.core.client.BatchWriter;
|
||||
@@ -65,7 +66,8 @@ import com.hazelcast.spring.cache.HazelcastCacheManager;
|
||||
|
||||
import datawave.core.common.connection.AccumuloConnectionFactory;
|
||||
import datawave.ingest.protobuf.Uid;
|
||||
import datawave.marking.MarkingFunctions;
|
||||
import datawave.marking.AccessExpressionMarkings;
|
||||
import datawave.marking.Markings;
|
||||
import datawave.microservice.authorization.preauth.ProxiedEntityX509Filter;
|
||||
import datawave.microservice.authorization.user.DatawaveUserDetails;
|
||||
import datawave.microservice.querymetric.config.QueryMetricClientProperties;
|
||||
@@ -144,14 +146,14 @@ public class QueryMetricTestBase {
|
||||
protected DatawaveUserDetails nonAdminUser;
|
||||
protected static boolean isHazelCast;
|
||||
protected static CacheManager staticCacheManager;
|
||||
protected static Map<String,String> metricMarkings;
|
||||
protected static Markings<?> metricMarkings;
|
||||
protected List<String> tables;
|
||||
protected Collection<String> auths;
|
||||
protected AccumuloClient accumuloClient;
|
||||
|
||||
static {
|
||||
metricMarkings = new HashMap<>();
|
||||
metricMarkings.put(MarkingFunctions.Default.COLUMN_VISIBILITY, "A&C");
|
||||
AccessExpression ae = ACCESS.newExpression("A&C");
|
||||
metricMarkings = AccessExpressionMarkings.builder().accessExpression(ae).build();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
|
||||
+1
-1
@@ -48,7 +48,7 @@ public class AlternateQueryMetricConfiguration {
|
||||
@Bean
|
||||
public ShardTableQueryMetricHandler shardTableQueryMetricHandler(QueryMetricHandlerProperties queryMetricHandlerProperties,
|
||||
AccumuloConnectionFactory connectionFactory, QueryMetricQueryLogicFactory logicFactory, QueryMetricFactory metricFactory,
|
||||
MarkingFunctions markingFunctions, QueryMetricCombiner queryMetricCombiner, LuceneToJexlQueryParser luceneToJexlQueryParser,
|
||||
MarkingFunctions<?> markingFunctions, QueryMetricCombiner queryMetricCombiner, LuceneToJexlQueryParser luceneToJexlQueryParser,
|
||||
DnUtils dnUtils) {
|
||||
return new AlternateShardTableQueryMetricHandler(queryMetricHandlerProperties, connectionFactory, logicFactory, metricFactory, markingFunctions,
|
||||
queryMetricCombiner, luceneToJexlQueryParser, dnUtils);
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ import datawave.webservice.query.result.event.FieldBase;
|
||||
public class AlternateShardTableQueryMetricHandler extends LocalShardTableQueryMetricHandler<AlternateQueryMetric> {
|
||||
|
||||
public AlternateShardTableQueryMetricHandler(QueryMetricHandlerProperties queryMetricHandlerProperties, AccumuloConnectionFactory connectionFactory,
|
||||
QueryMetricQueryLogicFactory logicFactory, QueryMetricFactory metricFactory, MarkingFunctions markingFunctions,
|
||||
QueryMetricQueryLogicFactory logicFactory, QueryMetricFactory metricFactory, MarkingFunctions<?> markingFunctions,
|
||||
QueryMetricCombiner queryMetricCombiner, LuceneToJexlQueryParser luceneToJexlQueryParser, DnUtils dnUtils) {
|
||||
super(queryMetricHandlerProperties, connectionFactory, logicFactory, metricFactory, markingFunctions, queryMetricCombiner, luceneToJexlQueryParser,
|
||||
dnUtils);
|
||||
|
||||
@@ -75,6 +75,11 @@
|
||||
<artifactId>datawave-query-core</artifactId>
|
||||
<version>${version.datawave}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>gov.nsa.datawave.core</groupId>
|
||||
<artifactId>accumulo-utils</artifactId>
|
||||
<version>${version.datawave}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>gov.nsa.datawave.core</groupId>
|
||||
<artifactId>base-rest-responses</artifactId>
|
||||
@@ -367,6 +372,10 @@
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>gov.nsa.datawave.core</groupId>
|
||||
<artifactId>accumulo-utils</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>gov.nsa.datawave.core</groupId>
|
||||
<artifactId>base-rest-responses</artifactId>
|
||||
|
||||
+1
-1
@@ -165,7 +165,7 @@ public class AuditClient {
|
||||
params.set(AuditParameters.QUERY_AUDIT_TYPE, b.auditType.name());
|
||||
}
|
||||
if (null != b.marking) {
|
||||
params.set(AuditParameters.QUERY_SECURITY_MARKING_COLVIZ, b.marking.toColumnVisibilityString());
|
||||
params.set(AuditParameters.QUERY_SECURITY_MARKING_COLVIZ, b.marking.toAccessExpressionString());
|
||||
}
|
||||
if (null != b.queryLogic) {
|
||||
params.set(AuditParameters.QUERY_LOGIC_CLASS, b.queryLogic);
|
||||
|
||||
@@ -90,12 +90,6 @@
|
||||
<groupId>gov.nsa.datawave.core</groupId>
|
||||
<artifactId>accumulo-utils</artifactId>
|
||||
<version>${version.datawave}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>*</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>gov.nsa.datawave.core</groupId>
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ public class MarkingConfig {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnProperty(name = "datawave.defaults.MarkingFunctions.enabled", havingValue = "true", matchIfMissing = true)
|
||||
public MarkingFunctions markingFunctions() {
|
||||
public MarkingFunctions<?> markingFunctions() {
|
||||
return new MarkingFunctions.Default();
|
||||
}
|
||||
|
||||
|
||||
@@ -124,6 +124,7 @@
|
||||
<version.kryo>2.20</version.kryo>
|
||||
<version.kryonet>2.20</version.kryonet>
|
||||
<version.log4j>2.25.4</version.log4j>
|
||||
<version.lombok>1.18.36</version.lombok>
|
||||
<version.lucene>7.5.0</version.lucene>
|
||||
<version.metrics-cdi>1.6.0</version.metrics-cdi>
|
||||
<version.minlog>1.2</version.minlog>
|
||||
@@ -1375,6 +1376,12 @@
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${version.lombok}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.wildfly</groupId>
|
||||
<artifactId>wildfly-security</artifactId>
|
||||
|
||||
@@ -21,13 +21,13 @@ public class MarkingFunctionsFactory {
|
||||
|
||||
@Inject
|
||||
@SpringBean(refreshable = true)
|
||||
private static MarkingFunctions applicationMarkingFunctions;
|
||||
private static MarkingFunctions<?> applicationMarkingFunctions;
|
||||
|
||||
public static final Logger log = LoggerFactory.getLogger(MarkingFunctionsFactory.class);
|
||||
|
||||
private static MarkingFunctions markingFunctions;
|
||||
private static MarkingFunctions<?> markingFunctions;
|
||||
|
||||
public static synchronized MarkingFunctions createMarkingFunctions() {
|
||||
public static synchronized MarkingFunctions<?> createMarkingFunctions() {
|
||||
if (markingFunctions != null)
|
||||
return markingFunctions;
|
||||
|
||||
|
||||
+17
-31
@@ -15,8 +15,8 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentSkipListSet;
|
||||
|
||||
import org.apache.accumulo.access.AccessExpression;
|
||||
import org.apache.accumulo.core.security.ColumnVisibility;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang.builder.ToStringBuilder;
|
||||
import org.apache.hadoop.conf.Configurable;
|
||||
@@ -36,7 +36,8 @@ import datawave.ingest.data.TypeRegistry;
|
||||
import datawave.ingest.data.config.ConfigurationHelper;
|
||||
import datawave.ingest.data.config.ingest.IgnorableErrorHelperInterface;
|
||||
import datawave.ingest.protobuf.RawRecordContainer.Data;
|
||||
import datawave.marking.MarkingFunctions;
|
||||
import datawave.marking.AccessExpressionMarkings;
|
||||
import datawave.marking.Markings;
|
||||
import datawave.util.CompositeTimestamp;
|
||||
|
||||
public class RawRecordContainerImpl implements Writable, Configurable, RawRecordContainer {
|
||||
@@ -81,56 +82,41 @@ public class RawRecordContainerImpl implements Writable, Configurable, RawRecord
|
||||
private Map<String,String> auxMap = null;
|
||||
|
||||
// RawRecordContainer support
|
||||
Map<String,String> securityMarkings = null;
|
||||
Markings<?> securityMarkings = null;
|
||||
|
||||
public RawRecordContainerImpl() {
|
||||
uidBuilder = UID.builder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String,String> getSecurityMarkings() {
|
||||
public Markings<?> getSecurityMarkings() {
|
||||
return this.securityMarkings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSecurityMarkings(Map<String,String> securityMarkings) {
|
||||
this.securityMarkings = (securityMarkings == null ? null : new HashMap<>(securityMarkings));
|
||||
public void setSecurityMarkings(Markings<?> securityMarkings) {
|
||||
this.securityMarkings = securityMarkings;
|
||||
syncSecurityMarkingsToFields();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSecurityMarking(String domain, String marking) {
|
||||
if (null == securityMarkings) {
|
||||
securityMarkings = new HashMap<>();
|
||||
}
|
||||
securityMarkings.put(domain, marking);
|
||||
syncSecurityMarkingsToFields();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSecurityMarking(String domain, String marking) {
|
||||
return null != securityMarkings && securityMarkings.containsKey(domain) && StringUtils.equals(securityMarkings.get(domain), marking);
|
||||
}
|
||||
|
||||
protected void syncSecurityMarkingsToFields() {
|
||||
if (securityMarkings != null) {
|
||||
setVisibility(securityMarkings.get(MarkingFunctions.Default.COLUMN_VISIBILITY));
|
||||
AccessExpression ae = securityMarkings.toAccessExpression();
|
||||
if (ae != null) {
|
||||
setVisibilityNoSync(ae.getExpression());
|
||||
} else {
|
||||
setVisibilityNoSync(null);
|
||||
}
|
||||
} else {
|
||||
setVisibility((String) null);
|
||||
setVisibilityNoSync(null);
|
||||
}
|
||||
}
|
||||
|
||||
protected void syncFieldsToSecurityMarkings() {
|
||||
if (visibility != null) {
|
||||
if (securityMarkings == null) {
|
||||
securityMarkings = new HashMap<>();
|
||||
}
|
||||
securityMarkings.put(MarkingFunctions.Default.COLUMN_VISIBILITY, new String(visibility.getExpression()));
|
||||
|
||||
} else if (securityMarkings != null) {
|
||||
securityMarkings.remove(MarkingFunctions.Default.COLUMN_VISIBILITY);
|
||||
}
|
||||
if (securityMarkings != null && securityMarkings.isEmpty()) {
|
||||
String expr = new String(visibility.getExpression());
|
||||
securityMarkings = AccessExpressionMarkings.builder().columnVisibility(expr).build();
|
||||
} else {
|
||||
securityMarkings = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,11 @@ import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.accumulo.core.security.ColumnVisibility;
|
||||
|
||||
import datawave.data.hash.UID;
|
||||
import datawave.marking.Markings;
|
||||
import datawave.util.CompositeTimestamp;
|
||||
|
||||
/**
|
||||
@@ -17,13 +17,9 @@ import datawave.util.CompositeTimestamp;
|
||||
*/
|
||||
public interface RawRecordContainer {
|
||||
|
||||
Map<String,String> getSecurityMarkings();
|
||||
Markings<?> getSecurityMarkings();
|
||||
|
||||
void setSecurityMarkings(Map<String,String> securityMarkings);
|
||||
|
||||
void addSecurityMarking(String domain, String marking);
|
||||
|
||||
boolean hasSecurityMarking(String domain, String marking);
|
||||
void setSecurityMarkings(Markings<?> securityMarkings);
|
||||
|
||||
UID getId();
|
||||
|
||||
|
||||
+5
-6
@@ -1,11 +1,10 @@
|
||||
package datawave.ingest.data.config;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
|
||||
import datawave.data.type.Type;
|
||||
import datawave.marking.Markings;
|
||||
|
||||
/**
|
||||
* Base container class implementation of the NormalizedContentInterface. This class is utilized to retain the original and transformed content and labels for a
|
||||
@@ -22,7 +21,7 @@ public class BaseNormalizedContent implements NormalizedContentInterface, Clonea
|
||||
protected String _indexedFieldValue = null;
|
||||
|
||||
/** The security markings for the field value pair. */
|
||||
protected Map<String,String> _markings = null;
|
||||
protected Markings<?> _markings = null;
|
||||
|
||||
/** The field processing error if any. */
|
||||
protected Throwable error = null;
|
||||
@@ -40,7 +39,7 @@ public class BaseNormalizedContent implements NormalizedContentInterface, Clonea
|
||||
_indexedFieldValue = value;
|
||||
}
|
||||
|
||||
public BaseNormalizedContent(String field, String value, Map<String,String> markings) {
|
||||
public BaseNormalizedContent(String field, String value, Markings<?> markings) {
|
||||
this(field, value);
|
||||
_markings = markings;
|
||||
}
|
||||
@@ -117,12 +116,12 @@ public class BaseNormalizedContent implements NormalizedContentInterface, Clonea
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String,String> getMarkings() {
|
||||
public Markings<?> getMarkings() {
|
||||
return _markings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMarkings(Map<String,String> markings) {
|
||||
public void setMarkings(Markings<?> markings) {
|
||||
hashCode = null;
|
||||
this._markings = markings;
|
||||
}
|
||||
|
||||
+11
-12
@@ -8,7 +8,8 @@ import org.apache.hadoop.conf.Configuration;
|
||||
|
||||
import datawave.ingest.data.Type;
|
||||
import datawave.ingest.data.config.ingest.BaseIngestHelper;
|
||||
import datawave.marking.MarkingFunctions;
|
||||
import datawave.marking.AccessExpressionMarkings;
|
||||
import datawave.marking.Markings;
|
||||
|
||||
public interface MarkingsHelper {
|
||||
|
||||
@@ -28,7 +29,7 @@ public interface MarkingsHelper {
|
||||
*
|
||||
* @return markings
|
||||
*/
|
||||
Map<String,String> getDefaultMarkings();
|
||||
Markings<?> getDefaultMarkings();
|
||||
|
||||
/**
|
||||
* Returns the markings override for the field
|
||||
@@ -37,7 +38,7 @@ public interface MarkingsHelper {
|
||||
* the field name
|
||||
* @return markings
|
||||
*/
|
||||
Map<String,String> getFieldMarking(String fieldName);
|
||||
Markings<?> getFieldMarking(String fieldName);
|
||||
|
||||
/**
|
||||
* Method to set the markings on a field
|
||||
@@ -48,12 +49,12 @@ public interface MarkingsHelper {
|
||||
void markField(NormalizedContentInterface field);
|
||||
|
||||
/**
|
||||
* No-op helper for default ColumnVisibility implementation. Should only be used for testing purposes.
|
||||
* No-op helper for default AccessExpression implementation. Should only be used for testing purposes.
|
||||
*/
|
||||
class NoOp implements MarkingsHelper {
|
||||
|
||||
private Map<String,Map<String,String>> fieldMarkingMap = new HashMap<>();
|
||||
private Map<String,String> defaultMarkings = null;
|
||||
private Map<String,Markings<?>> fieldMarkingMap = new HashMap<>();
|
||||
private Markings<?> defaultMarkings = null;
|
||||
|
||||
Configuration conf;
|
||||
Type dataType;
|
||||
@@ -67,15 +68,13 @@ public interface MarkingsHelper {
|
||||
private void initDefaultMarkings() {
|
||||
String marking = conf.get(dataType.typeName() + DEFAULT_MARKING);
|
||||
if (null != marking) {
|
||||
defaultMarkings = new HashMap<>();
|
||||
defaultMarkings.put(MarkingFunctions.Default.COLUMN_VISIBILITY, marking);
|
||||
defaultMarkings = AccessExpressionMarkings.builder().columnVisibility(marking).build();
|
||||
}
|
||||
for (Entry<String,String> property : conf) {
|
||||
if (property.getKey().startsWith(dataType.typeName()) && property.getKey().endsWith(FIELD_MARKING)) {
|
||||
String fieldName = null;
|
||||
if (null != (fieldName = BaseIngestHelper.getFieldName(dataType, property.getKey(), FIELD_MARKING))) {
|
||||
Map<String,String> fieldMarking = new HashMap<>();
|
||||
fieldMarking.put(MarkingFunctions.Default.COLUMN_VISIBILITY, property.getValue());
|
||||
Markings<?> fieldMarking = AccessExpressionMarkings.builder().columnVisibility(property.getValue()).build();
|
||||
fieldMarkingMap.put(fieldName, fieldMarking);
|
||||
}
|
||||
}
|
||||
@@ -83,12 +82,12 @@ public interface MarkingsHelper {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String,String> getDefaultMarkings() {
|
||||
public Markings<?> getDefaultMarkings() {
|
||||
return defaultMarkings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String,String> getFieldMarking(String fieldName) {
|
||||
public Markings<?> getFieldMarking(String fieldName) {
|
||||
return fieldMarkingMap.get(fieldName);
|
||||
}
|
||||
|
||||
|
||||
+3
-4
@@ -1,8 +1,7 @@
|
||||
package datawave.ingest.data.config;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import datawave.data.type.Type;
|
||||
import datawave.marking.Markings;
|
||||
|
||||
/**
|
||||
* Interface utilized to reference the original and transformed content and labels for a value pair ingested into accumulo.
|
||||
@@ -66,7 +65,7 @@ public interface NormalizedContentInterface extends Cloneable {
|
||||
* @param markings
|
||||
* the markings to set
|
||||
*/
|
||||
void setMarkings(Map<String,String> markings);
|
||||
void setMarkings(Markings<?> markings);
|
||||
|
||||
/**
|
||||
* When we fail to process a field (e.g. normalize), then an error can be set which in the EventMapper results in the event being dropped from normal
|
||||
@@ -82,7 +81,7 @@ public interface NormalizedContentInterface extends Cloneable {
|
||||
*
|
||||
* @return The field specific markings, or null if the overall event markings are to be used.
|
||||
*/
|
||||
Map<String,String> getMarkings();
|
||||
Markings<?> getMarkings();
|
||||
|
||||
/**
|
||||
* Get the processing error for this field if any.
|
||||
|
||||
+2
-2
@@ -6,7 +6,6 @@ package datawave.ingest.data.config;
|
||||
* will be used.
|
||||
*/
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang.builder.HashCodeBuilder;
|
||||
@@ -15,6 +14,7 @@ import org.apache.hadoop.io.Text;
|
||||
import datawave.ingest.config.IngestConfiguration;
|
||||
import datawave.ingest.config.IngestConfigurationFactory;
|
||||
import datawave.ingest.config.MimeDecoder;
|
||||
import datawave.marking.Markings;
|
||||
|
||||
public class NormalizedFieldAndValue extends BaseNormalizedContent implements GroupedNormalizedContentInterface {
|
||||
private boolean grouped = false;
|
||||
@@ -42,7 +42,7 @@ public class NormalizedFieldAndValue extends BaseNormalizedContent implements Gr
|
||||
super(field, value);
|
||||
}
|
||||
|
||||
public NormalizedFieldAndValue(String field, String value, Map<String,String> markings) {
|
||||
public NormalizedFieldAndValue(String field, String value, Markings<?> markings) {
|
||||
super(field, value, markings);
|
||||
}
|
||||
|
||||
|
||||
+19
-33
@@ -30,6 +30,7 @@ import datawave.ingest.data.config.GroupedNormalizedContentInterface;
|
||||
import datawave.ingest.data.config.NormalizedContentInterface;
|
||||
import datawave.ingest.data.config.NormalizedFieldAndValue;
|
||||
import datawave.marking.MarkingFunctions;
|
||||
import datawave.marking.Markings;
|
||||
|
||||
/**
|
||||
* Similar to VirtualIngest virtual fields, but composite fields are not written in the event section of the shard table (only in the field index section)
|
||||
@@ -131,7 +132,7 @@ public interface CompositeIngest {
|
||||
protected Map<String,Boolean> allowMissing = new HashMap<>();
|
||||
private Set<String> ignoreNormalizationForFields = new HashSet<>();
|
||||
|
||||
protected MarkingFunctions markingFunctions;
|
||||
protected MarkingFunctions<?> markingFunctions;
|
||||
|
||||
public void setup(Type type, Configuration config) {
|
||||
|
||||
@@ -285,30 +286,6 @@ public interface CompositeIngest {
|
||||
return new String[] {str2, str1};
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper routine to merge markings maps when merging fields of a NormalizedContentInterface
|
||||
*
|
||||
* @param markings1
|
||||
* a map of markings
|
||||
* @param markings2
|
||||
* a different map of markings
|
||||
* @return the merged markings
|
||||
*/
|
||||
protected Map<String,String> mergeMarkings(Map<String,String> markings1, Map<String,String> markings2) {
|
||||
if (markings2 != null) {
|
||||
if (markings1 == null) {
|
||||
markings1 = markings2;
|
||||
} else {
|
||||
try {
|
||||
markings1 = markingFunctions.combine(markings1, markings2);
|
||||
} catch (MarkingFunctions.Exception e) {
|
||||
throw new RuntimeException("Unable to combine markings.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return markings1;
|
||||
}
|
||||
|
||||
public Multimap<String,NormalizedContentInterface> normalize(Multimap<String,String> fields) {
|
||||
Multimap<String,NormalizedContentInterface> eventFields = HashMultimap.create();
|
||||
for (Entry<String,String> field : fields.entries()) {
|
||||
@@ -356,7 +333,7 @@ public interface CompositeIngest {
|
||||
// Create the composite field from the event Fields members
|
||||
public void addCompositeFields(List<NormalizedContentInterface> compositeFields, Multimap<String,NormalizedContentInterface> eventFields,
|
||||
String compositeFieldName, String replacement, String[] grouping, GroupingPolicy groupingPolicy, boolean allowMissing, String[] fields,
|
||||
int pos, StringBuilder originalValue, StringBuilder normalizedValue, Map<String,String> markings, boolean isOverloadedField) {
|
||||
int pos, StringBuilder originalValue, StringBuilder normalizedValue, Markings<?> markings, boolean isOverloadedField) {
|
||||
String separator = (pos > 0) ? compositeSeparator.get(compositeFieldName) : "";
|
||||
// append any constants that have been specified
|
||||
while (pos < fields.length && isConstant(fields[pos])) {
|
||||
@@ -405,9 +382,14 @@ public interface CompositeIngest {
|
||||
normalizedValue.append(separator);
|
||||
normalizedValue.append(value.getIndexedFieldValue());
|
||||
if (pos + 1 < fields.length) {
|
||||
addCompositeFields(compositeFields, eventFields, compositeFieldName.replace("*", replacement), replacement,
|
||||
(grouping == null ? newGrouping : grouping), groupingPolicy, allowMissing, fields, pos + 1, originalValue,
|
||||
normalizedValue, mergeMarkings(markings, value.getMarkings()), isOverloadedField);
|
||||
try {
|
||||
addCompositeFields(compositeFields, eventFields, compositeFieldName.replace("*", replacement), replacement,
|
||||
(grouping == null ? newGrouping : grouping), groupingPolicy, allowMissing, fields, pos + 1,
|
||||
originalValue, normalizedValue, markingFunctions.combine(markings, value.getMarkings()),
|
||||
isOverloadedField);
|
||||
} catch (MarkingFunctions.Exception e) {
|
||||
throw new RuntimeException("Could not combine markings", e);
|
||||
}
|
||||
}
|
||||
originalValue.setLength(oLen);
|
||||
normalizedValue.setLength(nLen);
|
||||
@@ -427,7 +409,7 @@ public interface CompositeIngest {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!isOverloadedField || (isOverloadedField && pos == 0)) {
|
||||
if (!isOverloadedField || pos == 0) {
|
||||
originalValue.append(separator);
|
||||
originalValue.append(value.getEventFieldValue());
|
||||
}
|
||||
@@ -437,9 +419,13 @@ public interface CompositeIngest {
|
||||
} else {
|
||||
normalizedValue.append(value.getIndexedFieldValue());
|
||||
}
|
||||
addCompositeFields(compositeFields, eventFields, compositeFieldName, replacement, (grouping == null ? newGrouping : grouping),
|
||||
groupingPolicy, allowMissing, fields, pos + 1, originalValue, normalizedValue,
|
||||
mergeMarkings(markings, value.getMarkings()), isOverloadedField);
|
||||
try {
|
||||
addCompositeFields(compositeFields, eventFields, compositeFieldName, replacement, (grouping == null ? newGrouping : grouping),
|
||||
groupingPolicy, allowMissing, fields, pos + 1, originalValue, normalizedValue,
|
||||
markingFunctions.combine(markings, value.getMarkings()), isOverloadedField);
|
||||
} catch (MarkingFunctions.Exception e) {
|
||||
throw new RuntimeException("Could not combine markings", e);
|
||||
}
|
||||
originalValue.setLength(oLen);
|
||||
normalizedValue.setLength(nLen);
|
||||
}
|
||||
|
||||
+18
-33
@@ -28,6 +28,7 @@ import datawave.ingest.data.config.GroupedNormalizedContentInterface;
|
||||
import datawave.ingest.data.config.NormalizedContentInterface;
|
||||
import datawave.ingest.data.config.NormalizedFieldAndValue;
|
||||
import datawave.marking.MarkingFunctions;
|
||||
import datawave.marking.Markings;
|
||||
|
||||
public interface VirtualIngest {
|
||||
|
||||
@@ -126,7 +127,7 @@ public interface VirtualIngest {
|
||||
protected transient Map<String,Boolean> allowMissing = new HashMap<>();
|
||||
private Set<String> ignoreNormalizationForFields = new HashSet<>();
|
||||
|
||||
private transient MarkingFunctions markingFunctions;
|
||||
private transient MarkingFunctions<?> markingFunctions;
|
||||
|
||||
public void setup(Type type, String instance, Configuration config) {
|
||||
|
||||
@@ -338,30 +339,6 @@ public interface VirtualIngest {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper routine to merge markings maps when merging fields of a NormalizedContentInterface
|
||||
*
|
||||
* @param markings1
|
||||
* a map of markings
|
||||
* @param markings2
|
||||
* a different map of markings
|
||||
* @return the merged markings
|
||||
*/
|
||||
protected Map<String,String> mergeMarkings(Map<String,String> markings1, Map<String,String> markings2) {
|
||||
if (markings2 != null) {
|
||||
if (markings1 == null) {
|
||||
markings1 = markings2;
|
||||
} else {
|
||||
try {
|
||||
markings1 = markingFunctions.combine(markings1, markings2);
|
||||
} catch (MarkingFunctions.Exception e) {
|
||||
throw new RuntimeException("Unable to combine markings.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return markings1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the normalized form of a map of fields, and add the virtual fields as configured above.
|
||||
*
|
||||
@@ -544,7 +521,7 @@ public interface VirtualIngest {
|
||||
public void addVirtualFields(List<NormalizedContentInterface> virtualFields, Multimap<String,NormalizedContentInterface> eventFields,
|
||||
Map<String,Multimap<VirtualFieldGrouping,NormalizedContentInterface>> groupings, String virtualFieldName, String replacement,
|
||||
VirtualFieldGrouping grouping, GroupingPolicy groupingPolicy, boolean allowMissing, String[] fields, int pos, String startSeparator,
|
||||
String endSeparator, StringBuilder originalValue, StringBuilder normalizedValue, Map<String,String> markings) {
|
||||
String endSeparator, StringBuilder originalValue, StringBuilder normalizedValue, Markings<?> markings) {
|
||||
String separator = "";
|
||||
// append any constants that have been specified
|
||||
while (pos < fields.length && isConstant(fields[pos])) {
|
||||
@@ -599,10 +576,14 @@ public interface VirtualIngest {
|
||||
normalizedValue.append(endSeparator);
|
||||
|
||||
// recurse for the next virtual field definition segment
|
||||
addVirtualFields(virtualFields, eventFields, groupings, virtualFieldName.replace("*", replacement), replacement,
|
||||
(grouping == null ? newGrouping : grouping), groupingPolicy, allowMissing, fields, pos + 1,
|
||||
this.defaultStartSeparator, this.defaultEndSeparator, originalValue, normalizedValue,
|
||||
mergeMarkings(markings, value.getMarkings()));
|
||||
try {
|
||||
addVirtualFields(virtualFields, eventFields, groupings, virtualFieldName.replace("*", replacement), replacement,
|
||||
(grouping == null ? newGrouping : grouping), groupingPolicy, allowMissing, fields, pos + 1,
|
||||
this.defaultStartSeparator, this.defaultEndSeparator, originalValue, normalizedValue,
|
||||
markingFunctions.combine(markings, value.getMarkings()));
|
||||
} catch (MarkingFunctions.Exception e) {
|
||||
throw new RuntimeException("Could not combine markings", e);
|
||||
}
|
||||
|
||||
// reset the values to the original length
|
||||
originalValue.setLength(oLen);
|
||||
@@ -638,9 +619,13 @@ public interface VirtualIngest {
|
||||
normalizedValue.append(endSeparator);
|
||||
|
||||
// recurse on the next virtual field segment
|
||||
addVirtualFields(virtualFields, eventFields, groupings, virtualFieldName, replacement, (grouping == null ? newGrouping : grouping),
|
||||
groupingPolicy, allowMissing, fields, pos + 1, this.defaultStartSeparator, this.defaultEndSeparator, originalValue,
|
||||
normalizedValue, mergeMarkings(markings, value.getMarkings()));
|
||||
try {
|
||||
addVirtualFields(virtualFields, eventFields, groupings, virtualFieldName, replacement, (grouping == null ? newGrouping : grouping),
|
||||
groupingPolicy, allowMissing, fields, pos + 1, this.defaultStartSeparator, this.defaultEndSeparator, originalValue,
|
||||
normalizedValue, markingFunctions.combine(markings, value.getMarkings()));
|
||||
} catch (MarkingFunctions.Exception e) {
|
||||
throw new RuntimeException("Could not combine markings", e);
|
||||
}
|
||||
|
||||
// reset the values to the original length
|
||||
originalValue.setLength(oLen);
|
||||
|
||||
@@ -161,7 +161,7 @@ public class EventMapper<K1,V1 extends RawRecordContainer,K2,V2> extends StatsDE
|
||||
|
||||
protected Set<String> sequenceFileNames = new HashSet<>();
|
||||
|
||||
protected MarkingFunctions markingFunctions;
|
||||
protected MarkingFunctions<?> markingFunctions;
|
||||
|
||||
private boolean metricsEnabled = false;
|
||||
private MetricsService<K2,V2> metricsService;
|
||||
|
||||
+5
-9
@@ -30,6 +30,7 @@ import datawave.ingest.mapreduce.job.BulkIngestKey;
|
||||
import datawave.ingest.mapreduce.job.writer.ContextWriter;
|
||||
import datawave.ingest.metadata.RawRecordMetadata;
|
||||
import datawave.marking.MarkingFunctions;
|
||||
import datawave.marking.Markings;
|
||||
import datawave.util.StringUtils;
|
||||
import datawave.util.TextUtil;
|
||||
|
||||
@@ -63,7 +64,7 @@ public class AtomDataTypeHandler<KEYIN,KEYOUT,VALUEOUT> implements ExtendedDataT
|
||||
protected String[] fieldOverrides = null;
|
||||
protected HashMap<String,Set<String>> subCategories;
|
||||
protected String[] sCategories = null;
|
||||
protected MarkingFunctions markingFunctions;
|
||||
protected MarkingFunctions<?> markingFunctions;
|
||||
|
||||
protected Configuration conf;
|
||||
|
||||
@@ -254,16 +255,11 @@ public class AtomDataTypeHandler<KEYIN,KEYOUT,VALUEOUT> implements ExtendedDataT
|
||||
* the value
|
||||
* @return the visibility
|
||||
*/
|
||||
|
||||
protected String getColumnQualifier(RawRecordContainer event, NormalizedContentInterface value) {
|
||||
ColumnVisibility visibility = event.getVisibility();
|
||||
if (value.getMarkings() != null && !value.getMarkings().isEmpty()) {
|
||||
try {
|
||||
visibility = markingFunctions.translateToColumnVisibility(value.getMarkings());
|
||||
} catch (MarkingFunctions.Exception e) {
|
||||
throw new RuntimeException("Cannot convert record-level markings into a column visibility", e);
|
||||
|
||||
}
|
||||
Markings<?> markings = value.getMarkings();
|
||||
if (markings != null && !markings.isEmpty()) {
|
||||
visibility = markings.toColumnVisibility();
|
||||
}
|
||||
return flatten(visibility);
|
||||
}
|
||||
|
||||
+15
-25
@@ -5,6 +5,7 @@ import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.accumulo.access.AccessExpression;
|
||||
import org.apache.accumulo.core.data.Key;
|
||||
import org.apache.accumulo.core.security.ColumnVisibility;
|
||||
import org.apache.hadoop.conf.Configuration;
|
||||
@@ -29,6 +30,7 @@ import datawave.ingest.mapreduce.handler.error.ErrorShardedDataTypeHandler;
|
||||
import datawave.ingest.mapreduce.job.BulkIngestKey;
|
||||
import datawave.ingest.mapreduce.job.writer.ContextWriter;
|
||||
import datawave.marking.MarkingFunctions;
|
||||
import datawave.marking.Markings;
|
||||
|
||||
/**
|
||||
* This class differs from the parent in that when it sees a field name of ERROR it creates a category name using the field name and value.
|
||||
@@ -48,13 +50,10 @@ public class AtomErrorDataTypeHandler<KEYIN,KEYOUT,VALUEOUT> extends AtomDataTyp
|
||||
public static final String ERROR_FIELD = "ERROR";
|
||||
public static final String STACK_TRACE_FIELD = "STACKTRACE";
|
||||
public static final String EVENT_CONTENT_FIELD = "EVENT";
|
||||
public static final String COLUMN_VISIBILITY = "columnVisibility";
|
||||
|
||||
private MarkingsHelper mHelper = null;
|
||||
private ColumnVisibility defaultVisibility = null;
|
||||
private AccessExpression defaultVisibility = null;
|
||||
private Configuration conf = null;
|
||||
private ErrorShardedIngestHelper errorHelper = null;
|
||||
private MarkingFunctions markingFunctions;
|
||||
|
||||
@Override
|
||||
public void setup(TaskAttemptContext context) {
|
||||
@@ -77,11 +76,7 @@ public class AtomErrorDataTypeHandler<KEYIN,KEYOUT,VALUEOUT> extends AtomDataTyp
|
||||
}
|
||||
|
||||
mHelper = IngestConfigurationFactory.getIngestConfiguration().getMarkingsHelper(conf, record.getDataType());
|
||||
try {
|
||||
defaultVisibility = markingFunctions.translateToColumnVisibility(mHelper.getDefaultMarkings());
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("Failed to parse security marking configuration", e);
|
||||
}
|
||||
defaultVisibility = mHelper.getDefaultMarkings().toAccessExpression();
|
||||
|
||||
// write out the event into a value before we muck with it
|
||||
DataOutputBuffer buffer = new DataOutputBuffer();
|
||||
@@ -180,22 +175,17 @@ public class AtomErrorDataTypeHandler<KEYIN,KEYOUT,VALUEOUT> extends AtomDataTyp
|
||||
}
|
||||
|
||||
protected String getVisibilityColumnString(RawRecordContainer event, NormalizedContentInterface value) {
|
||||
|
||||
ColumnVisibility visibility = getVisibilityColumnVisibility(event, value);
|
||||
return visibility.toString();
|
||||
|
||||
}
|
||||
|
||||
protected ColumnVisibility getVisibilityColumnVisibility(RawRecordContainer event, NormalizedContentInterface value) {
|
||||
ColumnVisibility visibility = event.getVisibility();
|
||||
if (value.getMarkings() != null && !value.getMarkings().isEmpty()) {
|
||||
try {
|
||||
visibility = markingFunctions.translateToColumnVisibility(value.getMarkings());
|
||||
} catch (MarkingFunctions.Exception e) {
|
||||
throw new RuntimeException("Cannot convert record-level markings into a column visibility", e);
|
||||
|
||||
}
|
||||
Markings<?> markings = value.getMarkings();
|
||||
// value marking is 1st choice
|
||||
if (markings != null && !markings.isEmpty()) {
|
||||
return markings.toAccessExpression().getExpression();
|
||||
}
|
||||
return visibility == null ? defaultVisibility : visibility;
|
||||
ColumnVisibility visibility = event.getVisibility();
|
||||
if (visibility != null) {
|
||||
// event marking is 2nd choice
|
||||
return new String(visibility.getExpression());
|
||||
}
|
||||
// default marking is the last resort
|
||||
return defaultVisibility != null ? defaultVisibility.getExpression() : "";
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -94,6 +94,7 @@ public class DateIndexDataTypeHandler<KEYIN> implements DataTypeHandler<KEYIN>,
|
||||
protected DateNormalizer dateNormalizer = new DateNormalizer();
|
||||
protected ShardIdFactory shardIdFactory = null;
|
||||
protected TaskAttemptContext taskAttemptContext = null;
|
||||
protected MarkingFunctions<?> markingFunctions;
|
||||
|
||||
public Set<Type> getDataTypes() {
|
||||
Set<Type> types = new HashSet<>();
|
||||
@@ -148,6 +149,7 @@ public class DateIndexDataTypeHandler<KEYIN> implements DataTypeHandler<KEYIN>,
|
||||
this.taskAttemptContext = context;
|
||||
this.conf = context.getConfiguration();
|
||||
this.shardIdFactory = new ShardIdFactory(conf);
|
||||
markingFunctions = MarkingFunctions.Factory.createMarkingFunctions();
|
||||
|
||||
String tableName = conf.get(DATEINDEX_TNAME, null);
|
||||
if (null == tableName) {
|
||||
@@ -364,7 +366,7 @@ public class DateIndexDataTypeHandler<KEYIN> implements DataTypeHandler<KEYIN>,
|
||||
* @return the flattened visibility
|
||||
*/
|
||||
protected byte[] flatten(ColumnVisibility vis) {
|
||||
return MarkingFunctions.Factory.createMarkingFunctions().flatten(vis);
|
||||
return markingFunctions == null ? vis.flatten() : markingFunctions.flatten(vis);
|
||||
}
|
||||
|
||||
public Text getDateIndexTableName() {
|
||||
|
||||
+14
-11
@@ -1,5 +1,7 @@
|
||||
package datawave.ingest.mapreduce.handler.edge;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import static datawave.ingest.mapreduce.handler.shard.ShardedDataTypeHandler.METADATA_TABLE_LOADER_PRIORITY;
|
||||
import static datawave.ingest.mapreduce.handler.shard.ShardedDataTypeHandler.METADATA_TABLE_NAME;
|
||||
|
||||
@@ -20,6 +22,7 @@ import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.accumulo.access.AccessExpression;
|
||||
import org.apache.accumulo.core.data.Key;
|
||||
import org.apache.accumulo.core.data.Value;
|
||||
import org.apache.accumulo.core.security.ColumnVisibility;
|
||||
@@ -73,7 +76,9 @@ import datawave.ingest.mapreduce.job.writer.ContextWriter;
|
||||
import datawave.ingest.metadata.RawRecordMetadata;
|
||||
import datawave.ingest.table.config.LoadDateTableConfigHelper;
|
||||
import datawave.ingest.time.Now;
|
||||
import datawave.marking.AccessExpressionUtil;
|
||||
import datawave.marking.MarkingFunctions;
|
||||
import datawave.marking.Markings;
|
||||
import datawave.metadata.protobuf.EdgeMetadata;
|
||||
import datawave.metadata.protobuf.EdgeMetadata.MetadataValue;
|
||||
import datawave.metadata.protobuf.EdgeMetadata.MetadataValue.Metadata;
|
||||
@@ -141,7 +146,7 @@ public class ProtobufEdgeDataTypeHandler<KEYIN,KEYOUT,VALUEOUT> implements Exten
|
||||
protected String edgeTableName = null;
|
||||
protected String metadataTableName = null;
|
||||
protected boolean enableMetadata = false;
|
||||
protected MarkingFunctions markingFunctions;
|
||||
protected MarkingFunctions<?> markingFunctions;
|
||||
|
||||
protected Map<String,EdgeDefinitionConfigurationHelper> edges = null;
|
||||
|
||||
@@ -1327,15 +1332,13 @@ public class ProtobufEdgeDataTypeHandler<KEYIN,KEYOUT,VALUEOUT> implements Exten
|
||||
* the event container
|
||||
* @return the visibility as Text object
|
||||
*/
|
||||
protected Text getVisibility(Map<String,String> markings, RawRecordContainer event) {
|
||||
try {
|
||||
if (null == markings || markings.isEmpty()) {
|
||||
return new Text(flatten(event.getVisibility()));
|
||||
} else {
|
||||
return new Text(flatten(markingFunctions.translateToColumnVisibility(markings)));
|
||||
}
|
||||
} catch (datawave.marking.MarkingFunctions.Exception e) {
|
||||
throw new RuntimeException("Cannot convert markings into column visibility", e);
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Text getVisibility(Markings<?> markings, RawRecordContainer event) {
|
||||
if (null == markings || markings.isEmpty()) {
|
||||
return new Text(flatten(event.getVisibility()));
|
||||
} else {
|
||||
AccessExpression ae = AccessExpressionUtil.normalize(markings.toAccessExpression());
|
||||
return new Text(ae.getExpression().getBytes(UTF_8));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1363,7 +1366,7 @@ public class ProtobufEdgeDataTypeHandler<KEYIN,KEYOUT,VALUEOUT> implements Exten
|
||||
* @return the flattened visibility
|
||||
*/
|
||||
protected byte[] flatten(ColumnVisibility vis) {
|
||||
return markingFunctions.flatten(vis);
|
||||
return markingFunctions == null ? vis.flatten() : markingFunctions.flatten(vis);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-4
@@ -1,8 +1,7 @@
|
||||
package datawave.ingest.mapreduce.handler.edge.define;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import datawave.ingest.data.config.NormalizedContentInterface;
|
||||
import datawave.marking.Markings;
|
||||
|
||||
/**
|
||||
* Extracts the duration field specified by a Normalized Content Interface
|
||||
@@ -13,7 +12,7 @@ import datawave.ingest.data.config.NormalizedContentInterface;
|
||||
public class DurationValue {
|
||||
private int duration = -1;
|
||||
|
||||
private Map<String,String> markings = null;
|
||||
private Markings<?> markings = null;
|
||||
|
||||
public DurationValue(NormalizedContentInterface elapsedTimeNCI) {
|
||||
String durString = elapsedTimeNCI.getIndexedFieldValue();
|
||||
@@ -36,7 +35,7 @@ public class DurationValue {
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String,String> getMarkings() {
|
||||
public Markings<?> getMarkings() {
|
||||
return this.markings;
|
||||
}
|
||||
}
|
||||
+30
-54
@@ -3,7 +3,6 @@ package datawave.ingest.mapreduce.handler.edge.define;
|
||||
import java.io.IOException;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.accumulo.core.data.Value;
|
||||
import org.apache.accumulo.core.security.ColumnVisibility;
|
||||
@@ -20,7 +19,7 @@ import datawave.ingest.data.config.NormalizedContentInterface;
|
||||
import datawave.ingest.data.config.ingest.IngestHelperInterface;
|
||||
import datawave.ingest.mapreduce.handler.edge.define.VertexValue.ValueType;
|
||||
import datawave.marking.MarkingFunctions;
|
||||
import datawave.marking.MarkingFunctions.Exception;
|
||||
import datawave.marking.Markings;
|
||||
import datawave.util.time.DateHelper;
|
||||
|
||||
/**
|
||||
@@ -34,43 +33,43 @@ public class EdgeDataBundle {
|
||||
// Input/Setup variables
|
||||
// final so you're not tempted to change them
|
||||
private final RawRecordContainer event;
|
||||
private final MarkingFunctions<?> markingFunctions;
|
||||
private VertexValue source;
|
||||
private VertexValue sink;
|
||||
private EdgeDefinition edgeDefinition = null;
|
||||
private EdgeDefinition edgeDefinition;
|
||||
private EdgeDirection edgeDirection = EdgeDirection.UNIDIRECTIONAL;
|
||||
|
||||
private String sourceMaskedValue = null;
|
||||
private boolean hasMaskedSource = false;
|
||||
private String sinkMaskedValue = null;
|
||||
private boolean hasMaskedSink = false;
|
||||
private String sourceMaskedValue;
|
||||
private boolean hasMaskedSource;
|
||||
private String sinkMaskedValue;
|
||||
private boolean hasMaskedSink;
|
||||
|
||||
// Variables for output
|
||||
private boolean requiresMasking = false;
|
||||
private boolean isDeleting = false;
|
||||
private boolean requiresMasking;
|
||||
private boolean isDeleting;
|
||||
private String edgeType;
|
||||
private String enrichedIndex;
|
||||
private String enrichedValue;
|
||||
private String edgeAttribute3;
|
||||
private String edgeAttribute2;
|
||||
|
||||
private long eventDate = 0;
|
||||
private long eventDate;
|
||||
private IngestHelperInterface helper;
|
||||
private Map<String,String> markings = null;
|
||||
private ColumnVisibility maskedVisibility = null;
|
||||
private boolean forceMaskedVisibility = false; // if this is a masked event, but the
|
||||
private Markings<?> markings;
|
||||
private ColumnVisibility maskedVisibility;
|
||||
private boolean forceMaskedVisibility; // if this is a masked event, but the
|
||||
// the fields defined aren't masked, use the unmasked visibility
|
||||
|
||||
// Duration value if defined
|
||||
private DurationValue durationValue = null;
|
||||
private DurationValue durationValue;
|
||||
|
||||
private String loadDate;
|
||||
private MarkingFunctions mf = null;
|
||||
private String uuid;
|
||||
private long activityDate;
|
||||
private boolean validActivityDate;
|
||||
|
||||
public EdgeDataBundle(RawRecordContainer event, String typeName, String id, IngestHelperInterface helper) {
|
||||
this.mf = MarkingFunctions.Factory.createMarkingFunctions();
|
||||
this.markingFunctions = MarkingFunctions.Factory.createMarkingFunctions();
|
||||
this.event = event;
|
||||
this.eventDate = event.getDate();
|
||||
this.edgeType = typeName;
|
||||
@@ -80,7 +79,7 @@ public class EdgeDataBundle {
|
||||
|
||||
public EdgeDataBundle(EdgeDefinition edgeDef, NormalizedContentInterface ifaceSource, NormalizedContentInterface ifaceSink, RawRecordContainer event,
|
||||
IngestHelperInterface helper) {
|
||||
this(event, edgeDef.getEdgeType().toString(), null, helper);
|
||||
this(event, edgeDef.getEdgeType(), null, helper);
|
||||
|
||||
this.setSource(new VertexValue(edgeDef.isUseRealm(), edgeDef.getSourceIndexedFieldRealm(), edgeDef.getSourceEventFieldRealm(),
|
||||
edgeDef.getSourceRelationship(), edgeDef.getSourceCollection(), ifaceSource));
|
||||
@@ -95,7 +94,11 @@ public class EdgeDataBundle {
|
||||
// even though event, etc. references are saved above, passing in the event
|
||||
// prevents future bug
|
||||
this.initFieldMasking(helper, event);
|
||||
this.initMarkings(getSource().getMarkings(), getSink().getMarkings());
|
||||
try {
|
||||
this.markings = markingFunctions.combine(getSource().getMarkings(), getSink().getMarkings());
|
||||
} catch (MarkingFunctions.Exception e) {
|
||||
throw new RuntimeException("Could not combine markings", e);
|
||||
}
|
||||
}
|
||||
|
||||
private int getHour(long time) {
|
||||
@@ -140,23 +143,6 @@ public class EdgeDataBundle {
|
||||
this.maskedVisibility = maskedVisibility;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void initMarkings(Map<String,String> m1, Map<String,String> m2) {
|
||||
if (m1 != null) {
|
||||
if (m2 != null) {
|
||||
try {
|
||||
this.markings = mf.combine(m1, m2);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Unable to combine markings", e);
|
||||
}
|
||||
} else {
|
||||
this.markings = m1;
|
||||
}
|
||||
} else if (m2 != null) {
|
||||
this.markings = m2;
|
||||
}
|
||||
}
|
||||
|
||||
public int getDuration() {
|
||||
return null == this.getDurationValue() ? -1 : this.getDurationValue().getDuration();
|
||||
}
|
||||
@@ -192,24 +178,19 @@ public class EdgeDataBundle {
|
||||
}
|
||||
|
||||
if (date_type == EdgeKey.DATE_TYPE.EVENT_ONLY) {
|
||||
if (validActivityDate) {
|
||||
builder.setBadActivityDate(false);
|
||||
} else {
|
||||
builder.setBadActivityDate(true);
|
||||
}
|
||||
|
||||
builder.setBadActivityDate(!validActivityDate);
|
||||
}
|
||||
// Set counts
|
||||
if (!this.isDeleting()) {
|
||||
builder.setCount(1l);
|
||||
builder.setCount(1L);
|
||||
} else {
|
||||
builder.setCount(-1l);
|
||||
builder.setCount(-1L);
|
||||
}
|
||||
// Set Hour Bitmask
|
||||
if (hour != -1) {
|
||||
builder.setHour(hour);
|
||||
}
|
||||
if (forwardEdge == true) {
|
||||
if (forwardEdge) {
|
||||
builder.setSourceValue(source.getValue(ValueType.EVENT));
|
||||
builder.setSinkValue(sink.getValue(ValueType.EVENT));
|
||||
} else {
|
||||
@@ -236,16 +217,11 @@ public class EdgeDataBundle {
|
||||
}
|
||||
|
||||
if (date_type == EdgeKey.DATE_TYPE.EVENT_ONLY) {
|
||||
if (validActivityDate) {
|
||||
builder.setBadActivityDate(false);
|
||||
} else {
|
||||
builder.setBadActivityDate(true);
|
||||
}
|
||||
|
||||
builder.setBadActivityDate(!validActivityDate);
|
||||
}
|
||||
List<Long> hours = EdgeValueHelper.getLongListForHour(hour, this.isDeleting());
|
||||
builder.setHours(hours);
|
||||
if (forwardEdge == true) {
|
||||
if (forwardEdge) {
|
||||
builder.setSourceValue(source.getValue(ValueType.EVENT));
|
||||
} else {
|
||||
builder.setSourceValue(sink.getValue(ValueType.EVENT));
|
||||
@@ -276,7 +252,7 @@ public class EdgeDataBundle {
|
||||
EdgeValueBuilder builder = datawave.edge.util.EdgeValue.newBuilder();
|
||||
List<Long> duration = EdgeValueHelper.getLongListForDuration(this.getDuration(), this.isDeleting());
|
||||
builder.setDuration(duration);
|
||||
if (forwardEdge == true) {
|
||||
if (forwardEdge) {
|
||||
builder.setSourceValue(source.getValue(ValueType.EVENT));
|
||||
} else {
|
||||
builder.setSourceValue(sink.getValue(ValueType.EVENT));
|
||||
@@ -385,11 +361,11 @@ public class EdgeDataBundle {
|
||||
this.sink = sink;
|
||||
}
|
||||
|
||||
public Map<String,String> getMarkings() {
|
||||
public Markings<?> getMarkings() {
|
||||
return this.markings;
|
||||
}
|
||||
|
||||
public void setMarkings(Map<String,String> markings) {
|
||||
public void setMarkings(Markings<?> markings) {
|
||||
this.markings = markings;
|
||||
}
|
||||
|
||||
|
||||
+3
-4
@@ -1,8 +1,7 @@
|
||||
package datawave.ingest.mapreduce.handler.edge.define;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import datawave.ingest.data.config.NormalizedContentInterface;
|
||||
import datawave.marking.Markings;
|
||||
|
||||
/**
|
||||
* Combines a VertexDefinition with value obtained from a {@link datawave.ingest.data.config.NormalizedContentInterface}.
|
||||
@@ -23,7 +22,7 @@ public class VertexValue {
|
||||
private String indexedRealmLabel = null;
|
||||
private String eventRealmLabel = null;
|
||||
private String sourceIndex = null;
|
||||
private Map<String,String> markings = null;
|
||||
private Markings<?> markings = null;
|
||||
private String maskedValue = null;
|
||||
private boolean hasMaskedValue = false;
|
||||
private String relationshipType = null;
|
||||
@@ -50,7 +49,7 @@ public class VertexValue {
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String,String> getMarkings() {
|
||||
public Markings<?> getMarkings() {
|
||||
return this.markings;
|
||||
}
|
||||
|
||||
|
||||
+13
-16
@@ -1,10 +1,12 @@
|
||||
package datawave.ingest.mapreduce.handler.error;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.accumulo.access.AccessExpression;
|
||||
import org.apache.accumulo.core.data.Key;
|
||||
import org.apache.accumulo.core.data.Value;
|
||||
import org.apache.accumulo.core.security.ColumnVisibility;
|
||||
@@ -109,7 +111,7 @@ public class ErrorDataTypeHandler<KEYIN,KEYOUT,VALUEOUT> implements ExtendedData
|
||||
|
||||
private byte[] defaultVisibility = null;
|
||||
protected MarkingsHelper markingsHelper;
|
||||
protected MarkingFunctions markingFunctions;
|
||||
protected MarkingFunctions<?> markingFunctions;
|
||||
|
||||
private String tableName = null;
|
||||
|
||||
@@ -133,11 +135,11 @@ public class ErrorDataTypeHandler<KEYIN,KEYOUT,VALUEOUT> implements ExtendedData
|
||||
|
||||
this.conf = context.getConfiguration();
|
||||
|
||||
try {
|
||||
Map<String,String> defaultMarkings = markingsHelper.getDefaultMarkings();
|
||||
defaultVisibility = flatten(markingFunctions.translateToColumnVisibility(defaultMarkings));
|
||||
} catch (MarkingFunctions.Exception e) {
|
||||
throw new IllegalArgumentException("Failed to convert default markings to a ColumnVisibility.", e);
|
||||
if (markingsHelper != null && markingsHelper.getDefaultMarkings() != null) {
|
||||
AccessExpression ae = markingsHelper.getDefaultMarkings().toAccessExpression();
|
||||
if (ae != null) {
|
||||
defaultVisibility = ae.getExpression().getBytes(UTF_8);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize a UID builder based on the configuration
|
||||
@@ -320,12 +322,7 @@ public class ErrorDataTypeHandler<KEYIN,KEYOUT,VALUEOUT> implements ExtendedData
|
||||
protected byte[] getVisibility(RawRecordContainer event, NormalizedContentInterface value) {
|
||||
byte[] visibility;
|
||||
if (value != null && value.getMarkings() != null && !value.getMarkings().isEmpty()) {
|
||||
try {
|
||||
visibility = flatten(markingFunctions.translateToColumnVisibility(value.getMarkings()));
|
||||
} catch (MarkingFunctions.Exception e) {
|
||||
log.error("Failed to create visibility from markings, using default", e);
|
||||
visibility = defaultVisibility;
|
||||
}
|
||||
visibility = flatten(value.getMarkings().toColumnVisibility());
|
||||
} else if (event.getVisibility() != null) {
|
||||
visibility = flatten(event.getVisibility());
|
||||
} else {
|
||||
@@ -335,14 +332,14 @@ public class ErrorDataTypeHandler<KEYIN,KEYOUT,VALUEOUT> implements ExtendedData
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a flattened visibility, using the cache if possible
|
||||
* Normalize a ColumnVisibility expression via AccessExpression and return the expression bytes.
|
||||
*
|
||||
* @param vis
|
||||
* the visibility
|
||||
* @return the flattened visibility
|
||||
* @return the normalized visibility bytes
|
||||
*/
|
||||
protected byte[] flatten(ColumnVisibility vis) {
|
||||
return markingFunctions.flatten(vis);
|
||||
return markingFunctions == null ? vis.flatten() : markingFunctions.flatten(vis);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+9
-11
@@ -1,5 +1,7 @@
|
||||
package datawave.ingest.mapreduce.handler.error;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayList;
|
||||
@@ -7,6 +9,7 @@ import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.accumulo.access.AccessExpression;
|
||||
import org.apache.accumulo.core.data.Key;
|
||||
import org.apache.accumulo.core.data.Value;
|
||||
import org.apache.hadoop.conf.Configurable;
|
||||
@@ -41,7 +44,6 @@ import datawave.ingest.mapreduce.handler.shard.AbstractColumnBasedHandler;
|
||||
import datawave.ingest.mapreduce.handler.shard.ShardedDataTypeHandler;
|
||||
import datawave.ingest.mapreduce.job.BulkIngestKey;
|
||||
import datawave.ingest.mapreduce.job.writer.ContextWriter;
|
||||
import datawave.marking.MarkingFunctions;
|
||||
import datawave.table.constants.ColumnFamilyConstants;
|
||||
|
||||
/**
|
||||
@@ -156,10 +158,11 @@ public class ErrorShardedDataTypeHandler<KEYIN,KEYOUT,VALUEOUT> extends Abstract
|
||||
tableName = conf.get(ERROR_PROP_PREFIX + SHARD_DINDX_NAME);
|
||||
setShardDictionaryIndexTableName(tableName == null ? null : new Text(tableName));
|
||||
|
||||
try {
|
||||
defaultVisibility = flatten(markingFunctions.translateToColumnVisibility(markingsHelper.getDefaultMarkings()));
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("Failed to parse security marking configuration", e);
|
||||
if (markingsHelper != null && markingsHelper.getDefaultMarkings() != null) {
|
||||
AccessExpression ae = markingsHelper.getDefaultMarkings().toAccessExpression();
|
||||
if (ae != null) {
|
||||
defaultVisibility = ae.getExpression().getBytes(UTF_8);
|
||||
}
|
||||
}
|
||||
|
||||
log.info("ShardedErrorDataTypeHandler configured.");
|
||||
@@ -347,12 +350,7 @@ public class ErrorShardedDataTypeHandler<KEYIN,KEYOUT,VALUEOUT> extends Abstract
|
||||
public byte[] getVisibility(RawRecordContainer event, NormalizedContentInterface value) {
|
||||
byte[] visibility;
|
||||
if (value != null && value.getMarkings() != null && !value.getMarkings().isEmpty()) {
|
||||
try {
|
||||
visibility = flatten(markingFunctions.translateToColumnVisibility(value.getMarkings()));
|
||||
} catch (MarkingFunctions.Exception e) {
|
||||
log.error("Failed to create visibility from markings, using default", e);
|
||||
visibility = defaultVisibility;
|
||||
}
|
||||
visibility = flatten(value.getMarkings().toColumnVisibility());
|
||||
} else if (event.getVisibility() != null) {
|
||||
visibility = flatten(event.getVisibility());
|
||||
} else {
|
||||
|
||||
+1
-1
@@ -91,7 +91,7 @@ public class FacetHandler<KEYIN,KEYOUT,VALUEOUT> implements ExtendedDataTypeHand
|
||||
|
||||
/* Instance variables */
|
||||
|
||||
protected MarkingFunctions markingFunctions;
|
||||
protected MarkingFunctions<?> markingFunctions;
|
||||
protected ShardIdFactory shardIdFactory;
|
||||
protected TaskAttemptContext taskAttemptContext;
|
||||
|
||||
|
||||
+7
-9
@@ -50,6 +50,7 @@ import datawave.ingest.util.BloomFilterUtil;
|
||||
import datawave.ingest.util.BloomFilterWrapper;
|
||||
import datawave.ingest.util.DiskSpaceStarvationStrategy;
|
||||
import datawave.marking.MarkingFunctions;
|
||||
import datawave.marking.Markings;
|
||||
import datawave.query.model.Direction;
|
||||
import datawave.util.CompositeTimestamp;
|
||||
import datawave.util.TableName;
|
||||
@@ -219,7 +220,7 @@ public abstract class ShardedDataTypeHandler<KEYIN> extends StatsDEnabledDataTyp
|
||||
private RawRecordMetadata metadata = null;
|
||||
private ShardIdFactory shardIdFactory = null;
|
||||
private LoadingCache<String,String> dCache = null;
|
||||
protected MarkingFunctions markingFunctions;
|
||||
protected MarkingFunctions<?> markingFunctions;
|
||||
protected IngestConfiguration ingestConfig = IngestConfigurationFactory.getIngestConfiguration();
|
||||
|
||||
// default setting is a standard index with uid and event keys
|
||||
@@ -1129,22 +1130,19 @@ public abstract class ShardedDataTypeHandler<KEYIN> extends StatsDEnabledDataTyp
|
||||
*/
|
||||
public byte[] getVisibility(RawRecordContainer event, NormalizedContentInterface value) {
|
||||
ColumnVisibility visibility = event.getVisibility();
|
||||
if (value.getMarkings() != null && !value.getMarkings().isEmpty()) {
|
||||
try {
|
||||
visibility = markingFunctions.translateToColumnVisibility(value.getMarkings());
|
||||
} catch (MarkingFunctions.Exception e) {
|
||||
throw new RuntimeException("Cannot convert record-level markings into a column visibility", e);
|
||||
}
|
||||
Markings<?> markings = value.getMarkings();
|
||||
if (markings != null && !markings.isEmpty()) {
|
||||
visibility = markings.toColumnVisibility();
|
||||
}
|
||||
return flatten(visibility);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a flattened visibility, using the cache if possible
|
||||
* Normalize a ColumnVisibility expression via AccessExpression and return the expression bytes.
|
||||
*
|
||||
* @param vis
|
||||
* the visibility
|
||||
* @return the flattened visibility
|
||||
* @return the normalized visibility bytes
|
||||
*/
|
||||
protected byte[] flatten(ColumnVisibility vis) {
|
||||
return markingFunctions == null ? vis.flatten() : markingFunctions.flatten(vis);
|
||||
|
||||
-84
@@ -5,7 +5,6 @@ import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.hadoop.conf.Configuration;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
@@ -170,89 +169,6 @@ public class ExtendedContentIngestHelper extends BaseIngestHelper implements Ter
|
||||
}
|
||||
}
|
||||
|
||||
public void inheritFromRootPayload(RawRecordContainer event, Map<String,Collection<Object>> metadata) {
|
||||
// TODO: No-op here, but need to refactor the following in upstream
|
||||
// if (metadata == null)
|
||||
// return;
|
||||
//
|
||||
// IBaseDataObject payload = (IBaseDataObject) event.getAuxData();
|
||||
// if (payload != null) {
|
||||
// for (String field : helper.getInheritedPayloadFields()) {
|
||||
// if (metadata.containsKey(field) && (!payload.hasParameter(field))) {
|
||||
// payload.putParameter(field, metadata.get(field));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
public void addMetadataFromParms(RawRecordContainer event, Map<String,Collection<Object>> metadata, String id) {
|
||||
|
||||
for (Map.Entry<String,Collection<Object>> entry : metadata.entrySet()) {
|
||||
CharSequence key = entry.getKey();
|
||||
for (Object value : entry.getValue()) {
|
||||
if (value == null)
|
||||
continue;
|
||||
|
||||
if (helper.getUuids().contains(key)) {
|
||||
event.getAltIds().add(String.valueOf(value));
|
||||
}
|
||||
if (this.helper.getSecurityMarkingFieldDomainMap().containsKey(key)) {
|
||||
addSecurityMetadataFromParms(key, value, event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Multimap<String,String> newMetadata = HashMultimap.create();
|
||||
Multimap<String,MetadataIdParser> fieldParsers = helper.getMetadataFieldParsers();
|
||||
for (String field : fieldParsers.keySet()) {
|
||||
if (metadata.containsKey(field) && metadata.get(field) != null) {
|
||||
for (MetadataIdParser parser : fieldParsers.get(field)) {
|
||||
for (Object v : metadata.get(field)) {
|
||||
if (v == null)
|
||||
continue;
|
||||
try {
|
||||
parser.addMetadata(event, newMetadata, v.toString());
|
||||
} catch (Exception e) {
|
||||
log.error("Unable to apply " + parser + " to " + field, e);
|
||||
event.addError(RawDataErrorNames.FIELD_EXTRACTION_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the ID is a UUID (i.e., contains no date), try to get
|
||||
// event metadata from the parameters
|
||||
if ((id != null) && (id.length() >= UUID_LENGTH) && id.matches(UUID_PATTERN)) {
|
||||
fieldParsers = helper.getMetadataFieldUuidParsers();
|
||||
for (String field : fieldParsers.keySet()) {
|
||||
if (metadata.containsKey(field) && metadata.get(field) != null) {
|
||||
for (MetadataIdParser parser : fieldParsers.get(field)) {
|
||||
for (Object v : metadata.get(field)) {
|
||||
if (v == null)
|
||||
continue;
|
||||
try {
|
||||
parser.addMetadata(event, newMetadata, v.toString());
|
||||
} catch (Exception e) {
|
||||
log.error("Unable to apply " + parser + " to " + field, e);
|
||||
event.addError(RawDataErrorNames.FIELD_EXTRACTION_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void addSecurityMetadataFromParms(CharSequence key, Object value, RawRecordContainer event) {
|
||||
// If fieldName is a security marking field (as configured by EVENT_SECURITY_MARKING_FIELD_NAMES),
|
||||
// then put the marking value into this.securityMarkings, where 'key' maps to the domain for the marking
|
||||
// (as configured by EVENT_SECURITY_MARKING_FIELD_DOMAINS)
|
||||
if (!StringUtils.isEmpty(key.toString()) && !StringUtils.isEmpty(value.toString())) {
|
||||
event.addSecurityMarking(this.helper.getSecurityMarkingFieldDomainMap().get(key.toString()), value.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the normalize call to enable event field value normalization
|
||||
*
|
||||
|
||||
+1
-1
@@ -398,7 +398,7 @@ public class RawRecordContainerImplTest {
|
||||
if (getVisibility() == null && getSecurityMarkings() == null) {
|
||||
if (markingsHelper != null) {
|
||||
setSecurityMarkings(markingsHelper.getDefaultMarkings());
|
||||
} else {}
|
||||
}
|
||||
}
|
||||
|
||||
if (getSecurityMarkings() == null) {
|
||||
|
||||
+5
-6
@@ -1,13 +1,12 @@
|
||||
package datawave.ingest.data.config;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.hadoop.conf.Configuration;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import datawave.ingest.data.Type;
|
||||
import datawave.marking.MarkingFunctions;
|
||||
import datawave.marking.AccessExpressionMarkings;
|
||||
import datawave.marking.Markings;
|
||||
|
||||
public class MarkingsHelperTest {
|
||||
public static final String FIELD_NAME = "FIELDNAME1";
|
||||
@@ -36,10 +35,10 @@ public class MarkingsHelperTest {
|
||||
|
||||
// use the same type name to retrieve a markings helper and retrieve the field marking
|
||||
MarkingsHelper markingsHelper = new MarkingsHelper.NoOp(conf, createType(typeName));
|
||||
Map<String,String> fieldMarkingMap = markingsHelper.getFieldMarking(FIELD_NAME);
|
||||
Markings<?> fieldMarkings = markingsHelper.getFieldMarking(FIELD_NAME);
|
||||
|
||||
Assert.assertNotNull(fieldMarkingMap);
|
||||
Assert.assertEquals(FIELD_MARKING_VALUE, fieldMarkingMap.get(MarkingFunctions.Default.COLUMN_VISIBILITY));
|
||||
Assert.assertNotNull(fieldMarkings);
|
||||
Assert.assertEquals(FIELD_MARKING_VALUE, ((AccessExpressionMarkings) fieldMarkings).getAccessExpression().getExpression());
|
||||
}
|
||||
|
||||
private Configuration createConfWithFieldMarking(String typeName) {
|
||||
|
||||
+7
-8
@@ -1,11 +1,10 @@
|
||||
package datawave.ingest.data.config;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import datawave.data.type.Type;
|
||||
import datawave.marking.Markings;
|
||||
|
||||
public class NormalizedFieldAndValueTest {
|
||||
|
||||
@@ -19,7 +18,7 @@ public class NormalizedFieldAndValueTest {
|
||||
private String _eventFieldName;
|
||||
private String _eventFieldValue;
|
||||
|
||||
private Map<String,String> _markings;
|
||||
private Markings<?> _markings;
|
||||
private Throwable _error;
|
||||
|
||||
protected NonGroupedInstance() {
|
||||
@@ -84,7 +83,7 @@ public class NormalizedFieldAndValueTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMarkings(Map<String,String> markings) {
|
||||
public void setMarkings(Markings<?> markings) {
|
||||
_markings = markings;
|
||||
}
|
||||
|
||||
@@ -95,7 +94,7 @@ public class NormalizedFieldAndValueTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String,String> getMarkings() {
|
||||
public Markings<?> getMarkings() {
|
||||
return _markings;
|
||||
}
|
||||
|
||||
@@ -135,7 +134,7 @@ public class NormalizedFieldAndValueTest {
|
||||
private String _eventFieldName;
|
||||
private String _eventFieldValue;
|
||||
|
||||
private Map<String,String> _markings;
|
||||
private Markings<?> _markings;
|
||||
private Throwable _error;
|
||||
private boolean _grouped;
|
||||
|
||||
@@ -208,7 +207,7 @@ public class NormalizedFieldAndValueTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMarkings(Map<String,String> markings) {
|
||||
public void setMarkings(Markings<?> markings) {
|
||||
_markings = markings;
|
||||
}
|
||||
|
||||
@@ -219,7 +218,7 @@ public class NormalizedFieldAndValueTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String,String> getMarkings() {
|
||||
public Markings<?> getMarkings() {
|
||||
return _markings;
|
||||
}
|
||||
|
||||
|
||||
+3
-4
@@ -1,7 +1,6 @@
|
||||
package datawave.ingest.data.config.ingest;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.apache.accumulo.access.Access;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
@@ -9,6 +8,7 @@ import com.google.common.collect.Multimap;
|
||||
import datawave.ingest.data.RawRecordContainer;
|
||||
import datawave.ingest.data.config.NormalizedContentInterface;
|
||||
import datawave.ingest.data.config.NormalizedFieldAndValue;
|
||||
import datawave.marking.AccessExpressionMarkings;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -19,8 +19,7 @@ public class FakeIngestHelper extends BaseIngestHelper {
|
||||
@Override
|
||||
public Multimap<String,NormalizedContentInterface> getEventFields(RawRecordContainer event) {
|
||||
Multimap<String,NormalizedContentInterface> eventFields = HashMultimap.create();
|
||||
Map<String,String> markings = new HashMap<>();
|
||||
markings.put("P", "PERSONAL");
|
||||
AccessExpressionMarkings markings = AccessExpressionMarkings.builder().accessExpression(Access.builder().build().newExpression("PERSONAL")).build();
|
||||
|
||||
eventFields.put("FAKE_FIELD", new NormalizedFieldAndValue("FAKE_FIELD", "fake value", markings));
|
||||
return eventFields;
|
||||
|
||||
+20
-16
@@ -9,8 +9,8 @@ import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.apache.accumulo.access.AccessExpression;
|
||||
import org.apache.accumulo.core.security.ColumnVisibility;
|
||||
import org.apache.hadoop.io.Writable;
|
||||
|
||||
@@ -20,6 +20,8 @@ import datawave.data.hash.UIDBuilder;
|
||||
import datawave.ingest.data.RawRecordContainer;
|
||||
import datawave.ingest.data.Type;
|
||||
import datawave.ingest.data.TypeRegistry;
|
||||
import datawave.marking.AccessExpressionMarkings;
|
||||
import datawave.marking.Markings;
|
||||
import datawave.util.CompositeTimestamp;
|
||||
|
||||
/**
|
||||
@@ -29,7 +31,7 @@ public class SimpleRawRecord implements RawRecordContainer, Writable {
|
||||
|
||||
private UIDBuilder<UID> uidBuilder = HashUID.builder();
|
||||
|
||||
private Map<String,String> securityMarkings = new TreeMap<>();
|
||||
private Markings<?> securityMarkings = null;
|
||||
private UID id = uidBuilder.newId();
|
||||
private Type dataType;
|
||||
private long timestamp = CompositeTimestamp.INVALID_TIMESTAMP;
|
||||
@@ -45,25 +47,15 @@ public class SimpleRawRecord implements RawRecordContainer, Writable {
|
||||
private boolean fatalError = false;
|
||||
|
||||
@Override
|
||||
public Map<String,String> getSecurityMarkings() {
|
||||
public Markings<?> getSecurityMarkings() {
|
||||
return securityMarkings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSecurityMarkings(Map<String,String> securityMarkings) {
|
||||
public void setSecurityMarkings(Markings<?> securityMarkings) {
|
||||
this.securityMarkings = securityMarkings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSecurityMarking(String domain, String marking) {
|
||||
securityMarkings.put(domain, marking);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSecurityMarking(String domain, String marking) {
|
||||
return marking.equals(securityMarkings.get(domain));
|
||||
}
|
||||
|
||||
@Override
|
||||
public UID getId() {
|
||||
return id;
|
||||
@@ -244,7 +236,14 @@ public class SimpleRawRecord implements RawRecordContainer, Writable {
|
||||
|
||||
@Override
|
||||
public void write(DataOutput dataOutput) throws IOException {
|
||||
TestWritableUtil.writeMap(securityMarkings, dataOutput);
|
||||
String expr = "";
|
||||
if (securityMarkings != null) {
|
||||
AccessExpression ae = securityMarkings.toAccessExpression();
|
||||
if (ae != null) {
|
||||
expr = ae.getExpression();
|
||||
}
|
||||
}
|
||||
dataOutput.writeUTF(expr);
|
||||
|
||||
id.write(dataOutput);
|
||||
dataOutput.writeUTF(dataType.typeName());
|
||||
@@ -269,7 +268,12 @@ public class SimpleRawRecord implements RawRecordContainer, Writable {
|
||||
|
||||
@Override
|
||||
public void readFields(DataInput dataInput) throws IOException {
|
||||
securityMarkings = TestWritableUtil.readMap(dataInput);
|
||||
String expr = dataInput.readUTF();
|
||||
if (!expr.isEmpty()) {
|
||||
securityMarkings = AccessExpressionMarkings.builder().columnVisibility(expr).build();
|
||||
} else {
|
||||
securityMarkings = null;
|
||||
}
|
||||
|
||||
id = uidBuilder.newId();
|
||||
id.readFields(dataInput);
|
||||
|
||||
+1
-1
@@ -131,7 +131,7 @@ public class ProtobufEdgeDeleteModeTest {
|
||||
private RawRecordContainer getEvent(Configuration conf) {
|
||||
|
||||
RawRecordContainerImpl myEvent = new RawRecordContainerImpl();
|
||||
myEvent.addSecurityMarking("columnVisibility", "PRIVATE");
|
||||
myEvent.setVisibility("PRIVATE");
|
||||
myEvent.setDataType(type);
|
||||
myEvent.setId(UID.builder().newId());
|
||||
myEvent.setConf(conf);
|
||||
|
||||
Loaded 100 of 210 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user