'use strict'; const AuthProvider = require('./auth_provider').AuthProvider; const retrieveKerberos = require('../utils').retrieveKerberos; let kerberos; /** * Creates a new GSSAPI authentication mechanism * @class * @extends AuthProvider */ class GSSAPI extends AuthProvider { /** * Implementation of authentication for a single connection * @override */ _authenticateSingleConnection(sendAuthCommand, connection, credentials, callback) { const source = credentials.source; const username = credentials.username; const password = credentials.password; const mechanismProperties = credentials.mechanismProperties; const gssapiServiceName = mechanismProperties['gssapiservicename'] || mechanismProperties['gssapiServiceName'] || 'mongodb'; GSSAPIInitialize( this, kerberos.processes.MongoAuthProcess, source, username, password, source, gssapiServiceName, sendAuthCommand, connection, mechanismProperties, callback ); } /** * Authenticate * @override * @method */ auth(sendAuthCommand, connections, credentials, callback) { if (kerberos == null) { try { kerberos = retrieveKerberos(); } catch (e) { return callback(e, null); } } super.auth(sendAuthCommand, connections, credentials, callback); } } // // Initialize step var GSSAPIInitialize = function( self, MongoAuthProcess, db, username, password, authdb, gssapiServiceName, sendAuthCommand, connection, options, callback ) { // Create authenticator var mongo_auth_process = new MongoAuthProcess( connection.host, connection.port, gssapiServiceName, options ); // Perform initialization mongo_auth_process.init(username, password, function(err) { if (err) return callback(err, false); // Perform the first step mongo_auth_process.transition('', function(err, payload) { if (err) return callback(err, false); // Call the next db step MongoDBGSSAPIFirstStep( self, mongo_auth_process, payload, db, username, password, authdb, sendAuthCommand, connection, callback ); }); }); }; // // Perform first step against mongodb var MongoDBGSSAPIFirstStep = function( self, mongo_auth_process, payload, db, username, password, authdb, sendAuthCommand, connection, callback ) { // Build the sasl start command var command = { saslStart: 1, mechanism: 'GSSAPI', payload: payload, autoAuthorize: 1 }; // Write the commmand on the connection sendAuthCommand(connection, '$external.$cmd', command, (err, doc) => { if (err) return callback(err, false); // Execute mongodb transition mongo_auth_process.transition(doc.payload, function(err, payload) { if (err) return callback(err, false); // MongoDB API Second Step MongoDBGSSAPISecondStep( self, mongo_auth_process, payload, doc, db, username, password, authdb, sendAuthCommand, connection, callback ); }); }); }; // // Perform first step against mongodb var MongoDBGSSAPISecondStep = function( self, mongo_auth_process, payload, doc, db, username, password, authdb, sendAuthCommand, connection, callback ) { // Build Authentication command to send to MongoDB var command = { saslContinue: 1, conversationId: doc.conversationId, payload: payload }; // Execute the command // Write the commmand on the connection sendAuthCommand(connection, '$external.$cmd', command, (err, doc) => { if (err) return callback(err, false); // Call next transition for kerberos mongo_auth_process.transition(doc.payload, function(err, payload) { if (err) return callback(err, false); // Call the last and third step MongoDBGSSAPIThirdStep( self, mongo_auth_process, payload, doc, db, username, password, authdb, sendAuthCommand, connection, callback ); }); }); }; var MongoDBGSSAPIThirdStep = function( self, mongo_auth_process, payload, doc, db, username, password, authdb, sendAuthCommand, connection, callback ) { // Build final command var command = { saslContinue: 1, conversationId: doc.conversationId, payload: payload }; // Execute the command sendAuthCommand(connection, '$external.$cmd', command, (err, r) => { if (err) return callback(err, false); mongo_auth_process.transition(null, function(err) { if (err) return callback(err, null); callback(null, r); }); }); }; /** * This is a result from a authentication strategy * * @callback authResultCallback * @param {error} error An error object. Set to null if no error present * @param {boolean} result The result of the authentication process */ module.exports = GSSAPI;