'use strict'; const AuthProvider = require('./auth_provider').AuthProvider; const retrieveKerberos = require('../utils').retrieveKerberos; let kerberos; /** * Creates a new SSPI authentication mechanism * @class * @extends AuthProvider */ class SSPI extends AuthProvider { /** * Implementation of authentication for a single connection * @override */ _authenticateSingleConnection(sendAuthCommand, connection, credentials, callback) { // TODO: Destructure this const username = credentials.username; const password = credentials.password; const mechanismProperties = credentials.mechanismProperties; const gssapiServiceName = mechanismProperties['gssapiservicename'] || mechanismProperties['gssapiServiceName'] || 'mongodb'; SSIPAuthenticate( this, kerberos.processes.MongoAuthProcess, username, password, 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); } } function SSIPAuthenticate( self, MongoAuthProcess, username, password, gssapiServiceName, sendAuthCommand, connection, options, callback ) { const authProcess = new MongoAuthProcess( connection.host, connection.port, gssapiServiceName, options ); function authCommand(command, authCb) { sendAuthCommand(connection, '$external.$cmd', command, authCb); } authProcess.init(username, password, err => { if (err) return callback(err, false); authProcess.transition('', (err, payload) => { if (err) return callback(err, false); const command = { saslStart: 1, mechanism: 'GSSAPI', payload, autoAuthorize: 1 }; authCommand(command, (err, doc) => { if (err) return callback(err, false); authProcess.transition(doc.payload, (err, payload) => { if (err) return callback(err, false); const command = { saslContinue: 1, conversationId: doc.conversationId, payload }; authCommand(command, (err, doc) => { if (err) return callback(err, false); authProcess.transition(doc.payload, (err, payload) => { if (err) return callback(err, false); const command = { saslContinue: 1, conversationId: doc.conversationId, payload }; authCommand(command, (err, response) => { if (err) return callback(err, false); authProcess.transition(null, err => { if (err) return callback(err, null); callback(null, response); }); }); }); }); }); }); }); }); } module.exports = SSPI;