mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 20:36:07 +01:00 
			
		
		
		
	Support disable passkey auth (#33348)
Fix #33314 --------- Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
		@@ -790,10 +790,13 @@ LEVEL = Info
 | 
				
			|||||||
;; Please note that setting this to false will not disable OAuth Basic or Basic authentication using a token
 | 
					;; Please note that setting this to false will not disable OAuth Basic or Basic authentication using a token
 | 
				
			||||||
;ENABLE_BASIC_AUTHENTICATION = true
 | 
					;ENABLE_BASIC_AUTHENTICATION = true
 | 
				
			||||||
;;
 | 
					;;
 | 
				
			||||||
;; Show the password sign-in 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 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.
 | 
					;; 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
 | 
					;ENABLE_PASSWORD_SIGNIN_FORM = true
 | 
				
			||||||
;;
 | 
					;;
 | 
				
			||||||
 | 
					;; Allow users to sign-in with a passkey
 | 
				
			||||||
 | 
					;ENABLE_PASSKEY_AUTHENTICATION = true
 | 
				
			||||||
 | 
					;;
 | 
				
			||||||
;; More detail: https://github.com/gogits/gogs/issues/165
 | 
					;; More detail: https://github.com/gogits/gogs/issues/165
 | 
				
			||||||
;ENABLE_REVERSE_PROXY_AUTHENTICATION = false
 | 
					;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.
 | 
					; Enable this to allow reverse proxy authentication for API requests, the reverse proxy is responsible for ensuring that no CSRF is possible.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,6 +46,7 @@ var Service = struct {
 | 
				
			|||||||
	RequireSignInView                       bool
 | 
						RequireSignInView                       bool
 | 
				
			||||||
	EnableNotifyMail                        bool
 | 
						EnableNotifyMail                        bool
 | 
				
			||||||
	EnableBasicAuth                         bool
 | 
						EnableBasicAuth                         bool
 | 
				
			||||||
 | 
						EnablePasskeyAuth                       bool
 | 
				
			||||||
	EnableReverseProxyAuth                  bool
 | 
						EnableReverseProxyAuth                  bool
 | 
				
			||||||
	EnableReverseProxyAuthAPI               bool
 | 
						EnableReverseProxyAuthAPI               bool
 | 
				
			||||||
	EnableReverseProxyAutoRegister          bool
 | 
						EnableReverseProxyAutoRegister          bool
 | 
				
			||||||
@@ -161,6 +162,7 @@ func loadServiceFrom(rootCfg ConfigProvider) {
 | 
				
			|||||||
	Service.RequireSignInView = sec.Key("REQUIRE_SIGNIN_VIEW").MustBool()
 | 
						Service.RequireSignInView = sec.Key("REQUIRE_SIGNIN_VIEW").MustBool()
 | 
				
			||||||
	Service.EnableBasicAuth = sec.Key("ENABLE_BASIC_AUTHENTICATION").MustBool(true)
 | 
						Service.EnableBasicAuth = sec.Key("ENABLE_BASIC_AUTHENTICATION").MustBool(true)
 | 
				
			||||||
	Service.EnablePasswordSignInForm = sec.Key("ENABLE_PASSWORD_SIGNIN_FORM").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.EnableReverseProxyAuth = sec.Key("ENABLE_REVERSE_PROXY_AUTHENTICATION").MustBool()
 | 
				
			||||||
	Service.EnableReverseProxyAuthAPI = sec.Key("ENABLE_REVERSE_PROXY_AUTHENTICATION_API").MustBool()
 | 
						Service.EnableReverseProxyAuthAPI = sec.Key("ENABLE_REVERSE_PROXY_AUTHENTICATION_API").MustBool()
 | 
				
			||||||
	Service.EnableReverseProxyAutoRegister = sec.Key("ENABLE_REVERSE_PROXY_AUTO_REGISTRATION").MustBool()
 | 
						Service.EnableReverseProxyAutoRegister = sec.Key("ENABLE_REVERSE_PROXY_AUTO_REGISTRATION").MustBool()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -169,6 +169,7 @@ func prepareSignInPageData(ctx *context.Context) {
 | 
				
			|||||||
	ctx.Data["PageIsLogin"] = true
 | 
						ctx.Data["PageIsLogin"] = true
 | 
				
			||||||
	ctx.Data["EnableSSPI"] = auth.IsSSPIEnabled(ctx)
 | 
						ctx.Data["EnableSSPI"] = auth.IsSSPIEnabled(ctx)
 | 
				
			||||||
	ctx.Data["EnablePasswordSignInForm"] = setting.Service.EnablePasswordSignInForm
 | 
						ctx.Data["EnablePasswordSignInForm"] = setting.Service.EnablePasswordSignInForm
 | 
				
			||||||
 | 
						ctx.Data["EnablePasskeyAuth"] = setting.Service.EnablePasskeyAuth
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if setting.Service.EnableCaptcha && setting.Service.RequireCaptchaForLogin {
 | 
						if setting.Service.EnableCaptcha && setting.Service.RequireCaptchaForLogin {
 | 
				
			||||||
		context.SetCaptchaData(ctx)
 | 
							context.SetCaptchaData(ctx)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,6 +46,7 @@ func LinkAccount(ctx *context.Context) {
 | 
				
			|||||||
	ctx.Data["AllowOnlyInternalRegistration"] = setting.Service.AllowOnlyInternalRegistration
 | 
						ctx.Data["AllowOnlyInternalRegistration"] = setting.Service.AllowOnlyInternalRegistration
 | 
				
			||||||
	ctx.Data["EnablePasswordSignInForm"] = setting.Service.EnablePasswordSignInForm
 | 
						ctx.Data["EnablePasswordSignInForm"] = setting.Service.EnablePasswordSignInForm
 | 
				
			||||||
	ctx.Data["ShowRegistrationButton"] = false
 | 
						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
 | 
						// 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"
 | 
						ctx.Data["SignInLink"] = setting.AppSubURL + "/user/link_account_signin"
 | 
				
			||||||
@@ -145,6 +146,7 @@ func LinkAccountPostSignIn(ctx *context.Context) {
 | 
				
			|||||||
	ctx.Data["AllowOnlyInternalRegistration"] = setting.Service.AllowOnlyInternalRegistration
 | 
						ctx.Data["AllowOnlyInternalRegistration"] = setting.Service.AllowOnlyInternalRegistration
 | 
				
			||||||
	ctx.Data["EnablePasswordSignInForm"] = setting.Service.EnablePasswordSignInForm
 | 
						ctx.Data["EnablePasswordSignInForm"] = setting.Service.EnablePasswordSignInForm
 | 
				
			||||||
	ctx.Data["ShowRegistrationButton"] = false
 | 
						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
 | 
						// 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"
 | 
						ctx.Data["SignInLink"] = setting.AppSubURL + "/user/link_account_signin"
 | 
				
			||||||
@@ -235,6 +237,7 @@ func LinkAccountPostRegister(ctx *context.Context) {
 | 
				
			|||||||
	ctx.Data["AllowOnlyInternalRegistration"] = setting.Service.AllowOnlyInternalRegistration
 | 
						ctx.Data["AllowOnlyInternalRegistration"] = setting.Service.AllowOnlyInternalRegistration
 | 
				
			||||||
	ctx.Data["EnablePasswordSignInForm"] = setting.Service.EnablePasswordSignInForm
 | 
						ctx.Data["EnablePasswordSignInForm"] = setting.Service.EnablePasswordSignInForm
 | 
				
			||||||
	ctx.Data["ShowRegistrationButton"] = false
 | 
						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
 | 
						// 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"
 | 
						ctx.Data["SignInLink"] = setting.AppSubURL + "/user/link_account_signin"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -50,6 +50,11 @@ func WebAuthn(ctx *context.Context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// WebAuthnPasskeyAssertion submits a WebAuthn challenge for the passkey login to the browser
 | 
					// WebAuthnPasskeyAssertion submits a WebAuthn challenge for the passkey login to the browser
 | 
				
			||||||
func WebAuthnPasskeyAssertion(ctx *context.Context) {
 | 
					func WebAuthnPasskeyAssertion(ctx *context.Context) {
 | 
				
			||||||
 | 
						if !setting.Service.EnablePasskeyAuth {
 | 
				
			||||||
 | 
							ctx.Error(http.StatusForbidden)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assertion, sessionData, err := wa.WebAuthn.BeginDiscoverableLogin()
 | 
						assertion, sessionData, err := wa.WebAuthn.BeginDiscoverableLogin()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		ctx.ServerError("webauthn.BeginDiscoverableLogin", err)
 | 
							ctx.ServerError("webauthn.BeginDiscoverableLogin", err)
 | 
				
			||||||
@@ -66,6 +71,11 @@ func WebAuthnPasskeyAssertion(ctx *context.Context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// WebAuthnPasskeyLogin handles the WebAuthn login process using a Passkey
 | 
					// WebAuthnPasskeyLogin handles the WebAuthn login process using a Passkey
 | 
				
			||||||
func WebAuthnPasskeyLogin(ctx *context.Context) {
 | 
					func WebAuthnPasskeyLogin(ctx *context.Context) {
 | 
				
			||||||
 | 
						if !setting.Service.EnablePasskeyAuth {
 | 
				
			||||||
 | 
							ctx.Error(http.StatusForbidden)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sessionData, okData := ctx.Session.Get("webauthnPasskeyAssertion").(*webauthn.SessionData)
 | 
						sessionData, okData := ctx.Session.Get("webauthnPasskeyAssertion").(*webauthn.SessionData)
 | 
				
			||||||
	if !okData || sessionData == nil {
 | 
						if !okData || sessionData == nil {
 | 
				
			||||||
		ctx.ServerError("ctx.Session.Get", errors.New("not in WebAuthn session"))
 | 
							ctx.ServerError("ctx.Session.Get", errors.New("not in WebAuthn session"))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -60,10 +60,11 @@
 | 
				
			|||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<div class="ui container fluid">
 | 
					<div class="ui container fluid">
 | 
				
			||||||
	{{template "user/auth/webauthn_error" .}}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	<div class="ui attached segment header top tw-max-w-2xl tw-m-auto tw-flex tw-flex-col tw-items-center">
 | 
						<div class="ui attached segment header top tw-max-w-2xl tw-m-auto tw-flex tw-flex-col tw-items-center">
 | 
				
			||||||
 | 
							{{if .EnablePasskeyAuth}}
 | 
				
			||||||
 | 
								{{template "user/auth/webauthn_error" .}}
 | 
				
			||||||
			<a class="signin-passkey">{{ctx.Locale.Tr "auth.signin_passkey"}}</a>
 | 
								<a class="signin-passkey">{{ctx.Locale.Tr "auth.signin_passkey"}}</a>
 | 
				
			||||||
 | 
							{{end}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		{{if .ShowRegistrationButton}}
 | 
							{{if .ShowRegistrationButton}}
 | 
				
			||||||
			<div class="field">
 | 
								<div class="field">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -98,7 +98,7 @@ func TestSigninWithRememberMe(t *testing.T) {
 | 
				
			|||||||
	session.MakeRequest(t, req, http.StatusOK)
 | 
						session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestEnablePasswordSignInForm(t *testing.T) {
 | 
					func TestEnablePasswordSignInFormAndEnablePasskeyAuth(t *testing.T) {
 | 
				
			||||||
	defer tests.PrepareTestEnv(t)()
 | 
						defer tests.PrepareTestEnv(t)()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mockLinkAccount := func(ctx *context.Context) {
 | 
						mockLinkAccount := func(ctx *context.Context) {
 | 
				
			||||||
@@ -141,4 +141,22 @@ func TestEnablePasswordSignInForm(t *testing.T) {
 | 
				
			|||||||
		resp = MakeRequest(t, req, http.StatusOK)
 | 
							resp = MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
		NewHTMLParser(t, resp.Body).AssertElement(t, "form[action='/user/link_account_signin']", true)
 | 
							NewHTMLParser(t, resp.Body).AssertElement(t, "form[action='/user/link_account_signin']", true)
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user