dbMango/Rms.Risk.Mango/Services/Context/DatabaseConfigurationService.cs
Alexander Shabarshov 2a7a24c9e7 Initial contribution
2025-11-03 14:43:26 +00:00

234 lines
8.2 KiB
C#
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* dbMango
*
* Copyright 2025 Deutsche Bank AG
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.Collections.Concurrent;
using Microsoft.Extensions.Options;
using Rms.Risk.Mango.Interfaces;
using Rms.Service.Bootstrap.Security;
namespace Rms.Risk.Mango.Services.Context;
// ReSharper disable InconsistentNaming
public class DatabaseConfigurationService : IDatabaseConfigurationService
// ReSharper restore InconsistentNaming
{
public static TimeSpan DefaultTimeout = TimeSpan.FromSeconds(30);
private readonly IDatabaseConfigurationStorage? _storage;
private readonly IOptions<DatabasesConfig> _config;
private readonly IPasswordManager _passwordManager;
public const string ContextTypeNameDbMangoDatabase = "dbMangoDatabase";
public DatabaseConfigurationService(
IOptions<DatabasesConfig> config,
IPasswordManager passwordManager,
IDatabaseConfigurationStorage? storage = null
)
{
_storage = storage;
_config = config;
_passwordManager = passwordManager;
Databases = _config.Value.Databases.ToDictionary(x => x.Key, x => x.Value.Clone());
var cts = new CancellationTokenSource(DefaultTimeout);
_ = Task.Run(Reload, cts.Token);
}
private ConcurrentDictionary<string,DbMangoDatabaseConfigContext> RawDatabases { get; set; } = [];
public Dictionary<string, DatabasesConfig.DatabaseConfig> Databases { get; set; }
public async Task Reload()
{
if ( _storage == null)
return;
var cts = new CancellationTokenSource(DefaultTimeout);
var raw = await _storage.List("dbMango", cts.Token);
RawDatabases = new(raw.ToDictionary(x => x.Name, x => x));
var newDb = _config.Value.Databases.ToDictionary(x => x.Key, x => x.Value.Clone());
foreach (var databaseConfig in RawDatabases.Select( x => (x.Key, Config : ConvertTo(x.Value))))
{
newDb[databaseConfig.Key] = databaseConfig.Config;
}
Databases = newDb;
}
public async Task Update(string name, DatabasesConfig.DatabaseConfig c, string email)
{
await Reload();
if (RawDatabases.ContainsKey(name))
await UpdateInternal(name, c, email);
else
await CreateInternal(name, c, email);
}
private async Task CreateInternal(string name, DatabasesConfig.DatabaseConfig c, string email)
{
var ctx = ConvertFrom(name, c, true);
if ( _storage != null )
{
var cts = new CancellationTokenSource(DefaultTimeout);
await _storage.Create(ctx, email, cts.Token);
}
RawDatabases[name] = ctx;
}
private async Task UpdateInternal(string name, DatabasesConfig.DatabaseConfig c, string email)
{
var ctx = ConvertFrom(name, c, false);
if ( _storage != null )
{
var cts = new CancellationTokenSource(DefaultTimeout);
await _storage.Update(ctx, email, cts.Token);
}
RawDatabases[name] = ctx;
}
public async Task Delete(string name, string email)
{
await Reload();
if (!RawDatabases.TryGetValue(name, out var raw))
throw new ApplicationException($"Configuration for {name} is not loaded");
if ( _storage != null )
{
var cts = new CancellationTokenSource(DefaultTimeout);
await _storage.Delete(raw.ID, email, cts.Token);
}
RawDatabases.Remove(name, out _);
}
private DatabasesConfig.DatabaseConfig ConvertTo(DbMangoDatabaseConfigContext ctx)
{
var userPass = DecryptPassword(ctx.DatabaseParams.UserAuthPassword);
var adminPass = DecryptPassword(ctx.DatabaseParams.AdminAuthPassword);
var c = new DatabasesConfig.DatabaseConfig
{
Contacts = ctx.DatabaseParams.Contacts,
Config = new()
{
MongoDbUrl = ctx.DatabaseParams.MongoDbUrl,
MongoDbDatabase = ctx.DatabaseParams.MongoDbDatabase,
DirectConnection = ctx.DatabaseParams.DirectConnection,
UseTls = ctx.DatabaseParams.UseTls,
AllowShardAccess = ctx.DatabaseParams.AllowShardAccess,
Auth = new()
{
User = ctx.DatabaseParams.UserAuthUser,
Password = userPass,
AuthDatabase = ctx.DatabaseParams.UserAuthAuthDatabase,
Method = ctx.DatabaseParams.UserAuthMethod
},
AdminAuth = new()
{
User = ctx.DatabaseParams.AdminAuthUser,
Password = adminPass,
AuthDatabase = ctx.DatabaseParams.AdminAuthAuthDatabase,
Method = ctx.DatabaseParams.AdminAuthMethod
}
},
Groups = ctx.LdapParams
};
if (string.IsNullOrWhiteSpace(c.Config.Auth.User) ||
string.IsNullOrWhiteSpace(c.Config.Auth.Password))
{
c.Config.Auth = null;
}
if (string.IsNullOrWhiteSpace(c.Config.AdminAuth.User) ||
string.IsNullOrWhiteSpace(c.Config.AdminAuth.Password))
{
c.Config.AdminAuth = null;
}
return c;
}
private string DecryptPassword(string? p) =>
string.IsNullOrWhiteSpace(p)
? ""
: p.StartsWith("*")
? _passwordManager.DecryptPassword(p)
: p;
private string EncryptPassword(string? p) =>
string.IsNullOrWhiteSpace(p)
? ""
: p.StartsWith("*")
? p
: _passwordManager.EncryptPassword(p);
private DbMangoDatabaseConfigContext ConvertFrom( string name, DatabasesConfig.DatabaseConfig c, bool isNew )
{
DbMangoDatabaseConfigContext? raw = null;
if (!isNew && !RawDatabases.TryGetValue(name, out raw))
throw new ApplicationException($"Configuration for {name} is not loaded");
var userPass = EncryptPassword(c.Config.Auth?.Password);
var adminPass = EncryptPassword(c.Config.AdminAuth?.Password);
var ctx = new DbMangoDatabaseConfigContext
{
Type = ContextTypeNameDbMangoDatabase ,
Name = isNew ? name : raw!.Name,
ID = isNew ? 0 : raw!.ID,
IsTemplate = !isNew && raw!.IsTemplate,
ProposedForDeletion = !isNew && raw!.ProposedForDeletion,
DatabaseParams = new()
{
Contacts = c.Contacts,
MongoDbUrl = c.Config.MongoDbUrl,
MongoDbDatabase = c.Config.MongoDbDatabase,
DirectConnection = c.Config.DirectConnection,
UseTls = c.Config.UseTls,
AllowShardAccess = c.Config.AllowShardAccess,
UserAuthUser = c.Config.Auth?.User ?? "",
UserAuthPassword = userPass,
UserAuthAuthDatabase = c.Config.Auth?.AuthDatabase,
UserAuthMethod = c.Config.Auth?.Method,
AdminAuthUser = c.Config.AdminAuth?.User ?? "",
AdminAuthPassword = adminPass,
AdminAuthAuthDatabase = c.Config.AdminAuth?.AuthDatabase,
AdminAuthMethod = c.Config.AdminAuth?.Method,
},
LdapParams = c.Groups
};
return ctx;
}
}