moved parsing of saml request to saml20 lib (#486)
This commit is contained in:
parent
4028487c13
commit
0ad3b3bfac
19
package-lock.json
generated
19
package-lock.json
generated
@ -9,20 +9,18 @@
|
||||
"version": "1.3.1",
|
||||
"license": "Apache 2.0",
|
||||
"dependencies": {
|
||||
"@boxyhq/saml20": "1.4.2",
|
||||
"@boxyhq/saml20": "1.4.5",
|
||||
"daisyui": "4.6.1",
|
||||
"next": "14.1.0",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-gtm-module": "2.0.11",
|
||||
"xml2js": "0.6.2",
|
||||
"xmlbuilder": "15.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "20.11.16",
|
||||
"@types/react": "18.2.51",
|
||||
"@types/react-gtm-module": "2.0.3",
|
||||
"@types/xml2js": "0.4.14",
|
||||
"@typescript-eslint/parser": "6.20.0",
|
||||
"autoprefixer": "10.4.17",
|
||||
"eslint": "8.56.0",
|
||||
@ -250,9 +248,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@boxyhq/saml20": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@boxyhq/saml20/-/saml20-1.4.2.tgz",
|
||||
"integrity": "sha512-eAYoPfAMOSawyw5YFHpe4wIg7vALDgza0c/D5jfGEfg7GoI8MOsa7bLCo8FR45kGDji2NSfM8HkCexr8pkqw6A==",
|
||||
"version": "1.4.5",
|
||||
"resolved": "https://registry.npmjs.org/@boxyhq/saml20/-/saml20-1.4.5.tgz",
|
||||
"integrity": "sha512-iI+pEmCzl3r0RrIZ6L6QwuCoCZAkkcYTLJZbHLwNxll5JuDEXwg/tZu4Df7j5rO08aggf1w6cpIf/Ng/6hhLLw==",
|
||||
"dependencies": {
|
||||
"@xmldom/xmldom": "0.8.10",
|
||||
"lodash": "4.17.21",
|
||||
@ -1050,15 +1048,6 @@
|
||||
"integrity": "sha512-s/FPdYRmZR8SjLWGMCuax7r3qCWQw9QKHzXVukAuuIJkXkDRwp+Pu5LMIVFi0Fxbav35WURicYr8u1QsoybnQw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/xml2js": {
|
||||
"version": "0.4.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.14.tgz",
|
||||
"integrity": "sha512-4YnrRemBShWRO2QjvUin8ESA41rH+9nQGLUGZV/1IDhi3SL9OhdpNC/MrulTWuptXKwhx/aDxE7toV0f/ypIXQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "6.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.20.0.tgz",
|
||||
|
||||
@ -12,20 +12,18 @@
|
||||
"release": "git checkout release && git merge origin/main && release-it && git checkout main && git merge origin/release && git push origin main"
|
||||
},
|
||||
"dependencies": {
|
||||
"@boxyhq/saml20": "1.4.2",
|
||||
"@boxyhq/saml20": "1.4.5",
|
||||
"daisyui": "4.6.1",
|
||||
"next": "14.1.0",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-gtm-module": "2.0.11",
|
||||
"xml2js": "0.6.2",
|
||||
"xmlbuilder": "15.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "20.11.16",
|
||||
"@types/react": "18.2.51",
|
||||
"@types/react-gtm-module": "2.0.3",
|
||||
"@types/xml2js": "0.4.14",
|
||||
"@typescript-eslint/parser": "6.20.0",
|
||||
"autoprefixer": "10.4.17",
|
||||
"eslint": "8.56.0",
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { decodeBase64, extractSAMLRequestAttributes } from 'utils';
|
||||
import saml from '@boxyhq/saml20';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse<string>) {
|
||||
@ -30,12 +29,9 @@ async function processSAMLRequest(req: NextApiRequest, res: NextApiResponse, isP
|
||||
}
|
||||
|
||||
try {
|
||||
const rawRequest = await decodeBase64(samlRequest, isDeflated);
|
||||
const rawRequest = await saml.decodeBase64(samlRequest, isDeflated);
|
||||
|
||||
const { id, audience, acsUrl, providerName, publicKey } = await extractSAMLRequestAttributes(
|
||||
rawRequest,
|
||||
isPost
|
||||
);
|
||||
const { id, audience, acsUrl, providerName, publicKey } = await saml.parseSAMLRequest(rawRequest, isPost);
|
||||
|
||||
if (isPost) {
|
||||
const { valid } = await saml.hasValidSignature(rawRequest, publicKey, null);
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
export * from './certificate';
|
||||
export * from './idp';
|
||||
export * from './request';
|
||||
export * from './response';
|
||||
|
||||
@ -1,58 +0,0 @@
|
||||
import { promisify } from 'util';
|
||||
import xml2js from 'xml2js';
|
||||
import { inflateRaw } from 'zlib';
|
||||
|
||||
const inflateRawAsync = promisify(inflateRaw);
|
||||
|
||||
// Parse XML
|
||||
const parseXML = (xml: string): Promise<Record<string, any>> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
xml2js.parseString(
|
||||
xml,
|
||||
{
|
||||
tagNameProcessors: [xml2js.processors.stripPrefix],
|
||||
strict: true,
|
||||
},
|
||||
(err: Error | null, result: any) => {
|
||||
if (err) {
|
||||
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();
|
||||
};
|
||||
|
||||
// Parse SAMLRequest attributes
|
||||
const extractSAMLRequestAttributes = async (rawRequest: string, isPost = true) => {
|
||||
const result = await parseXML(rawRequest);
|
||||
|
||||
const attributes = result['AuthnRequest']['$'];
|
||||
const issuer = result['AuthnRequest']['Issuer'];
|
||||
|
||||
const publicKey = result['AuthnRequest']['Signature']
|
||||
? result['AuthnRequest']['Signature'][0]['KeyInfo'][0]['X509Data'][0]['X509Certificate'][0]
|
||||
: null;
|
||||
|
||||
if (!publicKey && isPost) {
|
||||
throw new Error('Missing signature');
|
||||
}
|
||||
|
||||
return {
|
||||
id: attributes.ID,
|
||||
acsUrl: attributes.AssertionConsumerServiceURL,
|
||||
providerName: attributes.ProviderName,
|
||||
audience: issuer[0]['_'] ?? issuer[0],
|
||||
publicKey,
|
||||
};
|
||||
};
|
||||
|
||||
export { extractSAMLRequestAttributes, decodeBase64 };
|
||||
Loading…
Reference in New Issue
Block a user