fix: recipe config cleanup, report-only CSP, logout redirect validation (#6124)
This commit is contained in:
1 parent
973631b7e8
commit
f8546ce0e0
27 files changed
+446
-75
No files matched your search
@@ -176,3 +176,33 @@ accurate documentation, we will link to each provider's own recommended steps:
|
||||
|
||||
- [Add SSL Support](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-https-custom-domain-cdn)
|
||||
- [Configure a Custom Domain](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-custom-domain-name)
|
||||
|
||||
## Content-Security-Policy
|
||||
|
||||
The hosted viewer ships a `Content-Security-Policy-Report-Only` header (see
|
||||
`netlify.toml`; the nginx recipes under `platform/app/.recipes` carry the same
|
||||
policy as commented `add_header` examples). Report-Only means the browser
|
||||
evaluates the policy and logs violations to the console, but blocks nothing.
|
||||
|
||||
What the policy covers:
|
||||
|
||||
- `default-src 'self'` with `frame-ancestors 'none'` (mirrors the existing
|
||||
`X-Frame-Options: DENY`), `base-uri 'self'`, and `form-action 'self'`.
|
||||
- `script-src` allows `'unsafe-inline'`/`'unsafe-eval'` (required by the
|
||||
current bundles and the cornerstone/vtk WASM and worker paths) plus
|
||||
`https://cdnjs.cloudflare.com` for the Rollbar snippet used by demo builds.
|
||||
- `worker-src`, `object-src`, `frame-src`, and `img-src` allow `blob:` because
|
||||
web workers, DICOM PDF rendering, and image data all use blob URLs.
|
||||
- `connect-src` allows any `https:` origin because deployments point the
|
||||
viewer at arbitrary DICOMweb servers; narrow this to your archive's origin
|
||||
in your own deployment if you can.
|
||||
|
||||
Reading violations: open the browser devtools console and filter for
|
||||
`Content-Security-Policy`. Report-only violations are logged as warnings and
|
||||
do not affect behavior; each one is either telemetry for tightening the policy
|
||||
or a directive that must stay relaxed.
|
||||
|
||||
Criteria for promoting Report-Only to an enforcing `Content-Security-Policy`
|
||||
header: zero unexplained violations across the e2e suite and a manual session
|
||||
that exercises study load, MPR, SEG display, PDF display, and video display.
|
||||
Until then, keep the header name `Content-Security-Policy-Report-Only`.
|
||||
@@ -0,0 +1,104 @@
|
||||
---
|
||||
sidebar_position: 9
|
||||
sidebar_label: Deployment recipes
|
||||
title: Deployment recipes migration
|
||||
---
|
||||
|
||||
# Deployment recipes migration
|
||||
|
||||
The deployment recipes under `platform/app/.recipes` no longer ship working
|
||||
credential values or permissive CORS defaults. If you deploy from these
|
||||
recipes, or you templated your own deployment from an earlier checkout, a few
|
||||
one-time steps are now required. The viewer application itself is unaffected.
|
||||
|
||||
## Keycloak recipes require a .env file
|
||||
|
||||
Applies to `Nginx-Orthanc-Keycloak` and `Nginx-Dcm4chee-Keycloak`.
|
||||
|
||||
The docker-compose files previously hardcoded the Keycloak admin and
|
||||
PostgreSQL passwords. They now read them from the environment and refuse to
|
||||
start while any is unset:
|
||||
|
||||
```text
|
||||
error while interpolating services.keycloak.environment.POSTGRES_PASSWORD:
|
||||
required variable POSTGRES_PASSWORD is missing a value: set POSTGRES_PASSWORD in your .env
|
||||
```
|
||||
|
||||
**Migration:** copy `.env.example` to `.env` next to `docker-compose.yml` and
|
||||
set strong values:
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
# then edit .env and fill in:
|
||||
# POSTGRES_PASSWORD=
|
||||
# KEYCLOAK_ADMIN_PASSWORD=
|
||||
```
|
||||
|
||||
`POSTGRES_PASSWORD` is the single PostgreSQL credential - Keycloak connects to
|
||||
Postgres as the `keycloak` role provisioned with it, so `KC_DB_PASSWORD` is
|
||||
derived from `POSTGRES_PASSWORD` in the compose file rather than set
|
||||
separately.
|
||||
|
||||
## Keycloak client secret is now a placeholder
|
||||
|
||||
The realm import (`config/ohif-keycloak-realm.json`) and the oauth2-proxy
|
||||
config (`config/oauth2-proxy.cfg`) previously shipped a fixed value for the
|
||||
`ohif_viewer` client secret. Both files now contain the placeholder
|
||||
`REPLACE_WITH_A_GENERATED_CLIENT_SECRET`.
|
||||
|
||||
**Migration:** generate a fresh value and put the same value in both files
|
||||
before `docker compose up`. To generate one after the realm is imported:
|
||||
Keycloak admin console -> Clients -> `ohif_viewer` -> Credentials ->
|
||||
Regenerate.
|
||||
|
||||
**If you deployed from an earlier checkout:** the old fixed value is public in
|
||||
the repository history, so regenerating it is required for existing
|
||||
deployments too, not just new ones. Regenerate it in the Keycloak admin
|
||||
console and update `config/oauth2-proxy.cfg` to match. Rotating the Keycloak
|
||||
admin and PostgreSQL passwords is likewise recommended. See the
|
||||
`SECURITY-NOTES.md` file inside each Keycloak recipe directory for the full
|
||||
checklist.
|
||||
|
||||
## nginx recipes no longer send wildcard CORS headers
|
||||
|
||||
Applies to `Nginx-Orthanc`, `Nginx-Orthanc-Keycloak`, and
|
||||
`Nginx-Dcm4chee-Keycloak`.
|
||||
|
||||
The nginx configs previously answered PACS/DICOMweb proxy requests with
|
||||
`Access-Control-Allow-Origin: *`. Those headers were removed.
|
||||
|
||||
- **Same-origin deployments (the recipe default):** no action needed. The
|
||||
viewer is served by the same nginx as the proxy, so these requests never
|
||||
needed CORS headers.
|
||||
- **Cross-origin deployments** (viewer hosted on a different origin than the
|
||||
proxy): browser requests to the proxy will now fail CORS checks until you
|
||||
re-add the headers with your viewer's origin spelled out explicitly. Each
|
||||
config contains a commented example next to the old location:
|
||||
|
||||
```nginx
|
||||
# add_header 'Access-Control-Allow-Origin' 'https://viewer.example.com' always;
|
||||
```
|
||||
|
||||
Use your actual viewer origin; avoid `'*'` on endpoints that serve patient
|
||||
data.
|
||||
|
||||
## Logout redirect_uri is validated
|
||||
|
||||
`/logout?redirect_uri=...` now only honors same-origin (or relative) values.
|
||||
Anything else falls back to the configured `post_logout_redirect_uri` from
|
||||
your OIDC configuration. The viewer's own logout flows always pass same-origin
|
||||
values, so in-app behavior is unchanged.
|
||||
|
||||
**Migration:** only needed if you linked to `/logout` with a `redirect_uri`
|
||||
pointing at a different origin (for example, an external portal). Configure
|
||||
that destination as the client's `post_logout_redirect_uri` in your OIDC
|
||||
configuration instead of passing it in the query string.
|
||||
|
||||
## New Content-Security-Policy-Report-Only header (no action needed)
|
||||
|
||||
Hosted deployments configured via `netlify.toml` now send a
|
||||
`Content-Security-Policy-Report-Only` header. It is observational only:
|
||||
browsers log would-be violations to the devtools console and block nothing.
|
||||
The nginx recipes carry the same policy as commented examples. See the
|
||||
[Deploy Static Assets](../../deployment/static-assets.md#content-security-policy)
|
||||
docs for what the policy covers and how to read the console reports.
|
||||
@@ -26,5 +26,9 @@ The largest changes in 3.13 are infrastructure-level:
|
||||
- **[DICOM video viewport](./dicom-video.md)** — the
|
||||
`@ohif/extension-dicom-video.viewportModule.dicom-video` namespace was
|
||||
removed; route DICOM video display sets through the Cornerstone viewport.
|
||||
- **[Deployment recipes](./deployment-recipes.md)** — the Keycloak recipes
|
||||
now require a `.env` file and a generated client secret before
|
||||
`docker compose up`, and the nginx recipes no longer send wildcard CORS
|
||||
headers (cross-origin deployments must set an explicit origin).
|
||||
|
||||
<DocCardList />
|
||||
Reference in new issue
Block a user