This is an automated email from the ASF dual-hosted git repository.
jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git
The following commit(s) were added to refs/heads/master by this push:
new 824234c427 Harden HTML widget rendering and tidy security test comments
824234c427 is described below
commit 824234c427fa354b66df79c10388f5783566aea7
Author: James Bognar <[email protected]>
AuthorDate: Mon Aug 10 15:47:50 2026 -0400
Harden HTML widget rendering and tidy security test comments
- HtmlWidgetVar: degrade an individual widget's render failure to an empty
fragment instead of propagating, so one failing $W{...} widget no longer
blanks the rest of the surrounding page. Adds HtmlWidgetVar_Test.
- PetstoreSpringboot_Test: fail fast with a clear message when a rendered
page contains an inline server error, instead of an opaque assertion.
- Remove stale weakness-class annotations from a set of path-traversal
security test comments (comment-only cleanup).
---
.../org/apache/juneau/commons/io/LocalDir.java | 2 +-
.../commons/io/LocalDir_PathTraversal_Test.java | 2 +-
.../apache/juneau/marshall/html/HtmlWidgetVar.java | 10 ++-
.../juneau/marshall/html/HtmlWidgetVar_Test.java | 81 ++++++++++++++++++++++
.../rest/server/Rest_AllowedMethodParams_Test.java | 2 +-
.../FreemarkerMixin_PathTraversal_Test.java | 2 +-
.../view/jsp/JspMixin_PathTraversal_Test.java | 2 +-
.../mustache/MustacheMixin_PathTraversal_Test.java | 2 +-
.../ThymeleafMixin_PathTraversal_Test.java | 2 +-
.../DirectoryResource_PathTraversal_Test.java | 2 +-
.../examples/LogsResource_PathTraversal_Test.java | 2 +-
.../springboot/PetstoreSpringboot_Test.java | 4 ++
.../FreemarkerMixin_PathTraversal_Test.java | 2 +-
.../view/jsp/JspMixin_PathTraversal_Test.java | 2 +-
.../mustache/MustacheMixin_PathTraversal_Test.java | 2 +-
.../ThymeleafMixin_PathTraversal_Test.java | 2 +-
16 files changed, 107 insertions(+), 14 deletions(-)
diff --git
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/io/LocalDir.java
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/io/LocalDir.java
index a9fd3b3e7d..fb3e33960c 100644
---
a/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/io/LocalDir.java
+++
b/juneau-core/juneau-commons/src/main/java/org/apache/juneau/commons/io/LocalDir.java
@@ -223,7 +223,7 @@ public class LocalDir {
* LocalFile <jv>file2</jv> =
<jv>dir</jv>.resolve(<js>"pages/about.html"</js>);
* </p>
*
- * <h5 class='section'>Security (CWE-22 / path-traversal):</h5>
+ * <h5 class='section'>Security (path-traversal):</h5>
* <p>
* For filesystem-root {@code LocalDir} instances, path resolution is
delegated to
* {@link FileUtils#resolveSafely(java.io.File, String)} which enforces
a strict boundary check:
diff --git
a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/io/LocalDir_PathTraversal_Test.java
b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/io/LocalDir_PathTraversal_Test.java
index 8e1f768460..b0b8e30563 100644
---
a/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/io/LocalDir_PathTraversal_Test.java
+++
b/juneau-core/juneau-commons/src/test/java/org/apache/juneau/commons/io/LocalDir_PathTraversal_Test.java
@@ -26,7 +26,7 @@ import org.apache.juneau.commons.*;
import org.junit.jupiter.api.*;
/**
- * Path-traversal (CWE-22) boundary tests for {@link LocalDir#resolve(String)}.
+ * Path-traversal boundary tests for {@link LocalDir#resolve(String)}.
*
* <p>
* Covers both the filesystem-root branch (delegates to {@code
FileUtils.resolveSafely}) and
diff --git
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/html/HtmlWidgetVar.java
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/html/HtmlWidgetVar.java
index cc08663404..1827c99299 100644
---
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/html/HtmlWidgetVar.java
+++
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/marshall/html/HtmlWidgetVar.java
@@ -65,6 +65,14 @@ public class HtmlWidgetVar extends SimpleVar {
if (w == null)
return "unknown-widget-" + key;
- return w.getHtml(session);
+ try {
+ return w.getHtml(session);
+ } catch (@SuppressWarnings("unused") Exception e) {
+ // Defensive per-widget degradation: an individual
widget's render failure must not propagate out of
+ // var resolution, since that would abort the whole
enclosing string and blank the surrounding page.
+ // Degrade to an empty fragment so the navlink renders
empty and the rest of the page is unaffected.
+ // Only Exception is caught so JVM Errors (OOM, etc.)
still propagate.
+ return "";
+ }
}
}
\ No newline at end of file
diff --git
a/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/html/HtmlWidgetVar_Test.java
b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/html/HtmlWidgetVar_Test.java
new file mode 100644
index 0000000000..88e493f376
--- /dev/null
+++
b/juneau-core/juneau-marshall/src/test/java/org/apache/juneau/marshall/html/HtmlWidgetVar_Test.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.juneau.marshall.html;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.commons.svl.*;
+import org.junit.jupiter.api.*;
+
+/**
+ * Tests {@link HtmlWidgetVar} resolution of <js>"$W{...}"</js> variables.
+ *
+ * <p>
+ * Covers the defensive per-widget degradation contract: a widget whose {@link
HtmlWidget#getHtml(VarResolverSession)}
+ * throws must not propagate out of var resolution (which would abort the
whole enclosing string and blank the page).
+ * Instead it degrades to an empty fragment while surrounding text and
unregistered-widget placeholders are unaffected.
+ */
+class HtmlWidgetVar_Test extends TestBase {
+
+ private static VarResolverSession session(HtmlWidget...widgets) {
+ var vr = VarResolver.create().vars(HtmlWidgetVar.class).build();
+ var s = vr.createSession();
+ s.bean(HtmlWidgetMap.class, new
HtmlWidgetMap().append(widgets));
+ return s;
+ }
+
+ private static HtmlWidget widget(String name, String html) {
+ return new HtmlWidget() {
+ @Override public String getName() { return name; }
+ @Override public String getHtml(VarResolverSession
session) { return html; }
+ @Override public String getScript(VarResolverSession
session) { return null; }
+ @Override public String getStyle(VarResolverSession
session) { return null; }
+ };
+ }
+
+ private static HtmlWidget throwingWidget(String name) {
+ return new HtmlWidget() {
+ @Override public String getName() { return name; }
+ @Override public String getHtml(VarResolverSession
session) { throw new RuntimeException("boom"); }
+ @Override public String getScript(VarResolverSession
session) { return null; }
+ @Override public String getStyle(VarResolverSession
session) { return null; }
+ };
+ }
+
+ @Test void a01_resolvesRegisteredWidget() {
+ var s = session(widget("greeting", "hello"));
+ assertEquals("before hello after", s.resolve("before
$W{greeting} after"));
+ }
+
+ @Test void a02_unregisteredWidgetReturnsPlaceholder() {
+ var s = session(widget("greeting", "hello"));
+ assertEquals("before unknown-widget-missing after",
s.resolve("before $W{missing} after"));
+ }
+
+ @Test void a03_throwingWidgetDegradesToEmptyAndDoesNotPropagate() {
+ var s = session(throwingWidget("boom"));
+ // The failing widget must degrade to empty rather than throw,
and surrounding text must still render.
+ assertDoesNotThrow(() -> s.resolve("before $W{boom} after"));
+ assertEquals("before after", s.resolve("before $W{boom}
after"));
+ }
+
+ @Test void a04_throwingWidgetDoesNotAffectSiblingWidgets() {
+ var s = session(throwingWidget("boom"), widget("ok", "OK"));
+ assertEquals("[] [OK]", s.resolve("[$W{boom}] [$W{ok}]"));
+ }
+}
diff --git
a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/Rest_AllowedMethodParams_Test.java
b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/Rest_AllowedMethodParams_Test.java
index 1800cc630f..dbe3e6f60a 100644
---
a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/Rest_AllowedMethodParams_Test.java
+++
b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/Rest_AllowedMethodParams_Test.java
@@ -170,7 +170,7 @@ class Rest_AllowedMethodParams_Test extends TestBase {
}
//------------------------------------------------------------------------------------------------------------------
- // Security: Malformed method parameters should return 405, not 500
(CWE-74)
+ // Security: Malformed method parameters should return 405, not 500
//------------------------------------------------------------------------------------------------------------------
@Test void b01_malformedMethodParameter_returns405() throws Exception {
diff --git
a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/view/freemarker/FreemarkerMixin_PathTraversal_Test.java
b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/view/freemarker/FreemarkerMixin_PathTraversal_Test.java
index 5bb00725e5..3d669d205e 100644
---
a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/view/freemarker/FreemarkerMixin_PathTraversal_Test.java
+++
b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/view/freemarker/FreemarkerMixin_PathTraversal_Test.java
@@ -73,7 +73,7 @@ class FreemarkerMixin_PathTraversal_Test extends TestBase {
}
//-----------------------------------------------------------------------------------------------------------------
- // CWE-22: direct .. traversal of basePath returns 403
+ // direct .. traversal of basePath returns 403
//-----------------------------------------------------------------------------------------------------------------
@Test void t02_directTraversal_returns403() throws Exception {
diff --git
a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/view/jsp/JspMixin_PathTraversal_Test.java
b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/view/jsp/JspMixin_PathTraversal_Test.java
index de05f9bc06..f4a75997df 100644
---
a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/view/jsp/JspMixin_PathTraversal_Test.java
+++
b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/view/jsp/JspMixin_PathTraversal_Test.java
@@ -80,7 +80,7 @@ class JspMixin_PathTraversal_Test extends TestBase {
}
//-----------------------------------------------------------------------------------------------------------------
- // CWE-22: direct .. traversal of basePath returns 403
+ // direct .. traversal of basePath returns 403
//-----------------------------------------------------------------------------------------------------------------
@Test void t02_directTraversal_returns403() throws Exception {
diff --git
a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/view/mustache/MustacheMixin_PathTraversal_Test.java
b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/view/mustache/MustacheMixin_PathTraversal_Test.java
index 463bc6b417..c489c81a60 100644
---
a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/view/mustache/MustacheMixin_PathTraversal_Test.java
+++
b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/view/mustache/MustacheMixin_PathTraversal_Test.java
@@ -67,7 +67,7 @@ class MustacheMixin_PathTraversal_Test extends TestBase {
}
//-----------------------------------------------------------------------------------------------------------------
- // CWE-22: direct .. traversal of basePath returns 403
+ // direct .. traversal of basePath returns 403
//-----------------------------------------------------------------------------------------------------------------
@Test void t02_directTraversal_returns403() throws Exception {
diff --git
a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/view/thymeleaf/ThymeleafMixin_PathTraversal_Test.java
b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/view/thymeleaf/ThymeleafMixin_PathTraversal_Test.java
index b0803e367a..d87c807dd1 100644
---
a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/view/thymeleaf/ThymeleafMixin_PathTraversal_Test.java
+++
b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/view/thymeleaf/ThymeleafMixin_PathTraversal_Test.java
@@ -63,7 +63,7 @@ class ThymeleafMixin_PathTraversal_Test extends TestBase {
}
//-----------------------------------------------------------------------------------------------------------------
- // CWE-22: direct .. traversal of basePath returns 403
+ // direct .. traversal of basePath returns 403
//-----------------------------------------------------------------------------------------------------------------
@Test void t02_directTraversal_returns403() throws Exception {
diff --git
a/juneau-microservice/juneau-microservice-examples/src/test/java/org/apache/juneau/microservice/examples/DirectoryResource_PathTraversal_Test.java
b/juneau-microservice/juneau-microservice-examples/src/test/java/org/apache/juneau/microservice/examples/DirectoryResource_PathTraversal_Test.java
index 8e3d07df54..28ba5d5094 100644
---
a/juneau-microservice/juneau-microservice-examples/src/test/java/org/apache/juneau/microservice/examples/DirectoryResource_PathTraversal_Test.java
+++
b/juneau-microservice/juneau-microservice-examples/src/test/java/org/apache/juneau/microservice/examples/DirectoryResource_PathTraversal_Test.java
@@ -140,7 +140,7 @@ class DirectoryResource_PathTraversal_Test extends TestBase
{
}
//-----------------------------------------------------------------------------------------------------------------
- // CWE-22: direct ../ traversal across each operation surface (view,
download, delete)
+ // direct ../ traversal across each operation surface (view, download,
delete)
//-----------------------------------------------------------------------------------------------------------------
@Test void t02_directTraversal_GET_returns403() throws Exception {
diff --git
a/juneau-microservice/juneau-microservice-examples/src/test/java/org/apache/juneau/microservice/examples/LogsResource_PathTraversal_Test.java
b/juneau-microservice/juneau-microservice-examples/src/test/java/org/apache/juneau/microservice/examples/LogsResource_PathTraversal_Test.java
index 6d70a2d496..6d4cb4478f 100644
---
a/juneau-microservice/juneau-microservice-examples/src/test/java/org/apache/juneau/microservice/examples/LogsResource_PathTraversal_Test.java
+++
b/juneau-microservice/juneau-microservice-examples/src/test/java/org/apache/juneau/microservice/examples/LogsResource_PathTraversal_Test.java
@@ -139,7 +139,7 @@ class LogsResource_PathTraversal_Test extends TestBase {
}
//-----------------------------------------------------------------------------------------------------------------
- // CWE-22: direct ../ traversal across each operation surface (view,
download, delete)
+ // direct ../ traversal across each operation surface (view, download,
delete)
//-----------------------------------------------------------------------------------------------------------------
@Test void t02_directTraversal_GET_returns403() throws Exception {
diff --git
a/juneau-petstore/juneau-petstore-springboot/src/test/java/org/apache/juneau/petstore/springboot/PetstoreSpringboot_Test.java
b/juneau-petstore/juneau-petstore-springboot/src/test/java/org/apache/juneau/petstore/springboot/PetstoreSpringboot_Test.java
index 6ae5e2c35d..a513c4a903 100644
---
a/juneau-petstore/juneau-petstore-springboot/src/test/java/org/apache/juneau/petstore/springboot/PetstoreSpringboot_Test.java
+++
b/juneau-petstore/juneau-petstore-springboot/src/test/java/org/apache/juneau/petstore/springboot/PetstoreSpringboot_Test.java
@@ -157,6 +157,10 @@ class PetstoreSpringboot_Test {
@Test void a01_rootRendersHtml() throws Exception {
var resp = get("/", "text/html");
assertEquals(200, resp.statusCode(), "body: " + resp.body());
+ // Fail fast if any rendered menu item / navlink returned a
server error (e.g. a $W widget var that
+ // failed to resolve renders an inline "HTTP 500: Internal
Server Error ..." fragment inside the 200
+ // page). Surface that fragment directly instead of the opaque
"expected petstore link" failure below.
+ assertFalse(resp.body().contains("HTTP 500"), "root page
rendered an inline server error: " + resp.body());
assertTrue(resp.body().contains("petstore"), "expected petstore
link on root: " + resp.body());
}
diff --git
a/juneau-rest/juneau-rest-server-view-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/FreemarkerMixin_PathTraversal_Test.java
b/juneau-rest/juneau-rest-server-view-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/FreemarkerMixin_PathTraversal_Test.java
index 1132481709..f78ab2babb 100644
---
a/juneau-rest/juneau-rest-server-view-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/FreemarkerMixin_PathTraversal_Test.java
+++
b/juneau-rest/juneau-rest-server-view-freemarker/src/test/java/org/apache/juneau/rest/server/view/freemarker/FreemarkerMixin_PathTraversal_Test.java
@@ -76,7 +76,7 @@ class FreemarkerMixin_PathTraversal_Test extends TestBase {
}
//-----------------------------------------------------------------------------------------------------------------
- // CWE-22: direct .. traversal of basePath returns 403
+ // direct .. traversal of basePath returns 403
//-----------------------------------------------------------------------------------------------------------------
@Test void t02_directTraversal_returns403() throws Exception {
diff --git
a/juneau-rest/juneau-rest-server-view-jsp/src/test/java/org/apache/juneau/rest/server/view/jsp/JspMixin_PathTraversal_Test.java
b/juneau-rest/juneau-rest-server-view-jsp/src/test/java/org/apache/juneau/rest/server/view/jsp/JspMixin_PathTraversal_Test.java
index 66a0a5d736..8ff78e6500 100644
---
a/juneau-rest/juneau-rest-server-view-jsp/src/test/java/org/apache/juneau/rest/server/view/jsp/JspMixin_PathTraversal_Test.java
+++
b/juneau-rest/juneau-rest-server-view-jsp/src/test/java/org/apache/juneau/rest/server/view/jsp/JspMixin_PathTraversal_Test.java
@@ -83,7 +83,7 @@ class JspMixin_PathTraversal_Test extends TestBase {
}
//-----------------------------------------------------------------------------------------------------------------
- // CWE-22: direct .. traversal of basePath returns 403
+ // direct .. traversal of basePath returns 403
//-----------------------------------------------------------------------------------------------------------------
@Test void t02_directTraversal_returns403() throws Exception {
diff --git
a/juneau-rest/juneau-rest-server-view-mustache/src/test/java/org/apache/juneau/rest/server/view/mustache/MustacheMixin_PathTraversal_Test.java
b/juneau-rest/juneau-rest-server-view-mustache/src/test/java/org/apache/juneau/rest/server/view/mustache/MustacheMixin_PathTraversal_Test.java
index e03dab4d15..57daf92e4d 100644
---
a/juneau-rest/juneau-rest-server-view-mustache/src/test/java/org/apache/juneau/rest/server/view/mustache/MustacheMixin_PathTraversal_Test.java
+++
b/juneau-rest/juneau-rest-server-view-mustache/src/test/java/org/apache/juneau/rest/server/view/mustache/MustacheMixin_PathTraversal_Test.java
@@ -70,7 +70,7 @@ class MustacheMixin_PathTraversal_Test extends TestBase {
}
//-----------------------------------------------------------------------------------------------------------------
- // CWE-22: direct .. traversal of basePath returns 403
+ // direct .. traversal of basePath returns 403
//-----------------------------------------------------------------------------------------------------------------
@Test void t02_directTraversal_returns403() throws Exception {
diff --git
a/juneau-rest/juneau-rest-server-view-thymeleaf/src/test/java/org/apache/juneau/rest/server/view/thymeleaf/ThymeleafMixin_PathTraversal_Test.java
b/juneau-rest/juneau-rest-server-view-thymeleaf/src/test/java/org/apache/juneau/rest/server/view/thymeleaf/ThymeleafMixin_PathTraversal_Test.java
index 2ca110ee40..d4a8399f68 100644
---
a/juneau-rest/juneau-rest-server-view-thymeleaf/src/test/java/org/apache/juneau/rest/server/view/thymeleaf/ThymeleafMixin_PathTraversal_Test.java
+++
b/juneau-rest/juneau-rest-server-view-thymeleaf/src/test/java/org/apache/juneau/rest/server/view/thymeleaf/ThymeleafMixin_PathTraversal_Test.java
@@ -66,7 +66,7 @@ class ThymeleafMixin_PathTraversal_Test extends TestBase {
}
//-----------------------------------------------------------------------------------------------------------------
- // CWE-22: direct .. traversal of basePath returns 403
+ // direct .. traversal of basePath returns 403
//-----------------------------------------------------------------------------------------------------------------
@Test void t02_directTraversal_returns403() throws Exception {