Platform Identity, Session And Impersonation — Source Authority¶
- Status:
CURRENT SOURCE-AUTHORITY MAP / DOCUMENTATION ONLY - Current source baseline:
qa/master@3c084671c034f8f5136b02dce990ecff6c66d107 - Related documentation:
Platform foundation index - Target: React + Next.js adapters over one framework-independent identity/session contract
- Phase implementation:
USER HOLD - Effects: no Runtime, DB, role, account, password, session, provider, Wiki DB or deployment mutation
1. Authority Decision¶
Identity, authentication, session and impersonation answer different questions.
Credential verification
= may this credential start an authenticated session?
Physical actor
= which person/system actually initiated the request?
Effective subject
= which user identity is being represented?
Tenant target
= which tenant owns the requested business data?
Session
= which authenticated interaction continuity is active?
Impersonation
= which explicit actor-to-subject or actor-to-tenant delegation is active?
Authorization
= may this actor/subject perform this action on this record?
A successful answer to one question does not imply the others.
1.1 Required invariants¶
Actor != Subject
Authenticated != Authorized
Session active != Tenant target valid
Impersonation active != Super-admin actor erased
Password changed != all sessions revoked
Provider-linked identity != local user authority
Client-side session metadata != backend authorization
1.2 No generic identity Process ID¶
This is a shared platform foundation, not one L3 business process. Do not add a generic identity Process merely to register login/session concerns. Business processes consume a typed identity and access result.
2. Current Source Families¶
| Source | Current responsibility | Important limitation |
|---|---|---|
login.php |
username/password lookup, password verification/rehash, session regeneration and original session fields | no visible application lockout/MFA/rate-limit; username lookup is not tenant-qualified |
config/session.php |
cookie/session parameters and 20-hour lifetime | one TTL used for cookie and GC; no separate idle/absolute/revocation model; @session_start() |
app/platform/auth/password_helper.php |
bcrypt writes plus legacy SHA-512 compatibility verification | legacy shared salt remains until legacy callers/data reach zero |
app/platform/auth/account_post_helper.php |
current-password verification and own-password update | no session regeneration or other-session invalidation is visible |
app/platform/audit/super_admin_post_helper.php |
super-admin password reset and impersonation start | impersonation reason/expiry/reauth/session regeneration are not established |
admin-console.php |
admin entry, tenant selection, tenant-only impersonation and impersonation end | impersonation start/end mutate the same PHP session and do not visibly regenerate its ID |
config/config.php |
effective client/user/username/role helpers and physical super-admin test | effective subject can replace scalar user/username while original session actor remains implicit |
TenantExecutionContext.php |
typed tenant, actor, subject, request, provenance and strict/compatibility contract | foundation is additive; it is not the universal session authority |
tenant_execution_context_adapter.php |
direct user, impersonation, admin override, CLI and integration constructors | broad caller adoption is incomplete |
app/shared/api/runtime.php |
authenticated API session and scalar/strict request context | strict principal is route opt-in |
app/shared/endpoint/* |
legacy authenticated JSON/page/download entrypoints | identity/access behavior differs from API v2 router |
index.php |
application shell authentication, logout and UI session projection | logout is a GET page action and manually unsets selected session keys |
3. Current Authentication Contract¶
3.1 Username lookup¶
Current login lookup is effectively:
SELECT ...
FROM T_USER
WHERE USERNAME = ?
AND DELETED_AT IS NULL
LIMIT 1
The request does not submit a tenant identity. Therefore one of the following must be true for safe operation:
- active usernames are globally unique; or
- some undocumented DB/application constraint resolves collisions; or
- cross-tenant duplicate usernames are a latent ambiguity.
This documentation does not assert global uniqueness without current schema/data evidence.
3.2 Password verification¶
bcrypt/modern hash
-> password_verify
legacy 128-hex hash
-> SHA-512(password + Config::PASSWORD_SALT)
When a verified stored hash needs rehashing, login performs a compare-and-set update using the old hash. Failure to update exactly one row aborts sign-in.
3.3 Session creation¶
After credential verification:
session_regenerate_id(true)
-> CLIENT_ID
-> login_username
-> login_id
-> login_name
-> login_email
-> login_role
-> Telegram linkage fields
-> LAST_LOGIN update
-> role/default landing redirect
The original authenticated session fields remain the physical actor source for super-admin detection.
3.4 Current missing or unproven controls¶
The inspected source does not establish:
- login-attempt throttling;
- account lockout;
- MFA;
- password breach/complexity policy beyond minimum length in change/reset flows;
- trusted-proxy allowlist for
X-Forwarded-Proto; - session revocation version/store;
- other-session invalidation after password change/reset;
- privileged-action reauthentication;
- device/session inventory;
- security-notification workflow.
These remain OPEN POLICY / RUNTIME EVIDENCE REQUIRED, not assumed defects or automatic implementation scope.
4. Current Session Contract¶
4.1 Session settings¶
TTL: 20 hours
strict mode: enabled
cookies only: enabled
HttpOnly: enabled
SameSite: Lax
Secure: HTTPS or X-Forwarded-Proto=https
cookie lifetime = TTL
gc lifetime = TTL
There is no explicit distinction in the inspected source between:
idle timeout
absolute timeout
privileged-action timeout
impersonation timeout
remembered device
revocation time
4.2 Current session states¶
The current implementation mainly infers state from PHP session fields.
No login_username
-> anonymous
login_username present
-> authenticated
IMPERSONATE array present
-> impersonation context
session destroyed / expired by PHP
-> unauthenticated on next request
There is no accepted durable session row or session-version check in the inspected path.
4.3 Read-only session release¶
API GET routes may opt into:
sessionMode = read-only
-> copy session into request
-> session_write_close()
This reduces PHP session lock duration. It does not create a separate identity authority.
4.4 Logout and reset¶
Current application shell exposes GET page actions.
?page=reset
-> clears selected UI/menu/sessionStorage state
-> does not log out
?page=logout
-> manually unsets known auth/session fields
-> session_destroy()
-> browser redirect
Current source does not visibly delete the session cookie, rotate the session before destruction or revoke other sessions.
5. Actor, Subject And Effective Scalar Identity¶
5.1 Physical actor¶
isSuperAdmin() is based on the original session:
SESSION.CLIENT_ID = 0
AND SESSION.login_role = 0
User/tenant impersonation does not overwrite those original fields.
5.2 Effective scalar user¶
Compatibility helpers can return the impersonated subject instead of the actor.
getSessionUserId()
-> TARGET_USER_ID when selected
-> otherwise login_id
getSessionUsername()
-> TARGET_USERNAME when selected
-> otherwise login_username
getClientId()
-> TARGET_CLIENT_ID when impersonating
-> otherwise session CLIENT_ID
-> otherwise Config::CLIENT_ID
This is useful for legacy caller compatibility but can hide the physical actor unless the caller also reads typed context or audit provenance.
5.3 Effective roles¶
getEffectiveRoleIds():
- rereads the impersonated target user's
ROLE_IDwhen a target user exists; - otherwise rereads the logged-in user's
ROLE_IDfor the original session tenant; - falls back to session
login_roleafter missing row or DB error; - caches the result for the request.
Tenant-only impersonation has no target user, so the effective role set remains the original super-admin role set unless the caller supplies a different compatibility role path. Page behavior may use special super-admin/impersonation logic rather than this role set alone.
6. Current Impersonation Modes¶
6.1 User impersonation¶
Current stored session shape:
ORIGINAL_ADMIN_ID
ORIGINAL_ADMIN_USERNAME
TARGET_USER_ID
TARGET_CLIENT_ID
TARGET_USERNAME
TARGET_NAME
STARTED_AT
Start sequence:
assert super-admin at owning endpoint
-> validate target tenant
-> if TARGET_USER_ID > 0, validate user belongs to tenant
-> clear direct-page grant
-> write IMPERSONATE session object
-> invalidate menu cache
-> redirect
Typed context reconstructs:
actor = original SUPER_ADMIN
subject = target USER
accessMode = IMPERSONATION
policyState = STRICT
6.2 Tenant-only impersonation¶
TARGET_USER_ID = 0
TARGET_CLIENT_ID > 0
subject = null
actor = original SUPER_ADMIN
This mode selects tenant context without representing a real tenant user. It must not be documented as equivalent to target-user role acceptance.
6.3 Admin tenant override¶
Typed API context supports a separate allowlisted API override:
API entry
+ physical super-admin
+ route explicitly allows override
+ target tenant
+ authorizationRef
+ no simultaneous impersonation
This is distinct from session impersonation.
6.4 Current lifecycle gaps¶
The inspected source does not establish:
- reason/ticket requirement for session impersonation start;
- explicit impersonation expiry beyond the PHP session lifetime;
- session ID regeneration at start/end;
- prohibited action categories during impersonation;
- privileged reauthentication before impersonation/password reset;
- universal durable start/end audit;
- automatic end on password/role/tenant changes;
- cross-device awareness;
- a complete read-only support mode distinct from write-capable impersonation.
7. Password Change And Reset Boundaries¶
7.1 Own-password change¶
Current command uses effective scalar identity:
getSessionUserId()
+ getClientId()
+ current password verify
-> bcrypt update
During user impersonation, those effective values can point at the target user. The intended policy—whether a super-admin may invoke “change own password” while impersonating—is not established by this helper alone.
7.2 Super-admin reset¶
Current reset identifies:
target user ID
+ target client ID
+ new password
It verifies the target row and writes a bcrypt hash.
7.3 Non-implications¶
Password row updated
!= current session rotated
!= other sessions revoked
!= provider tokens revoked
!= impersonation ended
!= user notified
8. Service, CLI And Provider Identities¶
Typed execution context supports:
CLI explicit tenant binding
INTEGRATION explicit tenant binding
SYSTEM or INTEGRATION actor
credential owner reference
authorization reference
Legacy CLI default context remains COMPATIBILITY_ONLY and rejects a new strict write when forWrite=true.
Current provider-specific mappings—Telegram, QuickBooks, Gmail, Twilio or others—remain separate adapter concerns. A provider-linked identifier does not become the local actor or subject automatically.
9. Current Source Discrepancy And Gap Register¶
| ID | Current fact / gap | Consequence |
|---|---|---|
IDN-GAP-010 |
login query is username-only | duplicate username policy must be proven |
IDN-GAP-020 |
one 20-hour TTL, no explicit idle/absolute split | timeout semantics cannot be reconstructed from UI alone |
IDN-GAP-030 |
X-Forwarded-Proto influences Secure cookie |
trusted proxy boundary must be documented separately |
IDN-GAP-040 |
no visible durable session revocation/version | password/reset/logout does not prove all-session invalidation |
IDN-GAP-050 |
impersonation start/end does not visibly regenerate session ID | session-fixation and continuity policy remains open |
IDN-GAP-060 |
scalar helpers replace actor with subject | audit/authorization callers can lose physical actor provenance |
IDN-GAP-070 |
tenant-only impersonation has no real subject | cannot substitute for target-role testing |
IDN-GAP-080 |
effective-role DB failure falls back to session role | stale role compatibility is possible |
IDN-GAP-090 |
own-password helper uses effective subject identity | impersonation policy must explicitly constrain this action |
IDN-GAP-100 |
logout is GET and destroys current PHP session only | CSRF/revocation/cookie semantics remain open |
IDN-GAP-110 |
no current PHP↔Next.js session bridge contract | migration cannot begin from UI route alone |
IDN-GAP-120 |
provider/service identities remain adapter-specific | system identity must be explicit per callback/job |
10. Target Authority Map¶
| Concern | Target owner |
|---|---|
| Credential verification | Identity application service and password/identity repository |
| Session issue/rotate/revoke | one session authority shared by PHP/Next.js coexistence adapters |
| Actor/subject/tenant construction | typed ActorContext + TenantExecutionContext |
| Impersonation delegation | explicit impersonation application command and durable audit |
| Privileged reauthentication | identity policy/command, not React component |
| Service identity | explicit system/integration binding |
| Authorization | separate access policy evaluator |
| Business command | owning application module |
| Audit/correlation | separate evidence foundation |
React renders identity/session state. Next.js authenticates/adapts requests. Neither owns password policy, impersonation authorization or record access.
11. Source Caller And Retirement Conditions¶
Current compatibility callers include:
getClientId();getSessionUserId();getSessionUsername();getEffectiveRoleIds();- direct
$_SESSIONreads; isSuperAdmin();- legacy endpoint authentication checks;
- route-specific strict tenant principal opt-ins.
A compatibility helper reaches caller-zero only when:
- every consequential caller has an explicit actor/subject/tenant contract;
- current direct pages and legacy endpoints have accepted adapters;
- PHP and Next.js coexistence uses one authoritative session decision;
- impersonation start/end/audit/reauth semantics are accepted;
- rollback remains possible without issuing duplicate sessions;
- current role/page/API behavior is revalidated for Client 1 and Client 2.
12. Evidence Boundary¶
This source map was produced from repository source. It does not prove:
- current Production cookie headers;
- actual proxy topology;
- real session expiry;
- duplicate usernames in data;
- active legacy-password count;
- login failure frequency;
- current concurrent sessions;
- role-change propagation;
- impersonation field usage in every caller;
- cross-device logout;
- provider identity mappings;
- current Wiki content;
- Next.js session behavior.
Those require separately authorized Runtime, DB, browser, provider or deployment evidence.
---¶
Source:
docs/reconstruction/PLATFORM_IDENTITY_SESSION_IMPERSONATION_SOURCE_AUTHORITY.md— ctc repository · This page is an English translation of the source document. Identifiers, file paths and code symbols are unchanged.