Skip to content

Add unit tests with HTTP mocking for vanilla dSTS + fix Authority par…#3805

Merged
XiaoxinMS2 merged 7 commits into
masterfrom
zhanli1/dsts-unit-tests-with-http-mocking
May 21, 2026
Merged

Add unit tests with HTTP mocking for vanilla dSTS + fix Authority par…#3805
XiaoxinMS2 merged 7 commits into
masterfrom
zhanli1/dsts-unit-tests-with-http-mocking

Conversation

@XiaoxinMS2

@XiaoxinMS2 XiaoxinMS2 commented May 5, 2026

Copy link
Copy Markdown
Contributor

…sing

Adds 6 HTTP-mocked unit tests for the vanilla dSTS (Dedicated Security Token Service) token-acquisition path in Microsoft.Identity.Web, and fixes MergedOptions.ParseAuthorityIfNecessary so that the natural / documented dSTS configuration form works end-to-end:

options.Authority = "https://{host}/dstsv2/{tenantGuid}";

Without the fix, the AAD-style parser took the literal "dstsv2" as the tenant and dropped the actual tenant GUID, producing an authority MSAL rejected with "The DSTS authority URI should have at least 2 segments...".

Tests cover: token endpoint URI; client_credentials grant body; second-call cache hit; OAuth2 error -> MsalServiceException mapping; SendX5C=true includes x5c JWT header; SendX5C=false omits it. All tests use the existing MockHttpClientFactory infrastructure (no real network / Key Vault / cert) and run in any CI environment.

No public API changes.

Add unit tests with HTTP mocking for vanilla dSTS scenarios + fix Authority-only configuration

  • You've read the Contributor Guide and Code of Conduct.
  • You've included unit or integration tests for your change, where applicable.
  • You've included inline docs for your change, where applicable.
  • There's an open issue for the PR that you are making. If you'd like to propose a new feature or change, please open an issue to discuss the change or find an existing issue.

Summary of the changes (Less than 80 chars)

Description

Adds 6 HTTP-mocked unit tests covering the vanilla dSTS (Dedicated Security Token Service) token-acquisition path in Microsoft.Identity.Web, and fixes a parser bug in MergedOptions.ParseAuthorityIfNecessary that prevented the natural / documented dSTS configuration form (options.Authority = "https://{host}/dstsv2/{tenantGuid}") from working.

Both changes ship together because the new tests use the natural configuration form, which is the form the parser fix unblocks.

Vanilla dSTS support in Id.Web previously had zero unit-test coverage — the only assertion lived in integration tests that required a real dSTS deployment + Key Vault certificate, so they couldn't run in CI. Anyone refactoring MergedOptions / TokenAcquirerFactory could silently break dSTS token acquisition without any signal.

Fixes #{bug number} (in this specific format)

@XiaoxinMS2 XiaoxinMS2 requested a review from a team as a code owner May 5, 2026 14:57
Adds 7 HTTP-mocked unit tests for the vanilla dSTS (Dedicated Security Token Service) token-acquisition path in Microsoft.Identity.Web.

Per PR review feedback, dSTS users MUST configure 'Instance' (e.g. "https://{host}/dstsv2") and 'TenantId' separately. The single-string 'Authority' option is reserved for vanilla OIDC / CIAM scenarios and routes through MSAL.WithOidcAuthority(), which is incompatible with dSTS; configuring a dSTS-style URL there now throws an InvalidOperationException with a clear, actionable error message instead of letting MSAL surface its opaque "DSTS authority URI should have at least 2 segments..." error later.

Tests cover (canonical Instance + TenantId shape):

  1. Token endpoint URI lock (POST to https://{host}/dstsv2/{tenant}/oauth2/v2.0/token)

  2. Client_credentials grant body (grant_type, scope, client_id, client_secret)

  3. Second-call cache hit (only one mock handler registered)

  4. OAuth2 token-endpoint error -> MsalServiceException mapping

  5. SendX5C=true -> client_assertion JWT header includes x5c

  6. SendX5C=false -> x5c omitted

Plus 1 negative test:

  7. Configuring dSTS URL via 'Authority' option -> InvalidOperationException with clear guidance to use Instance + TenantId

All tests use the existing MockHttpClientFactory infrastructure (no real network / Key Vault / cert) and run in any CI environment.

Implementation change in MergedOptions.ParseAuthorityIfNecessary: detects dSTS-shaped Authority (path segment "dstsv2") and throws an InvalidOperationException with a message that points users to the canonical Instance+TenantId shape. No public API changes.
@XiaoxinMS2 XiaoxinMS2 force-pushed the zhanli1/dsts-unit-tests-with-http-mocking branch from eedbd53 to c625531 Compare May 5, 2026 21:54
Comment thread src/Microsoft.Identity.Web.TokenAcquisition/MergedOptions.cs Outdated

Copilot AI commented May 21, 2026

Copy link
Copy Markdown
Contributor

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • login.microsoftonline.com
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/microsoft-identity-web/microsoft-identity-web/tests/Microsoft.Identity.Web.Test/bin/Release/net8.0/Microsoft.Identity.Web.Test.runtimeconfig.json --depsfile /home/REDACTED/work/microsoft-identity-web/microsoft-identity-web/tests/Microsoft.Identity.Web.Test/bin/Release/net8.0/Microsoft.Identity.Web.Test.deps.json /home/REDACTED/work/microsoft-identity-web/microsoft-identity-web/tests/Microsoft.Identity.Web.Test/bin/Release/net8.0/testhost.dll --port 40265 --endpoint 127.0.0.1:040265 --role client --parentprocessid 5124 --telemetryoptedin false (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

@XiaoxinMS2

XiaoxinMS2 commented May 21, 2026

Copy link
Copy Markdown
Contributor Author

@microsoft-github-policy-service agree company="Microsoft"

gunndabad added a commit to DFE-Digital/teaching-record-system that referenced this pull request Jun 1, 2026
….0 (#3431)

Updated
[Microsoft.Identity.Web.GraphServiceClientBeta](https://github.com/AzureAD/microsoft-identity-web)
from 4.9.0 to 4.10.0.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.Identity.Web.GraphServiceClientBeta's
releases](https://github.com/AzureAD/microsoft-identity-web/releases)._

## 4.10.0

### New features
- Add `WithExtraBodyParameters` fluent API for attaching extra body
parameters to token acquisition requests. See
[#​3819](AzureAD/microsoft-identity-web#3819).
- Add `IConfidentialClientApplicationProvider` extensibility interface
and `CachePartitionKey` support for silent token acquisition. See
[#​3822](AzureAD/microsoft-identity-web#3822).

### Bug fixes
- Redirect URI sanitization in authorization scenarios; centralize
redirect URI validation in a shared helper. See
[#​3825](AzureAD/microsoft-identity-web#3825).
- Reject dSTS-shaped `Authority` values with a clearer exception,
steering users to use `Instance` + `TenantId` instead. See
[#​3805](AzureAD/microsoft-identity-web#3805).
- Improve regex handling and adding length/timeout safeguards for
SameSite User Agent. See
[#​3811](AzureAD/microsoft-identity-web#3811).

### Behavior changes
- **B2C OpenID Connect event handler: LRU cache for issuer address.**
Issuer address lookups in the B2C OIDC event handler are now cached with
an LRU cache, improving performance for repeated lookups. See
[#​3821](AzureAD/microsoft-identity-web#3821).

### Dependencies updates
- Update MSAL.NET to 4.84.1. See
[#​3822](AzureAD/microsoft-identity-web#3822).
- Pin `Microsoft.Kiota.Abstractions` to 1.22.0 for GraphServiceClient.
See
[#​3817](AzureAD/microsoft-identity-web#3817).
- Bump `uuid` and `@​azure/msal-node` in SidecarAdapter TypeScript test
app. See
[#​3826](AzureAD/microsoft-identity-web#3826).
- Bump `qs` in SidecarAdapter TypeScript test app. See
[#​3829](AzureAD/microsoft-identity-web#3829).

Commits viewable in [compare
view](AzureAD/microsoft-identity-web@4.9.0...4.10.0).
</details>

[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=Microsoft.Identity.Web.GraphServiceClientBeta&package-manager=nuget&previous-version=4.9.0&new-version=4.10.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: James Gunn <james@gunn.io>
gunndabad added a commit to DFE-Digital/teaching-record-system that referenced this pull request Jun 4, 2026
Updated
[Microsoft.Identity.Web](https://github.com/AzureAD/microsoft-identity-web)
from 4.7.0 to 4.10.0.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.Identity.Web's
releases](https://github.com/AzureAD/microsoft-identity-web/releases)._

## 4.10.0

### New features
- Add `WithExtraBodyParameters` fluent API for attaching extra body
parameters to token acquisition requests. See
[#​3819](AzureAD/microsoft-identity-web#3819).
- Add `IConfidentialClientApplicationProvider` extensibility interface
and `CachePartitionKey` support for silent token acquisition. See
[#​3822](AzureAD/microsoft-identity-web#3822).

### Bug fixes
- Redirect URI sanitization in authorization scenarios; centralize
redirect URI validation in a shared helper. See
[#​3825](AzureAD/microsoft-identity-web#3825).
- Reject dSTS-shaped `Authority` values with a clearer exception,
steering users to use `Instance` + `TenantId` instead. See
[#​3805](AzureAD/microsoft-identity-web#3805).
- Improve regex handling and adding length/timeout safeguards for
SameSite User Agent. See
[#​3811](AzureAD/microsoft-identity-web#3811).

### Behavior changes
- **B2C OpenID Connect event handler: LRU cache for issuer address.**
Issuer address lookups in the B2C OIDC event handler are now cached with
an LRU cache, improving performance for repeated lookups. See
[#​3821](AzureAD/microsoft-identity-web#3821).

### Dependencies updates
- Update MSAL.NET to 4.84.1. See
[#​3822](AzureAD/microsoft-identity-web#3822).
- Pin `Microsoft.Kiota.Abstractions` to 1.22.0 for GraphServiceClient.
See
[#​3817](AzureAD/microsoft-identity-web#3817).
- Bump `uuid` and `@​azure/msal-node` in SidecarAdapter TypeScript test
app. See
[#​3826](AzureAD/microsoft-identity-web#3826).
- Bump `qs` in SidecarAdapter TypeScript test app. See
[#​3829](AzureAD/microsoft-identity-web#3829).

## 4.9.0

### New features
- **Sidecar: per-route override gating.** New `Sidecar:AllowOverrides`
configuration section provides explicit, per-route control over whether
`optionsOverride.*` query-string parameters are honored. Authenticated
routes default to allowing overrides (preserving existing behavior);
unauthenticated routes default to rejecting them.
`optionsOverride.BaseUrl` is unconditionally rejected on all routes as a
hardening measure. See
[#​3794](AzureAD/microsoft-identity-web#3794).

### Bug fixes
- Fix `AccountController.Challenge` redirect URI validation to reject
percent-encoded protocol-relative bypasses (`%2F%2F`, `%5C%2F`, etc.)
that could be decoded by misconfigured reverse proxies. See
[#​3792](AzureAD/microsoft-identity-web#3792).

### Behavior changes
- **DownstreamApi: reserved header filtering.** Headers supplied via
`DownstreamApiOptions.ExtraHeaderParameters` whose names match reserved
HTTP headers (`Authorization`, `Host`, `Content-Length`,
`Proxy-Authorization`, `Sec-*`, `Proxy-*`, etc.) or duplicate a header
the library already set are now silently skipped. A warning-level log
entry (`ReservedHeaderIgnored` / `DuplicateHeaderIgnored`) is emitted so
operators can spot misconfigurations. No exception is thrown. See
[#​3793](AzureAD/microsoft-identity-web#3793).

### Dependencies updates
- **Update Azure.Identity 1.11.4 → 1.17.2 and establish
Microsoft.Extensions.\* 8.0.x minimum on older TFMs.** Azure.Identity
1.17.2 (sovereign-cloud fixes) pulls in Azure.Core 1.50.0, which
introduces a transitive dependency on
`Microsoft.Extensions.DependencyInjection.Abstractions` 8.0.2 on
non-framework-coupled TFMs (net462, net472, netstandard2.0). This caused
a `CS0433` type collision with the previously-pinned
`Microsoft.Extensions.DependencyInjection` 2.1.0. Rather than patch
individual packages, the entire `Microsoft.Extensions.*` stack on these
older TFMs has been bumped to 8.0.x, closing several 5-year version gaps
and aligning with the net8.0 baseline. **If your application targets
net462, net472, or netstandard2.0**, your resolved
`Microsoft.Extensions.*` versions will increase (e.g., `Extensions.Http`
3.1.3 → 8.0.0, `Extensions.DependencyInjection` 2.1.0 → 8.0.0,
`Extensions.Caching.Memory` 2.1.0/6.0.2 → 8.0.1). Applications already
targeting net8.0+ are unaffected. See
[#​3787](AzureAD/microsoft-identity-web#3787).
- Bump `System.Text.Json` 8.0.5 → 8.0.6 (CVE-2024-43485). See
[#​3787](AzureAD/microsoft-identity-web#3787).
- Bump `Microsoft.AspNetCore.DataProtection` to 10.0.7 for CVE fix on
net10.0. See
[#​3796](AzureAD/microsoft-identity-web#3796).
- Bump `OpenTelemetry.Exporter.OpenTelemetryProtocol` 1.14.0 → 1.15.3.
See
[#​3788](AzureAD/microsoft-identity-web#3788).

**Full Changelog**:
AzureAD/microsoft-identity-web@4.8.0...4.9.0

## 4.8.0

## What's Changed
* Bump flatted from 3.3.3 to 3.4.2 in
/tests/DevApps/SidecarAdapter/typescript by @​dependabot[bot] in
AzureAD/microsoft-identity-web#3753
* Update changelog.md for ID.Web 4.6.0 by @​bgavrilMS in
AzureAD/microsoft-identity-web#3756
* Add token binding to MicrosoftIdentityMessageHandler by @​cpp11nullptr
in AzureAD/microsoft-identity-web#3743
* Bump picomatch in /tests/DevApps/SidecarAdapter/typescript by
@​dependabot[bot] in
AzureAD/microsoft-identity-web#3759
* Documentation: Clarify managed identity credential types for
containerized vs. VM/App Service deployments by @​Copilot in
AzureAD/microsoft-identity-web#3585
* Bump path-to-regexp from 8.3.0 to 8.4.0 in
/tests/DevApps/SidecarAdapter/typescript by @​dependabot[bot] in
AzureAD/microsoft-identity-web#3762
* Upgrade Microsoft Application Insights packages by @​RojaEnnam in
AzureAD/microsoft-identity-web#3763
* Use Abstractions 12 by @​pmaytak in
AzureAD/microsoft-identity-web#3761
* Post-4.7.0 by @​pmaytak in
AzureAD/microsoft-identity-web#3768
* Fix Comp Gov DOTNET-Security-10.0 by @​reginayap8 in
AzureAD/microsoft-identity-web#3769
* Upgrade CodeQL to V4: Fix 10 CodeQL Analysis Warnings and Errors by
@​reginayap8 in
AzureAD/microsoft-identity-web#3770
* fix warnings by @​gladjohn in
AzureAD/microsoft-identity-web#3771
* adding examples for using postgres as a distributed cache by
@​JaredMSFT in
AzureAD/microsoft-identity-web#3766
* Suppress AOT configuration-binding SYSLIB warnings in AotCompatibility
test app by @​Copilot in
AzureAD/microsoft-identity-web#3774
* Bump vite from 7.1.11 to 7.3.2 in
/tests/DevApps/SidecarAdapter/typescript by @​dependabot[bot] in
AzureAD/microsoft-identity-web#3772
* Skip legacy B2C local-account Todo UI test in WebAppUiTests by
@​Copilot in AzureAD/microsoft-identity-web#3778
* Fix initialization of ConfidentialClientApplicationOptions in
MergedOptions by @​cpp11nullptr in
AzureAD/microsoft-identity-web#3760
* Bump net8/net9/net10 runtime package baselines to patched crypto
servicing versions by @​Copilot in
AzureAD/microsoft-identity-web#3779
* Fix flaky certificate test failures on CI by @​gladjohn in
AzureAD/microsoft-identity-web#3780
* MTLS Without Tokens Support by @​tlupes in
AzureAD/microsoft-identity-web#3747
* Fix CredentialsProvider DI lifetime mismatch causing startup crash in
Development by @​Avery-Dunn in
AzureAD/microsoft-identity-web#3783
* Remove unused DataProtection configuration from Sidecar by @​Copilot
in AzureAD/microsoft-identity-web#3776

## New Contributors
* @​RojaEnnam made their first contribution in
AzureAD/microsoft-identity-web#3763
* @​reginayap8 made their first contribution in
AzureAD/microsoft-identity-web#3769
* @​JaredMSFT made their first contribution in
AzureAD/microsoft-identity-web#3766

**Full Changelog**:
AzureAD/microsoft-identity-web@4.6.0...4.8.0

Commits viewable in [compare
view](AzureAD/microsoft-identity-web@4.7.0...4.10.0).
</details>

[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=Microsoft.Identity.Web&package-manager=nuget&previous-version=4.7.0&new-version=4.10.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: James Gunn <james@gunn.io>
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.

4 participants