This is an automated email from the ASF dual-hosted git repository.

bamaer pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git


The following commit(s) were added to refs/heads/main by this push:
     new 4de05ac5b9 Hop Web security follow-ups: mode NONE docs, threat model, 
EXTERNAL w… (#8402)
4de05ac5b9 is described below

commit 4de05ac5b9af30ea303af8ff02ac9e557b4be8e2
Author: Bart Maertens <[email protected]>
AuthorDate: Mon Sep 21 10:17:05 2026 +0200

    Hop Web security follow-ups: mode NONE docs, threat model, EXTERNAL w… 
(#8402)
    
    * Hop Web security follow-ups: mode NONE docs, threat model, EXTERNAL 
warning #8391
    
    - hop-web.adoc: correct the mode NONE description (/ui open by design, 
/hop/*
      default-denied) and document allowUnauthenticatedServerApi /
      HOP_WEB_ALLOW_UNAUTHENTICATED_SERVER_API as the execution-server opt-in.
      Add an IMPORTANT note that EXTERNAL delegates rather than enforces.
    - THREAT_MODEL.md: add Hop Web as a distinct deployment, scope the 
enable_auth
      assumption to hop-server, and describe the per-mode boundary.
    - HopWebEntryPoint: log a warning when a session has no principal in a mode
      other than NONE, so EXTERNAL without a container security-constraint no
      longer fails open silently.
    
    * Address review feedback: thread Hop Web through the threat model #8391
    
    - THREAT_MODEL.md: name Hop Web as a second HTTP trust boundary in the 
in-scope
      line, the untrusted-actor sentence, SS7 and SS12; qualify the JSON API 
row so
      ConstraintSecurityHandler/Basic-JAAS is scoped to standalone hop-server 
and
      Hop Web's own filters are named for the co-deployed /hop/api/v1/*.
    - THREAT_MODEL.md SS11: mode NONE is an unrestricted GUI that runs pipelines
      in-process (LocalPipelineEngine), so it is RCE even while /hop/* returns 
403;
      HOP_WEB_ALLOW_UNAUTHENTICATED_SERVER_API additionally opens the remote 
API.
    - hop-web.adoc + SS8: EXTERNAL without a container constraint shows the 
General
      tab on an authenticated mode while the status line still reads 
unrestricted /
      no AuthN - the tab surfaces the contradiction, it does not claim auth is 
on.
    - HopWebEntryPoint: trim the block comment; the log message carries the 
detail. fixes #8391
---
 THREAT_MODEL.md                                    | 106 +++++++++++++++++----
 .../modules/ROOT/pages/hop-gui/hop-web.adoc        |  27 +++++-
 .../org/apache/hop/ui/hopgui/HopWebEntryPoint.java |  31 +++++-
 3 files changed, 145 insertions(+), 19 deletions(-)

diff --git a/THREAT_MODEL.md b/THREAT_MODEL.md
index 4696a98d37..f30730655a 100644
--- a/THREAT_MODEL.md
+++ b/THREAT_MODEL.md
@@ -22,8 +22,10 @@ were then code-verified against the source and 
confirmed/corrected by the PMC
 (2026-06-22). Claims below cite `file:line` evidence where it is load-bearing.
 
 **Revision triggers:** a change to the Hop Server's auth / remote-execution
-model; a new scripting/exec transform or action; a change to how connection
-credentials / variables are stored or resolved; a new metadata source.
+model; a change to the Hop Web authentication modes or to what the Hop Web
+web application deploys; a new scripting/exec transform or action; a change to
+how connection credentials / variables are stored or resolved; a new metadata
+source.
 
 ---
 
@@ -53,17 +55,20 @@ the `hop-run` CLI, or submitted to a **Hop Server** for 
local/remote execution.
 |---|---|---|
 | Execution engine | `engine/`, `engine-beam/` | Runs pipelines/workflows the 
operator authored — incl. transforms that touch files, DBs, network, and 
**scripting/exec** steps. |
 | Hop Server (servlet / HTTP) | `engine/` — package `org.apache.hop.www` + 
`HopServerMeta` in `org.apache.hop.server`; launched by the `hop-server` 
command (`org.apache.hop.www.HopServer`). *(The `org.apache.hop.server` 
connection helpers `HttpUtil`/`ServerConnectionManager` — see §9 — live in 
`core/`.)* | The **network trust boundary**: an embedded Jetty server whose 
servlets accept pipeline/workflow run requests over HTTP (`/hop/execPipeline`, 
`/hop/addPipeline`+`/hop/startExec`, `/hop [...]
-| Hop JSON API | `engine/src/main/java/org/apache/hop/www/api/` | **Part of 
Hop Server**, not a separate deployable. Mounted on `/hop/api/v1/` 
([`WebServer.java`](engine/src/main/java/org/apache/hop/www/WebServer.java)) 
and exposes `execute/sync` (run a web service), `metadata` CRUD, `plugins` and 
`location` execution info. It sits inside the same `ConstraintSecurityHandler` 
as every servlet, so it inherits Hop Server's Basic/JAAS auth (§8). |
-| Arrow Flight server (gRPC) | `plugins/tech/arrow/` — package 
`org.apache.hop.arrow.flight`; launched by the `hop arrow` command 
(`org.apache.hop.arrow.command.ArrowCommand`) | A **second network listener**, 
separate from Hop Server: a gRPC/Arrow Flight endpoint that hands rows to and 
from Data Stream metadata elements. Binds `0.0.0.0:33333` by default. TLS 
(incl. mutual TLS) and username/password authentication are configurable but 
**off unless the operator passes the options** (§8) —  [...]
-| GUI (desktop / web) | `ui/` (`hop-ui`, SWT core), `rcp/` (desktop fragment), 
`rap/` (`hop-ui-rap`, RAP/RWT **web** GUI) | Authoring surface used by the 
trusted operator. `rap/` is the **web GUI**, not a server. |
+| Hop JSON API | `engine/src/main/java/org/apache/hop/www/api/` | **Part of 
Hop Server**, not a separate deployable. Mounted on `/hop/api/v1/` 
([`WebServer.java`](engine/src/main/java/org/apache/hop/www/WebServer.java)) 
and exposes `execute/sync` (run a web service), `metadata` CRUD, `plugins` and 
`location` execution info. In the standalone `hop-server` deployment it sits 
inside the same `ConstraintSecurityHandler` as every servlet, so it inherits 
Hop Server's Basic/JAAS auth; when the  [...]
+| Arrow Flight server (gRPC) | `plugins/tech/arrow/` — package 
`org.apache.hop.arrow.flight`; launched by the `hop arrow` command 
(`org.apache.hop.arrow.command.ArrowCommand`) | A **separate network 
listener**, distinct from both Hop Server and Hop Web: a gRPC/Arrow Flight 
endpoint that hands rows to and from Data Stream metadata elements. Binds 
`0.0.0.0:33333` by default. TLS (incl. mutual TLS) and username/password 
authentication are configurable but **off unless the operator passes th [...]
+| GUI (desktop / web) | `ui/` (`hop-ui`, SWT core), `rcp/` (desktop fragment), 
`rap/` (`hop-ui-rap`, RAP/RWT **web** GUI) | Authoring surface used by the 
trusted operator. `rap/` is the **web GUI code**, not a server — but see the 
Hop Web row: the shipped web application deploys it together with Hop Server 
servlets. |
+| Hop Web (deployed web application) | `assemblies/web/` (WAR + 
`apache/hop-web` image), built from `rap/` + `engine/` | A **distinct 
network-facing deployment**, separate from both `rap/` and `hop-server`. The 
one WAR co-deploys the RAP UI on `/ui` and `/ui-dark`, `HopServerServlet` on 
`/hop/*`, and `HopApiApplication` on `/hop/api/v1/*` on the same origin 
([`web.xml`](assemblies/web/src/main/resources/WEB-INF/web.xml)). It does 
**not** use Hop Server's `enable_auth` / `hop.pwd` Basic a [...]
 | Plugins | `plugins/` | The large transform/action set, incl. scripting 
(GraalJS/Rhino/Groovy), shell/exec, SQL, and per-DB/per-cloud connectors 
(`plugins/tech/*`). |
 | Connection / driver layer | `lib-jdbc/` (bundled JDBC drivers), `core/` 
(`org.apache.hop.core.database`, `org.apache.hop.metadata`) | DB/file/cloud 
credentials + JDBC drivers the operator configures. (There is no standalone 
`metadata/` module — connection/metadata code is in `core/`.) |
 
-**In scope:** engine + Hop Server + plugins + connection layer + GUI glue.
+**In scope:** engine + Hop Server + Hop Web + plugins + connection layer + GUI 
glue.
 **Intended caller trust:** Hop is operated as a **single trust domain** — the
 pipeline/workflow **author, the local operator, and anyone holding Hop Server
-credentials are all trusted** (they direct what Hop does). The **network-facing
-Hop Server** is where an untrusted actor can appear.
+credentials are all trusted** (they direct what Hop does). There are **several
+network-facing surfaces — Hop Server, Hop Web and the optional Arrow Flight
+server** — and any of them is where an untrusted actor can appear; Hop Server
+and Hop Web have **separate auth models** (§8).
 
 ## §3 Out of scope (explicit non-goals)
 
@@ -132,17 +137,22 @@ where strict outbound TLS verification is required (see 
§9).
   holder of Hop Server credentials** — Hop is a single trust domain, and they
   already control execution (a scripting step that runs code is intent, not an
   attack).
-- **In scope:** a **remote actor against an exposed Hop Server** (submitting or
-  running pipelines, reading results, mutating metadata) —
-  bounded by whatever auth fronts the surface; and a **network MITM** between
-  Hop and its backends or between client and server.
+- **In scope:** a **remote actor against an exposed Hop Server or Hop Web
+  deployment** — submitting or running pipelines, reading results and mutating
+  metadata over `/hop/*` or `/hop/api/v1/*`, or driving the RAP authoring UI on
+  `/ui` — bounded by whatever auth fronts the surface (`enable_auth` for
+  `hop-server`, the Hop Web auth mode for Hop Web, §8); and a **network MITM**
+  between Hop and its backends or between client and server.
 - **Conditional:** an attacker who can get an **untrusted pipeline/metadata
   file** loaded/run, or who controls a **variable/parameter** value (incl. an
   upstream row value picked up by `Set Variables`) that reaches a sink.
 
 ## §8 Security properties the project provides
 
-- **Hop Server authentication (with a critical caveat).** The servlet Hop 
Server
+- **Hop Server authentication (with a critical caveat).** *(This property is
+  scoped to the standalone `hop-server` deployment only — Hop Web has no
+  `enable_auth` and no `hop.pwd`; see the separate Hop Web property below.)*
+  The servlet Hop Server
   enables HTTP Basic authentication **by default** (`enable_auth` defaults to
   true — 
[`HopServerMeta.java:229,251`](engine/src/main/java/org/apache/hop/server/HopServerMeta.java#L229),
 
[`WebServer.java:197`](engine/src/main/java/org/apache/hop/www/WebServer.java#L197)),
 gating every endpoint, so a *fully unauthenticated* client is
   rejected. **Caveat:** the only shipped credential is the **publicly-known
@@ -152,6 +162,49 @@ where strict outbound TLS verification is required (see 
§9).
   Changing the credential and restricting exposure is an operator 
responsibility
   (§10). — violation symptom: remote code execution using the unchanged default
   credential on an exposed deployment; severity: critical.
+- **Hop Web authentication and authorization (separate model from 
`hop-server`).**
+  Hop Web does not inherit the `hop-server` `enable_auth` / `cluster:cluster`
+  posture described above; it has its own authentication mode in
+  `security-config.json`
+  
([`HopSecurityConfig.java`](core/src/main/java/org/apache/hop/core/security/HopSecurityConfig.java),
+  `HOP_WEB_SECURITY_MODE`), and it **ships in mode `NONE`**. The boundary per
+  mode:
+  - **`NONE` (default).** The RAP UI on `/ui` / `/ui-dark` is **open by 
design**
+    — this is the single-user / trusted-network install and the session is
+    treated as *unrestricted*. The co-deployed Hop Server API on `/hop/*` is
+    **default-denied** (`403`) by
+    
[`HopServerAuthorizationFilter`](rap/src/main/java/org/apache/hop/ui/hopgui/security/HopServerAuthorizationFilter.java),
+    because mode `NONE` has no identity to authorize against and those 
endpoints
+    deploy and execute pipelines/workflows. Opt-in flag
+    `allowUnauthenticatedServerApi` /
+    `HOP_WEB_ALLOW_UNAUTHENTICATED_SERVER_API` reopens it for operators running
+    Hop Web purely as an execution server behind their own network controls —
+    violation symptom: unauthenticated remote code execution via `/hop/*` on an
+    exposed deployment that enabled the flag; severity: critical; mitigation is
+    operator-side network control (§10).
+  - **`BASIC` / `OAUTH2`.** Hop's own servlet filters
+    
([`HopBasicAuthFilter`](rap/src/main/java/org/apache/hop/ui/hopgui/security/HopBasicAuthFilter.java),
+    
[`HopOidcAuthFilter`](rap/src/main/java/org/apache/hop/ui/hopgui/security/HopOidcAuthFilter.java))
+    are mapped on `/*` — the whole application, UI and server API alike — and
+    establish a principal plus roles. Unlike `hop-server`, `/hop/*` then gets
+    **per-endpoint authorization**: each path maps to a required permission and
+    unmapped paths are **default-denied**, so a *Read-only* user can read 
status
+    but not `addPipeline` / `startPipeline` / `execWorkflow`.
+  - **`EXTERNAL`.** Authentication is **delegated to the servlet container or a
+    reverse proxy**; Hop only reads `request.getUserPrincipal()`. Nothing in
+    `rap/` enforces it, and the shipped
+    [`web.xml`](assemblies/web/src/main/resources/WEB-INF/web.xml) contains 
**no
+    `<security-constraint>`** — so an operator who selects `EXTERNAL` without
+    adding one gets an unauthenticated `/ui` while the General tab shows an
+    authenticated mode (`EXTERNAL`) — the Security tab's own status line still
+    reads *"Session is unrestricted (no AuthN)"*, so the tab surfaces the
+    contradiction rather than claiming authentication is on. `/hop/*` still
+    returns `401` (no principal) and `HopWebEntryPoint` now logs a warning for
+    every principal-less session in a non-`NONE` mode, but the UI itself is
+    open. — violation symptom: a fail-open UI on a deployment the operator
+    believes is authenticated;
+    severity: high; mitigation: a container `<security-constraint>` over `/*`,
+    or a proxy that rejects unauthenticated requests (§10).
 - **Cross-site browser requests to the Hop Server are rejected.** The servlets
   answer state-changing operations on `GET`, so a page the operator is visiting
   could otherwise drive them with the operator's browser and credentials
@@ -264,6 +317,15 @@ where strict outbound TLS verification is required (see 
§9).
   protects the XML servlets and the JSON API alike —
   it has none of its own. Be aware the Docker image binds `0.0.0.0:8080` with
   the default credential.
+- **Lock down Hop Web** (separate from `hop-server` above — `enable_auth` and
+  `hop.pwd` do not apply): it ships in mode `NONE`, where `/ui` is open by
+  design. For any shared deployment set `HOP_WEB_SECURITY_MODE` to `BASIC` or
+  `OAUTH2`, or to `EXTERNAL` **together with** a container
+  `<security-constraint>` over `/*` (or an authenticating reverse proxy) —
+  `EXTERNAL` on its own fails open. Leave
+  `HOP_WEB_ALLOW_UNAUTHENTICATED_SERVER_API` off unless you deliberately run 
Hop
+  Web as an execution server behind network controls. Persist
+  `HOP_CONFIG_FOLDER/security/` so users and role mappings survive upgrades.
 - **Protect credentials at rest:** enable the AES2 encoder
   (`HOP_PASSWORD_ENCODER_PLUGIN=AES2` + `HOP_AES_ENCODER_KEY` or
   `HOP_AES_ENCODER_KEY_FILE`) and/or a secrets
@@ -285,6 +347,16 @@ where strict outbound TLS verification is required (see 
§9).
   pipeline execution = remote code execution.
 - Running Hop Server with `enable_auth=false` on an untrusted network →
   unauthenticated pipeline execution + metadata mutation over the JSON API.
+- Exposing **Hop Web in mode `NONE`** to an untrusted network → `/ui` is an
+  **unrestricted** GUI session, so anyone who can reach it can author *and* run
+  pipelines/workflows **in-process** (the GUI executes locally through
+  `PipelineEngineFactory` / `LocalPipelineEngine`, it does not go through
+  `/hop/*`) = remote code execution, even though `/hop/*` still answers `403`.
+  Enabling `HOP_WEB_ALLOW_UNAUTHENTICATED_SERVER_API` additionally opens the
+  remote `/hop/*` and `/hop/api/v1/*` execution API.
+- Selecting Hop Web mode **`EXTERNAL` without a container
+  `<security-constraint>`** (or proxy) → an open `/ui` on a deployment the
+  operator believes is authenticated.
 - Running an **untrusted pipeline/workflow file** (or one fetched from an
   untrusted source).
 - Building unparameterized SQL / shell / file paths from **untrusted variable
@@ -332,9 +404,11 @@ vulnerabilities:
 
 ## §12 Conditions that would change this model
 
-A change to the Hop Server auth or remote-exec model; a new
-scripting/exec transform or action; a change to credential/variable storage or
-resolution (e.g. a new default encoder); a new metadata source format/location;
+A change to the Hop Server auth or remote-exec model; a change to the Hop Web
+authentication modes, its servlet filters, or to what the Hop Web web
+application deploys; a new scripting/exec transform or action; a change to
+credential/variable storage or resolution (e.g. a new default encoder); a new
+metadata source format/location;
 or a decision to support multi-tenant isolation (which today does not exist).
 
 ## §13 Triage dispositions
diff --git a/docs/hop-user-manual/modules/ROOT/pages/hop-gui/hop-web.adoc 
b/docs/hop-user-manual/modules/ROOT/pages/hop-gui/hop-web.adoc
index 279b492f91..84ca08ce03 100644
--- a/docs/hop-user-manual/modules/ROOT/pages/hop-gui/hop-web.adoc
+++ b/docs/hop-user-manual/modules/ROOT/pages/hop-gui/hop-web.adoc
@@ -193,7 +193,20 @@ Hop Web co-deploys the RAP UI, RAP service handlers, and 
the Hop Server servlet
 NOTE: The Hop Server API under `/hop/*` follows the same authorization as the 
rest of Hop Web.
 In the authenticated modes (`BASIC`, `EXTERNAL`, `OAUTH2`) each endpoint 
requires the matching permission from the caller's role — for example a 
*Read-only* user can call `status` and the status/image endpoints but not 
`addPipeline`, `startPipeline`, `execWorkflow`, or the register/remove 
endpoints, and an *Operator* can run and stop but not deploy (`add*`) or remove.
 Endpoints that are not recognized are denied by default.
-In mode `NONE` (the default, open install) `/hop/*` is unauthenticated just 
like `/ui`; put an authentication layer in front of Hop Web for any shared 
deployment.
+In mode `NONE` (the default, open install) the two surfaces behave differently:
+
+* `/ui` stays **open by design** — mode `NONE` is the single-user / 
trusted-network install and the UI is the product.
+* `/hop/*` is **closed by default** and returns `403`, because mode `NONE` has 
no user identity to authorize against and the Hop Server API can run and deploy 
pipelines and workflows.
+
+To use Hop Web as an execution server in mode `NONE`, opt in explicitly:
+
+* *Configuration perspective → Security → General → Expose the Hop Server API 
without authentication*, or
+* set `HOP_WEB_ALLOW_UNAUTHENTICATED_SERVER_API=true` (persisted as 
`allowUnauthenticatedServerApi` in `security-config.json`).
+
+WARNING: With that option on, anyone who can reach `/hop/*` can deploy and 
execute pipelines and workflows without credentials. Only enable it behind your 
own network controls (private network, firewall, service mesh, authenticating 
reverse proxy).
+The option applies to mode `NONE` only — `BASIC`, `EXTERNAL`, and `OAUTH2` 
always enforce the per-endpoint role permission and ignore it.
+
+Put an authentication layer in front of Hop Web for any shared deployment.
 
 === Built-in Hop roles
 
@@ -267,6 +280,14 @@ To keep audit data across container restarts, mount a 
volume and set the same pa
 
 The default Hop Web docker image picks up `tomcat-users.xml` and `web.xml` 
files and moves them to the correct location before Hop Web starts.
 
+IMPORTANT: Mode `EXTERNAL` is *delegation, not enforcement*.
+Hop itself does not challenge anyone in this mode: it only reads the 
`Principal` the servlet container (or authenticating reverse proxy) put on the 
request.
+The `web.xml` that ships with Hop Web contains no `<security-constraint>`, so 
selecting `EXTERNAL` without supplying your own constraint over `/*` leaves 
`/ui` **completely open**.
+The Security perspective makes that contradiction visible rather than hiding 
it: the General tab shows an authenticated mode (`EXTERNAL`), while the status 
line for the same session still reads `Session is unrestricted (no AuthN). 
Config mode: EXTERNAL.`
+If you see that combination, the container is not challenging anyone.
+`/hop/*` still returns `401` (no principal), and Hop logs a warning on every 
unauthenticated UI session, but the UI itself is unprotected.
+Always pair `EXTERNAL` with a `<security-constraint>` + `<login-config>` 
covering `/*` (see <<hop-web-external-full-webxml,the full `web.xml` sample>>) 
or with a proxy that rejects unauthenticated requests before they reach Tomcat.
+
 ==== Single user (minimal)
 
 A minimal sample `tomcat-users.xml` file (legacy single role `apachehop` → Hop 
*User*):
@@ -389,6 +410,9 @@ Environment variables (evaluated at startup):
 
 | `HOP_WEB_SEED_DEMO_USERS`
 | `true` to seed admin, developer, operator, viewer (password = username) when 
the store is empty
+
+| `HOP_WEB_ALLOW_UNAUTHENTICATED_SERVER_API`
+| `true` to open the embedded Hop Server API (`/hop/*`) in mode `NONE`. Off by 
default; ignored in the authenticated modes. Only use behind your own network 
controls.
 |===
 
 Example Docker run:
@@ -569,6 +593,7 @@ IMPORTANT: These tokens are not revoked when you log off or 
when an administrato
 
 Hop creates `jdbc-token.secret` with owner-only permissions (`0600`) on local 
filesystems when it can. Anyone who can read that file can mint tokens for any 
user.
 
+[[hop-web-external-full-webxml]]
 ==== Full web.xml with Tomcat BASIC (single role, EXTERNAL)
 
 The following sample `web.xml` extends Hop Web's default `web.xml` with the 
`<security-constraint />` and `<login-config />` elements required for basic 
authentication.
diff --git a/rap/src/main/java/org/apache/hop/ui/hopgui/HopWebEntryPoint.java 
b/rap/src/main/java/org/apache/hop/ui/hopgui/HopWebEntryPoint.java
index ed9833a429..09c143c21b 100644
--- a/rap/src/main/java/org/apache/hop/ui/hopgui/HopWebEntryPoint.java
+++ b/rap/src/main/java/org/apache/hop/ui/hopgui/HopWebEntryPoint.java
@@ -31,6 +31,7 @@ import org.apache.hop.core.extension.HopExtensionPoint;
 import org.apache.hop.core.gui.plugin.GuiRegistry;
 import org.apache.hop.core.gui.plugin.key.KeyboardShortcut;
 import org.apache.hop.core.logging.LogChannel;
+import org.apache.hop.core.security.HopSecurityConfig;
 import org.apache.hop.core.security.HopSecurityContext;
 import org.apache.hop.history.AuditManager;
 import org.apache.hop.history.AuditState;
@@ -163,8 +164,20 @@ public class HopWebEntryPoint extends AbstractEntryPoint {
           "Hop Web security: user ''{0}'' roles={1}",
           securityContext.getUsername(), securityContext.getRoleIds());
     } else {
-      LogChannel.UI.logDebug(
-          "Hop Web security: no authenticated principal (mode NONE or 
unrestricted)");
+      HopSecurityConfig.AuthMode mode = resolveAuthMode();
+      if (mode == HopSecurityConfig.AuthMode.NONE) {
+        LogChannel.UI.logDebug("Hop Web security: no authenticated principal 
(mode NONE)");
+      } else {
+        // A principal-less session in a non-NONE mode is unexpected: log at 
error level so
+        // EXTERNAL without a container security-constraint is visible instead 
of failing open.
+        LogChannel.UI.logError(
+            "Hop Web security WARNING: authentication mode is ''{0}'' but this 
request has no "
+                + "authenticated principal, so the UI is being served 
unauthenticated. "
+                + "In EXTERNAL mode Hop relies on the servlet container or 
reverse proxy: add a "
+                + "<security-constraint> covering /* (and a <login-config>) to 
WEB-INF/web.xml, "
+                + "or switch to BASIC / OAUTH2.",
+            mode.name());
+      }
     }
 
     ResourceManager resourceManager = RWT.getResourceManager();
@@ -326,6 +339,20 @@ public class HopWebEntryPoint extends AbstractEntryPoint {
             });
   }
 
+  /**
+   * The configured Hop Web authentication mode, or {@code NONE} when the 
security configuration
+   * cannot be read. Used to decide whether an unauthenticated request is 
expected (mode {@code
+   * NONE}) or a sign that the container security constraint for {@code 
EXTERNAL} is missing.
+   */
+  private HopSecurityConfig.AuthMode resolveAuthMode() {
+    try {
+      return HopSecurityConfig.load().getAuthMode();
+    } catch (Exception e) {
+      LogChannel.UI.logDebug("Could not read the Hop Web security 
configuration", e);
+      return HopSecurityConfig.AuthMode.NONE;
+    }
+  }
+
   /**
    * When there is no saved theme preference, run a client script to check 
prefers-color-scheme and
    * redirect to /ui or /ui-dark so the UI follows system light/dark mode. 
Preserves query string

Reply via email to