Skip to content

Commit d3a9689

Browse files
author
Kalyan Krishna
committed
Merge branch 'master' into kkrishna/updates2019
2 parents 3041519 + 0ba646f commit d3a9689

File tree

12 files changed

+309
-38
lines changed

12 files changed

+309
-38
lines changed

2-WebApp-graph-user/2-1-Call-MSGraph/README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,37 @@ The two new lines of code:
104104
> - replace `using Microsoft.Identity.Web.TokenCacheProviders.InMemory` by `using Microsoft.Identity.Web.TokenCacheProviders.Session`
105105
> - Replace `.AddInMemoryTokenCaches()` by `.AddSessionTokenCaches()`
106106
> add `app.UseSession();` in the `Configure(IApplicationBuilder app, IHostingEnvironment env)` method, for instance after `app.UseCookiePolicy();`
107+
>
108+
>
109+
> You can also use a distributed token cache, and choose the serialization implementation. For this, in **Startup.cs**:
110+
> - replace `using Microsoft.Identity.Web.TokenCacheProviders.InMemory` by `using Microsoft.Identity.Web.TokenCacheProviders.Distributed`
111+
> - Replace `.AddInMemoryTokenCaches()` by `.AddDistributedTokenCaches()`
112+
> - Then choose the distributed cache implementation. For details, see https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed?view=aspnetcore-2.2#distributed-memory-cache
113+
>
114+
> ```CSharp
115+
> // use a distributed Token Cache by adding
116+
> .AddDistributedTokenCaches();
117+
>
118+
> // and then choose your implementation.
119+
>
120+
> // For instance the distributed in memory cache (not cleaned when you stop the app)
121+
> services.AddDistributedMemoryCache()
122+
>
123+
> // Or a Redis cache
124+
> services.AddStackExchangeRedisCache(options =>
125+
> {
126+
> options.Configuration = "localhost";
127+
> options.InstanceName = "SampleInstance";
128+
> });
129+
>
130+
> // Or even a SQL Server token cache
131+
> services.AddDistributedSqlServerCache(options =>
132+
> {
133+
> options.ConnectionString =_config["DistCache_ConnectionString"];
134+
> options.SchemaName = "dbo";
135+
> options.TableName = "TestCache";
136+
> });
137+
> ```
107138

108139
### Add additional files to call Microsoft Graph
109140

2-WebApp-graph-user/2-1-Call-MSGraph/Startup.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using Microsoft.Extensions.Configuration;
88
using Microsoft.Extensions.DependencyInjection;
99
using Microsoft.Identity.Web;
10+
using Microsoft.Identity.Web.TokenCacheProviders.Distributed;
1011
using Microsoft.Identity.Web.TokenCacheProviders.InMemory;
1112
using WebApp_OpenIDConnect_DotNet.Infrastructure;
1213
using WebApp_OpenIDConnect_DotNet.Services;
@@ -40,6 +41,32 @@ public void ConfigureServices(IServiceCollection services)
4041
.AddMsal(Configuration, new string[] { Constants.ScopeUserRead })
4142
.AddInMemoryTokenCaches();
4243

44+
/*
45+
// or use a distributed Token Cache by adding
46+
.AddDistributedTokenCaches();
47+
48+
// and then choose your implementation.
49+
// See https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed?view=aspnetcore-2.2#distributed-memory-cache
50+
51+
// For instance the distributed in memory cache (not cleared when you stop the app)
52+
services.AddDistributedMemoryCache()
53+
54+
// Or a Redis cache
55+
services.AddStackExchangeRedisCache(options =>
56+
{
57+
options.Configuration = "localhost";
58+
options.InstanceName = "SampleInstance";
59+
});
60+
61+
// Or even a SQL Server token cache
62+
services.AddDistributedSqlServerCache(options =>
63+
{
64+
options.ConnectionString =
65+
_config["DistCache_ConnectionString"];
66+
options.SchemaName = "dbo";
67+
options.TableName = "TestCache";
68+
});
69+
*/
4370
// Add Graph
4471
services.AddGraphService(Configuration);
4572

4-WebApp-your-API/Client/Startup.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public void ConfigureServices(IServiceCollection services)
4040
// By default, the claims mapping will map claim names in the old format to accommodate older SAML applications.
4141
// 'http://schemas.microsoft.com/ws/2008/06/identity/claims/role' instead of 'roles'
4242
// This flag ensures that the ClaimsIdentity claims collection will be built from the claims in the token
43-
JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
43+
//JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
4444

4545
// Token acquisition service based on MSAL.NET
4646
// and chosen token cache implementation

4-WebApp-your-API/TodoListService/Startup.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,9 @@ public void ConfigureServices(IServiceCollection services)
5151
// By default, the claims mapping will map claim names in the old format to accommodate older SAML applications.
5252
// 'http://schemas.microsoft.com/ws/2008/06/identity/claims/role' instead of 'roles'
5353
// This flag ensures that the ClaimsIdentity claims collection will be built from the claims in the token
54-
JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
54+
//JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
5555

5656
services.AddProtectedWebApi(Configuration);
57-
services.Configure<JwtBearerOptions>(AzureADDefaults.JwtBearerAuthenticationScheme, options =>
58-
{
59-
options.TokenValidationParameters.NameClaimType = "name";
60-
});
6157

6258
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
6359
}
Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,20 @@
11
{
2-
"AzureAd": {
3-
"Instance": "https://login.microsoftonline.com/",
4-
"Domain": "kalyankrishna.com",
5-
"TenantId": "4d39e77c-b0f3-4253-ae0b-7068ddd47949",
6-
"ClientId": "7f1d4458-72e7-41b5-ad81-103bd6e307b7",
7-
"CallbackPath": "/signin-oidc",
8-
"SignedOutCallbackPath ": "/signout-callback-oidc",
2+
"AzureAd": {
3+
"Instance": "https://login.microsoftonline.com/",
4+
"Domain": "[Enter the domain of your tenant, e.g. contoso.onmicrosoft.com]",
5+
"TenantId": "[Enter 'common', or 'organizations' or the Tenant Id (Obtained from the Azure portal. Select 'Endpoints' from the 'App registrations' blade and use the GUID in any of the URLs), e.g. da41245a5-11b3-996c-00a8-4d99re19f292]",
6+
"ClientId": "[Enter the Client Id (Application ID obtained from the Azure portal), e.g. ba74781c2-53c2-442a-97c2-3d60re42f403]",
7+
"CallbackPath": "/signin-oidc",
8+
"SignedOutCallbackPath ": "/signout-callback-oidc",
99

10-
// To call an API
11-
"ClientSecret": "9Y7lZKjDwKYZC3Ut1S8Dzg3TmAqVEJKUIbmIbH0jMdM="
12-
13-
},
14-
"Logging": {
15-
"LogLevel": {
16-
"Default": "Warning"
17-
}
18-
},
19-
"AllowedHosts": "*",
20-
"GraphApiUrl": "https://graph.microsoft.com/beta"
10+
// To call an API
11+
"ClientSecret": "[Copy the client secret added to the app from the Azure portal]"
12+
},
13+
"Logging": {
14+
"LogLevel": {
15+
"Default": "Warning"
16+
}
17+
},
18+
"AllowedHosts": "*",
19+
"GraphApiUrl": "https://graph.microsoft.com/beta"
2120
}

Microsoft.Identity.Web/Diagrams.cd

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,28 +46,28 @@
4646
</TypeIdentifier>
4747
</Class>
4848
<Class Name="Microsoft.Identity.Web.WebAppServiceCollectionExtensions">
49-
<Position X="0.5" Y="0.5" Width="11" />
49+
<Position X="0.5" Y="0.5" Width="13.25" />
5050
<TypeIdentifier>
51-
<HashCode>AAAAAAAAAAAAAgAAAAAAAAAAAAAAAACAAAAAAAAAAAA=</HashCode>
51+
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAI=</HashCode>
5252
<FileName>WebAppServiceCollectionExtensions.cs</FileName>
5353
</TypeIdentifier>
5454
</Class>
5555
<Class Name="Microsoft.Identity.Web.WebApiServiceCollectionExtensions">
56-
<Position X="0.5" Y="2" Width="15" />
56+
<Position X="0.5" Y="2" Width="14.5" />
5757
<TypeIdentifier>
58-
<HashCode>AAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAA=</HashCode>
58+
<HashCode>AAAAAACAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAA=</HashCode>
5959
<FileName>WebApiServiceCollectionExtensions.cs</FileName>
6060
</TypeIdentifier>
6161
</Class>
62-
<Class Name="Microsoft.Identity.Web.MsalUiRequiredExceptionFilterAttribute">
62+
<Class Name="Microsoft.Identity.Web.AuthorizeForScopesAttribute">
6363
<Position X="0.5" Y="5.75" Width="3.5" />
6464
<Members>
6565
<Method Name="BuildAuthenticationPropertiesForIncrementalConsent" Hidden="true" />
6666
<Method Name="CanBeSolvedByReSignInUser" Hidden="true" />
6767
</Members>
6868
<TypeIdentifier>
69-
<HashCode>AAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAgAIAIA=</HashCode>
70-
<FileName>MsalUiRequiredExceptionFilterAttribute.cs</FileName>
69+
<HashCode>AAAAAAAAAAAAACAAAAAAIAAAAAAAAAAAAAAAAgAIAIA=</HashCode>
70+
<FileName>AuthorizeForScopesAttribute.cs</FileName>
7171
</TypeIdentifier>
7272
</Class>
7373
<Class Name="Microsoft.Identity.Web.AccountExtensions">

Microsoft.Identity.Web/README.md

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ to enable them to work with the Microsoft identity platform (formerly named Azur
1313

1414
As of today, ASP.NET Core web apps templates (`dot net new mvc -auth`) create web apps that sign in users with the Azure AD v1.0 endpoint (allowing to sign in users with their organizational accounts, also named *Work or school accounts*). This library brings `ServiceCollection` extension methods to be used in the ASP.NET Core web app **Startup.cs** file to enable the web app to sign in users with the Microsoft identity platform (formerly Azure AD v2.0 endpoint), and, optionally enable the web app to call APIs on behalf of the signed-in user.
1515

16-
![WebAppServiceCollectionExtensions](https://user-images.githubusercontent.com/13203188/62526924-0a563780-b7ef-11e9-8ce0-db284db3f02c.png)
16+
![WebAppServiceCollectionExtensions](https://user-images.githubusercontent.com/13203188/64252959-82ae3680-cf1c-11e9-8a01-0a0be728a78e.png)
1717

1818
### Web apps that sign in users - Startup.cs
1919

@@ -84,6 +84,11 @@ public class Startup
8484
}
8585
```
8686

87+
Note that by default, `AddMicrosoftIdentityPlatformAuthentication` gets the configuration from the "AzureAD" section of the configuration files. It has
88+
several parameters that you can change.
89+
90+
Also the proposed token cache serialization is in memory. you can also use the session cache, or various distributed caches
91+
8792
### Web app controller
8893

8994
For your web app to call web APIs on behalf of the signed-in user, you'll need to add a parameter of type `ITokenAcquisition` to the constructor of your controller (the `ITokenAcquisition` service will be injected by dependency injection by ASP.NET Core)
@@ -125,7 +130,7 @@ public class HomeController : Controller
125130

126131
The controller action is decorated by an attribute `AuthorizeForScopesAttribute` which enables to process the `MsalUiRequiredException` that could be thrown by the service implementing `ITokenAcquisition.GetAccessTokenOnBehalfOfUserAsync` so that the web app interacts with the user, and ask them to consent to the scopes, or re-sign-in if needed.
127132

128-
<img alt="AuthorizeForScopesAttribute" src="https://user-images.githubusercontent.com/13203188/62526956-18a45380-b7ef-11e9-99f3-c75085d61ce5.png" width="50%"/>
133+
<img alt="AuthorizeForScopesAttribute" src="https://user-images.githubusercontent.com/13203188/64253212-0bc56d80-cf1d-11e9-9666-2e72b78886ed.png" width="50%"/>
129134

130135
### Samples and documentation
131136

@@ -139,7 +144,7 @@ You can see in details how the library is used in the following samples:
139144

140145
The library also enables web APIs to work with the Microsoft identity platform, enabling them to process access tokens for both work and school and Microsoft personal accounts.
141146

142-
![image](https://user-images.githubusercontent.com/13203188/62526937-10e4af00-b7ef-11e9-9fee-c205c97653c5.png)
147+
![image](https://user-images.githubusercontent.com/13203188/64253058-ba1ce300-cf1c-11e9-8f01-88180fc0faed.png)
143148
144149
### Protected web APIS - Startup.cs
145150

@@ -209,6 +214,8 @@ public class Startup
209214
}
210215
```
211216

217+
Like for Web Apps, you can choose various token cache implementations.
218+
212219
If you're certain that your web API will need some specific scopes, you can optionally pass them as arguments to `AddProtectedApiCallsWebApis`.
213220

214221
### Web API controller
@@ -218,7 +225,7 @@ For your web API to call downstream APIs, you'll need to:
218225
- add (like in web apps), a parameter of type `ITokenAcquisition` to the constructor of your controller (the `ITokenAcquisition` service will be injected by dependency injection by ASP.NET Core)
219226
- verify, in your controller actions, that the token contains the scopes expected by the action. For this, you'll call the `VerifyUserHasAnyAcceptedScope` extension method on the `HttpContext`
220227

221-
<img alt="ScopesRequiredHttpContextExtensions" src="https://user-images.githubusercontent.com/13203188/62527104-60c37600-b7ef-11e9-8dcb-66bb982fe147.png" width="80%"/>
228+
<img alt="ScopesRequiredHttpContextExtensions" src="https://user-images.githubusercontent.com/13203188/64253176-f9e3ca80-cf1c-11e9-8fe9-df06cee11c25.png" width="80%"/>
222229

223230
- in your controller actions, to call: `ITokenAcquisition.GetAccessTokenOnBehalfOfUserAsync` passing the scopes for which to request a token.
224231

@@ -262,6 +269,36 @@ For web apps that calls web apis, and web APIs that call downstream APIs, the co
262269
| `AddInMemoryTokenCaches` | `TokenCacheProviders.InMemory` | In memory token cache serialization. This implementation is great in samples. It's also good in production applications provided you don't mind if the token cache is lost when the web app is restarted. `AddInMemoryTokenCaches` takes an optional parameter of type `MsalMemoryTokenCacheOptions` that enables you to specify the duration after which the cache entry will expire unless it's used.
263270
| `AddSqlTokenCaches` | `TokenCacheProviders.Sql` | The token cache maintained in a SQL database. This implementation is ideal for production applications that need to keep their token caches. AddSqlTokenCaches takes a parameter of type `MsalSqlTokenCacheOptions` that let you specify the SQL connection string
264271
| `AddSessionTokenCaches` | `TokenCacheProviders.Session` | The token cache is bound to the user session. This option isn't ideal if the ID token is too large because it contains too many claims as the cookie would be too large.
272+
| `AddDistributedTokenCaches` | `TokenCacheProviders.Distributed` | The token cache is an adapter against the ASP.NET Core `IDistributedCache` implementation, therefore enabling you to choose between a distributed memory cache, a Redis cache, or a SQL Server cache. For details about the IDistributedCache` implementations, see https://docs.microsoft.com/en-us/aspnet/core/performance/caching/distributed?view=aspnetcore-2.2#distributed-memory-cache.
273+
274+
Examples of possible distributed cache:
275+
276+
```CSharp
277+
// or use a distributed Token Cache by adding
278+
services.AddMicrosoftIdentityPlatformAuthentication(Configuration)
279+
.AddMsal(new string[] { scopesToRequest })
280+
.AddDistributedTokenCaches();
281+
282+
// and then choose your implementation
283+
284+
// For instance the distributed in memory cache (not cleared when you stop the app)
285+
services.AddDistributedMemoryCache()
286+
287+
// Or a Redis cache
288+
services.AddStackExchangeRedisCache(options =>
289+
{
290+
options.Configuration = "localhost";
291+
options.InstanceName = "SampleInstance";
292+
});
293+
294+
// Or even a SQL Server token cache
295+
services.AddDistributedSqlServerCache(options =>
296+
{
297+
options.ConnectionString = _config["DistCache_ConnectionString"];
298+
options.SchemaName = "dbo";
299+
options.TableName = "TestCache";
300+
});
301+
```
265302

266303
## Other utility classes
267304

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using Microsoft.Extensions.DependencyInjection;
5+
6+
namespace Microsoft.Identity.Web.TokenCacheProviders.Distributed
7+
{
8+
/// <summary>
9+
/// Extension class used to add an in-memory token cache serializer to MSAL
10+
/// </summary>
11+
public static class DistributedTokenCacheAdapterExtension
12+
{
13+
/// <summary>Adds both the app and per-user in-memory token caches.</summary>
14+
/// <param name="services">The services collection to add to.</param>
15+
/// <param name="cacheOptions">The MSALMemoryTokenCacheOptions allows the caller to set the token cache expiration</param>
16+
/// <returns></returns>
17+
public static IServiceCollection AddDistributedTokenCaches(
18+
this IServiceCollection services)
19+
{
20+
AddDistributedAppTokenCache(services);
21+
AddDistributedUserTokenCache(services);
22+
return services;
23+
}
24+
25+
/// <summary>Adds the in-memory based application token cache to the service collection.</summary>
26+
/// <param name="services">The services collection to add to.</param>
27+
/// <param name="cacheOptions">The MSALMemoryTokenCacheOptions allows the caller to set the token cache expiration</param>
28+
public static IServiceCollection AddDistributedAppTokenCache(
29+
this IServiceCollection services)
30+
{
31+
services.AddDistributedMemoryCache();
32+
services.AddSingleton<IMsalAppTokenCacheProvider, MsalAppDistributedTokenCacheProvider>();
33+
return services;
34+
}
35+
36+
/// <summary>Adds the in-memory based per user token cache to the service collection.</summary>
37+
/// <param name="services">The services collection to add to.</param>
38+
/// <param name="cacheOptions">The MSALMemoryTokenCacheOptions allows the caller to set the token cache expiration</param>
39+
/// <returns></returns>
40+
public static IServiceCollection AddDistributedUserTokenCache(
41+
this IServiceCollection services)
42+
{
43+
services.AddDistributedMemoryCache();
44+
services.AddHttpContextAccessor();
45+
services.AddSingleton<IMsalUserTokenCacheProvider, MsalPerUserDistributedTokenCacheProvider>();
46+
return services;
47+
}
48+
}
49+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System.Security.Principal;
5+
using System.Threading.Tasks;
6+
using Microsoft.AspNetCore.Authentication.AzureAD.UI;
7+
using Microsoft.AspNetCore.Http;
8+
using Microsoft.Extensions.Caching.Distributed;
9+
using Microsoft.Extensions.Caching.Memory;
10+
using Microsoft.Extensions.Options;
11+
using Microsoft.Identity.Client;
12+
13+
namespace Microsoft.Identity.Web.TokenCacheProviders.Distributed
14+
{
15+
/// <summary>
16+
/// An implementation of token cache for Confidential clients backed by MemoryCache.
17+
/// MemoryCache is useful in Api scenarios where there is no HttpContext to cache data.
18+
/// </summary>
19+
/// <seealso cref="https://aka.ms/msal-net-token-cache-serialization"/>
20+
public class MsalAppDistributedTokenCacheProvider : MsalDistributedTokenCacheAdapter, IMsalAppTokenCacheProvider
21+
{
22+
public MsalAppDistributedTokenCacheProvider(IOptions<AzureADOptions> azureAdOptions,
23+
IHttpContextAccessor httpContextAccessor,
24+
IDistributedCache memoryCache,
25+
IOptions<DistributedCacheEntryOptions> cacheOptions) :
26+
base(azureAdOptions, httpContextAccessor, memoryCache, cacheOptions)
27+
{
28+
29+
}
30+
31+
public async Task InitializeAsync(ITokenCache tokenCache)
32+
{
33+
await InitializeAsync(tokenCache, true).ConfigureAwait(false);
34+
}
35+
}
36+
}

0 commit comments

Comments
 (0)