diff --git a/core/src/main/java/com/opensymphony/xwork2/config/providers/StrutsDefaultConfigurationProvider.java b/core/src/main/java/com/opensymphony/xwork2/config/providers/StrutsDefaultConfigurationProvider.java index 6e66dd7a37..81b7b40783 100644 --- a/core/src/main/java/com/opensymphony/xwork2/config/providers/StrutsDefaultConfigurationProvider.java +++ b/core/src/main/java/com/opensymphony/xwork2/config/providers/StrutsDefaultConfigurationProvider.java @@ -68,6 +68,8 @@ import ognl.PropertyAccessor; import org.apache.struts2.dispatcher.HttpParameters; import org.apache.struts2.dispatcher.Parameter; +import org.apache.struts2.interceptor.csp.CspNonceReader; +import org.apache.struts2.interceptor.csp.StrutsCspNonceReader; import org.apache.struts2.interceptor.exec.ExecutorProvider; import org.apache.struts2.interceptor.exec.StrutsExecutorProvider; import org.apache.struts2.url.QueryStringBuilder; @@ -159,7 +161,9 @@ public void register(ContainerBuilder builder, LocatableProperties props) throws .factory(UrlEncoder.class, StrutsUrlEncoder.class, Scope.SINGLETON) .factory(UrlDecoder.class, StrutsUrlDecoder.class, Scope.SINGLETON) - .factory(ExecutorProvider.class, StrutsExecutorProvider.class, Scope.SINGLETON); + .factory(ExecutorProvider.class, StrutsExecutorProvider.class, Scope.SINGLETON) + + .factory(CspNonceReader.class, StrutsCspNonceReader.class, Scope.SINGLETON); for (Map.Entry entry : DefaultConfiguration.BOOTSTRAP_CONSTANTS.entrySet()) { props.setProperty(entry.getKey(), String.valueOf(entry.getValue())); diff --git a/core/src/main/java/com/opensymphony/xwork2/inject/ContainerImpl.java b/core/src/main/java/com/opensymphony/xwork2/inject/ContainerImpl.java index 455f8a4495..1596077aba 100644 --- a/core/src/main/java/com/opensymphony/xwork2/inject/ContainerImpl.java +++ b/core/src/main/java/com/opensymphony/xwork2/inject/ContainerImpl.java @@ -419,8 +419,12 @@ Object construct(InternalContext context, Class expectedType) { // First time through... constructionContext.startConstruction(); try { - final Object[] parameters = getParameters(constructor, context, parameterInjectors); - t = constructor.newInstance(parameters); + if (constructor.getParameterCount() > 0 && parameterInjectors == null) { + t = constructor.newInstance(new Object[constructor.getParameterCount()]); + } else { + final Object[] parameters = getParameters(constructor, context, parameterInjectors); + t = constructor.newInstance(parameters); + } constructionContext.setProxyDelegates(t); } finally { constructionContext.finishConstruction(); diff --git a/core/src/main/java/org/apache/struts2/StrutsConstants.java b/core/src/main/java/org/apache/struts2/StrutsConstants.java index 91b8eb2f4b..44cb014687 100644 --- a/core/src/main/java/org/apache/struts2/StrutsConstants.java +++ b/core/src/main/java/org/apache/struts2/StrutsConstants.java @@ -509,4 +509,11 @@ public final class StrutsConstants { /** See {@link org.apache.struts2.interceptor.exec.ExecutorProvider} */ public static final String STRUTS_EXECUTOR_PROVIDER = "struts.executor.provider"; + + /** + * See {@link org.apache.struts2.interceptor.csp.CspNonceReader} + * @since 6.8.0 + */ + public static final String STRUTS_CSP_NONCE_READER = "struts.csp.nonce.reader"; + public static final String STRUTS_CSP_NONCE_SOURCE = "struts.csp.nonce.source"; } 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 e525b92a7a..9675084269 100644 --- a/core/src/main/java/org/apache/struts2/components/UIBean.java +++ b/core/src/main/java/org/apache/struts2/components/UIBean.java @@ -33,6 +33,7 @@ import org.apache.struts2.components.template.TemplateEngineManager; import org.apache.struts2.components.template.TemplateRenderingContext; import org.apache.struts2.dispatcher.StaticContentLoader; +import org.apache.struts2.interceptor.csp.CspNonceReader; import org.apache.struts2.util.ComponentUtils; import org.apache.struts2.util.TextProviderHelper; import org.apache.struts2.views.annotations.StrutsTagAttribute; @@ -40,7 +41,6 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; import java.io.Writer; import java.util.HashMap; import java.util.LinkedHashMap; @@ -521,6 +521,8 @@ public UIBean(ValueStack stack, HttpServletRequest request, HttpServletResponse protected TemplateEngineManager templateEngineManager; + protected CspNonceReader cspNonceReader; + @Inject(StrutsConstants.STRUTS_UI_TEMPLATEDIR) public void setDefaultTemplateDir(String dir) { this.defaultTemplateDir = dir; @@ -546,6 +548,11 @@ public void setTemplateEngineManager(TemplateEngineManager mgr) { this.templateEngineManager = mgr; } + @Inject + public void setCspNonceReader(CspNonceReader cspNonceReader) { + this.cspNonceReader = cspNonceReader; + } + @Override public boolean end(Writer writer, String body) { evaluateParams(); @@ -864,13 +871,12 @@ public void evaluateParams() { } // to be used with the CSP interceptor - adds the nonce value as a parameter to be accessed from ftl files - HttpSession session = stack.getActionContext().getServletRequest().getSession(false); - Object nonceValue = session != null ? session.getAttribute("nonce") : null; + CspNonceReader.NonceValue nonceValue = cspNonceReader.readNonceValue(stack); - if (nonceValue != null) { - addParameter("nonce", nonceValue.toString()); + if (nonceValue.isNonceValueSet()) { + addParameter("nonce", nonceValue.getNonceValue()); } else { - LOG.debug("Session is not active, cannot obtain nonce value"); + LOG.debug("Nonce not defined in: {}", nonceValue.getSource()); } evaluateExtraParams(); diff --git a/core/src/main/java/org/apache/struts2/config/StrutsBeanSelectionProvider.java b/core/src/main/java/org/apache/struts2/config/StrutsBeanSelectionProvider.java index a52a67749f..e914b04524 100644 --- a/core/src/main/java/org/apache/struts2/config/StrutsBeanSelectionProvider.java +++ b/core/src/main/java/org/apache/struts2/config/StrutsBeanSelectionProvider.java @@ -69,6 +69,7 @@ import org.apache.struts2.dispatcher.StaticContentLoader; import org.apache.struts2.dispatcher.mapper.ActionMapper; import org.apache.struts2.dispatcher.multipart.MultiPartRequest; +import org.apache.struts2.interceptor.csp.CspNonceReader; import org.apache.struts2.interceptor.exec.ExecutorProvider; import org.apache.struts2.ognl.OgnlGuard; import org.apache.struts2.url.QueryStringBuilder; @@ -450,6 +451,8 @@ public void register(ContainerBuilder builder, LocatableProperties props) { alias(ExecutorProvider.class, StrutsConstants.STRUTS_EXECUTOR_PROVIDER, builder, props, Scope.SINGLETON); + alias(CspNonceReader.class, StrutsConstants.STRUTS_CSP_NONCE_READER, builder, props, Scope.SINGLETON); + switchDevMode(props); } diff --git a/core/src/main/java/org/apache/struts2/interceptor/csp/CspNonceReader.java b/core/src/main/java/org/apache/struts2/interceptor/csp/CspNonceReader.java new file mode 100644 index 0000000000..de1412465a --- /dev/null +++ b/core/src/main/java/org/apache/struts2/interceptor/csp/CspNonceReader.java @@ -0,0 +1,76 @@ +/* + * 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.struts2.interceptor.csp; + +import org.apache.struts2.util.ValueStack; + +/** + * Reads the nonce value using the ValueStack, {@link StrutsCspNonceReader} is the default implementation + * @since 6.8.0 + */ +public interface CspNonceReader { + + NonceValue readNonceValue(ValueStack stack); + + class NonceValue { + private final String nonceValue; + private final CspNonceSource source; + + private NonceValue(String nonceValue, CspNonceSource source) { + this.nonceValue = nonceValue; + this.source = source; + } + + public static NonceValue ofSession(String nonceValue) { + return new NonceValue(nonceValue, CspNonceSource.SESSION); + } + + public static NonceValue ofRequest(String nonceValue) { + return new NonceValue(nonceValue, CspNonceSource.REQUEST); + } + + public static NonceValue ofNullSession() { + return new NonceValue(null, CspNonceSource.REQUEST); + } + + public static NonceValue ofNullRequest() { + return new NonceValue(null, CspNonceSource.REQUEST); + } + + public boolean isNonceValueSet() { + return nonceValue != null; + } + + public String getNonceValue() { + return nonceValue; + } + + public CspNonceSource getSource() { + return source; + } + + @Override + public String toString() { + return "NonceValue{" + + String.format("nonceValue='%s**********'", nonceValue.substring(0, 4)) + + ", source=" + source + + '}'; + } + } +} diff --git a/core/src/main/java/org/apache/struts2/interceptor/csp/CspNonceSource.java b/core/src/main/java/org/apache/struts2/interceptor/csp/CspNonceSource.java new file mode 100644 index 0000000000..cc34e35819 --- /dev/null +++ b/core/src/main/java/org/apache/struts2/interceptor/csp/CspNonceSource.java @@ -0,0 +1,27 @@ +/* + * 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.struts2.interceptor.csp; + +/** + * Source of the nonce value + */ +public enum CspNonceSource { + REQUEST, + SESSION +} diff --git a/core/src/main/java/org/apache/struts2/interceptor/csp/CspSettings.java b/core/src/main/java/org/apache/struts2/interceptor/csp/CspSettings.java index a8c2a68c2e..bce684d599 100644 --- a/core/src/main/java/org/apache/struts2/interceptor/csp/CspSettings.java +++ b/core/src/main/java/org/apache/struts2/interceptor/csp/CspSettings.java @@ -45,7 +45,7 @@ public interface CspSettings { String CSP_REPORT_TYPE = "application/csp-report"; /** - * @deprecated use {@link #addCspHeaders(HttpServletRequest, HttpServletResponse)} instead + * @deprecated since 6.0.3, use {@link #addCspHeaders(HttpServletRequest, HttpServletResponse)} instead */ @Deprecated void addCspHeaders(HttpServletResponse response); diff --git a/core/src/main/java/org/apache/struts2/interceptor/csp/DefaultCspSettings.java b/core/src/main/java/org/apache/struts2/interceptor/csp/DefaultCspSettings.java index b245ab3526..9627a91ac6 100644 --- a/core/src/main/java/org/apache/struts2/interceptor/csp/DefaultCspSettings.java +++ b/core/src/main/java/org/apache/struts2/interceptor/csp/DefaultCspSettings.java @@ -18,15 +18,17 @@ */ package org.apache.struts2.interceptor.csp; +import com.opensymphony.xwork2.inject.Inject; +import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.apache.struts2.StrutsConstants; import org.apache.struts2.action.CspSettingsAware; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.security.SecureRandom; import java.util.Base64; -import java.util.Objects; import static java.lang.String.format; @@ -43,15 +45,27 @@ */ public class DefaultCspSettings implements CspSettings { - private final static Logger LOG = LogManager.getLogger(DefaultCspSettings.class); + private static final Logger LOG = LogManager.getLogger(DefaultCspSettings.class); + private static final String NONCE_KEY = "nonce"; private final SecureRandom sRand = new SecureRandom(); + private CspNonceSource nonceSource = CspNonceSource.SESSION; + protected String reportUri; protected String reportTo; // default to reporting mode protected String cspHeader = CSP_REPORT_HEADER; + @Inject(value = StrutsConstants.STRUTS_CSP_NONCE_SOURCE, required = false) + public void setNonceSource(String nonceSource) { + if (StringUtils.isBlank(nonceSource)) { + this.nonceSource = CspNonceSource.SESSION; + } else { + this.nonceSource = CspNonceSource.valueOf(nonceSource.toUpperCase()); + } + } + @Override public void addCspHeaders(HttpServletResponse response) { throw new UnsupportedOperationException("Unsupported implementation, use #addCspHeaders(HttpServletRequest request, HttpServletResponse response)"); @@ -59,52 +73,79 @@ public void addCspHeaders(HttpServletResponse response) { @Override public void addCspHeaders(HttpServletRequest request, HttpServletResponse response) { + if (this.nonceSource == CspNonceSource.SESSION) { + addCspHeadersWithSession(request, response); + } else if (this.nonceSource == CspNonceSource.REQUEST) { + addCspHeadersWithRequest(request, response); + } else { + LOG.warn("Unknown nonce source: {}, ignoring CSP settings", nonceSource); + } + } + + private void addCspHeadersWithSession(HttpServletRequest request, HttpServletResponse response) { if (isSessionActive(request)) { LOG.trace("Session is active, applying CSP settings"); - associateNonceWithSession(request); - response.setHeader(cspHeader, createPolicyFormat(request)); + String nonceValue = generateNonceValue(); + request.getSession().setAttribute(NONCE_KEY, nonceValue); + response.setHeader(cspHeader, createPolicyFormat(nonceValue)); } else { - LOG.trace("Session is not active, ignoring CSP settings"); + LOG.debug("Session is not active, ignoring CSP settings"); } } + private void addCspHeadersWithRequest(HttpServletRequest request, HttpServletResponse response) { + String nonceValue = generateNonceValue(); + request.setAttribute(NONCE_KEY, nonceValue); + response.setHeader(cspHeader, createPolicyFormat(nonceValue)); + } + private boolean isSessionActive(HttpServletRequest request) { return request.getSession(false) != null; } - private void associateNonceWithSession(HttpServletRequest request) { - String nonceValue = Base64.getUrlEncoder().encodeToString(getRandomBytes()); - request.getSession().setAttribute("nonce", nonceValue); + private String generateNonceValue() { + return Base64.getUrlEncoder().encodeToString(getRandomBytes()); } - protected String createPolicyFormat(HttpServletRequest request) { - StringBuilder policyFormatBuilder = new StringBuilder() - .append(OBJECT_SRC) - .append(format(" '%s'; ", NONE)) - .append(SCRIPT_SRC) - .append(" 'nonce-%s' ") // nonce placeholder - .append(format("'%s' ", STRICT_DYNAMIC)) - .append(format("%s %s; ", HTTP, HTTPS)) - .append(BASE_URI) - .append(format(" '%s'; ", NONE)); + protected String createPolicyFormat(String nonceValue) { + StringBuilder builder = new StringBuilder() + .append(OBJECT_SRC) + .append(format(" '%s'; ", NONE)) + .append(SCRIPT_SRC) + .append(format(" 'nonce-%s' ", nonceValue)) + .append(format("'%s' ", STRICT_DYNAMIC)) + .append(format("%s %s; ", HTTP, HTTPS)) + .append(BASE_URI) + .append(format(" '%s'; ", NONE)); if (reportUri != null) { - policyFormatBuilder - .append(REPORT_URI) - .append(format(" %s; ", reportUri)); - if(reportTo != null) { - policyFormatBuilder + builder + .append(REPORT_URI) + .append(format(" %s; ", reportUri)); + if (reportTo != null) { + builder .append(REPORT_TO) .append(format(" %s; ", reportTo)); } } - return format(policyFormatBuilder.toString(), getNonceString(request)); + return builder.toString(); + } + + /** + * @deprecated since 6.8.0, for removal + */ + @Deprecated + protected String createPolicyFormat(HttpServletRequest request) { + throw new UnsupportedOperationException("Unsupported implementation, use #createPolicyFormat(String) instead!"); } + /** + * @deprecated since 6.8.0, for removal + */ + @Deprecated protected String getNonceString(HttpServletRequest request) { - Object nonce = request.getSession().getAttribute("nonce"); - return Objects.toString(nonce); + throw new UnsupportedOperationException("Unsupported implementation, don't use!"); } private byte[] getRandomBytes() { @@ -133,10 +174,10 @@ public void setReportTo(String reportTo) { @Override public String toString() { return "DefaultCspSettings{" + - "reportUri='" + reportUri + '\'' + - ", reportTo='" + reportTo + '\'' + - ", cspHeader='" + cspHeader + '\'' + - '}'; + "reportUri='" + reportUri + '\'' + + ", reportTo='" + reportTo + '\'' + + ", cspHeader='" + cspHeader + '\'' + + '}'; } } diff --git a/core/src/main/java/org/apache/struts2/interceptor/csp/StrutsCspNonceReader.java b/core/src/main/java/org/apache/struts2/interceptor/csp/StrutsCspNonceReader.java new file mode 100644 index 0000000000..3de7afdfda --- /dev/null +++ b/core/src/main/java/org/apache/struts2/interceptor/csp/StrutsCspNonceReader.java @@ -0,0 +1,87 @@ +/* + * 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.struts2.interceptor.csp; + +import com.opensymphony.xwork2.inject.Inject; +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.struts2.StrutsConstants; +import org.apache.struts2.util.ValueStack; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +/** + * Reads nonce value from session or request attribute. + * @since 6.8.0 + */ +public class StrutsCspNonceReader implements CspNonceReader { + + private static final Logger LOG = LogManager.getLogger(StrutsCspNonceReader.class); + + private final CspNonceSource nonceSource; + + @Inject(value = StrutsConstants.STRUTS_CSP_NONCE_SOURCE, required = false) + public StrutsCspNonceReader(String source) { + if (StringUtils.isBlank(source)) { + this.nonceSource = CspNonceSource.SESSION; + } else { + this.nonceSource = CspNonceSource.valueOf(source.toUpperCase()); + } + } + + @Override + public NonceValue readNonceValue(ValueStack stack) { + HttpServletRequest request = stack.getActionContext().getServletRequest(); + NonceValue nonceValue; + + if (nonceSource == CspNonceSource.SESSION) { + LOG.debug("Reading nonce value from session"); + nonceValue = readNonceFromSession(request); + } else if (nonceSource == CspNonceSource.REQUEST) { + LOG.debug("Reading nonce value from request attribute"); + nonceValue = readNonceFromRequest(request); + } else { + LOG.warn("Unknown nonce source: {}, reading nonce value from session", nonceSource); + nonceValue = readNonceFromSession(request); + } + return nonceValue; + } + + private NonceValue readNonceFromSession(HttpServletRequest request) { + HttpSession session = request.getSession(false); + Object nonceValue = session != null ? session.getAttribute("nonce") : null; + if (nonceValue == null) { + LOG.debug("Session is not active, cannot obtain nonce value"); + return NonceValue.ofNullSession(); + } + return NonceValue.ofSession(nonceValue.toString()); + } + + private NonceValue readNonceFromRequest(HttpServletRequest request) { + Object nonceValue = request.getAttribute("nonce"); + if (nonceValue == null) { + LOG.warn("Request attribute 'nonce' is not set, cannot obtain nonce value"); + return NonceValue.ofNullRequest(); + } + + return NonceValue.ofRequest(nonceValue.toString()); + } +} diff --git a/core/src/main/resources/org/apache/struts2/default.properties b/core/src/main/resources/org/apache/struts2/default.properties index 8b7226a89b..7dd782ccb1 100644 --- a/core/src/main/resources/org/apache/struts2/default.properties +++ b/core/src/main/resources/org/apache/struts2/default.properties @@ -280,4 +280,7 @@ struts.url.queryStringParser=strutsQueryStringParser struts.url.encoder=strutsUrlEncoder struts.url.decoder=strutsUrlDecoder +### Defines source to read nonce value from, possible values are: request, session +struts.csp.nonceSource=session + ### END SNIPPET: complete_file diff --git a/core/src/main/resources/struts-beans.xml b/core/src/main/resources/struts-beans.xml index 5c3121f77f..6aad85ca68 100644 --- a/core/src/main/resources/struts-beans.xml +++ b/core/src/main/resources/struts-beans.xml @@ -265,4 +265,7 @@ + + 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 ff3dc50f1b..1f20584f16 100644 --- a/core/src/test/java/org/apache/struts2/components/UIBeanTest.java +++ b/core/src/test/java/org/apache/struts2/components/UIBeanTest.java @@ -21,6 +21,8 @@ import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.config.ConfigurationException; import com.opensymphony.xwork2.util.ValueStack; +import net.bytebuddy.implementation.InvokeDynamic; +import org.apache.struts2.StrutsConstants; import org.apache.struts2.StrutsInternalTestCase; import org.apache.struts2.components.template.Template; import org.apache.struts2.components.template.TemplateEngine; @@ -32,6 +34,7 @@ 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; @@ -236,6 +239,8 @@ public void testSetAccesskey() { ActionContext.getContext().withServletRequest(req); TextField txtFld = new TextField(stack, req, res); + container.inject(txtFld); + txtFld.setAccesskey(accesskeyValue); txtFld.evaluateParams(); @@ -250,6 +255,8 @@ public void testValueParameterEvaluation() { ActionContext.getContext().withServletRequest(req); TextField txtFld = new TextField(stack, req, res); + container.inject(txtFld); + txtFld.addParameter("value", value); txtFld.evaluateParams(); @@ -338,6 +345,8 @@ public void testSetClass() { ActionContext.getContext().withServletRequest(req); TextField txtFld = new TextField(stack, req, res); + container.inject(txtFld); + txtFld.setCssClass(cssClass); txtFld.evaluateParams(); @@ -352,6 +361,8 @@ public void testSetStyle() { ActionContext.getContext().withServletRequest(req); TextField txtFld = new TextField(stack, req, res); + container.inject(txtFld); + txtFld.setStyle(cssStyle); txtFld.evaluateParams(); @@ -372,6 +383,8 @@ public void testNonce() { actionContext.withSession(new SessionMap(req)); DoubleSelect dblSelect = new DoubleSelect(stack, req, res); + container.inject(dblSelect); + dblSelect.evaluateParams(); assertEquals(nonceVal, dblSelect.getAttributes().get("nonce")); @@ -392,11 +405,35 @@ public void testNonceOfInvalidSession() { session.invalidate(); DoubleSelect dblSelect = new DoubleSelect(stack, req, res); + container.inject(dblSelect); + dblSelect.evaluateParams(); assertNull(dblSelect.getAttributes().get("nonce")); } + public void testNonceOfRequestAttribute() { + Map params = new HashMap(){{ + put(StrutsConstants.STRUTS_CSP_NONCE_SOURCE, "request"); + }}; + initDispatcher(params); + + String nonceVal = "r4nd0m"; + ValueStack stack = ActionContext.getContext().getValueStack(); + MockHttpServletRequest req = new MockHttpServletRequest(); + req.setAttribute("nonce", nonceVal); + MockHttpServletResponse res = new MockHttpServletResponse(); + ActionContext actionContext = stack.getActionContext(); + actionContext.withServletRequest(req); + + DoubleSelect dblSelect = new DoubleSelect(stack, req, res); + container.inject(dblSelect); + + dblSelect.evaluateParams(); + + assertEquals(nonceVal, dblSelect.getAttributes().get("nonce")); + } + public void testSetNullUiStaticContentPath() { // given ValueStack stack = ActionContext.getContext().getValueStack(); diff --git a/core/src/test/java/org/apache/struts2/interceptor/CspInterceptorTest.java b/core/src/test/java/org/apache/struts2/interceptor/CspInterceptorTest.java index 221e725db2..55df85ca38 100644 --- a/core/src/test/java/org/apache/struts2/interceptor/CspInterceptorTest.java +++ b/core/src/test/java/org/apache/struts2/interceptor/CspInterceptorTest.java @@ -312,7 +312,7 @@ public CspSettings getCspSettings() { */ public static class CustomDefaultCspSettings extends DefaultCspSettings { - protected String createPolicyFormat(HttpServletRequest request) { + protected String createPolicyFormat(String nonceValue) { return "foo"; } } diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ActionErrorTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ActionErrorTest.java index 192e5a4815..9129f24bc7 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ActionErrorTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ActionErrorTest.java @@ -23,6 +23,8 @@ import org.apache.struts2.components.ActionError; import org.apache.struts2.components.Anchor; import org.apache.struts2.components.UIBean; +import org.apache.struts2.interceptor.csp.CspNonceSource; +import org.apache.struts2.interceptor.csp.StrutsCspNonceReader; import java.util.ArrayList; import java.util.List; @@ -72,6 +74,7 @@ protected void setUp() throws Exception { //errors are needed to setup stack super.setUp(); this.tag = new ActionError(stack, request, response); + this.tag.setCspNonceReader(new StrutsCspNonceReader(CspNonceSource.SESSION.name())); } @Override diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ActionMessageTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ActionMessageTest.java index bd550819f1..8d88953723 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ActionMessageTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ActionMessageTest.java @@ -23,6 +23,8 @@ import org.apache.struts2.components.ActionError; import org.apache.struts2.components.UIBean; +import org.apache.struts2.interceptor.csp.CspNonceSource; +import org.apache.struts2.interceptor.csp.StrutsCspNonceReader; import java.util.ArrayList; import java.util.List; @@ -72,6 +74,7 @@ protected void setUp() throws Exception { //errors are needed to setup stack super.setUp(); this.tag = new ActionError(stack, request, response); + this.tag.setCspNonceReader(new StrutsCspNonceReader(CspNonceSource.SESSION.name())); } @Override diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AnchorTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AnchorTest.java index 2ac3b38d63..d7b1de8aa5 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AnchorTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/AnchorTest.java @@ -24,6 +24,8 @@ import org.apache.struts2.components.Anchor; import org.apache.struts2.components.UIBean; import org.apache.struts2.components.ServletUrlRenderer; +import org.apache.struts2.interceptor.csp.CspNonceSource; +import org.apache.struts2.interceptor.csp.StrutsCspNonceReader; public class AnchorTest extends AbstractTest { private Anchor tag; @@ -111,6 +113,7 @@ protected void setUp() throws Exception { this.tag = new Anchor(stack, request, response); this.tag.setUrlRenderer(new ServletUrlRenderer()); this.tag.setNotExcludedAcceptedPatterns(new DefaultNotExcludedAcceptedPatternsChecker()); + this.tag.setCspNonceReader(new StrutsCspNonceReader(CspNonceSource.SESSION.name())); } @Override diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/CheckboxTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/CheckboxTest.java index a7060130fc..d729703e1a 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/CheckboxTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/CheckboxTest.java @@ -23,6 +23,8 @@ import com.opensymphony.xwork2.security.DefaultNotExcludedAcceptedPatternsChecker; import org.apache.struts2.components.Checkbox; import org.apache.struts2.components.UIBean; +import org.apache.struts2.interceptor.csp.CspNonceSource; +import org.apache.struts2.interceptor.csp.StrutsCspNonceReader; public class CheckboxTest extends AbstractCommonAttributesTest { private Checkbox tag; @@ -88,6 +90,7 @@ protected void setUp() throws Exception { super.setUp(); tag = new Checkbox(stack, request, response); tag.setNotExcludedAcceptedPatterns(new DefaultNotExcludedAcceptedPatternsChecker()); + this.tag.setCspNonceReader(new StrutsCspNonceReader(CspNonceSource.SESSION.name())); } @Override diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/DateTextFieldTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/DateTextFieldTest.java index 67d9dc5a5d..7b1d360696 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/DateTextFieldTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/DateTextFieldTest.java @@ -22,6 +22,8 @@ import org.apache.struts2.components.DateTextField; import org.apache.struts2.components.UIBean; +import org.apache.struts2.interceptor.csp.CspNonceSource; +import org.apache.struts2.interceptor.csp.StrutsCspNonceReader; public class DateTextFieldTest extends AbstractCommonAttributesTest { @@ -56,6 +58,7 @@ public void testRenderTextFieldDynamicAttrs() throws Exception { } protected void setUp() throws Exception { super.setUp(); this.tag = new DateTextField(stack, request, response); + this.tag.setCspNonceReader(new StrutsCspNonceReader(CspNonceSource.SESSION.name())); } @Override diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FieldErrorTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FieldErrorTest.java index fe35a58a0e..fca2392933 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FieldErrorTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FieldErrorTest.java @@ -22,6 +22,8 @@ import org.apache.struts2.components.FieldError; import org.apache.struts2.components.UIBean; +import org.apache.struts2.interceptor.csp.CspNonceSource; +import org.apache.struts2.interceptor.csp.StrutsCspNonceReader; import java.util.*; @@ -100,6 +102,7 @@ protected void setUp() throws Exception { //errors are needed to setup stack super.setUp(); this.tag = new FieldError(stack, request, response); + this.tag.setCspNonceReader(new StrutsCspNonceReader(CspNonceSource.SESSION.name())); } @Override diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FileTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FileTest.java index bf9786f3aa..dce590b308 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FileTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FileTest.java @@ -22,6 +22,8 @@ import org.apache.struts2.components.File; import org.apache.struts2.components.UIBean; +import org.apache.struts2.interceptor.csp.CspNonceSource; +import org.apache.struts2.interceptor.csp.StrutsCspNonceReader; public class FileTest extends AbstractCommonAttributesTest { private File tag; @@ -50,6 +52,7 @@ public void testRenderTextField() { protected void setUp() throws Exception { super.setUp(); this.tag = new File(stack, request, response); + this.tag.setCspNonceReader(new StrutsCspNonceReader(CspNonceSource.SESSION.name())); } @Override diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FormTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FormTest.java index 34d176962d..9ee9c91525 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FormTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/FormTest.java @@ -23,6 +23,8 @@ import org.apache.struts2.components.Form; import org.apache.struts2.components.UIBean; import org.apache.struts2.components.UrlRenderer; +import org.apache.struts2.interceptor.csp.CspNonceSource; +import org.apache.struts2.interceptor.csp.StrutsCspNonceReader; import org.easymock.EasyMock; public class FormTest extends AbstractCommonAttributesTest { @@ -80,5 +82,6 @@ protected void setUp() throws Exception { UrlRenderer renderer = EasyMock.createNiceMock(UrlRenderer.class); EasyMock.replay(renderer); tag.setUrlRenderer(renderer); + this.tag.setCspNonceReader(new StrutsCspNonceReader(CspNonceSource.SESSION.name())); } } 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 a1c2762803..ace29fdbcf 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 @@ -22,6 +22,8 @@ import org.apache.struts2.components.Head; import org.apache.struts2.components.UIBean; +import org.apache.struts2.interceptor.csp.CspNonceSource; +import org.apache.struts2.interceptor.csp.StrutsCspNonceReader; public class HeadTest extends AbstractTest { private Head tag; @@ -39,6 +41,7 @@ public void testRenderTextField() { protected void setUp() throws Exception { super.setUp(); this.tag = new Head(stack, request, response); + this.tag.setCspNonceReader(new StrutsCspNonceReader(CspNonceSource.SESSION.name())); } @Override diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/HiddenTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/HiddenTest.java index 8884aaca04..c517a62e81 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/HiddenTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/HiddenTest.java @@ -22,6 +22,8 @@ import org.apache.struts2.components.Hidden; import org.apache.struts2.components.UIBean; +import org.apache.struts2.interceptor.csp.CspNonceSource; +import org.apache.struts2.interceptor.csp.StrutsCspNonceReader; public class HiddenTest extends AbstractTest { private Hidden tag; @@ -49,6 +51,7 @@ public void testRenderHidden() { protected void setUp() throws Exception { super.setUp(); this.tag = new Hidden(stack, request, response); + this.tag.setCspNonceReader(new StrutsCspNonceReader(CspNonceSource.SESSION.name())); } @Override diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/LabelTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/LabelTest.java index 0dfbb81ad4..90cda064c0 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/LabelTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/LabelTest.java @@ -22,6 +22,8 @@ import org.apache.struts2.components.Label; import org.apache.struts2.components.UIBean; +import org.apache.struts2.interceptor.csp.CspNonceSource; +import org.apache.struts2.interceptor.csp.StrutsCspNonceReader; public class LabelTest extends AbstractCommonAttributesTest { private Label tag; @@ -48,6 +50,7 @@ public void testRenderLabel() { protected void setUp() throws Exception { super.setUp(); this.tag = new Label(stack, request, response); + this.tag.setCspNonceReader(new StrutsCspNonceReader(CspNonceSource.SESSION.name())); } @Override 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 1fe7f01061..69c1a11bbc 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 @@ -20,6 +20,8 @@ import org.apache.struts2.components.Link; import org.apache.struts2.components.UIBean; +import org.apache.struts2.interceptor.csp.CspNonceSource; +import org.apache.struts2.interceptor.csp.StrutsCspNonceReader; public class LinkTest extends AbstractTest { @@ -103,5 +105,6 @@ protected String getTagName() { protected void setUp() throws Exception { super.setUp(); this.tag = new Link(stack, request, response); + this.tag.setCspNonceReader(new StrutsCspNonceReader(CspNonceSource.SESSION.name())); } } diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/PasswordTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/PasswordTest.java index a17e0fdce0..ca12ff316e 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/PasswordTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/PasswordTest.java @@ -22,15 +22,14 @@ import org.apache.struts2.components.Password; import org.apache.struts2.components.UIBean; +import org.apache.struts2.interceptor.csp.CspNonceSource; +import org.apache.struts2.interceptor.csp.StrutsCspNonceReader; public class PasswordTest extends AbstractCommonAttributesTest { private Password tag; public void testRenderPassword() throws Exception { - super.setUp(); - this.tag = new Password(stack, request, response); - tag.setName("name"); tag.setValue("val1"); tag.setSize("10"); @@ -51,9 +50,6 @@ public void testRenderPassword() throws Exception { } public void testRenderPasswordShowIt() throws Exception { - super.setUp(); - this.tag = new Password(stack, request, response); - tag.setName("name"); tag.setValue("val1"); tag.setSize("10"); @@ -75,7 +71,9 @@ public void testRenderPasswordShowIt() throws Exception { @Override protected void setUp() throws Exception { - //dont call base setup + super.setUp(); + this.tag = new Password(stack, request, response); + this.tag.setCspNonceReader(new StrutsCspNonceReader(CspNonceSource.SESSION.name())); } @Override @@ -85,8 +83,6 @@ protected void setUpStack() { @Override protected UIBean getUIBean() throws Exception { - super.setUp(); - this.tag = new Password(stack, request, response); return tag; } diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ResetTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ResetTest.java index 9695e884f5..14464145f2 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ResetTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/ResetTest.java @@ -22,6 +22,8 @@ import org.apache.struts2.components.Reset; import org.apache.struts2.components.UIBean; +import org.apache.struts2.interceptor.csp.CspNonceSource; +import org.apache.struts2.interceptor.csp.StrutsCspNonceReader; public class ResetTest extends AbstractCommonAttributesTest { private Reset tag; @@ -69,6 +71,7 @@ public void testRenderResetNoType() { protected void setUp() throws Exception { super.setUp(); this.tag = new Reset(stack, request, response); + this.tag.setCspNonceReader(new StrutsCspNonceReader(CspNonceSource.SESSION.name())); } @Override 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 c0d93a629d..6e51f8a44d 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 @@ -21,6 +21,8 @@ import com.opensymphony.xwork2.security.DefaultNotExcludedAcceptedPatternsChecker; import org.apache.struts2.components.Script; import org.apache.struts2.components.UIBean; +import org.apache.struts2.interceptor.csp.CspNonceSource; +import org.apache.struts2.interceptor.csp.StrutsCspNonceReader; public class ScriptTest extends AbstractTest { @@ -72,5 +74,6 @@ protected void setUp() throws Exception { this.tag = new Script(stack, request, response); tag.setNotExcludedAcceptedPatterns(new DefaultNotExcludedAcceptedPatternsChecker()); + this.tag.setCspNonceReader(new StrutsCspNonceReader(CspNonceSource.SESSION.name())); } } diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/SelectTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/SelectTest.java index 4fa2a6ed72..441d4e1529 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/SelectTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/SelectTest.java @@ -22,6 +22,8 @@ import org.apache.struts2.components.Select; import org.apache.struts2.components.UIBean; +import org.apache.struts2.interceptor.csp.CspNonceSource; +import org.apache.struts2.interceptor.csp.StrutsCspNonceReader; import java.util.Arrays; import java.util.HashMap; @@ -114,6 +116,7 @@ protected String getTagName() { protected void setUp() throws Exception { super.setUp(); this.tag = new Select(stack, request, response); + this.tag.setCspNonceReader(new StrutsCspNonceReader(CspNonceSource.SESSION.name())); } @Override diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/SubmitTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/SubmitTest.java index 84f45c2d8b..4760bcc5c2 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/SubmitTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/SubmitTest.java @@ -22,6 +22,8 @@ import org.apache.struts2.components.Submit; import org.apache.struts2.components.UIBean; +import org.apache.struts2.interceptor.csp.CspNonceSource; +import org.apache.struts2.interceptor.csp.StrutsCspNonceReader; public class SubmitTest extends AbstractCommonAttributesTest { private Submit tag; @@ -154,6 +156,7 @@ public void testRenderButtonImageWithBody() { protected void setUp() throws Exception { super.setUp(); this.tag = new Submit(stack, request, response); + this.tag.setCspNonceReader(new StrutsCspNonceReader(CspNonceSource.SESSION.name())); } @Override diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TextAreaTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TextAreaTest.java index d72f42bcb5..08d08cabaf 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TextAreaTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TextAreaTest.java @@ -22,6 +22,8 @@ import org.apache.struts2.components.TextArea; import org.apache.struts2.components.UIBean; +import org.apache.struts2.interceptor.csp.CspNonceSource; +import org.apache.struts2.interceptor.csp.StrutsCspNonceReader; public class TextAreaTest extends AbstractCommonAttributesTest { private TextArea tag; @@ -71,6 +73,7 @@ public void testRenderTextAreaDefaults() { protected void setUp() throws Exception { super.setUp(); this.tag = new TextArea(stack, request, response); + this.tag.setCspNonceReader(new StrutsCspNonceReader(CspNonceSource.SESSION.name())); } @Override diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TextFieldTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TextFieldTest.java index 212a991ccb..331442f13c 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TextFieldTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TextFieldTest.java @@ -22,6 +22,8 @@ import org.apache.struts2.components.TextField; import org.apache.struts2.components.UIBean; +import org.apache.struts2.interceptor.csp.CspNonceSource; +import org.apache.struts2.interceptor.csp.StrutsCspNonceReader; public class TextFieldTest extends AbstractCommonAttributesTest { private TextField tag; @@ -52,6 +54,7 @@ public void testRenderTextField() { protected void setUp() throws Exception { super.setUp(); this.tag = new TextField(stack, request, response); + this.tag.setCspNonceReader(new StrutsCspNonceReader(CspNonceSource.SESSION.name())); } @Override diff --git a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TokenTest.java b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TokenTest.java index 7f7b3fbef9..c667e8b9fe 100644 --- a/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TokenTest.java +++ b/plugins/javatemplates/src/test/java/org/apache/struts2/views/java/simple/TokenTest.java @@ -23,6 +23,8 @@ import com.opensymphony.xwork2.ActionContext; import org.apache.struts2.components.Token; import org.apache.struts2.components.UIBean; +import org.apache.struts2.interceptor.csp.CspNonceSource; +import org.apache.struts2.interceptor.csp.StrutsCspNonceReader; import java.util.HashMap; import java.util.regex.Pattern; @@ -49,6 +51,7 @@ public void testRenderTokenTag() { protected void setUp() throws Exception { super.setUp(); this.tag = new Token(stack, request, response); + this.tag.setCspNonceReader(new StrutsCspNonceReader(CspNonceSource.SESSION.name())); ActionContext.of() .withSession(new HashMap<>())