Fix the api endpoints
This commit is contained in:
parent
6466c3a59f
commit
dc9b150304
4
.env.example
Normal file
4
.env.example
Normal file
@ -0,0 +1,4 @@
|
||||
NODE_ENV=dev
|
||||
DATABASE_URL=
|
||||
APP_URL=http://localhost:4000
|
||||
ENTITY_ID=http://saml.example.com
|
||||
6
lib/env.ts
Normal file
6
lib/env.ts
Normal file
@ -0,0 +1,6 @@
|
||||
const config = {
|
||||
appUrl: process.env.APP_URL || 'http://localhost:4000',
|
||||
entityId: process.env.ENTITY_ID || 'http://saml.example.com',
|
||||
}
|
||||
|
||||
export default config;
|
||||
145
package-lock.json
generated
145
package-lock.json
generated
@ -9,6 +9,7 @@
|
||||
"@prisma/client": "^3.7.0",
|
||||
"axios": "^0.24.0",
|
||||
"next": "12.0.7",
|
||||
"node-fetch": "^3.2.0",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"rsuite": "^5.5.2",
|
||||
@ -3247,6 +3248,28 @@
|
||||
"reusify": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/fetch-blob": {
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.1.4.tgz",
|
||||
"integrity": "sha512-Eq5Xv5+VlSrYWEqKrusxY1C3Hm/hjeAsCGVG3ft7pZahlUAChpGZT/Ms1WmSLnEAisEXszjzu/s+ce6HZB2VHA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/jimmywarting"
|
||||
},
|
||||
{
|
||||
"type": "paypal",
|
||||
"url": "https://paypal.me/jimmywarting"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"node-domexception": "^1.0.0",
|
||||
"web-streams-polyfill": "^3.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.20 || >= 14.13"
|
||||
}
|
||||
},
|
||||
"node_modules/file-entry-cache": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
|
||||
@ -3341,6 +3364,17 @@
|
||||
"resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz",
|
||||
"integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k="
|
||||
},
|
||||
"node_modules/formdata-polyfill": {
|
||||
"version": "4.0.10",
|
||||
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
|
||||
"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
|
||||
"dependencies": {
|
||||
"fetch-blob": "^3.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fraction.js": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.2.tgz",
|
||||
@ -4430,6 +4464,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/next/node_modules/node-fetch": {
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
|
||||
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==",
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/next/node_modules/postcss": {
|
||||
"version": "8.2.15",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.15.tgz",
|
||||
@ -4455,12 +4497,47 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
|
||||
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==",
|
||||
"node_modules/node-domexception": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
|
||||
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/jimmywarting"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://paypal.me/jimmywarting"
|
||||
}
|
||||
],
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
"node": ">=10.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.0.tgz",
|
||||
"integrity": "sha512-8xeimMwMItMw8hRrOl3C9/xzU49HV/yE6ORew/l+dxWimO5A4Ra8ld2rerlJvc/O7et5Z1zrWsPX43v1QBjCxw==",
|
||||
"dependencies": {
|
||||
"data-uri-to-buffer": "^4.0.0",
|
||||
"fetch-blob": "^3.1.4",
|
||||
"formdata-polyfill": "^4.0.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/node-fetch"
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch/node_modules/data-uri-to-buffer": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz",
|
||||
"integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==",
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"node_modules/node-html-parser": {
|
||||
@ -6086,6 +6163,14 @@
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/web-streams-polyfill": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.0.tgz",
|
||||
"integrity": "sha512-EqPmREeOzttaLRm5HS7io98goBgZ7IVz79aDvqjD0kYXLtFZTc0T/U6wHTPKyIjb+MdN7DFIIX6hgdBEpWmfPA==",
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
|
||||
@ -8655,6 +8740,15 @@
|
||||
"reusify": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"fetch-blob": {
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.1.4.tgz",
|
||||
"integrity": "sha512-Eq5Xv5+VlSrYWEqKrusxY1C3Hm/hjeAsCGVG3ft7pZahlUAChpGZT/Ms1WmSLnEAisEXszjzu/s+ce6HZB2VHA==",
|
||||
"requires": {
|
||||
"node-domexception": "^1.0.0",
|
||||
"web-streams-polyfill": "^3.0.3"
|
||||
}
|
||||
},
|
||||
"file-entry-cache": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
|
||||
@ -8717,6 +8811,14 @@
|
||||
"resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz",
|
||||
"integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k="
|
||||
},
|
||||
"formdata-polyfill": {
|
||||
"version": "4.0.10",
|
||||
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
|
||||
"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
|
||||
"requires": {
|
||||
"fetch-blob": "^3.1.2"
|
||||
}
|
||||
},
|
||||
"fraction.js": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.2.tgz",
|
||||
@ -9502,6 +9604,11 @@
|
||||
"watchpack": "2.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"node-fetch": {
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
|
||||
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
|
||||
},
|
||||
"postcss": {
|
||||
"version": "8.2.15",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.15.tgz",
|
||||
@ -9519,10 +9626,27 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node-domexception": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
|
||||
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
|
||||
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.0.tgz",
|
||||
"integrity": "sha512-8xeimMwMItMw8hRrOl3C9/xzU49HV/yE6ORew/l+dxWimO5A4Ra8ld2rerlJvc/O7et5Z1zrWsPX43v1QBjCxw==",
|
||||
"requires": {
|
||||
"data-uri-to-buffer": "^4.0.0",
|
||||
"fetch-blob": "^3.1.4",
|
||||
"formdata-polyfill": "^4.0.10"
|
||||
},
|
||||
"dependencies": {
|
||||
"data-uri-to-buffer": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz",
|
||||
"integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"node-html-parser": {
|
||||
"version": "1.4.9",
|
||||
@ -10721,6 +10845,11 @@
|
||||
"graceful-fs": "^4.1.2"
|
||||
}
|
||||
},
|
||||
"web-streams-polyfill": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.0.tgz",
|
||||
"integrity": "sha512-EqPmREeOzttaLRm5HS7io98goBgZ7IVz79aDvqjD0kYXLtFZTc0T/U6wHTPKyIjb+MdN7DFIIX6hgdBEpWmfPA=="
|
||||
},
|
||||
"webidl-conversions": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
"@prisma/client": "^3.7.0",
|
||||
"axios": "^0.24.0",
|
||||
"next": "12.0.7",
|
||||
"node-fetch": "^3.2.0",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"rsuite": "^5.5.2",
|
||||
|
||||
@ -1,60 +0,0 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { createCertificate, createIdPMetadataXML } from '../../../utils';
|
||||
import { IdPMetadata } from '../../../types';
|
||||
|
||||
const idpEntityId = 'http://saml.example.com';
|
||||
const baseUrl = 'http://localhost:4000'; // TODO: Read from .env
|
||||
|
||||
// https://boxyhqdemo.onelogin.com/trust/saml2/http-post/sso/a810f17d-48a8-4ac2-ae0f-253c823b272c
|
||||
// https://dev-8924093.okta.com/app/dev-8924093_jacksondemo_1/exk3u9pl6jx4P9AE15d7/sso/saml
|
||||
// https://accounts.google.com/o/saml2/idp?idpid=C02frd9s1
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse<IdPMetadata>
|
||||
) {
|
||||
|
||||
switch (req.method) {
|
||||
case 'GET':
|
||||
return await getMetadata();
|
||||
case 'POST':
|
||||
return await downloadMetadata();
|
||||
default:
|
||||
return res.status(405).end(`Method ${req.method} Not Allowed`);
|
||||
}
|
||||
|
||||
// Get metadata for an app
|
||||
async function getMetadata() {
|
||||
//const {id} = req.query;
|
||||
const appId = '0480c44e-f200-4f72-8af0-a5a57611fd2d';
|
||||
|
||||
const metadata = {
|
||||
certificate: await createCertificate(),
|
||||
fingerprint: '',
|
||||
sso_url: `${baseUrl}/saml2/app/${appId}`,
|
||||
entity_id: idpEntityId,
|
||||
}
|
||||
|
||||
return res.json(metadata);
|
||||
}
|
||||
|
||||
// Download metadata for an app
|
||||
async function downloadMetadata() {
|
||||
const appId = '0480c44e-f200-4f72-8af0-a5a57611fd2d';
|
||||
|
||||
const certificate = await createCertificate();
|
||||
const idpEntityId = 'http://localhost:4000/sso';
|
||||
const idpSsoUrl = 'http://localhost:4000/sso';
|
||||
|
||||
const xml = await createIdPMetadataXML({
|
||||
idpEntityId,
|
||||
idpSsoUrl,
|
||||
certificate,
|
||||
});
|
||||
|
||||
res.setHeader('Content-type', 'text/xml');
|
||||
res.setHeader('Content-Disposition', 'attachment; filename="metadata.xml"');
|
||||
|
||||
return res.send(xml);
|
||||
}
|
||||
}
|
||||
37
pages/api/apps/metadata/download.ts
Normal file
37
pages/api/apps/metadata/download.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { createCertificate, createIdPMetadataXML } from '../../../../utils';
|
||||
import { IdPMetadata } from '../../../../types';
|
||||
import stream from 'stream';
|
||||
import { promisify } from 'util';
|
||||
import config from '../../../../lib/env'
|
||||
|
||||
const pipeline = promisify(stream.pipeline);
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse<IdPMetadata | string>
|
||||
) {
|
||||
|
||||
switch (req.method) {
|
||||
case 'GET':
|
||||
return await downloadMetadata();
|
||||
default:
|
||||
return res.status(405).end(`Method ${req.method} Not Allowed`);
|
||||
}
|
||||
|
||||
// Download metadata for an app
|
||||
async function downloadMetadata() {
|
||||
const appId = '0480c44e-f200-4f72-8af0-a5a57611fd2d';
|
||||
|
||||
const xml = await createIdPMetadataXML({
|
||||
idpEntityId: config.entityId,
|
||||
idpSsoUrl: `${config.appUrl}/saml2/app/${appId}`,
|
||||
certificate: await createCertificate(),
|
||||
});
|
||||
|
||||
res.setHeader('Content-type', 'text/xml');
|
||||
res.setHeader('Content-Disposition', 'attachment; filename=metadata.xml');
|
||||
|
||||
await pipeline(xml, res);
|
||||
}
|
||||
}
|
||||
32
pages/api/apps/metadata/index.ts
Normal file
32
pages/api/apps/metadata/index.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { createCertificate } from '../../../../utils';
|
||||
import { IdPMetadata } from '../../../../types';
|
||||
import config from '../../../../lib/env'
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse<IdPMetadata | string>
|
||||
) {
|
||||
|
||||
switch (req.method) {
|
||||
case 'GET':
|
||||
return await getMetadata();
|
||||
default:
|
||||
return res.status(405).end(`Method ${req.method} Not Allowed`);
|
||||
}
|
||||
|
||||
// Get metadata for an app
|
||||
async function getMetadata() {
|
||||
//const {id} = req.query;
|
||||
const appId = '0480c44e-f200-4f72-8af0-a5a57611fd2d';
|
||||
|
||||
const metadata = {
|
||||
certificate: await createCertificate(),
|
||||
fingerprint: '',
|
||||
sso_url: `${config.appUrl}/saml2/app/${appId}`,
|
||||
entity_id: config.entityId,
|
||||
}
|
||||
|
||||
return res.json(metadata);
|
||||
}
|
||||
}
|
||||
@ -1,10 +1,11 @@
|
||||
import prisma from '../../lib/prisma';
|
||||
import { GetServerSideProps } from 'next';
|
||||
import React from 'react';
|
||||
import { App } from '../../types';
|
||||
import axios from 'axios';
|
||||
import { IdPMetadata } from '../../types';
|
||||
import React, { ChangeEvent, FormEvent, useState } from 'react';
|
||||
|
||||
// TODO: Remove this
|
||||
export const getServerSideProps: GetServerSideProps = async ({ params }) => {
|
||||
const app = await prisma.app.findUnique({
|
||||
where: {
|
||||
@ -34,6 +35,8 @@ const ShowApp: React.FC<{app: App, metadata: IdPMetadata}> = ({app, metadata}) =
|
||||
<p>sso_url: {metadata.sso_url}</p>
|
||||
<p>entity_id: {metadata.entity_id}</p>
|
||||
<p>certificate: {metadata.certificate}</p>
|
||||
|
||||
<a href="/api/apps/metadata/download" className="px-3 py-2 text-white bg-red-500 rounded">Download Metadata</a>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
import type { NextPage } from 'next';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { Sidenav, Nav, Dropdown } from 'rsuite';
|
||||
|
||||
const Demo: NextPage = (prop) => {
|
||||
return (
|
||||
<div>
|
||||
<h2>Hello from demo</h2>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Demo;
|
||||
@ -32,14 +32,6 @@ const Apps: NextPage = () => {
|
||||
setMetadata(data);
|
||||
};
|
||||
|
||||
const downloadMetadata = async (e: ChangeEvent<HTMLInputElement>) => {
|
||||
e.preventDefault();
|
||||
|
||||
const {data} = await axios.post('/api/apps/metadata', {
|
||||
...formData
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<form onSubmit={createApp} className="px-8 pt-6 pb-8 mb-4 bg-white rounded shadow-md">
|
||||
@ -64,16 +56,8 @@ const Apps: NextPage = () => {
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<button type="submit" className="px-4 py-2 text-white bg-blue-500 rounded">Build IdP Metadata</button>
|
||||
<button type="submit" className="px-4 py-2 text-white bg-blue-500 rounded">Create App</button>
|
||||
</form>
|
||||
|
||||
<button type="button" className="px-3 py-2 text-white bg-red-500 rounded" onClick={downloadMetadata}>Download Metadata</button>
|
||||
|
||||
<ul className="px-8 pt-6 pb-8 mb-4 bg-white rounded shadow-md">
|
||||
<li className="px-2 py-2"><strong>SSO URL:</strong> <br></br> {metadata.sso_url}</li>
|
||||
<li className="px-2 py-2"><strong>Entity ID:</strong> <br></br> {metadata.entity_id}</li>
|
||||
<li className="px-2 py-2"><strong>Certificate:</strong> <br></br> {metadata.certificate}</li>
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user