Una biblioteca Kerberos completa construida íntegramente en código administrado sin (muchas) dependencias del sistema operativo.
Este proyecto cuenta con el apoyo de la Fundación .NET.
Esta biblioteca NO cuenta con el respaldo oficial de Microsoft. Si lo está utilizando a través de ODP.NET de Oracle, Kerberos.NET solo se admite a través del soporte de Oracle. Debe comunicarse con el soporte de Oracle, incluso si sabe que el problema está en Kerberos.NET. El soporte de Oracle trabajará directamente con Microsoft si el problema existe en Kerberos.NET. Microsoft cerrará los casos de soporte creados directamente con Microsoft para Kerberos.NET.
Para resumir: este repositorio NO cuenta con soporte oficial de Microsoft, a pesar de que algunos empleados de Microsoft podrían administrarlo y contribuir a él. Lo hacen en su tiempo libre o parcialmente como tiempo de trabajo para uso interno, sin ningún SLA de Microsoft (o de los empleados de Microsoft). El uso de ODP.NET de Kerberos.NET solo se admite a través del soporte de Oracle.
Una biblioteca integrada en .NET que le permite operar con mensajes Kerberos. Puede ejecutar un cliente, alojar su propio KDC o simplemente validar tickets entrantes. Se pretende que sea lo más ligero posible.
Está disponible una inmersión profunda en el diseño de Kerberos.NET y vale la pena leerla.
Este proyecto es principalmente una biblioteca, pero también incluye un montón de herramientas útiles que envuelven la biblioteca para ayudar a desarrollar aplicaciones y solucionar problemas de Kerberos.
Puede encontrar el instalador de la extensión Fiddler en las versiones en el lado derecho de esta página. Para obtener más información, lea un artículo sobre cómo instalarlo y usarlo.
La herramienta de línea de comandos de Bruce es una colección de utilidades que le permiten interactuar con los componentes de la biblioteca Kerberos.NET y está disponible a través de dotnet tool install bruce -g
. Incluye herramientas útiles para cosas como caché de tickets y gestión de tablas de claves. También incluye la utilidad Ticket Decoder que se menciona a continuación. La herramienta sigue más o menos los estándares de línea de comandos del MIT y Heimdal, pero para obtener más información sobre todas las herramientas de la suite, escriba help
desde la línea de comandos de Bruce.
Consulte esta publicación de blog sobre cómo utilizar la herramienta.
Ver y modificar archivos de configuración krb5.
Decodifica Kerberos/Negocia tickets y, opcionalmente, descifra si conoces los secretos.
Elimine cualquier archivo de caché de tickets.
Autentica a un usuario y solicita un TGT con un montón de opciones disponibles para la solicitud.
Vea todos los tickets en un caché y, opcionalmente, solicite más tickets.
Envíe un "ping" AS-REQ a un KDC para que el usuario actual o proporcionado obtenga metadatos para el usuario.
Vea y manipule archivos de tabla de claves con soporte para la resolución de problemas.
Solicite un ticket para el usuario actual y formatee los detalles de manera útil.
La herramienta expone mensajes de registro útiles si pasa el parámetro de línea de comando /verbose
.
La biblioteca funcionará en todas las plataformas .NET Standard 2.0 compatibles con algunas advertencias.
Hay dos formas de utilizar esta biblioteca. La primera es descargar el código y compilarlo localmente. La segunda opción, mejor, es simplemente usar nuget.
PM> Paquete de instalación Kerberos.NET
Hay tres formas de utilizar esta biblioteca.
El cliente es intencionalmente simple en comparación con los clientes que se encuentran en otras plataformas. Tiene todas las funciones y admite la generación de mensajes SPNego.
var client = new KerberosClient();var kerbCred = new KerberosPasswordCredential("[email protected]", "userP@ssw0rd!");await client.Authenticate(kerbCred);var ticket = await client.GetServiceTicket("host/appservice .corp.identityintervention.com");var encabezado = "Negociar " + Convert.ToBase64String(ticket.EncodeGssApi().ToArray());
Alojar un KDC es un poco más complicado ya que requiere escuchar en un puerto en particular. Normalmente escuchas en el puerto 88.
var puerto = 88;var opciones = new ListenerOptions{ListeningOn = nuevo IPEndPoint(IPAddress.Loopback, puerto),DefaultRealm = "corp.identityintervention.com".ToUpper(),RealmLocator = domainName => new MyRealmService(realmName)};var oyente = nuevo KdcServiceListener(opciones);esperar oyente.Start();
El oyente esperará hasta que se llame (o se elimine) listener.Stop()
.
La autenticación de tickets se produce en dos etapas. La primera etapa valida la corrección del ticket a través de un IKerberosValidator
con una implementación predeterminada de KerberosValidator
. La segunda etapa implica convertir el ticket en un ClaimsIdentity
utilizable (un KerberosIdentity : ClaimsIdentity
específicamente), lo que ocurre en KerberosAuthenticator
.
La forma más sencilla de comenzar es crear un nuevo KerberosAuthenticator
y llamar Authenticate
. Si necesita modificar el comportamiento de la conversión, puede hacerlo anulando el método ConvertTicket(DecryptedData data)
.
var autenticador = nuevo KerberosAuthenticator(nueva KeyTable(File.ReadAllBytes("sample.keytab")));var identidad = autenticador.Authenticate("YIIHCAYGKwYBBQUCoIIG...");Assert.IsNotNull(identidad);var nombre = identidad.Nombre ;Assert.IsFalse(string.IsNullOrWhitespace(nombre));
Tenga en cuenta que el parámetro constructor del autenticador es KeyTable
. KeyTable
es un formato común utilizado para almacenar claves en otras plataformas. Puede usar un archivo creado por una herramienta como ktpass
o simplemente puede pasar una KerberosKey
durante la creación de instancias y tendrá el mismo efecto.
Los paquetes nuget generalmente se mantendrán actualizados con cualquier cambio en la biblioteca principal.
¡Oye, funciona! Simplemente agregue el paquete nuget como referencia y listo.
Más información
Active Directory requiere que esté presente una identidad que coincida con el dominio al que se envía el token. Esta identidad puede ser cualquier usuario u objeto de computadora en Active Directory, pero debe configurarse correctamente. Esto significa que necesita un nombre principal de servicio (SPN). Puede encontrar instrucciones sobre cómo configurar un usuario de prueba aquí.
Active Directory ha admitido reclamos desde Server 2012. En ese momento, solo se podía acceder a los reclamos a través de los principios de Windows o la magia oscura de ADFS. Kerberos.NET ahora admite de forma nativa el análisis de reclamaciones en tickets de Kerberos. Eche un vistazo a la Guía de reclamaciones para obtener más información sobre cómo configurar esto.
Kerberos.NET admite el formato de archivo KeyTable (keytab) para pasar las claves utilizadas para descifrar y validar tickets de Kerberos. El formato de archivo keytab es un formato común utilizado por muchas plataformas para almacenar claves. Puede generar estos archivos en Windows utilizando la utilidad de línea de comandos ktpass
, que forma parte del paquete de herramientas de administración remota del servidor (RSAT). Puede instalarlo en un servidor a través de PowerShell (o mediante el cuadro de diálogo para agregar componentes de Windows):
Agregar función RSAT de Windows
Desde allí puede generar el archivo keytab ejecutando el siguiente comando:
ktpass /princ HTTP/[email protected] /mapuser IDENTITYINTERserver01$ /pass P@ssw0rd! /out sample.keytab /crypto all /PTYPE KRB5_NT_SRV_INST /mapop set
El parámetro princ
se usa para especificar el nombre principal generado y mapuser
, que se usa para asignarlo al usuario en Active Directory. El parámetro crypto
especifica qué algoritmos deben generar entradas.
Los tickets AES son compatibles de forma nativa. ¡No es necesario hacer nada adicional!
Esto ahora también incluye soporte para SHA256 y SHA384 a través de RFC8009.
Para obtener más información, consulte Armadura FAST.
Esto no es compatible actualmente, pero está en la hoja de ruta.
Puede agregar su propio soporte para otros algoritmos como DES (no sé por qué lo haría, pero...) donde asocia un tipo de cifrado a una Func<> que crea instancias de nuevos descifradores. Tampoco hay nada que le impida realizar este proceso si lo desea.
KerberosRequest.RegisterDecryptor( Tipo de cifrado.DES_CBC_MD5, (token) => nuevo DESMD5DecryptedData(token));
La detección de reproducción incorporada utiliza MemoryCache
para almacenar temporalmente referencias a hashes de los tickets nonces. Estas referencias se eliminan cuando el billete caduca. El proceso de detección ocurre inmediatamente después del descifrado, tan pronto como el número de secuencia del autenticador esté disponible.
Tenga en cuenta que la lógica de detección integrada no funciona eficazmente cuando la aplicación está agrupada porque la caché no se comparte entre máquinas. La implementación integrada utiliza un servicio en memoria y, como tal, no se comparte con nadie.
Deberá crear una caché que se comparta entre máquinas para que esto funcione correctamente en un entorno agrupado. Esto se ha simplificado enormemente gracias a los nuevos servicios de inyección de dependencias de .NET Core. Todo lo que necesitas hacer es registrar una implementación IDistributedCache
. Puede encontrar más información al respecto en Microsoft Docs.
Si desea utilizar su propia detección de reproducción, simplemente implemente la interfaz ITicketReplayValidator
y pásela al constructor KerberosValidator
.
¡Hay muestras!
KerbCrypto se ejecuta en los 6 formatos de token admitidos.
datos-rc4-kerberos
rc4-spnego-datos
datos-aes128-kerberos
aes128-spnego-datos
datos-kerberos-aes256
aes256-spnego-datos
KerbTester Una herramienta de línea de comandos utilizada para probar tickets reales y volcar los resultados analizados.
KerberosMiddlewareEndToEndSample Un ejemplo de un extremo a otro que muestra cómo el servidor solicita la negociación y la respuesta del navegador emulado.
KerberosMiddlewareSample Un ejemplo simple de middleware de aprobación/fallo que decodifica un ticket si está presente, pero que, por lo demás, nunca solicita negociar.
KerberosWebSample Un proyecto web de muestra destinado a hospedarse en IIS que solicita negociar y validar cualquier ticket entrante desde el navegador.
Este proyecto tiene una Licencia MIT. Consulte el archivo de licencia para obtener más detalles. Consulte también el archivo de Avisos para obtener más información sobre las licencias de los proyectos de los que depende.
Esta biblioteca viene con una utilidad opcional para decodificar tickets de servicio. Es fácil de usar. Simplemente copie la copia codificada en Base64 del boleto en el cuadro de texto de la izquierda. Decodificará el mensaje no cifrado si no proporciona una clave. Intentará descifrar el mensaje si proporciona una clave. No necesitará proporcionar un valor de host si el ticket se cifró con RC4, pero necesitará un valor de host si está cifrado con AES (para derivar la sal). Alternativamente, también puede incluir un archivo de tabla de claves si también lo tiene.
Puedes iniciarlo usando la herramienta Bruce con bruce kdecode
.
El decodificador convertirá el ticket de Kerberos en una vista de árbol estructurada. El proceso es Kerberos ASN.1 => JSON () => Representación de vista de árbol. Aquí está el JSON intermedio que le muestra toda la información disponible en el ticket.
{ "Request": {"KrbApReq": { "ProtocolVersionNumber": 5, "MessageType": "KRB_AP_REQ", "ApOptions": "Reserved", "Ticket": {"TicketNumber": 5,"Realm": "CORP. IDENTITYINTERVENTION.COM","SName": { "FullyQualifiedName": "desktop-h71o9uu", "IsServiceName": false, "Tipo": "NT_PRINCIPAL", "Nombre": ["desktop-h71o9uu" ]},"EncryptedPart": { "EType": "AES256_CTS_HMAC_SHA1_96", "KeyVersionNumber": 3, "Cifrado": "Vo4uodU2.. .snip...XBwjmsshgyjs+Vr+A=="} }, "Authenticator": {"EType": "AES256_CTS_HMAC_SHA1_96","KeyVersionNumber": null,"Cipher": "NnLmEFkmO3HXCS...snip...up0YmNW5AicQVvvk" }},"KrbApRep": null }, "Decrypted": {"Options": "Reserved","EType": "AES256_CTS_HMAC_SHA1_96","SName": { "FullyQualifiedName": "desktop-h71o9uu", "IsServiceName": false, "Type": "NT_PRINCIPAL", "Nombre": ["desktop-h71o9uu" ]},"Authenticator": { "AuthenticatorVersionNumber": 5, "Realm": "CORP.IDENTITYINTERVENTION.COM", "CName": {"FullyQualifiedName": "jack","IsServiceName": false,"Type": "NT_PRINCIPAL","Name": [ "jack"] }, "Suma de comprobación": {"Tipo": "32771","Suma de comprobación": "EAAAAAAAAAAAAAAAAAAAAAAAAAA8QAAA" }, "CuSec": 305, "CTime": "2021-04-21T17:38:11+00:00", "Subclave": {"Uso": "Desconocido","EType": "AES256_CTS_HMAC_SHA1_96","KeyValue" : "nPIQrMQu/tpUV3dmeIJYjdUCnpg0sVDjFGHt8EK94EM=" }, "SequenceNumber": 404160760, "AuthorizationData": [{ "Type": "AdIfRelevant", "Data": "MIHTMD+gBAICAI2hNwQ1M...snip...BJAE8ATgAuAEMATwBNAA=="} ]},"Ticket": { "Flags": ["EncryptedPreAuthentication","PreAuthenticated","Renovable","Reenviable" ], "Clave": {"Uso": "Desconocido","EType": "AES256_CTS_HMAC_SHA1_96" ,"ValorClave": "gXZ5AIsNAdQSo/qdEzkfw3RrLhhypyuG+YcZwqdX9mk=" }, "CRealm": "CORP.IDENTITYINTERVENTION.COM", "CName": {"FullyQualifiedName": "jack","IsServiceName": false,"Type": "NT_PRINCIPAL"," Nombre": [ "jack"] }, "Transitado": {"Tipo": "DomainX500Compress","Contents": "" }, "AuthTime": "2021-04-21T17:24:53+00:00", "StartTime": "2021-04-21T17:38:11+00:00 ", "Hora de finalización": "2021-04-22T03:24:53+00:00", "RenewTill": "2021-04-28T17:24:53+00:00", "CADdr": null, "AuthorizationData": [{ "Type": "AdIfRelevant", "Data": "MIIDIjCCAx6gBAICAIChg...snip ...muoGI9Mcg0="},{ "Tipo": "AdIfRelevant", "Datos": "MF0wP6AEAgIAj...snip...AXg9hCAgAACTDBBAAAAAA="} ]},"DelegationTicket": null,"SessionKey": { "Usage": null, "EncryptionType": "AES256_CTS_HMAC_SHA1_96", "Host": null, "PrincipalName" : nulo, "Versión": nulo, "Salt": "", "Contraseña": null, "IterationParameter": "", "PasswordBytes": "", "SaltFormat": "ActiveDirectoryService", "RequiresDerivation": false},"Skew": "00:05:00" }, "Computado": {"Nombre": "[email protected]","Restricciones": { "KerbAuthDataTokenRestrictions": [{ "RestrictionType": 0, "Restriction": {"Flags": "Completo"," TokenIntegrityLevel": "Alto","MachineId": "Txr82+sI2kbFmPnkrjldLUfESt/oJzLaWWNqCkOgC7I=" }, "Type": "KerbAuthDataTokenRestrictions"},{ "RestrictionType": 0, "Restriction": {"Flags": "Full","TokenIntegrityLevel": "High","MachineId" : "Txr82+sI2kbFmPnkrjldLUfESt/oJzLaWWNqCkOgC7I=" }, "Type": "KerbAuthDataTokenRestrictions"} ], "KerbLocal": [{ "Valor": "EBeD2EICAAAJMMEEAAAAAA==", "Tipo": "KerbLocal"},{ "Valor": "EBeD2EICAAAJMMEEAAAAAA==", "Type": "KerbLocal"} ], "KerbApOptions": [{ "Options": "ChannelBindingSupported", "Type": "KerbApOptions"} ], "KerbServiceTarget": [{ "ServiceName": "[email protected]", "Tipo": "KerbServiceTarget"} ], "AdWin2kPac": [{ "Mode": "Server", "DecodingErrors": [], "Version": 0, "LogonInfo": {"PacType": "LOGON_INFO","LogonTime": "2021-04-21T17:24:53.4021307+00:00","Hora de cierre de sesión": "0001-01-01T00:00:00+00:00","KickOffTime": "0001-01-01T00:00:00+00:00","PwdLastChangeTime": "2021-01-14T23:55:39.0024458 +00:00","PwdCanChangeTime": "2021-01-15T23:55:39.0024458+00:00","PwdMustChangeTime": "0001-01-01T00:00:00+00:00","UserName": "jack","UserDisplayName": "Jack Handey","LogonScript": "","ProfilePath": "","HomeDirectory": "","HomeDrive": "","LogonCount": 99,"BadPasswordCount": 0,"UserId": 1126,"GroupId": 513,"GroupCount": 6,"GroupIds": [ {"RelativeId": 1132,"Attributes": [ "SE_GROUP_MANDATORY", "SE_GROUP_ENABLED_BY_DEFAULT" , "SE_GROUP_ENABLED"] }, {"RelativeId": 1131,"Atributos": [ "SE_GROUP_MANDATORY", "SE_GROUP_ENABLED_BY_DEFAULT", "SE_GROUP_ENABLED"] }, {"RelativeId": 1128,"Atributos": [ "SE_GROUP_MANDATORY", "SE_GROUP_ENABLED_BY_DEFAULT", "SE_GROUP_ENABLED"] }, {"RelativeId": 1130,"Atributos": [ "SE_GROUP_MANDATORY", "SE_GROUP_ENABLED_BY_DEFAULT", "SE_GROUP_ENABLED"] }, {"RelativeId": 513,"Atributos": [ "SE_GROUP_MANDATORY", "SE_GROUP_ENABLED_BY_DEFAULT", "SE_GROUP_ENABLED"] }, {"RelativeId": 1129,"Attributes": [ "SE_GROUP_MANDATORY", "SE_GROUP_ENABLED_BY_DEFAULT", "SE_GROUP_ENABLED"] }],"UserFlags": "LOGON_EXTRA_SIDS","UserSessionKey": "AAAAAAAAAAAAAAAAAAAAAA==","ServerName": "DC01u0000","DomainName": "CORPu0000","DomainId": "S-1-5-21-311626132-1109945507-1757856464", "Reservado1": "AAAAAAAAAAA=","UserAccountControl": [ "ADS_UF_LOCKOUT", "ADS_UF_NORMAL_ACCOUNT"],"SubAuthStatus": 0,"LastSuccessfulILogon": "1601-01-01T00:00:00+00:00","LastFailedILogon": "1601-01-01T00:00:00+00:00","FailedILogonCount": 0,"Reserved3": 0,"ExtraSidCount": 1,"ExtraIds": [ {"Sid": "S-1-18 -1","Atributos": [ "SE_GROUP_MANDATORY", "SE_GROUP_ENABLED_BY_DEFAULT", "SE_GROUP_ENABLED"] }],"ResourceDomainId": null,"ResourceGroupCount": 0,"ResourceGroupIds": null,"UserSid": { "Id": 1126, "Atributos": "0", "Valor": "S-1-5-21-311626132-1109945507-1757856464-1126"},"GroupSid": { "Id": 513, "Atributos": "0", "Valor": "S-1-5-21-311626132-1109945507-1757856464-513"},"GroupSids": [ {"Id": 1132,"Atributos": [ "SE_GROUP_MANDATORY", "SE_GROUP_ENABLED_BY_DEFAULT", "SE_GROUP_ENABLED"],"Valor": "S-1-5-21-311626132-1109945507-1757856464-1132" }, {"Id": 1131,"Atributos": [ "SE_GROUP_MANDATORY", "SE_GROUP_ENABLED_BY_DEFAULT", "SE_GROUP_ENABLED"],"Valor": "S-1-5-21-311626132-1109945507-1757856464-1131" }, {"Id": 1128,"Atributos": [ "SE_GROUP_MANDATORY", "SE_GROUP_ENABLED_BY_DEFAULT", "SE_GROUP_ENABLED"],"Valor": "S-1-5-21-311626132-1109945507-1757856464-1128" }, {"Id": 1130,"Atributos": [ "SE_GROUP_MANDATORY", "SE_GROUP_ENABLED_BY_DEFAULT", "SE_GROUP_ENABLED"],"Valor": "S-1-5-21-311626132-1109945507-1757856464-1130" }, {"Id": 513,"Atributos": [ "SE_GROUP_MANDATORY", "SE_GROUP_ENABLED_BY_DEFAULT", "SE_GROUP_ENABLED"],"Valor": "S-1-5-21-311626132-1109945507-1757856464-513" }, {"Id": 1129,"Atributos": [ "SE_GROUP_MANDATORY", "SE_GROUP_ENABLED_BY_DEFAULT", "SE_GROUP_ENABLED"],"Value": "S-1-5-21-311626132-1109945507-1757856464-1129" }],"ExtraSids": [ {"Id": 1,"Attributes": "0"," Valor": "S-1-18-1" }],"ResourceDomainSid": null,"ResourceGroups": [],"DomainSid": { "Id": 1757856464, "Atributos": "0", "Valor": "S-1-5-21-311626132-1109945507-1757856464"} }, "Firma del servidor": {"Tipo": "HMAC_SHA1_96_AES256","Signature": "Q0gnRmxBoh5w0DzS","RODCIdentifier": 0,"PacType": "0" }, "CredentialType": nulo, "KdcSignature": {"Type": "HMAC_SHA1_96_AES256","Signature": "HVsreq5rqBiPTHIN","RODCIdentifier": 0,"PacType": "0" }, "ClientClaims": nulo, "DeviceClaims": nulo, "ClientInformation": {"ClientId": "2021-04-21T17:24:53+00:00","Nombre ": "jack","PacType": "CLIENT_NAME_TICKET_INFO" }, "UpnDomainInformation": {"Upn": "[email protected]","Domain": "CORP.IDENTITYINTERVENTION.COM","Flags": "0","PacType": "UPN_DOMAIN_INFO" }, "DelegationInformation": null, "HasRequiredFields": verdadero , "Tipo": "AdWin2kPac"} ]},"ValidationMode": "Pac","Claims": [ {"Tipo": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/sid","Value": "S-1-5-21-311626132-1109945507-1757856464-1126" }, {"Tipo ": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname","Valor": "Jack Handey" }, {"Tipo": "http://schemas.xmlsoap.org/ ws/2005/05/identity/claims/nameidentifier","Value": "[email protected]" }, {"Tipo": "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid","Value": "S-1-5-21-311626132-1109945507-1757856464-1132" }, {"Tipo ": "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid","Value": "S-1-5-21-311626132-1109945507-1757856464-1131" }, {"Tipo ": "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid","Value": "S-1-5-21-311626132-1109945507-1757856464-1128" }, {"Tipo ": "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid","Value": "S-1-5-21-311626132-1109945507-1757856464-1130" }, {"Tipo ": "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid","Value": "S-1-5-21-311626132-1109945507-1757856464-513" }, {"Tipo ": "http://schemas.microsoft.com/ws/2008/06/identity/claims/role","Value": "Usuarios de dominio" }, {"Tipo": "http://schemas.microsoft.com/ ws/2008/06/identity/claims/groupsid","Valor": "S-1-5-21-311626132-1109945507-1757856464-1129" }, {"Tipo": "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid","Valor ": "T-1-18-1" }] }, "KeyTable": {"FileVersion": 2,"KerberosVersion": 5,"Entries": [ {"EncryptionType": "NULL","Length": 0,"Timestamp": "2021-04-21T23:52: 22.5460123+00:00","Versión": 5,"Host": nulo,"ContraseñaBytes": "jBBI1KL19X3olbCK/f9p/+cxZi3RnqqQRH4WawB4EzY=","KeyPrincipalName": { "Reino": "CORP.IDENTITYINTERVENTION.COM", "Nombres": ["STEVE-HOME" ], "NameType": "NT_SRV_HST", "FullyQualifiedName" : "STEVE-HOME"},"Sal": nulo }] }}