Created
September 10, 2024 12:33
-
-
Save rajanadar/28c86d967695262bfe1f17ae82fb3d3d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Threading.Tasks; | |
using Kerberos.NET.Client; | |
using Kerberos.NET.Configuration; | |
using Kerberos.NET.Credentials; | |
using Kerberos.NET.Crypto; | |
// Written by Raja Nadar for users of VaultSharp dealing with Kerberos based AuthMethod | |
namespace VaultSharp.V1.AuthMethods.Kerberos | |
{ | |
/// <summary> | |
/// Helper class for Kerberos based Vault Auth Method | |
/// Include the Nuget package Kerberos.NET before using this helper class. | |
/// </summary> | |
public static class KerberosAuthMethodHelper | |
{ | |
/// <summary> | |
/// Creates the Kerberos Service Principal Negotiation Token header from the keytab and conf files. | |
/// </summary> | |
/// <param name="serviceAccountUsername"> | |
/// The username for the entry within the keytab to use for logging into Kerberos. | |
/// This username must match a service account in LDAP. | |
/// </param> | |
/// <param name="servicePrincipalName"> | |
/// The service principal name to use in obtaining a service ticket for gaining a SPNEGO token. | |
/// This service must exist in LDAP. | |
/// </param> | |
/// <param name="realmName"> | |
/// The name of the Kerberos realm. | |
/// This realm must match the UPNDomain configured on the LDAP connection. | |
/// This check is case-sensitive. | |
/// </param> | |
/// <param name="keyTabFilePath"> | |
/// The path to the keytab in which the entry lives for the entity authenticating to Vault. | |
/// Keytab files should be protected from other users on a shared server using appropriate file permissions. | |
/// </param> | |
/// <param name="krb5ConfigurationFilePath"> | |
/// The path to a valid krb5.conf file describing how to communicate with the Kerberos environment. | |
/// </param> | |
/// <param name="disableFastNegotiation"> | |
/// For disabling the Kerberos auth method's default of using FAST negotiation. | |
/// FAST is a pre-authentication framework for Kerberos. | |
/// It includes a mechanism for tunneling pre-authentication exchanges using armoured KDC messages. | |
/// FAST provides increased resistance to passive password guessing attacks. | |
/// Some common Kerberos implementations do not support FAST negotiation. | |
/// </param> | |
/// <returns>The "Negotiate " + ServicePrincipalNegotiationToken value.</returns> | |
public static async Task<string> GetServicePrincipalNegotiationTokenAsync( | |
string serviceAccountUsername, | |
string servicePrincipalName, | |
string realmName, | |
string keyTabFilePath, | |
string krb5ConfigurationFilePath, | |
bool disableFastNegotiation) | |
{ | |
if (string.IsNullOrEmpty(serviceAccountUsername)) | |
{ | |
throw new ArgumentNullException(nameof(serviceAccountUsername)); | |
} | |
if (string.IsNullOrEmpty(servicePrincipalName)) | |
{ | |
throw new ArgumentNullException(nameof(servicePrincipalName)); | |
} | |
if (string.IsNullOrEmpty(realmName)) | |
{ | |
throw new ArgumentNullException(nameof(realmName)); | |
} | |
if (!System.IO.File.Exists(krb5ConfigurationFilePath)) | |
{ | |
throw new System.IO.FileNotFoundException("Krb5Configuration file could not be found: " + krb5ConfigurationFilePath); | |
} | |
if (!System.IO.File.Exists(keyTabFilePath)) | |
{ | |
throw new System.IO.FileNotFoundException("KeyTabFile file could not be found: " + keyTabFilePath); | |
} | |
try | |
{ | |
var krb5Config = Krb5Config.Parse(krb5ConfigurationFilePath); | |
var kerberosClient = new KerberosClient(krb5Config); | |
// Assume pre-auth | |
kerberosClient.AuthenticationOptions &= AuthenticationOptions.PreAuthenticate; | |
if (disableFastNegotiation) | |
{ | |
kerberosClient.AuthenticationOptions &= ~AuthenticationOptions.PreAuthenticate; | |
} | |
var keyTable = new KeyTable(System.IO.File.ReadAllBytes(keyTabFilePath)); | |
KerberosCredential keytabCredential = | |
new KeytabCredential(serviceAccountUsername, | |
keyTable, realmName); | |
await kerberosClient.Authenticate(keytabCredential); | |
var ticket = await kerberosClient.GetServiceTicket(servicePrincipalName); | |
var servicePrincipalNegotiationToken = Convert.ToBase64String(ticket.EncodeGssApi().ToArray()); | |
var kerberosAuthHeader = "Negotiate " + servicePrincipalNegotiationToken; | |
return kerberosAuthHeader; | |
} | |
catch (Exception ex) | |
{ | |
throw new Exception("Failed to generate Kerberos service principal negotiation token.", ex); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment