UNPKG

@pagopa/io-spid-commons

Version:

Common code for integrating SPID authentication

182 lines 7.25 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ExtraParams = exports.SpidUser = void 0; const fs = require("fs"); const responses_1 = require("@pagopa/ts-commons/lib/responses"); const strings_1 = require("@pagopa/ts-commons/lib/strings"); const bodyParser = require("body-parser"); const express = require("express"); const function_1 = require("fp-ts/lib/function"); const T = require("fp-ts/lib/Task"); const t = require("io-ts"); const passport = require("passport"); const redis = require("redis"); const TE = require("fp-ts/lib/TaskEither"); const E = require("fp-ts/Either"); const Either_1 = require("fp-ts/lib/Either"); const logger_1 = require("./utils/logger"); const middleware_1 = require("./utils/middleware"); const _1 = require("."); exports.SpidUser = t.intersection([ t.interface({ // the following values may be set // by the calling application: // authnContextClassRef -> SpidLevel, // issuer -> Issuer getAssertionXml: t.Function, }), t.partial({ email: strings_1.EmailString, familyName: t.string, fiscalNumber: strings_1.FiscalCode, mobilePhone: strings_1.NonEmptyString, name: t.string, nameID: t.string, nameIDFormat: t.string, sessionIndex: t.string, }), ]); exports.ExtraParams = t.type({ test: t.number }); const appConfig = { assertionConsumerServicePath: "/acs", clientErrorRedirectionUrl: "/error", clientLoginRedirectionUrl: "/success", extraLoginRequestParamConfig: { codec: exports.ExtraParams, requestMapper: (_req) => E.of({ test: 1 }), }, loginPath: "/login", metadataPath: "/metadata", sloPath: "/logout", spidLevelsWhitelist: ["SpidL2", "SpidL3"], }; const serviceProviderConfig = { IDPMetadataUrl: "https://registry.spid.gov.it/metadata/idp/spid-entities-idps.xml", organization: { URL: "https://example.com", displayName: "Organization display name", name: "Organization name", }, publicCert: fs.readFileSync("./certs/cert.pem", "utf-8"), requiredAttributes: { attributes: [ "address", "email", "name", "familyName", "fiscalNumber", "mobilePhone", ], name: "Required attrs", }, spidCieTestUrl: "https://collaudo.idserver.servizicie.interno.gov.it/idp/shibboleth", spidCieUrl: "https://preproduzione.idserver.servizicie.interno.gov.it/idp/shibboleth?Metadata", spidTestEnvUrl: "https://spid-testenv2:8088", // this line is commented due to a future refactor that enables spid-saml-check locally // spidValidatorUrl: "http://localhost:8080", strictResponseValidation: { // eslint-disable-next-line @typescript-eslint/naming-convention "http://localhost:8080": true, // eslint-disable-next-line @typescript-eslint/naming-convention "https://spid-testenv2:8088": true, }, // eslint-disable-next-line sort-keys contacts: [ { company: "Sogetto Aggregatore s.r.l", contactType: middleware_1.ContactType.OTHER, email: "email@example.com", entityType: middleware_1.EntityType.AGGREGATOR, extensions: { FiscalCode: "12345678901", IPACode: "1", VATNumber: "12345678902", aggregatorType: middleware_1.AggregatorType.PublicServicesFullOperator, }, phone: "+393331234567", }, ], }; const redisClient = redis.createClient({ url: "redis://redis", }); const samlConfig = { RACComparison: "minimum", acceptedClockSkewMs: 0, attributeConsumingServiceIndex: "0", authnContext: "https://www.spid.gov.it/SpidL1", callbackUrl: "http://localhost:3000" + appConfig.assertionConsumerServicePath, // decryptionPvk: fs.readFileSync("./certs/key.pem", "utf-8"), identifierFormat: "urn:oasis:names:tc:SAML:2.0:nameid-format:transient", issuer: "https://spid.agid.gov.it/cd", logoutCallbackUrl: "http://localhost:3000/slo", privateCert: fs.readFileSync("./certs/key.pem", "utf-8"), validateInResponseTo: true, }; const acs = (payload, extraParams) => __awaiter(void 0, void 0, void 0, function* () { logger_1.logger.info("acs:%s%s", JSON.stringify(payload), JSON.stringify(extraParams)); return (0, responses_1.ResponsePermanentRedirect)({ href: "/success?acs" }); }); const logout = () => __awaiter(void 0, void 0, void 0, function* () { return (0, responses_1.ResponsePermanentRedirect)({ href: "/success?logout" }); }); const app = express(); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); app.use(passport.initialize()); // Create a Proxy to forward local calls to spid validator container const proxyApp = express(); proxyApp.get("*", (req, res) => { res.redirect(`http://spid-saml-check:8080${req.path}`); }); proxyApp.listen(8080); // eslint-disable-next-line @typescript-eslint/explicit-function-return-type const doneCb = (ip, request, response, extraParams) => { // eslint-disable-next-line no-console console.log("*************** done", ip); // eslint-disable-next-line no-console console.log(request); // eslint-disable-next-line no-console console.log(response); // eslint-disable-next-line no-console console.log(extraParams === null || extraParams === void 0 ? void 0 : extraParams.test); }; (0, function_1.pipe)(TE.tryCatch(() => redisClient.connect(), Either_1.toError), TE.fold(() => T.of(void 0), (_) => T.of(_)), T.chain(() => (0, _1.withSpid)({ acs, app, appConfig, doneCb, logout, redisClient, samlConfig, serviceProviderConfig, })), T.map(({ app: withSpidApp, idpMetadataRefresher }) => { withSpidApp.get("/success", (_, res) => res.json({ success: "success", })); withSpidApp.get("/error", (_, res) => res .json({ error: "error", }) .status(400)); withSpidApp.get("/refresh", (_, res) => __awaiter(void 0, void 0, void 0, function* () { yield idpMetadataRefresher()(); res.json({ metadataUpdate: "completed", }); })); withSpidApp.use((error, _, res, ___) => res.status(505).send({ error: error.message, })); withSpidApp.listen(3000); }))() // eslint-disable-next-line no-console .catch((e) => console.error("Application error: ", e)); //# sourceMappingURL=example.js.map