Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 4 additions & 0 deletions packages/sasl-ht-sha-256-none/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
7 changes: 6 additions & 1 deletion packages/sasl2/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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

Expand Down
53 changes: 53 additions & 0 deletions packages/sasl2/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(
<features xmlns="http://etherx.jabber.org/streams">
<authentication xmlns="urn:xmpp:sasl:2">
<inline>
<fast xmlns="urn:xmpp:fast:0">
<mechanism>{mech}</mechanism>
</fast>
</inline>
</authentication>
</features>,
);

expect(await promise(entity, "send")).toEqual(
<authenticate xmlns="urn:xmpp:sasl:2" mechanism={mech}>
<initial-response>
bnVsbACNMNimsTBnxS04m8x7wgKjBHdDUL/nXPU4J4vqxqjBIg==
</initial-response>
{userAgent}
<fast xmlns="urn:xmpp:fast:0" />
</authenticate>,
);

entity.mockInput(
<challenge xmlns="urn:xmpp:sasl:2">
aGVyZXNhYnVuY2hvZmJhZGNoYWxsZW5nZWRhdGEK
</challenge>,
);

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");
});