From 9da3108825ea2a1bbdd6504eb751892b82c853cd Mon Sep 17 00:00:00 2001 From: Hans Ott Date: Thu, 19 Sep 2024 10:23:43 +0200 Subject: [PATCH 1/5] Add ghost session cookie --- library/agent/api-discovery/getApiAuthType.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/library/agent/api-discovery/getApiAuthType.ts b/library/agent/api-discovery/getApiAuthType.ts index 770a23212..437db3c0f 100644 --- a/library/agent/api-discovery/getApiAuthType.ts +++ b/library/agent/api-discovery/getApiAuthType.ts @@ -36,6 +36,7 @@ const commonAuthCookieNames = [ "auth_token", "access_token", "refresh_token", + "ghost-admin-api-session", ...commonApiKeyHeaderNames, ]; From 34ce05d6b4e4ef376d682c84cd675975ae7bc336 Mon Sep 17 00:00:00 2001 From: Hans Ott Date: Fri, 20 Sep 2024 11:17:00 +0200 Subject: [PATCH 2/5] Use includes for matching header and cookie names --- .../api-discovery/getApiAuthType.test.ts | 54 +++++++++++++++++++ library/agent/api-discovery/getApiAuthType.ts | 37 +++++++++---- 2 files changed, 82 insertions(+), 9 deletions(-) diff --git a/library/agent/api-discovery/getApiAuthType.test.ts b/library/agent/api-discovery/getApiAuthType.test.ts index 06a9d1bde..b101ff1db 100644 --- a/library/agent/api-discovery/getApiAuthType.test.ts +++ b/library/agent/api-discovery/getApiAuthType.test.ts @@ -41,6 +41,17 @@ t.test("it detects api keys", async (t) => { ]); }); +t.test("it doesn't add the same api key again", async () => { + t.same(get(getContext({ "api-key": "token", "api-key-a": "token" })), [ + { type: "apiKey", in: "header", name: "api-key" }, + { type: "apiKey", in: "header", name: "api-key-a" }, + ]); + t.same(get(getContext({ "api-key": "token", "api-key-apikey": "token" })), [ + { type: "apiKey", in: "header", name: "api-key" }, + { type: "apiKey", in: "header", name: "api-key-apikey" }, + ]); +}); + t.test("it detects auth cookies", async (t) => { t.same(get(getContext({}, { "api-key": "token" })), [ { type: "apiKey", in: "cookie", name: "api-key" }, @@ -54,6 +65,49 @@ t.test("it detects auth cookies", async (t) => { ]); }); +t.test("it detects multiple auth cookies", async (t) => { + t.same(get(getContext({}, { "api-key": "token", "api-key-a": "token" })), [ + { type: "apiKey", in: "cookie", name: "api-key" }, + { type: "apiKey", in: "cookie", name: "api-key-a" }, + ]); + t.same(get(getContext({}, { "api-key": "token", "api-key-sid": "token" })), [ + { type: "apiKey", in: "cookie", name: "api-key-sid" }, + { type: "apiKey", in: "cookie", name: "api-key" }, + ]); +}); + +t.test("it detects cookies and api keys at same time", async (t) => { + t.same( + get( + getContext( + { + "api-key": "token", + }, + { "api-key": "token" } + ) + ), + [ + { type: "apiKey", in: "header", name: "api-key" }, + { type: "apiKey", in: "cookie", name: "api-key" }, + ] + ); + + t.same( + get( + getContext( + { + "x-api-key": "token", + }, + { "api-key": "token" } + ) + ), + [ + { type: "apiKey", in: "header", name: "x-api-key" }, + { type: "apiKey", in: "cookie", name: "api-key" }, + ] + ); +}); + t.test("no auth", async (t) => { t.same(get(getContext()), undefined); t.same(get(getContext({})), undefined); diff --git a/library/agent/api-discovery/getApiAuthType.ts b/library/agent/api-discovery/getApiAuthType.ts index 437db3c0f..50a2bae02 100644 --- a/library/agent/api-discovery/getApiAuthType.ts +++ b/library/agent/api-discovery/getApiAuthType.ts @@ -83,12 +83,13 @@ function getAuthorizationHeaderType( if (authHeader.includes(" ")) { const [type, value] = authHeader.split(" "); - if (typeof type === "string" && typeof value === "string") { + if (type && value) { if (isHTTPAuthScheme(type)) { return { type: "http", scheme: type.toLowerCase() as HTTPAuthScheme }; } } } + // Default to apiKey if the auth type is not recognized return { type: "apiKey", in: "header", name: "Authorization" }; } @@ -99,10 +100,20 @@ function getAuthorizationHeaderType( function findApiKeys(context: Context): APIAuthType[] { const result: APIAuthType[] = []; + const headerNames = Object.keys(context.headers); for (const header of commonApiKeyHeaderNames) { - if (context.headers[header]) { - result.push({ type: "apiKey", in: "header", name: header }); - } + const matches = headerNames.filter((name) => + name.toLowerCase().includes(header.toLowerCase()) + ); + + matches.forEach((match) => { + const alreadyAdded = result.some( + (authType) => authType.name === match && authType.in === "header" + ); + if (!alreadyAdded) { + result.push({ type: "apiKey", in: "header", name: match }); + } + }); } if ( @@ -111,11 +122,19 @@ function findApiKeys(context: Context): APIAuthType[] { !Array.isArray(context.cookies) && Object.keys(context.cookies).length > 0 ) { - const relevantCookies = Object.keys(context.cookies).filter((cookieName) => - commonAuthCookieNames.includes(cookieName.toLowerCase()) - ); - for (const cookie of relevantCookies) { - result.push({ type: "apiKey", in: "cookie", name: cookie }); + for (const cookie of commonAuthCookieNames) { + const matches = Object.keys(context.cookies).filter((name) => + name.toLowerCase().includes(cookie.toLowerCase()) + ); + + matches.forEach((match) => { + const alreadyAdded = result.some( + (authType) => authType.name === match && authType.in === "cookie" + ); + if (!alreadyAdded) { + result.push({ type: "apiKey", in: "cookie", name: match }); + } + }); } } From 4958daeee35e570bda06cac5ec48705b8eafc082 Mon Sep 17 00:00:00 2001 From: Hans Ott Date: Fri, 20 Sep 2024 11:59:28 +0200 Subject: [PATCH 3/5] Remove unused names --- library/agent/api-discovery/getApiAuthType.ts | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/library/agent/api-discovery/getApiAuthType.ts b/library/agent/api-discovery/getApiAuthType.ts index 50a2bae02..a4d8457cb 100644 --- a/library/agent/api-discovery/getApiAuthType.ts +++ b/library/agent/api-discovery/getApiAuthType.ts @@ -18,25 +18,13 @@ export type APIAuthType = { }; // Incoming request headers are lowercase in Node.js -const commonApiKeyHeaderNames = [ - "x-api-key", - "api-key", - "apikey", - "x-token", - "token", -]; +const commonApiKeyHeaderNames = ["x-api-key", "api-key", "apikey", "token"]; const commonAuthCookieNames = [ "auth", "session", "jwt", - "token", "sid", - "connect.sid", - "auth_token", - "access_token", - "refresh_token", - "ghost-admin-api-session", ...commonApiKeyHeaderNames, ]; From 0e778d6b19e6043fe7f6cd5979e4f6ddcc04ce29 Mon Sep 17 00:00:00 2001 From: Hans Ott Date: Fri, 20 Sep 2024 12:02:42 +0200 Subject: [PATCH 4/5] Remove x-api-key --- library/agent/api-discovery/getApiAuthType.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/agent/api-discovery/getApiAuthType.ts b/library/agent/api-discovery/getApiAuthType.ts index a4d8457cb..8d4d6c0d9 100644 --- a/library/agent/api-discovery/getApiAuthType.ts +++ b/library/agent/api-discovery/getApiAuthType.ts @@ -18,7 +18,7 @@ export type APIAuthType = { }; // Incoming request headers are lowercase in Node.js -const commonApiKeyHeaderNames = ["x-api-key", "api-key", "apikey", "token"]; +const commonApiKeyHeaderNames = ["api-key", "apikey", "token"]; const commonAuthCookieNames = [ "auth", From f61da42233cb495383d5b710ce22f9d95867ca70 Mon Sep 17 00:00:00 2001 From: Hans Ott Date: Mon, 7 Oct 2024 15:33:49 +0200 Subject: [PATCH 5/5] Update library/agent/api-discovery/getApiAuthType.ts --- library/agent/api-discovery/getApiAuthType.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/agent/api-discovery/getApiAuthType.ts b/library/agent/api-discovery/getApiAuthType.ts index 8d4d6c0d9..b024db919 100644 --- a/library/agent/api-discovery/getApiAuthType.ts +++ b/library/agent/api-discovery/getApiAuthType.ts @@ -91,7 +91,7 @@ function findApiKeys(context: Context): APIAuthType[] { const headerNames = Object.keys(context.headers); for (const header of commonApiKeyHeaderNames) { const matches = headerNames.filter((name) => - name.toLowerCase().includes(header.toLowerCase()) + name.toLowerCase().includes(header) ); matches.forEach((match) => {