Add response signing - wip
This commit is contained in:
parent
4022901ea9
commit
364cd92ffb
@ -1,3 +1,5 @@
|
||||
// import { fetchPrivateKey, fetchPublicKey } from "utils";
|
||||
|
||||
const appUrl = process.env.APP_URL || 'http://localhost:4000';
|
||||
const entityId = process.env.ENTITY_ID || 'http://saml.example.com';
|
||||
const ssoUrl = `${appUrl}/api/saml/sso`;
|
||||
|
||||
28
package-lock.json
generated
28
package-lock.json
generated
@ -6,10 +6,10 @@
|
||||
"": {
|
||||
"name": "fake",
|
||||
"dependencies": {
|
||||
"@types/xml-crypto": "^1.4.2",
|
||||
"axios": "^0.24.0",
|
||||
"next": "12.1.0",
|
||||
"node-fetch": "^3.2.0",
|
||||
"node-forge": "^1.2.1",
|
||||
"rambda": "^7.0.2",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
@ -21,6 +21,7 @@
|
||||
"devDependencies": {
|
||||
"@types/node": "17.0.8",
|
||||
"@types/react": "17.0.38",
|
||||
"@types/xml-crypto": "^1.4.2",
|
||||
"@types/xml2js": "0.4.9",
|
||||
"autoprefixer": "10.4.2",
|
||||
"eslint": "8.6.0",
|
||||
@ -429,7 +430,8 @@
|
||||
"node_modules/@types/node": {
|
||||
"version": "17.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.8.tgz",
|
||||
"integrity": "sha512-YofkM6fGv4gDJq78g4j0mMuGMkZVxZDgtU0JRdx6FgiJDG+0fY0GKVolOV8WqVmEhLCXkQRjwDdKyPxJp/uucg=="
|
||||
"integrity": "sha512-YofkM6fGv4gDJq78g4j0mMuGMkZVxZDgtU0JRdx6FgiJDG+0fY0GKVolOV8WqVmEhLCXkQRjwDdKyPxJp/uucg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/parse-json": {
|
||||
"version": "4.0.0",
|
||||
@ -464,6 +466,7 @@
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/xml-crypto/-/xml-crypto-1.4.2.tgz",
|
||||
"integrity": "sha512-1kT+3gVkeBDg7Ih8NefxGYfCApwZViMIs5IEs5AXF6Fpsrnf9CLAEIRh0DYb1mIcRcvysVbe27cHsJD6rJi36w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"xpath": "0.0.27"
|
||||
@ -473,6 +476,7 @@
|
||||
"version": "0.0.27",
|
||||
"resolved": "https://registry.npmjs.org/xpath/-/xpath-0.0.27.tgz",
|
||||
"integrity": "sha512-fg03WRxtkCV6ohClePNAECYsmpKKTv5L8y/X3Dn1hQrec3POx2jHZ/0P2qQ6HvsrU1BmeqXcof3NGGueG6LxwQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.6.0"
|
||||
}
|
||||
@ -4817,6 +4821,14 @@
|
||||
"url": "https://opencollective.com/node-fetch"
|
||||
}
|
||||
},
|
||||
"node_modules/node-forge": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.2.1.tgz",
|
||||
"integrity": "sha512-Fcvtbb+zBcZXbTTVwqGA5W+MKBj56UjVRevvchv5XrcyXbmNdesfZL37nlcWOfpgHhgmxApw3tQbTr4CqNmX4w==",
|
||||
"engines": {
|
||||
"node": ">= 6.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-libs-browser": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz",
|
||||
@ -8288,7 +8300,8 @@
|
||||
"@types/node": {
|
||||
"version": "17.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.8.tgz",
|
||||
"integrity": "sha512-YofkM6fGv4gDJq78g4j0mMuGMkZVxZDgtU0JRdx6FgiJDG+0fY0GKVolOV8WqVmEhLCXkQRjwDdKyPxJp/uucg=="
|
||||
"integrity": "sha512-YofkM6fGv4gDJq78g4j0mMuGMkZVxZDgtU0JRdx6FgiJDG+0fY0GKVolOV8WqVmEhLCXkQRjwDdKyPxJp/uucg==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/parse-json": {
|
||||
"version": "4.0.0",
|
||||
@ -8323,6 +8336,7 @@
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/xml-crypto/-/xml-crypto-1.4.2.tgz",
|
||||
"integrity": "sha512-1kT+3gVkeBDg7Ih8NefxGYfCApwZViMIs5IEs5AXF6Fpsrnf9CLAEIRh0DYb1mIcRcvysVbe27cHsJD6rJi36w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*",
|
||||
"xpath": "0.0.27"
|
||||
@ -8331,7 +8345,8 @@
|
||||
"xpath": {
|
||||
"version": "0.0.27",
|
||||
"resolved": "https://registry.npmjs.org/xpath/-/xpath-0.0.27.tgz",
|
||||
"integrity": "sha512-fg03WRxtkCV6ohClePNAECYsmpKKTv5L8y/X3Dn1hQrec3POx2jHZ/0P2qQ6HvsrU1BmeqXcof3NGGueG6LxwQ=="
|
||||
"integrity": "sha512-fg03WRxtkCV6ohClePNAECYsmpKKTv5L8y/X3Dn1hQrec3POx2jHZ/0P2qQ6HvsrU1BmeqXcof3NGGueG6LxwQ==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -11787,6 +11802,11 @@
|
||||
"formdata-polyfill": "^4.0.10"
|
||||
}
|
||||
},
|
||||
"node-forge": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.2.1.tgz",
|
||||
"integrity": "sha512-Fcvtbb+zBcZXbTTVwqGA5W+MKBj56UjVRevvchv5XrcyXbmNdesfZL37nlcWOfpgHhgmxApw3tQbTr4CqNmX4w=="
|
||||
},
|
||||
"node-libs-browser": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz",
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
"axios": "^0.24.0",
|
||||
"next": "12.1.0",
|
||||
"node-fetch": "^3.2.0",
|
||||
"node-forge": "^1.2.1",
|
||||
"rambda": "^7.0.2",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
@ -22,13 +23,13 @@
|
||||
"devDependencies": {
|
||||
"@types/node": "17.0.8",
|
||||
"@types/react": "17.0.38",
|
||||
"@types/xml-crypto": "^1.4.2",
|
||||
"@types/xml2js": "0.4.9",
|
||||
"autoprefixer": "10.4.2",
|
||||
"eslint": "8.6.0",
|
||||
"eslint-config-next": "12.0.7",
|
||||
"postcss": "8.4.6",
|
||||
"tailwindcss": "3.0.23",
|
||||
"typescript": "4.5.4",
|
||||
"@types/xml-crypto": "^1.4.2"
|
||||
"typescript": "4.5.4"
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ import { User } from '../types';
|
||||
import xmlbuilder from 'xmlbuilder';
|
||||
import crypto from 'crypto';
|
||||
import { SignedXml, FileKeyInfo } from 'xml-crypto';
|
||||
import { pki, util, asn1 } from 'node-forge';
|
||||
|
||||
const createResponseXML = async (params: {
|
||||
idpIdentityId: string,
|
||||
@ -66,15 +67,15 @@ const createResponseXML = async (params: {
|
||||
'@Destination': acsUrl,
|
||||
'@InResponseTo': inResponseTo,
|
||||
'@IssueInstant': authTimestamp,
|
||||
'saml:Issuer': {
|
||||
'@xmlns:saml': 'urn:oasis:names:tc:SAML:2.0:assertion',
|
||||
'#text': idpIdentityId,
|
||||
},
|
||||
'samlp:Status': {
|
||||
'samlp:StatusCode': {
|
||||
'@Value': 'urn:oasis:names:tc:SAML:2.0:status:Success'
|
||||
}
|
||||
},
|
||||
'saml:Issuer': {
|
||||
'@xmlns:saml': 'urn:oasis:names:tc:SAML:2.0:assertion',
|
||||
'#text': idpIdentityId,
|
||||
},
|
||||
'saml:Assertion': {
|
||||
'@xmlns:saml': 'urn:oasis:names:tc:SAML:2.0:assertion',
|
||||
'@Version': '2.0',
|
||||
@ -141,15 +142,42 @@ const createResponseForm = (relayState: string, encodedSamlResponse: string, acs
|
||||
return formElements.join('');
|
||||
};
|
||||
|
||||
function getPublicKeyPemFromCertificate(x509Certificate: string) {
|
||||
const certDerBytes = util.decode64(x509Certificate);
|
||||
const obj = asn1.fromDer(certDerBytes);
|
||||
const cert = pki.certificateFromAsn1(obj);
|
||||
return pki.publicKeyToPem(cert.publicKey);
|
||||
}
|
||||
|
||||
const stripCertHeaderAndFooter = (cert: string): string => {
|
||||
cert = cert.replace(/-+BEGIN CERTIFICATE-+\r?\n?/, '');
|
||||
cert = cert.replace(/-+END CERTIFICATE-+\r?\n?/, '');
|
||||
cert = cert.replace(/\r\n/g, '\n');
|
||||
return cert;
|
||||
};
|
||||
|
||||
function GetKeyInfo(x509Certificate: string, signatureConfig: any = {}) {
|
||||
x509Certificate = stripCertHeaderAndFooter(x509Certificate);
|
||||
|
||||
this.getKeyInfo = () => {
|
||||
const prefix = signatureConfig.prefix ? `${signatureConfig.prefix}:` : '';
|
||||
return `<${prefix}X509Data><${prefix}X509Certificate>${x509Certificate}</${prefix}X509Certificate></${prefix}X509Data>`;
|
||||
};
|
||||
|
||||
this.getKey = () => {
|
||||
return getPublicKeyPemFromCertificate(x509Certificate).toString();
|
||||
};
|
||||
}
|
||||
|
||||
const signResponseXML = async (xml: string, signingKey: any, publicKey: any): Promise<string> => {
|
||||
const sig = new SignedXml();
|
||||
const responseXPath = '/*[local-name(.)="Response" and namespace-uri(.)="urn:oasis:names:tc:SAML:2.0:protocol"]';
|
||||
const issuerXPath = '/*[local-name(.)="Issuer" and namespace-uri(.)="urn:oasis:names:tc:SAML:2.0:assertion"]';
|
||||
|
||||
console.log({publicKey, signingKey})
|
||||
|
||||
sig.signatureAlgorithm = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256';
|
||||
sig.keyInfoProvider = new FileKeyInfo(publicKey);
|
||||
|
||||
// @ts-ignore
|
||||
sig.keyInfoProvider = new GetKeyInfo(publicKey, {});
|
||||
sig.signingKey = signingKey;
|
||||
|
||||
sig.addReference(responseXPath, ['http://www.w3.org/2000/09/xmldsig#enveloped-signature', 'http://www.w3.org/2001/10/xml-exc-c14n#'], 'http://www.w3.org/2001/04/xmlenc#sha256');
|
||||
|
||||
Loading…
Reference in New Issue
Block a user