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 set | false | ServiceBusJmsConnectionFactory |
* | true | not set | JmsPoolConnectionFactory |
* | true | true | CachingConnectionFactory |
- * | true | false | JmsPoolConnectionFactory |
+ * | true | false | ServiceBusJmsConnectionFactory |
* | false | not set | ServiceBusJmsConnectionFactory |
* | false | true | CachingConnectionFactory |
* | false | false | ServiceBusJmsConnectionFactory |
@@ -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) {