Skip to content

Fix WAC 403 for path-based pod access when subdomains enabled - #145

Merged
melvincarvalho merged 2 commits into
gh-pagesfrom
issue-144-wac-path-based-subdomain-fix
Mar 3, 2026
Merged

Fix WAC 403 for path-based pod access when subdomains enabled#145
melvincarvalho merged 2 commits into
gh-pagesfrom
issue-144-wac-path-based-subdomain-fix

Conversation

@melvincarvalho

Copy link
Copy Markdown
Contributor

Summary

  • Extracts a buildResourceUrl() helper that normalizes path-based pod URLs to subdomain form for WAC checking
  • Applies normalization in three places: resource URL, parent container URL (write ops), and ACL protected resource URL
  • No changes to behavior when subdomains are disabled or when accessing via subdomain directly

Problem

With subdomains: true, accessing example.com/alice/public/file.ttl returns 403 even when the ACL grants public Read access. The WAC checker builds the resource URL as https://example.com/alice/public/file.ttl but ACLs reference https://alice.example.com/public/.

Test plan

  • Access public resource via path (example.com/alice/public/file) — should return 200
  • Access public resource via subdomain (alice.example.com/public/file) — should still return 200
  • Access private resource via path without auth — should return 401
  • PUT to path-based URL with auth — parent container URL also normalized
  • ACL file access via path — protected resource URL normalized

Fixes #144

When subdomains are enabled, ACLs reference subdomain URLs
(e.g. https://alice.example.com/public/) but path-based access
on the main domain (e.g. https://example.com/alice/public/file.ttl)
constructs a different resource URL that doesn't match.

Extract a buildResourceUrl() helper that normalizes path-based
pod URLs to subdomain form for WAC checking. Applied to resource
URL construction, parent container URL for write ops, and ACL
protected resource URL.

Fixes #144

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes WAC authorization mismatches when subdomains: true by normalizing path-based pod URLs (https://example.com/alice/...) into their subdomain form (https://alice.example.com/...) before ACL checks, so the resource URLs align with ACL accessTo / default entries generated during pod creation.

Changes:

  • Added buildResourceUrl() helper to normalize base-domain path-based pod URLs into subdomain-form URLs for WAC.
  • Applied normalization to the main resource URL used for WAC checks and to the parent-container URL used for write ops on non-existent resources.
  • Applied normalization when authorizing access to .acl resources (protected resource URL computation).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/auth/middleware.js Outdated
request.hostname === request.baseDomain && !request.podName) {
const pathMatch = urlPath.match(/^\/([^/]+)(\/.*)$/);
if (pathMatch) {
return `${request.protocol}://${pathMatch[1]}.${request.baseDomain}${pathMatch[2]}`;

Copilot AI Mar 3, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

buildResourceUrl() will rewrite any path of the form /<segment>/<rest> on the base domain into a subdomain URL. This includes allowed dotfile routes like /.meta/... (see ALLOWED_DOTFILES), producing hosts such as .meta.<baseDomain> which may be an invalid URL and can throw inside checkAccess() (it calls new URL(resourceUrl) without a try/catch). Restrict normalization to valid pod names (same pattern used at pod creation, and/or reuse getPodName() which already ignores leading-dot segments) before constructing the subdomain URL.

Suggested change
return `${request.protocol}://${pathMatch[1]}.${request.baseDomain}${pathMatch[2]}`;
const candidatePod = pathMatch[1];
// Ignore leading-dot segments such as ".meta" which are not pod names
if (!candidatePod.startsWith('.')) {
return `${request.protocol}://${candidatePod}.${request.baseDomain}${pathMatch[2]}`;
}

Copilot uses AI. Check for mistakes.
Comment thread src/auth/middleware.js Outdated
Comment on lines +29 to +31
const pathMatch = urlPath.match(/^\/([^/]+)(\/.*)$/);
if (pathMatch) {
return `${request.protocol}://${pathMatch[1]}.${request.baseDomain}${pathMatch[2]}`;

Copilot AI Mar 3, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The normalization regex ^\/([^/]+)(\/.*)$ does not match pod-root requests like /alice (no trailing slash / second segment), so in subdomain mode https://<baseDomain>/alice would still be checked against the un-normalized URL and can continue to 403 even though the pod root ACL is subdomain-based. Consider handling the /<pod> case (e.g., treat missing remainder as /) so pod-root path access is normalized too.

Suggested change
const pathMatch = urlPath.match(/^\/([^/]+)(\/.*)$/);
if (pathMatch) {
return `${request.protocol}://${pathMatch[1]}.${request.baseDomain}${pathMatch[2]}`;
// Normalize path-based pod access (/alice, /alice/, /alice/...) to subdomain form
const pathMatch = urlPath.match(/^\/([^/]+)(\/.*)?$/);
if (pathMatch) {
const podName = pathMatch[1];
const remainder = pathMatch[2] || '/';
return `${request.protocol}://${podName}.${request.baseDomain}${remainder}`;

Copilot uses AI. Check for mistakes.
Comment thread src/auth/middleware.js
Comment on lines +81 to +82
// Build resource URL, normalizing path-based pod access to subdomain form for WAC
const resourceUrl = buildResourceUrl(request, urlPath);

Copilot AI Mar 3, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change alters authorization behavior in subdomain mode for path-based pod access, but there doesn't appear to be test coverage for subdomains: true + baseDomain scenarios. Please add an integration test that starts the server with subdomains: true and baseDomain: "127.0.0.1", creates a pod, and verifies that GET /alice/public/ returns 200 (and e.g. /alice/private/ returns 401 without auth) to prevent regressions.

Copilot uses AI. Check for mistakes.
…ation

Skip leading-dot segments (e.g. /.well-known, /.meta) to avoid
producing invalid subdomain URLs. Also handle pod-root access
(/alice without trailing slash) by making the remainder optional.

Addresses Copilot review feedback on #145.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/auth/middleware.js
Comment on lines 83 to +100
@@ -70,9 +95,9 @@ export async function authorize(request, reply, options = {}) {
// Check write permission on parent container
const parentPath = getParentPath(storagePath);
checkPath = parentPath;
// For URL, also need to get parent
// For URL, also need to get parent (normalized for subdomain WAC matching)
const parentUrlPath = getParentPath(urlPath);
checkUrl = `${request.protocol}://${request.hostname}${parentUrlPath}`;
checkUrl = buildResourceUrl(request, parentUrlPath);

Copilot AI Mar 3, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change adds URL-normalization behavior that affects authorization decisions in subdomain mode (resource URL, parent container URL for writes, and ACL protected resource URL), but there are no automated tests covering the path-based access case that previously returned 403. Since the repo already has WAC integration tests, please add a test that starts the server with { subdomains: true, baseDomain: "example.com" } and verifies that Host: example.com + path-based pod access authorizes the same as Host: <pod>.example.com (including the parent-container check for PUT/POST/PATCH and .acl access).

Copilot uses AI. Check for mistakes.
@melvincarvalho
melvincarvalho merged commit 4d6498f into gh-pages Mar 3, 2026
4 checks passed
@melvincarvalho
melvincarvalho deleted the issue-144-wac-path-based-subdomain-fix branch March 3, 2026 09:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

WAC returns 403 for path-based pod access when subdomains enabled

2 participants