This commit is contained in:
Kiran 2022-01-15 01:25:28 +05:30
parent 505416e828
commit 141a920a50
9 changed files with 235 additions and 80 deletions

View File

@ -7,4 +7,4 @@
- Fix the SAML metadata URL - Fix the SAML metadata URL
- Improve the UI - Improve the UI
http://localhost:4000/api/apps/saml?RelayState=boxyhq_jackson_2fd72712996df6104811ff8cc233d1e2&SAMLRequest=PD94bWwgdmVyc2lvbj0iMS4wIj8%2BPHNhbWxwOkF1dGhuUmVxdWVzdCB4bWxuczpzYW1scD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnByb3RvY29sIiBJRD0iXzZiMmU1ZDdhMDRiNjEzMzAyZDhmIiBWZXJzaW9uPSIyLjAiIElzc3VlSW5zdGFudD0iMjAyMi0wMS0xNFQxNToxODoxNi4yNTlaIiBQcm90b2NvbEJpbmRpbmc9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpiaW5kaW5nczpIVFRQLVBPU1QiIEFzc2VydGlvbkNvbnN1bWVyU2VydmljZVVSTD0iaHR0cHM6Ly8yOGEyLTEwMy0xNTMtMTA0LTQzLm5ncm9rLmlvL3Nzby9hY3MiIFByb3ZpZGVyTmFtZT0iQm94eUhRIj48c2FtbDpJc3N1ZXIgeG1sbnM6c2FtbD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFzc2VydGlvbiI%2BaHR0cHM6Ly9zYW1sLmJveHlocS5jb208L3NhbWw6SXNzdWVyPjxTaWduYXR1cmUgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPjxTaWduZWRJbmZvPjxDYW5vbmljYWxpemF0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8%2BPFNpZ25hdHVyZU1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZHNpZy1tb3JlI3JzYS1zaGEyNTYiLz48UmVmZXJlbmNlIFVSST0iI182YjJlNWQ3YTA0YjYxMzMwMmQ4ZiI%2BPFRyYW5zZm9ybXM%2BPFRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNlbnZlbG9wZWQtc2lnbmF0dXJlIi8%2BPFRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIvPjwvVHJhbnNmb3Jtcz48RGlnZXN0TWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxlbmMjc2hhMjU2Ii8%2BPERpZ2VzdFZhbHVlPlBXVFlGek9hV1FvZHNqK21haEdnam1VQkZsVFk5cGlQNy8yVVkvNEZkN289PC9EaWdlc3RWYWx1ZT48L1JlZmVyZW5jZT48L1NpZ25lZEluZm8%2BPFNpZ25hdHVyZVZhbHVlPm5HbEMrZVkwMC82eDZQNlBMcGFoOVR5QzlRTnNKR0U3V0Y1czQ1SXZRbWlJWmwrSmhNVGRQeExBSjJ1dVpQMWZzZ1NwUllPZG5HanRLNjlobS9LOHZDVGlab29EODdjdkJmdXp4NVVNQ3NiV0VQSERJV01rV1k3S2ZrYk5ySjNMdVZyYTR0SEZvY2luQnVwRzNMeVQ5dUtwRzI1NlQrNm9LUDNOdkJSTzRROUFpWlk4czlxaVhzRE9QQlJRd3NEaEdNdGRJcGVDaGZQU2RQdFV1RXV3UEdRS1pZellFY0d3WHpOTGYydm5PaS9QUE5rRHA4QTdPN2FJd09HWFNDVVlqL29oNUo4RWRQdVpyRzFuL0ZMdm04L0dNY2pNTTYwQWZ1NFg3WGMzRlFRUG5aZ2lxdFlsd2YwbjFDemlkbnYvbDE3NjF6T3grWXJqb08zaUp0SHB6Zz09PC9TaWduYXR1cmVWYWx1ZT48L1NpZ25hdHVyZT48c2FtbHA6TmFtZUlEUG9saWN5IHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIEZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4xOm5hbWVpZC1mb3JtYXQ6ZW1haWxBZGRyZXNzIiBBbGxvd0NyZWF0ZT0idHJ1ZSIvPjwvc2FtbHA6QXV0aG5SZXF1ZXN0Pg%3D%3D http://localhost:4000/apps/saml?RelayState=boxyhq_jackson_2fd72712996df6104811ff8cc233d1e2&SAMLRequest=PD94bWwgdmVyc2lvbj0iMS4wIj8%2BPHNhbWxwOkF1dGhuUmVxdWVzdCB4bWxuczpzYW1scD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOnByb3RvY29sIiBJRD0iXzZiMmU1ZDdhMDRiNjEzMzAyZDhmIiBWZXJzaW9uPSIyLjAiIElzc3VlSW5zdGFudD0iMjAyMi0wMS0xNFQxNToxODoxNi4yNTlaIiBQcm90b2NvbEJpbmRpbmc9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpiaW5kaW5nczpIVFRQLVBPU1QiIEFzc2VydGlvbkNvbnN1bWVyU2VydmljZVVSTD0iaHR0cHM6Ly8yOGEyLTEwMy0xNTMtMTA0LTQzLm5ncm9rLmlvL3Nzby9hY3MiIFByb3ZpZGVyTmFtZT0iQm94eUhRIj48c2FtbDpJc3N1ZXIgeG1sbnM6c2FtbD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFzc2VydGlvbiI%2BaHR0cHM6Ly9zYW1sLmJveHlocS5jb208L3NhbWw6SXNzdWVyPjxTaWduYXR1cmUgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiPjxTaWduZWRJbmZvPjxDYW5vbmljYWxpemF0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8%2BPFNpZ25hdHVyZU1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZHNpZy1tb3JlI3JzYS1zaGEyNTYiLz48UmVmZXJlbmNlIFVSST0iI182YjJlNWQ3YTA0YjYxMzMwMmQ4ZiI%2BPFRyYW5zZm9ybXM%2BPFRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNlbnZlbG9wZWQtc2lnbmF0dXJlIi8%2BPFRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4Yy1jMTRuIyIvPjwvVHJhbnNmb3Jtcz48RGlnZXN0TWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxlbmMjc2hhMjU2Ii8%2BPERpZ2VzdFZhbHVlPlBXVFlGek9hV1FvZHNqK21haEdnam1VQkZsVFk5cGlQNy8yVVkvNEZkN289PC9EaWdlc3RWYWx1ZT48L1JlZmVyZW5jZT48L1NpZ25lZEluZm8%2BPFNpZ25hdHVyZVZhbHVlPm5HbEMrZVkwMC82eDZQNlBMcGFoOVR5QzlRTnNKR0U3V0Y1czQ1SXZRbWlJWmwrSmhNVGRQeExBSjJ1dVpQMWZzZ1NwUllPZG5HanRLNjlobS9LOHZDVGlab29EODdjdkJmdXp4NVVNQ3NiV0VQSERJV01rV1k3S2ZrYk5ySjNMdVZyYTR0SEZvY2luQnVwRzNMeVQ5dUtwRzI1NlQrNm9LUDNOdkJSTzRROUFpWlk4czlxaVhzRE9QQlJRd3NEaEdNdGRJcGVDaGZQU2RQdFV1RXV3UEdRS1pZellFY0d3WHpOTGYydm5PaS9QUE5rRHA4QTdPN2FJd09HWFNDVVlqL29oNUo4RWRQdVpyRzFuL0ZMdm04L0dNY2pNTTYwQWZ1NFg3WGMzRlFRUG5aZ2lxdFlsd2YwbjFDemlkbnYvbDE3NjF6T3grWXJqb08zaUp0SHB6Zz09PC9TaWduYXR1cmVWYWx1ZT48L1NpZ25hdHVyZT48c2FtbHA6TmFtZUlEUG9saWN5IHhtbG5zOnNhbWxwPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6cHJvdG9jb2wiIEZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6MS4xOm5hbWVpZC1mb3JtYXQ6ZW1haWxBZGRyZXNzIiBBbGxvd0NyZWF0ZT0idHJ1ZSIvPjwvc2FtbHA6QXV0aG5SZXF1ZXN0Pg%3D%3D

15
data/idp-metadata.xml Normal file
View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" entityID="idp_entity_id" validUntil="2026-06-22T18:39:53.000Z">
<md:IDPSSODescriptor WantAuthnRequestsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:KeyDescriptor use="signing">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>idp_certificate</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="idp_sso_url"/>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="idp_sso_url"/>
</md:IDPSSODescriptor>
</md:EntityDescriptor>

58
data/saml-response.xml Normal file
View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" Destination="https://28a2-103-153-104-43.ngrok.io/sso/acs" ID="_41a01ff26e2669a4ffe974cd57079b3c" InResponseTo="_f5da12eb6e20fd04b654" IssueInstant="2022-01-14T18:39:01.757Z" Version="2.0">
<saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">idp_entity_id</saml2:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<ds:Reference URI="#_41a01ff26e2669a4ffe974cd57079b3c">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>xPMc7SSHhFSWGljyk1L8mRE1M6otu0qlukR42E6QdiQ=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>VXlnv1pN3BsHvfbwkugYfsgcjoiXzsbm8OiWczkbNQcadaYTHgIOPf9mNLLJXq1vSfBVLyDY+1Xq</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509SubjectName>ST=California,C=US,OU=Google For Work,CN=Google,L=Mountain View,O=Google Inc.</ds:X509SubjectName>
<ds:X509Certificate>MIIDdDCCAlygAwIBAgIGAXo6K+u/MA0GCSqGSIb3DQEBCwUAMHsxFDASBgNVBAoTC0dvb2dsZSBJ</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<saml2p:Status>
<saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</saml2p:Status>
<saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" ID="_28c7bb0ebe6359c70c1b2a9b7b1f280a" IssueInstant="2022-01-14T18:39:01.757Z" Version="2.0">
<saml2:Issuer>idp_entity_id</saml2:Issuer>
<saml2:Subject>
<saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">user_email</saml2:NameID>
<saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml2:SubjectConfirmationData InResponseTo="_f5da12eb6e20fd04b654" NotOnOrAfter="2022-01-14T18:44:01.757Z" Recipient="sp_acs_url"/>
</saml2:SubjectConfirmation>
</saml2:Subject>
<saml2:Conditions NotBefore="2022-01-14T18:34:01.757Z" NotOnOrAfter="2022-01-14T18:44:01.757Z">
<saml2:AudienceRestriction>
<saml2:Audience>https://saml.boxyhq.com</saml2:Audience>
</saml2:AudienceRestriction>
</saml2:Conditions>
<saml2:AttributeStatement>
<saml2:Attribute Name="email">
<saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:anyType">user_email</saml2:AttributeValue>
</saml2:Attribute>
<saml2:Attribute Name="firstName">
<saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:anyType">user_firstName</saml2:AttributeValue>
</saml2:Attribute>
<saml2:Attribute Name="lastName">
<saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:anyType">user_lastName</saml2:AttributeValue>
</saml2:Attribute>
</saml2:AttributeStatement>
<saml2:AuthnStatement AuthnInstant="2022-01-14T15:01:16.000Z" SessionIndex="_28c7bb0ebe6359c70c1b2a9b7b1f280a">
<saml2:AuthnContext>
<saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml2:AuthnContextClassRef>
</saml2:AuthnContext>
</saml2:AuthnStatement>
</saml2:Assertion>
</saml2p:Response>

View File

@ -1,7 +1,5 @@
import { promises as fs } from 'fs';
import type { NextApiRequest, NextApiResponse } from 'next'; import type { NextApiRequest, NextApiResponse } from 'next';
import path from 'path'; import { createCertificate, createIdPMetadataXML } from '../../../utils';
import { metadata } from '../../../services';
export default async function handler( export default async function handler(
req: NextApiRequest, req: NextApiRequest,
@ -12,12 +10,17 @@ export default async function handler(
} }
async function download(req: NextApiRequest) { async function download(req: NextApiRequest) {
const { acs_url, entity_id } = req.body; const { acs_url, sp_entity_id } = req.body;
const certificateFilePath = path.join('data', 'x509cert.txt'); const certificate = await createCertificate();
const certificate = await fs.readFile(certificateFilePath, 'utf8'); const idpEntityId = 'http://localhost:4000/sso';
const idpSsoUrl = 'http://localhost:4000/sso';
const xml = await metadata.createXML(acs_url, entity_id, certificate); const xml = await createIdPMetadataXML({
idpEntityId,
idpSsoUrl,
certificate,
});
res.setHeader('Content-type', 'text/xml'); res.setHeader('Content-type', 'text/xml');
res.setHeader('Content-Disposition', 'attachment; filename="metadata.xml"'); res.setHeader('Content-Disposition', 'attachment; filename="metadata.xml"');

View File

@ -1,39 +1,33 @@
import type { NextApiRequest, NextApiResponse } from 'next'; import type { NextApiRequest, NextApiResponse } from 'next';
import xml2js from 'xml2js'; import { User } from '../../../types';
import {
const parseXML = (xml: string): Promise<Record<string, any>> => { createSAMLResponseXML,
return new Promise((resolve, reject) => { extractSAMLRequestAttributes,
xml2js.parseString(xml, (err: Error, result: any) => { } from '../../../utils';
resolve(result);
});
});
};
const extractSAMLRequestAttribute = async (SAMLRequest: string | string[]) => {
// @ts-ignore
const result = await parseXML(Buffer.from(SAMLRequest, 'base64').toString());
const sp = result['samlp:AuthnRequest']['$'];
return {
ID: sp['ID'],
IssueInstant: sp['IssueInstant'],
AssertionConsumerServiceURL: sp['AssertionConsumerServiceURL'],
ProviderName: sp['ProviderName'],
};
};
export default async function handler( export default async function handler(
req: NextApiRequest, req: NextApiRequest,
res: NextApiResponse<any> res: NextApiResponse<any>
) { ) {
if (req.method === 'GET') { if (req.method === 'POST') {
return await response(req); return await response(req);
} }
if (req.method === 'GET') {
const user: User = {
id: '1',
email: 'kiran@demo.com',
firstName: 'Kiran',
lastName: 'K',
};
return res.status(200).json(await createSAMLResponseXML(user));
}
async function response(req: NextApiRequest) { async function response(req: NextApiRequest) {
const { RelayState, SAMLRequest } = req.query; const { RelayState, SAMLRequest } = req.query;
const attributes = await extractSAMLRequestAttribute(SAMLRequest); const attributes = await extractSAMLRequestAttributes(SAMLRequest);
return res.status(200).json(attributes); return res.status(200).json(attributes);
} }

42
pages/apps/saml.tsx Normal file
View File

@ -0,0 +1,42 @@
import type { NextPage } from 'next';
import { useEffect, useRef, useState } from "react";
export async function getServerSideProps(context: any) {
const {RelayState, SAMLRequest} = context.query;
return {
props: {
RelayState: RelayState,
SAMLRequest: SAMLRequest
},
}
}
// const createSAMLResponse = ({RelayState, SAMLRequest}: Prop) => {
// const url = new URL('http://28a2-103-153-104-43.ngrok.io/sso/acs');
// url.searchParams.append('RelayState', RelayState);
// url.searchParams.append('SAMLResponse', 'SAMLResponse');
// return url.href;
// }
const SAML: NextPage = (prop) => {
const [] = useState();
const formRef = useRef(null);
useEffect(() => {
// @ts-ignore
formRef?.current?.submit();
}, []);
return (
<div>
<form action="http://28a2-103-153-104-43.ngrok.io/sso/acs" method="POST" ref={formRef}>
</form>
</div>
);
};
export default SAML;

View File

@ -1,4 +1,3 @@
import * as xmlbuilder from 'xmlbuilder';
import type { IdPMetadata } from '../types'; import type { IdPMetadata } from '../types';
const baseUrl = 'http://localhost:3000/saml'; const baseUrl = 'http://localhost:3000/saml';
@ -19,50 +18,3 @@ export const create = (
certificate: certificate, certificate: certificate,
}; };
}; };
const extractCert = (certificate: string) => {
return certificate
.replace('-----BEGIN CERTIFICATE-----', '')
.replace('-----END CERTIFICATE-----', '')
.trim();
};
export const createXML = async (
acs_url: string,
entity_id: string,
certificate: string
) => {
const metadata = create(acs_url, entity_id, certificate);
const data = {
'md:EntityDescriptor': {
'@xmlns:md': 'urn:oasis:names:tc:SAML:2.0:metadata',
'@entityID': `${metadata.entity_id}`,
'@validUntil': '2026-06-22T18:39:53.000Z',
'md:IDPSSODescriptor': {
'@WantAuthnRequestsSigned': 'false',
'@protocolSupportEnumeration': 'urn:oasis:names:tc:SAML:2.0:protocol',
'md:KeyDescriptor': {
'@use': 'signing',
'ds:KeyInfo': {
'@xmlns:ds': 'http://www.w3.org/2000/09/xmldsig#',
'ds:X509Data': {
'ds:X509Certificate': {
'#text': `${extractCert(certificate)}`,
},
},
},
},
'md:NameIDFormat': {
'#text': 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress',
},
'md:SingleSignOnService': {
'@Binding': 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect',
'@Location': `${metadata.sso_url}`,
},
},
},
};
return xmlbuilder.create(data).end({ pretty: true });
};

View File

@ -30,3 +30,10 @@ export type AuthNRequest = {
RelayState: string; RelayState: string;
SAMLRequest: SAMLRequest; SAMLRequest: SAMLRequest;
}; };
export type User = {
id: string;
email: string;
firstName: string;
lastName: string;
};

84
utils/index.ts Normal file
View File

@ -0,0 +1,84 @@
// @ts-ignore
import { promises as fs } from 'fs';
import path from 'path';
import xml2js from 'xml2js';
import { User } from '../types';
// Parse XML
const parseXML = (xml: string): Promise<Record<string, any>> => {
return new Promise((resolve, reject) => {
xml2js.parseString(xml, (err: Error, result: any) => {
resolve(result);
});
});
};
// Extract SAML Request Attributes
const extractSAMLRequestAttributes = async (SAMLRequest: string | string[]) => {
// @ts-ignore
const result = await parseXML(Buffer.from(SAMLRequest, 'base64').toString());
const attributes = result['samlp:AuthnRequest']['$'];
return {
ID: attributes['ID'],
IssueInstant: attributes['IssueInstant'],
AssertionConsumerServiceURL: attributes['AssertionConsumerServiceURL'],
ProviderName: attributes['ProviderName'],
};
};
const createIdPMetadataXML = async ({
idpEntityId,
idpSsoUrl,
certificate,
}: {
idpEntityId: string;
idpSsoUrl: string;
certificate: string;
}): Promise<string> => {
const xmlPath = path.join('data', 'idp-metadata.xml');
const xml = await fs.readFile(xmlPath, 'utf8');
return xml
.replace('idp_entity_id', idpEntityId)
.replace('idp_certificate', extractCert(certificate))
.replace(/idp_sso_url/g, idpSsoUrl);
};
const createCertificate = async () => {
const certificateFilePath = path.join('data', 'x509cert.txt');
return await fs.readFile(certificateFilePath, 'utf8');
};
const extractCert = (certificate: string) => {
return certificate
.replace('-----BEGIN CERTIFICATE-----', '')
.replace('-----END CERTIFICATE-----', '')
.trim();
};
// Create SAML Response XML
const createSAMLResponseXML = async (user: User): Promise<string> => {
const xmlPath = path.join('data', 'saml-response.xml');
const xml = await fs.readFile(xmlPath, 'utf8');
return xml
.replace(
/idp_entity_id/g,
'https://accounts.google.com/o/saml2?idpid=C02frd9s1'
)
.replace('sp_acs_url', 'some-url')
.replace(/user_email/g, 'kiran@demo.com')
.replace('user_firstName', 'Kiran')
.replace('user_lastName', 'K');
};
export {
parseXML,
extractSAMLRequestAttributes,
createIdPMetadataXML,
createSAMLResponseXML,
createCertificate,
extractCert,
};