Resolve recommended-profile Critical and High findings, retain narrow analyzer exceptions, and update the edge-broker WebSocket dependency to a non-vulnerable release.
115 lines
3.6 KiB
PHP
115 lines
3.6 KiB
PHP
<?php
|
|
|
|
namespace classes;
|
|
|
|
require_once WD . '/modules/entra/entra_c.php';
|
|
|
|
use entra\entra_c;
|
|
|
|
|
|
class entra
|
|
{
|
|
/**
|
|
* Configuration of the Entra module
|
|
* @var entra_c
|
|
*/
|
|
public entra_c $config;
|
|
|
|
public function __construct()
|
|
{
|
|
$this->config = new entra_c();
|
|
}
|
|
|
|
public function get_users(bool $array = false): array
|
|
{
|
|
$accessToken = $this->requestAccessToken();
|
|
$usersResponse = $this->requestJson(
|
|
'https://graph.microsoft.com/v1.0/users?$select=id,displayName,mail,userPrincipalName',
|
|
['Authorization: Bearer ' . $accessToken]
|
|
);
|
|
$users = is_array($usersResponse['value'] ?? null) ? $usersResponse['value'] : [];
|
|
if (!$array) {
|
|
return $users;
|
|
}
|
|
|
|
$result = [];
|
|
foreach ($users as $user) {
|
|
if (!is_array($user)) {
|
|
continue;
|
|
}
|
|
$result[] = [
|
|
'id' => $user['id'] ?? null,
|
|
'displayName' => $user['displayName'] ?? null,
|
|
'mail' => $user['mail'] ?? null,
|
|
'userPrincipalName' => $user['userPrincipalName'] ?? null,
|
|
];
|
|
}
|
|
return $result;
|
|
}
|
|
|
|
private function requestAccessToken(): string
|
|
{
|
|
$tenantId = trim((string)$this->config->tenant_id->getVariableValue());
|
|
$response = $this->requestJson(
|
|
'https://login.microsoftonline.com/' . rawurlencode($tenantId) . '/oauth2/v2.0/token',
|
|
['Content-Type: application/x-www-form-urlencoded'],
|
|
http_build_query([
|
|
'client_id' => (string)$this->config->client_id->getVariableValue(),
|
|
'client_secret' => (string)$this->config->client_secret->getVariableValue(),
|
|
'scope' => 'https://graph.microsoft.com/.default',
|
|
'grant_type' => 'client_credentials',
|
|
])
|
|
);
|
|
|
|
$token = trim((string)($response['access_token'] ?? ''));
|
|
if ($token === '') {
|
|
throw new \RuntimeException('Microsoft Entra token response did not contain an access token.');
|
|
}
|
|
|
|
return $token;
|
|
}
|
|
|
|
/**
|
|
* @param list<string> $headers
|
|
* @return array<string,mixed>
|
|
*/
|
|
private function requestJson(string $url, array $headers, ?string $postFields = null): array
|
|
{
|
|
$curl = curl_init($url);
|
|
if ($curl === false) {
|
|
throw new \RuntimeException('Unable to initialize Microsoft Entra request.');
|
|
}
|
|
|
|
curl_setopt_array($curl, [
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_CONNECTTIMEOUT => 5,
|
|
CURLOPT_TIMEOUT => 20,
|
|
CURLOPT_HTTPHEADER => $headers,
|
|
]);
|
|
if ($postFields !== null) {
|
|
curl_setopt($curl, CURLOPT_POST, true);
|
|
curl_setopt($curl, CURLOPT_POSTFIELDS, $postFields);
|
|
}
|
|
|
|
try {
|
|
$body = curl_exec($curl);
|
|
$status = (int)curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
|
|
if ($body === false) {
|
|
throw new \RuntimeException('Microsoft Entra request failed: ' . curl_error($curl));
|
|
}
|
|
} finally {
|
|
curl_close($curl);
|
|
}
|
|
|
|
$decoded = json_decode((string)$body, true);
|
|
if ($status < 200 || $status >= 300 || !is_array($decoded)) {
|
|
$message = is_array($decoded)
|
|
? (string)($decoded['error_description'] ?? $decoded['error']['message'] ?? 'Unexpected response')
|
|
: 'Invalid JSON response';
|
|
throw new \RuntimeException('Microsoft Entra request failed with HTTP ' . $status . ': ' . $message);
|
|
}
|
|
|
|
return $decoded;
|
|
}
|
|
}
|