Signed SAML Request
samlify honours the signing preferences declared in metadata. When metadata does not specify otherwise, SAML requests are not signed by default.
In the IdP metadata, the WantAuthnRequestsSigned attribute controls whether the IdP requires signed requests. The default is false:
<IDPSSODescriptor
WantAuthnRequestsSigned="true"
ID="SM14a93e72cb19411b4fc4eec882c98b12dbf55cea68e"
protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">In the SP metadata, the AuthnRequestsSigned attribute controls whether the SP signs its requests. The default is false:
<SPSSODescriptor
AuthnRequestsSigned="true"
protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">When the SP signs requests, its X.509 certificate must be included in the 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 the SP and IdP preferences do not agree, samlify throws an error at runtime so the mismatch can be diagnosed quickly.
If the IdP does not publish metadata, either request it or configure the IdP programmatically (see IdP configuration).
Metadata only declares preferences. To sign an XML document, samlify also needs the private key and the signature algorithm:
const saml = require('samlify');
// Define the SP settings.
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 the service provider.
const sp = saml.ServiceProvider(setting);privateKeyPass is only required when the private key is encrypted. requestSignatureAlgorithm defaults to RSA-SHA256.
Supported 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 the SP is configured, sending a signed SAML request uses the same entry point as the unsigned case:
router.get('/spinitsso-redirect', (req, res) => {
const { id, context } = sp.createLoginRequest(idp, 'redirect');
return res.redirect(context);
});How the signature is generated
This section explains how samlify computes the signature for each binding. Skip it if you only need the API surface.
HTTP-Redirect binding
- The canonical octet string is the URL-encoded concatenation of
SAMLRequest,RelayState, andSigAlg:SAMLRequest=xxx&RelayState=yyy&SigAlg=zzz. - The resulting signature is base64-encoded.
RelayStateis optional. When absent, it is omitted from the octet string:SAMLRequest=xxx&SigAlg=zzz.
HTTP-POST binding
The binding uses an XML digital signature embedded inside the AuthnRequest:
<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>