You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2026/09/29 00:09:15 UTC
(sis) 02/02: Add a property for declaring that the environment is trusted. In trusted environment, some security constraints are relaxed.
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 <ma...@geomatys.com>
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 "$@"