Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions src/Models/Service.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use DreamFactory\Core\Events\ServiceDeletedEvent;
use DreamFactory\Core\Events\ServiceModifiedEvent;
use DreamFactory\Core\Exceptions\BadRequestException;
use DreamFactory\Core\Utility\Session;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Arr;
use ServiceManager;
Expand Down Expand Up @@ -280,4 +281,95 @@ protected static function cleanResult($response, $fields)

return $response;
}

/**
* Override selectByRequest to apply RBAC filtering for API docs
*
* @param array $criteria
* @param array $options
* @return mixed
*/
public static function selectByRequest(array $criteria = [], array $options = [])
{
$condition = array_get($criteria, 'condition', '');
$params = array_get($criteria, 'params', []);

// Detect different types of service listing requests that should be filtered by RBAC

// 1. API Docs Request: filtering for non-swagger services
$isApiDocsRequest = (
(strpos(strtolower($condition), 'type') !== false && strpos(strtolower($condition), 'not like') !== false) ||
(strpos($condition, '`type`') !== false && strpos($condition, 'NOT LIKE') !== false)
) && (
!empty($params) && is_array($params) &&
count(array_filter($params, function($p) { return strpos($p, 'swagger') !== false; })) > 0
);

// 2. Services Management Request: general service listing (no specific type filter or type IN filter)
$isServicesManagementRequest = (
empty($condition) || // No filter condition
(strpos($condition, 'type in') !== false) || // Type IN filter (service type filtering)
(strpos($condition, '`type` IN') !== false) // SQL formatted type IN filter
);

// 3. Database Services Request: filtering for database-related service types
$isDatabaseServicesRequest = !empty($params) && is_array($params) &&
count(array_filter($params, function($p) {
return in_array($p, ['mysql', 'sqlite', 'postgres', 'sqlserver', 'mongodb', 'cassandra', 'oracle', 'firebird']);
})) > 0;

// 4. Role Configuration Request: when configuring service access for roles
// This can be detected by checking if we're in a role management context
$isRoleConfigRequest = strpos($condition, 'is_active') !== false && empty($params);

// Apply RBAC filtering for non-admin users on any of these request types
$shouldApplyFiltering = ($isApiDocsRequest || $isServicesManagementRequest || $isDatabaseServicesRequest || $isRoleConfigRequest);

if ($shouldApplyFiltering && !Session::isSysAdmin()) {
// Get the current user's accessible services
$userServices = static::getUserAccessibleServices();

if (empty($userServices)) {
// User has no service access, return empty result
return [];
}

// Add service ID filter to criteria using parameterized queries
$placeholders = str_repeat('?,', count($userServices) - 1) . '?';
$existingCondition = array_get($criteria, 'condition', '');
$existingParams = array_get($criteria, 'params', []);

if (!empty($existingCondition)) {
$criteria['condition'] = $existingCondition . " and id in ($placeholders)";
} else {
$criteria['condition'] = "id in ($placeholders)";
}

// Merge the service IDs with existing parameters
$criteria['params'] = array_merge($existingParams, $userServices);
}

return parent::selectByRequest($criteria, $options);
}

/**
* Get service IDs that the current user has access to based on their role
*
* @return array
*/
protected static function getUserAccessibleServices()
{
$roleServices = (array)Session::get('role.services');
$accessibleServiceIds = [];

foreach ($roleServices as $serviceAccess) {
$serviceId = array_get($serviceAccess, 'service_id');
// Validate that service_id is a positive integer
if (!empty($serviceId) && is_numeric($serviceId) && $serviceId > 0 && !in_array($serviceId, $accessibleServiceIds)) {
$accessibleServiceIds[] = (int)$serviceId;
}
}

return $accessibleServiceIds;
}
}