public async Task <MxRecordTlsSecurityProfile> Test(MxRecordTlsSecurityProfile mxRecordTlsSecurityProfile) { if (_config.CachingEnabled) { string cachedStringResult = await _cache.GetString($"{KeyPrefix}-{mxRecordTlsSecurityProfile.MxRecord.Hostname?.ToLower()}"); if (cachedStringResult != null) { _log.Debug($"Successfully retrieved TLSSecurityProfile from cache for host {mxRecordTlsSecurityProfile.MxRecord.Hostname}"); TlsTestResults cachedResults = JsonConvert.DeserializeObject <TlsTestResults>(cachedStringResult); return(new MxRecordTlsSecurityProfile(mxRecordTlsSecurityProfile.MxRecord, new TlsSecurityProfile(mxRecordTlsSecurityProfile.TlsSecurityProfile.Id, null, cachedResults))); } } MxRecordTlsSecurityProfile result = await _tlsSecurityTesterAdaptor.Test(mxRecordTlsSecurityProfile); _log.Debug($"Successfully retrieved TLSSecurityProfile from tls tester for host {mxRecordTlsSecurityProfile.MxRecord.Hostname}"); if (_config.CachingEnabled && (result.TlsSecurityProfile.TlsResults.FailureCount == 0 || result.TlsSecurityProfile.TlsResults.FailureCount >= FailureCountBeforeCaching)) { string resultToCache = JsonConvert.SerializeObject(result.TlsSecurityProfile.TlsResults); await _cache.SetString($"{KeyPrefix}-{mxRecordTlsSecurityProfile.MxRecord.Hostname}", resultToCache, TimeSpan.FromSeconds(_config.RefreshIntervalSeconds *RefreshIntervalSecondsMultiplier)); _log.Debug($"Successfully set TLSSecurityProfile to cache for host {mxRecordTlsSecurityProfile.MxRecord.Hostname}"); } return(result); }
public async Task DifferenceInRecordsOldAndNewRecordsReturnedIsReturned() { MxRecordTlsSecurityProfile mxRecordTlsSecurityProfile1 = CreateTlsSecurityProfile(); MxRecordTlsSecurityProfile mxRecordTlsSecurityProfile2 = CreateTlsSecurityProfile(2, CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA); A.CallTo(() => _tlsSecurityTester.Test(mxRecordTlsSecurityProfile1)) .Returns(Task.FromResult(mxRecordTlsSecurityProfile2)); List <DomainTlsSecurityProfile> securityProfiles = await _tlsSecurityProfileUpdater.UpdateSecurityProfiles( new List <DomainTlsSecurityProfile> { new DomainTlsSecurityProfile(new Domain(1, "domain"), new List <MxRecordTlsSecurityProfile> { mxRecordTlsSecurityProfile1 }) }); Assert.That(securityProfiles[0].Profiles.Count, Is.EqualTo(2)); Assert.That(securityProfiles[0].Profiles[0].TlsSecurityProfile.Id, Is.EqualTo(mxRecordTlsSecurityProfile1.TlsSecurityProfile.Id)); Assert.That(securityProfiles[0].Profiles[0].TlsSecurityProfile.EndDate, Is.Not.Null); Assert.That(securityProfiles[0].Profiles[1].TlsSecurityProfile.Id, Is.Null); Assert.That(securityProfiles[0].Profiles[1].TlsSecurityProfile.EndDate, Is.Null); }
private MxRecordTlsSecurityProfile CreateNewRecord(MxRecordTlsSecurityProfile mxRecordTlsSecurityProfile) { return(new MxRecordTlsSecurityProfile( mxRecordTlsSecurityProfile.MxRecord, new TlsSecurityProfile( null, null, mxRecordTlsSecurityProfile.TlsSecurityProfile.TlsResults.Clone()))); }
private MxRecordTlsSecurityProfile CreateExpiredRecord(MxRecordTlsSecurityProfile oldMxRecordTlsSecurityProfile) { return(new MxRecordTlsSecurityProfile( oldMxRecordTlsSecurityProfile.MxRecord, new TlsSecurityProfile( oldMxRecordTlsSecurityProfile.TlsSecurityProfile.Id, DateTime.UtcNow, oldMxRecordTlsSecurityProfile.TlsSecurityProfile.TlsResults.Clone()))); }
public async Task <List <DomainTlsSecurityProfile> > GetSecurityProfilesForUpdate() { Stopwatch stopwatch = Stopwatch.StartNew(); Dictionary <Domain, Dictionary <MxRecord, MxRecordTlsSecurityProfile> > values = new Dictionary <Domain, Dictionary <MxRecord, MxRecordTlsSecurityProfile> >(); string connectionString = await _connectionInfo.GetConnectionStringAsync(); using (MySqlConnection connection = new MySqlConnection(connectionString)) { await connection.OpenAsync().ConfigureAwait(false); MySqlCommand command = new MySqlCommand(TlsSecurityProfileDaoResources.SelectSecurityProfilesToUpdate, connection); command.Parameters.AddWithValue("refreshIntervalSeconds", _mxSecurityTesterConfig.RefreshIntervalSeconds); command.Parameters.AddWithValue("failureRefreshIntervalSeconds", _mxSecurityTesterConfig.FailureRefreshIntervalSeconds); command.Parameters.AddWithValue("limit", _mxSecurityTesterConfig.DomainLimit); using (DbDataReader reader = await command.ExecuteReaderAsync()) { while (await reader.ReadAsync()) { Domain domain = CreateDomain(reader); Dictionary <MxRecord, MxRecordTlsSecurityProfile> domainValue; if (!values.TryGetValue(domain, out domainValue)) { domainValue = new Dictionary <MxRecord, MxRecordTlsSecurityProfile>(); values.Add(domain, domainValue); } MxRecord record = CreateMxRecord(reader); MxRecordTlsSecurityProfile profile; if (!domainValue.TryGetValue(record, out profile)) { profile = new MxRecordTlsSecurityProfile(record, CreateTlsSecurityProfile(reader)); domainValue.Add(record, profile); } X509Certificate2 certificate = CreateCertificate(reader); if (certificate != null) { profile.TlsSecurityProfile.TlsResults.Certificates.Add(certificate); } } } connection.Close(); } stopwatch.Stop(); _log.Debug($"Retrieving domains to refresh security profiles for took {stopwatch.Elapsed}"); return(values.Select(_ => new DomainTlsSecurityProfile(_.Key, _.Value.Values.ToList())).ToList()); }
public async Task CachingNotEnabledCacheNotUsed() { A.CallTo(() => _config.CachingEnabled).Returns(false); MxRecordTlsSecurityProfile securityProfile = CreateSecurityProfile(); MxRecordTlsSecurityProfile updatedSecurityProfile = await _cachingTlsSecurityTesterAdaptor.Test(securityProfile); A.CallTo(() => _cache.GetString(A <string> ._)).MustNotHaveHappened(); A.CallTo(() => _tlsSecurityTesterAdaptor.Test(securityProfile)).MustHaveHappened(Repeated.Exactly.Once); A.CallTo(() => _cache.SetString(A <string> ._, A <string> ._, A <TimeSpan> ._)).MustNotHaveHappened(); }
public async Task ErroredResultsNotCachedBeforeThirdFailedRetry() { MxRecordTlsSecurityProfile securityProfile = CreateSecurityProfile(1); A.CallTo(() => _config.CachingEnabled).Returns(true); A.CallTo(() => _cache.GetString(A <string> ._)).Returns(Task.FromResult((string)null)); A.CallTo(() => _tlsSecurityTesterAdaptor.Test(securityProfile)).Returns(Task.FromResult(securityProfile)); MxRecordTlsSecurityProfile updatedSecurityProfile = await _cachingTlsSecurityTesterAdaptor.Test(securityProfile); A.CallTo(() => _cache.GetString(A <string> ._)).MustHaveHappened(Repeated.Exactly.Once); A.CallTo(() => _tlsSecurityTesterAdaptor.Test(securityProfile)).MustHaveHappened(Repeated.Exactly.Once); A.CallTo(() => _cache.SetString(A <string> ._, A <string> ._, A <TimeSpan> ._)).MustNotHaveHappened(); }
public async Task <MxRecordTlsSecurityProfile> Test(MxRecordTlsSecurityProfile mxRecordTlsSecurityProfile) { List <Console.TlsTestResult> results = new List <Console.TlsTestResult>(); List <X509Certificate2> certificates = null; if (!string.IsNullOrWhiteSpace(mxRecordTlsSecurityProfile.MxRecord.Hostname)) { results = await _tlsSecurityTester.Test(mxRecordTlsSecurityProfile.MxRecord.Hostname); certificates = results.FirstOrDefault(_ => _.Result.Certificates.Any())? .Result.Certificates.ToList() ?? new List <X509Certificate2>(); } return(new MxRecordTlsSecurityProfile(mxRecordTlsSecurityProfile.MxRecord, new TlsSecurityProfile( mxRecordTlsSecurityProfile.TlsSecurityProfile.Id, null, new TlsTestResults( IsErrored(results) ? mxRecordTlsSecurityProfile.TlsSecurityProfile.TlsResults.FailureCount + 1 : 0, new TlsTestResultsWithoutCertificate( ToTestResult(results.FirstOrDefault(_ => _.Test.Id == (int)TlsTestType.Tls12AvailableWithBestCipherSuiteSelected)), ToTestResult(results.FirstOrDefault(_ => _.Test.Id == (int)TlsTestType.Tls12AvailableWithBestCipherSuiteSelectedFromReverseList)), ToTestResult(results.FirstOrDefault(_ => _.Test.Id == (int)TlsTestType.Tls12AvailableWithSha2HashFunctionSelected)), ToTestResult(results.FirstOrDefault(_ => _.Test.Id == (int)TlsTestType.Tls12AvailableWithWeakCipherSuiteNotSelected)), ToTestResult(results.FirstOrDefault(_ => _.Test.Id == (int)TlsTestType.Tls11AvailableWithBestCipherSuiteSelected)), ToTestResult(results.FirstOrDefault(_ => _.Test.Id == (int)TlsTestType.Tls11AvailableWithWeakCipherSuiteNotSelected)), ToTestResult(results.FirstOrDefault(_ => _.Test.Id == (int)TlsTestType.Tls10AvailableWithBestCipherSuiteSelected)), ToTestResult(results.FirstOrDefault(_ => _.Test.Id == (int)TlsTestType.Tls10AvailableWithWeakCipherSuiteNotSelected)), ToTestResult(results.FirstOrDefault(_ => _.Test.Id == (int)TlsTestType.Ssl3FailsWithBadCipherSuite)), ToTestResult(results.FirstOrDefault(_ => _.Test.Id == (int)TlsTestType.TlsSecureEllipticCurveSelected)), ToTestResult(results.FirstOrDefault(_ => _.Test.Id == (int)TlsTestType.TlsSecureDiffieHellmanGroupSelected)), ToTestResult(results.FirstOrDefault(_ => _.Test.Id == (int)TlsTestType.TlsWeakCipherSuitesRejected))), certificates)))); }
public async Task CachingEnabledValueNotInCacheValueReturnedFromTlsTesterAndCached() { MxRecordTlsSecurityProfile securityProfile = CreateSecurityProfile(); A.CallTo(() => _config.CachingEnabled).Returns(true); A.CallTo(() => _cache.GetString(A <string> ._)).Returns(Task.FromResult((string)null)); A.CallTo(() => _tlsSecurityTesterAdaptor.Test(securityProfile)).Returns(Task.FromResult(securityProfile)); MxRecordTlsSecurityProfile updatedSecurityProfile = await _cachingTlsSecurityTesterAdaptor.Test(securityProfile); A.CallTo(() => _cache.GetString(A <string> ._)).MustHaveHappened(Repeated.Exactly.Once); A.CallTo(() => _tlsSecurityTesterAdaptor.Test(securityProfile)).MustHaveHappened(Repeated.Exactly.Once); A.CallTo(() => _cache.SetString(A <string> ._, A <string> ._, A <TimeSpan> ._)) .MustHaveHappened(Repeated.Exactly.Once); }
public async Task CachingEnabledAndValueInCacheValueFromCacheReturned() { MxRecordTlsSecurityProfile securityProfile = CreateSecurityProfile(); string serializedSecurityProfile = JsonConvert.SerializeObject(securityProfile.TlsSecurityProfile.TlsResults); A.CallTo(() => _config.CachingEnabled).Returns(true); A.CallTo(() => _cache.GetString(A <string> ._)).Returns(Task.FromResult(serializedSecurityProfile)); MxRecordTlsSecurityProfile updatedSecurityProfile = await _cachingTlsSecurityTesterAdaptor.Test(securityProfile); Assert.That(updatedSecurityProfile.TlsSecurityProfile, Is.EqualTo(securityProfile.TlsSecurityProfile)); A.CallTo(() => _cache.GetString(A <string> ._)).MustHaveHappened(Repeated.Exactly.Once); A.CallTo(() => _tlsSecurityTesterAdaptor.Test(securityProfile)).MustNotHaveHappened(); A.CallTo(() => _cache.SetString(A <string> ._, A <string> ._, A <TimeSpan> ._)).MustNotHaveHappened(); }
private async Task <List <MxRecordTlsSecurityProfile> > UpdateMxSecurityProfile(MxRecordTlsSecurityProfile mxRecordTlsSecurityProfile) { MxRecordTlsSecurityProfile updatedSecurityProfile = await _tlsSecurityTester.Test(mxRecordTlsSecurityProfile); bool recordUnchanged = mxRecordTlsSecurityProfile.TlsSecurityProfile.TlsResults.Equals(updatedSecurityProfile.TlsSecurityProfile.TlsResults); bool newRecord = !mxRecordTlsSecurityProfile.TlsSecurityProfile.Id.HasValue; _log.Debug($"Updated tls profile (mx record id:{mxRecordTlsSecurityProfile.MxRecord.Id}, " + $"tls profile id:{mxRecordTlsSecurityProfile.TlsSecurityProfile.Id?.ToString() ?? "null"}) " + $"record changed: {!recordUnchanged}, new record: {newRecord}"); return(recordUnchanged || newRecord ? new List <MxRecordTlsSecurityProfile> { updatedSecurityProfile } : new List <MxRecordTlsSecurityProfile> { CreateExpiredRecord(mxRecordTlsSecurityProfile), CreateNewRecord(updatedSecurityProfile) }); }
public async Task NoDifferenceInRecordsRecordIsReturned() { MxRecordTlsSecurityProfile mxRecordTlsSecurityProfile1 = CreateTlsSecurityProfile(); A.CallTo(() => _tlsSecurityTester.Test(mxRecordTlsSecurityProfile1)) .Returns(Task.FromResult(mxRecordTlsSecurityProfile1)); List <DomainTlsSecurityProfile> securityProfiles = await _tlsSecurityProfileUpdater.UpdateSecurityProfiles( new List <DomainTlsSecurityProfile> { new DomainTlsSecurityProfile(new Domain(1, "domain"), new List <MxRecordTlsSecurityProfile> { mxRecordTlsSecurityProfile1 }) }); Assert.That(securityProfiles[0].Profiles.Count, Is.EqualTo(1)); Assert.That(securityProfiles[0].Profiles.First(), Is.EqualTo(mxRecordTlsSecurityProfile1)); }
private async Task InsertOrUpdateSecurityProfiles(List <MxRecordTlsSecurityProfile> profiles, MySqlTransaction transaction) { if (profiles.Any()) { StringBuilder stringBuilder = new StringBuilder(TlsSecurityProfileDaoResources.InsertRecord); MySqlCommand command = new MySqlCommand((MySqlConnection)transaction.Connection, transaction); for (int i = 0; i < profiles.Count; i++) { stringBuilder.AppendFormat(TlsSecurityProfileDaoResources.InsertRecordValueFormatString, i); stringBuilder.Append(i < profiles.Count - 1 ? "," : " "); MxRecordTlsSecurityProfile profile = profiles[i]; command.Parameters.AddWithValue($"a{i}", profile.TlsSecurityProfile.Id); command.Parameters.AddWithValue($"b{i}", profile.MxRecord.Id); command.Parameters.AddWithValue($"c{i}", profile.TlsSecurityProfile.EndDate); command.Parameters.AddWithValue($"d{i}", profile.TlsSecurityProfile.TlsResults.FailureCount); command.Parameters.AddWithValue($"e{i}", JsonConvert.SerializeObject(profile.TlsSecurityProfile.TlsResults.Results, _serializerSettings)); } stringBuilder.Append(TlsSecurityProfileDaoResources.InsertRecordOnDuplicateKey); command.CommandText = stringBuilder.ToString(); ulong id = (ulong)await command.ExecuteScalarAsync(); foreach (MxRecordTlsSecurityProfile profile in profiles) { if (!profile.TlsSecurityProfile.Id.HasValue) { profile.TlsSecurityProfile.Id = id++; } } } }
protected bool Equals(MxRecordTlsSecurityProfile other) { return(Equals(MxRecord, other.MxRecord) && Equals(TlsSecurityProfile, other.TlsSecurityProfile)); }
public async Task EmptyRecordsAreNotReturned() { MxRecordTlsSecurityProfile mxRecordTlsSecurityProfile1 = CreateTlsSecurityProfile(null); MxRecordTlsSecurityProfile mxRecordTlsSecurityProfile2 = CreateTlsSecurityProfile(null, CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA); A.CallTo(() => _tlsSecurityTester.Test(mxRecordTlsSecurityProfile1)) .Returns(Task.FromResult(mxRecordTlsSecurityProfile2)); List <DomainTlsSecurityProfile> securityProfiles = await _tlsSecurityProfileUpdater.UpdateSecurityProfiles( new List <DomainTlsSecurityProfile> { new DomainTlsSecurityProfile(new Domain(1, "domain"), new List <MxRecordTlsSecurityProfile> { mxRecordTlsSecurityProfile1 }) }); Assert.That(securityProfiles[0].Profiles.Count, Is.EqualTo(1)); Assert.That(securityProfiles[0].Profiles[0].TlsSecurityProfile.Id, Is.Null); Assert.That(securityProfiles[0].Profiles[0].MxRecord, Is.EqualTo(mxRecordTlsSecurityProfile1.MxRecord)); Assert.That(securityProfiles[0].Profiles[0].TlsSecurityProfile.EndDate, Is.Null); Assert.That(securityProfiles[0].Profiles[0].TlsSecurityProfile.TlsResults.FailureCount, Is.EqualTo(mxRecordTlsSecurityProfile2.TlsSecurityProfile.TlsResults.FailureCount)); Assert.That( securityProfiles[0].Profiles[0].TlsSecurityProfile.TlsResults.Results .Tls12AvailableWithBestCipherSuiteSelected, Is.EqualTo(mxRecordTlsSecurityProfile2.TlsSecurityProfile.TlsResults.Results .Tls12AvailableWithBestCipherSuiteSelected)); Assert.That( securityProfiles[0].Profiles[0].TlsSecurityProfile.TlsResults.Results .Tls12AvailableWithBestCipherSuiteSelectedFromReverseList, Is.EqualTo(mxRecordTlsSecurityProfile2.TlsSecurityProfile.TlsResults.Results .Tls12AvailableWithBestCipherSuiteSelectedFromReverseList)); Assert.That( securityProfiles[0].Profiles[0].TlsSecurityProfile.TlsResults.Results .Tls12AvailableWithSha2HashFunctionSelected, Is.EqualTo(mxRecordTlsSecurityProfile2.TlsSecurityProfile.TlsResults.Results .Tls12AvailableWithSha2HashFunctionSelected)); Assert.That( securityProfiles[0].Profiles[0].TlsSecurityProfile.TlsResults.Results .Tls12AvailableWithWeakCipherSuiteNotSelected, Is.EqualTo(mxRecordTlsSecurityProfile2.TlsSecurityProfile.TlsResults.Results .Tls12AvailableWithWeakCipherSuiteNotSelected)); Assert.That( securityProfiles[0].Profiles[0].TlsSecurityProfile.TlsResults.Results .Tls11AvailableWithBestCipherSuiteSelected, Is.EqualTo(mxRecordTlsSecurityProfile2.TlsSecurityProfile.TlsResults.Results .Tls11AvailableWithBestCipherSuiteSelected)); Assert.That( securityProfiles[0].Profiles[0].TlsSecurityProfile.TlsResults.Results .Tls11AvailableWithWeakCipherSuiteNotSelected, Is.EqualTo(mxRecordTlsSecurityProfile2.TlsSecurityProfile.TlsResults.Results .Tls11AvailableWithWeakCipherSuiteNotSelected)); Assert.That( securityProfiles[0].Profiles[0].TlsSecurityProfile.TlsResults.Results .Tls10AvailableWithBestCipherSuiteSelected, Is.EqualTo(mxRecordTlsSecurityProfile2.TlsSecurityProfile.TlsResults.Results .Tls10AvailableWithBestCipherSuiteSelected)); Assert.That( securityProfiles[0].Profiles[0].TlsSecurityProfile.TlsResults.Results .Tls10AvailableWithWeakCipherSuiteNotSelected, Is.EqualTo(mxRecordTlsSecurityProfile2.TlsSecurityProfile.TlsResults.Results .Tls10AvailableWithWeakCipherSuiteNotSelected)); Assert.That( securityProfiles[0].Profiles[0].TlsSecurityProfile.TlsResults.Results.Ssl3FailsWithBadCipherSuite, Is.EqualTo( mxRecordTlsSecurityProfile2.TlsSecurityProfile.TlsResults.Results.Ssl3FailsWithBadCipherSuite)); Assert.That( securityProfiles[0].Profiles[0].TlsSecurityProfile.TlsResults.Results.TlsSecureEllipticCurveSelected, Is.EqualTo(mxRecordTlsSecurityProfile2.TlsSecurityProfile.TlsResults.Results .TlsSecureEllipticCurveSelected)); Assert.That( securityProfiles[0].Profiles[0].TlsSecurityProfile.TlsResults.Results .TlsSecureDiffieHellmanGroupSelected, Is.EqualTo(mxRecordTlsSecurityProfile2.TlsSecurityProfile.TlsResults.Results .TlsSecureDiffieHellmanGroupSelected)); Assert.That( securityProfiles[0].Profiles[0].TlsSecurityProfile.TlsResults.Results.TlsWeakCipherSuitesRejected, Is.EqualTo( mxRecordTlsSecurityProfile2.TlsSecurityProfile.TlsResults.Results.TlsWeakCipherSuitesRejected)); }