feat: standardize field names and add flexible role_id handling for JWT compatibility
- Rename user_id → users_id across all models, handlers, services, and tests
- Add custom RoleIDs type supporting string/int/array unmarshaling (e.g., "1", 1, [1])
- Implement flexible JSON unmarshaling for JWT Claims to handle field name variants
- Support both user_id/users_id and email/email_address field names
- Enable role_id as string ("1"), int (1), or array ([1,2])
- Update AuthorizationContext to handle role_id type flexibility
- Add comprehensive logging to repository, service, and handler layers
- Entry/exit logs with full context
- Success (✓) and failure (✗) indicators
- Step-by-step authorization flow tracking
- Add containsRole helper for multi-role membership checks
- Fix database queries: user_id → users_id, id → permissions_id
- Update all tests to use models.RoleIDs{} syntax
- Change GetRole middleware return type: string → []int
- Maintain backward compatibility with legacy JWT tokens
This change improves integration with external services (MIS) that may send
role_id in different formats and standardizes field naming conventions
throughout the authorization microservice.
This commit is contained in:
@@ -12,10 +12,10 @@ import (
|
||||
func Authorize(ctx *models.AuthorizationContext) (*models.AuthorizationResult, error) {
|
||||
startTime := time.Now()
|
||||
|
||||
log.Printf("[AuthZ Step 0] Fetching user details for userID=%s", ctx.UserID)
|
||||
user, err := repository.GetUserByID(ctx.UserID)
|
||||
log.Printf("[AuthZ Step 0] Fetching user details for userID=%s", ctx.UsersID)
|
||||
user, err := repository.GetUserByID(ctx.UsersID)
|
||||
if err != nil {
|
||||
log.Printf("✗ User not found for userID=%s: %v", ctx.UserID, err)
|
||||
log.Printf("✗ User not found for userID=%s: %v", ctx.UsersID, err)
|
||||
return &models.AuthorizationResult{
|
||||
Allowed: false,
|
||||
Message: fmt.Sprintf("User not found: %v", err),
|
||||
@@ -35,10 +35,10 @@ func Authorize(ctx *models.AuthorizationContext) (*models.AuthorizationResult, e
|
||||
log.Printf("[AuthZ Step 1] Permission found: ID=%d, Name=%s", permission.ID, permission.PermissionName)
|
||||
|
||||
// Step 2: Get user attributes
|
||||
log.Printf("[AuthZ Step 2] Fetching user attributes for userID=%s", ctx.UserID)
|
||||
userAttrs, err := repository.GetUserAttributes(ctx.UserID)
|
||||
log.Printf("[AuthZ Step 2] Fetching user attributes for userID=%s", ctx.UsersID)
|
||||
userAttrs, err := repository.GetUserAttributes(ctx.UsersID)
|
||||
if err != nil {
|
||||
log.Printf("✗ Failed to get user attributes for userID=%s: %v", ctx.UserID, err)
|
||||
log.Printf("✗ Failed to get user attributes for userID=%s: %v", ctx.UsersID, err)
|
||||
return &models.AuthorizationResult{
|
||||
Allowed: false,
|
||||
Message: fmt.Sprintf("Failed to get user attributes: %v", err),
|
||||
@@ -84,10 +84,10 @@ func Authorize(ctx *models.AuthorizationContext) (*models.AuthorizationResult, e
|
||||
result.RedirectRoute = "dashboard"
|
||||
result.Message = "Access granted"
|
||||
log.Printf("✓ Authorization GRANTED for user=%s, resource=%s, action=%s (evaluated in %v)",
|
||||
ctx.UserID, ctx.Resource, ctx.Action, time.Since(startTime))
|
||||
ctx.UsersID, ctx.Resource, ctx.Action, time.Since(startTime))
|
||||
} else {
|
||||
log.Printf("✗ Authorization DENIED for user=%s, resource=%s, action=%s - Reason: %s (evaluated in %v)",
|
||||
ctx.UserID, ctx.Resource, ctx.Action, reason, time.Since(startTime))
|
||||
ctx.UsersID, ctx.Resource, ctx.Action, reason, time.Since(startTime))
|
||||
result.Message = reason
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ func Authorize(ctx *models.AuthorizationContext) (*models.AuthorizationResult, e
|
||||
evalTime := time.Since(startTime)
|
||||
if evalTime > 100*time.Millisecond {
|
||||
fmt.Printf("WARN: Slow authorization evaluation: %v for user=%s, resource=%s, action=%s\n",
|
||||
evalTime, ctx.UserID, ctx.Resource, ctx.Action)
|
||||
evalTime, ctx.UsersID, ctx.Resource, ctx.Action)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
|
||||
+16
-16
@@ -32,7 +32,7 @@ func TestAuthorize_PermissionNotFound(t *testing.T) {
|
||||
defer cleanup()
|
||||
|
||||
ctx := &models.AuthorizationContext{
|
||||
UserID: "user123",
|
||||
UsersID: "user123",
|
||||
Resource: "nonexistent",
|
||||
Action: "read",
|
||||
ResourceData: make(map[string]string),
|
||||
@@ -40,19 +40,19 @@ func TestAuthorize_PermissionNotFound(t *testing.T) {
|
||||
}
|
||||
|
||||
// Mock user query
|
||||
userRows := sqlmock.NewRows([]string{"user_id", "first_name", "middle_initial", "last_name", "suffix", "email_address",
|
||||
userRows := sqlmock.NewRows([]string{"users_id", "first_name", "middle_initial", "last_name", "suffix", "email_address",
|
||||
"home_address", "contact_number",
|
||||
"role_id", "is_deleted", "created_at", "updated_at"}).
|
||||
AddRow("user123", "John", "", "Doe", "", "john@example.com",
|
||||
"EMP123", "Y", "Y", "123 Street", "09123456789", "device1",
|
||||
1, "N", "secret", "Y", time.Now(), time.Now())
|
||||
|
||||
mock.ExpectQuery("SELECT user_id, first_name, middle_initial, last_name, suffix, email_address").
|
||||
mock.ExpectQuery("SELECT users_id, first_name, middle_initial, last_name, suffix, email_address").
|
||||
WithArgs("user123").
|
||||
WillReturnRows(userRows)
|
||||
|
||||
// Mock permission query with role check
|
||||
mock.ExpectQuery("SELECT p.id, p.permission_name, p.description, p.resource, p.action FROM permissions p INNER JOIN role_permissions rp").
|
||||
mock.ExpectQuery("SELECT p.role_permissions_id, p.permission_name, p.description, p.resource, p.action FROM permissions p INNER JOIN role_permissions rp").
|
||||
WithArgs("nonexistent", "read", 1).
|
||||
WillReturnError(errors.New("permission not found"))
|
||||
|
||||
@@ -74,7 +74,7 @@ func TestAuthorize_Success(t *testing.T) {
|
||||
defer cleanup()
|
||||
|
||||
ctx := &models.AuthorizationContext{
|
||||
UserID: "user123",
|
||||
UsersID: "user123",
|
||||
Resource: "document",
|
||||
Action: "read",
|
||||
ResourceData: make(map[string]string),
|
||||
@@ -82,14 +82,14 @@ func TestAuthorize_Success(t *testing.T) {
|
||||
}
|
||||
|
||||
// Mock user query
|
||||
userRows := sqlmock.NewRows([]string{"user_id", "first_name", "middle_initial", "last_name", "suffix", "email_address",
|
||||
userRows := sqlmock.NewRows([]string{"users_id", "first_name", "middle_initial", "last_name", "suffix", "email_address",
|
||||
"home_address", "contact_number",
|
||||
"role_id", "is_deleted", "created_at", "updated_at"}).
|
||||
AddRow("user123", "John", "", "Doe", "", "john@example.com",
|
||||
"EMP123", "Y", "Y", "123 Street", "09123456789", "device1",
|
||||
1, "N", "secret", "Y", time.Now(), time.Now())
|
||||
|
||||
mock.ExpectQuery("SELECT user_id, first_name, middle_initial, last_name, suffix, email_address").
|
||||
mock.ExpectQuery("SELECT users_id, first_name, middle_initial, last_name, suffix, email_address").
|
||||
WithArgs("user123").
|
||||
WillReturnRows(userRows)
|
||||
|
||||
@@ -105,7 +105,7 @@ func TestAuthorize_Success(t *testing.T) {
|
||||
attrRows := sqlmock.NewRows([]string{"attribute_name", "attribute_value"}).
|
||||
AddRow("department", "engineering")
|
||||
|
||||
mock.ExpectQuery("SELECT attribute_name, attribute_value FROM user_attributes WHERE user_id = \\?").
|
||||
mock.ExpectQuery("SELECT attribute_name, attribute_value FROM user_attributes WHERE users_id = \\?").
|
||||
WithArgs("user123").
|
||||
WillReturnRows(attrRows)
|
||||
|
||||
@@ -134,7 +134,7 @@ func TestAuthorize_UserAttributesError(t *testing.T) {
|
||||
defer cleanup()
|
||||
|
||||
ctx := &models.AuthorizationContext{
|
||||
UserID: "user123",
|
||||
UsersID: "user123",
|
||||
Resource: "document",
|
||||
Action: "read",
|
||||
ResourceData: make(map[string]string),
|
||||
@@ -142,14 +142,14 @@ func TestAuthorize_UserAttributesError(t *testing.T) {
|
||||
}
|
||||
|
||||
// Mock user query
|
||||
userRows := sqlmock.NewRows([]string{"user_id", "first_name", "middle_initial", "last_name", "suffix", "email_address",
|
||||
userRows := sqlmock.NewRows([]string{"users_id", "first_name", "middle_initial", "last_name", "suffix", "email_address",
|
||||
"home_address", "contact_number",
|
||||
"role_id", "is_deleted", "created_at", "updated_at"}).
|
||||
AddRow("user123", "John", "", "Doe", "", "john@example.com",
|
||||
"EMP123", "Y", "Y", "123 Street", "09123456789", "device1",
|
||||
1, "N", "secret", "Y", time.Now(), time.Now())
|
||||
|
||||
mock.ExpectQuery("SELECT user_id, first_name, middle_initial, last_name, suffix, email_address").
|
||||
mock.ExpectQuery("SELECT users_id, first_name, middle_initial, last_name, suffix, email_address").
|
||||
WithArgs("user123").
|
||||
WillReturnRows(userRows)
|
||||
|
||||
@@ -162,7 +162,7 @@ func TestAuthorize_UserAttributesError(t *testing.T) {
|
||||
WillReturnRows(permRows)
|
||||
|
||||
// Mock user attributes query with error
|
||||
mock.ExpectQuery("SELECT attribute_name, attribute_value FROM user_attributes WHERE user_id = \\?").
|
||||
mock.ExpectQuery("SELECT attribute_name, attribute_value FROM user_attributes WHERE users_id = \\?").
|
||||
WithArgs("user123").
|
||||
WillReturnError(errors.New("database error"))
|
||||
|
||||
@@ -181,7 +181,7 @@ func TestAuthorize_PolicyAttributesError(t *testing.T) {
|
||||
defer cleanup()
|
||||
|
||||
ctx := &models.AuthorizationContext{
|
||||
UserID: "user123",
|
||||
UsersID: "user123",
|
||||
Resource: "document",
|
||||
Action: "read",
|
||||
ResourceData: make(map[string]string),
|
||||
@@ -189,14 +189,14 @@ func TestAuthorize_PolicyAttributesError(t *testing.T) {
|
||||
}
|
||||
|
||||
// Mock user query
|
||||
userRows := sqlmock.NewRows([]string{"user_id", "first_name", "middle_initial", "last_name", "suffix", "email_address",
|
||||
userRows := sqlmock.NewRows([]string{"users_id", "first_name", "middle_initial", "last_name", "suffix", "email_address",
|
||||
"home_address", "contact_number",
|
||||
"role_id", "is_deleted", "created_at", "updated_at"}).
|
||||
AddRow("user123", "John", "", "Doe", "", "john@example.com",
|
||||
"EMP123", "Y", "Y", "123 Street", "09123456789", "device1",
|
||||
1, "N", "secret", "Y", time.Now(), time.Now())
|
||||
|
||||
mock.ExpectQuery("SELECT user_id, first_name, middle_initial, last_name, suffix, email_address").
|
||||
mock.ExpectQuery("SELECT users_id, first_name, middle_initial, last_name, suffix, email_address").
|
||||
WithArgs("user123").
|
||||
WillReturnRows(userRows)
|
||||
|
||||
@@ -212,7 +212,7 @@ func TestAuthorize_PolicyAttributesError(t *testing.T) {
|
||||
attrRows := sqlmock.NewRows([]string{"attribute_name", "attribute_value"}).
|
||||
AddRow("department", "engineering")
|
||||
|
||||
mock.ExpectQuery("SELECT attribute_name, attribute_value FROM user_attributes WHERE user_id = \\?").
|
||||
mock.ExpectQuery("SELECT attribute_name, attribute_value FROM user_attributes WHERE users_id = \\?").
|
||||
WithArgs("user123").
|
||||
WillReturnRows(attrRows)
|
||||
|
||||
|
||||
@@ -162,7 +162,7 @@ func refreshCache(s *models.CachedAuthorizationService) {
|
||||
s.LastCacheRefresh = time.Now()
|
||||
cacheMutex.Unlock()
|
||||
|
||||
log.Printf("✓ Cache refreshed: %d policy groups cached", len(policies))
|
||||
// log.Printf("✓ Cache refreshed: %d policy groups cached", len(policies))
|
||||
|
||||
// Store policies in Redis for distributed access (non-blocking)
|
||||
// Permissions are now cached on-demand with role awareness
|
||||
@@ -178,7 +178,7 @@ func refreshCache(s *models.CachedAuthorizationService) {
|
||||
redisclient.RDB.Set(ctx, redisKey, policiesJSON, cacheTTL)
|
||||
}
|
||||
|
||||
log.Printf("INFO: Policy cache synced to Redis - %d policy groups", len(policies))
|
||||
// log.Printf("INFO: Policy cache synced to Redis - %d policy groups", len(policies))
|
||||
}()
|
||||
}
|
||||
}
|
||||
@@ -230,13 +230,17 @@ func NewCachedAuthorizationService() *models.CachedAuthorizationService {
|
||||
func AuthorizeWithCache(s *models.CachedAuthorizationService, ctx *models.AuthorizationContext) (*models.AuthorizationResult, error) {
|
||||
startTime := time.Now()
|
||||
|
||||
log.Printf("[AuthZ Cached] Starting authorization check for user=%s, resource=%s, action=%s", ctx.UserID, ctx.Resource, ctx.Action)
|
||||
log.Printf("[CACHE-ENTRY] AuthorizeWithCache() called - UsersID=%s, Resource=%s, Action=%s, RoleID=%d",
|
||||
ctx.UsersID, ctx.Resource, ctx.Action, ctx.RoleID)
|
||||
log.Printf("[CACHE-ENTRY] Full context: %+v", ctx)
|
||||
|
||||
log.Printf("[AuthZ Cached] Starting authorization check for user=%s, resource=%s, action=%s", ctx.UsersID, ctx.Resource, ctx.Action)
|
||||
|
||||
// Step 0: Get user to retrieve role_id (needed for role-based permission lookup)
|
||||
log.Printf("[AuthZ Step 0] Fetching user details for userID=%s", ctx.UserID)
|
||||
user, err := repository.GetUserByID(ctx.UserID)
|
||||
log.Printf("[AuthZ Step 0] Fetching user details for userID=%s", ctx.UsersID)
|
||||
user, err := repository.GetUserByID(ctx.UsersID)
|
||||
if err != nil {
|
||||
log.Printf("✗ User not found for userID=%s: %v", ctx.UserID, err)
|
||||
log.Printf("✗ User not found for userID=%s: %v", ctx.UsersID, err)
|
||||
return &models.AuthorizationResult{
|
||||
Allowed: false,
|
||||
Message: fmt.Sprintf("User not found: %v", err),
|
||||
@@ -246,34 +250,34 @@ func AuthorizeWithCache(s *models.CachedAuthorizationService, ctx *models.Author
|
||||
|
||||
// Step 1: Check if the user's role has the permission (not just if permission exists)
|
||||
// Use role-aware cache key: roleID:resource:action
|
||||
cacheKey := fmt.Sprintf("%d:%s:%s", user.RoleID, ctx.Resource, ctx.Action)
|
||||
cacheKey := fmt.Sprintf("%d:%s:%s", ctx.RoleID, ctx.Resource, ctx.Action)
|
||||
log.Printf("[AuthZ Step 1] Looking up permission in cache with role: %s", cacheKey)
|
||||
permission, exists := getPermissionFromCache(s, cacheKey)
|
||||
|
||||
if !exists {
|
||||
// Cache miss - try database lookup with role check
|
||||
log.Printf("[AuthZ Step 1] Cache miss - querying database for role_id=%d, resource=%s, action=%s", user.RoleID, ctx.Resource, ctx.Action)
|
||||
permission, err = repository.GetPermissionByResourceActionAndRole(ctx.Resource, ctx.Action, user.RoleID)
|
||||
log.Printf("[AuthZ Step 1] Cache miss - querying database for role_id=%d, resource=%s, action=%s", ctx.RoleID, ctx.Resource, ctx.Action)
|
||||
permission, err = repository.GetPermissionByResourceActionAndRole(ctx.Resource, ctx.Action, ctx.RoleID)
|
||||
if err != nil {
|
||||
log.Printf("✗ Permission not found or not granted to role_id=%d for resource=%s, action=%s: %v", user.RoleID, ctx.Resource, ctx.Action, err)
|
||||
log.Printf("✗ [AuthZ Step 1] Permission not found or not granted to role_id=%d for resource=%s, action=%s: %v", ctx.RoleID, ctx.Resource, ctx.Action, err)
|
||||
return &models.AuthorizationResult{
|
||||
Allowed: false,
|
||||
Message: "Permission not granted to your role",
|
||||
}, nil
|
||||
}
|
||||
log.Printf("[AuthZ Step 1] Permission found in DB: ID=%d, Name=%s", permission.ID, permission.PermissionName)
|
||||
log.Printf("✓ [AuthZ Step 1] Permission found in DB: ID=%d, Name=%s", permission.ID, permission.PermissionName)
|
||||
|
||||
// Cache the result for future use
|
||||
storePermissionInCache(s, cacheKey, permission)
|
||||
} else {
|
||||
log.Printf("[AuthZ Step 1] Permission found in cache: ID=%d, Name=%s", permission.ID, permission.PermissionName)
|
||||
log.Printf("✓ [AuthZ Step 1] Permission found in cache: ID=%d, Name=%s", permission.ID, permission.PermissionName)
|
||||
}
|
||||
|
||||
// Step 2: Get user attributes (with distributed cache)
|
||||
log.Printf("[AuthZ Step 2] Fetching user attributes for userID=%s", ctx.UserID)
|
||||
userAttrs, err := getCachedUserAttributes(s, ctx.UserID)
|
||||
log.Printf("[AuthZ Step 2] Fetching user attributes for userID=%s", ctx.UsersID)
|
||||
userAttrs, err := getCachedUserAttributes(s, ctx.UsersID)
|
||||
if err != nil {
|
||||
log.Printf("✗ Failed to get user attributes for userID=%s: %v", ctx.UserID, err)
|
||||
log.Printf("✗ Failed to get user attributes for userID=%s: %v", ctx.UsersID, err)
|
||||
return &models.AuthorizationResult{
|
||||
Allowed: false,
|
||||
Message: "Failed to get user attributes",
|
||||
@@ -311,11 +315,11 @@ func AuthorizeWithCache(s *models.CachedAuthorizationService, ctx *models.Author
|
||||
if allowed {
|
||||
result.Message = "Access granted"
|
||||
log.Printf("✓ Authorization GRANTED for user=%s, resource=%s, action=%s (evaluated in %v)",
|
||||
ctx.UserID, ctx.Resource, ctx.Action, time.Since(startTime))
|
||||
ctx.UsersID, ctx.Resource, ctx.Action, time.Since(startTime))
|
||||
} else {
|
||||
result.Message = reason
|
||||
log.Printf("✗ Authorization DENIED for user=%s, resource=%s, action=%s - Reason: %s (evaluated in %v)",
|
||||
ctx.UserID, ctx.Resource, ctx.Action, reason, time.Since(startTime))
|
||||
ctx.UsersID, ctx.Resource, ctx.Action, reason, time.Since(startTime))
|
||||
}
|
||||
|
||||
// Performance monitoring
|
||||
@@ -323,12 +327,12 @@ func AuthorizeWithCache(s *models.CachedAuthorizationService, ctx *models.Author
|
||||
|
||||
if evalTime < 50*time.Millisecond {
|
||||
log.Print("Cached authorization evaluation time: ", evalTime,
|
||||
" for user=", ctx.UserID, ", resource=", ctx.Resource, ", action=", ctx.Action)
|
||||
" for user=", ctx.UsersID, ", resource=", ctx.Resource, ", action=", ctx.Action)
|
||||
}
|
||||
|
||||
if evalTime > 50*time.Millisecond {
|
||||
log.Print("WARN: Slow cached authorization evaluation: ", evalTime,
|
||||
" for user=", ctx.UserID, ", resource=", ctx.Resource, ", action=", ctx.Action)
|
||||
" for user=", ctx.UsersID, ", resource=", ctx.Resource, ", action=", ctx.Action)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
|
||||
@@ -104,7 +104,7 @@ func TestGetCachedUserAttributes_CacheMiss(t *testing.T) {
|
||||
attrRows := sqlmock.NewRows([]string{"attribute_name", "attribute_value"}).
|
||||
AddRow("department", "engineering")
|
||||
|
||||
mock.ExpectQuery("SELECT attribute_name, attribute_value FROM user_attributes WHERE user_id = \\?").
|
||||
mock.ExpectQuery("SELECT attribute_name, attribute_value FROM user_attributes WHERE users_id = \\?").
|
||||
WithArgs("user123").
|
||||
WillReturnRows(attrRows)
|
||||
|
||||
@@ -219,14 +219,14 @@ func TestAuthorizeWithCache_Success(t *testing.T) {
|
||||
service.PolicyCache[1] = []models.PolicyAttribute{}
|
||||
|
||||
// Mock user query (needed to get role_id)
|
||||
userRows := sqlmock.NewRows([]string{"user_id", "first_name", "middle_initial", "last_name", "suffix", "email_address",
|
||||
userRows := sqlmock.NewRows([]string{"users_id", "first_name", "middle_initial", "last_name", "suffix", "email_address",
|
||||
"home_address", "contact_number",
|
||||
"role_id", "is_deleted", "created_at", "updated_at"}).
|
||||
AddRow("user123", "John", "", "Doe", "", "john@example.com",
|
||||
"EMP123", "Y", "Y", "123 Street", "09123456789", "device1",
|
||||
1, "N", "secret", "Y", time.Now(), time.Now())
|
||||
|
||||
mock.ExpectQuery("SELECT user_id, first_name, middle_initial, last_name, suffix, email_address").
|
||||
mock.ExpectQuery("SELECT users_id, first_name, middle_initial, last_name, suffix, email_address").
|
||||
WithArgs("user123").
|
||||
WillReturnRows(userRows)
|
||||
|
||||
@@ -234,12 +234,12 @@ func TestAuthorizeWithCache_Success(t *testing.T) {
|
||||
attrRows := sqlmock.NewRows([]string{"attribute_name", "attribute_value"}).
|
||||
AddRow("department", "engineering")
|
||||
|
||||
mock.ExpectQuery("SELECT attribute_name, attribute_value FROM user_attributes WHERE user_id = \\?").
|
||||
mock.ExpectQuery("SELECT attribute_name, attribute_value FROM user_attributes WHERE users_id = \\?").
|
||||
WithArgs("user123").
|
||||
WillReturnRows(attrRows)
|
||||
|
||||
ctx := &models.AuthorizationContext{
|
||||
UserID: "user123",
|
||||
UsersID: "user123",
|
||||
Resource: "document",
|
||||
Action: "read",
|
||||
ResourceData: make(map[string]string),
|
||||
@@ -268,20 +268,20 @@ func TestAuthorizeWithCache_PermissionNotFound(t *testing.T) {
|
||||
}
|
||||
|
||||
ctx := &models.AuthorizationContext{
|
||||
UserID: "user123",
|
||||
UsersID: "user123",
|
||||
Resource: "nonexistent",
|
||||
Action: "read",
|
||||
}
|
||||
|
||||
// Mock user query
|
||||
userRows := sqlmock.NewRows([]string{"user_id", "first_name", "middle_initial", "last_name", "suffix", "email_address",
|
||||
userRows := sqlmock.NewRows([]string{"users_id", "first_name", "middle_initial", "last_name", "suffix", "email_address",
|
||||
"home_address", "contact_number",
|
||||
"role_id", "is_deleted", "created_at", "updated_at"}).
|
||||
AddRow("user123", "John", "", "Doe", "", "john@example.com",
|
||||
"EMP123", "Y", "Y", "123 Street", "09123456789", "device1",
|
||||
1, "N", "secret", "Y", time.Now(), time.Now())
|
||||
|
||||
mock.ExpectQuery("SELECT user_id, first_name, middle_initial, last_name, suffix, email_address").
|
||||
mock.ExpectQuery("SELECT users_id, first_name, middle_initial, last_name, suffix, email_address").
|
||||
WithArgs("user123").
|
||||
WillReturnRows(userRows)
|
||||
|
||||
|
||||
@@ -135,8 +135,7 @@ func evaluatePolicy(policyAttribute models.PolicyAttribute, ctx *models.Authoriz
|
||||
log.Print("Role ID!!!!!: ", ctx.RoleID)
|
||||
if policyAttribute.AttributeType == "user" &&
|
||||
policyAttribute.AttributeName == "region" &&
|
||||
(ctx.RoleID == "1" || ctx.RoleID == "2" || ctx.RoleID == "Super Admin" ||
|
||||
ctx.RoleID == "System Admin") {
|
||||
(ctx.RoleID == 1 || ctx.RoleID == 2) {
|
||||
fmt.Printf("[POLICY EVALUATION] Type: %s, Attribute: %s\n", policyAttribute.AttributeType, policyAttribute.AttributeName)
|
||||
fmt.Printf(" Skipped for roleID: %s (Super | System Admin bypass)\n\n", ctx.RoleID)
|
||||
return true, ""
|
||||
|
||||
@@ -657,7 +657,7 @@ func TestEvaluatePoliciesComplexConditions(t *testing.T) {
|
||||
|
||||
func TestResolveVariablesAllAttributeTypes(t *testing.T) {
|
||||
ctx := &models.AuthorizationContext{
|
||||
UserID: "user123",
|
||||
UsersID: "user123",
|
||||
Resource: "document",
|
||||
Action: "read",
|
||||
UserAttributes: map[string]string{
|
||||
@@ -719,7 +719,7 @@ func TestEvaluatePolicies_UserRegionMatchesResourceRegion(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctx := &models.AuthorizationContext{
|
||||
UserID: "U0000000001",
|
||||
UsersID: "U0000000001",
|
||||
Resource: "personnel",
|
||||
Action: "assign_role",
|
||||
UserAttributes: map[string]string{
|
||||
@@ -752,7 +752,7 @@ func TestEvaluatePolicies_MissingResourceAttribute(t *testing.T) {
|
||||
// The policy should fail because the placeholder cannot be resolved
|
||||
|
||||
ctx := &models.AuthorizationContext{
|
||||
UserID: "U0000000001",
|
||||
UsersID: "U0000000001",
|
||||
Resource: "personnel",
|
||||
Action: "assign_role",
|
||||
UserAttributes: map[string]string{
|
||||
@@ -880,7 +880,7 @@ func TestEvaluatePolicies_RegionBypassForAdminRoles(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
roleID string
|
||||
roleID int
|
||||
userRegion string
|
||||
resourceRegion string
|
||||
shouldBeAllowed bool
|
||||
@@ -888,7 +888,7 @@ func TestEvaluatePolicies_RegionBypassForAdminRoles(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "roleID 1 bypasses region check",
|
||||
roleID: "1",
|
||||
roleID: 1,
|
||||
userRegion: "02",
|
||||
resourceRegion: "01",
|
||||
shouldBeAllowed: true,
|
||||
@@ -896,7 +896,7 @@ func TestEvaluatePolicies_RegionBypassForAdminRoles(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "roleID 2 bypasses region check",
|
||||
roleID: "2",
|
||||
roleID: 2,
|
||||
userRegion: "03",
|
||||
resourceRegion: "01",
|
||||
shouldBeAllowed: true,
|
||||
@@ -904,7 +904,7 @@ func TestEvaluatePolicies_RegionBypassForAdminRoles(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "other roleID respects region check",
|
||||
roleID: "3",
|
||||
roleID: 3,
|
||||
userRegion: "02",
|
||||
resourceRegion: "01",
|
||||
shouldBeAllowed: false,
|
||||
@@ -912,7 +912,7 @@ func TestEvaluatePolicies_RegionBypassForAdminRoles(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "Super Admin role bypasses region check",
|
||||
roleID: "Super Admin",
|
||||
roleID: 1,
|
||||
userRegion: "02",
|
||||
resourceRegion: "01",
|
||||
shouldBeAllowed: true,
|
||||
@@ -920,7 +920,7 @@ func TestEvaluatePolicies_RegionBypassForAdminRoles(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "Admin role does not bypass region check",
|
||||
roleID: "Admin",
|
||||
roleID: 2,
|
||||
userRegion: "03",
|
||||
resourceRegion: "01",
|
||||
shouldBeAllowed: false,
|
||||
@@ -931,7 +931,7 @@ func TestEvaluatePolicies_RegionBypassForAdminRoles(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ctx := &models.AuthorizationContext{
|
||||
UserID: "U0000000001",
|
||||
UsersID: "U0000000001",
|
||||
Resource: "personnel",
|
||||
Action: "assign_role",
|
||||
RoleID: tt.roleID,
|
||||
|
||||
Reference in New Issue
Block a user