# iPaaS Authorization Middleware - Implementation Summary

## Date: November 7, 2025

---

## Overview

Centralized iPaaS authorization logic using a **custom middleware** instead of repetitive inline checks in every controller method. This provides a cleaner, more maintainable, and "Laravel way" approach to authorization.

---

## Implementation

### 1. **Middleware Created**

**File:** `src/App/Http/Middleware/EnsureUserCanManageIpaas.php`

```php
<?php
namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;

class EnsureUserCanManageIpaas
{
    public function handle(Request $request, Closure $next): Response
    {
        // Check authentication
        if (!auth()->check()) {
            Log::warning('Unauthenticated iPaaS access attempt');
            abort(401, 'Authentication required.');
        }

        // Check permission
        $user = auth()->user();
        if (!$user->hasPermission('can_manage_ipass')) {
            Log::warning('Unauthorized iPaaS access attempt', [
                'user_id' => $user->id,
                'url' => $request->fullUrl(),
                'ip' => $request->ip()
            ]);
            
            // JSON response for API requests
            if ($request->expectsJson()) {
                return response()->json([
                    'success' => false,
                    'message' => 'You do not have permission to manage iPaaS resources.'
                ], 403);
            }
            
            abort(403, 'Unauthorized action.');
        }
        
        return $next($request);
    }
}
```

**Key Features:**
- ✅ Centralized authorization logic
- ✅ Comprehensive logging (user, URL, IP, method)
- ✅ Dual response (JSON for API, abort for web)
- ✅ Reusable across all iPaaS controllers

---

### 2. **Middleware Registered**

**File:** `src/App/Http/Kernel.php`

```php
protected $middlewareAliases = [
    'auth' => \App\Http\Middleware\Authenticate::class,
    'can.manage.ipass' => \App\Http\Middleware\EnsureUserCanManageIpaas::class, // ← Added
    // ... other middleware
];
```

**Alias:** `can.manage.ipass`

---

### 3. **Controllers Updated**

All iPaaS controllers now use the middleware in their constructors:

#### **ConnectorController**
```php
public function __construct()
{
    $this->middleware('auth');
    $this->middleware('can.manage.ipass'); // ← Added
    $this->pageTitle = 'Connector';
    $this->routeprefix = 'connector';
}
```

#### **ApiNodeController**
```php
public function __construct()
{
    $this->middleware('auth');
    $this->middleware('can.manage.ipass'); // ← Added
    $this->pageTitle = 'Api Node';
    $this->routeprefix = 'api_node';
}
```

#### **MapNodeController**
```php
public function __construct()
{
    $this->middleware('auth');
    $this->middleware('can.manage.ipass'); // ← Added
    $this->pageTitle = 'Map Node';
    $this->routeprefix = 'mapnode';
}
```

#### **TransformNodeController**
```php
public function __construct()
{
    $this->middleware('auth');
    $this->middleware('can.manage.ipass'); // ← Added
}
```

#### **BranchsNodeController**
```php
public function __construct()
{
    $this->middleware('auth');
    $this->middleware('can.manage.ipass'); // ← Added
}
```

---

### 4. **Code Removed**

**Before** (repetitive in every method):
```php
public function index()
{
    /** @var \App\Models\User $user */
    $user = auth()->user();
    if (!$user->hasPermission('can_manage_ipass')) {
        abort(403, 'Unauthorized action.');
    }
    
    // ... actual logic
}
```

**After** (clean methods):
```php
public function index()
{
    // ... actual logic only
    // Authorization handled by middleware
}
```

**Lines of code removed:** ~150+ lines across 5 controllers

---

## Benefits

### ✅ **DRY (Don't Repeat Yourself)**
- Authorization logic written **once**, used everywhere
- No copy-paste code across methods
- Easier to maintain and update

### ✅ **Centralized Logging**
- All authorization attempts logged in one place
- Consistent log format across all iPaaS resources
- Easier security auditing

### ✅ **"Laravel Way"**
- Follows Laravel best practices
- Middleware is the standard approach for cross-cutting concerns
- Familiar pattern for other developers

### ✅ **Reusability**
- Can be applied to new iPaaS controllers instantly
- Can be used in route groups if needed
- Can be combined with other middleware

### ✅ **Testability**
- Middleware can be tested independently
- Controllers can be tested without worrying about authorization
- Easier to mock in tests

### ✅ **Cleaner Code**
- Controller methods focus on business logic only
- No authorization clutter in every method
- Improved readability

---

## Usage

### Apply to Controller
```php
class MyIpaasController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');
        $this->middleware('can.manage.ipass');
    }
}
```

### Apply to Route Group
```php
// In routes/tenant.php
Route::middleware(['auth', 'can.manage.ipass'])->group(function () {
    Route::paramResource('connector', ConnectorController::class);
    Route::paramResource('api_node', ApiNodeController::class);
    // ... other iPaaS routes
});
```

### Apply to Specific Methods
```php
public function __construct()
{
    $this->middleware('auth');
    $this->middleware('can.manage.ipass')->only(['store', 'update', 'destroy']);
}
```

### Exclude Specific Methods
```php
public function __construct()
{
    $this->middleware('auth');
    $this->middleware('can.manage.ipass')->except(['index', 'show']);
}
```

---

## Testing

### Unit Test for Middleware
```php
use Tests\TestCase;
use App\Models\User;
use Domain\Roles\Models\Role;
use App\Http\Middleware\EnsureUserCanManageIpaas;
use Illuminate\Http\Request;

class EnsureUserCanManageIpaasTest extends TestCase
{
    /** @test */
    public function it_allows_users_with_permission()
    {
        $role = Role::factory()->create(['can_manage_ipass' => true]);
        $user = User::factory()->create(['current_role_id' => $role->id]);
        
        $this->actingAs($user);
        
        $middleware = new EnsureUserCanManageIpaas();
        $request = Request::create('/ipaas/connector', 'GET');
        
        $response = $middleware->handle($request, function ($req) {
            return response('OK');
        });
        
        $this->assertEquals('OK', $response->getContent());
    }
    
    /** @test */
    public function it_blocks_users_without_permission()
    {
        $role = Role::factory()->create(['can_manage_ipass' => false]);
        $user = User::factory()->create(['current_role_id' => $role->id]);
        
        $this->actingAs($user);
        
        $this->expectException(\Symfony\Component\HttpKernel\Exception\HttpException::class);
        
        $middleware = new EnsureUserCanManageIpaas();
        $request = Request::create('/ipaas/connector', 'GET');
        
        $middleware->handle($request, function ($req) {
            return response('OK');
        });
    }
}
```

### Feature Test for Controller
```php
use Tests\TestCase;
use App\Models\User;
use Domain\Roles\Models\Role;

class ConnectorControllerTest extends TestCase
{
    /** @test */
    public function authorized_user_can_access_connector_index()
    {
        $role = Role::factory()->create(['can_manage_ipass' => true]);
        $user = User::factory()->create(['current_role_id' => $role->id]);
        
        $response = $this->actingAs($user)->get(route('connector.index'));
        
        $response->assertStatus(200);
    }
    
    /** @test */
    public function unauthorized_user_cannot_access_connector_index()
    {
        $role = Role::factory()->create(['can_manage_ipass' => false]);
        $user = User::factory()->create(['current_role_id' => $role->id]);
        
        $response = $this->actingAs($user)->get(route('connector.index'));
        
        $response->assertStatus(403);
    }
}
```

---

## Security

### Multi-Layer Authorization

The system maintains **two layers** of authorization:

1. **Middleware** (Controller-level)
   - Applied in constructor
   - Protects ALL methods automatically
   - No way to bypass

2. **FormRequest** (Request-level)
   - Applied in `store()` and `update()` methods
   - Validates before processing
   - Additional security layer

Both layers check the same permission (`can_manage_ipass`), ensuring consistent security.

---

## Logging

All unauthorized access attempts are logged with context:

```php
Log::warning('Unauthorized iPaaS access attempt', [
    'user_id' => $user->id,
    'current_role_id' => $user->current_role_id,
    'url' => $request->fullUrl(),
    'method' => $request->method(),
    'ip' => $request->ip()
]);
```

**Log Location:** `storage/logs/tenants/tenant_{id}/{date}.log`

---

## Permission Management

### Via UI (Recommended)
1. Navigate to **Roles Management**
2. Edit the desired role
3. Check **"Can Manage iPaaS"**
4. Save

### Via Artisan Command
```bash
# Grant to all roles in a tenant
php artisan ipaas:grant-permission 7675435 all

# Grant to specific user
php artisan ipaas:grant-permission 7675435 user@example.com

# Grant to specific role
php artisan ipaas:grant-permission 7675435 all --role-id=5
```

### Via Database
```sql
-- Update specific role
UPDATE roles SET can_manage_ipass = 1 WHERE id = {role_id};

-- Grant to all roles
UPDATE roles SET can_manage_ipass = 1;
```

---

## Future Enhancements

### 1. **Granular Permissions**
Instead of a single `can_manage_ipass` permission, implement:
- `can_view_ipass`
- `can_create_ipass`
- `can_update_ipass`
- `can_delete_ipass`
- `can_execute_flows`

Update middleware to check specific permissions based on HTTP method.

### 2. **Resource-Specific Permissions**
- `can_manage_connectors`
- `can_manage_api_nodes`
- `can_manage_flows`

Create separate middleware for each resource type.

### 3. **Tenant-Scoped Authorization**
Verify that the resource belongs to the user's current tenant:

```php
public function handle(Request $request, Closure $next): Response
{
    // ... existing checks ...
    
    // Verify tenant scope
    if ($request->route('id')) {
        $resourceId = $request->route('id');
        $connector = Connector::find($resourceId);
        
        if ($connector && $connector->tenant_id !== auth()->user()->getCurrentTenantId()) {
            abort(403, 'Resource does not belong to your tenant.');
        }
    }
    
    return $next($request);
}
```

---

## Troubleshooting

### Middleware Not Working

**Symptoms:** Authorization checks not being applied

**Solutions:**
1. Clear route cache: `php artisan route:clear`
2. Clear config cache: `php artisan config:clear`
3. Verify middleware is registered in `Kernel.php`
4. Check constructor is calling `$this->middleware('can.manage.ipass')`

### Still Getting 403 Errors

**Symptoms:** Authorized users receiving 403

**Solutions:**
1. Verify user has `can_manage_ipass = 1` in their role
2. Check user has `current_role_id` assigned
3. Verify `User->hasPermission()` method exists and works
4. Check logs for specific error details

### Middleware Running Multiple Times

**Symptoms:** Logs show duplicate entries

**Solutions:**
1. Check middleware is not applied both in constructor AND route definition
2. Verify not using both `Route::middleware()` and constructor middleware
3. Remove duplicate middleware registrations

---

## Summary

The iPaaS Authorization Middleware provides:

✅ **Centralized authorization** - One place to manage access control  
✅ **Clean code** - No repetitive checks in every method  
✅ **Comprehensive logging** - All access attempts tracked  
✅ **Reusable** - Apply to any iPaaS controller instantly  
✅ **Testable** - Easy to unit test independently  
✅ **Maintainable** - Update once, applies everywhere  
✅ **Laravel best practices** - Standard middleware approach

All iPaaS resources (Connectors, API Nodes, Map Nodes, Transform Nodes, Branch Nodes) are now protected by this centralized middleware, ensuring consistent and secure authorization across the entire iPaaS module.

