Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## 3.5.0
### Changed
- #214 Trim attribute values

## 3.4.0
### Changed
- fix: #153 Invalid status code: 524
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.lfenergy.shapeshifter.core.common.xml;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
import org.xml.sax.helpers.XMLFilterImpl;

/**
* A custom XML filter that trims whitespace from the values of XML element attributes.
* <p>
* This filter extends the {@link XMLFilterImpl} class, allowing it to intercept and modify
* the XML parsing process. Specifically, it overrides the {@code startElement} method to
* ensure that all attribute values are stripped of leading and trailing whitespace.
* </p>
*/
class AttributeTrimmingFilter extends XMLFilterImpl {

@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
var trimmedAttributes = new AttributesImpl(attributes);

for (var i = 0; i < trimmedAttributes.getLength(); i++) {
var value = trimmedAttributes.getValue(i);
trimmedAttributes.setValue(i, value != null ? value.trim() : null);
}

super.startElement(uri, localName, qName, trimmedAttributes);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@
package org.lfenergy.shapeshifter.core.common.xml;

import jakarta.xml.bind.JAXBException;
import java.io.StringReader;
import java.io.StringWriter;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.sax.SAXSource;
import org.lfenergy.shapeshifter.core.common.exception.UftpConnectorException;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.sax.SAXSource;
import java.io.StringReader;
import java.io.StringWriter;

public class XmlSerializer {

Expand All @@ -32,15 +34,24 @@ public <T> String toXml(final T object) {

public <T> T fromXml(String xmlString, Class<T> typeToUnmarshal) {
try {
var xmlSource = new SAXSource(SAX_PARSER_FACTORY.newSAXParser().getXMLReader(),
new InputSource(new StringReader(xmlString)));
var xmlSource = new SAXSource(xmlReader(),
new InputSource(new StringReader(xmlString)));
var unmarshaller = jaxbTools.createUnmarshaller(typeToUnmarshal);
return typeToUnmarshal.cast(unmarshaller.unmarshal(xmlSource));
} catch (JAXBException | ParserConfigurationException | SAXException cause) {
throw new UftpConnectorException("Failed to unmarshal XML to " + typeToUnmarshal.getSimpleName() + " instance.", cause);
}
}

private static XMLReader xmlReader() throws ParserConfigurationException, SAXException {
var parser = SAX_PARSER_FACTORY.newSAXParser();

var attributeTrimmingFilter = new AttributeTrimmingFilter();
attributeTrimmingFilter.setParent(parser.getXMLReader());

return attributeTrimmingFilter;
}

/**
* Creates a SAX Parser factory with some measures to prevent XML External Entity vulnerabilities Taken from: <a
* href="https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#jaxb-unmarshaller">...</a>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ void fromXml_PayloadMessage() {
assertThat(flexRequest).isNotNull();
}

@Test
void fromXml_attributesTrailingSpaces() {
var flexRequest = xmlSerializer.fromXml("<FlexRequest ContractID=\"abc \"/>", FlexRequest.class);

assertThat(flexRequest.getContractID()).isEqualTo("abc");
}

@Test
void fromXml_PayloadMessage_with_prolog() {
var flexRequest = xmlSerializer.fromXml(XML_PROLOG + FLEX_REQUEST_XML, FlexRequest.class);
Expand Down