157 lines
5.2 KiB
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']);
|
|
}
|
|
|
|
// 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/404', [
|
|
'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');
|
|
}
|
|
}
|