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