nhance/app/Filters/AclFilter.php

157 lines
5.2 KiB
PHP

<?php
namespace App\Filters;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use CodeIgniter\Filters\FilterInterface;
use Config\Acl;
use App\Libraries\AuthLogout;
class AclFilter implements FilterInterface
{
public function before(RequestInterface $request, $arguments = null)
{
// ===================== CLI BYPASS =====================
if (is_cli()) {
return;
}
// ===================== PATH NORMALIZATION =====================
$uri = service('uri');
// Raw path: /PHP828APPS/ruc/nhance/index.php/dashboard/view
$fullPath = '/' . ltrim($uri->getPath(), '/');
// Base path: /PHP828APPS/ruc/nhance
$basePath = rtrim(parse_url(base_url(), PHP_URL_PATH), '/');
// Remove base path
if ($basePath && str_starts_with($fullPath, $basePath)) {
$path = substr($fullPath, strlen($basePath));
} else {
$path = $fullPath;
}
// Remove index.php if present
if (str_starts_with($path, '/index.php')) {
$path = substr($path, strlen('/index.php'));
}
// Normalize
$path = '/' . ltrim($path, '/');
// Fallback
if ($path === '') {
$path = '/';
}
// echo'<br>BASH PATH: ' . base_url();
// echo'<br>ACL RAW PATH: ' . $fullPath;
// echo'<br>ACL BASE PATH: ' . $basePath;
// echo'<br>ACL FINAL PATH: ' . $path;
// ===================== LOAD ACL =====================
$acl = new Acl();
$rules = $acl->rules;
// print_rr($rules);die;
// ===================== MATCH RULE =====================
$matchedRule = null;
foreach ($rules as $pattern => $rule) {
// echo "$pattern".'---------<br>';
if (preg_match($pattern, $path)) {
// echo "matched - $pattern";
$matchedRule = $rule;
break; // FIRST MATCH WINS
}
}
// print_r($matchedRule);//die;
// ===================== NO RULE = DENY =====================
if ($matchedRule === null) {
return $this->deny($path, 'No ACL rule matched');
}
// ===================== PUBLIC ROUTE =====================
if (!empty($matchedRule['public'])) {
return; // ALLOW
}
// ===================== AUTH CHECK =====================
if (!check_session()) {
// For API requests return 401 JSON
if ($request->isAJAX() || str_starts_with($path, '/api') || str_starts_with($path, '/employeeRest')) {
return service('response')
->setStatusCode(401)
->setJSON(['error' => 'Unauthorized Resource Access']);
}
// For web redirect to login
return AuthLogout::logout();
}
// ===================== GET USER CONTEXT =====================
$userRole = check_role(); //
$userTeams = user_team(); // must return array of TEAM IDs
$allowedRoles = $matchedRule['roles'] ?? [];
$allowedTeams = $matchedRule['teams'] ?? [];
// ===================== ROLE FIRST =====================
if (!empty($allowedRoles) && in_array((int)$userRole, $allowedRoles, true)) {
return; // ALLOW
}
// ===================== TEAM FALLBACK =====================
if (!empty($allowedTeams) && is_array($userTeams)) {
foreach ($userTeams as $teamId) {
if (in_array($teamId, $allowedTeams, true)) {
return; // ALLOW
}
}
}
// ===================== DENY =====================
return $this->deny($path, 'Role/Team not permitted');
}
public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
{
// nothing
}
// ===================== DENY HANDLER =====================
protected function deny(string $path, string $reason)
{
log_message('error', 'ACL BLOCKED: {user} {path} - {reason}', [
'user' => session()->get('userid') ?? 'guest',
'path' => $path,
'reason' => $reason,
]);
// API / AJAX → JSON
$request = service('request');
if ($request->isAJAX() || str_starts_with($path, '/api') || str_starts_with($path, '/employeeRest')) {
return service('response')
->setStatusCode(403)
->setJSON([
'error' => 'Forbidden',
'message' => 'You do not have permission to access this resource'
]);
}
$response = service('response');
$response->setStatusCode(403);
$response->setBody(view('errors/403', [
'message' => '403 Access denied - You do not have permission to access this resource'
]));
return $response;
// Web → nice 403 page or simple text
return service('response')
->setStatusCode(403)
->setBody('403 Forbidden - Access denied - You do not have permission to access this resource');
}
}