-
Notifications
You must be signed in to change notification settings - Fork 188
Respect idAttribute when generating signatures. #508
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| import { NamespacedId } from "./types"; | ||
|
|
||
| /** Well known namespaced ids */ | ||
| export const KNOWN_NAMESPACED_IDS: { [key: string]: NamespacedId } = { | ||
| /** WS-Security */ | ||
| wssecurity: { | ||
| prefix: "wsu", | ||
| localName: "Id", | ||
| nameSpaceURI: | ||
| "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", | ||
| }, | ||
| /** Xml */ | ||
| xml: { | ||
| prefix: "xml", | ||
| localName: "id", | ||
| nameSpaceURI: "http://www.w3.org/XML/1998/namespace", | ||
| }, | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,7 @@ import type { | |
| GetKeyInfoContentArgs, | ||
| HashAlgorithm, | ||
| HashAlgorithmType, | ||
| NamespacedId, | ||
| ObjectAttributes, | ||
| Reference, | ||
| SignatureAlgorithm, | ||
|
|
@@ -26,10 +27,11 @@ import * as execC14n from "./exclusive-canonicalization"; | |
| import * as hashAlgorithms from "./hash-algorithms"; | ||
| import * as signatureAlgorithms from "./signature-algorithms"; | ||
| import * as utils from "./utils"; | ||
| import { KNOWN_NAMESPACED_IDS } from "./constants"; | ||
|
|
||
| export class SignedXml { | ||
| idMode?: "wssecurity"; | ||
| idAttributes: string[]; | ||
| idAttributes: (string | NamespacedId)[]; | ||
| /** | ||
| * A {@link Buffer} or pem encoded {@link String} containing your private key | ||
| */ | ||
|
|
@@ -155,6 +157,10 @@ export class SignedXml { | |
| if (idAttribute) { | ||
| this.idAttributes.unshift(idAttribute); | ||
| } | ||
| if (idMode === "wssecurity") { | ||
| this.idAttributes.unshift(KNOWN_NAMESPACED_IDS["wssecurity"]); | ||
| } | ||
|
|
||
| this.privateKey = privateKey; | ||
| this.publicCert = publicCert; | ||
| this.signatureAlgorithm = signatureAlgorithm ?? this.signatureAlgorithm; | ||
|
|
@@ -503,7 +509,10 @@ export class SignedXml { | |
| const uri = ref.uri?.[0] === "#" ? ref.uri.substring(1) : ref.uri; | ||
|
|
||
| for (const attr of this.idAttributes) { | ||
| const elemId = elem.getAttribute(attr); | ||
| const elemId = | ||
| typeof attr === "string" | ||
| ? elem.getAttribute(attr) | ||
| : elem.getAttribute(`${attr.prefix}:${attr.localName}`); | ||
|
Comment on lines
+512
to
+515
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Consider using getAttributeNS for namespaced attributes. The code constructs a prefixed attribute name ( Apply this pattern for reading namespaced attributes: const elemId =
typeof attr === "string"
? elem.getAttribute(attr)
- : elem.getAttribute(`${attr.prefix}:${attr.localName}`);
+ : elem.getAttributeNS(attr.nameSpaceURI, attr.localName);This ensures correct attribute resolution regardless of prefix usage in the document.
🤖 Prompt for AI Agents |
||
| if (uri === elemId) { | ||
| ref.xpath = `//*[@*[local-name(.)='${attr}']='${uri}']`; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix XPath construction for NamespacedId. When Apply this fix: + const attrName = typeof attr === "string" ? attr : attr.localName;
- if (uri === elemId) {
- ref.xpath = `//*[@*[local-name(.)='${attr}']='${uri}']`;
+ if (uri === elemId) {
+ ref.xpath = `//*[@*[local-name(.)='${attrName}']='${uri}']`;
break; // found the correct element, no need to check further
}
🤖 Prompt for AI Agents |
||
| break; // found the correct element, no need to check further | ||
|
|
@@ -1297,18 +1306,10 @@ export class SignedXml { | |
| private ensureHasId(node) { | ||
| let attr; | ||
|
|
||
| if (this.idMode === "wssecurity") { | ||
| attr = utils.findAttr( | ||
| node, | ||
| "Id", | ||
| "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", | ||
| ); | ||
| } else { | ||
| this.idAttributes.some((idAttribute) => { | ||
| attr = utils.findAttr(node, idAttribute); | ||
| return !!attr; // This will break the loop as soon as a truthy attr is found. | ||
| }); | ||
| } | ||
| this.idAttributes.some((idAttribute) => { | ||
| attr = utils.findAttr(node, idAttribute); | ||
| return !!attr; // This will break the loop as soon as a truthy attr is found. | ||
| }); | ||
|
|
||
| if (attr) { | ||
| return attr.value; | ||
|
|
@@ -1317,21 +1318,20 @@ export class SignedXml { | |
| //add the attribute | ||
| const id = `_${this.id++}`; | ||
|
|
||
| if (this.idMode === "wssecurity") { | ||
| if (typeof this.idAttributes[0] === "string") { | ||
| node.setAttribute(this.idAttributes[0], id); | ||
| } else { | ||
| node.setAttributeNS( | ||
| "http://www.w3.org/2000/xmlns/", | ||
| "xmlns:wsu", | ||
| "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", | ||
| `xmlns:${this.idAttributes[0].prefix}`, | ||
| this.idAttributes[0].nameSpaceURI, | ||
| ); | ||
| node.setAttributeNS( | ||
| "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", | ||
| "wsu:Id", | ||
| this.idAttributes[0].nameSpaceURI, | ||
| `${this.idAttributes[0].prefix}:${this.idAttributes[0].localName}`, | ||
| id, | ||
| ); | ||
| } else { | ||
| node.setAttribute("Id", id); | ||
| } | ||
|
|
||
| return id; | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
LGTM! Supports the xml:id use case.
The
xmlentry correctly models thexml:idattribute, addressing the customer requirement mentioned in the PR comments where they need to generate signatures withxml:idinstead ofId.Verify that the
xmlconstant is actually used in the codebase:🏁 Script executed:
Length of output: 0
🏁 Script executed:
Length of output: 1317
🏁 Script executed:
Length of output: 110
🏁 Script executed:
Length of output: 815
Add implementation logic to complete the xml:id support feature.
The
xmlconstant has been added toKNOWN_NAMESPACED_IDS, but the feature is incomplete and currently dead code. To make this functional:Update the
idModetype atsrc/signed-xml.ts:33to include"xml":Add the corresponding handler in the constructor (after line 162):
Without these changes, the
xmlconstant cannot be used and the customer's xml:id use case won't function.🤖 Prompt for AI Agents