Skip to content

[Do not merge until MSAL.NET 4.0 releases] Jmprieur/msal4.0 #107

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 4, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions 2-WebApp-graph-user/2-2-TokenCache/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,15 @@ Go to the `"2-WebApp-graph-user\2-2-TokenCache"` folder
#### In the appsettings.json file, configure a Sql server database for token caching, if you have not already done so:

1. In the `TokenCacheDbConnStr` key, provide the Sql server connection string to the database you wish to use for token caching.
> Note:
> If you want to test this sample locally with Visual Studio, you might want to use localdb, which is installed with Visual Studio.
> In that case, use the following connection string:
>
> ```XML
> "ConnectionStrings": {
> "TokenCacheDbConnStr": "Data Source=(LocalDb)\\MSSQLLocalDB;Database=MY_TOKEN_CACHE_DATABASE;Trusted_Connection=True;"
> },
> ```
1. If you do not have an existing database and tables needed for token caching, this sample can use [EF Core- code first](https://docs.microsoft.com/en-us/ef/core/get-started/aspnetcore/new-db?tabs=visual-studio) to create a database and tables for you. to do that, follow the steps below.
1. In the file `Microsoft.Identity.Web\Client\TokenCacheProviders\Sql\MSALAppSqlTokenCacheProviderExtension.cs`, uncomment the code under the **// Uncomment the following lines to create the database.**. This comment exists once in the **AddSqlAppTokenCache** and **AddSqlPerUserTokenCache** methods.
1. Run the solution again, when a user signs-in the very first time, the Entity Framework will create the database and tables `AppTokenCache` and `UserTokenCache` for app and user token caching respectively.
Expand Down
8 changes: 7 additions & 1 deletion 2-WebApp-graph-user/2-2-TokenCache/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@

// To call an API
"ClientSecret": "[Enter�app�key�of�the�first�app�as�obtained�from�Azure�Portal,�e.g.�rZJJ9bHSi/cYnYwmQFxLYDn/6EfnrnIfKoNzv9NKgbo]"
},
},

/*
To try the sample locally on your development machine, if you have installed Visual Studio you can
use the following connection string
"TokenCacheDbConnStr": "Data Source=(LocalDb)\\MSSQLLocalDB;Database=MY_TOKEN_CACHE_DATABASE;Trusted_Connection=True;"
*/
"ConnectionStrings": {
"TokenCacheDbConnStr": "[Enter�the Sql server connection string, e.g. Server=MY_SQL_SERVER;Database=MY_TOKEN_CACHE_DATABASE;Trusted_Connection=True;"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

namespace Microsoft.Identity.Web.Client.TokenCacheProviders
{
Expand All @@ -46,7 +47,12 @@ public class MSALAppSessionTokenCacheProvider : IMSALAppTokenCacheProvider
/// <summary>
/// The HTTP context being used by this app
/// </summary>
internal HttpContext HttpContext = null;
internal HttpContext HttpContext { get { return httpContextAccessor.HttpContext; } }

/// <summary>
/// HTTP context accessor
/// </summary>
internal IHttpContextAccessor httpContextAccessor;

/// <summary>
/// The duration till the tokens are kept in memory cache. In production, a higher value , upto 90 days is recommended.
Expand All @@ -63,26 +69,26 @@ public class MSALAppSessionTokenCacheProvider : IMSALAppTokenCacheProvider
/// <summary>Initializes a new instance of the <see cref="MSALAppSessionTokenCacheProvider"/> class.</summary>
/// <param name="azureAdOptionsAccessor">The azure ad options accessor.</param>
/// <exception cref="ArgumentNullException">AzureADOptions - The app token cache needs {nameof(AzureADOptions)}</exception>
public MSALAppSessionTokenCacheProvider(IOptionsMonitor<AzureADOptions> azureAdOptionsAccessor)
public MSALAppSessionTokenCacheProvider(IOptionsMonitor<AzureADOptions> azureAdOptionsAccessor, IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor;
if (azureAdOptionsAccessor.CurrentValue == null && string.IsNullOrWhiteSpace(azureAdOptionsAccessor.CurrentValue.ClientId))
{
throw new ArgumentNullException(nameof(AzureADOptions), $"The app token cache needs {nameof(AzureADOptions)}, populated with clientId to initialize.");
}

this.AppId = azureAdOptionsAccessor.CurrentValue.ClientId;
AppId = azureAdOptionsAccessor.CurrentValue.ClientId;
}

/// <summary>Initializes this instance of TokenCacheProvider with essentials to initialize themselves.</summary>
/// <param name="tokenCache">The token cache instance of MSAL application</param>
/// <param name="httpcontext">The Httpcontext whose Session will be used for caching.This is required by some providers.</param>
public void Initialize(ITokenCache tokenCache, HttpContext httpcontext)
{
this.AppCacheId = this.AppId + "_AppTokenCache";
this.HttpContext = httpcontext;
AppCacheId = this.AppId + "_AppTokenCache";

tokenCache.SetBeforeAccess(this.AppTokenCacheBeforeAccessNotification);
tokenCache.SetAfterAccess(this.AppTokenCacheAfterAccessNotification);
tokenCache.SetBeforeAccessAsync(this.AppTokenCacheBeforeAccessNotificationAsync);
tokenCache.SetAfterAccessAsync(this.AppTokenCacheAfterAccessNotificationAsync);
tokenCache.SetBeforeWrite(this.AppTokenCacheBeforeWriteNotification);
}

Expand Down Expand Up @@ -119,9 +125,9 @@ public void Clear()
/// Triggered right before MSAL needs to access the cache. Reload the cache from the persistence store in case it changed since the last access.
/// </summary>
/// <param name="args">Contains parameters used by the MSAL call accessing the cache.</param>
private void AppTokenCacheBeforeAccessNotification(TokenCacheNotificationArgs args)
private async Task AppTokenCacheBeforeAccessNotificationAsync(TokenCacheNotificationArgs args)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And therefore the callback are async

{
this.HttpContext.Session.LoadAsync().Wait();
await this.HttpContext.Session.LoadAsync();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And we don't need to block any longer!


SessionLock.EnterReadLock();
try
Expand All @@ -147,7 +153,7 @@ private void AppTokenCacheBeforeAccessNotification(TokenCacheNotificationArgs ar
/// Triggered right after MSAL accessed the cache.
/// </summary>
/// <param name="args">Contains parameters used by the MSAL call accessing the cache.</param>
private void AppTokenCacheAfterAccessNotification(TokenCacheNotificationArgs args)
private async Task AppTokenCacheAfterAccessNotificationAsync(TokenCacheNotificationArgs args)
{
// if the access operation resulted in a cache update
if (args.HasStateChanged)
Expand All @@ -159,8 +165,8 @@ private void AppTokenCacheAfterAccessNotification(TokenCacheNotificationArgs arg

// Reflect changes in the persistent store
byte[] blob = args.TokenCache.SerializeMsalV3();
this.HttpContext.Session.Set(this.AppCacheId, blob);
this.HttpContext.Session.CommitAsync().Wait();
HttpContext.Session.Set(this.AppCacheId, blob);
await HttpContext.Session.CommitAsync();
}
finally
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
*/

using Microsoft.AspNetCore.Authentication.AzureAD.UI;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;

Expand All @@ -46,9 +47,11 @@ public static IServiceCollection AddSessionTokenCaches(this IServiceCollection s
/// <returns></returns>
public static IServiceCollection AddSessionAppTokenCache(this IServiceCollection services)
{
services.AddHttpContextAccessor();
services.AddScoped<IMSALAppTokenCacheProvider>(factory =>
{
return new MSALAppSessionTokenCacheProvider(factory.GetRequiredService<IOptionsMonitor<AzureADOptions>>());
return new MSALAppSessionTokenCacheProvider(factory.GetRequiredService<IOptionsMonitor<AzureADOptions>>(),
factory.GetRequiredService<IHttpContextAccessor>());
});

return services;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,13 @@ public static IServiceCollection AddSqlAppTokenCache(this IServiceCollection ser
{
// Uncomment the following lines to create the database. In production scenarios, the database
// will most probably be already present.
//var tokenCacheDbContextBuilder = new DbContextOptionsBuilder<TokenCacheDbContext>();
//tokenCacheDbContextBuilder.UseSqlServer(sqlTokenCacheOptions.SqlConnectionString);

//var tokenCacheDbContext = new TokenCacheDbContext(tokenCacheDbContextBuilder.Options);
//tokenCacheDbContext.Database.EnsureCreated();
/*
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Transforming in /* comments so that it's obvious what to uncomment

var tokenCacheDbContextBuilder = new DbContextOptionsBuilder<TokenCacheDbContext>();
tokenCacheDbContextBuilder.UseSqlServer(sqlTokenCacheOptions.SqlConnectionString);

var tokenCacheDbContextForCreation = new TokenCacheDbContext(tokenCacheDbContextBuilder.Options);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed tokenCacheDbContext -> tokenCacheDbContextForCreation as there was a conflict

tokenCacheDbContextForCreation.Database.EnsureCreated();
*/
services.AddDataProtection();

services.AddDbContext<TokenCacheDbContext>(options =>
Expand Down
2 changes: 1 addition & 1 deletion Microsoft.Identity.Web/Microsoft.Identity.Web.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.AzureAD.UI" Version="2.2.0" />
<PackageReference Include="Microsoft.Identity.Client" Version="3.0.8" />
<PackageReference Include="Microsoft.Identity.Client" Version="4.0.0" />
</ItemGroup>
</Project>