Skip to content

Commit

Permalink
feat(NODE-6333): Allow callers to specify the 'protect' flag (#198)
Browse files Browse the repository at this point in the history
Co-authored-by: Michael Johns <michael.johns@apiture.com>
Co-authored-by: Bailey Pearson <bailey.pearson@mongodb.com>
Co-authored-by: Durran Jordan <durran@gmail.com>
Co-authored-by: Bailey Pearson <bailey.pearson@gmail.com>
  • Loading branch information
5 people authored Sep 5, 2024
1 parent 281d076 commit 515f4bf
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 3 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ Processes a single kerberos client-side step using the supplied server challenge
| 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 |
| [options.protect] | <code>boolean</code> | Indicates if the wrap should request message confidentiality |
| [callback] | <code>function</code> | |

Perform the client side kerberos wrap step.
Expand Down
1 change: 1 addition & 0 deletions lib/kerberos.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down
11 changes: 11 additions & 0 deletions src/kerberos.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,17 @@ std::string ToStringWithNonStringAsEmpty(Napi::Value value) {
return value.As<String>();
}

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<Boolean>();
return protect ? 1 : 0;
}

Function KerberosClient::Init(Napi::Env env) {
return
DefineClass(env,
Expand Down
2 changes: 2 additions & 0 deletions src/kerberos.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ class KerberosClient : public Napi::ObjectWrap<KerberosClient> {
void UnwrapData(const Napi::CallbackInfo& info);
void WrapData(const Napi::CallbackInfo& info);

int ParseWrapOptionsProtect(const Napi::Object& options);

private:
friend class Napi::ObjectWrap<KerberosClient>;
explicit KerberosClient(const Napi::CallbackInfo& info);
Expand Down
3 changes: 1 addition & 2 deletions src/unix/kerberos_unix.cc
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,7 @@ void KerberosClient::WrapData(const CallbackInfo& info) {
Object options = info[1].ToObject();
Function callback = info[2].As<Function>();
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(
Expand Down
2 changes: 1 addition & 1 deletion src/win32/kerberos_win32.cc
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ void KerberosClient::WrapData(const CallbackInfo& info) {
Object options = info[1].ToObject();
Function callback = info[2].As<Function>();
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");
Expand Down
47 changes: 47 additions & 0 deletions test/kerberos_tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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/);
});
});
});
});
});

0 comments on commit 515f4bf

Please sign in to comment.