mirror of
https://github.com/yusing/godoxy.git
synced 2026-04-25 09:48:32 +02:00
fix(oidc): correct behavior when working with bypass rules
- Introduced a new handler for unknown paths in the OIDCProvider to prevent fallback to the default login page. - Forced OIDC middleware to treat unknown path as logic path to redirect to login property when bypass rules is declared. - Refactored OIDC path constants. - Updated checkBypass middleware to enforce path prefixes for bypass rules, ensuring proper request handling.
This commit is contained in:
@@ -31,6 +31,8 @@ type (
|
|||||||
endSessionURL *url.URL
|
endSessionURL *url.URL
|
||||||
allowedUsers []string
|
allowedUsers []string
|
||||||
allowedGroups []string
|
allowedGroups []string
|
||||||
|
|
||||||
|
onUnknownPathHandler http.HandlerFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
IDTokenClaims struct {
|
IDTokenClaims struct {
|
||||||
@@ -64,8 +66,9 @@ func (auth *OIDCProvider) getAppScopedCookieName(baseName string) string {
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
OIDCAuthInitPath = "/"
|
OIDCAuthInitPath = "/"
|
||||||
OIDCPostAuthPath = "/auth/callback"
|
OIDCAuthBasePath = "/auth"
|
||||||
OIDCLogoutPath = "/auth/logout"
|
OIDCPostAuthPath = OIDCAuthBasePath + "/callback"
|
||||||
|
OIDCLogoutPath = OIDCAuthBasePath + "/logout"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -177,6 +180,10 @@ func (auth *OIDCProvider) SetScopes(scopes []string) {
|
|||||||
auth.oauthConfig.Scopes = scopes
|
auth.oauthConfig.Scopes = scopes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (auth *OIDCProvider) SetOnUnknownPathHandler(handler http.HandlerFunc) {
|
||||||
|
auth.onUnknownPathHandler = handler
|
||||||
|
}
|
||||||
|
|
||||||
// optRedirectPostAuth returns an oauth2 option that sets the "redirect_uri"
|
// optRedirectPostAuth returns an oauth2 option that sets the "redirect_uri"
|
||||||
// parameter of the authorization URL to the post auth path of the current
|
// parameter of the authorization URL to the post auth path of the current
|
||||||
// request host.
|
// request host.
|
||||||
@@ -213,6 +220,10 @@ func (auth *OIDCProvider) HandleAuth(w http.ResponseWriter, r *http.Request) {
|
|||||||
case OIDCLogoutPath:
|
case OIDCLogoutPath:
|
||||||
auth.LogoutHandler(w, r)
|
auth.LogoutHandler(w, r)
|
||||||
default:
|
default:
|
||||||
|
if auth.onUnknownPathHandler != nil {
|
||||||
|
auth.onUnknownPathHandler(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
http.Redirect(w, r, OIDCAuthInitPath, http.StatusFound)
|
http.Redirect(w, r, OIDCAuthInitPath, http.StatusFound)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ package middleware
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/yusing/godoxy/internal/auth"
|
||||||
"github.com/yusing/godoxy/internal/route/rules"
|
"github.com/yusing/godoxy/internal/route/rules"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -21,17 +23,29 @@ type checkBypass struct {
|
|||||||
bypass Bypass
|
bypass Bypass
|
||||||
modReq RequestModifier
|
modReq RequestModifier
|
||||||
modRes ResponseModifier
|
modRes ResponseModifier
|
||||||
|
|
||||||
|
// when request path matches any of these prefixes, bypass is not applied
|
||||||
|
enforcedPathPrefixes []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *checkBypass) isEnforced(r *http.Request) bool {
|
||||||
|
for _, prefix := range c.enforcedPathPrefixes {
|
||||||
|
if strings.HasPrefix(r.URL.Path, prefix) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *checkBypass) before(w http.ResponseWriter, r *http.Request) (proceedNext bool) {
|
func (c *checkBypass) before(w http.ResponseWriter, r *http.Request) (proceedNext bool) {
|
||||||
if c.modReq == nil || c.bypass.ShouldBypass(w, r) {
|
if c.modReq == nil || (!c.isEnforced(r) && c.bypass.ShouldBypass(w, r)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return c.modReq.before(w, r)
|
return c.modReq.before(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *checkBypass) modifyResponse(resp *http.Response) error {
|
func (c *checkBypass) modifyResponse(resp *http.Response) error {
|
||||||
if c.modRes == nil || c.bypass.ShouldBypass(rules.ResponseAsRW(resp), resp.Request) {
|
if c.modRes == nil || (!c.isEnforced(resp.Request) && c.bypass.ShouldBypass(rules.ResponseAsRW(resp), resp.Request)) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return c.modRes.modifyResponse(resp)
|
return c.modRes.modifyResponse(resp)
|
||||||
@@ -42,10 +56,22 @@ func (m *Middleware) withCheckBypass() any {
|
|||||||
modReq, _ := m.impl.(RequestModifier)
|
modReq, _ := m.impl.(RequestModifier)
|
||||||
modRes, _ := m.impl.(ResponseModifier)
|
modRes, _ := m.impl.(ResponseModifier)
|
||||||
return &checkBypass{
|
return &checkBypass{
|
||||||
bypass: m.Bypass,
|
bypass: m.Bypass,
|
||||||
modReq: modReq,
|
enforcedPathPrefixes: getEnforcedPathPrefixes(modReq, modRes),
|
||||||
modRes: modRes,
|
modReq: modReq,
|
||||||
|
modRes: modRes,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return m.impl
|
return m.impl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getEnforcedPathPrefixes(modReq RequestModifier, modRes ResponseModifier) []string {
|
||||||
|
if modReq == nil && modRes == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
switch modReq.(type) {
|
||||||
|
case *oidcMiddleware:
|
||||||
|
return []string{auth.OIDCAuthBasePath}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -74,6 +74,11 @@ func (amw *oidcMiddleware) initSlow() error {
|
|||||||
}
|
}
|
||||||
// If no custom credentials, authProvider remains the global one
|
// If no custom credentials, authProvider remains the global one
|
||||||
|
|
||||||
|
// Always trigger login on unknown paths.
|
||||||
|
// This prevents falling back to the default login page, which applies bypass rules.
|
||||||
|
// Without this, redirecting to the global login page could circumvent the intended route restrictions.
|
||||||
|
authProvider.SetOnUnknownPathHandler(authProvider.LoginHandler)
|
||||||
|
|
||||||
// Apply per-route user/group restrictions (these always override global)
|
// Apply per-route user/group restrictions (these always override global)
|
||||||
if len(amw.AllowedUsers) > 0 {
|
if len(amw.AllowedUsers) > 0 {
|
||||||
authProvider.SetAllowedUsers(amw.AllowedUsers)
|
authProvider.SetAllowedUsers(amw.AllowedUsers)
|
||||||
|
|||||||
Reference in New Issue
Block a user