This commit is contained in:
Kiran 2022-02-17 21:43:25 +05:30
parent 14b0b29386
commit c3c09856bc
10 changed files with 8160 additions and 113 deletions

View File

@ -1,7 +1,5 @@
# Mock SAML from BoxyHQ # Mock SAML from BoxyHQ
http://localhost:4000/apps/saml?RelayState&SAMLRequest=
- Parse the SAML Request - Parse the SAML Request
- Create the SAML Response - Create the SAML Response
- Fix the certificate - Fix the certificate

View File

@ -1,4 +1,14 @@
/** @type {import('next').NextConfig} */ /** @type {import('next').NextConfig} */
module.exports = { module.exports = {
reactStrictMode: true, reactStrictMode: true,
webpack: (config, { isServer }) => {
if (!isServer) {
config.resolve.fallback = {
fs: false,
zlib: false,
}
}
return config;
}
} }

8140
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -12,9 +12,11 @@
"axios": "^0.24.0", "axios": "^0.24.0",
"next": "12.0.10", "next": "12.0.10",
"node-fetch": "^3.2.0", "node-fetch": "^3.2.0",
"rambda": "^7.0.2",
"react": "17.0.2", "react": "17.0.2",
"react-dom": "17.0.2", "react-dom": "17.0.2",
"rsuite": "^5.5.2", "rsuite": "^5.5.2",
"webpack-filter-warnings-plugin": "^1.2.1",
"xml2js": "^0.4.23", "xml2js": "^0.4.23",
"xmlbuilder": "^15.1.1" "xmlbuilder": "^15.1.1"
}, },

View File

@ -1,5 +1,5 @@
import type { NextApiRequest, NextApiResponse } from 'next'; import type { NextApiRequest, NextApiResponse } from 'next';
import { createCertificate, createIdPMetadataXML } from '../../../../utils'; import { createCertificate, createIdPMetadataXML, createIdPSSOUrl } from '../../../../utils';
import { IdPMetadata } from '../../../../types'; import { IdPMetadata } from '../../../../types';
import stream from 'stream'; import stream from 'stream';
import { promisify } from 'util'; import { promisify } from 'util';
@ -25,7 +25,7 @@ export default async function handler(
const xml = await createIdPMetadataXML({ const xml = await createIdPMetadataXML({
idpEntityId: config.entityId, idpEntityId: config.entityId,
idpSsoUrl: `${config.appUrl}/saml2/app/${appId}`, idpSsoUrl: createIdPSSOUrl(appId),
certificate: await createCertificate(), certificate: await createCertificate(),
}); });

View File

@ -1,5 +1,5 @@
import type { NextApiRequest, NextApiResponse } from 'next'; import type { NextApiRequest, NextApiResponse } from 'next';
import { createCertificate } from '../../../../utils'; import { createCertificate, createIdPSSOUrl } from '../../../../utils';
import { IdPMetadata } from '../../../../types'; import { IdPMetadata } from '../../../../types';
import config from '../../../../lib/env' import config from '../../../../lib/env'
@ -23,7 +23,7 @@ export default async function handler(
const metadata = { const metadata = {
certificate: await createCertificate(), certificate: await createCertificate(),
fingerprint: '', fingerprint: '',
sso_url: `${config.appUrl}/saml2/app/${appId}`, sso_url: createIdPSSOUrl(appId),
entity_id: config.entityId, entity_id: config.entityId,
} }

View File

@ -1,42 +0,0 @@
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

@ -0,0 +1,38 @@
import type { GetServerSideProps } from 'next';
import React from "react";
import { AuthNRequest } from '../../../types'
import {extractSAMLRequestAttributes} from '../../../utils'
export const getServerSideProps: GetServerSideProps = async ({query, params}) => {
const relayState = query.RelayState as string;
const samlRequest = query.SAMLRequest as string;
const attributes = await extractSAMLRequestAttributes(samlRequest);
console.log(attributes)
return {
props: {
relayState,
samlRequest,
},
}
}
const ProcessRequest: React.FC<AuthNRequest> = ({relayState, samlRequest}) => {
return (
<div>Process Request</div>
);
}
export default ProcessRequest;
// Start a session
// Store the RelayState in the session
// Parse the SAMLRequest
// Validate the SAMLRequest
// Create SAMLResponse
// POST the SAMLResponse to ACS URL
// Remove the RelayState from the session

View File

@ -27,8 +27,8 @@ export type SAMLRequest = {
}; };
export type AuthNRequest = { export type AuthNRequest = {
RelayState: string; relayState: string;
SAMLRequest: SAMLRequest; samlRequest: string;
}; };
export type User = { export type User = {

View File

@ -3,6 +3,8 @@ import { promises as fs } from 'fs';
import path from 'path'; import path from 'path';
import xml2js from 'xml2js'; import xml2js from 'xml2js';
import { User } from '../types'; import { User } from '../types';
import config from '../lib/env';
import * as rambda from 'rambda';
// Parse XML // Parse XML
const parseXML = (xml: string): Promise<Record<string, any>> => { const parseXML = (xml: string): Promise<Record<string, any>> => {
@ -13,17 +15,17 @@ const parseXML = (xml: string): Promise<Record<string, any>> => {
}); });
}; };
// Extract SAML Request Attributes // Parse SAMLRequest attributes
const extractSAMLRequestAttributes = async (SAMLRequest: string | string[]) => { const extractSAMLRequestAttributes = async (samlRequest: string) => {
// @ts-ignore // @ts-ignore
const result = await parseXML(Buffer.from(SAMLRequest, 'base64').toString()); const result = await parseXML(Buffer.from(samlRequest, 'base64').toString());
const attributes = result['samlp:AuthnRequest']['$']; const attributes = result['samlp:AuthnRequest']['$'];
return { return {
ID: attributes['ID'], id: attributes['ID'],
IssueInstant: attributes['IssueInstant'], issueInstant: attributes['IssueInstant'],
AssertionConsumerServiceURL: attributes['AssertionConsumerServiceURL'], acsUrl: attributes['AssertionConsumerServiceURL'],
ProviderName: attributes['ProviderName'], providerName: attributes['ProviderName'],
}; };
}; };
@ -74,6 +76,10 @@ const createSAMLResponseXML = async (user: User): Promise<string> => {
.replace('user_lastName', 'K'); .replace('user_lastName', 'K');
}; };
const createIdPSSOUrl = (appId: string) => {
return `${config.appUrl}/saml2/apps/${appId}`;
}
export { export {
parseXML, parseXML,
extractSAMLRequestAttributes, extractSAMLRequestAttributes,
@ -81,4 +87,5 @@ export {
createSAMLResponseXML, createSAMLResponseXML,
createCertificate, createCertificate,
extractCert, extractCert,
}; createIdPSSOUrl,
};