Uma biblioteca Kerberos completa construída inteiramente em código gerenciado sem (muitas) dependências de sistema operacional.
Este projeto é apoiado pela .NET Foundation.
Esta biblioteca NÃO é oficialmente suportada pela Microsoft. Se você estiver usando-o por meio do ODP.NET da Oracle, o Kerberos.NET terá suporte somente por meio do Oracle Support. Você deve entrar em contato com o Suporte Oracle, mesmo sabendo que o problema está no Kerberos.NET. O Suporte Oracle trabalhará diretamente com a Microsoft se o problema existir no Kerberos.NET. A Microsoft encerrará os casos de suporte criados diretamente com a Microsoft para Kerberos.NET.
Resumindo: Este repositório NÃO é oficialmente suportado pela Microsoft, apesar do fato de que alguns funcionários da Microsoft possam gerenciá-lo e contribuir para ele. Eles fazem isso em seu tempo livre ou parcialmente como horário de trabalho para uso interno, sem qualquer SLA da Microsoft (ou dos funcionários da Microsoft). O uso do Kerberos.NET pelo ODP.NET é suportado somente pelo Suporte Oracle.
Uma biblioteca integrada em .NET que permite operar em mensagens Kerberos. Você pode executar um cliente, hospedar seu próprio KDC ou apenas validar tickets recebidos. O objetivo é ser o mais leve possível.
Um mergulho profundo no design do Kerberos.NET está disponível e vale a pena ler.
Este projeto é principalmente uma biblioteca, mas também inclui um monte de ferramentas úteis que envolvem a biblioteca para ajudar a construir aplicativos e solucionar problemas de Kerberos.
Você pode encontrar o instalador da extensão Fiddler em versões no lado direito desta página. Para obter mais informações, leia um artigo sobre como instalá-lo e usá-lo.
A ferramenta de linha de comando Bruce é uma coleção de utilitários que permitem interagir com os componentes da biblioteca Kerberos.NET e está disponível por meio da dotnet tool install bruce -g
. Inclui ferramentas úteis para coisas como cache de tickets e gerenciamento de keytab. Também inclui o utilitário Ticket Decoder mencionado abaixo. A ferramenta segue mais ou menos os padrões de linha de comando do MIT e Heimdal, mas para obter mais informações sobre todas as ferramentas do conjunto, help
na linha de comando de Bruce.
Veja esta postagem do blog sobre como usar a ferramenta.
Visualize e modifique os arquivos de configuração krb5.
Decodifique tickets Kerberos/Negociar e, opcionalmente, descriptografe se você conhece os segredos.
Exclua todos os arquivos de cache de tickets.
Autentique um usuário e solicite um TGT com diversas opções disponíveis para a solicitação.
Visualize todos os tickets em um cache e, opcionalmente, solicite mais tickets.
Envie um "ping" AS-REQ para um KDC para o usuário atual ou fornecido para obter metadados para o usuário.
Visualize e manipule arquivos keytab com suporte para solução de problemas.
Solicite um ticket para o usuário atual e formate os detalhes de maneira útil.
A ferramenta expõe mensagens de log úteis se você passar o parâmetro de linha de comando /verbose
.
A biblioteca funcionará em todas as plataformas .NET Standard 2.0 suportadas, com algumas ressalvas.
Existem duas maneiras de usar esta biblioteca. A primeira é baixar o código e construí-lo localmente. A segunda opção, melhor, é usar apenas o nuget.
PM> Pacote de instalação Kerberos.NET
Existem três maneiras de usar esta biblioteca.
O cliente é intencionalmente simples em comparação com clientes encontrados em outras plataformas. É completo e suporta a geração de mensagens 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 header = "Negociar " + Convert.ToBase64String(ticket.EncodeGssApi().ToArray());
Hospedar um KDC é um pouco mais complicado, pois requer escuta em uma porta específica. Normalmente você escuta na porta 88.
var port = 88;var options = new ListenerOptions{ListeningOn = new IPEndPoint(IPAddress.Loopback, port),DefaultRealm = "corp.identityintervention.com".ToUpper(),RealmLocator = realmName => new MyRealmService(realmName)};var ouvinte = new KdcServiceListener(opções);aguardar ouvinte.Start();
O ouvinte esperará até que listener.Stop()
seja chamado (ou descartado).
A autenticação do ticket ocorre em duas etapas. O primeiro estágio valida a correção do ticket por meio de um IKerberosValidator
com uma implementação padrão de KerberosValidator
. O segundo estágio envolve a conversão do ticket em um ClaimsIdentity
utilizável (um KerberosIdentity : ClaimsIdentity
especificamente), que ocorre no KerberosAuthenticator
.
A maneira mais fácil de começar é criar um novo KerberosAuthenticator
e chamar Authenticate
. Se precisar ajustar o comportamento da conversão, você pode fazer isso substituindo o método ConvertTicket(DecryptedData data)
.
var authenticator = new KerberosAuthenticator(new KeyTable(File.ReadAllBytes("sample.keytab")));var identidade = authenticator.Authenticate("YIIHCAYGKwYBBQUCoIIG...");Assert.IsNotNull(identity);var nome = identidade.Nome ;Assert.IsFalse(string.IsNullOrWhitespace(nome));
Observe que o parâmetro construtor do autenticador é KeyTable
. O KeyTable
é um formato comum usado para armazenar chaves em outras plataformas. Você pode usar um arquivo criado por uma ferramenta como ktpass
ou simplesmente passar um KerberosKey
durante a instanciação e terá o mesmo efeito.
Os pacotes nuget geralmente serão mantidos atualizados com quaisquer alterações na biblioteca principal.
Ei, funciona! Basta adicionar o pacote nuget como referência e pronto.
Mais informações
O Active Directory exige a presença de uma identidade que corresponda ao domínio para o qual o token está sendo enviado. Essa identidade pode ser qualquer usuário ou objeto de computador no Active Directory, mas precisa ser configurada corretamente. Isso significa que ele precisa de um nome principal de serviço (SPN). Você pode encontrar instruções sobre como configurar um usuário de teste aqui.
O Active Directory oferece suporte a declarações desde o Server 2012. Na época, você só podia acessar as declarações por meio de entidades principais do Windows ou magia negra do ADFS. Kerberos.NET agora oferece suporte nativo à análise de declarações em tickets Kerberos. Dê uma olhada no Guia de Reivindicações para obter mais informações sobre como configurar isso.
Kerberos.NET suporta o formato de arquivo KeyTable (keytab) para passar as chaves usadas para descriptografar e validar tickets Kerberos. O formato de arquivo keytab é um formato comum usado por muitas plataformas para armazenar chaves. Você pode gerar esses arquivos no Windows usando o utilitário de linha de comando ktpass
, que faz parte do pacote RSAT (Ferramentas de Administração de Servidor Remoto). Você pode instalá-lo em um servidor via PowerShell (ou através da caixa de diálogo Adicionar componentes do Windows):
Adicionar WindowsFeature RSAT
A partir daí você pode gerar o arquivo keytab executando o seguinte comando:
ktpass /princ HTTP/[email protected] /mapuser IDENTITYINTERserver01$ /pass P@ssw0rd! /out sample.keytab /crypto all /PTYPE KRB5_NT_SRV_INST /mapop set
O parâmetro princ
é usado para especificar o PrincipalName gerado e mapuser
que é usado para mapeá-lo para o usuário no Active Directory. O parâmetro crypto
especifica quais algoritmos devem gerar entradas.
Os tickets AES são suportados nativamente. Não há necessidade de fazer nada extra!
Agora isso também inclui suporte para SHA256 e SHA384 por meio de RFC8009.
Para obter mais informações, consulte Blindagem FAST.
Isso não é compatível no momento, mas está no roteiro.
Você pode adicionar seu próprio suporte para outros algoritmos como DES (não sei por que faria isso, mas...) onde você associa um tipo de criptografia a um Func<> que instancia novos descriptografadores. Também não há nada que o impeça de realizar esse processo, se desejar.
KerberosRequest.RegisterDecryptor( Tipo de criptografia.DES_CBC_MD5, (token) => novo DESMD5DecryptedData(token));
A detecção de repetição integrada usa um MemoryCache
para armazenar temporariamente referências a hashes dos nonces do ticket. Essas referências são removidas quando o ticket expira. O processo de detecção ocorre logo após a descriptografia, assim que o número de sequência do autenticador estiver disponível.
Observe que a lógica de detecção integrada não funciona de maneira eficaz quando o aplicativo está em cluster porque o cache não é compartilhado entre máquinas. A implementação integrada usa um serviço na memória e, como tal, não é compartilhada com ninguém.
Você precisará criar um cache compartilhado entre máquinas para que isso funcione corretamente em um ambiente em cluster. Isso foi bastante simplificado por meio dos novos serviços de injeção de dependência do .NET Core. Tudo que você precisa fazer é registrar uma implementação IDistributedCache
. Você pode encontrar mais informações sobre isso no Microsoft Docs.
Se você quiser usar sua própria detecção de repetição, basta implementar a interface ITicketReplayValidator
e passá-la no construtor KerberosValidator
.
Existem amostras!
KerbCrypto Executa os 6 formatos de token suportados.
dados rc4-kerberos
dados rc4-spnego
dados aes128-kerberos
aes128-spnego-dados
dados aes256-kerberos
aes256-spnego-dados
KerbTester Uma ferramenta de linha de comando usada para testar tickets reais e despejar os resultados analisados.
KerberosMiddlewareEndToEndSample Um exemplo completo que mostra como o servidor solicita negociação e a resposta do navegador emulado.
KerberosMiddlewareSample Um exemplo simples de middleware aprovado/reprovado que decodifica um ticket, se presente, mas nunca solicita negociação.
KerberosWebSample Um exemplo de projeto da Web destinado a ser hospedado no IIS que solicita a negociação e valida quaisquer tickets recebidos do navegador.
Este projeto possui uma licença MIT. Consulte o arquivo de licença para obter mais detalhes. Consulte também o arquivo de Avisos para obter mais informações sobre as licenças dos projetos dos quais depende.
Esta biblioteca vem com um utilitário opcional para decodificar tickets de serviço. É fácil de usar. Basta copiar a cópia codificada em Base64 do ticket na caixa de texto à esquerda. Ele decodificará a mensagem não criptografada se você não fornecer uma chave. Ele tentará descriptografar a mensagem se você fornecer uma chave. Você não precisará fornecer um valor de host se o ticket tiver sido criptografado usando RC4, mas precisará de um valor de host se estiver criptografado com AES (para derivar o salt). Alternativamente, você também pode incluir um arquivo keytab se também o tiver.
Você pode iniciá-lo usando a ferramenta Bruce com bruce kdecode
.
O decodificador converterá o ticket Kerberos em uma visualização em árvore estruturada. O processo é Kerberos ASN.1 => JSON () => renderização Tree View. Aqui está o JSON intermediário que mostra todas as informações disponíveis no ticket.
{ "Request": {"KrbApReq": { "ProtocolVersionNumber": 5, "MessageType": "KRB_AP_REQ", "ApOptions": "Reservado", "Ticket": {"TicketNumber": 5,"Realm": "CORP. IDENTITYINTERVENTION.COM","SNome": { "Nome Totalmente Qualificado": "desktop-h71o9uu", "IsServiceName": false, "Type": "NT_PRINCIPAL", "Nome": ["desktop-h71o9uu" ]},"EncryptedPart": { "EType": "AES256_CTS_HMAC_SHA1_96", "KeyVersionNumber": 3, "Cifra": "Vo4uodU2...snip...XBwjmsshgyjs+Vr+A=="} }, "Autenticador": {"EType": "AES256_CTS_HMAC_SHA1_96","KeyVersionNumber": null,"Cipher": "NnLmEFkmO3HXCS...snip. ..up0YmNW5AicQVvvk" }},"KrbApRep": nulo }, "Descriptografado": {"Opções": "Reservado","EType": "AES256_CTS_HMAC_SHA1_96","SName": { "FullyQualifiedName": "desktop-h71o9uu", "IsServiceName": false, "Type": "NT_PRINCIPAL", "Nome": ["desktop-h71o9uu" ]},"Authenticator": { "AuthenticatorVersionNumber": 5, "Realm": "CORP.IDENTITYINTERVENTION.COM", "CName": {"FullyQualifiedName": "jack","IsServiceName": false,"Type": " NT_PRINCIPAL","Nome": ["jack"] }, "Checksum": {"Tipo": "32771","Checksum": "EAAAAAAAAAAAAAAAAAAAAAAAAA8QAAA" }, "CuSec": 305, "CTime": "2021-04-21T17:38:11+00:00", "Subchave": {"Uso": "Desconhecido ","ETipo": "AES256_CTS_HMAC_SHA1_96","KeyValue": "nPIQrMQu/tpUV3dmeIJYjdUCnpg0sVDjFGHt8EK94EM=" }, "SequenceNumber": 404160760, "AuthorizationData": [{ "Tipo": "AdIfRelevant", "Dados": "MIHTMD+gBAICAI2hNwQ1M...snip...BJAE8ATgAuAEMATwBNAA=="} ]},"Ticket": { "Sinalizadores": ["EncryptedPreAuthentication","Pré-autenticado","Renovável","Encaminhável" ], "Chave": {"Uso": "Desconhecido","EType": "AES256_CTS_HMAC_SHA1_96","KeyValue": "gXZ5AIsNAdQSo/qdEzkfw3RrLhhypyuG+YcZwqdX9mk=" }, "CRealm": "CORP.IDENTITYINTERVENTION.COM", "CName": {"FullyQualifiedName": "jack","IsServiceName": false,"Tipo": "NT_PRINCIPAL","Nome": [ "jack"] }, "Transited": {"Tipo": "DomainX500Compress","Conteúdo": "" }, "AuthTime": "2021-04 -21T17:24:53+00:00", "Hora de início": "2021-04-21T17:38:11+00:00", "EndTime": "2021-04-22T03:24:53+00:00", "RenewTill": "2021-04-28T17:24:53 +00:00", "CAddr": null, "AuthorizationData": [{ "Tipo": "AdIfRelevant", "Dados": "MIIDIjCCAx6gBAICAIChg...snip...muoGI9Mcg0="},{ "Tipo": "AdIfRelevant", "Dados": "MF0wP6AEAgIAj...snip...AXg9hCAgAACTDBBAAAAAA="} ]} ,"DelegationTicket": null,"SessionKey": { "Uso": null, "EncryptionType": "AES256_CTS_HMAC_SHA1_96", "Host": nulo, "PrincipalName": nulo, "Versão": nulo, "Salt": "", "Senha": nulo, "IterationParameter": "", "PasswordBytes": "", "SaltFormat": "ActiveDirectoryService", "RequiresDerivation": false},"Inclinação": "00:05:00" }, "Computado": {"Nome": "[email protected]","Restrições": { "KerbAuthDataTokenRestrictions": [{ "RestrictionType": 0, "Restriction": {"Sinalizadores": "Completo"," TokenIntegrityLevel": "Alto","MachineId": "Txr82+sI2kbFmPnkrjldLUfESt/oJzLaWWNqCkOgC7I=" }, "Type": "KerbAuthDataTokenRestrictions"},{ "RestrictionType": 0, "Restriction": {"Flags": "Full","TokenIntegrityLevel": "High","MachineId" : "Txr82+sI2kbFmPnkrjldLUfESt/oJzLaWWNqCkOgC7I=" }, "Tipo": "KerbAuthDataTokenRestrictions"} ], "KerbLocal": [{ "Valor": "EBeD2EICAAAJMMEEAAAAAA==", "Tipo": "KerbLocal"},{ "Valor": "EBeD2EICAAAJMMEEAAAAAA==", "Type": "KerbLocal"} ], "KerbApOptions": [{ "Options": "ChannelBindingSupported", "Type": "KerbApOptions"} ], "KerbServiceTarget": [{ "ServiceName": "[email protected]", "Type": "KerbServiceTarget"} ], "AdWin2kPac": [{ "Mode": "Server", "DecodingErrors": [], "Version": 0, "LogonInfo": {"PacType": "LOGON_INFO", "LogonTime": "2021-04-21T17:24:53.4021307+00:00","LogoffTime": "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,"Atributos": [ "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,"Atributos": [ "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","Reserved1": "AAAAAAAAAA=","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"],"Valor": "S-1-5-21-311626132-1109945507-1757856464-1129" }],"ExtraSids": [ {"Id": 1,"Atributos": "0"," Valor": "S-1-18-1" }],"ResourceDomainSid": null,"ResourceGroups": [],"DomainSid": { "Id": 1757856464, "Atributos": "0", "Valor": "S-1-5-21-311626132- 1109945507-1757856464"} }, "ServerSignature": {"Tipo": "HMAC_SHA1_96_AES256","Assinatura": "Q0gnRmxBoh5w0DzS","RODCIdentifier": 0,"PacType": "0" }, "CredentialType": nulo, "KdcSignature": {"Tipo": "HMAC_SHA1_96_AES256" ,"Assinatura": "HVsreq5rqBiPTHIN","RODCIdentifier": 0,"PacType": "0" }, "ClientClaims": nulo, "DeviceClaims": nulo, "ClientInformation": {"ClientId": "2021-04-21T17:24:53 +00:00","Nome": "jack","PacType": "CLIENT_NAME_TICKET_INFO" }, "UpnDomainInformation": {"Upn": "[email protected]","Domínio": "CORP.IDENTITYINTERVENTION.COM","Flags": "0","PacType": "UPN_DOMAIN_INFO " }, "DelegationInformation": null, "HasRequiredFields": verdadeiro, "Tipo": "AdWin2kPac"} ]},"ValidationMode": "Pac","Reivindicações": [ {"Tipo": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/ sid","Valor": "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","Valor": "S-1-5-21-311626132-1109945507-1757856464-1132" }, {"Tipo": "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid","Valor ": "S-1-5-21-311626132-1109945507-1757856464-1131" }, {"Tipo": "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid","Valor ": "S-1-5-21-311626132-1109945507-1757856464-1128" }, {"Tipo": "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid","Valor ": "S-1-5-21-311626132-1109945507-1757856464-1130" }, {"Tipo": "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid","Valor ": "S-1-5-21-311626132-1109945507-1757856464-513" }, {"Tipo": "http://schemas.microsoft.com/ws/2008/06/identity/claims/role","Valor ": "Usuários do domínio" }, {"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": "S-1-18-1" }] }, "KeyTable": {"FileVersion": 2,"KerberosVersion": 5,"Entradas": [ {"EncryptionType": "NULL","Comprimento": 0,"Timestamp": "2021-04-21T23:52: 22.5460123+00:00","Versão": 5,"Host": null,"PasswordBytes": "jBBI1KL19X3olbCK/f9p/+cxZi3RnqqQRH4WawB4EzY=","KeyPrincipalName": { "Reino": "CORP.IDENTITYINTERVENTION.COM", "Nomes": ["STEVE-HOME" ], "NameType": "NT_SRV_HST", "FullyQualifiedName" : "STEVE-HOME"},"Sal": null }] }}