mocksaml/utils/request.ts

86 lines
2.5 KiB
TypeScript
Raw Normal View History

import { DOMParser as Dom } from '@xmldom/xmldom';
2022-02-22 06:14:12 +00:00
import { promisify } from 'util';
import { certToPEM } from 'utils';
import { SignedXml, xpath as select } from 'xml-crypto';
2022-02-23 13:48:20 +00:00
import xml2js from 'xml2js';
2022-02-22 06:14:12 +00:00
import { inflateRaw } from 'zlib';
2022-02-21 14:31:47 +00:00
2022-02-22 05:35:42 +00:00
const inflateRawAsync = promisify(inflateRaw);
2022-02-21 14:31:47 +00:00
// Parse XML
const parseXML = (xml: string): Promise<Record<string, any>> => {
return new Promise((resolve, reject) => {
xml2js.parseString(xml, (err: Error, result: any) => {
2022-02-22 05:36:06 +00:00
if (err) {
2022-02-21 14:31:47 +00:00
reject(err);
}
resolve(result);
});
});
};
// Decode the base64 string
const decodeBase64 = async (string: string, isDeflated: boolean) => {
return isDeflated
? (await inflateRawAsync(Buffer.from(string, 'base64'))).toString()
: Buffer.from(string, 'base64').toString();
};
2022-02-21 14:31:47 +00:00
// Parse SAMLRequest attributes
const extractSAMLRequestAttributes = async (rawRequest: string) => {
const result = await parseXML(rawRequest);
2022-02-21 14:31:47 +00:00
2022-02-22 06:14:12 +00:00
const attributes = result['samlp:AuthnRequest']['$'];
const issuer = result['samlp:AuthnRequest']['saml:Issuer'];
2022-02-21 14:31:47 +00:00
return {
2022-02-22 05:35:42 +00:00
id: attributes.ID,
acsUrl: attributes.AssertionConsumerServiceURL,
providerName: attributes.ProviderName,
2022-02-22 06:14:12 +00:00
audience: issuer[0]['_'],
publicKey:
result['samlp:AuthnRequest']['Signature'][0]['KeyInfo'][0]['X509Data'][0]['X509Certificate'][0],
2022-02-21 14:31:47 +00:00
};
};
// Validate signature
const hasValidSignature = async (xml: string, certificate: string): Promise<boolean> => {
return new Promise((resolve, reject) => {
const doc = new Dom().parseFromString(xml);
const signature =
select(
doc,
"/*/*/*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']"
)[0] ||
select(
doc,
"/*/*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']"
)[0] ||
select(
doc,
"/*/*/*/*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']"
)[0];
const signed = new SignedXml();
signed.keyInfoProvider = {
getKey: function getKey(keyInfo: any) {
return certToPEM(certificate);
},
getKeyInfo: function getKeyInfo(key: any) {
return '<X509Data></X509Data>';
},
};
signed.loadSignature(signature.toString());
const response = signed.checkSignature(xml);
return !response ? reject(false) : resolve(true);
});
};
export { extractSAMLRequestAttributes, hasValidSignature, decodeBase64 };