Skip to content

Commit

Permalink
Update README.md file in the resource-server-obo (#18372)
Browse files Browse the repository at this point in the history
  • Loading branch information
ZhuXiaoBing-cn authored Dec 29, 2020
1 parent f19b24f commit ae0c6a1
Show file tree
Hide file tree
Showing 11 changed files with 68 additions and 81 deletions.
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
# OAuth 2.0 Sample for azure-spring-boot-sample-active-directory-resource-server-obo library for Java

## Key concepts
[Resource server access other resources usage][resource-server-access-other-resources-usage] is an extension scenario of the *azure-spring-boot-sample-active-directory-resource-server* sample. Similarly, this sample illustrates how to protect a Java web API by restricting access to its resources to authorized accounts, and the restricted resource will access other restricted resource, such as Graph API and Custom API.
[Resource server access other resources usage] is an extension scenario of the *azure-spring-boot-sample-active-directory-resource-server* sample. Similarly, this sample illustrates how to protect a Java web API by restricting access to its resources to authorized accounts, and the restricted resource will access other restricted resource, such as Graph API and Custom API.

### Protocol diagram
Assume that the user has been authenticated on an application using the OAuth 2.0 authorization code grant flow or another login flow. At this point, the application has an access token for API A (token A) with the user's claims and consent to access the middle-tier web API (API A). Now, API A needs to make an authenticated request to the downstream web API (API B).
The steps that follow constitute the OBO flow and are explained with the help of the following diagram.

![OBO flow](docs/image-aad-obo-flow.png)
1. The client application makes a request to API A with token A (with an aud claim of API A).
2. API A authenticates to the Microsoft identity platform token issuance endpoint and requests a token to access API B.
4. The Microsoft identity platform token issuance endpoint validates API A's credentials along with token A and issues the access token for API B (token B) to API A.
4. Token B is set by API A in the authorization header of the request to API B.
5. Data from the secured resource is returned by API B to API A, and from there to the client.

## Getting started
We will prepare two application to demonstrate the dependent calls of resources.
Another sample [spring security resource server sample][azure-spring-boot-sample-active-directory-resource-server] will be as Custom API resource.
We will prepare two application to demonstrate the dependent calls of resources.
Another sample [azure-spring-boot-sample-active-directory-resource-server] will be as Custom API resource (let's call it Web API B).

### Environment checklist
We need to ensure that this [environment checklist][ready-to-run-checklist] is completed before the run.

### Include the package

```xml
<dependencies>
<dependency>
Expand All @@ -26,7 +35,6 @@ We need to ensure that this [environment checklist][ready-to-run-checklist] is c
<dependency>
<groupId>com.azure.spring</groupId>
<artifactId>azure-spring-boot-starter-active-directory</artifactId>
<version>3.0.0-beta.2</version> <!-- {x-version-update;com.azure.spring:azure-spring-boot-starter-active-directory;current} -->
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
Expand All @@ -39,7 +47,6 @@ We need to ensure that this [environment checklist][ready-to-run-checklist] is c
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>msal4j</artifactId>
<version>1.8.0</version> <!-- {x-version-update;com.microsoft.azure:msal4j;external_dependency} -->
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
Expand All @@ -48,68 +55,46 @@ We need to ensure that this [environment checklist][ready-to-run-checklist] is c
</dependencies>
```

### Register your Web API
You can follow *azure-spring-boot-sample-active-directory-resource-server* sample to add `ResourceAccessGraph.read`, `ResourceAccessGraphCustomResources.read` scopes.
Convention current application id url is `api://sample-client-id`, ; the application id url of the sample *azure-spring-boot-sample-active-directory-resource-server* is `custom-client-id`.
After adding as shown below:

![API Permissions](resource/resource-server-obo-add-scope.png)

### Add API permissions
The current Web API will access Graph API and Custom API.

Sign in to the [Azure portal][azure-portal]. If you have access to multiple tenants, use the **Directory + subscription** filter in the top menu to select the tenant containing your client app's registration.

#### Add Graph API Permission
1. Select **Azure Active Directory** > **App registrations**, and then select your current sample application (not your web API).

2. Select **API permissions** > **Add a permission** > **Microsoft APIs** > **Microsoft Graph** > **Delegated permissions**, select **User.Read**, select **Add permission** to complete the process.
### Configure your middle-tier Web API A
1. Expose two scopes for ***Web API A***, `Obo.Graph.Read` and `Obo.File.Read`. The **Application ID URI** is generated by default.
**NOTE**: Theses scopes (`Obo.Graph.Read`, `Obo.File.Read`) should be added to the **Web APP**.
![API Permissions](docs/image-resource-server-obo-add-scope.png)
2. Select **API permissions** > **Add a permission** > **My APIs**, select ***Web API B*** application name. ![Select MyAPIs](docs/image-select-myapis.png)
3. **Delegated permissions** is selected by default, Select **File** > **File.Read** permission, select **Add permission** to complete the process.![Add Permissions](docs/image-add-permissions.png)
4. Grant admin consent for ***Web API B*** permissions.![API Permissions](docs/image-add-grant-admin-consent.png)

#### Add Custom API Permission

1. Select **Azure Active Directory** > **App registrations**, and then select your current sample application (not your web API).

2. Select **API permissions** > **Add a permission** > **My APIs**, select *azure-spring-boot-sample-active-directory-resource-server* application name.

3. **Delegated permissions** is selected by default, Select **File** > **File.Read** permission, select **Add permission** to complete the process.

### Grant consent for your tenant
Respectively grant admin consent to the Graph and Custom permissions. After adding as shown below:
![API Permissions](resource/resource-server-obo-add-permissions.png)
See [OAuth 2.0 On-Behalf-Of flow] for more information about OBO.

## Examples

### Configure application.yaml

### Configure application.yml
```yaml
azure:
activedirectory:
resource-server:
obo:
enabled: true
client-id: [resource-server-application-client-id]
client-secret: [resource-server-application-client-secret]
tenant-id: [tenant-id-registered-by-application]
app-id-uri: api://sample-client-id
client-id: <Web-API-A-client-id>
client-secret: <Web-API-A-client-secret>
tenant-id: <tenant-id-registered-by-application>
app-id-uri: <Web-API-A-app-id-url>
authorization-clients:
graph:
scopes:
- https://graph.microsoft.com/User.Read
custom:
scopes:
- api://custom-client-id/File.read
- <Web-API-B-app-id-url>/File.Read
```
### Run with Maven
### Run with Maven
```shell
cd azure-spring-boot-samples/azure-spring-boot-sample-active-directory-resource-server-obo
mvn spring-boot:run
```

### Access the Web API
First, you need to obtain an access token to access Sample API.
- API will Only call Graph resource.
### Access the Web API A
First, you need to obtain an access token to access Web API A.
- Web API A will Only call Graph resource.
```shell script
# Replace to valid access token.
curl localhost:8081/call-graph-only -H "Authorization: Bearer <replace-the-access-token>"
Expand All @@ -119,7 +104,7 @@ Verify response:
Graph response success.
```

- Sample API will Only call Graph resource.
- Web API A will Only call Graph resource through annotation.

```shell script
# Replace to valid access token.
Expand All @@ -133,16 +118,16 @@ Verify response:
Graph response success.
```

- Sample API will call Graph and Custom resources.
- Web API A will call Custom(Web API B) resources.

```shell script
# Replace to valid access token.
curl localhost:8081/call-graph-and-custom-resources -H "Authorization: Bearer <replace-the-access-token>"
curl localhost:8081/call-custom-resources -H "Authorization: Bearer <replace-the-access-token>"
```

Verify response:
```text
Graph response success. Custom(local) response success.
Custom response success.
```

## Troubleshooting
Expand All @@ -151,7 +136,8 @@ Graph response success. Custom(local) response success.
## Contributing

<!-- LINKS -->
[azure-portal]: https://portal.azure.com/
[Azure portal]: https://portal.azure.com/
[ready-to-run-checklist]: https://github.com/Azure/azure-sdk-for-java/blob/master/sdk/spring/azure-spring-boot-samples/README.md#ready-to-run-checklist
[resource-server-access-other-resources-usage]: https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/spring/azure-spring-boot-starter-active-directory#resource-server-access-other-resources-usage
[azure-spring-boot-sample-active-directory-resource-server]: https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/spring/azure-spring-boot-samples/azure-spring-boot-sample-active-directory-resource-server
[Resource server access other resources usage]: https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/spring/azure-spring-boot-starter-active-directory#resource-server-access-other-resources-usage
[azure-spring-boot-sample-active-directory-resource-server]: https://github.com/Azure/azure-sdk-for-java/tree/master/sdk/spring/azure-spring-boot-samples/azure-spring-boot-sample-active-directory-resource-server
[OAuth 2.0 On-Behalf-Of flow]: https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-on-behalf-of-flow
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public class SampleController {
* @return Response with graph data
*/
@GetMapping("call-graph-only")
@PreAuthorize("hasAuthority('SCOPE_ResourceAccessGraph.read')")
@PreAuthorize("hasAuthority('SCOPE_Obo.Graph.Read')")
public String callGraphOnly() {
Authentication principal = SecurityContextHolder.getContext().getAuthentication();
RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
Expand All @@ -57,23 +57,21 @@ public String callGraphOnly() {
* @return Response with graph data
*/
@GetMapping("call-graph-only-with-annotation")
@PreAuthorize("hasAuthority('SCOPE_ResourceAccessGraph.read')")
@PreAuthorize("hasAuthority('SCOPE_Obo.Graph.Read')")
public String callGraphOnlyWithAnnotation(@RegisteredOAuth2AuthorizedClient("graph") OAuth2AuthorizedClient graph) {
return callMicrosoftGraphMeEndpoint(graph);
}

/**
* Call the graph and custom(local) resources, combine all the response and return.
* @param graph authorized client for Graph
* Call custom resources, combine all the response and return.
* @param custom authorized client for Custom
* @return Response Graph and Custom data.
*/
@PreAuthorize("hasAuthority('SCOPE_ResourceAccessGraphCustomResources.read')")
@GetMapping("call-graph-and-custom-resources")
public String callGraphAndCustomResources(
@RegisteredOAuth2AuthorizedClient("graph") OAuth2AuthorizedClient graph,
@GetMapping("call-custom-resources")
@PreAuthorize("hasAuthority('SCOPE_Obo.File.Read')")
public String callCustomResources(
@RegisteredOAuth2AuthorizedClient("custom") OAuth2AuthorizedClient custom) {
return callMicrosoftGraphMeEndpoint(graph) + " " + callCustomLocalFileEndpoint(custom);
return callCustomLocalFileEndpoint(custom);
}

/**
Expand Down Expand Up @@ -111,10 +109,10 @@ private String callCustomLocalFileEndpoint(OAuth2AuthorizedClient custom) {
.retrieve()
.bodyToMono(String.class)
.block();
LOGGER.info("Response from Custom(local): {}", body);
return "Custom(local) response " + (null != body ? "success." : "failed.");
LOGGER.info("Response from Custom: {}", body);
return "Custom response " + (null != body ? "success." : "failed.");
} else {
return "Custom(local) response failed.";
return "Custom response failed.";
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
server:
port: 8080

azure:
activedirectory:
resource-server:
obo:
enabled: true
client-id: <Web-API-A-client-id>
client-secret: <Web-API-A-client-secret>
tenant-id: <Tenant-id-registered-by-application>
app-id-uri: <Web-API-A-app-id-url>
authorization-clients:
graph:
scopes:
- https://graph.microsoft.com/User.Read
custom:
scopes:
- <Web-API-B-app-id-url>/Obo.File.Read

0 comments on commit ae0c6a1

Please sign in to comment.