Skip to content
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

[Feature Request] Encryption strategy for Distributed token cache #1044

Closed
jmprieur opened this issue Mar 4, 2021 · 3 comments
Closed

[Feature Request] Encryption strategy for Distributed token cache #1044

jmprieur opened this issue Mar 4, 2021 · 3 comments
Assignees
Labels
enhancement New feature or request

Comments

@jmprieur
Copy link
Collaborator

jmprieur commented Mar 4, 2021

Is your feature request related to a problem? Please describe.
Today the distributed token cache does not encrypt the blob for caches.

Describe the solution you'd like
Provide an optional way to enable apps developer to provide/choose an encryption strategy

@jmprieur jmprieur added the enhancement New feature or request label Mar 4, 2021
@jmprieur jmprieur added this to the 1.9.0 milestone Mar 4, 2021
@jmprieur jmprieur modified the milestones: 1.9.0, 1.10.0 Mar 10, 2021
@jmprieur jmprieur modified the milestones: 1.10.0, 1.11.0 Apr 22, 2021
@jmprieur jmprieur modified the milestones: 1.11.0, 1.12.0 May 6, 2021
@jennyf19 jennyf19 modified the milestones: 1.12.0, 1.13.0 May 28, 2021
@jmprieur
Copy link
Collaborator Author

One possibility: https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/introduction

Configuration: https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/overview?view=aspnetcore-5.0

for instance:

   // In startup.cs / or when adding cache
   services.AddDataProtection() 
      .PersistKeysToAzureBlobStorage(dataProtectionConnectionString, dataProtectionContainerName, dataProtectionKeyFile)                
      .ProtectKeysWithAzureKeyVault(new Uri(dataProtectionKeyKeyUri), cred)                
      .SetApplicationName(AuthenticationConstants.ApplicationName);

    // In the controller etc ...
    var dataProtectionProvider = serviceProvider.GetService<IDataProtectionProvider>

@jennyf19 jennyf19 removed this from the 1.13.0 milestone Jun 11, 2021
@jmprieur
Copy link
Collaborator Author

jmprieur commented Jul 16, 2021

Proposed experience.

ASP.NET Core

ASP.NET Core developers who want to benefit from cache encryption will add a few lines in their startup.cs:

  services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
               .AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"))
                 .EnableTokenAcquisitionToCallDownstreamApi()
                   .AddMicrosoftGraph(Configuration.GetSection("GraphBeta"))
                   .AddDownstreamWebApi("GraphBeta", Configuration.GetSection("GraphBeta"))
                   .AddDistributedTokenCache();

  services.AddDistributedMemoryCache();
  services.Configure<MsalDistributedTokenCacheAdapterOptions>(o =>
  {
   o.Encrypt = true;
  });
 });

It's also possible to control the data protector:

   services.AddDataProtection() 
      .PersistKeysToAzureBlobStorage(
          dataProtectionConnectionString, 
          dataProtectionContainerName, 
          dataProtectionKeyFile)            
      .ProtectKeysWithAzureKeyVault(new Uri(dataProtectionKeyKeyUri), cred)                
      .SetApplicationName(AuthenticationConstants.ApplicationName);

ASP.NET classic or .NET or .NET Core

 clientapp = ConfidentialClientApplicationBuilder.Create(AuthenticationConfig.ClientId)
                      .WithClientSecret(AuthenticationConfig.ClientSecret)
                      .WithRedirectUri(AuthenticationConfig.RedirectUri)
                      .WithAuthority(new Uri(AuthenticationConfig.Authority))
                      .Build();

 clientapp.AddDistributedTokenCache(services =>
 {
   services.AddDistributedMemoryCache();
   services.Configure<MsalDistributedTokenCacheAdapterOptions>(o =>
   {
     o.Encrypt = true;
   });
 });

Proposed design:

  • Inject IServiceProvider in the MsalAbstractTokenCacheProvider constructor. Have a null default value to avoid a breaking change in existing token caches deriving from MsalAbstractTokenCacheProvider and not provided by us

  • Add a member dataProtectionProvider of type IDataProtectionProvider computed from the service provider argument when it's not null

  • Before writing, if dataProtectionProvider is not null, encrypt the cache

    await WriteCacheBytesAsync(args.SuggestedCacheKey, args.TokenCache.SerializeMsalV3(), cacheSerializerHints).ConfigureAwait(false);

  • After reading, if dataProtectionProvider is not null, decrypt the cache.

  • Inject a IServiceProvider in the constructor of all the classes derived from MsalAbstractTokenCacheProvider, and that would call the new constructor of MsalAbstractTokenCacheProvider.

Questions

  • do we want to use IDataProtectionProvider or our own interface? (and in which case do we provide a default implementation that uses the IDataProtectionProvider ?

@jennyf19
Copy link
Collaborator

Included in 1.15 release

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants