/// <summary>
        /// Checks there's a Kerberos Ticket in current user's Windows Ticket Cache matched with the service principal name.
        /// If there's a valid ticket, then show the Ticket Information on the console.
        /// </summary>
        /// <returns></returns>
        public bool ShowCachedTicket()
        {
            try
            {
                byte[] ticket
                    = KerberosSupplementalTicketManager.GetKerberosTicketFromWindowsTicketCache(_kerberosServicePrincipalName, _logonId);
                if (ticket != null && ticket.Length > 32)
                {
                    var encode = Convert.ToBase64String(ticket);

                    AADKerberosLogger.PrintLines(2);
                    AADKerberosLogger.Save($"---Find cached Ticket: {ticket.Length} bytes");
                    AADKerberosLogger.PrintBinaryData(ticket);

                    TicketDecoder decoder = new TicketDecoder();
                    decoder.ShowApReqTicket(encode);
                    return(true);
                }

                Console.WriteLine($"There's no ticket associated with '{_kerberosServicePrincipalName}'");
            }
            catch (Win32Exception ex)
            {
                Console.WriteLine($"ERROR while finding Kerberos Ticket for '{_kerberosServicePrincipalName}': {ex.Message}");
            }
            return(false);
        }
        /// <summary>
        /// Shows the Kerberos Ticket included in an authentication token with KrbCred format
        /// which is used to transfer Kerberos credentials between applications.
        /// Reference:
        ///     The Unencrypted Form of Kerberos 5 KRB-CRED Message
        ///     https://tools.ietf.org/html/rfc6448
        /// </summary>
        /// <param name="message"></param>
        internal void ShowKrbCredTicket(string message)
        {
            var krbAsRepBytes = Convert.FromBase64String(message);
            var krbCred       = KrbCred.DecodeApplication(krbAsRepBytes);

            Assert.IsNotNull(krbCred);

            var credPart = krbCred.Validate();

            Assert.IsNotNull(credPart);

            AADKerberosLogger.PrintLines(2);
            AADKerberosLogger.Save("KRB-CRED Supplemental Ticket -----------------------------");
            AADKerberosLogger.Save("  ProtocolVersionNumber: " + krbCred.ProtocolVersionNumber);
            AADKerberosLogger.Save("  Message Type: " + krbCred.MessageType);
            AADKerberosLogger.Save("  # of Tickets: " + krbCred.Tickets.Length);

            for (int i = 0; i < krbCred.Tickets.Length; i++)
            {
                var ticket     = krbCred.Tickets[i];
                var ticketInfo = credPart.TicketInfo[i];

                var key = new byte[ticketInfo.Key.KeyValue.Length];
                ticketInfo.Key.KeyValue.CopyTo(key);

                AADKerberosLogger.Save("  Number: " + ticket.TicketNumber);
                AADKerberosLogger.Save("  Realm: " + ticket.Realm);
                AADKerberosLogger.Save("  SName: " + ticket.SName.FullyQualifiedName);
                ShowEncryptedDataPart("EncryptedPart", ticket.EncryptedPart);

                AADKerberosLogger.Save("  Ticket.Flags: " + ticketInfo.Flags);
                AADKerberosLogger.Save("  Ticket.Realm: " + ticketInfo.Realm);
                AADKerberosLogger.Save("  Ticket.PName: " + ticketInfo.PName.FullyQualifiedName);
                AADKerberosLogger.Save("  Ticket.SRealm: " + ticketInfo.SRealm);
                AADKerberosLogger.Save("  Ticket.SName: " + ticketInfo.SName.FullyQualifiedName);
                AADKerberosLogger.Save("  Ticket.AuthTime: " + ticketInfo.AuthTime);
                AADKerberosLogger.Save("  Ticket.StartTime: " + ticketInfo.StartTime);
                AADKerberosLogger.Save("  Ticket.EndTime: " + ticketInfo.EndTime);
                AADKerberosLogger.Save("  Ticket.RenewTill: " + ticketInfo.RenewTill);
                ShowEncrytionKey("Ticket.Key", ticketInfo.Key);

                if (ticketInfo.AuthorizationData == null)
                {
                    AADKerberosLogger.Save("  Ticket.AuthorizationData:");
                }
                else
                {
                    for (int j = 0; j < ticketInfo.AuthorizationData.Length; j++)
                    {
                        ShowAuthorizationData("Ticket.AuthorizationData", ticketInfo.AuthorizationData[j]);
                    }
                }
                AADKerberosLogger.Save("");
            }
        }
        /// <summary>
        /// Checks there's a valid Kerberos Ticket information within the received authentication token.
        /// If there's a valid one, show the ticket information and cache it into current user's
        /// Windows Ticket Cache so that it can be shared with other Kerberos-aware applications.
        /// </summary>
        /// <param name="result">The <see cref="AuthenticationResult"/> from token request.</param>
        private void ProcessKerberosTicket(AuthenticationResult result)
        {
            KerberosSupplementalTicket ticket;

            if (_ticketContainer == KerberosTicketContainer.IdToken)
            {
                // 1. Get the Kerberos Ticket contained in the Id Token.
                ticket = KerberosSupplementalTicketManager.FromIdToken(result.IdToken);
                if (ticket == null)
                {
                    AADKerberosLogger.Save("ERROR: There's no Kerberos Ticket information within the IdToken.");
                    return;
                }

                AADKerberosLogger.PrintLines(2);

                try
                {
                    // 2. Save the Kerberos Ticket into current user's Windows Ticket Cache.
                    KerberosSupplementalTicketManager.SaveToWindowsTicketCache(ticket, _logonId);
                    AADKerberosLogger.Save("---Kerberos Ticket cached into user's Ticket Cache\n");
                }
                catch (Win32Exception ex)
                {
                    AADKerberosLogger.Save("---Kerberos Ticket caching failed: " + ex.Message);
                }

                AADKerberosLogger.PrintLines(2);
                AADKerberosLogger.Save("KerberosSupplementalTicket {");
                AADKerberosLogger.Save("                Client Key: " + ticket.ClientKey);
                AADKerberosLogger.Save("                  Key Type: " + ticket.KeyType);
                AADKerberosLogger.Save("            Errorr Message: " + ticket.ErrorMessage);
                AADKerberosLogger.Save("                     Realm: " + ticket.Realm);
                AADKerberosLogger.Save("    Service Principal Name: " + ticket.ServicePrincipalName);
                AADKerberosLogger.Save("               Client Name: " + ticket.ClientName);
                AADKerberosLogger.Save("     KerberosMessageBuffer: " + ticket.KerberosMessageBuffer);
                AADKerberosLogger.Save("}\n");

                // shows detailed ticket information.
                TicketDecoder decoder = new TicketDecoder();
                decoder.ShowKrbCredTicket(ticket.KerberosMessageBuffer);
            }
            else
            {
                AADKerberosLogger.PrintLines(2);
                AADKerberosLogger.Save("Kerberos Ticket handling is not supported for access token.");
            }
        }
        /// <summary>
        /// Shows the internal information of a cached Kerberos Ticket in current user's Windows Ticket Cache
        /// with KRB_AP_REQ format.
        /// Reference:
        ///     The Kerberos Network Authentication Service (V5)
        ///     https://tools.ietf.org/html/rfc4120#section-3.2.1
        /// </summary>
        /// <param name="messaage"></param>
        internal void ShowApReqTicket(string messaage)
        {
            var tokenBytes   = System.Convert.FromBase64String(messaage);
            var contextToken = MessageParser.Parse <KerberosContextToken>(tokenBytes);

            Assert.IsNotNull(contextToken);
            Assert.IsNotNull(contextToken.KrbApReq);

            var req = contextToken.KrbApReq;

            Assert.IsNotNull(req.Ticket);

            AADKerberosLogger.PrintLines(2);
            AADKerberosLogger.Save("AP-REQ Cached Ticket----------------------------------------");
            AADKerberosLogger.Save("  Protocol Version Number: " + req.ProtocolVersionNumber);
            AADKerberosLogger.Save("  MessageType: " + req.MessageType);
            AADKerberosLogger.Save("  ApOptions: " + req.ApOptions);

            AADKerberosLogger.Save("  Ticket.TicketNumber: " + req.Ticket.TicketNumber);
            AADKerberosLogger.Save("  Ticket.Realm: " + req.Ticket.Realm);
            AADKerberosLogger.Save("  Ticket.SName: " + req.Ticket.SName.FullyQualifiedName);
            ShowEncryptedDataPart("Ticket.EncryptedPart", req.Ticket.EncryptedPart);
            ShowEncryptedDataPart("Ticket.Authenticator", req.Authenticator);
        }