diff --git a/packages/sasl-ht-sha-256-none/index.js b/packages/sasl-ht-sha-256-none/index.js index 618794488..87acdae4d 100644 --- a/packages/sasl-ht-sha-256-none/index.js +++ b/packages/sasl-ht-sha-256-none/index.js @@ -9,6 +9,10 @@ Mechanism.prototype.Mechanism = Mechanism; Mechanism.prototype.name = "HT-SHA-256-NONE"; Mechanism.prototype.clientFirst = true; +Mechanism.prototype.challenge = async function challenge(_) { + throw new Error(`${this.name} does not support SASL challenges`); +} + Mechanism.prototype.response = async function response({ username, password }) { this.key = await crypto.subtle.importKey( "raw", diff --git a/packages/sasl2/index.js b/packages/sasl2/index.js index 7cb819754..6c3092834 100644 --- a/packages/sasl2/index.js +++ b/packages/sasl2/index.js @@ -115,6 +115,11 @@ export default function sasl2({ streamFeatures, saslFactory }, onAuthenticate) { async function done(credentials, mechanism, userAgent) { // Try fast + let err; + entity.on("error", (_err) => { + // catch internal/protocol errors in fast.auth() + err = _err; + }) const success = await fast.auth({ authenticate, entity, @@ -123,7 +128,7 @@ export default function sasl2({ streamFeatures, saslFactory }, onAuthenticate) { features, credentials, }); - if (success) return; + if (success || err) return; // fast.auth may mutate streamFeatures to request a token diff --git a/packages/sasl2/test.js b/packages/sasl2/test.js index 07c4ce805..f608573c7 100644 --- a/packages/sasl2/test.js +++ b/packages/sasl2/test.js @@ -224,3 +224,56 @@ test("use ANONYMOUS if username and password are not provided", async () => { const result = await promise(entity, "send"); expect(result.attrs.mechanism).toEqual("ANONYMOUS"); }); + +test("fail if server sends a challenge during FAST login", async () => { + const mech = "HT-SHA-256-NONE"; + + function onAuthenticate(authenticate, mechanisms, fast) { + expect(mechanisms).toEqual([]); + expect(fast.mechanism).toEqual(mech); + return authenticate( + { + token: { + token: "hai", + mechanism: fast.mechanism, + }, + }, + null, + userAgent, + ); + } + + const { entity } = mockClient({ credentials: onAuthenticate }); + + entity.mockInput( + + + + + {mech} + + + + , + ); + + expect(await promise(entity, "send")).toEqual( + + + bnVsbACNMNimsTBnxS04m8x7wgKjBHdDUL/nXPU4J4vqxqjBIg== + + {userAgent} + + , + ); + + entity.mockInput( + + aGVyZXNhYnVuY2hvZmJhZGNoYWxsZW5nZWRhdGEK + , + ); + + const error = await promise(entity, "error"); + expect(error instanceof Error).toBe(true); + expect(error.message).toBe("HT-SHA-256-NONE does not support SASL challenges"); +});