feat(authz): support multi-role claim evaluation and role-aware permission checks
Parse and normalize user and project role claims (role_id + projects[].role_id) Intersect requested roles with JWT-available roles before authorization Evaluate permissions across candidate roles in both cached and non-cached flows Fix claim field fallbacks (user_id/email) and role ID log formatting Update tests and SQL mock expectations for new role-resolution behavior
This commit is contained in:
@@ -5,7 +5,6 @@ import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/DATA-DOG/go-sqlmock"
|
||||
)
|
||||
@@ -105,19 +104,10 @@ func TestGetUserByIDSuccess(t *testing.T) {
|
||||
mock, cleanup := setupMockDB(t)
|
||||
defer cleanup()
|
||||
|
||||
testTime := time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
rows := sqlmock.NewRows([]string{"users_id", "email_address"}).
|
||||
AddRow("user123", "john@example.com")
|
||||
|
||||
rows := 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", "M", "Doe", "Jr", "john@example.com",
|
||||
"EMP001", "Y", "Y", "123 Main St", "1234567890", "device001",
|
||||
1, "N", "secret", "Y", testTime, testTime,
|
||||
)
|
||||
|
||||
mock.ExpectQuery("SELECT users_id, first_name").
|
||||
mock.ExpectQuery("SELECT users_id, email_address").
|
||||
WithArgs("user123").
|
||||
WillReturnRows(rows)
|
||||
|
||||
@@ -132,8 +122,8 @@ func TestGetUserByIDSuccess(t *testing.T) {
|
||||
if user.UsersID != "user123" {
|
||||
t.Errorf("Expected UsersID 'user123', got '%s'", user.UsersID)
|
||||
}
|
||||
if user.FirstName != "John" {
|
||||
t.Errorf("Expected FirstName 'John', got '%s'", user.FirstName)
|
||||
if user.EmailAddress != "john@example.com" {
|
||||
t.Errorf("Expected EmailAddress 'john@example.com', got '%s'", user.EmailAddress)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +131,7 @@ func TestGetUserByIDNotFound(t *testing.T) {
|
||||
mock, cleanup := setupMockDB(t)
|
||||
defer cleanup()
|
||||
|
||||
mock.ExpectQuery("SELECT users_id, first_name").
|
||||
mock.ExpectQuery("SELECT users_id, email_address").
|
||||
WithArgs("nonexistent").
|
||||
WillReturnError(sql.ErrNoRows)
|
||||
|
||||
@@ -180,12 +170,12 @@ func TestGetAllPolicyAttributesSuccess(t *testing.T) {
|
||||
mock, cleanup := setupMockDB(t)
|
||||
defer cleanup()
|
||||
|
||||
rows := sqlmock.NewRows([]string{"id", "attribute_name", "attribute_type", "comparison", "attribute_value", "permission_id"}).
|
||||
rows := sqlmock.NewRows([]string{"policy_attributes_id", "attribute_name", "attribute_type", "comparison", "attribute_value", "permission_id"}).
|
||||
AddRow(1, "department", "user", "=", "engineering", 1).
|
||||
AddRow(2, "level", "user", ">=", "5", 1).
|
||||
AddRow(3, "role", "user", "=", "admin", 2)
|
||||
|
||||
mock.ExpectQuery("SELECT id, attribute_name, attribute_type, comparison, attribute_value, permission_id FROM policy_attributes ORDER BY permission_id, id").
|
||||
mock.ExpectQuery("SELECT policy_attributes_id, attribute_name, attribute_type, comparison, attribute_value, permission_id FROM policy_attributes ORDER BY permission_id, policy_attributes_id").
|
||||
WillReturnRows(rows)
|
||||
|
||||
attrs, err := GetAllPolicyAttributes()
|
||||
@@ -208,9 +198,9 @@ func TestGetAllPolicyAttributesEmpty(t *testing.T) {
|
||||
mock, cleanup := setupMockDB(t)
|
||||
defer cleanup()
|
||||
|
||||
rows := sqlmock.NewRows([]string{"id", "attribute_name", "attribute_type", "comparison", "attribute_value", "permission_id"})
|
||||
rows := sqlmock.NewRows([]string{"policy_attributes_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 ORDER BY permission_id, id").
|
||||
mock.ExpectQuery("SELECT policy_attributes_id, attribute_name, attribute_type, comparison, attribute_value, permission_id FROM policy_attributes ORDER BY permission_id, policy_attributes_id").
|
||||
WillReturnRows(rows)
|
||||
|
||||
attrs, err := GetAllPolicyAttributes()
|
||||
@@ -313,14 +303,9 @@ func TestGetUserByIDEmptyID(t *testing.T) {
|
||||
mock, cleanup := setupMockDB(t)
|
||||
defer cleanup()
|
||||
|
||||
rows := 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",
|
||||
})
|
||||
rows := sqlmock.NewRows([]string{"users_id", "email_address"})
|
||||
|
||||
// Match the actual query format with all the fields
|
||||
mock.ExpectQuery(`SELECT users_id, first_name, middle_initial, last_name, suffix, email_address`).
|
||||
mock.ExpectQuery(`SELECT users_id, email_address`).
|
||||
WithArgs("").
|
||||
WillReturnRows(rows)
|
||||
|
||||
@@ -339,7 +324,7 @@ func TestGetUserByIDDatabaseError(t *testing.T) {
|
||||
mock, cleanup := setupMockDB(t)
|
||||
defer cleanup()
|
||||
|
||||
mock.ExpectQuery("SELECT id, username, role, email, created_at, updated_at FROM users WHERE id = \\?").
|
||||
mock.ExpectQuery("SELECT users_id, email_address").
|
||||
WithArgs("user123").
|
||||
WillReturnError(errors.New("database connection failed"))
|
||||
|
||||
@@ -415,7 +400,7 @@ func TestGetAllPolicyAttributesDatabaseError(t *testing.T) {
|
||||
mock, cleanup := setupMockDB(t)
|
||||
defer cleanup()
|
||||
|
||||
mock.ExpectQuery("SELECT id, attribute_name, attribute_type, comparison, attribute_value, permission_id FROM policy_attributes ORDER BY permission_id, id").
|
||||
mock.ExpectQuery("SELECT policy_attributes_id, attribute_name, attribute_type, comparison, attribute_value, permission_id FROM policy_attributes ORDER BY permission_id, policy_attributes_id").
|
||||
WillReturnError(errors.New("connection lost"))
|
||||
|
||||
attrs, err := GetAllPolicyAttributes()
|
||||
@@ -432,7 +417,7 @@ func TestGetAllPolicyAttributesManyPermissions(t *testing.T) {
|
||||
mock, cleanup := setupMockDB(t)
|
||||
defer cleanup()
|
||||
|
||||
rows := sqlmock.NewRows([]string{"id", "attribute_name", "attribute_type", "comparison", "attribute_value", "permission_id"})
|
||||
rows := sqlmock.NewRows([]string{"policy_attributes_id", "attribute_name", "attribute_type", "comparison", "attribute_value", "permission_id"})
|
||||
|
||||
// Add attributes for multiple permissions
|
||||
for permID := 1; permID <= 50; permID++ {
|
||||
@@ -441,7 +426,7 @@ func TestGetAllPolicyAttributesManyPermissions(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
mock.ExpectQuery("SELECT id, attribute_name, attribute_type, comparison, attribute_value, permission_id FROM policy_attributes ORDER BY permission_id, id").
|
||||
mock.ExpectQuery("SELECT policy_attributes_id, attribute_name, attribute_type, comparison, attribute_value, permission_id FROM policy_attributes ORDER BY permission_id, policy_attributes_id").
|
||||
WillReturnRows(rows)
|
||||
|
||||
attrs, err := GetAllPolicyAttributes()
|
||||
@@ -465,7 +450,7 @@ func TestGetUserAttributesDatabaseError(t *testing.T) {
|
||||
mock, cleanup := setupMockDB(t)
|
||||
defer cleanup()
|
||||
|
||||
mock.ExpectQuery("SELECT attribute_name, attribute_value, attribute_type FROM user_attributes WHERE users_id = \\?").
|
||||
mock.ExpectQuery("SELECT attribute_name, attribute_value FROM user_attributes WHERE users_id = \\?").
|
||||
WithArgs("user123").
|
||||
WillReturnError(errors.New("timeout"))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user