Skip to content

feat: enforce scoped ADLS SAS authorization - #158

Merged
hectorvent merged 1 commit into
floci-io:mainfrom
snazy:cred-vending-2
Aug 18, 2026
Merged

feat: enforce scoped ADLS SAS authorization#158
hectorvent merged 1 commit into
floci-io:mainfrom
snazy:cred-vending-2

Conversation

@snazy

@snazy snazy commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add parsed storage SAS context and deterministic shared user-delegation signing key material.
  • Validate user-delegation SAS signatures, resource scope, path scope, and operation permissions before Blob-backed ADLS operations.
  • Add Blob and Java DataLake SDK compatibility coverage for accepted and denied SAS behavior.
  • Signed user-delegation key-window validation now includes: skt/ske, signed key identity/service, and SAS expiry bounded by key expiry

Type of change

  • New feature (feat:)

Azure Compatibility

  • Matches Java Azure SDK DataLake user-delegation SAS string-to-sign behavior for the compatibility-suite SDK version.
  • SDK test source compile verified with repo-local Maven cache.

Checklist

  • ./mvnw test passes locally
  • New or updated integration test added.
  • Commit messages follow Conventional Commits.

@github-actions

Copy link
Copy Markdown

🎉 Thanks for your first pull request to floci-az!

Your CI checks need a maintainer to approve them before they run. That is GitHub's standard gate on first-time contributors, not a problem with your PR — so if the checks look like they are doing nothing, that is why. Once a maintainer approves, CI and the compatibility suite start automatically. Nothing is needed from you in the meantime.

While you wait, a couple of things that make review faster:

  • Link the issue this fixes with Closes #N in the description
  • Commits follow Conventional Commits (feat(blob): ..., fix(keyvault): ...)
  • Behaviour changes come with a test — see CONTRIBUTING.md

Come join us in Slack — it is the fastest way to reach maintainers if you get stuck, or want feedback on an approach before investing more time in it.

@greptile-apps

greptile-apps Bot commented Jul 31, 2026

Copy link
Copy Markdown

Greptile Summary

Implements scoped user-delegation SAS authorization for Blob-backed ADLS operations.

  • Replaces publicly derivable delegation keys with process-local random key material and account-scoped HMAC derivation.
  • Validates signatures, delegation-key windows, resource/path scope, and operation permissions.
  • Prevents append-only SAS tokens from authorizing general create or write operations.
  • Adds unit, integration, and Java Data Lake SDK compatibility coverage.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains; the random shared key material resolves the signing-key forgery issue, and append-only SAS tokens are denied by every implemented general mutation path.

Important Files Changed

Filename Overview
src/main/java/io/floci/az/core/auth/UserDelegationKeyMaterial.java Uses a process-local random master key to derive stable, account-scoped delegation keys without retaining the prior public derivation.
src/main/java/io/floci/az/core/auth/StorageSasAuthorization.java Enforces user-delegation signature, key-window, resource-scope, path-scope, and operation-permission checks.
src/main/java/io/floci/az/services/blob/BlobServiceHandler.java Applies SAS authorization to implemented Blob and ADLS-backed read, list, create, write, and delete operations.
src/main/java/io/floci/az/services/blob/UserDelegationKeyService.java Issues delegation keys from the shared application-scoped key-material service.
src/test/java/io/floci/az/services/BlobServiceTest.java Covers signature rejection, key validity, resource and directory scope, and operation-specific permission enforcement.
compatibility-tests/sdk-test-java/src/test/java/io/floci/az/compat/DataLakeCompatibilityTest.java Verifies accepted and denied user-delegation SAS behavior through the Java Data Lake SDK.

Sequence Diagram

sequenceDiagram
  participant SDK as Azure SDK
  participant Auth as SAS Verifier
  participant Handler as Blob Handler
  participant Policy as SAS Authorization
  participant Store as Blob Backend
  SDK->>Auth: Blob/ADLS request with SAS
  Auth->>Auth: Parse token and validate time window
  Auth-->>Handler: AuthContext with parsed SAS
  Handler->>Policy: Authorize operation and resource path
  Policy->>Policy: Validate delegation key and signature
  Policy->>Policy: Check scope and permission
  alt Authorized
    Policy-->>Handler: Allowed
    Handler->>Store: Read or mutate resource
    Store-->>SDK: Azure-compatible response
  else Denied
    Policy-->>SDK: 403 Azure error
  end
Loading

Reviews (3): Last reviewed commit: "feat: enforce scoped ADLS SAS authorizat..." | Re-trigger Greptile

Comment thread src/main/java/io/floci/az/core/auth/UserDelegationKeyMaterial.java Outdated
Comment thread src/main/java/io/floci/az/core/auth/StorageSasAuthorization.java
@hectorvent hectorvent added feature blob Azure Blob Storage labels Aug 6, 2026
@hectorvent

Copy link
Copy Markdown
Contributor

Thank you for taking this from parsing to actual enforcement, and for keeping the new types in core/auth alongside the existing verifiers rather than starting a parallel path.

Two things, and the first one is our fault. We merged #166 today and it touched BlobServiceHandler, which has put this branch into conflict. Only BlobServiceTest.java actually conflicts, so it should be a small rebase, and I am sorry for the churn.

The second is that I have not finished checking the SAS field semantics against Azurite yet. Given this flips a permissive path into an enforcing one I would rather not sign off from a skim. The pieces I want to walk properly are the signed permission to operation mapping, the sr scoping including the directory depth case, and the user delegation key fields.

Nothing looks wrong so far. I will come back with specifics once you have rebased.

Summary:
- Add parsed storage SAS context and deterministic shared user-delegation signing key material.
- Validate user-delegation SAS signatures, resource scope, path scope, and operation permissions before Blob-backed ADLS operations.
- Add Blob and Java DataLake SDK compatibility coverage for accepted and denied SAS behavior.
- Signed user-delegation key-window validation now includes: skt/ske, signed key identity/service, and SAS expiry bounded by key expiry

Type of change:
- [x] New feature (feat:)

Azure Compatibility:
- Matches Java Azure SDK DataLake user-delegation SAS string-to-sign behavior for the compatibility-suite SDK version.
- SDK test source compile verified with repo-local Maven cache.

Checklist:
- [x] `./mvnw test` passes locally
- [x] New or updated integration test added.
- [x] Commit messages follow Conventional Commits.
@greptile-apps

greptile-apps Bot commented Aug 17, 2026

Copy link
Copy Markdown

Want your agent to iterate on Greptile's feedback? Try greploops.

@hectorvent

Copy link
Copy Markdown
Contributor

Thank you for this, and sorry it sat with me so long. A change that turns a permissive path into an enforcing one deserved a proper pass rather than a skim, and I have now done it.

The signing is right. I compared the string-to-sign field by field against Azurite and your ordering matches its sv >= 2020-12-06 layout exactly, including ses sitting between the blob version timestamp placeholder and the response header overrides, which is the easy one to get wrong. Deriving the canonical name from the first sdd segments so that containment is enforced by the signature itself, rather than by a prefix comparison, is also the right shape.

Three things worth a follow up issue rather than holding this: the signing uses the 2020-12-06 layout regardless of sv, the a permission is not mapped so an append only SAS would be refused, and sr=bs is rejected. All three fail closed, which is the safe direction.

No blockers from my side.

@hectorvent
hectorvent merged commit 3f951ae into floci-io:main Aug 18, 2026
10 checks passed
@hectorvent

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 0.11.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

@snazy
snazy deleted the cred-vending-2 branch August 18, 2026 08:17
snazy pushed a commit to snazy/floci-az that referenced this pull request Aug 18, 2026
# [0.11.0](floci-io/floci-az@0.10.0...0.11.0) (2026-08-18)

### Bug Fixes

* **blob:** persist upload HTTP properties ([floci-io#166](floci-io#166)) ([28cd215](floci-io@28cd215)), closes [floci-io#163](floci-io#163)
* **core:** omit Content-Type on bodyless error responses ([floci-io#185](floci-io#185)) ([51b545a](floci-io@51b545a))
* **cosmos:** enforce item ETag conditions ([floci-io#167](floci-io#167)) ([dd5ae45](floci-io@dd5ae45)), closes [floci-io#160](floci-io#160) [floci-io#161](floci-io#161)
* **cosmos:** evaluate correlated EXISTS queries ([floci-io#168](floci-io#168)) ([fbaa6bf](floci-io@fbaa6bf)), closes [floci-io#162](floci-io#162)
* **dns,tls:** converge dns and tls clusters on floci-aws baseline 0142dc4 ([floci-io#177](floci-io#177)) ([90736bc](floci-io@90736bc))
* **docker:** converge docker cluster on floci-aws baseline 0142dc4 ([floci-io#178](floci-io#178)) ([eb0bf42](floci-io@eb0bf42)), closes [floci-io#157](floci-io#157) [floci-io#95](floci-io#95)
* **entra:** make EntraStore participate in /_admin/reset ([floci-io#195](floci-io#195)) ([a370440](floci-io@a370440))
* **functions:** accept deployment packages larger than 20 MB ([floci-io#196](floci-io#196)) ([c247f32](floci-io@c247f32)), closes [floci-io#192](floci-io#192)
* **postgres:** answer 202 with Location so azurerm 3.x and 4.x both apply ([floci-io#135](floci-io#135)) ([3a11776](floci-io@3a11776))
* **sql:** replace retired Azure SQL Edge image ([floci-io#139](floci-io#139)) ([11fc293](floci-io@11fc293)), closes [floci-io#138](floci-io#138)
* **storage:** converge storage cluster on floci-aws baseline 0142dc4 ([floci-io#180](floci-io#180)) ([7b375a7](floci-io@7b375a7))
* **storage:** serve service-properties XML for table, queue, and blob ([floci-io#134](floci-io#134)) ([1848a4d](floci-io@1848a4d)), closes [floci-io#132](floci-io#132) [floci-io#131](floci-io#131)

### Features

* **cosmos:** container DefaultTimeToLive (TTL) with per-document overrides ([floci-io#141](floci-io#141)) ([d4f1d70](floci-io@d4f1d70)), closes [floci-io#126](floci-io#126)
* enforce scoped ADLS SAS authorization ([floci-io#158](floci-io#158)) ([3f951ae](floci-io@3f951ae))
* Entra ID phase 2 — auth-code+PKCE grant + Microsoft Graph slice ([floci-io#143](floci-io#143)) ([913954b](floci-io@913954b)), closes [floci-io#120](floci-io#120)
* **release:** release parity, one-button release cut, and the -compat image ([floci-io#188](floci-io#188)) ([6fe9958](floci-io@6fe9958))
* **servicebus:** support message sessions ([floci-io#190](floci-io#190)) ([dccc3dd](floci-io@dccc3dd)), closes [floci-io#159](floci-io#159)

### Performance Improvements

* **docker:** stop duplicating the native binary into a second image layer ([floci-io#187](floci-io#187)) ([5354201](floci-io@5354201))
@snazy

snazy commented Aug 18, 2026

Copy link
Copy Markdown
Contributor Author

Thank you for this, and sorry it sat with me so long. A change that turns a permissive path into an enforcing one deserved a proper pass rather than a skim, and I have now done it.

The signing is right. I compared the string-to-sign field by field against Azurite and your ordering matches its sv >= 2020-12-06 layout exactly, including ses sitting between the blob version timestamp placeholder and the response header overrides, which is the easy one to get wrong. Deriving the canonical name from the first sdd segments so that containment is enforced by the signature itself, rather than by a prefix comparison, is also the right shape.

Three things worth a follow up issue rather than holding this: the signing uses the 2020-12-06 layout regardless of sv, the a permission is not mapped so an append only SAS would be refused, and sr=bs is rejected. All three fail closed, which is the safe direction.

No blockers from my side.

Thanks!
I'll prepare commits for follow-up PRs (on top of a change in the PR stack #121).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

blob Azure Blob Storage feature released

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants