Support GSSAPI Authentication/encryption
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 8.7k
- Forks
- 374
- Avg merge
- 11d 16h
- Merged PRs (30d)
- 1
Description
Postgres supports authentication and optionally encryption using GSSAPI, allowing authentication using Kerberos, SSPI and the like. I'm currently trying to create a PR using https://www.npmjs.com/package/kerberos which is used by mongodb-js, and poking around it seems like it should be possible to implement, though I've run into a bit of a roadblock when it comes to sending raw bytes as required by the GSSAPI authentication process.
WIP code diff
Index: src/connection.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/connection.js b/src/connection.js
--- a/src/connection.js (revision 32feb259a3c9abffab761bd1758b3168d9e0cebc)
+++ b/src/connection.js (date 1752946656209)
@@ -11,6 +11,8 @@
import { Query, CLOSE } from './query.js'
import b from './bytes.js'
+import {Kerberos} from "kerberos" // todo: make optional
+
export default Connection
let uid = 1
@@ -18,6 +20,7 @@
const Sync = b().S().end()
, Flush = b().H().end()
, SSLRequest = b().i32(8).i32(80877103).end(8)
+ , GSSRequest = b().i32(8).i32(80877104).end(8)
, ExecuteUnnamed = Buffer.concat([b().E().str(b.N).i32(0).end(), Sync])
, DescribeUnnamed = b().D().str('S').str(b.N).end()
, noop = () => { /* noop */ }
@@ -104,6 +107,8 @@
, nonce = null
, query = null
, final = null
+ , kerberosClient = null
+ , kerberosEncClient = null
const connection = {
queue: queues.closed,
@@ -327,7 +332,6 @@
terminated = false
backendParameters = {}
socket || (socket = await createSocket())
-
if (!socket)
return
@@ -353,7 +357,57 @@
setTimeout(connect, closedDate ? closedDate + delay - performance.now() : 0)
}
- function connected() {
+ async function connectedGss() {
+ let gssToken
+ try {
+ kerberosEncClient = await Kerberos.initializeClient("postgres@" + host)
+ gssToken = await kerberosEncClient.step('')
+ } catch (e) {
+ return false
+ }
+
+ write(GSSRequest)
+ const canGSS = await new Promise(r => socket.once('data', x => r(x[0] === 71))) // G
+ if (!canGSS) {
+ return false
+ }
+ try {
+ while (!kerberosEncClient.contextComplete) {
+ let buffer = Buffer.from(gssToken, 'base64')
+ write(b().raw(buffer).end())
+ let ret = await new Promise(r => socket.once('data', x => r(x)))
+
+ }
+ } catch (e) {
+ console.log(e)
+ return false
+ }
+ const s = StartupMessage()
+ write(s)
+
+ statements = {}
+ needsTypes = options.fetch_types
+ statementId = Math.random().toString(36).slice(2)
+ statementCount = 1
+ lifeTimer.start()
+
+ socket.on('data', data)
+
+ keep_alive && socket.setKeepAlive && socket.setKeepAlive(true, 1000 * keep_alive)
+ }
+
+ async function connected() {
+ if (Kerberos !== null) {
+ try {
+ await connectedGss()
+ } catch (e) {
+ error(e)
+ }
+ }
try {
statements = {}
needsTypes = options.fetch_types
@@ -654,6 +708,8 @@
(
type === 3 ? AuthenticationCleartextPassword :
type === 5 ? AuthenticationMD5Password :
+ Kerberos !== null && type === 7 ? AuthenticationGss :
+ Kerberos !== null && type === 8 ? AuthenticationGssContinue :
type === 10 ? SASL :
type === 11 ? SASLContinue :
type === 12 ? SASLFinal :
@@ -684,6 +740,22 @@
)
}
+ async function AuthenticationGss() {
+ console.assert(Kerberos !== null)
+
+ kerberosClient = await Kerberos.initializeClient("postgres/" + host) //todo
+ b().p().str('GSSAPI' + b.N)
+ const i = b.i
+ write(b.inc(1).str('p=' + kerberosClient.response).i32(b.i - i - 1, i).end())
+ }
+
+ async function AuthenticationGssContinue(x) {
+ console.assert(Kerberos !== null)
+ console.assert(kerberosClient !== null)
+
+
+ }
+
async function SASL() {
nonce = (await crypto.randomBytes(18)).toString('base64')
b().p().str('SCRAM-SHA-256' + b.N)
The above code fails at write(b().raw(buffer).end()), and I'm not sure if returning data using ret = await new Promise(r => socket.once('data', x => r(x))) is correct.
ref:
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/connection.js, especially connectedGss, AuthenticationGss, AuthenticationGssContinue, and the write call using b().raw(buffer). Review the linked PostgreSQL GSSAPI protocol references and the kerberos package behavior. Done means the client can complete the GSSAPI authentication and encryption flow, including the raw-byte exchange.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, nodejs, postgresql
- Domain
- authentication, backend, databases, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100