X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fnetconf%2Fnetconf-netty-util%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fnetconf%2Fnettyutil%2Fhandler%2FNetconfEXICodec.java;h=16da7a7f9dcf3eabb7fee06e8c3201fce1c41155;hp=98baef0f8580fb5ae8b2677ee20072ff14c3ab5c;hb=dcf48864ca54fe1b27d44de10e0bcb6e241cc5c4;hpb=2d586172a138afacb388ca2b35b74160ba26b0ba diff --git a/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/NetconfEXICodec.java b/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/NetconfEXICodec.java index 98baef0f85..16da7a7f9d 100644 --- a/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/NetconfEXICodec.java +++ b/opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/NetconfEXICodec.java @@ -1,6 +1,9 @@ package org.opendaylight.controller.netconf.nettyutil.handler; import com.google.common.base.Preconditions; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import org.openexi.proc.HeaderOptionsOutputType; import org.openexi.proc.common.EXIOptions; import org.openexi.proc.common.EXIOptionsException; @@ -8,6 +11,9 @@ import org.openexi.proc.common.GrammarOptions; import org.openexi.proc.grammars.GrammarCache; import org.openexi.sax.EXIReader; import org.openexi.sax.Transmogrifier; +import org.openexi.sax.TransmogrifierException; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; public final class NetconfEXICodec { /** @@ -16,13 +22,41 @@ public final class NetconfEXICodec { * of the stream. This is really useful, so let's output it now. */ private static final boolean OUTPUT_EXI_COOKIE = true; + /** + * OpenEXI does not allow us to directly prevent resolution of external entities. In order + * to prevent XXE attacks, we reuse a single no-op entity resolver. + */ + private static final EntityResolver ENTITY_RESOLVER = new EntityResolver() { + @Override + public InputSource resolveEntity(final String publicId, final String systemId) { + return new InputSource(); + } + }; + + /** + * Since we have a limited number of options we can have, instantiating a weak cache + * will allow us to reuse instances where possible. + */ + private static final LoadingCache GRAMMAR_CACHES = CacheBuilder.newBuilder().weakValues().build(new CacheLoader() { + @Override + public GrammarCache load(final Short key) { + return new GrammarCache(key); + } + }); + + /** + * Grammar cache acts as a template and is duplicated by the Transmogrifier and the Reader + * before use. It is safe to reuse a single instance. + */ + private final GrammarCache exiGrammarCache; private final EXIOptions exiOptions; public NetconfEXICodec(final EXIOptions exiOptions) { this.exiOptions = Preconditions.checkNotNull(exiOptions); + this.exiGrammarCache = createGrammarCache(exiOptions); } - private GrammarCache getGrammarCache() { + private static GrammarCache createGrammarCache(final EXIOptions exiOptions) { short go = GrammarOptions.DEFAULT_OPTIONS; if (exiOptions.getPreserveComments()) { go = GrammarOptions.addCM(go); @@ -37,23 +71,25 @@ public final class NetconfEXICodec { go = GrammarOptions.addPI(go); } - return new GrammarCache(null, go); + return GRAMMAR_CACHES.getUnchecked(go); } EXIReader getReader() throws EXIOptionsException { final EXIReader r = new EXIReader(); r.setPreserveLexicalValues(exiOptions.getPreserveLexicalValues()); - r.setGrammarCache(getGrammarCache()); + r.setGrammarCache(exiGrammarCache); + r.setEntityResolver(ENTITY_RESOLVER); return r; } - Transmogrifier getTransmogrifier() throws EXIOptionsException { + Transmogrifier getTransmogrifier() throws EXIOptionsException, TransmogrifierException { final Transmogrifier transmogrifier = new Transmogrifier(); transmogrifier.setAlignmentType(exiOptions.getAlignmentType()); transmogrifier.setBlockSize(exiOptions.getBlockSize()); - transmogrifier.setGrammarCache(getGrammarCache()); + transmogrifier.setGrammarCache(exiGrammarCache); transmogrifier.setOutputCookie(OUTPUT_EXI_COOKIE); transmogrifier.setOutputOptions(HeaderOptionsOutputType.all); + transmogrifier.setResolveExternalGeneralEntities(false); return transmogrifier; } }