Skip to content

Forward-port WS-Trust support to dev - #3603

Open
Ignacio Inglese (iNinja) wants to merge 3 commits into
devfrom
iinglese/wstrust-forward-port-dev
Open

Ignacio Inglese (iNinja) wants to merge 3 commits into
devfrom
iinglese/wstrust-forward-port-dev

Conversation

@iNinja

@iNinja Ignacio Inglese (iNinja) commented Aug 25, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Forward-ports the WS-Trust package restored by #3547 from dev8x to dev.

The reviewed squash commit from #3547 was cherry-picked as a single commit. The intermediate 19-commit feature history was intentionally not replayed because it contains merge commits and superseded implementation states.

Additional pipeline integration

This PR also registers the WS-Trust source and test projects in:

  • buildConfiguration.xml, so the official test script and legacy build, pack, and signing paths include them.
  • WilsonUnix.sln, so Unix build, test, and packaging workflows include them.

Validation

Check Result
WilsonUnix.sln Release build Succeeded with 0 warnings and 0 errors
WS-Trust tests on net462 183 passed
WS-Trust tests on net472 183 passed
WS-Trust tests on net6.0 183 passed
WS-Trust tests on net8.0 183 passed
WS-Trust tests on net9.0 183 passed
WS-Trust tests on net10.0 183 passed
Total WS-Trust test executions 1,098 passed, 0 failed, 0 skipped
9.x package creation Succeeded
Package dependency alignment Package and all Microsoft.IdentityModel dependencies aligned to the same pinned 9.0 preview version

The package contains assemblies for net462, net472, netstandard2.0, net6.0, net8.0, net9.0, and net10.0, together with the expected README and buildTransitive version-mismatch assets.

…x package (#3547)

* Forward-port Microsoft.IdentityModel.Protocols.WsTrust from origin/wstrust to dev8x

Port the WS-Trust implementation from the origin/wstrust feature branch
(based on 6.x) to the current dev8x branch (8.x). This package provides
the active WS-Trust SOAP profile needed by System.ServiceModel.Federation
(WCF), which cannot be replaced by WsFederation (passive/browser SSO).

Addresses: #3463

Changes from the original branch code:
- Modernized csproj: removed FxCopAnalyzers, PackageReference -> ProjectReference,
  added PublicApiAnalyzers/InternalApiAnalyzers support, trimming annotations
- Updated file headers to match current .editorconfig conventions
- Replaced obsolete RNGCryptoServiceProvider with RandomNumberGenerator.Create()
- Added DynamicallyAccessedMembers annotations for AOT/trimming compatibility
- Added using Microsoft.IdentityModel.Xml to test files for XmlReadException
- Fixed CLSCompliant attribute in test AssemblyInfo (true -> false)
- Generated PublicAPI.Unshipped.txt (588 entries) and InternalAPI.Unshipped.txt

Test results: 117 tests pass across net8.0, net9.0, and net10.0

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Post-port improvements to Microsoft.IdentityModel.Protocols.WsTrust

AOT compatibility:
- Replace Type.InvokeMember reflection in WsTrustSerializer.TryWriteSourceData
  with direct access to the internal XmlTokenStream property
- Add InternalsVisibleTo from Tokens.Saml to Protocols.WsTrust
- Zero trimming/AOT warnings

Security hardening:
- Set XmlResolver = null on all XmlDocument instances (XXE defence)
- IDX15101 error uses reader.LocalName instead of ReadOuterXml (prevents
  token content leakage in exception messages)
- Add DepthLimitingXmlReader (MaxDepth=32) to ReadUnknownElement and
  ReadEndpointReference (XML nesting DoS defence)
- Apply BoundedXmlDictionaryReaderQuotas in ReadAsXmlElement and
  CreateXmlElement
- Replace XmlTextReader with XmlDictionaryReader.CreateTextReader in
  WsSecuritySerializer.CreateXmlElement
- Fix ReadBinarySecrect to read attributes before empty-element check;
  return null for empty elements to avoid NullReferenceException on .Data
- Add missing throw to null guards in Entropy static helpers and
  Psha1KeyGenerator.FillRandomBytes
- Fix double-wrapped FormatInvariant in Psha1KeyGenerator entropy size
  checks, restoring ArgumentException.ParamName

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a191b9da-fe1b-4bf7-89a2-be044b10e0ee

* Address GHCP review findings

Bugs:
- WsTrustResponse: add missing throw to null guard (null was silently
  accepted into RequestSecurityTokenResponseCollection)
- WsTrustBinarySecrectTypes: fix WS-Trust 1.4 AsymmetricKey URI
  (was Bearer URI; correct value is 200802/AsymmetricKey)
- Psha1KeyGenerator.GenerateSymmetricKey: fix swapped issuer/requestor
  entropy in ComputeCombinedKey call
- WsSecuritySerializer: read wsu:Id using WS-Utility namespace instead
  of WS-Security namespace
- WsSecuritySerializer: write Id as wsu:Id with correct namespace/prefix
- WsFedSerializer: fix error message for missing ClaimType Uri attribute
  (was referencing ContextItem/Name)

Minor:
- WsSecurityConstants: cache WsSecurity10/WsSecurity11 as static fields
  instead of allocating on each property access
- Psha1KeyGenerator: align XML doc param order with method signature

Cleanup:
- Remove trailing semicolon in WsTrustBinarySecrectTypes
- Fix test method name misspelling (ReadRequestSeurityTokenResponse)
- Fix pragma comment typo in WsDefaults (nEndoot)
- Remove commented-out dead assertion in EntropyTests

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a191b9da-fe1b-4bf7-89a2-be044b10e0ee

* Fix Wilson.sln: remove spurious x64/x86 platform entries

The solution file was opened in Visual Studio which regenerated all
platform configuration entries adding Debug|x64, Debug|x86, Release|x64
and Release|x86 for every project. Restore to the original Any CPU-only
format and retain only the two new WsTrust project entries.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a191b9da-fe1b-4bf7-89a2-be044b10e0ee

* Address Andre's review findings

BinarySecret URI fix:
- WsTrust14BinarySecretTypes: update Nonce and SymmetricKey to 200802
  namespace (AsymmetricKey was already fixed; Actions and KeyTypes use
  200512 intentionally per the WS-Trust 1.4 spec WSDL)

ReadBinarySecrect empty element:
- Return BinarySecret with EncodingType set instead of null for empty
  elements, preserving the Type attribute per spec (BinarySecret content
  is optional, Type attribute is OPTIONAL but meaningful)

BoundedReaderQuotas consistency:
- WsSecuritySerializer.CreateXmlElement: use WsUtils.BoundedReaderQuotas
  instead of XmlDictionaryReaderQuotas.Max

GenerateSymmetricKey naming:
- Rename senderEntropy/receiverEntropy to requestorEntropy/issuerEntropy
  to match ComputeCombinedKey parameter names and eliminate ambiguity

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a191b9da-fe1b-4bf7-89a2-be044b10e0ee

* Add CredScan suppression for WsTrust PSHA1 test vectors

CredScan's CodeConnString searcher flags the base64 PSHA1 key derivation
reference vectors in ComputedKeyReferences.cs as storage credentials
(5 matches). These are deterministic test vectors for verifying the
PSHA1 combined-key algorithm, not secrets.

The existing 'References.cs' entry does not cover this file as CredScan
matches on exact filename, so an explicit entry is required.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a191b9da-fe1b-4bf7-89a2-be044b10e0ee

* Keep WsTrust 1.4 BinarySecret types in the 200512 namespace

An earlier change moved the WsTrust14BinarySecretTypes constants to the
http://docs.oasis-open.org/ws-sx/ws-trust/200802 namespace. That was wrong
and this reverts it.

WS-Trust 1.4 is an addendum to 1.3, not a standalone schema. The 1.4 XSD
declares targetNamespace 200802 but binds xmlns:wst to 200512, and it only
defines the 1.4 additions (InteractiveChallenge, TextChallenge,
ChoiceChallenge, ContextData). It never redefines BinarySecretTypeEnum, so
the BinarySecret @type URIs stay at 200512. The same reasoning applies to
WsTrust14Actions and WsTrust14KeyTypes, which were already correct.

The one genuine bug from 6.8.0 is retained: WsTrust14BinarySecretTypes
.AsymmetricKey pointed at the 200512 Bearer KeyType URI instead of
AsymmetricKey.

Adds WsTrustConstantsTests to pin the expected URIs so these values are not
"corrected" again. Verified end to end against a self hosted WCF STS: all 10
System.ServiceModel.Federation federation scenario tests pass over
wstrust13 and wstrustFeb2005, Text and Mtom, with and without secure
conversation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a191b9da-fe1b-4bf7-89a2-be044b10e0ee

* Fix WS-Trust parser progress and container boundaries

Ensure unknown and empty extension elements advance their outer readers,
reset per-element AppliesTo dispatch state, and preserve request attribute
values without duplicating Context or namespace declarations.

Keep accepted empty request and response models within their own XML
boundaries so they do not inspect or consume following siblings.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a191b9da-fe1b-4bf7-89a2-be044b10e0ee

* Handle encrypted proof tokens without silent data loss

Capture and round-trip parsed XML Encryption EncryptedKey elements in
RequestedProofToken. Reject manually constructed empty EncryptedKey values
and protected entropy before mutating the XML writer instead of emitting
misleading empty wrappers.

Add regression tests for parsed encrypted-key round-tripping and atomic
unsupported-state failures.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a191b9da-fe1b-4bf7-89a2-be044b10e0ee

* Complete WS-Trust token and reference serialization paths

Share token, security-token-reference, and preserved raw XML handling across
OnBehalfOf, ProofEncryption, UseKey, and RequestedSecurityToken. Use capable
token handlers when source XML is unavailable and validate representability
before writing wrappers.

Preserve existing empty ProofEncryption skip behavior and TokenElement
precedence. Add round-trip coverage for references, SAML tokens, and raw
EndpointReference content.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a191b9da-fe1b-4bf7-89a2-be044b10e0ee

* Round-trip WS-Trust extensions with exact QName handling

Preserve response Context, custom attributes, and unknown elements. Add a
typed XML attribute collection for BinarySecret, retain empty BinarySecret
Type values with safe data, and serialize SecurityTokenReference Usage.

Recognize typed WS-* children by exact QName while skipping or capturing
wrong-namespace lookalikes, including lookalikes that precede valid
reference children.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a191b9da-fe1b-4bf7-89a2-be044b10e0ee

* Bound WS-Trust XML resources before buffering

Apply parse-scoped cumulative budgets for elements, attributes, characters,
and buffered bytes. Stream string, Base64, and attribute values through the
budget and bound every XML materialization before allocating its DOM.

Use finite dictionary-reader quotas and expose IDX15026 directly for quota
failures. Add coverage for quota boundaries across extensions, known strings,
decoded binary secrets, sibling collections, attributes, and
comment-interleaved text.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a191b9da-fe1b-4bf7-89a2-be044b10e0ee

* Complete WS-Trust parser and writer validation

Apply the shared parse budget to skipped subtrees and reference wrappers,
preflight nested request and response states before writing parent elements,
and validate EndpointReference Address by exact QName.

Add static UseKey and ProofEncryption overloads for custom token handlers,
with coverage for custom handlers, top-level writer atomicity, bounded skips,
reference child quotas, and wrong-namespace Address handling.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a191b9da-fe1b-4bf7-89a2-be044b10e0ee

* Stream bounded XML content before materialization

Replace eager subtree and DOM copying with a shared bounded streaming copier
that reads text and attribute values in chunks. Route unknown, skipped,
endpoint-reference, and token XML through the same path before constructing
an XmlDocument.

Add guard-reader, attribute-boundary, chunk-boundary, and special-node tests
for the library-owned buffering paths.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a191b9da-fe1b-4bf7-89a2-be044b10e0ee

* Add opt-in WS-Trust ActAs serialization

Add a WriteRequest overload that emits the existing ActAs property in the
WS-Trust 1.4 extension namespace when explicitly requested. Keep the
existing overload and disabled path byte-for-byte compatible.

Reuse source-preserving token, SecurityTokenReference, and custom-handler
serialization with preflight validation before writing the request root.
Add coverage for namespace, ordering, SAML 1.1 and 2.0, signatures, custom
handlers, coexistence, and atomic unsupported-state failure.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a191b9da-fe1b-4bf7-89a2-be044b10e0ee

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a191b9da-fe1b-4bf7-89a2-be044b10e0ee
Register the source and test projects in buildConfiguration.xml and WilsonUnix.sln so official Windows and Unix build, test, and packaging workflows include WS-Trust.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants