Skip to content

Commit

Permalink
feat(serverPrincipalDetails): add server pricipal details method
Browse files Browse the repository at this point in the history
  • Loading branch information
mbroadst committed Jul 8, 2018
1 parent c12a5c4 commit 385fcd1
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 66 deletions.
95 changes: 30 additions & 65 deletions lib/kerberos.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,24 @@ function validateParameter(parameter, spec) {
}
}

/**
* This function returns the service principal for the server given a service
* type and hostname.
*
* Details are looked up via the `/etc/keytab` file.
*
* @param {string} service The Kerberos service type for the server.
* @param {string} hostname The hostname of the server.
* @param {function} callback
*/
function serverPrincipalDetails(service, hostname, callback) {
validateParameter(service, { name: 'service', type: 'string' });
validateParameter(hostname, { name: 'options', type: 'string' });
validateParameter(callback, { name: 'callback', type: 'function' });

kerberos.serverPrincipalDetails(service, hostname, callback);
}

/**
* The callback format for inserts
* @callback authGSSClientInitCallback
Expand All @@ -54,7 +72,7 @@ function validateParameter(parameter, spec) {
* @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 {authGSSClientInitCallback} callback The operation callback
* @param {initializeClientCallback} callback The operation callback
*/
function initializeClient(service, options, callback) {
if (typeof options === 'function') (callback = options), (options = {});
Expand All @@ -74,7 +92,7 @@ function initializeClient(service, options, callback) {
* are complete.
*
* @param {string} service A string containing the service principal in the form 'type@fqdn' (e.g. 'imap@mail.apple.com').
* @param {function} callback
* @param {initializeServerCallback} callback
*/
function initializeServer(service, callback) {
validateParameter(service, { name: 'service', type: 'string' });
Expand All @@ -83,105 +101,50 @@ function initializeServer(service, callback) {
kerberos.initializeServer(service, callback);
}

/**
* Destroys the context for GSSAPI client-side authentication.
*
* @param {KerberosContext} context The context object returned from `authGSSClientInit`
* @param {function} callback
*/
// function authGSSClientClean(context, callback) {
// validateParameter(context, { name: 'context', type: 'object' });
// validateParameter(callback, { name: 'callback', type: 'function' });

// kerberos.authGSSClientClean(context, callback);
// }

/**
* Processes a single GSSAPI client-side step using the supplied server data.
*
* @param {KerberosContext} context The context object returned from `authGSSClientInit`
* @memberof KerberosClient
* @param {string} challenge A string containing the base64-encoded server data (which may be empty for the first step)
* @param {function} callback Returns a result code, or an error if one was encountered
*/
// function authGSSClientStep(context, challenge, callback) {
// validateParameter(context, { name: 'context', type: 'object' });
// validateParameter(challenge, { name: 'challenge', type: 'string' });
// validateParameter(callback, { name: 'callback', type: 'function' });

// kerberos.authGSSClientStep(context, challenge, callback);
// }

/**
* Perform the client side GSSAPI unwrap step
*
* @param {KerberosContext} context The context object returned from `authGSSClientInit`
* @memberof KerberosClient
* @param {string} challenge A string containing the base64-encoded server data
* @param {function} callback
*/
// function authGSSClientUnwrap(context, challenge, callback) {
// validateParameter(context, { name: 'context', type: 'object' });
// validateParameter(challenge, { name: 'challenge', type: 'string' });
// validateParameter(callback, { name: 'callback', type: 'function' });

// kerberos.authGSSClientUnwrap(context, challenge, callback);
// }

/**
* Perform the client side GSSAPI wrap step.
*
* @param {KerberosContext} context The context object returned from `authGSSClientInit`
* @memberof KerberosClient
* @param {string} challenge The result of the `authGSSClientResponse` after the `authGSSClientUnwrap`
* @param {object} [options] Optional settings
* @param {string} [options.user] The user to authorize
* @param {function} callback
*/
// function authGSSClientWrap(context, challenge, options, callback) {
// if (typeof options === 'function') (callback = options), (options = {});
// options = options || {};

// validateParameter(context, { name: 'context', type: 'object' });
// validateParameter(challenge, { name: 'challenge', type: 'string' });
// validateParameter(options, { name: 'options', type: 'object' });
// validateParameter(callback, { name: 'callback', type: 'function' });

// kerberos.authGSSClientWrap(context, challenge, options, callback);
// }

/**
* Destroys the context for GSSAPI server-side authentication.
*
* @param {KerberosContext} context The context object returned from `authGSSServerInit`
* @param {function} callback
*/
// function authGSSServerClean(context, callback) {
// validateParameter(context, { name: 'context', type: 'object' });
// validateParameter(callback, { name: 'callback', type: 'function' });

// kerberos.authGSSServerClean(context, callback);
// }

/**
* Processes a single GSSAPI server-side step using the supplied client data.
*
* @param {KerberosContext} context The context object returned from `authGSSServerInit`
* @memberof KerberosServer
* @param {string} challenge A string containing the base64-encoded client data
* @param {function} callback
*/
// function authGSSServerStep(context, challenge, callback) {

This comment has been minimized.

Copy link
@justknife

justknife Mar 18, 2021

please explain how this function looks now

// validateParameter(context, { name: 'context', type: 'object' });
// validateParameter(challenge, { name: 'challenge', type: 'string' });
// validateParameter(callback, { name: 'callback', type: 'function' });

// kerberos.authGSSServerStep(context, challenge, callback);
// }

module.exports = {
initializeClient,
initializeServer,
serverPrincipalDetails,

// Constants
// result codes
AUTH_GSS_CONTINUE,
AUTH_GSS_COMPLETE,

// gss flags
GSS_C_DELEG_FLAG,
GSS_C_MUTUAL_FLAG,
GSS_C_REPLAY_FLAG,
Expand All @@ -192,6 +155,8 @@ module.exports = {
GSS_C_PROT_READY_FLAG,
GSS_C_TRANS_FLAG,
GSS_C_NO_OID,

// mechanism OIDs
GSS_MECH_OID_KRB5,
GSS_MECH_OID_SPNEGO
};
44 changes: 44 additions & 0 deletions src/kerberos.cc
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,48 @@ NAN_METHOD(InitializeServer) {
AsyncQueueWorker(new InitializeServerWorker(service, callback));
}

class ServerPrincipalDetailsWorker : public Nan::AsyncWorker {
public:
ServerPrincipalDetailsWorker(std::string service, std::string hostname, Nan::Callback *callback)
: AsyncWorker(callback, "kerberos:ServerPrincipalDetails"),
_service(service),
_hostname(hostname)
{}

virtual void Execute() {
std::unique_ptr<gss_result, FreeDeleter> result(
server_principal_details(_service.c_str(), _hostname.c_str()));

if (result->code == AUTH_GSS_ERROR) {
SetErrorMessage(result->message);
return;
}

_details = std::string(result->data);
}

protected:
virtual void HandleOKCallback() {
Nan::HandleScope scope;
v8::Local<v8::Value> argv[] = { Nan::Null(), Nan::New(_details).ToLocalChecked() };
callback->Call(2, argv, async_resource);
}

private:
std::string _service;
std::string _hostname;
std::string _details;

};

NAN_METHOD(ServerPrincipalDetails) {
std::string service(*Nan::Utf8String(info[0]));
std::string hostname(*Nan::Utf8String(info[1]));
Nan::Callback* callback = new Nan::Callback(Nan::To<v8::Function>(info[2]).ToLocalChecked());

AsyncQueueWorker(new ServerPrincipalDetailsWorker(service, hostname, callback));
}

NAN_MODULE_INIT(Init) {
// Custom types
KerberosClient::Init(target);
Expand All @@ -124,6 +166,8 @@ NAN_MODULE_INIT(Init) {
Nan::GetFunction(Nan::New<FunctionTemplate>(InitializeClient)).ToLocalChecked());
Nan::Set(target, Nan::New("initializeServer").ToLocalChecked(),
Nan::GetFunction(Nan::New<FunctionTemplate>(InitializeServer)).ToLocalChecked());
Nan::Set(target, Nan::New("serverPrincipalDetails").ToLocalChecked(),
Nan::GetFunction(Nan::New<FunctionTemplate>(ServerPrincipalDetails)).ToLocalChecked());
}

NODE_MODULE(kerberos, Init)
1 change: 1 addition & 0 deletions src/kerberos.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include <nan.h>

NAN_METHOD(ServerPrincipalDetails);
NAN_METHOD(InitializeClient);
NAN_METHOD(InitializeServer);

Expand Down
4 changes: 3 additions & 1 deletion src/kerberos_gss.cc
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,13 @@ gss_result* server_principal_details(const char* service, const char* hostname)
}

if (details == NULL)
{
result = gss_error_result_with_message_and_code("Principal not found in keytab", -1);
}
else
{
result = gss_success_result(AUTH_GSS_COMPLETE);
result->message = details;
result->data = details;
}
end:
if (cursor)
Expand Down
9 changes: 9 additions & 0 deletions test/kerberos_tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ const hostname = process.env.KERBEROS_HOSTNAME || 'hostname.example.com';
const port = process.env.KERBEROS_PORT || '80';

describe('Kerberos', function() {
it('should lookup principal details on a server', function(done) {
const expected = `HTTP/${hostname}@${realm.toUpperCase()}`;
kerberos.serverPrincipalDetails('HTTP', hostname, (err, details) => {
expect(err).to.not.exist;
expect(details).to.equal(expected);
done();
});
});

it('should authenticate against a kerberos server using GSSAPI', function(done) {
const service = `HTTP@${hostname}`;

Expand Down

0 comments on commit 385fcd1

Please sign in to comment.