diff --git a/docs/pages/docs/features/security/oauth2/installation/index.md b/docs/pages/docs/features/security/oauth2/installation/index.md index 7b072a2548cb12c1e551b36afa865bf8d6182e99..5ad2874563c725f97f485a4fd02cc105561e75ba 100644 --- a/docs/pages/docs/features/security/oauth2/installation/index.md +++ b/docs/pages/docs/features/security/oauth2/installation/index.md @@ -103,3 +103,31 @@ $ php ./bin/resonance.php generate:defuse-key > oauth2/defuse.key ``` Then, change the CHMOD permissions for that key to `0600`. + +## Post Session Authentication Hook + +If you are using {{tutorials/session-based-authentication/index}} you need +to return `OAuth2UserSessionAuthenticated` instance +from your authentication {{docs/features/http/responders}} (see also: +{{docs/features/http/interceptors}}). + +It allows OAuth2 to know that the user is authenticated and that it should +check if user is in the middle of OAuth2 flow. + +```php +<?php + +use Distantmagic\Resonance\OAuth2UserSessionAuthenticated; + +final readonly class LoginValidation extends HttpController +{ + public function createResponse(): HttpInterceptableInterface + { + // ... + // perform session authentication somehow + // ... + + return new OAuth2UserSessionAuthenticated(); + } +} +``` diff --git a/resources/css/docs-hljs.css b/resources/css/docs-hljs.css index f9fafeb9cc86bd6e31aca9831f06be0c35b0a679..ff3a8f727cb8c3c3ae972d5f8bae812415cc7161 100644 --- a/resources/css/docs-hljs.css +++ b/resources/css/docs-hljs.css @@ -85,6 +85,7 @@ code[class] { .fenced-code { background-color: var(--color-block-background); box-shadow: 8px 8px #00000033; + margin: 20px 0; @media screen and (min-width: 1024px) { position: relative; diff --git a/src/HttpResponder/OAuth2/PostSessionAuthentication.php b/src/HttpInterceptor/OAuth2UserSessionAuthenticatedInterceptor.php similarity index 69% rename from src/HttpResponder/OAuth2/PostSessionAuthentication.php rename to src/HttpInterceptor/OAuth2UserSessionAuthenticatedInterceptor.php index 5579045b7ce61b11ecb5e57f58e2f222ce6ac0e7..8db3569731953fc911f98f6ebf5709231d007892 100644 --- a/src/HttpResponder/OAuth2/PostSessionAuthentication.php +++ b/src/HttpInterceptor/OAuth2UserSessionAuthenticatedInterceptor.php @@ -2,25 +2,32 @@ declare(strict_types=1); -namespace Distantmagic\Resonance\HttpResponder\OAuth2; +namespace Distantmagic\Resonance\HttpInterceptor; use Distantmagic\Resonance\Attribute\GrantsFeature; +use Distantmagic\Resonance\Attribute\Intercepts; use Distantmagic\Resonance\Attribute\Singleton; use Distantmagic\Resonance\Feature; use Distantmagic\Resonance\HttpInterceptableInterface; -use Distantmagic\Resonance\HttpResponder; +use Distantmagic\Resonance\HttpInterceptor; use Distantmagic\Resonance\HttpResponderInterface; use Distantmagic\Resonance\OAuth2AuthorizationCodeFlowControllerInterface; use Distantmagic\Resonance\OAuth2AuthorizationRequestSessionStore; use Distantmagic\Resonance\OAuth2AuthorizedUser; +use Distantmagic\Resonance\OAuth2UserSessionAuthenticated; use Distantmagic\Resonance\SessionAuthentication; +use Distantmagic\Resonance\SingletonCollection; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use RuntimeException; +/** + * @template-extends HttpInterceptor<OAuth2UserSessionAuthenticated> + */ #[GrantsFeature(Feature::OAuth2)] -#[Singleton] -final readonly class PostSessionAuthentication extends HttpResponder +#[Intercepts(OAuth2UserSessionAuthenticated::class)] +#[Singleton(collection: SingletonCollection::HttpInterceptor)] +final readonly class OAuth2UserSessionAuthenticatedInterceptor extends HttpInterceptor { public function __construct( private OAuth2AuthorizationCodeFlowControllerInterface $authorizationCodeFlowController, @@ -28,8 +35,11 @@ final readonly class PostSessionAuthentication extends HttpResponder private SessionAuthentication $sessionAuthentication, ) {} - public function respond(ServerRequestInterface $request, ResponseInterface $response): HttpInterceptableInterface|HttpResponderInterface|ResponseInterface - { + public function intercept( + ServerRequestInterface $request, + ResponseInterface $response, + object $intercepted, + ): HttpInterceptableInterface|HttpResponderInterface|ResponseInterface { if (!$this->authorizationRequestSessionStore->has($request)) { return $this->authorizationCodeFlowController->redirectToAuthenticatedPage($request, $response); } diff --git a/src/OAuth2UserSessionAuthenticated.php b/src/OAuth2UserSessionAuthenticated.php new file mode 100644 index 0000000000000000000000000000000000000000..998d33b8d5c2bab42dbfd64d79ad8967a1782e85 --- /dev/null +++ b/src/OAuth2UserSessionAuthenticated.php @@ -0,0 +1,36 @@ +<?php + +declare(strict_types=1); + +namespace Distantmagic\Resonance; + +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; + +final readonly class OAuth2UserSessionAuthenticated implements HttpInterceptableInterface +{ + private SwooleContextRequestResponseReader $swooleContextRequestResponseReader; + + /** + * @psalm-taint-source file $templatePath + */ + public function __construct( + ?ServerRequestInterface $request = null, + ?ResponseInterface $response = null, + ) { + $this->swooleContextRequestResponseReader = new SwooleContextRequestResponseReader( + request: $request, + response: $response, + ); + } + + public function getResponse(): ResponseInterface + { + return $this->swooleContextRequestResponseReader->getResponse(); + } + + public function getServerRequest(): ServerRequestInterface + { + return $this->swooleContextRequestResponseReader->getServerRequest(); + } +}