diff --git a/sdk/spring/CHANGELOG.md b/sdk/spring/CHANGELOG.md index 13874b75783e..23990163194d 100644 --- a/sdk/spring/CHANGELOG.md +++ b/sdk/spring/CHANGELOG.md @@ -15,6 +15,7 @@ This section includes changes in `spring-cloud-azure-autoconfigure` module. #### Bugs Fixed +- Fixed Service Bus JMS listener containers using `JmsPoolConnectionFactory` when both `spring.jms.servicebus.pool.enabled=true` and `spring.jms.cache.enabled=false`. The sender continues to use `JmsPoolConnectionFactory`, while listener containers now use a dedicated `ServiceBusJmsConnectionFactory`, enabling topic subscriptions on the Standard tier. ([#49308](https://github.com/Azure/azure-sdk-for-java/issues/49308)) - Fixed the AAD authentication filter (`AadAuthenticationFilter` and `AadAppRoleStatelessAuthenticationFilter`) not validating the `tid` (tenant ID) claim in JWT tokens against the configured tenant, allowing tokens from other tenants to be accepted. The JWT token validator now validates that the token's `tid` claim matches the configured tenant ID, preventing cross-tenant authentication bypass. This hardening is only enforced when a specific tenant ID is configured. ([#49631](https://github.com/Azure/azure-sdk-for-java/pull/49631)) - Fixed the AAD and B2C OpenID Connect login (`oauth2Login`) ID token decoders not validating the `iss` (issuer) and `aud` (audience) claims. `AadOidcIdTokenDecoderFactory` and `AadB2cOidcIdTokenDecoderFactory` now validate the standard OIDC ID token claims (audience, expiry, issued-at and subject) and the issuer. For single tenant applications the issuer must belong to the configured tenant, and for multi-tenant applications (the `common`, `organizations` or `consumers` endpoints) the issuer must be a trusted Microsoft identity platform issuer consistent with the token's own `tid` claim. This prevents users from unauthorized tenants from signing in to multi-tenant applications that rely on the issuer/tenant claim for tenant restriction ([#49423](https://github.com/Azure/azure-sdk-for-java/pull/49423)). - Fixed the missing bean name in `@ConditionalOnMissingBean` for `LettuceClientConfigurationBuilderCustomizer` ([#49290](https://github.com/Azure/azure-sdk-for-java/issues/49290)). diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsContainerConfiguration.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsContainerConfiguration.java index abfb825aed06..25d7789a76e3 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsContainerConfiguration.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsContainerConfiguration.java @@ -52,7 +52,7 @@ class ServiceBusJmsContainerConfiguration implements DisposableBean { * not setfalseServiceBusJmsConnectionFactory * truenot setJmsPoolConnectionFactory * truetrueCachingConnectionFactory - * truefalseJmsPoolConnectionFactory + * truefalseServiceBusJmsConnectionFactory * falsenot setServiceBusJmsConnectionFactory * falsetrueCachingConnectionFactory * falsefalseServiceBusJmsConnectionFactory @@ -62,7 +62,7 @@ class ServiceBusJmsContainerConfiguration implements DisposableBean { // pool: not set {SERVICE_BUS, CACHE, SERVICE_BUS}, // cache: not set, true, false // pool: true - {POOL, CACHE, POOL}, // cache: not set, true, false + {POOL, CACHE, SERVICE_BUS}, // cache: not set, true, false // pool: false {SERVICE_BUS, CACHE, SERVICE_BUS} // cache: not set, true, false }; diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsAutoConfigurationTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsAutoConfigurationTests.java index 77f3d3940f84..34508978be38 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsAutoConfigurationTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/jms/ServiceBusJmsAutoConfigurationTests.java @@ -526,6 +526,39 @@ void listenerContainerUsesPoolConnectionFactoryWhenExplicitlyEnabled(String pric }); } + @ParameterizedTest + @ValueSource(strings = {"standard", "premium"}) + void listenerContainerUsesDedicatedServiceBusConnectionFactoryWhenPoolEnabledAndCacheDisabled(String pricingTier) { + this.contextRunner + .withPropertyValues( + "spring.jms.servicebus.pricing-tier=" + pricingTier, + "spring.jms.servicebus.connection-string=" + CONNECTION_STRING, + "spring.jms.servicebus.pool.enabled=true", + "spring.jms.cache.enabled=false" + ) + .run(context -> { + JmsPoolConnectionFactory senderBean = context.getBean(JmsPoolConnectionFactory.class); + Object pooledTarget = senderBean.getConnectionFactory(); + DefaultJmsListenerContainerFactory queueFactory = context.getBean( + "jmsListenerContainerFactory", DefaultJmsListenerContainerFactory.class); + DefaultJmsListenerContainerFactory topicFactory = context.getBean( + "topicJmsListenerContainerFactory", DefaultJmsListenerContainerFactory.class); + + DefaultMessageListenerContainer queueContainer = + queueFactory.createListenerContainer(mock(JmsListenerEndpoint.class)); + DefaultMessageListenerContainer topicContainer = + topicFactory.createListenerContainer(mock(JmsListenerEndpoint.class)); + + assertThat(queueContainer.getConnectionFactory()) + .isInstanceOf(ServiceBusJmsConnectionFactory.class) + .isNotSameAs(pooledTarget); + assertThat(topicContainer.getConnectionFactory()) + .isInstanceOf(ServiceBusJmsConnectionFactory.class) + .isNotSameAs(pooledTarget) + .isSameAs(queueContainer.getConnectionFactory()); + }); + } + @ParameterizedTest @ValueSource(strings = {"standard", "premium"}) void listenerContainerUsesDedicatedServiceBusConnectionFactoryWhenPoolDisabled(String pricingTier) {