Files
lijiaoqiao/supply-api/internal/iam/scope_test.go

391 lines
9.2 KiB
Go
Raw Normal View History

package iam
import (
"testing"
)
// TestP102_ParseScope 解析scope字符串
func TestP102_ParseScope(t *testing.T) {
testCases := []struct {
name string
scopeStr string
wantErr bool
domain string
resource string
action string
}{
{
name: "valid supply scope",
scopeStr: "supply:accounts:read",
wantErr: false,
domain: "supply",
resource: "accounts",
action: "read",
},
{
name: "valid billing scope",
scopeStr: "billing:settlements:write",
wantErr: false,
domain: "billing",
resource: "settlements",
action: "write",
},
{
name: "invalid format",
scopeStr: "supply:accounts",
wantErr: true,
},
{
name: "invalid domain",
scopeStr: "unknown:accounts:read",
wantErr: true,
},
{
name: "invalid action",
scopeStr: "supply:accounts:unknown",
wantErr: true,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
scope, err := ParseScope(tc.scopeStr)
if tc.wantErr {
if err == nil {
t.Error("expected error but got nil")
}
} else {
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if scope.Domain != tc.domain {
t.Errorf("domain: expected %s, got %s", tc.domain, scope.Domain)
}
if scope.Resource != tc.resource {
t.Errorf("resource: expected %s, got %s", tc.resource, scope.Resource)
}
if scope.Action != tc.action {
t.Errorf("action: expected %s, got %s", tc.action, scope.Action)
}
}
})
}
t.Log("P1-02: scope解析验证通过")
}
// TestP102_HasScope 检查权限
func TestP102_HasScope(t *testing.T) {
userScopes := []string{
"supply:accounts:read",
"supply:accounts:write",
"supply:packages:read",
}
testCases := []struct {
name string
checkScope *Scope
expected bool
}{
{
name: "has exact scope",
checkScope: &Scope{
Domain: "supply",
Resource: "accounts",
Action: "read",
},
expected: true,
},
{
name: "has exact scope write",
checkScope: &Scope{
Domain: "supply",
Resource: "accounts",
Action: "write",
},
expected: true,
},
{
name: "has manage scope",
checkScope: &Scope{
Domain: "supply",
Resource: "accounts",
Action: "manage",
},
expected: false, // 用户没有manage但有read/write
},
{
name: "missing scope",
checkScope: &Scope{
Domain: "supply",
Resource: "orders",
Action: "read",
},
expected: false,
},
{
name: "admin has all",
checkScope: &Scope{
Domain: "billing",
Resource: "ledgers",
Action: "read",
},
expected: false, // 没有admin scope
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
result := HasScope(userScopes, tc.checkScope)
if result != tc.expected {
t.Errorf("expected %v, got %v", tc.expected, result)
}
})
}
t.Log("P1-02: HasScope验证通过")
}
// TestP102_HasScopeWithManage 验证manage权限
func TestP102_HasScopeWithManage(t *testing.T) {
userScopes := []string{
"supply:accounts:manage", // manage包含所有account操作
"supply:packages:read",
}
// 检查manage是否包含read
readScope := &Scope{
Domain: "supply",
Resource: "accounts",
Action: "read",
}
if !HasScope(userScopes, readScope) {
t.Error("manage should include read")
}
// 检查manage是否包含write
writeScope := &Scope{
Domain: "supply",
Resource: "accounts",
Action: "write",
}
if !HasScope(userScopes, writeScope) {
t.Error("manage should include write")
}
// 检查manage是否包含delete
deleteScope := &Scope{
Domain: "supply",
Resource: "accounts",
Action: "delete",
}
if !HasScope(userScopes, deleteScope) {
t.Error("manage should include delete")
}
t.Log("P1-02: manage权限验证通过")
}
// TestP102_HasAnyScope 任一权限检查
func TestP102_HasAnyScope(t *testing.T) {
userScopes := []string{
"supply:accounts:read",
}
requiredScopes := []*Scope{
{Domain: "supply", Resource: "accounts", Action: "read"},
{Domain: "supply", Resource: "packages", Action: "read"},
{Domain: "billing", Resource: "ledgers", Action: "read"},
}
if !HasAnyScope(userScopes, requiredScopes) {
t.Error("should return true when user has at least one scope")
}
t.Log("P1-02: HasAnyScope验证通过")
}
// TestP102_CommonScopes 常用scope定义
func TestP102_CommonScopes(t *testing.T) {
// 验证常用scope格式正确
scopes := []string{
CommonScopes.SupplyAccountsRead,
CommonScopes.SupplyAccountsWrite,
CommonScopes.SupplyAccountsDelete,
CommonScopes.SupplyAccountsManage,
CommonScopes.SupplyPackagesRead,
CommonScopes.BillingAccountsRead,
CommonScopes.BillingSettlementsWrite,
CommonScopes.IAMUsersRead,
CommonScopes.AuditEventsRead,
CommonScopes.AdminAll,
}
for _, scopeStr := range scopes {
scope, err := ParseScope(scopeStr)
if err != nil {
t.Errorf("invalid common scope %s: %v", scopeStr, err)
}
if scope == nil {
t.Errorf("failed to parse common scope %s", scopeStr)
}
}
t.Log("P1-02: 常用scope定义验证通过")
}
// TestP102_RoleScopes 角色默认scope
func TestP102_RoleScopes(t *testing.T) {
roles := []string{"viewer", "operator", "admin", "owner"}
for _, role := range roles {
scopes := GetScopesForRole(role)
if len(scopes) == 0 {
t.Errorf("role %s should have scopes", role)
}
// 验证每个scope都能正确解析
for _, scopeStr := range scopes {
_, err := ParseScope(scopeStr)
if err != nil {
t.Errorf("role %s has invalid scope %s: %v", role, scopeStr, err)
}
}
}
t.Log("P1-02: 角色默认scope验证通过")
}
// TestP102_Summary 测试总结
func TestP102_Summary(t *testing.T) {
t.Log("=== P1-02 Token Scope授权模型测试总结 ===")
t.Log("问题: Token runtime定义scope为string[]但未定义scope命名空间和授权规则")
t.Log("")
t.Log("修复方案:")
t.Log(" - scope格式: {domain}:{resource}:{action}")
t.Log(" - 域: supply, billing, iam, audit, admin")
t.Log(" - 动作: read, write, delete, manage, execute")
t.Log(" - manage权限包含所有其他权限")
t.Log(" - admin:admin:manage 包含所有权限")
t.Log("")
t.Log("示例scope:")
t.Log(" supply:accounts:read")
t.Log(" billing:settlements:write")
t.Log(" iam:users:manage")
}
// TestHasAllScopes_True tests HasAllScopes when user has all required scopes
func TestHasAllScopes_True(t *testing.T) {
userScopes := []string{
"supply:accounts:read",
"supply:accounts:write",
"supply:accounts:delete",
}
requiredScopes := []*Scope{
{Domain: "supply", Resource: "accounts", Action: "read"},
{Domain: "supply", Resource: "accounts", Action: "write"},
}
result := HasAllScopes(userScopes, requiredScopes)
if !result {
t.Error("expected true, user has all required scopes")
}
}
// TestHasAllScopes_False tests HasAllScopes when user is missing some scopes
func TestHasAllScopes_False(t *testing.T) {
userScopes := []string{
"supply:accounts:read",
}
requiredScopes := []*Scope{
{Domain: "supply", Resource: "accounts", Action: "read"},
{Domain: "supply", Resource: "accounts", Action: "write"},
}
result := HasAllScopes(userScopes, requiredScopes)
if result {
t.Error("expected false, user is missing write scope")
}
}
// TestHasAllScopes_EmptyRequired tests HasAllScopes with empty required scopes
func TestHasAllScopes_EmptyRequired(t *testing.T) {
userScopes := []string{"supply:accounts:read"}
result := HasAllScopes(userScopes, []*Scope{})
if !result {
t.Error("expected true, empty required scopes should return true")
}
}
// TestHasAllScopes_EmptyUser tests HasAllScopes with empty user scopes
func TestHasAllScopes_EmptyUser(t *testing.T) {
requiredScopes := []*Scope{
{Domain: "supply", Resource: "accounts", Action: "read"},
}
result := HasAllScopes([]string{}, requiredScopes)
if result {
t.Error("expected false, user has no scopes")
}
}
// TestInvalidScopeError tests the InvalidScopeError type
func TestInvalidScopeError(t *testing.T) {
err := &InvalidScopeError{
Scope: "invalid:scope:format",
Reason: "invalid format",
}
result := err.Error()
expected := "invalid scope 'invalid:scope:format': invalid format"
if result != expected {
t.Errorf("expected '%s', got '%s'", expected, result)
}
}
// TestHasAnyScope_False tests HasAnyScope when user has no matching scopes
func TestHasAnyScope_False(t *testing.T) {
userScopes := []string{
"supply:accounts:read",
}
requiredScopes := []*Scope{
{Domain: "billing", Resource: "ledgers", Action: "read"},
{Domain: "iam", Resource: "users", Action: "write"},
}
result := HasAnyScope(userScopes, requiredScopes)
if result {
t.Error("expected false, user has no matching scopes")
}
}
// TestHasAnyScope_EmptyRequired tests HasAnyScope with empty required scopes
func TestHasAnyScope_EmptyRequired(t *testing.T) {
userScopes := []string{"supply:accounts:read"}
result := HasAnyScope(userScopes, []*Scope{})
if result {
t.Error("expected false, empty required scopes should return false")
}
}
// TestHasAnyScope_EmptyUser tests HasAnyScope with empty user scopes
func TestHasAnyScope_EmptyUser(t *testing.T) {
requiredScopes := []*Scope{
{Domain: "supply", Resource: "accounts", Action: "read"},
}
result := HasAnyScope([]string{}, requiredScopes)
if result {
t.Error("expected false, user has no scopes")
}
}