private static void ValidatePermissions(CertificateDefinition certificate, ServerStore serverStore) { if (certificate.Permissions == null) { throw new ArgumentException($"{nameof(certificate.Permissions)} is a required field in the certificate definition"); } foreach (var kvp in certificate.Permissions) { if (string.IsNullOrWhiteSpace(kvp.Key)) { throw new ArgumentException("Error in permissions in the certificate definition, database name is empty"); } if (ResourceNameValidator.IsValidResourceName(kvp.Key, serverStore.Configuration.Core.DataDirectory.FullPath, out var errorMessage) == false) { throw new ArgumentException("Error in permissions in the certificate definition:" + errorMessage); } if (kvp.Value != DatabaseAccess.ReadWrite && kvp.Value != DatabaseAccess.Admin) { throw new ArgumentException($"Error in permissions in the certificate definition, invalid access {kvp.Value} for database {kvp.Key}"); } } }
public async Task DefineHub() { if (ResourceNameValidator.IsValidResourceName(Database.Name, ServerStore.Configuration.Core.DataDirectory.FullPath, out string errorMessage) == false) { throw new BadRequestException(errorMessage); } ServerStore.LicenseManager.AssertCanAddPullReplicationAsHub(); PullReplicationDefinition pullReplication = null; await DatabaseConfigurations((_, databaseName, blittableJson, guid) => { pullReplication = JsonDeserializationClient.PullReplicationDefinition(blittableJson); pullReplication.Validate(ServerStore.Server.Certificate?.Certificate != null); var updatePullReplication = new UpdatePullReplicationAsHubCommand(databaseName, guid) { Definition = pullReplication }; return(ServerStore.SendToLeaderAsync(updatePullReplication)); }, "update-hub-pull-replication", GetRaftRequestIdFromQuery(), fillJson : (json, _, index) => { json[nameof(OngoingTask.TaskId)] = pullReplication.TaskId == 0 ? index : pullReplication.TaskId; }, statusCode : HttpStatusCode.Created); }
public async Task UpdatePullReplicationOnSinkNode() { if (ResourceNameValidator.IsValidResourceName(Database.Name, ServerStore.Configuration.Core.DataDirectory.FullPath, out string errorMessage) == false) { throw new BadRequestException(errorMessage); } ServerStore.LicenseManager.AssertCanAddPullReplicationAsSink(); using (ServerStore.ContextPool.AllocateOperationContext(out TransactionOperationContext context)) { PullReplicationAsSink pullReplication = null; await DatabaseConfigurations( (_, databaseName, blittableJson, guid) => ServerStore.UpdatePullReplicationAsSink(databaseName, blittableJson, guid, out pullReplication), "update-sink-pull-replication", GetRaftRequestIdFromQuery(), fillJson : (json, _, index) => { using (context.OpenReadTransaction()) { var topology = ServerStore.Cluster.ReadDatabaseTopology(context, Database.Name); json[nameof(OngoingTask.ResponsibleNode)] = Database.WhoseTaskIsIt(topology, pullReplication, null); } json[nameof(ModifyOngoingTaskResult.TaskId)] = pullReplication.TaskId == 0 ? index : pullReplication.TaskId; }, statusCode : HttpStatusCode.Created); } }
public async Task UnregisterHubAccess() { var hub = GetStringQueryString("name", true); var thumbprint = GetStringQueryString("thumbprint", true); if (ResourceNameValidator.IsValidResourceName(Database.Name, ServerStore.Configuration.Core.DataDirectory.FullPath, out string errorMessage) == false) { throw new BadRequestException(errorMessage); } ServerStore.LicenseManager.AssertCanAddPullReplicationAsHub(); using (ServerStore.ContextPool.AllocateOperationContext(out TransactionOperationContext context)) { var command = new UnregisterReplicationHubAccessCommand(Database.Name, hub, thumbprint, GetRaftRequestIdFromQuery()); var result = await Server.ServerStore.SendToLeaderAsync(command); await WaitForIndexToBeApplied(context, result.Index); await using (var writer = new AsyncBlittableJsonTextWriter(context, ResponseBodyStream())) { writer.WriteStartObject(); writer.WritePropertyName(nameof(ReplicationHubAccessResponse.RaftCommandIndex)); writer.WriteInteger(result.Index); writer.WriteEndObject(); } } }
protected async Task DatabaseConfigurations(SetupFunc setupConfigurationFunc, string debug, string raftRequestId, RefAction beforeSetupConfiguration = null, Action <DynamicJsonValue, BlittableJsonReaderObject, long> fillJson = null, HttpStatusCode statusCode = HttpStatusCode.OK) { if (TryGetAllowedDbs(Database.Name, out var _, requireAdmin: true) == false) { return; } if (ResourceNameValidator.IsValidResourceName(Database.Name, ServerStore.Configuration.Core.DataDirectory.FullPath, out string errorMessage) == false) { throw new BadRequestException(errorMessage); } ServerStore.EnsureNotPassive(); using (ServerStore.ContextPool.AllocateOperationContext(out TransactionOperationContext context)) { var configurationJson = await context.ReadForMemoryAsync(RequestBodyStream(), debug); beforeSetupConfiguration?.Invoke(Database.Name, ref configurationJson, context); var(index, _) = await setupConfigurationFunc(context, Database.Name, configurationJson, raftRequestId); DatabaseTopology dbTopology; using (context.OpenReadTransaction()) { dbTopology = ServerStore.Cluster.ReadDatabaseTopology(context, Database.Name); } if (dbTopology.RelevantFor(ServerStore.NodeTag)) { var db = await ServerStore.DatabasesLandlord.TryGetOrCreateResourceStore(Database.Name); await db.RachisLogIndexNotifications.WaitForIndexNotification(index, ServerStore.Engine.OperationTimeout); } else { await ServerStore.Cluster.WaitForIndexNotification(index); } HttpContext.Response.StatusCode = (int)statusCode; using (var writer = new BlittableJsonTextWriter(context, ResponseBodyStream())) { var json = new DynamicJsonValue { ["RaftCommandIndex"] = index, }; fillJson?.Invoke(json, configurationJson, index); context.Write(writer, json); writer.Flush(); } } }
public async Task RegisterHubAccess() { var hubTaskName = GetStringQueryString("name", true); if (ResourceNameValidator.IsValidResourceName(Database.Name, ServerStore.Configuration.Core.DataDirectory.FullPath, out string errorMessage) == false) { throw new BadRequestException(errorMessage); } ServerStore.LicenseManager.AssertCanAddPullReplicationAsHub(); using (ServerStore.ContextPool.AllocateOperationContext(out TransactionOperationContext context)) { PullReplicationDefinition hubDefinition; using (context.OpenReadTransaction()) { hubDefinition = Server.ServerStore.Cluster.ReadPullReplicationDefinition(Database.Name, hubTaskName, context); if (hubDefinition == null) { HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound; return; } } #pragma warning disable CS0618 // Type or member is obsolete if (hubDefinition.Certificates != null && hubDefinition.Certificates.Count > 0) #pragma warning restore CS0618 // Type or member is obsolete { // handle backward compatibility throw new InvalidOperationException("Cannot register hub access to a replication hub that already has inline certificates: " + hubTaskName + ". Create a new replication hub and try again"); } var blittableJson = await context.ReadForMemoryAsync(RequestBodyStream(), "register-hub-access"); var access = JsonDeserializationClient.ReplicationHubAccess(blittableJson); access.Validate(hubDefinition.WithFiltering); using var cert = new X509Certificate2(Convert.FromBase64String(access.CertificateBase64)); var command = new RegisterReplicationHubAccessCommand(Database.Name, hubTaskName, access, cert, GetRaftRequestIdFromQuery()); var result = await Server.ServerStore.SendToLeaderAsync(command); await WaitForIndexToBeApplied(context, result.Index); await using (var writer = new AsyncBlittableJsonTextWriter(context, ResponseBodyStream())) { writer.WriteStartObject(); writer.WritePropertyName(nameof(ReplicationHubAccessResponse.RaftCommandIndex)); writer.WriteInteger(result.Index); writer.WriteEndObject(); } } }
public void DatabaseNameWithDocsValidation() { Assert.False(ResourceNameValidator.IsValidResourceName(".", null, out _)); Assert.False(ResourceNameValidator.IsValidResourceName("..", null, out _)); Assert.False(ResourceNameValidator.IsValidResourceName("...", null, out _)); Assert.False(ResourceNameValidator.IsValidResourceName("../..", null, out _)); Assert.False(ResourceNameValidator.IsValidResourceName("../../aa", null, out _)); Assert.False(ResourceNameValidator.IsValidResourceName("..\\..", null, out _)); Assert.False(ResourceNameValidator.IsValidResourceName("..\\..\\aa", null, out _)); Assert.True(ResourceNameValidator.IsValidResourceName("a.a", null, out _)); Assert.True(ResourceNameValidator.IsValidResourceName("4.a", null, out _)); }
public async Task IsValidName() { if (Enum.TryParse(GetQueryStringValueAndAssertIfSingleAndNotEmpty("type").Trim(), out ItemType elementType) == false) { throw new ArgumentException($"Type {elementType} is not supported"); } var name = GetQueryStringValueAndAssertIfSingleAndNotEmpty("name").Trim(); var path = GetStringQueryString("dataPath", false); using (ServerStore.ContextPool.AllocateOperationContext(out JsonOperationContext context)) { bool isValid = true; string errorMessage = null; switch (elementType) { case ItemType.Database: isValid = ResourceNameValidator.IsValidResourceName(name, path, out errorMessage); break; case ItemType.Index: isValid = IndexStore.IsValidIndexName(name, isStatic: true, out errorMessage); break; case ItemType.Script: isValid = ResourceNameValidator.IsValidFileName(name, out errorMessage); break; case ItemType.ElasticSearchIndex: isValid = ElasticSearchIndexValidator.IsValidIndexName(name, out errorMessage); break; } await using (var writer = new AsyncBlittableJsonTextWriter(context, ResponseBodyStream())) { context.Write(writer, new DynamicJsonValue { [nameof(NameValidation.IsValid)] = isValid, [nameof(NameValidation.ErrorMessage)] = errorMessage }); } } }
protected async Task DatabaseConfigurations(SetupFunc setupConfigurationFunc, string debug, string raftRequestId, RefAction beforeSetupConfiguration = null, Action <DynamicJsonValue, BlittableJsonReaderObject, long> fillJson = null, HttpStatusCode statusCode = HttpStatusCode.OK) { if (TryGetAllowedDbs(Database.Name, out var _, requireAdmin: true) == false) { return; } if (ResourceNameValidator.IsValidResourceName(Database.Name, ServerStore.Configuration.Core.DataDirectory.FullPath, out string errorMessage) == false) { throw new BadRequestException(errorMessage); } await ServerStore.EnsureNotPassiveAsync(); using (ServerStore.ContextPool.AllocateOperationContext(out TransactionOperationContext context)) { var configurationJson = await context.ReadForMemoryAsync(RequestBodyStream(), debug); beforeSetupConfiguration?.Invoke(Database.Name, ref configurationJson, context); var(index, _) = await setupConfigurationFunc(context, Database.Name, configurationJson, raftRequestId); await WaitForIndexToBeApplied(context, index); HttpContext.Response.StatusCode = (int)statusCode; using (var writer = new BlittableJsonTextWriter(context, ResponseBodyStream())) { var json = new DynamicJsonValue { ["RaftCommandIndex"] = index, }; fillJson?.Invoke(json, configurationJson, index); context.Write(writer, json); writer.Flush(); } } }
protected RestoreBackupTaskBase(ServerStore serverStore, RestoreBackupConfigurationBase restoreFromConfiguration, string nodeTag, OperationCancelToken operationCancelToken) { _serverStore = serverStore; RestoreFromConfiguration = restoreFromConfiguration; _nodeTag = nodeTag; _operationCancelToken = operationCancelToken; var dataDirectoryThatWillBeUsed = string.IsNullOrWhiteSpace(RestoreFromConfiguration.DataDirectory) ? _serverStore.Configuration.Core.DataDirectory.FullPath : new PathSetting(RestoreFromConfiguration.DataDirectory, _serverStore.Configuration.Core.DataDirectory.FullPath).FullPath; if (ResourceNameValidator.IsValidResourceName(RestoreFromConfiguration.DatabaseName, dataDirectoryThatWillBeUsed, out string errorMessage) == false) { throw new InvalidOperationException(errorMessage); } _serverStore.EnsureNotPassive(); ClusterTopology clusterTopology; using (_serverStore.ContextPool.AllocateOperationContext(out TransactionOperationContext context)) using (context.OpenReadTransaction()) { if (_serverStore.Cluster.DatabaseExists(context, RestoreFromConfiguration.DatabaseName)) { throw new ArgumentException($"Cannot restore data to an existing database named {RestoreFromConfiguration.DatabaseName}"); } clusterTopology = _serverStore.GetClusterTopology(context); } _hasEncryptionKey = string.IsNullOrWhiteSpace(RestoreFromConfiguration.EncryptionKey) == false; if (_hasEncryptionKey) { var key = Convert.FromBase64String(RestoreFromConfiguration.EncryptionKey); if (key.Length != 256 / 8) { throw new InvalidOperationException($"The size of the key must be 256 bits, but was {key.Length * 8} bits."); } if (AdminDatabasesHandler.NotUsingHttps(clusterTopology.GetUrlFromTag(_serverStore.NodeTag))) { throw new InvalidOperationException("Cannot restore an encrypted database to a node which doesn't support SSL!"); } } var backupEncryptionSettings = RestoreFromConfiguration.BackupEncryptionSettings; if (backupEncryptionSettings != null) { if (backupEncryptionSettings.EncryptionMode == EncryptionMode.UseProvidedKey && backupEncryptionSettings.Key == null) { throw new InvalidOperationException($"{nameof(BackupEncryptionSettings.EncryptionMode)} is set to {nameof(EncryptionMode.UseProvidedKey)} but an encryption key wasn't provided"); } if (backupEncryptionSettings.EncryptionMode != EncryptionMode.UseProvidedKey && backupEncryptionSettings.Key != null) { throw new InvalidOperationException($"{nameof(BackupEncryptionSettings.EncryptionMode)} is set to {backupEncryptionSettings.EncryptionMode} but an encryption key was provided"); } } var hasRestoreDataDirectory = string.IsNullOrWhiteSpace(RestoreFromConfiguration.DataDirectory) == false; if (hasRestoreDataDirectory && HasFilesOrDirectories(dataDirectoryThatWillBeUsed)) { throw new ArgumentException("New data directory must be empty of any files or folders, " + $"path: {dataDirectoryThatWillBeUsed}"); } if (hasRestoreDataDirectory == false) { RestoreFromConfiguration.DataDirectory = GetDataDirectory(); } _restoringToDefaultDataDirectory = IsDefaultDataDirectory(RestoreFromConfiguration.DataDirectory, RestoreFromConfiguration.DatabaseName); }