[
https://issues.apache.org/jira/browse/WW-5233?focusedWorklogId=868411&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-868411
]
ASF GitHub Bot logged work on WW-5233:
--------------------------------------
Author: ASF GitHub Bot
Created on: 29/Jun/23 10:52
Start Date: 29/Jun/23 10:52
Worklog Time Spent: 10m
Work Description: github-code-scanning[bot] commented on code in PR #608:
URL: https://github.com/apache/struts/pull/608#discussion_r1246462268
##########
plugins/tiles/src/main/java/org/apache/tiles/core/definition/digester/DigesterDefinitionsReader.java:
##########
@@ -0,0 +1,464 @@
+/*
+ * 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.tiles.core.definition.digester;
+
+import org.apache.commons.digester.Digester;
+import org.apache.commons.digester.Rule;
+import org.apache.tiles.api.Attribute;
+import org.apache.tiles.api.Definition;
+import org.apache.tiles.api.Expression;
+import org.apache.tiles.api.ListAttribute;
+import org.apache.tiles.core.definition.DefinitionsFactoryException;
+import org.apache.tiles.core.definition.DefinitionsReader;
+import org.xml.sax.Attributes;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Reads {@link Definition} objects from
+ * an XML InputStream using Digester. <p/>
+ * <p>
+ * This <code>DefinitionsReader</code> implementation expects the source to be
+ * passed as an <code>InputStream</code>. It parses XML data from the source
+ * and builds a Map of Definition objects.
+ * </p>
+ * <p/>
+ * <p>
+ * The Digester object can be configured by passing in initialization
+ * parameters. Currently the only parameter that is supported is the
+ * <code>validating</code> parameter. This value is set to <code>false</code>
+ * by default. To enable DTD validation for XML Definition files, give the init
+ * method a parameter with a key of
+ *
<code>org.apache.tiles.definition.digester.DigesterDefinitionsReader.PARSER_VALIDATE</code>
+ * and a value of <code>"true"</code>. <p/>
+ * <p>
+ * The Definition objects are stored internally in a Map. The Map is stored as
+ * an instance variable rather than a local variable in the <code>read</code>
+ * method. This means that instances of this class are <strong>not</strong>
+ * thread-safe and access by multiple threads must be synchronized.
+ * </p>
+ */
+public class DigesterDefinitionsReader implements DefinitionsReader {
+
+ /**
+ * Digester validation parameter name.
+ */
+ public static final String PARSER_VALIDATE_PARAMETER_NAME =
"org.apache.tiles.definition.digester.DigesterDefinitionsReader.PARSER_VALIDATE";
+
+ // Digester rules constants for tag interception.
+
+ /**
+ * Intercepts a <definition> tag.
+ */
+ private static final String DEFINITION_TAG =
"tiles-definitions/definition";
+
+ /**
+ * Intercepts a <put-attribute> tag.
+ */
+ private static final String PUT_TAG = "*/definition/put-attribute";
+
+ /**
+ * Intercepts a <definition> inside a <put-attribute> tag.
+ */
+ private static final String PUT_DEFINITION_TAG =
"*/put-attribute/definition";
+
+ /**
+ * Intercepts a <definition> inside an <add-attribute> tag.
+ */
+ private static final String ADD_DEFINITION_TAG =
"*/add-attribute/definition";
+
+ /**
+ * Intercepts a <put-list-attribute> tag inside a %lt;definition>
+ * tag.
+ */
+ private static final String DEF_LIST_TAG =
"*/definition/put-list-attribute";
+
+ /**
+ * Intercepts a <add-attribute> tag.
+ */
+ private static final String ADD_LIST_ELE_TAG = "*/add-attribute";
+
+ /**
+ * Intercepts a <add-list-attribute> tag.
+ */
+ private static final String NESTED_LIST = "*/add-list-attribute";
+
+ // Handler class names.
+
+ /**
+ * The handler to create definitions.
+ *
+ * @since 2.1.0
+ */
+ protected static final String DEFINITION_HANDLER_CLASS =
+ Definition.class.getName();
+
+ /**
+ * The handler to create attributes.
+ *
+ * @since 2.1.0
+ */
+ protected static final String PUT_ATTRIBUTE_HANDLER_CLASS =
+ Attribute.class.getName();
+
+ /**
+ * The handler to create list attributes.
+ *
+ * @since 2.1.0
+ */
+ protected static final String LIST_HANDLER_CLASS =
+ ListAttribute.class.getName();
+
+ /**
+ * Digester rule to manage definition filling.
+ *
+ * @since 2.1.2
+ */
+ public static class FillDefinitionRule extends Rule {
+
+ /** {@inheritDoc} */
+ @Override
+ public void begin(String namespace, String name, Attributes
attributes) {
+ Definition definition = (Definition) digester.peek();
+ definition.setName(attributes.getValue("name"));
+ definition.setPreparer(attributes.getValue("preparer"));
+ String extendsAttribute = attributes.getValue("extends");
+ definition.setExtends(extendsAttribute);
+
+ String template = attributes.getValue("template");
+ Attribute attribute = Attribute.createTemplateAttribute(template);
+ attribute.setExpressionObject(Expression
+ .createExpressionFromDescribedExpression(attributes
+ .getValue("templateExpression")));
+ attribute.setRole(attributes.getValue("role"));
+ String templateType = attributes.getValue("templateType");
+ if (templateType != null) {
+ attribute.setRenderer(templateType);
+ } else if (extendsAttribute != null) {
+ attribute.setRenderer(null);
+ }
+ definition.setTemplateAttribute(attribute);
+ }
+ }
+
+ /**
+ * Digester rule to manage attribute filling.
+ *
+ * @since 2.1.0
+ */
+ public static class FillAttributeRule extends Rule {
+
+ /** {@inheritDoc} */
+ @Override
+ public void begin(String namespace, String name, Attributes
attributes) {
+ Attribute attribute = (Attribute) digester.peek();
+ attribute.setValue(attributes.getValue("value"));
+ String expression = attributes.getValue("expression");
+ attribute.setExpressionObject(Expression
+ .createExpressionFromDescribedExpression(expression));
+ attribute.setRole(attributes.getValue("role"));
+ attribute.setRenderer(attributes.getValue("type"));
+ }
+ }
+
+ /**
+ * Digester rule to manage assignment of the attribute to the parent
+ * element.
+ *
+ * @since 2.1.0
+ */
+ public static class PutAttributeRule extends Rule {
+
+ /** {@inheritDoc} */
+ @Override
+ public void begin(String namespace, String name, Attributes
attributes) {
+ Attribute attribute = (Attribute) digester.peek(0);
+ Definition definition = (Definition) digester.peek(1);
+ definition.putAttribute(attributes.getValue("name"), attribute,
+ "true".equals(attributes.getValue("cascade")));
+ }
+ }
+
+ /**
+ * Digester rule to manage assignment of a nested definition in an
attribute
+ * value.
+ *
+ * @since 2.1.0
+ */
+ public class AddNestedDefinitionRule extends Rule {
+
+ /** {@inheritDoc} */
+ @Override
+ public void begin(String namespace, String name, Attributes
attributes) {
+ Definition definition = (Definition) digester.peek(0);
+ if (definition.getName() == null) {
+ definition.setName(getNextUniqueDefinitionName(definitions));
+ }
+ Attribute attribute = (Attribute) digester.peek(1);
+ attribute.setValue(definition.getName());
+ attribute.setRenderer("definition");
+ }
+ }
+
+ /**
+ * <code>Digester</code> object used to read Definition data
+ * from the source.
+ */
+ protected Digester digester;
+
+ /**
+ * The set of public identifiers, and corresponding resource names for
+ * the versions of the configuration file DTDs we know about. There
+ * <strong>MUST</strong> be an even number of Strings in this list!
+ */
+ protected String[] registrations;
+
+ /**
+ * Stores Definition objects.
+ */
+ private Map<String, Definition> definitions;
+
+ /**
+ * Index to be used to create unique definition names for anonymous
+ * (nested) definitions.
+ */
+ private int anonymousDefinitionIndex = 1;
+
+ /**
+ * Creates a new instance of DigesterDefinitionsReader.
+ */
+ public DigesterDefinitionsReader() {
+ digester = new Digester();
+ digester.setNamespaceAware(true);
+ digester.setUseContextClassLoader(true);
+ digester.setErrorHandler(new ThrowingErrorHandler());
+
+ // Register our local copy of the DTDs that we can find
+ String[] registrations = getRegistrations();
+ for (int i = 0; i < registrations.length; i += 2) {
+ URL url = this.getClass().getResource(
+ registrations[i + 1]);
+ if (url != null) {
+ digester.register(registrations[i], url.toString());
+ }
+ }
+
+ initSyntax(digester);
+ }
+
+ /**
+ * Sets the validation of XML files.
+ *
+ * @param validating <code>true</code> means that XML validation is turned
+ * on. <code>false</code> otherwise.
+ * @since 3.3.0
+ */
+ public void setValidating(boolean validating) {
+ digester.setValidating(validating);
+ }
+
+ /**
+ * Reads <code>{@link Definition}</code> objects from a source.
+ * <p/>
+ * Implementations should publish what type of source object is expected.
+ *
+ * @param source The <code>InputStream</code> source from which definitions
+ * will be read.
+ * @return a Map of <code>Definition</code> objects read from
+ * the source.
+ * @throws DefinitionsFactoryException If the source is invalid or
+ * an error occurs when reading definitions.
+ */
+ public Map<String, Definition> read(Object source) {
+ // This is an instance variable instead of a local variable because
+ // we want to be able to call the addDefinition method to populate it.
+ // But we reset the Map here, which, of course, has threading
implications.
+ definitions = new LinkedHashMap<>();
+
+ if (source == null) {
+ // Perhaps we should throw an exception here.
+ return null;
+ }
+
+ InputStream input;
+ try {
+ input = (InputStream) source;
+ } catch (ClassCastException e) {
+ throw new DefinitionsFactoryException(
+ "Invalid source type. Requires java.io.InputStream.", e);
+ }
+
+ try {
+ // set first object in stack
+ //digester.clear();
+ digester.push(this);
+ // parse
+ digester.parse(input);
Review Comment:
## Resolving XML external entity in user-controlled data
XML parsing depends on a [user-provided value](1) without guarding against
external entity expansion.
XML parsing depends on a [user-provided value](2) without guarding against
external entity expansion.
[Show more
details](https://github.com/apache/struts/security/code-scanning/235)
Issue Time Tracking
-------------------
Worklog Id: (was: 868411)
Time Spent: 3h 20m (was: 3h 10m)
> Include Apache Tiles code base in the Tiles plugin
> --------------------------------------------------
>
> Key: WW-5233
> URL: https://issues.apache.org/jira/browse/WW-5233
> Project: Struts 2
> Issue Type: Improvement
> Components: Plugin - Tiles
> Reporter: Lukasz Lenart
> Priority: Major
> Fix For: 6.3.0
>
> Time Spent: 3h 20m
> Remaining Estimate: 0h
>
> Apache Tiles has retired and it isn't maintained anymore. There are some
> outstanding security issues that can be addressed right now. It will be
> easier to maintain the code base as a part of the Tiles plugin instead of
> taking the project back from attick.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)