Some checks are pending
Security Checks / security (push) Waiting to run
修复管理员用户列表成员版本缺失导致的多分组保存失败,并保留管理员不可管理分组的成员关系,补充回归测试。
170 lines
5.7 KiB
Go
170 lines
5.7 KiB
Go
package accountgroup
|
||
|
||
import (
|
||
"testing"
|
||
|
||
"git.pcux.cn/xuans/Smail/models"
|
||
"git.pcux.cn/xuans/Smail/services/access"
|
||
_ "modernc.org/sqlite"
|
||
"xorm.io/xorm"
|
||
)
|
||
|
||
func TestCanAccessExcludesSuperAdminFromAdminScope(t *testing.T) {
|
||
engine, err := xorm.NewEngine("sqlite", ":memory:")
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
defer engine.Close()
|
||
|
||
if err := engine.Sync2(new(models.User), new(models.AccountGroupMember)); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
|
||
superAdmin := models.User{Account: "superadmin", Name: "超级管理员", Role: string(access.RoleSuperAdmin)}
|
||
admin := models.User{Account: "admin", Name: "分组管理员", Role: string(access.RoleAdmin), IsAdmin: 1}
|
||
member := models.User{Account: "member", Name: "普通用户", Role: string(access.RoleUser)}
|
||
if _, err := engine.Insert(&superAdmin, &admin, &member); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
|
||
if _, err := engine.Insert(
|
||
&models.AccountGroupMember{UserID: admin.ID, GroupID: 1},
|
||
&models.AccountGroupMember{UserID: member.ID, GroupID: 1},
|
||
); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
|
||
if CanAccess(engine, admin.ID, access.RoleAdmin, superAdmin.ID) {
|
||
t.Fatal("管理员不应访问超级管理员账户")
|
||
}
|
||
if !CanAccess(engine, admin.ID, access.RoleAdmin, member.ID) {
|
||
t.Fatal("管理员应访问同组普通用户账户")
|
||
}
|
||
}
|
||
|
||
func TestMembershipScopeGuardLimitsAdminToOwnedGroups(t *testing.T) {
|
||
engine, err := xorm.NewEngine("sqlite", ":memory:")
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
defer engine.Close()
|
||
|
||
if err := engine.Sync2(new(models.User), new(models.AccountGroup), new(models.AccountGroupMember)); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
admin := models.User{Account: "admin", Name: "分组管理员", Role: string(access.RoleAdmin), IsAdmin: 1}
|
||
superAdmin := models.User{Account: "superadmin", Name: "超级管理员", Role: string(access.RoleSuperAdmin)}
|
||
if _, err := engine.Insert(&admin, &superAdmin); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if _, err := engine.Insert(
|
||
&models.AccountGroup{ID: 1, Name: "一组"},
|
||
&models.AccountGroup{ID: 2, Name: "二组"},
|
||
&models.AccountGroupMember{UserID: admin.ID, GroupID: 1},
|
||
); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
|
||
tx := engine.NewSession()
|
||
defer tx.Close()
|
||
if err := tx.Begin(); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
defer tx.Rollback()
|
||
|
||
if err := MembershipScopeGuard(admin.ID, access.RoleAdmin, []int{1})(tx); err != nil {
|
||
t.Fatalf("管理员应能管理所属分组:%v", err)
|
||
}
|
||
if err := MembershipScopeGuard(admin.ID, access.RoleAdmin, []int{2})(tx); err != ErrDenied {
|
||
t.Fatalf("管理员不应管理其他分组,得到:%v", err)
|
||
}
|
||
if err := MembershipScopeGuard(superAdmin.ID, access.RoleSuperAdmin, []int{2})(tx); err != nil {
|
||
t.Fatalf("超级管理员应能管理全部分组:%v", err)
|
||
}
|
||
}
|
||
|
||
func TestMembershipScopeGuardUsesDefaultGroupWhenAdminHasNoMembership(t *testing.T) {
|
||
engine, err := xorm.NewEngine("sqlite", ":memory:")
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
defer engine.Close()
|
||
|
||
if err := engine.Sync2(new(models.User), new(models.AccountGroupMember)); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
admin := models.User{Account: "admin", Name: "默认分组管理员", Role: string(access.RoleAdmin), IsAdmin: 1}
|
||
if _, err := engine.Insert(&admin); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
|
||
tx := engine.NewSession()
|
||
defer tx.Close()
|
||
if err := tx.Begin(); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
defer tx.Rollback()
|
||
|
||
if err := MembershipScopeGuard(admin.ID, access.RoleAdmin, []int{0})(tx); err != nil {
|
||
t.Fatalf("无明确分组的管理员应能管理默认分组:%v", err)
|
||
}
|
||
if err := MembershipScopeGuard(admin.ID, access.RoleAdmin, []int{1})(tx); err != ErrDenied {
|
||
t.Fatalf("无明确分组的管理员不应管理其他分组,得到:%v", err)
|
||
}
|
||
}
|
||
|
||
func TestValidateMembershipKeepsAdminMultiGroupAndUserSingleGroupRules(t *testing.T) {
|
||
engine, err := xorm.NewEngine("sqlite", ":memory:")
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
defer engine.Close()
|
||
if err := engine.Sync2(new(models.AccountGroup)); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if _, err := engine.Insert(&models.AccountGroup{ID: 1, Name: "一组"}, &models.AccountGroup{ID: 2, Name: "二组"}); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
|
||
tx := engine.NewSession()
|
||
defer tx.Close()
|
||
if ids, err := ValidateMembership(tx, access.RoleAdmin, []int{1, 2}); err != nil || len(ids) != 2 {
|
||
t.Fatalf("管理员应允许多个分组,ids=%v err=%v", ids, err)
|
||
}
|
||
if _, err := ValidateMembership(tx, access.RoleUser, []int{1, 2}); err != ErrInvalid {
|
||
t.Fatalf("普通用户不应允许多个分组,得到:%v", err)
|
||
}
|
||
}
|
||
|
||
func TestSetScopedMembershipPreservesGroupsOutsideAdminScope(t *testing.T) {
|
||
engine, err := xorm.NewEngine(`sqlite`, `:memory:`)
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
defer engine.Close()
|
||
if err := engine.Sync2(new(models.User), new(models.AccountGroup), new(models.AccountGroupMember)); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
target := models.User{Account: `target`, Name: `Target`, Role: string(access.RoleUser), SessionVersion: 1, SecurityVersion: 1}
|
||
if _, err := engine.Insert(&target); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if _, err := engine.Insert(&models.AccountGroup{ID: 1, Name: `visible`}, &models.AccountGroup{ID: 2, Name: `hidden`}); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if _, err := engine.Insert(&models.AccountGroupMember{UserID: target.ID, GroupID: 1}, &models.AccountGroupMember{UserID: target.ID, GroupID: 2}); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
allow := func(*xorm.Session) error { return nil }
|
||
if err := SetScopedMembership(engine, target, []int{0}, []int{0, 1}, allow); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
rows := make([]models.AccountGroupMember, 0)
|
||
if err := engine.Where(`user_id = ?`, target.ID).Asc(`group_id`).Find(&rows); err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if len(rows) != 2 || rows[0].GroupID != 0 || rows[1].GroupID != 2 {
|
||
t.Fatalf(`scoped membership changed an inaccessible group: %+v`, rows)
|
||
}
|
||
}
|