From 0ace88a8774b8df7499f7fb6d2661b6a738d9a1c Mon Sep 17 00:00:00 2001 From: Stavros Date: Thu, 10 Jul 2025 00:53:22 +0300 Subject: [PATCH] feat: add support for bypassing authentication for specific IPs --- internal/auth/auth.go | 24 ++++++++++++++++++++---- internal/handlers/handlers.go | 24 +++++++++++++++++++++--- internal/types/config.go | 5 +++-- 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/internal/auth/auth.go b/internal/auth/auth.go index 50379e5..d863c69 100644 --- a/internal/auth/auth.go +++ b/internal/auth/auth.go @@ -452,10 +452,7 @@ func (auth *Auth) GetBasicAuth(c *gin.Context) *types.User { } } -func (auth *Auth) CheckIP(c *gin.Context, labels types.Labels) bool { - // Get the IP address from the request - ip := c.ClientIP() - +func (auth *Auth) CheckIP(labels types.Labels, ip string) bool { // Check if the IP is in block list for _, blocked := range labels.IP.Block { res, err := utils.FilterIP(blocked, ip) @@ -492,3 +489,22 @@ func (auth *Auth) CheckIP(c *gin.Context, labels types.Labels) bool { return true } + +func (auth *Auth) BypassedIP(labels types.Labels, ip string) bool { + // For every IP in the bypass list, check if the IP matches + for _, bypassed := range labels.IP.Bypass { + res, err := utils.FilterIP(bypassed, ip) + if err != nil { + log.Warn().Err(err).Str("item", bypassed).Msg("Invalid IP/CIDR in bypass list") + continue + } + if res { + log.Debug().Str("ip", ip).Str("item", bypassed).Msg("IP is in bypass list, allowing access") + return true + } + } + + log.Debug().Str("ip", ip).Msg("IP not in bypass list, continuing with authentication") + + return false +} diff --git a/internal/handlers/handlers.go b/internal/handlers/handlers.go index 87d1f8d..495c7d8 100644 --- a/internal/handlers/handlers.go +++ b/internal/handlers/handlers.go @@ -96,11 +96,29 @@ func (h *Handlers) AuthHandler(c *gin.Context) { return } - // Check if the IP is allowed/blocked + // Get client IP ip := c.ClientIP() - if !h.Auth.CheckIP(c, labels) { - log.Warn().Str("ip", ip).Msg("IP not allowed") + // Check if the IP is in bypass list + if h.Auth.BypassedIP(labels, ip) { + headersParsed := utils.ParseHeaders(labels.Headers) + for key, value := range headersParsed { + log.Debug().Str("key", key).Msg("Setting header") + c.Header(key, value) + } + if labels.Basic.Username != "" && utils.GetSecret(labels.Basic.Password.Plain, labels.Basic.Password.File) != "" { + log.Debug().Str("username", labels.Basic.Username).Msg("Setting basic auth headers") + c.Header("Authorization", fmt.Sprintf("Basic %s", utils.GetBasicAuth(labels.Basic.Username, utils.GetSecret(labels.Basic.Password.Plain, labels.Basic.Password.File)))) + } + c.JSON(200, gin.H{ + "status": 200, + "message": "Authenticated", + }) + return + } + + // Check if the IP is allowed/blocked + if !h.Auth.CheckIP(labels, ip) { if proxy.Proxy == "nginx" || !isBrowser { c.JSON(403, gin.H{ "status": 403, diff --git a/internal/types/config.go b/internal/types/config.go index 2a9683d..a09a59e 100644 --- a/internal/types/config.go +++ b/internal/types/config.go @@ -120,8 +120,9 @@ type PassowrdLabels struct { // IP labels for a tinyauth protected container type IPLabels struct { - Allow []string - Block []string + Allow []string + Block []string + Bypass []string } // Labels is a struct that contains the labels for a tinyauth protected container