Unable to create SAML response from IDP

Viewed 294

I have to create a Single Sign-On (SSO) for Salesforce. For authorization, I will be using user's mobile number with OTP. I have to only create a SAML response using Go once the OTP is verified.

I can see that there are a couple of libraries for that go-saml, gosaml, go-oauth and goauth for the Go Programming Language, but even after a couple of hours of searching, I couldn't decide which one is suitable for me. I don't have to implement complete IDP, I only have to dynamically create a SAML response.

I found the XML response template which I need to create from https://www.samltool.com/generic_sso_res.php. So I have to create SAML response like below:-

<?xml version="1.0" encoding="UTF-8"?>
<saml1p:Response xmlns:saml1p="urn:oasis:names:tc:SAML:1.0:protocol" IssueInstant="2020-02-26T17:32:05.200Z" MajorVersion="1" MinorVersion="1" Recipient="https://im--partial.my.salesforce.com" ResponseID="_34ae7ce8-5f7fbd4d">
    <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <ds:SignedInfo>
            <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
            <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha1"/>
            <ds:Reference URI="#_34ae7ce8-5f7fbd4d">
                <ds:Transforms>
                    <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
                    <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                </ds:Transforms>
                <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                <ds:DigestValue>fxk4drd6yhVQrJCtdfvYOyYYGAM=</ds:DigestValue>
            </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue>EsjQYhFsL+Xvcgg59AkZja....8INZrTwyfLmo4+NMyYViDX6Q==</ds:SignatureValue>
        <ds:KeyInfo>
            <ds:X509Data>
                <ds:X509Certificate>MIID0zCCA5GgAwIBAgIEF...XWlGzJ3SdBlgRsdFgKyFtcxE=</ds:X509Certificate>
            </ds:X509Data>
        </ds:KeyInfo>
    </ds:Signature>
    <saml1p:Status>
        <saml1p:StatusCode Value="saml1p:Success"/>
    </saml1p:Status>
    <saml1:Assertion xmlns:saml1="urn:oasis:names:tc:SAML:1.0:assertion" AssertionID="_7f959448-5dbf311f" IssueInstant="2020-02-26T17:32:05.200Z" Issuer="AXIOM" MajorVersion="1" MinorVersion="1">
        <saml1:Conditions NotBefore="2020-02-26T17:32:05.199Z" NotOnOrAfter="2020-02-26T17:33:05.199Z">
            <saml1:AudienceRestrictionCondition>
                <saml1:Audience>https://saml.salesforce.com</saml1:Audience>
            </saml1:AudienceRestrictionCondition>
        </saml1:Conditions>
        <saml1:AuthenticationStatement AuthenticationInstant="2020-02-26T17:32:05.199Z" AuthenticationMethod="urn:oasis:names:tc:SAML:1.0:am:unspecified">
            <saml1:Subject>
                <saml1:NameIdentifier>rahul.satal@xyz.com</saml1:NameIdentifier>
                <saml1:SubjectConfirmation>
                    <saml1:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:bearer</saml1:ConfirmationMethod>
                </saml1:SubjectConfirmation>
            </saml1:Subject>
        </saml1:AuthenticationStatement>
    </saml1:Assertion>
</saml1p:Response>

Wherein I only need to update a couple of parameters like Assertion_Id, Issuer, Audience, Recipient, Subject, Not before/After date, Attribute Statement, etc. I am not sure if I need any library for this or can get a single script.

1 Answers

This library appears to be a simple SAML library for Go that takes care of SAML Response generation as well as signing that Response.

I've also seen this done using "templates", where no SAML processing was actually done. A prepared block of text, with placeholders was opened, the placeholders replaced with the required text and the response sent.

saml1p:Response

could be a template with IssueInstant and ResponseID created at run time. e.g pseudo code would be:

String samlTemplate = loadSAMLTemplate()
  .gsub("__IssueInstant__", "2020-02-26T17:32:05.200Z")
  .gsub("__ResponseID__", "9421878f98")
  .gsub( ... and so on ...)

it's possible to do it that way, if not ideal and it only works if you only ever have a single Assertion.

You would use the above template and replace the substituable parts with placeholders, e.g.

<saml1p:Response
  xmlns:saml1p="urn:oasis:names:tc:SAML:1.0:protocol"
  IssueInstant="__IssueInstant__"
  MajorVersion="1"
  MinorVersion="1"
  Recipient="https://im--partial.my.salesforce.com"
  ResponseID="__ResponseID__">

to build up an XML SAML Response. You would have placeholders for AssertionID etc. Anything that needs to be unique per SAML Response would need a placeholder, with its content replaced at run time.

You then need to sign that Response. You can't do that by replacing stuff. You can only do it by digitally signing using XML Signature. You could use this library to do that. It's still coding the Response but you only have to work with the signature and not the entire SAML process.

So the workflow would be:

  • Create reusable SAML Response as a text template with PlaceHolders for each replaceable text.
  • Load the template, replace all the bits you need to replace. This is your SAML Response.
  • Use the XML Signature library to sign the SAML Response. This is what you send to the SP.
Related