-
Notifications
You must be signed in to change notification settings - Fork 218
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Lozensky/enable managed identity (#2650)
* Add logic to default to using managed identity if provided. * remove blank line * Updated with caching and new design * rearranging methods * made GetOrBuildManagedIdentityApplication async * added unit test for application caching * finished unit test first draft * minor changes * changed according to PR feedback * Add logic to default to using managed identity if provided. * remove blank line * Updated with caching and new design * rearranging methods * made GetOrBuildManagedIdentityApplication async * added unit test for application caching * finished unit test first draft * minor changes * changed according to PR feedback * Rebase onto main * added system-assigned managed identity e2e test * Implemented PR feedback * changing test to use user-assigned managed identity * fixing tests * Added configuration to e2e test * moved build to after identity options config * moving builder back * fixed bug with TokenAcquisitionOptions/DefaultAuthorizationHeaderProvider * simplified e2e test * added concurrency test and removed reflection * addressed PR comments and removed unnecessary code * removed extra space * addressed PR feedback * making changes per PR comments * removing test traces --------- Co-authored-by: Jean-Marc Prieur <jmprieur@microsoft.com>
- Loading branch information
1 parent
59ce6ad
commit 8909553
Showing
9 changed files
with
363 additions
and
45 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
114 changes: 114 additions & 0 deletions
114
src/Microsoft.Identity.Web.TokenAcquisition/TokenAcquisition.ManagedIdentity.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using System.Collections.Concurrent; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.Identity.Abstractions; | ||
using Microsoft.Identity.Client; | ||
using Microsoft.Identity.Client.AppConfig; | ||
using Microsoft.IdentityModel.Tokens; | ||
|
||
namespace Microsoft.Identity.Web | ||
{ | ||
/// <summary> | ||
/// Portion of the TokenAcquisition class that handles logic unique to managed identity. | ||
/// </summary> | ||
internal partial class TokenAcquisition | ||
{ | ||
private readonly ConcurrentDictionary<string, IManagedIdentityApplication> _managedIdentityApplicationsByClientId = new(); | ||
private readonly SemaphoreSlim _managedIdSemaphore = new(1, 1); | ||
private const string SystemAssignedManagedIdentityKey = "SYSTEM"; | ||
|
||
/// <summary> | ||
/// Gets a cached ManagedIdentityApplication object or builds a new one if not found. | ||
/// </summary> | ||
/// <param name="mergedOptions">The configuration options for the app.</param> | ||
/// <param name="managedIdentityOptions">The configuration specific to managed identity.</param> | ||
/// <returns>The application object used to request a token with managed identity.</returns> | ||
internal async Task<IManagedIdentityApplication> GetOrBuildManagedIdentityApplication( | ||
MergedOptions mergedOptions, | ||
ManagedIdentityOptions managedIdentityOptions) | ||
{ | ||
string key = GetCacheKeyForManagedId(managedIdentityOptions); | ||
|
||
// Check if the application is already built, if so return it without grabbing the lock | ||
if (_managedIdentityApplicationsByClientId.TryGetValue(key, out IManagedIdentityApplication? application)) | ||
{ | ||
return application; | ||
} | ||
|
||
// Lock the potential write of the dictionary to prevent multiple threads from creating the same application. | ||
await _managedIdSemaphore.WaitAsync(); | ||
try | ||
{ | ||
// Check if the application is already built (could happen between previous check and obtaining the key) | ||
if (_managedIdentityApplicationsByClientId.TryGetValue(key, out application)) | ||
{ | ||
return application; | ||
} | ||
|
||
// Set managedIdentityId to the correct value for either system or user assigned | ||
ManagedIdentityId managedIdentityId; | ||
if (key == SystemAssignedManagedIdentityKey) | ||
{ | ||
managedIdentityId = ManagedIdentityId.SystemAssigned; | ||
} | ||
else | ||
{ | ||
managedIdentityId = ManagedIdentityId.WithUserAssignedClientId(key); | ||
} | ||
|
||
// Build the application | ||
application = BuildManagedIdentityApplication( | ||
managedIdentityId, | ||
mergedOptions.ConfidentialClientApplicationOptions.EnablePiiLogging | ||
); | ||
|
||
// Add the application to the cache | ||
_managedIdentityApplicationsByClientId.TryAdd(key, application); | ||
} | ||
finally | ||
{ | ||
// Now that the dictionary is updated, release the semaphore | ||
_managedIdSemaphore.Release(); | ||
} | ||
return application; | ||
} | ||
|
||
/// <summary> | ||
/// Creates a managed identity client application. | ||
/// </summary> | ||
/// <param name="managedIdentityId">Indicates if system-assigned or user-assigned managed identity is used.</param> | ||
/// <param name="enablePiiLogging">Indicates if logging that may contain personally identifiable information is enabled.</param> | ||
/// <returns>A managed identity application.</returns> | ||
private IManagedIdentityApplication BuildManagedIdentityApplication(ManagedIdentityId managedIdentityId, bool enablePiiLogging) | ||
{ | ||
return ManagedIdentityApplicationBuilder | ||
.Create(managedIdentityId) | ||
.WithLogging( | ||
Log, | ||
ConvertMicrosoftExtensionsLogLevelToMsal(_logger), | ||
enablePiiLogging: enablePiiLogging) | ||
.Build(); | ||
} | ||
|
||
/// <summary> | ||
/// Gets the key value for the Managed Identity cache, the default key for system-assigned identity is used if there is | ||
/// no clientId for a user-assigned identity specified. The method is internal rather than private for testing purposes. | ||
/// </summary> | ||
/// <param name="managedIdOptions">Holds the clientId for managed identity if none is present.</param> | ||
/// <returns>A key value for the Managed Identity cache.</returns> | ||
internal static string GetCacheKeyForManagedId(ManagedIdentityOptions managedIdOptions) | ||
{ | ||
if (managedIdOptions.UserAssignedClientId.IsNullOrEmpty()) | ||
{ | ||
return SystemAssignedManagedIdentityKey; | ||
} | ||
else | ||
{ | ||
return managedIdOptions.UserAssignedClientId!; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
20
tests/E2E Tests/TokenAcquirerTests/OnlyOnAzureDevopsFactAttribute.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using System; | ||
using Xunit; | ||
|
||
namespace TokenAcquirerTests | ||
{ | ||
public sealed class OnlyOnAzureDevopsFactAttribute : FactAttribute | ||
{ | ||
public OnlyOnAzureDevopsFactAttribute() | ||
{ | ||
if (IgnoreOnAzureDevopsFactAttribute.IsRunningOnAzureDevOps()) | ||
{ | ||
return; | ||
} | ||
Skip = "Ignored when not on Azure DevOps"; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.