/// <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); }
private void ShowAuthorizationData(string title, KrbAuthorizationData auth) { if (auth != null) { AADKerberosLogger.Save($" {title}.Type: {auth.Type}"); AADKerberosLogger.Save($" {title}.Data.Length: {auth.Data.Length}"); AADKerberosLogger.Save($" {title}.Data.Value:"); AADKerberosLogger.PrintBinaryData(auth.Data.ToArray()); } }
/// <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> /// Shows the account information included in the authentication result. /// </summary> /// <param name="account">The <see cref="IAccount"/> information to display.</param> private void ShowAccount(IAccount account) { if (account != null) { AADKerberosLogger.Save("Account Info:"); AADKerberosLogger.Save(" Username: "******" Environment: " + account.Environment); AADKerberosLogger.Save(" HomeAccount Tenant Id: " + account.HomeAccountId.TenantId); AADKerberosLogger.Save(" HomeAccount Object Id: " + account.HomeAccountId.ObjectId); AADKerberosLogger.Save(" Home Account Identifier: " + account.HomeAccountId.Identifier); } }
/// <summary> /// Acquire an authentication token with public client configuration using username/password non-interactively. /// </summary> /// <returns>The <see cref="AuthenticationResult"/> object.</returns> private AuthenticationResult AcquireTokenWithDeviceCodeFlow() { // 1. Setup pulic client application to get Kerberos Ticket. var app = PublicClientApplicationBuilder.Create(_clientId) .WithTenantId(_tenantId) .WithRedirectUri(_redirectUri) .WithKerberosTicketClaim(_kerberosServicePrincipalName, _ticketContainer) .WithLogging(LogDelegate, LogLevel.Verbose, true, true) .Build(); try { AADKerberosLogger.Save("Calling AcquireTokenWithDeviceCodeFlow() with:"); AADKerberosLogger.Save(" Tenant Id: " + _tenantId); AADKerberosLogger.Save(" Client Id: " + _clientId); AADKerberosLogger.Save(" Redirect Uri: " + _redirectUri); AADKerberosLogger.Save(" spn: " + _kerberosServicePrincipalName); AADKerberosLogger.Save(" Ticket container: " + _ticketContainer); // 2. Acquire the authentication token. // Kerberos Ticket will be contained in Id Token or Access Token // according to specified ticket container parameter. AuthenticationResult result = app .AcquireTokenWithDeviceCode( _publicAppScopes, deviceCodeCallback => { ConsoleColor current = Console.ForegroundColor; Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine(deviceCodeCallback.Message); Console.ForegroundColor = current; // stop console output of logging information posted from the MSAL. AADKerberosLogger.SkipLoggingToConsole = true; return(Task.FromResult(0)); }) .ExecuteAsync() .GetAwaiter() .GetResult(); AADKerberosLogger.SkipLoggingToConsole = false; ShowAuthenticationResult(result); return(result); } catch (Exception ex) { AADKerberosLogger.Save("Exception: " + ex); return(null); } }
private void ShowEncrytionKey(string title, KrbEncryptionKey key) { if (key == null) { AADKerberosLogger.Save($" {title}:"); } else { AADKerberosLogger.Save($" {title}.Usage: {key.Usage}"); AADKerberosLogger.Save($" {title}.EType: {key.EType}"); AADKerberosLogger.Save($" {title}.KeyValue.Length: {key.KeyValue.Length}"); AADKerberosLogger.Save($" {title}.KeyValue.Value:"); AADKerberosLogger.PrintBinaryData(key.KeyValue.ToArray()); } }
private void ShowEncryptedDataPart(string title, KrbEncryptedData data) { if (data == null) { AADKerberosLogger.Save($" {title}:"); } else { AADKerberosLogger.Save($" {title}.EType: " + data.EType); AADKerberosLogger.Save($" {title}.KeyVersionNumber: " + data.KeyVersionNumber); AADKerberosLogger.Save($" {title}.Cipher.Length: " + data.Cipher.Length); AADKerberosLogger.Save($" {title}.Cipher.Value:"); AADKerberosLogger.PrintBinaryData(data.Cipher.ToArray()); } }
/// <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."); } }
private void ShowAuthenticationResult(AuthenticationResult result) { ConsoleColor current = Console.ForegroundColor; Console.ForegroundColor = ConsoleColor.Yellow; ShowAccount(result.Account); AADKerberosLogger.Save("Token Information:"); AADKerberosLogger.Save(" Correlation Id: " + result.CorrelationId); AADKerberosLogger.Save(" Unique Id:" + result.UniqueId); AADKerberosLogger.Save(" Expres On: " + result.ExpiresOn); AADKerberosLogger.Save(" IsExtendedLifeTimeToken: " + result.IsExtendedLifeTimeToken); AADKerberosLogger.Save(" Extended Expres On: " + result.ExtendedExpiresOn); AADKerberosLogger.Save(" Access Token:\n" + result.AccessToken); AADKerberosLogger.Save(" Id Token:\n" + result.IdToken); Console.ForegroundColor = current; }
/// <summary> /// Acquire an authentication token with public client configuration using username/password non-interactively. /// /// NOTE: You have to enable public client flows for your application in the Azure Portal: /// Login to the Azure Portal /// Goto "App Registrations" /// Select your application /// Select "Authentication" under the Manage section. /// Select "Yes" for the "Allow public client flows" under the Advanced Settings. /// Click "Save" to save the changes. /// </summary> /// <returns>The <see cref="AuthenticationResult"/> object.</returns> private AuthenticationResult AcquireTokenFromPublicClientWithUserPassword() { // 1. Setup pulic client application to get Kerberos Ticket. var app = PublicClientApplicationBuilder.Create(_clientId) .WithTenantId(_tenantId) .WithRedirectUri(_redirectUri) .WithKerberosTicketClaim(_kerberosServicePrincipalName, _ticketContainer) .WithLogging(LogDelegate, LogLevel.Verbose, true, true) .Build(); try { AADKerberosLogger.Save("Calling AcquireTokenByUsernamePassword() with:"); AADKerberosLogger.Save(" Tenant Id: " + _tenantId); AADKerberosLogger.Save(" Client Id: " + _clientId); AADKerberosLogger.Save(" Redirect Uri: " + _redirectUri); AADKerberosLogger.Save(" spn: " + _kerberosServicePrincipalName); AADKerberosLogger.Save(" Ticket container: " + _ticketContainer); AADKerberosLogger.Save(" Username: "******"Exception: " + ex); return(null); } }
/// <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); }
/// <summary> /// Callback to receive logging message for internal operation of the MSAL. /// Show the received message to the console and save to the logging file. /// </summary> /// <param name="level">Log level of the log message to process</param> /// <param name="message">Pre-formatted log message</param> /// <param name="containsPii">Indicates if the log message contains Organizational Identifiable Information (OII) /// or Personally Identifiable Information (PII) nor not.</param> private static void LogDelegate(LogLevel level, string message, bool containsPii) { AADKerberosLogger.Save(message); }