diff --git a/services/authorize.go b/services/authorize.go index 10dd926..ddcada7 100644 --- a/services/authorize.go +++ b/services/authorize.go @@ -45,6 +45,13 @@ func Authorize(ctx *models.AuthorizationContext) (*models.AuthorizationResult, e }, err } ctx.UserAttributes = userAttrs + fmt.Printf("[DEBUG] User attributes map: %+v\n", userAttrs) + fmt.Println("[DEBUG] About to print user attributes") + for k, v := range userAttrs { + log.Printf("User Attribute - %s: %v", k, v) + fmt.Printf("[DEBUG] User Attribute - %s: %v\n", k, v) + } + fmt.Println("[DEBUG] Finished printing user attributes") log.Printf("[AuthZ Step 2] User attributes retrieved: %d attributes", len(userAttrs)) // Step 3: Get policy attributes for the permission @@ -58,6 +65,13 @@ func Authorize(ctx *models.AuthorizationContext) (*models.AuthorizationResult, e }, err } log.Printf("[AuthZ Step 3] Policies retrieved: %d policies to evaluate", len(policies)) + if len(policies) > 0 { + for i, p := range policies { + log.Printf("[DEBUG] Policy %d: AttributeType=%s, AttributeName=%s, Comparison=%s, AttributeValue=%s", i+1, p.AttributeType, p.AttributeName, p.Comparison, p.AttributeValue) + } + } else { + log.Printf("[DEBUG] No policies loaded for permissionID=%d", permission.ID) + } log.Printf("[AuthZ Step 4] Using RoleID: %s (from context or user record)", ctx.RoleID) allowed, reason := EvaluatePolicies(policies, ctx) @@ -86,24 +100,3 @@ func Authorize(ctx *models.AuthorizationContext) (*models.AuthorizationResult, e return result, nil } - -// CheckPermission is a simplified authorization check -func CheckPermission(userID, resource, action string, resourceData map[string]string) (bool, string, error) { - ctx := &models.AuthorizationContext{ - UserID: userID, - Resource: resource, - Action: action, - ResourceData: resourceData, - Environment: make(map[string]string), - } - - // Add current time to environment - ctx.Environment["time"] = time.Now().Format(time.RFC3339) - - result, err := Authorize(ctx) - if err != nil { - return false, fmt.Sprintf("Authorization error: %v", err), err - } - - return result.Allowed, result.Message, nil -} diff --git a/services/authorize_test.go b/services/authorize_test.go index 90d840c..f83fb75 100644 --- a/services/authorize_test.go +++ b/services/authorize_test.go @@ -230,140 +230,3 @@ func TestAuthorize_PolicyAttributesError(t *testing.T) { t.Error("Expected access denied") } } - -func TestCheckPermission_Success(t *testing.T) { - mock, cleanup := setupMockDB(t) - defer cleanup() - - // Mock user query - userRows := sqlmock.NewRows([]string{"user_id", "first_name", "middle_initial", "last_name", "suffix", "email_address", - "emp_id", "is_logged_in", "first_logged_in", "home_address", "contact_number", "device_id", - "role_id", "is_deleted", "secret_key", "is_activated", "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"). - WithArgs("user123"). - WillReturnRows(userRows) - - // Mock permission query with role check - permRows := sqlmock.NewRows([]string{"id", "permission_name", "description", "resource", "action"}). - AddRow(1, "read_document", "Read document permission", "document", "read") - - mock.ExpectQuery("SELECT p.id, p.permission_name, p.description, p.resource, p.action FROM permissions p INNER JOIN role_permissions rp"). - WithArgs("document", "read", 1). - WillReturnRows(permRows) - - // Mock user attributes query - attrRows := sqlmock.NewRows([]string{"attribute_name", "attribute_value"}). - AddRow("department", "engineering") - - mock.ExpectQuery("SELECT attribute_name, attribute_value FROM user_attributes WHERE user_id = \\?"). - WithArgs("user123"). - WillReturnRows(attrRows) - - // Mock policy attributes query - policyRows := sqlmock.NewRows([]string{"id", "attribute_name", "attribute_type", "comparison", "attribute_value", "permission_id"}) - - mock.ExpectQuery("SELECT id, attribute_name, attribute_type, comparison, attribute_value, permission_id FROM policy_attributes WHERE permission_id = \\?"). - WithArgs(1). - WillReturnRows(policyRows) - - resourceData := map[string]string{"document_id": "123"} - allowed, message, err := CheckPermission("user123", "document", "read", resourceData) - - if err != nil { - t.Errorf("Expected no error, got %v", err) - } - if !allowed { - t.Error("Expected access allowed") - } - if message != "Access granted" { - t.Errorf("Expected 'Access granted', got '%s'", message) - } -} - -func TestCheckPermission_Denied(t *testing.T) { - mock, cleanup := setupMockDB(t) - defer cleanup() - - // Mock user query - userRows := sqlmock.NewRows([]string{"user_id", "first_name", "middle_initial", "last_name", "suffix", "email_address", - "emp_id", "is_logged_in", "first_logged_in", "home_address", "contact_number", "device_id", - "role_id", "is_deleted", "secret_key", "is_activated", "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"). - WithArgs("user123"). - WillReturnRows(userRows) - - // Mock permission query with role check - should fail - mock.ExpectQuery("SELECT p.id, p.permission_name, p.description, p.resource, p.action FROM permissions p INNER JOIN role_permissions rp"). - WithArgs("document", "read", 1). - WillReturnError(errors.New("permission not found")) - - resourceData := map[string]string{"document_id": "123"} - allowed, message, err := CheckPermission("user123", "document", "read", resourceData) - - if err != nil { - t.Errorf("Expected no error, got %v", err) - } - if allowed { - t.Error("Expected access denied") - } - if message == "" { - t.Error("Expected error message") - } -} - -func TestCheckPermission_NilResourceData(t *testing.T) { - mock, cleanup := setupMockDB(t) - defer cleanup() - - // Mock user query - userRows := sqlmock.NewRows([]string{"user_id", "first_name", "middle_initial", "last_name", "suffix", "email_address", - "emp_id", "is_logged_in", "first_logged_in", "home_address", "contact_number", "device_id", - "role_id", "is_deleted", "secret_key", "is_activated", "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"). - WithArgs("user123"). - WillReturnRows(userRows) - - // Mock permission query with role check - permRows := sqlmock.NewRows([]string{"id", "permission_name", "description", "resource", "action"}). - AddRow(1, "read_document", "Read document permission", "document", "read") - - mock.ExpectQuery("SELECT p.id, p.permission_name, p.description, p.resource, p.action FROM permissions p INNER JOIN role_permissions rp"). - WithArgs("document", "read", 1). - WillReturnRows(permRows) - - // Mock user attributes query - attrRows := sqlmock.NewRows([]string{"attribute_name", "attribute_value"}) - - mock.ExpectQuery("SELECT attribute_name, attribute_value FROM user_attributes WHERE user_id = \\?"). - WithArgs("user123"). - WillReturnRows(attrRows) - - // Mock policy attributes query - policyRows := sqlmock.NewRows([]string{"id", "attribute_name", "attribute_type", "comparison", "attribute_value", "permission_id"}) - - mock.ExpectQuery("SELECT id, attribute_name, attribute_type, comparison, attribute_value, permission_id FROM policy_attributes WHERE permission_id = \\?"). - WithArgs(1). - WillReturnRows(policyRows) - - allowed, message, err := CheckPermission("user123", "document", "read", nil) - - if err != nil { - t.Errorf("Expected no error, got %v", err) - } - // Should not panic with nil resourceData - if !allowed { - t.Logf("Access denied with message: %s", message) - } -} diff --git a/services/cached_authorization.go b/services/cached_authorization.go index 71a2ec9..afb0962 100644 --- a/services/cached_authorization.go +++ b/services/cached_authorization.go @@ -16,7 +16,7 @@ const ( permissionCachePrefix = "authz:perm:" policyCachePrefix = "authz:policy:" userAttrCachePrefix = "authz:userattr:" - cacheTTL = 30 * time.Second + cacheTTL = 5 * time.Second ) // getCachedUserAttributes retrieves user attributes from Redis or DB @@ -213,7 +213,7 @@ func NewCachedAuthorizationService() *models.CachedAuthorizationService { UserAttrCache: make(map[string]map[string]string), CacheMutex: &sync.RWMutex{}, UserAttrMutex: &sync.RWMutex{}, - CacheExpiry: 30 * time.Second, // Changed from 5 minutes for faster updates + CacheExpiry: 5 * time.Second, // Changed from 5 minutes for faster updates LastCacheRefresh: time.Now(), } @@ -280,12 +280,26 @@ func AuthorizeWithCache(s *models.CachedAuthorizationService, ctx *models.Author }, err } ctx.UserAttributes = userAttrs + fmt.Printf("[DEBUG] User attributes map: %+v\n", userAttrs) + fmt.Println("[DEBUG] About to print user attributes (cache)") + for k, v := range userAttrs { + log.Printf("User Attribute (cache) - %s: %v", k, v) + fmt.Printf("[DEBUG] User Attribute (cache) - %s: %v\n", k, v) + } + fmt.Println("[DEBUG] Finished printing user attributes (cache)") log.Printf("[AuthZ Step 2] User attributes retrieved: %d attributes", len(userAttrs)) // Step 3: Get policies from distributed cache log.Printf("[AuthZ Step 3] Fetching policies for permissionID=%d", permission.ID) policies := getPoliciesFromCache(s, permission.ID) log.Printf("[AuthZ Step 3] Policies retrieved: %d policies to evaluate", len(policies)) + if len(policies) > 0 { + for i, p := range policies { + log.Printf("[DEBUG] Policy %d: AttributeType=%s, AttributeName=%s, Comparison=%s, AttributeValue=%s", i+1, p.AttributeType, p.AttributeName, p.Comparison, p.AttributeValue) + } + } else { + log.Printf("[DEBUG] No policies loaded for permissionID=%d", permission.ID) + } log.Printf("[AuthZ Step 4] Using RoleID: %s (from context or user record)", ctx.RoleID) allowed, reason := EvaluatePolicies(policies, ctx) diff --git a/services/cached_authorization_test.go b/services/cached_authorization_test.go index 37ef871..53ee769 100644 --- a/services/cached_authorization_test.go +++ b/services/cached_authorization_test.go @@ -58,7 +58,7 @@ func TestNewCachedAuthorizationService(t *testing.T) { if service.UserAttrCache == nil { t.Error("Expected UserAttrCache to be initialized") } - if service.CacheExpiry != 30*time.Second { + if service.CacheExpiry != 5*time.Second { t.Errorf("Expected CacheExpiry 30s, got %v", service.CacheExpiry) } diff --git a/services/policy_evaluator.go b/services/policy_evaluator.go index 1878c3e..d1ab5bd 100644 --- a/services/policy_evaluator.go +++ b/services/policy_evaluator.go @@ -142,27 +142,34 @@ func evaluatePolicy(policyAttribute models.PolicyAttribute, ctx *models.Authoriz return true, "" } + // Always check user attributes in context if type is user switch policyAttribute.AttributeType { case "user": - log.Print("Fetching from User Attributes") - log.Print("User Attributes: ", ctx.UserAttributes) + log.Print("Checking user attribute in context for: ", policyAttribute.AttributeName) + if ctx.UserAttributes == nil { + return false, "User attributes missing in context" + } actualValue, exists = ctx.UserAttributes[policyAttribute.AttributeName] if !exists { - return false, fmt.Sprintf("User attribute '%s' not found", policyAttribute.AttributeName) + return false, fmt.Sprintf("User attribute '%s' not found in context", policyAttribute.AttributeName) } log.Print("Found User Attribute: ", actualValue) case "resource": + if ctx.ResourceData == nil { + return false, "Resource data missing in context" + } actualValue, exists = ctx.ResourceData[policyAttribute.AttributeName] if !exists { - return false, fmt.Sprintf("Resource attribute '%s' not found", policyAttribute.AttributeName) + return false, fmt.Sprintf("Resource attribute '%s' not found in context", policyAttribute.AttributeName) } - case "environment": + if ctx.Environment == nil { + return false, "Environment data missing in context" + } actualValue, exists = ctx.Environment[policyAttribute.AttributeName] if !exists { - return false, fmt.Sprintf("Environment attribute '%s' not found", policyAttribute.AttributeName) + return false, fmt.Sprintf("Environment attribute '%s' not found in context", policyAttribute.AttributeName) } - default: return false, fmt.Sprintf("Unknown attribute type: %s", policyAttribute.AttributeType) }