handnot2 / samly

Elixir Plug library to enable SAML 2.0 SP SSO in Phoenix/Plug applications.
MIT License
125 stars 90 forks source link

:badmatch error upon verifying response from ADFS #42

Closed richardbourne-ct closed 5 years ago

richardbourne-ct commented 5 years ago

I’m currently trying to use Samly with ADFS, everything going well up until the response is verified - where I start seeing a :badmatch error:

access_denied {:invalid_request, "{:error, {{:badmatch, []}, [{:xmerl_dsig, :verify, 2, [file: '/PHX/deps/esaml/src/xmerl_dsig.erl', line: 168]}...

Line 168 in xmerl_dsig.erl is:

[#xmlAttribute{value = SignatureMethodAlgorithm}] = xmerl_xpath:string("ds:Signature/ds:SignedInfo/ds:SignatureMethod/@Algorithm", Element, [{namespace, DsNs}]),

I’ve added some logging in there to confirm that Element exists and appears to contain what is being asked of it.

This error comes with config for the IDP like:

{
  ...
  sign_requests: true,
  sign_metadata: true
  signed_assertion_in_resp: true,
  signed_envelopes_in_resp: true
  ...
}

I’ve tried setting the latter two to false individually and together and get different errors.

I can see the SAML response when it comes back and verify that it’s what I’m expecting (via an online SAML decoder).

Versions are:

phoenix: 1.3.4 esaml: 3.6.1 samly: 0.9.3


@handnot2: Is ADFS configured to encrypt the SAML assertion attributes?


ADFS is only set to sign the assertion - there is no option to encrypt.

I tried again just to confirm with signed_assertions_in_resp: false and got the same error.

Maybe there is something else going on with ADFS?

I did have to enter a couple of the config settings in what seemed to be the wrong place in order to get things working - for example (which might help with the integration if it hasn’t already been taken care of):


Here is an example SAML response (retrieved using the Firefox SAML-Tracer addon) with the details altered:

<Response ID="_85e7f245-f428-4d08-9ee4-d86aa3982d8f" Version="2.0" IssueInstant="2019-01-22T16:25:31.008Z" Destination="https://my-website/sso/sp/consume/idp_identifier" InResponseTo="id1548174206392814782111986" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
    <Issuer xmlns="urn:oasis:names:tc:SAML:2.0:assertion">
        https://sts.windows.net/idp_identifier/
    </Issuer>
    <Status>
        <StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" />
    </Status>
    <Assertion ID="_33506e7a-3e12-45d4-894e-f5a7cbb092ef" IssueInstant="2019-01-22T16:25:30.992Z" Version="2.0" xmlns="urn:oasis:names:tc:SAML:2.0:assertion">
        <Issuer>
            https://sts.windows.net/idp_identifier/
        </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="#_33506e7a-3e12-45d4-894e-f5a7cbb092ef">
                    <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>
                        pxiPLd9eT4KLEy488Eef4J/6q5aZdleiiYzMcOxRbYI=
                    </DigestValue>
                </Reference>
            </SignedInfo>
            <SignatureValue>
                NnZha0PyVlvjA2TZ0bzfgVsrS4sjFRAphs0wjD8suDY7jKO51QJ026SG/lss1N/nDF3snyU6lSFaX4vQFlcI3G/8z/J+fVIOoAsuIHdW160qtBtqUYJU4zce3Z/HHZi09eOzdUqqBg7z/zY8mFPxEIZ7/bz1F9FjzDDaY/tfEfl2UedNVsYu0KaapNUiGB5oeyvhZ/I6ELJfHBjwyUY6BU0unHx7jGUW7TC6nf3UULb/ir2sr1R3rv7UgxbrWE7P6UHU0SYGRkyf73XuLIM/gSESN0fvZjwCncSye05tpFUEog+OkYnBlJxCHQtBLuVf6Xxo2/sCdaG4EMGZULj7zQ==
            </SignatureValue>
            <KeyInfo>
                <X509Data>
                    <X509Certificate>
                        MIIC8DCCAdigAwIBAgIQLTJiSFda5qxGpkjtLwEBBjANBgkqhkpldo09d7ShADA0MTIwMAYDVQQDEylNaWNyb3NvZnQgQXp1cmUgRmVkZXJhdGVkIFNTTyBDZXJ0aWZpY2F0ZTAeFw0xOTAxMDkxNDAwMDJaFw0yMjAxMDkxNDAwMDJaMDQxMjAwBgNVBAMTKU1pY3Jvc29mdCBBenVyZSBGZWRlcmF0ZWQgU1NPIENlcnRpZmljYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAukESHqNsUOzhiwDjXgyvBFBpVhS2ZS6ePbW1SiB+18EnnZwSrxeO8beP8g43WSduqL0kxx5R+P5E+VAkH87IpXTm9HXRkhcwm8Xcp+6oTH7r7JqCvxgNP48AqqKSLeLj/vAjaUZa/AgT4b+9fj18ogcBYlCZ5iSLgyqB2FaBvli3L4P/c4zb35md7wQ7ez/Wl3ICcleleRjWvdOZzWHk7PwNJv7ZnnJ+SKVrWkSrRi0CQQQhXo4U0uM0u1paLAmopf9ASnOkvx2l5PIhvIJNulVJEHDVWgynyjy+RfvgRcUJgGcG7csvfjwIYZU4S1QJmNFUrlwU3dLV75sQRwZF1wIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAUlsUTF8MKW5FLqanNvddBhXSM8v7XxrhCrjd2u6v6G6OXSCkSphIJAymCcNCzDN6LLHOFNipSRg8V9jbFteuVOApECKPpgO0kRVHYqPAHyXqj8be9AwLJPEvYsHmujE9S6eamRiOJN3+MHEWUIUTJqaPNWezozVmvSHmpueoieQazZ7ZYOf/r5UH0q719+m5NuDYM2Ams38ec6mEly/kQezIrwruwfoWjSp1l+bdm+RmUE+VIGD8eXBQVmTCiA/50Et/gjmkx7SZgrETntBWjsnuf92wDaZKbrSeHnD1QZWs6/RDTTrRy6YbTB0dLX4gwU6TaJqDSrPv18KZ61LaC
                    </X509Certificate>
                </X509Data>
            </KeyInfo>
        </Signature>
        <Subject>
            <NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient">
                Ogssl0DHDyVZDB3v9H+HEUMQCKHoBlOAkrw7SAX5Uw8=
            </NameID>
            <SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
                <SubjectConfirmationData InResponseTo="id1548174206328404782111986" NotOnOrAfter="2019-01-22T16:30:30.992Z" Recipient="https://my-website/sso/sp/consume/idp_identifier" />
            </SubjectConfirmation>
        </Subject>
        <Conditions NotBefore="2019-01-22T16:20:30.992Z" NotOnOrAfter="2019-01-22T17:20:30.992Z">
            <AudienceRestriction>
                <Audience>
                    spn:be0cd693-414f-4369-b316-a89d948372ba
                </Audience>
            </AudienceRestriction>
        </Conditions>
        <AttributeStatement>
            <Attribute Name="http://schemas.microsoft.com/identity/claims/tenantid">
                <AttributeValue>
                    idp_identifier
                </AttributeValue>
            </Attribute>
            <Attribute Name="http://schemas.microsoft.com/identity/claims/objectidentifier">
                <AttributeValue>
                    f9fhud3e-7e79-4eeb-b28b-a91351ada5f9
                </AttributeValue>
            </Attribute>
            <Attribute Name="http://schemas.microsoft.com/identity/claims/displayname">
                <AttributeValue>
                    Logged_In_User_Name
                </AttributeValue>
            </Attribute>
            <Attribute Name="http://schemas.microsoft.com/identity/claims/identityprovider">
                <AttributeValue>
                    https://sts.windows.net/idp_identifier/
                </AttributeValue>
            </Attribute>
            <Attribute Name="http://schemas.microsoft.com/claims/authnmethodsreferences">
                <AttributeValue>
                    urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
                </AttributeValue>
            </Attribute>
            <Attribute Name="http://schemas.microsoft.com/ws/2008/06/identity/claims/role">
                <AttributeValue>
                    A_Role
                </AttributeValue>
            </Attribute>
            <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname">
                <AttributeValue>
                    Logged_In_User_Name
                </AttributeValue>
            </Attribute>
            <Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name">
                <AttributeValue>
                    Logged_In_User_Name@my-website.com
                </AttributeValue>
            </Attribute>
            <Attribute Name="Role Name">
                <AttributeValue>
                    A_Role
                </AttributeValue>
            </Attribute>
        </AttributeStatement>
        <AuthnStatement AuthnInstant="2019-01-22T16:25:25.642Z" SessionIndex="_33506e7a-3e12-45d4-894e-f5a7cbb092ef">
            <AuthnContext>
                <AuthnContextClassRef>
                    urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
                </AuthnContextClassRef>
            </AuthnContext>
        </AuthnStatement>
    </Assertion>
</Response>

Thanks in advance.

handnot2 commented 5 years ago

Looks like the assertion is signed but the message itself is not signed. Can enable message signing in your IdP and try it out?

What error are you getting with: signed_assertion_in_resp: true and signed_envelopes_in_resp: false?

richardbourne-ct commented 5 years ago

I'm working on message signing - will report back.

In the meantime, I tried those settings and received:

access_denied {:invalid_request, "{:error, {:assertion, {:error, :cert_not_accepted}}}"}
handnot2 commented 5 years ago

That is the root cause. esaml/samly not able to work with the Azure federated SSO cert include in the response.

Can you check if openssl is able to print the contents of this certificate?

handnot2 commented 5 years ago

Can you use a self-signed certificate? I think that will address this issue.

richardbourne-ct commented 5 years ago

Yes, openssl is able to print successfully.

I will check about using self-signed.

richardbourne-ct commented 5 years ago

I asked about self-signed:

"In SAML the signing/decryption certificates are always self-signed."

handnot2 commented 5 years ago

If you search for cert_not_accepted in esaml, you will find that this error occurs when the cert fingerprint is not trusted. It is possible for this to happen when the certificate in the idp metadata file specified in the config does not match the one coming through the SAML response. Can you check if this mismatch exists? Would you be able to share the idp metadata file? (Do so only if you think it is not an issue for you to share it publicly.)

richardbourne-ct commented 5 years ago

Ah! Looks like I was using the wrong idp metadata file (we have 3 environments set up). Now that I have the correct one in place, I'm further along!

Now seeing an issue with :bad_audience being returned from the validate_assertion/3 function in esaml.

validate_assertion(AssertionXml, Recipient, Audience) ->
    case decode_assertion(AssertionXml) of
        {error, Reason} ->
            {error, Reason};
        {ok, Assertion} ->
            esaml_util:threaduntil([
                fun(A) -> case A of
                    #esaml_assertion{version = "2.0"} -> A;
                    _ -> {error, bad_version}
                end end,
                fun(A) -> case A of
                    #esaml_assertion{recipient = Recipient} -> A;
                    _ -> {error, bad_recipient}
                end end,
                fun(A) -> case A of
                    #esaml_assertion{conditions = Conds} ->
                        case proplists:get_value(audience, Conds) of
                            undefined -> A;
                            Audience -> A;
                            _ -> {error, bad_audience}
                        end;
                    _ -> A
                end end,
                fun check_stale/1
            ], Assertion)
    end.

The only reference to conditions or Audience in the SAML response is:

<Conditions NotBefore="2019-01-28T11:34:28.244Z" NotOnOrAfter="2019-01-28T12:34:28.244Z">
  <AudienceRestriction>
    <Audience>
      spn:be0cd693-414f-4369-b316-a89d133953ba
    </Audience>
  </AudienceRestriction>
</Conditions>
handnot2 commented 5 years ago

Set your service provider entity_id to that audience value ("spn:be0cd693-414f-4369-b316-a89d133953ba") in config. If the entity_id value is not specified in config, the sp metadata URL is used. If you have multiple IdPs, make sure you are using the correct service provider config to set the entity_id value. Hopefully this resolves the issue! :-)

richardbourne-ct commented 5 years ago

Hurray! That did it - thank you for all your help.

I was specifying the entity_id but was setting it to the same as the SP id.