Improve the mock-idp to include in respnse : InResponseTo
References #4
This commit is contained in:
parent
f17ae330d3
commit
f548a0b31e
1 changed files with 43 additions and 4 deletions
|
@ -7,6 +7,7 @@ const path = require('path');
|
|||
const bodyParser = require('body-parser');
|
||||
const zlib = require('zlib');
|
||||
const xml2js = require('xml2js');
|
||||
const xpath = require('xpath');
|
||||
|
||||
const app = express();
|
||||
const port = 3000;
|
||||
|
@ -34,12 +35,15 @@ app.get('/saml/sso', async (req, res) => {
|
|||
storedSamlRequest = samlRequest;
|
||||
storedRelayState = relayState;
|
||||
|
||||
const authnRequestId = await extractAuthnRequestId(storedSamlRequest);
|
||||
console.log('SAML2 AuthnRequestId:', authnRequestId);
|
||||
|
||||
// Show simple login form
|
||||
res.send(createLoginForm());
|
||||
});
|
||||
|
||||
// Step 2: Handle login form and send SAMLResponse
|
||||
app.post('/saml/login', (req, res) => {
|
||||
app.post('/saml/login', async (req, res) => {
|
||||
const { username, email, orgCode, securityGroup, roles } = req.body;
|
||||
if (!storedSamlRequest) {
|
||||
return res.status(400).send('No SAMLRequest stored');
|
||||
|
@ -60,7 +64,8 @@ app.post('/saml/login', (req, res) => {
|
|||
console.log('ServiceProvider URL :', serviceProviderUrl);
|
||||
console.log('ServiceProvider ACS :', acsUrl);
|
||||
|
||||
const samlResponse = createFakeSamlResponse(username, email, orgCode, securityGroup, roles, serviceProviderUrl, issuerUrl);
|
||||
const inResponseTo = await extractAuthnRequestId(storedSamlRequest);
|
||||
const samlResponse = createFakeSamlResponse(username, email, orgCode, securityGroup, roles, serviceProviderUrl, issuerUrl, inResponseTo);
|
||||
const relayState = storedRelayState;
|
||||
|
||||
res.send(`
|
||||
|
@ -75,7 +80,41 @@ app.post('/saml/login', (req, res) => {
|
|||
`);
|
||||
});
|
||||
|
||||
function createFakeSamlResponse(nameId, email, orgCode, securityGroupCode, roles, serviceProviderUrl, issuerUrl) {
|
||||
/**
|
||||
* Extracts the AuthnRequest ID from a base64-encoded SAMLRequest.
|
||||
* @param {string} samlRequest - Base64-encoded SAMLRequest parameter from the URL.
|
||||
* @returns {Promise<string|null>} - Promise resolving to the AuthnRequest ID, or null if not found.
|
||||
*/
|
||||
function extractAuthnRequestId(samlRequest) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const decoded = Buffer.from(samlRequest, 'base64');
|
||||
|
||||
zlib.inflateRaw(decoded, (err, inflated) => {
|
||||
if (err) return reject(new Error('Failed to inflate SAMLRequest: ' + err.message));
|
||||
|
||||
const xml = inflated.toString('utf8');
|
||||
const doc = new DOMParser().parseFromString(xml, 'text/xml');
|
||||
|
||||
// Define namespace mappings for XPath
|
||||
const select = xpath.useNamespaces({
|
||||
saml2p: 'urn:oasis:names:tc:SAML:2.0:protocol',
|
||||
});
|
||||
|
||||
const node = select('//saml2p:AuthnRequest', doc)[0];
|
||||
if (node) {
|
||||
resolve(node.getAttribute('ID'));
|
||||
} else {
|
||||
resolve(null);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createFakeSamlResponse(nameId, email, orgCode, securityGroupCode, roles, serviceProviderUrl, issuerUrl, inResponseTo) {
|
||||
const issuer = issuerUrl;
|
||||
// const audience = "https://localhost:8443/saml2/service-provider-metadata/mock-idp";
|
||||
const audience = serviceProviderUrl + "/saml2/service-provider-metadata/mock-idp";
|
||||
|
@ -152,7 +191,7 @@ function createFakeSamlResponse(nameId, email, orgCode, securityGroupCode, roles
|
|||
});
|
||||
|
||||
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 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}" InResponseTo="${inResponseTo}"><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');
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue