Skip to content

Commit 2279742

Browse files
author
Moary Chen
authored
Fix the resource group of spring cloud usage cannot be created automatically issue (Azure#22039)
1 parent 0b14153 commit 2279742

File tree

28 files changed

+424
-395
lines changed

28 files changed

+424
-395
lines changed

sdk/spring/azure-spring-boot-samples/azure-spring-cloud-sample-eventhubs-binder/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ spring:
204204

205205
1. Verify in your app’s logs that a similar message was posted:
206206

207-
New message received: 'hello'
207+
New message received: 'hello', partition key: 2002572479, sequence number: 4, offset: 768, enqueued time: 2021-06-03T01:47:36.859Z
208208
Message 'hello' successfully checkpointed
209209

210210
1. Delete the resources on [Azure Portal][azure-portal] to avoid unexpected charges.

sdk/spring/azure-spring-boot-samples/azure-spring-cloud-sample-eventhubs-kafka/README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,16 @@ Running this sample will be charged by Azure. You can check the usage and bill a
7474

7575
1. Delete the resources on [Azure Portal][azure-portal] to avoid unexpected charges.
7676

77+
## Troubleshooting
7778

79+
- Meet with `Creating topics with default partitions/replication factor are only supported in CreateTopicRequest version 4+` error.
80+
81+
```text
82+
o.s.c.s.b.k.p.KafkaTopicProvisioner : Failed to create topics
83+
org.apache.kafka.common.errors.UnsupportedVersionException: Creating topics with default partitions/replication factor are only supported in CreateTopicRequest version 4+. The following topics need values for partitions and replicas
84+
```
7885

79-
## Troubleshooting
86+
When this error is found, add this configuration item `spring.cloud.stream.kafka.binder.replicationFactor`, with the value set to at least 1. For more information, see [Spring Cloud Stream Kafka Binder Reference Guide](https://docs.spring.io/spring-cloud-stream-binder-kafka/docs/current/reference/html/spring-cloud-stream-binder-kafka.html).
8087

8188
## Next steps
8289

sdk/spring/azure-spring-boot-samples/azure-spring-cloud-sample-servicebus-queue-binder/src/main/java/com/azure/spring/sample/servicebus/queue/binder/ServiceBusQueueBinderApplication.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ public static void main(String[] args) {
2828
public Consumer<Message<String>> consume() {
2929
return message -> {
3030
Checkpointer checkpointer = (Checkpointer) message.getHeaders().get(CHECKPOINTER);
31-
LOGGER.info("New message received: '{}'", message);
31+
LOGGER.info("New message received: '{}'", message.getPayload());
3232
checkpointer.success().handle((r, ex) -> {
3333
if (ex == null) {
34-
LOGGER.info("Message '{}' successfully checkpointed", message);
34+
LOGGER.info("Message '{}' successfully checkpointed", message.getPayload());
3535
}
3636
return null;
3737
});

sdk/spring/azure-spring-boot-samples/azure-spring-cloud-sample-servicebus-topic-binder/src/main/java/com/azure/spring/sample/servicebus/topic/binder/ServiceBusTopicBinderApplication.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ public static void main(String[] args) {
3131
public Consumer<Message<String>> consume() {
3232
return message -> {
3333
Checkpointer checkpointer = (Checkpointer) message.getHeaders().get(CHECKPOINTER);
34-
LOGGER.info("New message received: '{}'", message);
34+
LOGGER.info("New message received: '{}'", message.getPayload());
3535
checkpointer.success().handle((r, ex) -> {
3636
if (ex == null) {
37-
LOGGER.info("Message '{}' successfully checkpointed", message);
37+
LOGGER.info("Message '{}' successfully checkpointed", message.getPayload());
3838
}
3939
return null;
4040
});

sdk/spring/azure-spring-boot/src/main/java/com/azure/spring/aad/webapp/AADHandleConditionalAccessFilter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
6868
*/
6969
private Map<String, String> parseAuthParameters(String wwwAuthenticateHeader) {
7070
return Stream.of(wwwAuthenticateHeader)
71-
.filter(header -> !StringUtils.isEmpty(header))
71+
.filter(header -> StringUtils.hasText(header))
7272
.filter(header -> header.startsWith(Constants.BEARER_PREFIX))
7373
.map(str -> str.substring(Constants.BEARER_PREFIX.length() + 1, str.length() - 1))
7474
.map(str -> str.split(", "))

sdk/spring/azure-spring-boot/src/main/java/com/azure/spring/keyvault/KeyVaultEnvironmentPostProcessorHelper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ public TokenCredential getCredentials(String normalizedName) {
149149
// Use certificate to authenticate
150150
// Password can be empty
151151
if (clientId != null && tenantId != null && certificatePath != null) {
152-
if (StringUtils.isEmpty(certificatePassword)) {
152+
if (!StringUtils.hasText(certificatePassword)) {
153153
return new ClientCertificateCredentialBuilder()
154154
.tenantId(tenantId)
155155
.clientId(clientId)

sdk/spring/azure-spring-boot/src/test/java/com/azure/spring/aad/webapp/AADAccessTokenGroupRolesExtractionTest.java

Lines changed: 42 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
import com.azure.spring.autoconfigure.aad.AADAuthenticationProperties;
66
import org.junit.jupiter.api.AfterAll;
7-
import org.junit.jupiter.api.AfterEach;
87
import org.junit.jupiter.api.BeforeAll;
98
import org.junit.jupiter.api.Test;
109
import org.junit.jupiter.api.TestInstance;
@@ -14,7 +13,6 @@
1413
import org.springframework.security.oauth2.core.OAuth2AccessToken;
1514

1615
import java.util.ArrayList;
17-
import java.util.Collections;
1816
import java.util.HashSet;
1917
import java.util.List;
2018
import java.util.Set;
@@ -28,13 +26,11 @@ public class AADAccessTokenGroupRolesExtractionTest {
2826
private static final String GROUP_ID_1 = "d07c0bd6-4aab-45ac-b87c-23e8d00194ab";
2927
private static final String GROUP_ID_2 = "6eddcc22-a24a-4459-b036-b9d9fc0f0bc7";
3028

31-
private final AADAuthenticationProperties properties = new AADAuthenticationProperties();
32-
private final AADAuthenticationProperties.UserGroupProperties userGroup =
33-
new AADAuthenticationProperties.UserGroupProperties();
3429
private AutoCloseable autoCloseable;
3530

3631
@Mock
3732
private OAuth2AccessToken accessToken;
33+
3834
@Mock
3935
private GraphClient graphClient;
4036

@@ -50,31 +46,34 @@ public void setup() {
5046
groupIdsFromGraph.add(GROUP_ID_2);
5147
groupInformationFromGraph.setGroupsIds(groupIdsFromGraph);
5248
groupInformationFromGraph.setGroupsNames(groupNamesFromGraph);
53-
properties.setUserGroup(userGroup);
54-
properties.setGraphMembershipUri("https://graph.microsoft.com/v1.0/me/memberOf");
5549
Mockito.lenient().when(accessToken.getTokenValue())
5650
.thenReturn("fake-access-token");
5751
Mockito.lenient().when(graphClient.getGroupInformation(accessToken.getTokenValue()))
5852
.thenReturn(groupInformationFromGraph);
5953
}
6054

61-
@AfterEach
62-
public void reset() {
63-
userGroup.setAllowedGroupNames(Collections.emptyList());
64-
userGroup.setAllowedGroupIds(Collections.emptySet());
65-
userGroup.setEnableFullList(false);
66-
}
67-
6855
@AfterAll
6956
public void close() throws Exception {
7057
this.autoCloseable.close();
7158
}
7259

60+
private AADAuthenticationProperties getProperties() {
61+
AADAuthenticationProperties properties = new AADAuthenticationProperties();
62+
AADAuthenticationProperties.UserGroupProperties userGroup =
63+
new AADAuthenticationProperties.UserGroupProperties();
64+
properties.setUserGroup(userGroup);
65+
properties.setGraphMembershipUri("https://graph.microsoft.com/v1.0/me/memberOf");
66+
return properties;
67+
}
68+
7369
@Test
7470
public void testAllowedGroupsNames() {
7571
List<String> allowedGroupNames = new ArrayList<>();
7672
allowedGroupNames.add("group1");
77-
userGroup.setAllowedGroupNames(allowedGroupNames);
73+
74+
AADAuthenticationProperties properties = getProperties();
75+
properties.getUserGroup().setAllowedGroupNames(allowedGroupNames);
76+
7877
AADOAuth2UserService userService = new AADOAuth2UserService(properties, graphClient);
7978
Set<String> groupRoles = userService.extractGroupRolesFromAccessToken(accessToken);
8079
assertThat(groupRoles).hasSize(1);
@@ -86,7 +85,10 @@ public void testAllowedGroupsNames() {
8685
public void testAllowedGroupsIds() {
8786
Set<String> allowedGroupIds = new HashSet<>();
8887
allowedGroupIds.add(GROUP_ID_1);
89-
userGroup.setAllowedGroupIds(allowedGroupIds);
88+
89+
AADAuthenticationProperties properties = getProperties();
90+
properties.getUserGroup().setAllowedGroupIds(allowedGroupIds);
91+
9092
AADOAuth2UserService userService = new AADOAuth2UserService(properties, graphClient);
9193
Set<String> groupRoles = userService.extractGroupRolesFromAccessToken(accessToken);
9294
assertThat(groupRoles).hasSize(1);
@@ -100,8 +102,12 @@ public void testAllowedGroupsNamesAndAllowedGroupsIds() {
100102
allowedGroupIds.add(GROUP_ID_1);
101103
List<String> allowedGroupNames = new ArrayList<>();
102104
allowedGroupNames.add("group1");
103-
userGroup.setAllowedGroupIds(allowedGroupIds);
104-
userGroup.setAllowedGroupNames(allowedGroupNames);
105+
106+
107+
AADAuthenticationProperties properties = getProperties();
108+
properties.getUserGroup().setAllowedGroupIds(allowedGroupIds);
109+
properties.getUserGroup().setAllowedGroupNames(allowedGroupNames);
110+
105111
AADOAuth2UserService userService = new AADOAuth2UserService(properties, graphClient);
106112
Set<String> groupRoles = userService.extractGroupRolesFromAccessToken(accessToken);
107113
assertThat(groupRoles).hasSize(2);
@@ -117,9 +123,12 @@ public void testWithEnableFullList() {
117123
allowedGroupIds.add(GROUP_ID_1);
118124
List<String> allowedGroupNames = new ArrayList<>();
119125
allowedGroupNames.add("group1");
120-
userGroup.setAllowedGroupIds(allowedGroupIds);
121-
userGroup.setAllowedGroupNames(allowedGroupNames);
122-
userGroup.setEnableFullList(true);
126+
127+
AADAuthenticationProperties properties = getProperties();
128+
properties.getUserGroup().setAllowedGroupIds(allowedGroupIds);
129+
properties.getUserGroup().setAllowedGroupNames(allowedGroupNames);
130+
properties.getUserGroup().setEnableFullList(true);
131+
123132
AADOAuth2UserService userService = new AADOAuth2UserService(properties, graphClient);
124133
Set<String> groupRoles = userService.extractGroupRolesFromAccessToken(accessToken);
125134
assertThat(groupRoles).hasSize(3);
@@ -134,9 +143,12 @@ public void testWithoutEnableFullList() {
134143
Set<String> allowedGroupIds = new HashSet<>();
135144
allowedGroupIds.add(GROUP_ID_1);
136145
allowedGroupNames.add("group1");
137-
userGroup.setEnableFullList(false);
138-
userGroup.setAllowedGroupIds(allowedGroupIds);
139-
userGroup.setAllowedGroupNames(allowedGroupNames);
146+
147+
AADAuthenticationProperties properties = getProperties();
148+
properties.getUserGroup().setEnableFullList(false);
149+
properties.getUserGroup().setAllowedGroupIds(allowedGroupIds);
150+
properties.getUserGroup().setAllowedGroupNames(allowedGroupNames);
151+
140152
AADOAuth2UserService userService = new AADOAuth2UserService(properties, graphClient);
141153
Set<String> groupRoles = userService.extractGroupRolesFromAccessToken(accessToken);
142154
assertThat(groupRoles).hasSize(2);
@@ -152,9 +164,12 @@ public void testAllowedGroupIdsAllWithoutEnableFullList() {
152164
allowedGroupIds.add("all");
153165
List<String> allowedGroupNames = new ArrayList<>();
154166
allowedGroupNames.add("group1");
155-
userGroup.setAllowedGroupIds(allowedGroupIds);
156-
userGroup.setAllowedGroupNames(allowedGroupNames);
157-
userGroup.setEnableFullList(false);
167+
168+
AADAuthenticationProperties properties = getProperties();
169+
properties.getUserGroup().setAllowedGroupIds(allowedGroupIds);
170+
properties.getUserGroup().setAllowedGroupNames(allowedGroupNames);
171+
properties.getUserGroup().setEnableFullList(false);
172+
158173
AADOAuth2UserService userService = new AADOAuth2UserService(properties, graphClient);
159174
Set<String> groupRoles = userService.extractGroupRolesFromAccessToken(accessToken);
160175
assertThat(groupRoles).hasSize(3);

sdk/spring/azure-spring-boot/src/test/java/com/azure/spring/aad/webapp/AADIdTokenRolesExtractionTest.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,30 +18,34 @@
1818

1919
public class AADIdTokenRolesExtractionTest {
2020

21-
private OidcIdToken idToken = mock(OidcIdToken.class);
22-
private AADAuthenticationProperties properties = mock(AADAuthenticationProperties.class);
23-
private AADOAuth2UserService userService = new AADOAuth2UserService(properties);
21+
private AADOAuth2UserService getUserService() {
22+
AADAuthenticationProperties properties = mock(AADAuthenticationProperties.class);
23+
return new AADOAuth2UserService(properties);
24+
}
2425

2526
@Test
2627
public void testNoRolesClaim() {
28+
OidcIdToken idToken = mock(OidcIdToken.class);
2729
when(idToken.getClaim(ROLES)).thenReturn(null);
28-
Set<String> authorityStrings = userService.extractRolesFromIdToken(idToken);
30+
Set<String> authorityStrings = getUserService().extractRolesFromIdToken(idToken);
2931
assertThat(authorityStrings).hasSize(0);
3032
}
3133

3234
@Test
3335
public void testRolesClaimAsList() {
36+
OidcIdToken idToken = mock(OidcIdToken.class);
3437
JSONArray rolesClaim = new JSONArray().appendElement("Admin");
3538
when(idToken.getClaim(ROLES)).thenReturn(rolesClaim);
36-
Set<String> authorityStrings = userService.extractRolesFromIdToken(idToken);
39+
Set<String> authorityStrings = getUserService().extractRolesFromIdToken(idToken);
3740
assertThat(authorityStrings).hasSize(1);
3841
}
3942

4043
@Test
4144
public void testRolesClaimIllegal() {
45+
OidcIdToken idToken = mock(OidcIdToken.class);
4246
Set<String> rolesClaim = new HashSet<>(Arrays.asList("Admin"));
4347
when(idToken.getClaim(ROLES)).thenReturn(rolesClaim);
44-
Set<String> authorityStrings = userService.extractRolesFromIdToken(idToken);
48+
Set<String> authorityStrings = getUserService().extractRolesFromIdToken(idToken);
4549
assertThat(authorityStrings).hasSize(0);
4650
}
4751
}

sdk/spring/azure-spring-boot/src/test/java/com/azure/spring/aad/webapp/AADOAuth2AuthorizationCodeGrantRequestEntityConverterTest.java

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
import org.hamcrest.Matcher;
77
import org.junit.jupiter.api.Test;
8-
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
98
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
109
import org.springframework.http.HttpEntity;
1110
import org.springframework.http.HttpHeaders;
@@ -25,27 +24,22 @@
2524

2625
public class AADOAuth2AuthorizationCodeGrantRequestEntityConverterTest {
2726

28-
private AADWebAppClientRegistrationRepository clientRepo;
29-
private ClientRegistration azure;
30-
private ClientRegistration arm;
31-
32-
private final WebApplicationContextRunner contextRunner = WebApplicationContextRunnerUtils
33-
.getContextRunnerWithRequiredProperties().withPropertyValues(
34-
"azure.activedirectory.base-uri = fake-uri",
35-
"azure.activedirectory.authorization-clients.arm.scopes = Calendars.Read",
36-
"azure.activedirectory.authorization-clients.arm.on-demand=true");
37-
38-
private void getBeans(AssertableWebApplicationContext context) {
39-
clientRepo = context.getBean(AADWebAppClientRegistrationRepository.class);
40-
azure = clientRepo.findByRegistrationId("azure");
41-
arm = clientRepo.findByRegistrationId("arm");
27+
private WebApplicationContextRunner getContextRunner() {
28+
return WebApplicationContextRunnerUtils
29+
.getContextRunnerWithRequiredProperties()
30+
.withPropertyValues(
31+
"azure.activedirectory.base-uri = fake-uri",
32+
"azure.activedirectory.authorization-clients.arm.scopes = Calendars.Read",
33+
"azure.activedirectory.authorization-clients.arm.on-demand=true");
4234
}
4335

4436
@Test
4537
public void addScopeForDefaultClient() {
46-
contextRunner.run(context -> {
47-
getBeans(context);
48-
MultiValueMap<String, String> body = convertedBodyOf(createCodeGrantRequest(azure));
38+
getContextRunner().run(context -> {
39+
AADWebAppClientRegistrationRepository clientRepo =
40+
context.getBean(AADWebAppClientRegistrationRepository.class);
41+
ClientRegistration azure = clientRepo.findByRegistrationId("azure");
42+
MultiValueMap<String, String> body = convertedBodyOf(clientRepo, createCodeGrantRequest(azure));
4943
assertEquals(
5044
"openid profile offline_access",
5145
body.getFirst("scope")
@@ -55,34 +49,41 @@ public void addScopeForDefaultClient() {
5549

5650
@Test
5751
public void addScopeForOnDemandClient() {
58-
contextRunner.run(context -> {
59-
getBeans(context);
60-
MultiValueMap<String, String> body = convertedBodyOf(createCodeGrantRequest(arm));
52+
getContextRunner().run(context -> {
53+
AADWebAppClientRegistrationRepository clientRepo =
54+
context.getBean(AADWebAppClientRegistrationRepository.class);
55+
ClientRegistration arm = clientRepo.findByRegistrationId("arm");
56+
MultiValueMap<String, String> body = convertedBodyOf(clientRepo, createCodeGrantRequest(arm));
6157
assertEquals("Calendars.Read openid profile", body.getFirst("scope"));
6258
});
6359
}
6460

6561
@Test
6662
@SuppressWarnings("unchecked")
6763
public void addHeadersForDefaultClient() {
68-
contextRunner.run(context -> {
69-
getBeans(context);
70-
HttpHeaders httpHeaders = convertedHeaderOf(createCodeGrantRequest(azure));
71-
assertThat(httpHeaders.entrySet(), (Matcher) hasItems(expectedHeaders()));
64+
getContextRunner().run(context -> {
65+
AADWebAppClientRegistrationRepository clientRepo =
66+
context.getBean(AADWebAppClientRegistrationRepository.class);
67+
ClientRegistration azure = clientRepo.findByRegistrationId("azure");
68+
HttpHeaders httpHeaders = convertedHeaderOf(clientRepo, createCodeGrantRequest(azure));
69+
assertThat(httpHeaders.entrySet(), (Matcher) hasItems(expectedHeaders(clientRepo)));
7270
});
7371
}
7472

7573
@Test
7674
@SuppressWarnings("unchecked")
7775
public void addHeadersForOnDemandClient() {
78-
contextRunner.run(context -> {
79-
getBeans(context);
80-
HttpHeaders httpHeaders = convertedHeaderOf(createCodeGrantRequest(arm));
81-
assertThat(httpHeaders.entrySet(), (Matcher) hasItems(expectedHeaders()));
76+
getContextRunner().run(context -> {
77+
AADWebAppClientRegistrationRepository clientRepo =
78+
context.getBean(AADWebAppClientRegistrationRepository.class);
79+
ClientRegistration arm = clientRepo.findByRegistrationId("arm");
80+
HttpHeaders httpHeaders = convertedHeaderOf(clientRepo, createCodeGrantRequest(arm));
81+
assertThat(httpHeaders.entrySet(), (Matcher) hasItems(expectedHeaders(clientRepo)));
8282
});
8383
}
8484

85-
private HttpHeaders convertedHeaderOf(OAuth2AuthorizationCodeGrantRequest request) {
85+
private HttpHeaders convertedHeaderOf(AADWebAppClientRegistrationRepository clientRepo,
86+
OAuth2AuthorizationCodeGrantRequest request) {
8687
AADOAuth2AuthorizationCodeGrantRequestEntityConverter converter =
8788
new AADOAuth2AuthorizationCodeGrantRequestEntityConverter(clientRepo.getAzureClient());
8889
RequestEntity<?> entity = converter.convert(request);
@@ -91,7 +92,7 @@ private HttpHeaders convertedHeaderOf(OAuth2AuthorizationCodeGrantRequest reques
9192
.orElse(null);
9293
}
9394

94-
private Object[] expectedHeaders() {
95+
private Object[] expectedHeaders(AADWebAppClientRegistrationRepository clientRepo) {
9596
return new AADOAuth2AuthorizationCodeGrantRequestEntityConverter(clientRepo.getAzureClient())
9697
.getHttpHeaders()
9798
.entrySet()
@@ -100,7 +101,8 @@ private Object[] expectedHeaders() {
100101
.toArray();
101102
}
102103

103-
private MultiValueMap<String, String> convertedBodyOf(OAuth2AuthorizationCodeGrantRequest request) {
104+
private MultiValueMap<String, String> convertedBodyOf(AADWebAppClientRegistrationRepository clientRepo,
105+
OAuth2AuthorizationCodeGrantRequest request) {
104106
AADOAuth2AuthorizationCodeGrantRequestEntityConverter converter =
105107
new AADOAuth2AuthorizationCodeGrantRequestEntityConverter(clientRepo.getAzureClient());
106108
RequestEntity<?> entity = converter.convert(request);

0 commit comments

Comments
 (0)