config = $config ?? (array) config('iam_hub'); } public function apply(string $body, string $signature, string $eventHeader): void { if (!(bool) ($this->config['enabled'] ?? false)) { throw new IamHubException('IAM Hub integration is disabled', 503); } $secret = (string) ($this->config['revocation_secret'] ?? ''); if (!IamSecurity::verifySignature($secret, $body, $signature)) { throw new IamHubException('invalid IAM Hub signature', 401); } $event = json_decode($body, true); if (!is_array($event)) { throw new IamHubException('invalid IAM Hub event JSON'); } $eventId = trim((string) ($event['id'] ?? '')); $subject = trim((string) ($event['oidcSubject'] ?? '')); $applications = $event['applicationIds'] ?? []; if ($eventId === '' || $subject === '' || !is_array($applications)) { throw new IamHubException('invalid IAM Hub event'); } if (!hash_equals($eventId, trim($eventHeader))) { throw new IamHubException('IAM Hub event ID header mismatch'); } if (!in_array((string) ($this->config['application_id'] ?? 'zyt'), $applications, true)) { throw new IamHubException('IAM Hub event is not addressed to this application', 403); } if (IamRevocationEvent::where('event_id', '=', $eventId)->find()) { return; } Db::startTrans(); try { $admin = Admin::where('iam_subject', '=', $subject)->find(); $status = 'admin_not_found'; $adminId = 0; if ($admin) { $adminId = (int) $admin->id; $admin->disable = 1; $admin->iam_revoked_at = time(); $admin->save(); $sessions = AdminSession::where('admin_id', '=', $adminId)->select()->toArray(); foreach ($sessions as $session) { AdminLogic::expireToken((string) $session['token']); } (new AdminAuthCache($adminId))->clearAuthCache(); $status = 'applied'; } IamRevocationEvent::create([ 'event_id' => $eventId, 'iam_subject' => $subject, 'admin_id' => $adminId, 'status' => $status, 'reason' => (string) ($event['reason'] ?? ''), 'payload' => $event, ]); Db::commit(); } catch (\Throwable $error) { Db::rollback(); throw $error; } } }