Skip to content

Commit f615524

Browse files
author
Kalyan Krishna
committed
Removed unnecessary optimization from the Sql cache provider
1 parent d3a9689 commit f615524

File tree

9 files changed

+47
-60
lines changed

9 files changed

+47
-60
lines changed

2-WebApp-graph-user/2-2-TokenCache/AppCreationScripts/Cleanup.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ if ($null -eq (Get-Module -ListAvailable -Name "AzureAD")) {
99
Install-Module "AzureAD" -Scope CurrentUser
1010
}
1111
Import-Module AzureAD
12-
$ErrorActionPreference = 'Stop'
12+
$ErrorActionPreference = "Stop"
1313

1414
Function Cleanup
1515
{

2-WebApp-graph-user/2-2-TokenCache/AppCreationScripts/Configure.ps1

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ Function AddResourcePermission($requiredAccess, `
6565
}
6666

6767
#
68-
# Exemple: GetRequiredPermissions "Microsoft Graph" "Graph.Read|User.Read"
68+
# Example: GetRequiredPermissions "Microsoft Graph" "Graph.Read|User.Read"
6969
# See also: http://stackoverflow.com/questions/42164581/how-to-configure-a-new-azure-ad-application-through-powershell
7070
Function GetRequiredPermissions([string] $applicationDisplayName, [string] $requiredDelegatedPermissions, [string]$requiredApplicationPermissions, $servicePrincipal)
7171
{
@@ -134,18 +134,18 @@ Function UpdateTextFile([string] $configFilePath, [System.Collections.HashTable]
134134
Set-Content -Path $configFilePath -Value $lines -Force
135135
}
136136

137-
138137
Set-Content -Value "<html><body><table>" -Path createdApps.html
139138
Add-Content -Value "<thead><tr><th>Application</th><th>AppId</th><th>Url in the Azure portal</th></tr></thead><tbody>" -Path createdApps.html
140139

140+
$ErrorActionPreference = "Stop"
141+
141142
Function ConfigureApplications
142143
{
143144
<#.Description
144145
This function creates the Azure AD applications for the sample in the provided Azure AD tenant and updates the
145146
configuration files in the client and service project of the visual studio solution (App.Config and Web.Config)
146147
so that they are consistent with the Applications parameters
147148
#>
148-
149149
$commonendpoint = "common"
150150

151151
# $tenantId is the Active Directory Tenant. This is a GUID which represents the "Directory ID" of the AzureAD tenant
@@ -177,7 +177,7 @@ Function ConfigureApplications
177177
$tenant = Get-AzureADTenantDetail
178178
$tenantName = ($tenant.VerifiedDomains | Where { $_._Default -eq $True }).Name
179179

180-
# Get the user running the script
180+
# Get the user running the script to add the user as the app owner
181181
$user = Get-AzureADUser -ObjectId $creds.Account.Id
182182

183183
# Create the webApp AAD application
@@ -187,6 +187,7 @@ Function ConfigureApplications
187187
$fromDate = [DateTime]::Now;
188188
$key = CreateAppKey -fromDate $fromDate -durationInYears 2 -pw $pw
189189
$webAppAppKey = $pw
190+
# create the application
190191
$webAppAadApplication = New-AzureADApplication -DisplayName "WebApp-OpenIDConnect-DotNet-code-v2" `
191192
-HomePage "https://localhost:44321/" `
192193
-LogoutUrl "https://localhost:44321/signout-oidc" `
@@ -197,6 +198,7 @@ Function ConfigureApplications
197198
-Oauth2AllowImplicitFlow $true `
198199
-PublicClient $False
199200

201+
# create the service principal of the newly created application
200202
$currentAppId = $webAppAadApplication.AppId
201203
$webAppServicePrincipal = New-AzureADServicePrincipal -AppId $currentAppId -Tags {WindowsAzureActiveDirectoryIntegratedApp}
202204

@@ -225,7 +227,6 @@ Function ConfigureApplications
225227

226228
$requiredResourcesAccess.Add($requiredPermissions)
227229

228-
229230
Set-AzureADApplication -ObjectId $webAppAadApplication.ObjectId -RequiredResourceAccess $requiredResourcesAccess
230231
Write-Host "Granted permissions."
231232

@@ -241,7 +242,8 @@ Function ConfigureApplications
241242
# Pre-requisites
242243
if ((Get-Module -ListAvailable -Name "AzureAD") -eq $null) {
243244
Install-Module "AzureAD" -Scope CurrentUser
244-
}
245+
}
246+
245247
Import-Module AzureAD
246248

247249
# Run interactively (will ask you for the tenant ID)

2-WebApp-graph-user/2-2-TokenCache/AppCreationScripts/sample.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"Sample": {
3-
"Title": "Using the Microsoft identity platform to call the Microsoft Graph API from an An ASP.NET Core 2.x Web App, on behalf of a user signing-in using their work and school or Microsoft personal account",
3+
"Title": "Using the Microsoft identity platform to call the Microsoft Graph API from an a ASP.NET Core 2.x Web App, on behalf of a user signing-in using their work and school or Microsoft personal account",
44
"Level": 200,
55
"Client": "ASP.NET Core 2.x Web App",
66
"Service": "Microsoft Graph",

2-WebApp-graph-user/2-2-TokenCache/appsettings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"TokenCacheDbConnStr": "Data Source=(LocalDb)\\MSSQLLocalDB;Database=MY_TOKEN_CACHE_DATABASE;Trusted_Connection=True;"
1818
*/
1919
"ConnectionStrings": {
20-
"TokenCacheDbConnStr": "[Enter the Sql server connection string, e.g. Server=MY_SQL_SERVER;Database=MY_TOKEN_CACHE_DATABASE;Trusted_Connection=True;"
20+
"TokenCacheDbConnStr": "[Enter the Sql server connection string, e.g. Server=MY_SQL_SERVER;Database=MsalTokenCacheDatabase;Trusted_Connection=True;"
2121
},
2222
"Logging": {
2323
"LogLevel": {

Microsoft.Identity.Web/TokenAcquisition.cs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,11 @@ public TokenAcquisition(
6969
};
7070

7171
/// <summary>
72-
/// This handler is executed after authorization code is received (once the user signs-in and consents) during the
73-
/// <a href='https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow'>Authorization code flow grant flow</a> in a web app.
72+
/// This handler is executed after authorization code is received (once the user signs-in and consents) during the
73+
/// <a href='https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow'>Authorization code flow grant flow</a> in a web app.
7474
/// It uses the code to request an access token from the Microsoft Identity platform and caches the tokens and an entry about the signed-in user's account in the MSAL's token cache.
75-
/// The access token (and refresh token) provided in the <see cref="AuthorizationCodeReceivedContext"/>, once added to the cache, are then used to acquire more tokens using the
76-
/// <a href='https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-on-behalf-of-flow'>on-behalf-of flow</a> for the signed-in user's account,
75+
/// The access token (and refresh token) provided in the <see cref="AuthorizationCodeReceivedContext"/>, once added to the cache, are then used to acquire more tokens using the
76+
/// <a href='https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-on-behalf-of-flow'>on-behalf-of flow</a> for the signed-in user's account,
7777
/// in order to call to downstream APIs.
7878
/// </summary>
7979
/// <param name="context">The context used when an 'AuthorizationCode' is received over the OpenIdConnect protocol.</param>
@@ -117,7 +117,7 @@ public async Task AddAccountToCacheFromAuthorizationCodeAsync(AuthorizationCodeR
117117
// race condition ending-up in an error from Azure AD telling "code already redeemed")
118118
context.HandleCodeRedemption();
119119

120-
// The cache will need the claims from the ID token.
120+
// The cache will need the claims from the ID token.
121121
// If they are not yet in the HttpContext.User's claims, so adding them here.
122122
if (!context.HttpContext.User.Claims.Any())
123123
{
@@ -146,7 +146,7 @@ public async Task AddAccountToCacheFromAuthorizationCodeAsync(AuthorizationCodeR
146146

147147
/// <summary>
148148
/// Typically used from a Web App or WebAPI controller, this method retrieves an access token
149-
/// for a downstream API using the <a href='https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-on-behalf-of-flow'>on-behalf-of flow</a>
149+
/// for a downstream API using the <a href='https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-on-behalf-of-flow'>on-behalf-of flow</a>
150150
/// for the user account that is ascertained from claims are provided in the <see cref="HttpContext.User"/> instance of the <paramref name="context"/> parameter
151151
/// </summary>
152152
/// <param name="scopes">Scopes to request for the downstream API to call</param>
@@ -287,8 +287,6 @@ public async Task RemoveAccountAsync(RedirectContext context)
287287
}
288288
}
289289

290-
291-
292290
/// <summary>
293291
/// Creates an MSAL Confidential client application if needed
294292
/// </summary>
@@ -450,9 +448,9 @@ private async Task AddAccountToCacheFromJwtAsync(IEnumerable<string> scopes, Jwt
450448
}
451449

452450
/// <summary>
453-
/// Used by Web APIs, which cannot interact with the user, when they run into a situation where user consent is required for additional scopes.
454-
/// This method appends in the HttpResponse being sent back to the client, a 403 (forbidden) status code and populates the 'WWW-Authenticate' header with additional information.
455-
/// The client, when it receives the 403 code with this header, can use the additional information provided in the header to trigger an interaction with the user where the user
451+
/// Used by Web APIs, which cannot interact with the user, when they run into a situation where user consent is required for additional scopes.
452+
/// This method appends in the HttpResponse being sent back to the client, a 403 (forbidden) status code and populates the 'WWW-Authenticate' header with additional information.
453+
/// The client, when it receives the 403 code with this header, can use the additional information provided in the header to trigger an interaction with the user where the user
456454
/// can then consent to additional scopes.
457455
/// </summary>
458456
/// <param name="scopes">The additional scopes that the user needs to consent to</param>

Microsoft.Identity.Web/TokenCacheProviders/Distributed/MsalAppDistributedTokenCacheProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
namespace Microsoft.Identity.Web.TokenCacheProviders.Distributed
1414
{
1515
/// <summary>
16-
/// An implementation of token cache for Confidential clients backed by MemoryCache.
16+
/// An implementation of token cache for Confidential clients backed by a IDistributedCache .
1717
/// MemoryCache is useful in Api scenarios where there is no HttpContext to cache data.
1818
/// </summary>
1919
/// <seealso cref="https://aka.ms/msal-net-token-cache-serialization"/>

Microsoft.Identity.Web/TokenCacheProviders/MsalAbstractTokenCacheProvider.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
namespace Microsoft.Identity.Web.TokenCacheProviders
1111
{
12+
/// <summary></summary>
13+
/// <seealso cref="Microsoft.Identity.Web.TokenCacheProviders.IMsalTokenCacheProvider" />
1214
public abstract class MsalAbstractTokenCacheProvider : IMsalTokenCacheProvider
1315
{
1416
/// <summary>
@@ -113,6 +115,7 @@ public async Task ClearAsync()
113115
}
114116

115117
protected abstract Task WriteCacheBytesAsync(string cacheKey, byte[] bytes);
118+
116119
protected abstract Task<byte[]> ReadCacheBytesAsync(string cacheKey);
117120

118121
protected abstract Task RemoveKeyAsync(string cacheKey);

Microsoft.Identity.Web/TokenCacheProviders/Sql/MsalSqlTokenCacheProvider.cs

Lines changed: 22 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -27,77 +27,61 @@ public MsalSqlTokenCacheProvider(IHttpContextAccessor httpContextAccessor, Token
2727
private readonly TokenCacheDbContext _tokenCacheDb;
2828

2929
/// <summary>
30-
/// This keeps the latest copy of the token in memory to save calls to DB, if possible.
30+
/// This keeps the latest copy of the token in memory ..
3131
/// </summary>
32-
private TokenCacheDbRecord _inMemoryCache;
32+
private TokenCacheDbRecord _cacheDbRecord;
3333

3434
/// <summary>
3535
/// The data protector
3636
/// </summary>
3737
private readonly IDataProtector _dataProtector;
3838

3939

40-
protected override async Task<byte[]> ReadCacheBytesAsync(string cacheKey)
40+
protected override Task<byte[]> ReadCacheBytesAsync(string cacheKey)
4141
{
42-
if (_inMemoryCache == null) // first time access
42+
try
4343
{
44-
try
45-
{
46-
_inMemoryCache = GetLatestRecordQuery(cacheKey).FirstOrDefault();
47-
}
48-
catch (SqlException ex) when (ex.Message == "Invalid object name 'Records'")
49-
{
50-
// Microsoft.Identity.Web changed from several tables (AppTokenCache, UserTokenCache) to one table (record)
51-
// If you care about the cache, you can migrate them, otherwise re-create the database
52-
throw new Exception("You need to migrate the AppTokenCache and UserTokenCache tables to Records, or run SqlTokenCacheProviderExtension.CreateTokenCachingTablesInSqlDatabase() to create the database", ex);
53-
}
54-
catch (SqlException ex) when (ex.Message.StartsWith("Cannot open database \"MY_TOKEN_CACHE_DATABASE\" requested by the login."))
55-
{
56-
throw new Exception("You need to run SqlTokenCacheProviderExtension.CreateTokenCachingTablesInSqlDatabase() to create the database", ex);
57-
}
44+
_cacheDbRecord = GetLatestRecordQuery(cacheKey).FirstOrDefault();
5845
}
59-
else
46+
catch (SqlException ex) when (ex.Message == "Invalid object name 'Records'")
6047
{
61-
// retrieve last written record from the DB
62-
var lastwriteInDb = GetLatestRecordQuery(cacheKey).Select(n => n.LastWrite).FirstOrDefault();
63-
64-
// if the persisted copy is newer than the in-memory copy
65-
if (lastwriteInDb > _inMemoryCache.LastWrite)
66-
{
67-
// read from from storage, update in-memory copy
68-
_inMemoryCache = GetLatestRecordQuery(cacheKey).FirstOrDefault();
69-
}
48+
// Microsoft.Identity.Web changed from several tables (AppTokenCache, UserTokenCache) to one table (record)
49+
// If you care about the cache, you can migrate them, otherwise re-create the database
50+
throw new Exception("You need to migrate the AppTokenCache and UserTokenCache tables to Records, or run SqlTokenCacheProviderExtension.CreateTokenCachingTablesInSqlDatabase() to create the database", ex);
51+
}
52+
catch (SqlException ex) when (ex.Message.StartsWith("Cannot open database"))
53+
{
54+
throw new Exception("You need to run SqlTokenCacheProviderExtension.CreateTokenCachingTablesInSqlDatabase() to create the database", ex);
7055
}
7156

7257
// Send data to the TokenCache instance
73-
return (_inMemoryCache == null) ? null : _dataProtector.Unprotect(_inMemoryCache.CacheBits);
58+
return Task.FromResult((_cacheDbRecord == null) ? null : _dataProtector.Unprotect(_cacheDbRecord.CacheBits));
7459
}
7560

76-
protected override Task RemoveKeyAsync(string cacheKey)
61+
protected override async Task RemoveKeyAsync(string cacheKey)
7762
{
7863
var cacheEntries = _tokenCacheDb.Records.Where(c => c.CacheKey == cacheKey);
7964
_tokenCacheDb.Records.RemoveRange(cacheEntries);
80-
_tokenCacheDb.SaveChanges();
81-
return Task.CompletedTask;
65+
await _tokenCacheDb.SaveChangesAsync();
8266
}
8367

8468
protected override async Task WriteCacheBytesAsync(string cacheKey, byte[] bytes)
8569
{
86-
if (_inMemoryCache == null)
70+
if (_cacheDbRecord == null)
8771
{
88-
_inMemoryCache = new TokenCacheDbRecord
72+
_cacheDbRecord = new TokenCacheDbRecord
8973
{
9074
CacheKey = cacheKey
9175
};
9276
}
9377

94-
_inMemoryCache.CacheBits = _dataProtector.Protect(bytes);
95-
_inMemoryCache.LastWrite = DateTime.Now;
78+
_cacheDbRecord.CacheBits = _dataProtector.Protect(bytes);
79+
_cacheDbRecord.LastWrite = DateTime.Now;
9680

9781
try
9882
{
9983
// Update the DB and the lastwrite
100-
_tokenCacheDb.Entry(_inMemoryCache).State = _inMemoryCache.TokenCacheId == 0 ? EntityState.Added : EntityState.Modified;
84+
_tokenCacheDb.Entry(_cacheDbRecord).State = _cacheDbRecord.TokenCacheId == 0 ? EntityState.Added : EntityState.Modified;
10185
_tokenCacheDb.SaveChanges();
10286
}
10387
catch (DbUpdateConcurrencyException)
@@ -109,7 +93,7 @@ protected override async Task WriteCacheBytesAsync(string cacheKey, byte[] bytes
10993

11094
private IOrderedQueryable<TokenCacheDbRecord> GetLatestRecordQuery(string cacheKey)
11195
{
112-
return _tokenCacheDb.Records.Where(c => c.CacheKey == cacheKey).OrderByDescending(d => d.LastWrite);
96+
return _tokenCacheDb.Records.Where(c => c.CacheKey == cacheKey).OrderByDescending(d => d.LastWrite);
11397
}
11498
}
11599
}

Microsoft.Identity.Web/WebApiServiceCollectionExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ public static IServiceCollection AddProtectedApiCallsWebApis(
113113
this IServiceCollection services,
114114
IConfiguration configuration,
115115
IEnumerable<string> scopes = null,
116-
string configSectionName = "AzureAD")
116+
string configSectionName = "AzureAd")
117117
{
118118
services.AddTokenAcquisition();
119119
services.AddHttpContextAccessor();

0 commit comments

Comments
 (0)