]> source.dussan.org Git - gitea.git/commitdiff
Fix basic auth with webauthn (#32531)
authorLunny Xiao <xiaolunwen@gmail.com>
Sat, 16 Nov 2024 17:52:16 +0000 (09:52 -0800)
committerGitHub <noreply@github.com>
Sat, 16 Nov 2024 17:52:16 +0000 (17:52 +0000)
services/auth/basic.go
tests/integration/api_twofa_test.go

index 90bd64237091d3e6ab857f8753cc77bb59a97008..1f6c3a442d1d82309363c9bc670394cdff51b957 100644 (file)
@@ -5,6 +5,7 @@
 package auth
 
 import (
+       "errors"
        "net/http"
        "strings"
 
@@ -141,6 +142,15 @@ func (b *Basic) Verify(req *http.Request, w http.ResponseWriter, store DataStore
        }
 
        if skipper, ok := source.Cfg.(LocalTwoFASkipper); !ok || !skipper.IsSkipLocalTwoFA() {
+               // Check if the user has webAuthn registration
+               hasWebAuthn, err := auth_model.HasWebAuthnRegistrationsByUID(req.Context(), u.ID)
+               if err != nil {
+                       return nil, err
+               }
+               if hasWebAuthn {
+                       return nil, errors.New("Basic authorization is not allowed while webAuthn enrolled")
+               }
+
                if err := validateTOTP(req, u); err != nil {
                        return nil, err
                }
index aad806b6dc4ffd05daf3313caccdd7abf579ca70..18e6fa91b7e6c0f6840d3d86158dbd4c03b36a02 100644 (file)
@@ -53,3 +53,56 @@ func TestAPITwoFactor(t *testing.T) {
        req.Header.Set("X-Gitea-OTP", passcode)
        MakeRequest(t, req, http.StatusOK)
 }
+
+func TestBasicAuthWithWebAuthn(t *testing.T) {
+       defer tests.PrepareTestEnv(t)()
+
+       // user1 has no webauthn enrolled, he can request API with basic auth
+       user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
+       unittest.AssertNotExistsBean(t, &auth_model.WebAuthnCredential{UserID: user1.ID})
+       req := NewRequest(t, "GET", "/api/v1/user")
+       req.SetBasicAuth(user1.Name, "password")
+       MakeRequest(t, req, http.StatusOK)
+
+       // user1 has no webauthn enrolled, he can request git protocol with basic auth
+       req = NewRequest(t, "GET", "/user2/repo1/info/refs")
+       req.SetBasicAuth(user1.Name, "password")
+       MakeRequest(t, req, http.StatusOK)
+
+       // user1 has no webauthn enrolled, he can request container package with basic auth
+       req = NewRequest(t, "GET", "/v2/token")
+       req.SetBasicAuth(user1.Name, "password")
+       resp := MakeRequest(t, req, http.StatusOK)
+
+       type tokenResponse struct {
+               Token string `json:"token"`
+       }
+       var tokenParsed tokenResponse
+       DecodeJSON(t, resp, &tokenParsed)
+       assert.NotEmpty(t, tokenParsed.Token)
+
+       // user32 has webauthn enrolled, he can't request API with basic auth
+       user32 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 32})
+       unittest.AssertExistsAndLoadBean(t, &auth_model.WebAuthnCredential{UserID: user32.ID})
+
+       req = NewRequest(t, "GET", "/api/v1/user")
+       req.SetBasicAuth(user32.Name, "notpassword")
+       resp = MakeRequest(t, req, http.StatusUnauthorized)
+
+       type userResponse struct {
+               Message string `json:"message"`
+       }
+       var userParsed userResponse
+       DecodeJSON(t, resp, &userParsed)
+       assert.EqualValues(t, "Basic authorization is not allowed while webAuthn enrolled", userParsed.Message)
+
+       // user32 has webauthn enrolled, he can't request git protocol with basic auth
+       req = NewRequest(t, "GET", "/user2/repo1/info/refs")
+       req.SetBasicAuth(user32.Name, "notpassword")
+       MakeRequest(t, req, http.StatusUnauthorized)
+
+       // user32 has webauthn enrolled, he can't request container package with basic auth
+       req = NewRequest(t, "GET", "/v2/token")
+       req.SetBasicAuth(user1.Name, "notpassword")
+       MakeRequest(t, req, http.StatusUnauthorized)
+}