From 0ad3b3bfacec3158a6017ab471bd0fbcf08dcc62 Mon Sep 17 00:00:00 2001 From: Deepak Prabhakara Date: Sun, 4 Feb 2024 13:35:59 +0000 Subject: [PATCH] moved parsing of saml request to saml20 lib (#486) --- package-lock.json | 19 +++----------- package.json | 4 +-- pages/api/saml/sso.ts | 8 ++---- utils/index.ts | 1 - utils/request.ts | 58 ------------------------------------------- 5 files changed, 7 insertions(+), 83 deletions(-) delete mode 100644 utils/request.ts diff --git a/package-lock.json b/package-lock.json index 60f4967..f97d70e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", diff --git a/package.json b/package.json index a2363f9..b9ec2cd 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/pages/api/saml/sso.ts b/pages/api/saml/sso.ts index 78a9b0f..e69dd0a 100644 --- a/pages/api/saml/sso.ts +++ b/pages/api/saml/sso.ts @@ -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) { @@ -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); diff --git a/utils/index.ts b/utils/index.ts index fa460b1..4805765 100644 --- a/utils/index.ts +++ b/utils/index.ts @@ -1,4 +1,3 @@ export * from './certificate'; export * from './idp'; -export * from './request'; export * from './response'; diff --git a/utils/request.ts b/utils/request.ts deleted file mode 100644 index f05c196..0000000 --- a/utils/request.ts +++ /dev/null @@ -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> => { - 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 };