示例#1
0
    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;
    }
示例#2
0
        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
     };
 }
示例#4
0
        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
            });
        }
示例#5
0
        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
            });
        }
示例#6
0
 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);
            }
        }
示例#8
0
        public void DefaultSerializesAsEmpty()
        {
            var conf = Krb5Config.Default();

            var ds = conf.Serialize();

            Assert.IsTrue(string.IsNullOrWhiteSpace(ds));
        }
示例#9
0
        public void DefaultsAreHandled()
        {
            var emptyObj = new Krb5Config().Serialize();

            var obj = Krb5ConfigurationSerializer.Deserialize(emptyObj).ToConfigObject();

            Assert.AreEqual(5, obj.Defaults.DefaultTgsEncTypes.Count());
        }
示例#10
0
 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);
     }
 }
示例#11
0
        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);
        }
示例#12
0
        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);
        }
示例#13
0
        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);
        }
示例#14
0
 private static DateTimeOffset CalculateExpirationTime(Krb5Config config)
 {
     if (config.Defaults.TicketLifetime > TimeSpan.Zero)
     {
         return(DateTimeOffset.UtcNow.Add(config.Defaults.TicketLifetime));
     }
     else
     {
         return(EndOfTime);
     }
 }
示例#15
0
        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);
            }
        }
示例#17
0
        /// <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;
        }
示例#18
0
        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);
            }
        }
示例#19
0
        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)));
        }
示例#21
0
        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;
        }
示例#22
0
        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);
        }
示例#23
0
        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);
        }
示例#24
0
        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);
            }
        }
示例#27
0
        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);
            }
        }
示例#29
0
        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);
        }
示例#30
0
        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);
                }
            }
        }