From e56097721e1aa45fc526d69ead47d419f05f0f3e Mon Sep 17 00:00:00 2001 From: Josh Lozensky Date: Wed, 22 Nov 2023 14:34:13 -0800 Subject: [PATCH 1/7] Adding ManagedIdentityOptions to support Entra Managed Identity --- .../CredentialDescription.cs | 6 +- .../ManagedIdentity/ManagedIdentityOptions.cs | 66 ++++++++++++++++ .../ManagedIdentity/ManagedIdentityType.cs | 23 ++++++ .../TokenAcquisition/AcquireTokenOptions.cs | 37 ++++++++- .../AquireTokenOptionsTests.cs | 78 +++++++++++++++++++ .../DownstreamApiTests.cs | 4 +- .../ManagedIdentityDescriptionTests.cs | 26 +++++++ 7 files changed, 235 insertions(+), 5 deletions(-) create mode 100644 src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityOptions.cs create mode 100644 src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityType.cs create mode 100644 test/Microsoft.Identity.Abstractions.Tests/AquireTokenOptionsTests.cs create mode 100644 test/Microsoft.Identity.Abstractions.Tests/ManagedIdentityDescriptionTests.cs diff --git a/src/Microsoft.Identity.Abstractions/ApplicationOptions/CredentialDescription.cs b/src/Microsoft.Identity.Abstractions/ApplicationOptions/CredentialDescription.cs index 5d8f68d..8775306 100644 --- a/src/Microsoft.Identity.Abstractions/ApplicationOptions/CredentialDescription.cs +++ b/src/Microsoft.Identity.Abstractions/ApplicationOptions/CredentialDescription.cs @@ -67,7 +67,7 @@ public string? Container CredentialSource.StoreWithThumbprint or CredentialSource.StoreWithDistinguishedName => CertificateStorePath, CredentialSource.SignedAssertionFilePath => SignedAssertionFileDiskPath, CredentialSource.SignedAssertionFromVault => KeyVaultUrl, - _ => null, + _ => null }; } set @@ -257,8 +257,8 @@ public string? Container public string? ClientSecret { get; set; } /// - /// When is , specifies the client ID of the Azure user-assigned managed identity - /// used to provide an signed assertion that will be used as a client credential for the application. This requires that the application is deployed on Azure, that the managed identity is configured, + /// When is , it specifies the client ID of the Azure user-assigned managed identity + /// used to provide a signed assertion to act as a client credential for the application. This requires that the application is deployed on Azure, that the managed identity is configured, /// and that workload identity federation with the managed identity is declared in the application registration. For details, see https://learn.microsoft.com/azure/active-directory/workload-identities/workload-identity-federation. /// /// diff --git a/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityOptions.cs b/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityOptions.cs new file mode 100644 index 0000000..784bd58 --- /dev/null +++ b/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityOptions.cs @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.ComponentModel; + +namespace Microsoft.Identity.Abstractions +{ + /// + /// Data object to hold the definition of a managed identity for an application to use for authentication.

+ /// See for more details. + ///
+ public class ManagedIdentityOptions + { + /// + /// Gets or sets whether the is system-assigned or user assigned. + /// Defaults to if not set.

+ /// See for details on these two types of managed identity. + ///
+ [DefaultValue(ManagedIdentityType.SystemAssigned)] + public ManagedIdentityType ManagedIdentityType { get; set; } + + /// + /// Gets or sets the value of the client id when is set to + /// .
If not set, the default value is null. + ///
+ public string? ClientId { get; set; } + + /// + /// Ensures a clone of this object will not have the same reference. + /// + /// A new instance of with the same field values. + public ManagedIdentityOptions Clone() + { + return new ManagedIdentityOptions + { + ManagedIdentityType = this.ManagedIdentityType, + ClientId = this.ClientId + }; + } + + /// + /// Ensures any object is equal if all fields hold the same values. + /// + /// + /// + public override bool Equals(object obj) + { + if (obj == null || GetType() != obj.GetType()) + { + return false; + } + ManagedIdentityOptions other = (ManagedIdentityOptions)obj; + return ManagedIdentityType == other.ManagedIdentityType && + ClientId == other.ClientId; + } + + /// + /// Returns the hash code for the instance based on the values of its fields. + /// + /// A 32-bit signed integer hash code. + public override int GetHashCode() + { + return new { ManagedIdentityType, ClientId }.GetHashCode(); + } + } +} diff --git a/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityType.cs b/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityType.cs new file mode 100644 index 0000000..d405259 --- /dev/null +++ b/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityType.cs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Identity.Abstractions +{ + /// + /// Used by to specify the type of managed identity to use.

+ /// See for more details. + ///
+ public enum ManagedIdentityType + { + /// + /// The default value, indicating the managed identity to use is the one configured for the Azure resource on which the + /// application is running. + /// + SystemAssigned = 0, + + /// + /// Indicates the managed identity to use is a user-assigned identity which is defined in a standalone Azure resource. + /// + UserAssigned = 1, + } +} diff --git a/src/Microsoft.Identity.Abstractions/TokenAcquisition/AcquireTokenOptions.cs b/src/Microsoft.Identity.Abstractions/TokenAcquisition/AcquireTokenOptions.cs index 7e0588b..199e308 100644 --- a/src/Microsoft.Identity.Abstractions/TokenAcquisition/AcquireTokenOptions.cs +++ b/src/Microsoft.Identity.Abstractions/TokenAcquisition/AcquireTokenOptions.cs @@ -34,6 +34,7 @@ public AcquireTokenOptions(AcquireTokenOptions other) Claims = other.Claims; PopPublicKey = other.PopPublicKey; PopClaim = other.PopClaim; + ManagedIdentity = other.ManagedIdentity?.Clone(); LongRunningWebApiSessionKey = other.LongRunningWebApiSessionKey; Tenant = other.Tenant; UserFlow = other.UserFlow; @@ -64,7 +65,8 @@ public AcquireTokenOptions(AcquireTokenOptions other) /// A string with one or multiple claims to request. It's a json blob (encoded or not) /// Normally used with Conditional Access. It receives the Claims member of the UiRequiredException. /// It can also be used to request specific optional claims, and for - /// CA Auth context + /// + /// CA Auth context /// public string? Claims { get; set; } @@ -90,6 +92,39 @@ public AcquireTokenOptions(AcquireTokenOptions other) /// public string? PopClaim { get; set; } + /// + /// When is set, the application uses a managed identity instead of client credentials to + /// acquire an app token.

+ /// + /// The type of managed identity is defined by the field. When + /// using a identity, this is the only field that needs to be set and is + /// set by default. However, for readability it can be useful to set explicitly

+ /// + /// To use a user-assigned identity, select the that corresponds to the + /// you plan to use for authentication.

+ /// + /// Using either form of managed identity requires the application to be deployed on Azure and + /// the managed identity to be configured. For more details, check the + /// managed identities for Azure documentation. + ///
+ /// + /// + /// + /// + public ManagedIdentityOptions? ManagedIdentity { get; set; } + /// /// Key used for long running web APIs that need to call downstream web /// APIs on behalf of the user. Can be null, if you are not developing a long diff --git a/test/Microsoft.Identity.Abstractions.Tests/AquireTokenOptionsTests.cs b/test/Microsoft.Identity.Abstractions.Tests/AquireTokenOptionsTests.cs new file mode 100644 index 0000000..6a9291e --- /dev/null +++ b/test/Microsoft.Identity.Abstractions.Tests/AquireTokenOptionsTests.cs @@ -0,0 +1,78 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Xunit; + +namespace Microsoft.Identity.Abstractions.Tests +{ + public class AquireTokenOptionsTests + { + [Fact] + public void ManagedIdentitySystemAssigned() + { + // App token from a system-assigned managed identity. + // ------------------------------------------------- + // https://aka.ms/Entra/ManagedIdentityOverview + /* + // + { + "AquireTokenOptions": { + "ManagedIdentity": { + "ManagedIdentityType": "SystemAssigned" + } + } + } + // + */ + + // + AcquireTokenOptions acquireTokenOptions = new AcquireTokenOptions + { + ManagedIdentity = new ManagedIdentityOptions() + { + // default: ManagedIdentityType = ManagedIdentityType.SystemAssigned + } + }; + // + + Assert.Equal(ManagedIdentityType.SystemAssigned, acquireTokenOptions.ManagedIdentity.ManagedIdentityType); + Assert.Null(acquireTokenOptions.ManagedIdentity.ClientId); + } + + [Fact] + public void ManagedIdentityUserAssigned() + { + // App token from a user-assigned managed identity. + // ------------------------------------------------- + // https://aka.ms/Entra/ManagedIdentityOverview + /* + // + { + "AquireTokenOptions": { + "ManagedIdentity": { + "ManagedIdentityType": "UserAssigned" + "ClientId": "[ClientIdForTheManagedIdentityResource]" + } + } + } + // + */ + + // + ManagedIdentityOptions managedIdentityDescription = new ManagedIdentityOptions + { + ManagedIdentityType = ManagedIdentityType.UserAssigned, + ClientId = "[ClientIdForTheManagedIdentityResource]" + }; + + AcquireTokenOptions acquireTokenOptions = new AcquireTokenOptions + { + ManagedIdentity = managedIdentityDescription + }; + // + + Assert.Equal(ManagedIdentityType.UserAssigned, acquireTokenOptions.ManagedIdentity.ManagedIdentityType); + Assert.Equal(managedIdentityDescription.ClientId, acquireTokenOptions.ManagedIdentity.ClientId); + } + } +} diff --git a/test/Microsoft.Identity.Abstractions.Tests/DownstreamApiTests.cs b/test/Microsoft.Identity.Abstractions.Tests/DownstreamApiTests.cs index 378b200..48434b6 100644 --- a/test/Microsoft.Identity.Abstractions.Tests/DownstreamApiTests.cs +++ b/test/Microsoft.Identity.Abstractions.Tests/DownstreamApiTests.cs @@ -27,6 +27,7 @@ public void CloneClonesAllProperties() ExtraQueryParameters = new Dictionary { { "slice", "test" } }, ForceRefresh = true, LongRunningWebApiSessionKey = AcquireTokenOptions.LongRunningWebApiSessionKeyAuto, + ManagedIdentity = new ManagedIdentityOptions(), PopPublicKey = "PopKey", PopClaim = "jwkClaim", Tenant = "domain.com", @@ -75,6 +76,7 @@ public void CloneClonesAllProperties() Assert.Equal(downstreamApiOptions.AcquireTokenOptions.ExtraQueryParameters, downstreamApiClone.AcquireTokenOptions.ExtraQueryParameters); Assert.Equal(downstreamApiOptions.AcquireTokenOptions.ForceRefresh, downstreamApiClone.AcquireTokenOptions.ForceRefresh); Assert.Equal(downstreamApiOptions.AcquireTokenOptions.LongRunningWebApiSessionKey, downstreamApiClone.AcquireTokenOptions.LongRunningWebApiSessionKey); + Assert.Equal(downstreamApiOptions.AcquireTokenOptions.ManagedIdentity, downstreamApiClone.AcquireTokenOptions.ManagedIdentity); Assert.Equal(downstreamApiOptions.AcquireTokenOptions.PopPublicKey, downstreamApiClone.AcquireTokenOptions.PopPublicKey); Assert.Equal(downstreamApiOptions.AcquireTokenOptions.PopClaim, downstreamApiClone.AcquireTokenOptions.PopClaim); Assert.Equal(downstreamApiOptions.AcquireTokenOptions.Tenant, downstreamApiClone.AcquireTokenOptions.Tenant); @@ -82,7 +84,7 @@ public void CloneClonesAllProperties() // If this fails, think of also adding a line to test the new property Assert.Equal(10, typeof(DownstreamApiOptions).GetProperties().Length); - Assert.Equal(12, typeof(AcquireTokenOptions).GetProperties().Length); + Assert.Equal(13, typeof(AcquireTokenOptions).GetProperties().Length); DownstreamApiOptionsReadOnlyHttpMethod options = new DownstreamApiOptionsReadOnlyHttpMethod(downstreamApiOptions, HttpMethod.Delete.ToString()); Assert.Equal(HttpMethod.Delete.ToString(), options.HttpMethod); diff --git a/test/Microsoft.Identity.Abstractions.Tests/ManagedIdentityDescriptionTests.cs b/test/Microsoft.Identity.Abstractions.Tests/ManagedIdentityDescriptionTests.cs new file mode 100644 index 0000000..0b9ed05 --- /dev/null +++ b/test/Microsoft.Identity.Abstractions.Tests/ManagedIdentityDescriptionTests.cs @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Xunit; + +namespace Microsoft.Identity.Abstractions.Tests +{ + public class ManagedIdentityDescriptionTests + { + /// + /// If no field is set for the + /// field needs to default to as other Microsoft.Identity libraries + /// will depend on this. + /// + [Fact] + public void ManagedIdentity_NoDescriptionFieldsSet() + { + // Arrange + ManagedIdentityOptions description = new(); + + // Assert + Assert.Equal(ManagedIdentityType.SystemAssigned, description.ManagedIdentityType); + Assert.Null(description.ClientId); + } + } +} From d83afd23b80d3431862063689ad08b37f3cdcb7a Mon Sep 17 00:00:00 2001 From: Josh Lozensky Date: Fri, 1 Dec 2023 14:16:08 -0800 Subject: [PATCH 2/7] removed equals and gethashcode --- .../ManagedIdentity/ManagedIdentityOptions.cs | 29 ++----------------- .../DownstreamApiTests.cs | 5 ++-- 2 files changed, 5 insertions(+), 29 deletions(-) diff --git a/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityOptions.cs b/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityOptions.cs index 784bd58..d6c8a83 100644 --- a/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityOptions.cs +++ b/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityOptions.cs @@ -33,34 +33,9 @@ public ManagedIdentityOptions Clone() { return new ManagedIdentityOptions { - ManagedIdentityType = this.ManagedIdentityType, - ClientId = this.ClientId + ManagedIdentityType = ManagedIdentityType, + ClientId = ClientId }; } - - /// - /// Ensures any object is equal if all fields hold the same values. - /// - /// - /// - public override bool Equals(object obj) - { - if (obj == null || GetType() != obj.GetType()) - { - return false; - } - ManagedIdentityOptions other = (ManagedIdentityOptions)obj; - return ManagedIdentityType == other.ManagedIdentityType && - ClientId == other.ClientId; - } - - /// - /// Returns the hash code for the instance based on the values of its fields. - /// - /// A 32-bit signed integer hash code. - public override int GetHashCode() - { - return new { ManagedIdentityType, ClientId }.GetHashCode(); - } } } diff --git a/test/Microsoft.Identity.Abstractions.Tests/DownstreamApiTests.cs b/test/Microsoft.Identity.Abstractions.Tests/DownstreamApiTests.cs index 48434b6..83dc124 100644 --- a/test/Microsoft.Identity.Abstractions.Tests/DownstreamApiTests.cs +++ b/test/Microsoft.Identity.Abstractions.Tests/DownstreamApiTests.cs @@ -76,7 +76,8 @@ public void CloneClonesAllProperties() Assert.Equal(downstreamApiOptions.AcquireTokenOptions.ExtraQueryParameters, downstreamApiClone.AcquireTokenOptions.ExtraQueryParameters); Assert.Equal(downstreamApiOptions.AcquireTokenOptions.ForceRefresh, downstreamApiClone.AcquireTokenOptions.ForceRefresh); Assert.Equal(downstreamApiOptions.AcquireTokenOptions.LongRunningWebApiSessionKey, downstreamApiClone.AcquireTokenOptions.LongRunningWebApiSessionKey); - Assert.Equal(downstreamApiOptions.AcquireTokenOptions.ManagedIdentity, downstreamApiClone.AcquireTokenOptions.ManagedIdentity); + Assert.Equal(downstreamApiOptions.AcquireTokenOptions.ManagedIdentity.ManagedIdentityType, downstreamApiClone.AcquireTokenOptions.ManagedIdentity.ManagedIdentityType); + Assert.Equal(downstreamApiOptions.AcquireTokenOptions.ManagedIdentity.ClientId, downstreamApiClone.AcquireTokenOptions.ManagedIdentity.ClientId); Assert.Equal(downstreamApiOptions.AcquireTokenOptions.PopPublicKey, downstreamApiClone.AcquireTokenOptions.PopPublicKey); Assert.Equal(downstreamApiOptions.AcquireTokenOptions.PopClaim, downstreamApiClone.AcquireTokenOptions.PopClaim); Assert.Equal(downstreamApiOptions.AcquireTokenOptions.Tenant, downstreamApiClone.AcquireTokenOptions.Tenant); @@ -154,4 +155,4 @@ public CustomAcquireTokenOptions() : base() { } public CustomAcquireTokenOptions(CustomAcquireTokenOptions other) : base(other) { } } -} \ No newline at end of file +} From bb8bb341333ed611eac4fa744e1c4e1198ed2d7e Mon Sep 17 00:00:00 2001 From: Josh Lozensky Date: Mon, 4 Dec 2023 14:40:31 -0800 Subject: [PATCH 3/7] Minor documentation changes --- .../IdentityApplicationOptions.cs | 2 +- .../ManagedIdentity/ManagedIdentityOptions.cs | 10 +++++----- .../ManagedIdentity/ManagedIdentityType.cs | 2 +- .../TokenAcquisition/AcquireTokenOptions.cs | 13 +++++-------- .../DownstreamApiTests.cs | 4 ++-- 5 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/Microsoft.Identity.Abstractions/ApplicationOptions/IdentityApplicationOptions.cs b/src/Microsoft.Identity.Abstractions/ApplicationOptions/IdentityApplicationOptions.cs index 13a54a5..58308ee 100644 --- a/src/Microsoft.Identity.Abstractions/ApplicationOptions/IdentityApplicationOptions.cs +++ b/src/Microsoft.Identity.Abstractions/ApplicationOptions/IdentityApplicationOptions.cs @@ -99,7 +99,7 @@ public class IdentityApplicationOptions /// /// In a web API, accepted audiences for the tokens received by the web API. /// See also . - /// The audience is the intended recipient of the token. You can usually assume that the ApplicationId of your web API + /// The audience is the intended recipient of the token. You can usually assume that the ApplicationID of your web API /// is a valid audience. It can, in general be any of the App ID URIs (or resource identitfier) you defined for your application /// during its registration in the Azure portal. /// diff --git a/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityOptions.cs b/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityOptions.cs index d6c8a83..cc8cc7c 100644 --- a/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityOptions.cs +++ b/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityOptions.cs @@ -6,27 +6,27 @@ namespace Microsoft.Identity.Abstractions { /// - /// Data object to hold the definition of a managed identity for an application to use for authentication.

+ /// Data object to hold the definition of a managed identity for an application to use for authentication. /// See for more details. ///
public class ManagedIdentityOptions { /// /// Gets or sets whether the is system-assigned or user assigned. - /// Defaults to if not set.

+ /// Defaults to if not set. /// See for details on these two types of managed identity. ///
[DefaultValue(ManagedIdentityType.SystemAssigned)] public ManagedIdentityType ManagedIdentityType { get; set; } /// - /// Gets or sets the value of the client id when is set to - /// .
If not set, the default value is null. + /// Gets or sets the value of the ClientID when is set to + /// . If not set, the default value is null. ///
public string? ClientId { get; set; } /// - /// Ensures a clone of this object will not have the same reference. + /// Makes a new object to avoid sharing the same reference. /// /// A new instance of with the same field values. public ManagedIdentityOptions Clone() diff --git a/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityType.cs b/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityType.cs index d405259..9a87b00 100644 --- a/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityType.cs +++ b/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityType.cs @@ -4,7 +4,7 @@ namespace Microsoft.Identity.Abstractions { /// - /// Used by to specify the type of managed identity to use.

+ /// Used by to specify the type of managed identity to use. /// See for more details. ///
public enum ManagedIdentityType diff --git a/src/Microsoft.Identity.Abstractions/TokenAcquisition/AcquireTokenOptions.cs b/src/Microsoft.Identity.Abstractions/TokenAcquisition/AcquireTokenOptions.cs index 199e308..38b88e7 100644 --- a/src/Microsoft.Identity.Abstractions/TokenAcquisition/AcquireTokenOptions.cs +++ b/src/Microsoft.Identity.Abstractions/TokenAcquisition/AcquireTokenOptions.cs @@ -41,14 +41,14 @@ public AcquireTokenOptions(AcquireTokenOptions other) } /// - /// Gets the name of the options describing the confidential client application (ClientId, + /// Gets the name of the options describing the confidential client application (ClientID, /// Region, Authority, client credentials). In ASP.NET Core, the authenticatiopn options name /// is the same as the authentication scheme. /// public string? AuthenticationOptionsName { get; set; } /// - /// Sets the correlation id to be used in the request to the STS "/token" endpoint. + /// Sets the correlation ID to be used in the request to the STS "/token" endpoint. /// public Guid? CorrelationId { get; set; } @@ -94,15 +94,12 @@ public AcquireTokenOptions(AcquireTokenOptions other) /// /// When is set, the application uses a managed identity instead of client credentials to - /// acquire an app token.

- /// + /// acquire an app token. /// The type of managed identity is defined by the field. When /// using a identity, this is the only field that needs to be set and is - /// set by default. However, for readability it can be useful to set explicitly

- /// + /// set by default. However, for readability it can be useful to set explicitly. /// To use a user-assigned identity, select the that corresponds to the - /// you plan to use for authentication.

- /// + /// you plan to use for authentication. /// Using either form of managed identity requires the application to be deployed on Azure and /// the managed identity to be configured. For more details, check the /// managed identities for Azure documentation. diff --git a/test/Microsoft.Identity.Abstractions.Tests/DownstreamApiTests.cs b/test/Microsoft.Identity.Abstractions.Tests/DownstreamApiTests.cs index 83dc124..218adc7 100644 --- a/test/Microsoft.Identity.Abstractions.Tests/DownstreamApiTests.cs +++ b/test/Microsoft.Identity.Abstractions.Tests/DownstreamApiTests.cs @@ -76,8 +76,8 @@ public void CloneClonesAllProperties() Assert.Equal(downstreamApiOptions.AcquireTokenOptions.ExtraQueryParameters, downstreamApiClone.AcquireTokenOptions.ExtraQueryParameters); Assert.Equal(downstreamApiOptions.AcquireTokenOptions.ForceRefresh, downstreamApiClone.AcquireTokenOptions.ForceRefresh); Assert.Equal(downstreamApiOptions.AcquireTokenOptions.LongRunningWebApiSessionKey, downstreamApiClone.AcquireTokenOptions.LongRunningWebApiSessionKey); - Assert.Equal(downstreamApiOptions.AcquireTokenOptions.ManagedIdentity.ManagedIdentityType, downstreamApiClone.AcquireTokenOptions.ManagedIdentity.ManagedIdentityType); - Assert.Equal(downstreamApiOptions.AcquireTokenOptions.ManagedIdentity.ClientId, downstreamApiClone.AcquireTokenOptions.ManagedIdentity.ClientId); + Assert.Equal(downstreamApiOptions.AcquireTokenOptions.ManagedIdentity.ManagedIdentityType, downstreamApiClone.AcquireTokenOptions.ManagedIdentity?.ManagedIdentityType); + Assert.Equal(downstreamApiOptions.AcquireTokenOptions.ManagedIdentity.ClientId, downstreamApiClone.AcquireTokenOptions.ManagedIdentity?.ClientId); Assert.Equal(downstreamApiOptions.AcquireTokenOptions.PopPublicKey, downstreamApiClone.AcquireTokenOptions.PopPublicKey); Assert.Equal(downstreamApiOptions.AcquireTokenOptions.PopClaim, downstreamApiClone.AcquireTokenOptions.PopClaim); Assert.Equal(downstreamApiOptions.AcquireTokenOptions.Tenant, downstreamApiClone.AcquireTokenOptions.Tenant); From 8fc27ddeb45e4525c4dad410693b9b6a2c7091d0 Mon Sep 17 00:00:00 2001 From: Josh Lozensky Date: Wed, 22 Nov 2023 14:34:13 -0800 Subject: [PATCH 4/7] Adding ManagedIdentityOptions to support Entra Managed Identity --- .../CredentialDescription.cs | 6 +- .../ManagedIdentity/ManagedIdentityOptions.cs | 66 ++++++++++++++++ .../ManagedIdentity/ManagedIdentityType.cs | 23 ++++++ .../TokenAcquisition/AcquireTokenOptions.cs | 37 ++++++++- .../AquireTokenOptionsTests.cs | 78 +++++++++++++++++++ .../DownstreamApiTests.cs | 4 +- .../ManagedIdentityDescriptionTests.cs | 26 +++++++ 7 files changed, 235 insertions(+), 5 deletions(-) create mode 100644 src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityOptions.cs create mode 100644 src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityType.cs create mode 100644 test/Microsoft.Identity.Abstractions.Tests/AquireTokenOptionsTests.cs create mode 100644 test/Microsoft.Identity.Abstractions.Tests/ManagedIdentityDescriptionTests.cs diff --git a/src/Microsoft.Identity.Abstractions/ApplicationOptions/CredentialDescription.cs b/src/Microsoft.Identity.Abstractions/ApplicationOptions/CredentialDescription.cs index 5d8f68d..8775306 100644 --- a/src/Microsoft.Identity.Abstractions/ApplicationOptions/CredentialDescription.cs +++ b/src/Microsoft.Identity.Abstractions/ApplicationOptions/CredentialDescription.cs @@ -67,7 +67,7 @@ public string? Container CredentialSource.StoreWithThumbprint or CredentialSource.StoreWithDistinguishedName => CertificateStorePath, CredentialSource.SignedAssertionFilePath => SignedAssertionFileDiskPath, CredentialSource.SignedAssertionFromVault => KeyVaultUrl, - _ => null, + _ => null }; } set @@ -257,8 +257,8 @@ public string? Container public string? ClientSecret { get; set; } /// - /// When is , specifies the client ID of the Azure user-assigned managed identity - /// used to provide an signed assertion that will be used as a client credential for the application. This requires that the application is deployed on Azure, that the managed identity is configured, + /// When is , it specifies the client ID of the Azure user-assigned managed identity + /// used to provide a signed assertion to act as a client credential for the application. This requires that the application is deployed on Azure, that the managed identity is configured, /// and that workload identity federation with the managed identity is declared in the application registration. For details, see https://learn.microsoft.com/azure/active-directory/workload-identities/workload-identity-federation. /// /// diff --git a/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityOptions.cs b/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityOptions.cs new file mode 100644 index 0000000..784bd58 --- /dev/null +++ b/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityOptions.cs @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.ComponentModel; + +namespace Microsoft.Identity.Abstractions +{ + /// + /// Data object to hold the definition of a managed identity for an application to use for authentication.

+ /// See for more details. + ///
+ public class ManagedIdentityOptions + { + /// + /// Gets or sets whether the is system-assigned or user assigned. + /// Defaults to if not set.

+ /// See for details on these two types of managed identity. + ///
+ [DefaultValue(ManagedIdentityType.SystemAssigned)] + public ManagedIdentityType ManagedIdentityType { get; set; } + + /// + /// Gets or sets the value of the client id when is set to + /// .
If not set, the default value is null. + ///
+ public string? ClientId { get; set; } + + /// + /// Ensures a clone of this object will not have the same reference. + /// + /// A new instance of with the same field values. + public ManagedIdentityOptions Clone() + { + return new ManagedIdentityOptions + { + ManagedIdentityType = this.ManagedIdentityType, + ClientId = this.ClientId + }; + } + + /// + /// Ensures any object is equal if all fields hold the same values. + /// + /// + /// + public override bool Equals(object obj) + { + if (obj == null || GetType() != obj.GetType()) + { + return false; + } + ManagedIdentityOptions other = (ManagedIdentityOptions)obj; + return ManagedIdentityType == other.ManagedIdentityType && + ClientId == other.ClientId; + } + + /// + /// Returns the hash code for the instance based on the values of its fields. + /// + /// A 32-bit signed integer hash code. + public override int GetHashCode() + { + return new { ManagedIdentityType, ClientId }.GetHashCode(); + } + } +} diff --git a/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityType.cs b/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityType.cs new file mode 100644 index 0000000..d405259 --- /dev/null +++ b/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityType.cs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Microsoft.Identity.Abstractions +{ + /// + /// Used by to specify the type of managed identity to use.

+ /// See for more details. + ///
+ public enum ManagedIdentityType + { + /// + /// The default value, indicating the managed identity to use is the one configured for the Azure resource on which the + /// application is running. + /// + SystemAssigned = 0, + + /// + /// Indicates the managed identity to use is a user-assigned identity which is defined in a standalone Azure resource. + /// + UserAssigned = 1, + } +} diff --git a/src/Microsoft.Identity.Abstractions/TokenAcquisition/AcquireTokenOptions.cs b/src/Microsoft.Identity.Abstractions/TokenAcquisition/AcquireTokenOptions.cs index 7e0588b..199e308 100644 --- a/src/Microsoft.Identity.Abstractions/TokenAcquisition/AcquireTokenOptions.cs +++ b/src/Microsoft.Identity.Abstractions/TokenAcquisition/AcquireTokenOptions.cs @@ -34,6 +34,7 @@ public AcquireTokenOptions(AcquireTokenOptions other) Claims = other.Claims; PopPublicKey = other.PopPublicKey; PopClaim = other.PopClaim; + ManagedIdentity = other.ManagedIdentity?.Clone(); LongRunningWebApiSessionKey = other.LongRunningWebApiSessionKey; Tenant = other.Tenant; UserFlow = other.UserFlow; @@ -64,7 +65,8 @@ public AcquireTokenOptions(AcquireTokenOptions other) /// A string with one or multiple claims to request. It's a json blob (encoded or not) /// Normally used with Conditional Access. It receives the Claims member of the UiRequiredException. /// It can also be used to request specific optional claims, and for - /// CA Auth context + /// + /// CA Auth context ///
public string? Claims { get; set; } @@ -90,6 +92,39 @@ public AcquireTokenOptions(AcquireTokenOptions other) ///
public string? PopClaim { get; set; } + /// + /// When is set, the application uses a managed identity instead of client credentials to + /// acquire an app token.

+ /// + /// The type of managed identity is defined by the field. When + /// using a identity, this is the only field that needs to be set and is + /// set by default. However, for readability it can be useful to set explicitly

+ /// + /// To use a user-assigned identity, select the that corresponds to the + /// you plan to use for authentication.

+ /// + /// Using either form of managed identity requires the application to be deployed on Azure and + /// the managed identity to be configured. For more details, check the + /// managed identities for Azure documentation. + ///
+ /// + /// + /// + /// + public ManagedIdentityOptions? ManagedIdentity { get; set; } + /// /// Key used for long running web APIs that need to call downstream web /// APIs on behalf of the user. Can be null, if you are not developing a long diff --git a/test/Microsoft.Identity.Abstractions.Tests/AquireTokenOptionsTests.cs b/test/Microsoft.Identity.Abstractions.Tests/AquireTokenOptionsTests.cs new file mode 100644 index 0000000..6a9291e --- /dev/null +++ b/test/Microsoft.Identity.Abstractions.Tests/AquireTokenOptionsTests.cs @@ -0,0 +1,78 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Xunit; + +namespace Microsoft.Identity.Abstractions.Tests +{ + public class AquireTokenOptionsTests + { + [Fact] + public void ManagedIdentitySystemAssigned() + { + // App token from a system-assigned managed identity. + // ------------------------------------------------- + // https://aka.ms/Entra/ManagedIdentityOverview + /* + // + { + "AquireTokenOptions": { + "ManagedIdentity": { + "ManagedIdentityType": "SystemAssigned" + } + } + } + // + */ + + // + AcquireTokenOptions acquireTokenOptions = new AcquireTokenOptions + { + ManagedIdentity = new ManagedIdentityOptions() + { + // default: ManagedIdentityType = ManagedIdentityType.SystemAssigned + } + }; + // + + Assert.Equal(ManagedIdentityType.SystemAssigned, acquireTokenOptions.ManagedIdentity.ManagedIdentityType); + Assert.Null(acquireTokenOptions.ManagedIdentity.ClientId); + } + + [Fact] + public void ManagedIdentityUserAssigned() + { + // App token from a user-assigned managed identity. + // ------------------------------------------------- + // https://aka.ms/Entra/ManagedIdentityOverview + /* + // + { + "AquireTokenOptions": { + "ManagedIdentity": { + "ManagedIdentityType": "UserAssigned" + "ClientId": "[ClientIdForTheManagedIdentityResource]" + } + } + } + // + */ + + // + ManagedIdentityOptions managedIdentityDescription = new ManagedIdentityOptions + { + ManagedIdentityType = ManagedIdentityType.UserAssigned, + ClientId = "[ClientIdForTheManagedIdentityResource]" + }; + + AcquireTokenOptions acquireTokenOptions = new AcquireTokenOptions + { + ManagedIdentity = managedIdentityDescription + }; + // + + Assert.Equal(ManagedIdentityType.UserAssigned, acquireTokenOptions.ManagedIdentity.ManagedIdentityType); + Assert.Equal(managedIdentityDescription.ClientId, acquireTokenOptions.ManagedIdentity.ClientId); + } + } +} diff --git a/test/Microsoft.Identity.Abstractions.Tests/DownstreamApiTests.cs b/test/Microsoft.Identity.Abstractions.Tests/DownstreamApiTests.cs index 378b200..48434b6 100644 --- a/test/Microsoft.Identity.Abstractions.Tests/DownstreamApiTests.cs +++ b/test/Microsoft.Identity.Abstractions.Tests/DownstreamApiTests.cs @@ -27,6 +27,7 @@ public void CloneClonesAllProperties() ExtraQueryParameters = new Dictionary { { "slice", "test" } }, ForceRefresh = true, LongRunningWebApiSessionKey = AcquireTokenOptions.LongRunningWebApiSessionKeyAuto, + ManagedIdentity = new ManagedIdentityOptions(), PopPublicKey = "PopKey", PopClaim = "jwkClaim", Tenant = "domain.com", @@ -75,6 +76,7 @@ public void CloneClonesAllProperties() Assert.Equal(downstreamApiOptions.AcquireTokenOptions.ExtraQueryParameters, downstreamApiClone.AcquireTokenOptions.ExtraQueryParameters); Assert.Equal(downstreamApiOptions.AcquireTokenOptions.ForceRefresh, downstreamApiClone.AcquireTokenOptions.ForceRefresh); Assert.Equal(downstreamApiOptions.AcquireTokenOptions.LongRunningWebApiSessionKey, downstreamApiClone.AcquireTokenOptions.LongRunningWebApiSessionKey); + Assert.Equal(downstreamApiOptions.AcquireTokenOptions.ManagedIdentity, downstreamApiClone.AcquireTokenOptions.ManagedIdentity); Assert.Equal(downstreamApiOptions.AcquireTokenOptions.PopPublicKey, downstreamApiClone.AcquireTokenOptions.PopPublicKey); Assert.Equal(downstreamApiOptions.AcquireTokenOptions.PopClaim, downstreamApiClone.AcquireTokenOptions.PopClaim); Assert.Equal(downstreamApiOptions.AcquireTokenOptions.Tenant, downstreamApiClone.AcquireTokenOptions.Tenant); @@ -82,7 +84,7 @@ public void CloneClonesAllProperties() // If this fails, think of also adding a line to test the new property Assert.Equal(10, typeof(DownstreamApiOptions).GetProperties().Length); - Assert.Equal(12, typeof(AcquireTokenOptions).GetProperties().Length); + Assert.Equal(13, typeof(AcquireTokenOptions).GetProperties().Length); DownstreamApiOptionsReadOnlyHttpMethod options = new DownstreamApiOptionsReadOnlyHttpMethod(downstreamApiOptions, HttpMethod.Delete.ToString()); Assert.Equal(HttpMethod.Delete.ToString(), options.HttpMethod); diff --git a/test/Microsoft.Identity.Abstractions.Tests/ManagedIdentityDescriptionTests.cs b/test/Microsoft.Identity.Abstractions.Tests/ManagedIdentityDescriptionTests.cs new file mode 100644 index 0000000..0b9ed05 --- /dev/null +++ b/test/Microsoft.Identity.Abstractions.Tests/ManagedIdentityDescriptionTests.cs @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Xunit; + +namespace Microsoft.Identity.Abstractions.Tests +{ + public class ManagedIdentityDescriptionTests + { + /// + /// If no field is set for the + /// field needs to default to as other Microsoft.Identity libraries + /// will depend on this. + /// + [Fact] + public void ManagedIdentity_NoDescriptionFieldsSet() + { + // Arrange + ManagedIdentityOptions description = new(); + + // Assert + Assert.Equal(ManagedIdentityType.SystemAssigned, description.ManagedIdentityType); + Assert.Null(description.ClientId); + } + } +} From 38ec1f8bff5b3669188e03e9fffece123d5d2f33 Mon Sep 17 00:00:00 2001 From: Josh Lozensky Date: Fri, 1 Dec 2023 14:16:08 -0800 Subject: [PATCH 5/7] removed equals and gethashcode --- .../ManagedIdentity/ManagedIdentityOptions.cs | 29 ++----------------- .../DownstreamApiTests.cs | 5 ++-- 2 files changed, 5 insertions(+), 29 deletions(-) diff --git a/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityOptions.cs b/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityOptions.cs index 784bd58..d6c8a83 100644 --- a/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityOptions.cs +++ b/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityOptions.cs @@ -33,34 +33,9 @@ public ManagedIdentityOptions Clone() { return new ManagedIdentityOptions { - ManagedIdentityType = this.ManagedIdentityType, - ClientId = this.ClientId + ManagedIdentityType = ManagedIdentityType, + ClientId = ClientId }; } - - /// - /// Ensures any object is equal if all fields hold the same values. - /// - /// - /// - public override bool Equals(object obj) - { - if (obj == null || GetType() != obj.GetType()) - { - return false; - } - ManagedIdentityOptions other = (ManagedIdentityOptions)obj; - return ManagedIdentityType == other.ManagedIdentityType && - ClientId == other.ClientId; - } - - /// - /// Returns the hash code for the instance based on the values of its fields. - /// - /// A 32-bit signed integer hash code. - public override int GetHashCode() - { - return new { ManagedIdentityType, ClientId }.GetHashCode(); - } } } diff --git a/test/Microsoft.Identity.Abstractions.Tests/DownstreamApiTests.cs b/test/Microsoft.Identity.Abstractions.Tests/DownstreamApiTests.cs index 48434b6..83dc124 100644 --- a/test/Microsoft.Identity.Abstractions.Tests/DownstreamApiTests.cs +++ b/test/Microsoft.Identity.Abstractions.Tests/DownstreamApiTests.cs @@ -76,7 +76,8 @@ public void CloneClonesAllProperties() Assert.Equal(downstreamApiOptions.AcquireTokenOptions.ExtraQueryParameters, downstreamApiClone.AcquireTokenOptions.ExtraQueryParameters); Assert.Equal(downstreamApiOptions.AcquireTokenOptions.ForceRefresh, downstreamApiClone.AcquireTokenOptions.ForceRefresh); Assert.Equal(downstreamApiOptions.AcquireTokenOptions.LongRunningWebApiSessionKey, downstreamApiClone.AcquireTokenOptions.LongRunningWebApiSessionKey); - Assert.Equal(downstreamApiOptions.AcquireTokenOptions.ManagedIdentity, downstreamApiClone.AcquireTokenOptions.ManagedIdentity); + Assert.Equal(downstreamApiOptions.AcquireTokenOptions.ManagedIdentity.ManagedIdentityType, downstreamApiClone.AcquireTokenOptions.ManagedIdentity.ManagedIdentityType); + Assert.Equal(downstreamApiOptions.AcquireTokenOptions.ManagedIdentity.ClientId, downstreamApiClone.AcquireTokenOptions.ManagedIdentity.ClientId); Assert.Equal(downstreamApiOptions.AcquireTokenOptions.PopPublicKey, downstreamApiClone.AcquireTokenOptions.PopPublicKey); Assert.Equal(downstreamApiOptions.AcquireTokenOptions.PopClaim, downstreamApiClone.AcquireTokenOptions.PopClaim); Assert.Equal(downstreamApiOptions.AcquireTokenOptions.Tenant, downstreamApiClone.AcquireTokenOptions.Tenant); @@ -154,4 +155,4 @@ public CustomAcquireTokenOptions() : base() { } public CustomAcquireTokenOptions(CustomAcquireTokenOptions other) : base(other) { } } -} \ No newline at end of file +} From bd7405149a491f62fcf949c3c67412f937b2ffee Mon Sep 17 00:00:00 2001 From: Josh Lozensky Date: Mon, 4 Dec 2023 14:40:31 -0800 Subject: [PATCH 6/7] Minor documentation changes --- .../IdentityApplicationOptions.cs | 2 +- .../ManagedIdentity/ManagedIdentityOptions.cs | 10 +++++----- .../ManagedIdentity/ManagedIdentityType.cs | 2 +- .../TokenAcquisition/AcquireTokenOptions.cs | 13 +++++-------- .../DownstreamApiTests.cs | 4 ++-- 5 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/Microsoft.Identity.Abstractions/ApplicationOptions/IdentityApplicationOptions.cs b/src/Microsoft.Identity.Abstractions/ApplicationOptions/IdentityApplicationOptions.cs index 13a54a5..58308ee 100644 --- a/src/Microsoft.Identity.Abstractions/ApplicationOptions/IdentityApplicationOptions.cs +++ b/src/Microsoft.Identity.Abstractions/ApplicationOptions/IdentityApplicationOptions.cs @@ -99,7 +99,7 @@ public class IdentityApplicationOptions /// /// In a web API, accepted audiences for the tokens received by the web API. /// See also . - /// The audience is the intended recipient of the token. You can usually assume that the ApplicationId of your web API + /// The audience is the intended recipient of the token. You can usually assume that the ApplicationID of your web API /// is a valid audience. It can, in general be any of the App ID URIs (or resource identitfier) you defined for your application /// during its registration in the Azure portal. /// diff --git a/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityOptions.cs b/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityOptions.cs index d6c8a83..cc8cc7c 100644 --- a/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityOptions.cs +++ b/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityOptions.cs @@ -6,27 +6,27 @@ namespace Microsoft.Identity.Abstractions { /// - /// Data object to hold the definition of a managed identity for an application to use for authentication.

+ /// Data object to hold the definition of a managed identity for an application to use for authentication. /// See for more details. ///
public class ManagedIdentityOptions { /// /// Gets or sets whether the is system-assigned or user assigned. - /// Defaults to if not set.

+ /// Defaults to if not set. /// See for details on these two types of managed identity. ///
[DefaultValue(ManagedIdentityType.SystemAssigned)] public ManagedIdentityType ManagedIdentityType { get; set; } /// - /// Gets or sets the value of the client id when is set to - /// .
If not set, the default value is null. + /// Gets or sets the value of the ClientID when is set to + /// . If not set, the default value is null. ///
public string? ClientId { get; set; } /// - /// Ensures a clone of this object will not have the same reference. + /// Makes a new object to avoid sharing the same reference. /// /// A new instance of with the same field values. public ManagedIdentityOptions Clone() diff --git a/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityType.cs b/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityType.cs index d405259..9a87b00 100644 --- a/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityType.cs +++ b/src/Microsoft.Identity.Abstractions/ManagedIdentity/ManagedIdentityType.cs @@ -4,7 +4,7 @@ namespace Microsoft.Identity.Abstractions { /// - /// Used by to specify the type of managed identity to use.

+ /// Used by to specify the type of managed identity to use. /// See for more details. ///
public enum ManagedIdentityType diff --git a/src/Microsoft.Identity.Abstractions/TokenAcquisition/AcquireTokenOptions.cs b/src/Microsoft.Identity.Abstractions/TokenAcquisition/AcquireTokenOptions.cs index 199e308..38b88e7 100644 --- a/src/Microsoft.Identity.Abstractions/TokenAcquisition/AcquireTokenOptions.cs +++ b/src/Microsoft.Identity.Abstractions/TokenAcquisition/AcquireTokenOptions.cs @@ -41,14 +41,14 @@ public AcquireTokenOptions(AcquireTokenOptions other) } /// - /// Gets the name of the options describing the confidential client application (ClientId, + /// Gets the name of the options describing the confidential client application (ClientID, /// Region, Authority, client credentials). In ASP.NET Core, the authenticatiopn options name /// is the same as the authentication scheme. /// public string? AuthenticationOptionsName { get; set; } /// - /// Sets the correlation id to be used in the request to the STS "/token" endpoint. + /// Sets the correlation ID to be used in the request to the STS "/token" endpoint. /// public Guid? CorrelationId { get; set; } @@ -94,15 +94,12 @@ public AcquireTokenOptions(AcquireTokenOptions other) /// /// When is set, the application uses a managed identity instead of client credentials to - /// acquire an app token.

- /// + /// acquire an app token. /// The type of managed identity is defined by the field. When /// using a identity, this is the only field that needs to be set and is - /// set by default. However, for readability it can be useful to set explicitly

- /// + /// set by default. However, for readability it can be useful to set explicitly. /// To use a user-assigned identity, select the that corresponds to the - /// you plan to use for authentication.

- /// + /// you plan to use for authentication. /// Using either form of managed identity requires the application to be deployed on Azure and /// the managed identity to be configured. For more details, check the /// managed identities for Azure documentation. diff --git a/test/Microsoft.Identity.Abstractions.Tests/DownstreamApiTests.cs b/test/Microsoft.Identity.Abstractions.Tests/DownstreamApiTests.cs index 83dc124..218adc7 100644 --- a/test/Microsoft.Identity.Abstractions.Tests/DownstreamApiTests.cs +++ b/test/Microsoft.Identity.Abstractions.Tests/DownstreamApiTests.cs @@ -76,8 +76,8 @@ public void CloneClonesAllProperties() Assert.Equal(downstreamApiOptions.AcquireTokenOptions.ExtraQueryParameters, downstreamApiClone.AcquireTokenOptions.ExtraQueryParameters); Assert.Equal(downstreamApiOptions.AcquireTokenOptions.ForceRefresh, downstreamApiClone.AcquireTokenOptions.ForceRefresh); Assert.Equal(downstreamApiOptions.AcquireTokenOptions.LongRunningWebApiSessionKey, downstreamApiClone.AcquireTokenOptions.LongRunningWebApiSessionKey); - Assert.Equal(downstreamApiOptions.AcquireTokenOptions.ManagedIdentity.ManagedIdentityType, downstreamApiClone.AcquireTokenOptions.ManagedIdentity.ManagedIdentityType); - Assert.Equal(downstreamApiOptions.AcquireTokenOptions.ManagedIdentity.ClientId, downstreamApiClone.AcquireTokenOptions.ManagedIdentity.ClientId); + Assert.Equal(downstreamApiOptions.AcquireTokenOptions.ManagedIdentity.ManagedIdentityType, downstreamApiClone.AcquireTokenOptions.ManagedIdentity?.ManagedIdentityType); + Assert.Equal(downstreamApiOptions.AcquireTokenOptions.ManagedIdentity.ClientId, downstreamApiClone.AcquireTokenOptions.ManagedIdentity?.ClientId); Assert.Equal(downstreamApiOptions.AcquireTokenOptions.PopPublicKey, downstreamApiClone.AcquireTokenOptions.PopPublicKey); Assert.Equal(downstreamApiOptions.AcquireTokenOptions.PopClaim, downstreamApiClone.AcquireTokenOptions.PopClaim); Assert.Equal(downstreamApiOptions.AcquireTokenOptions.Tenant, downstreamApiClone.AcquireTokenOptions.Tenant); From 9cae9565e240a4e544a74004d012e9ea95c5673d Mon Sep 17 00:00:00 2001 From: Josh Lozensky Date: Mon, 4 Dec 2023 17:58:04 -0800 Subject: [PATCH 7/7] updating version --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 9ba0611..e6cc325 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -26,7 +26,7 @@ true enable 9.0 - 5.0.0 + 5.1.0 true 5.0.0