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 "$@"

Reply via email to