Compare commits

...

8 Commits

Author SHA1 Message Date
Lunny Xiao
d56e695a60
Merge 815e5e6588 into 2b8ff419a7 2024-10-17 16:11:16 +08:00
cloudchamb3r
2b8ff419a7
Add gh-access-token flag into backport script (#32283)
The current backport script does not have github access token flag. 
This patch will be useful when encountered rate limit issue.
2024-10-17 01:43:48 -04:00
wxiaoguang
0196b3583a
Warn users when they try to use a non-root-url to sign in/up (#32272) 2024-10-17 10:28:51 +08:00
Lunny Xiao
815e5e6588 Merge branch 'main' into lunny/improve_reverseproxy 2024-10-01 21:17:57 -07:00
Lunny Xiao
f6cbb4ead7
Fix comments 2024-10-01 21:17:51 -07:00
Lunny Xiao
162ff1a110 Merge branch 'main' into lunny/improve_reverseproxy 2024-09-27 12:51:34 -07:00
Lunny Xiao
1a8acdefbc
Fix lint 2024-09-27 12:51:27 -07:00
Lunny Xiao
f173431b8e
refactor reverseproxy setting 2024-09-26 19:23:34 -07:00
16 changed files with 133 additions and 58 deletions

View File

@ -64,6 +64,11 @@ func main() {
Value: "",
Usage: "Forked user name on Github",
},
&cli.StringFlag{
Name: "gh-access-token",
Value: "",
Usage: "Access token for GitHub api request",
},
&cli.BoolFlag{
Name: "no-fetch",
Usage: "Set this flag to prevent fetch of remote branches",
@ -169,9 +174,10 @@ func runBackport(c *cli.Context) error {
fmt.Printf("* Backporting %s to %s as %s\n", pr, localReleaseBranch, backportBranch)
sha := c.String("cherry-pick")
accessToken := c.String("gh-access-token")
if sha == "" {
var err error
sha, err = determineSHAforPR(ctx, pr)
sha, err = determineSHAforPR(ctx, pr, accessToken)
if err != nil {
return err
}
@ -427,13 +433,16 @@ func readVersion() string {
return strings.Join(split[:2], ".")
}
func determineSHAforPR(ctx context.Context, prStr string) (string, error) {
func determineSHAforPR(ctx context.Context, prStr, accessToken string) (string, error) {
prNum, err := strconv.Atoi(prStr)
if err != nil {
return "", err
}
client := github.NewClient(http.DefaultClient)
if accessToken != "" {
client = client.WithAuthToken(accessToken)
}
pr, _, err := client.PullRequests.Get(ctx, "go-gitea", "gitea", prNum)
if err != nil {

View File

@ -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"}
}
}

View File

@ -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
@ -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)

View File

@ -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
@ -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)

View File

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

View File

@ -3199,7 +3199,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

View File

@ -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.ReverseProxyAuth.Enabled {
authMethods = append(authMethods, &auth.ReverseProxy{})
}
authGroup := auth.NewGroup(authMethods...)

View File

@ -364,7 +364,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 {
@ -733,7 +733,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{})
}

View File

@ -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 {

View File

@ -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

View File

@ -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{})

View File

@ -28,13 +28,13 @@ 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
@ -42,11 +42,11 @@ 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) {
@ -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
@ -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)
@ -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
@ -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{

View File

@ -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>
@ -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>

View File

@ -91,3 +91,11 @@ export function checkAppUrl() {
showGlobalErrorMessage(`Your ROOT_URL in app.ini is "${appUrl}", it's unlikely matching the site you are visiting.
Mismatched ROOT_URL config causes wrong URL links for web UI/mail content/webhook notification/OAuth2 sign-in.`, 'warning');
}
export function checkAppUrlScheme() {
const curUrl = window.location.href;
// some users visit "http://domain" while appUrl is "https://domain", COOKIE_SECURE makes it impossible to sign in
if (curUrl.startsWith('http:') && appUrl.startsWith('https:')) {
showGlobalErrorMessage(`This instance is configured to run under HTTPS (by ROOT_URL config), you are accessing by HTTP. Mismatched scheme might cause problems for sign-in/sign-up.`, 'warning');
}
}

View File

@ -1,4 +1,9 @@
import {checkAppUrl} from './common-page.ts';
import {checkAppUrl, checkAppUrlScheme} from './common-page.ts';
export function initUserCheckAppUrl() {
if (!document.querySelector('.page-content.user.signin, .page-content.user.signup, .page-content.user.link-account')) return;
checkAppUrlScheme();
}
export function initUserAuthOauth2() {
const outer = document.querySelector('#oauth2-login-navigator');

View File

@ -24,7 +24,7 @@ import {initFindFileInRepo} from './features/repo-findfile.ts';
import {initCommentContent, initMarkupContent} from './markup/content.ts';
import {initPdfViewer} from './render/pdf.ts';
import {initUserAuthOauth2} from './features/user-auth.ts';
import {initUserAuthOauth2, initUserCheckAppUrl} from './features/user-auth.ts';
import {
initRepoIssueDue,
initRepoIssueReferenceRepositorySearch,
@ -219,6 +219,7 @@ onDomReady(() => {
initCommitStatuses,
initCaptcha,
initUserCheckAppUrl,
initUserAuthOauth2,
initUserAuthWebAuthn,
initUserAuthWebAuthnRegister,