public KerberosExecutor(ITestOutputHelper testOutputHelper, string realm) { var krb5Config = Krb5Config.Default(); krb5Config.KdcDefaults.RegisterDefaultPkInitPreAuthHandler = false; var logger = new KerberosDelegateLogger( (level, categoryName, eventId, scopeState, logState, exception, log) => testOutputHelper.WriteLine($"[{level}] [{categoryName}] {log}") ); _principalService = new FakePrincipalService(realm); byte[] krbtgtPassword = new byte[16]; var krbtgt = new FakeKerberosPrincipal(PrincipalType.Service, "krbtgt", realm, krbtgtPassword); _principalService.Add("krbtgt", krbtgt); _principalService.Add($"krbtgt/{realm}", krbtgt); _options = new ListenerOptions { Configuration = krb5Config, DefaultRealm = realm, RealmLocator = realm => new FakeRealmService(realm, krb5Config, _principalService), Log = logger, IsDebug = true, }; _kdcListener = new FakeKdcServer(_options); _realm = realm; _servicePrincipals = new List <FakeKerberosPrincipal>(); _testOutputHelper = testOutputHelper; }
public async Task ValidatorMemoryCacheExpirationExpired() { var config = Krb5Config.Default(); config.Defaults.ClockSkew = TimeSpan.Zero; using (var logger = new FakeExceptionLoggerFactory()) using (var replay = new TicketReplayValidator(config, logger)) { var entry = new TicketCacheEntry { Key = "blargh", Expires = DateTimeOffset.UtcNow.AddMilliseconds(100) }; var added = await replay.Add(entry); Assert.IsTrue(added); await Task.Delay(TimeSpan.FromSeconds(1)); added = await replay.Add(entry); Assert.IsTrue(added); Assert.IsTrue(logger.Logs.Count() > 1); } }
public TicketReplayValidator(Krb5Config config, ILoggerFactory logger) { this.cache = new MemoryTicketCache(config, logger) { BlockUpdates = true }; }
protected virtual KerberosClient CreateClient(string configValue = null, bool verbose = false) { Krb5Config config; if (configValue != null) { config = Krb5Config.Parse(configValue); } else { config = Krb5Config.CurrentUser(this.ConfigurationPath); } ILoggerFactory logger = null; if (verbose) { logger = this.IO.CreateVerboseLogger(labels: true); } return(new KerberosClient(config, logger) { CacheInMemory = false }); }
protected virtual KerberosClient CreateClient(string configValue = null, bool verbose = false) { Krb5Config config; if (!string.IsNullOrWhiteSpace(configValue)) { config = Krb5Config.Parse(configValue); } else { config = Krb5Config.CurrentUser(); } ILoggerFactory logger = null; if (verbose) { logger = this.CreateVerboseLogger(); } return(new KerberosClient(config, logger) { CacheInMemory = false }); }
public FakeRealmService(string realm, Krb5Config config, IPrincipalService principalService, KerberosCompatibilityFlags compatibilityFlags = KerberosCompatibilityFlags.None) { Name = realm; Configuration = config; _principalService = principalService; _compatibilityFlags = compatibilityFlags; }
public async Task ConfigRemovesValue() { var tmpCacheFile = Path.GetTempFileName(); var config = Krb5Config.Parse(File.ReadAllText(tmpCacheFile)); Assert.IsFalse(config.Defaults.AllowWeakCrypto); try { string commandLine = $"kconfig --config \"{tmpCacheFile}\" realms.\"example.com\".kdc=foo.com"; config = await ExecuteCommand(commandLine, tmpCacheFile); Assert.AreEqual(1, config.Realms["example.com"].Kdc.Count); Assert.AreEqual("foo.com", config.Realms["example.com"].Kdc.First()); commandLine = $"kconfig --config \"{tmpCacheFile}\" +realms.\"example.com\".kdc="; config = await ExecuteCommand(commandLine, tmpCacheFile); Assert.AreEqual(0, config.Realms["example.com"].Kdc.Count); } finally { TryCleanupTmp(tmpCacheFile); } }
public void DefaultSerializesAsEmpty() { var conf = Krb5Config.Default(); var ds = conf.Serialize(); Assert.IsTrue(string.IsNullOrWhiteSpace(ds)); }
public void DefaultsAreHandled() { var emptyObj = new Krb5Config().Serialize(); var obj = Krb5ConfigurationSerializer.Deserialize(emptyObj).ToConfigObject(); Assert.AreEqual(5, obj.Defaults.DefaultTgsEncTypes.Count()); }
public KerberosAuthenticator(string upn, KeyTable keytab, Krb5Config config, ILoggerFactory logger = null) : this(new KerberosValidator(keytab, logger)) { if (!string.IsNullOrWhiteSpace(upn)) { this.s4uProvider = new S4UProviderFactory(upn, keytab, config, logger); } }
public TicketCacheBase(Krb5Config config, ILoggerFactory logger) { this.Configuration = config; this.Logger = logger.CreateLoggerSafe <TicketCacheBase>(); this.Cancellation = new CancellationTokenSource(); this.backgroundRunner = Task.Run(this.RunBackground, this.Cancellation.Token); }
public void RealmsDefaultsEmpty() { var config = new Krb5Config(); config.Realms["foo.com"].DefaultDomain = "foo.com"; var serialized = config.Serialize(); Assert.AreEqual("[realms]\r\nfoo.com = {\r\n default_domain = foo.com\r\n}\r\n\r\n", serialized); }
public static IRealmService LocateRealm(string realm, bool slow = false, Krb5Config config = null) { IRealmService service = new FakeRealmService(realm, config); if (slow) { Thread.Sleep(500); } return(service); }
private static DateTimeOffset CalculateExpirationTime(Krb5Config config) { if (config.Defaults.TicketLifetime > TimeSpan.Zero) { return(DateTimeOffset.UtcNow.Add(config.Defaults.TicketLifetime)); } else { return(EndOfTime); } }
public static KrbAsReq CreateAsReq(KerberosCredential credential, AuthenticationOptions options) { if (credential == null) { throw new ArgumentNullException(nameof(credential)); } var config = credential.Configuration ?? Krb5Config.Default(); var kdcOptions = (KdcOptions)(options & ~AuthenticationOptions.AllAuthentication); var pacRequest = new KrbPaPacRequest { IncludePac = options.HasFlag(AuthenticationOptions.IncludePacRequest) }; var padata = new List <KrbPaData>() { new KrbPaData { Type = PaDataType.PA_PAC_REQUEST, Value = pacRequest.Encode() } }; var asreq = new KrbAsReq() { Body = new KrbKdcReqBody { Addresses = IncludeAddresses(config), CName = ExtractCName(credential), EType = GetPreferredETypes(config.Defaults.DefaultTicketEncTypes, config.Defaults.AllowWeakCrypto).ToArray(), KdcOptions = kdcOptions, Nonce = GetNonce(), RTime = CalculateRenewTime(kdcOptions, config), Realm = credential.Domain, SName = new KrbPrincipalName { Type = PrincipalNameType.NT_SRV_INST, Name = new[] { "krbtgt", credential.Domain } }, Till = CalculateExpirationTime(config) }, PaData = padata.ToArray() }; if (options.HasFlag(AuthenticationOptions.PreAuthenticate)) { credential.TransformKdcReq(asreq); } return(asreq); }
public async Task ConfigSetsValue() { using (var tmpConfigFile = new TemporaryFile()) { var config = Krb5Config.Parse(File.ReadAllText(tmpConfigFile.File)); Assert.IsFalse(config.Defaults.AllowWeakCrypto); string commandLine = $"kconfig --config \"{tmpConfigFile.File}\" libdefaults.allow_weak_crypto=true"; config = await ExecuteCommand(commandLine, tmpConfigFile.File); Assert.IsTrue(config.Defaults.AllowWeakCrypto); } }
/// <summary> /// Create a KerberosClient instance. /// </summary> /// <param name="config">The custom configuration this client should use when making Kerberos requests.</param> /// <param name="logger">A logger instance for recording client logs</param> /// <param name="transports">A collection of network transports that the client /// will attempt to use to communicate with the KDC</param> public KerberosClient(Krb5Config config = null, ILoggerFactory logger = null, params IKerberosTransport[] transports) { this.Configuration = config ?? Krb5ConfigurationSerializer.Deserialize(string.Empty).ToConfigObject(); this.loggerFactory = logger; this.logger = logger.CreateLoggerSafe <KerberosClient>(); this.clientLoggingScope = this.logger.BeginScope("KerberosClient"); this.transport = new KerberosTransportSelector(transports, this.Configuration, logger) { ScopeId = this.ScopeId }; this.MaximumRetries = 10; }
private static DateTimeOffset?CalculateRenewTime(KdcOptions kdcOptions, Krb5Config config) { if (!kdcOptions.HasFlag(KdcOptions.Renewable)) { return(null); } if (config.Defaults.RenewLifetime > TimeSpan.Zero) { return(DateTimeOffset.UtcNow.Add(config.Defaults.RenewLifetime)); } else { return(EndOfTime); } }
private async Task <KerberosIdentity> ProcessAsMiddleBox(Krb5Config config, ILoggerFactory logger, ApplicationSessionContext serviceTicket) { var serviceCred = new KerberosPasswordCredential(this.ServicePrincipalSamAccountName, this.ServicePrincipalNamePassword, serviceTicket.ApReq.Ticket.Realm); var ping = await KerberosPing.Ping(serviceCred, config, logger); serviceCred.IncludePreAuthenticationHints(ping.Error.DecodePreAuthentication()); var keytab = new KeyTable(serviceCred.CreateKey()); var authenticator = new KerberosAuthenticator(this.ServicePrincipalSamAccountName, keytab, config, logger); var identity = await authenticator.Authenticate(serviceTicket.ApReq.EncodeGssApi()) as KerberosIdentity; return(identity); }
private static async Task <Krb5Config> ExecuteCommand(string commandLine, string tmpCacheFile) { var io = new InputControl { Clear = () => { }, HookCtrlC = hook => { }, Writer = new StringWriter() }; var parameters = CommandLineParameters.Parse(commandLine); var command = (KerberosConfigCommand)parameters.CreateCommandExecutor(io); await command.Execute(); return(Krb5Config.Parse(File.ReadAllText(tmpCacheFile))); }
public KerberosTransportSelector(IEnumerable <IKerberosTransport> transports, Krb5Config config, ILoggerFactory logger) : base(logger) { if (transports == null) { throw new ArgumentNullException(nameof(transports)); } if (config == null) { throw new ArgumentNullException(nameof(config)); } this.logger = logger.CreateLoggerSafe <KerberosTransportSelector>(); this.Transports = transports; this.config = config; }
private static async Task ClientResolverProcessesEndpoint(string server) { var client = new ClientDomainService(null) { Configuration = Krb5Config.Default() }; client.Configuration.Realms["TEST.COM"].Kdc.Add(server); client.Configuration.Defaults.DefaultRealm = "TEST.COM"; client.Configuration.DomainRealm.Add("TEST.COM", "TEST.COM"); client.Configuration.Defaults.DnsLookupKdc = false; var result = await client.LocateKdc("TEST.COM", "_kerberos._http"); Assert.AreEqual(1, result.Count()); Assert.AreEqual(server, result.First().Address); }
private static KrbAsRep RequestTgt(out KrbEncryptionKey sessionKey) { var cred = new KerberosPasswordCredential(Upn, "P@ssw0rd!") { // cheating by skipping the initial leg of requesting PA-type Salts = new[] { new KeyValuePair <EncryptionType, string>( EncryptionType.AES256_CTS_HMAC_SHA1_96, "*****@*****.**" ) }, Configuration = Krb5Config.Default() }; var asReq = KrbAsReq.CreateAsReq( cred, AuthenticationOptions.AllAuthentication ); var handler = new KdcAsReqMessageHandler(asReq.EncodeApplication(), new KdcServerOptions { DefaultRealm = Realm, IsDebug = true, RealmLocator = realm => new FakeRealmService(realm) }); handler.PreAuthHandlers[PaDataType.PA_ENC_TIMESTAMP] = service => new PaDataTimestampHandler(service); var results = handler.Execute(); var decoded = KrbAsRep.DecodeApplication(results); var decrypted = cred.DecryptKdcRep( decoded, KeyUsage.EncAsRepPart, d => KrbEncAsRepPart.DecodeApplication(d) ); sessionKey = decrypted.Key; return(decoded); }
private static KrbHostAddress[] IncludeAddresses(Krb5Config config) { if (config.Defaults.NoAddresses) { return(null); } var addresses = new List <KrbHostAddress> { KrbHostAddress.ParseAddress(Environment.MachineName.PadRight(16, ' ')) }; if (config.Defaults?.ExtraAddresses?.Any() ?? false) { addresses.AddRange(config.Defaults.ExtraAddresses.Select(a => KrbHostAddress.ParseAddress(a))); } return(addresses.ToArray()); }
public async Task KinitExecutes() { var port = NextPort(); using (var tmpCacheFile = new TemporaryFile()) using (var tmpConfigFile = new TemporaryFile()) { var config = Krb5Config.Default(); File.WriteAllText(tmpConfigFile.File, config.Serialize()); using (var listener = StartTcpListener(port)) { _ = listener.Start(); var reader = new CommandLineAutoReader(); var io = new InputControl { Clear = () => { }, HookCtrlC = hook => { }, ResetColor = () => { }, SetColor = c => { }, Reader = reader, Writer = new StringWriter(), ReadKey = () => ReadKey(reader) }; var command = CreateCommand($"127.0.0.1:{port}", AdminAtCorpUserName, tmpCacheFile.File, tmpConfigFile.File, io); reader.QueueNext(FakeAdminAtCorpPassword + "\n"); await command.Execute(); var output = io.Writer.ToString(); Assert.IsTrue(output.Contains("Ticket Count: 1")); Assert.IsTrue(output.Contains("client : administrator", StringComparison.OrdinalIgnoreCase), output); } } }
public async Task ConfigSetsValue() { var tmpCacheFile = Path.GetTempFileName(); var config = Krb5Config.Parse(File.ReadAllText(tmpCacheFile)); Assert.IsFalse(config.Defaults.AllowWeakCrypto); try { string commandLine = $"kconfig --config \"{tmpCacheFile}\" libdefaults.allow_weak_crypto=true"; config = await ExecuteCommand(commandLine, tmpCacheFile); Assert.IsTrue(config.Defaults.AllowWeakCrypto); } finally { TryCleanupTmp(tmpCacheFile); } }
public void Version3DefaultsCorrectly() { using (var tmp = new TemporaryFile()) { var config = Krb5Config.Default(); config.Defaults.CCacheType = 3; config.Defaults.DefaultCCacheName = tmp.File; using (var client = new KerberosClient(config) { CacheInMemory = false }) { var cache = client.Cache as Krb5TicketCache; Assert.IsNotNull(cache); Assert.AreEqual(3, cache.Version); } } }
public async Task ConfigRemovesValue() { using (var tmpConfigFile = new TemporaryFile()) { var config = Krb5Config.Parse(File.ReadAllText(tmpConfigFile.File)); Assert.IsFalse(config.Defaults.AllowWeakCrypto); string commandLine = $"kconfig --config \"{tmpConfigFile.File}\" realms.\"example.com\".kdc=foo.com"; config = await ExecuteCommand(commandLine, tmpConfigFile.File); Assert.AreEqual(1, config.Realms["example.com"].Kdc.Count); Assert.AreEqual("foo.com", config.Realms["example.com"].Kdc.First()); commandLine = $"kconfig --config \"{tmpConfigFile.File}\" +realms.\"example.com\".kdc="; config = await ExecuteCommand(commandLine, tmpConfigFile.File); Assert.AreEqual(0, config.Realms["example.com"].Kdc.Count); } }
public static async Task <PingResult> Ping(KerberosCredential credential, Krb5Config config, ILoggerFactory logger = null) { credential.Configuration = config; var asReqMessage = KrbAsReq.CreateAsReq(credential, AuthenticationOptions.Renewable); var asReq = asReqMessage.EncodeApplication(); var transport = new KerberosTransportSelector( new IKerberosTransport[] { new TcpKerberosTransport(logger), new UdpKerberosTransport(logger), new HttpsKerberosTransport(logger) }, config, logger ) { ConnectTimeout = TimeSpan.FromSeconds(5) }; var result = new PingResult { AsReq = asReqMessage }; try { result.AsRep = await transport.SendMessage <KrbAsRep>(credential.Domain, asReq); } catch (KerberosProtocolException pex) { result.Error = pex.Error; } return(result); }
public async Task LsaLogonUserImportUseCache() { var cred = CreateKrbCredential(); var config = Krb5Config.Default(); using (var interop = LsaInterop.Connect()) { Assert.IsNotNull(interop); interop.LogonUser(); interop.ImportCredential(cred); using (var client = new KerberosClient(config) { Cache = new LsaCredentialCache(config, interop) }) { var ticket = await client.GetServiceTicket(RequestedSpn); Assert.IsNotNull(ticket); } } }