Skip to content
This repository has been archived by the owner on Jan 29, 2020. It is now read-only.

Add options for cookie domain, secure, and httponly #7

Merged
merged 3 commits into from Jan 22, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
24 changes: 23 additions & 1 deletion docs/book/v1/config.md
Expand Up @@ -4,7 +4,10 @@ This package allows configuring the following items:

- The PSR-6 `CacheItemPoolInterface` service to use.
- The session cookie name.
- The session cookie domain.
- The session cookie path.
- The session cookie secure option.
- The session cookie httponly option.
- The cache limiter (which controls how resources using sessions are cached by the browser).
- When the session expires.
- When the resource using a session was last modified.
Expand Down Expand Up @@ -92,9 +95,28 @@ return [
// the syntax outlined in https://tools.ietf.org/html/rfc6265.html
'cookie_name' => 'PHPSESSION',

// The (sub)domain that the cookie is available to. Setting this
// to a subdomain (such as 'www.example.com') will make the cookie
// available to that subdomain and all other sub-domains of it
// (i.e. w2.www.example.com). To make the cookie available to the
// whole domain (including all subdomains of it), simply set the
// value to the domain name ('example.com', in this case).
// Leave this null to use browser default (current hostname).
'cookie_domain' => null,

// The path prefix of the cookie domain to which it applies.
'cookie_path' => '/',

// Indicates that the cookie should only be transmitted over a
// secure HTTPS connection from the client. When set to TRUE, the
// cookie will only be set if a secure connection exists.
'cookie_secure' => false,

// When TRUE the cookie will be made accessible only through the
// HTTP protocol. This means that the cookie won't be accessible
// by scripting languages, such as JavaScript.
'cookie_http_only' => false,

// Governs the various cache control headers emitted when
// a session cookie is provided to the client. Value may be one
// of "nocache", "public", "private", or "private_no_expire";
Expand Down Expand Up @@ -131,7 +153,7 @@ return [

## Using the service

By default, this package define the service `Zend\Expressive\Session\Cache\CacheSessionPersistence`,
By default, this package define the service `Zend\Expressive\Session\Cache\CacheSessionPersistence`,
assigning it to the factory `Zend\Expressive\Session\Cache\CacheSessionPersistenceFactory`.
After you have installed the package, you will need to tell your application to
use this service when using the `SessionMiddleware`.
Expand Down
6 changes: 6 additions & 0 deletions docs/book/v1/manual.md
Expand Up @@ -29,7 +29,10 @@ The following details the constructor of the `Zend\Expressive\Session\Cache\Cach
public function __construct(
\Psr\Cache\CacheItemPoolInterface $cache,
string $cookieName,
string $cookieDomain = null,
string $cookiePath = '/',
bool $cookieSecure = false,
bool $cookieHttpOnly = false,
marcguyer marked this conversation as resolved.
Show resolved Hide resolved
string $cacheLimiter = 'nocache',
int $cacheExpire = 10800,
?int $lastModified = null,
Expand All @@ -48,7 +51,10 @@ $cachePool = new PredisCachePool('tcp://localhost:6379');
$persistence = new CacheSessionPersistence(
$cachePool,
'MYSITE',
null
'/',
false,
false,
marcguyer marked this conversation as resolved.
Show resolved Hide resolved
'public',
60 * 60 * 24 * 30 // 30 days
);
Expand Down
23 changes: 22 additions & 1 deletion src/CacheSessionPersistence.php
Expand Up @@ -72,9 +72,18 @@ class CacheSessionPersistence implements SessionPersistenceInterface
/** @var string */
private $cookieName;

/** @var string|null */
private $cookieDomain;

/** @var string */
private $cookiePath;

/** @var bool */
private $cookieSecure;

/** @var bool */
private $cookieHttpOnly;

/** @var false|string */
private $lastModified;

Expand Down Expand Up @@ -107,7 +116,10 @@ class CacheSessionPersistence implements SessionPersistenceInterface
public function __construct(
CacheItemPoolInterface $cache,
string $cookieName,
string $cookieDomain = null,
string $cookiePath = '/',
bool $cookieSecure = false,
bool $cookieHttpOnly = false,
marcguyer marked this conversation as resolved.
Show resolved Hide resolved
string $cacheLimiter = 'nocache',
int $cacheExpire = 10800,
?int $lastModified = null,
Expand All @@ -120,8 +132,14 @@ public function __construct(
}
$this->cookieName = $cookieName;

$this->cookieDomain = $cookieDomain;

$this->cookiePath = $cookiePath;

$this->cookieSecure = $cookieSecure;

$this->cookieHttpOnly = $cookieHttpOnly;

$this->cacheLimiter = in_array($cacheLimiter, self::SUPPORTED_CACHE_LIMITERS, true)
? $cacheLimiter
: 'nocache';
Expand Down Expand Up @@ -165,7 +183,10 @@ public function persistSession(SessionInterface $session, ResponseInterface $res

$sessionCookie = SetCookie::create($this->cookieName)
->withValue($id)
->withPath($this->cookiePath);
->withDomain($this->cookieDomain)
->withPath($this->cookiePath)
->withSecure($this->cookieSecure)
->withHttpOnly($this->cookieHttpOnly);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quick question: will these calls be problematic if the values are null?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only value that could be null is $this->cookieDomain and SetCookie::withDomain accepts a null value. Both $this->cookieSecure and $this->cookieHttpOnly are boolean values. Both SetCookie::withSecure and SetCookie::withHttpOnly only accept boolean values. In all cases, calling these methods with the default values as arguments will not change behavior.


$persistenceDuration = $this->getPersistenceDuration($session);
if ($persistenceDuration) {
Expand Down
18 changes: 12 additions & 6 deletions src/CacheSessionPersistenceFactory.php
Expand Up @@ -25,17 +25,23 @@ public function __invoke(ContainerInterface $container)
throw Exception\MissingDependencyException::forService($cacheService);
}

$cookieName = $config['cookie_name'] ?? 'PHPSESSION';
$cookiePath = $config['cookie_path'] ?? '/';
$cacheLimiter = $config['cache_limiter'] ?? 'nocache';
$cacheExpire = $config['cache_expire'] ?? 10800;
$lastModified = $config['last_modified'] ?? null;
$persistent = $config['persistent'] ?? false;
$cookieName = $config['cookie_name'] ?? 'PHPSESSION';
$cookieDomain = $config['cookie_domain'] ?? null;
$cookiePath = $config['cookie_path'] ?? '/';
$cookieSecure = $config['cookie_secure'] ?? false;
$cookieHttpOnly = $config['cookie_http_only'] ?? false;
$cacheLimiter = $config['cache_limiter'] ?? 'nocache';
$cacheExpire = $config['cache_expire'] ?? 10800;
$lastModified = $config['last_modified'] ?? null;
$persistent = $config['persistent'] ?? false;

return new CacheSessionPersistence(
$container->get($cacheService),
$cookieName,
$cookieDomain,
$cookiePath,
$cookieSecure,
$cookieHttpOnly,
$cacheLimiter,
$cacheExpire,
$lastModified,
Expand Down
21 changes: 15 additions & 6 deletions test/CacheSessionPersistenceFactoryTest.php
Expand Up @@ -55,6 +55,9 @@ public function testFactoryUsesSaneDefaultsForConstructorArguments()
// These we did not
$this->assertAttributeSame('PHPSESSION', 'cookieName', $persistence);
$this->assertAttributeSame('/', 'cookiePath', $persistence);
$this->assertAttributeSame(null, 'cookieDomain', $persistence);
$this->assertAttributeSame(false, 'cookieSecure', $persistence);
$this->assertAttributeSame(false, 'cookieHttpOnly', $persistence);
$this->assertAttributeSame('nocache', 'cacheLimiter', $persistence);
$this->assertAttributeSame(10800, 'cacheExpire', $persistence);
$this->assertAttributeNotEmpty('lastModified', $persistence);
Expand All @@ -70,12 +73,15 @@ public function testFactoryAllowsConfiguringAllConstructorArguments()
$this->container->has('config')->willReturn(true);
$this->container->get('config')->willReturn([
'zend-expressive-session-cache' => [
'cookie_name' => 'TESTING',
'cookie_path' => '/api',
'cache_limiter' => 'public',
'cache_expire' => 300,
'last_modified' => $lastModified,
'persistent' => true,
'cookie_name' => 'TESTING',
'cookie_domain' => 'example.com',
'cookie_path' => '/api',
'cookie_secure' => true,
'cookie_http_only' => true,
'cache_limiter' => 'public',
'cache_expire' => 300,
'last_modified' => $lastModified,
'persistent' => true,
],
]);
$this->container->has(CacheItemPoolInterface::class)->willReturn(true);
Expand All @@ -87,6 +93,9 @@ public function testFactoryAllowsConfiguringAllConstructorArguments()
$this->assertAttributeSame($cachePool, 'cache', $persistence);
$this->assertAttributeSame('TESTING', 'cookieName', $persistence);
$this->assertAttributeSame('/api', 'cookiePath', $persistence);
$this->assertAttributeSame('example.com', 'cookieDomain', $persistence);
$this->assertAttributeSame(true, 'cookieSecure', $persistence);
$this->assertAttributeSame(true, 'cookieHttpOnly', $persistence);
$this->assertAttributeSame('public', 'cacheLimiter', $persistence);
$this->assertAttributeSame(300, 'cacheExpire', $persistence);
$this->assertAttributeSame(
Expand Down
48 changes: 48 additions & 0 deletions test/CacheSessionPersistenceTest.php
Expand Up @@ -270,7 +270,10 @@ public function testConstructorUsesDefaultsForOptionalArguments()
$this->assertAttributeSame('test', 'cookieName', $persistence);

// These we did not
$this->assertAttributeSame(null, 'cookieDomain', $persistence);
$this->assertAttributeSame('/', 'cookiePath', $persistence);
$this->assertAttributeSame(false, 'cookieSecure', $persistence);
$this->assertAttributeSame(false, 'cookieHttpOnly', $persistence);
$this->assertAttributeSame('nocache', 'cacheLimiter', $persistence);
$this->assertAttributeSame(10800, 'cacheExpire', $persistence);
$this->assertAttributeNotEmpty('lastModified', $persistence);
Expand All @@ -296,7 +299,10 @@ public function testConstructorAllowsProvidingAllArguments($cacheLimiter)
$persistence = new CacheSessionPersistence(
$this->cachePool->reveal(),
'test',
'example.com',
'/api',
true,
true,
$cacheLimiter,
100,
$lastModified
Expand All @@ -305,6 +311,9 @@ public function testConstructorAllowsProvidingAllArguments($cacheLimiter)
$this->assertAttributeSame($this->cachePool->reveal(), 'cache', $persistence);
$this->assertAttributeSame('test', 'cookieName', $persistence);
$this->assertAttributeSame('/api', 'cookiePath', $persistence);
$this->assertAttributeSame('example.com', 'cookieDomain', $persistence);
$this->assertAttributeSame(true, 'cookieSecure', $persistence);
$this->assertAttributeSame(true, 'cookieHttpOnly', $persistence);
$this->assertAttributeSame($cacheLimiter, 'cacheLimiter', $persistence);
$this->assertAttributeSame(100, 'cacheExpire', $persistence);
$this->assertAttributeSame(
Expand All @@ -319,13 +328,19 @@ public function testDefaultsToNocacheIfInvalidCacheLimiterProvided()
$persistence = new CacheSessionPersistence(
$this->cachePool->reveal(),
'test',
'example.com',
'/api',
true,
true,
'not-valid'
);

$this->assertAttributeSame($this->cachePool->reveal(), 'cache', $persistence);
$this->assertAttributeSame('test', 'cookieName', $persistence);
$this->assertAttributeSame('example.com', 'cookieDomain', $persistence);
$this->assertAttributeSame('/api', 'cookiePath', $persistence);
$this->assertAttributeSame(true, 'cookieSecure', $persistence);
$this->assertAttributeSame(true, 'cookieHttpOnly', $persistence);
$this->assertAttributeSame('nocache', 'cacheLimiter', $persistence);
}

Expand Down Expand Up @@ -412,7 +427,10 @@ public function testPersistSessionWithNoIdentifierAndPopulatedDataPersistsDataAn
$persistence = new CacheSessionPersistence(
$this->cachePool->reveal(),
'test',
null,
'/',
false,
false,
$cacheLimiter,
10800,
time()
Expand Down Expand Up @@ -446,7 +464,10 @@ public function testPersistSessionWithIdentifierAndPopulatedDataPersistsDataAndS
$persistence = new CacheSessionPersistence(
$this->cachePool->reveal(),
'test',
null,
'/',
false,
false,
$cacheLimiter,
10800,
time()
Expand Down Expand Up @@ -476,7 +497,10 @@ public function testPersistSessionRequestingRegenerationPersistsDataAndSetsHeade
$persistence = new CacheSessionPersistence(
$this->cachePool->reveal(),
'test',
null,
'/',
false,
false,
$cacheLimiter,
10800,
time()
Expand Down Expand Up @@ -517,7 +541,10 @@ public function testPersistSessionRequestingRegenerationRemovesPreviousSession(s
$persistence = new CacheSessionPersistence(
$this->cachePool->reveal(),
'test',
null,
'/',
false,
false,
$cacheLimiter,
10800,
time()
Expand Down Expand Up @@ -558,7 +585,10 @@ public function testPersistSessionWithIdentifierAndChangedDataPersistsDataAndSet
$persistence = new CacheSessionPersistence(
$this->cachePool->reveal(),
'test',
null,
'/',
false,
false,
$cacheLimiter,
10800,
time()
Expand Down Expand Up @@ -599,7 +629,10 @@ public function testPersistSessionDeletesPreviousSessionIfItExists(string $cache
$persistence = new CacheSessionPersistence(
$this->cachePool->reveal(),
'test',
null,
'/',
false,
false,
$cacheLimiter,
10800,
time()
Expand Down Expand Up @@ -677,7 +710,10 @@ public function testPersistentSessionCookieIncludesExpiration()
$persistence = new CacheSessionPersistence(
$this->cachePool->reveal(),
'test',
null,
'/',
false,
false,
'nocache',
600, // expiry
time(),
Expand Down Expand Up @@ -744,7 +780,10 @@ public function testPersistenceDurationSpecifiedInSessionOverridesExpiryWhenSess
$persistence = new CacheSessionPersistence(
$this->cachePool->reveal(),
'test',
null,
'/',
false,
false,
'nocache',
600, // expiry
time(),
Expand Down Expand Up @@ -829,7 +868,10 @@ public function testPersistenceDurationOfZeroWithoutSessionLifetimeKeyInDataResu
$persistence = new CacheSessionPersistence(
$this->cachePool->reveal(),
'test',
null,
'/',
false,
false,
'nocache',
600, // expiry
time(),
Expand Down Expand Up @@ -872,7 +914,10 @@ public function testPersistenceDurationOfZeroIgnoresGlobalPersistenceExpiry()
$persistence = new CacheSessionPersistence(
$this->cachePool->reveal(),
'test',
null,
'/',
false,
false,
'nocache',
600, // expiry
time(),
Expand Down Expand Up @@ -919,7 +964,10 @@ public function testPersistenceDurationInSessionDataWithValueOfZeroIgnoresGlobal
$persistence = new CacheSessionPersistence(
$this->cachePool->reveal(),
'test',
null,
'/',
false,
false,
'nocache',
600, // expiry
time(),
Expand Down