mirror of
https://github.com/DuendeSoftware/products
synced 2026-05-24 09:28:24 +00:00
Fixed compilation errors after rebasing XUnit V3 changes
This commit is contained in:
parent
e0034d642a
commit
900af2eeab
21 changed files with 91 additions and 93 deletions
|
|
@ -2,6 +2,8 @@
|
|||
"solution": {
|
||||
"path": "..\\products.slnx",
|
||||
"projects": [
|
||||
"conformance-report\\src\\ConformanceReport\\ConformanceReport.csproj",
|
||||
"conformance-report\\test\\ConformanceReport.Tests\\ConformanceReport.Tests.csproj",
|
||||
"identity-server\\aspire\\AppHosts\\All\\All.csproj",
|
||||
"identity-server\\aspire\\AppHosts\\Dev\\Dev.csproj",
|
||||
"identity-server\\aspire\\ServiceDefaults\\ServiceDefaults.csproj",
|
||||
|
|
@ -40,13 +42,13 @@
|
|||
"identity-server\\clients\\src\\MvcJarUriJwt\\MvcJarUriJwt.csproj",
|
||||
"identity-server\\clients\\src\\Web\\Web.csproj",
|
||||
"identity-server\\clients\\src\\WindowsConsoleSystemBrowser\\WindowsConsoleSystemBrowser.csproj",
|
||||
"identity-server\\hosts\\AspNetIdentity10\\Host.AspNetIdentity10.csproj",
|
||||
"identity-server\\hosts\\EntityFramework10\\Host.EntityFramework10.csproj",
|
||||
"identity-server\\hosts\\Main10\\Host.Main10.csproj",
|
||||
"identity-server\\hosts\\Shared\\Host.Shared.csproj",
|
||||
"identity-server\\hosts\\UI\\AspNetIdentity\\UI.AspNetIdentity.csproj",
|
||||
"identity-server\\hosts\\UI\\EntityFramework\\UI.EntityFramework.csproj",
|
||||
"identity-server\\hosts\\UI\\Main\\UI.Main.csproj",
|
||||
"identity-server\\hosts\\AspNetIdentity10\\Host.AspNetIdentity10.csproj",
|
||||
"identity-server\\hosts\\EntityFramework10\\Host.EntityFramework10.csproj",
|
||||
"identity-server\\hosts\\Main10\\Host.Main10.csproj",
|
||||
"identity-server\\migrations\\AspNetIdentityDb\\AspNetIdentityDb.csproj",
|
||||
"identity-server\\migrations\\IdentityServerDb\\IdentityServerDb.csproj",
|
||||
"identity-server\\src\\AspNetIdentity\\IdentityServer.AspNetIdentity.csproj",
|
||||
|
|
@ -54,6 +56,7 @@
|
|||
"identity-server\\src\\Configuration\\IdentityServer.Configuration.csproj",
|
||||
"identity-server\\src\\EntityFramework.Storage\\IdentityServer.EntityFramework.Storage.csproj",
|
||||
"identity-server\\src\\EntityFramework\\IdentityServer.EntityFramework.csproj",
|
||||
"identity-server\\src\\IdentityServer.ConformanceReport\\IdentityServer.ConformanceReport.csproj",
|
||||
"identity-server\\src\\IdentityServer\\IdentityServer.csproj",
|
||||
"identity-server\\src\\Storage\\IdentityServer.Storage.csproj",
|
||||
"identity-server\\templates\\src\\IdentityServerAspNetIdentity\\IdentityServerAspNetIdentity.csproj",
|
||||
|
|
@ -69,4 +72,4 @@
|
|||
"shared\\Xunit.Playwright\\Xunit.Playwright.csproj"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -279,8 +279,8 @@ public static class IdentityServerConstants
|
|||
|
||||
public const string SamlPathPrefix = "saml";
|
||||
public const string SamlMetadata = SamlPathPrefix + "/metadata";
|
||||
public const string SamlSignin = SamlPathPrefix + "/sso";
|
||||
public const string SamlSigninCallback = SamlSignin + "/callback";
|
||||
public const string SamlSignin = SamlPathPrefix + "/signin";
|
||||
public const string SamlSigninCallback = SamlPathPrefix + "/signin_callback";
|
||||
public const string SamlIdpInitiated = SamlPathPrefix + "/idp-initiated";
|
||||
public const string SamlLogout = SamlPathPrefix + "/slo";
|
||||
public const string SamlLogoutCallback = SamlLogout + "/callback";
|
||||
|
|
|
|||
|
|
@ -8,16 +8,15 @@ using Duende.IdentityModel;
|
|||
using Duende.IdentityServer.Configuration;
|
||||
using Duende.IdentityServer.Saml;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Xunit.Abstractions;
|
||||
using static Duende.IdentityServer.IntegrationTests.Endpoints.Saml.SamlTestHelpers;
|
||||
|
||||
namespace Duende.IdentityServer.IntegrationTests.Endpoints.Saml;
|
||||
|
||||
public class SamlClaimsMappingTests(ITestOutputHelper output)
|
||||
public class SamlClaimsMappingTests
|
||||
{
|
||||
private const string Category = "SAML Claims Mapping";
|
||||
|
||||
private SamlFixture Fixture = new(output);
|
||||
private SamlFixture Fixture = new();
|
||||
private SamlDataBuilder Build => Fixture.Builder;
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
|
|
@ -9,17 +9,16 @@ using System.Security.Cryptography;
|
|||
using System.Security.Cryptography.X509Certificates;
|
||||
using Duende.IdentityModel;
|
||||
using Duende.IdentityServer.Models;
|
||||
using Xunit.Abstractions;
|
||||
using static Duende.IdentityServer.IntegrationTests.Endpoints.Saml.SamlTestHelpers;
|
||||
using SamlStatusCode = Duende.IdentityServer.Saml.Models.SamlStatusCode;
|
||||
|
||||
namespace Duende.IdentityServer.IntegrationTests.Endpoints.Saml;
|
||||
|
||||
public class SamlEncryptionTests(ITestOutputHelper output)
|
||||
public class SamlEncryptionTests
|
||||
{
|
||||
private const string Category = "SAML Encryption";
|
||||
|
||||
private SamlFixture Fixture = new(output);
|
||||
private SamlFixture Fixture = new();
|
||||
private SamlData Data => Fixture.Data;
|
||||
private SamlDataBuilder Build => Fixture.Builder;
|
||||
|
||||
|
|
|
|||
|
|
@ -13,11 +13,10 @@ using Microsoft.AspNetCore.Authentication;
|
|||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Duende.IdentityServer.IntegrationTests.Endpoints.Saml;
|
||||
|
||||
internal class SamlFixture(ITestOutputHelper output) : IAsyncLifetime
|
||||
internal class SamlFixture : IAsyncLifetime
|
||||
{
|
||||
public SamlData Data = new SamlData();
|
||||
public SamlDataBuilder Builder => new SamlDataBuilder(Data);
|
||||
|
|
@ -78,7 +77,7 @@ internal class SamlFixture(ITestOutputHelper output) : IAsyncLifetime
|
|||
|
||||
public T Get<T>() where T : notnull => Host!.Resolve<T>();
|
||||
|
||||
public async Task InitializeAsync()
|
||||
public async ValueTask InitializeAsync()
|
||||
{
|
||||
var selfSignedCertificate = X509CertificateLoader.LoadPkcs12(Convert.FromBase64String(StableSigningCert), null);
|
||||
|
||||
|
|
@ -178,7 +177,7 @@ internal class SamlFixture(ITestOutputHelper output) : IAsyncLifetime
|
|||
NonRedirectingClient = Host!.Server.CreateClient();
|
||||
}
|
||||
|
||||
public async Task DisposeAsync()
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
if (Host != null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,16 +8,15 @@ using System.Web;
|
|||
using Duende.IdentityModel;
|
||||
using Duende.IdentityServer.Internal.Saml;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Xunit.Abstractions;
|
||||
using static Duende.IdentityServer.IntegrationTests.Endpoints.Saml.SamlTestHelpers;
|
||||
|
||||
namespace Duende.IdentityServer.IntegrationTests.Endpoints.Saml;
|
||||
|
||||
public class SamlIdpInitiatedEndpointTests(ITestOutputHelper output)
|
||||
public class SamlIdpInitiatedEndpointTests
|
||||
{
|
||||
private const string Category = "SAML IdP-Initiated Endpoint";
|
||||
|
||||
private SamlFixture Fixture = new(output);
|
||||
private SamlFixture Fixture = new();
|
||||
|
||||
private SamlData Data => Fixture.Data;
|
||||
|
||||
|
|
@ -293,7 +292,7 @@ public class SamlIdpInitiatedEndpointTests(ITestOutputHelper output)
|
|||
var samlResponse = await ExtractSamlSuccessFromPostAsync(callbackResult, CancellationToken.None);
|
||||
|
||||
samlResponse.ShouldNotBeNull();
|
||||
samlResponse.Issuer.ShouldBe(Fixture.Host!.Uri());
|
||||
samlResponse.Issuer.ShouldBe(Fixture.Host!.Url());
|
||||
samlResponse.Destination.ShouldBe(Data.AcsUrl.ToString());
|
||||
samlResponse.StatusCode.ShouldBe("urn:oasis:names:tc:SAML:2.0:status:Success");
|
||||
|
||||
|
|
|
|||
|
|
@ -4,15 +4,14 @@
|
|||
using System.Net;
|
||||
using System.Xml.Linq;
|
||||
using Duende.IdentityServer.Internal.Saml;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Duende.IdentityServer.IntegrationTests.Endpoints.Saml;
|
||||
|
||||
public class SamlMetadataEndpointTests(ITestOutputHelper output)
|
||||
public class SamlMetadataEndpointTests
|
||||
{
|
||||
private const string Category = "SAML Metadata Endpoint";
|
||||
|
||||
private SamlFixture Fixture = new(output);
|
||||
private SamlFixture Fixture = new();
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", Category)]
|
||||
|
|
@ -30,7 +29,7 @@ public class SamlMetadataEndpointTests(ITestOutputHelper output)
|
|||
var content = await result.Content.ReadAsStringAsync(CancellationToken.None);
|
||||
|
||||
var settings = new VerifySettings();
|
||||
var hostUri = Fixture.Host!.Uri();
|
||||
var hostUri = Fixture.Host!.Url();
|
||||
settings.AddScrubber(sb =>
|
||||
{
|
||||
sb.Replace(hostUri, "https://localhost");
|
||||
|
|
@ -189,7 +188,7 @@ public class SamlMetadataEndpointTests(ITestOutputHelper output)
|
|||
public async Task metadata_urls_should_handle_edge_case_route_configurations()
|
||||
{
|
||||
// Verify that default configuration produces clean URLs
|
||||
// Edge cases (empty routes, whitespace, etc.) are comprehensively tested
|
||||
// Edge cases (empty routes, whitespace, etc.) are comprehensively tested
|
||||
// at the unit level in BuildServiceUrl unit tests
|
||||
await Fixture.InitializeAsync();
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><EntityDescriptor entityID="http://localhost" validUntil="2000-01-09T03:04:05Z" xmlns="urn:oasis:names:tc:SAML:2.0:metadata"><IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"><KeyDescriptor use="signing"><KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"><X509Data><X509Certificate>MIICojCCAYqgAwIBAgIIIjGqKDo3ME4wDQYJKoZIhvcNAQELBQAwETEPMA0GA1UEAxMGZm9vYmFyMB4XDTI1MTExMDE0MTEyNloXDTMwMTExMDE0MTEyNlowETEPMA0GA1UEAxMGZm9vYmFyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu/fcM55jlB810lyxGpgk0Zhw83Liqz80l3zLLAZgJ/IUdBx9VFD28BeO37eByHDXxBIQdHFYXQj+lv2g3KFRxVzfZhiFUrb1UydJYFZ951sQUEsP4T/Fpbyb95HNrwG2NwE5/fk1MXr9no4ydsQTZA6EWOfbxn6o2YQs/8QdDykhCzpZcWYbk5AKS/G6nYLpwuW4UsyMQ6ur9ZQXtwDS/hGyP3RjK8pjqkckbQG9ZapI+hWezIJkGmkXcuIx+FpZbdjjwu/SIcNNrBIXLbrbWyxoWt4y2jWfDixanBAubBLtx6tCg69trJ3M5gZkFZBR3CVqs78fYZUThKBTS20afQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCxB08tE2bDWpF5mR14kQvRUA/2hZKeC6CYYGEwOu1hbh5m3rVj4T9GPgOh+s6tX+rCb0IoV1uD9iSeTd3XaJ/1sSFkgVD/PaA6NRgzKVeDXLl9rZGAnOmp/Es3Pz35FbPxZKTe8UDyFHySbioLaLvtODhzX7SeGP3BcRpp8rZLvggMYiqo3w39+qZcgZPIBP4yRSulBYb3r9qagQ/n//gp7SmenCQmjA5L7pTn7QggFQsSQmB6dyNS54cUk0niUsTihT9oqpMnXmsXonXf5cv3tnaydreiB4aPea+OjjY3oy8hvHUH6FuQQX7t3RllZlPGJQFZe61rYMVmRRjlHWTA</X509Certificate></X509Data></KeyInfo></KeyDescriptor><NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</NameIDFormat><NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</NameIDFormat><NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat><NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</NameIDFormat><SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://localhost/saml/signin" /><SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://localhost/saml/signin" /><SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://localhost/saml/logout" /><SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://localhost/saml/logout" /></IDPSSODescriptor></EntityDescriptor>
|
||||
|
|
@ -10,17 +10,16 @@ using Duende.IdentityModel;
|
|||
using Duende.IdentityServer.Internal.Saml.SingleSignin;
|
||||
using Duende.IdentityServer.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Xunit.Abstractions;
|
||||
using static Duende.IdentityServer.IntegrationTests.Endpoints.Saml.SamlTestHelpers;
|
||||
using StateId = Duende.IdentityServer.Internal.Saml.SingleSignin.Models.StateId;
|
||||
|
||||
namespace Duende.IdentityServer.IntegrationTests.Endpoints.Saml;
|
||||
|
||||
public class SamlSigninCallbackEndpointTests(ITestOutputHelper output)
|
||||
public class SamlSigninCallbackEndpointTests
|
||||
{
|
||||
private const string Category = "SAML Signin Callback Endpoint";
|
||||
|
||||
private SamlFixture Fixture = new(output);
|
||||
private SamlFixture Fixture = new();
|
||||
|
||||
private SamlData Data => Fixture.Data;
|
||||
|
||||
|
|
|
|||
|
|
@ -15,19 +15,18 @@ using Duende.IdentityServer.Internal.Saml;
|
|||
using Duende.IdentityServer.Models;
|
||||
using Duende.IdentityServer.Saml.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Xunit.Abstractions;
|
||||
using static Duende.IdentityServer.IntegrationTests.Endpoints.Saml.SamlTestHelpers;
|
||||
using SamlStatusCode = Duende.IdentityServer.Saml.Models.SamlStatusCode;
|
||||
|
||||
namespace Duende.IdentityServer.IntegrationTests.Endpoints.Saml;
|
||||
|
||||
public class SamlSigninEndpointTests(ITestOutputHelper output)
|
||||
public class SamlSigninEndpointTests
|
||||
{
|
||||
private const string Category = "SAML Signin Endpoint";
|
||||
|
||||
private readonly CancellationToken _ct = CancellationToken.None;
|
||||
|
||||
private SamlFixture Fixture = new(output);
|
||||
private SamlFixture Fixture = new();
|
||||
|
||||
private SamlData Data => Fixture.Data;
|
||||
|
||||
|
|
@ -106,7 +105,7 @@ public class SamlSigninEndpointTests(ITestOutputHelper output)
|
|||
errorResponse.StatusCode.ShouldBe("urn:oasis:names:tc:SAML:2.0:status:VersionMismatch");
|
||||
errorResponse.StatusMessage.ShouldNotBeNull();
|
||||
errorResponse.StatusMessage.ShouldContain("Only Version 2.0 is supported");
|
||||
errorResponse.Issuer.ShouldBe(Fixture.Host!.Uri());
|
||||
errorResponse.Issuer.ShouldBe(Fixture.Host!.Url());
|
||||
errorResponse.InResponseTo.ShouldNotBeNullOrEmpty();
|
||||
errorResponse.AssertionConsumerServiceUrl.ShouldBe(Data.AcsUrl.ToString());
|
||||
}
|
||||
|
|
@ -223,7 +222,7 @@ public class SamlSigninEndpointTests(ITestOutputHelper output)
|
|||
errorResponse.StatusCode.ShouldBe("urn:oasis:names:tc:SAML:2.0:status:VersionMismatch");
|
||||
errorResponse.StatusMessage.ShouldNotBeNull();
|
||||
errorResponse.StatusMessage.ShouldContain("Only Version 2.0 is supported");
|
||||
errorResponse.Issuer.ShouldBe(Fixture.Host!.Uri());
|
||||
errorResponse.Issuer.ShouldBe(Fixture.Host!.Url());
|
||||
errorResponse.InResponseTo.ShouldNotBeNullOrEmpty();
|
||||
errorResponse.AssertionConsumerServiceUrl.ShouldBe(Data.AcsUrl.ToString());
|
||||
}
|
||||
|
|
@ -316,7 +315,7 @@ public class SamlSigninEndpointTests(ITestOutputHelper output)
|
|||
|
||||
errorResponse.StatusCode.ShouldBe("urn:oasis:names:tc:SAML:2.0:status:Requester");
|
||||
errorResponse.StatusMessage.ShouldBe("Request IssueInstant is in the future");
|
||||
errorResponse.Issuer.ShouldBe(Fixture.Host!.Uri());
|
||||
errorResponse.Issuer.ShouldBe(Fixture.Host!.Url());
|
||||
errorResponse.InResponseTo.ShouldNotBeNullOrEmpty();
|
||||
errorResponse.AssertionConsumerServiceUrl.ShouldBe(Data.AcsUrl.ToString());
|
||||
}
|
||||
|
|
@ -498,7 +497,7 @@ public class SamlSigninEndpointTests(ITestOutputHelper output)
|
|||
await Fixture.InitializeAsync();
|
||||
|
||||
// Use the correct Destination attribute
|
||||
var correctDestination = new Uri(Fixture.Host!.Uri() + "/saml/signin");
|
||||
var correctDestination = new Uri(Fixture.Host!.Url() + "/saml/signin");
|
||||
var authnRequestXml = Build.AuthNRequestXml(destination: correctDestination);
|
||||
|
||||
var urlEncoded = await EncodeRequest(authnRequestXml);
|
||||
|
|
@ -540,7 +539,7 @@ public class SamlSigninEndpointTests(ITestOutputHelper output)
|
|||
successResponse.ResponseId.ShouldNotBeNullOrEmpty();
|
||||
successResponse.Destination.ShouldBe(Fixture.Data.AcsUrl.ToString());
|
||||
successResponse.IssueInstant.ShouldBe(Data.FakeTimeProvider.GetUtcNow().ToString("yyyy-MM-ddTHH:mm:ss.fffZ"));
|
||||
successResponse.Issuer.ShouldBe(Fixture.Host?.Uri());
|
||||
successResponse.Issuer.ShouldBe(Fixture.Host?.Url());
|
||||
successResponse.InResponseTo.ShouldBe(Data.RequestId);
|
||||
|
||||
successResponse.StatusCode.ShouldBe(SamlStatusCode.Success.Value);
|
||||
|
|
@ -550,7 +549,7 @@ public class SamlSigninEndpointTests(ITestOutputHelper output)
|
|||
assertion.Id.ShouldNotBeNullOrEmpty();
|
||||
assertion.Version.ShouldBe("2.0");
|
||||
assertion.IssueInstant.ShouldBe(Data.FakeTimeProvider.GetUtcNow().ToString("yyyy-MM-ddTHH:mm:ss.fffZ"));
|
||||
assertion.Issuer.ShouldBe(Fixture.Host?.Uri());
|
||||
assertion.Issuer.ShouldBe(Fixture.Host?.Url());
|
||||
|
||||
var subject = assertion.Subject;
|
||||
subject.ShouldNotBeNull();
|
||||
|
|
@ -789,7 +788,7 @@ public class SamlSigninEndpointTests(ITestOutputHelper output)
|
|||
|
||||
errorResponse.StatusCode.ShouldBe("urn:oasis:names:tc:SAML:2.0:status:NoPassive");
|
||||
errorResponse.StatusMessage.ShouldBe("The user is not currently logged in and passive login was requested.");
|
||||
errorResponse.Issuer.ShouldBe(Fixture.Host!.Uri());
|
||||
errorResponse.Issuer.ShouldBe(Fixture.Host!.Url());
|
||||
errorResponse.InResponseTo.ShouldNotBeNullOrEmpty();
|
||||
errorResponse.AssertionConsumerServiceUrl.ShouldBe(Data.AcsUrl.ToString());
|
||||
}
|
||||
|
|
@ -814,7 +813,7 @@ public class SamlSigninEndpointTests(ITestOutputHelper output)
|
|||
|
||||
errorResponse.StatusCode.ShouldBe("urn:oasis:names:tc:SAML:2.0:status:NoPassive");
|
||||
errorResponse.StatusMessage.ShouldBe("The user is not currently logged in");
|
||||
errorResponse.Issuer.ShouldBe(Fixture.Host!.Uri());
|
||||
errorResponse.Issuer.ShouldBe(Fixture.Host!.Url());
|
||||
errorResponse.InResponseTo.ShouldNotBeNullOrEmpty();
|
||||
errorResponse.AssertionConsumerServiceUrl.ShouldBe(Data.AcsUrl.ToString());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,15 +5,14 @@ using System.Net;
|
|||
using Duende.IdentityServer.Models;
|
||||
using Duende.IdentityServer.Saml.Models;
|
||||
using Duende.IdentityServer.Stores;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Duende.IdentityServer.IntegrationTests.Endpoints.Saml;
|
||||
|
||||
public class SamlSingleLogoutCallbackEndpointTests(ITestOutputHelper output)
|
||||
public class SamlSingleLogoutCallbackEndpointTests
|
||||
{
|
||||
private const string Category = "SAML single logout callback endpoint";
|
||||
|
||||
private SamlFixture Fixture = new(output);
|
||||
private SamlFixture Fixture = new();
|
||||
|
||||
private SamlData Data => Fixture.Data;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,16 +10,15 @@ using Duende.IdentityModel;
|
|||
using Duende.IdentityServer.Models;
|
||||
using Duende.IdentityServer.Saml.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Xunit.Abstractions;
|
||||
using static Duende.IdentityServer.IntegrationTests.Endpoints.Saml.SamlTestHelpers;
|
||||
|
||||
namespace Duende.IdentityServer.IntegrationTests.Endpoints.Saml;
|
||||
|
||||
public class SamlSingleLogoutEndpointTests(ITestOutputHelper output)
|
||||
public class SamlSingleLogoutEndpointTests
|
||||
{
|
||||
private const string Category = "SAML single logout endpoint";
|
||||
|
||||
private SamlFixture Fixture = new(output);
|
||||
private SamlFixture Fixture = new();
|
||||
|
||||
private SamlData Data => Fixture.Data;
|
||||
|
||||
|
|
@ -151,7 +150,7 @@ public class SamlSingleLogoutEndpointTests(ITestOutputHelper output)
|
|||
await Fixture.Client.GetAsync("/__signin", CancellationToken.None);
|
||||
|
||||
var logoutRequestXml = Build.LogoutRequestXml(
|
||||
destination: new Uri($"{Fixture.Host!.Uri()}/saml/logout"),
|
||||
destination: new Uri($"{Fixture.Host!.Url()}/saml/logout"),
|
||||
sessionIndex: "session123");
|
||||
var urlEncoded = await EncodeAndSignRequest(logoutRequestXml, sp, CancellationToken.None);
|
||||
|
||||
|
|
@ -176,7 +175,7 @@ public class SamlSingleLogoutEndpointTests(ITestOutputHelper output)
|
|||
await Fixture.InitializeAsync();
|
||||
|
||||
var logoutRequestXml = Build.LogoutRequestXml(
|
||||
destination: new Uri($"{Fixture.Host!.Uri()}/saml/logout"),
|
||||
destination: new Uri($"{Fixture.Host!.Url()}/saml/logout"),
|
||||
version: "1.0");
|
||||
var urlEncoded = await EncodeAndSignRequest(logoutRequestXml, sp, CancellationToken.None);
|
||||
|
||||
|
|
@ -200,7 +199,7 @@ public class SamlSingleLogoutEndpointTests(ITestOutputHelper output)
|
|||
|
||||
var futureTime = Data.Now.AddMinutes(10);
|
||||
var logoutRequestXml = Build.LogoutRequestXml(
|
||||
destination: new Uri($"{Fixture.Host!.Uri()}/saml/logout"),
|
||||
destination: new Uri($"{Fixture.Host!.Url()}/saml/logout"),
|
||||
issueInstant: futureTime,
|
||||
sessionIndex: "session123");
|
||||
var urlEncoded = await EncodeAndSignRequest(logoutRequestXml, sp, CancellationToken.None);
|
||||
|
|
@ -226,7 +225,7 @@ public class SamlSingleLogoutEndpointTests(ITestOutputHelper output)
|
|||
|
||||
var oldTime = Data.Now.AddMinutes(-10);
|
||||
var logoutRequestXml = Build.LogoutRequestXml(
|
||||
destination: new Uri($"{Fixture.Host!.Uri()}/saml/logout"),
|
||||
destination: new Uri($"{Fixture.Host!.Url()}/saml/logout"),
|
||||
issueInstant: oldTime,
|
||||
sessionIndex: "session123");
|
||||
var urlEncoded = await EncodeAndSignRequest(logoutRequestXml, sp, CancellationToken.None);
|
||||
|
|
@ -261,7 +260,7 @@ public class SamlSingleLogoutEndpointTests(ITestOutputHelper output)
|
|||
// Assert
|
||||
var logoutResponse = await ExtractSamlLogoutResponseFromPostAsync(result, CancellationToken.None);
|
||||
logoutResponse.StatusCode.ShouldBe(SamlStatusCode.Requester.Value);
|
||||
logoutResponse.StatusMessage.ShouldBe($"Invalid destination. Expected '{Fixture.Host!.Uri()}/saml/logout'");
|
||||
logoutResponse.StatusMessage.ShouldBe($"Invalid destination. Expected '{Fixture.Host!.Url()}/saml/logout'");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
@ -275,7 +274,7 @@ public class SamlSingleLogoutEndpointTests(ITestOutputHelper output)
|
|||
await Fixture.InitializeAsync();
|
||||
|
||||
var logoutRequestXml = Build.LogoutRequestXml(
|
||||
destination: new Uri($"{Fixture.Host!.Uri()}/saml/logout"),
|
||||
destination: new Uri($"{Fixture.Host!.Url()}/saml/logout"),
|
||||
sessionIndex: "session123");
|
||||
var urlEncoded = await EncodeRequest(logoutRequestXml, CancellationToken.None);
|
||||
|
||||
|
|
@ -301,7 +300,7 @@ public class SamlSingleLogoutEndpointTests(ITestOutputHelper output)
|
|||
|
||||
// Create a logout request without a signature
|
||||
var logoutRequestXml = Build.LogoutRequestXml(
|
||||
destination: new Uri($"{Fixture.Host!.Uri()}/saml/logout"),
|
||||
destination: new Uri($"{Fixture.Host!.Url()}/saml/logout"),
|
||||
sessionIndex: "session123");
|
||||
var urlEncoded = await EncodeRequest(logoutRequestXml, CancellationToken.None);
|
||||
|
||||
|
|
@ -352,7 +351,7 @@ public class SamlSingleLogoutEndpointTests(ITestOutputHelper output)
|
|||
// Don't sign in a user - no authenticated session
|
||||
|
||||
var logoutRequestXml = Build.LogoutRequestXml(
|
||||
destination: new Uri($"{Fixture.Host!.Uri()}/saml/logout"),
|
||||
destination: new Uri($"{Fixture.Host!.Url()}/saml/logout"),
|
||||
sessionIndex: "session123");
|
||||
var urlEncoded = await EncodeAndSignRequest(logoutRequestXml, sp, CancellationToken.None);
|
||||
|
||||
|
|
@ -385,7 +384,7 @@ public class SamlSingleLogoutEndpointTests(ITestOutputHelper output)
|
|||
// Use a different service provider than what was established
|
||||
var logoutRequestXml = Build.LogoutRequestXml(
|
||||
issuer: anotherSp.EntityId, // Use a different SP so session will not be found
|
||||
destination: new Uri($"{Fixture.Host!.Uri()}/saml/logout"));
|
||||
destination: new Uri($"{Fixture.Host!.Url()}/saml/logout"));
|
||||
var urlEncoded = await EncodeAndSignRequest(logoutRequestXml, sp, CancellationToken.None);
|
||||
|
||||
// Act
|
||||
|
|
@ -413,7 +412,7 @@ public class SamlSingleLogoutEndpointTests(ITestOutputHelper output)
|
|||
|
||||
// Use a different session index than what was established
|
||||
var logoutRequestXml = Build.LogoutRequestXml(
|
||||
destination: new Uri($"{Fixture.Host!.Uri()}/saml/logout"),
|
||||
destination: new Uri($"{Fixture.Host!.Url()}/saml/logout"),
|
||||
sessionIndex: "wrong-session-index");
|
||||
var urlEncoded = await EncodeAndSignRequest(logoutRequestXml, sp, CancellationToken.None);
|
||||
|
||||
|
|
@ -444,7 +443,7 @@ public class SamlSingleLogoutEndpointTests(ITestOutputHelper output)
|
|||
var sessionIndex = await PerformSigninAndExtractSessionIndex(sp);
|
||||
|
||||
var logoutRequestXml = Build.LogoutRequestXml(
|
||||
destination: new Uri($"{Fixture.Host!.Uri()}/saml/logout"),
|
||||
destination: new Uri($"{Fixture.Host!.Url()}/saml/logout"),
|
||||
sessionIndex: sessionIndex);
|
||||
var urlEncoded = await EncodeAndSignRequest(logoutRequestXml, sp, CancellationToken.None);
|
||||
|
||||
|
|
@ -482,7 +481,7 @@ public class SamlSingleLogoutEndpointTests(ITestOutputHelper output)
|
|||
var sessionIndex = await PerformSigninAndExtractSessionIndex(sp);
|
||||
|
||||
var logoutRequestXml = Build.LogoutRequestXml(
|
||||
destination: new Uri($"{Fixture.Host!.Uri()}/saml/logout"),
|
||||
destination: new Uri($"{Fixture.Host!.Url()}/saml/logout"),
|
||||
sessionIndex: sessionIndex);
|
||||
var urlEncoded = await EncodeAndSignRequest(logoutRequestXml, sp, CancellationToken.None);
|
||||
|
||||
|
|
@ -495,7 +494,7 @@ public class SamlSingleLogoutEndpointTests(ITestOutputHelper output)
|
|||
// Verify user can no longer access protected resource and is redirected to login
|
||||
var finalProtectedResourceResult = await Fixture.Client.GetAsync("__protected-resource", CancellationToken.None);
|
||||
finalProtectedResourceResult.StatusCode.ShouldBe(HttpStatusCode.OK);
|
||||
finalProtectedResourceResult.RequestMessage?.RequestUri?.AbsoluteUri.ShouldStartWith($"{Fixture.Host!.Uri()}{Fixture.LoginUrl.ToString()}");
|
||||
finalProtectedResourceResult.RequestMessage?.RequestUri?.AbsoluteUri.ShouldStartWith($"{Fixture.Host!.Url()}{Fixture.LoginUrl.ToString()}");
|
||||
}
|
||||
|
||||
private static async Task<string> EncodeAndSignRequest(
|
||||
|
|
|
|||
|
|
@ -17,12 +17,11 @@ using Microsoft.AspNetCore.Http;
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Time.Testing;
|
||||
using Sustainsys.Saml2.AspNetCore2;
|
||||
using Xunit.Abstractions;
|
||||
using IdentityProvider = Sustainsys.Saml2.IdentityProvider;
|
||||
|
||||
namespace Duende.IdentityServer.IntegrationTests.Endpoints.Saml;
|
||||
|
||||
internal class SustainSysSamlTestFixture(ITestOutputHelper output) : IAsyncLifetime
|
||||
internal class SustainSysSamlTestFixture : IAsyncLifetime
|
||||
{
|
||||
public TestFramework.GenericHost? Host = null!;
|
||||
public HttpClient? BrowserClient = null!;
|
||||
|
|
@ -30,7 +29,7 @@ internal class SustainSysSamlTestFixture(ITestOutputHelper output) : IAsyncLifet
|
|||
|
||||
public Uri IdentityProviderLoginUri => new Uri(new Uri(_samlFixture.Host!.Url()), _samlFixture.LoginUrl);
|
||||
|
||||
private readonly SamlFixture _samlFixture = new(output);
|
||||
private readonly SamlFixture _samlFixture = new();
|
||||
private bool _shouldGenerateSigningCertificate;
|
||||
private bool _shouldRequireEncryptedAssertions;
|
||||
|
||||
|
|
@ -49,7 +48,7 @@ internal class SustainSysSamlTestFixture(ITestOutputHelper output) : IAsyncLifet
|
|||
|
||||
public void RequireEncryptedAssertions() => _shouldRequireEncryptedAssertions = true;
|
||||
|
||||
public async Task InitializeAsync()
|
||||
public async ValueTask InitializeAsync()
|
||||
{
|
||||
// need to use current time because the SustainSys library does not rely on an abstraction such
|
||||
// as TimeProvider and times need to be current
|
||||
|
|
@ -152,7 +151,7 @@ internal class SustainSysSamlTestFixture(ITestOutputHelper output) : IAsyncLifet
|
|||
BrowserClient = Host.HttpClient;
|
||||
}
|
||||
|
||||
public async Task DisposeAsync()
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
if (Host != null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,16 +3,15 @@
|
|||
|
||||
using System.Net;
|
||||
using System.Web;
|
||||
using Xunit.Abstractions;
|
||||
using static Duende.IdentityServer.IntegrationTests.Endpoints.Saml.SamlTestHelpers;
|
||||
|
||||
namespace Duende.IdentityServer.IntegrationTests.Endpoints.Saml;
|
||||
|
||||
public class SustainSysSigninTests(ITestOutputHelper output)
|
||||
public class SustainSysSigninTests
|
||||
{
|
||||
private const string Category = "SustainSys SAML signin";
|
||||
|
||||
private SustainSysSamlTestFixture Fixture = new(output);
|
||||
private SustainSysSamlTestFixture Fixture = new();
|
||||
|
||||
[Fact]
|
||||
[Trait("Category", Category)]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright (c) Duende Software. All rights reserved.
|
||||
// See LICENSE in the project root for license information.
|
||||
|
||||
using Duende.IdentityServer.Saml;
|
||||
using Duende.IdentityServer.Saml.Models;
|
||||
|
||||
namespace Duende.IdentityServer.IntegrationTests.Endpoints.Saml;
|
||||
|
||||
/// <summary>
|
||||
/// Test implementation of ISamlClaimsMapper that returns a single custom attribute.
|
||||
/// Used by both unit and integration tests.
|
||||
/// </summary>
|
||||
public class TestSamlClaimsMapper : ISamlClaimsMapper
|
||||
{
|
||||
public Task<IEnumerable<SamlAttribute>> MapClaimsAsync(SamlClaimsMappingContext mappingContext)
|
||||
{
|
||||
var attributes = new List<SamlAttribute>
|
||||
{
|
||||
new()
|
||||
{
|
||||
Name = "CUSTOM_MAPPED",
|
||||
NameFormat = "urn:oasis:names:tc:SAML:2.0:attrname-format:basic",
|
||||
Values = new List<string> { "custom_value" }
|
||||
}
|
||||
};
|
||||
return Task.FromResult<IEnumerable<SamlAttribute>>(attributes);
|
||||
}
|
||||
}
|
||||
|
|
@ -18,6 +18,7 @@
|
|||
<PackageReference Include="Sustainsys.Saml2.AspNetCore2" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" />
|
||||
<PackageReference Include="AngleSharp" />
|
||||
<PackageReference Include="Verify.XunitV3" />
|
||||
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
// Copyright (c) Duende Software. All rights reserved.
|
||||
// See LICENSE in the project root for license information.
|
||||
|
||||
#nullable enable
|
||||
using Duende.IdentityServer.Models;
|
||||
using Duende.IdentityServer.Stores;
|
||||
|
||||
namespace UnitTests.Saml;
|
||||
|
||||
/// <summary>
|
||||
/// Simple in-memory implementation of ISamlServiceProviderStore for unit testing.
|
||||
/// </summary>
|
||||
internal class InMemoryTestServiceProviderStore : ISamlServiceProviderStore
|
||||
{
|
||||
private readonly List<SamlServiceProvider> _providers = [];
|
||||
|
||||
public InMemoryTestServiceProviderStore() { }
|
||||
public InMemoryTestServiceProviderStore(params SamlServiceProvider[] providers) => _providers.AddRange(providers);
|
||||
|
||||
public void Add(SamlServiceProvider provider) => _providers.Add(provider);
|
||||
|
||||
public Task<SamlServiceProvider?> FindByEntityIdAsync(string entityId)
|
||||
=> Task.FromResult(_providers.FirstOrDefault(p => p.EntityId == entityId));
|
||||
}
|
||||
|
|
@ -12,7 +12,6 @@ using Duende.IdentityServer.Internal.Saml.SingleLogout;
|
|||
using Duende.IdentityServer.Models;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Time.Testing;
|
||||
using UnitTests.Common;
|
||||
|
||||
namespace UnitTests.Saml;
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ using Duende.IdentityServer.Services;
|
|||
using Duende.IdentityServer.Stores;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Time.Testing;
|
||||
using UnitTests.Common;
|
||||
|
||||
namespace UnitTests.Saml;
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ using Duende.IdentityServer.Internal.Saml.Infrastructure;
|
|||
using Duende.IdentityServer.Internal.Saml.SingleLogout;
|
||||
using Duende.IdentityServer.Models;
|
||||
using Duende.IdentityServer.Saml.Models;
|
||||
using Duende.IdentityServer.Stores;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Time.Testing;
|
||||
using UnitTests.Common;
|
||||
|
|
@ -30,7 +31,7 @@ public class SamlLogoutNotificationServiceTests
|
|||
|
||||
return new SamlLogoutNotificationService(
|
||||
_issuerNameService,
|
||||
new InMemoryTestServiceProviderStore(samlServiceProviders),
|
||||
new InMemorySamlServiceProviderStore(samlServiceProviders),
|
||||
frontChannelLogoutRequestBuilder,
|
||||
NullLogger<SamlLogoutNotificationService>.Instance);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -165,6 +165,7 @@
|
|||
<Project Path="identity-server/src/Configuration/IdentityServer.Configuration.csproj" />
|
||||
<Project Path="identity-server/src/EntityFramework.Storage/IdentityServer.EntityFramework.Storage.csproj" />
|
||||
<Project Path="identity-server/src/EntityFramework/IdentityServer.EntityFramework.csproj" />
|
||||
<Project Path="identity-server/src/IdentityServer.ConformanceReport/IdentityServer.ConformanceReport.csproj" />
|
||||
<Project Path="identity-server/src/IdentityServer/IdentityServer.csproj" />
|
||||
<Project Path="identity-server/src/Storage/IdentityServer.Storage.csproj" />
|
||||
</Folder>
|
||||
|
|
|
|||
Loading…
Reference in a new issue