SAML-Toolkits / wordpress-saml

OneLogin SAML plugin for Wordpress
MIT License
65 stars 74 forks source link

Decryption is breaking Encrypted Assertion Signatures #136

Open lwg-galuise opened 2 years ago

lwg-galuise commented 2 years ago

The Issue

Hi,

In my use case I am attempting to have WordPress consume a signed and encrypted assertion.

Unfortunately, when I turn on encryption (by checking Reject Unencrypted Assertions checkbox via the onelogin_saml_configuration settings - this triggers our IdP to then encrypt assertions as the SP metadata then includes an encryption certificate) the the assertions fail due to failed signature validation:

Signature validation failed. SAML Response rejected
There was at least one error processing the SAML Response: invalid_response
Contact the administrator

I believe I've managed to track down what I believe is the issue:

It appears that in php/lib/Saml2/Response.php lines 1175-1190 some manipulation of XML namespaces is made in an attempt to "Fix (a) possible issue with saml namespace": https://github.com/onelogin/wordpress-saml/blob/e0e1e68dea4ba100f380efcd7c2331d379376867/onelogin-saml-sso/php/lib/Saml2/Response.php#L1175-L1190

It appears that the default "else" case is what is causing the problem. Could the "else" case just "do nothing" instead of re-namespacing the assertion element?

Capturing the decrypted assertion via logs prior to the code above results in the following:

<?xml version="1.0"?>
<saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" ID="_73eec473-f437-401c-af82-2790270aaf4a" Version="2.0" IssueInstant="2022-06-28T22:54:45.592Z" Destination="https://my-website.example.com/wp-login.php?saml_acs" InResponseTo="ONELOGIN_19b5f14a9804d7f36a364128ea488de08d6b1413">
    <saml2:Issuer>my-sso-idp</saml2:Issuer>
    <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
        <SignedInfo>
            <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
            <SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
            <Reference URI="#_73eec473-f437-401c-af82-2790270aaf4a">
                <Transforms>
                    <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
                    <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                </Transforms>
                <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
                <DigestValue>...base64 encoded data...</DigestValue>
            </Reference>
        </SignedInfo>
        <SignatureValue>...base64 encoded data...</SignatureValue>
        <KeyInfo>
            <X509Data>
                <X509Certificate>...base64 encoded data...</X509Certificate>
            </X509Data>
        </KeyInfo>
    </Signature>
    <saml2p:Status>
        <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
    </saml2p:Status>
    <saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:default="http://www.w3.org/2000/09/xmldsig#" ID="_4355b3c7-c8e4-46e6-a3bb-85819a2d11ef" IssueInstant="2022-06-28T22:54:45.594Z" Version="2.0">
        <saml:Issuer>my-sso-idp</saml:Issuer>
        <default:Signature>
            <default:SignedInfo>
                <default:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                <default:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
                <default:Reference URI="#_4355b3c7-c8e4-46e6-a3bb-85819a2d11ef">
                    <default:Transforms>
                        <default:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
                        <default:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                    </default:Transforms>
                    <default:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
                    <default:DigestValue>...base64 encoded data...</default:DigestValue>
                </default:Reference>
            </default:SignedInfo>
            <default:SignatureValue>...base64 encoded data...</default:SignatureValue>
            <default:KeyInfo>
                <default:X509Data>
                    <default:X509Certificate>...base64 encoded data...</default:X509Certificate>
                </default:X509Data>
            </default:KeyInfo>
        </default:Signature>
        <saml:Subject>
            <saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">username@example.com</saml:NameID>
            <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
                <saml:SubjectConfirmationData InResponseTo="ONELOGIN_19b5f14a9804d7f36a364128ea488de08d6b1413" NotOnOrAfter="2022-06-28T22:59:45.594Z" Recipient="https://my-website.exampple.com/wp-login.php?saml_acs"/>
            </saml:SubjectConfirmation>
        </saml:Subject>
        <saml:Conditions NotBefore="2022-06-28T22:54:45.594Z" NotOnOrAfter="2022-06-28T23:54:45.594Z">
            <saml:AudienceRestriction>
                <saml:Audience>mywordpresssite</saml:Audience>
            </saml:AudienceRestriction>
        </saml:Conditions>
        <saml:AttributeStatement>
            <saml:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn">
                <saml:AttributeValue>username@example.com</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress">
                <saml:AttributeValue>username@example.com</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname">
                <saml:AttributeValue>First Name</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname">
                <saml:AttributeValue>Last Name</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/homephone">
                <saml:AttributeValue>(555) 555-5555</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/postalcode">
                <saml:AttributeValue>12345</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/streetaddress">
                <saml:AttributeValue>100 Cherry Tree  Road</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/locality">
                <saml:AttributeValue>Some City</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/country">
                <saml:AttributeValue>US</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/stateorprovince">
                <saml:AttributeValue>PA</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="extraAttribute1">
                <saml:AttributeValue>extraValue1</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="extraAttribute2">
                <saml:AttributeValue>extraValue2</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="extraAttribute3">
                <saml:AttributeValue>extraValue3</saml:AttributeValue>
            </saml:Attribute>
            <saml:Attribute Name="multiValueAttribute1">
                <saml:AttributeValue>Value1</saml:AttributeValue>
                <saml:AttributeValue>Value2</saml:AttributeValue>
                <saml:AttributeValue>Value3</saml:AttributeValue>
                <saml:AttributeValue>Value4</saml:AttributeValue>
                <saml:AttributeValue>Value5</saml:AttributeValue>
            </saml:Attribute>
        </saml:AttributeStatement>
        <saml:AuthnStatement AuthnInstant="2022-06-28T22:54:45.594Z" SessionIndex="564359f6-86b2-4ee6-a2f6-f1c6be41adb2">
            <saml:AuthnContext>
                <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
            </saml:AuthnContext>
        </saml:AuthnStatement>
    </saml:Assertion>
</saml2p:Response>

More importantly is the <SignedInfo> element. With the above mentioned lines the <SignedInfo> element receives a new prefix namespace "default" transforming it to the following:

<default:SignedInfo xmlns:default="http://www.w3.org/2000/09/xmldsig#">
    <default:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
    </default:CanonicalizationMethod>
    <default:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256">
    </default:SignatureMethod>
    <default:Reference URI="#_73eec473-f437-401c-af82-2790270aaf4a">
        <default:Transforms>
            <default:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature">
            </default:Transform>
            <default:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
            </default:Transform>
        </default:Transforms>
        <default:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256">
        </default:DigestMethod>
        <default:DigestValue>...base64 encoded data...</default:DigestValue>
    </default:Reference>
</default:SignedInfo>

This of course "breaks" (or invalidates) said signature/digest and thus causes the SAML Assertion to be rejected.

Configuration details

The site is running on Pressable. WordPress version: 6.0 php Version: 7.4

The IdP in question is an in-house developed IdP and we are using the following .NET SAML library: https://github.com/ITfoxtec/ITfoxtec.Identity.Saml2

What "possible issue with saml namespace" are those lines attempting to correct? This only appears to break encrypted assertions. Signed assertions left "in the clear" (unencrypted) are unaffected (and also do no have their <SignedInfo> element replaced with <default:SignedInfo>.