Skip to content

Commit 362eea9

Browse files
authored
Add support for Azure China (Azure#18415)
1 parent fcfea68 commit 362eea9

File tree

5 files changed

+244
-97
lines changed

5 files changed

+244
-97
lines changed

sdk/spring/azure-spring-boot-starter-active-directory/README.md

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ Refer to different samples for different authentication ways.
159159

160160
**Note**: `AADAppRoleStatelessAuthenticationFilter` and `AADAuthenticationFilter` will be deprecated. [Click here](https://github.com/Azure/azure-sdk-for-java/issues/17860) to replace it.
161161

162-
### Authenticate in web apps [Web apps]
162+
### [Web APP] Authenticate in web app
163163
Please refer to [azure-spring-boot-sample-active-directory-webapp] for authenticate in web apps.
164164

165165
#### Configure application.yml:
@@ -188,7 +188,7 @@ public class AADOAuth2LoginConfigSample extends AADWebSecurityConfigurerAdapter
188188
}
189189
```
190190

191-
### Configure scopes of multiple resources [Web apps]
191+
### [Web APP] Configure scopes of multiple resources
192192
By default, `azure-spring-boot-starter-active-directory` configures scopes of `openid`, `profile` and `https://graph.microsoft.com/user.read` to implement OpenID Connect protocol and access of membership information of logging in users.
193193

194194
To customize scope configurations of multiple resources, developers need to configure the registration id and scopes in the `application.yml` as needed. Here the {registration-id} is defined by developers themselves to generate correspondding `OAuth2AuthorizedClient` to acquire access tokens, and scope names should follow the specification of `resource-uri/permission`.
@@ -202,7 +202,7 @@ azure:
202202
scopes: {scope1}, {scope2}
203203
```
204204
205-
### Configure on-demand resource authorization [Web apps]
205+
### [Web APP] Configure on-demand resource authorization
206206
To configure the authorization of certain resource as on-demand, developers need to add following property in `application.yml`:
207207
```yaml
208208
azure:
@@ -213,7 +213,7 @@ azure:
213213
scopes: {scope1}, {scope2}
214214
```
215215

216-
### Protect the resource APIs in resource server [Web APIs]
216+
### [Web API] Protect the resource APIs in resource server
217217
Please refer to [azure-spring-boot-sample-active-directory-resource-server] for access resource APIs.
218218

219219
#### Include the package
@@ -250,7 +250,7 @@ public class AADOAuth2ResourceServerSecurityConfig extends WebSecurityConfigurer
250250
}
251251
```
252252

253-
### OAuth 2.0 On-Behalf-Of flow [Web APIs]
253+
### [Web API] OAuth 2.0 On-Behalf-Of flow
254254
Please refer [azure-spring-boot-sample-active-directory-resource-server-obo] to for access On-Behalf-Of flow.
255255

256256
#### Include the package
@@ -314,7 +314,7 @@ azure:
314314
}
315315
```
316316

317-
### Authenticate in web APIs [Web APIs]
317+
### [Web API] (Deprecated) Authenticate in web API by a filter
318318
Please refer to [azure-spring-boot-sample-active-directory-resource-server-by-filter] for how to integrate Spring Security and Azure AD for authentication and authorization in a Single Page Application (SPA) scenario.
319319

320320
#### Configure application.yml:
@@ -341,7 +341,7 @@ public class AADAuthenticationFilterConfigSample extends WebSecurityConfigurerAd
341341
* Role-based Authorization with annotation `@PreAuthorize("hasRole('GROUP_NAME')")`
342342
* Role-based Authorization with method `isMemberOf()`
343343

344-
### Authenticate stateless web APIs using AAD app roles [Web APIs]
344+
### [Web API] (Deprecated) Authenticate stateless web API by a filter, using AAD app roles
345345
This scenario fits best for stateless Spring backends exposing an API to SPAs ([OAuth 2.0 implicit grant flow]) or service-to-service access using the [client credentials grant flow].
346346
The stateless processing can be activated with the `azure.activedirectory.session-stateless` property. The authorization is using the [AAD App Roles feature], so instead of using the `groups` claim the token has a `roles` claim which contains roles [configured in your manifest].
347347

@@ -395,6 +395,15 @@ public class AADAppRoleStatelessAuthenticationFilterConfigSample extends WebSecu
395395

396396
The roles you want to use within your application have to be [set up in the manifest of your application registration].
397397

398+
### [Web APP & Web API] Use Azure China instead of Azure Global
399+
If you use [Azure China] instead of **Azure Global**, you need to configure your `application.yml`:
400+
```yaml
401+
azure:
402+
activedirectory:
403+
base-uri: https://login.partner.microsoftonline.cn
404+
graph-membership-uri: https://microsoftgraph.chinacloudapi.cn/v1.0/me/memberOf
405+
```
406+
398407
## Troubleshooting
399408
### Enable client logging
400409
Azure SDKs for Java offers a consistent logging story to help aid in troubleshooting application errors and expedite their resolution. The logs produced will capture the flow of an application before reaching the terminal state to help locate the root issue. View the [logging][logging] wiki for guidance about enabling logging.
@@ -446,3 +455,4 @@ Please follow [instructions here] to build from source or contribute.
446455
[refdocs]: https://azure.github.io/azure-sdk-for-java/springboot.html#azure-spring-boot
447456
[sample]: https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/spring/azure-spring-boot-samples
448457
[set up in the manifest of your application registration]: https://docs.microsoft.com/azure/active-directory/develop/howto-add-app-roles-in-azure-ad-apps
458+
[Azure China]: https://docs.microsoft.com/azure/china/resources-developer-guide#check-endpoints-in-azure

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ private AzureClientRegistration createDefaultClient() {
8181
// AAD server will return error if:
8282
// 1. authorizationCodeScopes have more than one resource server.
8383
// 2. accessTokenScopes have no resource server
84-
accessTokenScopes.add("https://graph.microsoft.com/User.Read");
84+
accessTokenScopes.add(properties.getGraphBaseUri() + "User.Read");
8585
}
8686
return new AzureClientRegistration(client, accessTokenScopes);
8787
}
@@ -115,8 +115,8 @@ private Set<String> accessTokenScopes() {
115115
result.addAll(openidScopes());
116116
if (properties.allowedGroupsConfigured()) {
117117
// The 2 scopes are need to get group name from graph.
118-
result.add("https://graph.microsoft.com/User.Read");
119-
result.add("https://graph.microsoft.com/Directory.AccessAsUser.All");
118+
result.add(properties.getGraphBaseUri() + "User.Read");
119+
result.add(properties.getGraphBaseUri() + "Directory.AccessAsUser.All");
120120
}
121121
return result;
122122
}

sdk/spring/azure-spring-boot/src/main/java/com/azure/spring/autoconfigure/aad/AADAuthenticationProperties.java

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55

66
import com.azure.spring.aad.webapp.AuthorizationClientProperties;
77
import com.nimbusds.jose.jwk.source.RemoteJWKSet;
8+
import org.springframework.beans.factory.InitializingBean;
89
import org.springframework.boot.context.properties.ConfigurationProperties;
910
import org.springframework.boot.context.properties.DeprecatedConfigurationProperty;
1011
import org.springframework.util.ClassUtils;
12+
import org.springframework.util.StringUtils;
1113
import org.springframework.validation.annotation.Validated;
1214

1315
import java.util.ArrayList;
@@ -23,7 +25,7 @@
2325
*/
2426
@Validated
2527
@ConfigurationProperties("azure.activedirectory")
26-
public class AADAuthenticationProperties {
28+
public class AADAuthenticationProperties implements InitializingBean {
2729

2830
private static final long DEFAULT_JWK_SET_CACHE_LIFESPAN = TimeUnit.MINUTES.toMillis(5);
2931
private static final long DEFAULT_JWK_SET_CACHE_REFRESH_TIME = DEFAULT_JWK_SET_CACHE_LIFESPAN;
@@ -97,9 +99,11 @@ public class AADAuthenticationProperties {
9799
*/
98100
private Boolean sessionStateless = false;
99101

100-
private String baseUri = "https://login.microsoftonline.com/";
102+
private String baseUri;
101103

102-
private String graphMembershipUri = "https://graph.microsoft.com/v1.0/me/memberOf";
104+
private String graphBaseUri;
105+
106+
private String graphMembershipUri;
103107

104108
private Map<String, AuthorizationClientProperties> authorizationClients = new HashMap<>();
105109

@@ -277,6 +281,14 @@ public void setBaseUri(String baseUri) {
277281
this.baseUri = baseUri;
278282
}
279283

284+
public String getGraphBaseUri() {
285+
return graphBaseUri;
286+
}
287+
288+
public void setGraphBaseUri(String graphBaseUri) {
289+
this.graphBaseUri = graphBaseUri;
290+
}
291+
280292
public String getGraphMembershipUri() {
281293
return graphMembershipUri;
282294
}
@@ -299,4 +311,35 @@ public boolean isAllowedGroup(String group) {
299311
.orElseGet(Collections::emptyList)
300312
.contains(group);
301313
}
314+
315+
@Override
316+
public void afterPropertiesSet() throws Exception {
317+
318+
if (!StringUtils.hasText(baseUri)) {
319+
baseUri = "https://login.microsoftonline.com/";
320+
} else {
321+
baseUri = addSlash(baseUri);
322+
}
323+
324+
if (!StringUtils.hasText(graphBaseUri)) {
325+
graphBaseUri = "https://graph.microsoft.com/";
326+
} else {
327+
graphBaseUri = addSlash(graphBaseUri);
328+
}
329+
330+
if (!StringUtils.hasText(graphMembershipUri)) {
331+
graphMembershipUri = graphBaseUri + "v1.0/me/memberOf";
332+
}
333+
334+
if (!graphMembershipUri.startsWith(graphBaseUri)) {
335+
throw new IllegalStateException("azure.activedirectory.graph-base-uri should be "
336+
+ "the prefix of azure.activedirectory.graph-membership-uri. "
337+
+ "azure.activedirectory.graph-base-uri = " + graphBaseUri + ", "
338+
+ "azure.activedirectory.graph-membership-uri = " + graphMembershipUri + ".");
339+
}
340+
}
341+
342+
private String addSlash(String uri) {
343+
return uri.endsWith("/") ? uri : uri + "/";
344+
}
302345
}

sdk/spring/azure-spring-boot/src/main/java/com/azure/spring/autoconfigure/aad/AzureADGraphClient.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
public class AzureADGraphClient {
4747

4848
private static final Logger LOGGER = LoggerFactory.getLogger(AzureADGraphClient.class);
49-
private static final String MICROSOFT_GRAPH_SCOPE = "https://graph.microsoft.com/user.read";
49+
private static final String MICROSOFT_GRAPH_SCOPE = "User.Read";
5050
// We use "aadfeed5" as suffix when client library is ADAL, upgrade to "aadfeed6" for MSAL
5151
private static final String REQUEST_ID_SUFFIX = "aadfeed6";
5252

0 commit comments

Comments
 (0)