UNPKG

passport-cas-ts

Version:

CAS strategy for passport.js authentication

124 lines 4.66 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.CasStrategy = void 0; const axios_1 = __importDefault(require("axios")); const xml2js_1 = __importDefault(require("xml2js")); const passport_1 = __importDefault(require("passport")); const XML_PARSE_OPTIONS = { trim: true, normalize: true, explicitArray: false, tagNameProcessors: [ xml2js_1.default.processors.normalize, xml2js_1.default.processors.stripPrefix, ], }; class CasStrategy extends passport_1.default.Strategy { name = "cas"; verify; config; errorLogger; debugLogger; constructor(verify, options, errorLogger, debugLogger) { super(); this.verify = verify; this.config = { ...options }; this.errorLogger = errorLogger; this.debugLogger = debugLogger; } logError = (msg, err) => { if (this.errorLogger) { this.errorLogger(msg, err); } }; logDebug = (msg) => { if (this.debugLogger) { this.debugLogger(msg); } }; async authenticate(req) { if (req.query.RelayState) { this.logDebug("RelayState present, logging out"); return this.logout(req); } const service = this.getReqService(req); this.logDebug(`Extracted service: ${service}`); const ticket = req.query.ticket; if (!ticket) { this.logDebug("No ticket provided, starting login process"); const redirectURL = new URL(this.config.loginRoute, this.config.base); redirectURL.searchParams.set("service", service); return this.redirect(redirectURL.toString()); } this.logDebug(`Got ticket ${ticket}, starting validation process`); const target = new URL(this.config.validateRoute, this.config.base); target.searchParams.set("ticket", ticket); target.searchParams.set("service", service); const res = await axios_1.default.get(target.toString()); if (res.status == 200) { this.logDebug(`Got info: ${res.data}`); this.validate(res.data); } else { const err = res.statusText; this.logError("Failed to validate ticket", err); return this.fail(new Error(err)); } } logout(req) { req.logout((err) => { if (err) { this.logError("Failed to log request out", err); } }); const redirectURL = new URL(this.config.logoutRoute, this.config.base); redirectURL.searchParams.set("_eventId", "next"); redirectURL.searchParams.set("RelayState", req.query.RelayState); return this.redirect(redirectURL.toString()); } getReqService(req) { const url = new URL(req.originalUrl, this.config.serverUrl); url.searchParams.delete("ticket"); return url.toString(); } validate(body) { const done = this.onceVerified.bind(this); xml2js_1.default.parseString(body, XML_PARSE_OPTIONS, (err, result) => { if (err || !result) { return done(new Error("Bad response from server"), null); } if (result.serviceresponse?.authenticationfailure) { return done(new Error("Authentication failed " + result.serviceresponse.authenticationfailure.$?.code), null); } const success = result.serviceresponse?.authenticationsuccess; if (success) { this.logDebug("CAS validate: ticket ok, calling user verify function"); this.logDebug("Got profile: " + JSON.stringify(success)); return this.verify(success, done); } else { return done(new Error("Authentication failed"), null); } }); } onceVerified = function (err, profile, info, challenge) { if (err) { this.logError("CAS verified callback error", err); return this.fail(challenge); } if (!profile) { this.logDebug("CAS verified callback error: invalid profile"); this.logDebug(JSON.stringify(profile)); return this.fail(challenge); } this.logDebug("CAS verified callback success"); this.logDebug(JSON.stringify(profile)); this.success(profile, info); }; } exports.CasStrategy = CasStrategy; //# sourceMappingURL=index.js.map