cakephp / cakephp/authentication
Next major: add preserveImpersonation option to setIdentity() / clearIdentity()
Nobody has claimed this yet.
- Dominant language
- PHP
- Stars
- 118
- Forks
- 104
- Avg merge
- 1d 16h
- Merged PRs (30d)
- 3
Description
Background
PR #788 added AuthenticationComponent::replaceIdentity() for the common request-only identity refresh case (e.g. attaching eager-loaded associations in beforeFilter() without ending an active impersonation).
An earlier iteration of that PR also expanded two existing signatures:
AuthenticationComponent::setIdentity(ArrayAccess|array $identity, bool $preserveImpersonation = false)AuthenticationService::clearIdentity(ServerRequestInterface $request, ResponseInterface $response, bool $stopImpersonation = true)
Those were reverted before merge to keep the public API surface unchanged on the 4.x minor. The signature growth belongs in the next major, where adding the flag to PersistenceInterface::clearIdentity() itself is clean.
Proposal for the next major
Add a first-class "persist a refreshed identity while keeping impersonation alive" path. Unlike replaceIdentity() (request attribute only, lost on the next request), this survives into subsequent requests.
1. Extend the interface
// PersistenceInterface
public function clearIdentity(
ServerRequestInterface $request,
ResponseInterface $response,
bool $stopImpersonation = true,
): array;
2. Honor the flag in AuthenticationService::clearIdentity()
public function clearIdentity(
ServerRequestInterface $request,
ResponseInterface $response,
bool $stopImpersonation = true,
): array {
foreach ($this->authenticators() as $authenticator) {
if ($authenticator instanceof PersistenceInterface) {
if (
$stopImpersonation
&& $authenticator instanceof ImpersonationInterface
&& $authenticator->isImpersonating($request)
) {
$stopImpersonationResult = $authenticator->stopImpersonating($request, $response);
['request' => $request, 'response' => $response] = $stopImpersonationResult;
}
$result = $authenticator->clearIdentity($request, $response);
['request' => $request, 'response' => $response] = $result;
}
}
if ($stopImpersonation) {
$this->_successfulAuthenticator = null;
}
return [
'request' => $request->withoutAttribute($this->getConfig('identityAttribute')),
'response' => $response,
];
}
3. Add the opt-in to the component
public function setIdentity(ArrayAccess|array $identity, bool $preserveImpersonation = false)
{
$controller = $this->getController();
$service = $this->getAuthenticationService();
$service->clearIdentity(
$controller->getRequest(),
$controller->getResponse(),
stopImpersonation: !$preserveImpersonation,
);
/** @var array{request: \Cake\Http\ServerRequest, response: \Cake\Http\Response} $result */
$result = $service->persistIdentity(
$controller->getRequest(),
$controller->getResponse(),
$identity,
);
$controller->setRequest($result['request']);
$controller->setResponse($result['response']);
return $this;
}
Usage
// Refresh the impersonated user and keep it across requests, without
// reverting to the impersonator:
$this->Authentication->setIdentity($reloaded, preserveImpersonation: true);
Note this also skips the session rotation that the default setIdentity() flow performs - it is a refresh, not a privilege transition, so it must not be used for login or role changes. That caveat should be documented.
Notes
- Because
clearIdentity()is onPersistenceInterface, adding the parameter there is a hard BC break and is why this is deferred to the major. - Tests for both the
preserveImpersonation: truepersist case and the default-ends-impersonation case existed in the PR branch history and can be lifted from there.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with PersistenceInterface, AuthenticationService::clearIdentity(), and AuthenticationComponent::setIdentity(), then inspect the existing tests and PR #788 branch history. Done means the preserveImpersonation path persists refreshed identities across requests, the default path still ends impersonation, and the session-rotation caveat is documented.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- php
- Domain
- authentication, backend-api-design
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100