Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions modules/setting/reverseproxy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package setting

var ReverseProxyAuth = struct {
Enabled bool
EnableReverseProxyAuthAPI bool
EnableReverseProxyAutoRegister bool
EnableReverseProxyEmail bool
EnableReverseProxyFullName bool
ReverseProxyAuthUser string
ReverseProxyAuthEmail string
ReverseProxyAuthFullName string
ReverseProxyLimit int
ReverseProxyTrustedProxies []string
}{}

func loadReverseProxyAuthFrom(rootCfg ConfigProvider) {
serviceSec := rootCfg.Section("service")

ReverseProxyAuth.Enabled = serviceSec.Key("ENABLE_REVERSE_PROXY_AUTHENTICATION").MustBool()
ReverseProxyAuth.EnableReverseProxyAuthAPI = serviceSec.Key("ENABLE_REVERSE_PROXY_AUTHENTICATION_API").MustBool()
ReverseProxyAuth.EnableReverseProxyAutoRegister = serviceSec.Key("ENABLE_REVERSE_PROXY_AUTO_REGISTRATION").MustBool()
ReverseProxyAuth.EnableReverseProxyEmail = serviceSec.Key("ENABLE_REVERSE_PROXY_EMAIL").MustBool()
ReverseProxyAuth.EnableReverseProxyFullName = serviceSec.Key("ENABLE_REVERSE_PROXY_FULL_NAME").MustBool()

securitySec := rootCfg.Section("security")
ReverseProxyAuth.ReverseProxyAuthUser = securitySec.Key("REVERSE_PROXY_AUTHENTICATION_USER").MustString("X-WEBAUTH-USER")
ReverseProxyAuth.ReverseProxyAuthEmail = securitySec.Key("REVERSE_PROXY_AUTHENTICATION_EMAIL").MustString("X-WEBAUTH-EMAIL")
ReverseProxyAuth.ReverseProxyAuthFullName = securitySec.Key("REVERSE_PROXY_AUTHENTICATION_FULL_NAME").MustString("X-WEBAUTH-FULLNAME")

ReverseProxyAuth.ReverseProxyLimit = securitySec.Key("REVERSE_PROXY_LIMIT").MustInt(1)
ReverseProxyAuth.ReverseProxyTrustedProxies = securitySec.Key("REVERSE_PROXY_TRUSTED_PROXIES").Strings(",")
if len(ReverseProxyAuth.ReverseProxyTrustedProxies) == 0 {
ReverseProxyAuth.ReverseProxyTrustedProxies = []string{"127.0.0.0/8", "::1/128"}
}
}
26 changes: 6 additions & 20 deletions modules/setting/security.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,12 @@ import (

var (
// Security settings
InstallLock bool
SecretKey string
InternalToken string // internal access token
LogInRememberDays int
CookieRememberName string
ReverseProxyAuthUser string
ReverseProxyAuthEmail string
ReverseProxyAuthFullName string
ReverseProxyLimit int
ReverseProxyTrustedProxies []string
InstallLock bool
SecretKey string
InternalToken string // internal access token
LogInRememberDays int
CookieRememberName string

MinPasswordLength int
ImportLocalPaths bool
DisableGitHooks bool
Expand Down Expand Up @@ -114,16 +110,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)
Expand Down
11 changes: 1 addition & 10 deletions modules/setting/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,6 @@ var Service = struct {
RequireSignInView bool
EnableNotifyMail bool
EnableBasicAuth bool
EnableReverseProxyAuth bool
EnableReverseProxyAuthAPI bool
EnableReverseProxyAutoRegister bool
EnableReverseProxyEmail bool
EnableReverseProxyFullName bool
EnableCaptcha bool
RequireCaptchaForLogin bool
RequireExternalRegistrationCaptcha bool
Expand Down Expand Up @@ -157,11 +152,7 @@ func loadServiceFrom(rootCfg ConfigProvider) {
Service.ShowMilestonesDashboardPage = sec.Key("SHOW_MILESTONES_DASHBOARD_PAGE").MustBool(true)
Service.RequireSignInView = sec.Key("REQUIRE_SIGNIN_VIEW").MustBool()
Service.EnableBasicAuth = sec.Key("ENABLE_BASIC_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)
Expand Down
2 changes: 2 additions & 0 deletions modules/setting/setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ func LoadSettings() {

loadDBSetting(CfgProvider)
loadServiceFrom(CfgProvider)
loadReverseProxyAuthFrom(CfgProvider)
loadOAuth2ClientFrom(CfgProvider)
loadCacheFrom(CfgProvider)
loadSessionFrom(CfgProvider)
Expand All @@ -223,6 +224,7 @@ func LoadSettings() {
func LoadSettingsForInstall() {
loadDBSetting(CfgProvider)
loadServiceFrom(CfgProvider)
loadReverseProxyAuthFrom(CfgProvider)
loadMailerFrom(CfgProvider)
}

Expand Down
11 changes: 10 additions & 1 deletion options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -3196,7 +3196,16 @@ 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.reverse_proxy_auth_config = Reverse Proxy Authentication Configuration
config.reverse_proxy_auth_user = Authentication User
config.reverse_proxy_auth_email = Authentication Email
config.reverse_proxy_auth_fullname = Authentication Fullname
config.reverse_proxy_auth_limit = Authentication Limit
config.reverse_proxy_auth_trusted_proxies = Authentication Trusted Proxies
config.reverse_proxy_auth_enable_api = Enable Authentication API
config.reverse_proxy_auth_enable_autoregister = Enable Authentication Auto Register
config.reverse_proxy_auth_enable_email = Enable Authentication Email
config.reverse_proxy_auth_enable_fullname = Enable Authentication Fullname

config.ssh_config = SSH Configuration
config.ssh_enabled = Enabled
Expand Down
2 changes: 1 addition & 1 deletion routers/api/packages/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func reqPackageAccess(accessMode perm.AccessMode) func(ctx *context.Context) {
}

func verifyAuth(r *web.Router, authMethods []auth.Method) {
if setting.Service.EnableReverseProxyAuth {
if setting.ReverseProxyAuth.Enabled {
authMethods = append(authMethods, &auth.ReverseProxy{})
}
authGroup := auth.NewGroup(authMethods...)
Expand Down
4 changes: 2 additions & 2 deletions routers/api/v1/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ func reqExploreSignIn() 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.ReverseProxyAuth.EnableReverseProxyAuthAPI && ctx.Data["AuthedMethod"].(string) == auth.ReverseProxyMethodName {
return
}
if !ctx.IsBasicAuth {
Expand Down Expand Up @@ -700,7 +700,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.ReverseProxyAuth.EnableReverseProxyAuthAPI {
group.Add(&auth.ReverseProxy{})
}

Expand Down
6 changes: 3 additions & 3 deletions routers/common/middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,11 @@ func ProtocolMiddlewares() (handlers []any) {
})
})

if setting.ReverseProxyLimit > 0 {
if setting.ReverseProxyAuth.ReverseProxyLimit > 0 {
opt := proxy.NewForwardedHeadersOptions().
WithForwardLimit(setting.ReverseProxyLimit).
WithForwardLimit(setting.ReverseProxyAuth.ReverseProxyLimit).
ClearTrustedProxies()
for _, n := range setting.ReverseProxyTrustedProxies {
for _, n := range setting.ReverseProxyAuth.ReverseProxyTrustedProxies {
if !strings.Contains(n, "/") {
opt.AddTrustedProxy(n)
} else {
Expand Down
3 changes: 1 addition & 2 deletions routers/web/admin/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +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["ReverseProxyAuth"] = setting.ReverseProxyAuth
ctx.Data["SSH"] = setting.SSH
ctx.Data["LFS"] = setting.LFS

Expand Down
2 changes: 1 addition & 1 deletion routers/web/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.ReverseProxyAuth.Enabled {
group.Add(&auth_service.ReverseProxy{}) // reverseproxy should before Session, otherwise the header will be ignored if user has login
}
group.Add(&auth_service.Session{})
Expand Down
24 changes: 12 additions & 12 deletions services/auth/reverseproxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,25 @@ const ReverseProxyMethodName = "reverse_proxy"
// ReverseProxy implements the Auth interface, but actually relies on
// a reverse proxy for authentication of users.
// On successful authentication the proxy is expected to populate the username in the
// "setting.ReverseProxyAuthUser" header. Optionally it can also populate the email of the
// "setting.ReverseProxyAuth.ReverseProxyAuthUser" header. Optionally it can also populate the email of the
// user in the "setting.ReverseProxyAuthEmail" header.
type ReverseProxy struct{}

// getUserName extracts the username from the "setting.ReverseProxyAuthUser" header
// getUserName extracts the username from the "setting.ReverseProxyAuth.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.ReverseProxyAuth.ReverseProxyAuthUser))
}

// Name represents the name of auth method
func (r *ReverseProxy) Name() string {
return ReverseProxyMethodName
}

// getUserFromAuthUser extracts the username from the "setting.ReverseProxyAuthUser" header
// getUserFromAuthUser extracts the username from the "setting.ReverseProxyAuth.ReverseProxyAuthUser" header
// of the request and returns the corresponding user object for that name.
// Verification of header data is not performed as it should have already been done by
// the reverse proxy.
// If a username is available in the "setting.ReverseProxyAuthUser" header an existing
// If a username is available in the "setting.ReverseProxyAuth.ReverseProxyAuthUser" header an existing
// user object is returned (populated with username or email found in header).
// Returns nil if header is empty.
func (r *ReverseProxy) getUserFromAuthUser(req *http.Request) (*user_model.User, error) {
Expand All @@ -69,7 +69,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.ReverseProxyAuth.ReverseProxyAuthEmail))
}

// getUserFromAuthEmail extracts the username from the "setting.ReverseProxyAuthEmail" header
Expand All @@ -80,7 +80,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.ReverseProxyAuth.EnableReverseProxyEmail {
return nil
}
email := r.getEmail(req)
Expand Down Expand Up @@ -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.ReverseProxyAuth.EnableReverseProxyAutoRegister
}

// newUser creates a new user object for the purpose of automatic registration
Expand All @@ -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.ReverseProxyAuth.EnableReverseProxyEmail {
webAuthEmail := req.Header.Get(setting.ReverseProxyAuth.ReverseProxyAuthEmail)
if len(webAuthEmail) > 0 {
email = webAuthEmail
}
}

var fullname string
if setting.Service.EnableReverseProxyFullName {
fullname = req.Header.Get(setting.ReverseProxyAuthFullName)
if setting.ReverseProxyAuth.EnableReverseProxyFullName {
fullname = req.Header.Get(setting.ReverseProxyAuth.ReverseProxyAuthFullName)
}

user := &user_model.User{
Expand Down
31 changes: 29 additions & 2 deletions templates/admin/config.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@
<dd>{{.LogRootPath}}</dd>
<dt>{{ctx.Locale.Tr "admin.config.script_type"}}</dt>
<dd>{{.ScriptType}}</dd>
<dt>{{ctx.Locale.Tr "admin.config.reverse_auth_user"}}</dt>
<dd>{{.ReverseProxyAuthUser}}</dd>
</dl>
</div>

Expand Down Expand Up @@ -180,6 +178,35 @@
</dl>
</div>

{{if .ReverseProxyAuth.Enabled}}
<h4 class="ui top attached header">
{{ctx.Locale.Tr "admin.config.reverse_proxy_auth_config"}}
</h4>
<div class="ui attached table segment">
<dl class="admin-dl-horizontal">
<dt>{{ctx.Locale.Tr "admin.config.reverse_proxy_auth_enable_autoregister"}}</dt>
<dd>{{.ReverseProxyAuth.EnableReverseProxyAutoRegister}}</dd>
<dt>{{ctx.Locale.Tr "admin.config.reverse_auth_user"}}</dt>
<dd>{{.ReverseProxyAuth.ReverseProxyAuthUser}}</dd>
<dt>{{ctx.Locale.Tr "admin.config.reverse_proxy_auth_enable_email"}}</dt>
<dd>{{.ReverseProxyAuth.EnableReverseProxyEmail}}</dd>
<dt>{{ctx.Locale.Tr "admin.config.reverse_proxy_auth_email"}}</dt>
<dd>{{.ReverseProxyAuth.ReverseProxyAuthEmail}}</dd>
<dt>{{ctx.Locale.Tr "admin.config.reverse_proxy_auth_enable_fullname"}}</dt>
<dd>{{.ReverseProxyAuth.EnableReverseProxyFullName}}</dd>
<dt>{{ctx.Locale.Tr "admin.config.reverse_proxy_auth_fullname"}}</dt>
<dd>{{.ReverseProxyAuth.ReverseProxyAuthFullName}}</dd>

<dt>{{ctx.Locale.Tr "admin.config.reverse_proxy_auth_enable_api"}}</dt>
<dd>{{.ReverseProxyAuth.EnableReverseProxyAuthAPI}}</dd>
<dt>{{ctx.Locale.Tr "admin.config.reverse_proxy_auth_limit"}}</dt>
<dd>{{.ReverseProxyAuth.ReverseProxyLimit}}</dd>
<dt>{{ctx.Locale.Tr "admin.config.reverse_proxy_auth_trusted_proxies"}}</dt>
<dd>{{.ReverseProxyAuth.ReverseProxyTrustedProxies}}</dd>
</dl>
</div>
{{end}}

<h4 class="ui top attached header">
{{ctx.Locale.Tr "admin.config.webhook_config"}}
</h4>
Expand Down
Loading