diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 5b3271b0..4b4ca848 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -68,7 +68,6 @@ functions: PROJECT_DIRECTORY: ${PROJECT_DIRECTORY} PROJECT: ${project} GYP_DEFINES: ${GYP_DEFINES|} - NPM_OPTIONS: ${NPM_OPTIONS|} args: - run - '--interactive' @@ -80,8 +79,6 @@ functions: - PROJECT_DIRECTORY=/app - '--env' - GYP_DEFINES - - '--env' - - NPM_OPTIONS - 'ubuntu:22.04' - /bin/bash - /app/.evergreen/run-tests-ubuntu.sh @@ -125,7 +122,6 @@ tasks: - func: run tests ubuntu vars: GYP_DEFINES: kerberos_use_rtld=false - NPM_OPTIONS: --build-from-source - name: run-prebuild commands: - func: install dependencies diff --git a/.evergreen/install-dependencies.sh b/.evergreen/install-dependencies.sh index ac6673ec..0b5fc2b6 100644 --- a/.evergreen/install-dependencies.sh +++ b/.evergreen/install-dependencies.sh @@ -104,5 +104,5 @@ fi echo "npm location: $(which npm)" echo "npm version: $(npm -v)" -npm install "${NPM_OPTIONS}" --build-from-source +npm install --build-from-source ldd build/*/kerberos.node || true diff --git a/README.md b/README.md index 321dad0c..8c1fb361 100644 --- a/README.md +++ b/README.md @@ -182,6 +182,7 @@ Processes a single kerberos client-side step using the supplied server challenge | challenge | string | The response returned after calling `unwrap` | | [options] | object | Optional settings | | [options.user] | string | The user to authorize | +| [options.protect] | boolean | Indicates if the wrap should request message confidentiality | | [callback] | function | | Perform the client side kerberos wrap step. diff --git a/lib/kerberos.js b/lib/kerberos.js index 09f8425f..f203d891 100644 --- a/lib/kerberos.js +++ b/lib/kerberos.js @@ -52,6 +52,7 @@ KerberosClient.prototype.step = defineOperation(KerberosClient.prototype.step, [ * @param {string} challenge The response returned after calling `unwrap` * @param {object} [options] Optional settings * @param {string} [options.user] The user to authorize + * @param {boolean} [options.protect] Indicates if the wrap should request message confidentiality * @param {function} [callback] * @return {Promise} returns Promise if no callback passed */ diff --git a/src/kerberos.cc b/src/kerberos.cc index 7a760423..a79dfdd4 100644 --- a/src/kerberos.cc +++ b/src/kerberos.cc @@ -37,6 +37,17 @@ std::string ToStringWithNonStringAsEmpty(Napi::Value value) { return value.As(); } +int KerberosClient::ParseWrapOptionsProtect(const Napi::Object& options) { + if (!options.Has("protect")) return 0; + + if (!options.Get("protect").IsBoolean()) { + throw TypeError::New(options.Env(), "options.protect must be a boolean."); + } + + bool protect = options.Get("protect").As(); + return protect ? 1 : 0; +} + Function KerberosClient::Init(Napi::Env env) { return DefineClass(env, diff --git a/src/kerberos.h b/src/kerberos.h index 7f1c2096..deec6e33 100644 --- a/src/kerberos.h +++ b/src/kerberos.h @@ -55,6 +55,8 @@ class KerberosClient : public Napi::ObjectWrap { void UnwrapData(const Napi::CallbackInfo& info); void WrapData(const Napi::CallbackInfo& info); + int ParseWrapOptionsProtect(const Napi::Object& options); + private: friend class Napi::ObjectWrap; explicit KerberosClient(const Napi::CallbackInfo& info); diff --git a/src/unix/kerberos_unix.cc b/src/unix/kerberos_unix.cc index 57a67ae8..fafa937b 100644 --- a/src/unix/kerberos_unix.cc +++ b/src/unix/kerberos_unix.cc @@ -74,8 +74,7 @@ void KerberosClient::WrapData(const CallbackInfo& info) { Object options = info[1].ToObject(); Function callback = info[2].As(); std::string user = ToStringWithNonStringAsEmpty(options["user"]); - - int protect = 0; // NOTE: this should be an option + int protect = ParseWrapOptionsProtect(options); KerberosWorker::Run(callback, "kerberos:ClientWrap", [=](KerberosWorker::SetOnFinishedHandler onFinished) { gss_result result = authenticate_gss_client_wrap( diff --git a/src/win32/kerberos_win32.cc b/src/win32/kerberos_win32.cc index aa653d43..21977799 100644 --- a/src/win32/kerberos_win32.cc +++ b/src/win32/kerberos_win32.cc @@ -92,7 +92,7 @@ void KerberosClient::WrapData(const CallbackInfo& info) { Object options = info[1].ToObject(); Function callback = info[2].As(); std::string user = ToStringWithNonStringAsEmpty(options["user"]); - int protect = 0; // NOTE: this should be an option + int protect = ParseWrapOptionsProtect(options); if (isStringTooLong(user)) { throw Error::New(info.Env(), "User name is too long"); diff --git a/test/kerberos_tests.js b/test/kerberos_tests.js index 18263bff..4be9de67 100644 --- a/test/kerberos_tests.js +++ b/test/kerberos_tests.js @@ -4,6 +4,7 @@ const request = require('request'); const chai = require('chai'); const expect = chai.expect; const os = require('os'); +const { test } = require('mocha'); chai.use(require('chai-string')); // environment variables @@ -122,4 +123,50 @@ describe('Kerberos', function () { }); }); }); + + describe('Client.wrap()', function () { + async function establishConext() { + const service = `HTTP@${hostname}`; + client = await kerberos.initializeClient(service, {}); + server = await kerberos.initializeServer(service); + const clientResponse = await client.step(''); + const serverResponse = await server.step(clientResponse); + await client.step(serverResponse); + expect(client.contextComplete).to.be.true; + return { client, server }; + } + + let client; + let server; + + before(establishConext); + describe('options.protect', function () { + context('valid values for `protect`', function () { + test('no options provided', async function () { + await client.wrap('challenge'); + }); + + test('options provided (protect omitted)', async function () { + await client.wrap('challenge', {}); + }); + + test('protect = false', async function () { + await client.wrap('challenge', { protect: false }); + }); + + test('protect = true', async function () { + await client.wrap('challenge', { protect: true }); + }); + }); + + context('when set to an invalid value', function () { + it('throws a TypeError', async function () { + const error = await client.wrap('challenge', { protect: 'non-boolean' }).catch(e => e); + expect(error) + .to.be.instanceOf(TypeError) + .to.match(/options.protect must be a boolean/); + }); + }); + }); + }); });