Signed SAML Request
We follow the preference in metadata files. If it doesn't state in the metadata, default is not to sign the SAML Request.
In IdP's metadata, there is an attribute called WantAuthnRequestsSigned. Default value is false.
<IDPSSODescriptor
WantAuthnRequestsSigned="true"
ID="SM14a93e72cb19411b4fc4eec882c98b12dbf55cea68e"
protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">In SP's metadata, there is an attribute called AuthnRequestsSigned. Default value is false.
<SPSSODescriptor
AuthnRequestsSigned="true"
protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">and include the X.509 certificate in SP's metadata.
<SPSSODescriptor
AuthnRequestsSigned="true"
WantAssertionsSigned="true"
protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<KeyDescriptor use="signing">
<KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<X509Data>
<X509Certificate>MIIDozCCAougAwIBAgIJAKN...</X509Certificate>
</X509Data>
</KeyInfo>
</KeyDescriptor>
...If both two attributes are not matched, an error will be thrown out during run-time. Developers can easily locate the error.
If IdP doesn't provide the metadata for you, 1) you may ask them 2) import an object setting, see advanced topics here.
Metadata stores the preferences only. To sign a XML document, we still need our private key and signature algorithm. We can configure our SP here:
const saml = require('samlify');
// Define the setting
const setting = {
privateKey: fs.readFileSync('./key/sp_key.pem'),
privateKeyPass: 'KCkGOSjrcAuXFwU1pVH5RUiBcrsNA8px',
requestSignatureAlgorithm: 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512',
metadata: fs.readFileSync('./metadata_sp.xml')
};
// Construct our service provider
const sp = saml.ServiceProvider(setting);The property privateKeyPass is optional in case you have set a passphrase when the private key is created. Also the default value of requestSignatureAlgorithm is RSA-SHA1.
All support signature algorithms:
'http://www.w3.org/2000/09/xmldsig#rsa-sha1',
'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256',
'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512'Once you have configured the SP correctly, all you need to send a signed SAML Request is to do as follow:
router.get('/spinitsso-redirect', (req, res) => {
const { id, context } = sp.createLoginRequest(idp, 'redirect');
return res.redirect(context);
});Yes, it's the same method we used to send a SAML Request without signature.
How to generate a signature
For those who are not interested in how the signature generates, you can skip this section. The signature is generated by two different formats.
In Redirect-Binding, the URL-encoded message should be assigned as follow:
- Octet string is a concatenation of SAMLRequest, RelayState and SigAlg.
SAMLRequest=xxx&RelayState=yyy&SigAlg=zzz - Signature MUST be encoded by base64 encoding.
- RelayState is an optional parameter. If there is no RelayState value, this parameter should be ignored from computing signature. e.g.
SAMLRequest=xxx&SigAlg=zzz
In Post-Binding, XML digital signature is used and embedded inside the Request XML.
<samlp:AuthnRequest
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="_809707f0030a5d00620c9d9df97f627afe9dcc24"
Version="2.0"
ProviderName="SP test"
IssueInstant="2014-07-16T23:52:45Z"
Destination="https://idp.example.org/SSOService"
ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
AssertionConsumerServiceURL="https://sp.example.org/sso/acs">
<saml:Issuer ID="_0">https://sp.example.org/metadata</saml:Issuer>
<samlp:NameIDPolicy Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress" AllowCreate="true"/>
<samlp:RequestedAuthnContext Comparison="exact">
<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
</samlp:RequestedAuthnContext>
<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/2000/09/xmldsig#rsa-sha1"/>
<Reference URI="#_0">
<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<DigestValue>tQDisBXKTQ+9OXJO5r7KuJga+KI=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>oxRkvau7UvYgFEZ7YNAUNf3067V7Tn5C9XSIiet1aZw2FYevNW5bUy/0mxp3aj6AvfFjnmpzAb88BjdwAz2BErDTomRcuZB7Lb0fYTf31N2oZOX0MiPiQOH54I63qJW4Xo3VqdF7GBuFZZHyllfSBv7gfCtjJDwFSCzWK70B9r3cFMRJZLhCJ9oPen+4U9scSYO6g+szBZLl6AiJ06PHc8jzEKGwfQrcZk8kDKUlvNfJMULyq8dpx2VvUAx4p5ewfMOwB9W3Hl3PPa0dO77zZif3CglpcN06f+m6UYG/wnoTQEyKW9hOe+2vGM80W77eWu0dmiaPuqT1ok8LXPuq1A==</SignatureValue>
</Signature>
</samlp:AuthnRequest>