Skip to content

Commit 6d3510c

Browse files
author
Kalyan Krishna
committed
review in progress
1 parent 2074945 commit 6d3510c

File tree

6 files changed

+65
-48
lines changed

6 files changed

+65
-48
lines changed

2-WebApp-graph-user/2-3-Multi-Tenant/README.md

Lines changed: 46 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,14 @@ For more information about apps and tenancy, see [Tenancy in Azure Active Direct
4141

4242
## Scenario
4343

44-
This sample shows how to build a .NET Core MVC web application that uses the [OpenID Connect](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-protocols-oidc) protocol to sign in users from multiple Azure AD tenants and acquire token for [Microsoft Graph](https://graph.microsoft.com) using the [Microsoft Authentication Library (MSAL)](https://docs.microsoft.com/en-us/azure/active-directory/develop/msal-overview). It leverages the ASP.NET Core OpenID Connect middleware.
44+
This sample shows how to build a .NET Core MVC web application that uses the [OpenID Connect](https://docs.microsoft.com/azure/active-directory/develop/v2-protocols-oidc) protocol to sign in users from multiple Azure AD tenants and acquire token for [Microsoft Graph](https://graph.microsoft.com) using the [Microsoft Authentication Library (MSAL)](https://docs.microsoft.com/azure/active-directory/develop/msal-overview). It leverages the ASP.NET Core OpenID Connect middleware.
4545

4646
The application puts forward a scenario where a SaaS application invites the administrators of Azure AD tenants to `enroll` their tenants into this app. This process is analogous to a customer `buying` a SaaS product.
4747

48-
1. Once you start the application, you will land in the homepage where you can sign-in or onboard your tenant.
49-
1. If you sign-in before onboarding your tenant, you'd land on a page with a heading **Unauthorized Tenant**. Click on the **Take me to the onboarding process** button to onboard your tenant to this application.
50-
1. On the onboarding page, you will be asked to sign-in as an **administrator** and accept an **admin consent** for the application.
51-
1. Once you have **registered your tenant**, all users from that tenant will be able to sign-in and explore the todo list.
48+
1. Once you start the application, you will land on the homepage where you can **sign-in** or **onboard** your tenant.
49+
1. If you try to **Sign-In** before onboarding your tenant, you'd land on the **Unauthorized Tenant** page. Click on the **Take me to the onboarding process** button to onboard your tenant to this application.
50+
1. On the onboarding page, you will be asked to sign-in as a tenant **administrator** and accept the permissions requested in the **admin consent** screen to successfully provision the application in your tenant.
51+
1. Once you have **registered your tenant**, all users from that tenant will be able to sign-in and explore the ToDo list.
5252

5353
> Looking for previous versions of this code sample? Check out the tags on the [releases](../../releases) GitHub page.
5454
@@ -75,8 +75,6 @@ or download and extract the repository .zip file.
7575
7676
### Step 2: Register the sample application with your Azure Active Directory tenant
7777

78-
> :warning: **If you had created this sample in the past already**: [Delete its **enterprise app** from the other tenants before re-creating this application](#error-AADSTS650051).
79-
8078
There is one project in this sample. To register it, you can:
8179

8280
- either follow the steps [Step 2: Register the sample with your Azure Active Directory tenant](#step-2-register-the-sample-with-your-azure-active-directory-tenant) and [Step 3: Configure the sample to use your Azure AD tenant](#choose-the-azure-ad-tenant-where-you-want-to-create-your-applications)
@@ -134,7 +132,7 @@ As a first step you'll need to:
134132
- `https://localhost:44321/signin-oidc`
135133
- `https://localhost:44321/Onboarding/ProcessCode`
136134
- In the **Advanced settings** section, set **Logout URL** to `https://localhost:44321/signout-oidc`.
137-
- In the **Advanced settings** | **Implicit grant** section, check the **ID tokens** option as this sample requires the [Implicit grant flow](https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-implicit-grant-flow) to be enabled to sign-in the user, and call an API.
135+
- In the **Advanced settings** | **Implicit grant** section, check the **ID tokens** option as the [AspNetCore security middleware](https://github.com/aspnet/AspNetCore/tree/master/src/Security) used in the sample uses the [Implicit grant flow](https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-implicit-grant-flow) by default to get the user info right after sign-in.
138136

139137
1. Click the **Save** button on top to save the changes.
140138
1. In the app's registration screen, click on the **Certificates & secrets** blade in the left to open the page where we can generate secrets and upload certificates.
@@ -164,60 +162,62 @@ Open the project in your IDE (like Visual Studio) to configure the code.
164162
### Step 4: Run the sample
165163

166164
Clean the solution, rebuild the solution, and run it.
167-
The sample implements two distinct tasks: the onboarding of a new tenant and a basic Todo List CRUD operation.
165+
The sample implements two distinct tasks: the onboarding of a new tenant and a basic ToDo List CRUD operation.
168166

169167
Ideally, you would want to have two Azure AD tenants so you can test the multi-tenant aspect of this sample. For more information on how to get an Azure AD tenant, see [How to get an Azure AD tenant](https://azure.microsoft.com/documentation/articles/active-directory-howto-tenant/).
170168

171169
#### Signing-in
172170

173-
Users can only sign-in if their tenant had been "onboarded". The sample will guide them how to do so, but it requires a **tenant admin account** to complete the onboarding process. Once the admin have consented, all users from their tenant will be able to sign-in.
171+
Users can only sign-in if their tenant had been "onboarded" first. The sample will guide them how to do so, but it requires a **tenant admin account** to complete the onboarding process. Once the admin has consented and provisioned the app in their tenant, all users from their tenant will be able to sign-in.
174172

175173
If you try to onboard without an admin account, you will be presented with the following screen. Please switch to an admin account to complete this step:
176174

177-
![Admin Approval](ReadmeFiles/admin-approval.png)
175+
![Admin Consent](ReadmeFiles/admin-approval.png)
178176

179-
If you try to sign-in with a tenant that haven't been "onboarded" yet, you will land in this page. Please click on **Take me to the onboarding process** button and follow the instructions to get your tenant registered in the sample database:
177+
If you try to sign-in with a tenant that hasn't been "onboarded" yet, you will land on the following page. Please click on **Take me to the onboarding process** button and follow the instructions to get your tenant registered in the sample database:
180178

181179
![Unauthorized Tenant](ReadmeFiles/unauthorized-tenant.png)
182180

183-
#### Todo List
181+
> :warning: If you onboarded your tenant using this sample in the past already and getting the **AADSTS650051** error when onboarding again, please refer to the [Error AADSTS650051](#error-aadsts650051) section below.
182+
183+
#### ToDo List
184184

185-
Users from one tenant can't see todo items from other tenants. They will be able to perform basic CRUD operations on todo items assigned to them. When editing a todo item, users can assign it to any other user from their tenant. The list of users is coming from Microsoft Graph, using the [Graph SDK](https://github.com/microsoftgraph/msgraph-sdk-dotnet).
185+
Users from one tenant can't see the **ToDo** items of users from other tenants. They will be able to perform basic CRUD operations on ToDo items assigned to them. When editing a ToDo item, users can assign it to any other user from their tenant. The list of users in a tenant is fetched from Microsoft Graph, using the [Graph SDK](https://github.com/microsoftgraph/msgraph-sdk-dotnet).
186186

187187
The list of users will be presented in the **Assigned To** dropdown:
188188

189-
![Todo Edit](ReadmeFiles/todo-edit.png)
189+
![todo Edit](ReadmeFiles/todo-edit.png)
190190

191191
## About The code
192192

193-
This sample covers the following topics on a multi-tenant app.
193+
This sample details the following aspects of a multi-tenant app.
194194

195-
- usage of the `/common` endpoint
196-
- service principle provision for new tenants
197-
- custom token validation allowing only registered tenants
198-
- data partition
199-
- Microsoft Graph token by tenant
195+
- usage of the `/common` endpoint.
196+
- Service Principle provisioning of an app in Azure AD tenants
197+
- Custom Token Validation to allow users from onboarded tenants only.
198+
- Data partitioning in multi-tenant apps.
199+
- Acquiring Access tokens for Microsoft Graph for each tenant.
200200

201-
It is using the OpenID Connect ASP.NET Core middleware to sign in users from multiple Azure AD tenants. The middleware is initialized in the `Startup.cs` file by passing it the Client ID of the app, and the URL of the Azure AD tenant where the app is registered. These values are read from the `appsettings.json` file.
201+
This sample is using the OpenID Connect ASP.NET Core middleware to sign in users from multiple Azure AD tenants. The middleware is initialized in the `Startup.cs` file by passing it the Client ID of the app, and the URL of the Azure AD tenant where the app is registered. These values are read from the `appsettings.json` file.
202202

203203
You can trigger the middleware to send an OpenID Connect sign-in request by decorating a class or method with the `[Authorize]` attribute or by issuing a challenge (see the [AccountController.cs](https://github.com/aspnet/AspNetCore/blob/master/src/Azure/AzureAD/Authentication.AzureAD.UI/src/Areas/AzureAD/Controllers/AccountController.cs) file which is part of ASP.NET Core):
204204

205205
These steps are encapsulated in the [Microsoft.Identity.Web](..\..\Microsoft.Identity.Web) project, and in particular in the [WebAppServiceCollectionExtensions.cs](..\..\Microsoft.Identity.Web\WebAppServiceCollectionExtensions.cs) file
206206

207207
### Usage of `/common` endpoint
208208

209-
In order to be able to sign-in users from multiple tenants using OpenID Connect, the [/common endpoint](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-protocols-oidc#fetch-the-openid-connect-metadata-document) must be used so Microsoft identity platform can fetch the metadata document. In the sample, this endpoint is used as a result of setting the value for `TenantId` as `organizations` on the `appsettings.json` file, and configuring the middleware to read the values from it.
209+
In order to be able to sign-in users from multiple tenants, the [/common endpoint](https://docs.microsoft.com/azure/active-directory/develop/howto-convert-app-to-be-multi-tenant#update-your-code-to-send-requests-to-common) must be used. In the sample, this endpoint is used as a result of setting the value for `TenantId` as `organizations` on the `appsettings.json` file, and configuring the middleware to read the values from it.
210210

211211
```csharp
212212
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
213213
.AddAzureAD(options => configuration.Bind(configSectionName, options));
214214
```
215215

216-
Read more about [OpenID Connect endpoints here](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-protocols#endpoints).
216+
You can read about the various endpoints of the Microsoft Identity Platform [here](https://docs.microsoft.com/azure/active-directory/develop/active-directory-v2-protocols#endpoints).
217217

218218
### Service principle provision for new tenants (onboarding process)
219219

220-
On a multi-tenant app, its service principle will be created on all the users' tenants that have signed-in at least once. Some might want that only tenant admins accept the service principle provisioning. For that, we are using the [admin consent endpoint](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-admin-consent) for the onboarding process on the `OnboardingController.cs`. The `Onboard` action and corresponding view, simulate an onboarding experience.
220+
For a multi-tenant app, its service principle will be created on all the users' tenants that have signed-in at least once. Some might want that only tenant admins accept the service principle provisioning. For that, we are using the [admin consent endpoint](https://docs.microsoft.com/azure/active-directory/develop/v2-admin-consent) for the onboarding process on the `OnboardingController.cs`. The `Onboard` action and corresponding view, simulate an onboarding experience.
221221

222222
```csharp
223223
[HttpPost]
@@ -238,7 +238,7 @@ public IActionResult Onboard()
238238

239239
This results in an OAuth2 code grant request that triggers the admin consent flow and creates the service principle in the admin's tenant. The `state` parameter is used to validate the response, preventing a man-in-the-middle attack. Then, the `ProcessCode` action receives the authorization code from Azure AD and, if they appear valid, it creates an entry in the application database for the new customer.
240240

241-
The `https://graph.microsoft.com/.default` is a static scope. You can find more about static scope on [this link.](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-admin-consent#request-the-permissions-from-a-directory-admin)
241+
The `https://graph.microsoft.com/.default` is a static scope. You can find more about static scope on [this link.](https://docs.microsoft.com/azure/active-directory/develop/v2-admin-consent#request-the-permissions-from-a-directory-admin)
242242

243243
### Custom token validation allowing only registered tenants
244244

@@ -281,15 +281,15 @@ services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =
281281
});
282282
```
283283

284-
### Data partition
284+
### Data partitioning by tenant
285285

286286
There are two common scenarios regarding data partition on a multi-tenant app. Having a separate database for each tenant or having a single database and using the **tenantId** to distinguish the data from each tenant. In this sample, we used the single database approach to save the todo items.
287287

288-
`TodoListController.cs` have basic CRUD actions for `TodoItem` and each operation takes into account the signed user's **tenantId** to separate data from each tenant. The tenantId can be found in the user' claims.
288+
`TodoListController.cs` have basic CRUD actions for `todoItem` and each operation takes into account the signed user's **tenantId** to separate data from each tenant. The tenantId can be found in the user' claims.
289289

290290
### Microsoft Graph token by tenant
291291

292-
If a multi-tenant app needs to acquire a token from Graph to read data from the signed user's tenant, the token must be issued with their tenantId authority and not where the application is registered. This feature is being showed on the **Edit** action result on `TodoListController.cs`.
292+
If a multi-tenant app needs to acquire a token from Graph to read data from the signed user's tenant, the token must be issued with their tenantId authority and not where the application is registered. This feature is being showed on the **Edit** action result on `todoListController.cs`.
293293

294294
```csharp
295295
var userTenant = User.GetTenantId();
@@ -312,7 +312,7 @@ AuthenticationResult result = await confidentialClientApplication
312312

313313
### Error AADSTS650051
314314

315-
If you are receiving the following error message, you might need to **delete older Enterprise Applications of this sample**
315+
If you are receiving the following error message, you might need to **delete older service principals of this application**. Please [delete the existing [service principal](https://docs.microsoft.com/azure/active-directory/develop/app-objects-and-service-principals) from the **enterprise app** blade of the tenant before re-creating this application]. Click on the **Enterprise Applications** blade in the portal, locate this application `WebApp-MultiTenant-v2`, navigate to its **properties** and click **Delete** to delete the service principal.
316316

317317
> OpenIdConnectProtocolException: Message contains error: 'invalid_client', error_description: 'AADSTS650051: Application '{applicationId}' is requesting permissions that are either invalid or out of date.
318318
@@ -325,10 +325,25 @@ If you'd like to contribute to this sample, see [CONTRIBUTING.MD](/CONTRIBUTING.
325325
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information, see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [[email protected]](mailto:[email protected]) with any additional questions or comments.
326326

327327
## Learn more
328-
To understand more about token validation, see
328+
329+
To learn more about single and multi-tenant apps
330+
331+
- [Tenancy in Azure Active Directory](https://docs.microsoft.com/en-us/azure/active-directory/develop/single-and-multi-tenant-apps)
332+
- [How to: Sign in any Azure Active Directory user using the multi-tenant application pattern](https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-convert-app-to-be-multi-tenant)
333+
- [Application and service principal objects in Azure Active Directory](https://docs.microsoft.com/en-us/azure/active-directory/develop/app-objects-and-service-principals)
334+
- [National Clouds](https://docs.microsoft.com/en-us/azure/active-directory/develop/authentication-national-cloud)
335+
- [Endpoints](https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-protocols#endpoints)
336+
337+
To learn more about admin consent experiences
338+
- [Understanding Azure AD application consent experiences](https://docs.microsoft.com/en-us/azure/active-directory/develop/application-consent-experience)
339+
- [Understand user and admin consent](https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-convert-app-to-be-multi-tenant#understand-user-and-admin-consent)
340+
341+
To learn more about token validation, see
329342
- [Validating tokens](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/wiki/ValidatingTokens)
343+
- [Validating an id_token](https://docs.microsoft.com/en-us/azure/active-directory/develop/id-tokens#validating-an-id_token)
330344

331345
To understand more about app registration, see:
332346

333347
- [Quickstart: Register an application with the Microsoft identity platform (Preview)](https://docs.microsoft.com/azure/active-directory/develop/quickstart-register-app)
334348
- [Quickstart: Configure a client application to access web APIs (Preview)](https://docs.microsoft.com/azure/active-directory/develop/quickstart-configure-app-access-web-apis)
349+
41.2 KB
Loading

2-WebApp-graph-user/2-3-Multi-Tenant/Views/Home/Index.cshtml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,22 @@
66
}
77

88
<h1>
9-
ASP.NET Core web app signing-in users in any Azure AD organization
9+
A ASP.NET Core web app signing-in users from any Azure AD organization
1010
</h1>
1111
<p>
1212
This sample shows how to build a .NET Core MVC Web app that uses OpenID Connect to sign in users. Users can use work and school accounts from any company or organization that has integrated with Azure Active Directory. It leverages the ASP.NET Core OpenID Connect middleware.
1313
</p>
14-
<img src="https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/raw/master/1-WebApp-OIDC/1-2-AnyOrg/ReadmeFiles/sign-in.png" />
14+
<img src="https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/raw/master/2-WebApp-graph-user/2-3-Multi-Tenant/ReadmeFiles/Sign-in.png" />
1515

1616
@if (User.Identity.IsAuthenticated)
1717
{
1818
<hr />
1919
<h2>Authorized Tenants</h2>
2020
<p>
21-
These are the authorized tenants on the database. If you want to repeat the onboarding process, offboard the desired tenant from this list.
21+
These are the authorized tenants on the database. If you want to repeat the onboarding process, off-board the desired tenant from this list.
2222
</p>
2323
<p>
24-
Offboarding the signed user's tenant, will trigger a <b>sign-out.</b>
24+
Off-boarding the signed user's tenant, will trigger a <b>sign-out.</b>
2525
</p>
2626

2727
<table class="table">
@@ -42,7 +42,7 @@
4242
<span class="label label-primary">your tenant</span>
4343
}
4444
</td>
45-
<td><a asp-controller="Home" asp-action="DeleteTenant" asp-route-id=@tenant.TenantId class="btn btn-danger">Offboard</a></td>
45+
<td><a asp-controller="Home" asp-action="DeleteTenant" asp-route-id=@tenant.TenantId class="btn btn-danger">Off-board</a></td>
4646
</tr>
4747
}
4848
</tbody>

0 commit comments

Comments
 (0)