mirror of
https://github.com/tinyauthapp/tinyauth.git
synced 2026-08-30 01:53:31 +08:00
fix(acls): auth bypass via forward auth
This commit is contained in:
@@ -2,7 +2,6 @@ package service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/tinyauthapp/tinyauth/internal/model"
|
||||
@@ -180,33 +179,45 @@ type AuthEnabledRule struct {
|
||||
Log *logger.Logger
|
||||
}
|
||||
|
||||
func matchPathRule(paths, path string) bool {
|
||||
for _, configuredPath := range strings.Split(paths, ",") {
|
||||
configuredPath = strings.TrimSpace(configuredPath)
|
||||
|
||||
if configuredPath == "/" {
|
||||
return true
|
||||
}
|
||||
|
||||
configuredPath = strings.TrimRight(configuredPath, "/")
|
||||
|
||||
if configuredPath == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
if path == configuredPath || strings.HasPrefix(path, configuredPath+"/") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (rule *AuthEnabledRule) Evaluate(ctx *ACLContext) Effect {
|
||||
if ctx.ACLs == nil {
|
||||
return EffectDeny
|
||||
}
|
||||
|
||||
if ctx.ACLs.Path.Block != "" {
|
||||
regex, err := regexp.Compile(ctx.ACLs.Path.Block)
|
||||
match := matchPathRule(ctx.ACLs.Path.Block, ctx.Path)
|
||||
|
||||
if err != nil {
|
||||
rule.Log.App.Error().Err(err).Msg("Failed to compile block regex")
|
||||
return EffectDeny
|
||||
}
|
||||
|
||||
if !regex.MatchString(ctx.Path) {
|
||||
if !match {
|
||||
return EffectAllow
|
||||
}
|
||||
}
|
||||
|
||||
if ctx.ACLs.Path.Allow != "" {
|
||||
regex, err := regexp.Compile(ctx.ACLs.Path.Allow)
|
||||
match := matchPathRule(ctx.ACLs.Path.Allow, ctx.Path)
|
||||
|
||||
if err != nil {
|
||||
rule.Log.App.Error().Err(err).Msg("Failed to compile allow regex")
|
||||
return EffectDeny
|
||||
}
|
||||
|
||||
if regex.MatchString(ctx.Path) {
|
||||
if match {
|
||||
return EffectAllow
|
||||
}
|
||||
}
|
||||
|
||||
@@ -527,52 +527,52 @@ func TestAuthEnabledRule(t *testing.T) {
|
||||
expected: EffectDeny,
|
||||
},
|
||||
{
|
||||
name: "allows when path does not match block regex",
|
||||
name: "allows when path does not match block path",
|
||||
ctx: &ACLContext{
|
||||
ACLs: &model.App{
|
||||
Path: model.AppPath{Block: "^/admin"},
|
||||
Path: model.AppPath{Block: "/admin"},
|
||||
},
|
||||
Path: "/public",
|
||||
},
|
||||
expected: EffectAllow,
|
||||
},
|
||||
{
|
||||
name: "denies when path matches block regex and no allow regex",
|
||||
name: "denies when path matches block path",
|
||||
ctx: &ACLContext{
|
||||
ACLs: &model.App{
|
||||
Path: model.AppPath{Block: "^/admin"},
|
||||
Path: model.AppPath{Block: "/admin"},
|
||||
},
|
||||
Path: "/admin/users",
|
||||
},
|
||||
expected: EffectDeny,
|
||||
},
|
||||
{
|
||||
name: "allows when path matches allow regex",
|
||||
name: "allows when path matches allow path",
|
||||
ctx: &ACLContext{
|
||||
ACLs: &model.App{
|
||||
Path: model.AppPath{Allow: "^/public"},
|
||||
Path: model.AppPath{Allow: "/public"},
|
||||
},
|
||||
Path: "/public/index",
|
||||
},
|
||||
expected: EffectAllow,
|
||||
},
|
||||
{
|
||||
name: "denies when path does not match allow regex",
|
||||
name: "denies when path does not match allow path",
|
||||
ctx: &ACLContext{
|
||||
ACLs: &model.App{
|
||||
Path: model.AppPath{Allow: "^/public"},
|
||||
Path: model.AppPath{Allow: "/public"},
|
||||
},
|
||||
Path: "/private",
|
||||
},
|
||||
expected: EffectDeny,
|
||||
},
|
||||
{
|
||||
name: "allows when blocked path is also explicitly allowed",
|
||||
name: "allows when blocked path is explicitly allowed",
|
||||
ctx: &ACLContext{
|
||||
ACLs: &model.App{
|
||||
Path: model.AppPath{
|
||||
Block: "^/admin",
|
||||
Allow: "^/admin/public",
|
||||
Block: "/admin",
|
||||
Allow: "/admin/public",
|
||||
},
|
||||
},
|
||||
Path: "/admin/public/page",
|
||||
@@ -580,20 +580,10 @@ func TestAuthEnabledRule(t *testing.T) {
|
||||
expected: EffectAllow,
|
||||
},
|
||||
{
|
||||
name: "denies when block regex fails to compile",
|
||||
name: "denies when root is blocked",
|
||||
ctx: &ACLContext{
|
||||
ACLs: &model.App{
|
||||
Path: model.AppPath{Block: "[invalid"},
|
||||
},
|
||||
Path: "/anything",
|
||||
},
|
||||
expected: EffectDeny,
|
||||
},
|
||||
{
|
||||
name: "denies when allow regex fails to compile",
|
||||
ctx: &ACLContext{
|
||||
ACLs: &model.App{
|
||||
Path: model.AppPath{Allow: "[invalid"},
|
||||
Path: model.AppPath{Block: "/"},
|
||||
},
|
||||
Path: "/anything",
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user