Split AuthService/Server

some refactoring
fix some stuff
add http context accessor
configure metrics as well
commit 713d054ccb965f7adb8eafa6e3fb52853a1e6dd2 (partial, Docker only)
This commit is contained in:
Stanley Dimant
2024-05-06 14:05:24 +02:00
committed by Loporrit
parent c400d9746f
commit 7639066249
61 changed files with 593 additions and 120 deletions

View File

@@ -0,0 +1,32 @@
FROM mcr.microsoft.com/dotnet/sdk:8.0 as BUILD
COPY MareAPI /server/MareAPI
COPY MareSynchronosServer/MareSynchronosShared /server/MareSynchronosServer/MareSynchronosShared
COPY MareSynchronosServer/MareSynchronosAuthService /server/MareSynchronosServer/MareSynchronosAuthService
WORKDIR /server/MareSynchronosServer/MareSynchronosAuthService/
RUN dotnet publish \
--configuration=Debug \
--os=linux \
--output=/build \
MareSynchronosAuthService.csproj
FROM mcr.microsoft.com/dotnet/aspnet:8.0
RUN adduser \
--disabled-password \
--group \
--no-create-home \
--quiet \
--system \
mare
COPY --from=BUILD /build /opt/MareSynchronosAuthService
RUN chown -R mare:mare /opt/MareSynchronosAuthService
RUN apt-get update; apt-get install curl -y
USER mare:mare
WORKDIR /opt/MareSynchronosAuthService
CMD ["./MareSynchronosAuthService"]

View File

@@ -0,0 +1,30 @@
FROM mcr.microsoft.com/dotnet/sdk:8.0 as BUILD
RUN git clone --recurse-submodules https://github.com/Penumbra-Sync/server
WORKDIR /server/MareSynchronosServer/MareSynchronosAuthService/
RUN dotnet publish \
--configuration=Release \
--os=linux \
--output=/MareSynchronosAuthService \
MareSynchronosAuthService.csproj
FROM mcr.microsoft.com/dotnet/aspnet:8.0
RUN adduser \
--disabled-password \
--group \
--no-create-home \
--quiet \
--system \
mare
COPY --from=BUILD /MareSynchronosAuthService /opt/MareSynchronosAuthService
RUN chown -R mare:mare /opt/MareSynchronosAuthService
RUN apt-get update; apt-get install curl -y
USER mare:mare
WORKDIR /opt/MareSynchronosAuthService
CMD ["./MareSynchronosAuthService"]

View File

@@ -0,0 +1,2 @@
#!/bin/sh
docker build -t darkarchon/mare-synchronos-authservice:latest . -f ../Dockerfile-MareSynchronosAuthService-git --no-cache --pull --force-rm

View File

@@ -1,4 +1,5 @@
#!/bin/sh
./docker-build-server.sh
./docker-build-authservice.sh
./docker-build-services.sh
./docker-build-staticfilesserver.sh

View File

@@ -0,0 +1,2 @@
#!/bin/sh
docker build -t darkarchon/mare-synchronos-authservice:latest . -f ../Dockerfile-MareSynchronosAuthService --no-cache --pull --force-rm

View File

@@ -1,4 +1,5 @@
#!/bin/sh
./docker-build-server.sh
./docker-build-authservice.sh
./docker-build-services.sh
./docker-build-staticfilesserver.sh

View File

@@ -0,0 +1,3 @@
@echo off
docker build -t darkarchon/mare-synchronos-authservice:latest . -f ..\Dockerfile-MareSynchronosAuthService-git --no-cache --pull --force-rm

View File

@@ -1,5 +1,6 @@
@echo off
call docker-build-server.bat
call docker-build-authservice.bat
call docker-build-services.bat
call docker-build-staticfilesserver.bat

View File

@@ -0,0 +1,4 @@
@echo off
cd ..\..\..\
docker build -t darkarchon/mare-synchronos-authservice:latest . -f Docker\build\Dockerfile-MareSynchronosAuthService --no-cache --pull --force-rm
cd Docker\build\windows-local

View File

@@ -1,5 +1,6 @@
@echo off
call docker-build-server.bat
call docker-build-authservice.bat
call docker-build-services.bat
call docker-build-staticfilesserver.bat

View File

@@ -44,6 +44,21 @@ services:
start_period: 10s
timeout: 1s
mare-auth:
image: darkarchon/mare-synchronos-authservice:latest
restart: on-failure
environment:
DOTNET_USE_POLLING_FILE_WATCHER: 1
volumes:
- ../config/standalone/authservice-standalone.json:/opt/MareSynchronosAuthService/appsettings.json
- ../log/authservice-standalone/:/opt/MareSynchronosAuthService/logs/:rw
- postgres_socket:/var/run/postgresql/:rw
depends_on:
mare-server:
condition: service_healthy
postgres:
condition: service_healthy
mare-services:
image: darkarchon/mare-synchronos-services:latest
restart: on-failure

View File

@@ -0,0 +1,42 @@
{
"ConnectionStrings": {
"DefaultConnection": "Host=/var/run/postgresql;Port=5432;Database=mare;Username=mare;Keepalive=15;Minimum Pool Size=10;Maximum Pool Size=50;No Reset On Close=true;Max Auto Prepare=50;Enlist=false"
},
"Logging": {
"LogLevel": {
"Default": "Warning",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"MareSynchronosServices": "Information",
"MareSynchronosShared": "Information",
"System.IO": "Information"
},
"File": {
"BasePath": "logs",
"FileAccessMode": "KeepOpenAndAutoFlush",
"FileEncodingName": "utf-8",
"DateFormat": "yyyMMdd",
"MaxFileSize": 104857600,
"Files": [
{
"Path": "<date:yyyy>/<date:MM>/<date:dd>/mare-<date:HH>-<counter:0000>.log"
}
]
}
},
"MareSynchronos": {
"DbContextPoolSize": 512,
"ShardName": "AuthServices",
"MetricsPort": 6150,
"Jwt": "teststringteststringteststringteststringteststringteststringteststringteststringteststringteststring",
"RedisConnectionString": "redis,password=secretredispassword",
"FailedAuthForTempBan": 5,
"UseGeoIP": false,
"GeoIPDbCityFile": ""
},
"AllowedHosts": "*",
"Kestrel": {
},
"IpRateLimiting": {},
"IPRateLimitPolicies": {}
}

View File

@@ -28,7 +28,6 @@
"DbContextPoolSize": 512,
"ShardName": "Files",
"MetricsPort": 6250,
"FileServerGrpcAddress": "",
"ForcedDeletionOfFilesAfterHours": -1,
"CacheSizeHardLimitInGiB": -1,
"UnusedFileRetentionPeriodInDays": 14,
@@ -37,7 +36,9 @@
"MainServerAddress": "http://mare-server:6000/",
"RedisConnectionString": "redis,password=secretredispassword",
"MainFileServerAddress": "",
"Jwt": "teststringteststringteststringteststringteststringteststringteststringteststringteststringteststring"
"Jwt": "teststringteststringteststringteststringteststringteststringteststringteststringteststringteststring",
"UseColdStorage": false,
"IsDistributionNode": true
},
"AllowedHosts": "*",
"Kestrel": {

View File

@@ -1,3 +1,3 @@
namespace MareSynchronosServer.Authentication;
namespace MareSynchronosAuthService.Authentication;
public record SecretKeyAuthReply(bool Success, string Uid, string Alias, bool TempBan, bool Permaban);

View File

@@ -1,4 +1,4 @@
namespace MareSynchronosServer.Authentication;
namespace MareSynchronosAuthService.Authentication;
internal record SecretKeyFailedAuthorization
{

View File

@@ -1,11 +1,11 @@
using MareSynchronos.API.Routes;
using MareSynchronosServer.Authentication;
using MareSynchronosServer.Services;
using MareSynchronosAuthService.Services;
using MareSynchronosShared;
using MareSynchronosShared.Data;
using MareSynchronosShared.Models;
using MareSynchronosShared.Services;
using MareSynchronosShared.Utils;
using MareSynchronosShared.Utils.Configuration;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
@@ -15,7 +15,7 @@ using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
namespace MareSynchronosServer.Controllers;
namespace MareSynchronosAuthService.Controllers;
[AllowAnonymous]
[Route(MareAuth.Auth)]
@@ -27,12 +27,12 @@ public class JwtController : Controller
private readonly GeoIPService _geoIPProvider;
private readonly SecretKeyAuthenticatorService _secretKeyAuthenticatorService;
private readonly AccountRegistrationService _accountRegistrationService;
private readonly IConfigurationService<MareConfigurationAuthBase> _configuration;
private readonly IConfigurationService<AuthServiceConfiguration> _configuration;
public JwtController(IHttpContextAccessor accessor, MareDbContext mareDbContext,
SecretKeyAuthenticatorService secretKeyAuthenticatorService,
AccountRegistrationService accountRegistrationService,
IConfigurationService<MareConfigurationAuthBase> configuration,
IConfigurationService<AuthServiceConfiguration> configuration,
IRedisDatabase redisDb, GeoIPService geoIPProvider)
{
_accessor = accessor;
@@ -133,7 +133,7 @@ public class JwtController : Controller
private JwtSecurityToken CreateToken(IEnumerable<Claim> authClaims)
{
var authSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(_configuration.GetValue<string>(nameof(MareConfigurationAuthBase.Jwt))));
var authSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(_configuration.GetValue<string>(nameof(MareConfigurationBase.Jwt))));
var token = new SecurityTokenDescriptor()
{

View File

@@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="IDisposableAnalyzers" Version="4.0.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Meziantou.Analyzer" Version="2.0.149">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="MaxMind.GeoIP2" Version="5.2.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="8.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MareSynchronosShared\MareSynchronosShared.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,40 @@
namespace MareSynchronosAuthService;
public class Program
{
public static void Main(string[] args)
{
var hostBuilder = CreateHostBuilder(args);
using var host = hostBuilder.Build();
try
{
host.Run();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
public static IHostBuilder CreateHostBuilder(string[] args)
{
using var loggerFactory = LoggerFactory.Create(builder =>
{
builder.ClearProviders();
builder.AddConsole();
});
var logger = loggerFactory.CreateLogger<Startup>();
return Host.CreateDefaultBuilder(args)
.UseSystemd()
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseContentRoot(AppContext.BaseDirectory);
webBuilder.ConfigureLogging((ctx, builder) =>
{
builder.AddConfiguration(ctx.Configuration.GetSection("Logging"));
builder.AddFile(o => o.RootPath = AppContext.BaseDirectory);
});
webBuilder.UseStartup(ctx => new Startup(ctx.Configuration, logger));
});
}
}

View File

@@ -0,0 +1,29 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:37726",
"sslPort": 0
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:5056",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@@ -4,11 +4,12 @@ using MareSynchronosShared.Data;
using MareSynchronosShared.Metrics;
using MareSynchronosShared.Services;
using MareSynchronosShared.Utils;
using MareSynchronosShared.Utils.Configuration;
using Microsoft.EntityFrameworkCore;
using System.Text.RegularExpressions;
using MareSynchronosShared.Models;
namespace MareSynchronosServer.Authentication;
namespace MareSynchronosAuthService.Services;
internal record IpRegistrationCount
{
@@ -27,14 +28,14 @@ public class AccountRegistrationService
private readonly MareMetrics _metrics;
private readonly MareDbContext _mareDbContext;
private readonly IServiceScopeFactory _serviceScopeFactory;
private readonly IConfigurationService<MareConfigurationAuthBase> _configurationService;
private readonly IConfigurationService<AuthServiceConfiguration> _configurationService;
private readonly ILogger<AccountRegistrationService> _logger;
private readonly ConcurrentDictionary<string, IpRegistrationCount> _registrationsPerIp = new(StringComparer.Ordinal);
private Regex _registrationUserAgentRegex = new Regex(@"^MareSynchronos/", RegexOptions.Compiled);
public AccountRegistrationService(MareMetrics metrics, MareDbContext mareDbContext,
IServiceScopeFactory serviceScopeFactory, IConfigurationService<MareConfigurationAuthBase> configuration,
IServiceScopeFactory serviceScopeFactory, IConfigurationService<AuthServiceConfiguration> configuration,
ILogger<AccountRegistrationService> logger)
{
_mareDbContext = mareDbContext;
@@ -55,7 +56,7 @@ public class AccountRegistrationService
}
if (_registrationsPerIp.TryGetValue(ip, out var registrationCount)
&& registrationCount.Count >= _configurationService.GetValueOrDefault(nameof(MareConfigurationAuthBase.RegisterIpLimit), 3))
&& registrationCount.Count >= _configurationService.GetValueOrDefault(nameof(AuthServiceConfiguration.RegisterIpLimit), 3))
{
_logger.LogWarning("Rejecting {ip} for registration spam", ip);
@@ -68,7 +69,7 @@ public class AccountRegistrationService
registrationCount.ResetTask = Task.Run(async () =>
{
await Task.Delay(TimeSpan.FromMinutes(_configurationService.GetValueOrDefault(nameof(MareConfigurationAuthBase.RegisterIpDurationInMinutes), 10))).ConfigureAwait(false);
await Task.Delay(TimeSpan.FromMinutes(_configurationService.GetValueOrDefault(nameof(AuthServiceConfiguration.RegisterIpDurationInMinutes), 10))).ConfigureAwait(false);
}).ContinueWith((t) =>
{
@@ -110,7 +111,7 @@ public class AccountRegistrationService
await _mareDbContext.SaveChangesAsync().ConfigureAwait(false);
_logger.LogInformation("User registered: {userUID} from IP {ip}", user.UID, ip);
_metrics.IncCounter(MetricsAPI.CounterAuthenticationRequests);
_metrics.IncCounter(MetricsAPI.CounterAccountsCreated);
reply.Success = true;
reply.UID = user.UID;
@@ -123,7 +124,7 @@ public class AccountRegistrationService
private void RecordIpRegistration(string ip)
{
var whitelisted = _configurationService.GetValueOrDefault(nameof(MareConfigurationAuthBase.WhitelistedIps), new List<string>());
var whitelisted = _configurationService.GetValueOrDefault(nameof(AuthServiceConfiguration.WhitelistedIps), new List<string>());
if (!whitelisted.Any(w => ip.Contains(w, StringComparison.OrdinalIgnoreCase)))
{
if (_registrationsPerIp.TryGetValue(ip, out var count))
@@ -141,7 +142,7 @@ public class AccountRegistrationService
count.ResetTask = Task.Run(async () =>
{
await Task.Delay(TimeSpan.FromMinutes(_configurationService.GetValueOrDefault(nameof(MareConfigurationAuthBase.RegisterIpDurationInMinutes), 10))).ConfigureAwait(false);
await Task.Delay(TimeSpan.FromMinutes(_configurationService.GetValueOrDefault(nameof(AuthServiceConfiguration.RegisterIpDurationInMinutes), 10))).ConfigureAwait(false);
}).ContinueWith((t) =>
{

View File

@@ -1,14 +1,14 @@
using MareSynchronosShared;
using MareSynchronosShared.Services;
using MareSynchronosShared.Utils;
using MareSynchronosShared.Utils.Configuration;
using MaxMind.GeoIP2;
namespace MareSynchronosServer.Services;
namespace MareSynchronosAuthService.Services;
public class GeoIPService : IHostedService
{
private readonly ILogger<GeoIPService> _logger;
private readonly IConfigurationService<ServerConfiguration> _mareConfiguration;
private readonly IConfigurationService<AuthServiceConfiguration> _mareConfiguration;
private bool _useGeoIP = false;
private string _cityFile = string.Empty;
private DatabaseReader? _dbReader;
@@ -17,7 +17,7 @@ public class GeoIPService : IHostedService
private bool _processingReload = false;
public GeoIPService(ILogger<GeoIPService> logger,
IConfigurationService<ServerConfiguration> mareConfiguration)
IConfigurationService<AuthServiceConfiguration> mareConfiguration)
{
_logger = logger;
_mareConfiguration = mareConfiguration;
@@ -38,11 +38,12 @@ public class GeoIPService : IHostedService
waitCts.CancelAfter(TimeSpan.FromSeconds(5));
while (_processingReload) await Task.Delay(100, waitCts.Token).ConfigureAwait(false);
if (_dbReader.TryCity(ip, out var response))
if (_dbReader!.TryCity(ip, out var response))
{
var continent = response.Continent.Code;
if (string.Equals(continent, "NA", StringComparison.Ordinal)
&& response.Location.Longitude != null)
string? continent = response?.Continent.Code;
if (!string.IsNullOrEmpty(continent) &&
string.Equals(continent, "NA", StringComparison.Ordinal)
&& response?.Location.Longitude != null)
{
if (response.Location.Longitude < -102)
{
@@ -84,8 +85,8 @@ public class GeoIPService : IHostedService
{
_processingReload = true;
var useGeoIP = _mareConfiguration.GetValueOrDefault(nameof(ServerConfiguration.UseGeoIP), false);
var cityFile = _mareConfiguration.GetValueOrDefault(nameof(ServerConfiguration.GeoIPDbCityFile), string.Empty);
var useGeoIP = _mareConfiguration.GetValueOrDefault(nameof(AuthServiceConfiguration.UseGeoIP), false);
var cityFile = _mareConfiguration.GetValueOrDefault(nameof(AuthServiceConfiguration.GeoIPDbCityFile), string.Empty);
var lastWriteTime = new FileInfo(cityFile).LastWriteTimeUtc;
if (useGeoIP && (!string.Equals(cityFile, _cityFile, StringComparison.OrdinalIgnoreCase) || lastWriteTime != _dbLastWriteTime))
{
@@ -131,7 +132,7 @@ public class GeoIPService : IHostedService
{
_fileWriteTimeCheckCts.Cancel();
_fileWriteTimeCheckCts.Dispose();
_dbReader.Dispose();
_dbReader?.Dispose();
return Task.CompletedTask;
}
}

View File

@@ -1,22 +1,23 @@
using System.Collections.Concurrent;
using MareSynchronosAuthService.Authentication;
using MareSynchronosShared.Data;
using MareSynchronosShared.Metrics;
using MareSynchronosShared.Services;
using MareSynchronosShared.Utils;
using MareSynchronosShared.Utils.Configuration;
using Microsoft.EntityFrameworkCore;
namespace MareSynchronosServer.Authentication;
namespace MareSynchronosAuthService.Services;
public class SecretKeyAuthenticatorService
{
private readonly MareMetrics _metrics;
private readonly MareDbContext _mareDbContext;
private readonly IConfigurationService<MareConfigurationAuthBase> _configurationService;
private readonly IConfigurationService<AuthServiceConfiguration> _configurationService;
private readonly ILogger<SecretKeyAuthenticatorService> _logger;
private readonly ConcurrentDictionary<string, SecretKeyFailedAuthorization> _failedAuthorizations = new(StringComparer.Ordinal);
public SecretKeyAuthenticatorService(MareMetrics metrics, MareDbContext mareDbContext,
IConfigurationService<MareConfigurationAuthBase> configuration, ILogger<SecretKeyAuthenticatorService> logger)
IConfigurationService<AuthServiceConfiguration> configuration, ILogger<SecretKeyAuthenticatorService> logger)
{
_logger = logger;
_configurationService = configuration;
@@ -29,7 +30,7 @@ public class SecretKeyAuthenticatorService
_metrics.IncCounter(MetricsAPI.CounterAuthenticationRequests);
if (_failedAuthorizations.TryGetValue(ip, out var existingFailedAuthorization)
&& existingFailedAuthorization.FailedAttempts > _configurationService.GetValueOrDefault(nameof(MareConfigurationAuthBase.FailedAuthForTempBan), 5))
&& existingFailedAuthorization.FailedAttempts > _configurationService.GetValueOrDefault(nameof(AuthServiceConfiguration.FailedAuthForTempBan), 5))
{
if (existingFailedAuthorization.ResetTask == null)
{
@@ -37,7 +38,7 @@ public class SecretKeyAuthenticatorService
existingFailedAuthorization.ResetTask = Task.Run(async () =>
{
await Task.Delay(TimeSpan.FromMinutes(_configurationService.GetValueOrDefault(nameof(MareConfigurationAuthBase.TempBanDurationInMinutes), 5))).ConfigureAwait(false);
await Task.Delay(TimeSpan.FromMinutes(_configurationService.GetValueOrDefault(nameof(AuthServiceConfiguration.TempBanDurationInMinutes), 5))).ConfigureAwait(false);
}).ContinueWith((t) =>
{
@@ -69,7 +70,7 @@ public class SecretKeyAuthenticatorService
_metrics.IncCounter(MetricsAPI.CounterAuthenticationFailures);
_logger.LogWarning("Failed authorization from {ip}", ip);
var whitelisted = _configurationService.GetValueOrDefault(nameof(MareConfigurationAuthBase.WhitelistedIps), new List<string>());
var whitelisted = _configurationService.GetValueOrDefault(nameof(AuthServiceConfiguration.WhitelistedIps), new List<string>());
if (!whitelisted.Any(w => ip.Contains(w, StringComparison.OrdinalIgnoreCase)))
{
if (_failedAuthorizations.TryGetValue(ip, out var auth))

View File

@@ -0,0 +1,226 @@
using MareSynchronosAuthService.Controllers;
using MareSynchronosShared.Metrics;
using MareSynchronosShared.Services;
using MareSynchronosShared.Utils;
using Microsoft.AspNetCore.Mvc.Controllers;
using StackExchange.Redis.Extensions.Core.Configuration;
using StackExchange.Redis.Extensions.System.Text.Json;
using StackExchange.Redis;
using System.Net;
using MareSynchronosAuthService.Services;
using MareSynchronosShared.RequirementHandlers;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using MareSynchronosShared.Data;
using Microsoft.EntityFrameworkCore;
using Prometheus;
using MareSynchronosShared.Utils.Configuration;
namespace MareSynchronosAuthService;
public class Startup
{
private readonly IConfiguration _configuration;
private ILogger<Startup> _logger;
public Startup(IConfiguration configuration, ILogger<Startup> logger)
{
_configuration = configuration;
_logger = logger;
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger)
{
var config = app.ApplicationServices.GetRequiredService<IConfigurationService<MareConfigurationBase>>();
app.UseRouting();
app.UseHttpMetrics();
app.UseAuthentication();
app.UseAuthorization();
KestrelMetricServer metricServer = new KestrelMetricServer(config.GetValueOrDefault<int>(nameof(MareConfigurationBase.MetricsPort), 4985));
metricServer.Start();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
foreach (var source in endpoints.DataSources.SelectMany(e => e.Endpoints).Cast<RouteEndpoint>())
{
if (source == null) continue;
_logger.LogInformation("Endpoint: {url} ", source.RoutePattern.RawText);
}
});
}
public void ConfigureServices(IServiceCollection services)
{
var mareConfig = _configuration.GetRequiredSection("MareSynchronos");
services.AddHttpContextAccessor();
ConfigureRedis(services, mareConfig);
services.AddSingleton<SecretKeyAuthenticatorService>();
services.AddSingleton<AccountRegistrationService>();
services.AddSingleton<GeoIPService>();
services.AddHostedService(provider => provider.GetRequiredService<GeoIPService>());
services.Configure<AuthServiceConfiguration>(_configuration.GetRequiredSection("MareSynchronos"));
services.Configure<MareConfigurationBase>(_configuration.GetRequiredSection("MareSynchronos"));
services.AddSingleton<ServerTokenGenerator>();
ConfigureAuthorization(services);
ConfigureDatabase(services, mareConfig);
ConfigureConfigServices(services);
ConfigureMetrics(services);
services.AddHealthChecks();
services.AddControllers().ConfigureApplicationPartManager(a =>
{
a.FeatureProviders.Remove(a.FeatureProviders.OfType<ControllerFeatureProvider>().First());
a.FeatureProviders.Add(new AllowedControllersFeatureProvider(typeof(JwtController)));
});
}
private static void ConfigureAuthorization(IServiceCollection services)
{
services.AddTransient<IAuthorizationHandler, UserRequirementHandler>();
services.AddOptions<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme)
.Configure<IConfigurationService<MareConfigurationBase>>((options, config) =>
{
options.TokenValidationParameters = new()
{
ValidateIssuer = false,
ValidateLifetime = true,
ValidateAudience = false,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(config.GetValue<string>(nameof(MareConfigurationBase.Jwt)))),
};
});
services.AddAuthentication(o =>
{
o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer();
services.AddAuthorization(options =>
{
options.DefaultPolicy = new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
.RequireAuthenticatedUser().Build();
options.AddPolicy("Authenticated", policy =>
{
policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme);
policy.RequireAuthenticatedUser();
});
options.AddPolicy("Identified", policy =>
{
policy.AddRequirements(new UserRequirement(UserRequirements.Identified));
});
options.AddPolicy("Admin", policy =>
{
policy.AddRequirements(new UserRequirement(UserRequirements.Identified | UserRequirements.Administrator));
});
options.AddPolicy("Moderator", policy =>
{
policy.AddRequirements(new UserRequirement(UserRequirements.Identified | UserRequirements.Moderator | UserRequirements.Administrator));
});
options.AddPolicy("Internal", new AuthorizationPolicyBuilder().RequireClaim(MareClaimTypes.Internal, "true").Build());
});
}
private static void ConfigureMetrics(IServiceCollection services)
{
services.AddSingleton<MareMetrics>(m => new MareMetrics(m.GetService<ILogger<MareMetrics>>(), new List<string>
{
MetricsAPI.CounterAuthenticationCacheHits,
MetricsAPI.CounterAuthenticationFailures,
MetricsAPI.CounterAuthenticationRequests,
MetricsAPI.CounterAuthenticationSuccesses,
MetricsAPI.CounterAccountsCreated,
}, new List<string>
{
}));
}
private static void ConfigureRedis(IServiceCollection services, IConfigurationSection mareConfig)
{
// configure redis for SignalR
var redisConnection = mareConfig.GetValue(nameof(ServerConfiguration.RedisConnectionString), string.Empty);
var options = ConfigurationOptions.Parse(redisConnection);
var endpoint = options.EndPoints[0];
string address = "";
int port = 0;
if (endpoint is DnsEndPoint dnsEndPoint) { address = dnsEndPoint.Host; port = dnsEndPoint.Port; }
if (endpoint is IPEndPoint ipEndPoint) { address = ipEndPoint.Address.ToString(); port = ipEndPoint.Port; }
var redisConfiguration = new RedisConfiguration()
{
AbortOnConnectFail = true,
KeyPrefix = "",
Hosts = new RedisHost[]
{
new RedisHost(){ Host = address, Port = port },
},
AllowAdmin = true,
ConnectTimeout = options.ConnectTimeout,
Database = 0,
Ssl = false,
Password = options.Password,
ServerEnumerationStrategy = new ServerEnumerationStrategy()
{
Mode = ServerEnumerationStrategy.ModeOptions.All,
TargetRole = ServerEnumerationStrategy.TargetRoleOptions.Any,
UnreachableServerAction = ServerEnumerationStrategy.UnreachableServerActionOptions.Throw,
},
MaxValueLength = 1024,
PoolSize = mareConfig.GetValue(nameof(ServerConfiguration.RedisPool), 50),
SyncTimeout = options.SyncTimeout,
};
services.AddStackExchangeRedisExtensions<SystemTextJsonSerializer>(redisConfiguration);
}
private void ConfigureConfigServices(IServiceCollection services)
{
services.AddSingleton<IConfigurationService<AuthServiceConfiguration>, MareConfigurationServiceServer<AuthServiceConfiguration>>();
services.AddSingleton<IConfigurationService<MareConfigurationBase>, MareConfigurationServiceServer<MareConfigurationBase>>();
}
private void ConfigureDatabase(IServiceCollection services, IConfigurationSection mareConfig)
{
services.AddDbContextPool<MareDbContext>(options =>
{
options.UseNpgsql(_configuration.GetConnectionString("DefaultConnection"), builder =>
{
builder.MigrationsHistoryTable("_efmigrationshistory", "public");
builder.MigrationsAssembly("MareSynchronosShared");
}).UseSnakeCaseNamingConvention();
options.EnableThreadSafetyChecks(false);
}, mareConfig.GetValue(nameof(MareConfigurationBase.DbContextPoolSize), 1024));
services.AddDbContextFactory<MareDbContext>(options =>
{
options.UseNpgsql(_configuration.GetConnectionString("DefaultConnection"), builder =>
{
builder.MigrationsHistoryTable("_efmigrationshistory", "public");
builder.MigrationsAssembly("MareSynchronosShared");
}).UseSnakeCaseNamingConvention();
options.EnableThreadSafetyChecks(false);
});
}
}

View File

@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View File

@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}

View File

@@ -18,6 +18,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
.editorconfig = .editorconfig
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MareSynchronosAuthService", "MareSynchronosAuthService\MareSynchronosAuthService.csproj", "{D7D4041C-DCD9-4B7A-B423-0F458DFFF3D6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -44,6 +46,10 @@ Global
{E29C8677-AB44-4950-9EB1-D8E70B710A56}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E29C8677-AB44-4950-9EB1-D8E70B710A56}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E29C8677-AB44-4950-9EB1-D8E70B710A56}.Release|Any CPU.Build.0 = Release|Any CPU
{D7D4041C-DCD9-4B7A-B423-0F458DFFF3D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D7D4041C-DCD9-4B7A-B423-0F458DFFF3D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D7D4041C-DCD9-4B7A-B423-0F458DFFF3D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D7D4041C-DCD9-4B7A-B423-0F458DFFF3D6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -8,7 +8,7 @@ using MareSynchronosShared;
using MareSynchronosShared.Data;
using MareSynchronosShared.Metrics;
using MareSynchronosShared.Services;
using MareSynchronosShared.Utils;
using MareSynchronosShared.Utils.Configuration;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;
using StackExchange.Redis.Extensions.Core.Abstractions;

View File

@@ -29,7 +29,6 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="MaxMind.GeoIP2" Version="5.2.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="8.0.0" />
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="7.5.1" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.4" />

View File

@@ -2,7 +2,7 @@ using Microsoft.EntityFrameworkCore;
using MareSynchronosShared.Data;
using MareSynchronosShared.Metrics;
using MareSynchronosShared.Services;
using MareSynchronosShared.Utils;
using MareSynchronosShared.Utils.Configuration;
namespace MareSynchronosServer;

View File

@@ -4,7 +4,7 @@ using MareSynchronosServer.Hubs;
using MareSynchronosShared.Data;
using MareSynchronosShared.Metrics;
using MareSynchronosShared.Services;
using MareSynchronosShared.Utils;
using MareSynchronosShared.Utils.Configuration;
using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;
using StackExchange.Redis.Extensions.Core.Abstractions;

View File

@@ -3,6 +3,7 @@ using MareSynchronosShared.Metrics;
using MareSynchronosShared.Models;
using MareSynchronosShared.Services;
using MareSynchronosShared.Utils;
using MareSynchronosShared.Utils.Configuration;
using Microsoft.EntityFrameworkCore;
namespace MareSynchronosServer.Services;

View File

@@ -13,7 +13,6 @@ using Prometheus;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using MareSynchronosServer.Authentication;
using StackExchange.Redis;
using StackExchange.Redis.Extensions.Core.Configuration;
using System.Net;
@@ -24,6 +23,7 @@ using MessagePack.Resolvers;
using Microsoft.AspNetCore.Mvc.Controllers;
using MareSynchronosServer.Controllers;
using MareSynchronosShared.RequirementHandlers;
using MareSynchronosShared.Utils.Configuration;
namespace MareSynchronosServer;
@@ -71,7 +71,7 @@ public class Startup
a.FeatureProviders.Remove(a.FeatureProviders.OfType<ControllerFeatureProvider>().First());
if (mareConfig.GetValue<Uri>(nameof(ServerConfiguration.MainServerAddress), defaultValue: null) == null)
{
a.FeatureProviders.Add(new AllowedControllersFeatureProvider(typeof(MareServerConfigurationController), typeof(MareAuthBaseConfigurationController), typeof(JwtController), typeof(ClientMessageController), typeof(MainController)));
a.FeatureProviders.Add(new AllowedControllersFeatureProvider(typeof(MareServerConfigurationController), typeof(MareBaseConfigurationController), typeof(ClientMessageController), typeof(MainController)));
}
else
{
@@ -86,7 +86,6 @@ public class Startup
services.Configure<ServerConfiguration>(Configuration.GetRequiredSection("MareSynchronos"));
services.Configure<MareConfigurationBase>(Configuration.GetRequiredSection("MareSynchronos"));
services.Configure<MareConfigurationAuthBase>(Configuration.GetRequiredSection("MareSynchronos"));
services.AddSingleton<ServerTokenGenerator>();
services.AddSingleton<SystemInfoService>();
@@ -96,10 +95,8 @@ public class Startup
if (isMainServer)
{
services.AddSingleton<GeoIPService>();
services.AddSingleton<UserCleanupService>();
services.AddHostedService(provider => provider.GetService<UserCleanupService>());
services.AddHostedService(provider => provider.GetService<GeoIPService>());
}
}
@@ -183,12 +180,10 @@ public class Startup
private static void ConfigureAuthorization(IServiceCollection services)
{
services.AddSingleton<SecretKeyAuthenticatorService>();
services.AddSingleton<AccountRegistrationService>();
services.AddTransient<IAuthorizationHandler, UserRequirementHandler>();
services.AddOptions<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme)
.Configure<IConfigurationService<MareConfigurationAuthBase>>((options, config) =>
.Configure<IConfigurationService<MareConfigurationBase>>((options, config) =>
{
options.TokenValidationParameters = new()
{
@@ -196,7 +191,7 @@ public class Startup
ValidateLifetime = false,
ValidateAudience = false,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(config.GetValue<string>(nameof(MareConfigurationAuthBase.Jwt)))),
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(config.GetValue<string>(nameof(MareConfigurationBase.Jwt)))),
};
});
@@ -258,7 +253,6 @@ public class Startup
MetricsAPI.CounterAuthenticationFailures,
MetricsAPI.CounterAuthenticationRequests,
MetricsAPI.CounterAuthenticationSuccesses,
MetricsAPI.CounterAccountsCreated,
}, new List<string>
{
MetricsAPI.GaugeAuthorizedConnections,
@@ -279,15 +273,15 @@ public class Startup
if (!isMainServer)
{
services.AddSingleton<IConfigurationService<ServerConfiguration>, MareConfigurationServiceClient<ServerConfiguration>>();
services.AddSingleton<IConfigurationService<MareConfigurationAuthBase>, MareConfigurationServiceClient<MareConfigurationAuthBase>>();
services.AddSingleton<IConfigurationService<MareConfigurationBase>, MareConfigurationServiceClient<MareConfigurationBase>>();
services.AddHostedService(p => (MareConfigurationServiceClient<ServerConfiguration>)p.GetService<IConfigurationService<ServerConfiguration>>());
services.AddHostedService(p => (MareConfigurationServiceClient<MareConfigurationAuthBase>)p.GetService<IConfigurationService<MareConfigurationAuthBase>>());
services.AddHostedService(p => (MareConfigurationServiceClient<MareConfigurationBase>)p.GetService<IConfigurationService<MareConfigurationBase>>());
}
else
{
services.AddSingleton<IConfigurationService<ServerConfiguration>, MareConfigurationServiceServer<ServerConfiguration>>();
services.AddSingleton<IConfigurationService<MareConfigurationAuthBase>, MareConfigurationServiceServer<MareConfigurationAuthBase>>();
services.AddSingleton<IConfigurationService<MareConfigurationBase>, MareConfigurationServiceServer<MareConfigurationBase>>();
}
}
@@ -295,7 +289,7 @@ public class Startup
{
logger.LogInformation("Running Configure");
var config = app.ApplicationServices.GetRequiredService<IConfigurationService<MareConfigurationAuthBase>>();
var config = app.ApplicationServices.GetRequiredService<IConfigurationService<MareConfigurationBase>>();
app.UseIpRateLimiting();

View File

@@ -8,7 +8,7 @@ using MareSynchronos.API.SignalR;
using MareSynchronosServer.Hubs;
using MareSynchronosShared.Data;
using MareSynchronosShared.Services;
using MareSynchronosShared.Utils;
using MareSynchronosShared.Utils.Configuration;
using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;
using StackExchange.Redis;

View File

@@ -11,6 +11,7 @@ using MareSynchronosShared.Services;
using StackExchange.Redis;
using MareSynchronos.API.Data.Enum;
using System.Net.Http.Headers;
using MareSynchronosShared.Utils.Configuration;
namespace MareSynchronosServices.Discord;

View File

@@ -1,7 +1,7 @@
using MareSynchronosServices;
using MareSynchronosShared.Data;
using MareSynchronosShared.Services;
using MareSynchronosShared.Utils;
using MareSynchronosShared.Utils.Configuration;
public class Program
{

View File

@@ -8,7 +8,7 @@ using MareSynchronosShared.Services;
using StackExchange.Redis;
using MessagePack.Resolvers;
using MessagePack;
using Microsoft.AspNetCore.Authorization;
using MareSynchronosShared.Utils.Configuration;
namespace MareSynchronosServices;
@@ -23,7 +23,7 @@ public class Startup
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
var config = app.ApplicationServices.GetRequiredService<IConfigurationService<MareConfigurationAuthBase>>();
var config = app.ApplicationServices.GetRequiredService<IConfigurationService<MareConfigurationBase>>();
var metricServer = new KestrelMetricServer(config.GetValueOrDefault<int>(nameof(MareConfigurationBase.MetricsPort), 4982));
metricServer.Start();
@@ -89,16 +89,16 @@ public class Startup
services.Configure<ServicesConfiguration>(Configuration.GetRequiredSection("MareSynchronos"));
services.Configure<ServerConfiguration>(Configuration.GetRequiredSection("MareSynchronos"));
services.Configure<MareConfigurationAuthBase>(Configuration.GetRequiredSection("MareSynchronos"));
services.Configure<MareConfigurationBase>(Configuration.GetRequiredSection("MareSynchronos"));
services.AddSingleton(Configuration);
services.AddSingleton<ServerTokenGenerator>();
services.AddSingleton<DiscordBotServices>();
services.AddHostedService<DiscordBot>();
services.AddSingleton<IConfigurationService<ServicesConfiguration>, MareConfigurationServiceServer<ServicesConfiguration>>();
services.AddSingleton<IConfigurationService<ServerConfiguration>, MareConfigurationServiceClient<ServerConfiguration>>();
services.AddSingleton<IConfigurationService<MareConfigurationAuthBase>, MareConfigurationServiceClient<MareConfigurationAuthBase>>();
services.AddSingleton<IConfigurationService<MareConfigurationBase>, MareConfigurationServiceClient<MareConfigurationBase>>();
services.AddHostedService(p => (MareConfigurationServiceClient<MareConfigurationAuthBase>)p.GetService<IConfigurationService<MareConfigurationAuthBase>>());
services.AddHostedService(p => (MareConfigurationServiceClient<MareConfigurationBase>)p.GetService<IConfigurationService<MareConfigurationBase>>());
services.AddHostedService(p => (MareConfigurationServiceClient<ServerConfiguration>)p.GetService<IConfigurationService<ServerConfiguration>>());
}
}

View File

@@ -1,4 +1,4 @@
using MareSynchronosShared.Utils;
using MareSynchronosShared.Utils.Configuration;
namespace MareSynchronosShared.Services;

View File

@@ -1,5 +1,4 @@
using MareSynchronosShared.Utils;
using MareSynchronosStaticFilesServer;
using MareSynchronosShared.Utils.Configuration;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
@@ -38,9 +37,9 @@ public class MareStaticFilesServerConfigurationController : MareConfigurationCon
}
}
public class MareAuthBaseConfigurationController : MareConfigurationController<MareConfigurationAuthBase>
public class MareBaseConfigurationController : MareConfigurationController<MareConfigurationBase>
{
public MareAuthBaseConfigurationController(IOptionsMonitor<MareConfigurationAuthBase> config, ILogger<MareAuthBaseConfigurationController> logger) : base(config, logger)
public MareBaseConfigurationController(IOptionsMonitor<MareConfigurationBase> config, ILogger<MareBaseConfigurationController> logger) : base(config, logger)
{
}
}

View File

@@ -1,5 +1,5 @@
using MareSynchronosShared.Utils;
using MareSynchronosStaticFilesServer;
using MareSynchronosShared.Utils.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
@@ -27,8 +27,8 @@ public class MareConfigurationServiceClient<T> : IHostedService, IConfigurationS
{
if (_config.CurrentValue.GetType() == typeof(ServerConfiguration))
return new Uri((_config.CurrentValue as ServerConfiguration).MainServerAddress, $"configuration/MareServerConfiguration/{nameof(MareServerConfigurationController.GetConfigurationEntry)}?key={key}&defaultValue={value}");
if (_config.CurrentValue.GetType() == typeof(MareConfigurationAuthBase))
return new Uri((_config.CurrentValue as MareConfigurationAuthBase).MainServerAddress, $"configuration/MareAuthBaseConfiguration/{nameof(MareAuthBaseConfigurationController.GetConfigurationEntry)}?key={key}&defaultValue={value}");
if (_config.CurrentValue.GetType() == typeof(MareConfigurationBase))
return new Uri((_config.CurrentValue as MareConfigurationBase).MainServerAddress, $"configuration/MareBaseConfiguration/{nameof(MareBaseConfigurationController.GetConfigurationEntry)}?key={key}&defaultValue={value}");
if (_config.CurrentValue.GetType() == typeof(ServicesConfiguration))
return new Uri((_config.CurrentValue as ServicesConfiguration).MainServerAddress, $"configuration/MareServicesConfiguration/{nameof(MareServicesConfigurationController.GetConfigurationEntry)}?key={key}&defaultValue={value}");
if (_config.CurrentValue.GetType() == typeof(StaticFilesServerConfiguration))

View File

@@ -1,4 +1,5 @@
using MareSynchronosShared.Utils;
using MareSynchronosShared.Utils.Configuration;
using Microsoft.Extensions.Options;
using System.Collections;
using System.Text;

View File

@@ -1,33 +1,26 @@
using System.Text;
namespace MareSynchronosShared.Utils;
namespace MareSynchronosShared.Utils.Configuration;
public class MareConfigurationAuthBase : MareConfigurationBase
public class AuthServiceConfiguration : MareConfigurationBase
{
[RemoteConfiguration]
public int FailedAuthForTempBan { get; set; } = 5;
[RemoteConfiguration]
public int TempBanDurationInMinutes { get; set; } = 5;
[RemoteConfiguration]
public int RegisterIpLimit { get; set; } = 3;
[RemoteConfiguration]
public int RegisterIpDurationInMinutes { get; set; } = 10;
[RemoteConfiguration]
public List<string> WhitelistedIps { get; set; } = new();
[RemoteConfiguration]
public string GeoIPDbCityFile { get; set; } = string.Empty;
public bool UseGeoIP { get; set; } = false;
public int FailedAuthForTempBan { get; set; } = 5;
public int TempBanDurationInMinutes { get; set; } = 5;
public List<string> WhitelistedIps { get; set; } = new();
public int RegisterIpLimit { get; set; } = 3;
public int RegisterIpDurationInMinutes { get; set; } = 10;
public override string ToString()
{
StringBuilder sb = new();
sb.AppendLine(base.ToString());
sb.AppendLine($"{nameof(FailedAuthForTempBan)} => {FailedAuthForTempBan}");
sb.AppendLine($"{nameof(TempBanDurationInMinutes)} => {TempBanDurationInMinutes}");
sb.AppendLine($"{nameof(GeoIPDbCityFile)} => {GeoIPDbCityFile}");
sb.AppendLine($"{nameof(UseGeoIP)} => {UseGeoIP}");
sb.AppendLine($"{nameof(RegisterIpLimit)} => {RegisterIpLimit}");
sb.AppendLine($"{nameof(RegisterIpDurationInMinutes)} => {RegisterIpDurationInMinutes}");
sb.AppendLine($"{nameof(Jwt)} => {Jwt}");
sb.AppendLine($"{nameof(WhitelistedIps)} => {string.Join(", ", WhitelistedIps)}");
sb.AppendLine($"{nameof(UseGeoIP)} => {UseGeoIP}");
return sb.ToString();
}
}
}

View File

@@ -1,4 +1,4 @@
namespace MareSynchronosShared.Utils;
namespace MareSynchronosShared.Utils.Configuration;
public class CdnShardConfiguration
{

View File

@@ -1,4 +1,4 @@
namespace MareSynchronosShared.Utils;
namespace MareSynchronosShared.Utils.Configuration;
public interface IMareConfiguration
{

View File

@@ -2,13 +2,14 @@
using System.Text;
using System.Text.Json;
namespace MareSynchronosShared.Utils;
namespace MareSynchronosShared.Utils.Configuration;
public class MareConfigurationBase : IMareConfiguration
{
public int DbContextPoolSize { get; set; } = 100;
public string Jwt { get; set; } = string.Empty;
public Uri MainServerAddress { get; set; }
public int RedisPool { get; set; } = 50;
public int MetricsPort { get; set; }
public string RedisConnectionString { get; set; } = string.Empty;
public string ShardName { get; set; } = string.Empty;

View File

@@ -1,8 +1,8 @@
using System.Text;
namespace MareSynchronosShared.Utils;
namespace MareSynchronosShared.Utils.Configuration;
public class ServerConfiguration : MareConfigurationAuthBase
public class ServerConfiguration : MareConfigurationBase
{
[RemoteConfiguration]
public Uri CdnFullUrl { get; set; } = null;
@@ -24,9 +24,6 @@ public class ServerConfiguration : MareConfigurationAuthBase
[RemoteConfiguration]
public int PurgeUnusedAccountsPeriodInDays { get; set; } = 14;
public string GeoIPDbCityFile { get; set; } = string.Empty;
public int RedisPool { get; set; } = 50;
public override string ToString()
{
@@ -34,14 +31,12 @@ public class ServerConfiguration : MareConfigurationAuthBase
sb.AppendLine(base.ToString());
sb.AppendLine($"{nameof(CdnFullUrl)} => {CdnFullUrl}");
sb.AppendLine($"{nameof(RedisConnectionString)} => {RedisConnectionString}");
sb.AppendLine($"{nameof(RedisPool)} => {RedisPool}");
sb.AppendLine($"{nameof(ExpectedClientVersion)} => {ExpectedClientVersion}");
sb.AppendLine($"{nameof(MaxExistingGroupsByUser)} => {MaxExistingGroupsByUser}");
sb.AppendLine($"{nameof(MaxJoinedGroupsByUser)} => {MaxJoinedGroupsByUser}");
sb.AppendLine($"{nameof(MaxGroupUserCount)} => {MaxGroupUserCount}");
sb.AppendLine($"{nameof(PurgeUnusedAccounts)} => {PurgeUnusedAccounts}");
sb.AppendLine($"{nameof(PurgeUnusedAccountsPeriodInDays)} => {PurgeUnusedAccountsPeriodInDays}");
sb.AppendLine($"{nameof(GeoIPDbCityFile)} => {GeoIPDbCityFile}");
return sb.ToString();
}
}

View File

@@ -1,6 +1,6 @@
using System.Text;
namespace MareSynchronosShared.Utils;
namespace MareSynchronosShared.Utils.Configuration;
public class ServicesConfiguration : MareConfigurationBase
{

View File

@@ -1,14 +1,14 @@
using MareSynchronosShared.Utils;
using System.Text;
namespace MareSynchronosStaticFilesServer;
namespace MareSynchronosShared.Utils.Configuration;
public class StaticFilesServerConfiguration : MareConfigurationBase
{
public bool IsDistributionNode { get; set; } = false;
public bool NotifyMainServerDirectly { get; set; } = false;
public Uri? MainFileServerAddress { get; set; } = null;
public Uri? DistributionFileServerAddress { get; set; } = null;
public Uri MainFileServerAddress { get; set; } = null;
public Uri DistributionFileServerAddress { get; set; } = null;
public bool DistributionFileServerForceHTTP2 { get; set; } = false;
public int ForcedDeletionOfFilesAfterHours { get; set; } = -1;
public double CacheSizeHardLimitInGiB { get; set; } = -1;
@@ -21,7 +21,7 @@ public class StaticFilesServerConfiguration : MareConfigurationBase
public int DownloadQueueClearLimit { get; set; } = 15000;
public int CleanupCheckInMinutes { get; set; } = 15;
public bool UseColdStorage { get; set; } = false;
public string? ColdStorageDirectory { get; set; } = null;
public string ColdStorageDirectory { get; set; } = null;
public double ColdStorageSizeHardLimitInGiB { get; set; } = -1;
public int ColdStorageMinimumFileRetentionPeriodInDays { get; set; } = 30;
public int ColdStorageUnusedFileRetentionPeriodInDays { get; set; } = 30;

View File

@@ -1,4 +1,5 @@
using Microsoft.Extensions.Logging;
using MareSynchronosShared.Utils.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
@@ -9,7 +10,7 @@ namespace MareSynchronosShared.Utils;
public class ServerTokenGenerator
{
private readonly IOptionsMonitor<MareConfigurationAuthBase> _configuration;
private readonly IOptionsMonitor<MareConfigurationBase> _configuration;
private readonly ILogger<ServerTokenGenerator> _logger;
private Dictionary<string, string> _tokenDictionary { get; set; } = new(StringComparer.Ordinal);
@@ -27,7 +28,7 @@ public class ServerTokenGenerator
}
}
public ServerTokenGenerator(IOptionsMonitor<MareConfigurationAuthBase> configuration, ILogger<ServerTokenGenerator> logger)
public ServerTokenGenerator(IOptionsMonitor<MareConfigurationBase> configuration, ILogger<ServerTokenGenerator> logger)
{
_configuration = configuration;
_logger = logger;

View File

@@ -1,5 +1,6 @@
using MareSynchronos.API.Routes;
using MareSynchronosShared.Services;
using MareSynchronosShared.Utils.Configuration;
using MareSynchronosStaticFilesServer.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

View File

@@ -7,13 +7,12 @@ using MareSynchronosShared.Data;
using MareSynchronosShared.Metrics;
using MareSynchronosShared.Models;
using MareSynchronosShared.Services;
using MareSynchronosShared.Utils;
using MareSynchronosShared.Utils.Configuration;
using MareSynchronosStaticFilesServer.Services;
using MareSynchronosStaticFilesServer.Utils;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using System.Collections.Concurrent;
using System.Security.Cryptography;
using System.Security.Policy;

View File

@@ -1,5 +1,5 @@
using MareSynchronosShared.Services;
using MareSynchronosShared.Utils;
using MareSynchronosShared.Utils.Configuration;
namespace MareSynchronosStaticFilesServer;
@@ -13,7 +13,7 @@ public class Program
using (var scope = host.Services.CreateScope())
{
var options = host.Services.GetService<IConfigurationService<StaticFilesServerConfiguration>>();
var optionsServer = host.Services.GetService<IConfigurationService<MareConfigurationAuthBase>>();
var optionsServer = host.Services.GetService<IConfigurationService<MareConfigurationBase>>();
var logger = host.Services.GetService<ILogger<Program>>();
logger.LogInformation("Loaded MareSynchronos Static Files Server Configuration (IsMain: {isMain})", options.IsMain);
logger.LogInformation(options.ToString());

View File

@@ -5,6 +5,7 @@ using System.Collections.Concurrent;
using System.Net.Http.Headers;
using MareSynchronosShared.Utils;
using MareSynchronos.API.Routes;
using MareSynchronosShared.Utils.Configuration;
namespace MareSynchronosStaticFilesServer.Services;

View File

@@ -1,4 +1,5 @@
using MareSynchronosShared.Services;
using MareSynchronosShared.Utils.Configuration;
using MareSynchronosStaticFilesServer.Utils;
using System.Collections.Concurrent;

View File

@@ -4,6 +4,7 @@ using MareSynchronosShared.Data;
using MareSynchronosShared.Metrics;
using MareSynchronosShared.Models;
using MareSynchronosShared.Services;
using MareSynchronosShared.Utils.Configuration;
using MareSynchronosStaticFilesServer.Utils;
using MessagePack.Formatters;
using Microsoft.EntityFrameworkCore;

View File

@@ -1,8 +1,8 @@
using MareSynchronosShared.Metrics;
using MareSynchronosShared.Services;
using MareSynchronosShared.Utils.Configuration;
using MareSynchronosStaticFilesServer.Utils;
using System.Collections.Concurrent;
using System.Linq;
using System.Timers;
namespace MareSynchronosStaticFilesServer.Services;

View File

@@ -1,6 +1,7 @@
using MareSynchronos.API.Routes;
using MareSynchronosShared.Services;
using MareSynchronosShared.Utils;
using MareSynchronosShared.Utils.Configuration;
using System.Net.Http.Headers;
namespace MareSynchronosStaticFilesServer.Services;

View File

@@ -1,6 +1,7 @@
using MareSynchronos.API.Routes;
using MareSynchronosShared.Services;
using MareSynchronosShared.Utils;
using MareSynchronosShared.Utils.Configuration;
using System.Net.Http.Headers;
namespace MareSynchronosStaticFilesServer.Services;

View File

@@ -20,6 +20,7 @@ using StackExchange.Redis.Extensions.System.Text.Json;
using StackExchange.Redis;
using System.Net;
using System.Text;
using MareSynchronosShared.Utils.Configuration;
namespace MareSynchronosStaticFilesServer;
@@ -49,7 +50,7 @@ public class Startup
services.AddLogging();
services.Configure<StaticFilesServerConfiguration>(Configuration.GetRequiredSection("MareSynchronos"));
services.Configure<MareConfigurationAuthBase>(Configuration.GetRequiredSection("MareSynchronos"));
services.Configure<MareConfigurationBase>(Configuration.GetRequiredSection("MareSynchronos"));
services.Configure<KestrelServerOptions>(Configuration.GetSection("Kestrel"));
services.AddSingleton(Configuration);
@@ -93,8 +94,8 @@ public class Startup
services.AddSingleton<FilePreFetchService>();
services.AddHostedService(p => p.GetService<FilePreFetchService>());
services.AddHostedService(m => m.GetService<FileStatisticsService>());
services.AddSingleton<IConfigurationService<MareConfigurationAuthBase>, MareConfigurationServiceClient<MareConfigurationAuthBase>>();
services.AddHostedService(p => (MareConfigurationServiceClient<MareConfigurationAuthBase>)p.GetService<IConfigurationService<MareConfigurationAuthBase>>());
services.AddSingleton<IConfigurationService<MareConfigurationBase>, MareConfigurationServiceClient<MareConfigurationBase>>();
services.AddHostedService(p => (MareConfigurationServiceClient<MareConfigurationBase>)p.GetService<IConfigurationService<MareConfigurationBase>>());
// specific services
if (_isMain)
@@ -212,7 +213,7 @@ public class Startup
// authentication and authorization
services.AddOptions<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme)
.Configure<IConfigurationService<MareConfigurationAuthBase>>((o, s) =>
.Configure<IConfigurationService<MareConfigurationBase>>((o, s) =>
{
o.TokenValidationParameters = new()
{
@@ -220,7 +221,7 @@ public class Startup
ValidateLifetime = false,
ValidateAudience = false,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(s.GetValue<string>(nameof(MareConfigurationAuthBase.Jwt))))
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(s.GetValue<string>(nameof(MareConfigurationBase.Jwt))))
};
});
services.AddAuthentication(o =>
@@ -246,7 +247,7 @@ public class Startup
app.UseRouting();
var config = app.ApplicationServices.GetRequiredService<IConfigurationService<MareConfigurationAuthBase>>();
var config = app.ApplicationServices.GetRequiredService<IConfigurationService<MareConfigurationBase>>();
var metricServer = new KestrelMetricServer(config.GetValueOrDefault<int>(nameof(MareConfigurationBase.MetricsPort), 4981));
metricServer.Start();

View File

@@ -1,6 +1,4 @@
using System.Text.RegularExpressions;
namespace MareSynchronosStaticFilesServer.Utils;
namespace MareSynchronosStaticFilesServer.Utils;
public static partial class FilePathUtil
{

View File

@@ -1,5 +1,6 @@
using MareSynchronosShared.Metrics;
using MareSynchronosShared.Services;
using MareSynchronosShared.Utils.Configuration;
using MareSynchronosStaticFilesServer.Services;
using Microsoft.AspNetCore.Mvc;
using System.Globalization;

View File

@@ -1,5 +1,6 @@
using MareSynchronosShared.Metrics;
using MareSynchronosShared.Services;
using MareSynchronosShared.Utils.Configuration;
using MareSynchronosStaticFilesServer.Services;
namespace MareSynchronosStaticFilesServer.Utils;