Skip to content

Possible regression when using combined signing options #628

Description

@Parsonswy

A new default introduced in #619 can cause the following error when idp.authnRequestSigned: true and sp.wantMessagesSigned: true when calling sp.createLoginRequest() for post binding. It was working before because of another default that gets overridden now.

Error

Error: the following xpath cannot be used because it was not found: /*[local-name(.)='Response']/*[local-name(.)='Issuer']
    at SignedXml.computeSignature (/home/wyatt/24g/Repos/lxs/node_modules/.pnpm/xml-crypto@6.1.2/node_modules/xml-crypto/src/signed-xml.ts:989:20)
    at Object.constructSAMLSignature (/home/wyatt/24g/Repos/lxs/node_modules/.pnpm/samlify@2.13.1/node_modules/samlify/src/libsaml.ts:547:13)
    at Object.base64LoginRequest (/home/wyatt/24g/Repos/lxs/node_modules/.pnpm/samlify@2.13.1/node_modules/samlify/src/binding-post.ts:112:24)
    at ServiceProvider.createLoginRequest (/home/wyatt/24g/Repos/lxs/node_modules/.pnpm/samlify@2.13.1/node_modules/samlify/src/entity-sp.ts:127:31)
    at file:///home/wyatt/24g/Repos/lxs/samlify-bug.ts:100:22
    at ModuleJob.run (node:internal/modules/esm/module_job:343:25)
    at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:665:26)
    at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:117:5)

I don't think wantMessagesSigned impacts the [*sp] signing process. Another interpretation of this is that wantMessagesSigned and wantAssertionsSigned should be left off when configuring a service provider to be used for <AuthNRequest> generation and this is instead a misconfiguration rather than a bug. My application was setup to load the full configuration I had saved for the SP and IDP regardless of how it was going to be used (create request or assert a response). As a work around I've setup my application to omit want*Signed config when the SP will be used for createLoginRequest() calls. Manually passing in the xpath config would also work.

Script to reproduce

// @ts-nocheck
import { createRequire } from "node:module";

const require = createRequire(import.meta.url);
const saml = require("samlify");

const bindingPost = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST";

const signingCert = `MIIDJTCCAg2gAwIBAgIUc80i8Xk6UKleV+LW3h+HwGOnO2swDQYJKoZIhvcNAQEL
BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI2MDUyMTE3MDc1OFoXDTI3MDUy
MTE3MDc1OFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAsmwZP+Sp2xjK5gL/EPZmwKmNhwVowp3TZXFicHQeQ4RA
usevA3tGuJPLsTtlGNGtio0kHkObMNFOb3ceziHCPBjNDlkhZY/Kcwd8oeeq0BbL
KKtoSP1PPHGaiWV6C2zXeOhd04Ndw8clkDNuUR0StwGigKTLZwXya3yAzRY+Feqg
kzxlmiXZK0rqkYq7pMeslvYmauFWGaC+3B86XIx8D+ESCImi3PBPy1buTSLpS7Mm
Q3BRTpU0/JEqMvoWwQJM5XHxSfB5MyH1m2WlOFbikW3tuiVS51xKrvvGnR9nDw/E
ml9aZ0odmoh6EFr3OJyYaNjeY5wkcdPBmme1ABkhRQIDAQABo28wbTAdBgNVHQ4E
FgQUv4IKD7R/Ey155qDTgQ0S4bIvyj0wHwYDVR0jBBgwFoAUv4IKD7R/Ey155qDT
gQ0S4bIvyj0wDwYDVR0TAQH/BAUwAwEB/zAaBgNVHREEEzARgglsb2NhbGhvc3SH
BH8AAAEwDQYJKoZIhvcNAQELBQADggEBAHCTuu9QGzW0dRPPE4G8LIKDMo5vGN/F
jOZt7SVirIGiF12qGna+56zZ20IIEfVVbzBc/BIDyDyuplIuEPg1GS/jZB5HTaOp
xmCc6i4d+Hj3i70l+xBcak4WcGjhE8wDmWPe5dDb1pfss7m9bbIH73JmtcA9hfTI
QqSHPqwX/ZxxEpdoFZde6suMgNXauqi6lWkb9AY0z1lWMzMf/6Awckks2PJ2zPxA
GsWm6MTMU0xrxKmclcgq6otRkxw2R923I2zGYOqQZRtGuWBMdhb+P/9ADsNmb7N1
1lkh+JApJBxD3jpfVGqqBAYuVxlGcRnz9QA7KuOtWGrqg71SZIAP/5k=`;

const privateKey = `-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCybBk/5KnbGMrm
Av8Q9mbAqY2HBWjCndNlcWJwdB5DhEC6x68De0a4k8uxO2UY0a2KjSQeQ5sw0U5v
dx7OIcI8GM0OWSFlj8pzB3yh56rQFssoq2hI/U88cZqJZXoLbNd46F3Tg13DxyWQ
M25RHRK3AaKApMtnBfJrfIDNFj4V6qCTPGWaJdkrSuqRirukx6yW9iZq4VYZoL7c
HzpcjHwP4RIIiaLc8E/LVu5NIulLsyZDcFFOlTT8kSoy+hbBAkzlcfFJ8HkzIfWb
ZaU4VuKRbe26JVLnXEqu+8adH2cPD8SaX1pnSh2aiHoQWvc4nJho2N5jnCRx08Ga
Z7UAGSFFAgMBAAECggEAJhl8OM8Q0EbWiNBJ/CrJnUl3fcYTbT97dTWFkkLRdZRn
qBrcze8EloSE4gcvWuHnX2ctN8My//Up/RZgPx8pVWDsZKx2u7O9RNvr6rzIFmBP
qJMVlUR2J4+Qstc2/PqUdm6UHob2PkinxkedPnfpV6fjNfo6rvivn/E5pdGil1Yj
2KONsn7AiEkgSOtGubhFuviFn4NnbFHfqREZABzRTZr64OzrZTcCaso53TRSkl+V
s8ImoWuyYa4YXOwvTn1gbgb1wPTsImrq+2TzT/aaaXHN+CVEQJdyfV7H6741MFPD
84r6aG6/EBNnrLe78yqOcdUTFFpA5M3ksF5l9mDenwKBgQDjh3pgqtaluJ4BV9QI
RTi0yHuX+KqCc+94zBG8rhH2v26HJ7vbNG5k7aWnVsccq9X3tm9liWcwWET6Dm07
8/bpBNnFOEeznjzt5F5Jysu8jEEKszD8TK4adDAzAsIhoJ+Ik3/h8TCMM9QS4eiL
6o8xx+cKmdJczblPNtwtZhObLwKBgQDIv4+GVCi4qlHNTO3jQUikUDUWYUrw4mRc
jg8CDeXPZuM8d6RCIHJWsCGjdi+bljYs6EUCWfyMcP7fULVZ2eH8Uq4b/bUniKyN
eeB2cF8Qndy6mcvgUy3RBLnBA8GsTQb7LpjlvqflXm2BHAAO2rmB84AJtTiMSeVQ
spr41GNdywKBgQDDHeYTSc3C1dwh2LiK0xm65oYen+9Q6az90TqQrFHZYPaezrMp
WwAkayt4olEjxDQ8NmW3FCq6aafVLFP+astdrnw1xXqvjM5BT2qQK2ml6jzIuTwT
0IopQ2QmCoKCJeVJUPwEvTndsYB3JOWwPtjHXt9B1wFv9jeot6n/AJ9lnwKBgQCr
dKD608pr3lw7gmbzYADRBggxcyt0jYe2XUaINKKA/5k5Pd429Etzqr8wQ3Lp6eOf
e0nldkHzGVc2GFKrySHwRhWappggieUGeH+z6MnpAUtSvKSalbBeAzE7nx+9L5S0
19mS78Gqb3oLeYS7Kyihyv0iTXtcpoiK4eDmgU/U/QKBgQDGfDBnDiebkN338WJp
/jIZuakSDwFHq+x+MjihIPjBNFyg3SIIL9brek0bDoHFkR2R8VrURGb8pkleK847
wE4eCmZLsuURDjed1rUoh+8VJHT2LsBBNOO4cOBMfO6fnrYA4jVN8Wxfv5hLjHUB
YGwbfEJVeUBFMIaabek/4kasjQ==
-----END PRIVATE KEY-----`;

function makeIdp() {
  return saml.IdentityProvider({
    entityID: "https://idp.example.test/metadata",
    wantAuthnRequestsSigned: true,
    singleSignOnService: [
      {
        Binding: bindingPost,
        Location: "https://idp.example.test/sso",
      },
    ],
    singleLogoutService: [
      {
        Binding: bindingPost,
        Location: "https://idp.example.test/slo",
      },
    ],
  });
}

function makeSp() {
  return saml.ServiceProvider({
    entityID: "https://sp.example.test/metadata",
    assertionConsumerService: [
      {
        Binding: bindingPost,
        Location: "https://sp.example.test/saml/assert",
      },
    ],
    signingCert,
    privateKey,
    authnRequestsSigned: true,
    wantAssertionsSigned: true,
    wantMessageSigned: true,
  });
}

console.log("Regression trigger: wantMessageSigned + signed POST AuthnRequest");

const sp = makeSp();
const idp = makeIdp();

console.log("samlify-populated SP signatureConfig", sp.entitySetting.signatureConfig);

try {
  const request = sp.createLoginRequest(idp, "post");
  console.log("created AuthnRequest", {
    id: request.id,
    destination: request.entityEndpoint,
    base64Length: request.context.length,
  });
} catch (error) {
  console.error(error);
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions