package authn
import (
"encoding/base64"
"errors"
"testing"
"time"
"github.com/dolthub/dolt/go/libraries/doltcore/creds"
"sourcecraft.dev/bigbes/sr-ht-core/auth"
)
func basicHeader(user, pass string) string {
return "Basic " + base64.StdEncoding.EncodeToString([]byte(user+":"+pass))
}
func TestResolveGRPCAuth_Empty(t *testing.T) {
withStubBackend(t, &stubBackend{})
ac, err := ResolveGRPCAuth(testCtx(), "", testAud, &stubKeyStore{})
if err != nil {
t.Fatalf("empty header must be anonymous (no error), got %v", err)
}
if ac != nil {
t.Fatalf("empty header must resolve to nil caller, got %+v", ac)
}
}
func TestResolveGRPCAuth_Basic(t *testing.T) {
withStubBackend(t, &stubBackend{users: map[string]auth.AuthContext{
"bigbes": sampleUser(1, "bigbes", auth.USER_TYPE_USER),
}})
pat := forgePAT("bigbes", "", time.Now().Add(time.Hour))
ac, err := ResolveGRPCAuth(testCtx(), basicHeader("bigbes", pat), testAud, &stubKeyStore{})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if ac == nil || ac.Username != "bigbes" {
t.Fatalf("expected bigbes, got %+v", ac)
}
}
func TestResolveGRPCAuth_Bearer(t *testing.T) {
withStubBackend(t, &stubBackend{users: map[string]auth.AuthContext{
"bigbes": sampleUser(1, "bigbes", auth.USER_TYPE_USER),
}})
priv, kid, ks := doltKeypair(t, "bigbes")
raw := mintDoltJWT(t, priv, kid, testAud, creds.ClientIssuer, validSub(kid), time.Now().Add(30*time.Second))
ac, err := ResolveGRPCAuth(testCtx(), "Bearer "+raw, testAud, ks)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if ac == nil || ac.Username != "bigbes" {
t.Fatalf("expected bigbes, got %+v", ac)
}
if ac.AuthMethod != AuthMethodDoltKey {
t.Fatalf("AuthMethod = %q, want %q", ac.AuthMethod, AuthMethodDoltKey)
}
}
func TestResolveGRPCAuth_SchemeIsCaseInsensitive(t *testing.T) {
withStubBackend(t, &stubBackend{users: map[string]auth.AuthContext{
"bigbes": sampleUser(1, "bigbes", auth.USER_TYPE_USER),
}})
pat := forgePAT("bigbes", "", time.Now().Add(time.Hour))
header := "basic " + base64.StdEncoding.EncodeToString([]byte("bigbes:"+pat))
if _, err := ResolveGRPCAuth(testCtx(), header, testAud, &stubKeyStore{}); err != nil {
t.Fatalf("lowercase scheme must work, got %v", err)
}
}
func TestResolveGRPCAuth_Malformed(t *testing.T) {
withStubBackend(t, &stubBackend{})
cases := map[string]string{
"no space": "Basicdeadbeef",
"bad base64": "Basic !!!not-base64!!!",
"no colon": "Basic " + base64.StdEncoding.EncodeToString([]byte("nocolon")),
"unknown scheme": "Digest abcdef",
"scheme no value": "Bearer ",
}
for name, header := range cases {
t.Run(name, func(t *testing.T) {
_, err := ResolveGRPCAuth(testCtx(), header, testAud, &stubKeyStore{})
if !errors.Is(err, ErrInvalidToken) {
t.Fatalf("expected ErrInvalidToken, got %v", err)
}
})
}
}