diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 3d0c778ec..97a4ed500 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -52,12 +52,12 @@ jobs: java-version: 17 cache: 'maven' - name: Initialize CodeQL - uses: github/codeql-action/init@v3.26.6 + uses: github/codeql-action/init@v3.26.12 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@v3.26.6 + uses: github/codeql-action/autobuild@v3.26.12 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3.26.6 + uses: github/codeql-action/analyze@v3.26.12 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/scorecards-analysis.yaml b/.github/workflows/scorecards-analysis.yaml index 93895ffab..9132e371d 100644 --- a/.github/workflows/scorecards-analysis.yaml +++ b/.github/workflows/scorecards-analysis.yaml @@ -58,13 +58,13 @@ jobs: publish_results: true - name: "Upload artifact" - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # 4.4.0 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # 4.4.3 with: name: SARIF file path: results.sarif retention-days: 5 - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@821ab42c90a42d1d5cd3241930dff56a7c7dcfb2 # 2.22.11 + uses: github/codeql-action/upload-sarif@ea2cd92c21b192add69983116b8b3222b09da33b # 2.22.11 with: sarif_file: results.sarif diff --git a/core/src/main/java/org/apache/struts2/components/UIBean.java b/core/src/main/java/org/apache/struts2/components/UIBean.java index ff89c035d..d4e9ee4b5 100644 --- a/core/src/main/java/org/apache/struts2/components/UIBean.java +++ b/core/src/main/java/org/apache/struts2/components/UIBean.java @@ -24,6 +24,7 @@ import com.opensymphony.xwork2.util.TextParseUtil; import com.opensymphony.xwork2.util.ValueStack; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; @@ -863,10 +864,13 @@ public abstract class UIBean extends Component { } // to be used with the CSP interceptor - adds the nonce value as a parameter to be accessed from ftl files - Map session = stack.getActionContext().getSession(); - Object nonceValue = session != null ? session.get("nonce") : null; + HttpSession session = stack.getActionContext().getServletRequest().getSession(false); + Object nonceValue = session != null ? session.getAttribute("nonce") : null; + if (nonceValue != null) { addParameter("nonce", nonceValue.toString()); + } else { + LOG.debug("Session is not active, cannot obtain nonce value"); } evaluateExtraParams(); diff --git a/core/src/test/java/org/apache/struts2/components/UIBeanTest.java b/core/src/test/java/org/apache/struts2/components/UIBeanTest.java index 690328942..15ff3d29d 100644 --- a/core/src/test/java/org/apache/struts2/components/UIBeanTest.java +++ b/core/src/test/java/org/apache/struts2/components/UIBeanTest.java @@ -25,12 +25,13 @@ import org.apache.struts2.StrutsInternalTestCase; import org.apache.struts2.components.template.Template; import org.apache.struts2.components.template.TemplateEngine; import org.apache.struts2.components.template.TemplateEngineManager; +import org.apache.struts2.dispatcher.SessionMap; import org.apache.struts2.dispatcher.StaticContentLoader; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockHttpSession; import java.util.Collections; -import java.util.HashMap; import java.util.Map; import static com.opensymphony.xwork2.security.DefaultNotExcludedAcceptedPatternsCheckerTest.NO_EXCLUSION_ACCEPT_ALL_PATTERNS_CHECKER; @@ -160,7 +161,7 @@ public class UIBeanTest extends StrutsInternalTestCase { try { txtFld.mergeTemplate(null, new Template(null, null, null)); fail("Exception not thrown"); - } catch(final Exception e){ + } catch (final Exception e) { assertTrue(e instanceof ConfigurationException); } } @@ -225,6 +226,7 @@ public class UIBeanTest extends StrutsInternalTestCase { ValueStack stack = ActionContext.getContext().getValueStack(); MockHttpServletRequest req = new MockHttpServletRequest(); MockHttpServletResponse res = new MockHttpServletResponse(); + ActionContext.getContext().withServletRequest(req); TextField txtFld = new TextField(stack, req, res); txtFld.setAccesskey(accesskeyValue); @@ -238,6 +240,7 @@ public class UIBeanTest extends StrutsInternalTestCase { ValueStack stack = ActionContext.getContext().getValueStack(); MockHttpServletRequest req = new MockHttpServletRequest(); MockHttpServletResponse res = new MockHttpServletResponse(); + ActionContext.getContext().withServletRequest(req); TextField txtFld = new TextField(stack, req, res); txtFld.addParameter("value", value); @@ -250,11 +253,13 @@ public class UIBeanTest extends StrutsInternalTestCase { ValueStack stack = ActionContext.getContext().getValueStack(); MockHttpServletRequest req = new MockHttpServletRequest(); MockHttpServletResponse res = new MockHttpServletResponse(); + ActionContext.getContext().withServletRequest(req); stack.push(new Object() { public String getMyValue() { return "%{myBad}"; } + public String getMyBad() { throw new IllegalStateException("Recursion detected!"); } @@ -273,11 +278,13 @@ public class UIBeanTest extends StrutsInternalTestCase { ValueStack stack = ActionContext.getContext().getValueStack(); MockHttpServletRequest req = new MockHttpServletRequest(); MockHttpServletResponse res = new MockHttpServletResponse(); + ActionContext.getContext().withServletRequest(req); stack.push(new Object() { public String getMyValueName() { return "getMyValue()"; } + public String getMyValue() { return "value"; } @@ -300,6 +307,7 @@ public class UIBeanTest extends StrutsInternalTestCase { ValueStack stack = ActionContext.getContext().getValueStack(); MockHttpServletRequest req = new MockHttpServletRequest(); MockHttpServletResponse res = new MockHttpServletResponse(); + ActionContext.getContext().withServletRequest(req); stack.push(new Object() { public String getMyValue() { @@ -320,6 +328,7 @@ public class UIBeanTest extends StrutsInternalTestCase { ValueStack stack = ActionContext.getContext().getValueStack(); MockHttpServletRequest req = new MockHttpServletRequest(); MockHttpServletResponse res = new MockHttpServletResponse(); + ActionContext.getContext().withServletRequest(req); TextField txtFld = new TextField(stack, req, res); txtFld.setCssClass(cssClass); @@ -333,6 +342,7 @@ public class UIBeanTest extends StrutsInternalTestCase { ValueStack stack = ActionContext.getContext().getValueStack(); MockHttpServletRequest req = new MockHttpServletRequest(); MockHttpServletResponse res = new MockHttpServletResponse(); + ActionContext.getContext().withServletRequest(req); TextField txtFld = new TextField(stack, req, res); txtFld.setStyle(cssStyle); @@ -347,9 +357,12 @@ public class UIBeanTest extends StrutsInternalTestCase { MockHttpServletRequest req = new MockHttpServletRequest(); MockHttpServletResponse res = new MockHttpServletResponse(); ActionContext actionContext = stack.getActionContext(); - Map session = new HashMap<>(); - session.put("nonce", nonceVal); - actionContext.withSession(session); + actionContext.withServletRequest(req); + MockHttpSession session = new MockHttpSession(); + session.setAttribute("nonce", nonceVal); + req.setSession(session); + + actionContext.withSession(new SessionMap(req)); DoubleSelect dblSelect = new DoubleSelect(stack, req, res); dblSelect.evaluateParams(); @@ -357,6 +370,26 @@ public class UIBeanTest extends StrutsInternalTestCase { assertEquals(nonceVal, dblSelect.getParameters().get("nonce")); } + public void testNonceOfInvalidSession() { + String nonceVal = "r4nd0m"; + ValueStack stack = ActionContext.getContext().getValueStack(); + MockHttpServletRequest req = new MockHttpServletRequest(); + MockHttpServletResponse res = new MockHttpServletResponse(); + ActionContext actionContext = stack.getActionContext(); + actionContext.withServletRequest(req); + MockHttpSession session = new MockHttpSession(); + session.setAttribute("nonce", nonceVal); + req.setSession(session); + actionContext.withSession(new SessionMap(req)); + + session.invalidate(); + + DoubleSelect dblSelect = new DoubleSelect(stack, req, res); + dblSelect.evaluateParams(); + + assertNull(dblSelect.getParameters().get("nonce")); + } + public void testSetNullUiStaticContentPath() { // given ValueStack stack = ActionContext.getContext().getValueStack(); diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AbstractTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AbstractTest.java index f48c52b2f..88052ceb1 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AbstractTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AbstractTest.java @@ -27,6 +27,7 @@ import com.opensymphony.xwork2.inject.Container; import com.opensymphony.xwork2.util.OgnlTextParser; import com.opensymphony.xwork2.util.TextParser; import com.opensymphony.xwork2.util.ValueStack; +import jakarta.servlet.http.HttpSession; import junit.framework.TestCase; import org.apache.struts2.components.Component; import org.apache.struts2.components.UIBean; @@ -51,6 +52,8 @@ public abstract class AbstractTest extends TestCase { private final Map commonAttrs = new HashMap<>(); private final Map dynamicAttrs = new HashMap<>(); + protected static final String NONCE_VAL = "r4andom"; + protected SimpleTheme theme; protected StringWriter writer; @@ -62,6 +65,7 @@ public abstract class AbstractTest extends TestCase { protected TemplateRenderingContext context; protected HttpServletRequest request; protected HttpServletResponse response; + protected HttpSession session; protected abstract UIBean getUIBean() throws Exception; @@ -107,6 +111,12 @@ public abstract class AbstractTest extends TestCase { expect(request.getContextPath()).andReturn("/some/path").anyTimes(); response = createNiceMock(HttpServletResponse.class); + session = createNiceMock(HttpSession.class); + expect(session.getAttribute("nonce")).andReturn(NONCE_VAL).anyTimes(); + expect(request.getSession(false)).andReturn(session).anyTimes(); + + actionContext.withServletRequest(request); + expect(stack.getActionContext()).andReturn(actionContext).anyTimes(); expect(stack.getContext()).andReturn(stackContext).anyTimes(); @@ -116,6 +126,7 @@ public abstract class AbstractTest extends TestCase { TextParser parser = new OgnlTextParser(); expect(container.getInstance(TextParser.class)).andReturn(parser).anyTimes(); + replay(session); replay(request); replay(stack); replay(container); diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/HeadTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/HeadTest.java index 073da1f2b..e116b3df4 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/HeadTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/HeadTest.java @@ -31,7 +31,7 @@ public class HeadTest extends AbstractTest { map.putAll(tag.getParameters()); theme.renderTag(getTagName(), context); String output = writer.getBuffer().toString(); - String expected = s(""); + String expected = s(""); assertEquals(expected, output); } diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/LinkTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/LinkTest.java index 873ede269..c8c9c414a 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/LinkTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/LinkTest.java @@ -18,19 +18,13 @@ */ package org.apache.struts2.views.java.simple; -import com.opensymphony.xwork2.ActionContext; import org.apache.struts2.components.Link; import org.apache.struts2.components.UIBean; -import java.util.HashMap; -import java.util.Map; - -public class LinkTest extends AbstractTest{ +public class LinkTest extends AbstractTest { private Link tag; - private static final String NONCE_VAL = "r4andom"; - public void testRenderLinkTag() { tag.setHref("testhref"); tag.setHreflang("test"); @@ -60,7 +54,7 @@ public class LinkTest extends AbstractTest{ assertTrue("Incorrect as attribute for link tag", output.contains(s("as='test'"))); assertFalse("Non-existent disabled attribute for link tag", output.contains(s("disabled='disabled'"))); assertTrue("Incorrect title attribute for link tag", output.contains(s("title='test'"))); - assertTrue("Incorrect nonce attribute for link tag", output.contains(s("nonce='" + NONCE_VAL+"'"))); + assertTrue("Incorrect nonce attribute for link tag", output.contains(s("nonce='" + NONCE_VAL + "'"))); } public void testRenderLinkTagAsStylesheet() { @@ -92,7 +86,7 @@ public class LinkTest extends AbstractTest{ assertTrue("Incorrect as attribute for link tag", output.contains(s("as='test'"))); assertTrue("Incorrect disabled attribute for link tag", output.contains(s("disabled='disabled'"))); assertTrue("Incorrect title attribute for link tag", output.contains(s("title='test'"))); - assertTrue("Incorrect nonce attribute for link tag", output.contains(s("nonce='" + NONCE_VAL+"'"))); + assertTrue("Incorrect nonce attribute for link tag", output.contains(s("nonce='" + NONCE_VAL + "'"))); } @Override @@ -108,12 +102,6 @@ public class LinkTest extends AbstractTest{ @Override protected void setUp() throws Exception { super.setUp(); - - ActionContext actionContext = stack.getActionContext(); - Map session = new HashMap<>(); - session.put("nonce", NONCE_VAL); - actionContext.withSession(session); - this.tag = new Link(stack, request, response); } } diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ScriptTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ScriptTest.java index 832653692..b37c76ec8 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ScriptTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ScriptTest.java @@ -18,22 +18,15 @@ */ package org.apache.struts2.views.java.simple; -import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.security.DefaultNotExcludedAcceptedPatternsChecker; import org.apache.struts2.components.Script; import org.apache.struts2.components.UIBean; -import java.util.HashMap; -import java.util.Map; - - public class ScriptTest extends AbstractTest { private Script tag; - private static final String NONCE_VAL = "r4andom"; - public void testRenderScriptTag() { tag.setName("name_"); tag.setType("text/javascript"); @@ -77,11 +70,6 @@ public class ScriptTest extends AbstractTest { protected void setUp() throws Exception { super.setUp(); - ActionContext actionContext = stack.getActionContext(); - Map session = new HashMap<>(); - session.put("nonce", NONCE_VAL); - actionContext.withSession(session); - this.tag = new Script(stack, request, response); tag.setNotExcludedAcceptedPatterns(new DefaultNotExcludedAcceptedPatternsChecker()); } diff --git a/plugins/tiles/pom.xml b/plugins/tiles/pom.xml index cf8e54cae..2967e0b91 100644 --- a/plugins/tiles/pom.xml +++ b/plugins/tiles/pom.xml @@ -40,7 +40,7 @@ org.codehaus.mojo exec-maven-plugin - 3.3.0 + 3.4.1 compile diff --git a/pom.xml b/pom.xml index 9bbfc5295..dbe52b290 100644 --- a/pom.xml +++ b/pom.xml @@ -114,8 +114,8 @@ 1.14.11 2.3.33 8.0.1.Final - 2.17.2 - 2.23.1 + 2.18.0 + 2.24.1 3.5.0 5.8.0 3.3.5 @@ -240,7 +240,7 @@ org.apache.maven.plugins maven-project-info-reports-plugin - 3.6.2 + 3.7.0 org.apache.maven.plugins @@ -332,7 +332,7 @@ org.owasp dependency-check-maven - 10.0.3 + 10.0.4 src/etc/project-suppression.xml @@ -405,7 +405,7 @@ org.apache.maven.plugins maven-site-plugin - 3.12.1 + 3.20.0 false @@ -797,7 +797,7 @@ commons-logging commons-logging - 1.3.3 + 1.3.4 org.apache.commons