Skip to content

Conversation

@MFarukDemirkoparan
Copy link
Collaborator

No description provided.

Mehmet Faruk Demirkoparan and others added 26 commits January 16, 2026 17:03
- Updated config structure (aauth.php, added aauth-permissions.php)
- Added parameters JSON column to role_permission table
- Added panel_id column to roles table
- Added defensive code for soft deprecation of type enum
- Add parameter support to AAuth::can()
- Integrate Laravel Gate via Gate::before()
- Keep permission logic centralized in AAuth.php
- Update helper functions and Blade directives
- Implement request-level cache using Laravel Context API in AAuth.php
- Add in-memory request cache via $requestCache property
- Optimize eager loading for roles, permissions, and ABAC rules
- Invalidate cached context using model observers
- Introduce context lifecycle helpers (loadAndCacheContext, clearContext)
…r bindings

- Introduce permission-based authorization middleware
- Add role-based access control middleware
- Implement organization scope enforcement middleware
- Register AAuth middleware in AAuthServiceProvider
- Add role lifecycle and assignment events
- Add permission change events
- Fire relevant events from role and permission observers
- Leverage existing observer registrations in AAuthServiceProvider
- Add migration to make roles.type column nullable
- Update unique constraint to use organization scope
- Adjust indexes to reflect new role scoping model
- Add defensive schema checks for safe migrations
- Add static factory methods for panel-scoped usage
- Introduce panel-aware instance methods without affecting existing API
- Provide static helpers for panel role resolution and panel detection
- Add global helper functions for Filament panel context
- Register Blade directives for panel-based authorization checks
Validation fixes:
- Change name field minimum length from 5 to 3 in all FormRequests
- Fix UpdateRoleRequest unique validation (permissions → roles table)
- Add missing authorize() and rules() methods to StoreOrganizationScopeRequest

Filament panel integration (Phase 7):
- Add optional panelId parameter to AAuth constructor for Filament context
- Add factory methods and panel-aware helpers (forPanel, forCurrentPanel, isInPanel)
- Add Blade directives (@panel, @aauth_panel_can) and helper functions
- Auto-detect Filament panel context in singleton binding
- Add recursive depth limit (max 10) and SQL injection prevention via regex validation
- Add strict JSON decode error handling and operator whitelist check
- Support multiple value types and user attribute references (@user.attribute)
- Add role and switchableRoles caching with config-driven enable/disable (default: false for safety)
- Fix cache invalidation in observers and service methods for immediate effect on role/permission changes
- Create performance indexes (panel_id, role_permission, user_role joins, org paths) with Laravel 11 + PostgreSQL/MySQL compatibility

Backward compatible: Cache disabled by default (opt-in via config), defensive hasIndex() prevents duplicate errors
Performance: Query optimization via composite indexes, cache TTL configurable
- Add getAccessibleOrganizationNodes() method with depth/scope filtering (minDepth, maxDepth, scopeName, scopeLevel)
- Create EN/TR language files for exception messages (resources/lang/en/aauth.php, resources/lang/tr/aauth.php)
- Add translation support to MissingRoleException with fallback for backward compatibility

Backward compatible: New method added, existing API unchanged. Translation opt-in via lang files.
SQL: MySQL + PostgreSQL compatible depth calculation using LENGTH(path) - LENGTH(REPLACE(path, '/', ''))
- Update README.md with v2 features (Filament Panel, Performance, i18n, Depth Filtering)
- Create UPGRADE.md for v1 to v2 migration guide with breaking changes and troubleshooting
- Create API.md with complete method documentation for AAuth, services, helpers, and directives
V2 Test Suite (99 new tests):
- AAuthCoreTest: Core method tests (currentRole, permissions, organizationNodes)
- PanelSupportTest: Panel context, forPanel, switchableRolesForPanel
- ExceptionTest: Exception handling coverage
- MiddlewareTest: Middleware tests
- V2FeaturesTest: Context caching, parametric permissions, super admin

Bug Fixes:
- Fix isset() returning false for null permission params (array_key_exists)
- Fix Observer not triggering on permission changes (use Eloquent instead of DB::table)
- Add Context clearing in RolePermissionObserver for cache invalidation
- Load rolePermissions relationship after context reload

CI:
- Run tests on all branches, not just main

Config:
- Add aauth-advanced.php for cache and performance settings
V2 Test Suite (99 new tests):
- AAuthCoreTest: Core method tests (currentRole, permissions, organizationNodes)
- PanelSupportTest: Panel context, forPanel, switchableRolesForPanel
- ExceptionTest: Exception handling coverage
- MiddlewareTest: Middleware tests
- V2FeaturesTest: Context caching, parametric permissions, super admin

Bug Fixes:
- Fix isset() returning false for null permission params (array_key_exists)
- Fix Observer not triggering on permission changes (use Eloquent instead of DB::table)
- Add Context clearing in RolePermissionObserver for cache invalidation
- Load rolePermissions relationship after context reload

CI:
- Run tests on all branches, not just main

Config:
- Add aauth-advanced.php for cache and performance settings
@claude
Copy link

claude bot commented Jan 22, 2026

AAuth v2 Release - Comprehensive Code Review

Overview

This is a major release with 4,349 additions and 170 deletions across 47 files. The v2 introduces significant features including Filament panel support, request-level caching, parametric permissions, and performance optimizations. Overall implementation is solid with excellent test coverage (99 new tests), but there are critical security gaps that must be addressed.


🔴 Critical Issues (Must Fix Before Merge)

1. ABAC Security Features NOT Implemented

Issue: Commit message claims "ABAC validation hardening (SQL injection prevention, depth limits, operator whitelisting)" but these features are not actually implemented.

Missing Security Features:

  • No depth limit (allows stack overflow attacks via deep nesting)
  • No operator whitelist (accepts any operator)
  • No SQL injection prevention for attribute names
  • No JSON decode error handling

Impact: Attackers could inject malicious SQL via ABAC attribute names or cause DoS via deeply nested rules.

2. SQL Injection Risks

Location: src/AAuth.php:415-449 - can() method
Issue: Permission names are not validated before use.

Location: src/AAuth.php:713, 717 - Depth filtering
Issue: Depth parameters not validated.

3. Database Migration Not Database-Agnostic

Location: database/migrations/2024_01_01_000003_make_type_nullable_in_roles.php
Issue: Uses MySQL-specific syntax that will fail on PostgreSQL, SQLite, and SQL Server.

4. Unsafe Serialization in Cache Keys

Location: src/AAuth.php:515
Issue: Using serialize() on untrusted input instead of json_encode().


🟡 High Priority Issues (Should Fix)

5. Race Condition in Cache Invalidation

  • Cache clearing without transactions
  • Potential for stale cache

6. N+1 Query Problem

  • Inefficient loading in RoleObserver
  • Could impact performance with many organization nodes

7. Generic Exception Catching

  • Catching Throwable hides real bugs
  • Should catch specific exceptions only

8. Memory Leak Potential

  • Request cache grows unbounded
  • Need LRU cache with size limit

9. Cache Stampede Risk

  • Multiple concurrent requests missing cache
  • Should use cache locks

🟢 Strengths

  • 99 comprehensive tests covering core functionality
  • Request-level caching prevents duplicate permission checks
  • Composite indexes for query optimization
  • Good backward compatibility with defensive checks
  • Clean architecture with factory methods and observers
  • Proper event firing for domain changes

📋 Testing Gaps

Missing critical tests:

  1. Concurrency tests for race conditions
  2. ABAC security tests (depth limit, SQL injection, invalid operators)
  3. Performance tests for caching and indexes
  4. Migration rollback tests
  5. Panel isolation tests

🔧 Code Quality Issues

  • Nullable return types inconsistent
  • Panel ID not validated
  • No cache cleanup on user deletion
  • Inefficient queries (leftJoin vs join, distinct vs groupBy)

✅ Recommendations

Before Merging (Critical):

  1. Implement ABAC validation hardening
  2. Add permission name validation
  3. Fix database migration to be database-agnostic
  4. Replace serialize() with json_encode()
  5. Add depth parameter validation

High Priority (Post-Merge):

  1. Fix race conditions with transactions
  2. Optimize N+1 query in RoleObserver
  3. Replace generic Throwable catches
  4. Implement cache stampede prevention
  5. Add LRU limit to request cache

🎯 Overall Assessment

Grade: B+ (would be A- with security fixes)

This is an impressive v2 release with excellent features and solid architecture. However, the critical gap between claimed and actual ABAC security features is concerning.

Recommendation: Do not merge until:

  1. ABAC hardening is properly implemented
  2. SQL injection risks are mitigated
  3. Database migration is made database-agnostic

Once these critical issues are resolved, this will be a production-ready release.


Review completed with automated code analysis and manual security audit.

- Replace serialize() with json_encode() in cache key generation (AAuth.php:515)
- Make migration database-agnostic using Laravel Schema builder instead of MySQL-specific syntax
@claude
Copy link

claude bot commented Jan 23, 2026

Code Review: AAuth v2

Overview

This is a major version upgrade introducing parametric permissions, Filament panel support, caching, super admin functionality, and comprehensive test coverage. The PR adds 4,353 lines across 47 files with excellent documentation.

✅ Strengths

1. Architecture & Design

  • Backward Compatibility: Excellent defensive programming with hasRolesTypeColumn() and hasRolesPanelIdColumn()
  • Clean Separation: New RolePermission model properly separates concerns
  • Event System: Well-implemented observers for cache invalidation and event broadcasting
  • Helper Functions: Comprehensive helper functions improve developer experience

2. Performance

  • Caching Strategy: Smart caching implementation with automatic invalidation
  • Request Cache: Prevents redundant permission checks within a single request
  • Database Indexes: Migration adds critical indexes for common queries
  • Context API: Uses Laravel's Context API for efficient in-request data sharing

3. Documentation

  • Excellent API.md with 520 lines of comprehensive documentation
  • Clear UPGRADE.md guide (210 lines)
  • Well-commented code with PHPDoc blocks

4. Test Coverage

  • 5 new test files with 1,426 lines of tests
  • Good test organization with descriptive test names

@claude
Copy link

claude bot commented Jan 23, 2026

⚠️ Issues & Concerns

🔴 Critical Issues

1. Cache Invalidation Race Condition (AAuth.php:462-493)

If a permission is updated mid-request after context is cached, the observer clears the context but the role model still has stale relationship data.

2. SQL Injection Risk in Depth Filtering (AAuth.php:713-717)

The raw SQL uses database-specific functions that break on SQLite. Add database driver check:

->when($minDepthFromRoot !== null, function ($query) use ($minDepthFromRoot) {
    $driver = DB::connection()->getDriverName();
    if (in_array($driver, ['mysql', 'mariadb', 'pgsql'])) {
        // Current implementation
    } else {
        throw new \RuntimeException("Depth filtering not supported on {$driver}");
    }
})

3. N+1 Query Problem in RoleObserver (RoleObserver.php:47-53)

The logic for clearing user cache appears incorrect. Query the pivot table directly:

$userIds = DB::table('user_role_organization_node')
    ->where('role_id', $role->id)
    ->distinct()
    ->pluck('user_id');

foreach ($userIds as $userId) {
    Cache::forget("{$prefix}:user:{$userId}:switchable_roles");
}

@claude
Copy link

claude bot commented Jan 23, 2026

🟡 Security Concerns

4. Weak Error Messages (Middleware files)

All middleware classes catch exceptions without logging. Recommendation:

} catch (\Throwable $e) {
    \Log::warning('AAuth authorization failed', [
        'exception' => $e->getMessage(),
        'user' => $request->user()?->id,
        'permission' => $permission,
    ]);
    abort(403, 'Unauthorized action.');
}

5. Cache Key Collision Risk (AAuth.php:515)

Add JSON_THROW_ON_ERROR to prevent silent failures:

protected function getPermissionCacheKey(string $permission, array $arguments): string
{
    $serialized = json_encode($arguments, JSON_THROW_ON_ERROR);
    return $permission . ':' . md5($serialized);
}

@claude
Copy link

claude bot commented Jan 23, 2026

🟠 Code Quality Issues

6. Inconsistent Null Checks (AAuth.php:42-43)
throw_unless($roleId, ...) would fail for $roleId = 0. Fix:

throw_unless($roleId !== null && $roleId > 0, new MissingRoleException());

7. Dead Code (AAuth.php:653-657)
Remove commented code before merging.

8. TODOs in Production Code
Multiple TODOs found in AAuth.php (lines 119, 214, 565, 583) and RolePermissionService.php (line 185). Create GitHub issues for these and remove from code.

9. Potential Null Reference (RolePermissionService.php:70-72)

$roleModel = Role::find($id);
if (!$roleModel) {
    return null;
}
return $roleModel->update($role) ? $roleModel : null;

10. Type Coercion (AAuth.php:648)
Use strict comparison: if ($nodeId === $organizationNode->id)

@claude
Copy link

claude bot commented Jan 23, 2026

🔵 Performance Considerations

11. Repeated Schema Checks
Cache schema checks at service provider level instead of per-request static variables.

12. Path Query Performance (AAuth.php:586-607)
Multiple database queries in loop. Batch load:

$rootNodes = OrganizationNode::whereIn('id', $this->organizationNodeIds)->get();
return OrganizationNode::where(function ($query) use ($rootNodes, $includeRootNode) {
    foreach ($rootNodes as $rootNode) {
        $query->orWhere('path', 'like', $rootNode->path . '/%');
        if ($includeRootNode) {
            $query->orWhere('path', $rootNode->path);
        }
    }
})

📋 Minor Issues

  1. Typo in README line 8: "Attibute" should be "Attribute"
  2. Workflow now runs on all branches - verify this is intentional
  3. Cache enabled by default in config - consider if this should be opt-in
  4. Type hints could be more specific in helper functions

@claude
Copy link

claude bot commented Jan 23, 2026

🎯 Recommendations

Must Fix Before Merge:

  1. Fix cache invalidation race condition (asdasds #1)
  2. Fix SQL injection risk / add database driver check (Bismillah #2)
  3. Fix RoleObserver cache clearing logic (Bismillah #3)
  4. Fix null reference in updateRole (Pr3 #9)
  5. Remove dead code (Pr3 #7)

Should Fix Before Merge:

  1. Add exception logging in middleware (Pr2 #4)
  2. Fix weak validation in constructor (Pr3 #6)
  3. Create issues for all TODOs (Pr3 #8)
  4. Batch load organization nodes (readme updated #12)

Nice to Have:

  1. Improve cache key generation (Pr3 #5)
  2. Use strict comparisons (Readme update #10)
  3. Centralize schema checks (readme updated #11)
  4. Fix typos in documentation (readme updated #13)

🏆 Overall Assessment

This is a well-architected major upgrade with excellent backward compatibility, comprehensive documentation, and good test coverage. The core design decisions (observers, caching strategy, helper functions) are solid.

However, there are 3 critical issues that must be addressed before merging:

  1. Cache invalidation race condition
  2. Database compatibility in raw SQL queries
  3. Incorrect cache clearing in RoleObserver

Once these are resolved, this will be a significant improvement to the package.

Recommendation: Request changes for critical issues, then approve after fixes.


Review generated by Claude Code

- Fix RoleObserver N+1 query with direct pivot table query
- Fix cache race condition by refreshing role on context reload
@claude
Copy link

claude bot commented Jan 23, 2026

AAuth v2 Pull Request Review

This is a significant release introducing v2 features with backward compatibility. The implementation demonstrates careful attention to migration concerns and comprehensive testing. Below are my findings:


Strengths

1. Excellent Backward Compatibility

  • Defensive coding with column checks (hasRolesTypeColumn(), hasRolesPanelIdColumn()) ensures smooth migration
  • Supports both old type column and new organization_scope_id approach
  • Legacy method permissions() preserved alongside new rolePermissions() relationship
  • This approach minimizes breaking changes for existing users

2. Strong Test Coverage

  • Comprehensive test suite with 5 test files covering:
    • Core functionality (AAuthCoreTest.php)
    • V2 features (V2FeaturesTest.php)
    • Middleware (MiddlewareTest.php)
    • Panel support (PanelSupportTest.php)
    • Exceptions (ExceptionTest.php)
  • Tests cover parametric permissions, context caching, and edge cases
  • Good use of beforeEach for clean test isolation

3. Performance Optimizations

  • Database indexes added for frequently queried columns (panel_id, composite indexes on role_permission and user_role_organization_node)
  • Request-level caching via requestCache array reduces duplicate permission checks
  • Optional role/permission caching with automatic invalidation via observers
  • Context storage using Laravel's Context API for efficient in-request state management

4. Event System

  • Well-designed event architecture for role and permission changes
  • Events: RoleCreatedEvent, RoleUpdatedEvent, PermissionAddedEvent, etc.
  • Enables external packages to react to authorization changes
  • Observers handle cache invalidation automatically

5. Filament Panel Integration

  • First-class support for multi-panel Filament applications
  • Panel detection via detectCurrentPanelId()
  • Factory methods forPanel() and forCurrentPanel()
  • Helper functions for panel-aware operations

6. Documentation

  • Comprehensive API.md with 520 lines documenting all public methods
  • Clear UPGRADE.md guide for migration (210 lines)
  • Updated README with v2 features and examples

⚠️ Issues & Concerns

1. Security Concerns

High Priority:

Location: src/AAuth.php:715-719

->whereRaw('(LENGTH(path) - LENGTH(REPLACE(path, ?, ?))) - 1 >= ?', ['/', '', $minDepthFromRoot]);
  • Issue: Raw SQL with user-controlled parameters could be vulnerable if or are not properly validated
  • Recommendation: Add explicit integer validation/casting before the whereRaw calls
->when($minDepthFromRoot \!== null || $maxDepthFromRoot \!== null, function ($query) use ($minDepthFromRoot, $maxDepthFromRoot) {
    if ($minDepthFromRoot \!== null) {
        $minDepth = (int) $minDepthFromRoot; // Cast to int
        $query->whereRaw('(LENGTH(path) - LENGTH(REPLACE(path, ?, ?))) - 1 >= ?', ['/', '', $minDepth]);
    }
    // ... same for maxDepthFromRoot
})

Medium Priority:

Location: src/Http/Middleware/AAuthPermission.php:26, AAuthRole.php:25, AAuthOrganizationScope.php:28

  • Issue: Generic error messages in middleware catch blocks hide specific errors
  • Recommendation: Consider logging the actual exception for debugging while still showing generic message to users:
} catch (\Throwable $e) {
    \Log::warning('AAuth authorization failed', ['error' => $e->getMessage()]);
    abort(403, 'Unauthorized action.');
}

2. Code Quality Issues

Location: src/AAuth.php:517

return $permission . ':' . md5(json_encode($arguments) ?: '');
  • Issue: json_encode() can return false on error, using ?: coalesces to empty string but doesn't handle the underlying error
  • Recommendation:
$encoded = json_encode($arguments);
if ($encoded === false) {
    $encoded = serialize($arguments); // Fallback
}
return $permission . ':' . md5($encoded);

Location: src/AAuth.php:604

  • Issue: Empty statement after closing brace
}
}
  • Recommendation: Remove the extra blank statement for cleaner code

Location: src/AAuth.php:655-658

  • Issue: Commented-out code should be removed
/*
if ($organizationNodes->contains(fn($node, $key) => $node->id == $nodeId)) {
    return OrganizationNode::findOrFail($nodeId)->first();
}
*/
  • Recommendation: Remove dead code or document why it's kept

3. Potential Bugs

Location: src/AAuth.php:650

if ($nodeId == $organizationNode->id) {
  • Issue: Loose comparison (==) instead of strict comparison (===)
  • Recommendation: Use strict comparison for integer IDs:
if ($nodeId === $organizationNode->id) {

Location: src/Observers/RolePermissionObserver.php:48-54

try {
    if (app()->bound('aauth')) {
        app('aauth')->clearContext();
    }
} catch (\Throwable $e) {
    Context::forgetHidden('aauth_context');
}
  • Issue: Silently catching all throwables could hide real errors
  • Recommendation: Only catch expected exceptions or add logging

4. Performance Considerations

Location: src/Observers/RoleObserver.php:48-56

$userIds = DB::table('user_role_organization_node')
    ->where('role_id', $role->id)
    ->distinct()
    ->pluck('user_id');

foreach ($userIds as $userId) {
    Cache::forget("{$prefix}:user:{$userId}:switchable_roles");
}
  • Issue: If a role has many users (e.g., 10,000), this creates 10,000 cache operations
  • Recommendation: Consider using cache tags or batch operations if supported by cache driver:
// Alternative with cache tags (if Redis/Memcached)
Cache::tags(["{$prefix}:switchable_roles"])->flush();

5. Type Safety

Location: src/AAuth.php:126

public function switchableRoles(): array|Collection|\Illuminate\Support\Collection
  • Issue: Union return type mixing different Collection types is confusing
  • Recommendation: Simplify to single return type:
public function switchableRoles(): Collection

6. Migration Considerations

Location: database/migrations/2024_01_01_000004_add_performance_indexes.php:63-76

  • Issue: Custom hasIndex() method checks for Laravel 10+ Schema API but doesn't handle older versions gracefully
  • Issue: If Schema::getIndexes() doesn't exist, hasIndex() always returns false, which will cause duplicate index errors on re-runs
  • Recommendation: Add database-specific index checking for older Laravel versions or wrap index creation in try-catch

📋 Suggestions

1. Helper Function Safety

Location: src/helpers.php:57-64

function aauth_for_panel(?$panelId = null): AAuth
{
    $user = \Illuminate\Support\Facades\Auth::user();
    $roleId = \Illuminate\Support\Facades\Session::get('roleId');
    // ...
}
  • Suggestion: Add null checks and handle cases where user or roleId might be missing

2. TODO Comments

Several TODO comments should be addressed:

  • src/AAuth.php:119: "// todo unit test" for currentRole()
  • src/AAuth.php:214: "// todo test'i yazılacak" for switchableRolesStatic()
  • src/AAuth.php:567: "// todo mesaj dil dosyasından gelecek" for passOrAbort()
  • src/AAuth.php:585: "// todo scope eklenecek. $scopeLevel $scopeName"

These features are implemented elsewhere in the PR, so TODOs may be outdated.

3. Config Naming

The split into aauth.php, aauth-advanced.php, and aauth-permissions.php is well-intentioned but might confuse users. Consider documenting the purpose of each config file clearly in README.

4. PHPStan Baseline

The phpstan-baseline.neon changes show 162 additions vs 67 deletions. While some baseline additions are expected with new features, review if new issues can be resolved rather than suppressed.


🎯 Recommendations Priority

Must Fix (Before Merge):

  1. ✅ Validate/cast integers in whereRaw calls (security)
  2. ✅ Handle json_encode failures properly
  3. ✅ Use strict comparison for ID checks

Should Fix (Before/Shortly After Merge):

  1. ✅ Remove commented-out dead code
  2. ✅ Add logging to middleware catch blocks
  3. ✅ Improve cache invalidation performance for high-user roles
  4. ✅ Add null safety to helper functions
  5. ✅ Review and resolve/remove TODO comments

Nice to Have:

  1. ⚪ Simplify return types for better type safety
  2. ⚪ Improve migration index checking for older Laravel versions
  3. ⚪ Consider cache tags for better cache management

📊 Overall Assessment

Code Quality: ⭐⭐⭐⭐☆ (4/5)
Test Coverage: ⭐⭐⭐⭐⭐ (5/5)
Documentation: ⭐⭐⭐⭐⭐ (5/5)
Backward Compatibility: ⭐⭐⭐⭐⭐ (5/5)
Performance: ⭐⭐⭐⭐☆ (4/5)
Security: ⭐⭐⭐⭐☆ (4/5 - address raw SQL parameter validation)

Overall: 4.5/5 - Excellent work with minor issues to address

This is a well-architected major version upgrade. The defensive coding approach, comprehensive testing, and detailed documentation make this a solid foundation for v2. The identified issues are mostly minor and can be addressed easily. The security concern with raw SQL should be fixed before merge, but overall this PR demonstrates high-quality software engineering.

Great job on maintaining backward compatibility while introducing powerful new features! 🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants