QueryProtocolUnmarshaller unmarshall() relies on the order of XML elements
- Dominant language
- Java
- Stars
- 2.6k
- Forks
- 1k
- Avg merge
- 2d 9h
- Merged PRs (30d)
- 51
Description
Implementation of unmarhall() in QueryProtocolUnmarshaller assumes that response is the first XML element
## Describe the bug
Method has implementation as follows
```
public Pair> unmarshall(SdkPojo sdkPojo,
SdkHttpFullResponse response) {
XmlElement document = response.content().map(XmlDomParser::parse).orElse(XmlElement.empty());
XmlElement resultRoot = hasResultWrapper ? document.getFirstChild() : document;
return Pair.of(unmarshall(sdkPojo, resultRoot, response), parseMetadata(document));
}
```
If ResponseMetadata element is first, the XML parsing will return incorrect result, although XML is in a valid format.
Implementation relies on the strict order of XML elements.
This can be reproduced with Ceph storage, which for listing IAM roles and possibly other operations returns ResponseMetadata as the first element.
## Expected Behavior
Parse XML without relying on the order of children
## Current Behavior
Operation of listing roles is successful but with Ceph storage it fails due to different order of children.
Example structure returned
```
tx000000000000000000bf3-00610902d3-df5c88-something
800c18b6-8259-4697-b1b0-7498d9487446
exampleRole
/base/
arn:aws:iam::demo:role/base/exampleRole
2021-07-20T10:03:45.743Z
3600
{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Federated":["arn:aws:iam:::oidc-provider/localhost.example.com:8443/auth/realms/demo"]},"Action":["sts:AssumeRoleWithWebIdentity"],"Condition":[{"StringEquals":{"localhost.example.com:8443/auth/realms/demo:app_id":"account"}},{"StringEquals":{"localhost.example.com:8443/auth/realms/demo:sub":["c7d03371-6d87-4b46-80ef-518eec3f7aa6"]}}]}]}
```
## Possible Solution
Reimplement the logic as below or similar
```
public Pair> unmarshall(SdkPojo sdkPojo, SdkHttpFullResponse response) {
XmlElement document = response.content().map(XmlDomParser::parse).orElse(XmlElement.empty());
XmlElement resultRoot;
if (hasResultWrapper) {
Optional element = document.children().stream().filter(e -> !"ResponseMetadata".equals(e.elementName())).findFirst();
resultRoot = element.orElse(document.getFirstChild());
} else {
resultRoot = document;
}
return Pair.of(unmarshall(sdkPojo, resultRoot, response), parseMetadata(document));
}
```
## Your Environment
Reproducible with currently used 2.16.103
Contributor guide
Assessment
This issue has not been assessed yet.