From b55627a10a51b255043086fd63c49a8855f38803 Mon Sep 17 00:00:00 2001 From: Alexa <53471801+Alexa-RR@users.noreply.github.com> Date: Tue, 30 Jun 2026 15:47:28 +0300 Subject: [PATCH] Migrate auth to Open.IdentityServer --- Dockerfile | 8 +++---- Dockerfile.service | 2 +- DorkNet.Contracts/DorkNet.Contracts.csproj | 2 +- DorkNet.Gateway/DorkNet.Gateway.csproj | 2 +- DorkNet.Models/DorkNet.Models.csproj | 2 +- .../DorkNet.Server.Tests.csproj | 4 ++-- DorkNet.Server.Tests/DorkNetServerFactory.cs | 19 ++--------------- .../GameClientEndpointContractTests.cs | 4 ++-- DorkNet.Server.Tests/GameClientSession.cs | 10 +++++---- .../VersionCheckControllerTests.cs | 8 +++---- .../Auth/IdentityServerIntegration.cs | 16 +++++--------- .../Controllers/Admin/AdminController.cs | 8 ------- .../Controllers/Auth/AuthController.cs | 2 +- DorkNet.Server/DorkNet.Server.csproj | 21 ++++++++++--------- .../admin-ui/src/pages/IdentityServer.tsx | 4 ---- .../DorkNet.ServiceDefaults.csproj | 2 +- .../DorkNet.Services.Commerce.csproj | 2 +- .../DorkNet.Services.Content.csproj | 2 +- .../DorkNet.Services.Identity.csproj | 2 +- .../DorkNet.Services.Moderation.csproj | 2 +- .../DorkNet.Services.Notify.csproj | 2 +- .../DorkNet.Services.Platform.csproj | 2 +- .../DorkNet.Services.Rooms.csproj | 2 +- .../DorkNet.Services.Social.csproj | 2 +- .../DorkNet.Services.Web.csproj | 2 +- README.md | 2 +- .../DorkNet.ApiRouteCoverage.csproj | 2 +- tools/DorkNet.ApiRouteCoverage/Program.cs | 4 ++-- .../DorkNet.EndpointContract.csproj | 2 +- tools/DorkNet.EndpointContract/Program.cs | 4 ++-- 30 files changed, 58 insertions(+), 88 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8c50073..176bbcc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,14 @@ # DorkNet.Server container image — Coolify deploy target. # ──────────────────────────────────────────────────────────────────── # Multi-stage: SDK image builds + publishes, runtime image is the -# slimmer aspnet:9.0 with only the published output. +# slimmer aspnet:10.0 with only the published output. # # Build context: repo root (so Tools/ and DorkNet.Models/ are visible # to ProjectReference + dotnet restore). The .dockerignore at the # repo root keeps the bin/, obj/, and other dev junk out of the # context. -ARG DOTNET_VERSION=9.0 +ARG DOTNET_VERSION=10.0 ARG NODE_VERSION=20 # ── admin SPA build stage ────────────────────────────────────────── @@ -76,13 +76,13 @@ WORKDIR /app # curl + wget for healthcheck probes — Coolify v4 defaults to wget for # its own probe regardless of what the image's HEALTHCHECK uses, so -# both have to be present. The aspnet:9.0 base image strips both by +# both have to be present. The aspnet:10.0 base image strips both by # default to keep the surface area small. RUN apt-get update \ && apt-get install -y --no-install-recommends curl wget \ && rm -rf /var/lib/apt/lists/* -# Run as a non-root user — aspnet:9.0 ships with the `app` UID 1654. +# Run as a non-root user — aspnet:10.0 ships with the `app` UID 1654. # Coolify mounts persistent volumes with write permission for this UID. USER app diff --git a/Dockerfile.service b/Dockerfile.service index a1151d4..ecff836 100644 --- a/Dockerfile.service +++ b/Dockerfile.service @@ -1,4 +1,4 @@ -ARG DOTNET_VERSION=9.0 +ARG DOTNET_VERSION=10.0 ARG NODE_VERSION=20 FROM node:${NODE_VERSION}-alpine AS admin-ui diff --git a/DorkNet.Contracts/DorkNet.Contracts.csproj b/DorkNet.Contracts/DorkNet.Contracts.csproj index 9623deb..93f5ab4 100644 --- a/DorkNet.Contracts/DorkNet.Contracts.csproj +++ b/DorkNet.Contracts/DorkNet.Contracts.csproj @@ -1,7 +1,7 @@ - net9.0 + net10.0 enable enable diff --git a/DorkNet.Gateway/DorkNet.Gateway.csproj b/DorkNet.Gateway/DorkNet.Gateway.csproj index 358445e..342cbdc 100644 --- a/DorkNet.Gateway/DorkNet.Gateway.csproj +++ b/DorkNet.Gateway/DorkNet.Gateway.csproj @@ -1,7 +1,7 @@ - net9.0 + net10.0 enable enable diff --git a/DorkNet.Models/DorkNet.Models.csproj b/DorkNet.Models/DorkNet.Models.csproj index 125f4c9..b760144 100644 --- a/DorkNet.Models/DorkNet.Models.csproj +++ b/DorkNet.Models/DorkNet.Models.csproj @@ -1,7 +1,7 @@  - net9.0 + net10.0 enable enable diff --git a/DorkNet.Server.Tests/DorkNet.Server.Tests.csproj b/DorkNet.Server.Tests/DorkNet.Server.Tests.csproj index 7cd69a8..27cfff7 100644 --- a/DorkNet.Server.Tests/DorkNet.Server.Tests.csproj +++ b/DorkNet.Server.Tests/DorkNet.Server.Tests.csproj @@ -1,7 +1,7 @@ - net9.0 + net10.0 enable enable false @@ -9,7 +9,7 @@ - + diff --git a/DorkNet.Server.Tests/DorkNetServerFactory.cs b/DorkNet.Server.Tests/DorkNetServerFactory.cs index 58f73cf..8351584 100644 --- a/DorkNet.Server.Tests/DorkNetServerFactory.cs +++ b/DorkNet.Server.Tests/DorkNetServerFactory.cs @@ -1,11 +1,8 @@ -using System.Text; -using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.HostFiltering; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.IdentityModel.Tokens; namespace DorkNet.Server.Tests; @@ -38,8 +35,8 @@ public sealed class DorkNetServerFactory : WebApplicationFactory ["S3:Endpoint"] = "", ["S3:AccessKey"] = "", ["S3:SecretKey"] = "", - ["DorkNet:DefaultClientVersion"] = "december_2020_12_18", - ["DorkNet:SupportedVersions:0"] = "december_2020_12_18", + ["DorkNet:DefaultClientVersion"] = "march_2023_03_21", + ["DorkNet:SupportedVersions:0"] = "march_2023_03_21", }); }); builder.ConfigureServices(services => @@ -56,18 +53,6 @@ public sealed class DorkNetServerFactory : WebApplicationFactory options.AllowEmptyHosts = true; options.IncludeFailureMessage = true; }); - services.PostConfigure(JwtBearerDefaults.AuthenticationScheme, options => - { - options.TokenValidationParameters = new TokenValidationParameters - { - ValidateIssuerSigningKey = true, - IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(JwtSecret)), - ValidateIssuer = true, - ValidIssuer = "https://api.rec.net/", - ValidateAudience = false, - ClockSkew = TimeSpan.Zero, - }; - }); }); } diff --git a/DorkNet.Server.Tests/GameClientEndpointContractTests.cs b/DorkNet.Server.Tests/GameClientEndpointContractTests.cs index 2d7b860..c08eba1 100644 --- a/DorkNet.Server.Tests/GameClientEndpointContractTests.cs +++ b/DorkNet.Server.Tests/GameClientEndpointContractTests.cs @@ -61,8 +61,8 @@ public sealed class GameClientEndpointContractTests : ToHttpMethod(route.Method), new Uri($"http://{host}{path}")); request.Headers.Accept.ParseAdd("application/json"); - request.Headers.UserAgent.ParseAdd("RecRoom/2020.12.18"); - request.Headers.TryAddWithoutValidation("X-DorkNet-Version", "december_2020_12_18"); + request.Headers.UserAgent.ParseAdd("RecRoom/2023.03.21"); + request.Headers.TryAddWithoutValidation("X-DorkNet-Version", "march_2023_03_21"); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", session.AccessToken); if (NeedsRequestBody(request.Method)) diff --git a/DorkNet.Server.Tests/GameClientSession.cs b/DorkNet.Server.Tests/GameClientSession.cs index cfc519e..a62dcf3 100644 --- a/DorkNet.Server.Tests/GameClientSession.cs +++ b/DorkNet.Server.Tests/GameClientSession.cs @@ -21,11 +21,13 @@ public static class GameClientSessionFactory HttpMethod.Post, new Uri($"http://auth.{apexDomain}/connect/token")); tokenRequest.Headers.Accept.ParseAdd("application/json"); - tokenRequest.Headers.UserAgent.ParseAdd("RecRoom/2020.12.18"); - tokenRequest.Headers.TryAddWithoutValidation("X-DorkNet-Version", "december_2020_12_18"); + tokenRequest.Headers.UserAgent.ParseAdd("RecRoom/2023.03.21"); + tokenRequest.Headers.TryAddWithoutValidation("X-DorkNet-Version", "march_2023_03_21"); tokenRequest.Content = new FormUrlEncodedContent(new Dictionary { ["grant_type"] = "password", + ["client_id"] = "recroom", + ["client_secret"] = "VxZ53kgbbEaRoZAeMe00MagtgD12GLL2", ["username"] = "EndpointContract", ["device_id"] = deviceId, ["platform"] = "0", @@ -49,8 +51,8 @@ public static class GameClientSessionFactory HttpMethod.Get, new Uri($"http://auth.{apexDomain}/connect/userinfo")); userInfoRequest.Headers.Accept.ParseAdd("application/json"); - userInfoRequest.Headers.UserAgent.ParseAdd("RecRoom/2020.12.18"); - userInfoRequest.Headers.TryAddWithoutValidation("X-DorkNet-Version", "december_2020_12_18"); + userInfoRequest.Headers.UserAgent.ParseAdd("RecRoom/2023.03.21"); + userInfoRequest.Headers.TryAddWithoutValidation("X-DorkNet-Version", "march_2023_03_21"); userInfoRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); using var userInfoResponse = await client.SendAsync(userInfoRequest); diff --git a/DorkNet.Server.Tests/VersionCheckControllerTests.cs b/DorkNet.Server.Tests/VersionCheckControllerTests.cs index e63e2e0..ab43d2d 100644 --- a/DorkNet.Server.Tests/VersionCheckControllerTests.cs +++ b/DorkNet.Server.Tests/VersionCheckControllerTests.cs @@ -11,11 +11,11 @@ namespace DorkNet.Server.Tests; public sealed class VersionCheckControllerTests { [Fact] - public void December_2020_build_is_valid_with_minimal_service_config() + public void March_2023_build_is_valid_with_minimal_service_config() { var controller = CreateController(); - var result = Assert.IsType(controller.Check("20201210", "0")); + var result = Assert.IsType(controller.Check("20230321", "0")); Assert.Equal(0, ReadVersionStatus(result.Value)); } @@ -37,9 +37,9 @@ public sealed class VersionCheckControllerTests [new Late2020VersionPlugin()], new HashSet(StringComparer.OrdinalIgnoreCase) { - "december_2020_12_18", + "march_2023_03_21", }, - "december_2020_12_18"); + "march_2023_03_21"); return new VersionCheckController( config, diff --git a/DorkNet.Server/Auth/IdentityServerIntegration.cs b/DorkNet.Server/Auth/IdentityServerIntegration.cs index 1c3a1d4..a7ec4ca 100644 --- a/DorkNet.Server/Auth/IdentityServerIntegration.cs +++ b/DorkNet.Server/Auth/IdentityServerIntegration.cs @@ -3,10 +3,10 @@ using System.Security.Claims; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Text; -using Duende.IdentityServer; -using Duende.IdentityServer.Models; -using Duende.IdentityServer.Services; -using Duende.IdentityServer.Validation; +using Open.IdentityServer; +using Open.IdentityServer.Models; +using Open.IdentityServer.Services; +using Open.IdentityServer.Validation; using Microsoft.AspNetCore.Http.Features; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Primitives; @@ -206,12 +206,6 @@ public static class RecRoomIdentityServerRegistration .AddIdentityServer(options => { options.IssuerUri = domain.AuthIssuer.TrimEnd('/'); - options.KeyManagement.Enabled = false; - var licenseKey = - Environment.GetEnvironmentVariable("DUENDE_IDENTITYSERVER_LICENSE_KEY") - ?? config["IdentityServer:LicenseKey"]; - if (!string.IsNullOrWhiteSpace(licenseKey)) - options.LicenseKey = licenseKey; }) .AddInMemoryIdentityResources(RecRoomIdentityServerConfig.IdentityResources) .AddInMemoryApiScopes(RecRoomIdentityServerConfig.ApiScopes) @@ -256,7 +250,7 @@ internal static class RecRoomIdentityServerConfig ClientName = "Rec Room game client", RequireClientSecret = true, ClientSecrets = { new Secret(ClientSecret.Sha256()) }, - AllowedGrantTypes = { GrantType.ResourceOwnerPassword, GrantType.RefreshToken, CachedLoginGrantType }, + AllowedGrantTypes = { GrantType.ResourceOwnerPassword, "refresh_token", CachedLoginGrantType }, AllowedScopes = RecRoomScopes(), AllowOfflineAccess = true, AccessTokenLifetime = 60 * 60 * 12, diff --git a/DorkNet.Server/Controllers/Admin/AdminController.cs b/DorkNet.Server/Controllers/Admin/AdminController.cs index b407a37..b532c74 100644 --- a/DorkNet.Server/Controllers/Admin/AdminController.cs +++ b/DorkNet.Server/Controllers/Admin/AdminController.cs @@ -40,7 +40,6 @@ public class AdminController( SignupCodeService signupCodes, IObjectStorage storage, DomainConfig domain, - IConfiguration config, IdentityServerSigningKeyProvider signingKeys, ILogger adminLogger) : ControllerBase { @@ -1490,9 +1489,6 @@ public class AdminController( var certPath = signingKeys.CertificatePath; var fullCertPath = Path.GetFullPath(certPath); var certificateExists = signingKeys.LoadedFromBase64 || System.IO.File.Exists(fullCertPath); - var licenseConfigured = - !string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("DUENDE_IDENTITYSERVER_LICENSE_KEY")) - || !string.IsNullOrWhiteSpace(config["IdentityServer:LicenseKey"]); return Ok(new { @@ -1524,10 +1520,6 @@ public class AdminController( NotAfterUtc = signingKeys.Certificate.NotAfter.ToUniversalTime(), Algorithm = SecurityAlgorithms.RsaSha256, }, - License = new - { - Configured = licenseConfigured, - }, PersistedGrants = new { Store = "in-memory", diff --git a/DorkNet.Server/Controllers/Auth/AuthController.cs b/DorkNet.Server/Controllers/Auth/AuthController.cs index 78bd5b3..37853df 100644 --- a/DorkNet.Server/Controllers/Auth/AuthController.cs +++ b/DorkNet.Server/Controllers/Auth/AuthController.cs @@ -6,7 +6,7 @@ using DorkNet.Server.Services; namespace DorkNet.Server.Controllers.Auth; /// -/// auth.rec.net game-specific auth helpers. OAuth/OIDC endpoints are owned by Duende IdentityServer. +/// auth.rec.net game-specific auth helpers. OAuth/OIDC endpoints are owned by IdentityServer. /// [ApiController] public class AuthController( diff --git a/DorkNet.Server/DorkNet.Server.csproj b/DorkNet.Server/DorkNet.Server.csproj index a009e22..04e5434 100644 --- a/DorkNet.Server/DorkNet.Server.csproj +++ b/DorkNet.Server/DorkNet.Server.csproj @@ -1,21 +1,22 @@ - net9.0 + net10.0 enable enable - - - - + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - - + + - - + + - +