forked from msyk/FMDataAPI
-
Notifications
You must be signed in to change notification settings - Fork 0
MT-2107 Add persistent session support with automatic token renewal and retry #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
filiptorphage-mjuk
wants to merge
40
commits into
master
Choose a base branch
from
dev-add-persistent-sessions
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
40 commits
Select commit
Hold shift + click to select a range
9cf6afa
Centralized `startCommunication` and `endCommunication` into Communic…
filiptorphage-mjuk 699d468
Added retry mechanism on `callRestAPI` on authentication errors.
filiptorphage-mjuk 311a768
Improved logic for setting inCommunicationScope in startCommunication…
filiptorphage-mjuk 5b18b9f
Now uses the result of login on retrying
filiptorphage-mjuk 43e1712
Clarified documentation on setRetryOnAccessTokenInvalidation
filiptorphage-mjuk c82c201
Replaced inCommunicationScope with keepAuth
filiptorphage-mjuk a415dee
Added minor documentation to the callRestAPI functions to clarify the…
filiptorphage-mjuk ab895f7
Added initial persistent session setup and session cache interface.
filiptorphage-mjuk fbf66ca
Adjusted logic of startCommunication and endCommunication to handle p…
filiptorphage-mjuk 8e3b442
Made callRestAPIWithoutRetry private and made callRestAPI the only en…
filiptorphage-mjuk 45c3445
Converted error code to int
filiptorphage-mjuk 7e748bc
Made callRestAPIWithoutRetry protected and made TestProvider override it
filiptorphage-mjuk cceb0f4
Added comment to explain edge case of orphaned tokens
filiptorphage-mjuk 73c72d9
Removed `PersistentSessionStore` and replaced it with `AbstractSessio…
filiptorphage-mjuk 2c091d5
Added methods to override internal session cache properties
filiptorphage-mjuk bbc8020
Updated documentation to reflect that specifying a session automatica…
filiptorphage-mjuk 1185f84
Cleared up documentation of startCommunication and endCommunication
filiptorphage-mjuk 238e891
Clarified session cache behavior
filiptorphage-mjuk 9fead75
Fixed the cache key generation
filiptorphage-mjuk f95432f
Added information that the APCu imlementation is not atomic
filiptorphage-mjuk 57f4741
Added suggestions to composer.json
filiptorphage-mjuk 720aea2
Added adapters for converting PSR-6 and PSR-16 cache implementations …
filiptorphage-mjuk 39cb1af
Added resumeScopeAfterReauth property to start a communication sessio…
filiptorphage-mjuk 1edfebf
Fixed setting cache key when no cache was provided
filiptorphage-mjuk be501ea
Corrected name of doc reference
filiptorphage-mjuk 5e2d5e8
Added exceptions on trying to modify session cache properties when no…
filiptorphage-mjuk 5a2b8f3
Now resumeScopeAfterReauth to false within endCommunication to not ac…
filiptorphage-mjuk a15fd28
Removed unused property
filiptorphage-mjuk ccd4acc
Now `resumeScopeAfterReath` is only used when a login attempt failed,…
filiptorphage-mjuk c4b0685
Fixed `resumeScopeAfterReauth` not being set if login() returned false
filiptorphage-mjuk e87bc8b
Better logic to set resumeScopeAfterReath
filiptorphage-mjuk d32d5c6
Removed PSR-6 and PSR-16 wrappers due to scope creep. Moved to a new …
filiptorphage-mjuk 1a93949
Set implode separator to null byte (\0)
filiptorphage-mjuk 4b60506
Removed misleading composer json suggestions of removed files.
filiptorphage-mjuk f33f01e
Fixed logic for setting keepAuth and resumeScopeAfterReauth
filiptorphage-mjuk 79bd44e
Fixed so retrieving a cached session token now sets keepAuth when it …
filiptorphage-mjuk 51d9f09
Fixed documentation of ApcuSessionCache
filiptorphage-mjuk a4d9665
Moved around logic in callRestAPI to make it clearer to read
filiptorphage-mjuk 9c34cee
Improved clarity of ApcuSessionCache suggestion
filiptorphage-mjuk 42f2e76
Enforced strict types declaration in ApcuSessionCache.
filiptorphage-mjuk File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace INTERMediator\FileMakerServer\RESTAPI\SessionCache; | ||
|
|
||
| /** | ||
| * Base class for session cache implementations. | ||
| * | ||
| * Provides the cache key and TTL to concrete implementations, both of which | ||
| * are managed internally by the library. The cache key and TTL will not change | ||
| * during a single PHP request. | ||
| * | ||
| * As this cache stores FileMaker Data API session tokens, which are sensitive | ||
| * credentials granting full API access on behalf of the authenticated user, | ||
| * implementors must ensure that the underlying cache storage is secure and | ||
| * not accessible to unauthorized parties. | ||
| * | ||
| * To provide a custom cache backend, extend this class and implement | ||
| * {@see SessionCacheInterface::get()}, {@see SessionCacheInterface::set()}, | ||
| * and {@see SessionCacheInterface::delete()}, using {@see self::$cacheKey} | ||
| * and {@see self::$ttl} in your implementations. | ||
| * | ||
| * Example: | ||
| * | ||
| * class RedisSessionCache extends AbstractSessionCache | ||
| * { | ||
| * public function get(): ?string | ||
| * { | ||
| * return $this->redis->get($this->cacheKey) ?? null; | ||
| * } | ||
| * | ||
| * public function set(string $value): bool | ||
| * { | ||
| * return $this->redis->setex($this->cacheKey, $this->ttl, $value); | ||
| * } | ||
| * | ||
| * public function delete(): bool | ||
| * { | ||
| * return $this->redis->del($this->cacheKey) > 0; | ||
| * } | ||
| * } | ||
| * | ||
| * @see SessionCacheInterface | ||
| */ | ||
| abstract class AbstractSessionCache implements SessionCacheInterface | ||
| { | ||
| /** | ||
| * The cache key for the current session. | ||
| * | ||
| * Always set by the library via {@see self::setCacheKey()} before any cache | ||
| * operation is performed. Will not change during a single PHP request. | ||
| * Implementing classes should use this property directly in their | ||
| * {@see SessionCacheInterface::get()}, {@see SessionCacheInterface::set()}, | ||
| * and {@see SessionCacheInterface::delete()} implementations. | ||
| */ | ||
| protected string $cacheKey; | ||
|
|
||
| /** | ||
| * The time-to-live in seconds for cached session tokens. | ||
| * | ||
| * Set by the library via {@see self::setTtl()} before any cache operation | ||
| * is performed, defaulting to the value provided at construction time. | ||
| * Will not change during a single PHP request. Implementing classes should | ||
| * use this property directly in their {@see SessionCacheInterface::set()} implementation. | ||
| * | ||
| */ | ||
| protected int $ttl; | ||
|
|
||
| /** | ||
| * @param int $defaultTtl Default time-to-live in seconds for cached session tokens. | ||
| * Defaults to 840 seconds (14 minutes), reflecting the | ||
| * default FileMaker Data API session timeout. Adjust this | ||
| * value if your FileMaker Server is configured with a | ||
| * different session timeout. | ||
| */ | ||
| public function __construct(int $defaultTtl = 840) | ||
| { | ||
| $this->ttl = $defaultTtl; | ||
| } | ||
|
|
||
| /** | ||
| * Sets the cache key for the current session. | ||
| * | ||
| * This method is called internally by the library and should not be called | ||
| * manually. The key will not change during a single PHP request. | ||
| * | ||
| * @param string $key The cache key to use for subsequent cache operations. | ||
| */ | ||
| final public function setCacheKey(string $key): void | ||
| { | ||
| $this->cacheKey = $key; | ||
| } | ||
|
|
||
| /** | ||
| * Sets the time-to-live for cached session tokens. | ||
| * | ||
| * This method is called internally by the library and should not be called | ||
| * manually. The TTL will not change during a single PHP request. | ||
| * | ||
| * @param int $ttl Time-to-live in seconds for the cached session token. | ||
| */ | ||
| final public function setTtl(int $ttl): void | ||
| { | ||
| $this->ttl = $ttl; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace INTERMediator\FileMakerServer\RESTAPI\SessionCache; | ||
|
|
||
| use RuntimeException; | ||
|
|
||
| /** | ||
| * APCu-based session cache implementation. | ||
| * | ||
| * Caches FileMaker Data API session tokens using APCu, which stores data in | ||
| * shared memory on the server. Note that APCu cache is shared across all PHP | ||
| * processes on the same server, so cache keys must be sufficiently unique to | ||
| * avoid collisions between different users or applications. | ||
| * | ||
| * APCu is not enabled by default on all PHP installations. This implementation | ||
| * is provided as a default for those that have APCu enabled. If APCu is not | ||
| * available, a custom extension of {@see AbstractSessionCache} should be used | ||
| * instead. | ||
| * | ||
|
filiptorphage-mjuk marked this conversation as resolved.
|
||
| * As this cache stores sensitive FileMaker Data API session tokens, APCu is | ||
| * only appropriate in environments where server memory access is properly | ||
| * restricted. | ||
| * | ||
| * Note that cache operations in this implementation are not atomic. While care | ||
| * has been taken to minimize the risk of race conditions, concurrent requests | ||
| * sharing the same cache key may occasionally result in redundant | ||
| * re-authentication against the FileMaker Server. This is considered an | ||
| * acceptable trade-off given the constraints of the current implementation. | ||
| * | ||
| * @package INTER-Mediator\FileMakerServer\RESTAPI\SessionCache | ||
| * @link https://github.com/msyk/FMDataAPI GitHub Repository | ||
| * @version 36 | ||
| */ | ||
| class ApcuSessionCache extends AbstractSessionCache | ||
| { | ||
| /** | ||
| * ApcuSessionCache constructor. | ||
| * @throws RuntimeException If APCu is not available. | ||
| */ | ||
| public function __construct() | ||
| { | ||
| parent::__construct(); | ||
| if (!function_exists('apcu_enabled') || !apcu_enabled()) { | ||
| throw new RuntimeException("APCu is required to use ApcuSessionCache."); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Retrieves the cached FileMaker Data API session token for the current session. | ||
| * | ||
| * @return string|null The cached session token, or null if no token exists | ||
| * for the current key. | ||
| */ | ||
| public function get(): string|null | ||
| { | ||
| $value = apcu_fetch($this->cacheKey, $success); | ||
| return $success && is_string($value) ? $value : null; | ||
| } | ||
|
|
||
| /** | ||
| * Persists a FileMaker Data API session token in APCu. | ||
| * | ||
| * @param string $value The FileMaker Data API session token to store. | ||
| * This is a sensitive credential and must be treated as such. | ||
| * @return bool True on success, false on failure. | ||
| */ | ||
| public function set(string $value): bool | ||
| { | ||
| return apcu_store($this->cacheKey, $value, $this->ttl); | ||
| } | ||
|
|
||
| /** | ||
| * Deletes the cached FileMaker Data API session token. | ||
| * | ||
| * Returns false both when the key does not exist and when deletion fails. | ||
| * | ||
| * @return bool True on success, false if the key did not exist or deletion failed. | ||
| */ | ||
| public function delete(): bool | ||
| { | ||
| return apcu_delete($this->cacheKey); | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.