Files
pedwfrontend/docs/administrative-authentication.md

143 lines
7.4 KiB
Markdown

# Administrative authentication foundation
## Integrated administrative sign-in
Administrators sign in at `/admin/login` using the shared credential configured
as `ADMIN_AUTH_SECRET`. The page submits the credential directly to
`POST /api/admin/auth/login`; it does not place the credential in a URL or store
it in browser storage.
Successful authentication creates the administrative session cookie and sends
the browser to `/admin`. The `/admin` server-side loader validates that cookie
before loading administrative data. A valid session is not sufficient by
itself: the existing `/admin` IP allowlist remains an additional restriction,
and a valid administrator outside the allowed network is sent to `/403`.
The administrative interface provides a **Sign out** control which calls
`POST /api/admin/auth/logout`, clears the cookie, and returns the browser to
`/admin/login`. Sessions expire after 20 minutes and expired, invalid, or
missing sessions are redirected to the login page.
## Required server-side configuration
The deployment must provide all of the following server-side values:
- `ADMIN_AUTH_SECRET`: a unique high-entropy administrative passphrase of at
least 32 characters.
- `ADMIN_SESSION_SECRET`: a different unique high-entropy signing key of at
least 32 characters.
- `NEXTAUTH_URL`: the existing canonical application URL. Administrative login
and logout compare the request `Origin` with this server-configured origin.
The administrative values must never use a `NEXT_PUBLIC_` prefix or be exposed
to browser JavaScript. Do not commit real values. Missing, short, or identical
administrative secrets fail closed.
## Security properties and limitations
- Credentials are derived with Node `scrypt` and compared with
`timingSafeEqual`.
- Sessions are stateless, versioned HMAC-SHA256 tokens with a 20-minute fixed
lifetime and a random nonce.
- The cookie is `HttpOnly`, `SameSite=Strict`, scoped to `/`, explicitly
expires, and is `Secure` in production.
- Login and logout require an exact same-origin `Origin` match against
`NEXTAUTH_URL`; missing or malformed origins fail closed.
- Authentication responses use `Cache-Control: no-store`.
- Logout clears the browser cookie. Because sessions are stateless, a stolen
token can remain valid until its short expiry; later protected routes must
continue verifying signature and expiry on every request.
- This is shared-credential authentication. A valid token proves knowledge of
the shared credential, not the identity of a named administrator.
- Protecting `/admin` prevents its server-side Prisma, storage, and CRM data
loading from running without a valid administrative session. It does not by
itself protect browser-addressable API routes.
## Administrative API protection limitations
The current administrative UI directly uses API routes that do not yet enforce
the administrative session, including:
- `/api/admin/getnewappeals_api`
- `/api/admin/getlatestdocuments_api`
- `/api/admin/getStatusCountsByAppeal_api`
- `/api/admin/getStatusCountsByAppealAndLPA_api`
The appeals and documents routes expose paging operations used after the page
has loaded. The status routes expose administrative dashboard reads. These
routes retain their existing relay token and HMAC behaviour but have no
independent administrative-session authorization. A later authorised stage
must enforce the administrative session on privileged API routes and account
for both browser calls and the existing server-side bootstrap callers.
Storage download and queue actions retain their existing authorization
behaviour. The other administrative API and storage limitations described in
this section remain open.
Directly observed storage routes include:
- `/api/file/getrepsblobproxy`, which forwards a caller-supplied container using
server relay credentials and path signing.
- `/api/file/downloadblob` and `/api/file/createrepcompletemessage_api`, which
enforce existing path-HMAC checks but not administrative authorization.
## Stage 3 deletion controls
Ordinary case and representation deletion through `/api/file/deleteblobcase`
and `/api/file/deleteblobrep` now requires a valid NextAuth session whose user
ID matches the requested Azure container. The existing signed-query/HMAC check
also remains required. Requests that fail ownership or HMAC validation are
rejected before the Azure storage deletion operation is called.
Ordinary JSON and multipart uploads through `/api/file/upload` and
`/api/file/uploadsinglefile` independently require a valid NextAuth session whose
user ID exactly matches the submitted `containerID`. The existing upload HMAC
remains mandatory. Missing or unusable sessions, cross-container requests, and
invalid HMACs are rejected before file processing or Azure storage writes.
Administrative cross-container representation deletion uses the dedicated
`POST /api/admin/deleteblobrep` route. That endpoint independently validates
the administrative session and requires a trusted same-origin request. It also
validates the requested container, case-folder segment, and representation-file
segment before performing deletion.
Administrative cross-container case deletion uses the dedicated
`POST /api/admin/deleteblobcase` route. That endpoint independently validates
the administrative session, requires a trusted same-origin request, and
validates the requested container and case-folder segment before performing
deletion. It invokes the same existing `deleteBlobCase(container,
casefolderID)` operation as the ordinary endpoint. That operation lists and
deletes blobs in the selected container whose names begin with the supplied
case-folder prefix; it does not delete the Azure container or broaden deletion
to unrelated containers.
Administrative representation JSON unlocking uses the dedicated
`POST /api/admin/editRepJson` route. That endpoint independently validates the
administrative session, requires a trusted same-origin request, and validates
the requested container and blob path before removing `repComplete`. The former
`/api/file/editRepJson` route is retired and no longer performs storage access.
Automated contract verification for the implemented deletion controls has
passed, including ordinary ownership/HMAC rejection, administrative method,
session, origin and input rejection, zero deletion calls on rejected requests,
and exact cross-container helper arguments on success. Live Azure behaviour,
browser-level behaviour, and deployment configuration have not been verified
by that automated coverage. The other administrative API and storage
limitations documented above remain open, and these changes do not establish
closure of the overall ITHC finding.
## Deployment requirements before production use
The repository does not provide a demonstrated distributed rate-limit service.
Administrative login must therefore be protected by an ingress, gateway, WAF,
or shared backing service that enforces rate limits consistently across all
deployed instances. A process-local limiter is intentionally not used because
it would reset on restart and could be bypassed across instances.
The deployment must also ensure `NEXTAUTH_URL` is the correct canonical HTTPS
origin. Login and logout intentionally do not derive trust from `Host` or
forwarding headers.
Any future administrative state-changing API must require more than possession
of the cookie: it must independently validate the administrative session and
enforce same-origin/CSRF protection before performing side effects.