Skip to content

Commit

Permalink
Merge pull request #1317 from jeremy-w/jeremy-w/feat/login-with-utf8-…
Browse files Browse the repository at this point in the history
…option-1143
  • Loading branch information
arthurschreiber authored Aug 29, 2021
2 parents 1189b4a + 6f4a270 commit fac4e6e
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 13 deletions.
4 changes: 2 additions & 2 deletions src/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3603,10 +3603,10 @@ Connection.prototype.STATE = {
this.loginError = ConnectionError(`Active Directory authentication acknowledgment for ${authentication.type} authentication method includes extra data`);
this.loggedIn = false;
}
} else if (token.fedAuth === undefined) {
} else if (token.fedAuth === undefined && token.utf8Support === undefined) {
this.loginError = ConnectionError('Received acknowledgement for unknown feature');
this.loggedIn = false;
} else {
} else if (token.fedAuth) {
this.loginError = ConnectionError('Did not request Active Directory authentication, but received the acknowledgment');
this.loggedIn = false;
}
Expand Down
12 changes: 12 additions & 0 deletions src/login7-payload.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { sprintf } from 'sprintf-js';
import { versions } from './tds-versions';

const FLAGS_1 = {
ENDIAN_LITTLE: 0x00,
Expand Down Expand Up @@ -411,6 +412,17 @@ class Login7Payload {
}
}

if (this.tdsVersion >= versions['7_4']) {
// Signal UTF-8 support: Value 0x0A, bit 0 must be set to 1. Added in TDS 7.4.
const UTF8_SUPPORT_FEATURE_ID = 0x0a;
const UTF8_SUPPORT_CLIENT_SUPPORTS_UTF8 = 0x01;
const buf = Buffer.alloc(6);
buf.writeUInt8(UTF8_SUPPORT_FEATURE_ID, 0);
buf.writeUInt32LE(1, 1);
buf.writeUInt8(UTF8_SUPPORT_CLIENT_SUPPORTS_UTF8, 5);
buffers.push(buf);
}

buffers.push(Buffer.from([FEATURE_EXT_TERMINATOR]));

return Buffer.concat(buffers);
Expand Down
14 changes: 10 additions & 4 deletions src/token/feature-ext-ack-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,30 @@ const FEATURE_ID = {
COLUMNENCRYPTION: 0x04,
GLOBALTRANSACTIONS: 0x05,
AZURESQLSUPPORT: 0x08,
UTF8_SUPPORT: 0x0A,
TERMINATOR: 0xFF
};

function featureExtAckParser(parser: Parser, _options: InternalConnectionOptions, callback: (token: FeatureExtAckToken) => void) {
let fedAuth: Buffer | undefined;
let utf8Support: boolean | undefined;

function next() {
parser.readUInt8((featureId) => {
if (featureId === FEATURE_ID.TERMINATOR) {
return callback(new FeatureExtAckToken(fedAuth));
return callback(new FeatureExtAckToken(fedAuth, utf8Support));
}

parser.readUInt32LE((featureAckDataLen) => {
parser.readBuffer(featureAckDataLen, (featureData) => {
if (featureId === FEATURE_ID.FEDAUTH) {
fedAuth = featureData;
switch (featureId) {
case FEATURE_ID.FEDAUTH:
fedAuth = featureData;
break;
case FEATURE_ID.UTF8_SUPPORT:
utf8Support = !!featureData[0];
break;
}

next();
});
});
Expand Down
8 changes: 7 additions & 1 deletion src/token/token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -317,10 +317,16 @@ export class FeatureExtAckToken extends Token {

fedAuth: Buffer | undefined;

constructor(fedAuth: Buffer | undefined) {
/** Value of UTF8_SUPPORT acknowledgement.
*
* undefined when UTF8_SUPPORT not included in token. */
utf8Support: boolean | undefined;

constructor(fedAuth: Buffer | undefined, utf8Support: boolean | undefined) {
super('FEATUREEXTACK', 'featureExtAck');

this.fedAuth = fedAuth;
this.utf8Support = utf8Support;
}
}

Expand Down
4 changes: 2 additions & 2 deletions test/unit/login7-payload-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ describe('Login7Payload', function() {
describe('for a login payload with active directory authentication', function() {
it('generates the expected data', function() {
const payload = new Login7Payload({
tdsVersion: 0x72090002,
tdsVersion: 0x74000004,
packetSize: 1024,
clientProgVer: 0,
clientPid: 12345,
Expand Down Expand Up @@ -175,7 +175,7 @@ describe('Login7Payload', function() {
2 + 2 + (2 * payload.changePassword.length) +
4 + // cbSSPILong
4 + // Extension offset
1 + 1 + 4 + 1 + 1; // Feature ext
1 + (1 + 4 + 1) + (1 + 4 + 1) + 1; // Feature ext - v7.4 includes UTF8_SUPPORT unlike prior versions

assert.lengthOf(data, expectedLength);
});
Expand Down
30 changes: 26 additions & 4 deletions test/unit/token/feature-ext-parser-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@ const StreamParser = require('../../../src/token/stream-parser');
const WritableTrackingBuffer = require('../../../src/tracking-buffer/writable-tracking-buffer');
const assert = require('chai').assert;

describe('Feature Ext Praser', () => {
describe('Feature Ext Parser', () => {
it('should be fed authentication', async () => {
const buffer = new WritableTrackingBuffer(50, 'ucs2');

buffer.writeUInt8(0xAE); // FEATUREEXTACK token header

buffer.writeUInt8(0x01);
buffer.writeUInt8(0x01); // SESSIONRECOVERY
buffer.writeUInt32LE(1);
buffer.writeBuffer(Buffer.from('a'));

buffer.writeUInt8(0x02);
buffer.writeUInt8(0x02); // FEDAUTH
buffer.writeUInt32LE(2);
buffer.writeBuffer(Buffer.from('bc'));

buffer.writeUInt8(0x03);
buffer.writeUInt8(0x03); // made-up feature ext
buffer.writeUInt32LE(0);
buffer.writeBuffer(Buffer.from(''));

Expand All @@ -27,6 +27,28 @@ describe('Feature Ext Praser', () => {
assert.isFalse(result.done);
const token = result.value;
assert.isOk(token.fedAuth.equals(Buffer.from('bc')));
assert.isUndefined(token.utf8Support); // feature ext ack for UTF8_SUPPORT was not received
assert.isTrue((await parser.next()).done);
});

it('should parse UTF-8 support token', async () => {
const buffer = new WritableTrackingBuffer(8);

buffer.writeUInt8(0xAE); // FEATUREEXTACK token header
buffer.writeUInt8(0x0A); // UTF8_SUPPORT feature id
buffer.writeUInt32LE(0x00_00_00_01); // datalen
buffer.writeUInt8(0x01); // supported

buffer.writeUInt8(0xFF); // TERMINATOR

const parser = StreamParser.parseTokens([buffer.data], {}, {});
const result = await parser.next();
assert.isFalse(result.done);

const token = result.value;
assert.strictEqual(token.utf8Support, true); // feature ext ack for UTF8_SUPPORT was positive
assert.isUndefined(token.fedAuth); // fed auth not ack'd

assert.isTrue((await parser.next()).done);
});
});

0 comments on commit fac4e6e

Please sign in to comment.