/// <summary> /// Generate a Kerberos Ticket Claim string. /// </summary> /// <param name="servicePrincipalName">Service principal name to use.</param> /// <param name="ticketContainer">Ticket container to use.</param> /// <returns>A Kerberos Ticket Claim string if valid service principal name was given. Empty string, otherwise.</returns> 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)); }
/// <summary> /// Sets the parameters required to get a Kerberos Ticket from Azure AD service. /// </summary> /// <param name="servicePrincipalName">Service principal name to get Kerberos Service Ticket.</param> /// <param name="ticketContainer">Container to use for Kerberos Ticket.</param> /// <returns>The builder to chain the .With methods</returns> public PublicClientApplicationBuilder WithKerberosTicketClaim(string servicePrincipalName, KerberosTicketContainer ticketContainer) { Config.KerberosServicePrincipalName = servicePrincipalName; Config.TicketContainer = ticketContainer; return(this); }
/// <summary> /// Parse the command line arguments and set internal parameters with supplied value. /// </summary> /// <param name="args">List of commandline arguments.</param> /// <returns>True if argument parsing completed. False, if there's an error detected.</returns> public bool ParseCommandLineArguments(string[] args) { for (int i = 0; i < args.Length; i++) { if (args[i].Equals("-tenantId", StringComparison.OrdinalIgnoreCase) && (i + 1) < args.Length) { _tenantId = args[++i]; } else if (args[i].Equals("-clientId", StringComparison.OrdinalIgnoreCase) && (i + 1) < args.Length) { _clientId = args[++i]; } else if (args[i].Equals("-spn", StringComparison.OrdinalIgnoreCase) && (i + 1) < args.Length) { _kerberosServicePrincipalName = args[++i]; } else if (args[i].Equals("-container", StringComparison.OrdinalIgnoreCase) && (i + 1) < args.Length) { ++i; if (args[i].Equals("id", StringComparison.OrdinalIgnoreCase)) { _ticketContainer = KerberosTicketContainer.IdToken; } else if (args[i].Equals("access", StringComparison.OrdinalIgnoreCase)) { _ticketContainer = KerberosTicketContainer.AccessToken; } else { Console.WriteLine("Unknown ticket container type '" + args[i] + "'"); ShowUsages(); return(false); } } else if (args[i].Equals("-redirectUri", StringComparison.OrdinalIgnoreCase) && (i + 1) < args.Length) { _redirectUri = args[++i]; } else if (args[i].Equals("-scopes", StringComparison.OrdinalIgnoreCase) && (i + 1) < args.Length) { _publicAppScopes = args[++i].Split(' '); } else if (args[i].Equals("-cached", StringComparison.OrdinalIgnoreCase)) { _isReadFromCache = true; } else if (args[i].Equals("-luid", StringComparison.OrdinalIgnoreCase)) { ++i; try { _logonId = long.Parse(args[i], NumberStyles.HexNumber, NumberFormatInfo.InvariantInfo); } catch (Exception ex) { Console.WriteLine("-luid should be a long number or HEX format string!"); Console.WriteLine(ex); return(false); } } else if (args[i].Equals("-upn", StringComparison.OrdinalIgnoreCase)) { i++; _Username = args[i]; } else if (args[i].Equals("-password", StringComparison.OrdinalIgnoreCase)) { i++; _UserPassword = args[i]; } else if (args[i].Equals("-devicecodeflow", StringComparison.OrdinalIgnoreCase)) { _isDeviceCodeFlow = true; } else { ShowUsages(); return(false); } } return(true); }
private async Task <AuthenticationResult> KerberosRunTestForUserAsync( LabResponse labResponse, KerberosTicketContainer ticketContainer) { HttpSnifferClientFactory factory = null; IPublicClientApplication pca = PublicClientApplicationBuilder .Create(labResponse.App.AppId) .WithRedirectUri(SeleniumWebUI.FindFreeLocalhostRedirectUri()) .WithAuthority(labResponse.Lab.Authority + "common") .WithTestLogging(out 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); }
/// <summary> /// Get a Kerberos Ticket contained in the given <see cref="AuthenticationResult"/> object. /// </summary> /// <param name="authResult">An <see cref="AuthenticationResult"/> object to get Kerberos Ticket from.</param> /// <param name="container">The <see cref="KerberosTicketContainer"/> indicating the token where the Kerberos Ticket stored.</param>" /// <param name="userUpn">UPN of the client.</param> /// <returns>A <see cref="KerberosSupplementalTicket"/> if there's valid one.</returns> 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)); }
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); }