occasional empty SAMLResponse with IE

199 views
Skip to first unread message

Anton Piatek

unread,
Jun 20, 2017, 11:10:11 AM6/20/17
to Pac4j users mailing list
I've been using pac4j in our application for a few months now and so far it has been fantastic.

We've recently come across an intermittent issue affecting SAML logins with Internet Explorer, hoping someone can shed some light (or at least point a torch on something)...

While SAML logins usually seem to work fine, occasionally in IE (one in every 10 attempts or so?) I get a stack trace like this

org.pac4j.saml.exceptions.SAMLException: Error decoding saml message
 at org
.pac4j.saml.sso.impl.SAML2WebSSOMessageReceiver.receiveMessage(SAML2WebSSOMessageReceiver.java:43) ~[pac4j-saml-1.9.4.jar:na]
 at org
.pac4j.saml.sso.impl.SAML2WebSSOProfileHandler.receive(SAML2WebSSOProfileHandler.java:35) ~[pac4j-saml-1.9.4.jar:na]
 at org
.pac4j.saml.client.SAML2Client.retrieveCredentials(SAML2Client.java:221) ~[pac4j-saml-1.9.4.jar:na]
 at org
.pac4j.saml.client.SAML2Client.retrieveCredentials(SAML2Client.java:60) ~[pac4j-saml-1.9.4.jar:na]
 at org
.pac4j.core.client.IndirectClient.getCredentials(IndirectClient.java:106) ~[pac4j-core-1.9.7.jar:na]
 at org
.pac4j.core.engine.DefaultCallbackLogic.perform(DefaultCallbackLogic.java:77) ~[pac4j-core-1.9.7.jar:na]
 at org
.pac4j.springframework.security.web.CallbackFilter.doFilter(CallbackFilter.java:88) ~[spring-security-pac4j-2.1.1.jar:na]
...
Caused by: org.opensaml.messaging.decoder.MessageDecodingException: Request did not contain either a SAMLRequest or SAMLResponse parameter. Invalid request for SAML 2 HTTP POST binding.
 at org
.pac4j.saml.transport.Pac4jHTTPPostDecoder.getBase64DecodedMessage(Pac4jHTTPPostDecoder.java:80) ~[pac4j-saml-1.9.4.jar:na]
 at org
.pac4j.saml.transport.Pac4jHTTPPostDecoder.doDecode(Pac4jHTTPPostDecoder.java:62) ~[pac4j-saml-1.9.4.jar:na]
 at org
.opensaml.messaging.decoder.AbstractMessageDecoder.decode(AbstractMessageDecoder.java:58) ~[opensaml-messaging-api-3.2.0.jar:na]
 at org
.pac4j.saml.sso.impl.SAML2WebSSOMessageReceiver.receiveMessage(SAML2WebSSOMessageReceiver.java:40) ~[pac4j-saml-1.9.4.jar:na]
 
... 50 common frames omitted

I've managed to set a breakpoint in a debugger in Pac4jHTTPPostDecoder.getBase64DecodedMessage() 
If I inspect the variable storing the result of calling this.context.getRequestParameter("SAMLResponse") then it is indeed empty, however if I call this.context.getRequestContent() then I get the following

SAMLResponse=PHNhbWxwOlJlc3BvbnNlIElEPSJfMGQ3ZDNmZmQtMWI4Zi00ZDI0LTg0YWUtNjJkNzRjMGJiMWUxIiBWZXJzaW9uPSIyLjAiIElzc3VlSW5zdGFudD0iMjAxNy0wNi0yMFQxNDo1MzowMC45MDRaIiBEZXN0aW5hdGlvbj0iaHR0cHM6Ly9ibG9ja3NlcnZlcjo0NDM2L2F1dGgvY2FsbGJhY2svY2xpZW50X25hbWUvU0FNTDJDbGllbnRfMS9hdXRoL2NhbGxiYWNrIiBDb25zZW50PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6Y29uc2VudDp1bnNwZWNpZmllZCIgSW5SZXNwb25zZVRvPSJfaDJxYnN4Z3U5MTVpbWl5eGV6eHpzYmtxc29qa2Vtd2VmcXZmdHBiIiB4bWxuczpzYW1scD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnByb3RvY29sIj48SXNzdWVyIHhtbG5zPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIj5odHRwczovL0JFTERDMS5DYW50b25hLm5ldC9hZGZzL3NlcnZpY2VzL3RydXN0PC9Jc3N1ZXI%2BPHNhbWxwOlN0YXR1cz48c2FtbHA6U3RhdHVzQ29kZSBWYWx1ZT0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnN0YXR1czpTdWNjZXNzIiAvPjwvc2FtbHA6U3RhdHVzPjxBc3NlcnRpb24gSUQ9Il84YmNmMmU4OC0zMDRiLTQ3YzctYmRiYS00MjFkMzU3MTI2MTAiIElzc3VlSW5zdGFudD0iMjAxNy0wNi0yMFQxNDo1MzowMC45MDRaIiBWZXJzaW9uPSIyLjAiIHhtbG5zPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIj48SXNzdWVyPmh0dHBzOi8vQkVMREMxLkNhbnRvbmEubmV0L2FkZnMvc2VydmljZXMvdHJ1c3Q8L0lzc3Vlcj48ZHM6U2lnbmF0dXJlIHhtbG5zOmRzPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjIj48ZHM6U2lnbmVkSW5mbz48ZHM6Q2Fub25pY2FsaXphdGlvbk1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIgLz48ZHM6U2lnbmF0dXJlTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxkc2lnLW1vcmUjcnNhLXNoYTI1NiIgLz48ZHM6UmVmZXJlbmNlIFVSST0iI184YmNmMmU4OC0zMDRiLTQ3YzctYmRiYS00MjFkMzU3MTI2MTAiPjxkczpUcmFuc2Zvcm1zPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjZW52ZWxvcGVkLXNpZ25hdHVyZSIgLz48ZHM6VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIiAvPjwvZHM6VHJhbnNmb3Jtcz48ZHM6RGlnZXN0TWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxlbmMjc2hhMjU2IiAvPjxkczpEaWdlc3RWYWx1ZT5xY3FrbjgyRjN5bDJkK3V1QXp2bEdHdUJuNW5QNS9BbmlreTE4Rm9jdVVvPTwvZHM6RGlnZXN0VmFsdWU%2BPC9kczpSZWZlcmVuY2U%2BPC9kczpTaWduZWRJbmZvPjxkczpTaWduYXR1cmVWYWx1ZT5hSmlHQlNYWjJTclNNa2htUW9Qc2lKRXVFRlY2a2VIS3RMS0wzV1B1RnVoU1NBUklmbG5vVHV1ZlBkb0xWYzgxSUhpblFxQXBMTUFzVzNObTN4TThxMXcrc1FENU50eGVTYUN4OG43bVhocU5hOFlYVEVueTNNWVhId3NDWFk0YjN2YTBOdStGTnE2Wm9wbEtqU3d2clRleWwvc3A3eVltL2VINytNR1pXai8xSW9PazlpMjRDRU12aThEa3cwTUdxN3lGbnRRNG1RQkJKVXdFWjRlYytGdUZaL3lhdVkwTkFYQmdNcHljUmpZZE5pcnIzbC82U0g4Q0xzVkQ5bzlacDIyRXRRL3pEaVlnZ0pWdkxOcDBuV3k5V2kyRTVhSm5lTTY4dmlOUkVDRkZTRnkwbGtLYnpBcDNmV09Bejk5K0x6RElCREtwSTdoVXNUSmRzVEZuYXc9PTwvZHM6U2lnbmF0dXJlVmFsdWU%2BPEtleUluZm8geG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPjxkczpYNTA5RGF0YT48ZHM6WDUwOUNlcnRpZmljYXRlPk1JSUM0RENDQWNpZ0F3SUJBZ0lRZHM2cGk3OUlVNGhNR0ZZeWo1dExCakFOQmdrcWhraUc5dzBCQVFzRkFEQXNNU293S0FZRFZRUURFeUZCUkVaVElGTnBaMjVwYm1jZ0xTQkNSVXhFUXpFdVEyRnVkRzl1WVM1dVpYUXdIaGNOTVRjd05USTJNVFl6TVRNeldoY05NVGd3TlRJMk1UWXpNVE16V2pBc01Tb3dLQVlEVlFRREV5RkJSRVpUSUZOcFoyNXBibWNnTFNCQ1JVeEVRekV1UTJGdWRHOXVZUzV1WlhRd2dnRWlNQTBHQ1NxR1NJYjNEUUVCQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUURIRWN5UEFjQ2JhZ3pBZy9QWHpwRDdRM2E0SVJHVnRjcDBYNFBuQlJ0OVBSejRQblFsNE5rMFBpeERqVFpPWTAxUFlqUU9NNGpnV0xqLzNkcktHclp5eG1EQTVSbVRSWHJBQWtablZXR3FMcGtSRzdNWnRFVnBhZ0tuekI2YmU0KzlvSjRvbnpVQmo4a0cxUVBwM1NNWlljRlExclkxaEYzSFJ1ekVqSVBxVW1vS1ZpWDZwN21jeWpaaEJadEx6NXNuR09VcFFoS3FtWnVNTzE1Zmd2NnlYNDRQNXAyUmc0Vnd6SzdKN3FlSE1pUWRQT2pUYzJQOXRPSnpKZVFLY3F3N3ZEajA2bnVaNFJxWUt3bWdxcDhUQ05CVzh0N1JhS2E1ZXNGanhWeTIwbE00RWc5UE1FeU4xcXhMQysyOGFtT1YxUDV4bER3N21KTGxpaWtYM3N4eEFnTUJBQUV3RFFZSktvWklodmNOQVFFTEJRQURnZ0VCQUtMWjZod0xtOHR2Z29Hb1J0VVpvbkpsTXM3NUp0T2QwTXpqK3NpRjRjaTBTajVZU3hST0dDSy90M3RUbWJaRkZHRDBXeUtrYW1BWTM0OUkrdHdWYlJmcTdNa3FPL0tSRmtDT0dwMXFiM1U1M09QR0NFNTdXNW1WcEZZWmRiU0RmV2dTRkZVMko3K1d6U3RJVTB5Zm9keVM0elJMSEdJNlltaTR0WWlpYXRHRUFvRWhieUtwOE9sOXdaa0hWTndMVTdmNFAxemtRMVNsWDVxeVI0ME40VDNRREFZMUFFSXlJaFU0US8wV1BzY3h5RDkvdFozbXIzbWJjTjgvTWJYakV0TEhZT0xEa3Rrc1A5enVqdFpmUmxrZjFPM3hYVFYxSEUwWm1hd24zUWE4WFpVaENvOHVLbkNrZjRYVTFDTTNYUEQxaGRYNzQvNU1vMjBIeWthTWlQTT08L2RzOlg1MDlDZXJ0aWZpY2F0ZT48L2RzOlg1MDlEYXRhPjwvS2V5SW5mbz48L2RzOlNpZ25hdHVyZT48U3ViamVjdD48TmFtZUlEPnNwbWFkbWluPC9OYW1lSUQ%2BPFN1YmplY3RDb25maXJtYXRpb24gTWV0aG9kPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6Y206YmVhcmVyIj48U3ViamVjdENvbmZpcm1hdGlvbkRhdGEgSW5SZXNwb25zZVRvPSJfaDJxYnN4Z3U5MTVpbWl5eGV6eHpzYmtxc29qa2Vtd2VmcXZmdHBiIiBOb3RPbk9yQWZ0ZXI9IjIwMTctMDYtMjBUMTQ6NTg6MDAuOTA0WiIgUmVjaXBpZW50PSJodHRwczovL2Jsb2Nrc2VydmVyOjQ0MzYvYXV0aC9jYWxsYmFjay9jbGllbnRfbmFtZS9TQU1MMkNsaWVudF8xL2F1dGgvY2FsbGJhY2siIC8%2BPC9TdWJqZWN0Q29uZmlybWF0aW9uPjwvU3ViamVjdD48Q29uZGl0aW9ucyBOb3RCZWZvcmU9IjIwMTctMDYtMjBUMTQ6NTM6MDAuOTA0WiIgTm90T25PckFmdGVyPSIyMDE3LTA2LTIwVDE1OjUzOjAwLjkwNFoiPjxBdWRpZW5jZVJlc3RyaWN0aW9uPjxBdWRpZW5jZT5odHRwczovL2Jsb2Nrc2VydmVyOjQ0MzYvYXV0aC9jYWxsYmFjay9jbGllbnRfbmFtZS9TQU1MMkNsaWVudF8xL2F1dGgvY2FsbGJhY2s8L0F1ZGllbmNlPjwvQXVkaWVuY2VSZXN0cmljdGlvbj48L0NvbmRpdGlvbnM%2BPEF1dGhuU3RhdGVtZW50IEF1dGhuSW5zdGFudD0iMjAxNy0wNi0yMFQxNDo0NToxOS43MDBaIiBTZXNzaW9uSW5kZXg9Il84YmNmMmU4OC0zMDRiLTQ3YzctYmRiYS00MjFkMzU3MTI2MTAiPjxBdXRobkNvbnRleHQ%2BPEF1dGhuQ29udGV4dENsYXNzUmVmPnVybjpmZWRlcmF0aW9uOmF1dGhlbnRpY2F0aW9uOndpbmRvd3M8L0F1dGhuQ29udGV4dENsYXNzUmVmPjwvQXV0aG5Db250ZXh0PjwvQXV0aG5TdGF0ZW1lbnQ%2BPC9Bc3NlcnRpb24%2BPC9zYW1scDpSZXNwb25zZT4%3D&RelayState=https%3A%2F%2Fblockserver%3A4436%2Fauth%2Fcallback%2Fclient_name%2FSAML2Client_1%2Fauth%2Fcallback

The request looks like it has a saml token to me, and the request is a POST but for some reason it isn't picked up as a request parameter. 
Now the really odd part is that if I call this.context.getRequestParameters() (which returns an empty list) and then try the getRequestContent() again then this time there is no request content.

I'm hoping someone will tell me this is a known bug and fixed in a newer version (I'm using pac4j-saml 1.9.4 and spring-security-pac4j 2.1.1 btw) thought I can't see any bugs ore commits that sound related, but if not, perhaps someone has some ideas of where to debug next... I'm rather stumped right now


Many thanks,

Anton


Jérôme LELEU

unread,
Jun 22, 2017, 8:49:44 AM6/22/17
to Anton Piatek, Pac4j users mailing list
Hi,

Indeed, it seems a bit strange. Did you try using spring-security-pac4j v3.0.0-SNAPSHOT and pac4j v2.0.0?

Be aware that getRequestContent should return the body of the request, not a parameter.

Thanks.
Best regards,
Jérôme


--
You received this message because you are subscribed to the Google Groups "Pac4j users mailing list" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pac4j-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Anton Piatek

unread,
Jun 26, 2017, 5:55:59 AM6/26/17
to Pac4j users mailing list, anton....@gmail.com


On Thursday, June 22, 2017 at 1:49:44 PM UTC+1, Jérôme LELEU wrote:
Hi,

Indeed, it seems a bit strange. Did you try using spring-security-pac4j v3.0.0-SNAPSHOT and pac4j v2.0.0?

Be aware that getRequestContent should return the body of the request, not a parameter.

Aren't all SAML parameters sent as form post data? And therefore are party of the body too? 
I can understand if the first call to parse parameters emptied the body as they are all parameters, but it is odd that we get a null for the parameter and still see a body until we try and get the parameters, then the body is empty.

My plan is to jump up to the newest version which seems to work with spring boot

Anton Piatek

unread,
Jun 26, 2017, 7:33:03 AM6/26/17
to Pac4j users mailing list, anton....@gmail.com
This is reproducible with SSO Circle as my SAML IdP using  IE 11.413. I don't know if it could be cookie related (I guess it is possible), I'm assuming the odd behaviour in the debugger is caused by this little comment on the tomcat code:
     * If the parameter data was sent in the request body, such as occurs with
     * an HTTP POST request, then reading the body directly via
     * {@link #getInputStream} or {@link #getReader} can interfere with the
     * execution of this method. .
     ..
     */
    public String getParameter(String name);

I wonder if there is something sometimes on my request which is causing something to read the input stream or get a reader, though I can't imagine what that would be or why it only happens sometimes.

It still seems to occur with pac4j 1.9.4 and spring-security-pac4j 2.1.2 which are the latest release versions. I'd rather not ship a snapshot release, but will try and get them working in my environment to see if the issue still exists there.

Anton Piatek

unread,
Jun 26, 2017, 8:20:18 AM6/26/17
to Pac4j users mailing list, anton....@gmail.com
So I reverse proxied and decrypted all my connections - and by getting a few success and a few failure cases I have found one thing different between then when comparing directly with a diff tool. The following headers seem to be missing on the failing cases...
Content-Type: application/x-www-form-urlencoded

I suspect (but have no idea to be honest) that the referer header is not required, but if we are missing a content-type header then it makes complete sense that the www-form-urlencoded data is being ignored from the request.

I'm not sure how this happens though as it looks like the html page loaded by IE has everything identical apart from the actual saml token. There is no explicit header, it is up to IE to set it dynamically because the javascript is submitting a form post on behalf of the user...

Jérôme LELEU

unread,
Jun 28, 2017, 3:16:10 AM6/28/17
to Anton Piatek, Pac4j users mailing list
Hi,

It seems a good reason to explain your problem. Maybe we should do a double parsing (request parameter and body if empty).

Can you create some custom Pac4jHTTPPostDecoder to see if it works?

Thanks.
Best regards,
Jérôme


Garanti sans virus. www.avast.com

--

Anton Piatek

unread,
Jun 28, 2017, 5:29:37 AM6/28/17
to Pac4j users mailing list, anton....@gmail.com
I didn't replace the Pac4jHTTPPostDecoder, but I did insert a filter early into request processing, which if the call is a post request to the saml callback url and has no content type and we're trying to get the parameter SAMLResponse then I manually decode the body and then call the apache tomcat parameters parser with that byte array.

It seems to work fine, but is pretty dirty. I guess the same could be done in the Pac4jHTTPPostDecoder but I don't think it has access to the InputStream to do it the same way (though the request content would get you pretty close to the same solution).
My only worry is that the actual tomcat request parsing does a lot of extra checks around request size/max size and character encoding which you normally take for-granted.

I don't know why the issue occurs, but maybe it is worth trying to report it to Microsoft? Has anyone tried this? Is it possible without a support contract?

It seems rather dirty to fix a client issue in the server, but I guess if it makes things work more reliably...

Anton


On Wednesday, June 28, 2017 at 8:16:10 AM UTC+1, Jérôme LELEU wrote:
Hi,

It seems a good reason to explain your problem. Maybe we should do a double parsing (request parameter and body if empty).

Can you create some custom Pac4jHTTPPostDecoder to see if it works?

Reply all
Reply to author
Forward
0 new messages