This is an automated email from the ASF dual-hosted git repository. asf-gitbox-commits pushed a commit to branch geoapi-4.0 in repository https://gitbox.apache.org/repos/asf/sis.git
commit 2cc5bb50ba082b09244b3abb8f0238505bfdc367 Author: Martin Desruisseaux <[email protected]> AuthorDate: Mon Sep 28 18:11:52 2026 +0900 Add a property for declaring that the environment is trusted. In trusted environment, some security constraints are relaxed. --- .../main/org/apache/sis/xml/ReferenceResolver.java | 26 ++++-------- .../main/org/apache/sis/xml/XML.java | 2 +- .../sis/xml/internal/shared/InputFactory.java | 49 ++++++++++++---------- .../org/apache/sis/xml/ReferenceResolverTest.java | 8 +++- .../operation/transform/MathTransformBuilder.java | 16 +++++-- .../geotiff/reader/ImageMetadataBuilder.java | 1 + .../main/org/apache/sis/setup/Configuration.java | 38 +++++++++++++++-- .../main/org/apache/sis/system/Environment.java | 8 ++++ optional/src/org.apache.sis.gui/bundle/bin/sis | 1 + optional/src/org.apache.sis.gui/bundle/bin/sisfx | 1 + 10 files changed, 100 insertions(+), 50 deletions(-) diff --git a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/ReferenceResolver.java b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/ReferenceResolver.java index bfa3034b2b..4ce9f46b33 100644 --- a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/ReferenceResolver.java +++ b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/ReferenceResolver.java @@ -25,6 +25,8 @@ import javax.xml.transform.URIResolver; import jakarta.xml.bind.Unmarshaller; import org.opengis.metadata.Identifier; import org.apache.sis.io.Authorization; +import org.apache.sis.system.Environment; +import org.apache.sis.setup.Configuration; import org.apache.sis.util.ArgumentChecks; import org.apache.sis.util.Emptiable; import org.apache.sis.util.LenientComparable; @@ -66,21 +68,6 @@ public class ReferenceResolver { */ public static final ReferenceResolver DEFAULT = new ReferenceResolver(); - /** - * A resolver which accepts to open all documents referenced by {@code xlink:href}. - * By {@linkplain #DEFAULT default}, only references in the same directory or sub-directory are followed. - * But if this resolver is specified as a {@link XML#RESOLVER} property, all <abbr>URI</abbr>s will be accepted. - * - * <p><b>Historical note:</b> this was the default behavior in Apache <abbr>SIS</abbr> 1.5 and 1.6, but - * <abbr>SIS</abbr> 1.7 reverted to not opening external document by default for security reasons.</p> - * - * @see XML#RESOLVER - * @see #accessControl(URI) - * - * @since 1.7 - */ - public static final ReferenceResolver FOLLOW_EXTERNAL_XLINK = new ReferenceResolver(); - /** * Provider of sources to use for unmarshalling objects referenced by links to another document. * It provides the {@code source} argument in {@link #resolveExternal(MarshalContext, Source)}. @@ -394,15 +381,18 @@ public class ReferenceResolver { * of the document containing the {@code xlink:href}, otherwise behave like {@code DENIED}.</li> * </ul> * + * The default implementation returns {@code GRANTED} in a + * {@linkplain Configuration#isTrustedEnvironment() trusted environment}, or {@code DEFAULT} otherwise. + * Security policy can be tuned more finely by overriding this method and specifying the customized + * {@code Resolver} instance as documented in {@link XML#RESOLVER}. + * * @param document the document or fragment referenced in a {@code xlink:href}. * @return whether the given document or fragment can be opened. * - * @see #FOLLOW_EXTERNAL_XLINK - * * @since 1.7 */ public Authorization accessControl(URI document) { - return (this == FOLLOW_EXTERNAL_XLINK) ? Authorization.GRANTED : Authorization.DEFAULT; + return Environment.isTrusted ? Authorization.GRANTED : Authorization.DEFAULT; } /** diff --git a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/XML.java b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/XML.java index 370d26481d..c34584386f 100644 --- a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/XML.java +++ b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/XML.java @@ -253,7 +253,7 @@ public final class XML { /** * Allows client code to replace {@code xlink} or {@code uuidref} attributes by the actual data. * The value for this property shall be an instance of {@link ReferenceResolver}. - * The specified reference resolver (of if none, the {@linkplain ReferenceResolver#DEFAULT default} one) + * The specified reference resolver (or if none, the {@linkplain ReferenceResolver#DEFAULT default} one) * is used when a <abbr>XML</abbr> element is defined only by {@code xlink} or {@code uuidref} attributes, * without any concrete definition. The typical choices are: * diff --git a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/internal/shared/InputFactory.java b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/internal/shared/InputFactory.java index f2a35ad9e6..dc34cf48e9 100644 --- a/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/internal/shared/InputFactory.java +++ b/endorsed/src/org.apache.sis.metadata/main/org/apache/sis/xml/internal/shared/InputFactory.java @@ -33,6 +33,7 @@ import javax.xml.transform.sax.SAXSource; import org.w3c.dom.Node; import org.xml.sax.InputSource; import org.apache.sis.system.Loggers; +import org.apache.sis.system.Environment; import org.apache.sis.util.logging.Logging; @@ -59,39 +60,41 @@ public final class InputFactory { private static final XMLInputFactory FACTORY = newSecureFactory(); /** - * Creates a new <abbr>XML</abbr> factory with some security setting enabled. + * Do not allow instantiation of this class. + */ + private InputFactory() { + } + + /** + * Creates a new <abbr>XML</abbr> factory with some security setting enabled, unless the environment is trusted. * * @return a new <abbr>XML</abbr> factory. */ public static XMLInputFactory newSecureFactory() { final XMLInputFactory factory = XMLInputFactory.newFactory(); - if (factory.isPropertySupported(XMLConstants.FEATURE_SECURE_PROCESSING)) { - factory.setProperty(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE); - } - try { - // No `isPropertySupported(…)` because support of this property is required. - if ("all".equals(factory.getProperty(XMLConstants.ACCESS_EXTERNAL_DTD))) { - factory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + if (!Environment.isTrusted) { + if (factory.isPropertySupported(XMLConstants.FEATURE_SECURE_PROCESSING)) { + factory.setProperty(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE); + } + try { + // No `isPropertySupported(…)` because support of this property is required. + if ("all".equals(factory.getProperty(XMLConstants.ACCESS_EXTERNAL_DTD))) { + factory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + } + } catch (IllegalArgumentException e) { + /* + * `ACCESS_EXTERNAL_DTD` is clearly documented as a mandatory property since JAXP 1.5 in Java 7. + * But Jackson 2.19.1, despite being released 14 years after Java 7, still doesn't support this + * property. + */ + final var record = new LogRecord(Level.CONFIG, e.getLocalizedMessage()); + record.setThrown(e); + Logging.completeAndLog(Logger.getLogger(Loggers.XML), InputFactory.class, "newSecureFactory", record); } - } catch (IllegalArgumentException e) { - /* - * `ACCESS_EXTERNAL_DTD` is clearly documented as a mandatory property since JAXP 1.5 in Java 7. - * But Jackson 2.19.1, despite being released 14 years after Java 7, still doesn't support this - * property. - */ - final var record = new LogRecord(Level.CONFIG, e.getLocalizedMessage()); - record.setThrown(e); - Logging.completeAndLog(Logger.getLogger(Loggers.XML), InputFactory.class, "newSecureFactory", record); } return factory; } - /** - * Do not allow instantiation of this class. - */ - private InputFactory() { - } - /* * Do not provide convenience method for java.io.File, because the caller needs to close the created * input stream himself (this is not done by XMLEventReader.close(), despite its method name). diff --git a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/xml/ReferenceResolverTest.java b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/xml/ReferenceResolverTest.java index 99b54c6751..b29a7cc2e3 100644 --- a/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/xml/ReferenceResolverTest.java +++ b/endorsed/src/org.apache.sis.metadata/test/org/apache/sis/xml/ReferenceResolverTest.java @@ -21,9 +21,11 @@ import java.util.logging.Filter; import java.util.logging.LogRecord; import java.io.IOException; import java.nio.file.AccessDeniedException; +import java.net.URI; import java.net.URISyntaxException; import javax.xml.transform.Source; import jakarta.xml.bind.JAXBException; +import org.apache.sis.io.Authorization; import org.opengis.metadata.citation.Citation; import org.opengis.metadata.identification.DataIdentification; @@ -81,7 +83,11 @@ public final class ReferenceResolverTest extends TestUsingFile implements Filter final var properties = new HashMap<String, Object>(4); assertNull(properties.put(XML.WARNING_FILTER, this)); if (readExternal) { - assertNull(properties.put(XML.RESOLVER, ReferenceResolver.FOLLOW_EXTERNAL_XLINK)); + assertNull(properties.put(XML.RESOLVER, new ReferenceResolver() { + @Override public Authorization accessControl(URI document) { + return Authorization.GRANTED; + } + })); } final var data = assertInstanceOf(DataIdentification.class, XML.unmarshal(source, properties)); assertTrue(data.getAbstract().toString().startsWith("Test the use of XLink to an external document")); diff --git a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/MathTransformBuilder.java b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/MathTransformBuilder.java index 8de5698b8a..07bf20469c 100644 --- a/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/MathTransformBuilder.java +++ b/endorsed/src/org.apache.sis.referencing/main/org/apache/sis/referencing/operation/transform/MathTransformBuilder.java @@ -25,6 +25,8 @@ import org.opengis.referencing.operation.MathTransform; import org.opengis.referencing.operation.MathTransformFactory; import org.opengis.referencing.operation.OperationMethod; import org.apache.sis.referencing.IdentifiedObjects; +import org.apache.sis.setup.Configuration; +import org.apache.sis.system.Environment; import org.apache.sis.io.Authorization; import org.apache.sis.util.Classes; import org.apache.sis.util.internal.shared.Strings; @@ -50,7 +52,9 @@ public abstract class MathTransformBuilder implements MathTransform.Builder { /** * A function which determines whether the <abbr>URI</abbr> specified in a parameter can be opened. - * The default access control returns {@link Authorization#DEFAULT}. + * The default access control returns {@link Authorization#DEFAULT} in non-trusted environment. + * + * @see #getAccessControl() */ private BiFunction<ParameterDescriptor<URI>, URI, Authorization> accessControl; @@ -76,7 +80,7 @@ public abstract class MathTransformBuilder implements MathTransform.Builder { accessControl = (param, file) -> { Objects.requireNonNull(param); Objects.requireNonNull(file); - return Authorization.DEFAULT; + return Environment.isTrusted ? Authorization.GRANTED : Authorization.DEFAULT; }; } @@ -102,13 +106,17 @@ public abstract class MathTransformBuilder implements MathTransform.Builder { * <li>the actual <abbr>URI</abbr> parameter value.</li> * </ol> * - * The default access control is a function returning {@link Authorization#DEFAULT}. - * The default authorization grants access to files in the {@code $SIS_DATA/DatumChanges} + * The default access control is a function returning {@link Authorization#GRANTED} + * in a {@linkplain Configuration#isTrustedEnvironment() trusted environment}, + * or {@link Authorization#DEFAULT} otherwise. + * The {@code DEFAULT} authorization grants access to files in the {@code $SIS_DATA/DatumChanges} * directory for parameters that are datum shift grid files, and to files in the same directory as the * <abbr>JSON</abbr>, <abbr>GML</abbr> or <abbr>WKT</abbr> document where the parameter value appears. * * @return a function deciding whether the <abbr>URI</abbr> can be opened. * + * @see org.apache.sis.setup.Configuration#isTrustedEnvironment() + * * @since 1.7 */ public BiFunction<ParameterDescriptor<URI>, URI, Authorization> getAccessControl() { diff --git a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/ImageMetadataBuilder.java b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/ImageMetadataBuilder.java index a0819d454e..8e5fbe81c9 100644 --- a/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/ImageMetadataBuilder.java +++ b/endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/reader/ImageMetadataBuilder.java @@ -174,6 +174,7 @@ public final class ImageMetadataBuilder extends MetadataBuilder { * * @throws DataStoreException if an error occurred while reading metadata from the data store. */ + @SuppressWarnings("UseSpecificCatch") public void finish(final GeoTiffStore store, final StoreListeners listeners) throws DataStoreException { /* * Add the resolution into the metadata. Our current ISO 19115 implementation restricts diff --git a/endorsed/src/org.apache.sis.util/main/org/apache/sis/setup/Configuration.java b/endorsed/src/org.apache.sis.util/main/org/apache/sis/setup/Configuration.java index 3c076e9370..c6e799ee43 100644 --- a/endorsed/src/org.apache.sis.util/main/org/apache/sis/setup/Configuration.java +++ b/endorsed/src/org.apache.sis.util/main/org/apache/sis/setup/Configuration.java @@ -24,14 +24,15 @@ import java.util.concurrent.TimeUnit; import javax.sql.DataSource; import java.sql.SQLException; import org.apache.sis.system.Shutdown; +import org.apache.sis.system.Environment; import org.apache.sis.system.SystemListener; import org.apache.sis.util.logging.Logging; import org.apache.sis.util.internal.shared.MetadataServices; /** - * Provides system-wide configuration for Apache SIS library. - * Methods in this class can be used for overriding SIS default values. + * Provides system-wide configuration of the Apache <abbr>SIS</abbr> library. + * Methods in this class can be used for overriding <abbr>SIS</abbr> default values. * Those methods can be used in final applications, but should not be used by libraries * in order to avoid interfering with user's settings. * @@ -45,7 +46,7 @@ import org.apache.sis.util.internal.shared.MetadataServices; * </ul> * * The following properties are defined by the standard Java environment. - * Apache SIS read those properties but does not modify them: + * Apache SIS reads those properties but does not modify them: * * <ul> * <li>{@link Locale#getDefault()} (sometimes using {@link Locale.Category})</li> @@ -83,6 +84,37 @@ public final class Configuration { return DEFAULT; } + /** + * Returns whether to relax the default security settings. + * By default, Apache <abbr>SIS</abbr> applies the following restrictions: + * + * <ul> + * <li>Disable all accesses to external <abbr>DTD</abbr>s and external Entity References + * when reading <abbr>XML</abbr> documents.</li> + * <li>Follow {@code xlink:href} only if it is an <abbr>XML</abbr> fragment or if the referenced file is in + * the same directory or in a sub-directory of the <abbr>GML</abbr> file containing the reference.</li> + * <li>Open file referenced in coordinate operation only if the parameter is a datum shift grid file + * and the file is in the {@code $SIS_DATA/DatumChanges} directory, or (for any parameter) if the + * file is in the same directory or in a sub-directory of + * <abbr>JSON</abbr>, <abbr>GML</abbr> or <abbr>WKT</abbr> file containing the parameter value.</li> + * </ul> + * + * If the {@systemProperty org.apache.sis.trustedEnvironment} is set to {@code true}, + * the above listed restrictions are ignored. + * + * @return whether the default security restrictions are relaxed. + * + * @see javax.xml.XMLConstants#ACCESS_EXTERNAL_DTD + * @see javax.xml.XMLConstants#FEATURE_SECURE_PROCESSING + * @see org.apache.sis.xml.ReferenceResolver#DEFAULT + * @see org.apache.sis.referencing.operation.transform.MathTransformBuilder#getAccessControl() + * + * @since 1.7 + */ + public boolean isTrustedEnvironment() { + return Environment.isTrusted; + } + /** * Returns the data source for the <abbr>SIS</abbr>-wide "SpatialMetadata" database. * This method returns the first of the following steps that succeed: diff --git a/endorsed/src/org.apache.sis.util/main/org/apache/sis/system/Environment.java b/endorsed/src/org.apache.sis.util/main/org/apache/sis/system/Environment.java index dc2844327c..bd6e2e171f 100644 --- a/endorsed/src/org.apache.sis.util/main/org/apache/sis/system/Environment.java +++ b/endorsed/src/org.apache.sis.util/main/org/apache/sis/system/Environment.java @@ -30,6 +30,13 @@ import org.apache.sis.pending.jdk.JDK17; * @author Martin Desruisseaux (Geomatys) */ public final class Environment { + /** + * Whether to relax security restrictions. + * + * @see org.apache.sis.setup.Configuration#isTrustedEnvironment() + */ + public static final boolean isTrusted = Boolean.getBoolean("org.apache.sis.trustedEnvironment"); + /** * Whether the use of the console writer should be avoided. * @@ -62,6 +69,7 @@ public final class Environment { * * @return the writer to use. */ + @SuppressWarnings("UseOfSystemOutOrSystemErr") public static PrintWriter writer() { return writer(System.console(), System.out); } diff --git a/optional/src/org.apache.sis.gui/bundle/bin/sis b/optional/src/org.apache.sis.gui/bundle/bin/sis index e82a73d56a..5daf4a5e06 100755 --- a/optional/src/org.apache.sis.gui/bundle/bin/sis +++ b/optional/src/org.apache.sis.gui/bundle/bin/sis @@ -30,5 +30,6 @@ export COLUMNS java --module-path "$BASE_DIR/lib:$BASE_DIR/lib/app/org.apache.sis.console.jar" \ -Djava.util.logging.config.class="org.apache.sis.util.logging.Initializer" \ -Djava.util.logging.config.file="$BASE_DIR/conf/logging.properties" \ + -Dorg.apache.sis.trustedEnvironment=true \ --module org.apache.sis.console/org.apache.sis.console.Command \ $SIS_OPTS "$@" diff --git a/optional/src/org.apache.sis.gui/bundle/bin/sisfx b/optional/src/org.apache.sis.gui/bundle/bin/sisfx index a5ed59ff7e..55aeceb785 100755 --- a/optional/src/org.apache.sis.gui/bundle/bin/sisfx +++ b/optional/src/org.apache.sis.gui/bundle/bin/sisfx @@ -93,6 +93,7 @@ java -splash:"$BASE_DIR/lib/logo.jpg" \ --module-path "$PATH_TO_FX:$BASE_DIR/lib:$BASE_DIR/lib/app/org.apache.sis.gui.jar" \ -Djava.util.logging.config.class="org.apache.sis.util.logging.Initializer" \ -Djava.util.logging.config.file="$BASE_DIR/conf/logging.properties" \ + -Dorg.apache.sis.trustedEnvironment=true \ $ADD_OPTIONAL_MODULES \ --module org.apache.sis.gui/org.apache.sis.gui.DataViewer \ $SIS_OPTS "$@"
