From 2f3380390db2aba9fbafcdca5a8b3ffbb92acac4 Mon Sep 17 00:00:00 2001 From: Matthew Burgess Date: Wed, 16 Feb 2022 18:07:57 -0500 Subject: [PATCH] NIFI-8492: Addressed issue in DatabaseReader class of IPLookupService that was attempting to set values on the JSON returned by MaxMind. Instead of modifying the object directly, we should use an Injectable in the Reader so that the value read will have the appropriate values but we don't need to modify those objects returned by MaxMind. Similar solution of NIFI-5814 Signed-off-by: Nathan Gough This closes #5777. --- .../nifi/lookup/maxmind/DatabaseReader.java | 60 +++++++++++-------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/main/java/org/apache/nifi/lookup/maxmind/DatabaseReader.java b/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/main/java/org/apache/nifi/lookup/maxmind/DatabaseReader.java index 1849f4f6e0..93fe31e3ca 100644 --- a/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/main/java/org/apache/nifi/lookup/maxmind/DatabaseReader.java +++ b/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/main/java/org/apache/nifi/lookup/maxmind/DatabaseReader.java @@ -21,18 +21,20 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.InetAddress; -import java.util.Arrays; +import java.util.Collections; import java.util.List; +import com.fasterxml.jackson.databind.BeanProperty; +import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.InjectableValues; +import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import com.maxmind.db.Metadata; import com.maxmind.db.Reader; import com.maxmind.db.Reader.FileMode; import com.maxmind.geoip2.GeoIp2Provider; -import com.maxmind.geoip2.exception.AddressNotFoundException; import com.maxmind.geoip2.exception.GeoIp2Exception; import com.maxmind.geoip2.model.AnonymousIpResponse; import com.maxmind.geoip2.model.CityResponse; @@ -40,6 +42,7 @@ import com.maxmind.geoip2.model.ConnectionTypeResponse; import com.maxmind.geoip2.model.CountryResponse; import com.maxmind.geoip2.model.DomainResponse; import com.maxmind.geoip2.model.IspResponse; +import com.maxmind.geoip2.record.Traits; /** *

@@ -56,7 +59,7 @@ public class DatabaseReader implements GeoIp2Provider, Closeable { private final Reader reader; private final ObjectMapper om; - private DatabaseReader(Builder builder) throws IOException { + private DatabaseReader(final Builder builder) throws IOException { if (builder.stream != null) { this.reader = new Reader(builder.stream); } else if (builder.database != null) { @@ -90,7 +93,7 @@ public class DatabaseReader implements GeoIp2Provider, Closeable { final File database; final InputStream stream; - List locales = Arrays.asList("en"); + List locales = Collections.singletonList("en"); FileMode mode = FileMode.MEMORY_MAPPED; /** @@ -146,25 +149,14 @@ public class DatabaseReader implements GeoIp2Provider, Closeable { * @return An object of type T with the data for the IP address or null if no information could be found for the given IP address * @throws IOException if there is an error opening or reading from the file. */ - private T get(InetAddress ipAddress, Class cls, boolean hasTraits, String type) throws IOException, AddressNotFoundException { + private T get(InetAddress ipAddress, Class cls, boolean hasTraits, String type) throws IOException { ObjectNode node = (ObjectNode) this.reader.get(ipAddress); if (node == null) { return null; } - ObjectNode ipNode; - if (hasTraits) { - if (!node.has("traits")) { - node.set("traits", this.om.createObjectNode()); - } - - ipNode = (ObjectNode) node.get("traits"); - } else { - ipNode = node; - } - - ipNode.put("ip_address", ipAddress.getHostAddress()); - return this.om.treeToValue(node, cls); + InjectableValues inject = new JsonInjector(ipAddress.getHostAddress()); + return this.om.reader(inject).treeToValue(node, cls); } /** @@ -185,12 +177,12 @@ public class DatabaseReader implements GeoIp2Provider, Closeable { } @Override - public CountryResponse country(InetAddress ipAddress) throws IOException, GeoIp2Exception { + public CountryResponse country(InetAddress ipAddress) throws IOException { return this.get(ipAddress, CountryResponse.class, true, "Country"); } @Override - public CityResponse city(InetAddress ipAddress) throws IOException, GeoIp2Exception { + public CityResponse city(InetAddress ipAddress) throws IOException { return this.get(ipAddress, CityResponse.class, true, "City"); } @@ -199,10 +191,9 @@ public class DatabaseReader implements GeoIp2Provider, Closeable { * * @param ipAddress IPv4 or IPv6 address to lookup. * @return a AnonymousIpResponse for the requested IP address. - * @throws GeoIp2Exception if there is an error looking up the IP * @throws IOException if there is an IO error */ - public AnonymousIpResponse anonymousIp(InetAddress ipAddress) throws IOException, GeoIp2Exception { + public AnonymousIpResponse anonymousIp(InetAddress ipAddress) throws IOException { return this.get(ipAddress, AnonymousIpResponse.class, false, "GeoIP2-Anonymous-IP"); } @@ -214,7 +205,7 @@ public class DatabaseReader implements GeoIp2Provider, Closeable { * @throws GeoIp2Exception if there is an error looking up the IP * @throws IOException if there is an IO error */ - public ConnectionTypeResponse connectionType(InetAddress ipAddress) throws IOException, GeoIp2Exception { + public ConnectionTypeResponse connectionType(InetAddress ipAddress) throws IOException { return this.get(ipAddress, ConnectionTypeResponse.class, false, "GeoIP2-Connection-Type"); } @@ -227,7 +218,7 @@ public class DatabaseReader implements GeoIp2Provider, Closeable { * @throws GeoIp2Exception if there is an error looking up the IP * @throws IOException if there is an IO error */ - public DomainResponse domain(InetAddress ipAddress) throws IOException, GeoIp2Exception { + public DomainResponse domain(InetAddress ipAddress) throws IOException { return this.get(ipAddress, DomainResponse.class, false, "GeoIP2-Domain"); } @@ -239,7 +230,7 @@ public class DatabaseReader implements GeoIp2Provider, Closeable { * @throws GeoIp2Exception if there is an error looking up the IP * @throws IOException if there is an IO error */ - public IspResponse isp(InetAddress ipAddress) throws IOException, GeoIp2Exception { + public IspResponse isp(InetAddress ipAddress) throws IOException { return this.get(ipAddress, IspResponse.class, false, "GeoIP2-ISP"); } @@ -249,4 +240,23 @@ public class DatabaseReader implements GeoIp2Provider, Closeable { public Metadata getMetadata() { return this.reader.getMetadata(); } + + private class JsonInjector extends InjectableValues { + private final String ip; + + JsonInjector(final String ip) { + this.ip = ip; + } + + @Override + public Object findInjectableValue(final Object valueId, final DeserializationContext ctxt, final BeanProperty forProperty, final Object beanInstance) throws JsonMappingException { + if ("ip_address".equals(valueId)) { + return ip; + } else if ("traits".equals(valueId)) { + return new Traits(ip); + } + + return null; + } + } }