added another test
This commit is contained in:
@@ -2,6 +2,7 @@ package services
|
||||
|
||||
import (
|
||||
"authorization/models"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -687,3 +688,274 @@ func TestResolveVariablesAllAttributeTypes(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvaluatePolicies_UserRegionMatchesResourceRegion(t *testing.T) {
|
||||
// Test case from the logs: user.region = ${resource.region}
|
||||
// User region should match the resource region provided in ResourceData
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
userRegion string
|
||||
resourceRegion string
|
||||
shouldBeAllowed bool
|
||||
description string
|
||||
}{
|
||||
{
|
||||
name: "same region",
|
||||
userRegion: "01",
|
||||
resourceRegion: "01",
|
||||
shouldBeAllowed: true,
|
||||
description: "user region matches resource region",
|
||||
},
|
||||
{
|
||||
name: "different region",
|
||||
userRegion: "02",
|
||||
resourceRegion: "01",
|
||||
shouldBeAllowed: false,
|
||||
description: "user region does not match resource region",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctx := &models.AuthorizationContext{
|
||||
UserID: "U0000000001",
|
||||
Resource: "personnel",
|
||||
Action: "assign_role",
|
||||
UserAttributes: map[string]string{
|
||||
"region": tt.userRegion,
|
||||
},
|
||||
ResourceData: map[string]string{
|
||||
"region": tt.resourceRegion,
|
||||
},
|
||||
}
|
||||
|
||||
policies := []models.PolicyAttribute{
|
||||
{
|
||||
AttributeType: "user",
|
||||
AttributeName: "region",
|
||||
Comparison: "=",
|
||||
AttributeValue: "${resource.region}",
|
||||
},
|
||||
}
|
||||
|
||||
satisfied, reason := EvaluatePolicies(policies, ctx)
|
||||
if satisfied != tt.shouldBeAllowed {
|
||||
t.Errorf("%s: got satisfied=%v, want %v. Reason: %s", tt.description, satisfied, tt.shouldBeAllowed, reason)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvaluatePolicies_MissingResourceAttribute(t *testing.T) {
|
||||
// Test case: when ResourceData doesn't have the required attribute
|
||||
// The policy should fail because the placeholder cannot be resolved
|
||||
|
||||
ctx := &models.AuthorizationContext{
|
||||
UserID: "U0000000001",
|
||||
Resource: "personnel",
|
||||
Action: "assign_role",
|
||||
UserAttributes: map[string]string{
|
||||
"region": "01",
|
||||
},
|
||||
ResourceData: map[string]string{
|
||||
// Missing "region" key - this should cause policy to fail
|
||||
},
|
||||
}
|
||||
|
||||
policies := []models.PolicyAttribute{
|
||||
{
|
||||
AttributeType: "user",
|
||||
AttributeName: "region",
|
||||
Comparison: "=",
|
||||
AttributeValue: "${resource.region}",
|
||||
},
|
||||
}
|
||||
|
||||
satisfied, reason := EvaluatePolicies(policies, ctx)
|
||||
// When resource attribute is missing, the placeholder stays unresolved
|
||||
// "01" != "${resource.region}", so policy fails
|
||||
if satisfied {
|
||||
t.Errorf("EvaluatePolicies should fail when resource attribute is missing. Reason: %s", reason)
|
||||
}
|
||||
|
||||
if reason == "" {
|
||||
t.Error("EvaluatePolicies should provide a reason when policy fails")
|
||||
}
|
||||
|
||||
// Check that the error message indicates missing attributes
|
||||
if !strings.Contains(reason, "Missing required attributes") || !strings.Contains(reason, "${resource.region}") {
|
||||
t.Errorf("Expected error message about missing resource.region, got: %s", reason)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHasUnresolvedPlaceholders(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
value string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "has unresolved placeholder",
|
||||
value: "${resource.region}",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "multiple unresolved placeholders",
|
||||
value: "${resource.region} and ${user.department}",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "no unresolved placeholders",
|
||||
value: "US",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "mixed resolved and unresolved",
|
||||
value: "US and ${resource.owner}",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "empty string",
|
||||
value: "",
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := hasUnresolvedPlaceholders(tt.value)
|
||||
if result != tt.expected {
|
||||
t.Errorf("hasUnresolvedPlaceholders(%q) = %v, want %v", tt.value, result, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractUnresolvedPlaceholders(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
value string
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
name: "single placeholder",
|
||||
value: "${resource.region}",
|
||||
expected: []string{"${resource.region}"},
|
||||
},
|
||||
{
|
||||
name: "multiple placeholders",
|
||||
value: "${resource.region} and ${user.department}",
|
||||
expected: []string{"${resource.region}", "${user.department}"},
|
||||
},
|
||||
{
|
||||
name: "no placeholders",
|
||||
value: "US",
|
||||
expected: []string{},
|
||||
},
|
||||
{
|
||||
name: "empty list when no matches",
|
||||
value: "",
|
||||
expected: []string{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := extractUnresolvedPlaceholders(tt.value)
|
||||
if len(result) != len(tt.expected) {
|
||||
t.Errorf("extractUnresolvedPlaceholders(%q) returned %d items, want %d", tt.value, len(result), len(tt.expected))
|
||||
}
|
||||
for i, expected := range tt.expected {
|
||||
if i >= len(result) || result[i] != expected {
|
||||
t.Errorf("extractUnresolvedPlaceholders(%q)[%d] = %q, want %q", tt.value, i, result[i], expected)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvaluatePolicies_RegionBypassForAdminRoles(t *testing.T) {
|
||||
// Test that region policies are skipped for roleID 1 (Super Admin) and 2 (Admin)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
roleID string
|
||||
userRegion string
|
||||
resourceRegion string
|
||||
shouldBeAllowed bool
|
||||
description string
|
||||
}{
|
||||
{
|
||||
name: "roleID 1 bypasses region check",
|
||||
roleID: "1",
|
||||
userRegion: "02",
|
||||
resourceRegion: "01",
|
||||
shouldBeAllowed: true,
|
||||
description: "Super Admin should bypass region check",
|
||||
},
|
||||
{
|
||||
name: "roleID 2 bypasses region check",
|
||||
roleID: "2",
|
||||
userRegion: "03",
|
||||
resourceRegion: "01",
|
||||
shouldBeAllowed: true,
|
||||
description: "Admin should bypass region check",
|
||||
},
|
||||
{
|
||||
name: "other roleID respects region check",
|
||||
roleID: "3",
|
||||
userRegion: "02",
|
||||
resourceRegion: "01",
|
||||
shouldBeAllowed: false,
|
||||
description: "Non-admin roles should not bypass region check",
|
||||
},
|
||||
{
|
||||
name: "Super Admin role bypasses region check",
|
||||
roleID: "Super Admin",
|
||||
userRegion: "02",
|
||||
resourceRegion: "01",
|
||||
shouldBeAllowed: true,
|
||||
description: "Super Admin role string should bypass region check",
|
||||
},
|
||||
{
|
||||
name: "Admin role bypasses region check",
|
||||
roleID: "Admin",
|
||||
userRegion: "03",
|
||||
resourceRegion: "01",
|
||||
shouldBeAllowed: true,
|
||||
description: "Admin role string should bypass region check",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctx := &models.AuthorizationContext{
|
||||
UserID: "U0000000001",
|
||||
Resource: "personnel",
|
||||
Action: "assign_role",
|
||||
RoleID: tt.roleID,
|
||||
UserAttributes: map[string]string{
|
||||
"region": tt.userRegion,
|
||||
},
|
||||
ResourceData: map[string]string{
|
||||
"region": tt.resourceRegion,
|
||||
},
|
||||
}
|
||||
|
||||
policies := []models.PolicyAttribute{
|
||||
{
|
||||
AttributeType: "user",
|
||||
AttributeName: "region",
|
||||
Comparison: "=",
|
||||
AttributeValue: "${resource.region}",
|
||||
},
|
||||
}
|
||||
|
||||
satisfied, reason := EvaluatePolicies(policies, ctx)
|
||||
if satisfied != tt.shouldBeAllowed {
|
||||
t.Errorf("%s: got satisfied=%v, want %v. Reason: %s", tt.description, satisfied, tt.shouldBeAllowed, reason)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user