mirror of
https://github.com/apache/struts.git
synced 2026-08-05 06:36:58 +00:00
Merge branch 'master' into merge/master-2024-06-10
This commit is contained in:
@@ -18,8 +18,9 @@ github:
|
||||
contexts:
|
||||
- build
|
||||
required_pull_request_reviews:
|
||||
require_code_owner_reviews: true
|
||||
required_approving_review_count: 1
|
||||
# it does not work because our github teams are private/secret, see INFRA-25666
|
||||
require_code_owner_reviews: false
|
||||
required_approving_review_count: 0
|
||||
autolink_jira:
|
||||
- WW
|
||||
dependabot_alerts: true
|
||||
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
persist-credentials: false
|
||||
|
||||
- name: "Run analysis"
|
||||
uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # 2.3.1
|
||||
uses: ossf/scorecard-action@dc50aa9510b46c811795eb24b2f1ba02a914e534 # 2.3.3
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
publish_results: true
|
||||
|
||||
- name: "Upload artifact"
|
||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # 4.3.1
|
||||
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # 4.3.3
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
|
||||
@@ -197,7 +197,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<version>3.0.0-M6</version>
|
||||
<version>3.2.5</version>
|
||||
<configuration>
|
||||
<includes>
|
||||
<include>it.org.apache.struts2.showcase.*Test</include>
|
||||
|
||||
+1
-1
@@ -106,7 +106,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>3.6.0</version>
|
||||
<version>3.7.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-assembly</id>
|
||||
|
||||
@@ -220,6 +220,12 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.awaitility</groupId>
|
||||
<artifactId>awaitility</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
|
||||
@@ -90,6 +90,11 @@ public class ActionSupport implements Action, Validateable, ValidationAware, Tex
|
||||
return getLocaleProvider().isValidLocale(locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale toLocale(String localeStr) {
|
||||
return getLocaleProvider().toLocale(localeStr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasKey(String key) {
|
||||
return getTextProvider().hasKey(key);
|
||||
|
||||
@@ -46,17 +46,23 @@ public class DefaultLocaleProvider implements LocaleProvider {
|
||||
|
||||
@Override
|
||||
public boolean isValidLocaleString(String localeStr) {
|
||||
Locale locale = this.toLocale(localeStr);
|
||||
return isValidLocale(locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidLocale(Locale locale) {
|
||||
return locale != null && LocaleUtils.isAvailableLocale(locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale toLocale(String localeStr) {
|
||||
Locale locale = null;
|
||||
try {
|
||||
locale = LocaleUtils.toLocale(StringUtils.trimToNull(localeStr));
|
||||
} catch (IllegalArgumentException e) {
|
||||
LOG.warn(new ParameterizedMessage("Cannot convert [{}] to proper locale", localeStr), e);
|
||||
}
|
||||
return isValidLocale(locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidLocale(Locale locale) {
|
||||
return LocaleUtils.isAvailableLocale(locale);
|
||||
return locale;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
*/
|
||||
package com.opensymphony.xwork2;
|
||||
|
||||
import org.apache.commons.lang3.LocaleUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
|
||||
@@ -58,4 +61,17 @@ public interface LocaleProvider {
|
||||
*/
|
||||
boolean isValidLocale(Locale locale);
|
||||
|
||||
/**
|
||||
* Tries to convert provided locale string into {@link Locale} or returns null
|
||||
* @param localeStr a String representing locale, e.g.: en_EN
|
||||
* @return instance of {@link Locale} or null
|
||||
* @since Struts 6.5.0
|
||||
*/
|
||||
default Locale toLocale(String localeStr) {
|
||||
try {
|
||||
return LocaleUtils.toLocale(StringUtils.trimToNull(localeStr));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.apache.struts2.ognl.ProviderAllowlist;
|
||||
import org.apache.struts2.ognl.ThreadAllowlist;
|
||||
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Modifier;
|
||||
@@ -147,11 +148,11 @@ public class SecurityMemberAccess implements MemberAccess {
|
||||
if (target != null) {
|
||||
// Special case: Target is a Class object but not Class.class
|
||||
if (Class.class.equals(target.getClass()) && !Class.class.equals(target)) {
|
||||
if (!isStatic(member)) {
|
||||
throw new IllegalArgumentException("Member expected to be static!");
|
||||
if (!isStatic(member) && !Constructor.class.equals(member.getClass())) {
|
||||
throw new IllegalArgumentException("Member expected to be static or constructor!");
|
||||
}
|
||||
if (!member.getDeclaringClass().equals(target)) {
|
||||
throw new IllegalArgumentException("Target class does not match static member!");
|
||||
throw new IllegalArgumentException("Target class does not match member!");
|
||||
}
|
||||
target = null; // This information is not useful to us and conflicts with following logic which expects target to be null or an instance containing the member
|
||||
// Standard case: Member should exist on target
|
||||
|
||||
@@ -36,7 +36,7 @@ public interface ActionValidatorManager {
|
||||
* @param method the name of the method being invoked on the action - can be <tt>null</tt>.
|
||||
* @return a list of all validators for the given class and context.
|
||||
*/
|
||||
List<Validator> getValidators(Class clazz, String context, String method);
|
||||
List<Validator> getValidators(Class<?> clazz, String context, String method);
|
||||
|
||||
/**
|
||||
* Returns a list of validators for the given class and context. This is the primary
|
||||
@@ -46,7 +46,7 @@ public interface ActionValidatorManager {
|
||||
* @param context the context of the action class - can be <tt>null</tt>.
|
||||
* @return a list of all validators for the given class and context.
|
||||
*/
|
||||
List<Validator> getValidators(Class clazz, String context);
|
||||
List<Validator> getValidators(Class<?> clazz, String context);
|
||||
|
||||
/**
|
||||
* Validates the given object using action and its context.
|
||||
|
||||
+9
-9
@@ -125,7 +125,7 @@ public class DefaultActionValidatorManager implements ActionValidatorManager {
|
||||
* @param context context
|
||||
* @return a validator key which is the class name plus context.
|
||||
*/
|
||||
protected String buildValidatorKey(Class clazz, String context) {
|
||||
protected String buildValidatorKey(Class<?> clazz, String context) {
|
||||
return clazz.getName() + "/" + context;
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ public class DefaultActionValidatorManager implements ActionValidatorManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<Validator> getValidators(Class clazz, String context, String method) {
|
||||
public synchronized List<Validator> getValidators(Class<?> clazz, String context, String method) {
|
||||
String validatorKey = buildValidatorKey(clazz, context);
|
||||
|
||||
if (!validatorCache.containsKey(validatorKey)) {
|
||||
@@ -158,7 +158,7 @@ public class DefaultActionValidatorManager implements ActionValidatorManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized List<Validator> getValidators(Class clazz, String context) {
|
||||
public synchronized List<Validator> getValidators(Class<?> clazz, String context) {
|
||||
return getValidators(clazz, context, null);
|
||||
}
|
||||
|
||||
@@ -277,7 +277,7 @@ public class DefaultActionValidatorManager implements ActionValidatorManager {
|
||||
* @param checked the set of previously checked class-contexts, null if none have been checked
|
||||
* @return a list of validator configs for the given class and context.
|
||||
*/
|
||||
protected List<ValidatorConfig> buildValidatorConfigs(Class clazz, String context, boolean checkFile, Set<String> checked) {
|
||||
protected List<ValidatorConfig> buildValidatorConfigs(Class<?> clazz, String context, boolean checkFile, Set<String> checked) {
|
||||
List<ValidatorConfig> validatorConfigs = new ArrayList<>();
|
||||
|
||||
if (checked == null) {
|
||||
@@ -287,7 +287,7 @@ public class DefaultActionValidatorManager implements ActionValidatorManager {
|
||||
}
|
||||
|
||||
if (clazz.isInterface()) {
|
||||
for (Class anInterface : clazz.getInterfaces()) {
|
||||
for (Class<?> anInterface : clazz.getInterfaces()) {
|
||||
validatorConfigs.addAll(buildValidatorConfigs(anInterface, context, checkFile, checked));
|
||||
}
|
||||
} else {
|
||||
@@ -297,7 +297,7 @@ public class DefaultActionValidatorManager implements ActionValidatorManager {
|
||||
}
|
||||
|
||||
// look for validators for implemented interfaces
|
||||
for (Class anInterface1 : clazz.getInterfaces()) {
|
||||
for (Class<?> anInterface1 : clazz.getInterfaces()) {
|
||||
if (checked.contains(anInterface1.getName())) {
|
||||
continue;
|
||||
}
|
||||
@@ -317,17 +317,17 @@ public class DefaultActionValidatorManager implements ActionValidatorManager {
|
||||
return validatorConfigs;
|
||||
}
|
||||
|
||||
protected List<ValidatorConfig> buildAliasValidatorConfigs(Class aClass, String context, boolean checkFile) {
|
||||
protected List<ValidatorConfig> buildAliasValidatorConfigs(Class<?> aClass, String context, boolean checkFile) {
|
||||
String fileName = aClass.getName().replace('.', '/') + "-" + context + VALIDATION_CONFIG_SUFFIX;
|
||||
return loadFile(fileName, aClass, checkFile);
|
||||
}
|
||||
|
||||
protected List<ValidatorConfig> buildClassValidatorConfigs(Class aClass, boolean checkFile) {
|
||||
protected List<ValidatorConfig> buildClassValidatorConfigs(Class<?> aClass, boolean checkFile) {
|
||||
String fileName = aClass.getName().replace('.', '/') + VALIDATION_CONFIG_SUFFIX;
|
||||
return loadFile(fileName, aClass, checkFile);
|
||||
}
|
||||
|
||||
protected List<ValidatorConfig> loadFile(String fileName, Class clazz, boolean checkFile) {
|
||||
protected List<ValidatorConfig> loadFile(String fileName, Class<?> clazz, boolean checkFile) {
|
||||
List<ValidatorConfig> retList = Collections.emptyList();
|
||||
|
||||
URL fileUrl = ClassLoaderUtil.getResource(fileName, clazz);
|
||||
|
||||
+11
-1
@@ -122,10 +122,15 @@ public class DelegatingValidatorContext implements ValidatorContext {
|
||||
return localeProvider.isValidLocale(locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale toLocale(String localeStr) {
|
||||
return localeProvider.toLocale(localeStr);
|
||||
}
|
||||
|
||||
public boolean hasKey(String key) {
|
||||
return textProvider.hasKey(key);
|
||||
}
|
||||
|
||||
|
||||
public String getText(String aTextName) {
|
||||
return textProvider.getText(aTextName);
|
||||
}
|
||||
@@ -280,6 +285,11 @@ public class DelegatingValidatorContext implements ValidatorContext {
|
||||
public boolean isValidLocale(Locale locale) {
|
||||
return getLocaleProvider().isValidLocale(locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Locale toLocale(String localeStr) {
|
||||
return getLocaleProvider().toLocale(localeStr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -104,17 +104,17 @@ public class Set extends ContextBean {
|
||||
body="";
|
||||
|
||||
if (DispatcherConstants.APPLICATION.equalsIgnoreCase(scope)) {
|
||||
stack.setValue("#application['" + getVar() + "']", o);
|
||||
stack.setValue(String.format("#application[\"%s\"]", getVar()), o);
|
||||
} else if (DispatcherConstants.SESSION.equalsIgnoreCase(scope)) {
|
||||
stack.setValue("#session['" + getVar() + "']", o);
|
||||
stack.setValue(String.format("#session[\"%s\"]", getVar()), o);
|
||||
} else if (DispatcherConstants.REQUEST.equalsIgnoreCase(scope)) {
|
||||
stack.setValue("#request['" + getVar() + "']", o);
|
||||
stack.setValue(String.format("#request[\"%s\"]", getVar()), o);
|
||||
} else if (DispatcherConstants.PAGE.equalsIgnoreCase(scope)) {
|
||||
stack.setValue("#attr['" + getVar() + "']", o, false);
|
||||
stack.setValue(String.format("#attr[\"%s\"]", getVar()), o, false);
|
||||
} else {
|
||||
// Default scope is action. Note: The action scope handling also adds the var to the page scope.
|
||||
stack.getContext().put(getVar(), o);
|
||||
stack.setValue("#attr['" + getVar() + "']", o, false);
|
||||
putInContext(o);
|
||||
stack.setValue(String.format("#attr[\"%s\"]", getVar()), o, false);
|
||||
}
|
||||
|
||||
return super.end(writer, body);
|
||||
|
||||
@@ -24,7 +24,6 @@ import com.opensymphony.xwork2.LocaleProviderFactory;
|
||||
import com.opensymphony.xwork2.inject.Inject;
|
||||
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
|
||||
import com.opensymphony.xwork2.util.TextParseUtil;
|
||||
import org.apache.commons.lang3.LocaleUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.message.ParameterizedMessage;
|
||||
@@ -85,7 +84,7 @@ public class I18nInterceptor extends AbstractInterceptor {
|
||||
}
|
||||
|
||||
public void setLocaleStorage(String storageName) {
|
||||
if (storageName == null || "".equals(storageName)) {
|
||||
if (storageName == null || storageName.isEmpty()) {
|
||||
this.storage = Storage.ACCEPT_LANGUAGE;
|
||||
} else {
|
||||
try {
|
||||
@@ -169,27 +168,21 @@ public class I18nInterceptor extends AbstractInterceptor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Locale object from the request param, which might
|
||||
* be already a Local or a String
|
||||
* Creates a Locale object from the request param
|
||||
*
|
||||
* @param requestedLocale the parameter from the request
|
||||
* @return the Locale
|
||||
* @return instance of {@link Locale} or null
|
||||
*/
|
||||
protected Locale getLocaleFromParam(Object requestedLocale) {
|
||||
protected Locale getLocaleFromParam(String requestedLocale) {
|
||||
LocaleProvider localeProvider = localeProviderFactory.createLocaleProvider();
|
||||
|
||||
Locale locale = null;
|
||||
if (requestedLocale != null) {
|
||||
if (requestedLocale instanceof Locale) {
|
||||
locale = (Locale) requestedLocale;
|
||||
} else {
|
||||
String localeStr = requestedLocale.toString();
|
||||
if (localeProvider.isValidLocaleString(localeStr)) {
|
||||
locale = LocaleUtils.toLocale(localeStr);
|
||||
} else {
|
||||
locale = localeProvider.getLocale();
|
||||
}
|
||||
locale = localeProvider.toLocale(requestedLocale);
|
||||
if (locale == null) {
|
||||
locale = localeProvider.getLocale();
|
||||
}
|
||||
|
||||
if (locale != null) {
|
||||
LOG.debug("Found locale: {}", locale);
|
||||
}
|
||||
@@ -285,7 +278,7 @@ public class I18nInterceptor extends AbstractInterceptor {
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public Locale find() {
|
||||
if (supportedLocale.size() > 0) {
|
||||
if (!supportedLocale.isEmpty()) {
|
||||
Enumeration locales = actionInvocation.getInvocationContext().getServletRequest().getLocales();
|
||||
while (locales.hasMoreElements()) {
|
||||
Locale locale = (Locale) locales.nextElement();
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
package org.apache.struts2.interceptor.csp;
|
||||
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
|
||||
import com.opensymphony.xwork2.util.ClassLoaderUtil;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.action.CspSettingsAware;
|
||||
@@ -46,6 +48,9 @@ public final class CspInterceptor extends AbstractInterceptor {
|
||||
private boolean prependServletContext = true;
|
||||
private boolean enforcingMode;
|
||||
private String reportUri;
|
||||
private String reportTo;
|
||||
|
||||
private String cspSettingsClassName = DefaultCspSettings.class.getName();
|
||||
|
||||
@Override
|
||||
public String intercept(ActionInvocation invocation) throws Exception {
|
||||
@@ -54,12 +59,30 @@ public final class CspInterceptor extends AbstractInterceptor {
|
||||
LOG.trace("Using CspSettings provided by the action: {}", action);
|
||||
applySettings(invocation, ((CspSettingsAware) action).getCspSettings());
|
||||
} else {
|
||||
LOG.trace("Using DefaultCspSettings with action: {}", action);
|
||||
applySettings(invocation, new DefaultCspSettings());
|
||||
LOG.trace("Using {} with action: {}", cspSettingsClassName, action);
|
||||
CspSettings cspSettings = createCspSettings(invocation);
|
||||
applySettings(invocation, cspSettings);
|
||||
}
|
||||
return invocation.invoke();
|
||||
}
|
||||
|
||||
private CspSettings createCspSettings(ActionInvocation invocation) throws ClassNotFoundException {
|
||||
Class<?> cspSettingsClass;
|
||||
|
||||
try {
|
||||
cspSettingsClass = ClassLoaderUtil.loadClass(cspSettingsClassName, getClass());
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new ConfigurationException(String.format("The class %s doesn't exist!", cspSettingsClassName));
|
||||
}
|
||||
|
||||
if (!CspSettings.class.isAssignableFrom(cspSettingsClass)) {
|
||||
throw new ConfigurationException(String.format("The class %s doesn't implement %s!",
|
||||
cspSettingsClassName, CspSettings.class.getName()));
|
||||
}
|
||||
|
||||
return (CspSettings) invocation.getInvocationContext().getContainer().inject(cspSettingsClass);
|
||||
}
|
||||
|
||||
private void applySettings(ActionInvocation invocation, CspSettings cspSettings) {
|
||||
HttpServletRequest request = invocation.getInvocationContext().getServletRequest();
|
||||
HttpServletResponse response = invocation.getInvocationContext().getServletResponse();
|
||||
@@ -76,6 +99,12 @@ public final class CspInterceptor extends AbstractInterceptor {
|
||||
}
|
||||
|
||||
cspSettings.setReportUri(finalReportUri);
|
||||
|
||||
// apply reportTo if set
|
||||
if (reportTo != null) {
|
||||
LOG.trace("Applying: {} to reportTo", reportTo);
|
||||
cspSettings.setReportTo(reportTo);
|
||||
}
|
||||
}
|
||||
|
||||
invocation.addPreResultListener((actionInvocation, resultCode) -> {
|
||||
@@ -97,6 +126,17 @@ public final class CspInterceptor extends AbstractInterceptor {
|
||||
this.reportUri = reportUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the report group where csp violation reports will be sent. This will
|
||||
* only be used if the reportUri is set.
|
||||
*
|
||||
* @param reportTo the report group where csp violation reports will be sent
|
||||
* @since Struts 6.5.0
|
||||
*/
|
||||
public void setReportTo(String reportTo) {
|
||||
this.reportTo = reportTo;
|
||||
}
|
||||
|
||||
private Optional<URI> buildUri(String reportUri) {
|
||||
try {
|
||||
return Optional.of(URI.create(reportUri));
|
||||
@@ -124,4 +164,13 @@ public final class CspInterceptor extends AbstractInterceptor {
|
||||
this.prependServletContext = prependServletContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the class name of the default {@link CspSettings} implementation to use when the action does not
|
||||
* set its own values. If not set, the default is {@link DefaultCspSettings}.
|
||||
*
|
||||
* @since Struts 6.5.0
|
||||
*/
|
||||
public void setCspSettingsClassName(String cspSettingsClassName) {
|
||||
this.cspSettingsClassName = cspSettingsClassName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ public interface CspSettings {
|
||||
String SCRIPT_SRC = "script-src";
|
||||
String BASE_URI = "base-uri";
|
||||
String REPORT_URI = "report-uri";
|
||||
String REPORT_TO = "report-to";
|
||||
String NONE = "none";
|
||||
String STRICT_DYNAMIC = "strict-dynamic";
|
||||
String HTTP = "http:";
|
||||
@@ -56,6 +57,13 @@ public interface CspSettings {
|
||||
*/
|
||||
void setReportUri(String uri);
|
||||
|
||||
/**
|
||||
* Sets the report group where csp violation reports will be sent
|
||||
*
|
||||
* @since Struts 6.5.0
|
||||
*/
|
||||
void setReportTo(String group);
|
||||
|
||||
/**
|
||||
* Sets CSP headers in enforcing mode when true, and report-only when false
|
||||
*/
|
||||
|
||||
@@ -20,6 +20,7 @@ package org.apache.struts2.interceptor.csp;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.struts2.action.CspSettingsAware;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
@@ -31,7 +32,11 @@ import static java.lang.String.format;
|
||||
|
||||
/**
|
||||
* 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>
|
||||
* 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>
|
||||
* You may extend or replace this class if you wish to customize the default policy further, and use your class
|
||||
* by setting the {@link CspInterceptor} defaultCspSettingsClassName parameter. Actions that
|
||||
* implement the {@link CspSettingsAware} interface will ignore the defaultCspSettingsClassName parameter.
|
||||
*
|
||||
* @see CspSettings
|
||||
* @see CspInterceptor
|
||||
@@ -42,20 +47,22 @@ public class DefaultCspSettings implements CspSettings {
|
||||
|
||||
private final SecureRandom sRand = new SecureRandom();
|
||||
|
||||
private String reportUri;
|
||||
protected String reportUri;
|
||||
protected String reportTo;
|
||||
// default to reporting mode
|
||||
private String cspHeader = CSP_REPORT_HEADER;
|
||||
protected String cspHeader = CSP_REPORT_HEADER;
|
||||
|
||||
@Override
|
||||
public void addCspHeaders(HttpServletResponse response) {
|
||||
throw new UnsupportedOperationException("Unsupported implementation, use #addCspHeaders(HttpServletRequest request, HttpServletResponse response)");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCspHeaders(HttpServletRequest request, HttpServletResponse response) {
|
||||
if (isSessionActive(request)) {
|
||||
LOG.trace("Session is active, applying CSP settings");
|
||||
associateNonceWithSession(request);
|
||||
response.setHeader(cspHeader, cratePolicyFormat(request));
|
||||
response.setHeader(cspHeader, createPolicyFormat(request));
|
||||
} else {
|
||||
LOG.trace("Session is not active, ignoring CSP settings");
|
||||
}
|
||||
@@ -70,7 +77,7 @@ public class DefaultCspSettings implements CspSettings {
|
||||
request.getSession().setAttribute("nonce", nonceValue);
|
||||
}
|
||||
|
||||
private String cratePolicyFormat(HttpServletRequest request) {
|
||||
protected String createPolicyFormat(HttpServletRequest request) {
|
||||
StringBuilder policyFormatBuilder = new StringBuilder()
|
||||
.append(OBJECT_SRC)
|
||||
.append(format(" '%s'; ", NONE))
|
||||
@@ -84,13 +91,18 @@ public class DefaultCspSettings implements CspSettings {
|
||||
if (reportUri != null) {
|
||||
policyFormatBuilder
|
||||
.append(REPORT_URI)
|
||||
.append(format(" %s", reportUri));
|
||||
.append(format(" %s; ", reportUri));
|
||||
if(reportTo != null) {
|
||||
policyFormatBuilder
|
||||
.append(REPORT_TO)
|
||||
.append(format(" %s; ", reportTo));
|
||||
}
|
||||
}
|
||||
|
||||
return format(policyFormatBuilder.toString(), getNonceString(request));
|
||||
}
|
||||
|
||||
private String getNonceString(HttpServletRequest request) {
|
||||
protected String getNonceString(HttpServletRequest request) {
|
||||
Object nonce = request.getSession().getAttribute("nonce");
|
||||
return Objects.toString(nonce);
|
||||
}
|
||||
@@ -101,20 +113,28 @@ public class DefaultCspSettings implements CspSettings {
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnforcingMode(boolean enforcingMode) {
|
||||
if (enforcingMode) {
|
||||
cspHeader = CSP_ENFORCE_HEADER;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReportUri(String reportUri) {
|
||||
this.reportUri = reportUri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReportTo(String reportTo) {
|
||||
this.reportTo = reportTo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DefaultCspSettings{" +
|
||||
"reportUri='" + reportUri + '\'' +
|
||||
", reportTo='" + reportTo + '\'' +
|
||||
", cspHeader='" + cspHeader + '\'' +
|
||||
'}';
|
||||
}
|
||||
|
||||
+16
-4
@@ -20,6 +20,8 @@ package org.apache.struts2.interceptor.exec;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@@ -30,6 +32,8 @@ public class StrutsBackgroundProcess implements BackgroundProcess, Serializable
|
||||
|
||||
private static final long serialVersionUID = 3884464776311686443L;
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(StrutsBackgroundProcess.class);
|
||||
|
||||
private final String threadName;
|
||||
private final int threadPriority;
|
||||
|
||||
@@ -44,8 +48,8 @@ public class StrutsBackgroundProcess implements BackgroundProcess, Serializable
|
||||
/**
|
||||
* Constructs a background process
|
||||
*
|
||||
* @param invocation The action invocation
|
||||
* @param threadName The name of background thread
|
||||
* @param invocation The action invocation
|
||||
* @param threadName The name of background thread
|
||||
* @param threadPriority The priority of background thread
|
||||
*/
|
||||
public StrutsBackgroundProcess(ActionInvocation invocation, String threadName, int threadPriority) {
|
||||
@@ -61,11 +65,19 @@ public class StrutsBackgroundProcess implements BackgroundProcess, Serializable
|
||||
try {
|
||||
beforeInvocation();
|
||||
result = invocation.invokeActionOnly();
|
||||
afterInvocation();
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Exception during invokeActionOnly() execution", e);
|
||||
exception = e;
|
||||
} finally {
|
||||
done = true;
|
||||
try {
|
||||
afterInvocation();
|
||||
} catch (Exception ex) {
|
||||
if (exception == null) {
|
||||
exception = ex;
|
||||
}
|
||||
LOG.warn("Exception during afterInvocation() execution", ex);
|
||||
}
|
||||
done = true;
|
||||
}
|
||||
});
|
||||
processThread.setName(threadName);
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* 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 com.opensymphony.xwork2;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class DefaultLocaleProviderTest {
|
||||
|
||||
private DefaultLocaleProvider provider;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
provider = new DefaultLocaleProvider();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
ActionContext.of().bind();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() throws Exception {
|
||||
ActionContext.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getLocale() {
|
||||
// given
|
||||
ActionContext.getContext().withLocale(Locale.ITALY);
|
||||
|
||||
// when
|
||||
Locale actual = provider.getLocale();
|
||||
|
||||
// then
|
||||
assertEquals(Locale.ITALY, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getLocaleNull() {
|
||||
// given
|
||||
ActionContext backup = ActionContext.getContext();
|
||||
ActionContext.clear();
|
||||
|
||||
// when
|
||||
Locale actual = provider.getLocale();
|
||||
|
||||
// then
|
||||
assertNull(actual);
|
||||
ActionContext.bind(backup);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toLocale() {
|
||||
// given
|
||||
ActionContext.getContext().withLocale(Locale.GERMAN);
|
||||
|
||||
// when
|
||||
Locale actual = provider.toLocale("it");
|
||||
|
||||
// then
|
||||
assertEquals(Locale.ITALIAN, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toLocaleFull() {
|
||||
// given
|
||||
ActionContext.getContext().withLocale(Locale.GERMAN);
|
||||
|
||||
// when
|
||||
Locale actual = provider.toLocale("it_IT");
|
||||
|
||||
// then
|
||||
assertEquals(Locale.ITALY, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toLocaleTrimEndOfLine() {
|
||||
// given
|
||||
ActionContext.getContext().withLocale(Locale.GERMAN);
|
||||
|
||||
// when
|
||||
Locale actual = provider.toLocale("it_IT\n");
|
||||
|
||||
// then
|
||||
assertEquals(Locale.ITALY, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toLocaleTrimEmptySpace() {
|
||||
// given
|
||||
ActionContext.getContext().withLocale(Locale.GERMAN);
|
||||
|
||||
// when
|
||||
Locale actual = provider.toLocale(" it_IT ");
|
||||
|
||||
// then
|
||||
assertEquals(Locale.ITALY, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isValidLocaleNull() {
|
||||
// given
|
||||
ActionContext.getContext().withLocale(Locale.GERMAN);
|
||||
|
||||
// when
|
||||
boolean actual = provider.isValidLocale(null);
|
||||
|
||||
// then
|
||||
assertFalse(actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isValidLocale() {
|
||||
// given
|
||||
ActionContext.getContext().withLocale(Locale.GERMAN);
|
||||
|
||||
// when
|
||||
boolean actual = provider.isValidLocale(Locale.ITALIAN);
|
||||
|
||||
// then
|
||||
assertTrue(actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isValidLocaleString() {
|
||||
// given
|
||||
ActionContext.getContext().withLocale(Locale.GERMAN);
|
||||
|
||||
// when
|
||||
boolean actual = provider.isValidLocaleString("it");
|
||||
|
||||
// then
|
||||
assertTrue(actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isValidLocaleStringNot() {
|
||||
// given
|
||||
ActionContext.getContext().withLocale(Locale.GERMAN);
|
||||
|
||||
// when
|
||||
boolean actual = provider.isValidLocaleString("italy");
|
||||
|
||||
// then
|
||||
assertFalse(actual);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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 com.opensymphony.xwork2;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class LocaleProviderTest {
|
||||
|
||||
@Test
|
||||
public void toLocale() {
|
||||
// given
|
||||
DummyLocale locale = new DummyLocale();
|
||||
|
||||
// when
|
||||
Locale actual = locale.toLocale("de");
|
||||
|
||||
// then
|
||||
assertEquals(Locale.GERMAN, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toLocaleTrim() {
|
||||
// given
|
||||
DummyLocale locale = new DummyLocale();
|
||||
|
||||
// when
|
||||
Locale actual = locale.toLocale(" de_DE ");
|
||||
|
||||
// then
|
||||
assertEquals(Locale.GERMANY, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toLocaleNull() {
|
||||
// given
|
||||
DummyLocale locale = new DummyLocale();
|
||||
|
||||
// when
|
||||
Locale actual = locale.toLocale("germany");
|
||||
|
||||
// then
|
||||
assertNull(actual);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class DummyLocale implements LocaleProvider {
|
||||
@Override
|
||||
public Locale getLocale() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidLocaleString(String localeStr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValidLocale(Locale locale) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+175
-181
@@ -18,161 +18,167 @@
|
||||
*/
|
||||
package com.opensymphony.xwork2.validator;
|
||||
|
||||
import com.mockobjects.dynamic.C;
|
||||
import com.mockobjects.dynamic.Mock;
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.FileManagerFactory;
|
||||
import com.opensymphony.xwork2.SimpleAction;
|
||||
import com.opensymphony.xwork2.StubValueStack;
|
||||
import com.opensymphony.xwork2.TestBean;
|
||||
import com.opensymphony.xwork2.ValidationOrderAction;
|
||||
import com.opensymphony.xwork2.XWorkTestCase;
|
||||
import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.interceptor.ValidationAware;
|
||||
import com.opensymphony.xwork2.test.DataAware2;
|
||||
import com.opensymphony.xwork2.test.SimpleAction2;
|
||||
import com.opensymphony.xwork2.test.SimpleAction3;
|
||||
import com.opensymphony.xwork2.util.ValueStack;
|
||||
import com.opensymphony.xwork2.util.fs.DefaultFileManager;
|
||||
import com.opensymphony.xwork2.util.fs.DefaultFileManagerFactory;
|
||||
import com.opensymphony.xwork2.test.User;
|
||||
import com.opensymphony.xwork2.validator.validators.DateRangeFieldValidator;
|
||||
import com.opensymphony.xwork2.validator.validators.DoubleRangeFieldValidator;
|
||||
import com.opensymphony.xwork2.validator.validators.ExpressionValidator;
|
||||
import com.opensymphony.xwork2.validator.validators.IntRangeFieldValidator;
|
||||
import com.opensymphony.xwork2.validator.validators.LongRangeFieldValidator;
|
||||
import com.opensymphony.xwork2.validator.validators.RequiredFieldValidator;
|
||||
import com.opensymphony.xwork2.validator.validators.RequiredStringValidator;
|
||||
import com.opensymphony.xwork2.validator.validators.ShortRangeFieldValidator;
|
||||
import org.apache.struts2.StrutsException;
|
||||
import org.xml.sax.SAXParseException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
/**
|
||||
* DefaultActionValidatorManagerTest
|
||||
*
|
||||
* @author Jason Carreira
|
||||
* @author tm_jee
|
||||
* @version $Date$ $Id$
|
||||
*/
|
||||
public class DefaultActionValidatorManagerTest extends XWorkTestCase {
|
||||
|
||||
protected final String alias = "validationAlias";
|
||||
|
||||
DefaultActionValidatorManager actionValidatorManager;
|
||||
Mock mockValidatorFileParser;
|
||||
Mock mockValidatorFactory;
|
||||
ValueStack stubValueStack;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
actionValidatorManager = new DefaultActionValidatorManager();
|
||||
super.setUp();
|
||||
mockValidatorFileParser = new Mock(ValidatorFileParser.class);
|
||||
actionValidatorManager.setValidatorFileParser((ValidatorFileParser)mockValidatorFileParser.proxy());
|
||||
|
||||
mockValidatorFactory = new Mock(ValidatorFactory.class);
|
||||
actionValidatorManager.setValidatorFactory((ValidatorFactory)mockValidatorFactory.proxy());
|
||||
|
||||
stubValueStack = new StubValueStack();
|
||||
ActionContext.of()
|
||||
.withValueStack(stubValueStack)
|
||||
.bind();
|
||||
|
||||
DefaultFileManagerFactory factory = new DefaultFileManagerFactory();
|
||||
factory.setContainer(container);
|
||||
factory.setFileManager(new DefaultFileManager());
|
||||
actionValidatorManager.setFileManagerFactory(factory);
|
||||
actionValidatorManager = container.inject(DefaultActionValidatorManager.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
actionValidatorManager = null;
|
||||
super.tearDown();
|
||||
mockValidatorFactory = null;
|
||||
mockValidatorFileParser = null;
|
||||
actionValidatorManager = null;
|
||||
}
|
||||
|
||||
|
||||
public void testBuildValidatorKey() {
|
||||
String validatorKey = actionValidatorManager.buildValidatorKey(SimpleAction.class, alias);
|
||||
assertEquals(SimpleAction.class.getName() + "/" + alias, validatorKey);
|
||||
}
|
||||
|
||||
public void testBuildsValidatorsForAlias() {
|
||||
mockValidatorFileParser.expectAndReturn("parseActionValidatorConfigs",
|
||||
C.args(C.IS_NOT_NULL, C.IS_NOT_NULL, C.eq("com/opensymphony/xwork2/SimpleAction-validation.xml")),
|
||||
new ArrayList());
|
||||
mockValidatorFileParser.expectAndReturn("parseActionValidatorConfigs",
|
||||
C.args(C.IS_NOT_NULL, C.IS_NOT_NULL, C.eq("com/opensymphony/xwork2/SimpleAction-validationAlias-validation.xml")),
|
||||
new ArrayList());
|
||||
actionValidatorManager.getValidators(SimpleAction.class, alias);
|
||||
mockValidatorFileParser.verify();
|
||||
List<Validator> validators = actionValidatorManager.getValidators(SimpleAction.class, alias);
|
||||
|
||||
assertThat(validators).hasSize(11).map(Validator::getClass).containsExactly(
|
||||
ExpressionValidator.class,
|
||||
RequiredFieldValidator.class,
|
||||
IntRangeFieldValidator.class,
|
||||
DoubleRangeFieldValidator.class,
|
||||
DateRangeFieldValidator.class,
|
||||
IntRangeFieldValidator.class,
|
||||
IntRangeFieldValidator.class,
|
||||
LongRangeFieldValidator.class,
|
||||
ShortRangeFieldValidator.class,
|
||||
RequiredFieldValidator.class,
|
||||
IntRangeFieldValidator.class
|
||||
);
|
||||
assertThat(validators).hasSize(11).map(Validator::getDefaultMessage).containsExactly(
|
||||
"Foo must be greater than Bar. Foo = ${foo}, Bar = ${bar}.",
|
||||
"You must enter a value for bar.",
|
||||
"bar must be between ${min} and ${max}, current value is ${bar}.",
|
||||
"percentage must be between ${minExclusive} and ${maxExclusive}, current value is ${percentage}.",
|
||||
"The date must be between 12-22-2002 and 12-25-2002.",
|
||||
"Could not find foo.range!",
|
||||
"Could not find baz.range!",
|
||||
"Could not find foo.range!",
|
||||
"Could not find foo.range!",
|
||||
"You must enter a value for baz.",
|
||||
"baz out of range."
|
||||
);
|
||||
}
|
||||
|
||||
public void testBuildsValidatorsForAliasError() {
|
||||
boolean pass = false;
|
||||
try {
|
||||
mockValidatorFileParser.expectAndReturn("parseActionValidatorConfigs",
|
||||
C.args(C.IS_NOT_NULL, C.IS_NOT_NULL, C.eq("com/opensymphony/xwork2/TestBean-validation.xml")),
|
||||
new ArrayList());
|
||||
mockValidatorFileParser.expectAndThrow("parseActionValidatorConfigs",
|
||||
C.args(C.IS_NOT_NULL, C.IS_NOT_NULL, C.eq("com/opensymphony/xwork2/TestBean-badtest-validation.xml")),
|
||||
new ConfigurationException());
|
||||
List validatorList = actionValidatorManager.getValidators(TestBean.class, "badtest");
|
||||
} catch (StrutsException ex) {
|
||||
pass = true;
|
||||
}
|
||||
mockValidatorFileParser.verify();
|
||||
assertTrue("Didn't throw exception on load failure", pass);
|
||||
assertThatThrownBy(() -> actionValidatorManager.getValidators(TestBean.class, "badtest"))
|
||||
.isInstanceOf(StrutsException.class)
|
||||
.hasCause(new SAXParseException("Attribute \"foo\" must be declared for element type \"field-validator\".", null));
|
||||
}
|
||||
|
||||
|
||||
public void testGetValidatorsForInterface() {
|
||||
mockValidatorFileParser.expectAndReturn("parseActionValidatorConfigs",
|
||||
C.args(C.IS_NOT_NULL, C.IS_NOT_NULL, C.eq("com/opensymphony/xwork2/test/DataAware-validation.xml")),
|
||||
new ArrayList());
|
||||
mockValidatorFileParser.expectAndReturn("parseActionValidatorConfigs",
|
||||
C.args(C.IS_NOT_NULL, C.IS_NOT_NULL, C.eq("com/opensymphony/xwork2/test/DataAware-validationAlias-validation.xml")),
|
||||
new ArrayList());
|
||||
mockValidatorFileParser.expectAndReturn("parseActionValidatorConfigs",
|
||||
C.args(C.IS_NOT_NULL, C.IS_NOT_NULL, C.eq("com/opensymphony/xwork2/test/DataAware2-validation.xml")),
|
||||
new ArrayList());
|
||||
actionValidatorManager.getValidators(DataAware2.class, alias);
|
||||
mockValidatorFileParser.verify();
|
||||
List<Validator> validators = actionValidatorManager.getValidators(DataAware2.class, alias);
|
||||
|
||||
assertThat(validators).hasSize(3).map(Validator::getClass).containsExactly(
|
||||
RequiredFieldValidator.class,
|
||||
RequiredStringValidator.class,
|
||||
RequiredStringValidator.class
|
||||
);
|
||||
assertThat(validators).hasSize(3).map(Validator::getValidatorType).containsExactly(
|
||||
"required",
|
||||
"requiredstring",
|
||||
"requiredstring"
|
||||
);
|
||||
assertThat(validators).hasSize(3).map(Validator::getDefaultMessage).containsExactly(
|
||||
"You must enter a value for data.",
|
||||
"You must enter a value for data.",
|
||||
"You must enter a value for data."
|
||||
);
|
||||
}
|
||||
|
||||
public void testGetValidatorsFromInterface() {
|
||||
mockValidatorFileParser.expectAndReturn("parseActionValidatorConfigs",
|
||||
C.args(C.IS_NOT_NULL, C.IS_NOT_NULL, C.eq("com/opensymphony/xwork2/SimpleAction-validation.xml")),
|
||||
new ArrayList());
|
||||
mockValidatorFileParser.expectAndReturn("parseActionValidatorConfigs",
|
||||
C.args(C.IS_NOT_NULL, C.IS_NOT_NULL, C.eq("com/opensymphony/xwork2/SimpleAction-validationAlias-validation.xml")),
|
||||
new ArrayList());
|
||||
mockValidatorFileParser.expectAndReturn("parseActionValidatorConfigs",
|
||||
C.args(C.IS_NOT_NULL, C.IS_NOT_NULL, C.eq("com/opensymphony/xwork2/test/DataAware-validation.xml")),
|
||||
new ArrayList());
|
||||
mockValidatorFileParser.expectAndReturn("parseActionValidatorConfigs",
|
||||
C.args(C.IS_NOT_NULL, C.IS_NOT_NULL, C.eq("com/opensymphony/xwork2/test/DataAware-validationAlias-validation.xml")),
|
||||
new ArrayList());
|
||||
actionValidatorManager.getValidators(SimpleAction3.class, alias);
|
||||
mockValidatorFileParser.verify();
|
||||
}
|
||||
List<Validator> validators = actionValidatorManager.getValidators(SimpleAction3.class, alias);
|
||||
|
||||
public void testSameAliasWithDifferentClass() {
|
||||
mockValidatorFileParser.expectAndReturn("parseActionValidatorConfigs",
|
||||
C.args(C.IS_NOT_NULL, C.IS_NOT_NULL, C.eq("com/opensymphony/xwork2/SimpleAction-validation.xml")),
|
||||
new ArrayList());
|
||||
mockValidatorFileParser.expectAndReturn("parseActionValidatorConfigs",
|
||||
C.args(C.IS_NOT_NULL, C.IS_NOT_NULL, C.eq("com/opensymphony/xwork2/SimpleAction-validationAlias-validation.xml")),
|
||||
new ArrayList());
|
||||
mockValidatorFileParser.expectAndReturn("parseActionValidatorConfigs",
|
||||
C.args(C.IS_NOT_NULL, C.IS_NOT_NULL, C.eq("com/opensymphony/xwork2/test/SimpleAction2-validation.xml")),
|
||||
new ArrayList());
|
||||
mockValidatorFileParser.expectAndReturn("parseActionValidatorConfigs",
|
||||
C.args(C.IS_NOT_NULL, C.IS_NOT_NULL, C.eq("com/opensymphony/xwork2/test/SimpleAction2-validationAlias-validation.xml")),
|
||||
new ArrayList());
|
||||
actionValidatorManager.getValidators(SimpleAction.class, alias);
|
||||
actionValidatorManager.getValidators(SimpleAction2.class, alias);
|
||||
mockValidatorFileParser.verify();
|
||||
assertThat(validators).hasSize(13).map(Validator::getClass).containsExactly(
|
||||
ExpressionValidator.class,
|
||||
RequiredFieldValidator.class,
|
||||
IntRangeFieldValidator.class,
|
||||
DoubleRangeFieldValidator.class,
|
||||
DateRangeFieldValidator.class,
|
||||
IntRangeFieldValidator.class,
|
||||
IntRangeFieldValidator.class,
|
||||
LongRangeFieldValidator.class,
|
||||
ShortRangeFieldValidator.class,
|
||||
RequiredFieldValidator.class,
|
||||
IntRangeFieldValidator.class,
|
||||
RequiredFieldValidator.class,
|
||||
RequiredStringValidator.class
|
||||
);
|
||||
assertThat(validators).hasSize(13).map(Validator::getValidatorType).containsExactly(
|
||||
"expression",
|
||||
"required",
|
||||
"int",
|
||||
"double",
|
||||
"date",
|
||||
"int",
|
||||
"int",
|
||||
"long",
|
||||
"short",
|
||||
"required",
|
||||
"int",
|
||||
"required",
|
||||
"requiredstring"
|
||||
);
|
||||
assertThat(validators).hasSize(13).map(Validator::getDefaultMessage).containsExactly(
|
||||
"Foo must be greater than Bar. Foo = ${foo}, Bar = ${bar}.",
|
||||
"You must enter a value for bar.",
|
||||
"bar must be between ${min} and ${max}, current value is ${bar}.",
|
||||
"percentage must be between ${minExclusive} and ${maxExclusive}, current value is ${percentage}.",
|
||||
"The date must be between 12-22-2002 and 12-25-2002.",
|
||||
"Could not find foo.range!",
|
||||
"Could not find baz.range!",
|
||||
"Could not find foo.range!",
|
||||
"Could not find foo.range!",
|
||||
"You must enter a value for baz.",
|
||||
"baz out of range.",
|
||||
"You must enter a value for data.",
|
||||
"You must enter a value for data."
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to verify WW-3850.
|
||||
*
|
||||
* @since 2.3.5
|
||||
*/
|
||||
public void testBuildsValidatorsForClassError() {
|
||||
// for this test we need to have a file manager with reloadingConfigs to true
|
||||
@@ -188,12 +194,8 @@ public class DefaultActionValidatorManagerTest extends XWorkTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// TODO: this all need to be converted to real unit tests
|
||||
|
||||
public void testSkipUserMarkerActionLevelShortCircuit() {
|
||||
// get validators
|
||||
List validatorList = actionValidatorManager.getValidators(User.class, null);
|
||||
List<Validator> validatorList = actionValidatorManager.getValidators(User.class, null);
|
||||
assertEquals(10, validatorList.size());
|
||||
|
||||
try {
|
||||
@@ -202,16 +204,17 @@ public class DefaultActionValidatorManagerTest extends XWorkTestCase {
|
||||
user.setEmail("bad_email");
|
||||
user.setEmail2("bad_email");
|
||||
|
||||
ValidatorContext context = new GenericValidatorContext(user);
|
||||
ValidationAware validationAware = new SimpleAction();
|
||||
ValidatorContext context = new DelegatingValidatorContext(validationAware, actionValidatorManager.textProviderFactory);
|
||||
actionValidatorManager.validate(user, null, context);
|
||||
assertTrue(context.hasFieldErrors());
|
||||
|
||||
// check field errors
|
||||
List l = (List) context.getFieldErrors().get("email");
|
||||
List<String> l = context.getFieldErrors().get("email");
|
||||
assertNotNull(l);
|
||||
assertEquals(1, l.size());
|
||||
assertEquals("Not a valid e-mail.", l.get(0));
|
||||
l = (List) context.getFieldErrors().get("email2");
|
||||
l = context.getFieldErrors().get("email2");
|
||||
assertNotNull(l);
|
||||
assertEquals(2, l.size());
|
||||
assertEquals("Not a valid e-mail2.", l.get(0));
|
||||
@@ -219,19 +222,17 @@ public class DefaultActionValidatorManagerTest extends XWorkTestCase {
|
||||
|
||||
// check action errors
|
||||
assertTrue(context.hasActionErrors());
|
||||
l = (List) context.getActionErrors();
|
||||
l = new ArrayList<>(context.getActionErrors());
|
||||
assertNotNull(l);
|
||||
assertEquals(2, l.size()); // both expression test failed see User-validation.xml
|
||||
assertEquals("Email does not start with mark", l.get(0));
|
||||
} catch (ValidationException ex) {
|
||||
ex.printStackTrace();
|
||||
fail("Validation error: " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testSkipAllActionLevelShortCircuit2() {
|
||||
// get validators
|
||||
List validatorList = actionValidatorManager.getValidators(User.class, null);
|
||||
List<Validator> validatorList = actionValidatorManager.getValidators(User.class, null);
|
||||
assertEquals(10, validatorList.size());
|
||||
|
||||
try {
|
||||
@@ -244,34 +245,30 @@ public class DefaultActionValidatorManagerTest extends XWorkTestCase {
|
||||
user.setEmail("mark_bad_email_for_field_val@foo.com");
|
||||
user.setEmail2("mark_bad_email_for_field_val@foo.com");
|
||||
|
||||
ValidatorContext context = new GenericValidatorContext(user);
|
||||
ValidationAware validationAware = new SimpleAction();
|
||||
ValidatorContext context = new DelegatingValidatorContext(validationAware, actionValidatorManager.textProviderFactory);
|
||||
actionValidatorManager.validate(user, null, context);
|
||||
assertTrue(context.hasFieldErrors());
|
||||
|
||||
// check field errors
|
||||
// we have an error in this field level, email does not ends with mycompany.com
|
||||
List l = (List) context.getFieldErrors().get("email");
|
||||
List<String> l = context.getFieldErrors().get("email");
|
||||
assertNotNull(l);
|
||||
assertEquals(1, l.size()); // because email-field-val is short-circuit
|
||||
assertEquals("Email not from the right company.", l.get(0));
|
||||
|
||||
|
||||
// check action errors
|
||||
l = (List) context.getActionErrors();
|
||||
l = new ArrayList<>(context.getActionErrors());
|
||||
assertFalse(context.hasActionErrors());
|
||||
assertEquals(0, l.size());
|
||||
|
||||
|
||||
} catch (ValidationException ex) {
|
||||
ex.printStackTrace();
|
||||
fail("Validation error: " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void testActionLevelShortCircuit() throws Exception {
|
||||
|
||||
List validatorList = actionValidatorManager.getValidators(User.class, null);
|
||||
List<Validator> validatorList = actionValidatorManager.getValidators(User.class, null);
|
||||
assertEquals(10, validatorList.size());
|
||||
|
||||
User user = new User();
|
||||
@@ -280,18 +277,18 @@ public class DefaultActionValidatorManagerTest extends XWorkTestCase {
|
||||
user.setEmail("tmjee(at)yahoo.co.uk");
|
||||
user.setEmail("tm_jee(at)yahoo.co.uk");
|
||||
|
||||
ValidatorContext context = new GenericValidatorContext(user);
|
||||
ValidationAware validationAware = new SimpleAction();
|
||||
ValidatorContext context = new DelegatingValidatorContext(validationAware, actionValidatorManager.textProviderFactory);
|
||||
actionValidatorManager.validate(user, null, context);
|
||||
|
||||
// check field level errors
|
||||
// check field level errors
|
||||
// shouldn't have any because action error prevents validation of anything else
|
||||
List l = (List) context.getFieldErrors().get("email2");
|
||||
List<String> l = context.getFieldErrors().get("email2");
|
||||
assertNull(l);
|
||||
|
||||
|
||||
// check action errors
|
||||
assertTrue(context.hasActionErrors());
|
||||
l = (List) context.getActionErrors();
|
||||
l = new ArrayList<>(context.getActionErrors());
|
||||
assertNotNull(l);
|
||||
// we only get one, because UserMarker-validation.xml action-level validator
|
||||
// already sc it :-)
|
||||
@@ -299,10 +296,8 @@ public class DefaultActionValidatorManagerTest extends XWorkTestCase {
|
||||
assertEquals("Email not the same as email2", l.get(0));
|
||||
}
|
||||
|
||||
|
||||
public void testShortCircuitNoErrors() {
|
||||
// get validators
|
||||
List validatorList = actionValidatorManager.getValidators(User.class, null);
|
||||
List<Validator> validatorList = actionValidatorManager.getValidators(User.class, null);
|
||||
assertEquals(10, validatorList.size());
|
||||
|
||||
try {
|
||||
@@ -311,73 +306,72 @@ public class DefaultActionValidatorManagerTest extends XWorkTestCase {
|
||||
user.setEmail("mark@mycompany.com");
|
||||
user.setEmail2("mark@mycompany.com");
|
||||
|
||||
ValidatorContext context = new GenericValidatorContext(user);
|
||||
ValidationAware validationAware = new SimpleAction();
|
||||
ValidatorContext context = new DelegatingValidatorContext(validationAware, actionValidatorManager.textProviderFactory);
|
||||
actionValidatorManager.validate(user, null, context);
|
||||
assertFalse(context.hasErrors());
|
||||
} catch (ValidationException ex) {
|
||||
ex.printStackTrace();
|
||||
fail("Validation error: " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testFieldErrorsOrder() throws Exception {
|
||||
ValidationOrderAction action = new ValidationOrderAction();
|
||||
actionValidatorManager.validate(action, "actionContext");
|
||||
Map fieldErrors = action.getFieldErrors();
|
||||
Iterator i = fieldErrors.entrySet().iterator();
|
||||
ValidationOrderAction action = new ValidationOrderAction();
|
||||
actionValidatorManager.validate(action, "actionContext");
|
||||
Map<String, List<String>> fieldErrors = action.getFieldErrors();
|
||||
Iterator<Map.Entry<String, List<String>>> i = fieldErrors.entrySet().iterator();
|
||||
|
||||
assertNotNull(fieldErrors);
|
||||
assertEquals(fieldErrors.size(), 12);
|
||||
assertNotNull(fieldErrors);
|
||||
assertEquals(fieldErrors.size(), 12);
|
||||
|
||||
|
||||
Map.Entry e = (Map.Entry) i.next();
|
||||
assertEquals(e.getKey(), "username");
|
||||
assertEquals(((List)e.getValue()).get(0), "username required");
|
||||
Map.Entry<String, List<String>> e = i.next();
|
||||
assertEquals(e.getKey(), "username");
|
||||
assertEquals(e.getValue().get(0), "username required");
|
||||
|
||||
e = (Map.Entry) i.next();
|
||||
assertEquals(e.getKey(), "password");
|
||||
assertEquals(((List)e.getValue()).get(0), "password required");
|
||||
e = i.next();
|
||||
assertEquals(e.getKey(), "password");
|
||||
assertEquals((e.getValue()).get(0), "password required");
|
||||
|
||||
e = (Map.Entry) i.next();
|
||||
assertEquals(e.getKey(), "confirmPassword");
|
||||
assertEquals(((List)e.getValue()).get(0), "confirm password required");
|
||||
e = i.next();
|
||||
assertEquals(e.getKey(), "confirmPassword");
|
||||
assertEquals((e.getValue()).get(0), "confirm password required");
|
||||
|
||||
e = (Map.Entry) i.next();
|
||||
assertEquals(e.getKey(), "firstName");
|
||||
assertEquals(((List)e.getValue()).get(0), "first name required");
|
||||
e = i.next();
|
||||
assertEquals(e.getKey(), "firstName");
|
||||
assertEquals((e.getValue()).get(0), "first name required");
|
||||
|
||||
e = (Map.Entry) i.next();
|
||||
assertEquals(e.getKey(), "lastName");
|
||||
assertEquals(((List)e.getValue()).get(0), "last name required");
|
||||
e = i.next();
|
||||
assertEquals(e.getKey(), "lastName");
|
||||
assertEquals((e.getValue()).get(0), "last name required");
|
||||
|
||||
e = (Map.Entry) i.next();
|
||||
assertEquals(e.getKey(), "city");
|
||||
assertEquals(((List)e.getValue()).get(0), "city is required");
|
||||
e = i.next();
|
||||
assertEquals(e.getKey(), "city");
|
||||
assertEquals((e.getValue()).get(0), "city is required");
|
||||
|
||||
e = (Map.Entry) i.next();
|
||||
assertEquals(e.getKey(), "province");
|
||||
assertEquals(((List)e.getValue()).get(0), "province is required");
|
||||
e = i.next();
|
||||
assertEquals(e.getKey(), "province");
|
||||
assertEquals((e.getValue()).get(0), "province is required");
|
||||
|
||||
e = (Map.Entry) i.next();
|
||||
assertEquals(e.getKey(), "country");
|
||||
assertEquals(((List)e.getValue()).get(0), "country is required");
|
||||
e = i.next();
|
||||
assertEquals(e.getKey(), "country");
|
||||
assertEquals((e.getValue()).get(0), "country is required");
|
||||
|
||||
e = (Map.Entry) i.next();
|
||||
assertEquals(e.getKey(), "postalCode");
|
||||
assertEquals(((List)e.getValue()).get(0), "postal code is required");
|
||||
e = i.next();
|
||||
assertEquals(e.getKey(), "postalCode");
|
||||
assertEquals((e.getValue()).get(0), "postal code is required");
|
||||
|
||||
e = (Map.Entry) i.next();
|
||||
assertEquals(e.getKey(), "email");
|
||||
assertEquals(((List)e.getValue()).get(0), "email is required");
|
||||
e = i.next();
|
||||
assertEquals(e.getKey(), "email");
|
||||
assertEquals((e.getValue()).get(0), "email is required");
|
||||
|
||||
e = (Map.Entry) i.next();
|
||||
assertEquals(e.getKey(), "website");
|
||||
assertEquals(((List)e.getValue()).get(0), "website is required");
|
||||
|
||||
e = (Map.Entry) i.next();
|
||||
assertEquals(e.getKey(), "passwordHint");
|
||||
assertEquals(((List)e.getValue()).get(0), "password hint is required");
|
||||
e = i.next();
|
||||
assertEquals(e.getKey(), "website");
|
||||
assertEquals((e.getValue()).get(0), "website is required");
|
||||
|
||||
e = i.next();
|
||||
assertEquals(e.getKey(), "passwordHint");
|
||||
assertEquals((e.getValue()).get(0), "password hint is required");
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ import com.opensymphony.xwork2.config.entities.ActionConfig;
|
||||
import com.opensymphony.xwork2.conversion.impl.ConversionData;
|
||||
import org.easymock.EasyMock;
|
||||
|
||||
import java.sql.Date;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.HashMap;
|
||||
@@ -142,6 +144,15 @@ public class VisitorFieldValidatorTest extends XWorkTestCase {
|
||||
assertEquals(1, errors.size());
|
||||
}
|
||||
|
||||
public void testDateValidation() throws Exception {
|
||||
action.setBirthday(Date.valueOf(LocalDate.now().minusYears(20)));
|
||||
action.setContext("birthday");
|
||||
|
||||
validate("birthday");
|
||||
|
||||
assertFalse(action.hasFieldErrors());
|
||||
}
|
||||
|
||||
public void testContextIsOverriddenByContextParamInValidationXML() throws Exception {
|
||||
validate("visitorValidationAlias");
|
||||
assertTrue(action.hasFieldErrors());
|
||||
|
||||
+10
-1
@@ -22,6 +22,7 @@ import com.opensymphony.xwork2.ActionSupport;
|
||||
import com.opensymphony.xwork2.TestBean;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@@ -37,7 +38,7 @@ public class VisitorValidatorTestAction extends ActionSupport {
|
||||
private String context;
|
||||
private TestBean bean = new TestBean();
|
||||
private TestBean[] testBeanArray;
|
||||
|
||||
private Date birthday;
|
||||
|
||||
public VisitorValidatorTestAction() {
|
||||
testBeanArray = new TestBean[5];
|
||||
@@ -80,4 +81,12 @@ public class VisitorValidatorTestAction extends ActionSupport {
|
||||
public List<TestBean> getTestBeanList() {
|
||||
return testBeanList;
|
||||
}
|
||||
|
||||
public Date getBirthday() {
|
||||
return birthday;
|
||||
}
|
||||
|
||||
public void setBirthday(Date birthday) {
|
||||
this.birthday = birthday;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
package org.apache.struts2.interceptor;
|
||||
|
||||
import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.config.ConfigurationException;
|
||||
import com.opensymphony.xwork2.mock.MockActionInvocation;
|
||||
import org.apache.logging.log4j.util.Strings;
|
||||
import org.apache.struts2.StrutsInternalTestCase;
|
||||
@@ -32,6 +33,7 @@ import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
|
||||
@@ -74,8 +76,10 @@ public class CspInterceptorTest extends StrutsInternalTestCase {
|
||||
|
||||
public void testEnforcingCspHeadersSet() throws Exception {
|
||||
String reportUri = "/csp-reports";
|
||||
String reportTo = "csp-group";
|
||||
boolean enforcingMode = true;
|
||||
interceptor.setReportUri(reportUri);
|
||||
interceptor.setReportTo(reportTo);
|
||||
interceptor.setEnforcingMode(enforcingMode);
|
||||
session.setAttribute("nonce", "foo");
|
||||
|
||||
@@ -84,13 +88,15 @@ public class CspInterceptorTest extends StrutsInternalTestCase {
|
||||
assertNotNull("Nonce key does not exist", session.getAttribute("nonce"));
|
||||
assertFalse("Nonce value is empty", Strings.isEmpty((String) session.getAttribute("nonce")));
|
||||
assertNotEquals("New nonce value couldn't be set", "foo", session.getAttribute("nonce"));
|
||||
checkHeader(reportUri, enforcingMode);
|
||||
checkHeader(reportUri, reportTo, enforcingMode);
|
||||
}
|
||||
|
||||
public void testReportingCspHeadersSet() throws Exception {
|
||||
String reportUri = "/csp-reports";
|
||||
String reportTo = "csp-group";
|
||||
boolean enforcingMode = false;
|
||||
interceptor.setReportUri(reportUri);
|
||||
interceptor.setReportTo(reportTo);
|
||||
interceptor.setEnforcingMode(enforcingMode);
|
||||
session.setAttribute("nonce", "foo");
|
||||
|
||||
@@ -98,7 +104,7 @@ public class CspInterceptorTest extends StrutsInternalTestCase {
|
||||
|
||||
assertNotNull("Nonce value is empty", session.getAttribute("nonce"));
|
||||
assertNotEquals("New nonce value couldn't be set", "foo", session.getAttribute("nonce"));
|
||||
checkHeader(reportUri, enforcingMode);
|
||||
checkHeader(reportUri, reportTo, enforcingMode);
|
||||
}
|
||||
|
||||
public void test_uriSetOnlyWhenSetIsCalled() throws Exception {
|
||||
@@ -174,21 +180,89 @@ public class CspInterceptorTest extends StrutsInternalTestCase {
|
||||
checkHeader("/report-uri", enforcingMode);
|
||||
}
|
||||
|
||||
public void testNonExistingCspSettingsClassName() throws Exception {
|
||||
boolean enforcingMode = true;
|
||||
mai.setAction(new TestAction());
|
||||
request.setContextPath("/app");
|
||||
|
||||
interceptor.setEnforcingMode(enforcingMode);
|
||||
interceptor.setReportUri("/report-uri");
|
||||
interceptor.setPrependServletContext(false);
|
||||
|
||||
try {
|
||||
interceptor.setCspSettingsClassName("foo");
|
||||
interceptor.intercept(mai);
|
||||
fail("Expected exception");
|
||||
} catch (ConfigurationException e) {
|
||||
assertEquals("The class foo doesn't exist!", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testInvalidCspSettingsClassName() throws Exception {
|
||||
boolean enforcingMode = true;
|
||||
mai.setAction(new TestAction());
|
||||
request.setContextPath("/app");
|
||||
|
||||
interceptor.setEnforcingMode(enforcingMode);
|
||||
interceptor.setReportUri("/report-uri");
|
||||
interceptor.setPrependServletContext(false);
|
||||
|
||||
try {
|
||||
interceptor.setCspSettingsClassName(Integer.class.getName());
|
||||
interceptor.intercept(mai);
|
||||
fail("Expected exception");
|
||||
} catch (ConfigurationException e) {
|
||||
assertEquals("The class java.lang.Integer doesn't implement org.apache.struts2.interceptor.csp.CspSettings!", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testCustomCspSettingsClassName() throws Exception {
|
||||
boolean enforcingMode = true;
|
||||
mai.setAction(new TestAction());
|
||||
request.setContextPath("/app");
|
||||
|
||||
interceptor.setEnforcingMode(enforcingMode);
|
||||
interceptor.setReportUri("/report-uri");
|
||||
interceptor.setPrependServletContext(false);
|
||||
interceptor.setCspSettingsClassName(CustomDefaultCspSettings.class.getName());
|
||||
|
||||
interceptor.intercept(mai);
|
||||
|
||||
String header = response.getHeader(CspSettings.CSP_ENFORCE_HEADER);
|
||||
|
||||
// no other customization matters for this particular class
|
||||
assertEquals("foo", header);
|
||||
}
|
||||
|
||||
public void checkHeader(String reportUri, boolean enforcingMode) {
|
||||
checkHeader(reportUri, null, enforcingMode);
|
||||
}
|
||||
|
||||
public void checkHeader(String reportUri, String reportTo, boolean enforcingMode) {
|
||||
String expectedCspHeader;
|
||||
if (Strings.isEmpty(reportUri)) {
|
||||
expectedCspHeader = String.format("%s '%s'; %s 'nonce-%s' '%s' %s %s; %s '%s'; ",
|
||||
CspSettings.OBJECT_SRC, CspSettings.NONE,
|
||||
CspSettings.SCRIPT_SRC, session.getAttribute("nonce"), CspSettings.STRICT_DYNAMIC, CspSettings.HTTP, CspSettings.HTTPS,
|
||||
CspSettings.BASE_URI, CspSettings.NONE
|
||||
CspSettings.OBJECT_SRC, CspSettings.NONE,
|
||||
CspSettings.SCRIPT_SRC, session.getAttribute("nonce"), CspSettings.STRICT_DYNAMIC, CspSettings.HTTP, CspSettings.HTTPS,
|
||||
CspSettings.BASE_URI, CspSettings.NONE
|
||||
);
|
||||
} else {
|
||||
expectedCspHeader = String.format("%s '%s'; %s 'nonce-%s' '%s' %s %s; %s '%s'; %s %s",
|
||||
CspSettings.OBJECT_SRC, CspSettings.NONE,
|
||||
CspSettings.SCRIPT_SRC, session.getAttribute("nonce"), CspSettings.STRICT_DYNAMIC, CspSettings.HTTP, CspSettings.HTTPS,
|
||||
CspSettings.BASE_URI, CspSettings.NONE,
|
||||
CspSettings.REPORT_URI, reportUri
|
||||
);
|
||||
if (Strings.isEmpty(reportTo)) {
|
||||
expectedCspHeader = String.format("%s '%s'; %s 'nonce-%s' '%s' %s %s; %s '%s'; %s %s; ",
|
||||
CspSettings.OBJECT_SRC, CspSettings.NONE,
|
||||
CspSettings.SCRIPT_SRC, session.getAttribute("nonce"), CspSettings.STRICT_DYNAMIC, CspSettings.HTTP, CspSettings.HTTPS,
|
||||
CspSettings.BASE_URI, CspSettings.NONE,
|
||||
CspSettings.REPORT_URI, reportUri
|
||||
);
|
||||
} else {
|
||||
expectedCspHeader = String.format("%s '%s'; %s 'nonce-%s' '%s' %s %s; %s '%s'; %s %s; %s %s; ",
|
||||
CspSettings.OBJECT_SRC, CspSettings.NONE,
|
||||
CspSettings.SCRIPT_SRC, session.getAttribute("nonce"), CspSettings.STRICT_DYNAMIC, CspSettings.HTTP, CspSettings.HTTPS,
|
||||
CspSettings.BASE_URI, CspSettings.NONE,
|
||||
CspSettings.REPORT_URI, reportUri,
|
||||
CspSettings.REPORT_TO, reportTo
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
String header;
|
||||
@@ -207,10 +281,11 @@ public class CspInterceptorTest extends StrutsInternalTestCase {
|
||||
super.setUp();
|
||||
container.inject(interceptor);
|
||||
ActionContext context = ActionContext.getContext()
|
||||
.withServletRequest(request)
|
||||
.withServletResponse(response)
|
||||
.withSession(new SessionMap(request))
|
||||
.bind();
|
||||
.withContainer(container)
|
||||
.withServletRequest(request)
|
||||
.withServletResponse(response)
|
||||
.withSession(new SessionMap(request))
|
||||
.bind();
|
||||
mai.setInvocationContext(context);
|
||||
session = request.getSession();
|
||||
}
|
||||
@@ -230,4 +305,15 @@ public class CspInterceptorTest extends StrutsInternalTestCase {
|
||||
return settings;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom DefaultCspSettings class that overrides the createPolicyFormat method
|
||||
* to return a fixed value.
|
||||
*/
|
||||
public static class CustomDefaultCspSettings extends DefaultCspSettings {
|
||||
|
||||
protected String createPolicyFormat(HttpServletRequest request) {
|
||||
return "foo";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,6 +147,26 @@ public class I18nInterceptorTest extends TestCase {
|
||||
assertEquals(Locale.getDefault(), session.get(I18nInterceptor.DEFAULT_SESSION_ATTRIBUTE)); // should create a locale object
|
||||
}
|
||||
|
||||
public void testTrimableLocaleString1() throws Exception {
|
||||
prepare(I18nInterceptor.DEFAULT_PARAMETER, "de\n");
|
||||
|
||||
interceptor.intercept(mai);
|
||||
|
||||
assertFalse(mai.getInvocationContext().getParameters().get(I18nInterceptor.DEFAULT_PARAMETER).isDefined()); // should have been removed
|
||||
assertNotNull(session.get(I18nInterceptor.DEFAULT_SESSION_ATTRIBUTE)); // should be stored here
|
||||
assertEquals(Locale.GERMAN, session.get(I18nInterceptor.DEFAULT_SESSION_ATTRIBUTE)); // should create a locale object
|
||||
}
|
||||
|
||||
public void testTrimableLocaleString2() throws Exception {
|
||||
prepare(I18nInterceptor.DEFAULT_PARAMETER, "de ");
|
||||
|
||||
interceptor.intercept(mai);
|
||||
|
||||
assertFalse(mai.getInvocationContext().getParameters().get(I18nInterceptor.DEFAULT_PARAMETER).isDefined()); // should have been removed
|
||||
assertNotNull(session.get(I18nInterceptor.DEFAULT_SESSION_ATTRIBUTE)); // should be stored here
|
||||
assertEquals(Locale.GERMAN, session.get(I18nInterceptor.DEFAULT_SESSION_ATTRIBUTE)); // should create a locale object
|
||||
}
|
||||
|
||||
public void testWithVariant() throws Exception {
|
||||
prepare(I18nInterceptor.DEFAULT_PARAMETER, "ja_JP_JP");
|
||||
interceptor.intercept(mai);
|
||||
|
||||
+54
-6
@@ -20,6 +20,7 @@ package org.apache.struts2.interceptor.exec;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.NotSerializableException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.security.SecureRandom;
|
||||
@@ -42,6 +43,8 @@ import com.opensymphony.xwork2.ActionContext;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.mock.MockActionInvocation;
|
||||
|
||||
import static org.awaitility.Awaitility.await;
|
||||
|
||||
/**
|
||||
* Test case for BackgroundProcessTest.
|
||||
*/
|
||||
@@ -60,9 +63,9 @@ public class StrutsBackgroundProcessTest extends StrutsInternalTestCase {
|
||||
invocation.setInvocationContext(ActionContext.getContext());
|
||||
|
||||
StrutsBackgroundProcess bp = (StrutsBackgroundProcess) new StrutsBackgroundProcess(
|
||||
invocation,
|
||||
"BackgroundProcessTest.testSerializeDeserialize",
|
||||
Thread.MIN_PRIORITY
|
||||
invocation,
|
||||
"BackgroundProcessTest.testSerializeDeserialize",
|
||||
Thread.MIN_PRIORITY
|
||||
).prepare();
|
||||
executor.execute(bp);
|
||||
|
||||
@@ -121,6 +124,31 @@ public class StrutsBackgroundProcessTest extends StrutsInternalTestCase {
|
||||
assertEquals(100, mutableState.get());
|
||||
}
|
||||
|
||||
public void testErrorableProcesses1() {
|
||||
MockActionInvocationWithActionInvoker invocation = new MockActionInvocationWithActionInvoker(() -> {
|
||||
throw new IllegalStateException("boom");
|
||||
});
|
||||
|
||||
BackgroundProcess bp = new ErrorableBackgroundProcess(invocation, null).prepare();
|
||||
executor.execute(bp);
|
||||
|
||||
await().atLeast(100, TimeUnit.MILLISECONDS).until(bp::isDone);
|
||||
|
||||
assertTrue("afterInvocation not called in case of exception", ((ErrorableBackgroundProcess) bp).isDoneAfter());
|
||||
}
|
||||
|
||||
public void testErrorableProcesses2() {
|
||||
MockActionInvocationWithActionInvoker invocation = new MockActionInvocationWithActionInvoker(() -> "done");
|
||||
|
||||
IllegalStateException expected = new IllegalStateException("after!");
|
||||
BackgroundProcess bp = new ErrorableBackgroundProcess(invocation, expected).prepare();
|
||||
executor.execute(bp);
|
||||
|
||||
await().atLeast(100, TimeUnit.MILLISECONDS).until(bp::isDone);
|
||||
|
||||
assertEquals(expected, bp.getException());
|
||||
}
|
||||
|
||||
public void testUnpreparedProcess() throws ExecutionException, InterruptedException, TimeoutException {
|
||||
// given
|
||||
MockActionInvocationWithActionInvoker invocation = new MockActionInvocationWithActionInvoker(() -> "done");
|
||||
@@ -148,7 +176,8 @@ public class StrutsBackgroundProcessTest extends StrutsInternalTestCase {
|
||||
}
|
||||
|
||||
private static class NotSerializableException extends Exception {
|
||||
private MockHttpServletRequest notSerializableField;
|
||||
@SuppressWarnings("unused")
|
||||
private final MockHttpServletRequest notSerializableField;
|
||||
|
||||
NotSerializableException(MockHttpServletRequest notSerializableField) {
|
||||
this.notSerializableField = notSerializableField;
|
||||
@@ -171,10 +200,29 @@ class LockBackgroundProcess extends StrutsBackgroundProcess {
|
||||
super.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ErrorableBackgroundProcess extends StrutsBackgroundProcess {
|
||||
|
||||
private final Exception afterException;
|
||||
private boolean doneAfter;
|
||||
|
||||
public ErrorableBackgroundProcess(ActionInvocation invocation, Exception afterException) {
|
||||
super(invocation, "errorabale process", Thread.NORM_PRIORITY);
|
||||
this.afterException = afterException;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void afterInvocation() throws Exception {
|
||||
super.afterInvocation();
|
||||
lock.notify();
|
||||
if (afterException != null) {
|
||||
throw afterException;
|
||||
} else {
|
||||
super.afterInvocation();
|
||||
doneAfter = true;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isDoneAfter() {
|
||||
return doneAfter;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,14 +25,10 @@ import org.springframework.mock.web.MockJspWriter;
|
||||
|
||||
import jakarta.servlet.jsp.JspException;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
public class SetTagTest extends AbstractUITagTest {
|
||||
|
||||
Chewbacca chewie;
|
||||
SetTag tag;
|
||||
|
||||
private Chewbacca chewie;
|
||||
private SetTag tag;
|
||||
|
||||
public void testApplicationScope() throws JspException {
|
||||
tag.setName("foo");
|
||||
@@ -400,6 +396,50 @@ public class SetTagTest extends AbstractUITagTest {
|
||||
strutsBodyTagsAreReflectionEqual(tag, freshTag));
|
||||
}
|
||||
|
||||
public void testShortVarNameInPageScope() throws JspException {
|
||||
tag.setName("f");
|
||||
tag.setValue("name");
|
||||
tag.setScope("page");
|
||||
|
||||
tag.doStartTag();
|
||||
tag.doEndTag();
|
||||
|
||||
assertEquals("chewie", pageContext.getAttribute("f"));
|
||||
}
|
||||
|
||||
public void testShortVarNameInRequestScope() throws JspException {
|
||||
tag.setName("f");
|
||||
tag.setValue("name");
|
||||
tag.setScope("request");
|
||||
|
||||
tag.doStartTag();
|
||||
tag.doEndTag();
|
||||
|
||||
assertEquals("chewie", request.getAttribute("f"));
|
||||
}
|
||||
|
||||
public void testShortVarNameInSessionScope() throws JspException {
|
||||
tag.setName("f");
|
||||
tag.setValue("name");
|
||||
tag.setScope("session");
|
||||
|
||||
tag.doStartTag();
|
||||
tag.doEndTag();
|
||||
|
||||
assertEquals("chewie", session.get("f"));
|
||||
}
|
||||
|
||||
public void testShortVarNameInApplicationScope() throws JspException {
|
||||
tag.setName("f");
|
||||
tag.setValue("name");
|
||||
tag.setScope("application");
|
||||
|
||||
tag.doStartTag();
|
||||
tag.doEndTag();
|
||||
|
||||
assertEquals("chewie", servletContext.getAttribute("f"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
@@ -411,9 +451,9 @@ public class SetTagTest extends AbstractUITagTest {
|
||||
}
|
||||
|
||||
|
||||
public class Chewbacca {
|
||||
String name;
|
||||
boolean furry;
|
||||
public static class Chewbacca {
|
||||
private String name;
|
||||
private boolean furry;
|
||||
|
||||
public Chewbacca(String name, boolean furry) {
|
||||
this.name = name;
|
||||
|
||||
+8
@@ -26,4 +26,12 @@
|
||||
<message>You must enter a context.</message>
|
||||
</field-validator>
|
||||
</field>
|
||||
<field name="birthday">
|
||||
<field-validator type="fieldexpression">
|
||||
<param name="expression"><![CDATA[
|
||||
(birthday == null || birthday.before(new java.util.Date()))
|
||||
]]></param>
|
||||
<message key="errors_birthday" />
|
||||
</field-validator>
|
||||
</field>
|
||||
</validators>
|
||||
|
||||
+11
-1
@@ -40,7 +40,7 @@
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<version>3.2.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>compile</phase>
|
||||
@@ -103,6 +103,16 @@
|
||||
<artifactId>log4j-jcl</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
|
||||
+6
-12
@@ -68,10 +68,7 @@ import jakarta.el.MapELResolver;
|
||||
import jakarta.el.ResourceBundleELResolver;
|
||||
import jakarta.servlet.jsp.JspFactory;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
@@ -103,21 +100,18 @@ public class StrutsTilesContainerFactory extends BasicTilesContainerFactory {
|
||||
public static final String PATTERN_WILDCARD = "WILDCARD";
|
||||
public static final String PATTERN_REGEXP = "REGEXP";
|
||||
|
||||
/**
|
||||
* Default pattern to be used to collect Tiles definitions if user didn't configure any
|
||||
*/
|
||||
public static final Set<String> TILES_DEFAULT_PATTERNS = TextParseUtil.commaDelimitedStringToSet("*tiles*.xml");
|
||||
|
||||
/**
|
||||
* Default pattern to be used to collect Tiles definitions if user didn't configure any
|
||||
*
|
||||
* @deprecated since Struts 6.4.0, use {@link #TILES_DEFAULT_PATTERNS} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String TILES_DEFAULT_PATTERN = "/WEB-INF/**/tiles*.xml,classpath*:META-INF/**/tiles*.xml";
|
||||
|
||||
/**
|
||||
* Default pattern to be used to collect Tiles definitions if user didn't configure any
|
||||
*/
|
||||
public static final Set<String> TILES_DEFAULT_PATTERNS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
|
||||
"/WEB-INF/**/tiles*.xml",
|
||||
"classpath*:META-INF/**/tiles*.xml"
|
||||
)));
|
||||
public static final String TILES_DEFAULT_PATTERN = String.join(",", TILES_DEFAULT_PATTERNS);
|
||||
|
||||
/**
|
||||
* Supported expression languages
|
||||
|
||||
+4
-5
@@ -43,7 +43,7 @@ public class StrutsWildcardServletApplicationContext extends ServletApplicationC
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(StrutsWildcardServletApplicationContext.class);
|
||||
|
||||
private ResourceFinder finder;
|
||||
private final ResourceFinder finder;
|
||||
|
||||
public StrutsWildcardServletApplicationContext(ServletContext context) {
|
||||
super(context);
|
||||
@@ -64,16 +64,15 @@ public class StrutsWildcardServletApplicationContext extends ServletApplicationC
|
||||
}
|
||||
|
||||
try {
|
||||
Enumeration<URL> resources = getClass().getClassLoader().getResources("/");
|
||||
Enumeration<URL> resources = getClass().getClassLoader().getResources("");
|
||||
while (resources.hasMoreElements()) {
|
||||
URL resource = resources.nextElement();
|
||||
urls.add(resource);
|
||||
urls.add(resources.nextElement());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new ConfigurationException(e);
|
||||
}
|
||||
|
||||
finder = new ResourceFinder(urls.toArray(new URL[urls.size()]));
|
||||
finder = new ResourceFinder(urls.toArray(new URL[0]));
|
||||
}
|
||||
|
||||
public Collection<ApplicationResource> getResources(String path) {
|
||||
|
||||
+4
-4
@@ -36,6 +36,7 @@ import org.junit.Test;
|
||||
|
||||
import jakarta.servlet.ServletContext;
|
||||
import jakarta.servlet.jsp.JspFactory;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@@ -64,12 +65,11 @@ public class StrutsTilesContainerFactoryTest {
|
||||
Objects.requireNonNull(getClass().getResource("/org/apache/tiles/core/config/tiles-defs.xml"))
|
||||
);
|
||||
ApplicationResource classpathResource = new URLApplicationResource(
|
||||
"/org/apache/tiles/core/config/defs1.xml",
|
||||
Objects.requireNonNull(getClass().getResource("/org/apache/tiles/core/config/defs1.xml"))
|
||||
"/org/apache/tiles/core/config/tiles_defs1.xml",
|
||||
Objects.requireNonNull(getClass().getResource("/org/apache/tiles/core/config/tiles_defs1.xml"))
|
||||
);
|
||||
when(applicationContext.getInitParams()).thenReturn(Collections.emptyMap());
|
||||
when(applicationContext.getResources("/WEB-INF/**/tiles*.xml")).thenReturn(Collections.singleton(pathResource));
|
||||
when(applicationContext.getResources("classpath*:META-INF/**/tiles*.xml")).thenReturn(Collections.singleton(classpathResource));
|
||||
when(applicationContext.getResources("*tiles*.xml")).thenReturn(Arrays.asList(pathResource, classpathResource));
|
||||
|
||||
List<ApplicationResource> resources = factory.getSources(applicationContext);
|
||||
assertEquals("The urls list is not two-sized", 2, resources.size());
|
||||
|
||||
+78
@@ -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.tiles;
|
||||
|
||||
import org.apache.tiles.request.ApplicationResource;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.core.io.FileUrlResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
|
||||
import jakarta.servlet.ServletContext;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class StrutsWildcardServletApplicationContextTest {
|
||||
|
||||
private ServletContext context;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
URL resource = getClass().getResource("/");
|
||||
context = new MockServletContext(resource.getPath(), new ResourceLoader() {
|
||||
@Override
|
||||
public Resource getResource(String location) {
|
||||
try {
|
||||
String finalLocation = location.replaceAll("//", "/");
|
||||
if (finalLocation.endsWith("/")) {
|
||||
return new FileSystemResource(finalLocation);
|
||||
}
|
||||
return new FileUrlResource(finalLocation);
|
||||
} catch (MalformedURLException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader getClassLoader() {
|
||||
return StrutsWildcardServletApplicationContextTest.class.getClassLoader();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wildcardSupport() {
|
||||
StrutsWildcardServletApplicationContext applicationContext = new StrutsWildcardServletApplicationContext(context);
|
||||
|
||||
Collection<ApplicationResource> resources = applicationContext.getResources("*tiles*.xml");
|
||||
|
||||
assertThat(resources)
|
||||
.hasSize(1)
|
||||
.extracting(ApplicationResource::getLocalePath)
|
||||
.first().asString()
|
||||
.endsWith("/WEB-INF/tiles.xml");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!--
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
-->
|
||||
|
||||
<!DOCTYPE tiles-definitions PUBLIC
|
||||
"-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
|
||||
"http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
|
||||
|
||||
<tiles-definitions>
|
||||
|
||||
<!-- Doc index page description -->
|
||||
<definition name="top.mainLayout" template="/layout/classicLayout.jsp">
|
||||
<put-attribute name="title" value="Tiles Library Documentation"/>
|
||||
<put-attribute name="header" value="/common/header.jsp"/>
|
||||
<put-attribute name="menu" value="doc.menu.main"/>
|
||||
<put-attribute name="footer" value="/common/footer.jsp"/>
|
||||
<put-attribute name="body" value="doc.portal.body"/>
|
||||
<put-attribute name="bean" value="This is an object" type="object"/>
|
||||
</definition>
|
||||
|
||||
</tiles-definitions>
|
||||
@@ -0,0 +1,75 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!--
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
-->
|
||||
|
||||
<!DOCTYPE tiles-definitions PUBLIC
|
||||
"-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
|
||||
"http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
|
||||
|
||||
<!-- Definitions for Tiles documentation -->
|
||||
|
||||
<tiles-definitions>
|
||||
|
||||
<!-- ======================================================= -->
|
||||
<!-- Master definition -->
|
||||
<!-- ======================================================= -->
|
||||
|
||||
<!-- This definition will remain the same for all locales -->
|
||||
<definition name="test.common" template="/test.jsp">
|
||||
<put-attribute name="country" value="none"/>
|
||||
<put-attribute name="title" value="Common Definition" />
|
||||
<put-attribute name="header" value="/common/header.jsp" />
|
||||
<put-attribute name="menu" value="doc.menu.main" />
|
||||
<put-attribute name="footer" value="/common/footer.jsp" />
|
||||
<put-attribute name="body" value="doc.portal.body" />
|
||||
</definition>
|
||||
|
||||
<!-- Doc index page description -->
|
||||
<definition name="test.def1" template="/test.jsp">
|
||||
<put-attribute name="country" value="default"/>
|
||||
<put-attribute name="title" value="Tiles Library Documentation" />
|
||||
<put-attribute name="header" value="/common/header.jsp" />
|
||||
<put-attribute name="menu" value="doc.menu.main" />
|
||||
<put-attribute name="footer" value="/common/footer.jsp" />
|
||||
<put-attribute name="body" value="doc.portal.body" />
|
||||
</definition>
|
||||
|
||||
<!-- This definition will be extended -->
|
||||
<definition name="test.def.toextend" template="/test.jsp">
|
||||
<put-attribute name="country" value="default"/>
|
||||
<put-attribute name="title" value="Definition to be extended" />
|
||||
<put-attribute name="header" value="/common/header.jsp" />
|
||||
<put-attribute name="menu" value="doc.menu.main" />
|
||||
<put-attribute name="footer" value="/common/footer.jsp" />
|
||||
<put-attribute name="body" value="doc.portal.body" />
|
||||
</definition>
|
||||
|
||||
<!-- This definition will be overridden -->
|
||||
<definition name="test.def.overridden" template="/test.jsp">
|
||||
<put-attribute name="country" value="default"/>
|
||||
<put-attribute name="title" value="Definition to be overridden" />
|
||||
<put-attribute name="header" value="/common/header.jsp" />
|
||||
<put-attribute name="menu" value="doc.menu.main" />
|
||||
<put-attribute name="footer" value="/common/footer.jsp" />
|
||||
<put-attribute name="body" value="doc.portal.body" />
|
||||
</definition>
|
||||
|
||||
</tiles-definitions>
|
||||
@@ -110,17 +110,17 @@
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
|
||||
<!-- dependency versions in alphanumeric order -->
|
||||
<asm.version>9.6</asm.version>
|
||||
<asm.version>9.7</asm.version>
|
||||
<byte-buddy.version>1.14.11</byte-buddy.version>
|
||||
<freemarker.version>2.3.32</freemarker.version>
|
||||
<freemarker.version>2.3.33</freemarker.version>
|
||||
<hibernate-validator.version>8.0.1.Final</hibernate-validator.version>
|
||||
<jackson.version>2.16.0</jackson.version>
|
||||
<jackson.version>2.17.1</jackson.version>
|
||||
<log4j2.version>2.23.1</log4j2.version>
|
||||
<maven-surefire-plugin.version>3.2.5</maven-surefire-plugin.version>
|
||||
<mockito.version>5.8.0</mockito.version>
|
||||
<ognl.version>3.3.5</ognl.version>
|
||||
<sitemesh.version>2.5.0</sitemesh.version>
|
||||
<slf4j.version>2.0.12</slf4j.version>
|
||||
<slf4j.version>2.0.13</slf4j.version>
|
||||
<spring.platformVersion>6.0.13</spring.platformVersion>
|
||||
<tiles.version>3.0.8</tiles.version>
|
||||
<tiles-request.version>1.0.7</tiles-request.version>
|
||||
@@ -206,7 +206,7 @@
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>0.8.11</version>
|
||||
<version>0.8.12</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>prepare-agent</id>
|
||||
@@ -240,7 +240,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-project-info-reports-plugin</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.5.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
@@ -287,7 +287,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<version>3.3.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.rat</groupId>
|
||||
@@ -332,7 +332,7 @@
|
||||
<plugin>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-maven</artifactId>
|
||||
<version>8.4.2</version>
|
||||
<version>9.2.0</version>
|
||||
<configuration>
|
||||
<suppressionFiles>
|
||||
<suppressionFile>src/etc/project-suppression.xml</suppressionFile>
|
||||
@@ -485,7 +485,7 @@
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>versions-maven-plugin</artifactId>
|
||||
<version>2.16.1</version>
|
||||
<version>2.16.2</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
@@ -730,6 +730,13 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.awaitility</groupId>
|
||||
<artifactId>awaitility</artifactId>
|
||||
<version>4.2.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
@@ -826,7 +833,7 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-text</artifactId>
|
||||
<version>1.11.0</version>
|
||||
<version>1.12.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-el</groupId>
|
||||
@@ -914,7 +921,7 @@
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>3.25.2</version>
|
||||
<version>3.25.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -978,7 +985,7 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-compress</artifactId>
|
||||
<version>1.26.0</version>
|
||||
<version>1.26.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
Reference in New Issue
Block a user