Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kerberos support for node-postgres #3267

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add tests
albertchang committed Sep 27, 2024
commit e2316805dd337c50d14f6987fae21fc9cf252356
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -10,3 +10,4 @@ dist
/.eslintcache
.vscode/
manually-test-on-heroku.js
.idea/
13 changes: 13 additions & 0 deletions packages/pg-protocol/src/inbound-parser.test.ts
Original file line number Diff line number Diff line change
@@ -178,6 +178,8 @@ var md5PasswordBuffer = buffers.authenticationMD5Password()
var SASLBuffer = buffers.authenticationSASL()
var SASLContinueBuffer = buffers.authenticationSASLContinue()
var SASLFinalBuffer = buffers.authenticationSASLFinal()
var GSSInitBuffer = buffers.authenticationGSSInit()
var GSSContinueBuffer = buffers.authenticationGSSContinue()

var expectedPlainPasswordMessage = {
name: 'authenticationCleartextPassword',
@@ -203,6 +205,15 @@ var expectedSASLFinalMessage = {
data: 'data',
}

var expectedGSSInitMessage = {
name: 'GSSInit',
}

var expectedGSSContinueMessage = {
name: 'GSSContinue',
inToken: btoa('data'),
}

var notificationResponseBuffer = buffers.notification(4, 'hi', 'boom')
var expectedNotificationResponseMessage = {
name: 'notification',
@@ -228,6 +239,8 @@ describe('PgPacketStream', function () {
testForMessage(md5PasswordBuffer, expectedMD5PasswordMessage)
testForMessage(SASLBuffer, expectedSASLMessage)
testForMessage(SASLContinueBuffer, expectedSASLContinueMessage)
testForMessage(GSSInitBuffer, expectedGSSInitMessage)
testForMessage(GSSContinueBuffer, expectedGSSContinueMessage)

// this exercises a found bug in the parser:
// https://github.com/brianc/node-postgres/pull/2210#issuecomment-627626084
8 changes: 8 additions & 0 deletions packages/pg-protocol/src/outbound-serializer.test.ts
Original file line number Diff line number Diff line change
@@ -264,6 +264,14 @@ describe('serializer', () => {
})
})

describe('send binary password', function () {
it('builds sendBinaryPassword', () => {
const actual = serialize.sendBinaryPassword(Buffer.from([1, 2, 3]))
const expected = new BufferList().add(Buffer.from([1, 2, 3])).join(true, 'p')
assert.deepEqual(actual, expected)
})
})

it('builds cancel message', () => {
const actual = serialize.cancel(3, 4)
const expected = new BufferList().addInt16(1234).addInt16(5678).addInt32(3).addInt32(4).join(true)
8 changes: 8 additions & 0 deletions packages/pg-protocol/src/testing/test-buffers.ts
Original file line number Diff line number Diff line change
@@ -21,6 +21,14 @@ const buffers = {
.join(true, 'R')
},

authenticationGSSInit: function () {
return new BufferList().addInt32(7).join(true, 'R')
},

authenticationGSSContinue: function () {
return new BufferList().addInt32(8).addString('data').join(true, 'R')
},

authenticationSASL: function () {
return new BufferList().addInt32(10).addCString('SCRAM-SHA-256').addCString('').join(true, 'R')
},
7 changes: 3 additions & 4 deletions packages/pg/lib/client.js
Original file line number Diff line number Diff line change
@@ -179,7 +179,6 @@ class Client extends EventEmitter {
// kerberos
con.on('GSSInit', this._handleGSSInit.bind(this))
con.on('GSSContinue', this._handleGSSContinue.bind(this))

// password request handling
con.on('authenticationCleartextPassword', this._handleAuthCleartextPassword.bind(this))
// password request handling
@@ -206,12 +205,12 @@ class Client extends EventEmitter {

async _handleGSSInit(msg) {
try {
this.client = await kerberos.initializeClient(`${this.principal}@${this.host}`, {
this.kclient = await kerberos.initializeClient(`${this.principal}@${this.host}`, {
mechOID: kerberos.GSS_MECH_OID_SPNEGO,
})

// TODO: below this might need to be a recursive loop to step multiple times.
const token = await this.client.step('')
const token = await this.kclient.step('')

const buf = Buffer.from(token, 'base64')
this.connection.sendBinaryPassword(buf)
@@ -223,7 +222,7 @@ class Client extends EventEmitter {
async _handleGSSContinue(msg) {
try {
const inToken = msg.inToken
const token = await this.client.step(inToken)
const token = await this.kclient.step(inToken)

// TODO: probably a better way to handle this.
if (token == null) {
Original file line number Diff line number Diff line change
@@ -83,6 +83,7 @@ suite.test('ConnectionParameters initializing from config', function () {
lock_timeout: 15000,
idle_in_transaction_session_timeout: 15000,
options: '-c geqo=off',
principal: 'postgres',
}
var subject = new ConnectionParameters(config)
compare(subject, config, 'config')
Original file line number Diff line number Diff line change
@@ -28,13 +28,15 @@ suite.test('ConnectionParameters initialized from environment variables', functi
process.env['PGPORT'] = 7890
process.env['PGDATABASE'] = 'allyerbase'
process.env['PGPASSWORD'] = 'open'
process.env['PGPRINCIPAL'] = 'postgres'

var subject = new ConnectionParameters()
assert.equal(subject.host, 'local', 'env host')
assert.equal(subject.user, 'bmc2', 'env user')
assert.equal(subject.port, 7890, 'env port')
assert.equal(subject.database, 'allyerbase', 'env database')
assert.equal(subject.password, 'open', 'env password')
assert.equal(subject.principal, 'postgres', 'env principal')
})

suite.test('ConnectionParameters initialized from mix', function () {
@@ -49,12 +51,14 @@ suite.test('ConnectionParameters initialized from mix', function () {
var subject = new ConnectionParameters({
user: 'testing',
database: 'zugzug',
principal: 'postgres',
})
assert.equal(subject.host, 'local', 'env host')
assert.equal(subject.user, 'testing', 'config user')
assert.equal(subject.port, 7890, 'env port')
assert.equal(subject.database, 'zugzug', 'config database')
assert.equal(subject.password, defaults.password, 'defaults password')
assert.equal(subject.principal, 'postgres', 'config principal')
})

suite.test('connection string parsing', function () {