Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<!--
SPDX-License-Identifier: Apache-2.0

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->

# Agent Guide for Apache CXF Fediz

This file is read by automated agents (security scanners, code analyzers,
AI assistants) operating on this repository. It points them at the
human-authored references they should consult before producing output.

## Security

Security model: [SECURITY.md](./SECURITY.md) -> [THREAT_MODEL.md](./THREAT_MODEL.md)

Agents that scan this repository should consult `SECURITY.md` and the linked
`THREAT_MODEL.md` before reporting issues. Fediz is a WS-Federation / SAML-SSO
system: the security pivot is SAML token validation at the Relying-Party plugin
(signature against a trusted IdP cert, audience/wtrealm, Conditions/timestamps,
replay, anti-signature-wrapping) and token issuance at the IdP (reply-URL
allow-listing, login CSRF/throttling). The token travels through the untrusted
browser, so most properties are about validating it.
9 changes: 9 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,12 @@

For information on how to report a new security problem please see [here](https://www.apache.org/security/).
Our existing security advisories are published [here](http://cxf.apache.org/security-advisories.html).

## Threat Model

What Fediz treats as in scope and out of scope, the security properties it
provides and disclaims (RP token validation: signature, audience, conditions,
replay, anti-signature-wrapping; IdP issuance and reply-URL validation), the
adversary model, and how inbound reports and tool/AI findings are triaged are
documented in [THREAT_MODEL.md](./THREAT_MODEL.md). Reporters and triagers
should consult it alongside this policy.
268 changes: 268 additions & 0 deletions THREAT_MODEL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
<!--
SPDX-License-Identifier: Apache-2.0

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->

# Threat Model — Apache CXF Fediz

## §1 Header

- **Project:** Apache CXF Fediz — a web-application **single sign-on** system implementing the
**WS-Federation 1.2 Passive Requestor Profile** (and SAML-SSO), with **SAML 1.1 / 2.0 tokens**, role
information carried as SAML `AttributeStatement`s, and a published WS-Federation metadata document
*(documented — README)*. It has two deployable halves: an **Identity Provider (IdP)** that authenticates
users and issues tokens (STS-backed), and **Relying-Party (RP) plugins** embedded in a protected web app
that redirect unauthenticated users to the IdP and **validate the returned token** *(documented — `services/`,
`plugins/`)*.
- **Modelled against:** `apache/cxf-fediz` `main`/HEAD (2026-05-31).
- **Status:** **DRAFT — v0, not yet reviewed by the CXF PMC.** Companion to the `apache/cxf` umbrella model;
Fediz's SSO trust surface is distinct and modelled here. Produced via the `threat-model-producer` rubric
(<https://gist.github.com/potiuk/da14a826283038ddfe38cc9fe6310573>).
- **Version binding / reporting / legend / advisories** as in the CXF model
(<https://cxf.apache.org/security-advisories.html>). **Draft confidence:** ~12 documented / 0 maintainer /
~46 inferred. Each *(inferred)* routes to §14.

In SSO the security pivot is **token validation at the RP** and **token issuance at the IdP**, both around a
token that travels through the *untrusted* browser. Most of this model lives in §8/§9 around those two points.

## §2 Scope and intended use

Intended use *(documented)*: protect web applications by delegating authentication to a Fediz IdP via
WS-Federation/SAML-SSO; the RP plugin enforces "authenticated + has claims" before the app runs.

Caller roles:

- **End-user browser (untrusted)** — drives the redirect-based flow and carries the token between IdP and RP.
- **Relying Party (the protected app + plugin)** — trusts tokens it can validate against the configured IdP.
- **Identity Provider** — authenticates users, issues signed tokens, exposes login + metadata.
- **STS** — issues/validates the underlying SAML tokens (WS-Trust) for the IdP.
- **Deployer/operator** — configures IdP trust (signing certs), RP `wtrealm`/audience, allowed reply URLs,
TLS, and the user/credential store. **Trusted; out of model as adversary (§3).**

**Component-family table:**

| Family | Entry point | Touches outside process | In model? |
| --- | --- | --- | --- |
| RP plugin — token processing | `plugins/core` (`saml`, `samlsso`, `processor`, `handler`) | browser-delivered token; IdP cert | **Yes** |
| RP plugin — container integration | tomcat/jetty/spring/websphere plugins | servlet request/session | **Yes** |
| IdP service — auth + token issuance | `services/` (IdP), login | network; user store; STS | **Yes** |
| STS / WS-Trust | STS service | crypto; user store | **Yes** |
| WS-Fed metadata publish | metadata endpoint | network | **Yes** |
| Examples / systests / packaging | `examples/`, `systests/`, `apache-fediz`, `etc/` | — | No → §3 |

## §3 Out of scope (explicit non-goals)

- **The operator/deployer as adversary** and pure misconfiguration (wrong IdP cert trust, audience left
unset, TLS disabled) — Fediz provides the validation; configuring it correctly is the deployer's job
(§10/§11) *(inferred)*.
- **The protected application's own logic and its use of the established identity** beyond what the plugin
provides.
- **The user-credential store / external auth backends** the IdP delegates to.
- **`examples/`, `systests/`, packaging, and `etc/` sample configs** *(inferred)*.
- **The underlying CXF/WSS4J XML-signature stack internals** except as Fediz configures and invokes them
(the CXF umbrella model covers those).

## §4 Trust boundaries and data flow

Two boundaries dominate:

1. **RP ← browser-delivered token (the critical one).** After IdP login the browser POSTs/redirects a
`wresult`/SAMLResponse to the RP. These bytes are **fully attacker-influenceable** (the user controls
their browser); the RP must treat the token as untrusted until it has verified: the **XML signature**
against the configured IdP signing certificate; the **issuer**; the **audience/`wtrealm`** equals this RP;
the **conditions/timestamps** (NotBefore/NotOnOrAfter, clock skew); **one-time use / replay**; and that
the signature covers the asserted content (**anti-XSW**) *(inferred — `samlsso`/`processor`; specifics §14)*.
2. **IdP ← login + token request.** The IdP authenticates the user and issues a token bound to the
requesting RP (`wtrealm`) with a reply address (`wreply`); it must validate the RP/realm and the reply
URL (open-redirect / token-forwarding surface) and protect the login from CSRF/brute-force *(inferred)*.

WS-Fed flow parameters (`wa`, `wresult`, `wctx`, `wtrealm`, `wreply`, `wfresh`, `wreq`) are all
attacker-tamperable in the browser and must be validated, not trusted *(inferred)*.

**Reachability preconditions:** an RP-side finding is in-model if reachable from a crafted/replayed token or
flow parameter *before* the plugin establishes the security context; an IdP-side finding is in-model if
reachable from an unauthenticated request to login/metadata/token endpoints; misconfiguration-only outcomes
are `OUT-OF-MODEL` (§3/§5a).

## §5 Assumptions about the environment

- **Runtime:** JVM web apps in a servlet container (RP plugins integrate with Tomcat/Jetty/Spring/WebSphere)
and a deployed IdP/STS *(documented)*.
- **Trust material:** the RP is configured with the IdP's signing certificate(s)/truststore; the IdP/STS hold
signing keys *(inferred)*.
- **Transport:** TLS protects the browser↔IdP and browser↔RP legs; Fediz supports but the deployer enforces
it *(inferred — wave-1)*.
- **Clocks:** IdP and RP clocks are roughly synchronized for `Conditions` validation (a skew window applies)
*(inferred)*.
- **What Fediz does to its host (*(inferred)* — wave-2):** processes XML/SAML; performs crypto; reads
configured truststores/keystores; the IdP talks to the STS and the user store; not assumed to execute host
commands.

## §5a Build-time and configuration variants

| Knob (names *(inferred)*) | Effect | Default ruling needed |
| --- | --- | --- |
| RP signature requirement / trusted IdP certs | Whether unsigned/untrusted tokens are rejected | **Open (wave-1):** signature + trust mandatory by default? |
| Audience (`wtrealm`) restriction enforcement | Prevents token replay to a different RP | **Open (wave-1)** |
| Token replay cache (one-time-use) | Replay protection of consumed tokens | **Open (wave-1)** |
| Clock-skew window for `Conditions` | Forgiveness of timestamp validation | Confirm default |
| `wreply`/reply-URL validation at the IdP | Open redirect / token forwarding | **Open (wave-1)** |
| SAML XML secure-processing (DTD/entity off) | XXE/XML-DoS on token parse | Confirm inherited CXF defaults |
| TLS enforcement on the flow | Token confidentiality/integrity in transit | Deployer (§10) |

## §6 Assumptions about inputs

| Entry point | Parameter | Attacker-controllable? | Caller/deployer must enforce |
| --- | --- | --- | --- |
| RP plugin | `wresult` / SAMLResponse (the token) | **yes** (browser-delivered) | full signature + issuer + audience + conditions + replay + anti-XSW |
| RP/IdP | `wctx`, `wtrealm`, `wreply`, `wfresh`, `wreq`, `RelayState` | **yes** | validate realm; allow-list reply URLs; treat context as opaque |
| IdP login | username/password / external auth | **yes** | credential verification; CSRF; throttling |
| IdP metadata endpoint | request | **yes** | safe publication; no SSRF via metadata refs |
| RP/IdP config (truststore, realm, certs) | all keys | **no — deployer-trusted** | never sourced from a request |

## §7 Adversary model

- **Primary adversary:** an untrusted web user/browser who crafts, tampers with, or **replays** SAML tokens and
WS-Fed parameters to an RP, or attacks the IdP login/token endpoints. Capabilities: submit arbitrary
`wresult`/parameters, replay a previously valid token, attempt signature-wrapping, forge an assertion,
redirect via a manipulated `wreply`.
- **Secondary:** a malicious or compromised RP requesting tokens it should not receive; a network MITM where
TLS is absent.
- **Goals:** authenticate as another user / bypass authentication at the RP; have a token minted or forwarded
to an attacker-controlled RP; escalate roles by injecting `AttributeStatement` claims; open-redirect a user.
- **Out of model:** the deployer/operator; anyone holding the IdP signing key or the configured truststore;
the credential store internals.

## §8 Security properties the project provides

*(All *(inferred)* pending §14; symptom + severity per the rubric.)*

1. **RP token authenticity & integrity.** The RP accepts a token only if its XML signature verifies against a
configured/trusted IdP certificate and the signature covers the asserted content (anti-XSW)
*(inferred — load-bearing)*. *Symptom:* acceptance of an unsigned/forged/wrapped token ⇒ authentication
bypass / impersonation. *Severity:* critical.
2. **Audience & freshness binding.** A token is accepted only if its audience/`wtrealm` matches this RP and its
`Conditions` (NotBefore/NotOnOrAfter, within skew) hold; consumed tokens are replay-protected
*(inferred)*. *Symptom:* cross-RP replay or replay of an expired/old token. *Severity:* critical.
3. **IdP token-issuance integrity.** The IdP issues tokens only for authenticated users and signs them; it
binds the token to the requesting realm and validates the reply target *(inferred)*. *Symptom:* token minted
without auth, or for/forwarded to the wrong RP. *Severity:* critical.
4. **Role/claim integrity.** Roles/claims come from the signed assertion, so a client cannot inject or elevate
claims *(inferred)*. *Symptom:* privilege escalation via tampered `AttributeStatement`. *Severity:* critical.
5. **Safe token parsing.** Malformed SAML/XML yields a clean rejection, not XXE/DoS/crash (inherits CXF/WSS4J
secure-XML defaults) *(inferred)*. *Symptom:* XXE/SSRF/OOM from a crafted token. *Severity:* critical.

## §9 Security properties the project does NOT provide

- **No security without correct trust configuration.** If the RP is not configured with the right IdP signing
trust, or audience validation is disabled, token validation is only as strong as what's left *(inferred)*.
- **No defence against a compromised IdP signing key or a deployer who trusts a hostile IdP** (§3).
- **No transport security by itself** — without TLS the token is interceptable/replayable on the wire.
- **The protected app must still authorize** beyond "authenticated"; Fediz establishes identity/claims, not
the app's access-control policy.

**False friends:**

- *"The token is signed" is not "the token is valid for me now"* — signature alone, without audience +
conditions + replay + anti-XSW checks, is the classic SAML-SSO bypass.
- *`wctx`/`RelayState` look like trusted state but are attacker-controlled* — treat as opaque, validate on return.
- *A published metadata document looks authoritative but is fetched over the same untrusted channels* — trust
is anchored in configured certs, not in fetched metadata.

**Well-known attack classes to keep in view:** XML signature wrapping (XSW); unsigned-assertion / signature
-stripping acceptance; assertion replay and cross-audience replay; `Conditions`/clock-skew abuse; open redirect
via `wreply`; XXE/XML-DoS on token parse; CSRF on IdP login; recipient/audience confusion.

## §10 Downstream (deployer) responsibilities

- Configure the RP with the **correct IdP signing certificate(s)** and require signed tokens; **set the
audience/`wtrealm`** so tokens for other RPs are rejected.
- Enforce **TLS** on every leg of the flow; keep IdP↔STS and truststore material protected.
- **Allow-list reply URLs** at the IdP (`wreply`) to prevent open redirect / token forwarding.
- Keep the **replay cache** and a sane **clock-skew window** enabled; sync clocks.
- Protect IdP login from CSRF/brute-force; secure the credential store.
- Stay on a supported line and watch <https://cxf.apache.org/security-advisories.html>.

## §11 Known misuse patterns

- Deploying an RP without configuring/validating the IdP signing trust (accepts any token).
- Disabling audience or conditions validation "to make it work".
- Running the flow over plain HTTP (token sniffable/replayable).
- Leaving `wreply` reply URLs unrestricted at the IdP (open redirect / token forwarding).
- Treating `wctx`/`RelayState` as trusted server state.

## §11a Known non-findings (recurring false positives)

*(v0 seed — the PMC will have the authoritative list — §14.)*

- **"Accepts a token" reports that assume validation is off** when the default requires signature + audience +
conditions + replay — `KNOWN-NON-FINDING` / misconfig unless a *default* check is missing (then `VALID`).
- **Findings in `examples/` / `systests/` / sample configs** — out of scope (§3).
- **"No TLS"** against sample/local configs — deployer responsibility (§10).
- **Use of SAML 1.1** (legacy but supported) flagged generically — supported by design; only specific weak
handling is a finding.

## §12 Conditions that would change this model

- A change to default signature/audience/conditions/replay enforcement in the RP.
- A new protocol (e.g. OIDC) or token type enabled by default.
- A change to `wreply` reply-URL validation or IdP login defaults.
- A change in the inherited CXF/WSS4J XML-security defaults.
- Any report not cleanly routable to a §13 disposition.

## §13 Triage dispositions

| Disposition | Meaning | Licensed by |
| --- | --- | --- |
| `VALID` | Violates a claimed property via an in-scope adversary/input *in a default/secure configuration*. | §8, §6, §7 |
| `VALID-HARDENING` | No §8 property broken, but a §11 misuse is easy enough to warrant a safer default/guard. | §11 |
| `OUT-OF-MODEL: trusted-input` | Requires control of deployer config / signing keys / truststore. | §6 |
| `OUT-OF-MODEL: adversary-not-in-scope` | Requires deployer / IdP-key / credential-store capability. | §7, §3 |
| `OUT-OF-MODEL: unsupported-component` | Lands in examples, systests, packaging, samples. | §3 |
| `OUT-OF-MODEL: non-default-build` | Only when the deployer disabled a validation control. | §5a |
| `BY-DESIGN: property-disclaimed` | Concerns a §9-disclaimed property (no security without trust config; identity ≠ app authorization). | §9 |
| `KNOWN-NON-FINDING` | Matches a §11a entry. | §11a |
| `MODEL-GAP` | Routes to none of the above → revise the model. | §12 |

## §14 Open questions for the maintainers

**Wave 1 — RP validation defaults (the SSO crux; §5a/§8):**
1. By default, does the RP **require a valid XML signature from a configured/trusted IdP cert** and reject
unsigned/untrusted tokens? *Proposed:* yes, mandatory.
2. Are **audience/`wtrealm`** and **`Conditions`** (NotBefore/NotOnOrAfter + skew) enforced by default, and is
a **replay cache** on by default? *Proposed:* all on by default.
3. Does the SAML processing defend **signature-wrapping (XSW)** by binding the verified signature to the
consumed assertion/elements? *Proposed:* yes (via WSS4J/CXF).

**Wave 2 — IdP & redirect surface (§4/§8/§9):**
4. Does the IdP **validate `wreply` reply URLs** (allow-list) to prevent open redirect / token forwarding, and
is its login **CSRF-protected and throttled**? *Proposed:* reply-URL allow-list configured per realm; login
CSRF-protected.
5. How is the underlying **XML/SAML parsing hardened** against XXE/DoS — inherited from CXF/WSS4J secure
defaults? *Proposed:* yes, inherited.

**Wave 3 — boundaries & §11a (§3/§9/§11a):**
6. Confirm the **deployer-misconfiguration** boundary (which "insecure" outcomes are `OUT-OF-MODEL`). *Proposed:*
per §3/§11.
7. From the advisory history, what do scanners most often (re)report that the PMC considers a **non-finding**?
(Seeds §11a.)

**Meta:**
8. Confirm this model lives in `apache/cxf-fediz` (linked from its `SECURITY.md`), separate from the
`apache/cxf` umbrella. *Proposed:* yes.

## §15 Machine-readable companion

Deferred for v0; a `threat-model.yaml` can later encode the §6 trust table, §2/§3 scoping, §8 rows, §9 false
friends, §11a non-findings, and §13 dispositions.
Loading