From b64c290f05578bc3eb2e4bad96e2e41a1d0bd82b Mon Sep 17 00:00:00 2001 From: William Aitken Date: Wed, 6 Dec 2023 14:40:17 -0800 Subject: [PATCH] Bugfix: 1385: Authentication fails if both date and both x-ms-date isiF specified For queues and blobs, when forming the shared key token, the Date header should be treated as the empty string when the x-ms-date header is present. For tables, the value of the x-ms-date header shoudl be used as the value of the Date header if teh x-ms-date header is present. This behavior is documented at https://learn.microsoft.com/en-us/rest/api/storageservices/authorize-with-shared-key --- ChangeLog.md | 4 ++++ src/blob/authentication/BlobSharedKeyAuthenticator.ts | 4 ++-- src/queue/authentication/QueueSharedKeyAuthenticator.ts | 4 ++-- src/table/authentication/TableSharedKeyAuthenticator.ts | 8 ++++---- .../authentication/TableSharedKeyLiteAuthenticator.ts | 8 ++++---- tests/table/utils/table.entity.tests.utils.for.rest.ts | 4 ++-- 6 files changed, 18 insertions(+), 14 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index bca2e5041..b86d8e4a8 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -4,6 +4,10 @@ ## Upcoming Release +General: + +- Fixed shared key authentication signature generation when x-ms-date header is present. + ## 2023.11 Version 3.28.0 General: diff --git a/src/blob/authentication/BlobSharedKeyAuthenticator.ts b/src/blob/authentication/BlobSharedKeyAuthenticator.ts index f762d5438..f81f4eacb 100644 --- a/src/blob/authentication/BlobSharedKeyAuthenticator.ts +++ b/src/blob/authentication/BlobSharedKeyAuthenticator.ts @@ -82,7 +82,7 @@ export default class BlobSharedKeyAuthenticator implements IAuthenticator { this.getHeaderValueToSign(req, HeaderConstants.CONTENT_LENGTH), this.getHeaderValueToSign(req, HeaderConstants.CONTENT_MD5), this.getHeaderValueToSign(req, HeaderConstants.CONTENT_TYPE), - this.getHeaderValueToSign(req, HeaderConstants.DATE), + this.getHeaderValueToSign(req, HeaderConstants.X_MS_DATE) ? "" : this.getHeaderValueToSign(req, HeaderConstants.DATE), this.getHeaderValueToSign(req, HeaderConstants.IF_MODIFIED_SINCE), this.getHeaderValueToSign(req, HeaderConstants.IF_MATCH), this.getHeaderValueToSign(req, HeaderConstants.IF_NONE_MATCH), @@ -148,7 +148,7 @@ export default class BlobSharedKeyAuthenticator implements IAuthenticator { this.getHeaderValueToSign(req, HeaderConstants.CONTENT_LENGTH), this.getHeaderValueToSign(req, HeaderConstants.CONTENT_MD5), this.getHeaderValueToSign(req, HeaderConstants.CONTENT_TYPE), - this.getHeaderValueToSign(req, HeaderConstants.DATE), + this.getHeaderValueToSign(req, HeaderConstants.X_MS_DATE) ? "" : this.getHeaderValueToSign(req, HeaderConstants.DATE), this.getHeaderValueToSign(req, HeaderConstants.IF_MODIFIED_SINCE), this.getHeaderValueToSign(req, HeaderConstants.IF_MATCH), this.getHeaderValueToSign(req, HeaderConstants.IF_NONE_MATCH), diff --git a/src/queue/authentication/QueueSharedKeyAuthenticator.ts b/src/queue/authentication/QueueSharedKeyAuthenticator.ts index a6dc36378..291cf88c8 100644 --- a/src/queue/authentication/QueueSharedKeyAuthenticator.ts +++ b/src/queue/authentication/QueueSharedKeyAuthenticator.ts @@ -328,7 +328,7 @@ export default class QueueSharedKeyAuthenticator implements IAuthenticator { this.getHeaderValueToSign(req, HeaderConstants.CONTENT_LENGTH), this.getHeaderValueToSign(req, HeaderConstants.CONTENT_MD5), this.getHeaderValueToSign(req, HeaderConstants.CONTENT_TYPE), - this.getHeaderValueToSign(req, HeaderConstants.DATE), + this.getHeaderValueToSign(req, HeaderConstants.X_MS_DATE) ? "" : this.getHeaderValueToSign(req, HeaderConstants.DATE), this.getHeaderValueToSign(req, HeaderConstants.IF_MODIFIED_SINCE), this.getHeaderValueToSign(req, HeaderConstants.IF_MATCH), this.getHeaderValueToSign(req, HeaderConstants.IF_NONE_MATCH), @@ -344,7 +344,7 @@ export default class QueueSharedKeyAuthenticator implements IAuthenticator { req.getMethod().toUpperCase(), this.getHeaderValueToSign(req, HeaderConstants.CONTENT_MD5), this.getHeaderValueToSign(req, HeaderConstants.CONTENT_TYPE), - this.getHeaderValueToSign(req, HeaderConstants.DATE) + this.getHeaderValueToSign(req, HeaderConstants.X_MS_DATE) ? "" : this.getHeaderValueToSign(req, HeaderConstants.DATE) ].join("\n") + "\n" + this.getCanonicalizedHeadersString(req) diff --git a/src/table/authentication/TableSharedKeyAuthenticator.ts b/src/table/authentication/TableSharedKeyAuthenticator.ts index 7f98ab67f..6039d2626 100644 --- a/src/table/authentication/TableSharedKeyAuthenticator.ts +++ b/src/table/authentication/TableSharedKeyAuthenticator.ts @@ -53,8 +53,8 @@ export default class TableSharedKeyAuthenticator implements IAuthenticator { req.getMethod().toUpperCase(), this.getHeaderValueToSign(req, HeaderConstants.CONTENT_MD5), this.getHeaderValueToSign(req, HeaderConstants.CONTENT_TYPE), - this.getHeaderValueToSign(req, HeaderConstants.DATE) || - this.getHeaderValueToSign(req, HeaderConstants.X_MS_DATE) + this.getHeaderValueToSign(req, HeaderConstants.X_MS_DATE) || + this.getHeaderValueToSign(req, HeaderConstants.DATE) ].join("\n") + "\n" + this.getCanonicalizedResourceString( @@ -111,8 +111,8 @@ export default class TableSharedKeyAuthenticator implements IAuthenticator { req.getMethod().toUpperCase(), this.getHeaderValueToSign(req, HeaderConstants.CONTENT_MD5), this.getHeaderValueToSign(req, HeaderConstants.CONTENT_TYPE), - this.getHeaderValueToSign(req, HeaderConstants.DATE) || - this.getHeaderValueToSign(req, HeaderConstants.X_MS_DATE) + this.getHeaderValueToSign(req, HeaderConstants.X_MS_DATE) || + this.getHeaderValueToSign(req, HeaderConstants.DATE) ].join("\n") + "\n" + this.getCanonicalizedResourceString( diff --git a/src/table/authentication/TableSharedKeyLiteAuthenticator.ts b/src/table/authentication/TableSharedKeyLiteAuthenticator.ts index 8c3a6d9c4..ebfde52c9 100644 --- a/src/table/authentication/TableSharedKeyLiteAuthenticator.ts +++ b/src/table/authentication/TableSharedKeyLiteAuthenticator.ts @@ -53,8 +53,8 @@ export default class TableSharedKeyLiteAuthenticator implements IAuthenticator { const stringToSign: string = [ - this.getHeaderValueToSign(req, HeaderConstants.DATE) || - this.getHeaderValueToSign(req, HeaderConstants.X_MS_DATE) + this.getHeaderValueToSign(req, HeaderConstants.X_MS_DATE) || + this.getHeaderValueToSign(req, HeaderConstants.DATE) ].join("\n") + "\n" + this.getCanonicalizedResourceString( @@ -108,8 +108,8 @@ export default class TableSharedKeyLiteAuthenticator implements IAuthenticator { // JS/.net Track2 SDK will generate stringToSign from IP style Uri with "-secondary" in authenticationPath, so will also compare signature with this kind stringToSignconst stringToSign: string = const stringToSign_secondary: string = [ - this.getHeaderValueToSign(req, HeaderConstants.DATE) || - this.getHeaderValueToSign(req, HeaderConstants.X_MS_DATE) + this.getHeaderValueToSign(req, HeaderConstants.X_MS_DATE) || + this.getHeaderValueToSign(req, HeaderConstants.DATE) ].join("\n") + "\n" + this.getCanonicalizedResourceString( diff --git a/tests/table/utils/table.entity.tests.utils.for.rest.ts b/tests/table/utils/table.entity.tests.utils.for.rest.ts index 21fd03aea..b7c83c001 100644 --- a/tests/table/utils/table.entity.tests.utils.for.rest.ts +++ b/tests/table/utils/table.entity.tests.utils.for.rest.ts @@ -52,8 +52,8 @@ export function createStringToSignForSharedKeyLite( ): string { const stringToSign: string = [ - getHeaderValueToSign(HeaderConstants.DATE, headers) || - getHeaderValueToSign(HeaderConstants.X_MS_DATE, headers) + getHeaderValueToSign(HeaderConstants.X_MS_DATE, headers) || + getHeaderValueToSign(HeaderConstants.DATE, headers) ].join("\n") + "\n" + getCanonicalizedResourceString(