public void GetKrbCred()
        {
            KerberosSupplementalTicket ticket = KerberosSupplementalTicketManager.FromIdToken(_testIdTokenWithKerberosTicketClaim);

            byte[] krbCred = KerberosSupplementalTicketManager.GetKrbCred(ticket);

            Assert.IsNotNull(krbCred);
        }
        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.");
        }
Example #3
0
        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);
        }
Example #4
0
        /// <summary>
        /// Get a Kerberos Ticket contained in the given token.
        /// </summary>
        /// <param name="token">Token to be validated.</param>
        /// <param name="userUpn">UPN of the client.</param>
        /// <returns>A <see cref="KerberosSupplementalTicket"/> if there's valid one.</returns>
        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);
        }
        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);
        }
Example #6
0
        /// <summary>
        /// Validates Windows Ticket Cache interface for the given <see cref="KerberosSupplementalTicket"/> Kerberos Ticket.
        /// </summary>
        /// <param name="ticket">A <see cref="KerberosSupplementalTicket"/> object to be checked.</param>
        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);
            }
        }
        public void FromIdToken_WithoutKerberosTicket()
        {
            KerberosSupplementalTicket ticket = KerberosSupplementalTicketManager.FromIdToken(_testIdToken);

            Assert.IsNull(ticket);
        }
        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);
        }
Example #9
0
        /// <summary>
        /// Validates there were no valid Kerberos Ticket contained in the given token.
        /// </summary>
        /// <param name="token">Token to be validated.</param>
        public static void ValidateNoKerberosTicketFromToken(string token)
        {
            KerberosSupplementalTicket ticket = KerberosSupplementalTicketManager.FromIdToken(token);

            Assert.IsNull(ticket, "Kerberos Ticket exists.");
        }