From 2213db0c29611a7a4bdcdec8a90ebddddc5ca1a9 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 22 Jan 2025 04:36:20 +0000 Subject: [PATCH 1/9] add --- custom/conf/app.example.ini | 5 ++++- modules/setting/service.go | 2 ++ routers/web/auth/auth.go | 1 + routers/web/auth/linkaccount.go | 3 +++ routers/web/auth/webauthn.go | 10 ++++++++++ templates/user/auth/signin_inner.tmpl | 8 ++++++-- 6 files changed, 26 insertions(+), 3 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 8e64c834d7373..583fa461febae 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -791,9 +791,12 @@ LEVEL = Info ;ENABLE_BASIC_AUTHENTICATION = true ;; ;; 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. +;; If you set it to false, maybe it also needs to set ENABLE_BASIC_AUTHENTICATION and ENABLE_PASSKEY_AUTHENTICATION to false to completely disable password-based authentication. ;ENABLE_PASSWORD_SIGNIN_FORM = true ;; +;; This setting enables gitea to be signed in with a passkey +;ENABLE_PASSKEY_AUTHENTICATION = 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. diff --git a/modules/setting/service.go b/modules/setting/service.go index 526ad64eb4001..8c1843eeb7548 100644 --- a/modules/setting/service.go +++ b/modules/setting/service.go @@ -46,6 +46,7 @@ var Service = struct { RequireSignInView bool EnableNotifyMail bool EnableBasicAuth bool + EnablePasskeyAuth bool EnableReverseProxyAuth bool EnableReverseProxyAuthAPI bool EnableReverseProxyAutoRegister bool @@ -161,6 +162,7 @@ func loadServiceFrom(rootCfg ConfigProvider) { Service.RequireSignInView = sec.Key("REQUIRE_SIGNIN_VIEW").MustBool() Service.EnableBasicAuth = sec.Key("ENABLE_BASIC_AUTHENTICATION").MustBool(true) Service.EnablePasswordSignInForm = sec.Key("ENABLE_PASSWORD_SIGNIN_FORM").MustBool(true) + Service.EnablePasskeyAuth = sec.Key("ENABLE_PASSKEY_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() diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index 3fe1d5970e816..363da8f392919 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -169,6 +169,7 @@ func prepareSignInPageData(ctx *context.Context) { ctx.Data["PageIsLogin"] = true ctx.Data["EnableSSPI"] = auth.IsSSPIEnabled(ctx) ctx.Data["EnablePasswordSignInForm"] = setting.Service.EnablePasswordSignInForm + ctx.Data["EnablePasskeyAuth"] = setting.Service.EnablePasskeyAuth if setting.Service.EnableCaptcha && setting.Service.RequireCaptchaForLogin { context.SetCaptchaData(ctx) diff --git a/routers/web/auth/linkaccount.go b/routers/web/auth/linkaccount.go index 147d8d380244c..e55d352e68250 100644 --- a/routers/web/auth/linkaccount.go +++ b/routers/web/auth/linkaccount.go @@ -44,6 +44,7 @@ func LinkAccount(ctx *context.Context) { ctx.Data["DisableRegistration"] = setting.Service.DisableRegistration ctx.Data["AllowOnlyInternalRegistration"] = setting.Service.AllowOnlyInternalRegistration ctx.Data["ShowRegistrationButton"] = false + ctx.Data["EnablePasskeyAuth"] = setting.Service.EnablePasskeyAuth // use this to set the right link into the signIn and signUp templates in the link_account template ctx.Data["SignInLink"] = setting.AppSubURL + "/user/link_account_signin" @@ -136,6 +137,7 @@ func LinkAccountPostSignIn(ctx *context.Context) { ctx.Data["CfTurnstileSitekey"] = setting.Service.CfTurnstileSitekey ctx.Data["DisableRegistration"] = setting.Service.DisableRegistration ctx.Data["ShowRegistrationButton"] = false + ctx.Data["EnablePasskeyAuth"] = setting.Service.EnablePasskeyAuth // use this to set the right link into the signIn and signUp templates in the link_account template ctx.Data["SignInLink"] = setting.AppSubURL + "/user/link_account_signin" @@ -224,6 +226,7 @@ func LinkAccountPostRegister(ctx *context.Context) { ctx.Data["CfTurnstileSitekey"] = setting.Service.CfTurnstileSitekey ctx.Data["DisableRegistration"] = setting.Service.DisableRegistration ctx.Data["ShowRegistrationButton"] = false + ctx.Data["EnablePasskeyAuth"] = setting.Service.EnablePasskeyAuth // use this to set the right link into the signIn and signUp templates in the link_account template ctx.Data["SignInLink"] = setting.AppSubURL + "/user/link_account_signin" diff --git a/routers/web/auth/webauthn.go b/routers/web/auth/webauthn.go index 69031adeaa671..8dbe34b2b1393 100644 --- a/routers/web/auth/webauthn.go +++ b/routers/web/auth/webauthn.go @@ -50,6 +50,11 @@ func WebAuthn(ctx *context.Context) { // WebAuthnPasskeyAssertion submits a WebAuthn challenge for the passkey login to the browser func WebAuthnPasskeyAssertion(ctx *context.Context) { + if !setting.Service.EnablePasskeyAuth { + ctx.Error(http.StatusForbidden) + return + } + assertion, sessionData, err := wa.WebAuthn.BeginDiscoverableLogin() if err != nil { ctx.ServerError("webauthn.BeginDiscoverableLogin", err) @@ -66,6 +71,11 @@ func WebAuthnPasskeyAssertion(ctx *context.Context) { // WebAuthnPasskeyLogin handles the WebAuthn login process using a Passkey func WebAuthnPasskeyLogin(ctx *context.Context) { + if !setting.Service.EnablePasskeyAuth { + ctx.Error(http.StatusForbidden) + return + } + sessionData, okData := ctx.Session.Get("webauthnPasskeyAssertion").(*webauthn.SessionData) if !okData || sessionData == nil { ctx.ServerError("ctx.Session.Get", errors.New("not in WebAuthn session")) diff --git a/templates/user/auth/signin_inner.tmpl b/templates/user/auth/signin_inner.tmpl index fbf86a92bf636..b792701fcacae 100644 --- a/templates/user/auth/signin_inner.tmpl +++ b/templates/user/auth/signin_inner.tmpl @@ -60,10 +60,14 @@
- {{template "user/auth/webauthn_error" .}} + {{if .EnablePasskeyAuth}} + {{template "user/auth/webauthn_error" .}} + {{end}}
- + {{if .EnablePasskeyAuth}} + + {{end}} {{if .ShowRegistrationButton}}
From a42885bfad3ac0ea2872b100c901c296bfcf1b48 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 22 Jan 2025 04:42:19 +0000 Subject: [PATCH 2/9] add test --- tests/integration/signin_test.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/integration/signin_test.go b/tests/integration/signin_test.go index d7c0b1bcd383f..f15e7b5f6fb04 100644 --- a/tests/integration/signin_test.go +++ b/tests/integration/signin_test.go @@ -122,3 +122,25 @@ func TestEnablePasswordSignInForm(t *testing.T) { MakeRequest(t, req, http.StatusOK) }) } + +func TestEnablePasskeyAuth(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + t.Run("EnablePasskeyAuth=false", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + defer test.MockVariableValue(&setting.Service.EnablePasskeyAuth, false)() + + req := NewRequest(t, "GET", "/user/login") + resp := MakeRequest(t, req, http.StatusOK) + NewHTMLParser(t, resp.Body).AssertElement(t, ".signin-passkey", false) + }) + + t.Run("EnablePasskeyAuth=true", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + defer test.MockVariableValue(&setting.Service.EnablePasskeyAuth, true)() + + req := NewRequest(t, "GET", "/user/login") + resp := MakeRequest(t, req, http.StatusOK) + NewHTMLParser(t, resp.Body).AssertElement(t, ".signin-passkey", true) + }) +} From c1eecfc98663f01bd65fd5c784bdd1d2c640e7a9 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 22 Jan 2025 04:49:17 +0000 Subject: [PATCH 3/9] improve --- custom/conf/app.example.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 583fa461febae..c052ac51473d5 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -790,8 +790,8 @@ 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 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 and ENABLE_PASSKEY_AUTHENTICATION to false to completely disable password-based authentication. +;; Show the password sign-in form (for password-based login), otherwise, only show OAuth2 login methods and passkey login link. +;; If you set it to false, maybe it also needs to set ENABLE_BASIC_AUTHENTICATION or ENABLE_PASSKEY_AUTHENTICATION to false to completely disable password-based authentication. ;ENABLE_PASSWORD_SIGNIN_FORM = true ;; ;; This setting enables gitea to be signed in with a passkey From b2617b51e15f715025a2a1d289dcac37122df6db Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 22 Jan 2025 05:51:25 +0000 Subject: [PATCH 4/9] fix --- 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 c052ac51473d5..af68d2bc1e0cd 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -791,7 +791,7 @@ LEVEL = Info ;ENABLE_BASIC_AUTHENTICATION = true ;; ;; Show the password sign-in form (for password-based login), otherwise, only show OAuth2 login methods and passkey login link. -;; If you set it to false, maybe it also needs to set ENABLE_BASIC_AUTHENTICATION or ENABLE_PASSKEY_AUTHENTICATION to false to completely disable password-based authentication. +;; 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 ;; ;; This setting enables gitea to be signed in with a passkey From e850728aef77e5ec0a43653d0dfc3f7c61a476d1 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 22 Jan 2025 09:00:31 +0000 Subject: [PATCH 5/9] improve --- templates/user/auth/signin_inner.tmpl | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/templates/user/auth/signin_inner.tmpl b/templates/user/auth/signin_inner.tmpl index b792701fcacae..de3a1cdea7b1f 100644 --- a/templates/user/auth/signin_inner.tmpl +++ b/templates/user/auth/signin_inner.tmpl @@ -60,12 +60,9 @@
- {{if .EnablePasskeyAuth}} - {{template "user/auth/webauthn_error" .}} - {{end}} -
{{if .EnablePasskeyAuth}} + {{template "user/auth/webauthn_error" .}} {{end}} From f1dd06b56983cbacdafa9d014adb5d8137a745ef Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 22 Jan 2025 09:01:13 +0000 Subject: [PATCH 6/9] improve --- tests/integration/signin_test.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/integration/signin_test.go b/tests/integration/signin_test.go index f15e7b5f6fb04..a00413c983f1f 100644 --- a/tests/integration/signin_test.go +++ b/tests/integration/signin_test.go @@ -95,7 +95,7 @@ func TestSigninWithRememberMe(t *testing.T) { session.MakeRequest(t, req, http.StatusOK) } -func TestEnablePasswordSignInForm(t *testing.T) { +func TestEnablePasswordSignInFormAndEnablePasskeyAuth(t *testing.T) { defer tests.PrepareTestEnv(t)() t.Run("EnablePasswordSignInForm=false", func(t *testing.T) { @@ -121,10 +121,6 @@ func TestEnablePasswordSignInForm(t *testing.T) { req = NewRequest(t, "POST", "/user/login") MakeRequest(t, req, http.StatusOK) }) -} - -func TestEnablePasskeyAuth(t *testing.T) { - defer tests.PrepareTestEnv(t)() t.Run("EnablePasskeyAuth=false", func(t *testing.T) { defer tests.PrintCurrentTest(t)() From 84fcdded5d3845e52ea1a6d555c107ab2dd0feba Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Wed, 22 Jan 2025 09:02:50 +0000 Subject: [PATCH 7/9] remove 'link' --- 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 af68d2bc1e0cd..d422031e4ebd7 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -790,7 +790,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 sign-in form (for password-based login), otherwise, only show OAuth2 login methods and passkey login link. +;; Show the password sign-in form (for password-based login), otherwise, only show OAuth2 login methods and passkey login. ;; 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 ;; From 11dee092ca90a16356ae96880713696680406f21 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Wed, 22 Jan 2025 17:07:18 +0800 Subject: [PATCH 8/9] Update custom/conf/app.example.ini --- 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 d422031e4ebd7..4bfc548b79bce 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -790,7 +790,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 sign-in form (for password-based login), otherwise, only show OAuth2 login methods and passkey login. +;; Show the password sign-in form (for password-based login), otherwise, only show OAuth2 or passkey login methods if they are enabled. ;; 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 ;; From cbd6a1b05ed2b655baea56ee0fb914b4c26837dc Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Wed, 22 Jan 2025 17:08:50 +0800 Subject: [PATCH 9/9] Update custom/conf/app.example.ini --- 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 4bfc548b79bce..15c525260f193 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -794,7 +794,7 @@ LEVEL = Info ;; 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 ;; -;; This setting enables gitea to be signed in with a passkey +;; Allow users to sign-in with a passkey ;ENABLE_PASSKEY_AUTHENTICATION = true ;; ;; More detail: https://github.com/gogits/gogs/issues/165