Skip to content

Commit

Permalink
Feature/add token generator (#58)
Browse files Browse the repository at this point in the history
* Refactor how session access works

* Add csrf token manager and secrets parameter store

* Properly add labrador to composer bin

* Set php version to 8.2 in CI

* temporarily remove static analysis from ci
  • Loading branch information
cspray authored May 16, 2023
1 parent d1e63d0 commit 3d6ad38
Show file tree
Hide file tree
Showing 89 changed files with 923 additions and 396 deletions.
6 changes: 2 additions & 4 deletions .github/workflows/php.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,10 @@ jobs:
- name: Composer
uses: php-actions/composer@v6
with:
php_version: "8.2"
php_extensions: pcntl

- name: Unit Test
uses: php-actions/phpunit@v3
with:
version: "9.5"

- name: Static Analysis
run: "vendor/bin/psalm.phar --long-progress"
version: "9.5"
2 changes: 1 addition & 1 deletion annotated-container.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,5 @@
<logging>
<stdout />
</logging>
<!-- <cacheDir>.annotated-container-cache</cacheDir> -->
<cacheDir>.annotated-container-cache</cacheDir>
</annotatedContainer>
7 changes: 5 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
},
"minimum-stability": "beta",
"require": {
"php": "^8.1",
"php": "^8.2",
"ext-json": "*",
"ext-pcntl": "*",
"amphp/cache": "^v2.0.0-beta.4",
"amphp/http": "^v2.0",
"amphp/http-server": "^v3.0.0-beta.8",
"amphp/http-server-session": "^v3.0.0-beta.2",
Expand All @@ -26,7 +27,8 @@
"nikic/fast-route": "^1.3",
"ocramius/package-versions": "^2.7",
"php-di/php-di": "^v7.0",
"ramsey/uuid": "^4.4"
"ramsey/uuid": "^4.4",
"adbario/php-dot-notation": "^3.3"
},
"require-dev": {
"amphp/http-client": "^v5.0",
Expand All @@ -38,6 +40,7 @@
"psalm/phar": "^5.0",
"roave/security-advisories": "dev-latest"
},
"bin": ["bin/labrador"],
"autoload": {
"psr-4": {
"Labrador\\": "src"
Expand Down
59 changes: 57 additions & 2 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions dummy_app/Controller/ControllerAttributeController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php declare(strict_types=1);

namespace Labrador\DummyApp\Controller;

use Amp\Http\Server\Request;
use Amp\Http\Server\Response;
use Labrador\Web\Controller\HttpController;
use Labrador\Web\Controller\SelfDescribingController;
use Labrador\Web\RequestAttribute;
use Labrador\Web\Router\GetMapping;

#[HttpController(new GetMapping('/controller-request-attribute'))]
final class ControllerAttributeController extends SelfDescribingController {

public function handleRequest(Request $request) : Response {
return new Response(body: $request->getAttribute(RequestAttribute::Controller->value));
}

}
28 changes: 0 additions & 28 deletions dummy_app/Controller/SessionActionDtoController.php

This file was deleted.

33 changes: 0 additions & 33 deletions dummy_app/Controller/SessionDtoController.php

This file was deleted.

34 changes: 34 additions & 0 deletions known-issues.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<files psalm-version="5.11.0@c9b192ab8400fdaf04b2b13d110575adc879aa90">
<file src="src/Security/InMemorySecretsSource.php">
<MixedReturnTypeCoercion>
<code><![CDATA[$this->data]]></code>
<code>array</code>
</MixedReturnTypeCoercion>
</file>
<file src="src/Security/JsonFileSecretsSource.php">
<MixedAssignment>
<code><![CDATA[$this->data]]></code>
</MixedAssignment>
<MixedReturnTypeCoercion>
<code><![CDATA[$this->data]]></code>
<code>array</code>
</MixedReturnTypeCoercion>
</file>
<file src="src/Web/Application/Analytics/RequestBenchmark.php">
<PossiblyNullOperand>
<code><![CDATA[$this->middlewareCompleted]]></code>
Expand All @@ -19,4 +34,23 @@
<code>$k</code>
</ArgumentTypeCoercion>
</file>
<file src="src/Web/Security/CsrfTokenManager.php">
<MixedArgument>
<code>$id</code>
<code>$storeIds</code>
</MixedArgument>
<MixedArrayAssignment>
<code>$storeIds[]</code>
</MixedArrayAssignment>
<MixedAssignment>
<code>$id</code>
<code>$storeIds</code>
<code>$storeIds</code>
<code>$token</code>
</MixedAssignment>
<PossiblyNullArgument>
<code><![CDATA[$session->get('csrfStoreIds')]]></code>
<code><![CDATA[$session->get('csrfStoreIds')]]></code>
</PossiblyNullArgument>
</file>
</files>
19 changes: 19 additions & 0 deletions src/Security/InMemorySecretsSource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php declare(strict_types=1);

namespace Labrador\Security;

final class InMemorySecretsSource implements SecretsSource {

public function __construct(
private readonly string $name,
private readonly array $data
) {}

public function getName() : string {
return $this->name;
}

public function getData() : array {
return $this->data;
}
}
28 changes: 28 additions & 0 deletions src/Security/JsonFileSecretsSource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php declare(strict_types=1);

namespace Labrador\Security;

use Labrador\Web\Exception\InvalidSecretsSource;

final class JsonFileSecretsSource implements SecretsSource {

private readonly string $name;
private readonly array $data;

public function __construct(string $filePath) {
if (!file_exists($filePath)) {
throw InvalidSecretsSource::fromFileNotPresent($filePath);
}

[$this->name] = explode('.', basename($filePath));
$this->data = json_decode(file_get_contents($filePath), associative: true, flags: JSON_THROW_ON_ERROR);
}

public function getName() : string {
return $this->name;
}

public function getData() : array {
return $this->data;
}
}
23 changes: 23 additions & 0 deletions src/Security/RandomEngineTokenGenerator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php declare(strict_types=1);

namespace Labrador\Security;

use Cspray\AnnotatedContainer\Attribute\Service;
use Random\Engine as RandomEngine;

#[Service]
final class RandomEngineTokenGenerator implements TokenGenerator {

private readonly RandomEngine $random;

public function __construct(
RandomEngine $random = null
) {
$this->random = $random ?? new RandomEngine\Secure();
}


public function generateToken() : string {
return bin2hex($this->random->generate());

This comment has been minimized.

Copy link
@TimWolla

TimWolla Jul 7, 2023

The output of Random\Engine::generate() is intended as a low-level building block. It should generally not be used directly, because you don't know what kind of engine is provided and thus you don't know how the output will look. It might be a 16 bit engine that only returns 65536 different values. Even with 64 bit engines the output size is insufficient for anything “token-like”.

I recommend to insert the engine into Random\Randomizer and then call $randomizer->getBytes($length) with $length being at least 16 (i.e. 128 Bits).

}
}
30 changes: 30 additions & 0 deletions src/Security/SecretsParameterStore.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php declare(strict_types=1);

namespace Labrador\Security;

use Adbar\Dot;
use Cspray\AnnotatedContainer\ContainerFactory\ParameterStore;
use Cspray\Typiphy\Type;
use Cspray\Typiphy\TypeIntersect;
use Cspray\Typiphy\TypeUnion;

final class SecretsParameterStore implements ParameterStore {

private readonly Dot $data;

public function __construct(SecretsSource... $secretsSource) {
$data = [];
foreach ($secretsSource as $source) {
$data[$source->getName()] = $source->getData();
}
$this->data = dot($data);
}

public function getName() : string {
return 'secrets';
}

public function fetch(TypeUnion|Type|TypeIntersect $type, string $key) : mixed {
return $this->data->get($key);
}
}
14 changes: 14 additions & 0 deletions src/Security/SecretsSource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php declare(strict_types=1);

namespace Labrador\Security;

interface SecretsSource {

public function getName() : string;

/**
* @return array<non-empty-string, mixed>
*/
public function getData() : array;

}
Loading

0 comments on commit 3d6ad38

Please sign in to comment.