diff --git a/data/idp-private.key b/data/idp-private.key index 74f2978..9062024 100644 --- a/data/idp-private.key +++ b/data/idp-private.key @@ -12,4 +12,4 @@ A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQENBQADgYEABIL+uv5KbnqLnvbeyglcuDSf MVlPqMlvvliPLZa2TGluutL3t+jFfJNi6Vavd4BNyVsCYRe/ab8+/nok1Lu/IqKF vifu1QGHsF1vKyafmVC8cMX/lxsvjedsOs++59yOAHAgXn+0IuBwupinKF4Tuqd7 n5gl9V4czyfFtrJUCQc= ------END CERTIFICATE----- \ No newline at end of file +-----END CERTIFICATE----- diff --git a/data/idp-public.key b/data/idp-public.key index 74f2978..9062024 100644 --- a/data/idp-public.key +++ b/data/idp-public.key @@ -12,4 +12,4 @@ A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQENBQADgYEABIL+uv5KbnqLnvbeyglcuDSf MVlPqMlvvliPLZa2TGluutL3t+jFfJNi6Vavd4BNyVsCYRe/ab8+/nok1Lu/IqKF vifu1QGHsF1vKyafmVC8cMX/lxsvjedsOs++59yOAHAgXn+0IuBwupinKF4Tuqd7 n5gl9V4czyfFtrJUCQc= ------END CERTIFICATE----- \ No newline at end of file +-----END CERTIFICATE----- diff --git a/package.json b/package.json index bed0a4f..6ac6f65 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,6 @@ "lint": "next lint" }, "dependencies": { - "@types/xml-crypto": "^1.4.2", "axios": "^0.24.0", "next": "12.1.0", "node-fetch": "^3.2.0", @@ -29,6 +28,7 @@ "eslint-config-next": "12.0.7", "postcss": "8.4.6", "tailwindcss": "3.0.23", - "typescript": "4.5.4" + "typescript": "4.5.4", + "@types/xml-crypto": "^1.4.2" } } diff --git a/pages/api/saml/sso.ts b/pages/api/saml/sso.ts index 4d151a4..e51f7a0 100644 --- a/pages/api/saml/sso.ts +++ b/pages/api/saml/sso.ts @@ -1,5 +1,5 @@ import type { NextApiRequest, NextApiResponse } from 'next'; -import { createResponseForm, createSAMLResponseXML } from 'utils'; +import { createResponseForm, createResponseXML } from 'utils'; import { User } from 'types'; import config from '../../../lib/env' import { signResponseXML } from 'utils/response'; @@ -32,7 +32,7 @@ export default async function handler( lastName: 'K', }; - const xml = await createSAMLResponseXML({ + const xml = await createResponseXML({ idpIdentityId: idpIdentityId, audience: audience, acsUrl: acsUrl, diff --git a/utils/certificate.ts b/utils/certificate.ts index ea9565a..4563d61 100644 --- a/utils/certificate.ts +++ b/utils/certificate.ts @@ -1,23 +1,24 @@ import { promises as fs } from 'fs'; import path from 'path'; -const fetchPublicKey = async () => { - return await fs.readFile(path.join('data', 'idp-public.key'), 'utf8'); +const fetchPublicKey = async (): Promise => { + return await fs.readFile(path.join('data', 'idp-public.key'), 'ascii'); }; -const fetchPrivateKey = async () => { - return await fs.readFile(path.join('data', 'idp-private.key'), 'utf8'); +const fetchPrivateKey = async (): Promise => { + return await fs.readFile(path.join('data', 'idp-private.key'), 'ascii'); } -const extractCert = (certificate: string) => { - return certificate - .replace('-----BEGIN CERTIFICATE-----', '') - .replace('-----END CERTIFICATE-----', '') - .trim(); +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; }; export { fetchPublicKey, fetchPrivateKey, - extractCert, + stripCertHeaderAndFooter, } \ No newline at end of file diff --git a/utils/index.ts b/utils/index.ts index ffbf4df..ada9ea8 100644 --- a/utils/index.ts +++ b/utils/index.ts @@ -1,3 +1,3 @@ -export { fetchPrivateKey, fetchPublicKey } from './certificate' -export {extractSAMLRequestAttributes, createIdPMetadataXML} from './request' -export { createSAMLResponseXML, createResponseForm, signResponseXML } from './response' \ No newline at end of file +export * from './certificate' +export * from './request' +export * from './response' \ No newline at end of file diff --git a/utils/response.ts b/utils/response.ts index 25f68c1..cc4cd5d 100644 --- a/utils/response.ts +++ b/utils/response.ts @@ -1,9 +1,10 @@ import { User } from '../types'; import xmlbuilder from 'xmlbuilder'; -import crypto from 'crypto'; -import {SignedXml, FileKeyInfo} from 'xml-crypto'; +import crypto, { sign } from 'crypto'; +import { SignedXml, FileKeyInfo } from 'xml-crypto'; +import { fetchPrivateKey, fetchPublicKey, stripCertHeaderAndFooter } from './certificate'; -const createSAMLResponseXML = async (params: { +const createResponseXML = async (params: { idpIdentityId: string, audience: string, acsUrl: string, @@ -142,24 +143,30 @@ const createResponseForm = (relayState: string, encodedSamlResponse: string, acs }; const signResponseXML = async (xml: string, signingKey: any, publicKey: any): Promise => { - return ''; + 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"]'; - // const sig = new SignedXml(); + publicKey = publicKey.replace(/\\n/gm, '\n'); + signingKey = signingKey.replace(/\\n/gm, '\n'); - // sig.signatureAlgorithm = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'; - // sig.keyInfoProvider = new PubKeyInfo(publicKey); + console.log({publicKey, signingKey}) - // sig.signingKey = signingKey; - // sig.addReference(authnXPath, ['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'); - // sig.computeSignature(xml, { - // location: { reference: authnXPath + issuerXPath, action: 'after' }, - // }); + sig.signatureAlgorithm = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'; + sig.keyInfoProvider = new FileKeyInfo(stripCertHeaderAndFooter(publicKey)); + sig.signingKey = signingKey; - // return sig.getSignedXml(); + 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'); + + sig.computeSignature(xml, { + location: { reference: responseXPath + issuerXPath, action: 'after' }, + }); + + return sig.getSignedXml(); } export { - createSAMLResponseXML, + createResponseXML, createResponseForm, signResponseXML } \ No newline at end of file