Wednesday, May 1, 2013

Extracting values from an XML payload using AXIOM

From the following XML payload (only the required parts are displayed) I received while testing Passive-STS with WSO2 Identity Server, I wanted to get the values of "NameIdentifier" and the Claims which are included in 'Attribute' tags.
<?xml version="1.0" encoding="UTF-8"?><wst:RequestSecurityTokenResponseCollection xmlns:wst="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
  <wst:RequestSecurityTokenResponse>
    <wst:TokenType>http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1</wst:TokenType>
    <wst:RequestedAttachedReference>
      <wsse:SecurityTokenReference xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
        <wsse:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.0#SAMLAssertionID">_619a4efa0be21de4227fa5c45e9d1c31</wsse:KeyIdentifier>
      </wsse:SecurityTokenReference>
    </wst:RequestedAttachedReference>
    <wst:RequestedUnattachedReference>
      <wsse:SecurityTokenReference xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
        <wsse:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.0#SAMLAssertionID">_619a4efa0be21de4227fa5c45e9d1c31</wsse:KeyIdentifier>
      </wsse:SecurityTokenReference>
    </wst:RequestedUnattachedReference>
    <wst:Lifetime>
      <wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2013-05-01T03:17:10.592Z</wsu:Created>
      <wsu:Expires xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2013-05-01T03:22:10.592Z</wsu:Expires>
    </wst:Lifetime>
    <wst:RequestedSecurityToken>
      <Assertion xmlns="urn:oasis:names:tc:SAML:1.0:assertion" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" AssertionID="_619a4efa0be21de4227fa5c45e9d1c31" IssueInstant="2013-05-01T03:17:10.595Z" Issuer="localhost" MajorVersion="1" MinorVersion="1">
        <Conditions NotBefore="2013-05-01T03:17:10.592Z" NotOnOrAfter="2013-05-01T03:22:10.592Z"/>
        <AttributeStatement>
          <Subject>
            <NameIdentifier Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">admin</NameIdentifier>
            <SubjectConfirmation>
              <ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:bearer</ConfirmationMethod>
            </SubjectConfirmation>
          </Subject>
          <Attribute AttributeName="Email" AttributeNamespace="http://wso2.org/claims/emailaddress">
            <AttributeValue>admin@wso2.com</AttributeValue>
          </Attribute>
          <Attribute AttributeName="First Name" AttributeNamespace="http://wso2.org/claims/givenname">
            <AttributeValue>admin</AttributeValue>
          </Attribute>
        </AttributeStatement>
        ...
After trying few methods, one of my colleagues suggested using AXIOM. Thanks to AXIOMUtil.stringToOM() It turned out to be a pretty simple thing :)

Following is the code I used to reach those values...
public void handleResponse(String response){
 OMElement element = null;
        
 try {
     element = AXIOMUtil.stringToOM(response);
 } catch (XMLStreamException e) {
     e.printStackTrace();
 }

 element = element.getFirstChildWithName(new QName("http://docs.oasis-open.org/ws-sx/ws-trust/200512", "RequestSecurityTokenResponse"));
 element = element.getFirstChildWithName(new QName("http://docs.oasis-open.org/ws-sx/ws-trust/200512", "RequestedSecurityToken"));
 element = element.getFirstChildWithName(new QName("urn:oasis:names:tc:SAML:1.0:assertion", "Assertion"));
 element = element.getFirstChildWithName(new QName("urn:oasis:names:tc:SAML:1.0:assertion", "AttributeStatement"));

 OMElement subjectElement = element.getFirstChildWithName(new QName("urn:oasis:names:tc:SAML:1.0:assertion", "Subject"));

 String username = subjectElement.getFirstElement().getText();

 Iterator itr = element.getChildrenWithName(new QName("urn:oasis:names:tc:SAML:1.0:assertion", "Attribute"));

 Map<String, String> claimMap = new HashMap<String, String>();
  
 while(itr.hasNext()){
     OMElement elem = (OMElement)itr.next();
     String claimURI = ((OMAttribute)elem.getAttribute(new QName("AttributeNamespace"))).getAttributeValue();
     claimMap.put(claimURI, elem.getFirstElement().getText()); 
 }
}
There, username will contain the value of the 'NameIdentifier' i.e. admin
And claimMap will contain the claims, where Map entry's key will be 'AttributeNamespace' and value will be 'AttributeValue'.

No comments: