Initial Project Commit
This commit is contained in:
commit
a6dea9c888
2148 changed files with 173870 additions and 0 deletions
28
src/main/resources/mock-idp/certs/idp-private.key
Normal file
28
src/main/resources/mock-idp/certs/idp-private.key
Normal file
|
@ -0,0 +1,28 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDyxkb2UrPwNyh4
|
||||
LFdNhmvP/wNUNnymDfZbUsigT3Klsw1fM15V21g89C6pqFS2fP8R9bHDK5Q9xGdj
|
||||
1EpdmHZzrbuY3x4MadIThuUgTuRrdNl/TzeRAy/UeAHwWJhtc+XQomhwZp5sLOcm
|
||||
yEe8MifopyyVcVGn48wDXE+da2VxBsidE4fGyNYO+VnL/37n1FdVPR8FiLgWWYq2
|
||||
EbWT5Vg7N6JRaV5VIUPcpnHrITG64+Xo9wQYCx8PqmcEe0RHK/8J4SvsNkVqADSC
|
||||
kCg4wsg5AK7xbcXzPcxdwmnikLWT1HJy6MiPCqrmKW9rcv4rlxNq7etU5VeEMLr4
|
||||
QSe/wgmnAgMBAAECggEAQWB8vpuh4jfwWYBTWEixIteBHX34zjznUUt3RJhwfse7
|
||||
e54ZMtS5K9zz7fMrMONzSvJXlv/W0VVhJESIbDEBAQDRiobXEC+1B1YlwLAOGhPi
|
||||
+EIsbAwoJrbUitVI4vy5cBg0OMSht+7Vpp97leYJ0kCmpG3aN/SDvYnv1KwVqrxL
|
||||
JtODOyCuBlttIH6uo1e6aU6HKWTwRDp177RSLuYOjBmQi6Hxwa+w31zQ6Q8Scubb
|
||||
S0z61C3L8Azdrb8B4/LfoARIDhy/gVvq7W3gIRkUZCl9oFBehpV+TT1BFPVGiKdm
|
||||
3vasOeo7BEORglbj+IaCovBooIGsUkDA1aZFCVx/3QKBgQD3e+owizU9Jp1j+8vl
|
||||
FtzHmbjBrNFIy4wiiMN0L1cKQzzVig7vb1JIwbK+uDg9csulObsdtva1FU4wFJOk
|
||||
R8JULJ0y4DRY1piT2p2bQA16IvSLvMrUlZ5KT1TqimsWxmkiodlBm3UM+q7rivca
|
||||
hSftmmayuNcjHj9FWKBM/6J/vQKBgQD7IOBRv2OgHcibQ5LdGX8TQqw55XKAmiEq
|
||||
nQI4Jk1XsTwdsdd+aqo81gp6Fdk3NdXM2x+kMDsP6IziaXyubI4w8Kkj6YJTL59p
|
||||
V3PACdfqToEkTblKdYVE7yN6gsuOT4qi0aedSAsRmeQpb8GMHjalgc5pv4Y34W8+
|
||||
E4LY4nbjMwKBgQCcLZjW1aLdWlcM18QOaGUfmUTdBEB2ne1rhb9CvPVCxrfHUn6m
|
||||
XywgOgyhCwSC0sTtGgeZcvMxx6Y19WZOz/I0yIrTpmWigpp7BAVeCgf3QcPtw1CE
|
||||
436nCnVeJcf68W87qcO/AWnWrQRiJKpYFBvkeAHDW554zQfErW9L6C8WSQKBgAoF
|
||||
Ms4wO9Jsvc9sL9UAqnBjTan1vM7i14Xyw97nsFhaaxKoQPf7W5WX2M0sSAGK9V/6
|
||||
MlYD0qd82PpDyUTQchAD2kvjil61XMAATE8SVXo07bQ8IbOV4t5wSFMgGu0vwVFj
|
||||
2jNNZ5upL1Bz9B4aKoYKGulfSgS6ywyIDMWIq8O/AoGAC1Ax4BQyB4/Jp2+oWtKF
|
||||
tkTdYPR3kmZtrtwhhYVDC+zXl/zSRlmRLNaHUpRyND/JRm/ngsYFrM1ZiRuiLTR+
|
||||
aYbKwy1AJh0HU2heH/5AL+mDbOkvHPkxiKRA+b58mUclMpll5x2l7sZ2hBg/Qspw
|
||||
6NjlEMHxyqq9Viz4DNxbQ20=
|
||||
-----END PRIVATE KEY-----
|
19
src/main/resources/mock-idp/certs/idp-public.cert
Normal file
19
src/main/resources/mock-idp/certs/idp-public.cert
Normal file
|
@ -0,0 +1,19 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDCTCCAfGgAwIBAgIUJGNdh9cxePuEzWTUlEuSOkwfwyUwDQYJKoZIhvcNAQEL
|
||||
BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI1MDQyNDA5MjI1MFoXDTI2MDQy
|
||||
NDA5MjI1MFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF
|
||||
AAOCAQ8AMIIBCgKCAQEA8sZG9lKz8DcoeCxXTYZrz/8DVDZ8pg32W1LIoE9ypbMN
|
||||
XzNeVdtYPPQuqahUtnz/EfWxwyuUPcRnY9RKXZh2c627mN8eDGnSE4blIE7ka3TZ
|
||||
f083kQMv1HgB8FiYbXPl0KJocGaebCznJshHvDIn6KcslXFRp+PMA1xPnWtlcQbI
|
||||
nROHxsjWDvlZy/9+59RXVT0fBYi4FlmKthG1k+VYOzeiUWleVSFD3KZx6yExuuPl
|
||||
6PcEGAsfD6pnBHtERyv/CeEr7DZFagA0gpAoOMLIOQCu8W3F8z3MXcJp4pC1k9Ry
|
||||
cujIjwqq5ilva3L+K5cTau3rVOVXhDC6+EEnv8IJpwIDAQABo1MwUTAdBgNVHQ4E
|
||||
FgQURDfHxj6ACRLLPcVRTgvlwhJSnyAwHwYDVR0jBBgwFoAURDfHxj6ACRLLPcVR
|
||||
TgvlwhJSnyAwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEABioO
|
||||
OCok/9JigKTupTEnJLxgueSIqk0lWXa7E6zwHLJh+DUUSlS1kECL2+s+HlGz7oCj
|
||||
uiemCLMssTd0ZOn95GN5b4IbEl8r+12hVaREKDC7qlydkFnKKomvEVQJUbAKPgqv
|
||||
EhNmJsp9TPKQzCdwTz00g0mmZCtc4cJoXEiOR+TKf/AwxXbh8/++9big1hIAnpHC
|
||||
zQgfebBg+I+1FPuUsqC6+zp4DrAflpQ2q0/4SNGyaPumf2K3ZjxLd9MPi+acd/HI
|
||||
USLnLV8fq77N+WxIqo20Az16biPxKL5jCq+NDqy0nF/J7ITBhMMCoYhPVxUhfjZ5
|
||||
7XLrSTjTVq7Mi1c5IQ==
|
||||
-----END CERTIFICATE-----
|
3
src/main/resources/mock-idp/certs/openssl_command.txt
Normal file
3
src/main/resources/mock-idp/certs/openssl_command.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
To create the idp-private.key and idp-public.cert:
|
||||
|
||||
> openssl req -x509 -newkey rsa:2048 -keyout idp-private.key -out idp-public.cert -days 365 -nodes -subj "/CN=localhost"
|
315
src/main/resources/mock-idp/idp.js
Normal file
315
src/main/resources/mock-idp/idp.js
Normal file
|
@ -0,0 +1,315 @@
|
|||
const { SignedXml } = require('xml-crypto');
|
||||
const { DOMParser } = require('@xmldom/xmldom');
|
||||
const crypto = require('crypto');
|
||||
const express = require('express');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const bodyParser = require('body-parser');
|
||||
const zlib = require('zlib');
|
||||
const xml2js = require('xml2js');
|
||||
|
||||
const app = express();
|
||||
const port = 3000;
|
||||
|
||||
// Enable body parsing
|
||||
app.use(bodyParser.urlencoded({ extended: true }));
|
||||
|
||||
let storedSamlRequest = null;
|
||||
let storedRelayState = null;
|
||||
let storedQueryParameters = null;
|
||||
|
||||
// Step 1: Receive SAMLRequest and render login form
|
||||
app.get('/saml/sso', async (req, res) => {
|
||||
storedQueryParameters = req.query;
|
||||
console.log('Received query parameters:', req.query); // 👈 log all query parameters
|
||||
|
||||
const samlRequest = req.query.SAMLRequest;
|
||||
const relayState = req.query.RelayState || '';
|
||||
|
||||
if (!samlRequest) {
|
||||
return res.status(400).send('Missing SAMLRequest');
|
||||
}
|
||||
|
||||
// Store temporarily
|
||||
storedSamlRequest = samlRequest;
|
||||
storedRelayState = relayState;
|
||||
|
||||
// Show simple login form
|
||||
res.send(createLoginForm());
|
||||
});
|
||||
|
||||
// Step 2: Handle login form and send SAMLResponse
|
||||
app.post('/saml/login', (req, res) => {
|
||||
const { username, email, orgCode, securityGroup, roles } = req.body;
|
||||
if (!storedSamlRequest) {
|
||||
return res.status(400).send('No SAMLRequest stored');
|
||||
}
|
||||
|
||||
// Get the issuer URL (the IDP ID [the application.yml = resilient.security.saml2.relyingparty.registration.mock-idp.assertingparty.entity-id])
|
||||
const issuerUrlDefault = 'http://localhost:3000/saml/metadata';
|
||||
const issuerUrl = storedQueryParameters['issuerUrl'] ? storedQueryParameters['issuerUrl'] : issuerUrlDefault;
|
||||
|
||||
// Get the base url of ServiceProvider (the server APP)
|
||||
const serviceProviderUrlDefault = 'https://localhost:8443'; // Or 'http://localhost:8081'
|
||||
const serviceProviderUrl = storedQueryParameters['spUrl'] ? storedQueryParameters['spUrl'] : serviceProviderUrlDefault;
|
||||
|
||||
// Build ACS (Assertion Consumer Service) URL — this is the Spring Boot app’s endpoint where the SAML Response is posted back after authentication.
|
||||
const acsUrlPath = '/login/saml2/sso/mock-idp';
|
||||
const acsUrl = serviceProviderUrl + acsUrlPath;
|
||||
|
||||
console.log('ServiceProvider URL :', serviceProviderUrl);
|
||||
console.log('ServiceProvider ACS :', acsUrl);
|
||||
|
||||
const samlResponse = createFakeSamlResponse(username, email, orgCode, securityGroup, roles, serviceProviderUrl, issuerUrl);
|
||||
const relayState = storedRelayState;
|
||||
|
||||
res.send(`
|
||||
<html>
|
||||
<body onload="document.forms[0].submit()">
|
||||
<form method="POST" action="${acsUrl}">
|
||||
<input type="hidden" name="SAMLResponse" value="${samlResponse.replace(/"/g, '"')}" />
|
||||
<input type="hidden" name="RelayState" value="${relayState.replace(/"/g, '"')}" />
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
});
|
||||
|
||||
function createFakeSamlResponse(nameId, email, orgCode, securityGroupCode, roles, serviceProviderUrl, issuerUrl) {
|
||||
const issuer = issuerUrl;
|
||||
// const audience = "https://localhost:8443/saml2/service-provider-metadata/mock-idp";
|
||||
const audience = serviceProviderUrl + "/saml2/service-provider-metadata/mock-idp";
|
||||
const now = new Date().toISOString();
|
||||
const fiveMinutesLater = new Date(Date.now() + 5 * 60000).toISOString();
|
||||
const assertionId = `_assertion_${crypto.randomUUID()}`;
|
||||
const responseId = `_response_${crypto.randomUUID()}`;
|
||||
|
||||
// const recipient = "https://localhost:8443/login/saml2/sso/mock-idp";
|
||||
const recipient = serviceProviderUrl + "/login/saml2/sso/mock-idp";
|
||||
// const destination = "https://localhost:8443/login/saml2/sso/mock-idp";
|
||||
const destination = serviceProviderUrl + "/login/saml2/sso/mock-idp";
|
||||
|
||||
console.log('SAML Recipient :', recipient);
|
||||
console.log('SAML Destination :', destination);
|
||||
console.log('SAML Issuer :', issuer);
|
||||
|
||||
const assertion = `
|
||||
<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="${assertionId}" IssueInstant="${now}" Version="2.0">
|
||||
<saml:Issuer>${issuer}</saml:Issuer>
|
||||
<saml:Subject>
|
||||
<saml:NameID>${nameId}</saml:NameID>
|
||||
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
|
||||
<saml:SubjectConfirmationData NotOnOrAfter="${fiveMinutesLater}" Recipient="${recipient}" />
|
||||
</saml:SubjectConfirmation>
|
||||
</saml:Subject>
|
||||
<saml:Conditions NotBefore="${now}" NotOnOrAfter="${fiveMinutesLater}">
|
||||
<saml:AudienceRestriction>
|
||||
<saml:Audience>${audience}</saml:Audience>
|
||||
</saml:AudienceRestriction>
|
||||
</saml:Conditions>
|
||||
<saml:AuthnStatement AuthnInstant="${now}">
|
||||
<saml:AuthnContext>
|
||||
<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
|
||||
</saml:AuthnContext>
|
||||
</saml:AuthnStatement>
|
||||
<saml:AttributeStatement>
|
||||
<saml:Attribute Name="email">
|
||||
<saml:AttributeValue>${email}</saml:AttributeValue>
|
||||
</saml:Attribute>
|
||||
<saml:Attribute Name="organization_code">
|
||||
<saml:AttributeValue>${orgCode}</saml:AttributeValue>
|
||||
</saml:Attribute>
|
||||
<saml:Attribute Name="security_group">
|
||||
<saml:AttributeValue>${securityGroupCode}</saml:AttributeValue>
|
||||
</saml:Attribute>
|
||||
<saml:Attribute Name="roles">
|
||||
<saml:AttributeValue>${roles}</saml:AttributeValue>
|
||||
</saml:Attribute>
|
||||
</saml:AttributeStatement>
|
||||
</saml:Assertion>`;
|
||||
|
||||
const privateKey = fs.readFileSync(path.join(__dirname, 'certs', 'idp-private.key'), 'utf8');
|
||||
const certificate = fs.readFileSync(path.join(__dirname, 'certs', 'idp-public.cert'), 'utf8');
|
||||
const certBase64 = certificate
|
||||
.replace(/-----BEGIN CERTIFICATE-----/, '')
|
||||
.replace(/-----END CERTIFICATE-----/, '')
|
||||
.replace(/\r?\n|\r/g, '');
|
||||
|
||||
const doc = new DOMParser().parseFromString(assertion);
|
||||
const sig = new SignedXml();
|
||||
sig.prefix = 'ds';
|
||||
sig.addReference("//*[local-name(.)='Assertion']", [
|
||||
"http://www.w3.org/2000/09/xmldsig#enveloped-signature",
|
||||
"http://www.w3.org/2001/10/xml-exc-c14n#",
|
||||
], "http://www.w3.org/2000/09/xmldsig#sha1");
|
||||
sig.signingKey = privateKey;
|
||||
sig.keyInfoProvider = {
|
||||
getKeyInfo: () => `<ds:X509Data><ds:X509Certificate>${certBase64}</ds:X509Certificate></ds:X509Data>`
|
||||
};
|
||||
sig.computeSignature(assertion, {
|
||||
prefix: 'ds',
|
||||
location: { reference: "//*[local-name(.)='Issuer']", action: 'after' }
|
||||
});
|
||||
|
||||
const signedAssertion = sig.getSignedXml();
|
||||
const samlResponse = `<?xml version="1.0" encoding="UTF-8"?><samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="${responseId}" Version="2.0" IssueInstant="${now}" Destination="${destination}"><saml:Issuer>${issuer}</saml:Issuer><samlp:Status><samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/></samlp:Status>${signedAssertion}</samlp:Response>`;
|
||||
|
||||
const samlResponseToUse = samlResponse.trim().replace(/^\uFEFF/, '');
|
||||
return Buffer.from(samlResponseToUse, 'utf-8').toString('base64');
|
||||
}
|
||||
|
||||
function createLoginFormOLD() {
|
||||
const form = `
|
||||
<html>
|
||||
<body>
|
||||
<h2>Mock Login</h2>
|
||||
<form method="POST" action="/saml/login">
|
||||
Username: <input name="username" value="test-user"/><br/>
|
||||
Email: <input name="email" value="test@example.com"/><br/>
|
||||
Org Code: <input name="orgCode" value="NOVA"/><br/>
|
||||
Security Group: <input name="securityGroup" value="GRP_USER"/><br/>
|
||||
Roles: <select name="roles" multiple size="4">
|
||||
<option value="ROLE_USER">ROLE_USER</option>
|
||||
<option value="ROLE_COORDINATOR">ROLE_COORDINATOR</option>
|
||||
<option value="ROLE_MANAGER">ROLE_MANAGER</option>
|
||||
<option value="ROLE_ADMIN">ROLE_ADMIN</option>
|
||||
</select><br/><br/>
|
||||
<button type="submit">Login</button>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
return form;
|
||||
}
|
||||
|
||||
function createLoginForm() {
|
||||
const form = `
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #f4f4f4;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
}
|
||||
.form-container {
|
||||
background: #fff;
|
||||
padding: 30px 40px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 10px rgba(0,0,0,0.1);
|
||||
width: 400px;
|
||||
}
|
||||
h2 {
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
label {
|
||||
display: block;
|
||||
margin: 10px 0 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
input[type="text"],
|
||||
input[type="email"],
|
||||
select {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
box-sizing: border-box;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
button {
|
||||
margin-top: 20px;
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="form-container">
|
||||
<h2>Mock Login</h2>
|
||||
<form method="POST" action="/saml/login">
|
||||
<label for="username">Username</label>
|
||||
<input id="username" name="username" value="test-user" type="text"/>
|
||||
|
||||
<label for="email">Email</label>
|
||||
<input id="email" name="email" value="test@example.com" type="email"/>
|
||||
|
||||
<label for="orgCode">Org Code</label>
|
||||
<input id="orgCode" name="orgCode" value="NOVA" type="text"/>
|
||||
|
||||
<label for="securityGroup">Security Group</label>
|
||||
<input id="securityGroup" name="securityGroup" value="GRP_USER" type="text"/>
|
||||
|
||||
<label for="roles">Roles</label>
|
||||
<select id="roles" name="roles" multiple size="4">
|
||||
<option value="ROLE_USER">ROLE_USER</option>
|
||||
<option value="ROLE_COORDINATOR">ROLE_COORDINATOR</option>
|
||||
<option value="ROLE_MANAGER">ROLE_MANAGER</option>
|
||||
<option value="ROLE_ADMIN">ROLE_ADMIN</option>
|
||||
</select>
|
||||
|
||||
<button type="submit">Login</button>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
|
||||
|
||||
return form;
|
||||
}
|
||||
|
||||
// Function to extract Issuer from SAMLRequest (returns a Promise)
|
||||
function extractIssuerFromSAMLRequest(samlRequestBase64) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const samlRequestBuffer = Buffer.from(samlRequestBase64, 'base64');
|
||||
|
||||
zlib.inflateRaw(samlRequestBuffer, (err, decoded) => {
|
||||
if (err) {
|
||||
return reject(new Error('Failed to inflate SAMLRequest'));
|
||||
}
|
||||
|
||||
const xml = decoded.toString('utf8');
|
||||
|
||||
xml2js.parseString(xml, { tagNameProcessors: [xml2js.processors.stripPrefix] }, (parseErr, result) => {
|
||||
if (parseErr) {
|
||||
return reject(new Error('Failed to parse SAMLRequest XML'));
|
||||
}
|
||||
|
||||
// Debugging: log the entire parsed result to see structure
|
||||
// console.log("Parsed XML result:", result);
|
||||
|
||||
// Extract Issuer from the first element of the array
|
||||
const issuerObject = result?.AuthnRequest?.Issuer?.[0]; // Issuer is an array, so we access the first element
|
||||
if (!issuerObject) {
|
||||
return reject(new Error('Issuer not found in SAMLRequest'));
|
||||
}
|
||||
|
||||
// Access the text content of the Issuer object (it may be in the '#text' property)
|
||||
const issuer = issuerObject._ || issuerObject['#text']; // Extract the actual string value
|
||||
|
||||
if (!issuer) {
|
||||
return reject(new Error('Issuer value is missing in the SAMLRequest'));
|
||||
}
|
||||
|
||||
resolve(issuer); // Return the issuer as a string
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Mock IDP running at http://localhost:${port}`);
|
||||
});
|
1026
src/main/resources/mock-idp/package-lock.json
generated
Normal file
1026
src/main/resources/mock-idp/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
20
src/main/resources/mock-idp/package.json
Normal file
20
src/main/resources/mock-idp/package.json
Normal file
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"name": "mock-idp2",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"body-parser": "^2.2.0",
|
||||
"express": "^5.1.0",
|
||||
"express-session": "^1.18.1",
|
||||
"saml2-js": "^4.0.3",
|
||||
"xml2js": "^0.6.2",
|
||||
"zlib": "^1.0.5"
|
||||
}
|
||||
}
|
14
src/main/resources/mock-idp/readme
Normal file
14
src/main/resources/mock-idp/readme
Normal file
|
@ -0,0 +1,14 @@
|
|||
/* ***************************************************** */
|
||||
/* To run : > node idp.js */
|
||||
/* > Mock IDP running at http://localhost:3000 */
|
||||
/* Starts an IDP server, allowing SAMLv2 auth testing */
|
||||
/* ***************************************************** */
|
||||
|
||||
mock-idp\certs
|
||||
Generated selfsigned cert for testing
|
||||
* idp-private.key - Used for signing the SAML XML Response
|
||||
* idp-public.cert - Included in the SAML XML Response
|
||||
* openssl_command.txt - A file containing the command used to generate this certificate files
|
||||
|
||||
idp.js
|
||||
The mock idp developed in JS
|
Loading…
Add table
Add a link
Reference in a new issue