@pagopa/io-spid-commons
Version:
Common code for integrating SPID authentication
182 lines • 7.25 kB
JavaScript
;
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