agent foundation
This commit is contained in:
@@ -9,6 +9,8 @@ use MintyPHP\Service\Auth\ApiTokenService;
|
||||
use MintyPHP\Service\Auth\AuthScopeGateway;
|
||||
use MintyPHP\Service\User\UserTenantContextService;
|
||||
|
||||
// Static facade for API authentication — state is set once per request during ApiBootstrap::init().
|
||||
// Dependencies are injected as lazy resolvers so services are only instantiated when actually needed.
|
||||
class ApiAuth
|
||||
{
|
||||
/** @var (callable(): AuthScopeGateway)|null */
|
||||
@@ -58,6 +60,7 @@ class ApiAuth
|
||||
{
|
||||
$header = trim((string) ($_SERVER['HTTP_AUTHORIZATION'] ?? ''));
|
||||
if ($header === '') {
|
||||
// Nginx with PHP-FPM may expose the header under this key instead
|
||||
$header = trim((string) ($_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ?? ''));
|
||||
}
|
||||
if ($header === '' || stripos($header, 'Bearer ') !== 0) {
|
||||
@@ -100,9 +103,11 @@ class ApiAuth
|
||||
$roleIds = $userRoleRepository->listRoleIdsByUserId($userId);
|
||||
$permissions = $rolePermissionRepository->listPermissionKeysByRoleIds($roleIds);
|
||||
|
||||
// Resolve tenant context
|
||||
// Resolve tenant context: a token may be scoped to a specific tenant,
|
||||
// otherwise fall back to the user's active tenant context.
|
||||
$tokenTenantId = $result['tenant_id'];
|
||||
if ($tokenTenantId !== null) {
|
||||
// Verify the token's tenant is still assigned to this user
|
||||
$userTenantIds = $scopeGateway->getUserTenantIds($userId);
|
||||
if (!in_array($tokenTenantId, $userTenantIds, true)) {
|
||||
return false;
|
||||
@@ -153,11 +158,14 @@ class ApiAuth
|
||||
return $decision->isAllowed();
|
||||
}
|
||||
|
||||
// Effective tenant for data filtering — may come from token scope or user session.
|
||||
public static function tenantId(): ?int
|
||||
{
|
||||
return self::$currentTenantId;
|
||||
}
|
||||
|
||||
// Non-null only when the token itself was issued for a specific tenant.
|
||||
// Used to restrict access in token-scoped requests (e.g. tenant integrations).
|
||||
public static function scopedTenantId(): ?int
|
||||
{
|
||||
return self::$tokenTenantId;
|
||||
@@ -204,6 +212,7 @@ class ApiAuth
|
||||
|
||||
$scopeGateway = self::scopeGateway();
|
||||
if (!$scopeGateway->resourceBelongsToTenant($resource, $resourceId, $tenantId)) {
|
||||
// 404 instead of 403 — don't reveal that the resource exists in another tenant
|
||||
ApiResponse::notFound();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user