Skip to content

Commit

Permalink
Rename CsrfMiddlware class to CsrfTokenMiddleware (#70)
Browse files Browse the repository at this point in the history
  • Loading branch information
ev-gor committed Oct 31, 2024
1 parent b26cf68 commit 32894f7
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 10 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## 2.1.2 under development

- no changes in this release.
- Chg #71: Deprecate `CsrfMiddleware` in favor of `CsrfTokenMiddleware` (@ev-gor)

## 2.1.1 May 08, 2024

Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ composer require yiisoft/csrf

## General usage

In order to enable CSRF protection you need to add `CsrfMiddleware` to your main middleware stack.
In order to enable CSRF protection you need to add `CsrfTokenMiddleware` to your main middleware stack.
In Yii it is done by configuring `config/web/application.php`:

```php
Expand All @@ -48,7 +48,7 @@ return [
[
ErrorCatcher::class,
SessionMiddleware::class,
CsrfMiddleware::class, // <-- add this
CsrfTokenMiddleware::class, // <-- add this
Router::class,
]
);
Expand All @@ -74,7 +74,7 @@ You can change this behavior by implementing your own request handler:
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Yiisoft\Csrf\CsrfMiddleware;
use Yiisoft\Csrf\CsrfTokenMiddleware;

/**
* @var Psr\Http\Message\ResponseFactoryInterface $responseFactory
Expand All @@ -99,7 +99,7 @@ $failureHandler = new class ($responseFactory) implements RequestHandlerInterfac
}
};

$middleware = new CsrfMiddleware($responseFactory, $csrfToken, $failureHandler);
$middleware = new CsrfTokenMiddleware($responseFactory, $csrfToken, $failureHandler);
```

## CSRF Tokens
Expand Down
1 change: 1 addition & 0 deletions src/CsrfMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
* PSR-15 middleware that takes care of token validation.
*
* @link https://www.php-fig.org/psr/psr-15/
* @deprecated Use the {@see CsrfTokenMiddleware} class instead.
*/
final class CsrfMiddleware implements MiddlewareInterface
{
Expand Down
109 changes: 109 additions & 0 deletions src/CsrfTokenMiddleware.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Csrf;

use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Yiisoft\Http\Method;
use Yiisoft\Http\Status;

use function in_array;
use function is_string;

/**
* PSR-15 middleware that takes care of token validation.
*
* @link https://www.php-fig.org/psr/psr-15/
*/
final class CsrfTokenMiddleware implements MiddlewareInterface
{
public const PARAMETER_NAME = '_csrf';
public const HEADER_NAME = 'X-CSRF-Token';

private string $parameterName = self::PARAMETER_NAME;
private string $headerName = self::HEADER_NAME;

private ResponseFactoryInterface $responseFactory;
private CsrfTokenInterface $token;
private ?RequestHandlerInterface $failureHandler;

public function __construct(
ResponseFactoryInterface $responseFactory,
CsrfTokenInterface $token,
RequestHandlerInterface $failureHandler = null
) {
$this->responseFactory = $responseFactory;
$this->token = $token;
$this->failureHandler = $failureHandler;
}

public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface

Check warning on line 45 in src/CsrfTokenMiddleware.php

View check run for this annotation

Codecov / codecov/patch

src/CsrfTokenMiddleware.php#L45

Added line #L45 was not covered by tests
{
if ($this->validateCsrfToken($request)) {
return $handler->handle($request);

Check warning on line 48 in src/CsrfTokenMiddleware.php

View check run for this annotation

Codecov / codecov/patch

src/CsrfTokenMiddleware.php#L47-L48

Added lines #L47 - L48 were not covered by tests
}

if ($this->failureHandler !== null) {
return $this->failureHandler->handle($request);

Check warning on line 52 in src/CsrfTokenMiddleware.php

View check run for this annotation

Codecov / codecov/patch

src/CsrfTokenMiddleware.php#L51-L52

Added lines #L51 - L52 were not covered by tests
}

$response = $this->responseFactory->createResponse(Status::UNPROCESSABLE_ENTITY);
$response
->getBody()
->write(Status::TEXTS[Status::UNPROCESSABLE_ENTITY]);
return $response;

Check warning on line 59 in src/CsrfTokenMiddleware.php

View check run for this annotation

Codecov / codecov/patch

src/CsrfTokenMiddleware.php#L55-L59

Added lines #L55 - L59 were not covered by tests
}

public function withParameterName(string $name): self
{
$new = clone $this;
$new->parameterName = $name;
return $new;
}

public function withHeaderName(string $name): self
{
$new = clone $this;
$new->headerName = $name;
return $new;
}

public function getParameterName(): string
{
return $this->parameterName;
}

public function getHeaderName(): string
{
return $this->headerName;
}

private function validateCsrfToken(ServerRequestInterface $request): bool

Check warning on line 86 in src/CsrfTokenMiddleware.php

View check run for this annotation

Codecov / codecov/patch

src/CsrfTokenMiddleware.php#L86

Added line #L86 was not covered by tests
{
if (in_array($request->getMethod(), [Method::GET, Method::HEAD, Method::OPTIONS], true)) {
return true;

Check warning on line 89 in src/CsrfTokenMiddleware.php

View check run for this annotation

Codecov / codecov/patch

src/CsrfTokenMiddleware.php#L88-L89

Added lines #L88 - L89 were not covered by tests
}

$token = $this->getTokenFromRequest($request);

Check warning on line 92 in src/CsrfTokenMiddleware.php

View check run for this annotation

Codecov / codecov/patch

src/CsrfTokenMiddleware.php#L92

Added line #L92 was not covered by tests

return !empty($token) && $this->token->validate($token);

Check warning on line 94 in src/CsrfTokenMiddleware.php

View check run for this annotation

Codecov / codecov/patch

src/CsrfTokenMiddleware.php#L94

Added line #L94 was not covered by tests
}

private function getTokenFromRequest(ServerRequestInterface $request): ?string

Check warning on line 97 in src/CsrfTokenMiddleware.php

View check run for this annotation

Codecov / codecov/patch

src/CsrfTokenMiddleware.php#L97

Added line #L97 was not covered by tests
{
$parsedBody = $request->getParsedBody();

Check warning on line 99 in src/CsrfTokenMiddleware.php

View check run for this annotation

Codecov / codecov/patch

src/CsrfTokenMiddleware.php#L99

Added line #L99 was not covered by tests

$token = $parsedBody[$this->parameterName] ?? null;
if (empty($token)) {
$headers = $request->getHeader($this->headerName);
$token = reset($headers);

Check warning on line 104 in src/CsrfTokenMiddleware.php

View check run for this annotation

Codecov / codecov/patch

src/CsrfTokenMiddleware.php#L101-L104

Added lines #L101 - L104 were not covered by tests
}

return is_string($token) ? $token : null;

Check warning on line 107 in src/CsrfTokenMiddleware.php

View check run for this annotation

Codecov / codecov/patch

src/CsrfTokenMiddleware.php#L107

Added line #L107 was not covered by tests
}
}
10 changes: 5 additions & 5 deletions tests/CsrfMiddlewareTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

use Nyholm\Psr7\Factory\Psr17Factory;
use PHPUnit\Framework\TestCase;
use Yiisoft\Csrf\CsrfMiddleware;
use Yiisoft\Csrf\CsrfTokenMiddleware;
use Yiisoft\Csrf\Synchronizer\Generator\RandomCsrfTokenGenerator;
use Yiisoft\Csrf\Synchronizer\SynchronizerCsrfToken;
use Yiisoft\Csrf\Tests\Synchronizer\Storage\MockCsrfTokenStorage;
Expand All @@ -16,7 +16,7 @@ final class CsrfMiddlewareTest extends TestCase
public function testDefaultParameterName(): void
{
$middleware = $this->createMiddleware();
$this->assertSame(CsrfMiddleware::PARAMETER_NAME, $middleware->getParameterName());
$this->assertSame(CsrfTokenMiddleware::PARAMETER_NAME, $middleware->getParameterName());
}

public function testGetParameterName(): void
Expand All @@ -30,7 +30,7 @@ public function testGetParameterName(): void
public function testDefaultHeaderName(): void
{
$middleware = $this->createMiddleware();
$this->assertSame(CsrfMiddleware::HEADER_NAME, $middleware->getHeaderName());
$this->assertSame(CsrfTokenMiddleware::HEADER_NAME, $middleware->getHeaderName());
}

public function testGetHeaderName(): void
Expand All @@ -48,9 +48,9 @@ public function testImmutability(): void
$this->assertNotSame($original, $original->withParameterName('csrf'));
}

private function createMiddleware(): CsrfMiddleware
private function createMiddleware(): CsrfTokenMiddleware
{
return new CsrfMiddleware(
return new CsrfTokenMiddleware(
new Psr17Factory(),
new SynchronizerCsrfToken(
new RandomCsrfTokenGenerator(),
Expand Down

0 comments on commit 32894f7

Please sign in to comment.