/// <summary> /// Parses the decoded ticket. /// </summary> /// <param name="ticket">Ticket to be parsed.</param> /// <returns>AuthenticationTicketData instance containing the parsed ticket data.</returns> /// <remarks> /// The expected format of the ticket is: /// digest (32 chars) + hex timestamp (8 chars) + user ID + '!' + user data /// OR /// digest (32 chars) + hex timestamp (8 chars) + user ID + '!' + tokens + '!' user data /// </remarks> private static AuthenticationTicketData Parse(string ticket) { if (string.IsNullOrWhiteSpace(ticket) || ticket.Length < 40) { return(null); } string[] ticketParts = (ticket.Length > 40) ? ticket.Substring(40).Split('!') : null; int length = (ticketParts != null) ? ticketParts.Length : 0; if (ticketParts == null) { return(null); } var ticketData = new AuthenticationTicketData { Digest = ticket.Substring(0, 32), HexTimeStamp = ticket.Substring(32, 8), UserId = (length > 0) ? ticketParts[0] : string.Empty, TokensAsString = (length > 2) ? ticketParts[1] : string.Empty, UserData = (length > 1) ? ticketParts[length - 1] : string.Empty }; return(ticketData); }
/// <summary> /// Creates a Base64-encoded ticket based on the provided data. /// </summary> /// <param name="userId">User ID</param> /// <param name="userData">User Data</param> /// <param name="tokens">Comma-delimited string of data</param> /// <param name="timeStamp">Time Stamp</param> /// <param name="secret">Secret key used to create the ticket</param> /// <param name="encode">True if the user id, user data, and tokens are to be encoded; false otherwise</param> /// <param name="ipAddress">IP Address</param> /// <param name="version">Version of the mod_auth_tkt algorithm used to create the ticket</param> /// <returns>String ticket</returns> /// <remarks>The ticket is created using the mod_auth_tkt algorithm.</remarks> public static string Create(string userId, string userData, string tokens, DateTime timeStamp, string secret, bool encode = false, string ipAddress = AuthenticationTicketData.DefaultIPAddress, string version = AuthenticationTicketData.DefaultVersion) { var ticketData = new AuthenticationTicketData { UserId = userId, UserData = userData, TokensAsString = tokens, IPAddress = ipAddress, TimeStamp = timeStamp, Version = version }; return(Create(ticketData, secret, encode)); }
/// <summary> /// Creates a Base64-encoded ticket based on the provided data. /// </summary> /// <param name="ticketData">Data used to create the ticket.</param> /// <param name="secret">Secret key used to create the ticket.</param> /// <param name="encode">True if the user id, user data, and tokens are to be encoded; false otherwise</param> /// <returns>String ticket</returns> /// <remarks>The ticket is created using the mod_auth_tkt algorithm.</remarks> public static string Create(AuthenticationTicketData ticketData, string secret, bool encode = false) { if (ticketData == null) { return null; } string digest = CreateDigest(ticketData, secret); string userId = (encode) ? Encode(ticketData.UserId, secret, ticketData.UnixTimeStamp, 0) : ticketData.UserId; string tokens = (encode) ? Encode(ticketData.TokensAsString, secret, ticketData.UnixTimeStamp, 4) : ticketData.TokensAsString; string userData = (encode) ? Encode(ticketData.UserData, secret, ticketData.UnixTimeStamp, 8) : ticketData.UserData; string ticket = digest + ticketData.HexTimeStamp + userId + '!'; ticket += (string.IsNullOrEmpty(tokens)) ? userData : tokens + '!' + userData; return Base64Helper.Encode(ticket); }
/// <summary> /// Validates a ticket based on the provided data. /// </summary> /// <param name="ticket">Base64-encoded ticket to be validated</param> /// <param name="secret">Secret key used to create the ticket</param> /// <param name="encoded">True if the user id, user data, and tokens are encoded; false otherwise </param> /// <param name="ipAddress">IP Address used to create the ticket</param> /// <param name="version">Version of the mod_auth_tkt algorithm used to validate the ticket</param> /// <returns>True if ticket is valid, false otherwise</returns> public static bool Validate(string ticket, string secret, bool encoded = false, string ipAddress = AuthenticationTicketData.DefaultIPAddress, string version = AuthenticationTicketData.DefaultVersion) { AuthenticationTicketData ticketData = ExtractData(ticket, secret, encoded, ipAddress); string digest = null; if (ticketData != null) { ticketData.Version = version; digest = ticketData.Digest; } string expectedDigest = CreateDigest(ticketData, secret); bool valid = (!string.IsNullOrEmpty(digest) && !string.IsNullOrEmpty(expectedDigest) && expectedDigest == digest); return(valid); }
/// <summary> /// Creates a Base64-encoded ticket based on the provided data. /// </summary> /// <param name="ticketData">Data used to create the ticket.</param> /// <param name="secret">Secret key used to create the ticket.</param> /// <param name="encode">True if the user id, user data, and tokens are to be encoded; false otherwise</param> /// <returns>String ticket</returns> /// <remarks>The ticket is created using the mod_auth_tkt algorithm.</remarks> public static string Create(AuthenticationTicketData ticketData, string secret, bool encode = false) { if (ticketData == null) { return(null); } string digest = CreateDigest(ticketData, secret); string userId = (encode) ? Encode(ticketData.UserId, secret, ticketData.UnixTimeStamp, 0) : ticketData.UserId; string tokens = (encode) ? Encode(ticketData.TokensAsString, secret, ticketData.UnixTimeStamp, 4) : ticketData.TokensAsString; string userData = (encode) ? Encode(ticketData.UserData, secret, ticketData.UnixTimeStamp, 8) : ticketData.UserData; string ticket = digest + ticketData.HexTimeStamp + userId + '!'; ticket += (string.IsNullOrEmpty(tokens)) ? userData : tokens + '!' + userData; return(Base64Helper.Encode(ticket)); }
/// <summary> /// Creates the digest portion of the ticket from the provided data. /// </summary> /// <param name="ticketData">Data used to create the digest</param> /// <param name="secret">Secret key used to create the digest</param> /// <returns>Digest string</returns> /// <remarks> /// The algorithm for the digest is as follows: /// digest = MD5(digest0 + key) /// where /// Version 1.3: digest0 = MD5(iptstamp + key + user_id + user_data) /// Version 2.0: digest0 = MD5(iptstamp + key + user_id + '\0' + token_list + '\0' + user_data) /// </remarks> private static string CreateDigest(AuthenticationTicketData ticketData, string secret) { if (ticketData == null) { return(null); } if (string.IsNullOrWhiteSpace(secret)) { secret = DefaultSecret; } string iptStamp = CreateIPTimeStamp(ticketData.IPAddressAsInt, ticketData.UnixTimeStamp); string digest; const HashHelper.HashType hashType = HashHelper.HashType.MD5; switch (ticketData.Version) { case "1.3": digest = HashHelper.Hash(iptStamp + secret + ticketData.UserId + ticketData.UserData, hashType); digest = HashHelper.Hash(digest + secret, hashType); break; case "2.0": digest = HashHelper.Hash( iptStamp + secret + ticketData.UserId + '\0' + ticketData.TokensAsString + '\0' + ticketData.UserData, hashType); digest = HashHelper.Hash(digest + secret, hashType); break; default: throw new NotSupportedException(string.Format("Version {0} of the mod_auth_tkt algorithm is not supported", ticketData.Version)); } return(digest); }
/// <summary> /// Extracts the data from a provided ticket. /// </summary> /// <param name="ticket">Base64-encoded ticket to parse for data</param> /// <param name="secret">Secret key used to create the ticket</param> /// <param name="encoded">True if the user id, user data, and tokens are encoded; false otherwise</param> /// <param name="ipAddress">IP Address used to create the ticket</param> /// <returns>AuthenticationTicketData instance containing the parsed ticket data.</returns> public static AuthenticationTicketData ExtractData(string ticket, string secret = null, bool encoded = false, string ipAddress = AuthenticationTicketData.DefaultIPAddress) { if (string.IsNullOrWhiteSpace(ticket)) { return(null); } if (string.IsNullOrWhiteSpace(secret)) { secret = DefaultSecret; } AuthenticationTicketData ticketData = null; ticket = Base64Helper.DecodeToString(ticket); if (!string.IsNullOrWhiteSpace(ticket) && ticket.Length >= 40) { ticketData = Parse(ticket); if (ticketData != null) { ticketData.IPAddress = ipAddress; if (encoded) { ticketData.UserId = Decode(ticketData.UserId, secret, ticketData.UnixTimeStamp, 0); ticketData.TokensAsString = Decode(ticketData.TokensAsString, secret, ticketData.UnixTimeStamp, 4); ticketData.UserData = Decode(ticketData.UserData, secret, ticketData.UnixTimeStamp, 8); } } } return(ticketData); }
/// <summary> /// Creates a Base64-encoded ticket based on the provided data. /// </summary> /// <param name="userId">User ID</param> /// <param name="userData">User Data</param> /// <param name="tokens">Comma-delimited string of data</param> /// <param name="timeStamp">Time Stamp</param> /// <param name="secret">Secret key used to create the ticket</param> /// <param name="encode">True if the user id, user data, and tokens are to be encoded; false otherwise</param> /// <param name="ipAddress">IP Address</param> /// <param name="version">Version of the mod_auth_tkt algorithm used to create the ticket</param> /// <returns>String ticket</returns> /// <remarks>The ticket is created using the mod_auth_tkt algorithm.</remarks> public static string Create(string userId, string userData, string tokens, DateTime timeStamp, string secret, bool encode = false, string ipAddress = AuthenticationTicketData.DefaultIPAddress, string version = AuthenticationTicketData.DefaultVersion) { var ticketData = new AuthenticationTicketData { UserId = userId, UserData = userData, TokensAsString = tokens, IPAddress = ipAddress, TimeStamp = timeStamp, Version = version }; return Create(ticketData, secret, encode); }
/// <summary> /// Parses the decoded ticket. /// </summary> /// <param name="ticket">Ticket to be parsed.</param> /// <returns>AuthenticationTicketData instance containing the parsed ticket data.</returns> /// <remarks> /// The expected format of the ticket is: /// digest (32 chars) + hex timestamp (8 chars) + user ID + '!' + user data /// OR /// digest (32 chars) + hex timestamp (8 chars) + user ID + '!' + tokens + '!' user data /// </remarks> private static AuthenticationTicketData Parse(string ticket) { if (string.IsNullOrWhiteSpace(ticket) || ticket.Length < 40) { return null; } string[] ticketParts = (ticket.Length > 40) ? ticket.Substring(40).Split('!') : null; int length = (ticketParts != null) ? ticketParts.Length : 0; if (ticketParts == null) return null; var ticketData = new AuthenticationTicketData { Digest = ticket.Substring(0, 32), HexTimeStamp = ticket.Substring(32, 8), UserId = (length > 0) ? ticketParts[0] : string.Empty, TokensAsString = (length > 2) ? ticketParts[1] : string.Empty, UserData = (length > 1) ? ticketParts[length - 1] : string.Empty }; return ticketData; }
/// <summary> /// Creates the digest portion of the ticket from the provided data. /// </summary> /// <param name="ticketData">Data used to create the digest</param> /// <param name="secret">Secret key used to create the digest</param> /// <returns>Digest string</returns> /// <remarks> /// The algorithm for the digest is as follows: /// digest = MD5(digest0 + key) /// where /// Version 1.3: digest0 = MD5(iptstamp + key + user_id + user_data) /// Version 2.0: digest0 = MD5(iptstamp + key + user_id + '\0' + token_list + '\0' + user_data) /// </remarks> private static string CreateDigest(AuthenticationTicketData ticketData, string secret) { if (ticketData == null) { return null; } if (string.IsNullOrWhiteSpace(secret)) { secret = DefaultSecret; } string iptStamp = CreateIPTimeStamp(ticketData.IPAddressAsInt, ticketData.UnixTimeStamp); string digest; const HashHelper.HashType hashType = HashHelper.HashType.MD5; switch (ticketData.Version) { case "1.3": digest = HashHelper.Hash(iptStamp + secret + ticketData.UserId + ticketData.UserData, hashType); digest = HashHelper.Hash(digest + secret, hashType); break; case "2.0": digest = HashHelper.Hash( iptStamp + secret + ticketData.UserId + '\0' + ticketData.TokensAsString + '\0' + ticketData.UserData, hashType); digest = HashHelper.Hash(digest + secret, hashType); break; default: throw new NotSupportedException(string.Format("Version {0} of the mod_auth_tkt algorithm is not supported", ticketData.Version)); } return digest; }