forked from ProcessMaker/processmaker
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathIsManager.php
More file actions
195 lines (160 loc) · 6.52 KB
/
IsManager.php
File metadata and controls
195 lines (160 loc) · 6.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
<?php
namespace ProcessMaker\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpFoundation\Response;
class IsManager
{
/**
* Handle an incoming request.
*
* @param Closure(Request): (Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
$user = $request->user();
if (!$user) {
return abort(401, 'Unauthenticated');
}
// if user is administrator, allow access
if ($user->is_administrator) {
return $next($request);
}
if (!Cache::get("user_{$user->id}_manager")) {
// if user is not manager, continue
return $next($request);
}
// get the required permissions for this specific URL
$requiredPermissions = $this->getRequiredPermissionsForRequest($request);
if (empty($requiredPermissions)) {
// if no required permissions, continue
return $next($request);
}
// simulate that the user has all the necessary permissions for this request
$this->simulateRequiredPermissionsForRequest($user, $requiredPermissions);
try {
// process the request - the internal endpoints will handle the permission validation
$response = $next($request);
// clean up the simulated permissions after processing the request
$this->cleanupSimulatedPermission($user);
return $response;
} catch (\Exception $e) {
// make sure to clean up the simulated permissions even if there is an exception
$this->cleanupSimulatedPermission($user);
throw $e;
}
}
/**
* Simula que el usuario tiene los permisos requeridos solo para esta solicitud
*/
private function simulateRequiredPermissionsForRequest($user, array $requiredPermissions)
{
try {
// get the current permissions of the user
$currentPermissions = $user->loadPermissions();
// filter only the permissions that the user does not have
$permissionsToAdd = array_diff($requiredPermissions, $currentPermissions);
if (empty($permissionsToAdd)) {
return;
}
// simulate the permissions by adding them temporarily to the cache of permissions
$cacheKey = "user_{$user->id}_permissions";
$simulatedPermissions = array_merge($currentPermissions, $permissionsToAdd);
// save in cache temporarily (only for this request)
// use a very short time to expire quickly if not cleaned manually
Cache::put($cacheKey, $simulatedPermissions, 5); // 5 segundos como fallback
} catch (\Exception $e) {
Log::error('IsManager middleware - Error simulating permissions: ' . $e->getMessage());
}
}
/**
* clean up the simulated permissions from the cache after processing the request
*/
private function cleanupSimulatedPermission($user)
{
try {
$cacheKey = "user_{$user->id}_permissions";
// delete the cache to force the reload of real permissions
Cache::forget($cacheKey);
} catch (\Exception $e) {
Log::error('IsManager middleware - Error cleaning up simulated permissions: ' . $e->getMessage());
}
}
/**
* get the required permissions for the current URL
*/
private function getRequiredPermissionsForRequest(Request $request): array
{
$permissions = [];
try {
$url = $request->fullUrl();
$path = $request->path();
$method = $request->method();
// first, get permissions from middlewares of the route
$middlewarePermissions = $this->getPermissionsFromMiddlewares($request);
$permissions = array_merge($permissions, $middlewarePermissions);
// then, get permissions based on URL patterns
$urlPermissions = $this->getPermissionsFromUrlPatterns($url, $path, $method);
$permissions = array_merge($permissions, $urlPermissions);
} catch (\Exception $e) {
Log::error('IsManager middleware - Error getting required permissions: ' . $e->getMessage());
}
return array_unique($permissions);
}
/**
* get permissions from the middlewares of the route
*/
private function getPermissionsFromMiddlewares(Request $request): array
{
$permissions = [];
try {
// get all the middlewares of the route
$middlewares = $request->route()->middleware();
// filter only the middlewares that contain 'can:'
$permissionMiddlewares = array_filter($middlewares, function ($middleware) {
return str_contains($middleware, 'can:');
});
// extract the permissions from each middleware
foreach ($permissionMiddlewares as $middleware) {
// format: "can:permission" or "can:permission,model"
if (preg_match('/can:([^,]+)/', $middleware, $matches)) {
$permissions[] = $matches[1];
}
}
} catch (\Exception $e) {
Log::error('IsManager middleware - Error getting permissions from middlewares: ' . $e->getMessage());
}
return $permissions;
}
/**
* get permissions based on URL patterns
*/
private function getPermissionsFromUrlPatterns(string $url, string $path, string $method): array
{
$permissions = [];
// for now we only support GET methods
if ($method !== 'GET') {
return $permissions;
}
try {
// URL patterns and their corresponding permissions
$urlPatterns = [
// patterns for users
'/api\/.*\/users(\?.*)?$/' => 'view-users',
// patterns for saved searches
'/api\/.*\/saved-searches\/columns(\?.*)?$/' => 'view-saved-searches-columns',
];
// check each pattern
foreach ($urlPatterns as $pattern => $permission) {
if (preg_match($pattern, $url)) {
$permissions[] = $permission;
}
}
} catch (\Exception $e) {
Log::error('IsManager middleware - Error getting permissions from URL patterns: ' . $e->getMessage());
}
return $permissions;
}
}