123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- "use strict";
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.resolveCname = exports.performGSSAPICanonicalizeHostName = exports.GSSAPI = exports.GSSAPICanonicalizationValue = void 0;
- const dns = require("dns");
- const deps_1 = require("../../deps");
- const error_1 = require("../../error");
- const utils_1 = require("../../utils");
- const auth_provider_1 = require("./auth_provider");
- /** @public */
- exports.GSSAPICanonicalizationValue = Object.freeze({
- on: true,
- off: false,
- none: 'none',
- forward: 'forward',
- forwardAndReverse: 'forwardAndReverse'
- });
- async function externalCommand(connection, command) {
- return connection.commandAsync((0, utils_1.ns)('$external.$cmd'), command, undefined);
- }
- let krb;
- class GSSAPI extends auth_provider_1.AuthProvider {
- async auth(authContext) {
- const { connection, credentials } = authContext;
- if (credentials == null) {
- throw new error_1.MongoMissingCredentialsError('Credentials required for GSSAPI authentication');
- }
- const { username } = credentials;
- const client = await makeKerberosClient(authContext);
- const payload = await client.step('');
- const saslStartResponse = await externalCommand(connection, saslStart(payload));
- const negotiatedPayload = await negotiate(client, 10, saslStartResponse.payload);
- const saslContinueResponse = await externalCommand(connection, saslContinue(negotiatedPayload, saslStartResponse.conversationId));
- const finalizePayload = await finalize(client, username, saslContinueResponse.payload);
- await externalCommand(connection, {
- saslContinue: 1,
- conversationId: saslContinueResponse.conversationId,
- payload: finalizePayload
- });
- }
- }
- exports.GSSAPI = GSSAPI;
- async function makeKerberosClient(authContext) {
- const { hostAddress } = authContext.options;
- const { credentials } = authContext;
- if (!hostAddress || typeof hostAddress.host !== 'string' || !credentials) {
- throw new error_1.MongoInvalidArgumentError('Connection must have host and port and credentials defined.');
- }
- loadKrb();
- if ('kModuleError' in krb) {
- throw krb['kModuleError'];
- }
- const { initializeClient } = krb;
- const { username, password } = credentials;
- const mechanismProperties = credentials.mechanismProperties;
- const serviceName = mechanismProperties.SERVICE_NAME ?? 'mongodb';
- const host = await performGSSAPICanonicalizeHostName(hostAddress.host, mechanismProperties);
- const initOptions = {};
- if (password != null) {
- // TODO(NODE-5139): These do not match the typescript options in initializeClient
- Object.assign(initOptions, { user: username, password: password });
- }
- const spnHost = mechanismProperties.SERVICE_HOST ?? host;
- let spn = `${serviceName}${process.platform === 'win32' ? '/' : '@'}${spnHost}`;
- if ('SERVICE_REALM' in mechanismProperties) {
- spn = `${spn}@${mechanismProperties.SERVICE_REALM}`;
- }
- return initializeClient(spn, initOptions);
- }
- function saslStart(payload) {
- return {
- saslStart: 1,
- mechanism: 'GSSAPI',
- payload,
- autoAuthorize: 1
- };
- }
- function saslContinue(payload, conversationId) {
- return {
- saslContinue: 1,
- conversationId,
- payload
- };
- }
- async function negotiate(client, retries, payload) {
- try {
- const response = await client.step(payload);
- return response || '';
- }
- catch (error) {
- if (retries === 0) {
- // Retries exhausted, raise error
- throw error;
- }
- // Adjust number of retries and call step again
- return negotiate(client, retries - 1, payload);
- }
- }
- async function finalize(client, user, payload) {
- // GSS Client Unwrap
- const response = await client.unwrap(payload);
- return client.wrap(response || '', { user });
- }
- async function performGSSAPICanonicalizeHostName(host, mechanismProperties) {
- const mode = mechanismProperties.CANONICALIZE_HOST_NAME;
- if (!mode || mode === exports.GSSAPICanonicalizationValue.none) {
- return host;
- }
- // If forward and reverse or true
- if (mode === exports.GSSAPICanonicalizationValue.on ||
- mode === exports.GSSAPICanonicalizationValue.forwardAndReverse) {
- // Perform the lookup of the ip address.
- const { address } = await dns.promises.lookup(host);
- try {
- // Perform a reverse ptr lookup on the ip address.
- const results = await dns.promises.resolvePtr(address);
- // If the ptr did not error but had no results, return the host.
- return results.length > 0 ? results[0] : host;
- }
- catch (error) {
- // This can error as ptr records may not exist for all ips. In this case
- // fallback to a cname lookup as dns.lookup() does not return the
- // cname.
- return resolveCname(host);
- }
- }
- else {
- // The case for forward is just to resolve the cname as dns.lookup()
- // will not return it.
- return resolveCname(host);
- }
- }
- exports.performGSSAPICanonicalizeHostName = performGSSAPICanonicalizeHostName;
- async function resolveCname(host) {
- // Attempt to resolve the host name
- try {
- const results = await dns.promises.resolveCname(host);
- // Get the first resolved host id
- return results.length > 0 ? results[0] : host;
- }
- catch {
- return host;
- }
- }
- exports.resolveCname = resolveCname;
- /**
- * Load the Kerberos library.
- */
- function loadKrb() {
- if (!krb) {
- krb = (0, deps_1.getKerberos)();
- }
- }
- //# sourceMappingURL=gssapi.js.map
|