Merge pull request #7630 from kenjis/remove-config-app-CSRF-items-4.4

Remove Config\App Security items
This commit is contained in:
kenjis 2023-06-30 08:09:45 +09:00 committed by GitHub
commit d9c7f06e96
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 175 additions and 202 deletions

View File

@ -158,91 +158,6 @@ class App extends BaseConfig
*/
public array $proxyIPs = [];
/**
* --------------------------------------------------------------------------
* CSRF Token Name
* --------------------------------------------------------------------------
*
* The token name.
*
* @deprecated Use `Config\Security` $tokenName property instead of using this property.
*/
public string $CSRFTokenName = 'csrf_test_name';
/**
* --------------------------------------------------------------------------
* CSRF Header Name
* --------------------------------------------------------------------------
*
* The header name.
*
* @deprecated Use `Config\Security` $headerName property instead of using this property.
*/
public string $CSRFHeaderName = 'X-CSRF-TOKEN';
/**
* --------------------------------------------------------------------------
* CSRF Cookie Name
* --------------------------------------------------------------------------
*
* The cookie name.
*
* @deprecated Use `Config\Security` $cookieName property instead of using this property.
*/
public string $CSRFCookieName = 'csrf_cookie_name';
/**
* --------------------------------------------------------------------------
* CSRF Expire
* --------------------------------------------------------------------------
*
* The number in seconds the token should expire.
*
* @deprecated Use `Config\Security` $expire property instead of using this property.
*/
public int $CSRFExpire = 7200;
/**
* --------------------------------------------------------------------------
* CSRF Regenerate
* --------------------------------------------------------------------------
*
* Regenerate token on every submission?
*
* @deprecated Use `Config\Security` $regenerate property instead of using this property.
*/
public bool $CSRFRegenerate = true;
/**
* --------------------------------------------------------------------------
* CSRF Redirect
* --------------------------------------------------------------------------
*
* Redirect to previous page with error on failure?
*
* @deprecated Use `Config\Security` $redirect property instead of using this property.
*/
public bool $CSRFRedirect = false;
/**
* --------------------------------------------------------------------------
* CSRF SameSite
* --------------------------------------------------------------------------
*
* Setting for CSRF SameSite cookie token. Allowed values are:
* - None
* - Lax
* - Strict
* - ''
*
* Defaults to `Lax` as recommended in this link:
*
* @see https://portswigger.net/web-security/csrf/samesite-cookies
*
* @deprecated `Config\Cookie` $samesite property is used.
*/
public string $CSRFSameSite = 'Lax';
/**
* --------------------------------------------------------------------------
* Content Security Policy

View File

@ -77,6 +77,7 @@ use Config\Modules;
use Config\Pager as PagerConfig;
use Config\Paths;
use Config\Routing;
use Config\Security as SecurityConfig;
use Config\Services as AppServices;
use Config\Session as SessionConfig;
use Config\Toolbar as ToolbarConfig;
@ -627,13 +628,13 @@ class Services extends BaseService
*
* @return Security
*/
public static function security(?App $config = null, bool $getShared = true)
public static function security(?SecurityConfig $config = null, bool $getShared = true)
{
if ($getShared) {
return static::getSharedInstance('security', $config);
}
$config ??= config(App::class);
$config ??= config(SecurityConfig::class);
return new Security($config);
}

View File

@ -18,7 +18,6 @@ use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\I18n\Time;
use CodeIgniter\Security\Exceptions\SecurityException;
use CodeIgniter\Session\Session;
use Config\App;
use Config\Cookie as CookieConfig;
use Config\Security as SecurityConfig;
use Config\Services;
@ -44,6 +43,8 @@ class Security implements SecurityInterface
* Protection Method for Cross Site Request Forgery protection.
*
* @var string 'cookie' or 'session'
*
* @deprecated 4.4.0 Use $this->config->csrfProtection.
*/
protected $csrfProtection = self::CSRF_PROTECTION_COOKIE;
@ -51,6 +52,8 @@ class Security implements SecurityInterface
* CSRF Token Randomization
*
* @var bool
*
* @deprecated 4.4.0 Use $this->config->tokenRandomize.
*/
protected $tokenRandomize = false;
@ -69,6 +72,8 @@ class Security implements SecurityInterface
* Token name for Cross Site Request Forgery protection.
*
* @var string
*
* @deprecated 4.4.0 Use $this->config->tokenName.
*/
protected $tokenName = 'csrf_token_name';
@ -78,6 +83,8 @@ class Security implements SecurityInterface
* Header name for Cross Site Request Forgery protection.
*
* @var string
*
* @deprecated 4.4.0 Use $this->config->headerName.
*/
protected $headerName = 'X-CSRF-TOKEN';
@ -105,6 +112,8 @@ class Security implements SecurityInterface
* Defaults to two hours (in seconds).
*
* @var int
*
* @deprecated 4.4.0 Use $this->config->expires.
*/
protected $expires = 7200;
@ -114,6 +123,8 @@ class Security implements SecurityInterface
* Regenerate CSRF Token on every request.
*
* @var bool
*
* @deprecated 4.4.0 Use $this->config->regenerate.
*/
protected $regenerate = true;
@ -123,6 +134,8 @@ class Security implements SecurityInterface
* Redirect to previous page with error on failure.
*
* @var bool
*
* @deprecated 4.4.0 Use $this->config->redirect.
*/
protected $redirect = false;
@ -163,35 +176,22 @@ class Security implements SecurityInterface
*/
private ?string $hashInCookie = null;
/**
* Security Config
*/
protected SecurityConfig $config;
/**
* Constructor.
*
* Stores our configuration and fires off the init() method to setup
* initial state.
*/
public function __construct(App $config)
public function __construct(SecurityConfig $config)
{
$security = config(SecurityConfig::class);
$this->config = $config;
// Store CSRF-related configurations
if ($security instanceof SecurityConfig) {
$this->csrfProtection = $security->csrfProtection ?? $this->csrfProtection;
$this->tokenName = $security->tokenName ?? $this->tokenName;
$this->headerName = $security->headerName ?? $this->headerName;
$this->regenerate = $security->regenerate ?? $this->regenerate;
$this->redirect = $security->redirect ?? $this->redirect;
$this->rawCookieName = $security->cookieName ?? $this->rawCookieName;
$this->expires = $security->expires ?? $this->expires;
$this->tokenRandomize = $security->tokenRandomize ?? $this->tokenRandomize;
} else {
// `Config/Security.php` is absence
$this->tokenName = $config->CSRFTokenName ?? $this->tokenName;
$this->headerName = $config->CSRFHeaderName ?? $this->headerName;
$this->regenerate = $config->CSRFRegenerate ?? $this->regenerate;
$this->rawCookieName = $config->CSRFCookieName ?? $this->rawCookieName;
$this->expires = $config->CSRFExpire ?? $this->expires;
$this->redirect = $config->CSRFRedirect ?? $this->redirect;
}
$this->rawCookieName = $config->cookieName;
if ($this->isCSRFCookie()) {
$cookie = config(CookieConfig::class);
@ -213,7 +213,7 @@ class Security implements SecurityInterface
private function isCSRFCookie(): bool
{
return $this->csrfProtection === self::CSRF_PROTECTION_COOKIE;
return $this->config->csrfProtection === self::CSRF_PROTECTION_COOKIE;
}
private function configureSession(): void
@ -287,7 +287,7 @@ class Security implements SecurityInterface
$postedToken = $this->getPostedToken($request);
try {
$token = ($postedToken !== null && $this->tokenRandomize)
$token = ($postedToken !== null && $this->config->tokenRandomize)
? $this->derandomize($postedToken) : $postedToken;
} catch (InvalidArgumentException $e) {
$token = null;
@ -300,7 +300,7 @@ class Security implements SecurityInterface
$this->removeTokenInRequest($request);
if ($this->regenerate) {
if ($this->config->regenerate) {
$this->generateHash();
}
@ -318,13 +318,13 @@ class Security implements SecurityInterface
$json = json_decode($request->getBody() ?? '');
if (isset($_POST[$this->tokenName])) {
if (isset($_POST[$this->config->tokenName])) {
// We kill this since we're done and we don't want to pollute the POST array.
unset($_POST[$this->tokenName]);
unset($_POST[$this->config->tokenName]);
$request->setGlobal('post', $_POST);
} elseif (isset($json->{$this->tokenName})) {
} elseif (isset($json->{$this->config->tokenName})) {
// We kill this since we're done and we don't want to pollute the JSON data.
unset($json->{$this->tokenName});
unset($json->{$this->config->tokenName});
$request->setBody(json_encode($json));
}
}
@ -335,19 +335,19 @@ class Security implements SecurityInterface
// Does the token exist in POST, HEADER or optionally php:://input - json data.
if ($tokenValue = $request->getPost($this->tokenName)) {
if ($tokenValue = $request->getPost($this->config->tokenName)) {
return $tokenValue;
}
if ($request->hasHeader($this->headerName) && ! empty($request->header($this->headerName)->getValue())) {
return $request->header($this->headerName)->getValue();
if ($request->hasHeader($this->config->headerName) && ! empty($request->header($this->config->headerName)->getValue())) {
return $request->header($this->config->headerName)->getValue();
}
$body = (string) $request->getBody();
$json = json_decode($body);
if ($body !== '' && ! empty($json) && json_last_error() === JSON_ERROR_NONE) {
return $json->{$this->tokenName} ?? null;
return $json->{$this->config->tokenName} ?? null;
}
return null;
@ -358,7 +358,7 @@ class Security implements SecurityInterface
*/
public function getHash(): ?string
{
return $this->tokenRandomize ? $this->randomize($this->hash) : $this->hash;
return $this->config->tokenRandomize ? $this->randomize($this->hash) : $this->hash;
}
/**
@ -407,7 +407,7 @@ class Security implements SecurityInterface
*/
public function getTokenName(): string
{
return $this->tokenName;
return $this->config->tokenName;
}
/**
@ -415,7 +415,7 @@ class Security implements SecurityInterface
*/
public function getHeaderName(): string
{
return $this->headerName;
return $this->config->headerName;
}
/**
@ -423,7 +423,7 @@ class Security implements SecurityInterface
*/
public function getCookieName(): string
{
return $this->cookieName;
return $this->config->cookieName;
}
/**
@ -443,7 +443,7 @@ class Security implements SecurityInterface
*/
public function shouldRedirect(): bool
{
return $this->redirect;
return $this->config->redirect;
}
/**
@ -521,9 +521,9 @@ class Security implements SecurityInterface
if ($this->isHashInCookie()) {
$this->hash = $this->hashInCookie;
}
} elseif ($this->session->has($this->tokenName)) {
} elseif ($this->session->has($this->config->tokenName)) {
// Session based CSRF protection
$this->hash = $this->session->get($this->tokenName);
$this->hash = $this->session->get($this->config->tokenName);
}
}
@ -562,7 +562,7 @@ class Security implements SecurityInterface
$this->rawCookieName,
$this->hash,
[
'expires' => $this->expires === 0 ? 0 : Time::now()->getTimestamp() + $this->expires,
'expires' => $this->config->expires === 0 ? 0 : Time::now()->getTimestamp() + $this->config->expires,
]
);
@ -606,6 +606,6 @@ class Security implements SecurityInterface
private function saveHashInSession(): void
{
$this->session->set($this->tokenName, $this->hash);
$this->session->set($this->config->tokenName, $this->hash);
}
}

View File

@ -18,14 +18,6 @@ class MockAppConfig extends App
public string $baseURL = 'http://example.com/';
public string $uriProtocol = 'REQUEST_URI';
public array $proxyIPs = [];
public string $CSRFTokenName = 'csrf_test_name';
public string $CSRFHeaderName = 'X-CSRF-TOKEN';
public string $CSRFCookieName = 'csrf_cookie_name';
public int $CSRFExpire = 7200;
public bool $CSRFRegenerate = true;
public array $CSRFExcludeURIs = ['http://example.com'];
public bool $CSRFRedirect = false;
public string $CSRFSameSite = 'Lax';
public bool $CSPEnabled = false;
public string $defaultLocale = 'en';
public bool $negotiateLocale = false;

View File

@ -34,6 +34,7 @@ use Config\Cookie;
use Config\Logger;
use Config\Modules;
use Config\Routing;
use Config\Security as SecurityConfig;
use Config\Services;
use Config\Session as SessionConfig;
use Exception;
@ -338,7 +339,7 @@ final class CommonFunctionsTest extends CIUnitTestCase
public function testCSRFToken()
{
Services::injectMock('security', new MockSecurity(new App()));
Services::injectMock('security', new MockSecurity(new SecurityConfig()));
$this->assertSame('csrf_test_name', csrf_token());
}
@ -498,7 +499,6 @@ final class CommonFunctionsTest extends CIUnitTestCase
public function testSlashItem()
{
$this->assertSame('en/', slash_item('defaultLocale')); // en
$this->assertSame('7200/', slash_item('CSRFExpire')); // int 7200
$this->assertSame('', slash_item('negotiateLocale')); // false
}

View File

@ -15,7 +15,7 @@ use CodeIgniter\Autoloader\FileLocator;
use CodeIgniter\Config\Services;
use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\Mock\MockSecurity;
use Config\App;
use Config\Security as SecurityConfig;
use ReflectionClass;
use ReflectionMethod;
@ -31,7 +31,7 @@ final class CommonSingleServiceTest extends CIUnitTestCase
*/
public function testSingleServiceWithNoParamsSupplied(string $service): void
{
Services::injectMock('security', new MockSecurity(new App()));
Services::injectMock('security', new MockSecurity(new SecurityConfig()));
$service1 = single_service($service);
$service2 = single_service($service);

View File

@ -43,6 +43,7 @@ use CodeIgniter\View\Cell;
use CodeIgniter\View\Parser;
use Config\App;
use Config\Exceptions;
use Config\Security as SecurityConfig;
use RuntimeException;
use Tests\Support\Config\Services;
@ -329,7 +330,7 @@ final class ServicesTest extends CIUnitTestCase
public function testResetSingle()
{
Services::injectMock('response', new MockResponse(new App()));
Services::injectMock('security', new MockSecurity(new App()));
Services::injectMock('security', new MockSecurity(new SecurityConfig()));
$response = service('response');
$security = service('security');
$this->assertInstanceOf(MockResponse::class, $response);
@ -411,7 +412,7 @@ final class ServicesTest extends CIUnitTestCase
public function testSecurity()
{
Services::injectMock('security', new MockSecurity(new App()));
Services::injectMock('security', new MockSecurity(new SecurityConfig()));
$result = Services::security();
$this->assertInstanceOf(Security::class, $result);

View File

@ -13,7 +13,7 @@ namespace CodeIgniter\Helpers;
use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\Mock\MockSecurity;
use Config\App;
use Config\Security as SecurityConfig;
use Tests\Support\Config\Services;
/**
@ -32,7 +32,7 @@ final class SecurityHelperTest extends CIUnitTestCase
public function testSanitizeFilenameSimpleSuccess()
{
Services::injectMock('security', new MockSecurity(new App()));
Services::injectMock('security', new MockSecurity(new SecurityConfig()));
$this->assertSame('hello.doc', sanitize_filename('hello.doc'));
}

View File

@ -38,19 +38,21 @@ final class SecurityCSRFCookieRandomizeTokenTest extends CIUnitTestCase
*/
private string $randomizedToken = '8bc70b67c91494e815c7d2219c1ae0ab005513c290126d34d41bf41c5265e0f1';
private SecurityConfig $config;
protected function setUp(): void
{
parent::setUp();
$_COOKIE = [];
$config = new SecurityConfig();
$config->csrfProtection = Security::CSRF_PROTECTION_COOKIE;
$config->tokenRandomize = true;
Factories::injectMock('config', 'Security', $config);
$this->config = new SecurityConfig();
$this->config->csrfProtection = Security::CSRF_PROTECTION_COOKIE;
$this->config->tokenRandomize = true;
Factories::injectMock('config', 'Security', $this->config);
// Set Cookie value
$security = new MockSecurity(new MockAppConfig());
$security = new MockSecurity($this->config);
$_COOKIE[$security->getCookieName()] = $this->hash;
$this->resetServices();
@ -58,7 +60,7 @@ final class SecurityCSRFCookieRandomizeTokenTest extends CIUnitTestCase
public function testTokenIsReadFromCookie()
{
$security = new MockSecurity(new MockAppConfig());
$security = new MockSecurity($this->config);
$this->assertSame(
$this->randomizedToken,
@ -74,7 +76,7 @@ final class SecurityCSRFCookieRandomizeTokenTest extends CIUnitTestCase
$request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent());
$security = new Security(new MockAppConfig());
$security = new Security($this->config);
$this->assertInstanceOf(Security::class, $security->verify($request));
$this->assertLogged('info', 'CSRF token verified.');

View File

@ -51,6 +51,8 @@ final class SecurityCSRFSessionRandomizeTokenTest extends CIUnitTestCase
*/
private string $randomizedToken = '8bc70b67c91494e815c7d2219c1ae0ab005513c290126d34d41bf41c5265e0f1';
private SecurityConfig $config;
protected function setUp(): void
{
parent::setUp();
@ -58,10 +60,10 @@ final class SecurityCSRFSessionRandomizeTokenTest extends CIUnitTestCase
$_SESSION = [];
Factories::reset();
$config = new SecurityConfig();
$config->csrfProtection = Security::CSRF_PROTECTION_SESSION;
$config->tokenRandomize = true;
Factories::injectMock('config', 'Security', $config);
$this->config = new SecurityConfig();
$this->config->csrfProtection = Security::CSRF_PROTECTION_SESSION;
$this->config->tokenRandomize = true;
Factories::injectMock('config', 'Security', $this->config);
$this->injectSession($this->hash);
}
@ -111,9 +113,14 @@ final class SecurityCSRFSessionRandomizeTokenTest extends CIUnitTestCase
Services::injectMock('session', $session);
}
private function createSecurity(): Security
{
return new Security($this->config);
}
public function testHashIsReadFromSession()
{
$security = new MockSecurity(new MockAppConfig());
$security = new MockSecurity($this->config);
$this->assertSame(
$this->randomizedToken,
@ -131,7 +138,7 @@ final class SecurityCSRFSessionRandomizeTokenTest extends CIUnitTestCase
$request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent());
$security = new Security(new MockAppConfig());
$security = $this->createSecurity();
$security->verify($request);
}
@ -146,7 +153,7 @@ final class SecurityCSRFSessionRandomizeTokenTest extends CIUnitTestCase
$request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent());
$security = new Security(new MockAppConfig());
$security = $this->createSecurity();
$security->verify($request);
}
@ -161,7 +168,7 @@ final class SecurityCSRFSessionRandomizeTokenTest extends CIUnitTestCase
$request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent());
$security = new Security(new MockAppConfig());
$security = $this->createSecurity();
$security->verify($request);
}
@ -174,7 +181,7 @@ final class SecurityCSRFSessionRandomizeTokenTest extends CIUnitTestCase
$request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent());
$security = new Security(new MockAppConfig());
$security = $this->createSecurity();
$this->assertInstanceOf(Security::class, $security->verify($request));
$this->assertLogged('info', 'CSRF token verified.');
@ -188,7 +195,7 @@ final class SecurityCSRFSessionRandomizeTokenTest extends CIUnitTestCase
$request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent());
$request->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005b');
$security = new Security(new MockAppConfig());
$security = $this->createSecurity();
$this->expectException(SecurityException::class);
$this->expectExceptionMessage('The action you requested is not allowed.');
@ -204,7 +211,7 @@ final class SecurityCSRFSessionRandomizeTokenTest extends CIUnitTestCase
$request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent());
$request->setHeader('X-CSRF-TOKEN', $this->randomizedToken);
$security = new Security(new MockAppConfig());
$security = $this->createSecurity();
$this->assertInstanceOf(Security::class, $security->verify($request));
$this->assertLogged('info', 'CSRF token verified.');
@ -218,7 +225,7 @@ final class SecurityCSRFSessionRandomizeTokenTest extends CIUnitTestCase
$request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent());
$request->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005b');
$security = new Security(new MockAppConfig());
$security = $this->createSecurity();
$this->expectException(SecurityException::class);
$this->expectExceptionMessage('The action you requested is not allowed.');
@ -233,7 +240,7 @@ final class SecurityCSRFSessionRandomizeTokenTest extends CIUnitTestCase
$request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent());
$request->setHeader('X-CSRF-TOKEN', $this->randomizedToken);
$security = new Security(new MockAppConfig());
$security = $this->createSecurity();
$this->assertInstanceOf(Security::class, $security->verify($request));
$this->assertLogged('info', 'CSRF token verified.');
@ -249,7 +256,7 @@ final class SecurityCSRFSessionRandomizeTokenTest extends CIUnitTestCase
$request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent());
$request->setBody('{"csrf_test_name":"8b9218a55906f9dcc1dc263dce7f005b"}');
$security = new Security(new MockAppConfig());
$security = $this->createSecurity();
$security->verify($request);
}
@ -261,7 +268,7 @@ final class SecurityCSRFSessionRandomizeTokenTest extends CIUnitTestCase
$request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent());
$request->setBody('{"csrf_test_name":"' . $this->randomizedToken . '","foo":"bar"}');
$security = new Security(new MockAppConfig());
$security = $this->createSecurity();
$this->assertInstanceOf(Security::class, $security->verify($request));
$this->assertLogged('info', 'CSRF token verified.');
@ -280,7 +287,7 @@ final class SecurityCSRFSessionRandomizeTokenTest extends CIUnitTestCase
$request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent());
$security = new MockSecurity(new MockAppConfig());
$security = new MockSecurity($this->config);
$oldHash = $security->getHash();
$security->verify($request);
@ -301,7 +308,7 @@ final class SecurityCSRFSessionRandomizeTokenTest extends CIUnitTestCase
$request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent());
$security = new Security(new MockAppConfig());
$security = $this->createSecurity();
$oldHash = $security->getHash();
$security->verify($request);

View File

@ -45,6 +45,8 @@ final class SecurityCSRFSessionTest extends CIUnitTestCase
*/
private string $hash = '8b9218a55906f9dcc1dc263dce7f005a';
private SecurityConfig $config;
protected function setUp(): void
{
parent::setUp();
@ -52,9 +54,9 @@ final class SecurityCSRFSessionTest extends CIUnitTestCase
$_SESSION = [];
Factories::reset();
$config = new SecurityConfig();
$config->csrfProtection = Security::CSRF_PROTECTION_SESSION;
Factories::injectMock('config', 'Security', $config);
$this->config = new SecurityConfig();
$this->config->csrfProtection = Security::CSRF_PROTECTION_SESSION;
Factories::injectMock('config', 'Security', $this->config);
$this->injectSession($this->hash);
}
@ -104,9 +106,14 @@ final class SecurityCSRFSessionTest extends CIUnitTestCase
Services::injectMock('session', $session);
}
private function createSecurity(): Security
{
return new Security($this->config);
}
public function testHashIsReadFromSession()
{
$security = new Security(new MockAppConfig());
$security = $this->createSecurity();
$this->assertSame($this->hash, $security->getHash());
}
@ -120,7 +127,7 @@ final class SecurityCSRFSessionTest extends CIUnitTestCase
$request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent());
$security = new Security(new MockAppConfig());
$security = $this->createSecurity();
$security->verify($request);
}
@ -133,7 +140,7 @@ final class SecurityCSRFSessionTest extends CIUnitTestCase
$request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent());
$security = new Security(new MockAppConfig());
$security = $this->createSecurity();
$this->assertInstanceOf(Security::class, $security->verify($request));
$this->assertLogged('info', 'CSRF token verified.');
@ -147,7 +154,7 @@ final class SecurityCSRFSessionTest extends CIUnitTestCase
$request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent());
$request->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005b');
$security = new Security(new MockAppConfig());
$security = $this->createSecurity();
$this->expectException(SecurityException::class);
$security->verify($request);
@ -161,7 +168,7 @@ final class SecurityCSRFSessionTest extends CIUnitTestCase
$request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent());
$request->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005a');
$security = new Security(new MockAppConfig());
$security = $this->createSecurity();
$this->assertInstanceOf(Security::class, $security->verify($request));
$this->assertLogged('info', 'CSRF token verified.');
@ -175,7 +182,7 @@ final class SecurityCSRFSessionTest extends CIUnitTestCase
$request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent());
$request->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005b');
$security = new Security(new MockAppConfig());
$security = $this->createSecurity();
$this->expectException(SecurityException::class);
$security->verify($request);
@ -188,7 +195,7 @@ final class SecurityCSRFSessionTest extends CIUnitTestCase
$request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent());
$request->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005a');
$security = new Security(new MockAppConfig());
$security = $this->createSecurity();
$this->assertInstanceOf(Security::class, $security->verify($request));
$this->assertLogged('info', 'CSRF token verified.');
@ -203,7 +210,7 @@ final class SecurityCSRFSessionTest extends CIUnitTestCase
$request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent());
$request->setBody('{"csrf_test_name":"8b9218a55906f9dcc1dc263dce7f005b"}');
$security = new Security(new MockAppConfig());
$security = $this->createSecurity();
$security->verify($request);
}
@ -215,7 +222,7 @@ final class SecurityCSRFSessionTest extends CIUnitTestCase
$request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent());
$request->setBody('{"csrf_test_name":"8b9218a55906f9dcc1dc263dce7f005a","foo":"bar"}');
$security = new Security(new MockAppConfig());
$security = $this->createSecurity();
$this->assertInstanceOf(Security::class, $security->verify($request));
$this->assertLogged('info', 'CSRF token verified.');
@ -233,7 +240,7 @@ final class SecurityCSRFSessionTest extends CIUnitTestCase
$request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent());
$security = new Security(new MockAppConfig());
$security = $this->createSecurity();
$oldHash = $security->getHash();
$security->verify($request);
@ -253,7 +260,7 @@ final class SecurityCSRFSessionTest extends CIUnitTestCase
$request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent());
$security = new Security(new MockAppConfig());
$security = $this->createSecurity();
$oldHash = $security->getHash();
$security->verify($request);

View File

@ -41,9 +41,16 @@ final class SecurityTest extends CIUnitTestCase
$this->resetServices();
}
private function createMockSecurity(?SecurityConfig $config = null): MockSecurity
{
$config ??= new SecurityConfig();
return new MockSecurity($config);
}
public function testBasicConfigIsSaved()
{
$security = new MockSecurity(new MockAppConfig());
$security = $this->createMockSecurity();
$hash = $security->getHash();
@ -55,7 +62,7 @@ final class SecurityTest extends CIUnitTestCase
{
$_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005a';
$security = new MockSecurity(new MockAppConfig());
$security = $this->createMockSecurity();
$this->assertSame(
'8b9218a55906f9dcc1dc263dce7f005a',
@ -65,7 +72,7 @@ final class SecurityTest extends CIUnitTestCase
public function testGetHashSetsCookieWhenGETWithoutCSRFCookie()
{
$security = new MockSecurity(new MockAppConfig());
$security = $this->createMockSecurity();
$_SERVER['REQUEST_METHOD'] = 'GET';
@ -80,7 +87,7 @@ final class SecurityTest extends CIUnitTestCase
$_SERVER['REQUEST_METHOD'] = 'GET';
$_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005a';
$security = new MockSecurity(new MockAppConfig());
$security = $this->createMockSecurity();
$security->verify(new Request(new MockAppConfig()));
@ -93,7 +100,7 @@ final class SecurityTest extends CIUnitTestCase
$_POST['csrf_test_name'] = '8b9218a55906f9dcc1dc263dce7f005a';
$_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005b';
$security = new MockSecurity(new MockAppConfig());
$security = $this->createMockSecurity();
$request = new IncomingRequest(
new MockAppConfig(),
new URI('http://badurl.com'),
@ -112,7 +119,7 @@ final class SecurityTest extends CIUnitTestCase
$_POST['csrf_test_name'] = '8b9218a55906f9dcc1dc263dce7f005a';
$_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005a';
$security = new MockSecurity(new MockAppConfig());
$security = $this->createMockSecurity();
$request = new IncomingRequest(
new MockAppConfig(),
new URI('http://badurl.com'),
@ -131,7 +138,7 @@ final class SecurityTest extends CIUnitTestCase
$_SERVER['REQUEST_METHOD'] = 'POST';
$_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005b';
$security = new MockSecurity(new MockAppConfig());
$security = $this->createMockSecurity();
$request = new IncomingRequest(
new MockAppConfig(),
new URI('http://badurl.com'),
@ -151,7 +158,7 @@ final class SecurityTest extends CIUnitTestCase
$_POST['foo'] = 'bar';
$_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005a';
$security = new MockSecurity(new MockAppConfig());
$security = $this->createMockSecurity();
$request = new IncomingRequest(
new MockAppConfig(),
new URI('http://badurl.com'),
@ -172,7 +179,7 @@ final class SecurityTest extends CIUnitTestCase
$_SERVER['REQUEST_METHOD'] = 'POST';
$_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005b';
$security = new MockSecurity(new MockAppConfig());
$security = $this->createMockSecurity();
$request = new IncomingRequest(
new MockAppConfig(),
new URI('http://badurl.com'),
@ -193,7 +200,7 @@ final class SecurityTest extends CIUnitTestCase
$_SERVER['REQUEST_METHOD'] = 'POST';
$_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005a';
$security = new MockSecurity(new MockAppConfig());
$security = $this->createMockSecurity();
$request = new IncomingRequest(
new MockAppConfig(),
new URI('http://badurl.com'),
@ -213,7 +220,7 @@ final class SecurityTest extends CIUnitTestCase
public function testSanitizeFilename()
{
$security = new MockSecurity(new MockAppConfig());
$security = $this->createMockSecurity();
$filename = './<!--foo-->';
@ -230,7 +237,7 @@ final class SecurityTest extends CIUnitTestCase
$config->regenerate = false;
Factories::injectMock('config', 'Security', $config);
$security = new MockSecurity(new MockAppConfig());
$security = new MockSecurity($config);
$request = new IncomingRequest(
new MockAppConfig(),
new URI('http://badurl.com'),
@ -255,7 +262,7 @@ final class SecurityTest extends CIUnitTestCase
$config->regenerate = false;
Factories::injectMock('config', 'Security', $config);
$security = new MockSecurity(new MockAppConfig());
$security = $this->createMockSecurity($config);
$request = new IncomingRequest(
new MockAppConfig(),
new URI('http://badurl.com'),
@ -281,7 +288,7 @@ final class SecurityTest extends CIUnitTestCase
$config->regenerate = true;
Factories::injectMock('config', 'Security', $config);
$security = new MockSecurity(new MockAppConfig());
$security = $this->createMockSecurity($config);
$request = new IncomingRequest(
new MockAppConfig(),
new URI('http://badurl.com'),
@ -298,7 +305,7 @@ final class SecurityTest extends CIUnitTestCase
public function testGetters(): void
{
$security = new MockSecurity(new MockAppConfig());
$security = $this->createMockSecurity();
$this->assertIsString($security->getHash());
$this->assertIsString($security->getTokenName());

View File

@ -40,18 +40,33 @@ Interface Changes
- **Validation:** Added the ``getValidated()`` method in ``ValidationInterface``.
.. _v440-method-signature-changes:
Method Signature Changes
========================
- **Routing:** The third parameter ``Routing $routing`` has been added to
``RouteCollection::__construct()``.
- **Validation:** The method signature of ``Validation::check()`` has been changed.
The ``string`` typehint on the ``$rule`` parameter was removed.
.. _v440-parameter-type-changes:
Parameter Type Changes
----------------------
- **Services:** The first parameter of ``Services::security()`` has been
changed from ``Config\App`` to ``Config\Security``.
- **Session:** The second parameter of ``Session::__construct()`` has been
changed from ``Config\App`` to ``Config\Session``.
- **Session:** The first parameter of ``__construct()`` in ``BaseHandler``,
``DatabaseHandler``, ``FileHandler``, ``MemcachedHandler``, and ``RedisHandler``
has been changed from ``Config\App`` to ``Config\Session``.
- **Security:** The first parameter of ``Security::__construct()`` has been
changed from ``Config\App`` to ``Config\Security``.
- **Validation:** The method signature of ``Validation::check()`` has been changed.
The ``string`` typehint on the ``$rule`` parameter was removed.
Added Parameters
----------------
- **Routing:** The third parameter ``Routing $routing`` has been added to
``RouteCollection::__construct()``.
Enhancements
************
@ -138,6 +153,7 @@ Changes
- **Images:** The default quality for WebP in ``GDHandler`` has been changed from 80 to 90.
- **Config:** The deprecated Cookie items in **app/Config/App.php** has been removed.
- **Config:** The deprecated Session items in **app/Config/App.php** has been removed.
- **Config:** The deprecated CSRF items in **app/Config/App.php** has been removed.
- **Config:** Routing settings have been moved to **app/Config/Routing.php** config file.
See :ref:`Upgrading Guide <upgrade-440-config-routing>`.
- **DownloadResponse:** When generating response headers, does not replace the ``Content-Disposition`` header if it was previously specified.
@ -168,6 +184,10 @@ Deprecations
``$sessionExpiration``, ``$sessionSavePath``, ``$sessionMatchIP``,
``$sessionTimeToUpdate``, and ``$sessionRegenerateDestroy`` in ``Session`` are
deprecated, and no longer used. Use ``$config`` instead.
- **Security:** The property ``$csrfProtection``, ``$tokenRandomize``,
``$tokenName``, ``$headerName``, ``$expires``, ``$regenerate``, and
``$redirect`` in ``Security`` are deprecated, and no longer used. Use
``$config`` instead.
Bugs Fixed
**********

View File

@ -66,6 +66,17 @@ Interface Changes
Some interface changes have been made. Classes that implement them should update
their APIs to reflect the changes. See :ref:`v440-interface-changes` for details.
Method Signature Changes
========================
Some method signature changes have been made. Classes that extend them should
update their APIs to reflect the changes. See :ref:`v440-method-signature-changes`
for details.
Also, the parameter types of some constructors and ``Services::security()`` have changed.
If you call them with the parameters, change the parameter values.
See :ref:`v440-parameter-type-changes` for details.
RouteCollection::$routes
========================
@ -115,6 +126,16 @@ The Cookie config items in **app/Config/App.php** are no longer used.
2. Remove the properties (from ``$cookiePrefix`` to ``$cookieSameSite``) in
**app/Config/App.php**.
app/Config/Security.php
-----------------------
The CSRF config items in **app/Config/App.php** are no longer used.
1. Copy **app/Config/Security.php** from the new framework to your **app/Config**
directory, and configure it.
2. Remove the properties (from ``$CSRFTokenName`` to ``$CSRFSameSite``) in
**app/Config/App.php**.
app/Config/Session.php
----------------------