Skip to content

Commit

Permalink
feat(async-worker): introduce a KerberosWorker using lambdas
Browse files Browse the repository at this point in the history
This allows us to signifcantly reduce the amount of boilerplate
required for async workers, by replacing the implementation with
a single lambda. This should also make it much easier to split up
implementation from definition in order to support both unix and
windows implementations.
  • Loading branch information
mbroadst committed Jul 9, 2018
1 parent a110868 commit 1239ef7
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 31 deletions.
4 changes: 4 additions & 0 deletions src/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
#include "kerberos_gss.h"

// Provide a default custom delter for the `gss_result` type
inline void ResultDeleter(gss_result* result) {
free(result);
}

struct FreeDeleter {
void operator()(void* result) {
free(result);
Expand Down
47 changes: 16 additions & 31 deletions src/kerberos.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "kerberos.h"
#include "kerberos_client.h"
#include "kerberos_server.h"
#include "kerberos_worker.h"

using v8::FunctionTemplate;

Expand Down Expand Up @@ -159,44 +160,28 @@ NAN_METHOD(PrincipalDetails) {
AsyncQueueWorker(new PrincipalDetailsWorker(service, hostname, callback));
}

class CheckPasswordWorker : public Nan::AsyncWorker {
public:
CheckPasswordWorker(std::string username,
std::string password,
std::string service,
std::string defaultRealm,
Nan::Callback* callback)
: AsyncWorker(callback, "kerberos:CheckPassword"),
_username(username),
_password(password),
_service(service),
_defaultRealm(defaultRealm) {}

virtual void Execute() {
std::unique_ptr<gss_result, FreeDeleter> result(authenticate_user_krb5pwd(
_username.c_str(), _password.c_str(), _service.c_str(), _defaultRealm.c_str()));

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

private:
std::string _username;
std::string _password;
std::string _service;
std::string _defaultRealm;
};

NAN_METHOD(CheckPassword) {
std::string username(*Nan::Utf8String(info[0]));
std::string password(*Nan::Utf8String(info[1]));
std::string service(*Nan::Utf8String(info[2]));
std::string defaultRealm(*Nan::Utf8String(info[3]));
Nan::Callback* callback = new Nan::Callback(Nan::To<v8::Function>(info[4]).ToLocalChecked());

AsyncQueueWorker(new CheckPasswordWorker(username, password, service, defaultRealm, callback));
KerberosWorker::Run(callback, "kerberos:CheckPassword", [=](KerberosWorker::SetOnFinishedHandler onFinished) {
std::shared_ptr<gss_result> result(authenticate_user_krb5pwd(
username.c_str(), password.c_str(), service.c_str(), defaultRealm.c_str()), ResultDeleter);

return onFinished([=](KerberosWorker* worker) {
Nan::HandleScope scope;
if (result->code == AUTH_GSS_ERROR) {
v8::Local<v8::Value> argv[] = {Nan::New(result->message).ToLocalChecked(), Nan::Null()};
worker->Call(2, argv);
} else {
v8::Local<v8::Value> argv[] = {Nan::Null(), Nan::Null()};
worker->Call(2, argv);
}
});
});
}

NAN_MODULE_INIT(Init) {
Expand Down
48 changes: 48 additions & 0 deletions src/kerberos_worker.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#ifndef ASYNC_WORKER_H
#define ASYNC_WORKER_H

#include <functional>
#include <nan.h>

class KerberosWorker : public Nan::AsyncWorker {
public:
typedef std::function<void(KerberosWorker*)> OnFinishedHandler;
typedef std::function<void(OnFinishedHandler)> SetOnFinishedHandler;
typedef std::function<void(SetOnFinishedHandler)> ExecuteHandler;

explicit KerberosWorker(Nan::Callback *callback, const char* resource_name, ExecuteHandler handler)
: Nan::AsyncWorker(callback, resource_name), execute_handler(handler) {}

template <class... T>
void Call(T... t) {
callback->Call(t..., async_resource);
}

virtual void Execute() {
execute_handler([=] (OnFinishedHandler handler) {
on_finished_handler = handler;
});
}

static void Run(Nan::Callback *callback, const char* resource_name, ExecuteHandler handler) {
Nan::TryCatch tryCatch;
if (tryCatch.HasCaught()) {
tryCatch.ReThrow();
return; // don't proceed in case there were any previous errors
}

auto worker = new KerberosWorker(callback, resource_name, handler);
Nan::AsyncQueueWorker(worker);
}

protected:
void HandleOKCallback() {
on_finished_handler(this);
}

private:
ExecuteHandler execute_handler;
OnFinishedHandler on_finished_handler;
};

#endif // ASYNC_WORKER_H

0 comments on commit 1239ef7

Please sign in to comment.