I'm writing a Node based web service that is going expecting a third party to send a SAML request that's deflated and base64 encoded. After flailing around for the better part of the day I fear I'm not sure I even know what to ask (I apologize if this is a dupe).
The docs say:
The SAMLRequest is first DEFLATE-compressed, then Base 64 encoded, then URL encoded. It must be decoded and parsed
The Webstorm Console log has this query string:
GET /login?SAMLRequest=fZJRa9swEMff9ymE3m1LipM4InbJ0mwrNCM0bqF9Gap8cQW2lOnksH37ObFbWgZ9lLj76X%2F30%2FLqT9uQE3g0zuaUx4wSsNpVxtY5vS%2B%2FRRm9Kr4sUbWNOMpVF17sHfzuAANZIYIPfd%2FaWexa8HvwJ6Ph%2Fu42py8hHFEmCV%2BImM%2BymMWCswRBd96Ev1GrrKrBJ2eueuXokUPJdc83VoVLqDPqA4lPmJwwxpLG1cZScnOd018HJeaLSsNkqhfAqql6nsyyVFQiEweWqnlfhrv%2BKXOCnB5Ug3C%2BwQ5uLAZlQ04F42nE5hHPSj6VKZc8jfmcP1Gy8y447Zqvxg6L6byVTqFBaVULKIOW%2B9X2VoqYyeehCOWPstxFq36yg9LhAjmZCvzPviOn352rGyAbG8AfvUEg%2B3E3ZDvshpKHVy3irKUXZVEOIj5PcBzj0mLwJi9z%2BveEzwFvRmgxLr%2B%2BxI21axN4i5zUqJIyjTaP23SzftyK9Wwm%2FnO8TN6HKMbjx79U%2FAM%3D
Output of
console.log(req.query.SAMLRequest)
shows the URL decoding is automatically done:
fZJRa9swEMff9ymE3m1LipM4InbJ0mwrNCM0bqF9Gap8cQW2lOnksH37ObFbWgZ9lLj76X/30/LqT9uQE3g0zuaUx4wSsNpVxtY5vS+/RRm9Kr4sUbWNOMpVF17sHfzuAANZIYIPfd/aWexa8HvwJ6Ph/u42py8hHFEmCV+ImM+ymMWCswRBd96Ev1GrrKrBJ2eueuXokUPJdc83VoVLqDPqA4lPmJwwxpLG1cZScnOd018HJeaLSsNkqhfAqql6nsyyVFQiEweWqnlfhrv+KXOCnB5Ug3C+wQ5uLAZlQ04F42nE5hHPSj6VKZc8jfmcP1Gy8y447Zqvxg6L6byVTqFBaVULKIOW+9X2VoqYyeehCOWPstxFq36yg9LhAjmZCvzPviOn352rGyAbG8AfvUEg+3E3ZDvshpKHVy3irKUXZVEOIj5PcBzj0mLwJi9z+veEzwFvRmgxLr++xI21axN4i5zUqJIyjTaP23SzftyK9Wwm/nO8TN6HKMbjx79U/AM=
So I assume I must decode the base64 then INFLATE it. (I've tried to inflate and then decode but that still failed and this makes the most sense):
var zlibJS = require('zlibjs'); //I've tried Node's own zlib but that only appears to work with call backs
...
var b = new Buffer(samlReq, 'base64');
var decoded = b.toString();
var inflated = zlibJS.inflateSync(decoded); //https://github.com/imaya/zlib.js/blob/master/test/node-test.js
//I get an Unsupported compression method
...//relooking at the test it appears it wants a buffer so switch the above line for this
var inflated = zlibJS.inflateSync(b); // same 500 error
Looking through the github source this error is thrown when a switch falls through to the default when looking for a compression method however, I don't see where I'm expected to set that. I've tried to log like crazy(stripped out for readability) and put each step into base64 decoder (http://www.motobit.com/util/base64-decoder-encoder.asp), url decoder (http://meyerweb.com/eric/tools/dencoder/), and a string uncompressor (http://i-tools.org/gzip) with inconclusive results (the uncompressor tool fails to uncompress its own compression so...)
Thanks for any advice, tips and or tools that might help
From your question I derived that you're trying to make the the SAML Request that should be deflated, base64 encoded and afterwards URL encoded (last part only because it its used as part of an url)
I'm not sure if async can be used to solve your synchronous problem, but I would go with something similar to this:
var async = require('async');
var zlib = require('zlib');
var url = require('url');
var samlRequest = '<?xml version="1.0" encoding="UTF-8"?>'
+ '<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">'
+ '...'
+ '</samlp:AuthnRequest>';
var buffer = new Buffer(samlRequest);
async.waterfall(
[
function deflate(callback) {
zlib.deflate(buffer, function deflated(err, resultBuffer) {
if (err) {
callback(err);
return;
}
callback(null, resultBuffer);
});
},
function encode(buffer, callback) {
callback(null, buffer.toString('base64'));
},
function urlEncode(request, callback) {
callback(null, encodeURIComponent(request));
}
], function handleResult(err, urlEncodedRequest) {
if (err) {
console.log(err);
return;
}
var baseUrl = 'http:xxx.salesforce.com/idp/endpoint/HttpRedirect?SAMLRequest=';
console.log(baseUrl + urlEncodedRequest);
}
);
The samlRequest is of course just an example. I used three function which definitely is overkill, but I wanted to show you async in the process as well, and it nicely demonstrates all the steps.
I had seen another SO answer mention pako and wikipedia mentions it in the ZLib article so I gave it a whirl and it worked second try:
var pako = require('pako');
...
var b = new Buffer(samlReq, 'base64');
var inflated = pako.inflateRaw(b, {to:'string'});