prepare("SELECT id, name, email, role, two_factor_enabled, created_at FROM users WHERE id = ?"); $stmtUser->execute([$stateUserId]); $recoveredUser = $stmtUser->fetch(); if ($recoveredUser) { $_SESSION['user_id'] = $recoveredUser['id']; $_SESSION['user_name'] = $recoveredUser['name']; $_SESSION['user_email'] = $recoveredUser['email']; $_SESSION['user_role'] = $recoveredUser['role']; $_SESSION['is_2fa_verified'] = true; $_SESSION['auth_date'] = date('Y-m-d'); $_SESSION['session_expires_at'] = strtotime('today 23:59:59'); clear_remember_cookie(); } } catch (Throwable $e) { // Foutafhandeling } } // 2. Controleer authenticatie $user = get_logged_in_user(); if (!$user) { header('Location: /auth/login.php?error=' . urlencode('Sessie verlopen tijdens Microsoft koppeling. Log opnieuw in en probeer het nogmaals.')); exit; } $db = get_db_connection(); // 3. Foutafhandeling vanuit Microsoft (bijv. gebruiker weigerde machtiging) if (!empty($_GET['error'])) { $errorDescription = $_GET['error_description'] ?? $_GET['error']; header('Location: /profile.php?error=' . urlencode("Microsoft melding: {$errorDescription}")); exit; } // 3b. Afhandeling van beheerderstoestemming (Admin Consent) // Microsoft stuurt bij het /adminconsent endpoint geen state mee, enkel ?admin_consent=True&tenant=... if (!empty($_GET['admin_consent'])) { header('Location: /admin.php?success=' . urlencode('Beheerdersgoedkeuring voor uw organisatie is succesvol verleend! U en uw collega\'s kunnen nu direct hun Outlook agenda en e-mail koppelen via Fociz.')); exit; } // 4. Valideer de state (via HMAC handtekening of fallback sessiestate) $expectedState = $_SESSION['ms_oauth_state'] ?? ''; unset($_SESSION['ms_oauth_state'], $_SESSION['ms_oauth_user_id']); if (!$stateUserId && (empty($receivedState) || empty($expectedState) || !hash_equals($expectedState, $receivedState))) { header('Location: /profile.php?error=' . urlencode('Ongeldige sessie of CSRF-controle mislukt. Probeer opnieuw in te loggen via Microsoft.')); exit; } // 5. Autorisatiecode controleren $code = $_GET['code'] ?? ''; if (empty($code)) { header('Location: /profile.php?error=' . urlencode('Geen autorisatiecode ontvangen van Microsoft.')); exit; } // 4. Centrale instellingen ophalen $appConfig = microsoft_get_app_config(); $clientId = $appConfig['client_id']; $clientSecret = $appConfig['client_secret']; $tenantId = (!empty($appConfig['tenant_id']) && $appConfig['tenant_id'] !== 'common') ? $appConfig['tenant_id'] : 'planningsagenda.nl'; 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.')); exit; } $redirectUri = rtrim(APP_URL, '/') . '/auth/callback_microsoft.php'; // 5. Code omwisselen voor access & refresh tokens $tokenResult = microsoft_exchange_code($code, $clientId, $clientSecret, $redirectUri, $tenantId); if (!$tokenResult['success']) { header('Location: /profile.php?error=' . urlencode('Token uitwisseling mislukt: ' . $tokenResult['error'])); exit; } $accessToken = $tokenResult['access_token']; $refreshToken = $tokenResult['refresh_token']; $expiresIn = $tokenResult['expires_in']; $expiresAt = time() + $expiresIn; // 6. Microsoft gebruikersprofiel ophalen $profile = microsoft_get_user_profile($accessToken); $accountEmail = $profile['mail'] ?? ($profile['userPrincipalName'] ?? $user['email']); $accountName = $profile['displayName'] ?? 'Microsoft 365 Account'; // 7. Opslaan in MariaDB $stmtExisting = $db->prepare("SELECT settings FROM integrations WHERE user_id = ? AND provider = 'OUTLOOK'"); $stmtExisting->execute([$user['id']]); $existingRow = $stmtExisting->fetch(); $existingSettings = json_decode($existingRow['settings'] ?? '{}', true) ?: []; $newSettings = array_merge($existingSettings, [ 'expires_at' => $expiresAt, 'account_email' => $accountEmail, 'account_name' => $accountName, ]); // Als de ingelogde gebruiker Beheerder (ADMIN) is, bewaren we ook de centrale app credentials if ($user['role'] === 'ADMIN') { $newSettings['client_id'] = $clientId; $newSettings['client_secret'] = $clientSecret; $newSettings['tenant_id'] = $tenantId; } $saveStmt = $db->prepare(" INSERT INTO integrations (user_id, provider, is_enabled, is_demo_mode, access_token, refresh_token, settings, last_sync_at) VALUES (?, 'OUTLOOK', 1, 0, ?, ?, ?, NOW()) ON DUPLICATE KEY UPDATE is_enabled = 1, is_demo_mode = 0, access_token = VALUES(access_token), refresh_token = VALUES(refresh_token), settings = VALUES(settings), last_sync_at = NOW() "); $saveStmt->execute([$user['id'], $accessToken, $refreshToken, json_encode($newSettings)]); // 8. Succesvol terugkeren naar de gewenste pagina of het Persoonlijk Profiel $returnTo = $_SESSION['ms_oauth_return_to'] ?? '/profile.php'; unset($_SESSION['ms_oauth_return_to']); $redirectUrl = ($returnTo === '/mail.php') ? '/mail.php?success=' . urlencode("Microsoft Outlook 365 e-mail & agenda succesvol gekoppeld als {$accountEmail}!") : '/profile.php?success=' . urlencode("Microsoft Outlook succesvol gekoppeld als {$accountEmail}!"); header('Location: ' . $redirectUrl); exit;