mirror of
https://github.com/apache/struts.git
synced 2026-08-11 01:27:14 +00:00
Merge pull request #430 from salcho/post-ww-5083
WW-5084: Add Content Security Policy support to Struts
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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.action;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.apache.struts2.interceptor.csp.CspSettings.CSP_REPORT_TYPE;
|
||||
|
||||
/**
|
||||
* An abstract Action that can be extended to process the incoming CSP violation reports. Performs
|
||||
* necessary checks to extract the JSON string of the CSP report and make sure it's a valid report.
|
||||
* Always returns a 204 response.
|
||||
*
|
||||
* Override the <code>processReport(String jsonCspReport)</code> method to customize how the action processes
|
||||
* the CSP report. See {@link DefaultCspReportAction} for the default implementation.
|
||||
*
|
||||
* Add the action to the endpoint that is the <code>reportUri</code> in the {@link org.apache.struts2.interceptor.csp.CspInterceptor}
|
||||
* to collect the reports.
|
||||
*
|
||||
* <pre>
|
||||
* <package name="csp-reports" namespace="/" extends="struts-default">
|
||||
* <action name="csp-reports" class="org.apache.struts2.action.DefaultCspReportAction">
|
||||
* <result type="httpheader">
|
||||
* <param name="statusCode">200</param>
|
||||
* </result>
|
||||
* </action>
|
||||
* </package>
|
||||
* </pre>
|
||||
*
|
||||
* @see DefaultCspReportAction
|
||||
*/
|
||||
public abstract class CspReportAction extends ActionSupport implements ServletRequestAware, ServletResponseAware {
|
||||
private HttpServletRequest request;
|
||||
|
||||
@Override
|
||||
public void withServletRequest(HttpServletRequest request) {
|
||||
if (!isCspReportRequest(request)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
BufferedReader reader = request.getReader();
|
||||
String cspReport = reader.readLine();
|
||||
processReport(cspReport);
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isCspReportRequest(HttpServletRequest request) {
|
||||
if (!"POST".equals(request.getMethod()) || request.getContentLength() <= 0){
|
||||
return false;
|
||||
}
|
||||
|
||||
String contentType = request.getContentType();
|
||||
return CSP_REPORT_TYPE.equals(contentType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void withServletResponse(HttpServletResponse response) {
|
||||
response.setStatus(204);
|
||||
}
|
||||
|
||||
abstract void processReport(String jsonCspReport);
|
||||
|
||||
public void setServletRequest(HttpServletRequest request) {
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
public HttpServletRequest getServletRequest() {
|
||||
return request;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.action;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
/**
|
||||
* The default implementation of {@link CspReportAction} that simply logs the JSON object
|
||||
* that contains the details of the CSP violation.
|
||||
*
|
||||
* @see CspReportAction
|
||||
*/
|
||||
public class DefaultCspReportAction extends CspReportAction {
|
||||
|
||||
protected static final Logger LOG = LogManager.getLogger(DefaultCspReportAction.class);
|
||||
|
||||
@Override
|
||||
void processReport(String jsonCspReport) {
|
||||
LOG.error(jsonCspReport);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* 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.components;
|
||||
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import org.apache.struts2.views.annotations.StrutsTag;
|
||||
import org.apache.struts2.views.annotations.StrutsTagAttribute;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Add nonce propagation feature to implement CSP in link tags
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The link tag allows the user to load external resources, most usually style sheets. External resources
|
||||
* can inject malicious code and perform XSS and data injection attacks. The s:link tag includes a nonce
|
||||
* attribute that is being randomly generated with each request and only allows links with the valid
|
||||
* nonce value to be executed.
|
||||
* </p>
|
||||
*
|
||||
* <p><b>Examples</b></p>
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* <s:link ... />
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
@StrutsTag(name="link",
|
||||
tldTagClass="org.apache.struts2.views.jsp.ui.LinkTag",
|
||||
description="Link tag automatically adds nonces to link elements - should be used in combination with Struts' CSP Interceptor.",
|
||||
allowDynamicAttributes=true)
|
||||
public class Link extends UIBean{
|
||||
|
||||
private static final String TEMPLATE="link";
|
||||
|
||||
protected String href;
|
||||
protected String hreflang;
|
||||
protected String rel;
|
||||
protected String media;
|
||||
protected String referrerpolicy;
|
||||
protected String sizes;
|
||||
protected String crossorigin;
|
||||
protected String type;
|
||||
protected String as;
|
||||
|
||||
public Link(ValueStack stack, HttpServletRequest request, HttpServletResponse response) {
|
||||
super(stack, request, response);
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="HTML link href attribute")
|
||||
public void setHref(String href) {
|
||||
this.href = href;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="HTML link hreflang attribute")
|
||||
public void setHreflang(String hreflang) {
|
||||
this.hreflang = hreflang;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="HTML link rel attribute")
|
||||
public void setRel(String rel) {
|
||||
this.rel = rel;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="HTML link sizes attribute")
|
||||
public void setSizes(String sizes) {
|
||||
this.sizes = sizes;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="HTML link crossorigin attribute")
|
||||
public void setCrossorigin(String crossorigin) {
|
||||
this.crossorigin = crossorigin;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="HTML link type attribute")
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="HTML link as attribute")
|
||||
public void setAs(String as) {
|
||||
this.as = as;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="HTML link media attribute")
|
||||
public void setMedia(String media) {
|
||||
this.media = media;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="HTML link referrerpolicy attribute")
|
||||
public void setReferrerpolicy(String referrerpolicy) {
|
||||
this.referrerpolicy = referrerpolicy;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDefaultTemplate() {
|
||||
return TEMPLATE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void evaluateExtraParams() {
|
||||
super.evaluateExtraParams();
|
||||
|
||||
if (href != null) {
|
||||
addParameter("href", findString(href));
|
||||
}
|
||||
|
||||
if (hreflang != null) {
|
||||
addParameter("hreflang", findString(hreflang));
|
||||
}
|
||||
|
||||
if (rel != null) {
|
||||
addParameter("rel", findString(rel));
|
||||
}
|
||||
|
||||
if (media != null) {
|
||||
addParameter("media", findString(media));
|
||||
}
|
||||
|
||||
if (referrerpolicy != null) {
|
||||
addParameter("referrerpolicy", findString(referrerpolicy));
|
||||
}
|
||||
|
||||
if (sizes != null) {
|
||||
addParameter("sizes", findString(sizes));
|
||||
}
|
||||
|
||||
if (crossorigin != null) {
|
||||
addParameter("crossorigin", findString(crossorigin));
|
||||
}
|
||||
|
||||
if (type != null) {
|
||||
addParameter("type", findString(type));
|
||||
}
|
||||
|
||||
if (as != null) {
|
||||
addParameter("as", findString(as));
|
||||
}
|
||||
|
||||
if (disabled != null) {
|
||||
addParameter("disabled", findString(disabled));
|
||||
}
|
||||
|
||||
if (title != null) {
|
||||
addParameter("title", findString(title));
|
||||
}
|
||||
|
||||
if (stack.getActionContext().getSession().containsKey("nonce")) {
|
||||
String nonceValue = stack.getActionContext().getSession().get("nonce").toString();
|
||||
addParameter("nonce", nonceValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* 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.components;
|
||||
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import org.apache.struts2.views.annotations.StrutsTag;
|
||||
import org.apache.struts2.views.annotations.StrutsTagAttribute;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Add nonce propagation feature to implement CSP in script tags
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The script tag allows the user to execute JavaScript. It also allows external resources to execute
|
||||
* scripts which can be malicious. The s:script tag includes a nonce attribute that is being randomly
|
||||
* generated with each request and only allows scripts with the valid nonce value to be executed.
|
||||
* </p>
|
||||
*
|
||||
* <p><b>Examples</b></p>
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* <s:script ... />
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
*/
|
||||
@StrutsTag(name="script",
|
||||
tldTagClass="org.apache.struts2.views.jsp.ui.ScriptTag",
|
||||
description="Script tag automatically adds nonces to script blocks - should be used in combination with Struts' CSP Interceptor.",
|
||||
allowDynamicAttributes=true)
|
||||
public class Script extends ClosingUIBean {
|
||||
|
||||
protected String async;
|
||||
protected String charset;
|
||||
protected String defer;
|
||||
protected String src;
|
||||
protected String type;
|
||||
protected String referrerpolicy;
|
||||
protected String nomodule;
|
||||
protected String integrity;
|
||||
protected String crossorigin;
|
||||
|
||||
private static final String TEMPLATE = "script-close";
|
||||
private static final String OPEN_TEMPLATE = "script";
|
||||
|
||||
public Script(ValueStack stack, HttpServletRequest request, HttpServletResponse response) {
|
||||
super(stack, request, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultOpenTemplate() {
|
||||
return OPEN_TEMPLATE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDefaultTemplate() {
|
||||
return TEMPLATE;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="HTML script async attribute")
|
||||
public void setAsync(String async) {
|
||||
this.async = async;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="HTML script charset attribute")
|
||||
public void setCharset(String charset) {
|
||||
this.charset = charset;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="HTML script defer attribute")
|
||||
public void setDefer(String defer) {
|
||||
this.defer = defer;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="HTML script src attribute")
|
||||
public void setSrc(String src) {
|
||||
this.src = src;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="HTML script type attribute")
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="HTML script referrerpolicy attribute")
|
||||
public void setReferrerpolicy(String referrerpolicy) {
|
||||
this.referrerpolicy = referrerpolicy;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="HTML script nomodule attribute")
|
||||
public void setNomodule(String nomodule) {
|
||||
this.nomodule = nomodule;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="HTML script integrity attribute")
|
||||
public void setIntegrity(String integrity) {
|
||||
this.integrity = integrity;
|
||||
}
|
||||
|
||||
@StrutsTagAttribute(description="HTML script crossorigin attribute")
|
||||
public void setCrossorigin(String crossorigin) {
|
||||
this.crossorigin = crossorigin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean usesBody() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void evaluateExtraParams() {
|
||||
super.evaluateExtraParams();
|
||||
|
||||
if (async != null) {
|
||||
addParameter("async", findString(async));
|
||||
}
|
||||
|
||||
if (charset != null) {
|
||||
addParameter("charset", findString(charset));
|
||||
}
|
||||
|
||||
if (defer != null) {
|
||||
addParameter("defer", findString(defer));
|
||||
}
|
||||
|
||||
if (src != null) {
|
||||
addParameter("src", findString(src));
|
||||
}
|
||||
|
||||
if (type != null) {
|
||||
addParameter("type", findString(type));
|
||||
}
|
||||
|
||||
if (referrerpolicy != null) {
|
||||
addParameter("referrerpolicy", findString(referrerpolicy));
|
||||
}
|
||||
|
||||
if (nomodule != null) {
|
||||
addParameter("nomodule", findString(nomodule));
|
||||
}
|
||||
|
||||
if (integrity != null) {
|
||||
addParameter("integrity", findString(integrity));
|
||||
}
|
||||
|
||||
if (crossorigin != null) {
|
||||
addParameter("crossorigin", findString(crossorigin));
|
||||
}
|
||||
|
||||
if (stack.getActionContext().getSession().containsKey("nonce")) {
|
||||
String nonceValue = stack.getActionContext().getSession().get("nonce").toString();
|
||||
addParameter("nonce", nonceValue);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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.ActionInvocation;
|
||||
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
|
||||
import com.opensymphony.xwork2.interceptor.PreResultListener;
|
||||
import java.net.URI;
|
||||
import java.util.Optional;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* Interceptor that implements Content Security Policy on incoming requests used to protect against
|
||||
* common XSS and data injection attacks. Uses {@link CspSettings} to add appropriate Content Security Policy header
|
||||
* to the response. These headers determine what the browser will consider a policy violation and the browser's behavior
|
||||
* when a violation occurs. A detailed explanation of CSP can be found <a href="https://csp.withgoogle.com/docs/index.html">here</a>.
|
||||
*
|
||||
* @see <a href="https://csp.withgoogle.com/docs/index.html">https://csp.withgoogle.com/docs/index.html/</a>
|
||||
* @see CspSettings
|
||||
* @see DefaultCspSettings
|
||||
**/
|
||||
public final class CspInterceptor extends AbstractInterceptor implements PreResultListener {
|
||||
private final CspSettings settings = new DefaultCspSettings();
|
||||
|
||||
@Override
|
||||
public String intercept(ActionInvocation invocation) throws Exception {
|
||||
invocation.addPreResultListener(this);
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
public void beforeResult(ActionInvocation invocation, String resultCode) {
|
||||
HttpServletResponse response = invocation.getInvocationContext().getServletResponse();
|
||||
settings.addCspHeaders(response);
|
||||
}
|
||||
|
||||
public void setReportUri(String reportUri) {
|
||||
Optional<URI> uri = buildUri(reportUri);
|
||||
if (!uri.isPresent()) {
|
||||
throw new IllegalArgumentException("Could not parse configured report URI for CSP interceptor: " + reportUri);
|
||||
}
|
||||
|
||||
if (!uri.get().isAbsolute() && !reportUri.startsWith("/")) {
|
||||
throw new IllegalArgumentException("Illegal configuration: report URI is not relative to the root. Please set a report URI that starts with /");
|
||||
}
|
||||
|
||||
settings.setReportUri(reportUri);
|
||||
}
|
||||
|
||||
private Optional<URI> buildUri(String reportUri) {
|
||||
try {
|
||||
return Optional.of(URI.create(reportUri));
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public void setEnforcingMode(String value){
|
||||
boolean enforcingMode = Boolean.parseBoolean(value);
|
||||
settings.setEnforcingMode(enforcingMode);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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 javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* CspSettings interface used by the {@link CspInterceptor} to add the CSP header to the response.
|
||||
* The default implementation can be found in {@link DefaultCspSettings}.
|
||||
*
|
||||
* @see DefaultCspSettings
|
||||
*/
|
||||
public interface CspSettings {
|
||||
|
||||
int NONCE_RANDOM_LENGTH = 18;
|
||||
|
||||
String CSP_ENFORCE_HEADER = "Content-Security-Policy";
|
||||
String CSP_REPORT_HEADER = "Content-Security-Policy-Report-Only";
|
||||
String OBJECT_SRC = "object-src";
|
||||
String SCRIPT_SRC = "script-src";
|
||||
String BASE_URI = "base-uri";
|
||||
String REPORT_URI = "report-uri";
|
||||
String NONE = "none";
|
||||
String STRICT_DYNAMIC = "strict-dynamic";
|
||||
String HTTP = "http:";
|
||||
String HTTPS = "https:";
|
||||
String CSP_REPORT_TYPE = "application/csp-report";
|
||||
|
||||
void addCspHeaders(HttpServletResponse response);
|
||||
// sets the uri where csp violation reports will be sent
|
||||
void setReportUri(String uri);
|
||||
// sets CSP headers in enforcing mode when true, and report-only when false
|
||||
void setEnforcingMode(boolean value);
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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 static java.lang.String.format;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Base64;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* Default implementation of {@link CspSettings}.
|
||||
* The default policy implements strict CSP with a nonce based approach and follows the guide: <a href="https://csp.withgoogle.com/docs/index.html">https://csp.withgoogle.com/docs/index.html/</a>
|
||||
*
|
||||
* @see CspSettings
|
||||
* @see CspInterceptor
|
||||
*/
|
||||
public class DefaultCspSettings implements CspSettings {
|
||||
private final SecureRandom sRand = new SecureRandom();
|
||||
// this lazy supplier computes a policy format the first time it's called and caches the result
|
||||
// to reduce string operations when attaching policies to HTTP responses
|
||||
private final Supplier<String> lazyPolicyBuilder = new Supplier<String>() {
|
||||
boolean hasBeenCalled;
|
||||
String policyFormat;
|
||||
|
||||
@Override
|
||||
public String get() {
|
||||
if (!hasBeenCalled) {
|
||||
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));
|
||||
|
||||
if (reportUri != null) {
|
||||
policyFormatBuilder
|
||||
.append(REPORT_URI)
|
||||
.append(format(" %s", reportUri));
|
||||
}
|
||||
|
||||
policyFormat = policyFormatBuilder.toString();
|
||||
}
|
||||
|
||||
return format(policyFormat, getNonceString());
|
||||
}
|
||||
};
|
||||
|
||||
private String reportUri;
|
||||
// default to reporting mode
|
||||
private String cspHeader = CSP_REPORT_HEADER;
|
||||
|
||||
public void addCspHeaders(HttpServletResponse response) {
|
||||
associateNonceWithSession();
|
||||
response.setHeader(cspHeader, lazyPolicyBuilder.get());
|
||||
}
|
||||
|
||||
private String getNonceString() {
|
||||
Map<String, Object> session = ActionContext.getContext().getSession();
|
||||
return (String) session.get("nonce");
|
||||
}
|
||||
|
||||
private void associateNonceWithSession() {
|
||||
Map<String, Object> session = ActionContext.getContext().getSession();
|
||||
String nonceValue = Base64.getUrlEncoder().encodeToString(getRandomBytes());
|
||||
session.put("nonce", nonceValue);
|
||||
}
|
||||
|
||||
private byte[] getRandomBytes() {
|
||||
byte[] ret = new byte[NONCE_RANDOM_LENGTH];
|
||||
sRand.nextBytes(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void setEnforcingMode(boolean enforcingMode) {
|
||||
if (enforcingMode) {
|
||||
cspHeader = CSP_ENFORCE_HEADER;
|
||||
}
|
||||
}
|
||||
|
||||
public void setReportUri(String reportUri) {
|
||||
this.reportUri = reportUri;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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.views.jsp.ui;
|
||||
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import org.apache.struts2.components.Component;
|
||||
import org.apache.struts2.components.Link;
|
||||
import org.apache.struts2.components.Script;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* @see Link
|
||||
*/
|
||||
public class LinkTag extends AbstractUITag {
|
||||
|
||||
protected String href;
|
||||
protected String hreflang;
|
||||
protected String rel;
|
||||
protected String media;
|
||||
protected String referrerpolicy;
|
||||
protected String sizes;
|
||||
protected String crossorigin;
|
||||
protected String type;
|
||||
protected String as;
|
||||
|
||||
@Override
|
||||
public Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res) {
|
||||
return new Link(stack, req, res);
|
||||
}
|
||||
|
||||
protected void populateParams() {
|
||||
super.populateParams();
|
||||
Link link = ((Link) component);
|
||||
link.setHref(href);
|
||||
link.setHreflang(hreflang);
|
||||
link.setRel(rel);
|
||||
link.setDisabled(disabled);
|
||||
link.setMedia(media);
|
||||
link.setReferrerpolicy(referrerpolicy);
|
||||
link.setSizes(sizes);
|
||||
link.setCrossorigin(crossorigin);
|
||||
link.setType(type);
|
||||
link.setAs(as);
|
||||
link.setTitle(title);
|
||||
}
|
||||
|
||||
public void setHref(String href) {
|
||||
this.href = href;
|
||||
}
|
||||
|
||||
public void setHreflang(String hreflang) {
|
||||
this.hreflang = hreflang;
|
||||
}
|
||||
|
||||
public void setRel(String rel) {
|
||||
this.rel = rel;
|
||||
}
|
||||
|
||||
public void setSizes(String sizes) {
|
||||
this.sizes = sizes;
|
||||
}
|
||||
|
||||
public void setCrossorigin(String crossorigin) {
|
||||
this.crossorigin = crossorigin;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public void setAs(String as) {
|
||||
this.as = as;
|
||||
}
|
||||
|
||||
public void setMedia(String media) {
|
||||
this.media = media;
|
||||
}
|
||||
|
||||
public void setReferrerpolicy(String referrerpolicy) {
|
||||
this.referrerpolicy = referrerpolicy;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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.views.jsp.ui;
|
||||
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import org.apache.struts2.components.Component;
|
||||
import org.apache.struts2.components.Form;
|
||||
import org.apache.struts2.components.Script;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* @see Script
|
||||
*/
|
||||
public class ScriptTag extends AbstractUITag {
|
||||
|
||||
protected String async;
|
||||
protected String charset;
|
||||
protected String defer;
|
||||
protected String src;
|
||||
protected String type;
|
||||
protected String referrerpolicy;
|
||||
protected String nomodule;
|
||||
protected String integrity;
|
||||
protected String crossorigin;
|
||||
|
||||
@Override
|
||||
public Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res) {
|
||||
return new Script(stack, req, res);
|
||||
}
|
||||
|
||||
protected void populateParams() {
|
||||
super.populateParams();
|
||||
Script script = ((Script) component);
|
||||
script.setAsync(async);
|
||||
script.setCharset(charset);
|
||||
script.setDefer(defer);
|
||||
script.setSrc(src);
|
||||
script.setType(type);
|
||||
script.setReferrerpolicy(referrerpolicy);
|
||||
script.setNomodule(nomodule);
|
||||
script.setIntegrity(integrity);
|
||||
script.setCrossorigin(crossorigin);
|
||||
}
|
||||
|
||||
public void setAsync(String async) {
|
||||
this.async = async;
|
||||
}
|
||||
|
||||
public void setCharset(String charset) {
|
||||
this.charset = charset;
|
||||
}
|
||||
|
||||
public void setSrc(String src) {
|
||||
this.src = src;
|
||||
}
|
||||
|
||||
public void setDefer(String defer) {
|
||||
this.defer = defer;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public void setReferrerpolicy(String referrerpolicy) {
|
||||
this.referrerpolicy = referrerpolicy;
|
||||
}
|
||||
|
||||
public void setNomodule(String nomodule) {
|
||||
this.nomodule = nomodule;
|
||||
}
|
||||
|
||||
public void setIntegrity(String integrity) {
|
||||
this.integrity = integrity;
|
||||
}
|
||||
|
||||
public void setCrossorigin(String crossorigin) {
|
||||
this.crossorigin = crossorigin;
|
||||
}
|
||||
}
|
||||
@@ -248,6 +248,7 @@
|
||||
<interceptor name="clearSession" class="org.apache.struts2.interceptor.ClearSessionInterceptor" />
|
||||
<interceptor name="coopInterceptor" class="org.apache.struts2.interceptor.CoopInterceptor"/>
|
||||
<interceptor name="createSession" class="org.apache.struts2.interceptor.CreateSessionInterceptor" />
|
||||
<interceptor name="cspInterceptor" class="org.apache.struts2.interceptor.csp.CspInterceptor"/>
|
||||
<interceptor name="debugging" class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor" />
|
||||
<interceptor name="execAndWait" class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor"/>
|
||||
<interceptor name="exception" class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/>
|
||||
@@ -379,6 +380,9 @@
|
||||
<interceptor-ref name="alias"/>
|
||||
<interceptor-ref name="servletConfig"/>
|
||||
<interceptor-ref name="i18n"/>
|
||||
<interceptor-ref name="cspInterceptor">
|
||||
<param name="enforcingMode">false</param>
|
||||
</interceptor-ref>
|
||||
<interceptor-ref name="prepare"/>
|
||||
<interceptor-ref name="chain"/>
|
||||
<interceptor-ref name="scopedModelDriven"/>
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
<#--
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
-->
|
||||
<#include "/${parameters.templateDir}/${parameters.expandTheme}/common-attributes.ftl" />
|
||||
<#include "/${parameters.templateDir}/${parameters.expandTheme}/dynamic-attributes.ftl" />
|
||||
<link nonce="${parameters.nonce}"<#rt/>
|
||||
<#if parameters.href?has_content>
|
||||
href="${parameters.href}"<#rt/>
|
||||
</#if>
|
||||
<#if parameters.hreflang?has_content>
|
||||
hreflang="${parameters.hreflang}"<#rt/>
|
||||
</#if>
|
||||
<#if parameters.rel?has_content>
|
||||
rel="${parameters.rel}"<#rt/>
|
||||
</#if>
|
||||
<#if parameters.disabled?has_content>
|
||||
<#if parameters.disabled=="true">
|
||||
disabled<#rt/>
|
||||
</#if>
|
||||
</#if>
|
||||
<#if parameters.media?has_content>
|
||||
media="${parameters.media}"<#rt/>
|
||||
</#if>
|
||||
<#if parameters.type?has_content>
|
||||
type="${parameters.type}"<#rt/>
|
||||
</#if>
|
||||
<#if parameters.title?has_content>
|
||||
title="${parameters.title}"<#rt/>
|
||||
</#if>
|
||||
<#if parameters.as?has_content>
|
||||
as="${parameters.as}"<#rt/>
|
||||
</#if>
|
||||
<#if parameters.referrerpolicy?has_content>
|
||||
referrerpolicy="${parameters.referrerpolicy}"<#rt/>
|
||||
</#if>
|
||||
<#if parameters.sizes?has_content>
|
||||
sizes="${parameters.sizes}"<#rt/>
|
||||
</#if>
|
||||
<#if parameters.crossorigin?has_content>
|
||||
crossorigin="${parameters.crossorigin}"<#rt/>
|
||||
</#if>
|
||||
<#if parameters.integrity?has_content>
|
||||
integrity="${parameters.integrity}"<#rt/>
|
||||
</#if>
|
||||
<#if parameters.importance?has_content>
|
||||
importance="${parameters.importance}"<#rt/>
|
||||
</#if>
|
||||
>
|
||||
@@ -0,0 +1,21 @@
|
||||
<#--
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
-->
|
||||
</script>
|
||||
@@ -0,0 +1,63 @@
|
||||
<#--
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
-->
|
||||
<#include "/${parameters.templateDir}/${parameters.expandTheme}/common-attributes.ftl" />
|
||||
<#include "/${parameters.templateDir}/${parameters.expandTheme}/dynamic-attributes.ftl" />
|
||||
<script <#rt/>
|
||||
<#if parameters.nonce?has_content>
|
||||
nonce="${parameters.nonce}"<#rt/>
|
||||
</#if>
|
||||
<#if parameters.async?has_content>
|
||||
<#if parameters.async=="true">
|
||||
async<#rt/>
|
||||
</#if>
|
||||
</#if>
|
||||
<#if parameters.charset?has_content>
|
||||
charset="${parameters.charset}"<#rt/>
|
||||
</#if>
|
||||
<#if parameters.defer?has_content>
|
||||
<#if parameters.defer=="true">
|
||||
defer<#rt/>
|
||||
</#if>
|
||||
</#if>
|
||||
<#if parameters.src?has_content>
|
||||
src="${parameters.src}"<#rt/>
|
||||
</#if>
|
||||
<#if parameters.type?has_content>
|
||||
type="${parameters.type}"<#rt/>
|
||||
</#if>
|
||||
<#if parameters.name?has_content>
|
||||
name="${parameters.name}"<#rt/>
|
||||
</#if>
|
||||
<#if parameters.referrerpolicy?has_content>
|
||||
referrerpolicy="${parameters.referrerpolicy}"<#rt/>
|
||||
</#if>
|
||||
<#if parameters.nomodule?has_content>
|
||||
<#if parameters.nomodule=="true">
|
||||
nomodule<#rt/>
|
||||
</#if>
|
||||
</#if>
|
||||
<#if parameters.integrity?has_content>
|
||||
integrity="${parameters.integrity}"<#rt/>
|
||||
</#if>
|
||||
<#if parameters.crossorigin?has_content>
|
||||
crossorigin="${parameters.crossorigin}"<#rt/>
|
||||
</#if>
|
||||
>
|
||||
@@ -0,0 +1,21 @@
|
||||
<#--
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
-->
|
||||
<#include "/${parameters.templateDir}/simple/link.ftl" />
|
||||
@@ -0,0 +1,21 @@
|
||||
<#--
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
-->
|
||||
<#include "/${parameters.templateDir}/simple/script.ftl" />
|
||||
@@ -0,0 +1,432 @@
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td colspan="6"><h4>Dynamic Attributes Allowed:</h4> true</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="6"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th align="left" valign="top"><h4>Name</h4></th>
|
||||
<th align="left" valign="top"><h4>Required</h4></th>
|
||||
<th align="left" valign="top"><h4>Default</h4></th>
|
||||
<th align="left" valign="top"><h4>Evaluated</h4></th>
|
||||
<th align="left" valign="top"><h4>Type</h4></th>
|
||||
<th align="left" valign="top"><h4>Description</h4></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">accesskey</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html accesskey attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">as</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">HTML link as attribute</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">class</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">The css class to use for element - it's an alias of cssClass attribute.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">crossorigin</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">HTML link crossorigin attribute</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">cssClass</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">The css class to use for element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">cssErrorClass</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">The css error class to use for element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">cssErrorStyle</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">The css error style definitions for element to use</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">cssStyle</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">The css style definitions for element to use</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">disabled</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html disabled attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">errorPosition</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Define error position of form element (top|bottom)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">href</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">HTML link href attribute</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">hreflang</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">HTML link hreflang attribute</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">id</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">HTML id attribute</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">javascriptTooltip</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">Boolean</td>
|
||||
<td align="left" valign="top">Use JavaScript to generate tooltips</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">key</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the key (name, value, label) for this particular component</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">label</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Label expression used for rendering an element specific label</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">labelSeparator</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">:</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">String that will be appended to the label</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">labelposition</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Define label position of form element (top/left)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">media</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">HTML link media attribute</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">name</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">The name to set for element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">onblur</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top"> Set the html onblur attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">onchange</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html onchange attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">onclick</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html onclick attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">ondblclick</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html ondblclick attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">onfocus</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html onfocus attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">onkeydown</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html onkeydown attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">onkeypress</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html onkeypress attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">onkeyup</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html onkeyup attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">onmousedown</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html onmousedown attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">onmousemove</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html onmousemove attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">onmouseout</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html onmouseout attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">onmouseover</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html onmouseover attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">onmouseup</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html onmouseup attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">onselect</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html onselect attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">referrerpolicy</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">HTML link referrerpolicy attribute</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">rel</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">HTML link rel attribute</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">requiredLabel</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">Boolean</td>
|
||||
<td align="left" valign="top">If set to true, the rendered element will indicate that input is required</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">requiredPosition</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Define required position of required form element (left|right)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">sizes</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">HTML link sizes attribute</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">style</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">The css style definitions for element to use - it's an alias of cssStyle attribute.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">tabindex</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html tabindex attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">template</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">The template (other than default) to use for rendering the element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">templateDir</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">The template directory.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">theme</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">The theme (other than default) to use for rendering the element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">title</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html title attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">tooltip</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the tooltip of this particular component</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">tooltipConfig</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Deprecated. Use individual tooltip configuration attributes instead.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">tooltipCssClass</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">StrutsTTClassic</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">CSS class applied to JavaScrip tooltips</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">tooltipDelay</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">Classic</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Delay in milliseconds, before showing JavaScript tooltips </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">tooltipIconPath</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Icon path used for image that will have the tooltip</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">type</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">HTML link type attribute</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">value</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Preset the value of input element.</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -0,0 +1 @@
|
||||
Link tag automatically adds nonces to link elements - should be used in combination with Struts' CSP Interceptor.
|
||||
@@ -0,0 +1,440 @@
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td colspan="6"><h4>Dynamic Attributes Allowed:</h4> true</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="6"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th align="left" valign="top"><h4>Name</h4></th>
|
||||
<th align="left" valign="top"><h4>Required</h4></th>
|
||||
<th align="left" valign="top"><h4>Default</h4></th>
|
||||
<th align="left" valign="top"><h4>Evaluated</h4></th>
|
||||
<th align="left" valign="top"><h4>Type</h4></th>
|
||||
<th align="left" valign="top"><h4>Description</h4></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">accesskey</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html accesskey attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">async</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">HTML script async attribute</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">charset</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">HTML script charset attribute</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">class</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">The css class to use for element - it's an alias of cssClass attribute.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">crossorigin</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">HTML script crossorigin attribute</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">cssClass</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">The css class to use for element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">cssErrorClass</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">The css error class to use for element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">cssErrorStyle</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">The css error style definitions for element to use</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">cssStyle</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">The css style definitions for element to use</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">defer</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">HTML script defer attribute</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">disabled</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html disabled attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">errorPosition</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Define error position of form element (top|bottom)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">id</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">HTML id attribute</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">integrity</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">HTML script integrity attribute</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">javascriptTooltip</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">Boolean</td>
|
||||
<td align="left" valign="top">Use JavaScript to generate tooltips</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">key</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the key (name, value, label) for this particular component</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">label</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Label expression used for rendering an element specific label</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">labelSeparator</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">:</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">String that will be appended to the label</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">labelposition</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Define label position of form element (top/left)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">name</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">The name to set for element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">nomodule</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">HTML script nomodule attribute</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">onblur</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top"> Set the html onblur attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">onchange</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html onchange attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">onclick</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html onclick attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">ondblclick</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html ondblclick attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">onfocus</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html onfocus attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">onkeydown</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html onkeydown attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">onkeypress</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html onkeypress attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">onkeyup</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html onkeyup attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">onmousedown</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html onmousedown attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">onmousemove</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html onmousemove attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">onmouseout</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html onmouseout attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">onmouseover</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html onmouseover attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">onmouseup</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html onmouseup attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">onselect</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html onselect attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">openTemplate</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set template to use for opening the rendered html.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">referrerpolicy</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">HTML script referrerpolicy attribute</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">requiredLabel</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">Boolean</td>
|
||||
<td align="left" valign="top">If set to true, the rendered element will indicate that input is required</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">requiredPosition</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Define required position of required form element (left|right)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">src</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">HTML script src attribute</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">style</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">The css style definitions for element to use - it's an alias of cssStyle attribute.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">tabindex</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html tabindex attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">template</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">The template (other than default) to use for rendering the element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">templateDir</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">The template directory.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">theme</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">The theme (other than default) to use for rendering the element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">title</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the html title attribute on rendered html element</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">tooltip</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Set the tooltip of this particular component</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">tooltipConfig</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Deprecated. Use individual tooltip configuration attributes instead.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">tooltipCssClass</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">StrutsTTClassic</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">CSS class applied to JavaScrip tooltips</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">tooltipDelay</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">Classic</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Delay in milliseconds, before showing JavaScript tooltips </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">tooltipIconPath</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Icon path used for image that will have the tooltip</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">type</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">HTML script type attribute</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">value</td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top"></td>
|
||||
<td align="left" valign="top">false</td>
|
||||
<td align="left" valign="top">String</td>
|
||||
<td align="left" valign="top">Preset the value of input element.</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -0,0 +1 @@
|
||||
Script tag automatically adds nonces to script blocks - should be used in combination with Struts' CSP Interceptor.
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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.action;
|
||||
|
||||
import com.opensymphony.xwork2.XWorkTestCase;
|
||||
import org.apache.struts2.interceptor.csp.CspSettings;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
|
||||
public class CspReportActionTest extends XWorkTestCase {
|
||||
public void testWhenMethodNotPost_thenReportNotProcessed() {
|
||||
for (HttpMethod method : HttpMethod.values()) {
|
||||
TestCspReportAction cspReportAction = new TestCspReportAction();
|
||||
|
||||
// only expect a report if the method is post
|
||||
int expectedReports = method == HttpMethod.POST ? 1 : 0;
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(method.toString(), "/requestUri");
|
||||
request.setContent("someSampleContent".getBytes());
|
||||
request.setContentType(CspSettings.CSP_REPORT_TYPE);
|
||||
|
||||
cspReportAction.withServletRequest(request);
|
||||
|
||||
assertEquals(
|
||||
"Unexpected behaviour with method " + method,
|
||||
expectedReports,
|
||||
cspReportAction.actualNumberOfReports
|
||||
);
|
||||
|
||||
assertCorrectResponseStatusCode(cspReportAction);
|
||||
}
|
||||
}
|
||||
|
||||
public void testWhenNoContentLength_thenReportNotProcessed() {
|
||||
TestCspReportAction cspReportAction = new TestCspReportAction();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/requestUri");
|
||||
request.setContentType(CspSettings.CSP_REPORT_TYPE);
|
||||
|
||||
cspReportAction.withServletRequest(request);
|
||||
|
||||
assertEquals(
|
||||
"Report request with empty body should not be processed",
|
||||
0,
|
||||
cspReportAction.actualNumberOfReports
|
||||
);
|
||||
|
||||
assertCorrectResponseStatusCode(cspReportAction);
|
||||
}
|
||||
|
||||
public void testWhenContentTypeNotCsp_thenReportNotProcessed() {
|
||||
TestCspReportAction cspReportAction = new TestCspReportAction();
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/requestUri");
|
||||
request.setContent("someSampleContent".getBytes());
|
||||
request.setContentType("application/json");
|
||||
|
||||
cspReportAction.withServletRequest(request);
|
||||
|
||||
assertEquals(
|
||||
"Report request with wrong content type should not be processed",
|
||||
0,
|
||||
cspReportAction.actualNumberOfReports
|
||||
);
|
||||
|
||||
assertCorrectResponseStatusCode(cspReportAction);
|
||||
}
|
||||
|
||||
public void testWhenValidReportRequest_thenReportProcessed() {
|
||||
TestCspReportAction cspReportAction = new TestCspReportAction();
|
||||
String sampleReport = "someSampleContent";
|
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/requestUri");
|
||||
request.setContent(sampleReport.getBytes());
|
||||
request.setContentType(CspSettings.CSP_REPORT_TYPE);
|
||||
|
||||
cspReportAction.withServletRequest(request);
|
||||
|
||||
assertEquals(
|
||||
"Valid report request was not processed",
|
||||
1,
|
||||
cspReportAction.actualNumberOfReports
|
||||
);
|
||||
|
||||
assertEquals(
|
||||
"Processed report body did not match",
|
||||
sampleReport,
|
||||
cspReportAction.actualReport
|
||||
);
|
||||
|
||||
assertCorrectResponseStatusCode(cspReportAction);
|
||||
}
|
||||
|
||||
private void assertCorrectResponseStatusCode(TestCspReportAction cspReportAction) {
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
cspReportAction.withServletResponse(response);
|
||||
|
||||
assertEquals(
|
||||
"Unexpected response status code: " + response.getStatus(),
|
||||
204,
|
||||
response.getStatus()
|
||||
);
|
||||
}
|
||||
|
||||
static class TestCspReportAction extends CspReportAction {
|
||||
int actualNumberOfReports;
|
||||
String actualReport;
|
||||
|
||||
@Override
|
||||
void processReport(String jsonCspReport) {
|
||||
actualNumberOfReports++;
|
||||
actualReport = jsonCspReport;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.mock.MockActionInvocation;
|
||||
import org.apache.logging.log4j.util.Strings;
|
||||
import org.apache.struts2.ServletActionContext;
|
||||
import org.apache.struts2.StrutsInternalTestCase;
|
||||
import org.apache.struts2.interceptor.csp.CspInterceptor;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.apache.struts2.interceptor.csp.CspSettings.*;
|
||||
|
||||
public class CspInterceptorTest extends StrutsInternalTestCase {
|
||||
|
||||
private final CspInterceptor interceptor = new CspInterceptor();
|
||||
private final MockActionInvocation mai = new MockActionInvocation();
|
||||
private final MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
private final MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
private final Map<String, Object> session = new HashMap<>();
|
||||
|
||||
public void test_whenRequestReceived_thenNonceIsSetInSession_andCspHeaderContainsIt() throws Exception {
|
||||
String reportUri = "/barfoo";
|
||||
String reporting = "false";
|
||||
interceptor.setReportUri(reportUri);
|
||||
interceptor.setEnforcingMode(reporting);
|
||||
|
||||
interceptor.intercept(mai);
|
||||
|
||||
assertTrue("Nonce key does not exist", session.containsKey("nonce"));
|
||||
assertFalse("Nonce value is empty", Strings.isEmpty((String) session.get("nonce")));
|
||||
checkHeader(reportUri, reporting);
|
||||
}
|
||||
|
||||
public void test_whenNonceAlreadySetInSession_andRequestReceived_thenNewNonceIsSet() throws Exception {
|
||||
String reportUri = "https://www.google.com/";
|
||||
String enforcingMode = "true";
|
||||
interceptor.setReportUri(reportUri);
|
||||
interceptor.setEnforcingMode(enforcingMode);
|
||||
session.put("nonce", "foo");
|
||||
|
||||
interceptor.intercept(mai);
|
||||
|
||||
assertTrue("Nonce key does not exist", session.containsKey("nonce"));
|
||||
assertFalse("Nonce value is empty", Strings.isEmpty((String) session.get("nonce")));
|
||||
assertFalse("New nonce value couldn't be set", session.get("nonce").equals("foo"));
|
||||
checkHeader(reportUri, enforcingMode);
|
||||
}
|
||||
|
||||
public void testEnforcingCspHeadersSet() throws Exception {
|
||||
String reportUri = "/csp-reports";
|
||||
String enforcingMode = "true";
|
||||
interceptor.setReportUri(reportUri);
|
||||
interceptor.setEnforcingMode(enforcingMode);
|
||||
session.put("nonce", "foo");
|
||||
|
||||
interceptor.intercept(mai);
|
||||
|
||||
assertTrue("Nonce key does not exist", session.containsKey("nonce"));
|
||||
assertFalse("Nonce value is empty", Strings.isEmpty((String) session.get("nonce")));
|
||||
assertFalse("New nonce value couldn't be set", session.get("nonce").equals("foo"));
|
||||
checkHeader(reportUri, enforcingMode);
|
||||
}
|
||||
|
||||
public void testReportingCspHeadersSet() throws Exception {
|
||||
String reportUri = "/csp-reports";
|
||||
String enforcingMode = "false";
|
||||
interceptor.setReportUri(reportUri);
|
||||
interceptor.setEnforcingMode(enforcingMode);
|
||||
session.put("nonce", "foo");
|
||||
|
||||
interceptor.intercept(mai);
|
||||
|
||||
assertTrue("Nonce key does not exist", session.containsKey("nonce"));
|
||||
assertFalse("Nonce value is empty", Strings.isEmpty((String) session.get("nonce")));
|
||||
assertFalse("New nonce value couldn't be set", session.get("nonce").equals("foo"));
|
||||
checkHeader(reportUri, enforcingMode);
|
||||
}
|
||||
|
||||
public void test_uriSetOnlyWhenSetIsCalled() throws Exception {
|
||||
String enforcingMode = "false";
|
||||
interceptor.setEnforcingMode(enforcingMode);
|
||||
|
||||
interceptor.intercept(mai);
|
||||
checkHeader(null, enforcingMode);
|
||||
|
||||
// set report uri
|
||||
String reportUri = "/some-uri";
|
||||
interceptor.setReportUri(reportUri);
|
||||
interceptor.intercept(mai);
|
||||
checkHeader(reportUri, enforcingMode);
|
||||
}
|
||||
|
||||
public void testCannotParseUri() throws Exception {
|
||||
String enforcingMode = "false";
|
||||
interceptor.setEnforcingMode(enforcingMode);
|
||||
|
||||
try{
|
||||
interceptor.setReportUri("ww w. google.@com");
|
||||
assert(false);
|
||||
} catch (IllegalArgumentException e){
|
||||
assert(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void testCannotParseRelativeUri() throws Exception {
|
||||
String enforcingMode = "false";
|
||||
interceptor.setEnforcingMode(enforcingMode);
|
||||
|
||||
try{
|
||||
interceptor.setReportUri("some-uri");
|
||||
assert(false);
|
||||
} catch (IllegalArgumentException e){
|
||||
assert(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void checkHeader(String reportUri, String enforcingMode){
|
||||
String expectedCspHeader = "";
|
||||
if (Strings.isEmpty(reportUri)) {
|
||||
expectedCspHeader = String.format("%s '%s'; %s 'nonce-%s' '%s' %s %s; %s '%s'; ",
|
||||
OBJECT_SRC, NONE,
|
||||
SCRIPT_SRC, session.get("nonce"), STRICT_DYNAMIC, HTTP, HTTPS,
|
||||
BASE_URI, NONE
|
||||
);
|
||||
} else {
|
||||
expectedCspHeader = String.format("%s '%s'; %s 'nonce-%s' '%s' %s %s; %s '%s'; %s %s",
|
||||
OBJECT_SRC, NONE,
|
||||
SCRIPT_SRC, session.get("nonce"), STRICT_DYNAMIC, HTTP, HTTPS,
|
||||
BASE_URI, NONE,
|
||||
REPORT_URI, reportUri
|
||||
);
|
||||
}
|
||||
|
||||
String header = "";
|
||||
if (enforcingMode.equals("true")){
|
||||
header = response.getHeader(CSP_ENFORCE_HEADER);
|
||||
} else {
|
||||
header = response.getHeader(CSP_REPORT_HEADER);
|
||||
}
|
||||
|
||||
assertFalse("No CSP header exists", Strings.isEmpty(header));
|
||||
assertEquals("Response headers do not contain nonce header", expectedCspHeader, header);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
container.inject(interceptor);
|
||||
ServletActionContext.setRequest(request);
|
||||
ServletActionContext.setResponse(response);
|
||||
ActionContext context = ServletActionContext.getActionContext().bind();
|
||||
context.withSession(session);
|
||||
mai.setInvocationContext(context);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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.views.jsp.ui;
|
||||
|
||||
import org.apache.struts2.views.jsp.AbstractUITagTest;
|
||||
|
||||
import javax.servlet.jsp.JspException;
|
||||
|
||||
public class LinkTagTest extends AbstractUITagTest {
|
||||
|
||||
private static final String NONCE_VAL = "r4andom";
|
||||
|
||||
public void testLinkTagAttributes() {
|
||||
LinkTag tag = new LinkTag();
|
||||
|
||||
tag.setHref("mysrc.js");
|
||||
tag.setHreflang("test");
|
||||
tag.setRel("module");
|
||||
tag.setMedia("foo");
|
||||
tag.setReferrerpolicy("test");
|
||||
tag.setSizes("foo");
|
||||
tag.setCrossorigin("same-origin");
|
||||
tag.setType("anonymous");
|
||||
tag.setAs("test");
|
||||
tag.setDisabled("false");
|
||||
tag.setTitle("test");
|
||||
|
||||
doLinkTest(tag);
|
||||
String s = writer.toString();
|
||||
|
||||
assertTrue("Incorrect href attribute for link tag", s.contains("href=\"mysrc.js\""));
|
||||
assertTrue("Incorrect hreflang attribute for link tag", s.contains("hreflang=\"test\""));
|
||||
assertTrue("Incorrect rel attribute for link tag", s.contains("rel=\"module\""));
|
||||
assertTrue("Incorrect media attribute for link tag", s.contains("media=\"foo\""));
|
||||
assertTrue("Incorrect referrerpolicy attribute for link tag", s.contains("referrerpolicy=\"test\""));
|
||||
assertTrue("Incorrect sizes attribute for link tag", s.contains("sizes=\"foo\""));
|
||||
assertTrue("Incorrect crossorigin attribute for link tag", s.contains("crossorigin=\"same-origin\""));
|
||||
assertTrue("Incorrect type attribute for link tag", s.contains("type=\"anonymous\""));
|
||||
assertTrue("Incorrect as attribute for link tag", s.contains("as=\"test\""));
|
||||
assertFalse("Non-existent disabled attribute for link tag", s.contains("disabled"));
|
||||
assertTrue("Incorrect title attribute for link tag", s.contains("title=\"test\""));
|
||||
assertTrue("Incorrect nonce attribute for link tag", s.contains("nonce=\"" + NONCE_VAL+"\""));
|
||||
}
|
||||
|
||||
private void doLinkTest(LinkTag tag) {
|
||||
//creating nonce value like the CspInterceptor does
|
||||
stack.getActionContext().getSession().put("nonce", NONCE_VAL);
|
||||
tag.setPageContext(pageContext);
|
||||
|
||||
try {
|
||||
tag.doStartTag();
|
||||
tag.doEndTag();
|
||||
} catch (JspException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.views.jsp.ui;
|
||||
|
||||
|
||||
import org.apache.struts2.views.jsp.AbstractUITagTest;
|
||||
|
||||
import javax.servlet.jsp.JspException;
|
||||
|
||||
public class ScriptTagTest extends AbstractUITagTest {
|
||||
|
||||
private static final String NONCE_VAL = "r4andom";
|
||||
|
||||
public void testScriptTagAttributes() {
|
||||
ScriptTag tag = new ScriptTag();
|
||||
|
||||
|
||||
tag.setSrc("mysrc.js");
|
||||
tag.setAsync("false");
|
||||
tag.setType("module");
|
||||
tag.setCharset("foo");
|
||||
tag.setNomodule("true");
|
||||
tag.setDefer("true");
|
||||
tag.setReferrerpolicy("same-origin");
|
||||
tag.setCrossorigin("anonymous");
|
||||
tag.setIntegrity("test");
|
||||
|
||||
doScriptTest(tag);
|
||||
String s = writer.toString();
|
||||
|
||||
assertTrue("Incorrect src attribute for script tag", s.contains("src=\"mysrc.js\""));
|
||||
assertFalse("Non-existent async attribute for script tag", s.contains("async"));
|
||||
assertTrue("Incorrect type attribute for script tag", s.contains("type=\"module\""));
|
||||
assertTrue("Incorrect charset attribute for script tag", s.contains("charset=\"foo\""));
|
||||
assertTrue("Non-existent nomodule attribute for script tag", s.contains("nomodule"));
|
||||
assertTrue("Non-existent defer attribute for script tag", s.contains("defer"));
|
||||
assertTrue("Incorrect referrerpolicy attribute for script tag", s.contains("referrerpolicy=\"same-origin\""));
|
||||
assertTrue("Incorrect crossorigin attribute for script tag", s.contains("crossorigin=\"anonymous\""));
|
||||
assertTrue("Incorrect integrity attribute for script tag", s.contains("integrity=\"test\""));
|
||||
assertTrue("Incorrect nonce attribute for script tag", s.contains("nonce=\"" + NONCE_VAL+"\""));
|
||||
}
|
||||
|
||||
private void doScriptTest(ScriptTag tag) {
|
||||
//creating nonce value like the CspInterceptor does
|
||||
stack.getActionContext().getSession().put("nonce", NONCE_VAL);
|
||||
tag.setPageContext(pageContext);
|
||||
|
||||
try {
|
||||
tag.doStartTag();
|
||||
tag.doEndTag();
|
||||
} catch (JspException e) {
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.views.java.simple;
|
||||
|
||||
import org.apache.struts2.views.java.Attributes;
|
||||
import org.apache.struts2.views.java.TagGenerator;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
public class LinkHandler extends AbstractTagHandler implements TagGenerator {
|
||||
|
||||
@Override
|
||||
public void generate() throws IOException {
|
||||
Map<String, Object> params = context.getParameters();
|
||||
Attributes attrs = new Attributes();
|
||||
|
||||
attrs.add("nonce", (String) params.get("nonce"))
|
||||
.addIfExists("href", params.get(("href")))
|
||||
.addIfExists("hreflang", params.get("hreflang"))
|
||||
.addIfExists("rel", params.get("rel"))
|
||||
.addIfExists("media", params.get("media"))
|
||||
.addIfExists("sizes", params.get("sizes"))
|
||||
.addIfExists("crossorigin", params.get("crossorigin"))
|
||||
.addIfExists("referrerpolicy", params.get("referrerpolicy"))
|
||||
.addIfExists("type", params.get("type"))
|
||||
.addIfExists("as", params.get("as"))
|
||||
.addIfExists("disabled", params.get("disabled"))
|
||||
.addIfExists("title", params.get("title"));
|
||||
|
||||
start("link", attrs);
|
||||
end("link");
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.views.java.simple;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.struts2.views.java.Attributes;
|
||||
import org.apache.struts2.views.java.TagGenerator;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
public class ScriptHandler extends AbstractTagHandler implements TagGenerator {
|
||||
|
||||
@Override
|
||||
public void generate() throws IOException {
|
||||
Map<String, Object> params = context.getParameters();
|
||||
Attributes attrs = new Attributes();
|
||||
|
||||
attrs.add("nonce", (String) params.get("nonce"))
|
||||
.addIfExists("async", params.get("async"))
|
||||
.addIfExists("charset", params.get("charset"))
|
||||
.addIfExists("defer", params.get("defer"))
|
||||
.addIfExists("src", params.get("src"))
|
||||
.addIfExists("type", params.get("type"))
|
||||
.addIfExists("name", params.get("name"))
|
||||
.addIfExists("referrerpolicy", params.get("referrerpolicy"))
|
||||
.addIfExists("nomodule", params.get("nomodule"))
|
||||
.addIfExists("integrity", params.get("integrity"))
|
||||
.addIfExists("crossorigin", params.get("crossorigin"));
|
||||
|
||||
start("script", attrs);
|
||||
}
|
||||
|
||||
public static class CloseHandler extends AbstractTagHandler implements TagGenerator {
|
||||
|
||||
public void generate() throws IOException {
|
||||
Map<String, Object> params = context.getParameters();
|
||||
String body = (String) params.get("body");
|
||||
if (StringUtils.isNotEmpty(body))
|
||||
characters(body, false); // false means no HTML encoding
|
||||
end("script");
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
@@ -50,6 +50,9 @@ public class SimpleTheme extends DefaultTheme {
|
||||
put("textarea", new FactoryList(TextAreaHandler.class, ScriptingEventsHandler.class, CommonAttributesHandler.class, DynamicAttributesHandler.class));
|
||||
put("radiomap", new FactoryList(RadioHandler.class, ScriptingEventsHandler.class, CommonAttributesHandler.class, DynamicAttributesHandler.class));
|
||||
put("checkboxlist", new FactoryList(CheckboxListHandler.class, ScriptingEventsHandler.class, CommonAttributesHandler.class, DynamicAttributesHandler.class));
|
||||
put("script", new FactoryList(ScriptHandler.class, CommonAttributesHandler.class, DynamicAttributesHandler.class));
|
||||
put("script-close", new FactoryList(ScriptHandler.CloseHandler.class));
|
||||
put("link", new FactoryList(LinkHandler.class, CommonAttributesHandler.class, DynamicAttributesHandler.class));
|
||||
put("actionerror", new FactoryList(ActionErrorHandler.class));
|
||||
put("token", new FactoryList(TokenHandler.class));
|
||||
put("actionmessage", new FactoryList(ActionMessageHandler.class));
|
||||
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.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{
|
||||
|
||||
private Link tag;
|
||||
|
||||
private static final String NONCE_VAL = "r4andom";
|
||||
|
||||
public void testRenderScriptTag() {
|
||||
tag.setHref("testhref");
|
||||
tag.setHreflang("test");
|
||||
tag.setRel("module");
|
||||
tag.setMedia("foo");
|
||||
tag.setReferrerpolicy("test");
|
||||
tag.setSizes("foo");
|
||||
tag.setCrossorigin("same-origin");
|
||||
tag.setType("anonymous");
|
||||
tag.setAs("test");
|
||||
tag.setDisabled("disabled_");
|
||||
tag.setTitle("test");
|
||||
|
||||
tag.evaluateParams();
|
||||
map.putAll(tag.getParameters());
|
||||
theme.renderTag(getTagName(), context);
|
||||
String s = writer.getBuffer().toString();
|
||||
|
||||
assertTrue("Incorrect href attribute for link tag", s.contains("href=\"testhref\""));
|
||||
assertTrue("Incorrect hreflang attribute for link tag", s.contains("hreflang=\"test\""));
|
||||
assertTrue("Incorrect rel attribute for link tag", s.contains("rel=\"module\""));
|
||||
assertTrue("Incorrect media attribute for link tag", s.contains("media=\"foo\""));
|
||||
assertTrue("Incorrect referrerpolicy attribute for link tag", s.contains("referrerpolicy=\"test\""));
|
||||
assertTrue("Incorrect sizes attribute for link tag", s.contains("sizes=\"foo\""));
|
||||
assertTrue("Incorrect crossorigin attribute for link tag", s.contains("crossorigin=\"same-origin\""));
|
||||
assertTrue("Incorrect type attribute for link tag", s.contains("type=\"anonymous\""));
|
||||
assertTrue("Incorrect as attribute for link tag", s.contains("as=\"test\""));
|
||||
assertTrue("Non-existent disabled attribute for link tag", s.contains("disabled=\"disabled_\""));
|
||||
assertTrue("Incorrect title attribute for link tag", s.contains("title=\"test\""));
|
||||
assertTrue("Incorrect nonce attribute for link tag", s.contains("nonce=\"" + NONCE_VAL+"\""));
|
||||
}
|
||||
@Override
|
||||
protected UIBean getUIBean() throws Exception {
|
||||
return tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTagName() {
|
||||
return "link";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
ActionContext actionContext = stack.getActionContext();
|
||||
Map<String, Object> session = new HashMap<>();
|
||||
session.put("nonce", NONCE_VAL);
|
||||
actionContext.withSession(session);
|
||||
|
||||
this.tag = new Link(stack, request, response);
|
||||
}
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.views.java.simple;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
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");
|
||||
tag.setSrc("mysrc");
|
||||
tag.setAsync("false");
|
||||
tag.setDefer("false");
|
||||
tag.setCharset("test");
|
||||
tag.setReferrerpolicy("foo");
|
||||
tag.setNomodule("bar");
|
||||
tag.setIntegrity("test");
|
||||
tag.setCrossorigin("test");
|
||||
|
||||
tag.evaluateParams();
|
||||
map.putAll(tag.getParameters());
|
||||
theme.renderTag(getTagName(), context);
|
||||
String output = writer.getBuffer().toString();
|
||||
|
||||
assertTrue("Script doesn't have nonce attribute", output.contains("nonce="));
|
||||
assertTrue("Script doesn't have type attribute", output.contains("type="));
|
||||
assertTrue("Script doesn't have src attribute", output.contains("src="));
|
||||
assertTrue("Script doesn't have async attribute", output.contains("async"));
|
||||
assertTrue("Script doesn't have defer attribute", output.contains("defer"));
|
||||
assertTrue("Script doesn't have charset attribute", output.contains("charset="));
|
||||
assertTrue("Script doesn't have referrerpolicy attribute", output.contains("referrerpolicy="));
|
||||
assertTrue("Script doesn't have nomodule attribute", output.contains("nomodule"));
|
||||
assertTrue("Script doesn't have integrity attribute", output.contains("integrity="));
|
||||
assertTrue("Script doesn't have crossorigin attribute", output.contains("crossorigin="));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected UIBean getUIBean() throws Exception {
|
||||
return tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTagName() {
|
||||
return "script";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
ActionContext actionContext = stack.getActionContext();
|
||||
Map<String, Object> session = new HashMap<>();
|
||||
session.put("nonce", NONCE_VAL);
|
||||
actionContext.withSession(session);
|
||||
|
||||
this.tag = new Script(stack, request, response);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user