From dbae827e3520a2ec86a952b56b079504b087a5d1 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 28 Nov 2025 21:17:57 -0800 Subject: [PATCH] Refactor reverseproxy configuration --- modules/setting/reverseproxy.go | 37 +++++++++++++++++++++++++++++++++ modules/setting/security.go | 15 ------------- modules/setting/service.go | 10 --------- modules/setting/setting.go | 1 + options/locale/locale_en-US.ini | 13 +++++++++++- routers/api/packages/api.go | 2 +- routers/api/v1/api.go | 4 ++-- routers/common/middleware.go | 4 ++-- routers/web/admin/config.go | 4 ++-- routers/web/web.go | 2 +- services/auth/reverseproxy.go | 16 +++++++------- templates/admin/config.tmpl | 33 +++++++++++++++++++++++++++-- 12 files changed, 97 insertions(+), 44 deletions(-) create mode 100644 modules/setting/reverseproxy.go diff --git a/modules/setting/reverseproxy.go b/modules/setting/reverseproxy.go new file mode 100644 index 0000000000000..67d0966dbf24b --- /dev/null +++ b/modules/setting/reverseproxy.go @@ -0,0 +1,37 @@ +// Copyright 2025 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package setting + +var ReverseProxy = struct { + EnableAuth bool + EnableAuthAPI bool + EnableAutoRegister bool + EnableEmail bool + EnableFullName bool + + AuthUser string + AuthEmail string + AuthFullName string + Limit int + TrustedProxies []string +}{} + +func loadReverseProxyFrom(rootCfg ConfigProvider) { + serviceSec := rootCfg.Section("service") + ReverseProxy.EnableAuth = serviceSec.Key("ENABLE_REVERSE_PROXY_AUTHENTICATION").MustBool() + ReverseProxy.EnableAuthAPI = serviceSec.Key("ENABLE_REVERSE_PROXY_AUTHENTICATION_API").MustBool() + ReverseProxy.EnableAutoRegister = serviceSec.Key("ENABLE_REVERSE_PROXY_AUTO_REGISTRATION").MustBool() + ReverseProxy.EnableEmail = serviceSec.Key("ENABLE_REVERSE_PROXY_EMAIL").MustBool() + ReverseProxy.EnableFullName = serviceSec.Key("ENABLE_REVERSE_PROXY_FULL_NAME").MustBool() + + securitySec := rootCfg.Section("security") + ReverseProxy.AuthUser = securitySec.Key("REVERSE_PROXY_AUTHENTICATION_USER").MustString("X-WEBAUTH-USER") + ReverseProxy.AuthEmail = securitySec.Key("REVERSE_PROXY_AUTHENTICATION_EMAIL").MustString("X-WEBAUTH-EMAIL") + ReverseProxy.AuthFullName = securitySec.Key("REVERSE_PROXY_AUTHENTICATION_FULL_NAME").MustString("X-WEBAUTH-FULLNAME") + ReverseProxy.Limit = securitySec.Key("REVERSE_PROXY_LIMIT").MustInt(1) + ReverseProxy.TrustedProxies = securitySec.Key("REVERSE_PROXY_TRUSTED_PROXIES").Strings(",") + if len(ReverseProxy.TrustedProxies) == 0 { + ReverseProxy.TrustedProxies = []string{"127.0.0.0/8", "::1/128"} + } +} diff --git a/modules/setting/security.go b/modules/setting/security.go index 153b6bc944ff5..c29f0c7a2a55e 100644 --- a/modules/setting/security.go +++ b/modules/setting/security.go @@ -21,11 +21,6 @@ var ( InternalToken string // internal access token LogInRememberDays int CookieRememberName string - ReverseProxyAuthUser string - ReverseProxyAuthEmail string - ReverseProxyAuthFullName string - ReverseProxyLimit int - ReverseProxyTrustedProxies []string MinPasswordLength int ImportLocalPaths bool DisableGitHooks = true @@ -116,16 +111,6 @@ func loadSecurityFrom(rootCfg ConfigProvider) { CookieRememberName = sec.Key("COOKIE_REMEMBER_NAME").MustString("gitea_incredible") - ReverseProxyAuthUser = sec.Key("REVERSE_PROXY_AUTHENTICATION_USER").MustString("X-WEBAUTH-USER") - ReverseProxyAuthEmail = sec.Key("REVERSE_PROXY_AUTHENTICATION_EMAIL").MustString("X-WEBAUTH-EMAIL") - ReverseProxyAuthFullName = sec.Key("REVERSE_PROXY_AUTHENTICATION_FULL_NAME").MustString("X-WEBAUTH-FULLNAME") - - ReverseProxyLimit = sec.Key("REVERSE_PROXY_LIMIT").MustInt(1) - ReverseProxyTrustedProxies = sec.Key("REVERSE_PROXY_TRUSTED_PROXIES").Strings(",") - if len(ReverseProxyTrustedProxies) == 0 { - ReverseProxyTrustedProxies = []string{"127.0.0.0/8", "::1/128"} - } - MinPasswordLength = sec.Key("MIN_PASSWORD_LENGTH").MustInt(8) ImportLocalPaths = sec.Key("IMPORT_LOCAL_PATHS").MustBool(false) DisableGitHooks = sec.Key("DISABLE_GIT_HOOKS").MustBool(true) diff --git a/modules/setting/service.go b/modules/setting/service.go index e652c13c9c9e3..071eed258b028 100644 --- a/modules/setting/service.go +++ b/modules/setting/service.go @@ -48,11 +48,6 @@ var Service = struct { EnableNotifyMail bool EnableBasicAuth bool EnablePasskeyAuth bool - EnableReverseProxyAuth bool - EnableReverseProxyAuthAPI bool - EnableReverseProxyAutoRegister bool - EnableReverseProxyEmail bool - EnableReverseProxyFullName bool EnableCaptcha bool RequireCaptchaForLogin bool RequireExternalRegistrationCaptcha bool @@ -182,11 +177,6 @@ func loadServiceFrom(rootCfg ConfigProvider) { Service.EnableBasicAuth = sec.Key("ENABLE_BASIC_AUTHENTICATION").MustBool(true) Service.EnablePasswordSignInForm = sec.Key("ENABLE_PASSWORD_SIGNIN_FORM").MustBool(true) Service.EnablePasskeyAuth = sec.Key("ENABLE_PASSKEY_AUTHENTICATION").MustBool(true) - Service.EnableReverseProxyAuth = sec.Key("ENABLE_REVERSE_PROXY_AUTHENTICATION").MustBool() - Service.EnableReverseProxyAuthAPI = sec.Key("ENABLE_REVERSE_PROXY_AUTHENTICATION_API").MustBool() - Service.EnableReverseProxyAutoRegister = sec.Key("ENABLE_REVERSE_PROXY_AUTO_REGISTRATION").MustBool() - Service.EnableReverseProxyEmail = sec.Key("ENABLE_REVERSE_PROXY_EMAIL").MustBool() - Service.EnableReverseProxyFullName = sec.Key("ENABLE_REVERSE_PROXY_FULL_NAME").MustBool() Service.EnableCaptcha = sec.Key("ENABLE_CAPTCHA").MustBool(false) Service.RequireCaptchaForLogin = sec.Key("REQUIRE_CAPTCHA_FOR_LOGIN").MustBool(false) Service.RequireExternalRegistrationCaptcha = sec.Key("REQUIRE_EXTERNAL_REGISTRATION_CAPTCHA").MustBool(Service.EnableCaptcha) diff --git a/modules/setting/setting.go b/modules/setting/setting.go index e14997801fed4..b95c42ae27822 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -118,6 +118,7 @@ func loadCommonSettingsFrom(cfg ConfigProvider) error { loadOAuth2From(cfg) loadSecurityFrom(cfg) + loadReverseProxyFrom(cfg) if err := loadAttachmentFrom(cfg); err != nil { return err } diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index b5b90b31a53cb..aaaf4ad3213f9 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -3341,7 +3341,18 @@ config.repo_root_path = Repository Root Path config.lfs_root_path = LFS Root Path config.log_file_root_path = Log Path config.script_type = Script Type -config.reverse_auth_user = Reverse Authentication User + +config.reverseproxy_config = Reverse Proxy Configuration +config.reverseproxy_enable_auth = Enable Reverse Proxy Authentication +config.reverseproxy_enable_auth_api = Enable Reverse Proxy Authentication for API +config.reverseproxy_enable_auto_register = Enable Reverse Proxy Auto Registration +config.reverseproxy_enable_email = Enable Reverse Proxy Email +config.reverseproxy_enable_full_name = Enable Reverse Proxy Full Name +config.reverseproxy_auth_user = Reverse Authentication User +config.reverseproxy_auth_email = Reverse Authentication Email +config.reverseproxy_auth_full_name = Reverse Authentication Full Name +config.reverseproxy_limit = Reverse Proxy Limit +config.reverseproxy_trusted_proxies = Reverse Proxy Trusted Proxies config.ssh_config = SSH Configuration config.ssh_enabled = Enabled diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go index f6ee5958b5bb9..29a9411ab730e 100644 --- a/routers/api/packages/api.go +++ b/routers/api/packages/api.go @@ -89,7 +89,7 @@ func reqPackageAccess(accessMode perm.AccessMode) func(ctx *context.Context) { } func verifyAuth(r *web.Router, authMethods []auth.Method) { - if setting.Service.EnableReverseProxyAuth { + if setting.ReverseProxy.EnableAuth { authMethods = append(authMethods, &auth.ReverseProxy{}) } authGroup := auth.NewGroup(authMethods...) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 8e07685759803..b9e763a19bce1 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -379,7 +379,7 @@ func reqUsersExploreEnabled() func(ctx *context.APIContext) { func reqBasicOrRevProxyAuth() func(ctx *context.APIContext) { return func(ctx *context.APIContext) { - if ctx.IsSigned && setting.Service.EnableReverseProxyAuthAPI && ctx.Data["AuthedMethod"].(string) == auth.ReverseProxyMethodName { + if ctx.IsSigned && setting.ReverseProxy.EnableAuthAPI && ctx.Data["AuthedMethod"].(string) == auth.ReverseProxyMethodName { return } if !ctx.IsBasicAuth { @@ -760,7 +760,7 @@ func buildAuthGroup() *auth.Group { &auth.HTTPSign{}, &auth.Basic{}, // FIXME: this should be removed once we don't allow basic auth in API ) - if setting.Service.EnableReverseProxyAuthAPI { + if setting.ReverseProxy.EnableAuthAPI { group.Add(&auth.ReverseProxy{}) } diff --git a/routers/common/middleware.go b/routers/common/middleware.go index bfa258b976552..8330e2d1040d9 100644 --- a/routers/common/middleware.go +++ b/routers/common/middleware.go @@ -28,8 +28,8 @@ func ProtocolMiddlewares() (handlers []any) { handlers = append(handlers, ChiRoutePathHandler()) // make sure chi has correct paths handlers = append(handlers, RequestContextHandler()) // prepare the context and panic recovery - if setting.ReverseProxyLimit > 0 && len(setting.ReverseProxyTrustedProxies) > 0 { - handlers = append(handlers, ForwardedHeadersHandler(setting.ReverseProxyLimit, setting.ReverseProxyTrustedProxies)) + if setting.ReverseProxy.Limit > 0 && len(setting.ReverseProxy.TrustedProxies) > 0 { + handlers = append(handlers, ForwardedHeadersHandler(setting.ReverseProxy.Limit, setting.ReverseProxy.TrustedProxies)) } if setting.IsRouteLogEnabled() { diff --git a/routers/web/admin/config.go b/routers/web/admin/config.go index 774b31ab9842a..1db1e03da8467 100644 --- a/routers/web/admin/config.go +++ b/routers/web/admin/config.go @@ -136,8 +136,8 @@ func Config(ctx *context.Context) { ctx.Data["CustomRootPath"] = setting.CustomPath ctx.Data["LogRootPath"] = setting.Log.RootPath ctx.Data["ScriptType"] = setting.ScriptType - ctx.Data["ReverseProxyAuthUser"] = setting.ReverseProxyAuthUser - ctx.Data["ReverseProxyAuthEmail"] = setting.ReverseProxyAuthEmail + + ctx.Data["ReverseProxy"] = setting.ReverseProxy ctx.Data["SSH"] = setting.SSH ctx.Data["LFS"] = setting.LFS diff --git a/routers/web/web.go b/routers/web/web.go index dd1b391c68983..f8592b5bfde2e 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -102,7 +102,7 @@ func buildAuthGroup() *auth_service.Group { group.Add(&auth_service.OAuth2{}) // FIXME: this should be removed and only applied in download and oauth related routers group.Add(&auth_service.Basic{}) // FIXME: this should be removed and only applied in download and git/lfs routers - if setting.Service.EnableReverseProxyAuth { + if setting.ReverseProxy.EnableAuth { group.Add(&auth_service.ReverseProxy{}) // reverse-proxy should before Session, otherwise the header will be ignored if user has login } group.Add(&auth_service.Session{}) diff --git a/services/auth/reverseproxy.go b/services/auth/reverseproxy.go index d6664d738de81..c78324a992c2e 100644 --- a/services/auth/reverseproxy.go +++ b/services/auth/reverseproxy.go @@ -33,7 +33,7 @@ type ReverseProxy struct{} // getUserName extracts the username from the "setting.ReverseProxyAuthUser" header func (r *ReverseProxy) getUserName(req *http.Request) string { - return strings.TrimSpace(req.Header.Get(setting.ReverseProxyAuthUser)) + return strings.TrimSpace(req.Header.Get(setting.ReverseProxy.AuthUser)) } // Name represents the name of auth method @@ -68,7 +68,7 @@ func (r *ReverseProxy) getUserFromAuthUser(req *http.Request) (*user_model.User, // getEmail extracts the email from the "setting.ReverseProxyAuthEmail" header func (r *ReverseProxy) getEmail(req *http.Request) string { - return strings.TrimSpace(req.Header.Get(setting.ReverseProxyAuthEmail)) + return strings.TrimSpace(req.Header.Get(setting.ReverseProxy.AuthEmail)) } // getUserFromAuthEmail extracts the username from the "setting.ReverseProxyAuthEmail" header @@ -79,7 +79,7 @@ func (r *ReverseProxy) getEmail(req *http.Request) string { // user object is returned (populated with the email found in header). // Returns nil if header is empty or if "setting.EnableReverseProxyEmail" is disabled. func (r *ReverseProxy) getUserFromAuthEmail(req *http.Request) *user_model.User { - if !setting.Service.EnableReverseProxyEmail { + if !setting.ReverseProxy.EnableEmail { return nil } email := r.getEmail(req) @@ -130,7 +130,7 @@ func (r *ReverseProxy) Verify(req *http.Request, w http.ResponseWriter, store Da // isAutoRegisterAllowed checks if EnableReverseProxyAutoRegister setting is true func (r *ReverseProxy) isAutoRegisterAllowed() bool { - return setting.Service.EnableReverseProxyAutoRegister + return setting.ReverseProxy.EnableAutoRegister } // newUser creates a new user object for the purpose of automatic registration @@ -142,16 +142,16 @@ func (r *ReverseProxy) newUser(req *http.Request) *user_model.User { } email := gouuid.New().String() + "@localhost" - if setting.Service.EnableReverseProxyEmail { - webAuthEmail := req.Header.Get(setting.ReverseProxyAuthEmail) + if setting.ReverseProxy.EnableEmail { + webAuthEmail := req.Header.Get(setting.ReverseProxy.AuthEmail) if len(webAuthEmail) > 0 { email = webAuthEmail } } var fullname string - if setting.Service.EnableReverseProxyFullName { - fullname = req.Header.Get(setting.ReverseProxyAuthFullName) + if setting.ReverseProxy.EnableFullName { + fullname = req.Header.Get(setting.ReverseProxy.AuthFullName) } user := &user_model.User{ diff --git a/templates/admin/config.tmpl b/templates/admin/config.tmpl index 080b2cd3d6bab..18b2f5133ed1e 100644 --- a/templates/admin/config.tmpl +++ b/templates/admin/config.tmpl @@ -44,11 +44,40 @@
{{.LogRootPath}}
{{ctx.Locale.Tr "admin.config.script_type"}}
{{.ScriptType}}
-
{{ctx.Locale.Tr "admin.config.reverse_auth_user"}}
-
{{.ReverseProxyAuthUser}}
+ {{if or .ReverseProxy.EnableAuth .ReverseProxy.EnableAuthAPI}} +

+ {{ctx.Locale.Tr "admin.config.reverseproxy_config"}} +

+
+
+
{{ctx.Locale.Tr "admin.config.reverseproxy_enable_auth"}}
+
{{.ReverseProxy.EnableAuth}}
+
{{ctx.Locale.Tr "admin.config.reverseproxy_enable_auth_api"}}
+
{{.ReverseProxy.EnableAuthAPI}}
+
{{ctx.Locale.Tr "admin.config.reverseproxy_enable_auto_register"}}
+
{{.ReverseProxy.EnableAutoRegister}}
+
{{ctx.Locale.Tr "admin.config.reverseproxy_enable_email"}}
+
{{.ReverseProxy.EnableEmail}}
+
{{ctx.Locale.Tr "admin.config.reverseproxy_enable_full_name"}}
+
{{.ReverseProxy.EnableFullName}}
+ +
{{ctx.Locale.Tr "admin.config.reverseproxy_auth_user"}}
+
{{.ReverseProxy.AuthUser}}
+
{{ctx.Locale.Tr "admin.config.reverseproxy_auth_email"}}
+
{{.ReverseProxy.AuthEmail}}
+
{{ctx.Locale.Tr "admin.config.reverseproxy_auth_full_name"}}
+
{{.ReverseProxy.AuthFullName}}
+
{{ctx.Locale.Tr "admin.config.reverseproxy_limit"}}
+
{{.ReverseProxy.Limit}}
+
{{ctx.Locale.Tr "admin.config.reverseproxy_trusted_proxies"}}
+
{{.ReverseProxy.TrustedProxies}}
+
+
+ {{end}} +

{{ctx.Locale.Tr "admin.config.ssh_config"}}