This is an automated email from the ASF dual-hosted git repository.
jamesbognar pushed a commit to branch docs
in repository https://gitbox.apache.org/repos/asf/juneau.git
The following commit(s) were added to refs/heads/docs by this push:
new 6e36c7d6c1 READY-395/384: Document actuator off-by-default policy and
MCP DCR secure-only registration
6e36c7d6c1 is described below
commit 6e36c7d6c1f44ac86b9476d4e561602675ae3583
Author: James Bognar <[email protected]>
AuthorDate: Sun Aug 16 15:33:58 2026 -0400
READY-395/384: Document actuator off-by-default policy and MCP DCR
secure-only registration
---
pages/release-notes/10.0.0.md | 13 ++++++++++++-
pages/topics/16.11.ManagementSurface.md | 11 ++++++++++-
2 files changed, 22 insertions(+), 2 deletions(-)
diff --git a/pages/release-notes/10.0.0.md b/pages/release-notes/10.0.0.md
index b830be7c8a..5de5b76fe7 100644
--- a/pages/release-notes/10.0.0.md
+++ b/pages/release-notes/10.0.0.md
@@ -364,6 +364,8 @@ New endpoints:
Exposure is **on-by-default-with-gating**: non-sensitive reads are exposed;
mutating/sensitive operations (`/loggers` set-level, the dumps) are
deny-by-default behind explicit opt-in settings beans (`LoggersSettings`,
`DumpsSettings`). No auth provider is auto-wired — the consumer supplies their
own guard.
+**`BasicActuatorGroup` mounts only `/healthz`/`/readyz`/`/livez` and the dumps
by default; `/info` and `/loggers` are off.** The convenience group composes
`HealthMixin` + `DumpsMixin` only — `InfoMixin` and `LoggersMixin` are
deliberately left out, since an unauthenticated manifest dump (`/info`) and
logger-topology disclosure (`/loggers` read) are both meaningful information
leaks with no guard auto-wired. Re-enable either (or both) with an a-la-carte
subclass adding `@Rest(mixins={Inf [...]
+
See the new [Management Surface](/docs/topics/ManagementSurface) topic page
for the endpoint catalog, the `BasicActuatorGroup` one-liner, the exposure
policy, and the manifest-stamping recipe.
### `/loggers` non-JUL backends (Logback, Log4j2)
@@ -1166,7 +1168,7 @@ See
[juneau-rest-server-mcp](/docs/topics/JuneauRestServerMcp#replay-protection-
**F3 — dynamic client registration + authorization hardening.** The third
slice completes the client story with RFC 7591 / OIDC Dynamic Client
Registration, issuer-keyed credential persistence (SEP-2352), and scoped
step-up authorization (SEP-2350, both halves), all in
`juneau-rest-client-mcp-auth` except the server step-up gate:
-- **Dynamic Client Registration (SEP-837 / RFC 7591 / OIDC).**
`McpDynamicClientRegistrar` POSTs client metadata to an AS
`registration_endpoint` and returns an immutable, secret-redacting
`McpClientRegistration`. `McpApplicationType` is a Juneau-owned `NATIVE`/`WEB`
enum (native is the SEP-837 SHOULD for CLI/desktop/`localhost` clients) so the
public API does not leak the Nimbus `provided` type. Loopback redirects are
built with `LoopbackRedirectUris`: `portAgnostic(path)` is the RFC 82 [...]
+- **Dynamic Client Registration (SEP-837 / RFC 7591 / OIDC).**
`McpDynamicClientRegistrar` POSTs client metadata to an AS
`registration_endpoint` and returns an immutable, secret-redacting
`McpClientRegistration`. `McpApplicationType` is a Juneau-owned `NATIVE`/`WEB`
enum (native is the SEP-837 SHOULD for CLI/desktop/`localhost` clients) so the
public API does not leak the Nimbus `provided` type. Loopback redirects are
built with `LoopbackRedirectUris`: `portAgnostic(path)` is the RFC 82 [...]
- **Issuer-keyed credential binding (SEP-2352).** Persisted credentials
**MUST** be keyed by the AS `issuer` and never reused across authorization
servers. `McpClientRegistrationStore` is the persistence SPI;
`InMemoryMcpClientRegistrationStore` is the thread-safe, secret-redacting
default. `McpClientRegistrationManager` orchestrates mechanism selection,
issuer-keying, and migration: on-demand (no store), store-hit reuse, or
re-registration when discovery indicates a different issuer — s [...]
- **Scoped step-up authorization (SEP-2350, both halves).** Server side,
`McpResourceServerConfig.addOperationScope(operation, scopes…)` declares
per-operation required scopes; the RS answers an under-scoped call with `403
insufficient_scope` + a `WWW-Authenticate` `scope=` hint, and the baseline
`401` now also carries the `scope` hint when a baseline required-scope set is
configured. Both the baseline and per-operation gates are **hierarchy-aware**
(a broader granted scope satisfies a n [...]
@@ -1239,6 +1241,15 @@ See [OIDC Relying Party
Login](/docs/topics/OidcRelyingParty#login-state-store-c
A related set of ReDoS-hardening fixes (bounded/escaped regex handling in
`HttpPartSchema`, `LogEntryFormatter`, and the request-routing
`UrlPathMatcher`) landed in the same sweep. **Migration:** none for normal
usage; an application that displayed unauthorized-request detail to end users,
or that parsed XML relying on DTD processing on the non-validating path, will
see the new generic/hardened behavior.
+- **Security hardening — parser and transport boundary sweep.** A follow-on
hardening pass tightened validation at several parser/transport boundaries:
+ - **`MultipartBody`** (`juneau-rest-common`) now rejects CR/LF and other
control characters in a part's `name`/`filename`/`contentType` (enforced both
at `MultipartPart` construction and defensively at write time), closing a
header-injection vector into the multipart wire format; `Content-Disposition`
quoted-string values are also now backslash-escaped.
+ - **`BsonInputStream`** (`juneau-marshall`) now enforces each declared
document/array length as a hard upper bound on every nested read (cstrings
included), rejecting a forged-short length that previously could be bypassed by
traversal relying solely on a `0x00` terminator.
+ - **`ProtobufReader`** (`juneau-marshall`) caps varint/tag decoding at 10
bytes (the maximum a 64-bit LEB128 varint can occupy) and validates a
wire-declared `LEN` field's length against the configured maximum before
skipping an unknown field, closing an unbounded-CPU decode loop and a
length-cap bypass, respectively.
+ - **`SamlAssertionValidator`** / `SamlAuthFilter`
(`juneau-rest-server-auth-saml`) now bind a bearer `SubjectConfirmationData`'s
`Recipient` to the request's actual ACS URL, rejecting an assertion issued for
a different endpoint.
+ - **`OidcDiscoveryClient.Builder`** (`juneau-rest-auth-oauth-flow`) now
requires the configured issuer to be `https` (loopback exempt), rejecting a
plaintext discovery endpoint at build time.
+
+ **Migration:** none for normal usage; each of these only rejects
previously-out-of-spec or previously-exploitable input.
+
- **Present-but-empty `RestContext.*` boolean settings no longer throw
(leniency improvement).** Landed alongside the new `RestContextProperties`
`@ConfigProperties` bean (see New Features above): previously, a
present-but-empty value for a boolean `RestContext.*` setting (e.g.
`RestContext.eagerInit=`) threw `BeanCreationException` at injection time,
because the old `@Value boolean` field's strict conversion had no tolerance for
an empty string. As of 10.0.0 this is resolved leniently t [...]
- **SVL variables in a `RestContext.*` boolean setting now resolve through the
resource's own var resolver (capability widening).** Landed alongside the same
`RestContextProperties` change: a `$C{...}` / `$R{...}` / `$S{...}`-style
variable embedded in a boolean `RestContext.*` value (e.g.
`RestContext.virtualThreads=$C{MyConfig/virtualThreads}`) is now resolved
through the owning resource's `VarResolver` rather than `VarResolver.DEFAULT`,
so resource-scoped variables like `$C{...}` (con [...]
diff --git a/pages/topics/16.11.ManagementSurface.md
b/pages/topics/16.11.ManagementSurface.md
index 58c8954267..d380a113e7 100644
--- a/pages/topics/16.11.ManagementSurface.md
+++ b/pages/topics/16.11.ManagementSurface.md
@@ -32,12 +32,21 @@ import org.apache.juneau.rest.server.*;
public class RootResources extends BasicRestServletGroup { /* ... */ }
```
-`BasicActuatorGroup` composes `InfoMixin`, `LoggersMixin`, `HealthMixin`, and
`DumpsMixin` under a single prefix. The prefix defaults to `/actuator` and is
configurable via the `juneau.actuator.path` system property (resolved through
the standard `$S{...}` SVL var):
+`BasicActuatorGroup` composes `HealthMixin` and `DumpsMixin` under a single
prefix. The prefix defaults to `/actuator` and is configurable via the
`juneau.actuator.path` system property (resolved through the standard `$S{...}`
SVL var):
```bash
java -Djuneau.actuator.path=/manage -jar myapp.jar
```
+> **`/info` and `/loggers` are off by default** — unlike health, they are not
mounted on the bare group, since `InfoMixin` discloses the full manifest and
`LoggersMixin`'s read side discloses logger topology, neither behind any auth.
Re-enable either (or both) a-la-carte on a subclass:
+>
+> ```java
+> @Rest(mixins={InfoMixin.class, LoggersMixin.class})
+> public class MyActuatorGroup extends BasicActuatorGroup { /* ... */ }
+> ```
+>
+> Mixins declared on a subclass are additive to the ones inherited from
`BasicActuatorGroup`, so `HealthMixin`/`DumpsMixin` stay mounted too. With no
such subclass, `/info` and `/loggers` return `404` under the group's prefix.
+
> **`/metrics` is not assembled into the group** — it lives in the
> `juneau-rest-server-metrics-micrometer` module (which `juneau-microservice`
> does not depend on). Add `MetricsMixin` a-la-carte to your host resource
> when that module is on the classpath.
Composition is convenience, not the only way in — every endpoint remains
independently mountable a-la-carte via its standalone `*Mixin`/`*Resource`
flavor.