Полная библиотека Kerberos, полностью построенная на управляемом коде без (многих) зависимостей от ОС.
Этот проект поддерживается .NET Foundation.
Эта библиотека НЕ официально поддерживается Microsoft. Если вы используете его через ODP.NET Oracle, Kerberos.NET поддерживается только через службу поддержки Oracle. Вам необходимо обратиться в службу поддержки Oracle, даже если вы знаете, что проблема в Kerberos.NET. Служба поддержки Oracle будет работать напрямую с Microsoft, если проблема существует в Kerberos.NET. Microsoft закроет заявки на поддержку, созданные непосредственно с Microsoft для Kerberos.NET.
Подводя итог: этот репозиторий НЕ поддерживается официально Microsoft, несмотря на то, что некоторые сотрудники Microsoft могут управлять им и вносить в него свой вклад. Они делают это либо в свободное время, либо частично как рабочее время для внутреннего использования, без каких-либо соглашений об уровне обслуживания со стороны Microsoft (или сотрудников Microsoft). Использование ODP.NET Kerberos.NET поддерживается только через службу поддержки Oracle.
Библиотека, встроенная в .NET, которая позволяет работать с сообщениями Kerberos. Вы можете запустить клиент, разместить собственный KDC или просто проверять входящие билеты. Он призван быть максимально легким.
Подробное описание устройства Kerberos.NET доступно и заслуживает прочтения.
Этот проект в первую очередь представляет собой библиотеку, но также включает в себя ряд полезных инструментов, которые помогают создавать приложения и устранять проблемы Kerberos.
Установщик расширения Fiddler можно найти в разделе «Выпуски» в правой части этой страницы. Для получения дополнительной информации прочитайте статью о том, как его установить и использовать.
Инструмент командной строки Брюс представляет собой набор утилит, которые позволяют взаимодействовать с компонентами библиотеки Kerberos.NET и доступны через dotnet tool install bruce -g
. Он включает в себя полезные инструменты для таких вещей, как кэш билетов и управление клавишами. Он также включает в себя утилиту Ticket Decoder, упомянутую ниже. Этот инструмент более или менее соответствует стандартам командной строки MIT и Heimdal, но для получения дополнительной информации обо всех инструментах в наборе введите help
из командной строки Брюса.
См. эту публикацию в блоге о том, как использовать этот инструмент.
Просмотр и изменение файлов конфигурации krb5.
Расшифруйте билеты Kerberos/Negotiate и при необходимости расшифруйте, если вы знаете секреты.
Удалите все файлы кэша билетов.
Аутентифицируйте пользователя и запросите TGT с множеством доступных опций для запроса.
Просмотрите все билеты в кеше и при необходимости запросите дополнительные билеты.
Отправьте «ping» AS-REQ в KDC для текущего или предоставленного пользователя, чтобы получить метаданные для пользователя.
Просматривайте файлы клавишных таблиц и управляйте ими с поддержкой устранения неполадок.
Запросите билет для текущего пользователя и отформатируйте данные удобным способом.
Инструмент предоставляет полезные сообщения журнала, если вы передаете параметр командной строки /verbose
.
Библиотека будет работать на всех поддерживаемых платформах .NET Standard 2.0 с некоторыми оговорками.
Есть два способа использования этой библиотеки. Первый — загрузить код и собрать его локально. Второй, лучший вариант — просто использовать nuget.
PM> Установочный пакет Kerberos.NET
Есть три способа использования этой библиотеки.
Клиент намеренно прост по сравнению с клиентами на других платформах. Он полнофункционален и поддерживает создание сообщений 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 = "Переговоры" + Convert.ToBase64String(ticket.EncodeGssApi().ToArray());
Размещение KDC немного сложнее, поскольку требует прослушивания определенного порта. Обычно вы слушаете порт 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 прослушиватель = новый KdcServiceListener (опции); ждут прослушиватель.Start();
Слушатель будет ждать, пока не будет вызван (или удален) listener.Stop()
.
Аутентификация билета происходит в два этапа. На первом этапе проверяется правильность билета с помощью IKerberosValidator
с реализацией KerberosValidator
по умолчанию. Второй этап включает преобразование билета в пригодный для использования ClaimsIdentity
(в частности, KerberosIdentity : ClaimsIdentity
), который встречается в KerberosAuthenticator
.
Самый простой способ начать — создать новый KerberosAuthenticator
и вызвать Authenticate
. Если вам нужно настроить поведение преобразования, вы можете сделать это, переопределив метод ConvertTicket(DecryptedData data)
.
var аутентификатор = новый KerberosAuthenticator(новый KeyTable(File.ReadAllBytes("sample.keytab")));var идентификация = аутентификация.Authenticate("YIIHCAYGKwYBBQUCoIIG...");Assert.IsNotNull(identity);var name =identity.Name ;Assert.IsFalse(string.IsNullOrWhitespace(name));
Обратите внимание, что параметром конструктора для аутентификатора является KeyTable
. KeyTable
— это распространенный формат, используемый для хранения ключей на других платформах. Вы можете использовать файл, созданный таким инструментом, как ktpass
, или просто передать KerberosKey
во время создания экземпляра, и это будет иметь тот же эффект.
Пакеты nuget обычно обновляются с учетом любых изменений в основной библиотеке.
Эй, это работает! Просто добавьте пакет nuget в качестве ссылки и приступайте.
Дополнительная информация
Active Directory требует присутствия удостоверения, соответствующего домену, куда отправляется токен. Это удостоверение может быть любым объектом пользователя или компьютера в Active Directory, но его необходимо правильно настроить. Это означает, что ему требуется имя участника службы (SPN). Инструкции по настройке тестового пользователя вы можете найти здесь.
Active Directory поддерживает утверждения начиная с Server 2012. В то время доступ к утверждениям можно было получить только через участников Windows или темную магию ADFS. Kerberos.NET теперь изначально поддерживает анализ утверждений в билетах Kerberos. Дополнительную информацию о настройке можно найти в Руководстве по претензиям.
Kerberos.NET поддерживает формат файла KeyTable (keytab) для передачи ключей, используемых для расшифровки и проверки билетов Kerberos. Формат файла keytab — это распространенный формат, используемый многими платформами для хранения ключей. Вы можете создать эти файлы в Windows с помощью утилиты командной строки ktpass
, которая является частью пакета инструментов удаленного администрирования сервера (RSAT). Установить его на сервер можно через PowerShell (или через диалог добавления компонентов Windows):
Надстройка WindowsFeature RSAT
Оттуда вы можете создать файл keytab, выполнив следующую команду:
ktpass /princ HTTP/[email protected] /mapuser IDENTITYINTERserver01$ /pass P@ssw0rd! /out sample.keytab /crypto all /PTYPE KRB5_NT_SRV_INST /mapop set
Параметр princ
используется для указания сгенерированного PrincipalName и mapuser
, который используется для сопоставления его с пользователем в Active Directory. Параметр crypto
указывает, какие алгоритмы должны генерировать записи.
Билеты AES поддерживаются изначально. Не нужно делать ничего лишнего!
Теперь это также включает поддержку SHA256 и SHA384 через RFC8009.
Для получения дополнительной информации см. FAST Armoring.
В настоящее время это не поддерживается, но это в планах.
Вы можете добавить собственную поддержку других алгоритмов, таких как DES (не знаю, зачем вам это нужно, но...), где вы связываете тип шифрования с Func<>, который создает экземпляры новых дешифраторов. Также ничто не мешает вам реализовать этот процесс, если хотите.
KerberosRequest.RegisterDecryptor( Тип шифрования.DES_CBC_MD5, (токен) => новый DESMD5DecryptedData(токен));
Встроенное обнаружение повторов использует MemoryCache
для временного хранения ссылок на хэши одноразовых номеров билетов. Эти ссылки удаляются по истечении срока действия билета. Процесс обнаружения происходит сразу после расшифровки, как только становится доступен порядковый номер аутентификатора.
Обратите внимание, что встроенная логика обнаружения не работает эффективно, когда приложение кластеризовано, поскольку кеш не является общим для всех компьютеров. Встроенная реализация использует службу в памяти и поэтому никому не передается.
Вам нужно будет создать кеш, общий для всех компьютеров, чтобы это работало правильно в кластерной среде. Это было значительно упрощено благодаря новым службам внедрения зависимостей .NET Core. Все, что вам нужно сделать, это зарегистрировать реализацию IDistributedCache
. Дополнительную информацию об этом можно найти в документации Microsoft.
Если вы хотите использовать собственное обнаружение повторов, просто реализуйте интерфейс ITicketReplayValidator
и передайте его в конструктор KerberosValidator
.
Есть образцы!
KerbCrypto поддерживает 6 поддерживаемых форматов токенов.
rc4-kerberos-данные
rc4-spnego-данные
aes128-kerberos-данные
aes128-spnego-данные
aes256-kerberos-данные
aes256-spnego-данные
KerbTester Инструмент командной строки, используемый для проверки реальных билетов и получения результатов анализа.
KerberosMiddlewareEndToEndSample Сквозной пример, показывающий, как сервер запрашивает согласование и ответ эмулируемого браузера.
KerberosMiddlewareSample Простой пример промежуточного программного обеспечения «пройден/не пройден», который декодирует билет, если он присутствует, но в противном случае никогда не предлагает провести согласование.
KerberosWebSample Пример веб-проекта, предназначенного для размещения в IIS, который предлагает согласовать и проверить все входящие билеты из браузера.
Этот проект имеет лицензию MIT. Дополнительные сведения см. в файле лицензии. Также см. файл уведомлений для получения дополнительной информации о лицензиях проектов, от которых это зависит.
Эта библиотека поставляется с дополнительной утилитой для декодирования служебных билетов. Он прост в использовании. Просто скопируйте копию билета в кодировке Base64 в левое текстовое поле. Он расшифрует незашифрованное сообщение, если вы не предоставите ключ. Он попытается расшифровать сообщение, если вы предоставите ключ. Вам не нужно будет указывать значение хоста, если билет был зашифрован с помощью RC4, но ему понадобится значение хоста, если он зашифрован с помощью AES (для получения соли). В качестве альтернативы вы также можете включить файл keytab, если он у вас тоже есть.
Вы можете запустить его с помощью инструмента Брюса с помощью bruce kdecode
.
Декодер преобразует билет Kerberos в структурированное древовидное представление. Процесс представляет собой Kerberos ASN.1 => JSON() => рендеринг в виде дерева. Вот промежуточный JSON, который показывает всю информацию, доступную вам в билете.
{ "Request": {"KrbApReq": { "ProtocolVersionNumber": 5, "MessageType": "KRB_AP_REQ", "ApOptions": "Reserved", "Ticket": {"TicketNumber": 5, "Realm": "CORP. IDENTITYINTERVENTION.COM","SName": { "FullyQualifiedName": "desktop-h71o9uu", "IsServiceName": false, "Type": "NT_PRINCIPAL", "Name": ["desktop-h71o9uu" ]}, "EncryptedPart": { "EType": "AES256_CTS_HMAC_SHA1_96", "KeyVersionNumber": 3, «Шифр»: "Vo4uodU2...snip...XBwjmsshgyjs+Vr+A=="} }, "Authenticator": {"EType": "AES256_CTS_HMAC_SHA1_96", "KeyVersionNumber": null, "Cipher": "NnLmEFkmO3HXCS...snip...up0YmNW5AicQVvvk" }},"KrbApRep": null }, "Расшифровано": {"Параметры": "Зарезервировано", "EType": "AES256_CTS_HMAC_SHA1_96", "SName": { "FullyQualifiedName": "desktop-h71o9uu", "IsServiceName": false, "Type": "NT_PRINCIPAL", "Имя": ["рабочий стол-h71o9uu" ]},"Authenticator": { "AuthenticatorVersionNumber": 5, "Realm": "CORP.IDENTITYINTERVENTION.COM", "CName": {"FullyQualifiedName": "jack","IsServiceName": false,"Type": " NT_PRINCIPAL","Name": [ "jack"] }, "Контрольная сумма": {"Тип": "32771", "Контрольная сумма": "EAAAAAAAAAAAAAAAAAAAAAAAAA8QAAA" }, "CuSec": 305, "CTime": "2021-04-21T17:38:11+00:00", "Подключ": {"Использование": "Неизвестно ","ЭТип": "AES256_CTS_HMAC_SHA1_96", "KeyValue": "nPIQrMQu/tpUV3dmeIJYjdUCnpg0sVDjFGHt8EK94EM=" }, "SequenceNumber": 404160760, "AuthorizationData": [{ "Type": "AdIfRelevant", "Data": "MIHTMD+gBAICAI2hNwQ1M...snip...BJAE8ATgAuAEMATwBNAA=="} ]},"Ticket": { "Flags": ["EncryptedPreAuthentication","PreAuthenticated","Renewable","Forwardable" ], "Key": {"Использование": "Неизвестно", "ETType": "AES256_CTS_HMAC_SHA1_96","KeyValue": "gXZ5AIsNAdQSo/qdEzkfw3RrLhhypyuG+YcZwqdX9mk=" }, "CRealm": "CORP.IDENTITYINTERVENTION.COM", "CName": {"FullyQualifiedName": "jack", "IsServiceName": false, "Type": "NT_PRINCIPAL", "Name": [ "jack"] }, "Transited": {"Type": "DomainX500Compress", "Contents": "" }, "AuthTime": "2021-04-21T17:24:53+00:00", "StartTime": "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": [{ "Type": "AdIfRelevant", "Data": "MIIDIjCCAx6gBAICAIChg...snip...muoGI9Mcg0="}, { "Type": "AdIfRelevant", "Data": "MF0wP6AEAgIAj...snip...AXg9hCAgAACTDBBAAAAAA="} ]} ,"DelegationTicket": null,"SessionKey": { «Использование»: ноль, «Тип шифрования»: «AES256_CTS_HMAC_SHA1_96», «Хост»: ноль, «Имя участника»: ноль, «Версия»: ноль, «Соль»: «», «Пароль»: ноль, «ИтерацияПараметр»: « ", "PasswordBytes": "", "SaltFormat": «ActiveDirectoryService», «RequiresDerivation»: false}, «Skew»: «00:05:00» }, "Computed": {"Name": "[email protected]", "Restrictions": { "KerbAuthDataTokenRestrictions": [{ "RestrictionType": 0, "Restriction": {"Flags": "Full"," TokenIntegrityLevel": "Высокий","MachineId": "Txr82+sI2kbFmPnkrjldLUfESt/oJzLaWWNqCkOgC7I=" }, "Type": "KerbAuthDataTokenRestrictions"}, { "RestrictionType": 0, "Restriction": {"Flags": "Full", "TokenIntegrityLevel": "High", "MachineId" : "Txr82+sI2kbFmPnkrjldLUfESt/oJzLaWWNqCkOgC7I=" }, "Type": "KerbAuthDataTokenRestrictions"} ], "KerbLocal": [{ "Value": "EBeD2EICAAAJMMEEAAAAAA==", "Type": "KerbLocal"}, { "Value": "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": "Джек Хэнди","LogonScript": "","ProfilePath": "","HomeDirectory" : "","HomeDrive": "","LogonCount": 99,"BadPasswordCount": 0, "UserId": 1126, "GroupId": 513, "GroupCount": 6, "GroupIds": [ {"RelativeId": 1132, "Атрибуты": [ "SE_GROUP_MANDATORY", "SE_GROUP_ENABLED_BY_DEFAULT", "SE_GROUP_ENABLED"] } , {"RelativeId": 1131, "Атрибуты": [ "SE_GROUP_MANDATORY", "SE_GROUP_ENABLED_BY_DEFAULT", "SE_GROUP_ENABLED"] }, {"RelativeId": 1128, "Атрибуты": [ "SE_GROUP_MANDATORY", "SE_GROUP_ENABLED_BY_DEFAULT", "SE_GROUP_ENABLED"] }, {"RelativeId": 1130, "Attributes": [ "SE_GROUP_MANDATORY", "SE_GROUP_ENABLED_BY_DEFAULT", "SE_GROUP_ENABLED"] }, {"RelativeId": 513, "Атрибуты": [ "SE_GROUP_MANDATORY", "SE_GROUP_ENABLED_BY_DEFAULT", "SE_GROUP_ENABLED"] }, {"RelativeId": 1129, "Атрибуты": [ "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", "Attributes": [ "SE_GROUP_MANDATORY", "SE_GROUP_ENABLED_BY_DEFAULT", "SE_GROUP_ENABLED"] }], "ResourceDomainId": null, "ResourceGroupCount ": 0,"ResourceGroupIds": null,"UserSid": { "Id": 1126, "Attributes": "0", "Value": "S-1-5-21-311626132-1109945507-1757856464-1126"},"GroupSid": { " Идентификатор": 513, "Атрибуты": "0", "Value": "S-1-5-21-311626132-1109945507-1757856464-513"},"GroupSids": [ {"Id": 1132,"Attributes": [ "SE_GROUP_MANDATORY", "SE_GROUP_ENABLED_BY_DEFAULT", "SE_GROUP_ENABLED"],"Value": "S-1-5-21-311626132-1109945507-1757856464-1132" }, {"Id": 1131,"Attributes": [ "SE_GROUP_MANDATORY", "SE_GROUP_ENABLED_BY_DEFAULT", "SE_GROUP_ENABLED"],"Value": "S-1-5-21-311626132-1109945507-1757856464-1131" }, {"Id": 1128,"Attributes": [ "SE_GROUP_MANDATORY", "SE_GROUP_ENABLED_BY_DEFAULT", "SE_GROUP_ENABLED"],"Value": "S-1-5-21-311626132-1109945507-1757856464-1128" }, {"Id": 1130,"Attributes": [ "SE_GROUP_MANDATORY", "SE_GROUP_ENABLED_BY_DEFAULT", "SE_GROUP_ENABLED"],"Value": "S-1-5-21-311626132-1109945507-1757856464-1130" }, {"Id": 513,"Attributes": [ "SE_GROUP_MANDATORY", "SE_GROUP_ENABLED_BY_DEFAULT", "SE_GROUP_ENABLED"],"Value": "S-1-5-21-311626132-1109945507-1757856464-513" }, {"Id": 1129,"Attributes": [ "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"," Значение": "S-1-18-1" }], «ResourceDomainSid»: null, «ResourceGroups»: [], «DomainSid»: { «Id»: 1757856464, «Атрибуты»: «0», «Значение»: «S-1-5-21-311626132- 1109945507-1757856464"} }, "ServerSignature": {"Type": "HMAC_SHA1_96_AES256", "Signature": "Q0gnRmxBoh5w0DzS", "RODCIdentifier": 0, "PacType": "0" }, "CredentialType": null, "KdcSignature": {"Type" : «HMAC_SHA1_96_AES256», «Signature»: «HVsreq5rqBiPTHIN», «RODCIdentifier»: 0, «PacType»: «0» }, «ClientClaims»: null, «DeviceClaims»: null, «ClientInformation»: {»ClientId»: "2021-04-21T17:24:53+00:00","Name": "jack","PacType": "CLIENT_NAME_TICKET_INFO" }, "UpnDomainInformation": {"Upn": "[email protected] ","Домен": "CORP.IDENTITYINTERVENTION.COM","Флаги": "0", "PacType": "UPN_DOMAIN_INFO" }, "DelegationInformation": null, "HasRequiredFields": true, "Type": "AdWin2kPac"} ]}, "ValidationMode": "Pac", "Claims": [ { "Тип": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/sid","Value": "S-1-5-21-311626132-1109945507-1757856464-1126" }, {"Type ": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname", "Value": "Jack Handey" }, {"Type": "http://schemas.xmlsoap.org/ ws/2005/05/identity/claims/nameidentifier","Value": "[email protected]" }, {"Type": "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid","Value": "S-1-5-21-311626132-1109945507-1757856464-1132" }, {"Type ": "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid","Value": "S-1-5-21-311626132-1109945507-1757856464-1131" }, {"Type ": "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid","Value": "S-1-5-21-311626132-1109945507-1757856464-1128" }, {"Type ": "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid","Value": "S-1-5-21-311626132-1109945507-1757856464-1130" }, {"Type ": "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid","Value": "S-1-5-21-311626132-1109945507-1757856464-513" }, {"Type ": "http://schemas.microsoft.com/ws/2008/06/identity/claims/role", "Значение": "Пользователи домена" }, {"Тип": "http://schemas.microsoft.com/ ws/2008/06/identity/claims/groupsid","Значение": "S-1-5-21-311626132-1109945507-1757856464-1129" }, {"Тип": "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid","Value ": "S-1-18-1" }] }, "KeyTable": {"FileVersion": 2, "KerberosVersion": 5, "Entries": [ {"EncryptionType": "NULL", "Length": 0, "Timestamp": "21 апреля 2021 г. T23:52: 22.5460123+00:00","Версия": 5,"Хост": null,"PasswordBytes": "jBBI1KL19X3olbCK/f9p/+cxZi3RnqqQRH4WawB4EzY=","KeyPrincipalName": { "Realm": "CORP.IDENTITYINTERVENTION.COM", "Names": ["STEVE-HOME" ], "NameType": " NT_SRV_HST", «FullyQualifiedName»: «STEVE-HOME»}, «Salt»: null }] }}