You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Many thanks for your great work with this library.
We use it to exchange Kerberos Tickets to JWT-Token (from ADFS) and also the vise versa JWT Token to Kerberos Tickets.
Describe the bug
We found a caching related bug.
If CacheServiceTickets on the KerberosClient is enabled, tickets for wrong users are returned.
To Reproduce
The sample below reproduces the bug.
Setup is a bit complicated, but the scenario is as follows:
A service requests a TGT Ticket on behalf of user for another target service.
On the target service itself, the ticket is decoded with the Authenticator and the according keytab.
This is the place where you can see that it is the wrong ticket.
Commands to create 2 demo users and a service user:
using System;
using System.IO;
using System.Threading.Tasks;
using Kerberos.NET;
using Kerberos.NET.Client;
using Kerberos.NET.Configuration;
using Kerberos.NET.Credentials;
using Kerberos.NET.Crypto;
using Kerberos.NET.Entities;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Console;
namespace TEP.Testing.Bug
{
class Program
{
static async Task Main(string[] args)
{
var loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddConsole(options => options.LogToStandardErrorThreshold = LogLevel.Trace);
builder.AddFilter<ConsoleLoggerProvider>(level => level >= LogLevel.Trace);
});
var user1 = "user-demo1@tep.local";
var user2 = "user-demo2@tep.local";
var config = Krb5Config.Parse(await File.ReadAllTextAsync("./krb5.conf"));
var serviceCredentials = new KerberosPasswordCredential("svc-top_lab@tep.local", "P@ssw0rd");
// SPN of the target service
var targetServiceSPN = "HTTP/api-krb.tep-loris.orchid.tribbles.cloud";
// keytab & authenticator for the target service that would receive the tickets
var keyTab = new KeyTable(await File.ReadAllBytesAsync("./keytab"));
var authenticator = new KerberosAuthenticator(keyTab, loggerFactory);
Console.WriteLine("\n\n\nWith CacheServiceTickets enabled;");
{
var s4UClient = new KerberosClient(config, loggerFactory)
{
CacheServiceTickets = true,
CacheInMemory = true,
RenewTickets = true,
};
await s4UClient.Authenticate(serviceCredentials);
// S4U flow to access a service in behave of a user
var s4U2SelfUser1Request = await s4UClient.GetServiceTicket(serviceCredentials.UserName, ApOptions.MutualRequired, user1);
var s4U2ProxyUser1Ticket = await s4UClient.GetServiceTicket(targetServiceSPN, ApOptions.MutualRequired, s4uTicket: s4U2SelfUser1Request.Ticket);
var s4U2SelfUser2Request = await s4UClient.GetServiceTicket(serviceCredentials.UserName, ApOptions.MutualRequired, user2);
var s4U2ProxyUser2Ticket = await s4UClient.GetServiceTicket(targetServiceSPN, ApOptions.MutualRequired, s4uTicket: s4U2SelfUser2Request.Ticket);
// encode & decode tickets and validate them with the keytab of the target service
var user1TicketBytes = s4U2ProxyUser1Ticket.EncodeGssApi().ToArray();
var user1Identity = await authenticator.Authenticate(user1TicketBytes);
var user2TicketBytes = s4U2ProxyUser2Ticket.EncodeGssApi().ToArray();
var user2Identity = await authenticator.Authenticate(user2TicketBytes);
Console.WriteLine($"\t Expected Identity: {user1} Identity Ticket: {user1Identity.Name}");
// user2Identity is the one from user1
Console.WriteLine($"\t Expected Identity: {user2} Identity Ticket: {user2Identity.Name}");
if (!user2.Equals(user2Identity.Name))
{
Console.WriteLine("Wrong user in ticket.");
}
}
//In this block everything is okay - if CacheServiceTickets are disabled the result is as expected
Console.WriteLine("With CacheServiceTickets disabled;");
{
var s4UClient = new KerberosClient(config, loggerFactory)
{
CacheServiceTickets = false,
CacheInMemory = true,
RenewTickets = true,
};
await s4UClient.Authenticate(serviceCredentials);
var s4U2SelfUser1Request = await s4UClient.GetServiceTicket(serviceCredentials.UserName, ApOptions.MutualRequired, user1);
var s4U2ProxyUser1Ticket = await s4UClient.GetServiceTicket(targetServiceSPN, ApOptions.MutualRequired, s4uTicket: s4U2SelfUser1Request.Ticket);
var s4U2SelfUser2Request = await s4UClient.GetServiceTicket(serviceCredentials.UserName, ApOptions.MutualRequired, user2);
var s4U2ProxyUser2Ticket = await s4UClient.GetServiceTicket(targetServiceSPN, ApOptions.MutualRequired, s4uTicket: s4U2SelfUser2Request.Ticket);
var user1TicketBytes = s4U2ProxyUser1Ticket.EncodeGssApi().ToArray();
var user1Identity = await authenticator.Authenticate(user1TicketBytes);
var user2TicketBytes = s4U2ProxyUser2Ticket.EncodeGssApi().ToArray();
var user2Identity = await authenticator.Authenticate(user2TicketBytes);
Console.WriteLine($"\t Expected Identity: {user1} Identity Ticket: {user1Identity.Name}");
Console.WriteLine($"\t Expected Identity: {user2} Identity Ticket: {user2Identity.Name}");
}
Console.ReadLine();
}
}
}
<img width="682" alt="Screenshot 2021-06-02 at 17 19 37" src="https://user-images.githubusercontent.com/343776/120513033-24053d80-c3cc-11eb-8ab9-2ab14fcdcead.png">
Console output looks like this:
With CacheServiceTickets enabled;
trce: Kerberos.NET.Client.KerberosClient[0]
Attempting AS-REQ. UserName = svc-top_lab; Domain = TEP.LOCAL; Nonce = -768730279
trce: Kerberos.NET.Transport.TcpKerberosTransport[0]
TCP connecting to dc.tep.local on port 88
dbug: Kerberos.NET.Transport.TcpKerberosTransport[0]
TCP connected to dc.tep.local on port 88
dbug: Kerberos.NET.Client.KerberosClient[0]
AS-REP PA-Data: EType = AES256_CTS_HMAC_SHA1_96; Salt = TEP.LOCALHTTPapi-krb.tep-lab.orchid.tribbles.cloud;
dbug: Kerberos.NET.Client.KerberosClient[0]
AS-REP PA-Data: EType = RC4_HMAC_NT; Salt = (null);
trce: Kerberos.NET.Client.KerberosClient[0]
Attempting AS-REQ. UserName = svc-top_lab; Domain = TEP.LOCAL; Nonce = -639463043
trce: Kerberos.NET.Transport.TcpKerberosTransport[0]
TCP connecting to dc.tep.local on port 88
dbug: Kerberos.NET.Transport.TcpKerberosTransport[0]
TCP connected to dc.tep.local on port 88
dbug: Kerberos.NET.Client.KerberosClient[0]
EncPart expected to be KrbEncAsRepPart and is actually KrbEncAsRepPart
trce: Kerberos.NET.TicketCacheBase[0]
Caching ticket until 06/03/2021 01:35:33 +00:00 for kerberos--krbtgt/tep.local with renewal option until 06/03/2021 15:35:33 +00:00
info: Kerberos.NET.Client.KerberosClient[0]
Requesting TGS for svc-top_lab; TGT Realm = TEP.LOCAL; TGT Service = krbtgt/TEP.LOCAL; S4U = user-demo1@tep.local; S4UTicket = (null)
trce: Kerberos.NET.Transport.TcpKerberosTransport[0]
TCP connecting to dc.tep.local on port 88
dbug: Kerberos.NET.Transport.TcpKerberosTransport[0]
TCP connected to dc.tep.local on port 88
info: Kerberos.NET.Client.KerberosClient[0]
TGS-REP for svc-top_lab
trce: Kerberos.NET.TicketCacheBase[0]
Caching ticket until 06/03/2021 01:35:33 +00:00 for kerberos-user-demo1@tep.local-svc-top_lab with renewal option until 06/03/2021 15:35:33 +00:00
info: Kerberos.NET.Client.KerberosClient[0]
Requesting TGS for HTTP/api-krb.tep-loris.orchid.tribbles.cloud; TGT Realm = TEP.LOCAL; TGT Service = krbtgt/TEP.LOCAL; S4U = (null); S4UTicket = Kerberos.NET.Entities.KrbPrincipalName
trce: Kerberos.NET.Transport.TcpKerberosTransport[0]
TCP connecting to dc.tep.local on port 88
dbug: Kerberos.NET.Transport.TcpKerberosTransport[0]
TCP connected to dc.tep.local on port 88
info: Kerberos.NET.Client.KerberosClient[0]
TGS-REP for HTTP/api-krb.tep-loris.orchid.tribbles.cloud
trce: Kerberos.NET.TicketCacheBase[0]
Caching ticket until 06/03/2021 01:35:33 +00:00 for kerberos--http/api-krb.tep-loris.orchid.tribbles.cloud with renewal option until 06/03/2021 15:35:33 +00:00
info: Kerberos.NET.Client.KerberosClient[0]
Requesting TGS for svc-top_lab; TGT Realm = TEP.LOCAL; TGT Service = krbtgt/TEP.LOCAL; S4U = user-demo2@tep.local; S4UTicket = (null)
trce: Kerberos.NET.Transport.TcpKerberosTransport[0]
TCP connecting to dc.tep.local on port 88
dbug: Kerberos.NET.Transport.TcpKerberosTransport[0]
TCP connected to dc.tep.local on port 88
info: Kerberos.NET.Client.KerberosClient[0]
TGS-REP for svc-top_lab
trce: Kerberos.NET.TicketCacheBase[0]
Caching ticket until 06/03/2021 01:35:33 +00:00 for kerberos-user-demo2@tep.local-svc-top_lab with renewal option until 06/03/2021 15:35:33 +00:00
trce: Kerberos.NET.KerberosValidator[0]
Validating Kerberos request NegTokenInit Oid: ;
trce: Kerberos.NET.KerberosValidator[0]
Kerberos request decrypted HTTP/api-krb.tep-loris.orchid.tribbles.cloud
trce: Kerberos.NET.TicketCacheBase[0]
Caching ticket until 06/03/2021 01:35:33 +00:00 for kerberos-b772fd429e857477071270c3569420eb44187782516464cc76e91e8e4e78bced-89a503cf9f0f22b3b318fe08ff8d62cc1553d1578321445299e3142ab2e841d8 with renewal option until (null)
trce: Kerberos.NET.KerberosValidator[0]
Validating Kerberos request NegTokenInit Oid: ;
Expected Identity: user-demo1@tep.local Identity Ticket: user-demo1@tep.local
trce: Kerberos.NET.KerberosValidator[0]
Kerberos request decrypted HTTP/api-krb.tep-loris.orchid.tribbles.cloud
trce: Kerberos.NET.TicketCacheBase[0]
Caching ticket until 06/03/2021 01:35:33 +00:00 for kerberos-b772fd429e857477071270c3569420eb44187782516464cc76e91e8e4e78bced-441550f47b514b4938e102c3148511fc41a096204929d6994086db4f981cc5c6 with renewal option until (null)
Expected Identity: user-demo2@tep.local Identity Ticket: user-demo1@tep.local
Wrong user in ticket.
Expected behavior
I expect that the user the ticket is requested for, is acutally in the ticket.
It works when CacheServiceTickets = false is set to false:
var s4UClient = new KerberosClient(config, loggerFactory)
{
CacheServiceTickets = false,
CacheInMemory = true,
RenewTickets = true,
};
Screenshots
The cache entries are looking good in my opinion:
Let me know if I can help to solve the issue.
Best regards,
Marcel
The text was updated successfully, but these errors were encountered:
Hi Steve
Many thanks for your great work with this library.
We use it to exchange Kerberos Tickets to JWT-Token (from ADFS) and also the vise versa JWT Token to Kerberos Tickets.
Describe the bug
We found a caching related bug.
If CacheServiceTickets on the KerberosClient is enabled, tickets for wrong users are returned.
To Reproduce
The sample below reproduces the bug.
Setup is a bit complicated, but the scenario is as follows:
A service requests a TGT Ticket on behalf of user for another target service.
On the target service itself, the ticket is decoded with the Authenticator and the according keytab.
This is the place where you can see that it is the wrong ticket.
Commands to create 2 demo users and a service user:
Code that reproduces the error:
Console output looks like this:
Expected behavior
I expect that the user the ticket is requested for, is acutally in the ticket.
It works when CacheServiceTickets = false is set to false:
var s4UClient = new KerberosClient(config, loggerFactory)
{
CacheServiceTickets = false,
CacheInMemory = true,
RenewTickets = true,
};
Screenshots
The cache entries are looking good in my opinion:
Let me know if I can help to solve the issue.
Best regards,
Marcel
The text was updated successfully, but these errors were encountered: