Repository navigation
Forward x-ms-copy-source-authorization when reading a copy source (issue #2815) - #2876
Ankit Chaudhary (ankit1324) wants to merge 2 commits into
Conversation
…sue Azure#2815) Put Blob From URL and Put Block From URL read the source with a loopback request that carried no credential, so a private source failed with CannotVerifyCopySource even with a valid bearer token in x-ms-copy-source-authorization. Send that header as the Authorization header of the source read, including the tags read for x-ms-copy-source-tag-option: COPY.
There was a problem hiding this comment.
🟡 Changes recommended
Both copy operations accept correctly signed SharedKey source credentials despite Azure’s Bearer-only restriction, allowing private-source authorization even when OAuth is disabled.
1 open issue
What changed in this PR
Addresses issue #2815 for Put Blob From URL and Put Block From URL by forwarding source authorization through Azurite’s existing authentication path. Copy Blob From URL remains outside this change.
Changes:
- Forward source authorization for content reads and optional source-tag copying.
- Add OAuth tests for successful copies, expired-token rejection, and SAS precedence.
- Document the behavior under Upcoming Release.
Validation here was limited to code inspection; builds and tests were not run.
| File | Description |
|---|---|
tests/blob/oauth.test.ts |
Adds five source-authorization regression tests. |
src/blob/handlers/BlockBlobHandler.ts |
Forwards source credentials for blob, block, and tag reads. |
ChangeLog.md |
Records the source-authorization fix for both operations. |
Review effort: Balanced
|
Ankit Chaudhary (@ankit1324) please read the following Contributor License Agreement(CLA). If you agree with the CLA, please reply with the following information.
Contributor License AgreementContribution License AgreementThis Contribution License Agreement (“Agreement”) is agreed to by the party signing below (“You”),
|

Fixes #2815
What was wrong
Put Blob From URL and Put Block From URL read the source with a loopback request in
BlockBlobHandler.readCopySource. That request only sendshost,accept-encodingand the range and source-condition headers. The generated layer parsesoptions.copySourceAuthorization, but no handler used it. With--oauth basic, a private source failed with403 CannotVerifyCopySourceeven whenx-ms-copy-source-authorization: Bearer <token>carried a valid token. Only a public container or a SAS in the source URL worked.What the fix does
When
x-ms-copy-source-authorizationcarries a Bearer token, it becomes theAuthorizationheader of the loopback source read. The token authenticator then checks it the same way it checks a direct request. This covers the content read of both operations, plus the tags read that Put Blob From URL does forx-ms-copy-source-tag-option: COPY. The handler does not log the value. The loopback URL is still pinned to this server's own address, so the token never goes to a host the caller chose.Only the Bearer scheme is forwarded. The scheme is matched case-insensitively (RFC 9110) and sent on as
Bearer, because the token authenticator only recognises that spelling. Any other scheme fails the request with400 InvalidHeaderValuenamingx-ms-copy-source-authorization, before the source is read. The error does not include the header value. Forwarding every scheme would let aSharedKeysignature computed for the loopback GET authorize the read, even on a server started without--oauth.On the error choice: the REST docs for Put Blob From URL, Put Block From URL and Copy Blob From URL say only the Bearer scheme is supported for this header, but don't say what Azure returns for other schemes. I couldn't find an SDK test or recording that sends a non-Bearer scheme either. The closest data point is the .NET SDK's
*_SourceBearerTokenFailtests (BlobBaseClientTests.cs, BlockBlobClientTests.cs). They sendBearer auth tokenand expectCannotVerifyCopySource. That covers a bad Bearer value, not another scheme, so I used Azurite's existingInvalidHeaderValueerror. Happy to switch to400 CannotVerifyCopySourceif you prefer.Without the header, or with an empty one, nothing changes. A SAS in the source URL still takes precedence, because the SAS authenticators run before the token one. A token the server rejects, or a server started without
--oauth, still givesCannotVerifyCopySource.Copy Blob From URL
The issue also mentions Copy Blob From URL, which I left out of this change. In Azurite,
BlobHandler.copyFromURLonly callsvalidateCopySourcewhen the source is in a different account. A same-account private source therefore already copies without any source authorization, which is more permissive than Azure. For cross-account sources,validateCopySourcealso drops the header. Testing that needs a second account, so it seemed better as a separate follow-up. I'm happy to do it if you want.Tests
New tests in
tests/blob/oauth.test.ts:COPY, and Put Block From URL from a private source with a bearersourceAuthorization. All three fail onmainwithCannotVerifyCopySourceand pass with the fix.CannotVerifyCopySourceand status 403. The token is generated with the same claims as the valid tokens exceptexp, so the token authenticator's lifetime check is what rejects it.x-ms-copy-source-authorizationstill copies.bearerscheme authorizes the copy, asBearerdoes.SharedKeysource credential for the loopback read (computed with the emulator account key) does not authorize Put Blob From URL or Put Block From URL. Both fail with400 InvalidHeaderValue, and the error message does not contain the signature. Before this change, both copies succeeded.npm run lintandnpm run buildare clean. The blob suite (test:blobwithout the lint step) gives 625 passing, 3 pending and 0 failing. oauth and blockblob also pass withAZURITE_TEST_INMEMORYPERSISTENCE=1.Checklist
main(Azurite V3).Upcoming ReleaseinChangeLog.md.I'll sign the Microsoft CLA when the bot asks.