From a126477e866c5d28b3dbe51f5e3ce97dffcbf199 Mon Sep 17 00:00:00 2001 From: George Tsiamasiotis Date: Tue, 26 Nov 2024 08:51:51 +0200 Subject: [PATCH] feat: Add option to disable builtin authentication. Setting ENABLE_INTERNAL_SIGNIN to false will disable the built-in signin form, should the administrator prefer to limit users to SSO. Continuation of forgejo/forgejo#6076 --- custom/conf/app.example.ini | 3 ++ modules/setting/service.go | 2 ++ routers/web/auth/auth.go | 8 +++++ templates/user/auth/oauth_container.tmpl | 2 ++ templates/user/auth/signin_inner.tmpl | 2 ++ tests/integration/signin_test.go | 42 ++++++++++++++++++++++++ 6 files changed, 59 insertions(+) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 7d508daa40..45b094d99c 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -901,6 +901,9 @@ LEVEL = Info ;; Show Registration button ;SHOW_REGISTRATION_BUTTON = true ;; +;; Whether to allow internal signin +; ENABLE_INTERNAL_SIGNIN = true +;; ;; Show milestones dashboard page - a view of all the user's milestones ;SHOW_MILESTONES_DASHBOARD_PAGE = true ;; diff --git a/modules/setting/service.go b/modules/setting/service.go index e630fe85b8..5a6cc254e0 100644 --- a/modules/setting/service.go +++ b/modules/setting/service.go @@ -43,6 +43,7 @@ var Service = struct { AllowOnlyInternalRegistration bool AllowOnlyExternalRegistration bool ShowRegistrationButton bool + EnableInternalSignIn bool ShowMilestonesDashboardPage bool RequireSignInView bool EnableNotifyMail bool @@ -175,6 +176,7 @@ func loadServiceFrom(rootCfg ConfigProvider) { Service.EmailDomainBlockList = append(Service.EmailDomainBlockList, toAdd...) } Service.ShowRegistrationButton = sec.Key("SHOW_REGISTRATION_BUTTON").MustBool(!(Service.DisableRegistration || Service.AllowOnlyExternalRegistration)) + Service.EnableInternalSignIn = sec.Key("ENABLE_INTERNAL_SIGNIN").MustBool(true) 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) diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index 941586db72..71d7b8ca11 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -164,6 +164,7 @@ func SignIn(ctx *context.Context) { ctx.Data["PageIsSignIn"] = true ctx.Data["PageIsLogin"] = true ctx.Data["EnableSSPI"] = auth.IsSSPIEnabled(ctx) + ctx.Data["EnableInternalSignIn"] = setting.Service.EnableInternalSignIn if setting.Service.EnableCaptcha && setting.Service.RequireCaptchaForLogin { context.SetCaptchaData(ctx) @@ -187,6 +188,13 @@ func SignInPost(ctx *context.Context) { ctx.Data["PageIsSignIn"] = true ctx.Data["PageIsLogin"] = true ctx.Data["EnableSSPI"] = auth.IsSSPIEnabled(ctx) + ctx.Data["EnableInternalSignIn"] = setting.Service.EnableInternalSignIn + + // Permission denied if EnableInternalSignIn is false + if !setting.Service.EnableInternalSignIn { + ctx.Error(http.StatusForbidden) + return + } if ctx.HasError() { ctx.HTML(http.StatusOK, tplSignIn) diff --git a/templates/user/auth/oauth_container.tmpl b/templates/user/auth/oauth_container.tmpl index bb6a10d408..ecae2bbbf3 100644 --- a/templates/user/auth/oauth_container.tmpl +++ b/templates/user/auth/oauth_container.tmpl @@ -1,7 +1,9 @@ {{if or .OAuth2Providers .EnableOpenIDSignIn}} +{{if .EnableInternalSignIn}}
{{ctx.Locale.Tr "sign_in_or"}}
+{{end}}
diff --git a/templates/user/auth/signin_inner.tmpl b/templates/user/auth/signin_inner.tmpl index 56532f4b98..ddef34f35d 100644 --- a/templates/user/auth/signin_inner.tmpl +++ b/templates/user/auth/signin_inner.tmpl @@ -10,6 +10,7 @@ {{end}}
+ {{if .EnableInternalSignIn}}
{{.CsrfTokenHtml}}
@@ -43,6 +44,7 @@
+ {{end}} {{template "user/auth/oauth_container" .}}
diff --git a/tests/integration/signin_test.go b/tests/integration/signin_test.go index 77e19bba96..c986b844f0 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" @@ -93,3 +94,44 @@ func TestSigninWithRememberMe(t *testing.T) { req = NewRequest(t, "GET", "/user/settings") session.MakeRequest(t, req, http.StatusOK) } + +func TestDisableSignin(t *testing.T) { + defer tests.PrepareTestEnv(t)() + t.Run("Disabled", func(t *testing.T) { + defer test.MockVariableValue(&setting.Service.EnableInternalSignIn, false)() + + t.Run("UI", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + + req := NewRequest(t, "GET", "/user/login") + resp := MakeRequest(t, req, http.StatusOK) + htmlDoc := NewHTMLParser(t, resp.Body) + htmlDoc.AssertElement(t, "form[action='/user/login']", false) + }) + + t.Run("Signin", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + req := NewRequest(t, "POST", "/user/login") + MakeRequest(t, req, http.StatusForbidden) + }) + }) + + t.Run("Enabled", func(t *testing.T) { + defer test.MockVariableValue(&setting.Service.EnableInternalSignIn, true)() + + t.Run("UI", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + + req := NewRequest(t, "GET", "/user/login") + resp := MakeRequest(t, req, http.StatusOK) + htmlDoc := NewHTMLParser(t, resp.Body) + htmlDoc.AssertElement(t, "form[action='/user/login']", true) + }) + + t.Run("Signin", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + req := NewRequest(t, "POST", "/user/login") + MakeRequest(t, req, http.StatusOK) + }) + }) +}