feat: integrate ZYT admin with IAM Hub
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user