Skip to content

Fix ABBA deadlock between AzureActiveDirectory and AzureActiveDirectoryAuthority class monitors, Fixes AB#3578299#3082

Merged
mohitc1 merged 6 commits intodevfrom
mchand/cloud-discovery-deadlock-fix
Apr 16, 2026
Merged

Fix ABBA deadlock between AzureActiveDirectory and AzureActiveDirectoryAuthority class monitors, Fixes AB#3578299#3082
mohitc1 merged 6 commits intodevfrom
mchand/cloud-discovery-deadlock-fix

Conversation

@mohitc1
Copy link
Copy Markdown
Contributor

@mohitc1 mohitc1 commented Apr 15, 2026

Summary

Fixes an ABBA deadlock between AzureActiveDirectory.class and AzureActiveDirectoryAuthority.class monitors, discovered during ANR investigation on Microsoft Authenticator (Broker v16.0.0). Under high concurrency (multiple apps calling into Broker simultaneously), two threads could deadlock:

  • Path A (isKnownAuthority): sLockauthority.getAuthorityURL()AzureActiveDirectoryAuthority.classAzureActiveDirectory.class
  • Path B (ensureCloudDiscoveryForAuthority): AzureActiveDirectory.classauthority.getAuthorityURL()AzureActiveDirectoryAuthority.class

Changes

Source (3 files)

Authority.java

  • Extract authority.getAuthorityURL() outside synchronized(sLock) in isKnownAuthority()
  • Add null check for authorityUrl
  • Improve error handling in getKnownAuthorityResult(): propagate original discovery exception error code instead of replacing with UNKNOWN_AUTHORITY
  • Make KnownAuthorityResult fields final

AzureActiveDirectory.java

  • Remove synchronized from read-only ConcurrentHashMap methods: hasCloudHost, getAzureActiveDirectoryCloud, getAzureActiveDirectoryCloudFromHostName, isValidCloudHost
  • Extract authority.getAuthorityURL() outside synchronized scope in ensureCloudDiscoveryForAuthority(Authority)

AzureActiveDirectoryAuthority.java

  • Remove synchronized from private static getAzureActiveDirectoryCloud()

Tests (2 files)

AzureActiveDirectoryTest.kt — 5 concurrency regression tests:

  1. ABBA deadlock between isKnownAuthority and ensureCloudDiscovery
  2. Concurrent reads do not block (ConcurrentHashMap safety)
  3. Concurrent getAuthorityURL() calls
  4. Concurrent reader/writer scenarios
  5. High-concurrency stress test with multiple authorities

AuthorityKnownAuthorityTest.kt — expanded:

  • Sovereign cloud recognition (Bleu, Delos, GovSG)
  • Null authority / null authorityUrl handling
  • Error code propagation (IO_ERROR, MALFORMED_URL, UNKNOWN_AUTHORITY)
  • Developer-configured authority with discovery failure
  • Pre-seeded metadata fallback

Linked Work Items

AB#3578299

Mohit added 2 commits April 15, 2026 14:18
…ryAuthority

- Extract authority.getAuthorityURL() outside synchronized(sLock) in
  Authority.isKnownAuthority() to avoid lock-ordering inversion
- Extract authority.getAuthorityURL() outside synchronized scope in
  AzureActiveDirectory.ensureCloudDiscoveryForAuthority(Authority)
- Remove synchronized from read-only ConcurrentHashMap methods in
  AzureActiveDirectory (hasCloudHost, getAzureActiveDirectoryCloud,
  getAzureActiveDirectoryCloudFromHostName, isValidCloudHost)
- Remove synchronized from AzureActiveDirectoryAuthority.getAzureActiveDirectoryCloud()
- Add null check for authorityUrl in isKnownAuthority()
- Improve error handling in getKnownAuthorityResult(): propagate original
  discovery exception instead of replacing with UNKNOWN_AUTHORITY
- Make KnownAuthorityResult fields final
- Add 5 concurrency regression tests in AzureActiveDirectoryTest
- Expand AuthorityKnownAuthorityTest with sovereign cloud, error propagation,
  and mock-based getKnownAuthorityResult tests

AB#3578299
@mohitc1 mohitc1 marked this pull request as ready for review April 15, 2026 21:20
@mohitc1 mohitc1 requested review from a team as code owners April 15, 2026 21:20
Copilot AI review requested due to automatic review settings April 15, 2026 21:20
@github-actions
Copy link
Copy Markdown

❌ Invalid work item number: AB#3578299
. Work item number must be a valid integer.

Click here to learn more.

@github-actions
Copy link
Copy Markdown

✅ Work item link check complete. Description contains link AB#3578299 to an Azure Boards work item.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Fixes a lock-order inversion (ABBA deadlock) between AzureActiveDirectory and AzureActiveDirectoryAuthority by moving polymorphic getAuthorityURL() calls out of synchronized scopes and reducing unnecessary synchronization in read-only cloud map accessors, with added regression tests around concurrency and error propagation.

Changes:

  • Prevent deadlock by resolving authority.getAuthorityURL() outside locks in Authority.isKnownAuthority() and AzureActiveDirectory.ensureCloudDiscoveryForAuthority(Authority).
  • Remove synchronized from read-only methods backed by ConcurrentHashMap and adjust known-authority discovery error propagation behavior.
  • Add/expand Kotlin tests for concurrency deadlock regression and known-authority result behaviors.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
common4j/src/test/com/microsoft/identity/common/java/providers/microsoft/azureactivedirectory/AzureActiveDirectoryTest.kt Adds concurrency regression/stress tests for deadlock and concurrent read/write behavior.
common4j/src/test/com/microsoft/identity/common/java/authorities/AuthorityKnownAuthorityTest.kt Expands tests for null handling, sovereign clouds, and discovery error-code propagation.
common4j/src/main/com/microsoft/identity/common/java/providers/microsoft/azureactivedirectory/AzureActiveDirectory.java Removes synchronization from read-only cloud map API and avoids lock inversion in authority-based discovery.
common4j/src/main/com/microsoft/identity/common/java/authorities/AzureActiveDirectoryAuthority.java Removes synchronized from a static cloud lookup helper.
common4j/src/main/com/microsoft/identity/common/java/authorities/Authority.java Avoids lock inversion in isKnownAuthority, improves getKnownAuthorityResult error propagation, finalizes result fields.
changelog.txt Documents the patch-level deadlock fix.

Comment thread common4j/src/main/com/microsoft/identity/common/java/authorities/Authority.java Outdated
Comment thread common4j/src/main/com/microsoft/identity/common/java/authorities/Authority.java Outdated
@github-actions github-actions bot changed the title Fix ABBA deadlock between AzureActiveDirectory and AzureActiveDirectoryAuthority class monitors Fix ABBA deadlock between AzureActiveDirectory and AzureActiveDirectoryAuthority class monitors, Fixes AB#3578299 Apr 15, 2026
Mohit added 2 commits April 15, 2026 14:54
- Fix race in isValidCloudHost: store cloud in local variable and null-check
  before calling isValidated() to prevent NPE
- Fix comment: getAuthorityUri() -> getAuthorityURL()
- Remove brittle PR#3027 reference from comment
- Add clearKnownAuthorities() test helper to Authority and use in @after
  to prevent state leaking between tests
- Mark all concurrency test threads as daemon to prevent JVM hang on deadlock
mAudience is only set during construction/deserialization and never mutated
after. The synchronized on this instance method added lock contention with
no thread-safety benefit, and created an unnecessary instance monitor →
AzureActiveDirectory.class lock ordering.
mohitc1 pushed a commit that referenced this pull request Apr 15, 2026
…eDirectoryAuthority

Cherry-picked from mchand/cloud-discovery-deadlock-fix (PR #3082).

- Extract authority.getAuthorityURL() outside synchronized scopes in
  Authority.isKnownAuthority() and AzureActiveDirectory.ensureCloudDiscoveryForAuthority()
- Remove synchronized from read-only ConcurrentHashMap methods in AzureActiveDirectory
- Remove synchronized from AzureActiveDirectoryAuthority.getAzureActiveDirectoryCloud()
  and isSameCloudAsAuthority()
- Fix race in isValidCloudHost() (null-check before isValidated())
- Add clearKnownAuthorities() test helper
- Improve error handling in getKnownAuthorityResult()
- Add concurrency regression tests

AB#3578299
mohitc1 pushed a commit that referenced this pull request Apr 15, 2026
…eDirectoryAuthority

Cherry-picked from mchand/cloud-discovery-deadlock-fix (PR #3082).

- Extract authority.getAuthorityURL() outside synchronized scopes in
  Authority.isKnownAuthority() and AzureActiveDirectory.ensureCloudDiscoveryForAuthority()
- Remove synchronized from read-only ConcurrentHashMap methods in AzureActiveDirectory
- Remove synchronized from AzureActiveDirectoryAuthority.getAzureActiveDirectoryCloud()
  and isSameCloudAsAuthority()
- Fix race in isValidCloudHost() (null-check before isValidated())
- Add clearKnownAuthorities() test helper
- Improve error handling in getKnownAuthorityResult()
- Add concurrency regression tests

AB#3578299
mohitc1 added a commit that referenced this pull request Apr 15, 2026
…ureActiveDirectoryAuthority, Fixes AB#3578299 (#3083)

## Hotfix for release/24.1.1

Cherry-pick of PR #3082 (dev branch fix) onto \working/release/24.1.1\.

### Problem

ABBA deadlock between \AzureActiveDirectory.class\ and
\AzureActiveDirectoryAuthority.class\ monitors under high concurrency
(multiple apps calling into Broker simultaneously), causing ANR in
Microsoft Authenticator.

### Changes

- Extract \�uthority.getAuthorityURL()\ outside synchronized scopes
- Remove \synchronized\ from read-only \ConcurrentHashMap\ methods
- Remove \synchronized\ from
\AzureActiveDirectoryAuthority.getAzureActiveDirectoryCloud()\ and
\isSameCloudAsAuthority()\
- Fix race in \isValidCloudHost()\ (null-check before \isValidated()\)
- Improve error handling in \getKnownAuthorityResult()\
- Add concurrency regression tests

### Testing

All \common4j\ tests pass on this branch.


[AB#3578299](https://identitydivision.visualstudio.com/fac9d424-53d2-45c0-91b5-ef6ba7a6bf26/_workitems/edit/3578299)

Co-authored-by: Mohit <mchand@microsoft.com>
@mohitc1 mohitc1 merged commit b53d87e into dev Apr 16, 2026
27 checks passed
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