Improved jwt logic

* No longer stores full token, but only payload.
This commit is contained in:
Chris 2024-03-11 22:29:17 +01:00
parent 99b5710c59
commit 0513ab0999
5 changed files with 33 additions and 32 deletions

View File

@ -34,24 +34,24 @@ $ ./mercureact.phar -c mercureact.conf
## ToDos
* [ ] Read config from file
* [x] Read config from file
* [ ] Security Security Security
* [x] Check JWTs on connect
* [x] Check claims on subscribe and publish
* [ ] WebSocket authentication
* [ ] Extract JWT claims to request attributes, instead of JWTToken
* [x] Extract JWT claims to request attributes, instead of JWTToken
* [x] Subscription/Topic manager
* [x] Unify distribution
* [ ] Enumerate subscriptions and topics
* [x] Enumerate subscriptions and topics
* [x] Publish events
* [x] Server-Side Events distributor
* [x] Distribute events over SSE
* [ ] WebSocket distributor
* [ ] WebSocket authentication
* [ ] Setup subscriptions
* [ ] Dynamic subscriptions
* [x] Distribute events over WS
* [x] Break out HTTP middleware into classes
* [ ] HTTP middleware unittests
* [ ] Replay missed events based on event id
* [ ] Figure out how to determine last event IDs
* [x] Figure out how to determine last event IDs
* [ ] Metrics endpoint

View File

@ -26,7 +26,12 @@ class SseSubscriber implements SubscriberInterface
public function isAuthorized(): bool
{
return $this->request->getAttribute('authorization') instanceof JWTToken;
return $this->request->getAttribute('authorized');
}
public function getPayload(): array
{
return $this->request->getAttribute('mercure.payload')??[];
}
public function getId(): string

View File

@ -69,7 +69,7 @@ class TopicManager
'topic' => $topic->getTopic(),
'subscriber' => $sub->getId(),
'active' => true,
'payload' => null, // TODO populate from mercure.payload in JWT
'payload' => $sub->getPayload(),
];
}
}

View File

@ -88,17 +88,13 @@ class MercureHandler
}
// Grab the JWT token from the requests authorization attribute
$tok = $request->getAttribute('authorization');
if ($tok instanceof JWTToken) {
$claims = $tok->claims->getAll();
if (isset($claims['mercure']['subscribe'])) {
$subscribeClaims = $claims['mercure']['subscribe'];
if (!$this->checkTopicClaims($topics, $subscribeClaims)) {
throw new SecurityException(
message: "Insufficient permissions for subscribe",
code: SecurityException::ERR_NO_PERMISSION
);
}
if ($request->getAttribute('authorized')) {
$claims = $request->getAttribute('mercure.subscribe');
if (!$this->checkTopicClaims($topics, $claims)) {
throw new SecurityException(
message: "Insufficient permissions for subscribe",
code: SecurityException::ERR_NO_PERMISSION
);
}
} else {
// Disallow if we don't allow anonymous subscribers. Note that anonymous
@ -153,18 +149,14 @@ class MercureHandler
}
// Grab the JWT token from the requests authorization attribute
$tok = $request->getAttribute('authorization');
if ($tok instanceof JWTToken) {
$claims = $tok->claims->getAll();
if (isset($claims['mercure']['publish'])) {
$publishClaims = $claims['mercure']['publish'];
// check topic against publishClaims
if (!$this->checkTopicClaims($data['topic']??[], $publishClaims)) {
throw new SecurityException(
message: "Insufficient permissions for publish",
code: SecurityException::ERR_NO_PERMISSION
);
}
if ($request->getAttribute('authorized')) {
$claims = $request->getAttribute('mercure.publish');
// check topic against publishClaims
if (!$this->checkTopicClaims($data['topic']??[], $claims)) {
throw new SecurityException(
message: "Insufficient permissions for publish",
code: SecurityException::ERR_NO_PERMISSION
);
}
} else {
// reject if access denied

View File

@ -61,11 +61,15 @@ class SecurityMiddleware
code: SecurityException::ERR_ACCESS_DENIED
);
}
$claims = $tok->claims->getAll()['mercure']??[];
return $request
->withAttribute('authorization', $tok);
->withAttribute('mercure.publish', $claims['publish']??[])
->withAttribute('mercure.subscribe', $claims['subscribe']??[])
->withAttribute('mercure.payload', $claims['payload']??[])
->withAttribute('authorized', true);
} else {
return $request
->withAttribute('authorization', null);
->withAttribute('authorized', false);
}
}