Add support for CPE digest authentication

This commit is contained in:
Shweelan Samson authored and Zaid Abdulla committed 2019-06-05 00:17:36 -07:00
1 parent f21ce3053a
commit 344ed3fdee
5 files changed
+228 -86

No files matched your search

+81 -45
View File
@@ -19,31 +19,9 @@
import { createHash, randomBytes, pbkdf2 } from "crypto";
export function parseAuthorizationHeader(authHeader): { method: string } {
authHeader = authHeader.trim();
const method = authHeader.split(" ", 1)[0];
const res = { method: method };
if (method === "Basic") {
// Inspired by https://github.com/jshttp/basic-auth
const USER_PASS_REGEX = /^([^:]*):(.*)$/;
const creds = USER_PASS_REGEX.exec(
Buffer.from(authHeader.slice(method.length + 1), "base64").toString()
);
if (!creds) throw new Error("Unable to parse auth header");
res["username"] = creds[1];
res["password"] = creds[2];
}
return res;
}
export function parseWwwAuthenticateHeader(authHeader): {} {
authHeader = authHeader.trim();
const method = authHeader.split(" ", 1)[0];
const res = { method: method };
const parts = authHeader.slice(method.length + 1).split(",");
function parseHeaderFeilds(str: string): {} {
const res = {};
const parts = str.split(",");
let part;
while ((part = parts.shift()) != null) {
@@ -72,33 +50,57 @@ export function parseWwwAuthenticateHeader(authHeader): {} {
return res;
}
export function parseAuthorizationHeader(authHeader): { method: string } {
authHeader = authHeader.trim();
const method = authHeader.split(" ", 1)[0];
const res = { method: method };
if (method === "Basic") {
// Inspired by https://github.com/jshttp/basic-auth
const USER_PASS_REGEX = /^([^:]*):(.*)$/;
const creds = USER_PASS_REGEX.exec(
Buffer.from(authHeader.slice(method.length + 1), "base64").toString()
);
if (!creds) throw new Error("Unable to parse auth header");
res["username"] = creds[1];
res["password"] = creds[2];
} else if (method === "Digest") {
Object.assign(res, parseHeaderFeilds(authHeader.slice(method.length + 1)));
}
return res;
}
export function parseWwwAuthenticateHeader(authHeader): {} {
authHeader = authHeader.trim();
const method = authHeader.split(" ", 1)[0];
const res = { method: method };
Object.assign(res, parseHeaderFeilds(authHeader.slice(method.length + 1)));
return res;
}
export function basic(username, password): string {
return "Basic " + Buffer.from(`${username}:${password}`).toString("base64");
}
export function digest(
username,
password,
uri,
httpMethod,
body,
authHeader
username: string | Buffer,
realm: string | Buffer,
password: string | Buffer,
nonce: string | Buffer,
httpMethod: string | Buffer,
uri: string | Buffer,
qop?: string | Buffer,
body?: string | Buffer,
cnonce?: string | Buffer,
nc?: string | Buffer
): string {
const cnonce = "0a4f113b";
const nc = "00000001";
let qop;
if (authHeader.qop) {
if (authHeader.qop.indexOf(",") !== -1) qop = "auth";
// Either auth or auth-int, prefer auth
else qop = authHeader.qop;
}
const ha1 = createHash("md5");
ha1
.update(username)
.update(":")
.update(authHeader.realm)
.update(realm)
.update(":")
.update(password);
// TODO support "MD5-sess" algorithm directive
@@ -112,7 +114,7 @@ export function digest(
if (qop === "auth-int") {
const bodyHash = createHash("md5")
.update(body)
.update(body || "")
.digest("hex");
ha2.update(":").update(bodyHash);
}
@@ -123,7 +125,7 @@ export function digest(
hash
.update(ha1d)
.update(":")
.update(authHeader.nonce);
.update(nonce);
if (qop) {
hash
.update(":")
@@ -135,13 +137,47 @@ export function digest(
}
hash.update(":").update(ha2d);
return hash.digest("hex");
}
export function solveDigest(
username: string | Buffer,
password: string | Buffer,
uri: string | Buffer,
httpMethod: string | Buffer,
body: string | Buffer,
authHeader
): string {
const cnonce = randomBytes(8).toString("hex");
const nc = "00000001";
let qop;
if (authHeader.qop) {
if (authHeader.qop.indexOf(",") !== -1) qop = "auth";
// Either auth or auth-int, prefer auth
else qop = authHeader.qop;
}
const hash = digest(
username,
authHeader.realm,
password,
authHeader.nonce,
httpMethod,
uri,
qop,
body,
cnonce,
nc
);
let authString = `Digest username="${username}"`;
authString += `,realm="${authHeader.realm}"`;
authString += `,nonce="${authHeader.nonce}"`;
authString += `,uri="${uri}"`;
if (authHeader.algorithm) authString += `,algorithm=${authHeader.algorithm}`;
if (qop) authString += `,qop=${qop},nc=${nc},cnonce="${cnonce}"`;
authString += `,response="${hash.digest("hex")}"`;
authString += `,response="${hash}"`;
if (authHeader.opaque) authString += `,opaque="${authHeader.opaque}"`;
return authString;