Skip to content
Open
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
2 changes: 2 additions & 0 deletions release-notes/CREDITS
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,5 @@ Christian Beikov (@beikov)
(3.3.0)
* Fixed #883: Translate `XMLStreamReader` creation errors to `StreamReadException`
(3.3.0)
* Fixed #886: Escape names already starting with prefix in `Base64NameProcessor`
(3.3.0)
2 changes: 2 additions & 0 deletions release-notes/VERSION
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ Version: 3.x (for earlier see VERSION-2.x)
#883: Translate `XMLStreamReader` creation errors to `StreamReadException`
(restores guard lost in 3.x port; see 2.x `_createParser(byte[])` for #618)
(fix by @Sahana2524)
#886: Escape names already starting with prefix in `Base64NameProcessor`
(fix by @Sahana2524)

3.2.2 (not yet released)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,9 @@ public static XmlNameProcessor newReplacementProcessor() {
* </DTO>
* }</pre>
*<p>
* NOTE: you must ensure that no incoming element or attribute name starts
* with {@code prefix}, otherwise decoding will not work.
* NOTE: names that already start with {@code prefix} are escaped as well, even
* though they are otherwise valid, so that decoding cannot confuse them with
* names this processor encoded.
*
* @param prefix The prefix to use for name that are escaped
*/
Expand Down Expand Up @@ -197,7 +198,12 @@ public Base64NameProcessor(String prefix) {

@Override
public void encodeName(XmlName name) {
if (!VALID_XML_NAME.matcher(name.localPart).matches()) {
// Names already starting with the prefix have to be escaped as well, even
// when otherwise valid: decodeName() base64-decodes anything carrying the
// prefix, so passing such a name through as-is would decode it into a
// different name than was written.
if (!VALID_XML_NAME.matcher(name.localPart).matches()
|| name.localPart.startsWith(_prefix)) {
name.localPart = _prefix + new String(BASE64_ENCODER.encode(name.localPart.getBytes(UTF_8)), UTF_8);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,42 @@ public void testAlwaysOnBase64UndecodableNameFailsAsReadException() throws Excep
assertNotEquals(TokenStreamLocation.NA, e.getLocation());
}

// A name that is a valid XML name but already starts with the magic prefix has
// to be escaped too: decoding keys off that prefix, so writing such a name
// through as-is makes it read back as a different name than was written.
@Test
public void testBase64PrefixedNamesRoundTrip() throws Exception {
DTO dto = new DTO();

// would otherwise read back as "admin"
dto.badMap.put("base64_tag_YWRtaW4", "xyz");
// valid XML name, but not valid base64 past the prefix
dto.badMap.put("base64_tag_hello", "bar");
dto.badMap.put("plain", "abc");

XmlMapper mapper = XmlMapper.builder(
xmlFactory(XmlNameProcessors.newBase64Processor())
).build();

final String res = mapper.writeValueAsString(dto);
DTO reversed = mapper.readValue(res, DTO.class);
assertEquals(dto, reversed);
}

@Test
public void testBase64CustomPrefixedNameRoundTrips() throws Exception {
DTO dto = new DTO();
dto.badMap.put("esc_YWRtaW4", "xyz");

XmlMapper mapper = XmlMapper.builder(
xmlFactory(XmlNameProcessors.newBase64Processor("esc_"))
).build();

final String res = mapper.writeValueAsString(dto);
DTO reversed = mapper.readValue(res, DTO.class);
assertEquals(dto, reversed);
}

protected XmlFactory xmlFactory(XmlNameProcessor proc) {
return XmlFactory.builder().xmlNameProcessor(proc).build();
}
Expand Down
Loading