From 8cef9432007a2248e23a1ab8055bc74426c14a0c Mon Sep 17 00:00:00 2001 From: Neha Bhargava <61847233+neha-bhargava@users.noreply.github.com> Date: Fri, 12 Sep 2025 10:14:29 -0700 Subject: [PATCH 1/5] Deprecate Kerberos API and remove tests --- .../PublicClientApplicationBuilder.cs | 4 +- .../DesktopOS/Kerberos/NativeMethods.cs | 1 - ...UsernamePasswordIntegrationTests.NetFwk.cs | 71 ----------- .../DeviceCodeFlowIntegrationTest.cs | 56 --------- .../InteractiveFlowTests.NetFwk.cs | 117 ------------------ 5 files changed, 2 insertions(+), 247 deletions(-) diff --git a/src/client/Microsoft.Identity.Client/AppConfig/PublicClientApplicationBuilder.cs b/src/client/Microsoft.Identity.Client/AppConfig/PublicClientApplicationBuilder.cs index 5704e23c0c..7fd645aeb6 100644 --- a/src/client/Microsoft.Identity.Client/AppConfig/PublicClientApplicationBuilder.cs +++ b/src/client/Microsoft.Identity.Client/AppConfig/PublicClientApplicationBuilder.cs @@ -51,8 +51,7 @@ public static PublicClientApplicationBuilder CreateWithApplicationOptions(Public { var config = new ApplicationConfiguration(MsalClientType.PublicClient); return new PublicClientApplicationBuilder(config) - .WithOptions(options) - .WithKerberosTicketClaim(options.KerberosServicePrincipalName, options.TicketContainer); + .WithOptions(options); } /// @@ -324,6 +323,7 @@ public PublicClientApplicationBuilder WithParentActivityOrWindow(Func wi /// The expiry of the Kerberos ticket is tied to the expiry of the token that contains it. /// MSAL provides several helper APIs to read and write Kerberos tickets from the Windows Ticket Cache - see . /// + [Obsolete] public PublicClientApplicationBuilder WithKerberosTicketClaim(string servicePrincipalName, KerberosTicketContainer ticketContainer) { Config.KerberosServicePrincipalName = servicePrincipalName; diff --git a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/NativeMethods.cs b/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/NativeMethods.cs index cc441e67fd..dea8a02557 100644 --- a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/NativeMethods.cs +++ b/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/NativeMethods.cs @@ -405,7 +405,6 @@ public void Dispose() // Replace the usage of Marshal.PtrToStructure(IntPtr, Type) with the generic version Marshal.PtrToStructure(IntPtr) // in the ForEachBuffer method inside SecBufferDesc struct. - private void ForEachBuffer(Action onBuffer) { for (int Index = 0; Index < cBuffers; Index++) diff --git a/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/UsernamePasswordIntegrationTests.NetFwk.cs b/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/UsernamePasswordIntegrationTests.NetFwk.cs index c5314b3793..98b0c0db58 100644 --- a/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/UsernamePasswordIntegrationTests.NetFwk.cs +++ b/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/UsernamePasswordIntegrationTests.NetFwk.cs @@ -473,77 +473,6 @@ private void AssertTelemetryHeaders(HttpSnifferClientFactory factory, bool IsFai Assert.IsFalse(httpTelemetryRecorder.ForceRefresh); } } - - #region Azure AD Kerberos Feature Tests - [IgnoreOnOneBranch] - public async Task Kerberos_ROPC_AAD_Async() - { - var labResponse = await LabUserHelper.GetDefaultUserAsync().ConfigureAwait(false); - await KerberosRunHappyPathTestAsync(labResponse).ConfigureAwait(false); - } - - [IgnoreOnOneBranch] -#if IGNORE_FEDERATED - [Ignore] -#endif - public async Task Kerberos_ROPC_ADFSv4Federated_Async() - { - var labResponse = await LabUserHelper.GetAdfsUserAsync(FederationProvider.AdfsV4, true).ConfigureAwait(false); - await KerberosRunHappyPathTestAsync(labResponse).ConfigureAwait(false); - } - - private async Task KerberosRunHappyPathTestAsync(LabResponse labResponse) - { - // Test with Id token - var factory = new HttpSnifferClientFactory(); - var idTokenPublicClient = PublicClientApplicationBuilder - .Create(labResponse.App.AppId) - .WithTestLogging() - .WithHttpClientFactory(factory) - .WithAuthority(labResponse.Lab.Authority, "organizations") - .WithClientId(TestConstants.KerberosTestApplicationId) - .WithKerberosTicketClaim(TestConstants.KerberosServicePrincipalName, KerberosTicketContainer.IdToken) - .Build(); - - AuthenticationResult authResult = await GetAuthenticationResultWithAssertAsync( - labResponse, - factory, - idTokenPublicClient, - "", - Guid.NewGuid()).ConfigureAwait(false); - KerberosSupplementalTicket ticket = TestCommon.GetValidatedKerberosTicketFromAuthenticationResult( - authResult, - KerberosTicketContainer.IdToken, - labResponse.User.Upn); - Assert.IsNotNull(ticket); - TestCommon.ValidateKerberosWindowsTicketCacheOperation(ticket); - - // Test with Access Token - factory = new HttpSnifferClientFactory(); - var accessTokenPublicClient = PublicClientApplicationBuilder - .Create(labResponse.App.AppId) - .WithTestLogging() - .WithHttpClientFactory(factory) - .WithAuthority(labResponse.Lab.Authority, "organizations") - .WithClientId(TestConstants.KerberosTestApplicationId) - .WithKerberosTicketClaim(TestConstants.KerberosServicePrincipalName, KerberosTicketContainer.AccessToken) - .Build(); - - authResult = await GetAuthenticationResultWithAssertAsync( - labResponse, - factory, - accessTokenPublicClient, - "", - Guid.NewGuid()).ConfigureAwait(false); - ticket = TestCommon.GetValidatedKerberosTicketFromAuthenticationResult( - authResult, - KerberosTicketContainer.AccessToken, - labResponse.User.Upn); - Assert.IsNotNull(ticket); - TestCommon.ValidateKerberosWindowsTicketCacheOperation(ticket); - } - -#endregion } } #endif diff --git a/tests/Microsoft.Identity.Test.Integration.netcore/SeleniumTests/DeviceCodeFlowIntegrationTest.cs b/tests/Microsoft.Identity.Test.Integration.netcore/SeleniumTests/DeviceCodeFlowIntegrationTest.cs index ec6ae38b50..48cccc6765 100644 --- a/tests/Microsoft.Identity.Test.Integration.netcore/SeleniumTests/DeviceCodeFlowIntegrationTest.cs +++ b/tests/Microsoft.Identity.Test.Integration.netcore/SeleniumTests/DeviceCodeFlowIntegrationTest.cs @@ -157,61 +157,5 @@ private async Task AcquireTokenSilentAfterDeviceCodeFlowWithBrokerAsync(LabRespo Assert.IsNotNull(silentTokenResult); Assert.IsTrue(!string.IsNullOrEmpty(silentTokenResult.AccessToken)); } - - #region Azure AD Kerberos Feature Tests - [IgnoreOnOneBranch] - [RunOn(TargetFrameworks.NetCore)] - [Timeout(2 * 60 * 1000)] // 2 min timeout - public async Task KerberosDeviceCodeFlowTestAsync() - { - LabResponse labResponse = await LabUserHelper.GetDefaultUserAsync().ConfigureAwait(false); - await KerberosAcquireTokenWithDeviceCodeFlowAsync(labResponse, "aad user", KerberosTicketContainer.IdToken).ConfigureAwait(false); - await KerberosAcquireTokenWithDeviceCodeFlowAsync(labResponse, "aad user", KerberosTicketContainer.AccessToken).ConfigureAwait(false); - } - - private async Task KerberosAcquireTokenWithDeviceCodeFlowAsync(LabResponse labResponse, string userType, KerberosTicketContainer ticketContainer) - { - Trace.WriteLine($"Calling KerberosAcquireTokenWithDeviceCodeFlowAsync with {0}", userType); - var builder = PublicClientApplicationBuilder.Create(labResponse.App.AppId) - .WithTestLogging() - .WithTenantId(labResponse.Lab.TenantId) - .WithClientId(TestConstants.KerberosTestApplicationId) - .WithKerberosTicketClaim(TestConstants.KerberosServicePrincipalName, ticketContainer); - - switch (labResponse.User.AzureEnvironment) - { - case AzureEnvironment.azureusgovernment: - builder.WithAuthority(labResponse.Lab.Authority + labResponse.Lab.TenantId); - break; - default: - break; - } - - var pca = builder.Build(); - var userCacheAccess = pca.UserTokenCache.RecordAccess(); - - var result = await pca.AcquireTokenWithDeviceCode(s_scopes, deviceCodeResult => - { - SeleniumExtensions.PerformDeviceCodeLogin(deviceCodeResult, labResponse.User, TestContext, false); - return Task.FromResult(0); - }).ExecuteAsync(CancellationToken.None).ConfigureAwait(false); - - Trace.WriteLine("Running asserts"); - - userCacheAccess.AssertAccessCounts(0, 1); - Assert.IsFalse(userCacheAccess.LastAfterAccessNotificationArgs.IsApplicationCache); - - Assert.IsNotNull(result); - Assert.IsTrue(!string.IsNullOrEmpty(result.AccessToken)); - - KerberosSupplementalTicket ticket = TestCommon.GetValidatedKerberosTicketFromAuthenticationResult( - result, - ticketContainer, - labResponse.User.Upn); - Assert.IsNotNull(ticket); - TestCommon.ValidateKerberosWindowsTicketCacheOperation(ticket); - } - - #endregion } } diff --git a/tests/Microsoft.Identity.Test.Integration.netcore/SeleniumTests/InteractiveFlowTests.NetFwk.cs b/tests/Microsoft.Identity.Test.Integration.netcore/SeleniumTests/InteractiveFlowTests.NetFwk.cs index 849d48d919..a3abb5a73b 100644 --- a/tests/Microsoft.Identity.Test.Integration.netcore/SeleniumTests/InteractiveFlowTests.NetFwk.cs +++ b/tests/Microsoft.Identity.Test.Integration.netcore/SeleniumTests/InteractiveFlowTests.NetFwk.cs @@ -409,122 +409,5 @@ private SeleniumWebUI CreateSeleniumCustomWebUIForDuende(string username, string loginBtn?.Click(); }, TestContext); } - - #region Azure AD Kerberos Feature Tests - [Ignore] - public async Task Kerberos_Interactive_AADAsync() - { - LabResponse labResponse = await LabUserHelper.GetDefaultUserAsync().ConfigureAwait(false); - await KerberosRunTestForUserAsync(labResponse, KerberosTicketContainer.IdToken).ConfigureAwait(false); - await KerberosRunTestForUserAsync(labResponse, KerberosTicketContainer.AccessToken).ConfigureAwait(false); - } - - private async Task KerberosRunTestForUserAsync( - LabResponse labResponse, - KerberosTicketContainer ticketContainer) - { - IPublicClientApplication pca = PublicClientApplicationBuilder - .Create(labResponse.App.AppId) - .WithRedirectUri(SeleniumWebUI.FindFreeLocalhostRedirectUri()) - .WithAuthority(labResponse.Lab.Authority + "common") - .WithTestLogging(out HttpSnifferClientFactory factory) - .WithTenantId(labResponse.Lab.TenantId) - .WithClientId(TestConstants.KerberosTestApplicationId) - .WithKerberosTicketClaim(TestConstants.KerberosServicePrincipalName, ticketContainer) - .Build(); - - var userCacheAccess = pca.UserTokenCache.RecordAccess(); - - Trace.WriteLine("Part 1 - Acquire a token interactively, no login hint"); - AuthenticationResult result = await pca - .AcquireTokenInteractive(s_scopes) - .WithCustomWebUi(CreateSeleniumCustomWebUI(labResponse.User, Prompt.SelectAccount, false, false)) - .ExecuteAsync(new CancellationTokenSource(_interactiveAuthTimeout).Token) - .ConfigureAwait(false); - - Assert.IsTrue(result.AuthenticationResultMetadata.DurationTotalInMs > 0); - Assert.IsTrue(result.AuthenticationResultMetadata.DurationInHttpInMs > 0); - - KerberosSupplementalTicket ticket = TestCommon.GetValidatedKerberosTicketFromAuthenticationResult( - result, - ticketContainer, - labResponse.User.Upn); - Assert.IsNotNull(ticket); - - userCacheAccess.AssertAccessCounts(0, 1); - IAccount account = await MsalAssert.AssertSingleAccountAsync(labResponse, pca, result).ConfigureAwait(false); - userCacheAccess.AssertAccessCounts(1, 1); // the assert calls GetAccounts - Assert.IsFalse(userCacheAccess.LastAfterAccessNotificationArgs.IsApplicationCache); - - Trace.WriteLine("Part 2 - Clear the cache"); - await pca.RemoveAsync(account).ConfigureAwait(false); - userCacheAccess.AssertAccessCounts(1, 2); - Assert.IsFalse((await pca.GetAccountsAsync().ConfigureAwait(false)).Any()); - userCacheAccess.AssertAccessCounts(2, 2); - Assert.IsFalse(userCacheAccess.LastAfterAccessNotificationArgs.IsApplicationCache); - - if (factory?.RequestsAndResponses != null) - { - factory.RequestsAndResponses.Clear(); - } - - Trace.WriteLine("Part 3 - Acquire a token interactively again, with login hint"); - result = await pca - .AcquireTokenInteractive(s_scopes) - .WithCustomWebUi(CreateSeleniumCustomWebUI(labResponse.User, Prompt.ForceLogin, true, false)) - .WithPrompt(Prompt.ForceLogin) - .WithLoginHint(labResponse.User.Upn) - .ExecuteAsync(new CancellationTokenSource(_interactiveAuthTimeout).Token) - .ConfigureAwait(false); - userCacheAccess.AssertAccessCounts(2, 3); - AssertCcsRoutingInformationIsSent(factory, labResponse); - ticket = TestCommon.GetValidatedKerberosTicketFromAuthenticationResult( - result, - ticketContainer, - labResponse.User.Upn); - Assert.IsNotNull(ticket); - - account = await MsalAssert.AssertSingleAccountAsync(labResponse, pca, result).ConfigureAwait(false); - userCacheAccess.AssertAccessCounts(3, 3); - Assert.IsFalse(userCacheAccess.LastAfterAccessNotificationArgs.IsApplicationCache); - - if (factory?.RequestsAndResponses != null) - { - factory.RequestsAndResponses.Clear(); - } - - Trace.WriteLine("Part 4 - Acquire a token silently"); - result = await pca - .AcquireTokenSilent(s_scopes, account) - .ExecuteAsync(CancellationToken.None) - .ConfigureAwait(false); - ticket = TestCommon.GetValidatedKerberosTicketFromAuthenticationResult( - result, - ticketContainer, - labResponse.User.Upn); - Assert.IsNotNull(ticket); - - Trace.WriteLine("Part 5 - Acquire a token silently with force refresh"); - result = await pca - .AcquireTokenSilent(s_scopes, account) - .WithForceRefresh(true) - .ExecuteAsync(CancellationToken.None) - .ConfigureAwait(false); - - await MsalAssert.AssertSingleAccountAsync(labResponse, pca, result).ConfigureAwait(false); - Assert.IsFalse(userCacheAccess.LastAfterAccessNotificationArgs.IsApplicationCache); - AssertCcsRoutingInformationIsSent(factory, labResponse); - - ticket = TestCommon.GetValidatedKerberosTicketFromAuthenticationResult( - result, - ticketContainer, - labResponse.User.Upn); - Assert.IsNotNull(ticket); - TestCommon.ValidateKerberosWindowsTicketCacheOperation(ticket); - - return result; - } - - #endregion } } From c5334c95b732812322a877becd5d3d8c2380bb0f Mon Sep 17 00:00:00 2001 From: Neha Bhargava <61847233+neha-bhargava@users.noreply.github.com> Date: Mon, 15 Sep 2025 12:25:37 -0700 Subject: [PATCH 2/5] Remove internal code and deprecate all public APIs --- .../AppConfig/ApplicationConfiguration.cs | 1 + .../AppConfig/ApplicationOptions.cs | 7 +- .../AppConfig/BaseApplicationOptions.cs | 6 - .../PublicClientApplicationBuilder.cs | 1 + .../Kerberos/KerberosKeyTypes.cs | 5 + .../Kerberos/KerberosSupplementalTicket.cs | 4 + .../KerberosSupplementalTicketManager.cs | 2 + .../Kerberos/KerberosTicketContainer.cs | 5 + .../OAuth2/TokenClient.cs | 2 + .../DesktopOS/Kerberos/AcceptContextFlag.cs | 33 ---- .../Features/DesktopOS/Kerberos/Credential.cs | 2 +- .../DesktopOS/Kerberos/TicketCacheReader.cs | 1 - .../DesktopOS/Kerberos/TicketCacheWriter.cs | 1 - .../OpenTelemetry/OtelInstrumentation.cs | 11 +- .../net/MsalJsonSerializerContext.cs | 4 +- .../TestCommon.cs | 103 ---------- .../TestConstants.cs | 7 - .../B2CUsernamePasswordIntegrationTests.cs | 5 - ...UsernamePasswordIntegrationTests.NetFwk.cs | 6 - .../DeviceCodeFlowIntegrationTest.cs | 4 - .../InteractiveFlowTests.NetFwk.cs | 10 - .../KerberosSupplementalTicketManagerTests.cs | 181 ------------------ 22 files changed, 32 insertions(+), 369 deletions(-) delete mode 100644 src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/AcceptContextFlag.cs delete mode 100644 tests/Microsoft.Identity.Test.Unit/Kerberos/KerberosSupplementalTicketManagerTests.cs diff --git a/src/client/Microsoft.Identity.Client/AppConfig/ApplicationConfiguration.cs b/src/client/Microsoft.Identity.Client/AppConfig/ApplicationConfiguration.cs index ab19425b9e..6bf57e3161 100644 --- a/src/client/Microsoft.Identity.Client/AppConfig/ApplicationConfiguration.cs +++ b/src/client/Microsoft.Identity.Client/AppConfig/ApplicationConfiguration.cs @@ -81,6 +81,7 @@ public string ClientVersion /// /// Kerberos Service Ticket container to be used. /// + [Obsolete] public KerberosTicketContainer TicketContainer { get; set; } = KerberosTicketContainer.IdToken; [Obsolete("Telemetry is sent automatically by MSAL.NET. See https://aka.ms/msal-net-telemetry.")] diff --git a/src/client/Microsoft.Identity.Client/AppConfig/ApplicationOptions.cs b/src/client/Microsoft.Identity.Client/AppConfig/ApplicationOptions.cs index 26adf5aba1..d0c5279b36 100644 --- a/src/client/Microsoft.Identity.Client/AppConfig/ApplicationOptions.cs +++ b/src/client/Microsoft.Identity.Client/AppConfig/ApplicationOptions.cs @@ -2,7 +2,6 @@ // Licensed under the MIT License. using System; -using System.Collections; using System.Collections.Generic; using System.ComponentModel; using Microsoft.Identity.Client.Kerberos; @@ -102,11 +101,15 @@ public abstract class ApplicationOptions : BaseApplicationOptions /// /// Service principal name for Kerberos Service Ticket. /// + [Obsolete] + [EditorBrowsable(EditorBrowsableState.Never)] public string KerberosServicePrincipalName { get; set; } = string.Empty; /// /// Kerberos Service Ticket container to be used. - /// + /// + [Obsolete] + [EditorBrowsable(EditorBrowsableState.Never)] public KerberosTicketContainer TicketContainer { get; set; } = KerberosTicketContainer.IdToken; } } diff --git a/src/client/Microsoft.Identity.Client/AppConfig/BaseApplicationOptions.cs b/src/client/Microsoft.Identity.Client/AppConfig/BaseApplicationOptions.cs index 4c998af1f1..28fa113efb 100644 --- a/src/client/Microsoft.Identity.Client/AppConfig/BaseApplicationOptions.cs +++ b/src/client/Microsoft.Identity.Client/AppConfig/BaseApplicationOptions.cs @@ -1,12 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System; -using System.Collections; -using System.Collections.Generic; -using System.ComponentModel; -using Microsoft.Identity.Client.Kerberos; - namespace Microsoft.Identity.Client { /// diff --git a/src/client/Microsoft.Identity.Client/AppConfig/PublicClientApplicationBuilder.cs b/src/client/Microsoft.Identity.Client/AppConfig/PublicClientApplicationBuilder.cs index 7fd645aeb6..59eed2e90c 100644 --- a/src/client/Microsoft.Identity.Client/AppConfig/PublicClientApplicationBuilder.cs +++ b/src/client/Microsoft.Identity.Client/AppConfig/PublicClientApplicationBuilder.cs @@ -324,6 +324,7 @@ public PublicClientApplicationBuilder WithParentActivityOrWindow(Func wi /// MSAL provides several helper APIs to read and write Kerberos tickets from the Windows Ticket Cache - see . /// [Obsolete] + [EditorBrowsable(EditorBrowsableState.Never)] public PublicClientApplicationBuilder WithKerberosTicketClaim(string servicePrincipalName, KerberosTicketContainer ticketContainer) { Config.KerberosServicePrincipalName = servicePrincipalName; diff --git a/src/client/Microsoft.Identity.Client/Kerberos/KerberosKeyTypes.cs b/src/client/Microsoft.Identity.Client/Kerberos/KerberosKeyTypes.cs index 36c9073342..95ddc61d3f 100644 --- a/src/client/Microsoft.Identity.Client/Kerberos/KerberosKeyTypes.cs +++ b/src/client/Microsoft.Identity.Client/Kerberos/KerberosKeyTypes.cs @@ -1,11 +1,16 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System; +using System.ComponentModel; + namespace Microsoft.Identity.Client.Kerberos { /// /// The Kerberos key types used in this assembly. /// + [Obsolete] + [EditorBrowsable(EditorBrowsableState.Never)] public enum KerberosKeyTypes { /// diff --git a/src/client/Microsoft.Identity.Client/Kerberos/KerberosSupplementalTicket.cs b/src/client/Microsoft.Identity.Client/Kerberos/KerberosSupplementalTicket.cs index 4fa47c578c..8acb38c107 100644 --- a/src/client/Microsoft.Identity.Client/Kerberos/KerberosSupplementalTicket.cs +++ b/src/client/Microsoft.Identity.Client/Kerberos/KerberosSupplementalTicket.cs @@ -1,5 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System; +using System.ComponentModel; #if SUPPORTS_SYSTEM_TEXT_JSON using JsonProperty = System.Text.Json.Serialization.JsonPropertyNameAttribute; @@ -13,6 +15,8 @@ namespace Microsoft.Identity.Client.Kerberos /// Class for Kerberos tickets that are included as claims and used as a supplemental token in an OAuth/OIDC /// protocol response. /// + [Obsolete] + [EditorBrowsable(EditorBrowsableState.Never)] public class KerberosSupplementalTicket { /// diff --git a/src/client/Microsoft.Identity.Client/Kerberos/KerberosSupplementalTicketManager.cs b/src/client/Microsoft.Identity.Client/Kerberos/KerberosSupplementalTicketManager.cs index 0cd7396d2c..dec0f903b0 100644 --- a/src/client/Microsoft.Identity.Client/Kerberos/KerberosSupplementalTicketManager.cs +++ b/src/client/Microsoft.Identity.Client/Kerberos/KerberosSupplementalTicketManager.cs @@ -23,6 +23,8 @@ namespace Microsoft.Identity.Client.Kerberos /// /// Helper class to manage Kerberos Ticket Claims. /// + [Obsolete] + [EditorBrowsable(EditorBrowsableState.Never)] public static class KerberosSupplementalTicketManager { private const int DefaultLogonId = 0; diff --git a/src/client/Microsoft.Identity.Client/Kerberos/KerberosTicketContainer.cs b/src/client/Microsoft.Identity.Client/Kerberos/KerberosTicketContainer.cs index 2b448e7d52..559b871b11 100644 --- a/src/client/Microsoft.Identity.Client/Kerberos/KerberosTicketContainer.cs +++ b/src/client/Microsoft.Identity.Client/Kerberos/KerberosTicketContainer.cs @@ -1,11 +1,16 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System; +using System.ComponentModel; + namespace Microsoft.Identity.Client.Kerberos { /// /// Declares the type of container to use for Kerberos Ticket Claim. /// + [Obsolete] + [EditorBrowsable(EditorBrowsableState.Never)] public enum KerberosTicketContainer { /// diff --git a/src/client/Microsoft.Identity.Client/OAuth2/TokenClient.cs b/src/client/Microsoft.Identity.Client/OAuth2/TokenClient.cs index cb49263fad..ba21483642 100644 --- a/src/client/Microsoft.Identity.Client/OAuth2/TokenClient.cs +++ b/src/client/Microsoft.Identity.Client/OAuth2/TokenClient.cs @@ -188,9 +188,11 @@ await _serviceBundle.Config.ClientCredential.AddConfidentialClientParametersAsyn /// private void AddClaims() { +#pragma warning disable CS0612 // Type or member is obsolete string kerberosClaim = KerberosSupplementalTicketManager.GetKerberosTicketClaim( _requestParams.RequestContext.ServiceBundle.Config.KerberosServicePrincipalName, _requestParams.RequestContext.ServiceBundle.Config.TicketContainer); +#pragma warning restore CS0612 // Type or member is obsolete string resolvedClaims; if (string.IsNullOrEmpty(kerberosClaim)) { diff --git a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/AcceptContextFlag.cs b/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/AcceptContextFlag.cs deleted file mode 100644 index e36a1e6a12..0000000000 --- a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/AcceptContextFlag.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; - -namespace Microsoft.Identity.Client.Platforms.Features.DesktopOs.Kerberos -{ - /// - /// Flags that specify the attributes required by the AcceptSecurityContext (CredSSP) function - /// for a server to establish the context. - /// https://learn.microsoft.com/windows/win32/api/sspi/nf-sspi-acceptsecuritycontext - /// - [Flags] - internal enum AcceptContextFlag - { - Zero = 0, - Delegate = 0x00000001, - MutualAuth = 0x00000002, - ReplayDetect = 0x00000004, - SequenceDetect = 0x00000008, - Confidentiality = 0x00000010, - UseSessionKey = 0x00000020, - AllocateMemory = 0x00000100, - Connection = 0x00000800, - AcceptExtendedError = 0x00008000, - AcceptStream = 0x00010000, - AcceptIntegrity = 0x00020000, - AcceptIdentify = 0x00080000, - ProxyBindings = 0x04000000, - AllowMissingBindings = 0x10000000, - UnverifiedTargetName = 0x20000000 - } -} diff --git a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/Credential.cs b/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/Credential.cs index 4ed4663eb2..37307a5f9e 100644 --- a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/Credential.cs +++ b/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/Credential.cs @@ -22,7 +22,7 @@ public static Credential Current() private class CurrentCredential : Credential { - internal unsafe override CredentialHandle Structify() + internal override unsafe CredentialHandle Structify() { return new CredentialHandle((void*)0); } diff --git a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/TicketCacheReader.cs b/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/TicketCacheReader.cs index 3eb7a54920..d1b0a8ed41 100644 --- a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/TicketCacheReader.cs +++ b/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/TicketCacheReader.cs @@ -4,7 +4,6 @@ using System; using System.ComponentModel; using System.Runtime.InteropServices; -using Microsoft.Identity.Client.PlatformsCommon.Interfaces; namespace Microsoft.Identity.Client.Platforms.Features.DesktopOs.Kerberos { diff --git a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/TicketCacheWriter.cs b/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/TicketCacheWriter.cs index 9cb3f70918..51e994cd80 100644 --- a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/TicketCacheWriter.cs +++ b/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/TicketCacheWriter.cs @@ -3,7 +3,6 @@ using System; using System.Runtime.InteropServices; -using Microsoft.Identity.Client.PlatformsCommon.Interfaces; namespace Microsoft.Identity.Client.Platforms.Features.DesktopOs.Kerberos { diff --git a/src/client/Microsoft.Identity.Client/Platforms/Features/OpenTelemetry/OtelInstrumentation.cs b/src/client/Microsoft.Identity.Client/Platforms/Features/OpenTelemetry/OtelInstrumentation.cs index 4c65cbdbaa..51f94757e6 100644 --- a/src/client/Microsoft.Identity.Client/Platforms/Features/OpenTelemetry/OtelInstrumentation.cs +++ b/src/client/Microsoft.Identity.Client/Platforms/Features/OpenTelemetry/OtelInstrumentation.cs @@ -1,16 +1,13 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. using System; -using System.Collections.Generic; -using System.Diagnostics; -using Microsoft.Identity.Client.Core; -using Microsoft.Identity.Client.Cache; -using Microsoft.Identity.Client.TelemetryCore; -using Microsoft.Identity.Client.TelemetryCore.OpenTelemetry; using System.Diagnostics.Metrics; +using Microsoft.Identity.Client.Cache; +using Microsoft.Identity.Client.Core; using Microsoft.Identity.Client.Internal; +using Microsoft.Identity.Client.TelemetryCore; using Microsoft.Identity.Client.TelemetryCore.Internal.Events; -using static Microsoft.Identity.Client.Platforms.Features.DesktopOs.Kerberos.NativeMethods; +using Microsoft.Identity.Client.TelemetryCore.OpenTelemetry; namespace Microsoft.Identity.Client.Platforms.Features.OpenTelemetry { diff --git a/src/client/Microsoft.Identity.Client/Platforms/net/MsalJsonSerializerContext.cs b/src/client/Microsoft.Identity.Client/Platforms/net/MsalJsonSerializerContext.cs index d36f036282..52fc2ec175 100644 --- a/src/client/Microsoft.Identity.Client/Platforms/net/MsalJsonSerializerContext.cs +++ b/src/client/Microsoft.Identity.Client/Platforms/net/MsalJsonSerializerContext.cs @@ -1,11 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -using System; using System.Collections.Generic; using System.Text.Json; using System.Text.Json.Serialization; -using System.Text.Json.Serialization.Metadata; using Microsoft.Identity.Client.Cache; using Microsoft.Identity.Client.Instance.Discovery; using Microsoft.Identity.Client.Instance.Oidc; @@ -24,7 +22,9 @@ namespace Microsoft.Identity.Client.Platforms.net /// See Source-generation modes in System.Text.Json. /// and How to use source generation in System.Text.Json for official docs. /// +#pragma warning disable CS0612 // Type or member is obsolete [JsonSerializable(typeof(KerberosSupplementalTicket))] +#pragma warning restore CS0612 // Type or member is obsolete [JsonSerializable(typeof(InstanceDiscoveryResponse))] [JsonSerializable(typeof(LocalImdsErrorResponse))] [JsonSerializable(typeof(AdalResultWrapper))] diff --git a/tests/Microsoft.Identity.Test.Common/TestCommon.cs b/tests/Microsoft.Identity.Test.Common/TestCommon.cs index 4411a37492..8258df4383 100644 --- a/tests/Microsoft.Identity.Test.Common/TestCommon.cs +++ b/tests/Microsoft.Identity.Test.Common/TestCommon.cs @@ -154,109 +154,6 @@ public static KeyValuePair> GetCcsHeaderFromSnifferF throw new MsalClientException("Could not find CCS Header in sniffer factory."); } - /// - /// Get a Kerberos Ticket contained in the given object. - /// - /// An object to get Kerberos Ticket from. - /// The indicating the token where the Kerberos Ticket stored." - /// UPN of the client. - /// A if there's valid one. - public static KerberosSupplementalTicket GetValidatedKerberosTicketFromAuthenticationResult(AuthenticationResult authResult, - KerberosTicketContainer container, - string userUpn) - { - if (container == KerberosTicketContainer.IdToken) - { - ValidateNoKerberosTicketFromToken(authResult.AccessToken); - return GetValidatedKerberosTicketFromToken(authResult.IdToken, userUpn); - } - - ValidateNoKerberosTicketFromToken(authResult.IdToken); - return GetValidatedKerberosTicketFromToken(authResult.AccessToken, userUpn); - } - - /// - /// Get a Kerberos Ticket contained in the given token. - /// - /// Token to be validated. - /// UPN of the client. - /// A if there's valid one. - public static KerberosSupplementalTicket GetValidatedKerberosTicketFromToken(string token, string userUpn) - { - KerberosSupplementalTicket ticket = KerberosSupplementalTicketManager.FromIdToken(token); - - Assert.IsNotNull(ticket, "Kerberos Ticket is not found."); - Assert.IsTrue(string.IsNullOrEmpty(ticket.ErrorMessage), "Kerberos Ticket creation failed with: " + ticket.ErrorMessage); - Assert.IsFalse(string.IsNullOrEmpty(ticket.KerberosMessageBuffer), "Kerberos Ticket data is not found."); - Assert.IsTrue(ticket.KerberosMessageBuffer.Length > TestConstants.KerberosMinMessageBufferLength, "Received Kerberos Ticket data is too short."); - Assert.AreEqual(KerberosKeyTypes.Aes256CtsHmacSha196, ticket.KeyType, "Kerberos key type is not matched."); - Assert.AreEqual(TestConstants.KerberosServicePrincipalName, ticket.ServicePrincipalName, true, CultureInfo.InvariantCulture, "Service principal name is not matched."); - Assert.AreEqual(userUpn, ticket.ClientName, true, CultureInfo.InvariantCulture, "Client name is not matched."); - - return ticket; - } - - /// - /// Validates Windows Ticket Cache interface for the given Kerberos Ticket. - /// - /// A object to be checked. - public static void ValidateKerberosWindowsTicketCacheOperation(KerberosSupplementalTicket ticket) - { - if (DesktopOsHelper.IsWindows()) - { - // First, save the given Kerberos Ticket (with KRB-CRED format) into the Windows Ticket Cache. - // Windows Ticket Cache decrypts the given Kerberos Ticket with KRB-CRED format, re-encrypt with it's - // credential and save it as AP-REQ format. - KerberosSupplementalTicketManager.SaveToWindowsTicketCache(ticket); - - // Read-back saved Ticket data. - byte[] ticketBytes - = KerberosSupplementalTicketManager.GetKerberosTicketFromWindowsTicketCache(ticket.ServicePrincipalName); - Assert.IsNotNull(ticketBytes); - - // To validate public field of AP-REQ format Kerberos Ticket, convert binary ticket data as a printable string format. - StringBuilder sb = new StringBuilder(); - foreach (byte ch in ticketBytes) - { - if (ch >= 32 && ch < 127) - { - sb.Append((char)ch); - } - else - { - sb.Append('*'); - } - } - string ticketAsString = sb.ToString(); - - // Check the Azure AD Kerberos Realm string exists. - Assert.IsTrue(ticketAsString.IndexOf(TestConstants.AzureADKerberosRealmName) >= 0); - - // Check the ticket has matched Kerberos Service Principal Name. - Assert.IsTrue(ticketAsString.IndexOf(TestConstants.KerberosServicePrincipalNameEscaped, StringComparison.OrdinalIgnoreCase) >= 0); - } - } - - /// - /// Validates there were no Kerberos Ticket with the given object. - /// - /// An object to be checked. - public static void ValidateNoKerberosTicketFromAuthenticationResult(AuthenticationResult authResult) - { - ValidateNoKerberosTicketFromToken(authResult.IdToken); - ValidateNoKerberosTicketFromToken(authResult.AccessToken); - } - - /// - /// Validates there were no valid Kerberos Ticket contained in the given token. - /// - /// Token to be validated. - public static void ValidateNoKerberosTicketFromToken(string token) - { - KerberosSupplementalTicket ticket = KerberosSupplementalTicketManager.FromIdToken(token); - Assert.IsNull(ticket, "Kerberos Ticket exists."); - } - public static bool YieldTillSatisfied(Func func, int maxTimeInMilliSec = 30000) { int iCount = maxTimeInMilliSec / 100; diff --git a/tests/Microsoft.Identity.Test.Common/TestConstants.cs b/tests/Microsoft.Identity.Test.Common/TestConstants.cs index 3d89cc1bbe..f74cee292f 100644 --- a/tests/Microsoft.Identity.Test.Common/TestConstants.cs +++ b/tests/Microsoft.Identity.Test.Common/TestConstants.cs @@ -404,13 +404,6 @@ public static MsalTokenResponse CreateMsalTokenResponseWithTokenSource() ""username"":""some_user@contoso.com"" }"; - // constants for Azure AD Kerberos Features - public const string KerberosTestApplicationId = "682992e9-c9c6-49c9-a819-3fbca2dd5111"; - public const string KerberosServicePrincipalName = "HTTP/msal-kerberos-test.msidlab4.com"; - public const string KerberosServicePrincipalNameEscaped = "HTTP**msal-kerberos-test.msidlab4.com"; - public const string AzureADKerberosRealmName = "KERBEROS.MICROSOFTONLINE.COM"; - public const int KerberosMinMessageBufferLength = 256; - // do not change these constants! public const string AadRawClientInfo = "eyJ1aWQiOiI5ZjQ4ODBkOC04MGJhLTRjNDAtOTdiYy1mN2EyM2M3MDMwODQiLCJ1dGlkIjoiZjY0NWFkOTItZTM4ZC00ZDFhLWI1MTAtZDFiMDlhNzRhOGNhIn0"; public const string MsaRawClientInfo = "eyJ2ZXIiOiIxLjAiLCJzdWIiOiJBQUFBQUFBQUFBQUFBQUFBQUFBQUFNTmVBRnBTTGdsSGlPVHI5SVpISkVBIiwibmFtZSI6Ik9sZ2EgRGFsdG9tIiwicHJlZmVycmVkX3VzZXJuYW1lIjoibXNhbHNka3Rlc3RAb3V0bG9vay5jb20iLCJvaWQiOiIwMDAwMDAwMC0wMDAwLTAwMDAtNDBjMC0zYmFjMTg4ZDAxZDEiLCJ0aWQiOiI5MTg4MDQwZC02YzY3LTRjNWItYjExMi0zNmEzMDRiNjZkYWQiLCJob21lX29pZCI6IjAwMDAwMDAwLTAwMDAtMDAwMC00MGMwLTNiYWMxODhkMDFkMSIsInVpZCI6IjAwMDAwMDAwLTAwMDAtMDAwMC00MGMwLTNiYWMxODhkMDFkMSIsInV0aWQiOiI5MTg4MDQwZC02YzY3LTRjNWItYjExMi0zNmEzMDRiNjZkYWQifQ"; diff --git a/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/B2CUsernamePasswordIntegrationTests.cs b/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/B2CUsernamePasswordIntegrationTests.cs index 551daca885..2999993f1c 100644 --- a/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/B2CUsernamePasswordIntegrationTests.cs +++ b/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/B2CUsernamePasswordIntegrationTests.cs @@ -2,13 +2,9 @@ // Licensed under the MIT License. using System.Linq; -using System.Net; -using System.Security; using System.Threading; using System.Threading.Tasks; using Microsoft.Identity.Client; -using Microsoft.Identity.Test.Common; -using Microsoft.Identity.Test.Common.Core.Helpers; using Microsoft.Identity.Test.Integration.Infrastructure; using Microsoft.Identity.Test.LabInfrastructure; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -54,7 +50,6 @@ public async Task ROPC_B2C_Async() Assert.AreEqual(TokenSource.IdentityProvider, authResult.AuthenticationResultMetadata.TokenSource); Assert.IsNotNull(authResult.AccessToken); Assert.IsNotNull(authResult.IdToken); - TestCommon.ValidateNoKerberosTicketFromAuthenticationResult(authResult); var acc = (await msalPublicClient.GetAccountsAsync().ConfigureAwait(false)).Single(); var claimsPrincipal = acc.GetTenantProfiles().Single().ClaimsPrincipal; diff --git a/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/UsernamePasswordIntegrationTests.NetFwk.cs b/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/UsernamePasswordIntegrationTests.NetFwk.cs index 98b0c0db58..0ca9f324f6 100644 --- a/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/UsernamePasswordIntegrationTests.NetFwk.cs +++ b/tests/Microsoft.Identity.Test.Integration.netcore/HeadlessTests/UsernamePasswordIntegrationTests.NetFwk.cs @@ -6,15 +6,11 @@ using System.IO; using System.Linq; using System.Net; -using System.Security; using System.Threading; using System.Threading.Tasks; using Microsoft.Identity.Client; -using Microsoft.Identity.Client.Cache; using Microsoft.Identity.Client.Internal; -using Microsoft.Identity.Client.Kerberos; using Microsoft.Identity.Client.TelemetryCore; -using Microsoft.Identity.Client.Utils; using Microsoft.Identity.Test.Common; using Microsoft.Identity.Test.Common.Core.Helpers; using Microsoft.Identity.Test.Integration.Infrastructure; @@ -137,7 +133,6 @@ public async Task AcquireTokenFromAdfsUsernamePasswordAsync() Assert.AreEqual(TokenSource.IdentityProvider, authResult.AuthenticationResultMetadata.TokenSource); Assert.IsNotNull(authResult.AccessToken); Assert.IsNotNull(authResult.IdToken); - TestCommon.ValidateNoKerberosTicketFromAuthenticationResult(authResult); } #endregion @@ -330,7 +325,6 @@ AuthenticationResult authResult Assert.IsNull(authResult.Account.GetTenantProfiles()); } - TestCommon.ValidateNoKerberosTicketFromAuthenticationResult(authResult); // If test fails with "user needs to consent to the application, do an interactive request" error, // Do the following: // 1) Add in code to pull the user's password, and put a breakpoint there. diff --git a/tests/Microsoft.Identity.Test.Integration.netcore/SeleniumTests/DeviceCodeFlowIntegrationTest.cs b/tests/Microsoft.Identity.Test.Integration.netcore/SeleniumTests/DeviceCodeFlowIntegrationTest.cs index 48cccc6765..20fc93ab86 100644 --- a/tests/Microsoft.Identity.Test.Integration.netcore/SeleniumTests/DeviceCodeFlowIntegrationTest.cs +++ b/tests/Microsoft.Identity.Test.Integration.netcore/SeleniumTests/DeviceCodeFlowIntegrationTest.cs @@ -5,13 +5,11 @@ using System.Threading.Tasks; using Microsoft.Identity.Client; using Microsoft.Identity.Client.Broker; -using Microsoft.Identity.Client.Kerberos; using Microsoft.Identity.Test.Common; using Microsoft.Identity.Test.Common.Core.Helpers; using Microsoft.Identity.Test.Integration.Infrastructure; using Microsoft.Identity.Test.Integration.Utils; using Microsoft.Identity.Test.LabInfrastructure; -using Microsoft.Identity.Test.Unit; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Microsoft.Identity.Test.Integration.SeleniumTests @@ -115,7 +113,6 @@ private async Task AcquireTokenWithDeviceCodeFlowAsync(LabResponse labResponse, Assert.IsNotNull(result); Assert.IsTrue(!string.IsNullOrEmpty(result.AccessToken)); - TestCommon.ValidateNoKerberosTicketFromAuthenticationResult(result); } private async Task AcquireTokenSilentAfterDeviceCodeFlowWithBrokerAsync(LabResponse labResponse, string userType) @@ -151,7 +148,6 @@ private async Task AcquireTokenSilentAfterDeviceCodeFlowWithBrokerAsync(LabRespo var account = result.Account as Account; Assert.IsTrue(account.AccountSource == "device_code_flow"); Assert.IsTrue(!string.IsNullOrEmpty(result.AccessToken)); - TestCommon.ValidateNoKerberosTicketFromAuthenticationResult(result); var silentTokenResult = await pca.AcquireTokenSilent(s_scopes, result.Account).ExecuteAsync(CancellationToken.None).ConfigureAwait(false); Assert.IsNotNull(silentTokenResult); diff --git a/tests/Microsoft.Identity.Test.Integration.netcore/SeleniumTests/InteractiveFlowTests.NetFwk.cs b/tests/Microsoft.Identity.Test.Integration.netcore/SeleniumTests/InteractiveFlowTests.NetFwk.cs index a3abb5a73b..8430e572b0 100644 --- a/tests/Microsoft.Identity.Test.Integration.netcore/SeleniumTests/InteractiveFlowTests.NetFwk.cs +++ b/tests/Microsoft.Identity.Test.Integration.netcore/SeleniumTests/InteractiveFlowTests.NetFwk.cs @@ -5,14 +5,10 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using System.Net; using System.Threading; using System.Threading.Tasks; using Microsoft.Identity.Client; using Microsoft.Identity.Client.Extensibility; -using Microsoft.Identity.Client.Internal; -using Microsoft.Identity.Client.Kerberos; -using Microsoft.Identity.Client.Utils; using Microsoft.Identity.Test.Common; using Microsoft.Identity.Test.Common.Core.Helpers; using Microsoft.Identity.Test.Integration.Infrastructure; @@ -266,7 +262,6 @@ private async Task RunTestForUserAsync(LabResponse labResp Assert.IsTrue(result.AuthenticationResultMetadata.DurationTotalInMs > 0); Assert.IsTrue(result.AuthenticationResultMetadata.DurationInHttpInMs > 0); - TestCommon.ValidateNoKerberosTicketFromAuthenticationResult(result); userCacheAccess.AssertAccessCounts(0, 1); IAccount account = await MsalAssert.AssertSingleAccountAsync(labResponse, pca, result).ConfigureAwait(false); @@ -296,7 +291,6 @@ private async Task RunTestForUserAsync(LabResponse labResp .ConfigureAwait(false); userCacheAccess.AssertAccessCounts(2, 3); AssertCcsRoutingInformationIsSent(factory, labResponse); - TestCommon.ValidateNoKerberosTicketFromAuthenticationResult(result); account = await MsalAssert.AssertSingleAccountAsync(labResponse, pca, result).ConfigureAwait(false); userCacheAccess.AssertAccessCounts(3, 3); @@ -313,8 +307,6 @@ private async Task RunTestForUserAsync(LabResponse labResp .ExecuteAsync(CancellationToken.None) .ConfigureAwait(false); - TestCommon.ValidateNoKerberosTicketFromAuthenticationResult(result); - Trace.WriteLine("Part 5 - Acquire a token silently with force refresh"); result = await pca .AcquireTokenSilent(s_scopes, account) @@ -325,7 +317,6 @@ private async Task RunTestForUserAsync(LabResponse labResp await MsalAssert.AssertSingleAccountAsync(labResponse, pca, result).ConfigureAwait(false); Assert.IsFalse(userCacheAccess.LastAfterAccessNotificationArgs.IsApplicationCache); AssertCcsRoutingInformationIsSent(factory, labResponse); - TestCommon.ValidateNoKerberosTicketFromAuthenticationResult(result); return result; } @@ -384,7 +375,6 @@ private async Task RunPromptTestForUserAsync(LabResponse labResponse, Prompt pro .ConfigureAwait(false); await MsalAssert.AssertSingleAccountAsync(labResponse, pca, result).ConfigureAwait(false); - TestCommon.ValidateNoKerberosTicketFromAuthenticationResult(result); } private SeleniumWebUI CreateSeleniumCustomWebUI(LabUser user, Prompt prompt, bool withLoginHint = false, bool adfsOnly = false) diff --git a/tests/Microsoft.Identity.Test.Unit/Kerberos/KerberosSupplementalTicketManagerTests.cs b/tests/Microsoft.Identity.Test.Unit/Kerberos/KerberosSupplementalTicketManagerTests.cs deleted file mode 100644 index d2897fa6a3..0000000000 --- a/tests/Microsoft.Identity.Test.Unit/Kerberos/KerberosSupplementalTicketManagerTests.cs +++ /dev/null @@ -1,181 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#if NETFRAMEWORK -using System.Linq; -using Microsoft.Identity.Client.Kerberos; -using Microsoft.Identity.Client.Utils; -using Microsoft.Identity.Json.Linq; -using Microsoft.Identity.Test.Common; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Microsoft.Identity.Test.Unit.Kerberos -{ - /// - /// For an overview of Kerberos and testing please see: - /// https://identitydivision.visualstudio.com/IdentityWiki/_wiki/wikis/IdentityWiki.wiki/20501/-AADK-AAD-Kerberos - /// https://identitydivision.visualstudio.com/IdentityWiki/_wiki/wikis/IdentityWiki.wiki/20601/AAD-Kerberos-for-MSAL - /// - [TestClass] - public class KerberosSupplementalTicketManagerTests - { - /// - /// Service principal name for testing. - /// - private static readonly string _testServicePrincipalName = "HTTP/prod.aadkreberos.msal.com"; - - /// - /// Username within the ID token. - /// - private static readonly string _testClientName = "localAdmin@aadktest.onmicrosoft.com"; - - /// - /// Sample ID Token without Kerbero Service Ticket. - /// - private static readonly string _testIdToken = - "eyJ0eXAiOiJKV1QiLCJyaCI6IjAuQWdBQXI0R0lRckdhczBDQldEWVJOWV9fYUlLMElWSlJKck5NbXRqQW1uamszcDRzQU5NLiIsImFsZyI6IlJTMjU2" - + "Iiwia2lkIjoibk9vM1pEck9EWEVLMWpLV2hYc2xIUl9LWEVnIn0.eyJhdWQiOiI1MjIxYjQ4Mi0yNjUxLTRjYjMtOWFkOC1jMDlhNzhlNGRlOWUiLCJp" - + "c3MiOiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vNDI4ODgxYWYtOWFiMS00MGIzLTgxNTgtMzYxMTM1OGZmZjY4L3YyLjAiLCJpYXQi" - + "OjE2MjAwNjU1NjksIm5iZiI6MTYyMDA2NTU2OSwiZXhwIjoxNjIwMDY5NDY5LCJhaW8iOiJBVFFBeS84VEFBQUErU2NsWnFRQ1hWeFUvTER2Zi9MbDMv" - + "bk8rRGlJczFNek1NbTdoYUNoeEdIa1MycFFVaVBEVlFzd0Qyd1Vvd2t5IiwibmFtZSI6ImxvY2FsQWRtaW4iLCJvaWQiOiIyZGEyYmNmZi03YzVmLTQ4" - + "OTEtYTFlNC1kYTU1Yjg2NmNjZDgiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJsb2NhbEFkbWluQGFhZGt0ZXN0Lm9ubWljcm9zb2Z0LmNvbSIsInJoIjoi" - + "SSIsInN1YiI6IkZGbjhTTENyZXdEcDdBTEZ0OF9fUnNkUWJHV0VLOV9JbzhHcW1QTWVVX1EiLCJ0aWQiOiI0Mjg4ODFhZi05YWIxLTQwYjMtODE1OC0z" - + "NjExMzU4ZmZmNjgiLCJ1dGkiOiJTNDJOTUlVQkMwU0RhVkxtQVJBZkFBIiwidmVyIjoiMi4wIn0.LONtuRER9-wKeaAkH7qfqrWPd6fZNEC4KqibSewb" - + "xz1bwscP37_HQs-mEAKcK20txLgnHhyBG9JESllnWrEhEjrRYwYhWMN9NxlZCaMm2elFh-CfMBNHxTRFcQaHKEATN07gNZmEFLHOTDHn9s1wmSLIHpM7" - + "UzMdLY9ifSWRcBesmi4kv3VVPHuMP8PruO0jQIVkDUyuEs9BvHh1mvO2cpmR_q2ICpMnREUd2KrrM8PU3yDkmhxIZpXwwDO_MGNFyt4hMlAY01qTiT2V" - + "G7KmTjWnsxUZq3ozyZWiSYAMgmbDqEPs0dYwniV0HnR4MTvpkoOPc3ohowUve-qNRT8brQ"; - - /// - /// Sample ID token sample with Kerberos Service Ticket. - /// - private static readonly string _testIdTokenWithKerberosTicketClaim = - "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Im5PbzNaRHJPRFhFSzFqS1doWHNsSFJfS1hFZyJ9.eyJhdWQiOiI1MjIxYjQ4Mi0yNjUxLTRj" - + "YjMtOWFkOC1jMDlhNzhlNGRlOWUiLCJpc3MiOiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vNDI4ODgxYWYtOWFiMS00MGIzLTgxNTgtMz" - + "YxMTM1OGZmZjY4L3YyLjAiLCJpYXQiOjE2MTk4MTg1MTgsIm5iZiI6MTYxOTgxODUxOCwiZXhwIjoxNjE5ODIyNDE4LCJhaW8iOiJBVFFBeS84VEFBQUFP" - + "em02eVhVWVoxM0xCV0l0ak14KytaMzVLZ3NiSlJJYkpVdzY1em9uWXRaR1dscWlWbXJjcXBwUkpoRDc5bGpRIiwibmFtZSI6ImxvY2FsQWRtaW4iLCJvaW" - + "QiOiIyZGEyYmNmZi03YzVmLTQ4OTEtYTFlNC1kYTU1Yjg2NmNjZDgiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJsb2NhbEFkbWluQGFhZGt0ZXN0Lm9ubWlj" - + "cm9zb2Z0LmNvbSIsInJoIjoiMC5BU3dBcjRHSVFyR2FzMENCV0RZUk5ZX19hSUswSVZKUkpyTk1tdGpBbW5qazNwNHNBTk0uIiwic3ViIjoiRkZuOFNMQ3" - + "Jld0RwN0FMRnQ4X19Sc2RRYkdXRUs5X0lvOEdxbVBNZVVfUSIsInRpZCI6IjQyODg4MWFmLTlhYjEtNDBiMy04MTU4LTM2MTEzNThmZmY2OCIsInV0aSI6" - + "InM3V3lid29PN2tLUEpQNS1iZTFSQWciLCJ2ZXIiOiIyLjAiLCJ4bXNfYXNfcmVwIjoie1wia2V5VHlwZVwiOjE4LFwibWVzc2FnZUJ1ZmZlclwiOlwiZG" - + "9JSEFUQ0NCdjJnQXdJQkJhRURBZ0VXb29JRmlqQ0NCWVpoZ2dXQ01JSUZmcUFEQWdFRm9SNGJIRXRGVWtKRlVrOVRMazFKUTFKUFUwOUdWRTlPVEVsT1JT" - + "NURUMDJpTERBcW9BTUNBUUtoSXpBaEd3UklWRlJRR3hsd2NtOWtMbUZoWkd0eVpXSmxjbTl6TG0xellXd3VZMjl0bzRJRkp6Q0NCU09nQXdJQkVxS0NCUm" - + "9FZ2dVV05JWklyd29jaEx5NHBaS3ZUbmZPcTZpWUJGd0l5dFFseXF0R2N6a1d2V2RMcFhzN3JMeUsxUmhKK2FOMHBLUXlPWXFBZ1YwTFdOekYzaGJQYWgz" - + "aGMyd01yZUxmb25Gdnl3akVrNisva2w4Q0VEbGxhL0hlV2ZRL0paYWNJKzVkZDBRM3B2NzBHOVBOMnRpTFNtVnF6UXZoTUtpTUVHTk5JTDk3dWIrRzhOVW" - + "tkT25RSUNTVXdsNXdyTUQ2anNjK0N2M2cvSVdIZm53d2htQUFqa3EyTjNzUkU2SWN6bTdGSW1uSEtLZE5YU1Y3WDdRc1l4cE1DdWYrOVhqRVZmQmRyTmF0" - + "bFNxaE43N3crc3NWS25odFZQdm9YZVFHUUJtVkgyWGVPVDFyVjFwRDFuZDV3TmVBdkJPdzg0Y1pSNFBud05KVCtJZ0F4alJOR0Izbjc4c2pZQyt4MFlJbG" - + "FoWHQ2VFVvU2Q5U3Q2UWFNbjdhWmxlenNIa0FYVVljUlpCSGxsUmpqQ3o0SGpmWWpGTjF1cFo5Ymo5TVhINXJJL1Yrbm52ZzJ2d284RjU4N2RyMGJQYUVT" - + "cVUvVytwUGNJTWs2UUlwOTBVc3Q4bVJ3NDhTRjhPY0k2QjQwZEgvKzU3UmlSTDMxUERiTUZhMi9BOXIzSjhJSGFiUndpQm1hYk5Ld2pOVlExQXhpWjR3Yk" - + "JpNWFXZkdjdFJCY1dvU2FOY2l3bFUvYWVYWGZuRXFObzlsN2pmeXJLOWRRQ1RIOTYvdGZVdDAyMzdBR0pYZnNjVUhhQU5McnFodUhMZnJLeElwRUFFNkdW" - + "RTJBdW5sTjRsSVNtaXoyWVo2aVYvZmVpSXdFVVloa0cybFVxY2ZJbTVYNFNJbE9BYnkwOUJQMTRrVjlUc0Q5ZXBlNDMyaHR1dE1YTEs0TUVDSVlndjBFYT" - + "hTOGk2R2tINmk1WWJOOXBZbVUvenJtQStlaXROQ1Q1ZEFUdHRBSHpIbHhZMVFxWU1pMU0yd2Y4MEJCOVFGcGFBS0NyeEx6T0dRMmFIeGNEb3RIUk53MTZl" - + "RlZCSHdFN3pubUw2ZlRkRWhFK1dKZG1hMnNMcUVJdWNraDdJayt1R09ieldwZU1oNklKa0tYT0FOS05EbERUd2ZEMDNlbEg5SFNFUjZ2Tk0rbjdwdExDZX" - + "RoZFYzcWs2bFIwSzVvODlqeUEweFBwMUpxdFhWQVMvRXMyd1BzN01tczh2UXZ1ZlBPUVVyeHJFWk1xLzlYZDA2WlRMY0xTQXZBbXRzL2ZJb05ZZUxCK0Vj" - + "V1A0UitwemdaL3RQS3ZFT1VJVUNQTVJlUnY0cDFlZmpjQm51NlZyUU9vSGdPRkFDblZHSnZZN0tNMk9iU1JxK3hxVkVnL3dock1QbUdUTEtJTkFWYkpOQW" - + "44V2MrTVRRZFc0M1dHNjRRRDMxTjVVZnJWY29Sc1dSb0dwYWM3UmNYb1d4cVliaHJIV29lRWRMR3Z6eTZ2Nm9FREt2S2VWZndnS3FKQ3g3QnVweFBuamlM" - + "RW56UXdBdDFRNVByamFFTDNFY2hQN0VJWkVmczBudnNpTUo2ZFp0VWovMHNuVHhieXQyRDB1L2JlVitKbm1tT1ZNa2FXS3FJWjRvQnJwWit2SS9KcFc4dU" - + "o3Z0N0YWJjM0RpZUxPRm5HY0NHODltVHdWczhEYlBuSVlzTVE2dm9neE5QZUpyYnJyQVVCS2w2NU41TmhJeGVpQjVoMGI1dVJFKzlBaWZpd1ViOERUYzdr" - + "Z2x4b094NEk0MnFrOEFZZ0lWR0xuNjVRU25rT1AyVThBNkpVdVNNeTBVRHdxbzNrUEN2dFJJUE9ybHpTUkRpMG5KeStMcHQzZEtyTjNlRFJJeE1rcm1jZV" - + "NxRnVDcGgwMkV3Lzc2eVQwazJnYXVrTWk1V2lCb2NRM3lnbm9nY1hRNnlydzYwanJVcmU3UHZTcWpGeGxlTHg3OEc0bVBEaWw0NWluVTdtd09GRHk3Visx" - + "Tkw4OW9KampBdll6TEwweFovaUFVbDdIQjF6OXZSSW5DUWcrUHRPeTNKYW0vK29nL2hmbjAzQnJQakxvcU1oR1cvZlBxd2h4NHhsQTVRMEgzRWk5MHh6Sn" - + "FmUHREbHN3WHp4aFNsaXB5UW81LzFJTHdlUlY0M3Q1YjV5K2lma1NveXlWaTdCWHZiTDZZZVVxeTlMNHY4Wjl2N2hKUkEzTEpKR2xTZjgzNVJ2STgzR0lz" - + "aFVyVUVCS2t2TGhxNStZV09GWlA2UzYrN2lScXl0dUw2a3E4Mm9Ddjl0SFpzWUN2ejByNng1KzMvWXNNbzRJQllUQ0NBVjJnQXdJQkFLS0NBVlFFZ2dGUW" - + "ZZSUJURENDQVVpZ2dnRXFNSUlCSmpDQ0FTS2dLekFwb0FNQ0FSS2hJZ1FnR1lCbzg5bndwblgxeEphRW82aCs2QmlrRlFad2ZEYXFqT1dmUG0wNXFOaWhI" - + "aHNjUzBWU1FrVlNUMU11VFVsRFVrOVRUMFpVVDA1TVNVNUZMa05QVGFJd01DNmdBd0lCQWFFbk1DVWJJMnh2WTJGc1FXUnRhVzVBWVdGa2EzUmxjM1F1Yj" - + "I1dGFXTnliM052Wm5RdVkyOXRvd2NEQlFBQWdBQUFwQkVZRHpJd01qRXdORE13TWpFME1ERTVXcVVSR0E4eU1ESXhNRFF6TURJeE5EQXhPVnFtRVJnUE1q" - + "QXlNVEEwTXpBeU1qUXdNVGxhcHhFWUR6SXdNakV3TlRBM01qRTBNREU1V3FnZUd4eExSVkpDUlZKUFV5NU5TVU5TVDFOUFJsUlBUa3hKVGtVdVEwOU5xU3" - + "d3S3FBREFnRUNvU013SVJzRVNGUlVVQnNaY0hKdlpDNWhZV1JyY21WaVpYSnZjeTV0YzJGc0xtTnZiYUlSR0E4eU1ESXhNRFF6TURJeE5EQXhPVnFqQlFJ" - + "RDlIZUxcIixcInJlYWxtXCI6XCJLRVJCRVJPUy5NSUNST1NPRlRPTkxJTkUuQ09NXCIsXCJzblwiOlwiSFRUUC9wcm9kLmFhZGtyZWJlcm9zLm1zYWwuY2" - + "9tXCIsXCJjblwiOlwibG9jYWxBZG1pbkBhYWRrdGVzdC5vbm1pY3Jvc29mdC5jb21cIixcImFjY291bnRUeXBlXCI6Mn0ifQ.j3LGWzeEDAmzJrRXSWK41" - + "HACEAIPr5g3j7Df0xC2V0FszD9e8GgC_GjNFhaSl0uNXzPoKnI7zwl90zlvJNx4NUh-ZzBbY59JDL6B2o1i9Mb-K3KrGJLRf6s1Mp1Z2lFve6d57eri3EF" - + "P0lxMESvknYs0zk9Z9yTDxdadAO9R46mrJhPcZSpuip6yexOeT-XoxRZwIdOZVMd1EwXao26q_3BeQ3N19kbkv6Dr9EPCT36_1sTzytcHBein9h4Yixmk9" - + "sPtueCF3vqdO5Yl3Q0bBrksqFelwZB8sxz9y1vOQ5cfraYJc6JkWRiRy26YFrZe2UnuBGV2ss_1sSm7aE1gaw"; - - [TestInitialize] - public void TestInit() - { - TestCommon.ResetInternalStaticCaches(); - } - - [TestMethod] - public void FromIdToken_WithKerberosTicket() - { - KerberosSupplementalTicket ticket = KerberosSupplementalTicketManager.FromIdToken(_testIdTokenWithKerberosTicketClaim); - - Assert.IsNotNull(ticket); - Assert.IsTrue(string.IsNullOrEmpty(ticket.ErrorMessage)); - Assert.IsFalse(string.IsNullOrEmpty(ticket.KerberosMessageBuffer)); - Assert.AreEqual(_testServicePrincipalName, ticket.ServicePrincipalName, "Service principal name is not matched."); - Assert.AreEqual(_testClientName, ticket.ClientName, "Client name is not matched."); - } - - [TestMethod] - public void FromIdToken_WithoutKerberosTicket() - { - KerberosSupplementalTicket ticket = KerberosSupplementalTicketManager.FromIdToken(_testIdToken); - - Assert.IsNull(ticket); - } - - [TestMethod] - public void GetKrbCred() - { - KerberosSupplementalTicket ticket = KerberosSupplementalTicketManager.FromIdToken(_testIdTokenWithKerberosTicketClaim); - byte[] krbCred = KerberosSupplementalTicketManager.GetKrbCred(ticket); - - Assert.IsNotNull(krbCred); - } - - [TestMethod] - public void GetKerberosTicketClaim_IdToken() - { - string kerberosClaim - = KerberosSupplementalTicketManager.GetKerberosTicketClaim(_testServicePrincipalName, KerberosTicketContainer.IdToken); - - Assert.IsFalse(string.IsNullOrEmpty(kerberosClaim)); - JsonHelper.DeserializeFromJson(kerberosClaim); - - JObject claim = JObject.Parse(kerberosClaim); - Assert.IsNotNull(claim); - - Assert.IsTrue(claim.ContainsKey("id_token")); - JToken idToken = claim.GetValue("id_token"); - - - Assert.IsNotNull(idToken); - - - CheckKerberosClaim(idToken); - } - - [TestMethod] - public void GetKerberosTicketClaim_AccessToken() - { - string kerberosClaim - = KerberosSupplementalTicketManager.GetKerberosTicketClaim(_testServicePrincipalName, KerberosTicketContainer.AccessToken); - - Assert.IsFalse(string.IsNullOrEmpty(kerberosClaim)); - - JObject claim = JObject.Parse(kerberosClaim); - Assert.IsNotNull(claim); - - Assert.IsTrue(claim.ContainsKey("access_token")); - JToken accessToken = claim.GetValue("access_token"); - Assert.IsNotNull(accessToken); - - CheckKerberosClaim(accessToken); - } - - private void CheckKerberosClaim(JToken claim) - { - JToken asRep = claim["xms_as_rep"]; - Assert.IsNotNull(asRep); - - Assert.AreEqual("false", asRep["essential"].Value(), - "essential field is not matched."); - - Assert.AreEqual(_testServicePrincipalName, asRep["value"].Value(), - "Service principal name is not matched."); - } - } -} -#endif From e5308ab8ed54f6a2d9f7a20de13cf41b33f1579d Mon Sep 17 00:00:00 2001 From: Neha Bhargava <61847233+neha-bhargava@users.noreply.github.com> Date: Thu, 18 Sep 2025 09:28:36 -0700 Subject: [PATCH 3/5] Remove the internal logic --- .../OAuth2/TokenClient.cs | 43 +------------------ 1 file changed, 1 insertion(+), 42 deletions(-) diff --git a/src/client/Microsoft.Identity.Client/OAuth2/TokenClient.cs b/src/client/Microsoft.Identity.Client/OAuth2/TokenClient.cs index ba21483642..2753726580 100644 --- a/src/client/Microsoft.Identity.Client/OAuth2/TokenClient.cs +++ b/src/client/Microsoft.Identity.Client/OAuth2/TokenClient.cs @@ -149,10 +149,7 @@ await _serviceBundle.Config.ClientCredential.AddConfidentialClientParametersAsyn _oAuth2Client.AddBodyParameter(OAuth2Parameter.Scope, scopes); - // Add Kerberos Ticket claims if there's valid service principal name in Configuration. - // Kerberos Ticket claim is only allowed at token request due to security issue. - // It should not be included for authorize request. - AddClaims(); + _oAuth2Client.AddBodyParameter(OAuth2Parameter.Claims, _requestParams.ClaimsAndClientCapabilities); foreach (var kvp in additionalBodyParameters) { @@ -183,44 +180,6 @@ await _serviceBundle.Config.ClientCredential.AddConfidentialClientParametersAsyn AddExtraHttpHeaders(); } - /// - /// Add Claims, including ClientCapabilities, to body parameter for POST request. - /// - private void AddClaims() - { -#pragma warning disable CS0612 // Type or member is obsolete - string kerberosClaim = KerberosSupplementalTicketManager.GetKerberosTicketClaim( - _requestParams.RequestContext.ServiceBundle.Config.KerberosServicePrincipalName, - _requestParams.RequestContext.ServiceBundle.Config.TicketContainer); -#pragma warning restore CS0612 // Type or member is obsolete - string resolvedClaims; - if (string.IsNullOrEmpty(kerberosClaim)) - { - resolvedClaims = _requestParams.ClaimsAndClientCapabilities; - } - else - { - if (!string.IsNullOrEmpty(_requestParams.ClaimsAndClientCapabilities)) - { - var existingClaims = JsonHelper.ParseIntoJsonObject(_requestParams.ClaimsAndClientCapabilities); - var mergedClaims = ClaimsHelper.MergeClaimsIntoCapabilityJson(kerberosClaim, existingClaims); - - resolvedClaims = JsonHelper.JsonObjectToString(mergedClaims); - _requestParams.RequestContext.Logger.Verbose( - () => $"Adding kerberos claim + Claims/ClientCapabilities to request: {resolvedClaims}"); - } - else - { - resolvedClaims = kerberosClaim; - _requestParams.RequestContext.Logger.Verbose( - () => $"Adding kerberos claim to request: {resolvedClaims}"); - } - } - - // no-op if resolvedClaims is null - _oAuth2Client.AddBodyParameter(OAuth2Parameter.Claims, resolvedClaims); - } - private void AddExtraHttpHeaders() { if (_requestParams.ExtraHttpHeaders != null) From fc02d18b306aee86a9dfbbdbc862f61c414e255c Mon Sep 17 00:00:00 2001 From: Neha Bhargava <61847233+neha-bhargava@users.noreply.github.com> Date: Wed, 1 Oct 2025 14:59:02 -0700 Subject: [PATCH 4/5] Delete all internal logic --- .../PublicClientApplicationBuilder.cs | 2 - .../KerberosSupplementalTicketManager.cs | 63 +-- .../DesktopOS/Kerberos/ContextStatus.cs | 17 - .../Features/DesktopOS/Kerberos/Credential.cs | 11 +- .../DesktopOS/Kerberos/CredentialHandle.cs | 37 -- .../DesktopOS/Kerberos/InitContextFlag.cs | 34 -- .../DesktopOS/Kerberos/LsaBufferSafeHandle.cs | 28 -- .../DesktopOS/Kerberos/LsaSafeHandle.cs | 30 -- .../DesktopOS/Kerberos/LsaTokenSafeHandle.cs | 50 -- .../DesktopOS/Kerberos/NativeMethods.cs | 466 ------------------ .../Features/DesktopOS/Kerberos/SecStatus.cs | 38 -- .../Kerberos/SecurityContextAttribute.cs | 21 - .../DesktopOS/Kerberos/SspiSecurityContext.cs | 190 ------- .../DesktopOS/Kerberos/TicketCacheReader.cs | 77 --- .../DesktopOS/Kerberos/TicketCacheWriter.cs | 175 ------- 15 files changed, 8 insertions(+), 1231 deletions(-) delete mode 100644 src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/ContextStatus.cs delete mode 100644 src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/CredentialHandle.cs delete mode 100644 src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/InitContextFlag.cs delete mode 100644 src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/LsaBufferSafeHandle.cs delete mode 100644 src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/LsaSafeHandle.cs delete mode 100644 src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/LsaTokenSafeHandle.cs delete mode 100644 src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/NativeMethods.cs delete mode 100644 src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/SecStatus.cs delete mode 100644 src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/SecurityContextAttribute.cs delete mode 100644 src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/SspiSecurityContext.cs delete mode 100644 src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/TicketCacheReader.cs delete mode 100644 src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/TicketCacheWriter.cs diff --git a/src/client/Microsoft.Identity.Client/AppConfig/PublicClientApplicationBuilder.cs b/src/client/Microsoft.Identity.Client/AppConfig/PublicClientApplicationBuilder.cs index 59eed2e90c..d5150fd017 100644 --- a/src/client/Microsoft.Identity.Client/AppConfig/PublicClientApplicationBuilder.cs +++ b/src/client/Microsoft.Identity.Client/AppConfig/PublicClientApplicationBuilder.cs @@ -327,8 +327,6 @@ public PublicClientApplicationBuilder WithParentActivityOrWindow(Func wi [EditorBrowsable(EditorBrowsableState.Never)] public PublicClientApplicationBuilder WithKerberosTicketClaim(string servicePrincipalName, KerberosTicketContainer ticketContainer) { - Config.KerberosServicePrincipalName = servicePrincipalName; - Config.TicketContainer = ticketContainer; return this; } diff --git a/src/client/Microsoft.Identity.Client/Kerberos/KerberosSupplementalTicketManager.cs b/src/client/Microsoft.Identity.Client/Kerberos/KerberosSupplementalTicketManager.cs index dec0f903b0..99b0a0910b 100644 --- a/src/client/Microsoft.Identity.Client/Kerberos/KerberosSupplementalTicketManager.cs +++ b/src/client/Microsoft.Identity.Client/Kerberos/KerberosSupplementalTicketManager.cs @@ -97,26 +97,7 @@ public static void SaveToWindowsTicketCache(KerberosSupplementalTicket ticket) /// public static void SaveToWindowsTicketCache(KerberosSupplementalTicket ticket, long logonId) { -#if !SUPPORTS_WIN32 - throw new PlatformNotSupportedException("Ticket Cache interface is not supported for this .NET platform. It is supported on .NET Classic, .NET Core and NetStandadrd"); -#else - if (!DesktopOsHelper.IsWindows()) - { - throw new PlatformNotSupportedException("Ticket Cache interface is not supported on this OS. It is supported on Windows only."); - - } - - if (ticket == null || string.IsNullOrEmpty(ticket.KerberosMessageBuffer)) - { - throw new ArgumentException("Kerberos Ticket information is not valid"); - } - - using (var cache = Platforms.Features.DesktopOs.Kerberos.TicketCacheWriter.Connect()) - { - byte[] krbCred = Convert.FromBase64String(ticket.KerberosMessageBuffer); - cache.ImportCredential(krbCred, logonId); - } -#endif + throw new NotImplementedException("This method is deprecated."); } /// @@ -146,20 +127,7 @@ public static byte[] GetKerberosTicketFromWindowsTicketCache(string servicePrinc /// public static byte[] GetKerberosTicketFromWindowsTicketCache(string servicePrincipalName, long logonId) { -#if !SUPPORTS_WIN32 - throw new PlatformNotSupportedException("Ticket Cache interface is not supported for this .NET platform. It is supported on .NET Classic, .NET Core and NetStandadrd"); -#else - if (!DesktopOsHelper.IsWindows()) - { - throw new PlatformNotSupportedException("Ticket Cache interface is not supported on this OS. It is supported on Windows only."); - - } - - using (var reader = new Platforms.Features.DesktopOs.Kerberos.TicketCacheReader(servicePrincipalName, logonId)) - { - return reader.RequestToken(); - } -#endif + throw new NotImplementedException("This method is deprecated."); } /// @@ -177,32 +145,5 @@ public static byte[] GetKrbCred(KerberosSupplementalTicket ticket) return null; } - - /// - /// Generate a Kerberos Ticket Claim string. - /// - /// Service principal name to use. - /// Ticket container to use. - /// A Kerberos Ticket Claim string if valid service principal name was given. Empty string, otherwise. - internal static string GetKerberosTicketClaim(string servicePrincipalName, KerberosTicketContainer ticketContainer) - { - if (string.IsNullOrEmpty(servicePrincipalName)) - { - return string.Empty; - } - - if (ticketContainer == KerberosTicketContainer.IdToken) - { - return string.Format( - CultureInfo.InvariantCulture, - IdTokenAsRepTemplate, - servicePrincipalName); - } - - return string.Format( - CultureInfo.InvariantCulture, - AccessTokenAsRepTemplate, - servicePrincipalName); - } } } diff --git a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/ContextStatus.cs b/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/ContextStatus.cs deleted file mode 100644 index 7ab10d0897..0000000000 --- a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/ContextStatus.cs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -namespace Microsoft.Identity.Client.Platforms.Features.DesktopOs.Kerberos -{ - /// - /// Result of AcceptSecurityContext (CredSSP) function call which lets the server component of a transport application - /// establish a security context between the server and a remote client. - /// https://learn.microsoft.com/windows/win32/api/sspi/nf-sspi-acceptsecuritycontext - /// - internal enum ContextStatus - { - RequiresContinuation, - Accepted, - Error - } -} diff --git a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/Credential.cs b/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/Credential.cs index 37307a5f9e..0077b86394 100644 --- a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/Credential.cs +++ b/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/Credential.cs @@ -1,15 +1,19 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +using System; +using System.ComponentModel; + namespace Microsoft.Identity.Client.Platforms.Features.DesktopOs.Kerberos { /// /// Previously authenticated logon data used by a security principal to establish its own identity, /// such as a password, or a Kerberos protocol ticket. /// + [Obsolete] + [EditorBrowsable(EditorBrowsableState.Never)] public abstract class Credential { - internal abstract CredentialHandle Structify(); /// /// Create a new object. @@ -22,10 +26,7 @@ public static Credential Current() private class CurrentCredential : Credential { - internal override unsafe CredentialHandle Structify() - { - return new CredentialHandle((void*)0); - } + } } } diff --git a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/CredentialHandle.cs b/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/CredentialHandle.cs deleted file mode 100644 index e900ca2c6c..0000000000 --- a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/CredentialHandle.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using System.Runtime.InteropServices; - -namespace Microsoft.Identity.Client.Platforms.Features.DesktopOs.Kerberos -{ - /// - /// Extension of a wrapper class for operating system handles. - /// - internal class CredentialHandle : SafeHandle - { - /// - /// Constructor. - /// - /// Credential handle to initialize. - public unsafe CredentialHandle(void* cred) - : base(new IntPtr(cred), true) - { - } - - /// - /// Checks the current contained handle is valid or not. - /// - public override bool IsInvalid => handle == IntPtr.Zero; - - /// - /// Release contained internal resource object. - /// - /// True always. - protected override bool ReleaseHandle() - { - return true; - } - } -} diff --git a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/InitContextFlag.cs b/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/InitContextFlag.cs deleted file mode 100644 index b078244183..0000000000 --- a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/InitContextFlag.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; - -namespace Microsoft.Identity.Client.Platforms.Features.DesktopOs.Kerberos -{ - /// - /// Bit flags that indicate requests for the context for InitializeSecurityContext API call. - /// https://learn.microsoft.com/windows/win32/api/sspi/nf-sspi-initializesecuritycontexta - /// - [Flags] - internal enum InitContextFlag - { - Zero = 0, - Delegate = 0x00000001, - MutualAuth = 0x00000002, - ReplayDetect = 0x00000004, - SequenceDetect = 0x00000008, - Confidentiality = 0x00000010, - UseSessionKey = 0x00000020, - AllocateMemory = 0x00000100, - Connection = 0x00000800, - InitExtendedError = 0x00004000, - InitStream = 0x00008000, - InitIntegrity = 0x00010000, - InitManualCredValidation = 0x00080000, - InitUseSuppliedCreds = 0x00000080, - InitIdentify = 0x00020000, - ProxyBindings = 0x04000000, - AllowMissingBindings = 0x10000000, - UnverifiedTargetName = 0x20000000 - } -} diff --git a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/LsaBufferSafeHandle.cs b/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/LsaBufferSafeHandle.cs deleted file mode 100644 index 86bda31cb0..0000000000 --- a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/LsaBufferSafeHandle.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using System.Runtime.InteropServices; - -namespace Microsoft.Identity.Client.Platforms.Features.DesktopOs.Kerberos -{ - internal class LsaBufferSafeHandle : SafeHandle - { - public LsaBufferSafeHandle() - : base(IntPtr.Zero, true) - { - } - - public override bool IsInvalid => handle == IntPtr.Zero; - - protected override bool ReleaseHandle() - { - var result = NativeMethods.LsaFreeReturnBuffer(handle); - - NativeMethods.LsaThrowIfError(result); - - handle = IntPtr.Zero; - return true; - } - } -} diff --git a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/LsaSafeHandle.cs b/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/LsaSafeHandle.cs deleted file mode 100644 index 0b1099cf2c..0000000000 --- a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/LsaSafeHandle.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using System.Runtime.InteropServices; - -namespace Microsoft.Identity.Client.Platforms.Features.DesktopOs.Kerberos -{ - internal class LsaSafeHandle : SafeHandle - { - public LsaSafeHandle() - : base(IntPtr.Zero, true) - { - } - - public override bool IsInvalid => handle == IntPtr.Zero; - - protected override bool ReleaseHandle() - { - - int result = NativeMethods.LsaDeregisterLogonProcess(handle); - - NativeMethods.LsaThrowIfError(result); - - handle = IntPtr.Zero; - - return true; - } - } -} diff --git a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/LsaTokenSafeHandle.cs b/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/LsaTokenSafeHandle.cs deleted file mode 100644 index 188c38f74b..0000000000 --- a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/LsaTokenSafeHandle.cs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using System.ComponentModel; -using System.Runtime.InteropServices; - -namespace Microsoft.Identity.Client.Platforms.Features.DesktopOs.Kerberos -{ - internal class LsaTokenSafeHandle : SafeHandle - { - public LsaTokenSafeHandle() - : base(IntPtr.Zero, true) - { - } - - public bool Impersonating { get; private set; } - - public override bool IsInvalid => handle == IntPtr.Zero; - - protected override bool ReleaseHandle() - { - Revert(); - - if (!NativeMethods.CloseHandle(handle)) - { - var error = Marshal.GetLastWin32Error(); - - throw new Win32Exception(error); - } - return true; - } - - private void Revert() - { - if (!Impersonating) - { - return; - } - - if (!NativeMethods.RevertToSelf()) - { - var error = Marshal.GetLastWin32Error(); - - throw new Win32Exception(error); - } - Impersonating = false; - } - } -} diff --git a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/NativeMethods.cs b/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/NativeMethods.cs deleted file mode 100644 index dea8a02557..0000000000 --- a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/NativeMethods.cs +++ /dev/null @@ -1,466 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Runtime.InteropServices; - -namespace Microsoft.Identity.Client.Platforms.Features.DesktopOs.Kerberos -{ -#pragma warning disable 618 // This workaround required for Native Win32 API call - - internal unsafe class NativeMethods - { - private const string SECUR32 = "secur32.dll"; - private const string ADVAPI32 = "advapi32.dll"; - private const string KERNEL32 = "kernel32.dll"; - - [DllImport( - SECUR32, - EntryPoint = "InitializeSecurityContext", - CharSet = (CharSet)4, - BestFitMapping = false, - ThrowOnUnmappableChar = true, - SetLastError = true)] - internal static extern SecStatus InitializeSecurityContext_0( - ref SECURITY_HANDLE phCredential, - IntPtr phContext, - string pszTargetName, - InitContextFlag fContextReq, - int Reserved1, - int TargetDataRep, - IntPtr pInput, - int Reserved2, - ref SECURITY_HANDLE phNewContext, - ref SecBufferDesc pOutput, - out InitContextFlag pfContextAttr, - IntPtr ptsExpiry - ); - - [DllImport( - SECUR32, - CharSet = (CharSet)4, - BestFitMapping = false, - ThrowOnUnmappableChar = true, - EntryPoint = "AcquireCredentialsHandle")] - internal static extern SecStatus AcquireCredentialsHandle( - string pszPrincipal, - string pszPackage, - int fCredentialUse, - IntPtr PAuthenticationID, - void* pAuthData, - IntPtr pGetKeyFn, - IntPtr pvGetKeyArgument, - ref SECURITY_HANDLE phCredential, - IntPtr ptsExpiry - ); - - [DllImport(SECUR32)] - internal static extern uint FreeCredentialsHandle(SECURITY_HANDLE* handle); - - [DllImport(SECUR32)] - public static extern SecStatus DeleteSecurityContext(SECURITY_HANDLE* context); - - [DllImport(SECUR32)] - public static extern int LsaDeregisterLogonProcess( - IntPtr LsaHandle - ); - - [DllImport(SECUR32)] - public static extern int LsaLookupAuthenticationPackage( - LsaSafeHandle LsaHandle, - ref LSA_STRING PackageName, - out int AuthenticationPackage - ); - - [DllImport(SECUR32)] - public static extern int LsaConnectUntrusted( - [Out] out LsaSafeHandle LsaHandle - ); - - [DllImport(SECUR32)] - public static extern unsafe int LsaCallAuthenticationPackage( - LsaSafeHandle LsaHandle, - int AuthenticationPackage, - void* ProtocolSubmitBuffer, - int SubmitBufferLength, - out LsaBufferSafeHandle ProtocolReturnBuffer, - out int ReturnBufferLength, - out int ProtocolStatus - ); - - [DllImport(SECUR32)] - public static extern int LsaFreeReturnBuffer(IntPtr Buffer); - - [DllImport(ADVAPI32)] - public static extern int LsaNtStatusToWinError(int Status); - - [DllImport(KERNEL32)] - public static extern bool CloseHandle(IntPtr hObject); - - [DllImport(ADVAPI32)] - public static extern bool ImpersonateLoggedOnUser(LsaTokenSafeHandle hToken); - - [DllImport(ADVAPI32)] - public static extern bool RevertToSelf(); - - public static void LsaThrowIfError(int result) - { - if (result != 0) - { - result = LsaNtStatusToWinError(result); - - throw new Win32Exception(result); - } - } - - [StructLayout(LayoutKind.Sequential)] - public struct KERB_INTERACTIVE_LOGON - { - public KERB_LOGON_SUBMIT_TYPE MessageType; - public UNICODE_STRING LogonDomainName; - public UNICODE_STRING UserName; - public UNICODE_STRING Password; - } - - [StructLayout(LayoutKind.Sequential)] - public struct TOKEN_SOURCE - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public byte[] SourceName; // TOKEN_SOURCE_LENGTH - public LUID SourceIdentifier; - } - - [StructLayout(LayoutKind.Sequential)] - public struct KERB_S4U_LOGON - { - public KERB_LOGON_SUBMIT_TYPE MessageType; - public S4uFlags Flags; - public UNICODE_STRING ClientUpn; - public UNICODE_STRING ClientRealm; - } - - [StructLayout(LayoutKind.Sequential)] - public struct UNICODE_STRING - { - public ushort Length; - public ushort MaximumLength; - public IntPtr Buffer; - } - - [Flags] - public enum S4uFlags - { - KERB_S4U_LOGON_FLAG_CHECK_LOGONHOURS = 0x2, - KERB_S4U_LOGON_FLAG_IDENTIFY = 0x8 - } - - public enum KERB_LOGON_SUBMIT_TYPE - { - KerbInteractiveLogon = 2, - KerbSmartCardLogon = 6, - KerbWorkstationUnlockLogon = 7, - KerbSmartCardUnlockLogon = 8, - KerbProxyLogon = 9, - KerbTicketLogon = 10, - KerbTicketUnlockLogon = 11, - KerbS4ULogon = 12, - KerbCertificateLogon = 13, - KerbCertificateS4ULogon = 14, - KerbCertificateUnlockLogon = 15, - KerbNoElevationLogon = 83, - KerbLuidLogon = 84, - } - - public enum SECURITY_LOGON_TYPE - { - UndefinedLogonType = 0, - Interactive = 2, - Network, - Batch, - Service, - Proxy, - Unlock, - NetworkCleartext, - NewCredentials, - RemoteInteractive, - CachedInteractive, - CachedRemoteInteractive, - CachedUnlock - } - - [StructLayout(LayoutKind.Sequential)] - internal struct LSA_STRING - { - public ushort Length; - public ushort MaximumLength; - public string Buffer; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct LUID - { - public uint LowPart; - public int HighPart; - - public static implicit operator ulong(LUID luid) - { - ulong val = (ulong)luid.HighPart << 32; - - return val + luid.LowPart; - } - - public static implicit operator LUID(long luid) - { - return new LUID - { - LowPart = (uint)(luid & 0xffffffffL), - HighPart = (int)(luid >> 32) - }; - } - } - - [StructLayout(LayoutKind.Sequential)] - public struct KERB_SUBMIT_TKT_REQUEST - { - public KERB_PROTOCOL_MESSAGE_TYPE MessageType; - public LUID LogonId; - public int Flags; - public KERB_CRYPTO_KEY32 Key; - public int KerbCredSize; - public int KerbCredOffset; - } - - [StructLayout(LayoutKind.Sequential)] - public struct KERB_PURGE_TKT_CACHE_EX_REQUEST - { - public KERB_PROTOCOL_MESSAGE_TYPE MessageType; - public LUID LogonId; - public int Flags; - public KERB_TICKET_CACHE_INFO_EX TicketTemplate; - } - - [StructLayout(LayoutKind.Sequential)] - public struct KERB_TICKET_CACHE_INFO_EX - { - public UNICODE_STRING ClientName; - public UNICODE_STRING ClientRealm; - public UNICODE_STRING ServerName; - public UNICODE_STRING ServerRealm; - public long StartTime; - public long EndTime; - public long RenewTime; - public int EncryptionType; - public int TicketFlags; - } - - public enum KERB_PROTOCOL_MESSAGE_TYPE : uint - { - KerbDebugRequestMessage = 0, - KerbQueryTicketCacheMessage, - KerbChangeMachinePasswordMessage, - KerbVerifyPacMessage, - KerbRetrieveTicketMessage, - KerbUpdateAddressesMessage, - KerbPurgeTicketCacheMessage, - KerbChangePasswordMessage, - KerbRetrieveEncodedTicketMessage, - KerbDecryptDataMessage, - KerbAddBindingCacheEntryMessage, - KerbSetPasswordMessage, - KerbSetPasswordExMessage, - KerbVerifyCredentialsMessage, - KerbQueryTicketCacheExMessage, - KerbPurgeTicketCacheExMessage, - KerbRefreshSmartcardCredentialsMessage, - KerbAddExtraCredentialsMessage, - KerbQuerySupplementalCredentialsMessage, - KerbTransferCredentialsMessage, - KerbQueryTicketCacheEx2Message, - KerbSubmitTicketMessage, - KerbAddExtraCredentialsExMessage, - KerbQueryKdcProxyCacheMessage, - KerbPurgeKdcProxyCacheMessage, - KerbQueryTicketCacheEx3Message, - KerbCleanupMachinePkinitCredsMessage, - KerbAddBindingCacheEntryExMessage, - KerbQueryBindingCacheMessage, - KerbPurgeBindingCacheMessage, - KerbPinKdcMessage, - KerbUnpinAllKdcsMessage, - KerbQueryDomainExtendedPoliciesMessage, - KerbQueryS4U2ProxyCacheMessage, - KerbRetrieveKeyTabMessage, - KerbRefreshPolicyMessage - } - - [StructLayout(LayoutKind.Sequential)] - public struct KERB_CRYPTO_KEY32 - { - public int KeyType; - public int Length; - public int Offset; - } - - internal enum SecBufferType - { - SECBUFFER_VERSION = 0, - SECBUFFER_DATA = 1, - SECBUFFER_TOKEN = 2 - } - - [StructLayout(LayoutKind.Sequential)] - internal struct SECURITY_HANDLE - { - public ulong dwLower; - public ulong dwUpper; - - public bool IsSet => dwLower > 0 || dwUpper > 0; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct SECURITY_INTEGER - { - public uint LowPart; - public int HighPart; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct SecPkgContext_SecString - { - public void* sValue; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct SecBuffer - { - public int cbBuffer; - public SecBufferType BufferType; - public IntPtr pvBuffer; - - public SecBuffer(int bufferSize) - { - cbBuffer = bufferSize; - BufferType = SecBufferType.SECBUFFER_TOKEN; - pvBuffer = Marshal.AllocHGlobal(bufferSize); - } - - public SecBuffer(byte[] secBufferBytes) - : this(secBufferBytes.Length) - { - Marshal.Copy(secBufferBytes, 0, pvBuffer, cbBuffer); - } - - public void Dispose() - { - if (pvBuffer != IntPtr.Zero) - { - Marshal.FreeHGlobal(pvBuffer); - pvBuffer = IntPtr.Zero; - } - } - } - - [StructLayout(LayoutKind.Sequential)] - internal struct SecBufferDesc : IDisposable - { - private readonly SecBufferType ulVersion; - public int cBuffers; - public IntPtr pBuffers; // Point to SecBuffer - - public SecBufferDesc(int bufferSize) - : this(new SecBuffer(bufferSize)) - { - } - - public SecBufferDesc(byte[] secBufferBytes) - : this(new SecBuffer(secBufferBytes)) - { - } - - private SecBufferDesc(SecBuffer secBuffer) - { - ulVersion = SecBufferType.SECBUFFER_VERSION; - - cBuffers = 1; - - pBuffers = Marshal.AllocHGlobal(Marshal.SizeOf(secBuffer)); - - Marshal.StructureToPtr(secBuffer, pBuffers, false); - } - - public void Dispose() - { - if (pBuffers != IntPtr.Zero) - { - ForEachBuffer(thisSecBuffer => thisSecBuffer.Dispose()); - - // Freeing pBuffers - - Marshal.FreeHGlobal(pBuffers); - pBuffers = IntPtr.Zero; - } - } - - // Replace the usage of Marshal.PtrToStructure(IntPtr, Type) with the generic version Marshal.PtrToStructure(IntPtr) - // in the ForEachBuffer method inside SecBufferDesc struct. - private void ForEachBuffer(Action onBuffer) - { - for (int Index = 0; Index < cBuffers; Index++) - { - int CurrentOffset = Index * Marshal.SizeOf(); - - SecBuffer thisSecBuffer = (SecBuffer)Marshal.PtrToStructure( - IntPtr.Add( - pBuffers, - CurrentOffset - )); - - onBuffer(thisSecBuffer); - } - } - - public byte[] ReadBytes() - { - if (cBuffers <= 0) - { - return Array.Empty(); - } - - int finalLen = 0; - var bufferList = new List(); - - ForEachBuffer(thisSecBuffer => - { - if (thisSecBuffer.cbBuffer <= 0) - { - return; - } - - var buffer = new byte[thisSecBuffer.cbBuffer]; - - Marshal.Copy(thisSecBuffer.pvBuffer, buffer, 0, thisSecBuffer.cbBuffer); - - bufferList.Add(buffer); - - finalLen += thisSecBuffer.cbBuffer; - }); - - var finalBuffer = new byte[finalLen]; - - var position = 0; - - for (var i = 0; i < bufferList.Count; i++) - { - bufferList[i].CopyTo(finalBuffer, position); - - position += bufferList[i].Length - 1; - } - - return finalBuffer; - } - } - } -#pragma warning restore 618 -} diff --git a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/SecStatus.cs b/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/SecStatus.cs deleted file mode 100644 index bc3a1b646a..0000000000 --- a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/SecStatus.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -namespace Microsoft.Identity.Client.Platforms.Features.DesktopOs.Kerberos -{ - /// - /// Status code returned from SSPI functions. - /// https://learn.microsoft.com/windows/win32/api/sspi/nf-sspi-initializesecuritycontexta - /// - internal enum SecStatus : uint - { - SEC_E_OK = 0x0, - SEC_E_ERROR = 0x80000000, - SEC_E_INSUFFICIENT_MEMORY = 0x80090300, - SEC_E_INVALID_HANDLE = 0x80090301, - SEC_E_TARGET_UNKNOWN = 0x80090303, - SEC_E_UNSUPPORTED_FUNCTION = 0x80090302, - SEC_E_INTERNAL_ERROR = 0x80090304, - SEC_E_SECPKG_NOT_FOUND = 0x80090305, - SEC_E_INVALID_TOKEN = 0x80090308, - SEC_E_QOP_NOT_SUPPORTED = 0x8009030A, - SEC_E_LOGON_DENIED = 0x8009030C, - SEC_E_UNKNOWN_CREDENTIALS = 0x8009030D, - SEC_E_NO_CREDENTIALS = 0x8009030E, - SEC_E_MESSAGE_ALTERED = 0x8009030F, - SEC_E_OUT_OF_SEQUENCE = 0x80090310, - SEC_E_NO_AUTHENTICATING_AUTHORITY = 0x80090311, - SEC_E_CONTEXT_EXPIRED = 0x80090317, - SEC_E_INCOMPLETE_MESSAGE = 0x80090318, - SEC_E_BUFFER_TOO_SMALL = 0x80090321, - SEC_E_WRONG_PRINCIPAL = 0x80090322, - SEC_E_CRYPTO_SYSTEM_INVALID = 0x80090337, - SEC_I_CONTINUE_NEEDED = 0x00090312, - SEC_I_CONTEXT_EXPIRED = 0x00090317, - SEC_I_INCOMPLETE_CREDENTIALS = 0x00090320, - SEC_I_RENEGOTIATE = 0x00090321 - } -} diff --git a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/SecurityContextAttribute.cs b/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/SecurityContextAttribute.cs deleted file mode 100644 index 870ad8eb40..0000000000 --- a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/SecurityContextAttribute.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -namespace Microsoft.Identity.Client.Platforms.Features.DesktopOs.Kerberos -{ - internal enum SecurityContextAttribute - { - SECPKG_ATTR_SIZES = 0, - SECPKG_ATTR_NAMES = 1, - SECPKG_ATTR_LIFESPAN = 2, - SECPKG_ATTR_DCE_INFO = 3, - SECPKG_ATTR_STREAM_SIZES = 4, - SECPKG_ATTR_AUTHORITY = 6, - SECPKG_ATTR_PACKAGE_INFO = 10, - SECPKG_ATTR_NEGOTIATION_INFO = 12, - SECPKG_ATTR_UNIQUE_BINDINGS = 25, - SECPKG_ATTR_ENDPOINT_BINDINGS = 26, - SECPKG_ATTR_CLIENT_SPECIFIED_TARGET = 27, - SECPKG_ATTR_APPLICATION_PROTOCOL = 35 - } -} diff --git a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/SspiSecurityContext.cs b/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/SspiSecurityContext.cs deleted file mode 100644 index f0965be758..0000000000 --- a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/SspiSecurityContext.cs +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Runtime.InteropServices; -using Microsoft.Identity.Client.PlatformsCommon.Shared; - -namespace Microsoft.Identity.Client.Platforms.Features.DesktopOs.Kerberos -{ - internal partial class SspiSecurityContext : IDisposable - { - private const int SECPKG_CRED_BOTH = 0x00000003; - private const int SECURITY_NETWORK_DREP = 0x00; - - private const int _maxTokenSize = 16 * 1024; - - private const InitContextFlag _defaultRequiredFlags = - InitContextFlag.Connection | - InitContextFlag.ReplayDetect | - InitContextFlag.SequenceDetect | - InitContextFlag.Confidentiality | - InitContextFlag.AllocateMemory | - InitContextFlag.Delegate | - InitContextFlag.InitExtendedError; - - private readonly HashSet _disposable = new HashSet(); - - private readonly Credential _credential; - private readonly InitContextFlag _clientFlags; - private NativeMethods.SECURITY_HANDLE _credentialsHandle; - private NativeMethods.SECURITY_HANDLE _securityContext; - private long _logonId; - - public SspiSecurityContext( - Credential credential, - string package, - long logonId = 0, - InitContextFlag clientFlags = _defaultRequiredFlags) - { - if (!DesktopOsHelper.IsWindows()) - { - throw new PlatformNotSupportedException("Ticket Cache interface is not supported for this OS platform."); - } - - _credential = credential; - _clientFlags = clientFlags; - Package = package; - _logonId = logonId; - } - - public string Package { get; private set; } - - private static void ThrowIfError(uint result) - { - if (result != 0 && result != 0x80090301) - { - throw new Win32Exception((int)result); - } - } - - public ContextStatus InitializeSecurityContext(string targetName, out byte[] clientRequest) - { - var targetNameNormalized = targetName.ToLowerInvariant(); - - clientRequest = null; - - SecStatus result = 0; - int tokenSize = 0; - NativeMethods.SecBufferDesc clientToken = default; - - try - { - do - { - InitContextFlag contextFlags; - - clientToken = new NativeMethods.SecBufferDesc(tokenSize); - - if (!_credentialsHandle.IsSet || result == SecStatus.SEC_I_CONTINUE_NEEDED) - { - AcquireCredentials(); - } - - result = NativeMethods.InitializeSecurityContext_0( - ref _credentialsHandle, - IntPtr.Zero, - targetNameNormalized, - _clientFlags, - 0, - SECURITY_NETWORK_DREP, - IntPtr.Zero, - 0, - ref _securityContext, - ref clientToken, - out contextFlags, - IntPtr.Zero); - - if (result == SecStatus.SEC_E_INSUFFICIENT_MEMORY) - { - if (tokenSize > _maxTokenSize) - { - break; - } - - tokenSize += 1000; - } - } - while (result == SecStatus.SEC_I_INCOMPLETE_CREDENTIALS || result == SecStatus.SEC_E_INSUFFICIENT_MEMORY); - - if (result > SecStatus.SEC_E_ERROR) - { - throw new Win32Exception((int)result); - } - - clientRequest = clientToken.ReadBytes(); - - if (result == SecStatus.SEC_I_CONTINUE_NEEDED) - { - return ContextStatus.RequiresContinuation; - } - - return ContextStatus.Accepted; - } - finally - { - clientToken.Dispose(); - } - } - - private void TrackUnmanaged(object thing) - { - _disposable.Add(thing); - } - - private unsafe void AcquireCredentials() - { - CredentialHandle creds = _credential.Structify(); - - TrackUnmanaged(creds); - IntPtr authIdPtr = IntPtr.Zero; - - if (_logonId != 0) - { - authIdPtr = Marshal.AllocHGlobal(Marshal.SizeOf()); - Marshal.StructureToPtr(_logonId, authIdPtr, false); - } - - SecStatus result = NativeMethods.AcquireCredentialsHandle( - null, - Package, - SECPKG_CRED_BOTH, - authIdPtr, - (void*)creds.DangerousGetHandle(), - IntPtr.Zero, - IntPtr.Zero, - ref _credentialsHandle, - IntPtr.Zero); - - if (result != SecStatus.SEC_E_OK) - { - throw new Win32Exception((int)result); - } - - TrackUnmanaged(_credentialsHandle); - } - - public unsafe void Dispose() - { - foreach (var thing in _disposable) - { - if (thing is IDisposable managedDispose) - { - managedDispose.Dispose(); - } - else if (thing is NativeMethods.SECURITY_HANDLE handle) - { - NativeMethods.DeleteSecurityContext(&handle); - - ThrowIfError(NativeMethods.FreeCredentialsHandle(&handle)); - } - else if (thing is IntPtr pThing) - { - Marshal.FreeHGlobal(pThing); - } - } - } - } -} diff --git a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/TicketCacheReader.cs b/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/TicketCacheReader.cs deleted file mode 100644 index d1b0a8ed41..0000000000 --- a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/TicketCacheReader.cs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using System.ComponentModel; -using System.Runtime.InteropServices; - -namespace Microsoft.Identity.Client.Platforms.Features.DesktopOs.Kerberos -{ - /// - /// Helper class to check Kerberos Ticket in user's Ticket Cache. - /// - internal class TicketCacheReader : IDisposable - { - private readonly string _spn; - private readonly SspiSecurityContext _context; - private bool _disposedValue; - - /// - /// Creates a object to read a Kerberos Ticket from Ticket Cache. - /// - /// Service principal name of ticket to read out from Ticket Cache. - /// The Logon ID of the user owning the ticket cache. - /// The default of 0 represents the currently logged in user. - /// The name of the Local Security Authority (LSA) authentication package that will be interacted with. - public TicketCacheReader(string spn, long logonId = 0, string package = "Kerberos") - { - - _spn = spn; - _context = new SspiSecurityContext(Credential.Current(), package, logonId); - } - - /// - /// Read out a Kerberos Ticket. - /// - /// Byte stream of Kerberos Ticket, if exists. Null otherwise. - /// - /// Throws if any error occurs while interfacing with Ticket Cache. - /// - public byte[] RequestToken() - { - var status = _context.InitializeSecurityContext(_spn, out byte[] clientRequest); - - if (status == ContextStatus.Error) - { - throw new Win32Exception(Marshal.GetLastWin32Error()); - } - - return clientRequest; - } - - /// - /// Clean up all data members used for interaction with Ticket Cache. - /// - protected virtual void Dispose(bool disposing) - { - if (!_disposedValue) - { - if (disposing) - { - _context.Dispose(); - } - - _disposedValue = true; - } - } - - /// - /// Clean up all data members used for interaction with Ticket Cache. - /// - public void Dispose() - { - Dispose(disposing: true); - GC.SuppressFinalize(this); - } - } -} diff --git a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/TicketCacheWriter.cs b/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/TicketCacheWriter.cs deleted file mode 100644 index 51e994cd80..0000000000 --- a/src/client/Microsoft.Identity.Client/Platforms/Features/DesktopOS/Kerberos/TicketCacheWriter.cs +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using System; -using System.Runtime.InteropServices; - -namespace Microsoft.Identity.Client.Platforms.Features.DesktopOs.Kerberos -{ - - /// - /// Provides a layer to interact with the LSA functions used to create logon sessions and manipulate the ticket caches. - /// - internal class TicketCacheWriter : IDisposable - { - private const string _kerberosPackageName = "Kerberos"; - private const string _negotiatePackageName = "Negotiate"; - - private readonly LsaSafeHandle _lsaHandle; - private readonly int _selectedAuthPackage; - private readonly int _negotiateAuthPackage; - private bool _disposedValue; - - /* - * Windows creates a new ticket cache for primary NT tokens. This allows callers to create a dedicated cache for whatever they're doing - * that way the cache operations like purge or import don't pollute the current users cache. - * - * To make this work we need to create a new NT token, which is only done during logon. We don't actually want Windows to validate the credentials - * so we tell it to treat the logon as `NewCredentials` which means Windows will just use those credentials as SSO credentials only. - * - * From there a new cache is created and any operations against the "current cache" such as SSPI ISC calls will hit this new cache. - * We then let callers import tickets into that cache using the krb-cred structure. - * - * When done the call to dispose will - * 1. Revert the impersonation context - * 2. Close the NT token handle - * 3. Close the Lsa Handle - * - * This destroys the cache and closes the logon session. - * - * For any operation that require native allocation and PtrToStructure copies we try and use the CryptoPool mechanism, which checks out a shared - * pool of memory to create a working for the current operation. On dispose it zeros the memory and returns it to the pool. - */ - - internal unsafe TicketCacheWriter(LsaSafeHandle lsaHandle, string packageName = _kerberosPackageName) - { - _lsaHandle = lsaHandle; - - var kerberosPackageName = new NativeMethods.LSA_STRING - { - Buffer = packageName, - Length = (ushort)packageName.Length, - MaximumLength = (ushort)packageName.Length - }; - - var result = NativeMethods.LsaLookupAuthenticationPackage(_lsaHandle, ref kerberosPackageName, out _selectedAuthPackage); - NativeMethods.LsaThrowIfError(result); - - var negotiatePackageName = new NativeMethods.LSA_STRING - { - Buffer = _negotiatePackageName, - Length = (ushort)_negotiatePackageName.Length, - MaximumLength = (ushort)_negotiatePackageName.Length - }; - - result = NativeMethods.LsaLookupAuthenticationPackage(_lsaHandle, ref negotiatePackageName, out _negotiateAuthPackage); - NativeMethods.LsaThrowIfError(result); - } - - /// - /// Create a new instance of the interop as a standard unprivileged caller. - /// - /// The name of the LSA authentication package that will be interacted with. - /// Returns an instance of the class. - public static TicketCacheWriter Connect(string package = _kerberosPackageName) - { - if (string.IsNullOrWhiteSpace(package)) - { - package = _kerberosPackageName; - } - - var result = NativeMethods.LsaConnectUntrusted(out LsaSafeHandle _lsaHandle); - - NativeMethods.LsaThrowIfError(result); - - return new TicketCacheWriter(_lsaHandle, package); - } - - /// - /// Import a kerberos ticket containing one or more tickets into the current user ticket cache. - /// - /// The ticket to import into the cache. - /// The Logon Id of the user owning the ticket cache. The default of 0 represents the currently logged on user. - public unsafe void ImportCredential(byte[] ticketBytes, long luid = 0) - { - if (ticketBytes is null) - { - throw new ArgumentNullException(nameof(ticketBytes)); - } - - var ticketRequest = new NativeMethods.KERB_SUBMIT_TKT_REQUEST - { - MessageType = NativeMethods.KERB_PROTOCOL_MESSAGE_TYPE.KerbSubmitTicketMessage, - KerbCredSize = ticketBytes.Length, - KerbCredOffset = Marshal.SizeOf(), - LogonId = luid - }; - - var bufferSize = ticketRequest.KerbCredOffset + ticketBytes.Length; - IntPtr pBuffer = Marshal.AllocHGlobal(bufferSize); - - Marshal.StructureToPtr(ticketRequest, pBuffer, false); - Marshal.Copy(ticketBytes, 0, pBuffer + ticketRequest.KerbCredOffset, ticketBytes.Length); - LsaCallAuthenticationPackage(pBuffer.ToPointer(), bufferSize); - } - - /// - /// Call Auth package to cache given Kerberos ticket. - /// - /// Pointer to Kerberos Ticket to cache. - /// Length of Kerberos Ticket data. - - private unsafe void LsaCallAuthenticationPackage(void* pBuffer, int bufferSize) - { - LsaBufferSafeHandle returnBuffer = null; - - try - { - var result = NativeMethods.LsaCallAuthenticationPackage( - _lsaHandle, - _selectedAuthPackage, - pBuffer, - bufferSize, - out returnBuffer, - out int _, - out int protocolStatus - ); - - NativeMethods.LsaThrowIfError(result); - NativeMethods.LsaThrowIfError(protocolStatus); - } - finally - { - returnBuffer?.Dispose(); - } - } - - /// - /// Dispose all interment members. - /// - /// True if Dispose() called by the user. False, otherwise. - protected virtual void Dispose(bool disposing) - { - if (!_disposedValue) - { - _lsaHandle.Dispose(); - _disposedValue = true; - } - } - - /// - /// Deletes current object. - /// - ~TicketCacheWriter() - { - Dispose(disposing: false); - } - - /// - public void Dispose() - { - Dispose(disposing: true); - GC.SuppressFinalize(this); - } - } -} From d8cd7953a1d3cc9390cc18b717b9124c87f035b0 Mon Sep 17 00:00:00 2001 From: Neha Bhargava <61847233+neha-bhargava@users.noreply.github.com> Date: Fri, 3 Oct 2025 09:58:33 -0700 Subject: [PATCH 5/5] Address comments --- .../Platforms/net/MsalJsonSerializerContext.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/client/Microsoft.Identity.Client/Platforms/net/MsalJsonSerializerContext.cs b/src/client/Microsoft.Identity.Client/Platforms/net/MsalJsonSerializerContext.cs index 52fc2ec175..d36af0533d 100644 --- a/src/client/Microsoft.Identity.Client/Platforms/net/MsalJsonSerializerContext.cs +++ b/src/client/Microsoft.Identity.Client/Platforms/net/MsalJsonSerializerContext.cs @@ -22,9 +22,6 @@ namespace Microsoft.Identity.Client.Platforms.net /// See Source-generation modes in System.Text.Json. /// and How to use source generation in System.Text.Json for official docs. /// -#pragma warning disable CS0612 // Type or member is obsolete - [JsonSerializable(typeof(KerberosSupplementalTicket))] -#pragma warning restore CS0612 // Type or member is obsolete [JsonSerializable(typeof(InstanceDiscoveryResponse))] [JsonSerializable(typeof(LocalImdsErrorResponse))] [JsonSerializable(typeof(AdalResultWrapper))]