gssapi.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.GSSAPI = void 0;
  4. const dns = require("dns");
  5. const deps_1 = require("../../deps");
  6. const error_1 = require("../../error");
  7. const utils_1 = require("../../utils");
  8. const auth_provider_1 = require("./auth_provider");
  9. class GSSAPI extends auth_provider_1.AuthProvider {
  10. auth(authContext, callback) {
  11. const { connection, credentials } = authContext;
  12. if (credentials == null)
  13. return callback(new error_1.MongoMissingCredentialsError('Credentials required for GSSAPI authentication'));
  14. const { username } = credentials;
  15. function externalCommand(command, cb) {
  16. return connection.command((0, utils_1.ns)('$external.$cmd'), command, undefined, cb);
  17. }
  18. makeKerberosClient(authContext, (err, client) => {
  19. if (err)
  20. return callback(err);
  21. if (client == null)
  22. return callback(new error_1.MongoMissingDependencyError('GSSAPI client missing'));
  23. client.step('', (err, payload) => {
  24. if (err)
  25. return callback(err);
  26. externalCommand(saslStart(payload), (err, result) => {
  27. if (err)
  28. return callback(err);
  29. if (result == null)
  30. return callback();
  31. negotiate(client, 10, result.payload, (err, payload) => {
  32. if (err)
  33. return callback(err);
  34. externalCommand(saslContinue(payload, result.conversationId), (err, result) => {
  35. if (err)
  36. return callback(err);
  37. if (result == null)
  38. return callback();
  39. finalize(client, username, result.payload, (err, payload) => {
  40. if (err)
  41. return callback(err);
  42. externalCommand({
  43. saslContinue: 1,
  44. conversationId: result.conversationId,
  45. payload
  46. }, (err, result) => {
  47. if (err)
  48. return callback(err);
  49. callback(undefined, result);
  50. });
  51. });
  52. });
  53. });
  54. });
  55. });
  56. });
  57. }
  58. }
  59. exports.GSSAPI = GSSAPI;
  60. function makeKerberosClient(authContext, callback) {
  61. var _a;
  62. const { hostAddress } = authContext.options;
  63. const { credentials } = authContext;
  64. if (!hostAddress || typeof hostAddress.host !== 'string' || !credentials) {
  65. return callback(new error_1.MongoInvalidArgumentError('Connection must have host and port and credentials defined.'));
  66. }
  67. if ('kModuleError' in deps_1.Kerberos) {
  68. return callback(deps_1.Kerberos['kModuleError']);
  69. }
  70. const { initializeClient } = deps_1.Kerberos;
  71. const { username, password } = credentials;
  72. const mechanismProperties = credentials.mechanismProperties;
  73. const serviceName = (_a = mechanismProperties.SERVICE_NAME) !== null && _a !== void 0 ? _a : 'mongodb';
  74. performGssapiCanonicalizeHostName(hostAddress.host, mechanismProperties, (err, host) => {
  75. if (err)
  76. return callback(err);
  77. const initOptions = {};
  78. if (password != null) {
  79. Object.assign(initOptions, { user: username, password: password });
  80. }
  81. let spn = `${serviceName}${process.platform === 'win32' ? '/' : '@'}${host}`;
  82. if ('SERVICE_REALM' in mechanismProperties) {
  83. spn = `${spn}@${mechanismProperties.SERVICE_REALM}`;
  84. }
  85. initializeClient(spn, initOptions, (err, client) => {
  86. // TODO(NODE-3483)
  87. if (err)
  88. return callback(new error_1.MongoRuntimeError(err));
  89. callback(undefined, client);
  90. });
  91. });
  92. }
  93. function saslStart(payload) {
  94. return {
  95. saslStart: 1,
  96. mechanism: 'GSSAPI',
  97. payload,
  98. autoAuthorize: 1
  99. };
  100. }
  101. function saslContinue(payload, conversationId) {
  102. return {
  103. saslContinue: 1,
  104. conversationId,
  105. payload
  106. };
  107. }
  108. function negotiate(client, retries, payload, callback) {
  109. client.step(payload, (err, response) => {
  110. // Retries exhausted, raise error
  111. if (err && retries === 0)
  112. return callback(err);
  113. // Adjust number of retries and call step again
  114. if (err)
  115. return negotiate(client, retries - 1, payload, callback);
  116. // Return the payload
  117. callback(undefined, response || '');
  118. });
  119. }
  120. function finalize(client, user, payload, callback) {
  121. // GSS Client Unwrap
  122. client.unwrap(payload, (err, response) => {
  123. if (err)
  124. return callback(err);
  125. // Wrap the response
  126. client.wrap(response || '', { user }, (err, wrapped) => {
  127. if (err)
  128. return callback(err);
  129. // Return the payload
  130. callback(undefined, wrapped);
  131. });
  132. });
  133. }
  134. function performGssapiCanonicalizeHostName(host, mechanismProperties, callback) {
  135. if (!mechanismProperties.gssapiCanonicalizeHostName)
  136. return callback(undefined, host);
  137. // Attempt to resolve the host name
  138. dns.resolveCname(host, (err, r) => {
  139. if (err)
  140. return callback(err);
  141. // Get the first resolve host id
  142. if (Array.isArray(r) && r.length > 0) {
  143. return callback(undefined, r[0]);
  144. }
  145. callback(undefined, host);
  146. });
  147. }
  148. //# sourceMappingURL=gssapi.js.map