Skip to content

fix(acls): auth bypass via forward auth - #1044

Open
scottmckendry wants to merge 2 commits into
mainfrom
fix/auth-bypass-fa
Open

fix(acls): auth bypass via forward auth#1044
scottmckendry wants to merge 2 commits into
mainfrom
fix/auth-bypass-fa

Conversation

@scottmckendry

@scottmckendry scottmckendry commented Jul 27, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • Bug Fixes
    • Improved path-based access control matching for forwarded requests.
    • Path rules now distinguish exact path prefixes from unrelated substrings and query-string values.
    • Root-path blocking and allowing behavior is handled consistently.
    • Invalid forwarded request URIs are rejected safely.
    • Malformed path patterns no longer bypass access restrictions.

Copilot AI review requested due to automatic review settings July 27, 2026 07:31
@dosubot dosubot Bot added the size:XS This PR changes 0-9 lines, ignoring generated files. label Jul 27, 2026
@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2c4d2e1e-b1d4-4bf6-9d54-de42fab8f75f

📥 Commits

Reviewing files that changed from the base of the PR and between 3a377ad and cce0eaa.

📒 Files selected for processing (3)
  • internal/controller/proxy_controller.go
  • internal/service/access_controls_rules.go
  • internal/service/access_controls_rules_test.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • internal/controller/proxy_controller.go
  • internal/service/access_controls_rules.go
  • internal/service/access_controls_rules_test.go

📝 Walkthrough

Walkthrough

Forward-auth now extracts the path component from x-forwarded-uri and applies normalized prefix or delimited-regex ACL matching. Tests cover query-string mismatches, substring paths, root blocking, literal allows, and blocked-path configuration.

Changes

Forward-auth ACL validation

Layer / File(s) Summary
Normalized path ACL matching
internal/service/access_controls_rules.go, internal/service/access_controls_rules_test.go
Path rules now support trimmed comma-separated entries, / wildcards, delimited regexes, and literal prefix matching; related allow/block cases are updated.
Parsed forwarded URI handling and coverage
internal/controller/proxy_controller.go, internal/test/test.go, internal/controller/proxy_controller_test.go
Forwarded URIs are parsed before populating ProxyContext.Path, and controller coverage adds blocked-path, query-string, and substring scenarios.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested reviewers: copilot

Sequence Diagram(s)

sequenceDiagram
  participant Traefik
  participant getForwardAuthContext
  participant AuthEnabledRule
  Traefik->>getForwardAuthContext: Send x-forwarded-uri
  getForwardAuthContext->>getForwardAuthContext: Parse URI and extract Path
  getForwardAuthContext->>AuthEnabledRule: Evaluate path ACL
  AuthEnabledRule-->>Traefik: Return allow or deny
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately reflects the main change: fixing an auth bypass in forward-auth ACL handling.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/auth-bypass-fa

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/controller/proxy_controller_test.go`:
- Around line 290-337: Update the ACL evaluator/matcher used for forwarded
requests to parse x-forwarded-uri and compare ACL path rules against the URL’s
exact path, excluding the query string and preventing substring matches.
Preserve allow matches only for the exact configured path and block only that
exact path so the four tests validate the intended behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 8967dd13-0c82-4c6e-ba02-bd63804bfd00

📥 Commits

Reviewing files that changed from the base of the PR and between c7077a7 and 4d35c25.

📒 Files selected for processing (2)
  • internal/controller/proxy_controller_test.go
  • internal/test/test.go

Comment thread internal/controller/proxy_controller_test.go

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 strengthens the forward-auth (Traefik) ACL regression suite to prevent authentication bypasses where path-based ACLs could be satisfied via forwarded URI query strings or unintended substring matches.

Changes:

  • Adds a new app_path_block test app configuration to exercise block-list path ACL behavior.
  • Adds forward-auth tests ensuring allow/block path ACLs don’t match via query-string injection or path substrings.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
internal/test/test.go Adds a new test app (app_path_block) used by proxy/controller ACL tests.
internal/controller/proxy_controller_test.go Adds forward-auth (Traefik) regression tests for query-string and substring path matching.

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

Comment thread internal/test/test.go
Comment thread internal/controller/proxy_controller_test.go
Copilot AI review requested due to automatic review settings July 27, 2026 07:37
@dosubot dosubot Bot added size:M This PR changes 30-99 lines, ignoring generated files. and removed size:XS This PR changes 0-9 lines, ignoring generated files. labels Jul 27, 2026
@codecov

codecov Bot commented Jul 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 45.94595% with 20 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/service/access_controls_rules.go 65.21% 5 Missing and 3 partials ⚠️
internal/test/test.go 0.00% 8 Missing ⚠️
internal/controller/proxy_controller.go 33.33% 2 Missing and 2 partials ⚠️

📢 Thoughts on this report? Let us know!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/service/access_controls_rules.go`:
- Around line 184-190: Update the configuredPath normalization in Evaluate to
preserve the root value "/" before trimming trailing slashes, ensuring a
path.block of "/" remains available to the root check and matches every request.
Keep empty non-root paths skipped while retaining the existing configuredPath
and path prefix matching behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 96c36242-4ebb-452f-8583-175eb519eb34

📥 Commits

Reviewing files that changed from the base of the PR and between 4d35c25 and be1fb1c.

📒 Files selected for processing (5)
  • internal/controller/proxy_controller.go
  • internal/controller/proxy_controller_test.go
  • internal/service/access_controls_rules.go
  • internal/service/access_controls_rules_test.go
  • internal/test/test.go
💤 Files with no reviewable changes (1)
  • internal/service/access_controls_rules_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • internal/controller/proxy_controller_test.go
  • internal/test/test.go

Comment thread internal/service/access_controls_rules.go Outdated

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 5 out of 5 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (2)

internal/service/access_controls_rules_test.go:533

  • TestAuthEnabledRule no longer validates any of the path allow/block behaviors (match, non-match, allow override for blocked subpaths, etc.). Since the PR changes path matching semantics, this leaves the core ACL rule effectively untested at the service layer.
		{
			name: "denies when no path rules are configured",
			ctx: &ACLContext{
				ACLs: &model.App{},
				Path: "/anything",

internal/controller/proxy_controller_test.go:340

  • There’s no test asserting that a matching blocked path (e.g. /blocked) is actually denied for the forward-auth flow; current additions only verify non-matches. A positive block assertion would catch regressions where block rules become no-ops.
		},
		{
			description: "Ensure path allow ACL works on nginx auth request",
			middlewares: []gin.HandlerFunc{},

Comment thread internal/service/access_controls_rules.go Outdated
Copilot AI review requested due to automatic review settings July 27, 2026 07:43

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 5 out of 5 changed files in this pull request and generated 2 comments.

Comment on lines 209 to 213
if ctx.ACLs.Path.Block != "" {
regex, err := regexp.Compile(ctx.ACLs.Path.Block)

if err != nil {
rule.Log.App.Error().Err(err).Msg("Failed to compile block regex")
return EffectDeny
}
match := matchPathRule(ctx.ACLs.Path.Block, ctx.Path)

if !regex.MatchString(ctx.Path) {
if !match {
return EffectAllow
Comment on lines +393 to +398
parsedURI, err := url.ParseRequestURI(uri)

if err != nil {
return ProxyContext{}, fmt.Errorf("invalid x-forwarded-uri: %w", err)
}

Copilot AI review requested due to automatic review settings July 28, 2026 07:49

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 6 out of 6 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (2)

internal/service/access_controls_rules_test.go:536

  • This test currently asserts that allow path "/public" matches request path "/publicity", which is a substring match (not a subpath match). If allow rules are meant to match exact paths and prefix subpaths (e.g. "/public" and "/public/..."), update this test case to use a real subpath like "/public/index" so it doesn't codify the substring behavior.
				ACLs: &model.App{
					Path: model.AppPath{Allow: "/public"},
				},
				Path: "/publicity",
			},

internal/model/config.go:336

  • The updated field descriptions don’t explain the exact matching semantics (exact path vs subpath) or how to write a regex unambiguously. Given the implementation treats any value that starts and ends with "/" as a regex, it would help to document that prefix matches are segment-aware ("/public" matches "/public" and "/public/...", not "/publicity") and that regexes must be wrapped with leading/trailing slashes (e.g. "/^/public-[0-9]+$/").
type AppPath struct {
	Allow string `description:"Comma-separated list of allowed path prefixes or slash-delimited regular expressions." yaml:"allow,omitempty"`
	Block string `description:"Comma-separated list of blocked path prefixes or slash-delimited regular expressions." yaml:"block,omitempty"`

Comment on lines +210 to +212
if strings.HasPrefix(path, configuredPath) {
return true, nil
}

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/service/access_controls_rules.go`:
- Around line 196-203: Update the path-matching logic around the regex
compilation branch in the access-control rule evaluator so trailing-slash
entries such as "/admin/" remain literal prefix rules rather than being
interpreted as regexes. Introduce and use a non-overlapping regex syntax for
explicitly marked expressions, while preserving regex anchors and adding
allow/block regression coverage for ambiguous literal prefixes and anchored
patterns.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 53485d81-e9e2-4b03-a32f-e6f669f400e3

📥 Commits

Reviewing files that changed from the base of the PR and between 3d5ab54 and 3a377ad.

📒 Files selected for processing (4)
  • internal/controller/proxy_controller.go
  • internal/model/config.go
  • internal/service/access_controls_rules.go
  • internal/service/access_controls_rules_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • internal/controller/proxy_controller.go

Comment on lines +196 to +203
// only apply regex if the path starts and ends with a slash, e.g. /regex/
if strings.HasPrefix(configuredPath, "/") && strings.HasSuffix(configuredPath, "/") {
regex, err := regexp.Compile(configuredPath[1 : len(configuredPath)-1])
if err != nil {
return false, fmt.Errorf("invalid path regex %q: %w", configuredPath, err)
}

if regex.MatchString(path) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

# Inventory potentially ambiguous slash-terminated path rules before changing syntax.
rg -n -i --glob '*.go' --glob '*.yml' --glob '*.yaml' --glob '*.md' \
  '(allow|block)[[:space:]]*[:=][[:space:]]*["'\'']?/[[:alnum:]_.-]+/' .

# Inspect matcher and existing AuthEnabledRule coverage.
rg -n -C3 'regexp\.Compile|MatchString|HasPrefix\(configuredPath' \
  internal/service/access_controls_rules.go
rg -n -C2 'TestAuthEnabledRule|Allow: "/admin/"|Block: "/admin/"' \
  internal/service/access_controls_rules_test.go

Repository: tinyauthapp/tinyauth

Length of output: 821


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '--- access_controls_rules.go relevant section ---\n'
sed -n '150,225p' internal/service/access_controls_rules.go

printf '\n--- TestAuthEnabledRule tests around prefix /admin/public regex ---\n'
sed -n '500,625p' internal/service/access_controls_rules_test.go

printf '\n--- README/docs references for path syntax ---\n'
rg -n -C3 'allow|block|regex|/admin|Access|Auth' README.md docs internal -g '*.md' -g '*.go' 2>/dev/null || true

printf '\n--- Go regexp MatchString behavioral probe for slash delimiters ---\n'
cat >/tmp/rematch.go <<'EOPY'
package main

import (
	"fmt"
	"regexp"
	"strings"
)

func configuredPathMatches(path, configuredPath string) bool {
	if strings.HasPrefix(configuredPath, "/") && strings.HasSuffix(configuredPath, "/") {
		regex, err := regexp.Compile(configuredPath[1 : len(configuredPath)-1])
		if err != nil {
			panic(err)
		}
		return regex.MatchString(path)
	}
	return strings.HasPrefix(path, configuredPath)
}

func main() {
	tests := []struct {
		path             string
		configuredPath   string
		wantAllowByRule  bool
	}{
		{"/admin/public", "/admin/public", true},
		{"/not-admin", "/admin/", true},
		{"/superadmin", "/admin/", true},
		{"/admin", "/admin/", true},
		{"/admin/", "/admin/", true},
	}
	for _, tc := range tests {
		fmt.Printf("%-15s matches config %-15s via %-30s = %v, wantByPrefix=%v\n",
			tc.path, tc.configuredPath,
			func() string {
				p := tc.configuredPath
				if strings.HasPrefix(p, "/") && strings.HasSuffix(p, "/") {
					return fmt.Sprintf("unanchored regex: %q", p[1:len(p)-1])
				}
				return "prefix"
			}(),
			configuredPathMatches(tc.path, tc.configuredPath),
			strings.HasPrefix(tc.path, tc.configuredPath),
		)
	}
}
EOPY
go run /tmp/rematch.go

Repository: tinyauthapp/tinyauth

Length of output: 249


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- access_controls_rules.go relevant section ---'
sed -n '150,225p' internal/service/access_controls_rules.go

printf '%s\n' ''
printf '%s\n' '--- TestAuthEnabledRule tests around prefix /admin/public regex ---'
sed -n '500,625p' internal/service/access_controls_rules_test.go

printf '%s\n' ''
printf '%s\n' '--- README/docs references for path syntax ---'
rg -n -C3 'allow|block|regex|/admin|Access|Auth' README.md docs internal -g '*.md' -g '*.go' 2>/dev/null || true

printf '%s\n' ''
printf '%s\n' '--- Go regexp MatchString behavioral probe for slash delimiters ---'
cat >/tmp/rematch.go <<'EOPY'
package main

import (
	"fmt"
	"regexp"
	"strings"
)

func configuredPathMatches(path, configuredPath string) bool {
	if strings.HasPrefix(configuredPath, "/") && strings.HasSuffix(configuredPath, "/") {
		regex, err := regexp.Compile(configuredPath[1 : len(configuredPath)-1])
		if err != nil {
			panic(err)
		}
		return regex.MatchString(path)
	}
	return strings.HasPrefix(path, configuredPath)
}

func main() {
	tests := []struct {
		path             string
		configuredPath   string
		wantAllowByRule  bool
	}{
		{"/admin/public", "/admin/public", true},
		{"/not-admin", "/admin/", true},
		{"/superadmin", "/admin/", true},
		{"/admin", "/admin/", true},
		{"/admin/", "/admin/", true},
	}
	for _, tc := range tests {
		fmt.Printf("%-15s matches config %-15s via %-30s = %v, wantByPrefix=%v\n",
			tc.path, tc.configuredPath,
			func() string {
				p := tc.configuredPath
				if strings.HasPrefix(p, "/") && strings.HasSuffix(p, "/") {
					return fmt.Sprintf("unanchored regex: %q", p[1:len(p)-1])
				}
				prefix := tc.configuredPath
				if strings.HasPrefix(prefix, "/") && strings.HasSuffix(prefix, "/") {
					prefix = tc.configuredPath[1 : len(tc.configuredPath)-1]
				}
				return fmt.Sprintf("prefix: %q", prefix)
			}(),
			configuredPathMatches(tc.path, tc.configuredPath),
			strings.HasPrefix(tc.path, tc.configuredPath),
		)
	}
}
EOPY
go run /tmp/rematch.go

Repository: tinyauthapp/tinyauth

Length of output: 50377


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- access_controls_rules.go lines 140-220 ---'
sed -n '140,220p' internal/service/access_controls_rules.go

printf '%s\n' ''
printf '%s\n' '--- access_controls_rules_test.go lines 500-620 ---'
sed -n '500,620p' internal/service/access_controls_rules_test.go

printf '%s\n' ''
printf '%s\n' '--- docs/config references for path rules outside internal/service ---'
rg -n -C3 'allow|block|/admin|/.*public|regex|Regex|re:' README.md docs . --glob '*.md' --glob '*.yaml' --glob '*.yml' --glob '*.json' --glob '*.toml' 2>/dev/null | head -n 220 || true

printf '%s\n' ''
printf '%s\n' '--- Go regex behavior probe ---'
cat >/tmp/rematch.go <<'EOPY'
package main

import (
	"fmt"
	"regexp"
	"strings"
)

type case struct {
	path           string
	configuredPath string
}

func main() {
	cases := []case{
		{"/admin/public", "/admin/public"},
		{"/not-admin", "/admin/"},
		{"/superadmin", "/admin/"},
		{"/admin", "/admin/"},
		{"/admin/", "/admin/"},
		{"/login/admin", "/admin/"},
		{"/api/admin/v1", "/admin/"},
	}
	for _, tc := range cases {
		pattern := tc.configuredPath
		mode := "prefix"
		if strings.HasPrefix(tc.configuredPath, "/") && strings.HasSuffix(tc.configuredPath, "/") {
			pattern = tc.configuredPath[1 : len(tc.configuredPath)-1]
			mode = "unanchored_regex"
		}
		got := false
		if mode == "prefix" {
			got = strings.HasPrefix(tc.path, tc.configuredPath)
		} else {
			got = regexp.MustCompile(pattern).MatchString(tc.path)
		}
		want = strings.HasPrefix(tc.path, tc.configuredPath)
		fmt.Printf("%-15s config %-15s %s %q -> match=%v prefix=%v\n",
			tc.path, tc.configuredPath, mode, pattern, got, want)
	}
}
func main(){}
EOPY
go run /tmp/rematch.go 2>&1 || true

Repository: tinyauthapp/tinyauth

Length of output: 19245


Disambiguate regexes from trailing-slash prefixes.

/admin/ is a valid prefix rule but is compiled as unanchored regex admin; allow: /admin/ can therefore grant access to unrelated paths such as /not-admin, bypassing forward auth. Use a non-overlapping regex syntax, keep trailing-slash entries as literal prefixes, and add allow/block regressions for ambiguous literals and regex anchors.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/service/access_controls_rules.go` around lines 196 - 203, Update the
path-matching logic around the regex compilation branch in the access-control
rule evaluator so trailing-slash entries such as "/admin/" remain literal prefix
rules rather than being interpreted as regexes. Introduce and use a
non-overlapping regex syntax for explicitly marked expressions, while preserving
regex anchors and adding allow/block regression coverage for ambiguous literal
prefixes and anchored patterns.

Copilot AI review requested due to automatic review settings July 28, 2026 07:53

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 5 out of 5 changed files in this pull request and generated 1 comment.

Comment on lines +196 to +208
// only apply regex if the path starts and ends with a slash, e.g. /regex/
if strings.HasPrefix(configuredPath, "/") && strings.HasSuffix(configuredPath, "/") {
regex, err := regexp.Compile(configuredPath[1 : len(configuredPath)-1])
if err != nil {
return false, fmt.Errorf("invalid path regex %q: %w", configuredPath, err)
}

if regex.MatchString(path) {
return true, nil
}

continue
}
Comment on lines +184 to +216
func matchPathRule(paths, path string) (bool, error) {
for _, configuredPath := range strings.Split(paths, ",") {
configuredPath = strings.TrimSpace(configuredPath)

if configuredPath == "/" {
return true, nil
}

if configuredPath == "" {
continue
}

// only apply regex if the path starts and ends with a slash, e.g. /regex/
if strings.HasPrefix(configuredPath, "/") && strings.HasSuffix(configuredPath, "/") {
regex, err := regexp.Compile(configuredPath[1 : len(configuredPath)-1])
if err != nil {
return false, fmt.Errorf("invalid path regex %q: %w", configuredPath, err)
}

if regex.MatchString(path) {
return true, nil
}

continue
}

if strings.HasPrefix(path, configuredPath) {
return true, nil
}
}

return false, nil
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@scottmckendry we are changing behavior here and possibly breaking things. The way ACLs for paths should work is the following:

Normal whitelist

In case we have something like:

tinyauth.apps.foo.path.allow: /bar,/foo/bar,/hello

On every request we loop through the rules and check if the request URI has any prefix that matches. For example, /bar and all sub-paths such as /bar/foo/bar will be allowed. This is the current intended behavior.

Regex whitelist

For regex whitelist there is no looping, the check for regex happens before the comma split and we just check if the rule starts and ends with slashes (/). For example this example is allowed:

tinyauth.apps.foo.path.allow: /\/foo|bar/

This is not allowed:

tinyauth.apps.foo.path.allow /\/foo|bar/,/\/test/

There is no need to allow such thing since your comma-seperated whitelist can be recreated using regex and users using regex will know what they are doing. Now, as for how regex is treated, it's a simple match (not a prefix match). It's the user's responsibility to know how to configure regex matching correctly, not ours.

Hopefully this clears things out a bit on how the parsing of the whitelist should work.

Comment on lines +393 to +401
parsedURI, err := url.ParseRequestURI(uri)

if err != nil {
return ProxyContext{}, fmt.Errorf("invalid x-forwarded-uri: %w", err)
}

if parsedURI.Path == "" {
parsedURI.Path = "/"
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We should do this for all auth module types and also strip out the query parameters immediately. Tinyauth won't need them in any part of the authentication chain anyway.

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

Labels

size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants