From 86dd4ac482d55cea32d8aa851f55c9d5102efa51 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Mon, 2 Dec 2024 00:15:46 +0800 Subject: [PATCH 1/3] fix --- custom/conf/app.example.ini | 22 ++++++----- modules/setting/service.go | 2 + routers/web/auth/auth.go | 48 +++++++++--------------- templates/user/auth/oauth_container.tmpl | 5 --- templates/user/auth/signin_inner.tmpl | 10 ++++- templates/user/auth/signup_inner.tmpl | 5 ++- tests/integration/signin_test.go | 29 ++++++++++++++ 7 files changed, 73 insertions(+), 48 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index c3b78e60bb47c..7a2378507b1fa 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -784,6 +784,10 @@ LEVEL = Info ;; Please note that setting this to false will not disable OAuth Basic or Basic authentication using a token ;ENABLE_BASIC_AUTHENTICATION = true ;; +;; Show the password login form (for password-based login), otherwise, only show OAuth2 login methods. +;; If you set it to false, maybe it also needs to set ENABLE_BASIC_AUTHENTICATION to false to completely disable password-based authentication. +;ENABLE_PASSWORD_LOGIN_FORM = true +;; ;; More detail: https://github.com/gogits/gogs/issues/165 ;ENABLE_REVERSE_PROXY_AUTHENTICATION = false ; Enable this to allow reverse proxy authentication for API requests, the reverse proxy is responsible for ensuring that no CSRF is possible. @@ -1944,13 +1948,13 @@ LEVEL = Info ;; Minio secretAccessKey to connect only available when STORAGE_TYPE is `minio` ;MINIO_SECRET_ACCESS_KEY = ;; -;; Preferred IAM Endpoint to override Minio's default IAM Endpoint resolution only available when STORAGE_TYPE is `minio`. -;; If not provided and STORAGE_TYPE is `minio`, will search for and derive endpoint from known environment variables -;; (AWS_CONTAINER_AUTHORIZATION_TOKEN, AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE, AWS_CONTAINER_CREDENTIALS_RELATIVE_URI, -;; AWS_CONTAINER_CREDENTIALS_FULL_URI, AWS_WEB_IDENTITY_TOKEN_FILE, AWS_ROLE_ARN, AWS_ROLE_SESSION_NAME, AWS_REGION), +;; Preferred IAM Endpoint to override Minio's default IAM Endpoint resolution only available when STORAGE_TYPE is `minio`. +;; If not provided and STORAGE_TYPE is `minio`, will search for and derive endpoint from known environment variables +;; (AWS_CONTAINER_AUTHORIZATION_TOKEN, AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE, AWS_CONTAINER_CREDENTIALS_RELATIVE_URI, +;; AWS_CONTAINER_CREDENTIALS_FULL_URI, AWS_WEB_IDENTITY_TOKEN_FILE, AWS_ROLE_ARN, AWS_ROLE_SESSION_NAME, AWS_REGION), ;; or the DefaultIAMRoleEndpoint if not provided otherwise. ;MINIO_IAM_ENDPOINT = -;; +;; ;; Minio bucket to store the attachments only available when STORAGE_TYPE is `minio` ;MINIO_BUCKET = gitea ;; @@ -2695,10 +2699,10 @@ LEVEL = Info ;; Minio secretAccessKey to connect only available when STORAGE_TYPE is `minio` ;MINIO_SECRET_ACCESS_KEY = ;; -;; Preferred IAM Endpoint to override Minio's default IAM Endpoint resolution only available when STORAGE_TYPE is `minio`. -;; If not provided and STORAGE_TYPE is `minio`, will search for and derive endpoint from known environment variables -;; (AWS_CONTAINER_AUTHORIZATION_TOKEN, AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE, AWS_CONTAINER_CREDENTIALS_RELATIVE_URI, -;; AWS_CONTAINER_CREDENTIALS_FULL_URI, AWS_WEB_IDENTITY_TOKEN_FILE, AWS_ROLE_ARN, AWS_ROLE_SESSION_NAME, AWS_REGION), +;; Preferred IAM Endpoint to override Minio's default IAM Endpoint resolution only available when STORAGE_TYPE is `minio`. +;; If not provided and STORAGE_TYPE is `minio`, will search for and derive endpoint from known environment variables +;; (AWS_CONTAINER_AUTHORIZATION_TOKEN, AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE, AWS_CONTAINER_CREDENTIALS_RELATIVE_URI, +;; AWS_CONTAINER_CREDENTIALS_FULL_URI, AWS_WEB_IDENTITY_TOKEN_FILE, AWS_ROLE_ARN, AWS_ROLE_SESSION_NAME, AWS_REGION), ;; or the DefaultIAMRoleEndpoint if not provided otherwise. ;MINIO_IAM_ENDPOINT = ;; diff --git a/modules/setting/service.go b/modules/setting/service.go index c858f803549d5..d144b92dc5796 100644 --- a/modules/setting/service.go +++ b/modules/setting/service.go @@ -41,6 +41,7 @@ var Service = struct { AllowOnlyInternalRegistration bool AllowOnlyExternalRegistration bool ShowRegistrationButton bool + EnablePasswordLoginForm bool ShowMilestonesDashboardPage bool RequireSignInView bool EnableNotifyMail bool @@ -159,6 +160,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.EnablePasswordLoginForm = sec.Key("ENABLE_PASSWORD_LOGIN_FORM").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() diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index c9ef9193f12e4..8209301f01abe 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -160,54 +160,42 @@ func CheckAutoLogin(ctx *context.Context) bool { return false } -// SignIn render sign in page -func SignIn(ctx *context.Context) { +func prepareSignPageData(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("sign_in") - - if CheckAutoLogin(ctx) { - return - } - - if ctx.IsSigned { - RedirectAfterLogin(ctx) - return - } - - oauth2Providers, err := oauth2.GetOAuth2Providers(ctx, optional.Some(true)) - if err != nil { - ctx.ServerError("UserSignIn", err) - return - } - ctx.Data["OAuth2Providers"] = oauth2Providers + ctx.Data["OAuth2Providers"], _ = oauth2.GetOAuth2Providers(ctx, optional.Some(true)) ctx.Data["Title"] = ctx.Tr("sign_in") ctx.Data["SignInLink"] = setting.AppSubURL + "/user/login" ctx.Data["PageIsSignIn"] = true ctx.Data["PageIsLogin"] = true ctx.Data["EnableSSPI"] = auth.IsSSPIEnabled(ctx) + ctx.Data["EnablePasswordLoginForm"] = setting.Service.EnablePasswordLoginForm if setting.Service.EnableCaptcha && setting.Service.RequireCaptchaForLogin { context.SetCaptchaData(ctx) } +} +// SignIn render sign in page +func SignIn(ctx *context.Context) { + if CheckAutoLogin(ctx) { + return + } + if ctx.IsSigned { + RedirectAfterLogin(ctx) + return + } + prepareSignPageData(ctx) ctx.HTML(http.StatusOK, tplSignIn) } // SignInPost response for sign in request func SignInPost(ctx *context.Context) { - ctx.Data["Title"] = ctx.Tr("sign_in") - - oauth2Providers, err := oauth2.GetOAuth2Providers(ctx, optional.Some(true)) - if err != nil { - ctx.ServerError("UserSignIn", err) + if !setting.Service.EnablePasswordLoginForm { + ctx.Error(http.StatusForbidden) return } - ctx.Data["OAuth2Providers"] = oauth2Providers - ctx.Data["Title"] = ctx.Tr("sign_in") - ctx.Data["SignInLink"] = setting.AppSubURL + "/user/login" - ctx.Data["PageIsSignIn"] = true - ctx.Data["PageIsLogin"] = true - ctx.Data["EnableSSPI"] = auth.IsSSPIEnabled(ctx) + prepareSignPageData(ctx) if ctx.HasError() { ctx.HTML(http.StatusOK, tplSignIn) return @@ -216,8 +204,6 @@ func SignInPost(ctx *context.Context) { form := web.GetForm(ctx).(*forms.SignInForm) if setting.Service.EnableCaptcha && setting.Service.RequireCaptchaForLogin { - context.SetCaptchaData(ctx) - context.VerifyCaptcha(ctx, tplSignIn, form) if ctx.Written() { return diff --git a/templates/user/auth/oauth_container.tmpl b/templates/user/auth/oauth_container.tmpl index 7599b49fbbf4b..d01aaefe1aa2d 100644 --- a/templates/user/auth/oauth_container.tmpl +++ b/templates/user/auth/oauth_container.tmpl @@ -1,7 +1,3 @@ -{{if or .OAuth2Providers .EnableOpenIDSignIn}} -
- {{ctx.Locale.Tr "sign_in_or"}} -
@@ -26,4 +22,3 @@
-{{end}} diff --git a/templates/user/auth/signin_inner.tmpl b/templates/user/auth/signin_inner.tmpl index ec61e56f4db7d..12f1e91c159b2 100644 --- a/templates/user/auth/signin_inner.tmpl +++ b/templates/user/auth/signin_inner.tmpl @@ -10,6 +10,7 @@ {{end}}
+ {{if .EnablePasswordLoginForm}}
{{.CsrfTokenHtml}}
@@ -46,8 +47,13 @@
- - {{template "user/auth/oauth_container" .}} + {{end}}{{/*if .EnablePasswordLoginForm*/}} + {{if and .OAuth2Providers .EnableOpenIDSignIn .EnablePasswordLoginForm}} +
{{ctx.Locale.Tr "sign_in_or"}}
+ {{end}} + {{if and .OAuth2Providers .EnableOpenIDSignIn}} + {{template "user/auth/oauth_container" .}} + {{end}}
diff --git a/templates/user/auth/signup_inner.tmpl b/templates/user/auth/signup_inner.tmpl index 08507e545dc84..6969003968670 100644 --- a/templates/user/auth/signup_inner.tmpl +++ b/templates/user/auth/signup_inner.tmpl @@ -48,7 +48,10 @@ {{end}} - {{template "user/auth/oauth_container" .}} + {{if and .OAuth2Providers .EnableOpenIDSignIn}} +
{{ctx.Locale.Tr "sign_in_or"}}
+ {{template "user/auth/oauth_container" .}} + {{end}} diff --git a/tests/integration/signin_test.go b/tests/integration/signin_test.go index 886d4a825932e..af053a36b92c0 100644 --- a/tests/integration/signin_test.go +++ b/tests/integration/signin_test.go @@ -12,6 +12,7 @@ import ( "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/modules/translation" "code.gitea.io/gitea/tests" @@ -91,3 +92,31 @@ func TestSigninWithRememberMe(t *testing.T) { req = NewRequest(t, "GET", "/user/settings") session.MakeRequest(t, req, http.StatusOK) } + +func TestEnablePasswordLoginForm(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + t.Run("EnablePasswordLoginForm=false", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + defer test.MockVariableValue(&setting.Service.EnablePasswordLoginForm, false)() + + req := NewRequest(t, "GET", "/user/login") + resp := MakeRequest(t, req, http.StatusOK) + NewHTMLParser(t, resp.Body).AssertElement(t, "form[action='/user/login']", false) + + req = NewRequest(t, "POST", "/user/login") + MakeRequest(t, req, http.StatusForbidden) + }) + + t.Run("EnablePasswordLoginForm=true", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + defer test.MockVariableValue(&setting.Service.EnablePasswordLoginForm, true)() + + req := NewRequest(t, "GET", "/user/login") + resp := MakeRequest(t, req, http.StatusOK) + NewHTMLParser(t, resp.Body).AssertElement(t, "form[action='/user/login']", true) + + req = NewRequest(t, "POST", "/user/login") + MakeRequest(t, req, http.StatusOK) + }) +} From bb7f05424aa55e73ded56ec99406429eeabe83d7 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Mon, 2 Dec 2024 00:57:19 +0800 Subject: [PATCH 2/3] use signin instead of login --- custom/conf/app.example.ini | 2 +- modules/setting/service.go | 4 ++-- routers/web/auth/auth.go | 10 +++++----- templates/user/auth/signin_inner.tmpl | 6 +++--- tests/integration/signin_test.go | 10 +++++----- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 7a2378507b1fa..a923887a6ad2a 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -786,7 +786,7 @@ LEVEL = Info ;; ;; Show the password login form (for password-based login), otherwise, only show OAuth2 login methods. ;; If you set it to false, maybe it also needs to set ENABLE_BASIC_AUTHENTICATION to false to completely disable password-based authentication. -;ENABLE_PASSWORD_LOGIN_FORM = true +;ENABLE_PASSWORD_SIGNIN_FORM = true ;; ;; More detail: https://github.com/gogits/gogs/issues/165 ;ENABLE_REVERSE_PROXY_AUTHENTICATION = false diff --git a/modules/setting/service.go b/modules/setting/service.go index d144b92dc5796..526ad64eb4001 100644 --- a/modules/setting/service.go +++ b/modules/setting/service.go @@ -41,7 +41,7 @@ var Service = struct { AllowOnlyInternalRegistration bool AllowOnlyExternalRegistration bool ShowRegistrationButton bool - EnablePasswordLoginForm bool + EnablePasswordSignInForm bool ShowMilestonesDashboardPage bool RequireSignInView bool EnableNotifyMail bool @@ -160,7 +160,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.EnablePasswordLoginForm = sec.Key("ENABLE_PASSWORD_LOGIN_FORM").MustBool(true) + Service.EnablePasswordSignInForm = sec.Key("ENABLE_PASSWORD_SIGNIN_FORM").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() diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index 8209301f01abe..3f16da3cddf8e 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -160,7 +160,7 @@ func CheckAutoLogin(ctx *context.Context) bool { return false } -func prepareSignPageData(ctx *context.Context) { +func prepareSignInPageData(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("sign_in") ctx.Data["OAuth2Providers"], _ = oauth2.GetOAuth2Providers(ctx, optional.Some(true)) ctx.Data["Title"] = ctx.Tr("sign_in") @@ -168,7 +168,7 @@ func prepareSignPageData(ctx *context.Context) { ctx.Data["PageIsSignIn"] = true ctx.Data["PageIsLogin"] = true ctx.Data["EnableSSPI"] = auth.IsSSPIEnabled(ctx) - ctx.Data["EnablePasswordLoginForm"] = setting.Service.EnablePasswordLoginForm + ctx.Data["EnablePasswordSignInForm"] = setting.Service.EnablePasswordSignInForm if setting.Service.EnableCaptcha && setting.Service.RequireCaptchaForLogin { context.SetCaptchaData(ctx) @@ -184,18 +184,18 @@ func SignIn(ctx *context.Context) { RedirectAfterLogin(ctx) return } - prepareSignPageData(ctx) + prepareSignInPageData(ctx) ctx.HTML(http.StatusOK, tplSignIn) } // SignInPost response for sign in request func SignInPost(ctx *context.Context) { - if !setting.Service.EnablePasswordLoginForm { + if !setting.Service.EnablePasswordSignInForm { ctx.Error(http.StatusForbidden) return } - prepareSignPageData(ctx) + prepareSignInPageData(ctx) if ctx.HasError() { ctx.HTML(http.StatusOK, tplSignIn) return diff --git a/templates/user/auth/signin_inner.tmpl b/templates/user/auth/signin_inner.tmpl index 12f1e91c159b2..e0a19a974330a 100644 --- a/templates/user/auth/signin_inner.tmpl +++ b/templates/user/auth/signin_inner.tmpl @@ -10,7 +10,7 @@ {{end}}
- {{if .EnablePasswordLoginForm}} + {{if .EnablePasswordSignInForm}}
{{.CsrfTokenHtml}}
@@ -47,8 +47,8 @@
- {{end}}{{/*if .EnablePasswordLoginForm*/}} - {{if and .OAuth2Providers .EnableOpenIDSignIn .EnablePasswordLoginForm}} + {{end}}{{/*if .EnablePasswordSignInForm*/}} + {{if and .OAuth2Providers .EnableOpenIDSignIn .EnablePasswordSignInForm}}
{{ctx.Locale.Tr "sign_in_or"}}
{{end}} {{if and .OAuth2Providers .EnableOpenIDSignIn}} diff --git a/tests/integration/signin_test.go b/tests/integration/signin_test.go index af053a36b92c0..abad9eb5e55f1 100644 --- a/tests/integration/signin_test.go +++ b/tests/integration/signin_test.go @@ -93,12 +93,12 @@ func TestSigninWithRememberMe(t *testing.T) { session.MakeRequest(t, req, http.StatusOK) } -func TestEnablePasswordLoginForm(t *testing.T) { +func TestEnablePasswordSignInForm(t *testing.T) { defer tests.PrepareTestEnv(t)() - t.Run("EnablePasswordLoginForm=false", func(t *testing.T) { + t.Run("EnablePasswordSignInForm=false", func(t *testing.T) { defer tests.PrintCurrentTest(t)() - defer test.MockVariableValue(&setting.Service.EnablePasswordLoginForm, false)() + defer test.MockVariableValue(&setting.Service.EnablePasswordSignInForm, false)() req := NewRequest(t, "GET", "/user/login") resp := MakeRequest(t, req, http.StatusOK) @@ -108,9 +108,9 @@ func TestEnablePasswordLoginForm(t *testing.T) { MakeRequest(t, req, http.StatusForbidden) }) - t.Run("EnablePasswordLoginForm=true", func(t *testing.T) { + t.Run("EnablePasswordSignInForm=true", func(t *testing.T) { defer tests.PrintCurrentTest(t)() - defer test.MockVariableValue(&setting.Service.EnablePasswordLoginForm, true)() + defer test.MockVariableValue(&setting.Service.EnablePasswordSignInForm, true)() req := NewRequest(t, "GET", "/user/login") resp := MakeRequest(t, req, http.StatusOK) From ce0d8f4714d1514017286ecc9f331402e0e0d9e4 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Mon, 2 Dec 2024 01:02:23 +0800 Subject: [PATCH 3/3] fix doc --- custom/conf/app.example.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index a923887a6ad2a..5c23f70d7ca7a 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -784,7 +784,7 @@ LEVEL = Info ;; Please note that setting this to false will not disable OAuth Basic or Basic authentication using a token ;ENABLE_BASIC_AUTHENTICATION = true ;; -;; Show the password login form (for password-based login), otherwise, only show OAuth2 login methods. +;; Show the password sign-in form (for password-based login), otherwise, only show OAuth2 login methods. ;; If you set it to false, maybe it also needs to set ENABLE_BASIC_AUTHENTICATION to false to completely disable password-based authentication. ;ENABLE_PASSWORD_SIGNIN_FORM = true ;;