Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5af4f9bdc2 | |||
| bc1537be0c |
@@ -32,8 +32,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
if ($action === 'save_azure') {
|
if ($action === 'save_azure') {
|
||||||
$clientId = trim($_POST['client_id'] ?? '');
|
$clientId = trim($_POST['client_id'] ?? '');
|
||||||
$clientSecret = trim($_POST['client_secret'] ?? '');
|
$clientSecret = trim($_POST['client_secret'] ?? '');
|
||||||
$tenantId = trim($_POST['tenant_id'] ?? 'common');
|
$tenantId = trim($_POST['tenant_id'] ?? '');
|
||||||
if (empty($tenantId)) $tenantId = 'common';
|
if (empty($tenantId) || $tenantId === 'common') {
|
||||||
|
$tenantId = 'planningsagenda.nl';
|
||||||
|
}
|
||||||
$isDemo = isset($_POST['is_demo_mode']) ? 1 : 0;
|
$isDemo = isset($_POST['is_demo_mode']) ? 1 : 0;
|
||||||
|
|
||||||
$stmtExisting = $db->prepare("SELECT * FROM integrations WHERE user_id = ? AND provider = 'OUTLOOK'");
|
$stmtExisting = $db->prepare("SELECT * FROM integrations WHERE user_id = ? AND provider = 'OUTLOOK'");
|
||||||
@@ -284,10 +286,10 @@ require_once __DIR__ . '/includes/header.php';
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-xs font-semibold text-slate-300 mb-1.5">
|
<label class="block text-xs font-semibold text-slate-300 mb-1.5">
|
||||||
Directory (Tenant) ID
|
Directory (Tenant) ID / Domeinnaam
|
||||||
</label>
|
</label>
|
||||||
<input type="text" name="tenant_id" value="<?= htmlspecialchars($appConfig['tenant_id']) ?>" placeholder="common of uwbedrijf.nl" class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3.5 py-2.5 text-xs text-white placeholder-slate-600 focus:outline-none focus:border-blue-500">
|
<input type="text" name="tenant_id" value="<?= htmlspecialchars((!empty($appConfig['tenant_id']) && $appConfig['tenant_id'] !== 'common') ? $appConfig['tenant_id'] : 'planningsagenda.nl') ?>" placeholder="bijv. planningsagenda.nl of Azure Tenant GUID" class="w-full bg-slate-950 border border-slate-800 rounded-xl px-3.5 py-2.5 text-xs text-white placeholder-slate-600 focus:outline-none focus:border-blue-500 font-mono">
|
||||||
<span class="text-[10px] text-slate-500 mt-1 block">Gebruik <code class="text-blue-400">common</code> of uw specifieke domeinnaam (bijv. planningsagenda.nl)</span>
|
<span class="text-[10px] text-slate-400 mt-1 block">Vul uw domeinnaam in (<code class="text-emerald-400 font-mono">planningsagenda.nl</code>) of de Directory (tenant) ID uit Azure. <em>Let op: Gebruik géén 'common' voor single-tenant apps.</em></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ $appConfig = microsoft_get_app_config();
|
|||||||
|
|
||||||
$clientId = $appConfig['client_id'];
|
$clientId = $appConfig['client_id'];
|
||||||
$clientSecret = $appConfig['client_secret'];
|
$clientSecret = $appConfig['client_secret'];
|
||||||
$tenantId = $appConfig['tenant_id'];
|
$tenantId = (!empty($appConfig['tenant_id']) && $appConfig['tenant_id'] !== 'common') ? $appConfig['tenant_id'] : 'planningsagenda.nl';
|
||||||
|
|
||||||
if (empty($clientId) || empty($clientSecret)) {
|
if (empty($clientId) || empty($clientSecret)) {
|
||||||
header('Location: /profile.php?error=' . urlencode('Microsoft 365 configuratie (Client ID of Secret) ontbreekt in Fociz. Neem contact op met de beheerder.'));
|
header('Location: /profile.php?error=' . urlencode('Microsoft 365 configuratie (Client ID of Secret) ontbreekt in Fociz. Neem contact op met de beheerder.'));
|
||||||
|
|||||||
@@ -15,6 +15,18 @@ $appConfig = microsoft_get_app_config();
|
|||||||
$clientId = !empty($_GET['client_id']) ? trim($_GET['client_id']) : $appConfig['client_id'];
|
$clientId = !empty($_GET['client_id']) ? trim($_GET['client_id']) : $appConfig['client_id'];
|
||||||
$tenantId = !empty($_GET['tenant_id']) ? trim($_GET['tenant_id']) : $appConfig['tenant_id'];
|
$tenantId = !empty($_GET['tenant_id']) ? trim($_GET['tenant_id']) : $appConfig['tenant_id'];
|
||||||
|
|
||||||
|
// Voorkom AADSTS50194: single-tenant Azure applicaties mogen NOOIT het /common endpoint gebruiken
|
||||||
|
if (empty($tenantId) || $tenantId === 'common') {
|
||||||
|
$userEmail = $user['email'] ?? '';
|
||||||
|
$parts = explode('@', $userEmail);
|
||||||
|
$domain = strtolower(trim(end($parts)));
|
||||||
|
if (!empty($domain) && !in_array($domain, ['gmail.com', 'outlook.com', 'hotmail.com', 'live.com', 'yahoo.com', 'icloud.com'])) {
|
||||||
|
$tenantId = $domain;
|
||||||
|
} else {
|
||||||
|
$tenantId = 'planningsagenda.nl';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (empty($clientId)) {
|
if (empty($clientId)) {
|
||||||
$err = ($user['role'] === 'ADMIN')
|
$err = ($user['role'] === 'ADMIN')
|
||||||
? 'Vul eerst de Application (Client) ID en het Client Secret in bij het Systeembeheer om te koppelen met Microsoft 365.'
|
? 'Vul eerst de Application (Client) ID en het Client Secret in bij het Systeembeheer om te koppelen met Microsoft 365.'
|
||||||
|
|||||||
@@ -24,74 +24,100 @@ function microsoft_get_app_config(): array {
|
|||||||
$clientSecret = fociz_env('MICROSOFT_CLIENT_SECRET', '');
|
$clientSecret = fociz_env('MICROSOFT_CLIENT_SECRET', '');
|
||||||
$tenantId = fociz_env('MICROSOFT_TENANT_ID', '');
|
$tenantId = fociz_env('MICROSOFT_TENANT_ID', '');
|
||||||
|
|
||||||
if (empty($clientId) || empty($clientSecret)) {
|
try {
|
||||||
try {
|
$db = get_db_connection();
|
||||||
$db = get_db_connection();
|
$adminOrgDomain = '';
|
||||||
// Zoek bij actieve beheerder(s) in de integrations tabel
|
|
||||||
$stmt = $db->query("
|
// Zoek bij actieve beheerder(s) in de integrations tabel
|
||||||
SELECT i.settings
|
$stmt = $db->query("
|
||||||
FROM integrations i
|
SELECT i.settings, u.email as admin_email
|
||||||
JOIN users u ON i.user_id = u.id
|
FROM integrations i
|
||||||
WHERE u.role = 'ADMIN' AND i.provider = 'OUTLOOK' AND i.settings IS NOT NULL
|
JOIN users u ON i.user_id = u.id
|
||||||
ORDER BY i.updated_at DESC
|
WHERE u.role = 'ADMIN' AND i.provider = 'OUTLOOK' AND i.settings IS NOT NULL
|
||||||
LIMIT 5
|
ORDER BY i.updated_at DESC
|
||||||
|
LIMIT 5
|
||||||
|
");
|
||||||
|
$rows = $stmt->fetchAll();
|
||||||
|
foreach ($rows as $row) {
|
||||||
|
if (!empty($row['admin_email']) && empty($adminOrgDomain)) {
|
||||||
|
$emailParts = explode('@', $row['admin_email']);
|
||||||
|
$domain = strtolower(trim(end($emailParts)));
|
||||||
|
if (!in_array($domain, ['gmail.com', 'outlook.com', 'hotmail.com', 'live.com', 'yahoo.com', 'icloud.com'])) {
|
||||||
|
$adminOrgDomain = $domain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!empty($row['settings'])) {
|
||||||
|
$saved = json_decode($row['settings'], true) ?: [];
|
||||||
|
if (empty($clientId) && !empty($saved['client_id'])) {
|
||||||
|
$clientId = trim($saved['client_id']);
|
||||||
|
}
|
||||||
|
if (empty($clientSecret) && !empty($saved['client_secret'])) {
|
||||||
|
$clientSecret = trim($saved['client_secret']);
|
||||||
|
}
|
||||||
|
if ((empty($tenantId) || $tenantId === 'common') && !empty($saved['tenant_id']) && $saved['tenant_id'] !== 'common') {
|
||||||
|
$tenantId = trim($saved['tenant_id']);
|
||||||
|
}
|
||||||
|
if (!empty($clientId) && !empty($clientSecret) && !empty($tenantId) && $tenantId !== 'common') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: zoek een willekeurige OUTLOOK rij met ingevulde client_id
|
||||||
|
if (empty($clientId) || empty($clientSecret) || empty($tenantId) || $tenantId === 'common') {
|
||||||
|
$stmtFallback = $db->query("
|
||||||
|
SELECT settings
|
||||||
|
FROM integrations
|
||||||
|
WHERE provider = 'OUTLOOK' AND settings LIKE '%client_id%'
|
||||||
|
ORDER BY updated_at DESC
|
||||||
|
LIMIT 3
|
||||||
");
|
");
|
||||||
$rows = $stmt->fetchAll();
|
$fallbackRows = $stmtFallback->fetchAll();
|
||||||
foreach ($rows as $row) {
|
foreach ($fallbackRows as $fbRow) {
|
||||||
if (!empty($row['settings'])) {
|
if (!empty($fbRow['settings'])) {
|
||||||
$saved = json_decode($row['settings'], true) ?: [];
|
$saved = json_decode($fbRow['settings'], true) ?: [];
|
||||||
if (empty($clientId) && !empty($saved['client_id'])) {
|
if (empty($clientId) && !empty($saved['client_id'])) {
|
||||||
$clientId = trim($saved['client_id']);
|
$clientId = trim($saved['client_id']);
|
||||||
}
|
}
|
||||||
if (empty($clientSecret) && !empty($saved['client_secret'])) {
|
if (empty($clientSecret) && !empty($saved['client_secret'])) {
|
||||||
$clientSecret = trim($saved['client_secret']);
|
$clientSecret = trim($saved['client_secret']);
|
||||||
}
|
}
|
||||||
if (empty($tenantId) && !empty($saved['tenant_id'])) {
|
if ((empty($tenantId) || $tenantId === 'common') && !empty($saved['tenant_id']) && $saved['tenant_id'] !== 'common') {
|
||||||
$tenantId = trim($saved['tenant_id']);
|
$tenantId = trim($saved['tenant_id']);
|
||||||
}
|
}
|
||||||
if (!empty($clientId) && !empty($clientSecret)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback: zoek een willekeurige OUTLOOK rij met ingevulde client_id
|
|
||||||
if (empty($clientId) || empty($clientSecret)) {
|
|
||||||
$stmtFallback = $db->query("
|
|
||||||
SELECT settings
|
|
||||||
FROM integrations
|
|
||||||
WHERE provider = 'OUTLOOK' AND settings LIKE '%client_id%'
|
|
||||||
ORDER BY updated_at DESC
|
|
||||||
LIMIT 3
|
|
||||||
");
|
|
||||||
$fallbackRows = $stmtFallback->fetchAll();
|
|
||||||
foreach ($fallbackRows as $fbRow) {
|
|
||||||
if (!empty($fbRow['settings'])) {
|
|
||||||
$saved = json_decode($fbRow['settings'], true) ?: [];
|
|
||||||
if (empty($clientId) && !empty($saved['client_id'])) {
|
|
||||||
$clientId = trim($saved['client_id']);
|
|
||||||
}
|
|
||||||
if (empty($clientSecret) && !empty($saved['client_secret'])) {
|
|
||||||
$clientSecret = trim($saved['client_secret']);
|
|
||||||
}
|
|
||||||
if (empty($tenantId) && !empty($saved['tenant_id'])) {
|
|
||||||
$tenantId = trim($saved['tenant_id']);
|
|
||||||
}
|
|
||||||
if (!empty($clientId) && !empty($clientSecret)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Throwable $e) {
|
|
||||||
error_log("microsoft_get_app_config error: " . $e->getMessage());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Als tenantId nog leeg of 'common' is, leid het domein af van de beheerder
|
||||||
|
if (empty($tenantId) || $tenantId === 'common') {
|
||||||
|
if (empty($adminOrgDomain)) {
|
||||||
|
$firstAdminEmail = $db->query("SELECT email FROM users WHERE role = 'ADMIN' ORDER BY id ASC LIMIT 1")->fetchColumn();
|
||||||
|
if ($firstAdminEmail) {
|
||||||
|
$parts = explode('@', $firstAdminEmail);
|
||||||
|
$domain = strtolower(trim(end($parts)));
|
||||||
|
if (!in_array($domain, ['gmail.com', 'outlook.com', 'hotmail.com', 'live.com', 'yahoo.com', 'icloud.com'])) {
|
||||||
|
$adminOrgDomain = $domain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!empty($adminOrgDomain)) {
|
||||||
|
$tenantId = $adminOrgDomain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
error_log("microsoft_get_app_config error: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default tenantId voor de organisatie
|
||||||
|
if (empty($tenantId) || $tenantId === 'common') {
|
||||||
|
$tenantId = 'planningsagenda.nl';
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'client_id' => $clientId ?: '',
|
'client_id' => $clientId ?: '',
|
||||||
'client_secret' => $clientSecret ?: '',
|
'client_secret' => $clientSecret ?: '',
|
||||||
'tenant_id' => !empty($tenantId) ? $tenantId : 'common',
|
'tenant_id' => $tenantId,
|
||||||
'is_configured' => !empty($clientId) && !empty($clientSecret),
|
'is_configured' => !empty($clientId) && !empty($clientSecret),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -99,8 +125,8 @@ function microsoft_get_app_config(): array {
|
|||||||
/**
|
/**
|
||||||
* Genereert de Microsoft OAuth2 login URL
|
* Genereert de Microsoft OAuth2 login URL
|
||||||
*/
|
*/
|
||||||
function microsoft_get_auth_url(string $clientId, string $redirectUri, string $tenantId = 'common', string $state = ''): string {
|
function microsoft_get_auth_url(string $clientId, string $redirectUri, string $tenantId = '', string $state = ''): string {
|
||||||
$tenant = !empty($tenantId) ? trim($tenantId) : 'common';
|
$tenant = (!empty($tenantId) && $tenantId !== 'common') ? trim($tenantId) : 'planningsagenda.nl';
|
||||||
$baseUrl = sprintf(MS_OAUTH_AUTHORIZE_URL, urlencode($tenant));
|
$baseUrl = sprintf(MS_OAUTH_AUTHORIZE_URL, urlencode($tenant));
|
||||||
|
|
||||||
$params = [
|
$params = [
|
||||||
@@ -119,8 +145,8 @@ function microsoft_get_auth_url(string $clientId, string $redirectUri, string $t
|
|||||||
/**
|
/**
|
||||||
* Wisselt de ontvangen autorisatiecode om voor access- en refresh tokens
|
* Wisselt de ontvangen autorisatiecode om voor access- en refresh tokens
|
||||||
*/
|
*/
|
||||||
function microsoft_exchange_code(string $code, string $clientId, string $clientSecret, string $redirectUri, string $tenantId = 'common'): array {
|
function microsoft_exchange_code(string $code, string $clientId, string $clientSecret, string $redirectUri, string $tenantId = ''): array {
|
||||||
$tenant = !empty($tenantId) ? trim($tenantId) : 'common';
|
$tenant = (!empty($tenantId) && $tenantId !== 'common') ? trim($tenantId) : 'planningsagenda.nl';
|
||||||
$tokenUrl = sprintf(MS_OAUTH_TOKEN_URL, urlencode($tenant));
|
$tokenUrl = sprintf(MS_OAUTH_TOKEN_URL, urlencode($tenant));
|
||||||
|
|
||||||
$payload = [
|
$payload = [
|
||||||
@@ -210,7 +236,8 @@ function microsoft_get_valid_token(int $userId): ?string {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$tokenUrl = sprintf(MS_OAUTH_TOKEN_URL, urlencode(!empty($tenantId) ? $tenantId : 'common'));
|
$cleanTenant = (!empty($tenantId) && $tenantId !== 'common') ? $tenantId : 'planningsagenda.nl';
|
||||||
|
$tokenUrl = sprintf(MS_OAUTH_TOKEN_URL, urlencode($cleanTenant));
|
||||||
$payload = [
|
$payload = [
|
||||||
'client_id' => $clientId,
|
'client_id' => $clientId,
|
||||||
'client_secret' => $clientSecret,
|
'client_secret' => $clientSecret,
|
||||||
|
|||||||
Reference in New Issue
Block a user