Dynamic Query Strings in ACS

23 views
Skip to first unread message

Alan Tomlinson

unread,
Sep 16, 2025, 7:12:10 PM (12 days ago) Sep 16
to SimpleSAMLphp
Hi all, 

I'm struggling to complete an integration with my SimpleSAML hosted IDP and a third-party Service Provider. They don't seem to want to share anything with me about their setup or any log information which is making my life a bit more difficult. Their service currently works with EntraID and Google but I cannot for the life of me get it to work with SimpleSAML.

I suspect it has something to do with the fact that they are using a dynamic query string in the samlp:AuthnRequest:

<samlp:AuthnRequest
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
ID="_a0f50dc1-eb09-4c03-9281-5a50adee7471"
Version="2.0"
IssueInstant="2025-09-04T02:53:13Z"
ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
...

The query parameter 'id' dynamically changes for each session. If I use EntraID as the IDP I can see in the response that the query string is passed back in the samlp:Response destination:   

<samlp:Response
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
ID="_10c77b0f-b5d1-4dcd-9211-2b19500de11e"
Version="2.0"
IssueInstant="2025-09-04T02:54:54.355Z"
Destination="https://www.example.school.nz/Pages/Consume.aspx?id=sylmNQK1v2o%3D"
InResponseTo="_a0f50dc1-eb09-4c03-9281-5a50adee7471">
...

When using the SimpleSAML as the IDP the response destination is exactly as configured in the saml20-sp-remote metadata which of course doesn't have a query string and is what I believe to be causing the SP to reject the response. 

Is it possible to get SimpleSAML to append the query parameters provided in the AuthnRequest to the AssertionConsumerService Location that is specified in the metadata? 
Is what they are doing even valid for the SAML2 spec? 

Any thoughts would be greatly appreciated.

Alan Tomlinson

unread,
Sep 16, 2025, 7:52:46 PM (12 days ago) Sep 16
to SimpleSAMLphp
Just an update to say I've resolved this.
 
Unfortunately the ServiceProvider was unwilling to make changes on their end to use the RelayState parameter or sign the AuthnRequests because as far far as they are concerned if it works for Entra/Google then that's all they care about.

For anyone else in the same boat with, I modified the getAssertionConsumerService function  in ./modules/saml/src/IdP/SAML2.php to allow use of the AssertionConsumerServiceURL even when the AuthnRequest is not signed:

private static function getAssertionConsumerService(
        array $supportedBindings,
        Configuration $spMetadata,
        ?string $AssertionConsumerServiceURL = null,
        ?string $ProtocolBinding = null,
        ?int $AssertionConsumerServiceIndex = null,
        bool $authnRequestSigned = false,
    ): ?array {
        /* We want to pick the best matching endpoint in the case where for example
         * only the ProtocolBinding is given. We therefore pick endpoints with the
         * following priority:
         *  1. isDefault="true"
         *  2. isDefault unset
         *  3. isDefault="false"
         */
        $firstNotFalse = null;
        $firstFalse = null;
        /* Check if AssertionConsumerServiceURL contains a query string to allow for
         * using the provided URL as long as the base domain matches.
        */
        if ($AssertionConsumerServiceURL !== null) {
            $AssertionConsumerServiceBaseURL = null;
            $hasQueryString = strpos($AssertionConsumerServiceURL, '?');
            if ($hasQueryString) {
                $AssertionConsumerServiceBaseURL = substr($AssertionConsumerServiceURL,0,$hasQueryString);
            }
        }
        foreach ($spMetadata->getEndpoints('AssertionConsumerService') as $ep) {
            if ($AssertionConsumerServiceBaseURL !== null && $ep['Location'] == $AssertionConsumerServiceBaseURL) {
               /* Use the given ACSUrl */
               $ep['Location'] = $AssertionConsumerServiceURL;
               return $ep;
            }
           ...

Tim van Dijen

unread,
Sep 22, 2025, 12:03:27 PM (6 days ago) Sep 22
to SimpleSAMLphp
Interesting case, Alan!

The SAML-specifications are not clear on the verification process that has to be done on the request's AssertionConsumerServiceURL against SP-metadata.
I've asked Grok because it's must better at relating all the specifications and forum posts on SAML over the last two decades and it basically came up with a match against the baseURL just like you did.

I've also discussed this internally and we're a little divided on whether we should 'fix' this, because we all _do agree_ that this application is misbehaving by not using the RelayState and it's just lucky that Entra/Google don't break on it.
Is there any way we can help you convince your service provider to adjust and just use the designated RelayState instead?  They could even change it without affecting any of their customers, because it's just standard SAML 2.0 functionality..

Kind regards,

Tim van Dijen, on behalf of the developers

Op woensdag 17 september 2025 om 01:52:46 UTC+2 schreef alan.to...@ourschool.co.nz:
Reply all
Reply to author
Forward
0 new messages