ETOOBUSY 🚀 minimal blogging for the impatient
SAMLRequest inspection
TL;DR
Some message parts in SAML 2.0 require fiddling to see what’s inside.
In SAML 2.0, the SAMLRequest
parameter is included in a URL like
this:
https://example.com/?SAMLRequest=...the-request...
where ...the-request...
is built as follows:
- start from the XML text that represents the
AuthnRequest
- apply the DEFLATE algorithm to obtain a compressed binary string
- apply the Base64 encoding
- apply url encoding to the Base64 string
So, if we start from this example:
<samlp:AuthnRequest
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="identifier_1"
Version="2.0"
IssueInstant="2004-12-05T09:21:59Z"
AssertionConsumerServiceIndex="1">
<saml:Issuer>https://sp.example.com/SAML2</saml:Issuer>
<samlp:NameIDPolicy
AllowCreate="true"
Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"/>
</samlp:AuthnRequest>
we end up with this:
https://example.com/?SAMLRequest=fZFLa8MwEITvhf4Ho3v8ojlksQ0hoWBoS2lKD70UYW%2BIQA9Xu2rdf1%2FFSUqaQ3ScmU87WlUkjR5gGXhnX%2FAzIPHtTRLPaLQlmNxaBG%2FBSVIEVhok4A42y8cHKNMcBu%2FYdU6LS%2B46JonQs3L2yLXrWqgeLautQv9RHOU39BRDtYjMKUkUsLXE0nLU8%2FxuVpSzfP6aL6AsYL54PwaXpxErZykY9Bv0X6qLbI9jLQrRHHLVvi1M1%2FpmxzwQZBkNKY7SDBrTzpls37ussvPkGTzAU3xgu352WnU%2FycGJBbR23yuPkrEW7AOK5M%2B7d95Ivr6jvaL62XaKAntpScUNiSzOPnT5%2F3PNLw%3D%3D
OK, now we received this and want to look inside… what do we do?
This:
Local versions: cpanfile and saml-request.
If we use Carton, the cpanfile
will help us installing the modules. We’re standing on the shoulders of giants here: IO-Compress, XML::Twig, and Mojolicious.
The program does the reverse of the encoding operations described above:
- function
get_urlparam
gives us the value of theSAMLRequest
URL parameter. Mojo::URL takes care to reverse the url encoding for us; - function
decode_saml
does the heavylifting of turning the encoded value back into an XML string - function
pretty_xml
helps us pretty-printing the XML text on the output.
Let’s see how it goes:
$ perl saml-request 'https://example.com/?SAMLRequest=fZFLa8MwEITvhf4Ho3v8ojlksQ0hoWBoS2lKD70UYW%2BIQA9Xu2rdf1%2FFSUqaQ3ScmU87WlUkjR5gGXhnX%2FAzIPHtTRLPaLQlmNxaBG%2FBSVIEVhok4A42y8cHKNMcBu%2FYdU6LS%2B46JonQs3L2yLXrWqgeLautQv9RHOU39BRDtYjMKUkUsLXE0nLU8%2FxuVpSzfP6aL6AsYL54PwaXpxErZykY9Bv0X6qLbI9jLQrRHHLVvi1M1%2FpmxzwQZBkNKY7SDBrTzpls37ussvPkGTzAU3xgu352WnU%2FycGJBbR23yuPkrEW7AOK5M%2B7d95Ivr6jvaL62XaKAntpScUNiSzOPnT5%2F3PNLw%3D%3D'
SAMLRequest = fZFLa8MwEITvhf4Ho3v8ojlksQ0hoWBoS2lKD70UYW+IQA9Xu2rdf1/FSUqaQ3ScmU87WlUkjR5gGXhnX/AzIPHtTRLPaLQlmNxaBG/BSVIEVhok4A42y8cHKNMcBu/YdU6LS+46JonQs3L2yLXrWqgeLautQv9RHOU39BRDtYjMKUkUsLXE0nLU8/xuVpSzfP6aL6AsYL54PwaXpxErZykY9Bv0X6qLbI9jLQrRHHLVvi1M1/pmxzwQZBkNKY7SDBrTzpls37ussvPkGTzAU3xgu352WnU/ycGJBbR23yuPkrEW7AOK5M+7d95Ivr6jvaL62XaKAntpScUNiSzOPnT5/3PNLw==
<samlp:AuthnRequest AssertionConsumerServiceIndex="1" ID="identifier_1" IssueInstant="2004-12-05T09:21:59Z" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
<saml:Issuer>https://sp.example.com/SAML2</saml:Issuer>
<samlp:NameIDPolicy AllowCreate="true" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"/>
</samlp:AuthnRequest>
It seems to be working… good.
Enough for today, stay safe folks!