Refactored out claim check logic to its own class

This commit is contained in:
2024-03-14 14:03:27 +01:00
parent e61d0abb5d
commit d8ae8ade70
6 changed files with 71 additions and 26 deletions

View File

@ -3,6 +3,7 @@
namespace NoccyLabs\Mercureact\Http\Middleware;
use NoccyLabs\Mercureact\Broker\Message;
use NoccyLabs\Mercureact\Broker\Security\ClaimChecker;
use NoccyLabs\Mercureact\Broker\Subscriber\SseSubscriber;
use NoccyLabs\Mercureact\Broker\TopicManager;
use NoccyLabs\Mercureact\Configuration;
@ -27,6 +28,8 @@ class MercureHandler
private int $seenIdHistorySize = 100;
private ClaimChecker $claimChecker;
public function __construct(
private Configuration $config,
private TopicManager $topicManager,
@ -35,6 +38,7 @@ class MercureHandler
{
$this->loop = $loop ?? Loop::get();
$this->seenIdHistorySize = $this->config->getDuplicateIdHistorySize();
$this->claimChecker = new ClaimChecker();
}
/**
@ -94,7 +98,7 @@ class MercureHandler
// Grab the JWT token from the requests authorization attribute
if ($request->getAttribute('authorized')) {
$claims = $request->getAttribute('mercure.subscribe');
if (!$this->checkTopicClaims($topics, $claims)) {
if (!$this->claimChecker->matchAll($topics, $claims)) {
throw new SecurityException(
message: "Insufficient permissions for subscribe",
code: SecurityException::ERR_NO_PERMISSION
@ -112,6 +116,7 @@ class MercureHandler
}
$this->topicManager->subscribe($subscriber, $topics);
$responseStream->on('close', function () use ($subscriber, $topics) {
$this->topicManager->unsubscribe($subscriber, $topics);
});
@ -156,7 +161,7 @@ class MercureHandler
if ($request->getAttribute('authorized')) {
$claims = $request->getAttribute('mercure.publish');
// check topic against publishClaims
if (!$this->checkTopicClaims($data['topic']??[], $claims)) {
if (!$this->claimChecker->matchAll($data['topic']??[], $claims)) {
throw new SecurityException(
message: "Insufficient permissions for publish",
code: SecurityException::ERR_NO_PERMISSION
@ -195,23 +200,4 @@ class MercureHandler
return Response::plaintext($message->id."\n");
}
private function checkTopicClaims(string|array $topic, array $claims): bool
{
$matched = 0;
foreach ((array)$topic as $match) {
foreach ($claims as $claim) {
if (($claim === "*") || ($claim === $match)) {
$matched++;
break;
}
// TODO make sure that UriTemplate parsing works
if ((new UriTemplate())->extract($claim, $match, true)) {
$matched++;
break;
}
}
}
return ($matched == count($topic));
}
}