opensaml encoding problems with xml to base64

Jason Novotny jason.novotny at gmail.com
Tue Nov 4 23:29:47 EST 2014


Here are some additional strange details, when I get the BASE64 
SAMLRequest from the identity provider, it is:

AX0Cgv08P3htbCB2ZXJzaW9uPSIxLjAiIGVuY29kaW5nPSJVVEYtOCI/PjxzYW1scDpBdXRoblJlcXVlc3QgeG1sbnM6c2FtbHA9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpwcm90b2NvbCIgQXNzZXJ0aW9uQ29uc3VtZXJTZXJ2aWNlSW5kZXg9IjAiIEFzc2VydGlvbkNvbnN1bWVyU2VydmljZVVSTD0iaHR0cHM6Ly9hbHBoYS5hZHZpc29yc2VydmljZXMuY29tL3NlcnZsZXQvYWR2aXNvci9zYW1sc3NvbG9naW4vIiBGb3JjZUF1dGhuPSJ0cnVlIiBJRD0iX2FiODIwM2U3MmI1YmU0Y2UiIElzUGFzc2l2ZT0idHJ1ZSIgSXNzdWVJbnN0YW50PSIyMDE0LTA5LTA4VDE2OjUxOjI5LjY0OVoiIFByb3RvY29sQmluZGluZz0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmJpbmRpbmdzOkhUVFAtUmVkaXJlY3QiIFByb3ZpZGVyTmFtZT0iaHR0cHM6Ly93d3cuYWR2aXNvcnNlcnZpY2VzLmNvbS8iIFZlcnNpb249IjIuMCI+PHNhbWw6SXNzdWVyIHhtbG5zOnNhbWw9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iPmh0dHBzOi8vd3d3LmFkdmlzb3JzZXJ2aWNlcy5jb20vPC9zYW1sOklzc3Vlcj48c2FtbHA6TmFtZUlEUG9saWN5IEFsbG93Q3JlYXRlPSJ0cnVlIi8+PC9zYW1scDpBdXRoblJlcXVlc3Q+

Now I print that to a file:

                byte[] samlBytes = Base64.decode(samlResponseStr);
                 FileOutputStream fos = new FileOutputStream("/tmp/test");
                 fos.write(samlBytes);
                 fos.close();


And the contents of the /tmp/test file are:

^A}^B<82><FD><?xml version="1.0" encoding="UTF-8"?><samlp:AuthnRequest 
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" 
AssertionConsumerServiceIndex="0" 
AssertionConsumerServiceURL="https://alpha.advisorservices.com/servlet/advisor/samlssologin/" 
ForceAuthn="true" ID="_ab8203e72b5be4ce" IsPassive="true" 
IssueInstant="2014-09-08T16:51:29.649Z" 
ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" 
ProviderName="https://www.advisorservices.com/" 
Version="2.0"><saml:Issuer 
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">https://www.advisorservices.com/</saml:Issuer><samlp:NameIDPolicy 
AllowCreate="true"/></samlp:AuthnRequest>


As you can see, there are 5 bytes at the beginning that I cleared away 
with my parseDocument1 method, but of course that's a terrible hack. I 
just can't quite understand how those bytes get there..

Thanks, Jason

On 11/4/14, 8:16 PM, Jason Novotny wrote:
> Hi,
>
> I'm having problems integrating SSO inbound and outbound with my 
> Identity Provider in that the AuthnRequest I get back will have some 
> strange bytes that I've had to write a hack to deal with and the 
> SAMLResponse that I send out apparently is not decoded into proper 
> XML. Googling around I see a number of ways to marshall/unmarshall and 
> I'd like to know which way is the approved way.
>
> Here's the code I was using for converting a base64 AuthnRequest into 
> a org.w3c.dom.Document:
>
>
>     private Document parseDocument(String encoded) throws 
> VeoSSOServiceException {
>         try {
>             return parseDocument1(encoded);
>         } catch (Exception e) {
>             try {
>                 return parseDocument2(encoded);
>             } catch (Exception ef) {
>                 // god help us
>             }
>         }
>         throw new VeoSSOServiceException("Can't parse the encoded 
> data!");
>     }
>
>     private Document parseDocument1(String encoded) throws Exception {
>         byte[] base64DecodedResponse = Base64.decode(encoded);
>         ByteArrayInputStream is = new 
> ByteArrayInputStream(base64DecodedResponse);
>         DocumentBuilderFactory documentBuilderFactory = 
> DocumentBuilderFactory.newInstance();
>         documentBuilderFactory.setNamespaceAware(true);
>         DocumentBuilder docBuilder = 
> documentBuilderFactory.newDocumentBuilder();
>         StringWriter writer = new StringWriter();
>         IOUtils.copy(is, writer, "UTF-8");
>         encoded = writer.toString().replaceAll("[^\\p{ASCII}]", "");
>         //encoded = 
> writer.toString().substring(writer.toString().indexOf("<"));
>         is = new ByteArrayInputStream(encoded.getBytes());
>         Document document = docBuilder.parse(is);
>         return document;
>     }
>
>
>     private Document parseDocument2(String encoded) throws Exception {
>         byte[] samlBytes = Base64.decode(encoded);
>         Inflater inflater = new Inflater(true);
>         inflater.setInput(samlBytes);
>         ByteArrayOutputStream stream = new ByteArrayOutputStream();
>         byte[] buffer = new byte[1024];
>         while (!inflater.finished()) {
>             int count = inflater.inflate(buffer);
>             if (count == 0)
>                 break;
>             stream.write(buffer, 0, count);
>         }
>         stream.close();
>         samlBytes = stream.toByteArray();
>         DocumentBuilderFactory documentBuilderFactory = 
> DocumentBuilderFactory.newInstance();
>         documentBuilderFactory.setNamespaceAware(true);
>         DocumentBuilder docBuilder = 
> documentBuilderFactory.newDocumentBuilder();
>
>         ByteArrayInputStream is = new ByteArrayInputStream(samlBytes);
>         Document document = docBuilder.parse(is);
>         return document;
>     }
>
> I'm also wondering how I should be encoding my SAMLresponse. Here is 
> the code I'm currently using:
>
> public VeoSSOResult parseSAMLRequest(String samlRequestStr) throws 
> VeoSSOServiceException {
>         try {
>             VeoSSOResult veoSSOResult = new VeoSSOResult();
>
>             Document document = parseDocument(samlRequestStr);
>
>             Element metadataRoot = document.getDocumentElement();
>
>             QName qName = new QName(metadataRoot.getNamespaceURI(), 
> metadataRoot.getLocalName(), "saml2p");
>
>             // get an unmarshaller
>             Unmarshaller unmarshaller = 
> Configuration.getUnmarshallerFactory().getUnmarshaller(qName);
>
>             Object object = unmarshaller.unmarshall(metadataRoot);
>             AuthnRequest authnRequest = (AuthnRequest) object;
>             String response = createSAMLResponse(authnRequest);
>             veoSSOResult.setBase64(response);
> veoSSOResult.setDestinationURL(authnRequest.getAssertionConsumerServiceURL()); 
>
>             return veoSSOResult;
>         } catch (Exception e) {
>             throw new VeoSSOServiceException("No good", e);
>         }
>     }
>
>     private void authenticateRequest(AuthnRequest authnRequest) {
>
>         // TODO anything we care about validating from AuthnRequest 
> input?
>
>     }
>
>     public String createSAMLResponse(AuthnRequest authnRequest) throws 
> VeoSSOServiceException, IOException {
>
>         authenticateRequest(authnRequest);
>         VeoSSOResponseInfo info = null;
>         try {
>             info = new VeoSSOResponseInfo();
>         } catch (Exception e) {
>             throw new VeoSSOServiceException("Unable to initiate:", e);
>         }
>         final SAMLObjectBuilder<Response> responseBuilder =
>             (SAMLObjectBuilder<Response>) 
> builderFactory.getBuilder(Response.DEFAULT_ELEMENT_NAME);
>         final Response responseMessage = responseBuilder.buildObject();
>
>         responseMessage.setID(createID());
>         responseMessage.setVersion(SAMLVersion.VERSION_20);
>         responseMessage.setIssueInstant(new DateTime());
>         responseMessage.setInResponseTo(authnRequest.getID());
> responseMessage.setDestination(authnRequest.getAssertionConsumerServiceURL()); 
>
>
>         final Issuer issuer = buildIssuer(info);
>         responseMessage.setIssuer(issuer);
>
>         final Status status = buildStatus(info);
>         responseMessage.setStatus(status);
>
>         final Assertion assertion = buildAssertion(info);
>         responseMessage.getAssertions().add(assertion);
>
>         ResponseMarshaller marshaller = new ResponseMarshaller();
>
>         Element plain = null;
>         String encodedRequestMessage;
>         try {
>             plain = marshaller.marshall(responseMessage);
>             String samlResponse = XMLHelper.nodeToString(plain);
>             byte[] xmlBytes = samlResponse.getBytes("UTF-8");
>             String base64Encoded = Base64.encodeBytes(xmlBytes);
>
>             encodedRequestMessage =
>                 Base64.encodeBytes(samlResponse.getBytes(),
>                     Base64.DONT_BREAK_LINES);
>
>             return base64Encoded;
>         } catch (MarshallingException e) {
>             throw new VeoSSOServiceException("Unable to marshall 
> SAMLResponse:", e);
>         }
>  }
>
> Any help is greatly appreciated!
>
> Thanks, Jason



More information about the dev mailing list