Coder Social home page Coder Social logo

kerberos.net's Introduction

Kerberos.NET

A complete Kerberos library built entirely in managed code without (many) OS dependencies.

Build Status Nuget Package

.NET Foundation

This project is supported by the .NET Foundation.

Microsoft Support

This library is NOT officially supported by Microsoft. If you are using it via Oracle's ODP.NET, Kerberos.NET is supported only via Oracle Support. You must contact Oracle Support, even if you know that the problem is in Kerberos.NET. Oracle Support will work with Microsoft directly if the problem exists in Kerberos.NET. Microsoft will close support cases created directly with Microsoft for Kerberos.NET.

To summarize: This repo is NOT officially supported by Microsoft, despite the fact that some Microsoft employees might be managing it and contributing to it. They are doing it either in their free time, or partially as work time for internal usage, without any SLA from Microsoft (or from Microsoft employees). ODP.NET usage of Kerberos.NET is supported only through Oracle Support.

What is it?

A library built in .NET that lets you operate on Kerberos messages. You can run a client, host your own KDC, or just validate incoming tickets. It's intended to be as lightweight as possible.

A deep dive into the design of Kerberos.NET is available and worth a read.

This project is primarily a library, but also includes a bunch of useful tools wrapping the library to help build out applications and troubleshoot Kerberos issues.

Useful Tools

Fiddler Extension

You can find the Fiddler extension installer under releases on the right hand side of this page. For more information go read a write up on how to install and use it.

Bruce Commmand Line Tool

The Bruce command line tool is a collection of utilities that let you interact with the Kerberos.NET library components and is available via dotnet tool install bruce -g. It includes useful tools for things like ticket cache and keytab management. It also includes the Ticket Decoder utility mentioned below. The tool more or less follows the MIT and Heimdal command line standards, but for more information on all the tools in the suite type help from the Bruce command line.

See this blog post on how to use the tool.

image

Available tools

kconfig

View and modify krb5 config files.

image

kdecode

Decode Kerberos/Negotiate tickets and optionally decrypt if you know the secrets.

image

kdestroy

Delete any ticket cache files.

image

kinit

Authenticate a user and request a TGT with a bunch of available options for the request.

image

klist

View all the tickets in a cache and optionally request more tickets.

image

kping

Send an AS-REQ "ping" to a KDC for the current or supplied user to get metadata for the user.

image

ktpass

View and manipulate keytab files with support for troubleshooting.

image

whoami

Request a ticket for the current user and format the details in a useful manner.

image

Verbose Logging

The tool exposes useful logging messages if you pass the /verbose command line parameter.

image

Cross Platform Support

The library will work on all supported .NET Standard 2.0 platforms with some caveats.

Getting Started

There are two ways you can go about using this library. The first is to download the code and build it locally. The second, better, option is to just use nuget.

PM> Install-Package Kerberos.NET

Using the Library

There are three ways you can use this library.

Using The Kerberos Client

The client is intentionally simple as compared to clients found in other platforms. It's fully-featured and supports generating SPNego messages.

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 = "Negotiate " + Convert.ToBase64String(ticket.EncodeGssApi().ToArray());

Using the KDC Server

Hosting a KDC is a little more complicated as it requires listening on a particular port. Usually you listen on port 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 listener = new KdcServiceListener(options);

await listener.Start();

The listener will wait until listener.Stop() is called (or disposed).

Using the Authenticator

Ticket authentication occurs in two stages. The first stage validates the ticket for correctness via an IKerberosValidator with a default implementation of KerberosValidator. The second stage involves converting the ticket in to a usable ClaimsIdentity (a KerberosIdentity : ClaimsIdentity specifically), which occurs in the KerberosAuthenticator.

The easiest way to get started is to create a new KerberosAuthenticator and calling Authenticate. If you need to tweak the behavior of the conversion, you can do so by overriding the ConvertTicket(DecryptedData data) method.

var authenticator = new KerberosAuthenticator(new KeyTable(File.ReadAllBytes("sample.keytab")));

var identity = authenticator.Authenticate("YIIHCAYGKwYBBQUCoIIG...");

Assert.IsNotNull(identity);

var name = identity.Name;

Assert.IsFalse(string.IsNullOrWhitespace(name));

Note that the constructor parameter for the authenticator is a KeyTable. The KeyTable is a common format used to store keys on other platforms. You can either use a file created by a tool like ktpass, or you can just pass a KerberosKey during instantiation and it'll have the same effect.

On Updates to the Nuget Packages

The nuget packages will generally be kept up to date with any changes to the core library.

.NET Core

Hey, it works! Just add the nuget package as a reference and go.

More Information

Creating a Kerberos SPN in Active Directory

Active Directory requires an identity to be present that matches the domain where the token is being sent. This identity can be any user or computer object in Active Directory, but it needs to be configured correctly. This means it needs a Service Principal Name (SPN). You can find instructions on setting up a test user here.

Active Directory Claims

Active Directory has supported claims since Server 2012. At the time you could only access the claims through Windows principals or ADFS dark magic. Kerberos.NET now natively supports parsing claims in kerberos tickets. Take a look at the Claims Guide for more information on setting this up.

KeyTable (keytab) File Generation

Kerberos.NET supports the KeyTable (keytab) file format for passing in the keys used to decrypt and validate Kerberos tickets. The keytab file format is a common format used by many platforms for storing keys. You can generate these files on Windows by using the ktpass command line utility, which is part of the Remote Server Administration Tools (RSAT) pack. You can install it on a server via PowerShell (or through the add Windows components dialog):

Add-WindowsFeature RSAT

From there you can generate the keytab file by running the following command:

ktpass /princ HTTP/test.identityintervention.com@IDENTITIYINTERVENTION.COM /mapuser IDENTITYINTER\server01$ /pass P@ssw0rd! /out sample.keytab /crypto all /PTYPE KRB5_NT_SRV_INST /mapop set

The parameter princ is used to specify the generated PrincipalName, and mapuser which is used to map it to the user in Active Directory. The crypto parameter specifies which algorithms should generate entries.

AES Support

AES tickets are supported natively. No need to do anything extra!

This also now includes support for SHA256 and SHA384 through RFC8009.

Compound Authentication and Flexible Authentication Secure Tunneling Support

For more information see FAST Armoring.

This is not currently supported, but it's on the roadmap.

Registering Custom Decryptors

You can add your own support for other algorithms like DES (don't know why you would, but...) where you associate an Encryption type to a Func<> that instantiates new decryptors. There's also nothing stopping you from DI'ing this process if you like.

KerberosRequest.RegisterDecryptor(
   EncryptionType.DES_CBC_MD5,
   (token) => new DESMD5DecryptedData(token)
);

Replay Detection

The built-in replay detection uses a MemoryCache to temporarily store references to hashes of the ticket nonces. These references are removed when the ticket expires. The detection process occurs right after decryption as soon as the authenticator sequence number is available.

Note that the built-in detection logic does not work effectively when the application is clustered because the cache is not shared across machines. The built-in implementation uses an in-memory service and as such isn't shared with anyone.

You will need to create a cache that is shared across machines for this to work correctly in a clustered environment. This has been simplified greatly through the new .NET Core dependency injection services. All you need to do is register an IDistributedCache implementation. You can find more information on that in the Microsoft Docs.

If you'd like to use your own replay detection just implement the ITicketReplayValidator interface and pass it in the KerberosValidator constructor.

Samples!

There are samples!

  • KerbCrypto Runs through the 6 supported token formats.
    • rc4-kerberos-data
    • rc4-spnego-data
    • aes128-kerberos-data
    • aes128-spnego-data
    • aes256-kerberos-data
    • aes256-spnego-data
  • KerbTester A command line tool used to test real tickets and dump the parsed results.
  • KerberosMiddlewareEndToEndSample An end-to-end sample that shows how the server prompts for negotiation and the emulated browser's response.
  • KerberosMiddlewareSample A simple pass/fail middleware sample that decodes a ticket if present, but otherwise never prompts to negotiate.
  • KerberosWebSample A sample web project intended to be hosted in IIS that prompts to negotiate and validates any incoming tickets from the browser.

License

This project has an MIT License. See the License File for more details. Also see the Notices file for more information on the licenses of projects this depends on.

Kerberos Ticket Decoder Tool

This library comes with an optional utility to decode service tickets. It's easy to use. Just copy the Base64 encoded copy of the ticket into the left textbox. It will decode the unencrypted message if you don't provide a key. It will attempt to decrypt the message if you provide a key. You won't need to provide a host value if the ticket was encrypted using RC4, but it will need a host value if it's encrypted with AES (to derive the salt). Alternatively you could also include a keytab file if you happen to have that too.

You can launch it using the Bruce tool with bruce kdecode.

image

The decoder will convert the Kerberos ticket into a structured tree view. The process is Kerberos ASN.1 => JSON (๐Ÿ˜จ) => Tree View rendering. Here's the intermediate JSON that shows you all the information available to you in the ticket.

{
  "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,
          "Cipher": "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",
      "Name": [
        "desktop-h71o9uu"
      ]
    },
    "Authenticator": {
      "AuthenticatorVersionNumber": 5,
      "Realm": "CORP.IDENTITYINTERVENTION.COM",
      "CName": {
        "FullyQualifiedName": "jack",
        "IsServiceName": false,
        "Type": "NT_PRINCIPAL",
        "Name": [
          "jack"
        ]
      },
      "Checksum": {
        "Type": "32771",
        "Checksum": "EAAAAAAAAAAAAAAAAAAAAAAAAAA8QAAA"
      },
      "CuSec": 305,
      "CTime": "2021-04-21T17:38:11+00:00",
      "Subkey": {
        "Usage": "Unknown",
        "EType": "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": {
        "Usage": "Unknown",
        "EType": "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": {
      "Usage": null,
      "EncryptionType": "AES256_CTS_HMAC_SHA1_96",
      "Host": null,
      "PrincipalName": null,
      "Version": null,
      "Salt": "",
      "Password": null,
      "IterationParameter": "",
      "PasswordBytes": "",
      "SaltFormat": "ActiveDirectoryService",
      "RequiresDerivation": false
    },
    "Skew": "00:05:00"
  },
  "Computed": {
    "Name": "[email protected]",
    "Restrictions": {
      "KerbAuthDataTokenRestrictions": [
        {
          "RestrictionType": 0,
          "Restriction": {
            "Flags": "Full",
            "TokenIntegrityLevel": "High",
            "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": "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,
                "Attributes": [
                  "SE_GROUP_MANDATORY",
                  "SE_GROUP_ENABLED_BY_DEFAULT",
                  "SE_GROUP_ENABLED"
                ]
              },
              {
                "RelativeId": 1128,
                "Attributes": [
                  "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,
                "Attributes": [
                  "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": "DC01\u0000",
            "DomainName": "CORP\u0000",
            "DomainId": "S-1-5-21-311626132-1109945507-1757856464",
            "Reserved1": "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",
                "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": {
              "Id": 513,
              "Attributes": "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",
                "Value": "S-1-18-1"
              }
            ],
            "ResourceDomainSid": null,
            "ResourceGroups": [],
            "DomainSid": {
              "Id": 1757856464,
              "Attributes": "0",
              "Value": "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]",
            "Domain": "CORP.IDENTITYINTERVENTION.COM",
            "Flags": "0",
            "PacType": "UPN_DOMAIN_INFO"
          },
          "DelegationInformation": null,
          "HasRequiredFields": true,
          "Type": "AdWin2kPac"
        }
      ]
    },
    "ValidationMode": "Pac",
    "Claims": [
      {
        "Type": "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",
        "Value": "Domain Users"
      },
      {
        "Type": "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid",
        "Value": "S-1-5-21-311626132-1109945507-1757856464-1129"
      },
      {
        "Type": "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": "2021-04-21T23:52:22.5460123+00:00",
        "Version": 5,
        "Host": null,
        "PasswordBytes": "jBBI1KL19X3olbCK/f9p/+cxZi3RnqqQRH4WawB4EzY=",
        "KeyPrincipalName": {
          "Realm": "CORP.IDENTITYINTERVENTION.COM",
          "Names": [
            "STEVE-HOME"
          ],
          "NameType": "NT_SRV_HST",
          "FullyQualifiedName": "STEVE-HOME"
        },
        "Salt": null
      }
    ]
  }
}

kerberos.net's People

Contributors

anikammsft avatar aupolnikov avatar ccallahan avatar damirainullin avatar dependabot-preview[bot] avatar dependabot[bot] avatar diaafathalla avatar ericlaw1979 avatar filipnavara avatar gfoidl avatar jeremydamon-qiw avatar jnardone avatar jorgebay avatar karelz avatar kpister avatar macsux avatar michael-dev avatar petrsnd avatar quietust avatar simonbaas avatar stevesyfuhs avatar sugardadyadamberg avatar timhess avatar tonytroeff avatar watfordgnf avatar yshao-js avatar zhongzhaofeng avatar zubastic avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

kerberos.net's Issues

Add better logging to client

Is your feature request related to a problem? Please describe.
The KerberosClient doesn't do much in the way of logging.

Describe the solution you'd like
It would be useful if an ILogger were available to it so callers can examine whats going on. This should get passed down through the stacks to transports and cache. Ideally there would be a way to transit some correlation Id to the server, but that's limited by the structure of the protocol.

can you validate implicitly vs. keytab?

Is there a way to use this library on a domain-connected machine to validate tokens, but without having to use a manual keytab file(and instead use the existing domain membership of the computer in question as the connection back to the directory)?

Add support for RFC 4556 "PKINIT"

Is your feature request related to a problem? Please describe.
PKINIT is an asymmetric crypto extension for the initial AS-REQ authentication exchange. It's used for smart card (cert-based) authentication.

Describe the solution you'd like
A new class should be implemented AsymmetricKerberosCredential that extends KerberosCredential and accepts X509Certificate2 and AsymmetricAlgorithm parameters.

A new abstract class AsymmetricKerberosCryptoTransformer should be added to contain all the shared asymmetric goo and specific classes should be implemented for a given algorithm such as RSA.

This should probably also honor RFC 8636 for crypto agility reasons.

Additional context

https://tools.ietf.org/html/rfc4556
https://tools.ietf.org/html/rfc8636

Use Keytab file for Credentials

Hi All,

I was wondering if there was plans to be able to use a keytab file as means of authentication.

Something like:
... = new KerberosKeytabCredential("PrincipalNameHere", "./PathToKeytabFile", "realm");

Thanks much for the library.

Web sample doesn't work

after running the websample i get asked to enter credentials in my browser...
Unsure, i put in the "P@ssw0rd!" i found in the sample into both fields (since i lack the username)

This gives me an InvalidDataException, thrown because he can't detect the mechtype (in TryDiscoverMechType method of the ContextToken class)
It expects my element to have a class 'TagClass.Universal', but it is 'Application'..

Am I doing something wrong?

//offtopic: perhaps good to add a small readme.md to the sample projects, so people like me don't ask stupid questions

How to acquire existing token without providing password again

Hello,

I have seen the sample where a client is authenticated using username and password. However, some libraries (maybe this one too) support the use case where we want to just acquire the current Kerberos ticket seamlessly without having username/password passed as inputs (so without prompting the user again to enter their credentials because they will have already logged in).

In NSSPI, that is known as the "current context" for client or server.

Is there something similar in this library?

Example:
var client = new KerberosClient();
var kerbCred = new KerberosCurrentClientCredential(); // not Password credentials
await client.Authenticate(kerbCred); // or server.Authenticate() to get a ticket
var ticket = await client.GetServiceTicket("host/appservice.corp.identityintervention.com");

Thanks

Support for S4U2Self & S4U2Proxy

Is your feature request related to a problem? Please describe.
Customers are transitioning to OAuth2 based flows but still need to support systems that talk Kerberos. We're looking to offer an OAuth2/STS server that can exchange one type of tickets for another.

Describe the solution you'd like
We would like ability to use Kerberos.NET to leverage S4U2Self & S4U2Proxy extensions to obtain Kerberos tickets on behalf of clients and then get a service ticket to destination service.

Describe alternatives you've considered
ADFS is not an option in this case

Replacing functionality

I came across Kerberos.net trying to migrate a section of code from sharpview into the newish .net core world. Namely this section:

System.IdentityModel.Tokens.KerberosRequestorSecurityToken Ticket = null; try { Ticket = new System.IdentityModel.Tokens.KerberosRequestorSecurityToken(UserSPN); }

Is there an equivalent in Kerberos.net that can do this??

Invalid checksum

Hi,

I've followed all the great samples provided and actually I'm facing the following issue:

Invalid checksum at Kerberos.NET.Crypto.AES.AESDecryptor.DecryptWith(Byte[] workBuffer, Int32[] workLens, Byte[] key, Byte[] iv, KeyUsage usage) at Kerberos.NET.Crypto.AES.AESDecryptor.Decrypt(Byte[] cipher, Byte[] key, Byte[] iv, KeyUsage usage) at Kerberos.NET.Crypto.AES.AESDecryptor.Decrypt(Byte[] cipher, KerberosKey key, KeyUsage usage) at Kerberos.NET.Crypto.AESDecryptedData.Decrypt(KeyTable keytab) at Kerberos.NET.KerberosRequest.Decrypt(KrbApReq token, KeyTable keytab) at Kerberos.NET.KerberosValidator.Validate(Byte[] requestBytes) at Kerberos.NET.KerberosAuthenticator.Authenticate(Byte[] token) at Kerberos.NET.KerberosAuthenticator.Authenticate(String token) at elearningapp.MessageHandlers.KerberosMiddleware.ParseKerberosHeader(OwinEnvironment env, HttpContext httpContext)

Does anyone has already encountered that before ?

Thansk in advance !

Getting casting error when authenticating ticket

I'm getting an exception when authenticating this ticket.

System.InvalidCastException: Unable to cast object of type 'Kerberos.NET.Entities.NegTokenTarg' to type 'Kerberos.NET.Entities.ContextToken'.
at Kerberos.NET.KerberosValidator.d__17.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Kerberos.NET.KerberosAuthenticator.d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Kerberos.NET.KerberosAuthenticator.d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at UserQuery.

d__0.MoveNext() in C:\Users\astakhov\AppData\Local\Temp\LINQPad5_joemrpwt\query_uelfxt.cs:line 37

SPN password is "New0rder"

Negotiate oYIG0DCCBsygAwoBAaKCBsMEgga/YIIGuwYJKoZIhvcSAQICAQBuggaqMIIGpqADAgEFoQMCAQ6iBwMFACAAAACjggTiYYIE3jCCBNqgAwIBBaEMGwpBTE1JUkVYLkRDoiEwH6ADAgECoRgwFhsESFRUUBsOYWQuYWxtaXJleC5jb22jggSgMIIEnKADAgEXoQMCAQKiggSOBIIEijZdM1Lqxe9ev+WykLJko9XhMPRl2/TxnuM3GOSfUUyEyheAj2mRgTwGfAkjMdYI44+gNLSVa+pIvAkJ9cbb0HVqRIgv7R4QAB0ftBtLpjdRpUjmBRbmZ4pjSbN9DHEWPxIqW3EYhbOOFSjgPXEVXieHS/UbGlBGamxYzHH+ngq/NvZqwZWwFLb/QFC32QKvbjYeKytDjF24czwm/e9316Uh81nUfQmhaUJmwRMEKvNgUyBRX555xkgx90kAlD6BC7QtCkRDmHtuG/vLr093CEE/KxjCt659DAj8rTtnUOlmY0EvhRfhgIXuAMG5UOl6e5fNnsd4/UHajcCBvlMX0h7tCSmXCZHIZj5MzEG6jLYj42kpgyQmo3zSoLKXfBR/L96QJtWbrmq4wcdQTHafWCjAtLmsE8birCco1p0VhU52ztbQD1dYGBcvJoh6NjaVIvazhrRCYOmJEZuVnZ32XCvaeEccamuIMQErxovqQ2+cLTLVgRzKExGxkXREEZu4oClE9BrjulwjeO89BNhlfmLxpDUuqF5CGdU/gp9FmlCMyLzlrTzm+i8+K5CX0/l6RL3xlHrh7DPwC9/1vNoaz2S3xp3w4KMeySXY+rQN2K9J2v3p1EBB/A08UaaVzF7/qukXYgaFUn2pEG7ywlulp0a097qxFT73flT9g99+33kgF1vh03JOEm1Pj2Au+e8M3P8SN0Ung7cPOIvLutj+l5SLLTDdxLC+QODF/SHlb/INNChbptf9qKMW3jMqGvhZLhatVFBWExAHTvCRfyYEdUZY3q0YTrSJNx//Vvmt5NHKHibxyrBVk/AyoAHhXO8OSx2WMnaZesEUmSKTWoL1zqeANG0opADK1++gX2KdcvqxL54d3zUCAOr/FRc0vdVciwkAOft4aq5+Hniy7VJlNIfZsBCx8JHW0GwuM1LEOOWgSg5AH/38lgXw1yGsazXcz6/9h+Z3/EDIUT2UryfmP0e6wt5saqs5zFXl+J/OUMn+ugbC0sOFTAHAZ6Lz5UTkXfSVkShq1a5g9YBJSoiDTdSIJTLTYBXd377bZs8PtIFGxtvzCwmXa9BXh1uRIc3vMm64Gh8cl5Iud2BGNCVOZGGYG9etGD6RP/oHxrMJI/EbBxZxmDEBP2slYTc1Kv27Cbtke52IjIxwjCrM9d+x7GERD6UUOzaeRFf1I1dYOWgXjhGkVhfvWPLNmEv9EsHrpG4PyM+xllNKJ5OKqMZefdDFmo6O4lQIIP8KfWD8ZWZjwNuyjk6DWJU80WJ5jeD6FmTnQTOt6mek3b/xOWqwM2igpKKcIg/bbCvPqYfaeDuBjydFKthbZIyFmxH4VNuCfl6hZ0WIaIAwaRoXsKIZ1i2PoM7BOxctZ51ZqoJ8dUx3klfpz9xKzumjiswhg/alOFcmXe8bZd7aeA8F5Vmqwynm9yvX9jY4bvYzH1e6GrF7aOWxwkqiH6GfjmHAq63jHenR9vNryViVHdGPe57kfpg5YqnFl0JaUIL9i3Q5mR6y+TnjSuHDD4egxeodbKwuoEubm0igLE/+VxekggGpMIIBpaADAgEXooIBnASCAZj6K4D8NqBiw9JmgFkf/NHPdwDBt+ukckoDOJCtEPlNeK6mqA9q1CA9vGmh2F7QaBpQcULTINDhzSjyjDACbUN9OHFBRf4prrRJIAG4zYfip1ZF6/CPDlyYe5+PYH+g+tjbd/hLcoYGHjDx71n9clkiSghIEDicwWRQ5Bqos8n7L7LNTAqqanXW58mJOdnTRjqVsb56BDm7ZsmSMwIuVnw0iE9aHLLbXcp12rVkgzcVFod9r2FydAUIjXX/Uyfdqpo5o7/zy3R4KFPllzdw56ljl+sYlZ3WiWMkCPWwBnTGB+9ymwWrGP0zDpw9tz7/Ds3ThQxO7EQutGUvKmNnmdw7/eaXTYJgraHlQhlGnL4/Tc1Q7HfTXj0PWr0/8V0GJ/dMkjfjth/khHFQHKMdD+V5+m8qe/THDCNE5cLgZVduy3/Ib6L8qgOfoMJiAvLyNnjKhAYHa0uNLXtVGsIajCxF1wij0M6wJ2RJaiWhC9BVfcDqpEPnhfSD1bN2JfpY1R8RnBy7aCDPKfTyjLOD/5BC6jPhX3cF4h8=

Build failing - AsnXml.targets(23, 5): [MSB4062] The "Microsoft.Build.Tasks.XslTransformation" task could not be loaded

AsnXml.targets(23, 5): [MSB4062] The "Microsoft.Build.Tasks.XslTransformation" task could not be loaded from the assembly Microsoft.Build.Tasks.Core, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a. Confirm that the declaration is correct, that the assembly and all its dependencies are available, and that the task contains a public class that implements Microsoft.Build.Framework.ITask.

Add server support for PKINIT

Is your feature request related to a problem? Please describe.
This is a tracker for the server side of PKINIT #95.

Describe the solution you'd like
Implement PublicKeyPreAuthenticationHandler : KdcPreAuthenticationHandlerBase that queries IRealmService for the KDC signing key. Extract the SignedCms signing certificate from the request and validate it is acceptable for the requested user. Expose a delegate or method overload that lets implementers specify their own validation logic.

Add support for RFC 3244 "Change Password" flow

Is your feature request related to a problem? Please describe.
Change password is a common enough requirement for Kerberos users and it should be possible to expose this functionality to callers with minimal implementation requirements. This supersedes #79.

Describe the solution you'd like
KerberosClient should add a method ChangePassword(KerberosCredential currentCredential, string newPassword). This should invoke an AS-REQ call to service kadmin/changepw@REALM and then a call to a KDC on port 464 with a change-password message.

Additional context

Spec is defined here: https://www.rfc-editor.org/rfc/rfc3244.txt

Support .NET Standard 1.x

There seems to be no blocking issue in order to support .NET Standard 1.3 (or at least 1.5). That way we can support .NET Core 1.0 users.

I hope I can give it a try in the next couple of days.

Also take the opportunity to congrats @SteveSyfuhs for a great lib!

Encryption token

In the "Using the Library" section of the ReadMe, the section line takes in a token to authenticate:
var identity = authenticator.Authenticate("YIIHCAYGKwYBBQUCoIIG...");
I also see these types of encryption tokens in the sample app "KerbTester". In the "KerberosMiddlewareEndtoEndSample" it is hard coded in the program as "NegotiateSample"

Where does this token come from? How do we generate one to use in our code if its needed? We are trying to use Kerberos to authenticate a http request, and we have a keytab but are stuck on this token.

Thanks!

Force refreshing ticket near expiration?

Is your feature request related to a problem? Please describe.
So currently as I am experimenting the ticket expiration is always the same even if you call renew/authenticate and getserviceticket multiple times. This makes me wonder what would happen if at the edge of expiration kerberos ticket is retrieved but used in the request a second after it has expired (due to just some delay).

Describe the solution you'd like
To avoid this I would like to force refresh/generate new ticket that would have new expiration.

Describe alternatives you've considered
I couldn't get this to happen any other way except when creating new instance of the KerberosClient. I obviously could just add some sleep if I can see that the ticket is about to expire, but that is not ideal.

Is this already possible in some way or maybe the usage of kerberos is incorrect here?

use with .net forms auth?

Hi there, I am new to all this stuff (kerberos). But I have been working on a .net Forms Auth application for 6 years. Recently the need to be able to validate a kerberos ticket has been asked of us and I was curious if there's some simple snippets you could provide that would point me in the right direction (without needing to upend our current authentication method). The samples provided are all using claims and I am not totally sure how that would port to forms auth/cookie auth.

We typically validate a user by username/password (sometimes through AD) and then create a forms auth ticket that is saved as a cookie and used to validate future requests.

Assuming we can validate the kerberos ticket, we can just create a session with (assuming here) a username?

Any guidance would be greatly appreciated.

Add support for RFC 5349 "Elliptic Curve PKINIT"

Is your feature request related to a problem? Please describe.
The base PKINIT spec supports straight Diffie Hellman using MODP 2 or 14 parameters. This is inefficient and leads to potential interop problems. ECC support was spec'ed shortly after PKINIT and introduces ECDH for key exchange and certificate signatures. This will have better performance implications as well as better cross-platform support as ECDH is supported in .NET Core.

Describe the solution you'd like
Introduce logic into AsymmetricKerberosCredential that detects if the client certificate is EC, and force everything into using EC.

Add a new property to the credential that indicates the key exchange should prefer ECDH over DH (should it be default?).

Additional context
https://tools.ietf.org/html/rfc5349

AES 256 Encryption type kerberos tickets

Hi,

I am getting a kerberos ticket that is encrypted with a key using AES256, when i try to validate the ticket using your kerberos validator, i get invalid check-sum error.

var kerberosValidator = new KerberosValidator(new KerberosKey("sampleKey")) { ValidateAfterDecrypt = ValidationActions.None };
var authenticator = new KerberosAuthenticator(kerberosValidator);
var identity = await authenticator.Authenticate(ticket);

GetKey is really strict

I am debugging a program trying to use this assembly.

KeyTable.GetKey seems really strict for what's trying to happen here.

I can understand the strict match on EncryptionType + PrincipalName, though using PrincipalName.Equals for this might be a bit too strict. Equals is built to exactly match, which is correct for Equals, but for finding a match, shouldn't this allow for a keytab that has more than one Name for a given Principal and EncryptionType? You can have more than one SPN for an account, but obviously an incoming request is only going to have a single SPN. (Also: it's not clear to me that a NameType mismatch is truly a mismatch, e.g. NT_PRINCIPAL in the keytab and NT_SRV_INST in the request. Other libraries are more forgiving in this area.)

Next... if that matching fails (in KeyTable.GetKey) it will use the first entry, but only if there's only a single entry in the keytab. But shouldn't this take the first entry for the given EncryptionType? If I have 5 entries in my keytab, for the 5 different supported algorithms, and my incoming request says RC4_HMAC_NT, if I don't get a match based on type+name, why wouldn't we pick the first RC4_HMAC_NT in the keytab?

Add client support for PKINIT

Is your feature request related to a problem? Please describe.
This is a tracker for the client side of PKINIT #95.

Describe the solution you'd like
Implement AsymmetricKerberosCredential : KerberosCredential which takes an X509Certificate2 instance containing a private key.

Invert the pre-auth logic such that a given credential controls how it injects a PA element into the as-req instead of leaving it to the KrbAsReq class. Move the default encrypted timestamp implementation into the abstract KerberosCredential class and have existing credentials use that default implementation.

Failure to parse keytab due to extra padding

While attempting to parse a keytab acquired using Samba's net ads join command (against a Windows Server 2012 R2 DC), only the first key (of type DES_CBC_CRC) was loaded successfully - the second one had garbage values (type 16718, version 81, length 0) because the first key had an extra 4 bytes of padding at the end which weren't being read, and the other 13 weren't loaded at all.

The problem is in Crypto/KeyTab.cs, in the constructor for KeyEntry - the BinaryReader needs to be explicitly seeked past any unread bytes to ensure that it's at the right offset for the next key.

There's actually another bug in that function too: according to various keytab file format documents, the logic for reading a 32-bit Version field at the end of the entry needs to check if there are at least 4 unread bytes available (Length - bytesConsumedInEntity >= 4, rather than just > 0), and it should probably also ensure that the value is nonzero before using it.

Support for mutual authentication?

Most other KRB5 implementations I've used (including mod_auth_kerb) support mutual authentication by default - after the client submits a valid Negotiate token, the server responds with its own WWW-Authenticate: Negotiate header containing a Base64-encoded value that the Client can decode in order to confirm that it's actually talking to the correct server.

This library does not appear to support it, at least in its current state - there are symbols defined in Entities/Enums.cs related to mutual authentication, but they are not referenced from anywhere else.

Are there any plans to implement this functionality in the near future?

Encoded tickets fail to decode

The encoded tickets created by Ticket.Encode method fail to decode when run through validator. I've also tried with EncodeApplication (not clear what the difference is).

var ticket = await client.GetServiceTicket("iwasvc");

var ticketString = Convert.ToBase64String(ticket.Ticket.EncodeApplication().ToArray());

var validator = new KerberosAuthenticator(new KerberosValidator(new KerberosKey("MYPASSWORD")));
var claims = await validator.Authenticate(ticketString);

Throws the following error:

System.Security.Cryptography.CryptographicException: ASN1 corrupted data. Expected Application-0; Actual: Constructed Application-1
   at System.Security.Cryptography.Asn1.AsnReader.CheckExpectedTag(Asn1Tag tag, Asn1Tag expectedTag, UniversalTagNumber tagNumber) in c:\Projects\Kerberos.NET\Kerberos.NET\Asn1\Experimental\AsnReader.cs:line 455
   at System.Security.Cryptography.Asn1.AsnReader.ReadSequence(Asn1Tag expectedTag) in c:\Projects\Kerberos.NET\Kerberos.NET\Asn1\Experimental\AsnReader.Sequence.cs:line 58
   at Kerberos.NET.Entities.GssApiToken.Decode(ReadOnlyMemory`1 data) in c:\Projects\Kerberos.NET\Kerberos.NET\Entities\GssApi\GssApiToken.cs:line 35
   at Kerberos.NET.MessageParser.Parse(ReadOnlyMemory`1 data) in c:\Projects\Kerberos.NET\Kerberos.NET\MessageParser.cs:line 66
   at Kerberos.NET.MessageParser.Parse[T](ReadOnlyMemory`1 data) in c:\Projects\Kerberos.NET\Kerberos.NET\MessageParser.cs:line 56
   at Kerberos.NET.MessageParser.ParseContext(ReadOnlyMemory`1 data) in c:\Projects\Kerberos.NET\Kerberos.NET\MessageParser.cs:line 41
   at Kerberos.NET.KerberosValidator.Validate(Byte[] requestBytes) in c:\Projects\Kerberos.NET\Kerberos.NET\KerberosValidator.cs:line 54
   at Kerberos.NET.KerberosAuthenticator.Authenticate(Byte[] token) in c:\Projects\Kerberos.NET\Kerberos.NET\KerberosAuthenticator.cs:line 48
   at Kerberos.NET.KerberosAuthenticator.Authenticate(String token) in c:\Projects\Kerberos.NET\Kerberos.NET\KerberosAuthenticator.cs:line 43
   at KerberosPlay.Program.Main(String[] args) in C:\Projects\SqlClientPlay\KerberosPlay\Program.cs:line 31

[question] Getting ticket details after authentication?

Is there a way to properly extract details about the incoming ticket after I've authenticated it?

The validator returns a bunch of interesting information, notably in the ticket (like the various timestamps and the ticket flags) but I can't figure out how to get at that information. Using the validator outside of .Authenticate triggers the replay detection logic, in either direction since the authentication call is doing it's own .Validate.

Am I missing something obvious of how to get at the validated/decrypted token inside of the KerberosAuthenticator?

Kerberos.NET Usage with untrusted domains

hi

i tried to use basic kerberos sample at my end. but i get invalid checksum error. can you help?

`

var keytab = new KeyTable(File.ReadAllBytes(@"C:\Kafka\SRV.keytab"));
string raw = "";
string something = "aes";
switch (something)
{
case "aes":
case "aes256":
raw = "YIIJOAYGKwYBBQUCoIIJLDCC...";
break;
case "aes128":
raw = "YIIHCAYGKwYBBQUCoIIG/DCCB...";
break;
case "rc4":
raw = "YIIKbQYGKwYBBQUCoIIKYTCCCl...";
break;
case "spnego":
raw = "YIGeBgYrBgEFBQKggZMwgZCgGjAYBgorBgEEAYI3AgIeBgorBgEEAYI3AgIKonIEcE5FR09FWFRTAAAAAAAAAABgAAAAcAAAAAPx046cicVOngxMfxUsCsEIMeUM39SSXP1N9DuDVIU3IFosQ3eWTsKOPdfTNWD4SAAAAAAAAAAAYAAAAAEAAAAAAAAAAAAAAMNbiTClcBVAolAmCpGQrZA=";
break;
default:
raw = args[1];
break;
}

        var validator = new KerberosValidator(keytab)
        {
            //Logger = W
        };

        var authenticator = new KerberosAuthenticator(validator);
        var identity = authenticator.Authenticate(raw);


        var t = identity.Result;

        Console.WriteLine(identity);

        var name = identity.Id;`

Add a better NDR encoder/decoder for PAC and Claims

Is your feature request related to a problem? Please describe.
The existing NDR encoder is buggy and does not scale to handling arbitrary structures. It would be nice if a generic implementation could be built to handle encoding and decoding for safety, security, and correctness.

Windows already supports this through the NdrMesTypeEncode2 and NdrMesTypeDecode2 functions for RPC. It might be reasonable to call into that on Windows and use a custom implementation for cross-platform using a PAL-like mechanism.

Add a Platform Abstraction Layer (PAL) for Crypto

Is your feature request related to a problem? Please describe.
Legacy cryptographic algorithms like MD4 require calling into Windows Win32 APIs directly. This is problematic because there's no Win32 equivalent on other platforms which will cause the calling application to break in terrible ways.

A PAL is useful here because the library can continue to call directly into Win32 APIs and use either a custom implementation or third party like OpenSSL on other platforms.

Describe the solution you'd like
Similar to how .NET corefx does it today with a class file with shared functionality, followed by a Class.Platform.cs file for each class.

[QUESTION] How can I use this package to use in my WCF client?

I am using a SOAP webservice with standard WCF tooling in Visual Studio.
On my machine that is in Active Directory, passing the Windows Credentials, it works properly, but when I send my app to other PC that is no in AD, the auth fail.

The SOAP webservice, use Kerberos protocol to authenticate users, I was trying to use this in standard SOAP client, but I didn't find a way.

How can I achieve that?

Using the Base 64 string of ticket.EncodeNegotiate in Authorization header gets rejected by kerberos service.

Hey,

This might just be me who does not have enough experience with the Kerberos protocol or the Kerberos.Net Nuget Package.

What I'm essentially attempting to do is call an API which required kerberos authentication.

Using Kerberos.NET, I have successfully gotten a Service Ticket from the authentication server for the SPN where the API is located.

However, after that it's not quite clear if I'm doing things correctly. What I want to do is put the ticket session key in the Authorization header, using the Negotiate scheme, when I send an HTTP request to the API. What I do right now is this:

`
var encodedNegotiateValue = Convert.ToBase64String(ticket.EncodeNegotiate().ToArray());

...
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Negotiate", encodedNegotiateValue);

`

However, this does not work. Am I missing something essential, or using the API incorrectly? I tried to check out the End 2 End tests and saw that a test for negotiate was there. It also uses the Authenticator class. However, I'm not sure where this fits into the protocol, or how exactly to build up the Base 64 encoded negotiate string :)

receiving a Kerberos ticket that is incorrect format

Hi Steve, based on convo,

I keep getting "Unknown Negotiate Extension Signature". I are using a keytab file generated on our dev box which has our entire AD. When i get the kerberos ticket from the client i get that error. You specified that the ticket i am getting is not correct format.

So i think i am not doing the handshake properly to get the right kerberos ticket from browser. based on your code,

if (!context.Request.Headers.TryGetValue("Authorization", out StringValues authzHeader) || authzHeader.Count != 1)
            {
                context.Response.Headers.Add("WWW-Authenticate", new[] { "Negotiate" });
                context.Response.StatusCode = 401;

                return false;
            }

we we send this, we are not getting a kerberos ticket the browser is sending something else. How can i force my browser or cleint to send the correct kerberos ticket, do i need to include something else int he WWW-Authenticate.

Thanks

Could not load file or assembly 'System.Runtime.Caching' Net Core 2.0

I get the following exception when calling
await authenticator.Authenticate(token);
in a netcoreapp2.0 webapi application.

---- System.IO.FileNotFoundException : Could not load file or assembly 'System.Runtime.Caching, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.

Im using nuget package <PackageReference Include="Kerberos.NET" Version="1.5.821.1"/>

Seems like the nuget package is binding to the assembly for net46 applications and not .net core 2.0 apps.

Unknown Negotiate Extension Signature error

Hi,

I tried creating a custom authenticator using .net core 2, and Kerberos.NET package (using a keytab validator) but I'm always getting this error of: Unknown Negotiate Extension Signature..
from this file:
Kerberos.NET/Kerberos.NET/Entities/NegotiateExtension.cs

Is there a reason for the hardcoded signature here?
What can I do to bypass this?

Thanks,
Liat

Add support for RFC 8070 "PKINIT Freshness"

Is your feature request related to a problem? Please describe.
Kerberos as spec'ed does not provide a guarantee of current possession of the client key. This means client as-req's can be generated infinitively into the future once, and then be used without requiring knowledge of the client key. The "Freshness" spec introduces the idea of a freshness token sent in the krb-error message to indicate the client needs to include it in the message to continue, which requires current knowledge of the client key to sign the message.

Describe the solution you'd like

KerberosClient should detect the PA_AS_FRESHNESS PA-Data element, inject the token into a new PA-Data element, and retry the request.

PublicKeyPreAuthenticationHandler should be extended to check for the freshness token and validate correctness. A new setting should be included on IRealmSettings that indicates whether freshness is supported or not and if it is, should be injected if not present.

The freshness token should be a short lived value tying the client to the current time. An example token might be something like AesGcm(value: upn | (now + 5 min), key: krbtgt) and validated by decrypting and checking the timestamp hasn't passed

Additional context

https://tools.ietf.org/html/rfc8070

Exception creating an instance of KerberosValidator on .NET Core 2.0

When creating an instance of the KerberosValidator were are getting the following exception:
Method 'GetAsync' in type 'Kerberos.NET.DistributedMemoryCache' from assembly 'Kerberos.NET, Version=2.0.0.0, Culture=neutral, PublicKeyToken=10b231fbfc8c4b4d' does not have an implementation.

var validator = new KerberosValidator(new KerberosKey(Options.Secret)) { ValidateAfterDecrypt = ValidationActions.All };

Is there something I need to do to avoid this exception?

Null reference exception on Authenticate

When calling KerberosAuthenticator.Authenticate a null reference exception is thrown.

I dug down into the code and it seems to happen when adding the Sid claim because the pac.LoginInfo is null.

Digging deeper, it seems the NdrBinaryReader can't read non ascii characters.

Configuration compatibility with MIT implementation

Trying to use a .net core application in a linux container against existing kerberos infrastructure.
Most documentation for apps in that situation indicate the need for using keytab files and rely on the MIT command line tools to set everything up.
The kdc information is in the /etc/krb5.conf.
It seems that the ASPNetCore team also uses that for their Negotiate mechanism. It would be nice if Kerberos.Net also did.

KerberosClient should provide an initialization mechanism that consumes the same krb5.conf.

I am going to be doing this in my client right now but with some guidance I could contribute whatever I do if wanted.

Thx

Generate TGT and "Authenticator"

Hi Steve, would your package work for the strictly client side functionality of generating a particular service TGT and the associated "Authenticator" to then send to the server service for authentication?

If so, do you mind pointing me to the calls that i would use to do it?

Thanks, Scot

Appears to be a bug in reading version 1 keytabs

In KeyTable.cs, ReadPrincipal Method, var nameType = (PrincipalNameType)ReadInt32(reader); should not be executed if it's version 1 according to this documentation: https://web.mit.edu/kerberos/krb5-1.12/doc/formats/keytab_file_format.html

I think the code should look like:

var nameType = PrincipalNameType.NT_UNKNOWN;
if (version != 1)
{
    nameType = (PrincipalNameType)ReadInt32(reader);
}

Not that I use that version 1, nor can confirm it, but noticed this as I was doing a code review.

Reorganize Tests into distinct areas and separate Unit and E2E tests

Is your feature request related to a problem? Please describe.
Tests are currently a haphazard mix of unit and E2E tests that often cover wide ranges of functionality in a given test or class.

E2E tests are also currently written as unit tests, which make it easy to quickly verify the library works, but doesn't make it easy to pinpoint exact failures.

Server side is also relying heavily on E2E tests to guarantee services work correctly, which is dangerous.

Describe the solution you'd like
It would be better if each test class was better organized and methods only tested smaller units of functionality.

Converge logging framework into Microsoft.Extensions.Logging

Is your feature request related to a problem? Please describe.
The logging framework in this library is simplistic which makes it difficult to diagnose issues, especially at scale. It would be useful if this library supported a library like Microsoft.Extensions.Logging for structured logging.

Describe the solution you'd like
Rewrite K.N.ILogger to wrap M.E.L.ILogger and provide structured data at critical points in the server and client processes.

ClaimIdentity cannot be mapped to legacy format

Currently, when Authenticator establishes ClaimsIdentity, it does so in the format of "user@REALM". For dealing with legacy scenarios, it would be useful to have access to principal in "DOMAIN\user" format. I propose either: a) an option for authenticator on how to establish the primary Name claim. b) adding additional claim into ClaimIdentity in the legacy format. c) a+b

Add GSS/SSPI compatible interface implementation for easier interop between systems

Is your feature request related to a problem? Please describe.
Most applications do not use Kerberos directly. They often rely on the platform below them exposing an interface for requesting tickets. This is GSS generically, and SSPI on Windows. It's defined in RFC 2743.

Describe the solution you'd like

An interface and implementation that exposes all the required functions of GSS:

interface IGssContext 
{
   GSS_Acquire_cred(...);
   GSS_Release_cred(...);
   GSS_Inquire_cred(...);
   
   GSS_Add_cred(...);
   GSS_Inquire_cred_by_mech(...);
   
   
   GSS_Init_sec_context(...);
   GSS_Accept_sec_context(...);
   GSS_Delete_sec_context(...);
   GSS_Process_context_token(...);
   GSS_Context_time(...);
   GSS_Inquire_context(...);
   GSS_Wrap_size_limit(...);
   GSS_Export_sec_context(...);
   GSS_Import_sec_context(...);
   
   GSS_GetMIC(...);
   GSS_VerifyMIC(...);
   GSS_Wrap(...);
   GSS_Unwrap(...);
   
   GSS_Display_status(...);
   GSS_Indicate_mechs(...);
   GSS_Compare_name(...);
   GSS_Display_name(...);
   GSS_Import_name(...);
   GSS_Release_name(...);
   GSS_Release_buffer(...);
   GSS_Release_OID_set(...);
   GSS_Create_empty_OID_set(...);
   GSS_Add_OID_set_member(...);
   GSS_Test_OID_set_member(...);
   GSS_Inquire_names_for_mech(...);
   GSS_Inquire_mechs_for_name(...);
   GSS_Canonicalize_name(...);
   GSS_Export_name(...);
   GSS_Duplicate_name(...);
}

Change Active Directory password using Kerberos Change-Password protocol and .NET Core 3

By reading Kerberos Change Password Protocol and Kerberos.NET Samples, I wrote the following code:

using Kerberos.NET;
using Kerberos.NET.Client;
using Kerberos.NET.Credentials;
using Kerberos.NET.Crypto;
using Kerberos.NET.Entities;
using System;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace KerberosDemo
{
    class Program
    {
        static async Task Main(string[] args)
        {
            string activeDirectoryServer = "10.12.34.56:88"; // kdc port
            string domain = "TEST.LOCAL";
            string username = "testuser@" + domain;
            string oldPassword = "123";
            string newPassword = "456";

            using var client = new KerberosClient(activeDirectoryServer);
            var kerbCred = new KerberosPasswordCredential(username, oldPassword, domain);
            await client.Authenticate(kerbCred);
            var serviceTicket = await client.GetServiceTicket("kadmin/changepw");

            var apReq = new KrbApReq
            {
                Ticket = serviceTicket.Ticket,
                Authenticator = KrbEncryptedData.Encrypt(Encoding.UTF8.GetBytes(newPassword).AsMemory(), kerbCred.CreateKey(), KeyUsage.ApReqAuthenticator),
                ProtocolVersionNumber = 1
            };

            var tcp = client.Transports.FirstOrDefault(t => t.Protocol == ProtocolType.Tcp);
            await tcp.SendMessage<KrbApReq, KrbAsRep>(domain, apReq);
        }
    }
}

I got the following exception at await tcp.SendMessage<KrbApReq, KrbAsRep>(domain, apReq);:

Unhandled exception.
System.Security.Cryptography.CryptographicException: ASN1 corrupted
data. at
System.Security.Cryptography.Asn1.AsnReader.ReadTagAndLength(Nullable1& contentsLength, Int32& bytesRead) in d:\a\1\s\Kerberos.NET\Asn1\Experimental\AsnReader.cs:line 305 at Kerberos.NET.Entities.KrbError.CanDecode(ReadOnlyMemory1 encoded) in
d:\a\1\s\Kerberos.NET\Entities\Krb\KrbError.cs:line 23 at
Kerberos.NET.Transport.KerberosTransportBase.Decode[T](ReadOnlyMemory1 response) in d:\a\1\s\Kerberos.NET\Client\Transport\KerberosTransportBase.cs:line 41 at Kerberos.NET.Transport.TcpKerberosTransport.ReadResponse[T](NetworkStream stream, CancellationToken cancellation) in d:\a\1\s\Kerberos.NET\Client\Transport\TcpKerberosTransport.cs:line 69 at Kerberos.NET.Transport.TcpKerberosTransport.SendMessage[T](String domain, ReadOnlyMemory1 encoded, CancellationToken cancellation) in
d:\a\1\s\Kerberos.NET\Client\Transport\TcpKerberosTransport.cs:line 58
at KerberosDemo.Program.Main(String[] args) at
KerberosDemo.Program.

(String[] args)

Your help is appreciated. Thanks.

https://stackoverflow.com/questions/58670044/change-active-directory-password-using-kerberos-change-password-protocol-and-ne

Service credentials and impersonation

I have validator and authenticator working with keytab created from a service account. Based on that:

  • Can I do away with need for keytab somehow if I'm running the Kerberos code in a process already running as the service account?
  • Is there anything I can grab after/during validate/authenticate (within ticket object, etc.) that I can use to get an impersonation token?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.