Skip to content

Security: Enforce tenant-aware issuer validation and enable audience check by default for AAD authentication#49033

Open
rujche wants to merge 27 commits intomainfrom
rujche/main/fix-issue-in-AadJwtIssuerValidator.trustedIssuerRepoValidIssuer
Open

Security: Enforce tenant-aware issuer validation and enable audience check by default for AAD authentication#49033
rujche wants to merge 27 commits intomainfrom
rujche/main/fix-issue-in-AadJwtIssuerValidator.trustedIssuerRepoValidIssuer

Conversation

@rujche
Copy link
Copy Markdown
Member

@rujche rujche commented May 4, 2026

This pull request introduces important security improvements and breaking changes to the Azure Spring Cloud AAD resource server integration. The main focus is to enforce explicit tenant restrictions and audience validation for JWT tokens, preventing cross-tenant and cross-application token misuse. These changes align the implementation with Microsoft’s security best practices and include comprehensive test coverage for the new behaviors.

Key changes include:

Breaking Security Changes

  • The AAD resource server now requires spring.cloud.azure.active-directory.profile.tenant-id to be set to a specific (non-reserved) tenant ID. Using empty, common, organizations, or consumers is now prohibited and will cause application startup to fail with an IllegalArgumentException. This enforces strict tenant isolation and prevents accidental security vulnerabilities. [1] [2]
  • The AadAuthenticationFilter now enables explicit audience (aud) validation by default. JWTs must have an audience claim that matches either the configured client ID or App ID URI, preventing tokens issued for other applications from being accepted. [1] [2] [3]

JWT Validation Improvements

  • The default JWT validator chain now enforces validation of the audience (aud), tenant ID (tid), issuer (iss), and token timestamps. The issuer validator now always requires a trusted issuer repository, and only accepts issuers from the configured tenant. [1] [2]
  • Added comprehensive documentation and comments explaining the claims validation process and the rationale for each step, in line with Microsoft’s official recommendations.

Test Enhancements

  • Updated and expanded test coverage to ensure the new tenant ID requirements and claim validations are enforced. Tests now verify that reserved tenant IDs are rejected and that valid GUIDs are accepted. [1] [2] [3] [4] [5] [6]

Minor Fixes

  • Improved error messages for invalid audience claims in UserPrincipalManager for better clarity.

Documentation

  • The changelog has been updated to clearly describe the breaking changes and their security implications.

All SDK Contribution checklist:

  • The pull request does not introduce [breaking changes]
  • CHANGELOG is updated for new features, bug fixes or other significant changes.
  • I have read the contribution guidelines.

General Guidelines and Best Practices

  • Title of the pull request is clear and informative.
  • There are a small number of commits, each of which have an informative message. This means that previously merged commits do not appear in the history of the PR. For more information on cleaning up the commits in your PR, see this page.

Testing Guidelines

  • Pull request includes test coverage for the included changes.

Copilot AI review requested due to automatic review settings May 4, 2026 04:39
@rujche rujche requested review from a team, Netyyyy, moarychan and saragluna as code owners May 4, 2026 04:39
@rujche rujche self-assigned this May 4, 2026
@rujche rujche added azure-spring All azure-spring related issues azure-spring-aad Spring active directory related issues. labels May 4, 2026
@rujche rujche moved this from Todo to In Progress in Spring Cloud Azure May 4, 2026
@rujche rujche added this to the 2026-06 milestone May 4, 2026
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

This PR tightens default AAD JWT validation behavior in spring-cloud-azure-autoconfigure by enforcing tenant-aware issuer validation for single-tenant resource servers and enabling explicit audience validation by default in AadAuthenticationFilter.

Changes:

  • Wire AadResourceServerConfiguration issuer validation to use AadTrustedIssuerRepository for single-tenant tenant IDs while preserving legacy prefix-based issuer validation for common/organizations/consumers.
  • Change AadAuthenticationFilter default constructors to enable explicit audience checking by default.
  • Add/update tests covering the new default behaviors.

Reviewed changes

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

Show a summary per file
File Description
sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/aad/filter/AadAuthenticationFilter.java Switch constructor defaults to enable explicit audience validation.
sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/aad/configuration/AadResourceServerConfiguration.java Use trusted-issuer exact matching for single-tenant issuer validation; keep multi-tenant legacy behavior.
sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aad/filter/AadAuthenticationFilterTests.java Add tests validating constructor defaults for explicit audience checking.
sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aad/configuration/AadResourceServerConfigurationTests.java Add tests validating single-tenant vs multi-tenant issuer validator wiring.
sdk/spring/CHANGELOG.md Document the hardened defaults in changelog.

Comment thread sdk/spring/CHANGELOG.md Outdated
@rujche
Copy link
Copy Markdown
Member Author

rujche commented May 4, 2026

@copilot apply changes based on the comments in this thread

…pplication, fix changelog link

Agent-Logs-Url: https://github.com/Azure/azure-sdk-for-java/sessions/ac6fd8b6-366e-4630-bcaf-fee4ad6e62c3

Co-authored-by: rujche <171773178+rujche@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI commented May 4, 2026

@copilot apply changes based on the comments in this thread

Applied all three changes from the review thread in commit 3d2b4b46:

  1. Import ordering (AadAuthenticationFilterTests.java): Moved ReflectionTestUtils import before the static imports block.
  2. Centralized isMultiTenantsApplication (AadAuthenticationProperties): Changed the method to public static so it can be shared, and updated AadResourceServerConfiguration to call AadAuthenticationProperties.isMultiTenantsApplication(tenantId) — removing the duplicate private method.
  3. CHANGELOG link (CHANGELOG.md): Fixed the label from [49032] to ([#49033](...)) to match the standard format.

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

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

@rujche
Copy link
Copy Markdown
Member Author

rujche commented May 6, 2026

Ignore the test failure about java - spring - ci (Build Test ubuntu2404_121_NotFromSource_TestsOnly), it's a know issue: #48622

Copilot finished work on behalf of rujche May 6, 2026 01:32
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

Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.

rujche and others added 2 commits May 6, 2026 18:35
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
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

Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (1)

sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aad/security/jwt/AadJwtIssuerValidatorTests.java:28

  • These tests still mock AadAuthenticationProperties and stub getProfile(), but AadJwtIssuerValidator no longer consumes AadAuthenticationProperties/profile. Consider removing the unused mock/stubbings (and the unused AadProfileProperties setup) to keep the tests focused on issuer validation via AadTrustedIssuerRepository.
    private final AadAuthenticationProperties aadAuthenticationProperties = mock(AadAuthenticationProperties.class);
    private final Jwt jwt = mock(Jwt.class);
    private final AadTrustedIssuerRepository aadTrustedIssuerRepository = new AadTrustedIssuerRepository("fake-tenant"
        + "-id");

    @Test
    void testIssuerSuccessVerify() {
        AadProfileProperties profile = new AadProfileProperties();
        profile.setTenantId("fake-tenant-id");
        when(aadAuthenticationProperties.getProfile()).thenReturn(profile);
        when(jwt.getClaim(AadJwtClaimNames.ISS)).thenReturn("https://sts.windows.net/fake-tenant-id/v2.0");

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@rujche
Copy link
Copy Markdown
Member Author

rujche commented May 6, 2026

@copilot apply changes based on the comments in this thread

Copy link
Copy Markdown
Contributor

Copilot AI commented May 6, 2026

@copilot apply changes based on the comments in this thread

Fixed in commit 72e7f88. Removed the .hasMessageContaining("security vulnerability") assertion from all 5 tenant-id rejection test methods — the production error message in validateTenantId doesn't contain that phrase, so the assertions were failing. The tests now assert only .hasMessageContaining("cannot be null, empty, or set to") which matches the actual exception message.

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

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/aad/security/jwt/AadJwtIssuerValidatorTests.java:28

  • In these tests, aadAuthenticationProperties and the profile stubbing are unused: AadJwtIssuerValidator only consults the iss claim and the provided AadTrustedIssuerRepository. Removing the unused mock/stubbing will make the tests clearer and avoid implying that tenantId from properties participates in issuer validation here.
    private final AadAuthenticationProperties aadAuthenticationProperties = mock(AadAuthenticationProperties.class);
    private final Jwt jwt = mock(Jwt.class);
    private final AadTrustedIssuerRepository aadTrustedIssuerRepository = new AadTrustedIssuerRepository("fake-tenant"
        + "-id");

    @Test
    void testIssuerSuccessVerify() {
        AadProfileProperties profile = new AadProfileProperties();
        profile.setTenantId("fake-tenant-id");
        when(aadAuthenticationProperties.getProfile()).thenReturn(profile);
        when(jwt.getClaim(AadJwtClaimNames.ISS)).thenReturn("https://sts.windows.net/fake-tenant-id/v2.0");

@rujche
Copy link
Copy Markdown
Member Author

rujche commented May 6, 2026

@copilot apply changes based on the comments in this thread

Copy link
Copy Markdown
Contributor

Copilot AI commented May 6, 2026

@copilot apply changes based on the comments in this thread

Fixed in commits ec7587c and 1174bab. The tenantId is now trimmed in createDefaultValidator before being passed to validateTenantId and used in the tid validator and AadTrustedIssuerRepository. A new test testValidateTenantIdRejectsWhitespacePaddedReservedValue was added to verify that ' common ' (with surrounding whitespace) is properly rejected after trimming.

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

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Comment on lines +68 to +72
String tenantId = aadAuthenticationProperties.getProfile().getTenantId();
if (tenantId != null) {
tenantId = tenantId.trim();
}
validateTenantId(tenantId);
@rujche
Copy link
Copy Markdown
Member Author

rujche commented May 6, 2026

@copilot apply changes based on the comments in this thread

Copy link
Copy Markdown
Contributor

Copilot AI commented May 6, 2026

@copilot apply changes based on the comments in this thread

Fixed in commit 3c3b72f. Extracted a getTrimmedTenantId() helper that is now called by both jwtDecoder() (for AadAuthorizationServerEndpoints) and createDefaultValidator() (for validators), so the normalized tenant ID is used consistently throughout.

Copilot finished work on behalf of rujche May 6, 2026 13:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

azure-spring All azure-spring related issues azure-spring-aad Spring active directory related issues.

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

3 participants