More security logic
This commit is contained in:
15
TODO.md
15
TODO.md
@@ -4,3 +4,18 @@
|
||||
- [ ] JWT authentication
|
||||
- [ ] Access control on groups, slots and props
|
||||
- [ ] Token authentication
|
||||
- [ ] HTTPS support
|
||||
- [ ] Handle remaining CLI options
|
||||
- [ ] Message bus
|
||||
- [ ] Slot update notifications
|
||||
- [ ] Slot creation and deletion
|
||||
- [ ] Group update notifications
|
||||
- [ ] Group creation and deletion
|
||||
- [ ] Group join/leave
|
||||
- [ ] Triggers
|
||||
- [ ] Listen for messages on bus to trigger events
|
||||
- [ ] Dynamic trigger management (post, delete)
|
||||
- [ ] Schemas
|
||||
- [ ] Apply schemas to group
|
||||
- [ ] Apply schemas to slot
|
||||
- [ ] Check schemas on update
|
||||
|
||||
@@ -18,6 +18,7 @@ use SlotDb\SlotDb\Data\Group\Group;
|
||||
use SlotDb\SlotDb\Data\Schema\Schema;
|
||||
use SlotDb\SlotDb\Data\Slot\Slot;
|
||||
use SlotDb\SlotDb\Data\Slot\SlotRepository;
|
||||
use SlotDb\SlotDb\Security\AccessChecker;
|
||||
|
||||
class Daemon
|
||||
{
|
||||
@@ -57,8 +58,10 @@ class Daemon
|
||||
|
||||
$this->messageBus = new MessageBus();
|
||||
|
||||
$accessChecker = new AccessChecker();
|
||||
|
||||
$routes = new RouteCollection();
|
||||
$routes->addController(new Http\Controller\SlotsController($em->getRepository(Slot::class), $this->messageBus));
|
||||
$routes->addController(new Http\Controller\SlotsController($em->getRepository(Slot::class), $this->messageBus, $accessChecker));
|
||||
$routes->addController(new Http\Controller\GroupsController($em->getRepository(Group::class), $em->getRepository(Slot::class)));
|
||||
$routes->addController(new Http\Controller\SchemassController($em->getRepository(Schema::class)));
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ use SlotDb\SlotDb\Bus\MessageBus;
|
||||
use SlotDb\SlotDb\Data\Slot\Slot;
|
||||
use SlotDb\SlotDb\Data\Slot\SlotNotFoundException;
|
||||
use SlotDb\SlotDb\Data\Slot\SlotRepository;
|
||||
|
||||
use SlotDb\SlotDb\Security\AccessChecker;
|
||||
|
||||
class SlotsController extends Controller
|
||||
{
|
||||
@@ -17,6 +17,7 @@ class SlotsController extends Controller
|
||||
public function __construct(
|
||||
private readonly SlotRepository $slots,
|
||||
private readonly MessageBus $bus,
|
||||
private readonly AccessChecker $accessChecker,
|
||||
)
|
||||
{
|
||||
|
||||
@@ -60,6 +61,7 @@ class SlotsController extends Controller
|
||||
#[Route(path:"/api/slotdb/v1/slots", methods:["POST"])]
|
||||
public function createSlots(ServerRequestInterface $request)
|
||||
{
|
||||
|
||||
$data = json_decode($request->getBody());
|
||||
$slots = [];
|
||||
foreach ($data as $item) {
|
||||
@@ -87,6 +89,8 @@ class SlotsController extends Controller
|
||||
return Response::json([ 'error'=>"Slot not found" ])->withStatus(404);
|
||||
}
|
||||
|
||||
$acl = $request->getAttribute("acl");
|
||||
|
||||
return Response::json($slotObj);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,11 +9,57 @@ use React\Promise\PromiseInterface;
|
||||
|
||||
class SecurityMiddleware
|
||||
{
|
||||
|
||||
private bool $useJwt = false;
|
||||
|
||||
private bool $useToken = false;
|
||||
|
||||
public function __construct(
|
||||
private readonly ?string $jwtSecret = null,
|
||||
private readonly ?string $jwtClaim = "slotdb",
|
||||
private readonly ?string $tokenFile = null,
|
||||
)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function __invoke(ServerRequestInterface $request, ?callable $next = null)
|
||||
{
|
||||
|
||||
if (!$this->useJwt && !$this->useToken) {
|
||||
// No authentication
|
||||
$request = $request->withAttribute("acl", [ "*/rw"]);
|
||||
} else {
|
||||
if ($this->useJwt && $request->hasHeader('authorization')) {
|
||||
$auth = $request->getHeader('authorization')[0];
|
||||
[$type,$token] = explode(" ", $auth, 2);
|
||||
$acl = $this->checkJwt($token);
|
||||
if ($acl === null) {
|
||||
return Response::json(['error'=>'Unauthorized'])->withStatus(Response::STATUS_UNAUTHORIZED);
|
||||
}
|
||||
$request = $request->withAttribute("acl", $acl);
|
||||
} elseif ($this->useToken && $request->hasHeader('x-token')) {
|
||||
$token = $request->getHeader('x-token')[0];
|
||||
$acl = $this->checkToken($token);
|
||||
if ($acl === null) {
|
||||
return Response::json(['error'=>'Unauthorized'])->withStatus(Response::STATUS_UNAUTHORIZED);
|
||||
}
|
||||
$request = $request->withAttribute("acl", $acl);
|
||||
}
|
||||
}
|
||||
|
||||
$response = $next($request);
|
||||
return $response;
|
||||
}
|
||||
|
||||
private function checkJwt(string $token): ?array
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
private function checkToken(string $token): ?array
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -32,16 +32,18 @@ function print_usage(): never {
|
||||
-v,--verbose Include debug level logging to STDOUT
|
||||
-V,--version Print version and exit
|
||||
-l,--listen ADDR Set listen address for HTTP requests (env: SLOTDB_LISTEN)
|
||||
-c,--config FILE Read configuration from file (env: SLOTDB_CONFIG)
|
||||
--db URI Use custom database connection URI (env: SLOTDB_DATABASE)
|
||||
--init-db Initialize database schema
|
||||
--upgrade-db Upgrade database schema
|
||||
--root FILE Set root CA certificate for SSL (env: SLOTDB_SSL_ROOT)
|
||||
--cert FILE Set certificate for SSL (env: SLOTDB_SSL_CERT)
|
||||
--key FILE Set private key file for SSL (env: SLOTDB_SSL_KEY)
|
||||
--jwt-secret SECRET Use JWT auth with secret (env: SLOTDB_JWT_SECRET)
|
||||
--jwt-claim CLAIM Claim key to use for matching properties (env: SLOTDB_JWT_CLAIM)
|
||||
-c,--config FILE ¤ Read configuration from file (env: SLOTDB_CONFIG)
|
||||
--db URI ¤ Use custom database connection URI (env: SLOTDB_DATABASE)
|
||||
--init-db ¤ Initialize database schema
|
||||
--upgrade-db ¤ Upgrade database schema
|
||||
--root FILE ¤ Set root CA certificate for SSL (env: SLOTDB_SSL_ROOT)
|
||||
--cert FILE ¤ Set certificate for SSL (env: SLOTDB_SSL_CERT)
|
||||
--key FILE ¤ Set private key file for SSL (env: SLOTDB_SSL_KEY)
|
||||
--jwt-secret SECRET ¤ Use JWT auth with secret (env: SLOTDB_JWT_SECRET)
|
||||
--jwt-claim CLAIM ¤ Key in JWT claims that contains ACLs (env: SLOTDB_JWT_CLAIM)
|
||||
--tokens FILE ¤ Read access tokens from file (env: SLOTDB_TOKENS_FILE)
|
||||
--http-log FILE Log HTTP requests to file (env: SLOTDB_HTTP_LOG)
|
||||
¤=not yet implemented
|
||||
|
||||
Defaults:
|
||||
HTTP listen address: 0.0.0.0:8080
|
||||
@@ -52,11 +54,11 @@ function print_usage(): never {
|
||||
The key pointed to by the claim option should be a string or an array of
|
||||
strings, with each string granting access to a group, slot or property.
|
||||
|
||||
"*#*:*/r" Read all groups, all slots, all properties
|
||||
"*#*.*/r" Read all groups, all slots, all properties
|
||||
"first#/rw" Read-write everything in the group first
|
||||
"slot*/rw" Read-write all slots starting with 'slot' in all groups
|
||||
"slota,slotb/w" Write-only access to slots 'slota' and 'slotb'
|
||||
"*:available" Read-only access to the 'available' prop on all slots
|
||||
"slot[ab]/w" Write-only access to slots 'slota' and 'slotb'
|
||||
"*.available" Read-only access to the 'available' prop on all slots
|
||||
|
||||
Examples:
|
||||
SLOTDB_LISTEN=0.0.0.0:9876 slotdb
|
||||
|
||||
Reference in New Issue
Block a user