Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

kerberos

Package Overview
Dependencies
Maintainers
2
Versions
42
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

kerberos - npm Package Compare versions

Comparing version 0.0.24 to 1.0.0

.clang-format

14

index.js

@@ -0,6 +1,14 @@

'use strict';
const kerberos = require('./lib/kerberos');
// Get the Kerberos library
module.exports = require('./lib/kerberos');
module.exports = kerberos;
// Support legacy versions of the mongodb driver which expect this export
module.exports.Kerberos = kerberos;
// Set up the auth processes
module.exports['processes'] = {
module.exports.processes = {
MongoAuthProcess: require('./lib/auth_processes/mongodb').MongoAuthProcess
}
};

@@ -1,347 +0,144 @@

var format = require('util').format,
dns = require('dns');
'use strict';
const dns = require('dns');
const kerberos = require('../kerberos');
var MongoAuthProcess = function(host, port, service_name, options) {
// Check what system we are on
if(process.platform == 'win32') {
this._processor = new Win32MongoProcessor(host, port, service_name, options);
} else {
this._processor = new UnixMongoProcessor(host, port, service_name, options);
}
}
class MongoAuthProcess {
constructor(host, port, serviceName, options) {
options = options || {};
this.host = host;
this.port = port;
MongoAuthProcess.prototype.init = function(username, password, callback) {
this._processor.init(username, password, callback);
}
// Set up service name
serviceName = serviceName || options.gssapiServiceName || 'mongodb';
MongoAuthProcess.prototype.transition = function(payload, callback) {
this._processor.transition(payload, callback);
}
// Options
this.canonicalizeHostName =
typeof options.gssapiCanonicalizeHostName === 'boolean'
? options.gssapiCanonicalizeHostName
: false;
/*******************************************************************
*
* Win32 SSIP Processor for MongoDB
*
*******************************************************************/
var Win32MongoProcessor = function(host, port, service_name, options) {
options = options || {};
this.host = host;
this.port = port
this.service =
process.platform === 'win32' ? `${serviceName}/${host}` : `${serviceName}@${host}`;
// Set up service name
service_name = service_name || "mongodb";
// Options
this.gssapiServiceName = options.gssapiServiceName || service_name;
this.gssapiServiceRealm = options.gssapiServiceRealm;
this.gssapiCanonicalizeHostName = typeof options.gssapiCanonicalizeHostName == 'boolean' ? options.gssapiCanonicalizeHostName : false;
// SSIP classes
this.ssip = require("../kerberos").SSIP;
// Set up first transition
this._transition = Win32MongoProcessor.first_transition(this);
// Number of retries
this.retries = 10;
}
// Set up first transition
this._transition = firstTransition(this);
Win32MongoProcessor.prototype.init = function(username, password, callback) {
var self = this;
// Save the values used later
this.username = username;
this.password = password;
// Canonicialize host name if needed
var performGssapiCanonicalizeHostName = function(gssapiCanonicalizeHostName, host, callback) {
if(!gssapiCanonicalizeHostName) return callback();
// Attempt to resolve the host name
dns.resolveCname(host, function(err, r) {
if(err) return callback(err);
// Get the first resolve host id
if(Array.isArray(r) && r.length > 0) {
self.host = r[0];
}
callback();
});
// Number of retries
this.retries = 10;
}
// Canonicialize host name if needed
performGssapiCanonicalizeHostName(this.gssapiCanonicalizeHostName, this.host, function(err) {
if(err) return callback(err);
// Acquire credentials
self.ssip.SecurityCredentials.aquire_kerberos(username, password, function(err, security_credentials) {
if(err) return callback(err);
init(username, password, callback) {
const self = this;
this.username = username;
this.password = password;
// Set up target
self.target = format("%s/%s", self.gssapiServiceName, self.host);
// Canonicialize host name if needed
function performGssapiCanonicalizeHostName(canonicalizeHostName, host, callback) {
if (!canonicalizeHostName) return callback();
// Do we have a service realm
if(self.gssapiServiceRealm) {
self.target = format("%s@%s", self.target, self.gssapiServiceRealm);
}
// Attempt to resolve the host name
dns.resolveCname(host, (err, r) => {
if (err) return callback(err);
// Save credentials
self.security_credentials = security_credentials;
// Callback with success
callback(null);
});
});
}
Win32MongoProcessor.prototype.transition = function(payload, callback) {
if(this._transition == null) return callback(new Error("Transition finished"));
this._transition(payload, callback);
}
Win32MongoProcessor.first_transition = function(self) {
return function(payload, callback) {
self.ssip.SecurityContext.initialize(
self.security_credentials,
self.target,
payload, function(err, security_context) {
if(err) return callback(err);
// If no context try again until we have no more retries
if(!security_context.hasContext) {
if(self.retries == 0) return callback(new Error("Failed to initialize security context"));
// Update the number of retries
self.retries = self.retries - 1;
// Set next transition
return self.transition(payload, callback);
// Get the first resolve host id
if (Array.isArray(r) && r.length > 0) {
self.host = r[0];
}
// Set next transition
self._transition = Win32MongoProcessor.second_transition(self);
self.security_context = security_context;
// Return the payload
callback(null, security_context.payload);
});
}
}
callback();
});
}
Win32MongoProcessor.second_transition = function(self) {
return function(payload, callback) {
// Perform a step
self.security_context.initialize(self.target, payload, function(err, security_context) {
if(err) return callback(err);
// Canonicialize host name if needed
performGssapiCanonicalizeHostName(this.canonicalizeHostName, this.host, err => {
if (err) return callback(err);
// If no context try again until we have no more retries
if(!security_context.hasContext) {
if(self.retries == 0) return callback(new Error("Failed to initialize security context"));
// Update the number of retries
self.retries = self.retries - 1;
// Set next transition
self._transition = Win32MongoProcessor.first_transition(self);
// Retry
return self.transition(payload, callback);
}
kerberos.initializeClient(self.service, { user: username, password }, (err, client) => {
if (err) return callback(err, null);
// Set next transition
self._transition = Win32MongoProcessor.third_transition(self);
// Return the payload
callback(null, security_context.payload);
self.client = client;
callback(null, client);
});
});
}
}
Win32MongoProcessor.third_transition = function(self) {
return function(payload, callback) {
var messageLength = 0;
// Get the raw bytes
var encryptedBytes = new Buffer(payload, 'base64');
var encryptedMessage = new Buffer(messageLength);
// Copy first byte
encryptedBytes.copy(encryptedMessage, 0, 0, messageLength);
// Set up trailer
var securityTrailerLength = encryptedBytes.length - messageLength;
var securityTrailer = new Buffer(securityTrailerLength);
// Copy the bytes
encryptedBytes.copy(securityTrailer, 0, messageLength, securityTrailerLength);
transition(payload, callback) {
if (this._transition == null) {
return callback(new Error('Transition finished'));
}
// Types used
var SecurityBuffer = self.ssip.SecurityBuffer;
var SecurityBufferDescriptor = self.ssip.SecurityBufferDescriptor;
// Set up security buffers
var buffers = [
new SecurityBuffer(SecurityBuffer.DATA, encryptedBytes)
, new SecurityBuffer(SecurityBuffer.STREAM, securityTrailer)
];
// Set up the descriptor
var descriptor = new SecurityBufferDescriptor(buffers);
// Decrypt the data
self.security_context.decryptMessage(descriptor, function(err, security_context) {
if(err) return callback(err);
var length = 4;
if(self.username != null) {
length += self.username.length;
}
var bytesReceivedFromServer = new Buffer(length);
bytesReceivedFromServer[0] = 0x01; // NO_PROTECTION
bytesReceivedFromServer[1] = 0x00; // NO_PROTECTION
bytesReceivedFromServer[2] = 0x00; // NO_PROTECTION
bytesReceivedFromServer[3] = 0x00; // NO_PROTECTION
if(self.username != null) {
var authorization_id_bytes = new Buffer(self.username, 'utf8');
authorization_id_bytes.copy(bytesReceivedFromServer, 4, 0);
}
self.security_context.queryContextAttributes(0x00, function(err, sizes) {
if(err) return callback(err);
var buffers = [
new SecurityBuffer(SecurityBuffer.TOKEN, new Buffer(sizes.securityTrailer))
, new SecurityBuffer(SecurityBuffer.DATA, bytesReceivedFromServer)
, new SecurityBuffer(SecurityBuffer.PADDING, new Buffer(sizes.blockSize))
]
var descriptor = new SecurityBufferDescriptor(buffers);
self.security_context.encryptMessage(descriptor, 0x80000001, function(err, security_context) {
if(err) return callback(err);
callback(null, security_context.payload);
});
});
});
this._transition(payload, callback);
}
}
/*******************************************************************
*
* UNIX MIT Kerberos processor
*
*******************************************************************/
var UnixMongoProcessor = function(host, port, service_name, options) {
options = options || {};
this.host = host;
this.port = port
// SSIP classes
this.Kerberos = require("../kerberos").Kerberos;
this.kerberos = new this.Kerberos();
// Set up service name
service_name = service_name || "mongodb";
// Options
this.gssapiServiceName = options.gssapiServiceName || service_name;
this.gssapiServiceRealm = options.gssapiServiceRealm;
this.gssapiCanonicalizeHostName = typeof options.gssapiCanonicalizeHostName == 'boolean' ? options.gssapiCanonicalizeHostName : false;
// Set up first transition
this._transition = UnixMongoProcessor.first_transition(this);
// Set up target
this.target = format("%s@%s", service_name, host);
// Number of retries
this.retries = 10;
}
function firstTransition(auth) {
return (payload, callback) => {
auth.client.step('', (err, response) => {
if (err) return callback(err);
UnixMongoProcessor.prototype.init = function(username, password, callback) {
var self = this;
this.username = username;
this.password = password;
// Set up the next step
auth._transition = secondTransition(auth);
// Canonicialize host name if needed
var performGssapiCanonicalizeHostName = function(gssapiCanonicalizeHostName, host, callback) {
if(!gssapiCanonicalizeHostName) return callback();
// Attempt to resolve the host name
dns.resolveCname(host, function(err, r) {
if(err) return callback(err);
// Get the first resolve host id
if(Array.isArray(r) && r.length > 0) {
self.host = r[0];
}
callback();
// Return the payload
callback(null, response);
});
}
// Canonicialize host name if needed
performGssapiCanonicalizeHostName(this.gssapiCanonicalizeHostName, this.host, function(err) {
if(err) return callback(err);
// Set up target
self.target = format("%s@%s", self.gssapiServiceName, self.host);
// Call client initiate
self.kerberos.authGSSClientInit(
self.target
, self.Kerberos.GSS_C_MUTUAL_FLAG, function(err, context) {
self.context = context;
// Return the context
callback(null, context);
});
});
};
}
UnixMongoProcessor.prototype.transition = function(payload, callback) {
if(this._transition == null) return callback(new Error("Transition finished"));
this._transition(payload, callback);
}
function secondTransition(auth) {
return (payload, callback) => {
auth.client.step(payload, (err, response) => {
if (err && auth.retries === 0) return callback(err);
UnixMongoProcessor.first_transition = function(self) {
return function(payload, callback) {
self.kerberos.authGSSClientStep(self.context, '', function(err, result) {
if(err) return callback(err);
// Set up the next step
self._transition = UnixMongoProcessor.second_transition(self);
// Return the payload
callback(null, self.context.response);
})
}
}
UnixMongoProcessor.second_transition = function(self) {
return function(payload, callback) {
self.kerberos.authGSSClientStep(self.context, payload, function(err, result) {
if(err && self.retries == 0) return callback(err);
// Attempt to re-establish a context
if(err) {
if (err) {
// Adjust the number of retries
self.retries = self.retries - 1;
auth.retries = auth.retries - 1;
// Call same step again
return self.transition(payload, callback);
return auth.transition(payload, callback);
}
// Set up the next step
self._transition = UnixMongoProcessor.third_transition(self);
auth._transition = thirdTransition(auth);
// Return the payload
callback(null, self.context.response || '');
callback(null, response || '');
});
}
};
}
UnixMongoProcessor.third_transition = function(self) {
return function(payload, callback) {
function thirdTransition(auth) {
return (payload, callback) => {
// GSS Client Unwrap
self.kerberos.authGSSClientUnwrap(self.context, payload, function(err, result) {
if(err) return callback(err, false);
auth.client.unwrap(payload, (err, response) => {
if (err) return callback(err, false);
// Wrap the response
self.kerberos.authGSSClientWrap(self.context, self.context.response, self.username, function(err, result) {
if(err) return callback(err, false);
auth.client.wrap(response, { user: auth.username }, (err, wrapped) => {
if (err) return callback(err, false);
// Set up the next step
self._transition = UnixMongoProcessor.fourth_transition(self);
auth._transition = fourthTransition(auth);
// Return the payload
callback(null, self.context.response);
callback(null, wrapped);
});
});
}
};
}
UnixMongoProcessor.fourth_transition = function(self) {
return function(payload, callback) {
// Clean up context
self.kerberos.authGSSClientClean(self.context, function(err, result) {
if(err) return callback(err, false);
// Set the transition to null
self._transition = null;
// Callback with valid authentication
callback(null, true);
});
}
function fourthTransition(auth) {
return (payload, callback) => {
// Set the transition to null
auth._transition = null;
// Callback with valid authentication
callback(null, true);
};
}
// Set the process
exports.MongoAuthProcess = MongoAuthProcess;
module.exports = {
MongoAuthProcess
};

@@ -1,191 +0,245 @@

var kerberos = require('../build/Release/kerberos')
, KerberosNative = kerberos.Kerberos;
'use strict';
var Kerberos = function() {
this._native_kerberos = new KerberosNative();
}
const kerberos = require('bindings')('kerberos');
const KerberosClient = kerberos.KerberosClient;
const KerberosServer = kerberos.KerberosServer;
// callback takes two arguments, an error string if defined and a new context
// uri should be given as service@host. Services are not always defined
// in a straightforward way. Use 'HTTP' for SPNEGO / Negotiate authentication.
// If credentialsCache is not specified, the default credentials cache from the
// environment will be used (ie. KRB5CCNAME). In the case where multiple
// credentials caches may be in use at once (such as for a server doing
// delegation), specify the cache name here and it will be used for this
// exchange. The credentialsCache is optional.
Kerberos.prototype.authGSSClientInit = function(uri, flags, credentialsCache, callback) {
if (typeof(credentialsCache) == 'function') {
callback = credentialsCache;
credentialsCache = '';
// GSS Flags
const GSS_C_DELEG_FLAG = 1;
const GSS_C_MUTUAL_FLAG = 2;
const GSS_C_REPLAY_FLAG = 4;
const GSS_C_SEQUENCE_FLAG = 8;
const GSS_C_CONF_FLAG = 16;
const GSS_C_INTEG_FLAG = 32;
const GSS_C_ANON_FLAG = 64;
const GSS_C_PROT_READY_FLAG = 128;
const GSS_C_TRANS_FLAG = 256;
// GSS_OID
const GSS_C_NO_OID = 0;
const GSS_MECH_OID_KRB5 = 9;
const GSS_MECH_OID_SPNEGO = 6;
function validateParameter(parameter, spec) {
if (parameter == null) {
throw new TypeError(`Required parameter \`${spec.name}\` missing`);
}
if (credentialsCache === undefined) {
credentialsCache = '';
if (spec.type && typeof parameter !== spec.type) {
throw new TypeError(
`Invalid type for parameter \`${spec.name}\`, expected \`${
spec.type
}\` but found \`${typeof parameter}\``
);
}
return this._native_kerberos.authGSSClientInit(uri, flags, credentialsCache, callback);
}
// This will obtain credentials using a credentials cache. To override the default
// location (posible /tmp/krb5cc_nnnnnn, where nnnn is your numeric uid) use
// the environment variable KRB5CNAME.
// The credentials (suitable for using in an 'Authenticate: ' header, when prefixed
// with 'Negotiate ') will be available as context.response inside the callback
// if no error is indicated.
// callback takes one argument, an error string if defined
Kerberos.prototype.authGSSClientStep = function(context, challenge, callback) {
if(typeof challenge == 'function') {
callback = challenge;
challenge = '';
}
/**
* Monkey-patches an existing method to support parameter validation, as well
* as adding support for returning Promises if callbacks are not provided.
*
* @private
* @param {function} fn the function to override
* @param {Array<Object>} paramDefs the definitions of each parameter to the function
*/
function defineOperation(fn, paramDefs) {
return function() {
const args = Array.prototype.slice.call(arguments);
const params = [];
for (let i = 0; i < paramDefs.length; ++i) {
const def = paramDefs[i];
let arg = args[i];
return this._native_kerberos.authGSSClientStep(context, challenge, callback);
}
if (def.default && arg == null) arg = def.default;
if (def.type === 'object' && def.default != null) {
arg = Object.assign({}, def.default, arg);
}
Kerberos.prototype.authGSSClientUnwrap = function(context, challenge, callback) {
if(typeof challenge == 'function') {
callback = challenge;
challenge = '';
}
// special case to allow `options` to be optional
if (def.name === 'options' && (typeof arg === 'function' || arg == null)) {
arg = {};
}
return this._native_kerberos.authGSSClientUnwrap(context, challenge, callback);
}
validateParameter(arg, paramDefs[i]);
params.push(arg);
}
Kerberos.prototype.authGSSClientWrap = function(context, challenge, user_name, callback) {
if(typeof user_name == 'function') {
callback = user_name;
user_name = '';
}
const callback = arguments[arguments.length - 1];
if (typeof callback !== 'function') {
return new Promise((resolve, reject) => {
params.push((err, response) => {
if (err) return reject(err);
resolve(response);
});
return this._native_kerberos.authGSSClientWrap(context, challenge, user_name, callback);
}
fn.apply(this, params);
});
}
// free memory used by a context created using authGSSClientInit.
// callback takes one argument, an error string if defined.
Kerberos.prototype.authGSSClientClean = function(context, callback) {
return this._native_kerberos.authGSSClientClean(context, callback);
params.push(callback);
fn.apply(this, params);
};
}
// The server will obtain credentials using a keytab. To override the
// default location (probably /etc/krb5.keytab) set the KRB5_KTNAME
// environment variable.
// The service name should be in the form service, or service@host.name
// e.g. for HTTP, use "HTTP" or "HTTP@my.host.name". See gss_import_name
// for GSS_C_NT_HOSTBASED_SERVICE.
//
// a boolean turns on "constrained_delegation". this enables acquisition of S4U2Proxy
// credentials which will be stored in a credentials cache during the authGSSServerStep
// method. this parameter is optional. The credentials will be stored in
// a new cache, the location of which will be made available as the "delegatedCredentialsCache"
// property on the returned context AFTER the authGSSServerStep stage.
//
// when "constrained_delegation" is enabled, a username can (optionally) be provided and
// S4U2Self protocol transition will be initiated. In this case, we will not
// require any "auth" data during the authGSSServerStep. This parameter is optional
// but constrained_delegation MUST be enabled for this to work. When S4U2Self is
// used, the username will be assumed to have been already authenticated, and no
// actual authentication will be performed. This is basically a way to "bootstrap"
// kerberos credentials (which can then be delegated with S4U2Proxy) for a user
// authenticated externally.
//
// callback takes two arguments, an error string if defined and a new context
//
Kerberos.prototype.authGSSServerInit = function(service, constrained_delegation, username, callback) {
if(typeof(constrained_delegation) === 'function') {
callback = constrained_delegation;
constrained_delegation = false;
username = null;
}
/**
* @class KerberosClient
*/
if (typeof(constrained_delegation) === 'string') {
throw new Error("S4U2Self protocol transation is not possible without enabling constrained delegation");
}
/**
* Processes a single kerberos client-side step using the supplied server challenge.
*
* @kind function
* @memberof KerberosClient
* @param {string} challenge A string containing the base64-encoded server data (which may be empty for the first step)
* @param {function} [callback]
* @return {Promise} returns Promise if no callback passed
*/
KerberosClient.prototype.step = defineOperation(KerberosClient.prototype.step, [
{ name: 'challenge', type: 'string' }
]);
if (typeof(username) === 'function') {
callback = username;
username = null;
}
/**
* Perform the client side kerberos wrap step.
*
* @kind function
* @memberof KerberosClient
* @param {string} challenge The response returned after calling `unwrap`
* @param {object} [options] Optional settings
* @param {string} [options.user] The user to authorize
* @param {function} [callback]
* @return {Promise} returns Promise if no callback passed
*/
KerberosClient.prototype.wrap = defineOperation(KerberosClient.prototype.wrap, [
{ name: 'challenge', type: 'string' },
{ name: 'options', type: 'object' }
]);
constrained_delegation = !!constrained_delegation;
return this._native_kerberos.authGSSServerInit(service, constrained_delegation, username, callback);
};
/**
* Perform the client side kerberos unwrap step
*
* @kind function
* @memberof KerberosClient
* @param {string} challenge A string containing the base64-encoded server data
* @param {function} [callback]
* @return {Promise} returns Promise if no callback passed
*/
KerberosClient.prototype.unwrap = defineOperation(KerberosClient.prototype.unwrap, [
{ name: 'challenge', type: 'string' }
]);
//callback takes one argument, an error string if defined.
Kerberos.prototype.authGSSServerClean = function(context, callback) {
return this._native_kerberos.authGSSServerClean(context, callback);
};
/**
* @class KerberosServer
*/
// authData should be the base64 encoded authentication data obtained
// from client, e.g., in the Authorization header (without the leading
// "Negotiate " string) during SPNEGO authentication. The authenticated user
// is available in context.username after successful authentication.
// callback takes one argument, an error string if defined.
//
// Note: when S4U2Self protocol transition was requested in the authGSSServerInit
// no actual authentication will be performed and authData will be ignored.
//
Kerberos.prototype.authGSSServerStep = function(context, authData, callback) {
return this._native_kerberos.authGSSServerStep(context, authData, callback);
};
/**
* Processes a single kerberos server-side step using the supplied client data.
*
* @kind function
* @memberof KerberosServer
* @param {string} challenge A string containing the base64-encoded client data
* @param {function} callback
* @return {Promise} returns Promise if no callback passed
*/
KerberosServer.prototype.step = defineOperation(KerberosServer.prototype.step, [
{ name: 'challenge', type: 'string' }
]);
// authenticate the username and password against the KDC, and verify the KDC using a local
// service key stored in the keytab. See above for details on providing the keytab.
// The service should be the service principal name for a key available in the local keytab,
// e.g. HTTP/somehost.example.com. If service is an empty tring, KDC verification will
// be skipped. DON'T DO THIS - it's a possible security vulnerability if an attacker
// can spoof your KDC (see: https://github.com/qesuto/node-krb5/issues/13)
// callback receives error and boolean
Kerberos.prototype.authUserKrb5Password = function(username, password, service, callback) {
return this._native_kerberos.authUserKrb5Password(username, password, service, callback);
};
/**
* This function provides a simple way to verify that a user name and password
* match those normally used for Kerberos authentication.
* It does this by checking that the supplied user name and password can be
* used to get a ticket for the supplied service.
* If the user name does not contain a realm, then the default realm supplied
* is used.
*
* For this to work properly the Kerberos must be configured properly on this
* machine.
* That will likely mean ensuring that the edu.mit.Kerberos preference file
* has the correct realms and KDCs listed.
*
* IMPORTANT: This method is vulnerable to KDC spoofing attacks and it should
* only be used for testing. Do not use this in any production system - your
* security could be compromised if you do.
*
* @kind function
* @param {string} username The Kerberos user name. If no realm is supplied, then the `defaultRealm` will be used.
* @param {string} password The password for the user.
* @param {string} service The Kerberos service to check access for.
* @param {string} [defaultRealm] The default realm to use if one is not supplied in the user argument.
* @param {function} [callback]
* @return {Promise} returns Promise if no callback passed
*/
const checkPassword = defineOperation(kerberos.checkPassword, [
{ name: 'username', type: 'string' },
{ name: 'password', type: 'string' },
{ name: 'service', type: 'string' },
{ name: 'defaultRealm', type: 'string' }
]);
Kerberos.prototype.acquireAlternateCredentials = function(user_name, password, domain) {
return this._native_kerberos.acquireAlternateCredentials(user_name, password, domain);
}
/**
* This function returns the service principal for the server given a service type and hostname.
*
* Details are looked up via the `/etc/keytab` file.
*
* @kind function
* @param {string} service The Kerberos service type for the server.
* @param {string} hostname The hostname of the server.
* @param {function} [callback]
* @return {Promise} returns Promise if no callback passed
*/
const principalDetails = defineOperation(kerberos.principalDetails, [
{ name: 'service', type: 'string' },
{ name: 'hostname', type: 'string' }
]);
Kerberos.prototype.prepareOutboundPackage = function(principal, inputdata) {
return this._native_kerberos.prepareOutboundPackage(principal, inputdata);
}
/**
* Initializes a context for client-side authentication with the given service principal.
*
* @kind function
* @param {string} service A string containing the service principal in the form 'type@fqdn' (e.g. 'imap@mail.apple.com').
* @param {object} [options] Optional settings
* @param {string} [options.principal] Optional string containing the client principal in the form 'user@realm' (e.g. 'jdoe@example.com').
* @param {number} [options.gssFlags] Optional integer used to set GSS flags. (e.g. GSS_C_DELEG_FLAG|GSS_C_MUTUAL_FLAG|GSS_C_SEQUENCE_FLAG will allow for forwarding credentials to the remote host)
* @param {number} [options.mechOID] Optional GSS mech OID. Defaults to None (GSS_C_NO_OID). Other possible values are `GSS_MECH_OID_KRB5`, `GSS_MECH_OID_SPNEGO`.
* @param {function} [callback]
* @return {Promise} returns Promise if no callback passed
*/
const initializeClient = defineOperation(kerberos.initializeClient, [
{ name: 'service', type: 'string' },
{ name: 'options', type: 'object', default: { mechOID: GSS_C_NO_OID } }
]);
Kerberos.prototype.decryptMessage = function(challenge) {
return this._native_kerberos.decryptMessage(challenge);
}
/**
* Initializes a context for server-side authentication with the given service principal.
*
* @kind function
* @param {string} service A string containing the service principal in the form 'type@fqdn' (e.g. 'imap@mail.apple.com').
* @param {function} [callback]
* @return {Promise} returns Promise if no callback passed
*/
const initializeServer = defineOperation(kerberos.initializeServer, [
{ name: 'service', type: 'string' }
]);
Kerberos.prototype.encryptMessage = function(challenge) {
return this._native_kerberos.encryptMessage(challenge);
}
module.exports = {
initializeClient,
initializeServer,
principalDetails,
checkPassword,
Kerberos.prototype.queryContextAttribute = function(attribute) {
if(typeof attribute != 'number' && attribute != 0x00) throw new Error("Attribute not supported");
return this._native_kerberos.queryContextAttribute(attribute);
}
// gss flags
GSS_C_DELEG_FLAG,
GSS_C_MUTUAL_FLAG,
GSS_C_REPLAY_FLAG,
GSS_C_SEQUENCE_FLAG,
GSS_C_CONF_FLAG,
GSS_C_INTEG_FLAG,
GSS_C_ANON_FLAG,
GSS_C_PROT_READY_FLAG,
GSS_C_TRANS_FLAG,
GSS_C_NO_OID,
// Some useful result codes
Kerberos.AUTH_GSS_CONTINUE = 0;
Kerberos.AUTH_GSS_COMPLETE = 1;
// Some useful gss flags
Kerberos.GSS_C_DELEG_FLAG = 1;
Kerberos.GSS_C_MUTUAL_FLAG = 2;
Kerberos.GSS_C_REPLAY_FLAG = 4;
Kerberos.GSS_C_SEQUENCE_FLAG = 8;
Kerberos.GSS_C_CONF_FLAG = 16;
Kerberos.GSS_C_INTEG_FLAG = 32;
Kerberos.GSS_C_ANON_FLAG = 64;
Kerberos.GSS_C_PROT_READY_FLAG = 128;
Kerberos.GSS_C_TRANS_FLAG = 256;
// Export Kerberos class
exports.Kerberos = Kerberos;
// If we have SSPI (windows)
if(kerberos.SecurityCredentials) {
// Put all SSPI classes in it's own namespace
exports.SSIP = {
SecurityCredentials: require('./win32/wrappers/security_credentials').SecurityCredentials
, SecurityContext: require('./win32/wrappers/security_context').SecurityContext
, SecurityBuffer: require('./win32/wrappers/security_buffer').SecurityBuffer
, SecurityBufferDescriptor: require('./win32/wrappers/security_buffer_descriptor').SecurityBufferDescriptor
}
}
// mechanism OIDs
GSS_MECH_OID_KRB5,
GSS_MECH_OID_SPNEGO
};
{
"name": "kerberos",
"version": "0.0.24",
"version": "1.0.0",
"description": "Kerberos library for Node.js",

@@ -16,10 +16,32 @@ "main": "index.js",

"dependencies": {
"nan": "~2.10.0"
"bindings": "^1.3.0",
"nan": "^2.10.0",
"prebuild-install": "^5.0.0"
},
"devDependencies": {
"nodeunit": "latest"
"chai": "^4.1.2",
"chai-string": "^1.4.0",
"clang-format": "^1.2.4",
"dmd-clear": "^0.1.2",
"eslint": "^5.3.0",
"eslint-plugin-prettier": "^2.6.2",
"jsdoc-to-markdown": "^4.0.1",
"mocha": "^5.2.0",
"mongodb": "^3.1.3",
"prebuild": "^7.6.2",
"prebuild-ci": "^2.2.3",
"prettier": "^1.14.2",
"request": "^2.88.0",
"segfault-handler": "^1.0.1"
},
"scripts": {
"install": "(node-gyp rebuild) || (exit 0)",
"test": "nodeunit ./test"
"install": "prebuild-install || node-gyp rebuild",
"format-cxx": "git-clang-format",
"format-js": "prettier --print-width 100 --tab-width 2 --single-quote --write index.js 'test/**/*.js' 'lib/**/*.js'",
"lint": "eslint index.js lib test",
"precommit": "check-clang-format",
"test": "mocha ./test && prebuild-ci",
"docs": "jsdoc2md --template etc/README.hbs --plugin dmd-clear --files lib/kerberos.js > README.md",
"rebuild": "prebuild --compile",
"prebuild": "prebuild --all --strip --verbose"
},

@@ -26,0 +48,0 @@ "author": "Christian Amor Kvalheim",

Kerberos
========
[![Build Status](https://travis-ci.org/mongodb-js/kerberos.svg?branch=master)](https://travis-ci.org/mongodb-js/kerberos)
The `kerberos` package is a C++ extension that requires a build environment to be installed on your system. You must be able to build node.js itself to be able to compile and install the `kerberos` module. Furthermore the `kerberos` module requires the MIT Kerberos package to correctly compile on UNIX operating systems. Consult your UNIX operation system package manager what libraries to install.
The `kerberos` package is a C++ extension for Node.js that provides cross-platform support for kerberos authentication using GSSAPI on linux/osx, and SSPI on windows. Much of the code in this module is adapted from [ccs-kerberos](https://github.com/apple/ccs-pykerberos) and [winkerberos](https://github.com/mongodb-labs/winkerberos).
{{% note class="important" %}}
Windows already contains the SSPI API used for Kerberos authentication. However you will need to install a full compiler tool chain using visual studio C++ to correctly install the kerberos extension.
{{% /note %}}
### Requirements
### Diagnosing on UNIX
**Linux**
- `python` v2.7
- `make`
- A proper C/C++ compiler toolchain, like [GCC](https://gcc.gnu.org/)
- Distribution-specific kerberos packages (e.g. `krb5-dev` on Ubuntu)
If you don’t have the build essentials it won’t build. In the case of linux you will need gcc and g++, node.js with all the headers and python. The easiest way to figure out what’s missing is by trying to build the kerberos project. You can do this by performing the following steps.
**macOS**
- `Xcode Command Line Tools`: Can be installed with `xcode-select --install`
- Distribution-specific kerberos packages (e.g. `krb5` on Homebrew)
```
git clone https://github.com/christkv/kerberos.git
cd kerberos
npm install
```
**Windows**
- **Option 1:** Install all the required tools and configurations using Microsoft's [windows-build-tools](https://github.com/felixrieseberg/windows-build-tools) by running `npm install -g windows-build-tools` from an elevated PowerShell (run as Administrator).
- **Option 2:** Install dependencies and configuration manually
1. Visual C++ Build Environment:
* **Option 1:** Install [Visual C++ Build Tools](http://go.microsoft.com/fwlink/?LinkId=691126) using the *Default Install* option.
* **Option 2:** Install [Visual Studio 2015](https://www.visualstudio.com/products/visual-studio-community-vs) (or modify an existing installation) and select *Common Tools for Visual C++* during setup.
If all the steps complete you have the right toolchain installed. If you get node-gyp not found you need to install it globally by doing.
> :bulb: [Windows Vista / 7 only] requires [.NET Framework 4.5.1](http://www.microsoft.com/en-us/download/details.aspx?id=40773)
```
npm install -g node-gyp
```
2. Install [Python 2.7](https://www.python.org/downloads/) or [Miniconda 2.7](http://conda.pydata.org/miniconda.html) (`v3.x.x` is not supported), and run `npm config set python python2.7`
3. Launch cmd, `npm config set msvs_version 2015`
If correctly compiles and runs the tests you are golden. We can now try to install the kerberos module by performing the following command.
### Installation
Now you can install `kerberos` with the following:
```bash
npm install kerberos
```
cd yourproject
npm install kerberos --save
```
If it still fails the next step is to examine the npm log. Rerun the command but in this case in verbose mode.
### Testing
Run the test suite using:
```bash
npm test
```
npm --loglevel verbose install kerberos
```
This will print out all the steps npm is performing while trying to install the module.
NOTE: The test suite requires an active kerberos deployment, see `test/scripts/travis.sh` to better understand these requirements.
### Diagnosing on Windows
# Documentation
A known compiler tool chain known to work for compiling `kerberos` on windows is the following.
## Classes
* Visual Studio c++ 2010 (do not use higher versions)
* Windows 7 64bit SDK
* Python 2.7 or higher
<dl>
<dt><a href="#KerberosClient">KerberosClient</a></dt>
<dd></dd>
<dt><a href="#KerberosServer">KerberosServer</a></dt>
<dd></dd>
</dl>
Open visual studio command prompt. Ensure node.exe is in your path and install node-gyp.
## Functions
```
npm install -g node-gyp
```
<dl>
<dt><a href="#checkPassword">checkPassword(username, password, service, [defaultRealm], [callback])</a> ⇒ <code>Promise</code></dt>
<dd><p>This function provides a simple way to verify that a user name and password
match those normally used for Kerberos authentication.
It does this by checking that the supplied user name and password can be
used to get a ticket for the supplied service.
If the user name does not contain a realm, then the default realm supplied
is used.</p>
<p>For this to work properly the Kerberos must be configured properly on this
machine.
That will likely mean ensuring that the edu.mit.Kerberos preference file
has the correct realms and KDCs listed.</p>
<p>IMPORTANT: This method is vulnerable to KDC spoofing attacks and it should
only be used for testing. Do not use this in any production system - your
security could be compromised if you do.</p>
</dd>
<dt><a href="#principalDetails">principalDetails(service, hostname, [callback])</a> ⇒ <code>Promise</code></dt>
<dd><p>This function returns the service principal for the server given a service type and hostname.</p>
<p>Details are looked up via the <code>/etc/keytab</code> file.</p>
</dd>
<dt><a href="#initializeClient">initializeClient(service, [options], [callback])</a> ⇒ <code>Promise</code></dt>
<dd><p>Initializes a context for client-side authentication with the given service principal.</p>
</dd>
<dt><a href="#initializeServer">initializeServer(service, [callback])</a> ⇒ <code>Promise</code></dt>
<dd><p>Initializes a context for server-side authentication with the given service principal.</p>
</dd>
</dl>
Next you will have to build the project manually to test it. Use any tool you use with git and grab the repo.
<a name="KerberosClient"></a>
```
git clone https://github.com/christkv/kerberos.git
cd kerberos
npm install
node-gyp rebuild
```
## KerberosClient
This should rebuild the driver successfully if you have everything set up correctly.
* [KerberosClient](#KerberosClient)
### Other possible issues
* [.step(challenge, [callback])](#KerberosClient+step)
Your python installation might be hosed making gyp break. I always recommend that you test your deployment environment first by trying to build node itself on the server in question as this should unearth any issues with broken packages (and there are a lot of broken packages out there).
* [.wrap(challenge, [options], [callback])](#KerberosClient+wrap)
Another thing is to ensure your user has write permission to wherever the node modules are being installed.
* [.unwrap(challenge, [callback])](#KerberosClient+unwrap)
<a name="KerberosClient+step"></a>
### *kerberosClient*.step(challenge, [callback])
| Param | Type | Description |
| --- | --- | --- |
| challenge | <code>string</code> | A string containing the base64-encoded server data (which may be empty for the first step) |
| [callback] | <code>function</code> | |
Processes a single kerberos client-side step using the supplied server challenge.
**Returns**: <code>Promise</code> - returns Promise if no callback passed
<a name="KerberosClient+wrap"></a>
### *kerberosClient*.wrap(challenge, [options], [callback])
| Param | Type | Description |
| --- | --- | --- |
| challenge | <code>string</code> | The response returned after calling `unwrap` |
| [options] | <code>object</code> | Optional settings |
| [options.user] | <code>string</code> | The user to authorize |
| [callback] | <code>function</code> | |
Perform the client side kerberos wrap step.
**Returns**: <code>Promise</code> - returns Promise if no callback passed
<a name="KerberosClient+unwrap"></a>
### *kerberosClient*.unwrap(challenge, [callback])
| Param | Type | Description |
| --- | --- | --- |
| challenge | <code>string</code> | A string containing the base64-encoded server data |
| [callback] | <code>function</code> | |
Perform the client side kerberos unwrap step
**Returns**: <code>Promise</code> - returns Promise if no callback passed
<a name="KerberosServer"></a>
## KerberosServer
<a name="KerberosServer+step"></a>
### *kerberosServer*.step(challenge, callback)
| Param | Type | Description |
| --- | --- | --- |
| challenge | <code>string</code> | A string containing the base64-encoded client data |
| callback | <code>function</code> | |
Processes a single kerberos server-side step using the supplied client data.
**Returns**: <code>Promise</code> - returns Promise if no callback passed
<a name="checkPassword"></a>
## checkPassword(username, password, service, [defaultRealm], [callback])
| Param | Type | Description |
| --- | --- | --- |
| username | <code>string</code> | The Kerberos user name. If no realm is supplied, then the `defaultRealm` will be used. |
| password | <code>string</code> | The password for the user. |
| service | <code>string</code> | The Kerberos service to check access for. |
| [defaultRealm] | <code>string</code> | The default realm to use if one is not supplied in the user argument. |
| [callback] | <code>function</code> | |
This function provides a simple way to verify that a user name and password
match those normally used for Kerberos authentication.
It does this by checking that the supplied user name and password can be
used to get a ticket for the supplied service.
If the user name does not contain a realm, then the default realm supplied
is used.
For this to work properly the Kerberos must be configured properly on this
machine.
That will likely mean ensuring that the edu.mit.Kerberos preference file
has the correct realms and KDCs listed.
IMPORTANT: This method is vulnerable to KDC spoofing attacks and it should
only be used for testing. Do not use this in any production system - your
security could be compromised if you do.
**Returns**: <code>Promise</code> - returns Promise if no callback passed
<a name="principalDetails"></a>
## principalDetails(service, hostname, [callback])
| Param | Type | Description |
| --- | --- | --- |
| service | <code>string</code> | The Kerberos service type for the server. |
| hostname | <code>string</code> | The hostname of the server. |
| [callback] | <code>function</code> | |
This function returns the service principal for the server given a service type and hostname.
Details are looked up via the `/etc/keytab` file.
**Returns**: <code>Promise</code> - returns Promise if no callback passed
<a name="initializeClient"></a>
## initializeClient(service, [options], [callback])
| Param | Type | Description |
| --- | --- | --- |
| service | <code>string</code> | A string containing the service principal in the form 'type@fqdn' (e.g. 'imap@mail.apple.com'). |
| [options] | <code>object</code> | Optional settings |
| [options.principal] | <code>string</code> | Optional string containing the client principal in the form 'user@realm' (e.g. 'jdoe@example.com'). |
| [options.gssFlags] | <code>number</code> | Optional integer used to set GSS flags. (e.g. GSS_C_DELEG_FLAG|GSS_C_MUTUAL_FLAG|GSS_C_SEQUENCE_FLAG will allow for forwarding credentials to the remote host) |
| [options.mechOID] | <code>number</code> | Optional GSS mech OID. Defaults to None (GSS_C_NO_OID). Other possible values are `GSS_MECH_OID_KRB5`, `GSS_MECH_OID_SPNEGO`. |
| [callback] | <code>function</code> | |
Initializes a context for client-side authentication with the given service principal.
**Returns**: <code>Promise</code> - returns Promise if no callback passed
<a name="initializeServer"></a>
## initializeServer(service, [callback])
| Param | Type | Description |
| --- | --- | --- |
| service | <code>string</code> | A string containing the service principal in the form 'type@fqdn' (e.g. 'imap@mail.apple.com'). |
| [callback] | <code>function</code> | |
Initializes a context for server-side authentication with the given service principal.
**Returns**: <code>Promise</code> - returns Promise if no callback passed

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc