Elisei Roca 2025-12-11 08:46:08 +07:00 committed by GitHub
commit 02d0bf1f77
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 46 additions and 4 deletions

@ -463,6 +463,11 @@ INTERNAL_TOKEN =
;; Name of cookie used to store authentication information.
;COOKIE_REMEMBER_NAME = gitea_incredible
;;
;; URL or path that Gitea should redirect users to *after* performing its own logout.
;; Use this, if needed, when authentication is handled by a reverse proxy or SSO.
;; Mellon example: REVERSE_PROXY_LOGOUT_REDIRECT = /mellon/logout?ReturnTo=/
;REVERSE_PROXY_LOGOUT_REDIRECT =
;;
;; Reverse proxy authentication header name of user name, email, and full name
;REVERSE_PROXY_AUTHENTICATION_USER = X-WEBAUTH-USER
;REVERSE_PROXY_AUTHENTICATION_EMAIL = X-WEBAUTH-EMAIL

@ -25,6 +25,7 @@ var (
ReverseProxyAuthEmail string
ReverseProxyAuthFullName string
ReverseProxyLimit int
ReverseProxyLogoutRedirect string
ReverseProxyTrustedProxies []string
MinPasswordLength int
ImportLocalPaths bool
@ -121,6 +122,7 @@ func loadSecurityFrom(rootCfg ConfigProvider) {
ReverseProxyAuthFullName = sec.Key("REVERSE_PROXY_AUTHENTICATION_FULL_NAME").MustString("X-WEBAUTH-FULLNAME")
ReverseProxyLimit = sec.Key("REVERSE_PROXY_LIMIT").MustInt(1)
ReverseProxyLogoutRedirect = sec.Key("REVERSE_PROXY_LOGOUT_REDIRECT").MustString("")
ReverseProxyTrustedProxies = sec.Key("REVERSE_PROXY_TRUSTED_PROXIES").Strings(",")
if len(ReverseProxyTrustedProxies) == 0 {
ReverseProxyTrustedProxies = []string{"127.0.0.0/8", "::1/128"}

@ -416,7 +416,11 @@ func SignOut(ctx *context.Context) {
})
}
HandleSignOut(ctx)
ctx.JSONRedirect(setting.AppSubURL + "/")
if setting.ReverseProxyLogoutRedirect != "" {
ctx.Redirect(setting.ReverseProxyLogoutRedirect)
return
}
ctx.Redirect(setting.AppSubURL + "/")
}
// SignUp render the register page

@ -55,7 +55,8 @@
</div>
<div class="divider"></div>
<a class="item link-action" href data-url="{{AppSubUrl}}/user/logout">
<form id="logout-form" method="post" action="{{AppSubUrl}}/user/logout"></form>
<a class="item" onclick="document.getElementById('logout-form').submit();">
{{svg "octicon-sign-out"}}
{{ctx.Locale.Tr "sign_out"}}
</a>
@ -128,7 +129,8 @@
</a>
{{end}}
<div class="divider"></div>
<a class="item link-action" href data-url="{{AppSubUrl}}/user/logout">
<form id="logout-form" method="post" action="{{AppSubUrl}}/user/logout"></form>
<a class="item" onclick="document.getElementById('logout-form').submit();">
{{svg "octicon-sign-out"}}
{{ctx.Locale.Tr "sign_out"}}
</a>

@ -7,6 +7,8 @@ import (
"net/http"
"testing"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/test"
"code.gitea.io/gitea/tests"
)
@ -16,7 +18,34 @@ func TestSignOut(t *testing.T) {
session := loginUser(t, "user2")
req := NewRequest(t, "POST", "/user/logout")
session.MakeRequest(t, req, http.StatusOK)
resp := session.MakeRequest(t, req, http.StatusSeeOther)
expected := "/"
loc := resp.Header().Get("Location")
if loc != expected {
t.Fatalf("expected redirect to %q, got %q", expected, loc)
}
// try to view a private repo, should fail
req = NewRequest(t, "GET", "/user2/repo2")
session.MakeRequest(t, req, http.StatusNotFound)
}
func TestSignOut_ReverseProxyLogoutRedirect(t *testing.T) {
defer tests.PrepareTestEnv(t)()
defer test.MockVariableValue(&setting.ReverseProxyLogoutRedirect, "/mellon/logout?ReturnTo=/")()
session := loginUser(t, "user2")
req := NewRequest(t, "POST", "/user/logout")
resp := session.MakeRequest(t, req, http.StatusSeeOther)
expected := "/mellon/logout?ReturnTo=/"
loc := resp.Header().Get("Location")
if loc != expected {
t.Fatalf("expected redirect to %q, got %q", expected, loc)
}
// try to view a private repo, should fail
req = NewRequest(t, "GET", "/user2/repo2")