protected TestCertificatesHolder GenerateAndSaveSelfSignedCertificate(bool createNew = false) { var selfSignedCertificatePaths = _selfSignedCertificates; if (selfSignedCertificatePaths != null && createNew == false) { return(ReturnCertificatesHolder(selfSignedCertificatePaths)); } lock (typeof(TestBase)) { selfSignedCertificatePaths = _selfSignedCertificates; if (selfSignedCertificatePaths == null || createNew) { _selfSignedCertificates = selfSignedCertificatePaths = Generate(); } return(ReturnCertificatesHolder(selfSignedCertificatePaths)); } TestCertificatesHolder ReturnCertificatesHolder(TestCertificatesHolder certificates) { return(new TestCertificatesHolder(certificates, GetTempFileName)); } TestCertificatesHolder Generate() { var log = new StringBuilder(); byte[] certBytes; try { certBytes = CertificateUtils.CreateSelfSignedTestCertificate(Environment.MachineName, "RavenTestsServer", log); } catch (Exception e) { throw new CryptographicException($"Unable to generate the test certificate for the machine '{Environment.MachineName}'. Log: {log}", e); } X509Certificate2 serverCertificate; try { serverCertificate = new X509Certificate2(certBytes, (string)null, X509KeyStorageFlags.MachineKeySet); } catch (Exception e) { throw new CryptographicException($"Unable to load the test certificate for the machine '{Environment.MachineName}'. Log: {log}", e); } if (certBytes.Length == 0) { throw new CryptographicException($"Test certificate length is 0 bytes. Machine: '{Environment.MachineName}', Log: {log}"); } string serverCertificatePath = null; try { serverCertificatePath = Path.GetTempFileName(); File.WriteAllBytes(serverCertificatePath, certBytes); } catch (Exception e) { throw new InvalidOperationException("Failed to write the test certificate to a temp file." + $"tempFileName = {serverCertificatePath}" + $"certBytes.Length = {certBytes.Length}" + $"MachineName = {Environment.MachineName}.", e); } GlobalPathsToDelete.Add(serverCertificatePath); SecretProtection.ValidatePrivateKey(serverCertificatePath, null, certBytes, out var pk); var clientCertificate1Path = GenerateClientCertificate(1, serverCertificate, pk); var clientCertificate2Path = GenerateClientCertificate(2, serverCertificate, pk); var clientCertificate3Path = GenerateClientCertificate(3, serverCertificate, pk); return(new TestCertificatesHolder(serverCertificatePath, clientCertificate1Path, clientCertificate2Path, clientCertificate3Path)); } string GenerateClientCertificate(int index, X509Certificate2 serverCertificate, Org.BouncyCastle.Pkcs.AsymmetricKeyEntry pk) { CertificateUtils.CreateSelfSignedClientCertificate( $"{Environment.MachineName}_CC_{index}", new RavenServer.CertificateHolder { Certificate = serverCertificate, PrivateKey = pk }, out var certBytes); string clientCertificatePath = null; try { clientCertificatePath = Path.GetTempFileName(); File.WriteAllBytes(clientCertificatePath, certBytes); } catch (Exception e) { throw new InvalidOperationException("Failed to write the test certificate to a temp file." + $"tempFileName = {clientCertificatePath}" + $"certBytes.Length = {certBytes.Length}" + $"MachineName = {Environment.MachineName}.", e); } GlobalPathsToDelete.Add(clientCertificatePath); return(clientCertificatePath); } }
public async Task CanReplaceClusterCert() { var clusterSize = 3; var databaseName = GetDatabaseName(); var leader = await CreateRaftClusterAndGetLeader(clusterSize, false, useSsl : true); X509Certificate2 adminCertificate = null; adminCertificate = AskServerForClientCertificate(_selfSignedCertFileName, new Dictionary <string, DatabaseAccess>(), SecurityClearance.ClusterAdmin, server: leader); DatabasePutResult databaseResult; using (var store = new DocumentStore { Urls = new[] { leader.WebUrl }, Database = databaseName, Certificate = adminCertificate, Conventions = { DisableTopologyUpdates = true } }.Initialize()) { var doc = new DatabaseRecord(databaseName); databaseResult = await store.Maintenance.Server.SendAsync(new CreateDatabaseOperation(doc, clusterSize)); } Assert.Equal(clusterSize, databaseResult.Topology.AllNodes.Count()); foreach (var server in Servers) { await server.ServerStore.Cluster.WaitForIndexNotification(databaseResult.RaftCommandIndex); } foreach (var server in Servers.Where(s => databaseResult.NodesAddedTo.Any(n => n == s.WebUrl))) { await server.ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(databaseName); } using (var store = new DocumentStore() { Urls = new[] { databaseResult.NodesAddedTo[0] }, Database = databaseName, Certificate = adminCertificate, Conventions = { DisableTopologyUpdates = true } }.Initialize()) { using (var session = store.OpenAsyncSession()) { await session.StoreAsync(new User { Name = "Karmelush" }, "users/1"); await session.SaveChangesAsync(); } var certBytes = CertificateUtils.CreateSelfSignedTestCertificate(Environment.MachineName, "RavenTestsServerReplacementCert"); var newServerCert = new X509Certificate2(certBytes, (string)null, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.MachineKeySet); var mre = new ManualResetEventSlim(); leader.ServerCertificateChanged += (sender, args) => mre.Set(); var requestExecutor = store.GetRequestExecutor(); using (requestExecutor.ContextPool.AllocateOperationContext(out JsonOperationContext context)) { var command = new ReplaceClusterCertificateOperation(certBytes, false) .GetCommand(store.Conventions, context); requestExecutor.Execute(command, context); } Assert.True(mre.Wait(5000)); Assert.True(leader.Certificate.Certificate.Thumbprint.Equals(newServerCert.Thumbprint)); using (var session = store.OpenSession()) { var user1 = session.Load <User>("users/1"); Assert.NotNull(user1); Assert.Equal("Karmelush", user1.Name); } } }