You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
OneAuth/auth/auth_test.go

253 lines
6.6 KiB
Go

package auth
import (
"context"
"fmt"
"os"
"testing"
"time"
"github.com/veypi/vbase/cfg"
"github.com/veypi/vbase/models"
)
// setupTestDB 初始化测试数据库
func setupTestDB() {
// 使用 SQLite 内存模式
cfg.Config.DB.Type = "sqlite"
cfg.Config.DB.Type = fmt.Sprintf("file::memory:?cache=shared&_time=%d", time.Now().UnixNano())
// 初始化数据库表
if err := models.AllModels.AutoMigrate(cfg.DB()); err != nil {
panic(err)
}
}
// TestMain 负责测试环境的全局初始化
func TestMain(m *testing.M) {
setupTestDB()
code := m.Run()
os.Exit(code)
}
func getTestAuth() Auth {
// 每次获取一个新的 scope避免测试间冲突虽然内存库是共享的但数据清理可能不完全
// 为了简单起见,我们在 TestMain 中只初始化一次 DB但可以通过 scope 区分
scope := fmt.Sprintf("test_scope_%d", time.Now().UnixNano())
a := Factory.New(scope)
// 添加角色定义
a.AddRole("admin", "Administrator", "*:*")
a.AddRole("editor", "Editor",
"article:create",
"article:read",
"article:update",
)
a.AddRole("viewer", "Viewer", "article:read")
a.AddRole("deleter", "Deleter", "article:delete")
// 初始化
if err := a.(*appAuth).init(); err != nil {
panic(err)
}
return a
}
// TestBasicPermission 测试基础权限授予与检查
func TestBasicPermission(t *testing.T) {
a := getTestAuth()
ctx := context.Background()
userID := "user_basic_001"
// 初始状态应该无权限
ok, err := a.CheckPermission(ctx, userID, "", "article:read", "")
if err != nil {
t.Fatalf("CheckPermission failed: %v", err)
}
if ok {
t.Error("Expected no permission initially")
}
// 授予 viewer 角色
if err := a.GrantRole(ctx, userID, "", "viewer"); err != nil {
t.Fatalf("GrantRole failed: %v", err)
}
// 应该有 article:read 权限
ok, err = a.CheckPermission(ctx, userID, "", "article:read", "")
if err != nil {
t.Fatalf("CheckPermission failed: %v", err)
}
if !ok {
t.Error("Expected article:read permission after granting viewer role")
}
// 不应该有 article:create 权限
ok, err = a.CheckPermission(ctx, userID, "", "article:create", "")
if err != nil {
t.Fatalf("CheckPermission failed: %v", err)
}
if ok {
t.Error("Expected no article:create permission for viewer")
}
}
// TestWildcardPermission 测试通配符权限
func TestWildcardPermission(t *testing.T) {
a := getTestAuth()
ctx := context.Background()
userID := "user_admin_001"
// 授予 admin 角色 (*:*)
if err := a.GrantRole(ctx, userID, "", "admin"); err != nil {
t.Fatalf("GrantRole failed: %v", err)
}
// 应该拥有所有权限
tests := []string{
"article:read",
"article:delete",
"user:create",
"config:update", // system:config:update 会被解析为 system 应用的权限,而 admin 是 test_app 的 admin
}
for _, perm := range tests {
ok, err := a.CheckPermission(ctx, userID, "", perm, "")
if err != nil {
t.Errorf("CheckPermission %s failed: %v", perm, err)
continue
}
if !ok {
t.Errorf("Expected permission %s for admin", perm)
}
}
}
// TestStrictPermissionIsolation 验证权限严格隔离性 (用户请求场景)
// 验证:拥有 delete 权限的用户,是否能通过 read 权限检查
func TestStrictPermissionIsolation(t *testing.T) {
a := getTestAuth()
ctx := context.Background()
userID := "user_deleter_001"
// 授予 deleter 角色 (只包含 article:delete)
if err := a.GrantRole(ctx, userID, "", "deleter"); err != nil {
t.Fatalf("GrantRole failed: %v", err)
}
// 1. 检查 article:delete (应该通过)
ok, err := a.CheckPermission(ctx, userID, "", "article:delete", "")
if err != nil {
t.Fatalf("CheckPermission error: %v", err)
}
if !ok {
t.Errorf("Expected user to have article:delete permission")
}
// 2. 检查 article:read (应该失败)
// 关键验证点delete 不包含 read
ok, err = a.CheckPermission(ctx, userID, "", "article:read", "")
if err != nil {
t.Fatalf("CheckPermission error: %v", err)
}
if ok {
t.Errorf("Strict isolation failed: User with 'article:delete' passed 'article:read' check")
}
}
// TestOrgIsolation 测试多租户/组织隔离
func TestOrgIsolation(t *testing.T) {
a := getTestAuth()
ctx := context.Background()
userID := "user_org_001"
orgA := "org_a"
orgB := "org_b"
// 在 OrgA 中授予 editor 角色
if err := a.GrantRole(ctx, userID, orgA, "editor"); err != nil {
t.Fatalf("GrantRole failed: %v", err)
}
// 在 OrgA 上下文中检查 article:create (应该通过)
ok, err := a.CheckPermission(ctx, userID, orgA, "article:create", "")
if err != nil {
t.Fatalf("CheckPermission failed: %v", err)
}
if !ok {
t.Error("Expected permission in OrgA")
}
// 在 OrgB 上下文中检查 article:create (应该失败)
ok, err = a.CheckPermission(ctx, userID, orgB, "article:create", "")
if err != nil {
t.Fatalf("CheckPermission failed: %v", err)
}
if ok {
t.Error("Expected no permission in OrgB (role was granted in OrgA)")
}
// 在全局上下文中检查 (应该失败,因为角色绑定在 OrgA)
ok, err = a.CheckPermission(ctx, userID, "", "article:create", "")
if err != nil {
t.Fatalf("CheckPermission failed: %v", err)
}
if ok {
t.Error("Expected no global permission")
}
}
// TestResourcePermission 测试特定资源权限
func TestResourcePermission(t *testing.T) {
a := getTestAuth()
ctx := context.Background()
userID := "user_res_001"
resID := "doc_123"
// 需要先创建权限定义,因为 GrantResourcePerm 会检查权限是否存在
permID := fmt.Sprintf("%s:doc:read", a.(*appAuth).scope)
perm := models.Permission{
ID: permID,
Scope: a.(*appAuth).scope,
Resource: "doc",
Action: "read",
Description: "Read Doc",
}
if err := cfg.DB().Create(&perm).Error; err != nil {
t.Fatalf("Failed to create permission: %v", err)
}
// 初始无权限
ok, err := a.CheckPermission(ctx, userID, "", "doc:read", resID)
if err != nil {
t.Fatalf("CheckPermission failed: %v", err)
}
if ok {
t.Error("Expected no permission")
}
// 授予对特定资源 doc_123 的 doc:read 权限
if err := a.GrantResourcePerm(ctx, userID, "", "doc:read", resID); err != nil {
t.Fatalf("GrantResourcePerm failed: %v", err)
}
// 检查 doc:read on doc_123 (应该通过)
ok, err = a.CheckPermission(ctx, userID, "", "doc:read", resID)
if err != nil {
t.Fatalf("CheckPermission failed: %v", err)
}
if !ok {
t.Error("Expected permission on specific resource")
}
// 检查 doc:read on doc_456 (应该失败)
ok, err = a.CheckPermission(ctx, userID, "", "doc:read", "doc_456")
if err != nil {
t.Fatalf("CheckPermission failed: %v", err)
}
if ok {
t.Error("Expected no permission on other resource")
}
}