84 lines
3.0 KiB
PHP
84 lines
3.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace app\common\service\iam;
|
|
|
|
use app\adminapi\logic\auth\AdminLogic;
|
|
use app\common\cache\AdminAuthCache;
|
|
use app\common\model\auth\Admin;
|
|
use app\common\model\auth\AdminSession;
|
|
use app\common\model\iam\IamRevocationEvent;
|
|
use think\facade\Db;
|
|
|
|
class IamRevocationService
|
|
{
|
|
private array $config;
|
|
|
|
public function __construct(?array $config = null)
|
|
{
|
|
$this->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;
|
|
}
|
|
}
|
|
}
|