ya-express-ntlm
Version:
108 lines • 5.85 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.authNTLM = void 0;
const af_color_1 = require("af-color");
const buffer_1 = require("buffer");
const handle_authenticate_1 = require("./handle-authenticate");
const handle_negotiate_1 = require("./handle-negotiate");
const debug_1 = require("./debug");
const ntlm_parser_1 = require("../ntlm-parser");
const prepare_options_1 = require("../prepare-options");
const constants_1 = require("./lib/constants");
const utils_1 = require("./lib/utils");
/**
* Returns data from the Authorization header: NTLM <data>
* If they can be parsed, then req.ntlm is filled
*/
const getNtlmAuthorizationData = (req) => {
const [title, data] = req.headers?.authorization?.split(' ') || [];
if (title === 'NTLM' && data) {
return data;
}
};
/**
* Fills req.ntlm with data from the Authorization header: NTLM <data>
* If they can be parsed.
*/
const fillReqNtlm = (req, data) => {
const parsedData = (0, ntlm_parser_1.ntlmParse)(data, { compact: true });
(0, debug_1.debugNtlmAuthFlow)(`Decoded Authorization header: ${debug_1.hvInColor}${JSON.stringify(parsedData, undefined, 2)}`);
['domain', 'username', 'workstation'].forEach((p) => {
if (parsedData[p]) {
req.ntlm[p] = parsedData[p];
}
});
return parsedData;
};
const authNTLM = (authNtlmOptions) => {
const options = (0, prepare_options_1.prepareOptions)(authNtlmOptions);
return async (req, res, next) => {
const rsn = { req, res, next, options };
let userData = options.getCachedUserData(rsn);
const uri = `${req.protocol}://${req.get('host')}${req.originalUrl}`;
const requestedURI = `${constants_1.arrowR} ${req.method}: ${req.protocol}://${req.get('host')}${req.originalUrl}`;
const authorizationHeader = req.headers.authorization;
const uriA = `${requestedURI} : ${authorizationHeader ? `${debug_1.hnColor}Authorization: ${debug_1.hvInColor}${authorizationHeader || ''}` : `${debug_1.hnColor}No Authorization header`}`;
req.ntlm = req.ntlm || { uri };
const mTitle = `============ Start NTLM Authorization. Strategy: '${options.getStrategy(rsn)}' ==================`;
// req.ntlm.isAuthenticated must be filled in earlier when determining the presence of a session cookie
if (userData.isAuthenticated) {
if (!authorizationHeader || (authorizationHeader && req.method !== 'POST')) {
const { username, domain } = (0, utils_1.transferExistingProps)({ ...userData, uri }, req.ntlm);
(0, debug_1.debugNtlmAuthFlow)(`${requestedURI}\nConnection already authenticated / user: ${username} / domain: ${domain}`);
return next();
}
(0, debug_1.debugNtlmAuthFlow)(`The connection is authenticated, but the "Authorization" header sent using the POST method was detected`);
}
(0, debug_1.debugNtlmAuthFlow)(uriA);
if (!authorizationHeader) {
(0, debug_1.debugNtlmAuthFlow)(mTitle);
(0, debug_1.debugNtlmAuthFlow)(`${constants_1.Larrow} Return ${af_color_1.blue}401${af_color_1.reset}: ${debug_1.hnColor}WWW-Authenticate${af_color_1.blue}: ${debug_1.hvOutColor}NTLM`);
return res
.setHeader('Content-Type', 'text/plain; charset=utf-8')
.setHeader('WWW-Authenticate', 'NTLM')
.setHeader('Date', (new Date()).toUTCString())
.status(401)
.send('401 UNAUTHORIZED');
}
// Returns data from the Authorization header: NTLM <data>
const ntlmAuthData = getNtlmAuthorizationData(req);
if (!ntlmAuthData) {
return options.handleHttpError400(res, `Authorization header does not contain NTLM data. URI ${uri}`);
}
// Fills req.ntlm with data from the Authorization header: NTLM <data>.
const { domain, messageType } = fillReqNtlm(req, ntlmAuthData);
// Domain names from NTLM messages - we believe
if (domain) {
(0, debug_1.debugNtlmLdapProxyId)(`↓ ${domain}`);
req.ntlm.domain = domain;
}
const dataBuf = buffer_1.Buffer.from(ntlmAuthData, 'base64');
if (messageType === ntlm_parser_1.NTLMMessageType.UNKNOWN) {
return options.handleHttpError400(res, `Incorrect NTLM message Type ${dataBuf.readUInt8(8)}`);
}
if (messageType === ntlm_parser_1.NTLMMessageType.NEGOTIATE_MESSAGE) {
return (0, handle_negotiate_1.handleNegotiate)(rsn, dataBuf).then(() => 0);
}
if (messageType === ntlm_parser_1.NTLMMessageType.AUTHENTICATE_MESSAGE) {
const isNoErrors = await (0, handle_authenticate_1.handleAuthenticate)(rsn, dataBuf);
if (!isNoErrors) {
return; // In this case the error has already been sent over HTTP
}
userData = options.getCachedUserData(rsn);
if (!userData.isAuthenticated) {
return options.handleHttpError403(rsn);
}
if (debug_1.debugNtlmAuthFlow.enabled) {
// eslint-disable-next-line no-console
console.log(`\n${af_color_1.bg.lGreen + af_color_1.black}req.ntlm:${af_color_1.bg.def + af_color_1.rs}`, userData, `\n`);
}
options.handleSuccessAuthentication(rsn);
(0, debug_1.debugNtlmAuthFlow)(`${constants_1.Larrow} handle success authorisation (Default ${af_color_1.bold + af_color_1.reset}next${af_color_1.blue}()${af_color_1.boldOff}${af_color_1.reset})`);
return;
}
return options.handleHttpError400(res, 'NTLM: Unexpected Type 2 message (CHALLENGE) in client request');
};
};
exports.authNTLM = authNTLM;
//# sourceMappingURL=auth-ntlm.js.map