Make Sanitizer instantiable taking a predicate also adds extra checking for other datatypes
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/fd307c87 Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/fd307c87 Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/fd307c87 Branch: refs/heads/master Commit: fd307c879d8d2978090b001460151a9958935671 Parents: 37341a8 Author: Robert Moss <[email protected]> Authored: Tue Mar 10 15:00:03 2015 +0000 Committer: Robert Moss <[email protected]> Committed: Tue Mar 10 15:00:03 2015 +0000 ---------------------------------------------------------------------- .../java/brooklyn/entity/basic/Entities.java | 13 ++- .../java/brooklyn/entity/basic/Sanitizer.java | 113 +++++++++++++++++-- 2 files changed, 111 insertions(+), 15 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fd307c87/core/src/main/java/brooklyn/entity/basic/Entities.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/entity/basic/Entities.java b/core/src/main/java/brooklyn/entity/basic/Entities.java index c826070..48ba2d0 100644 --- a/core/src/main/java/brooklyn/entity/basic/Entities.java +++ b/core/src/main/java/brooklyn/entity/basic/Entities.java @@ -127,7 +127,10 @@ public class Entities { /** * Names that, if they appear anywhere in an attribute/config/field indicates that it * may be private, so should not be logged etc. + * + * @deprecated since 0.7; instead use {@link Sanitizer#SECRET_NAMES} */ + @Deprecated public static final List<String> SECRET_NAMES = ImmutableList.of( "password", "passwd", @@ -250,12 +253,12 @@ public class Entities { return invokeEffector(callingEntity, entitiesToCall, effector, Collections.<String,Object>emptyMap()); } + /** + * @deprecated since 0.7; instead use {@link Sanitizer#IS_SECRET_PREDICATE.apply(Object)} + */ + @Deprecated public static boolean isSecret(String name) { - String lowerName = name.toLowerCase(); - for (String secretName : SECRET_NAMES) { - if (lowerName.contains(secretName)) return true; - } - return false; + return Sanitizer.IS_SECRET_PREDICATE.apply(name); } public static boolean isTrivial(Object v) { http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/fd307c87/core/src/main/java/brooklyn/entity/basic/Sanitizer.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/brooklyn/entity/basic/Sanitizer.java b/core/src/main/java/brooklyn/entity/basic/Sanitizer.java index 15dd63e..6e07071 100644 --- a/core/src/main/java/brooklyn/entity/basic/Sanitizer.java +++ b/core/src/main/java/brooklyn/entity/basic/Sanitizer.java @@ -18,18 +18,53 @@ */ package brooklyn.entity.basic; +import java.util.List; import java.util.Map; import java.util.Set; import brooklyn.util.config.ConfigBag; +import com.google.api.client.util.Lists; +import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Maps; import com.google.common.collect.Sets; public final class Sanitizer { - private Sanitizer() { - } // not instantiable + /** + * Names that, if they appear anywhere in an attribute/config/field + * indicates that it may be private, so should not be logged etc. + */ + public static final List<String> SECRET_NAMES = ImmutableList.of( + "password", + "passwd", + "credential", + "secret", + "private", + "access.cert", + "access.key"); + + public static final Predicate<Object> IS_SECRET_PREDICATE = new Predicate<Object>() { + + @Override + public boolean apply(Object name) { + String lowerName = name.toString().toLowerCase(); + for (String secretName : SECRET_NAMES) { + if (lowerName.contains(secretName)) + return true; + } + return false; + } + }; + + public static Sanitizer newInstance(Predicate<Object> sanitizingNeededCheck) { + return new Sanitizer(sanitizingNeededCheck); + } + + public static Sanitizer newInstance(){ + return newInstance(IS_SECRET_PREDICATE); + } public static Map<String, Object> sanitize(ConfigBag input) { return sanitize(input.getAllConfig()); @@ -39,21 +74,79 @@ public final class Sanitizer { return sanitize(input, Sets.newHashSet()); } - public static <K> Map<K, Object> sanitize(Map<K, ?> input, Set<Object> visited) { + static <K> Map<K, Object> sanitize(Map<K, ?> input, Set<Object> visited) { + return newInstance().apply(input, visited); + } + + private Predicate<Object> predicate; + + private Sanitizer(Predicate<Object> sanitizingNeededCheck) { + predicate = sanitizingNeededCheck; + } + + public <K> Map<K, Object> apply(Map<K, ?> input) { + return apply(input, Sets.newHashSet()); + } + + private <K> Map<K, Object> apply(Map<K, ?> input, Set<Object> visited) { Map<K, Object> result = Maps.newLinkedHashMap(); for (Map.Entry<K, ?> e : input.entrySet()) { - if (Entities.isSecret("" + e.getKey())) + if (predicate.apply(e.getKey())){ result.put(e.getKey(), "xxxxxxxx"); - else if (e.getValue() instanceof Map) { - if (visited.contains(e.getValue())) { - continue; - } - visited.add(e.getValue()); - result.put(e.getKey(), sanitize((Map<?, ?>) e.getValue(), visited)); + continue; + } + + // need to compare object reference, not equality since we may miss some. + // not a perfect identifier, but very low probability of collision. + if (visited.contains(System.identityHashCode(e.getValue()))) { + result.put(e.getKey(), e.getValue()); + continue; + } + + visited.add(System.identityHashCode(e.getValue())); + if (e.getValue() instanceof Map) { + result.put(e.getKey(), apply((Map<?, ?>) e.getValue(), visited)); + } else if (e.getValue() instanceof List) { + result.put(e.getKey(), applyList((List<?>) e.getValue(), visited)); + } else if (e.getValue() instanceof Set) { + result.put(e.getKey(), applySet((Set<?>) e.getValue(), visited)); } else { result.put(e.getKey(), e.getValue()); } } return result; } + + private List<Object> applyIterable(Iterable<?> input, Set<Object> visited){ + List<Object> result = Lists.newArrayList(); + for(Object o : input){ + if(visited.contains(System.identityHashCode(o))){ + result.add(o); + continue; + } + + visited.add(System.identityHashCode(o)); + if (o instanceof Map) { + result.add(apply((Map<?, ?>) o, visited)); + } else if (o instanceof List) { + result.add(applyList((List<?>) o, visited)); + } else if (o instanceof Set) { + result.add(applySet((Set<?>) o, visited)); + } else { + result.add(o); + } + + } + return result; + } + + private List<Object> applyList(List<?> input, Set<Object> visited) { + return applyIterable(input, visited); + } + + private Set<Object> applySet(Set<?> input, Set<Object> visited) { + Set<Object> result = Sets.newLinkedHashSet(); + result.addAll(applyIterable(input, visited)); + return result; + } }
