about to test remote access

This commit is contained in:
Paul Schneider 2026-04-19 16:02:50 +01:00
commit d21337d4a6
8 changed files with 86 additions and 81 deletions

1
.gitignore vendored
View file

@ -44,3 +44,4 @@ yavsc-pre
*.env *.env
generated/ generated/
*.lscache

View file

@ -13,5 +13,8 @@
"fr" "fr"
], ],
"cSpell.reportUnknownWords": true, "cSpell.reportUnknownWords": true,
"cSpell.language": "fr,fr-FR,en,en-GB" "cSpell.language": "fr,fr-FR,en,en-GB",
"chat.tools.terminal.autoApprove": {
"dotnet test": true
}
} }

View file

@ -1,16 +1,18 @@
using System.Diagnostics;
using System.Globalization; using System.Globalization;
using System.IdentityModel.Tokens.Jwt;
using System.Reflection;
using Google.Apis.Util.Store; using Google.Apis.Util.Store;
using IdentityModel;
using IdentityServer8; using IdentityServer8;
using Microsoft.Extensions.DependencyInjection; using IdentityServer8.EntityFramework.Entities;
using IdentityServer8.EntityFramework.Services;
using IdentityServer8.EntityFramework.Stores;
using IdentityServer8.Stores; using IdentityServer8.Stores;
using IdentityServer8.EntityFramework; using IdentityServer8.Validation;
using IdentityServer8.Extensions;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.AspNetCore.Localization; using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Razor; using Microsoft.AspNetCore.Mvc.Razor;
@ -22,28 +24,12 @@ using Microsoft.Net.Http.Headers;
using Newtonsoft.Json; using Newtonsoft.Json;
using Yavsc.Helpers; using Yavsc.Helpers;
using Yavsc.Interface; using Yavsc.Interface;
using Yavsc.Interfaces;
using Yavsc.Models; using Yavsc.Models;
using Yavsc.Server.Helpers;
using Yavsc.Services; using Yavsc.Services;
using Yavsc.Settings; using Yavsc.Settings;
using Yavsc.ViewModels.Auth; using Yavsc.ViewModels.Auth;
using Yavsc.Server.Helpers;
using System.Security.Cryptography;
using Microsoft.IdentityModel.Tokens;
using Microsoft.IdentityModel.Protocols.Configuration;
using IdentityModel;
using Yavsc.Interfaces;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Npgsql;
using System.Reflection;
using IdentityServer8.EntityFramework.DbContexts;
using IdentityServer8.EntityFramework.Mappers;
using System.IdentityModel.Tokens.Jwt;
using IdentityServer8.EntityFramework.Stores;
using IdentityServer8.EntityFramework.Services;
using IdentityServer8.EntityFramework.Interfaces;
using Microsoft.AspNetCore.Authentication.Cookies;
using IdentityServer8.Validation;
using IdentityServer8.EntityFramework.Entities;
namespace Yavsc.Extensions; namespace Yavsc.Extensions;
@ -177,7 +163,7 @@ public static class HostingExtensions
}); });
} }
return services.AddIdentity<ApplicationUser, IdentityRole>( var identityBuilder = services.AddIdentity<ApplicationUser, IdentityRole>(
options => options =>
{ {
options.SignIn.RequireConfirmedAccount = builder.Environment.IsEnvironment( options.SignIn.RequireConfirmedAccount = builder.Environment.IsEnvironment(
@ -187,6 +173,10 @@ public static class HostingExtensions
} }
) )
.AddEntityFrameworkStores<ApplicationDbContext>(); .AddEntityFrameworkStores<ApplicationDbContext>();
services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, UserClaimsPrincipalFactory<ApplicationUser, IdentityRole>>();
return identityBuilder;
} }
private static void AddYavscPolicies(IServiceCollection services) private static void AddYavscPolicies(IServiceCollection services)
@ -280,7 +270,7 @@ public static class HostingExtensions
}); });
} }
private static IIdentityServerBuilder AddIdentityServer(WebApplicationBuilder builder) public static IIdentityServerBuilder AddIdentityServer(WebApplicationBuilder builder)
{ {
builder.Services.Configure<IdentityOptions>(options => builder.Services.Configure<IdentityOptions>(options =>
{ {

View file

@ -50,7 +50,7 @@ namespace Yavsc.Helpers
} }
public static string GetSender(this ApplicationUser user) public static string GetSender(this ApplicationUser user)
{ {
return user.UserName+" ["+user.Id+"@"+Config.Authority+"]"; return user.UserName+" ["+user.Id+"@"+Config.AuthorityDomain+"]";
} }
public static HairCutQueryEvent CreateEvent(this HairMultiCutQuery query, public static HairCutQueryEvent CreateEvent(this HairMultiCutQuery query,
IStringLocalizer SR, BrusherProfile bpr) IStringLocalizer SR, BrusherProfile bpr)

View file

@ -9,8 +9,24 @@ namespace Yavsc;
public static class Config public static class Config
{ {
/// <summary>
/// Authority URL for IdentityServer, used for authentication and authorization.
/// </summary>
public static string Authority { get; set; } public static string Authority { get; set; }
public static string AuthorityDomain
{
get
{
if (Uri.TryCreate(Authority, UriKind.Absolute, out var uri))
{
return uri.GetLeftPart(UriPartial.Authority);
}
throw new InvalidOperationException("Invalid Authority URL");
}
}
public static IConfigurationRoot? GoogleWebClientConfiguration { get; set; } public static IConfigurationRoot? GoogleWebClientConfiguration { get; set; }
public static GoogleServiceAccount? GServiceAccount { get; set; } public static GoogleServiceAccount? GServiceAccount { get; set; }

View file

@ -1,9 +1,8 @@
using isnd.tests; using System.Security.Cryptography.X509Certificates;
using System.Net.Security;
using isnd.tests;
using Xunit.Abstractions; using Xunit.Abstractions;
using IdentityModel.Client; using IdentityModel.Client;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;
namespace yavscTests namespace yavscTests
{ {
@ -20,64 +19,55 @@ namespace yavscTests
[Fact] [Fact]
public async Task ObtainServiceToken() public async Task ObtainServiceToken()
{ {
var serverUrl = _serverFixture.Addresses.FirstOrDefault( var serverUrl = _serverFixture.Addresses.FirstOrDefault(u => u.StartsWith("https:"));
u => u.StartsWith("https:") if (string.IsNullOrEmpty(serverUrl))
); throw new InvalidOperationException("No HTTPS server address found");
String authority = _serverFixture.SiteSettings.Authority; HttpClient client = NewHttpClient();
HttpClient client = NewHttpClient(); var disco = await client.GetDiscoveryDocumentAsync(serverUrl);
var disco = await client.GetDiscoveryDocumentAsync(authority); if (disco.IsError) throw new Exception(disco.Error);
if (disco.IsError) throw new Exception(disco.Error);
var response = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest var response = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
{ {
Address = disco.TokenEndpoint, Address = disco.TokenEndpoint,
ClientId = _serverFixture.TestClientId, ClientId = _serverFixture.TestClientId,
ClientSecret = _serverFixture.TestClientSecret, ClientSecret = _serverFixture.TestClientSecret,
Scope = "test", Scope = "test",
GrantType = "client_credentials" GrantType = "client_credentials"
}); });
/*"mvc"; if (response.IsError) throw new Exception(response.Error);
options.ClientSecret = "49C1A7E1-0C79-4A89-A3D6-A37998FB86B0";*/ }
if (response.IsError) throw new Exception(response.Error);
}
private static HttpClient NewHttpClient() private static HttpClient NewHttpClient()
{ {
return new HttpClient(new BypassSslValidationHandler()); return new HttpClient(new BypassSslValidationHandler());
} }
[Fact] [Fact]
public async Task ObtainResourceOwnerPasswordToken() public async Task ObtainResourceOwnerPasswordToken()
{ {
var serverUrl = _serverFixture.Addresses.FirstOrDefault( var serverUrl = _serverFixture.Addresses.FirstOrDefault(u => u.StartsWith("https:"));
u => u.StartsWith("https:") if (string.IsNullOrEmpty(serverUrl))
); throw new InvalidOperationException("No HTTPS server address found");
String authority = _serverFixture.SiteSettings.Authority;
var client = NewHttpClient(); var client = NewHttpClient();
var disco = await client.GetDiscoveryDocumentAsync(authority); var disco = await client.GetDiscoveryDocumentAsync(serverUrl);
if (disco.IsError) throw new Exception(disco.Error); if (disco.IsError) throw new Exception(disco.Error);
var response = await client.RequestPasswordTokenAsync(new PasswordTokenRequest var response = await client.RequestPasswordTokenAsync(new PasswordTokenRequest
{ {
Address = disco.TokenEndpoint, Address = disco.TokenEndpoint,
ClientId = _serverFixture.TestClientId,
ClientId = _serverFixture.TestClientId, ClientSecret = _serverFixture.TestClientSecret,
ClientSecret = _serverFixture.TestClientSecret, UserName = _serverFixture.TestingUserName,
Password = _serverFixture.TestingUserPassword,
UserName = _serverFixture.TestingUserName, Scope = "test",
Password = _serverFixture.TestingUserPassword, Parameters =
Scope = "test",
Parameters =
{ {
{ "acr_values", "tenant:custom_account_store1 foo bar quux" } { "acr_values", "tenant:custom_account_store1 foo bar quux" }
} }
}); });
if (response.IsError) throw new Exception(response.Error); if (response.IsError) throw new Exception(response.Error);

View file

@ -1,20 +1,24 @@
using IdentityServer8.EntityFramework.Entities;
using IdentityServer8.Models;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Hosting.Server.Features;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Yavsc;
using Yavsc.Models;
using Yavsc.Extensions;
using Microsoft.EntityFrameworkCore;
using Serilog; using Serilog;
using Serilog.Events; using Serilog.Events;
using Serilog.Sinks.SystemConsole.Themes; using Serilog.Sinks.SystemConsole.Themes;
using IdentityServer8.EntityFramework.Entities; using System.Net;
using IdentityServer8.Models; using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using Yavsc;
using Yavsc.Extensions;
using Yavsc.Models;
using Client = IdentityServer8.EntityFramework.Entities.Client; using Client = IdentityServer8.EntityFramework.Entities.Client;
namespace isnd.tests namespace isnd.tests
@ -88,6 +92,7 @@ namespace isnd.tests
["Smtp:SenderName"] = "Yavsc Test", ["Smtp:SenderName"] = "Yavsc Test",
["Smtp:SenderEmail"] = "test@example.com" ["Smtp:SenderEmail"] = "test@example.com"
}); });
Configuration = builder.Configuration; Configuration = builder.Configuration;
this.app = builder.ConfigureWebAppServices(); this.app = builder.ConfigureWebAppServices();

View file

@ -1,6 +1,6 @@
{ {
"Site": { "Site": {
"Authority": "localhost", "Authority": "https://localhost",
"Title": "Yavsc dev", "Title": "Yavsc dev",
"Slogan": "Yavsc : WIP.", "Slogan": "Yavsc : WIP.",
"Banner": "/images/yavsc.png", "Banner": "/images/yavsc.png",