@mcp-abap-adt/auth-providers 3.0.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/CHANGELOG.md +105 -0
  2. package/README.md +620 -77
  3. package/dist/auth/saml2Auth.d.ts +6 -2
  4. package/dist/auth/saml2Auth.d.ts.map +1 -1
  5. package/dist/auth/saml2Auth.js +9 -20
  6. package/dist/auth/samlBearerAssertion.d.ts.map +1 -1
  7. package/dist/auth/samlBearerAssertion.js +2 -1
  8. package/dist/auth/strictXml.d.ts +13 -0
  9. package/dist/auth/strictXml.d.ts.map +1 -0
  10. package/dist/auth/strictXml.js +21 -0
  11. package/dist/errors/AssertionValidationError.d.ts +15 -0
  12. package/dist/errors/AssertionValidationError.d.ts.map +1 -0
  13. package/dist/errors/AssertionValidationError.js +24 -0
  14. package/dist/errors/TokenProviderErrors.d.ts +2 -0
  15. package/dist/errors/TokenProviderErrors.d.ts.map +1 -1
  16. package/dist/errors/TokenProviderErrors.js +3 -1
  17. package/dist/index.d.ts +3 -0
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +11 -1
  20. package/dist/providers/Saml2BearerProvider.d.ts +1 -0
  21. package/dist/providers/Saml2BearerProvider.d.ts.map +1 -1
  22. package/dist/providers/Saml2BearerProvider.js +17 -2
  23. package/dist/providers/Saml2PureProvider.d.ts +1 -0
  24. package/dist/providers/Saml2PureProvider.d.ts.map +1 -1
  25. package/dist/providers/Saml2PureProvider.js +19 -5
  26. package/dist/providers/saml2Utils.d.ts +49 -2
  27. package/dist/providers/saml2Utils.d.ts.map +1 -1
  28. package/dist/providers/saml2Utils.js +94 -2
  29. package/dist/validation/assertionValidator.d.ts +28 -0
  30. package/dist/validation/assertionValidator.d.ts.map +1 -0
  31. package/dist/validation/assertionValidator.js +444 -0
  32. package/dist/validation/documentIds.d.ts +15 -0
  33. package/dist/validation/documentIds.d.ts.map +1 -0
  34. package/dist/validation/documentIds.js +32 -0
  35. package/dist/validation/inMemoryReplayStore.d.ts +22 -0
  36. package/dist/validation/inMemoryReplayStore.d.ts.map +1 -0
  37. package/dist/validation/inMemoryReplayStore.js +49 -0
  38. package/dist/validation/signedNode.d.ts +54 -0
  39. package/dist/validation/signedNode.d.ts.map +1 -0
  40. package/dist/validation/signedNode.js +171 -0
  41. package/dist/validation/xsdDateTime.d.ts +17 -0
  42. package/dist/validation/xsdDateTime.d.ts.map +1 -0
  43. package/dist/validation/xsdDateTime.js +67 -0
  44. package/package.json +5 -4
package/CHANGELOG.md CHANGED
@@ -7,6 +7,111 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [4.0.0] - 2026-09-25
11
+
12
+ ### Breaking
13
+
14
+ - **Both SAML providers validate the assertion before trusting it** (#19).
15
+ Until now the only check was that the payload was a non-empty string, and
16
+ `Saml2PureProvider` took its session lifetime from a regular expression over
17
+ the unverified XML. `Saml2BearerProvider` now validates before the token
18
+ exchange, `Saml2PureProvider` before `cookieProvider`, through twelve checks:
19
+ document shape, unique IDs, signature, that the signed node is the node read,
20
+ `Status`, assertion ID, issuer, `Conditions`, `NotBefore`, `NotOnOrAfter`,
21
+ audience, one bearer subject confirmation (request ID, recipient, window) and
22
+ `Destination`, then replay. The README's *SAML assertion validation* lists
23
+ them with what refuses each.
24
+
25
+ **The configuration is required.** Supply `idpCertificates` (PEM or bare
26
+ base64 DER, a list for key rotation) and `idpEntityId`, or an
27
+ `assertionValidator` of your own; without them the provider's constructor
28
+ throws a `ValidationError` naming what is missing. A shipped validator
29
+ supplied as `assertionValidator` still needs `idpEntityId`, and its absence
30
+ fails at construction too; only a custom validator does without.
31
+ `spEntityId` becomes the `Audience` the assertion must name.
32
+
33
+ **Request IDs.** `InResponseTo` must answer the AuthnRequest the package
34
+ minted, or `authnRequestId` when the package did not build the request — a
35
+ pre-built `authorizationUrl`, or a strategy that returns a payload without
36
+ calling `buildAuthorizationUrl`. `idpInitiated: true` declares that no request
37
+ was sent, so the assertion must carry no `InResponseTo`; it gives up the
38
+ login-CSRF defence of a request ID, and is never inferred.
39
+ `Saml2BearerProvider` against UAA or XSUAA needs it, since both refuse an
40
+ assertion carrying `InResponseTo`. Having neither an ID nor the declaration,
41
+ or combining the declaration with an ID, raises a `ValidationError`. With
42
+ `idpInitiated` and no `authorizationUrl`, a strategy that calls
43
+ `buildAuthorizationUrl` is refused inside the builder, before any URL is
44
+ produced — so before a browser opens.
45
+
46
+ **Status, by validator.** Under `createSignedResponseValidator` —
47
+ `Saml2PureProvider`'s default — an identity provider returning a
48
+ non-`Success` status is now refused, where it was accepted before.
49
+ `Saml2BearerProvider`'s default, `createSignedAssertionValidator`, does not
50
+ read `Status`, so a bearer consumer sees no change there: a declining identity
51
+ provider mints no signed assertion, and the login fails for want of one.
52
+
53
+ **Migrating:** see *Migrating from 3.x to 4.0* in the README — add the trust
54
+ configuration, check `spEntityId`, and for `Saml2BearerProvider` against UAA
55
+ or XSUAA add `idpInitiated: true` with a strategy that never calls
56
+ `buildAuthorizationUrl`.
57
+ - **`parseSamlNotOnOrAfter` is removed.** `Saml2PureProvider`'s `expiresAt` is
58
+ now the validated assertion's expiry — the earlier of `Conditions/@NotOnOrAfter`
59
+ and the accepted bearer confirmation's — read from the verified document.
60
+ - **`buildSamlAuthorizationUrl` returns `{ url, requestId? }`**, since the
61
+ minted ID must survive to validation, and **`getSamlAssertion` returns
62
+ `Promise<SamlAssertionResult>`** (payload, request ID, ACS) instead of
63
+ `Promise<string>`. None of these, nor `parseSamlNotOnOrAfter`, was exported
64
+ from the package root; only a deep import of `dist/auth/saml2Auth` or
65
+ `dist/providers/saml2Utils` is affected.
66
+ - **`@mcp-abap-adt/interfaces-auth` `^2.0.0`** (was `^1.2.0`), where
67
+ `AssertionContext.expectedInResponseTo` is optional — a breaking change for
68
+ implementers of `IAssertionValidator`, which must refuse an assertion
69
+ carrying `InResponseTo` when it is absent.
70
+
71
+ ### Added
72
+
73
+ - **`createSignedResponseValidator`** and **`createSignedAssertionValidator`**,
74
+ sharing `ShippedValidatorOptions` (`idpCertificates`, `clockSkewMs`,
75
+ `replayStore`). The first requires the signature to cover the `Response` and
76
+ performs all twelve checks; the second accepts a signature over the
77
+ `Assertion` — bare, or inside a Response — and does not read `Status`,
78
+ `Response/Issuer` or `Destination` at all. `Saml2PureProvider` defaults to the
79
+ first, `Saml2BearerProvider` to the second; `assertionValidator` replaces
80
+ either.
81
+ - **Replay detection**: `defaultReplayStore`, a process-wide in-memory store
82
+ shared by every default validator, keyed by `{issuer, assertionId}` and
83
+ retained until the earlier of `Conditions/@NotOnOrAfter` and the latest
84
+ `NotOnOrAfter` of a bearer confirmation that answers the request and names
85
+ the ACS, plus `clockSkewMs` — as long as the assertion could still be
86
+ accepted, which can outlast `expiresAt`; `createInMemoryReplayStore()` for
87
+ an isolated one; `assertionReplayStore` on the providers for a shared store
88
+ across processes.
89
+ - **`clockSkewMs`**, default `0`.
90
+ - Any XML parse fault — including one `@xmldom/xmldom` would otherwise repair,
91
+ such as an undeclared entity — is a refusal at `document`, and the parser
92
+ never writes to the console; the bearer conversion (`toBearerAssertion`)
93
+ parses the same way.
94
+ - The validators refuse a payload carrying a `<!DOCTYPE` declaration, never
95
+ take a signing certificate from the document's own `KeyInfo`, and accept
96
+ RSA-SHA1 signatures and SHA-1 digests, as `xml-crypto` does by default; a
97
+ consumer wanting to refuse SHA-1 wraps a shipped validator in its own.
98
+ - **`AssertionValidationError`**, with `check: AssertionCheck` naming the check
99
+ that refused the assertion, and code `ASSERTION_VALIDATION_ERROR`.
100
+ - `xml-crypto` becomes a runtime dependency, for signature verification.
101
+
102
+ ### Development
103
+
104
+ - Both validators run end to end in `npm test`, through `Saml2PureProvider`
105
+ and a real callback, against responses from `@mcp-abap-adt/auth-mocks` (the
106
+ devDependency and its range are unchanged). Every corruption variant is refused at the
107
+ check it targets, except `statusFailure` and `wrongDestination`, which the
108
+ assertion-only validator accepts — both halves asserted.
109
+ - The provider stand's SAML suites run every login through the provider's
110
+ validation, including Keycloak's real responses, signed at both levels; the
111
+ live XSUAA suite does the same with its per-run identity provider, and now
112
+ refuses the `InResponseTo` case itself, before XSUAA sees it.
113
+ - `@mcp-abap-adt/interfaces-auth-sap` `^1.0.1`.
114
+
10
115
  ## [3.0.0] - 2026-09-24
11
116
 
12
117
  ### Added