UNPKG

@pagopa/io-spid-commons

Version:

Common code for integrating SPID authentication

59 lines 4.08 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getExtendedRedisCacheProvider = exports.noopCacheProvider = void 0; const dates_1 = require("@pagopa/ts-commons/lib/dates"); const reporters_1 = require("@pagopa/ts-commons/lib/reporters"); const E = require("fp-ts/lib/Either"); const function_1 = require("fp-ts/lib/function"); const O = require("fp-ts/lib/Option"); const TE = require("fp-ts/lib/TaskEither"); const t = require("io-ts"); const saml_1 = require("../utils/saml"); const SAMLRequestCacheItem = t.interface({ RequestXML: t.string, createdAt: dates_1.UTCISODateFromString, idpIssuer: t.string, }); // those methods must never fail since there's // practically no error handling in passport-saml // (a very bad lot of spaghetti code) const noopCacheProvider = () => ({ // invokes 'callback' and passes the value if found, null otherwise get: (_, callback) => { callback(null, {}); }, // removes the key from the cache, invokes `callback` with the // key removed, null if no key is removed remove: (key, callback) => { callback(null, key); }, // saves the key with the optional value // invokes the callback with the value saved save: (_, value, callback) => { const v = { createdAt: new Date(), value, }; callback(null, v); }, }); exports.noopCacheProvider = noopCacheProvider; const getExtendedRedisCacheProvider = (redisClient, extraLoginRequestParamsCodec, // 1 hour by default keyExpirationPeriodSeconds = 3600, keyPrefix = "SAML-EXT-") => ({ get: (AuthnRequestID) => (0, function_1.pipe)(TE.tryCatch(() => redisClient.get(`${keyPrefix}${AuthnRequestID}`), E.toError), TE.mapLeft((err) => new Error(`SAML#ExtendedRedisCacheProvider: get() error ${err}`)), // redis callbacks consider empty value as null instead of undefined, // hence the need for the following wrapper to convert nulls to undefined TE.chain(TE.fromPredicate((v) => v !== null, () => // If the value is missing a specific error is returned // This avoid to continue the execution with a Validation left from // SAMLRequestCacheItem decode. new Error("SAML#ExtendedRedisCacheProvider: get() value not found"))), TE.chain((value) => TE.fromEither((0, function_1.pipe)(E.parseJSON(value, E.toError), E.chain((_) => (0, function_1.pipe)(SAMLRequestCacheItem.decode(_), E.map((samlRequestCacheItem) => (Object.assign(Object.assign({}, samlRequestCacheItem), (0, function_1.pipe)(extraLoginRequestParamsCodec, E.fromNullable(undefined), E.chainW((codec) => codec.decode(_)), E.getOrElseW(() => ({})))))), E.mapLeft((__) => new Error(`SAML#ExtendedRedisCacheProvider: get() error ${(0, reporters_1.readableReport)(__)}`)))))))), remove: (AuthnRequestID) => (0, function_1.pipe)(TE.tryCatch(() => redisClient.del(`${keyPrefix}${AuthnRequestID}`), E.toError), TE.mapLeft((err) => new Error(`SAML#ExtendedRedisCacheProvider: remove() error ${err}`)), TE.map(() => AuthnRequestID)), save: (RequestXML, samlConfig, extraLoginRequestParams) => (0, function_1.pipe)(TE.fromEither(E.fromOption(() => new Error(`SAML#ExtendedRedisCacheProvider: missing AuthnRequest ID`))((0, saml_1.getIDFromRequest)(RequestXML))), TE.chain((AuthnRequestID) => (0, function_1.pipe)(TE.fromEither(E.fromOption(() => new Error("Missing idpIssuer inside configuration"))(O.fromNullable(samlConfig.idpIssuer))), TE.map((idpIssuer) => ({ AuthnRequestID, idpIssuer })))), TE.chain((_) => { const v = Object.assign(Object.assign({}, extraLoginRequestParams), { RequestXML, createdAt: new Date(), idpIssuer: _.idpIssuer }); return (0, function_1.pipe)(TE.tryCatch(() => redisClient.setEx(`${keyPrefix}${_.AuthnRequestID}`, keyExpirationPeriodSeconds, JSON.stringify(v)), E.toError), TE.mapLeft((err) => new Error(`SAML#ExtendedRedisCacheProvider: set() error ${err}`)), TE.map(() => v)); })), }); exports.getExtendedRedisCacheProvider = getExtendedRedisCacheProvider; //# sourceMappingURL=redis_cache_provider.js.map