diff --git a/src/Abc.IdentityServer.EidasLight/Abc.DuendeIdentityServer.EidasLight.csproj b/src/Abc.IdentityServer.EidasLight/Abc.DuendeIdentityServer.EidasLight.csproj
index be95dc0..d40e321 100644
--- a/src/Abc.IdentityServer.EidasLight/Abc.DuendeIdentityServer.EidasLight.csproj
+++ b/src/Abc.IdentityServer.EidasLight/Abc.DuendeIdentityServer.EidasLight.csproj
@@ -6,7 +6,7 @@
- net6.0
+ net6.0;net8.0
true
true
$(DefineConstants);DUENDE
@@ -17,10 +17,21 @@
$(PackageTags);duende
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
diff --git a/src/Abc.IdentityServer.EidasLight/Abc.IdentityServer4.EidasLight.csproj b/src/Abc.IdentityServer.EidasLight/Abc.IdentityServer4.EidasLight.csproj
index 20f0a78..c05ab43 100644
--- a/src/Abc.IdentityServer.EidasLight/Abc.IdentityServer4.EidasLight.csproj
+++ b/src/Abc.IdentityServer.EidasLight/Abc.IdentityServer4.EidasLight.csproj
@@ -10,6 +10,7 @@
true
true
10.0
+ $(DefineConstants);IDS4
diff --git a/src/Abc.IdentityServer.EidasLight/Endpoints/Results/ErrorPageResult.cs b/src/Abc.IdentityServer.EidasLight/Endpoints/Results/ErrorPageResult.cs
index e136789..030f93d 100644
--- a/src/Abc.IdentityServer.EidasLight/Endpoints/Results/ErrorPageResult.cs
+++ b/src/Abc.IdentityServer.EidasLight/Endpoints/Results/ErrorPageResult.cs
@@ -19,7 +19,8 @@ internal class ErrorPageResult : IEndpointResult
{
private IMessageStore _errorMessageStore;
private IdentityServerOptions _options;
- private ISystemClock _clock;
+ private IServerUrls _urls;
+ private IClock _clock;
public ErrorPageResult(string error, string errorDescription)
{
@@ -27,11 +28,12 @@ public ErrorPageResult(string error, string errorDescription)
ErrorDescription = errorDescription;
}
- internal ErrorPageResult(string error, string errorDescription, IdentityServerOptions options, ISystemClock clock, IMessageStore errorMessageStore)
+ internal ErrorPageResult(string error, string errorDescription, IdentityServerOptions options, IClock clock, IServerUrls urls, IMessageStore errorMessageStore)
: this(error, errorDescription)
{
_options = options;
_clock = clock;
+ _urls = urls;
_errorMessageStore = errorMessageStore;
}
@@ -56,14 +58,15 @@ public async Task ExecuteAsync(HttpContext context)
var redirectUrl = _options.UserInteraction.ErrorUrl;
redirectUrl = redirectUrl.AddQueryString(_options.UserInteraction.ErrorIdParameter, id);
- context.Response.RedirectToAbsoluteUrl(redirectUrl);
+ context.Response.Redirect(_urls.GetAbsoluteUrl(redirectUrl));
}
private void Init(HttpContext context)
{
_errorMessageStore ??= context.RequestServices.GetRequiredService>();
_options ??= context.RequestServices.GetRequiredService();
- _clock ??= context.RequestServices.GetRequiredService();
+ _urls ??= context.RequestServices.GetRequiredService();
+ _clock ??= context.RequestServices.GetRequiredService();
}
}
}
\ No newline at end of file
diff --git a/src/Abc.IdentityServer.EidasLight/Endpoints/Results/LoginPageResult.cs b/src/Abc.IdentityServer.EidasLight/Endpoints/Results/LoginPageResult.cs
index 7214c55..4a818e3 100644
--- a/src/Abc.IdentityServer.EidasLight/Endpoints/Results/LoginPageResult.cs
+++ b/src/Abc.IdentityServer.EidasLight/Endpoints/Results/LoginPageResult.cs
@@ -10,7 +10,6 @@
using Abc.IdentityModel.Protocols.EidasLight;
using Abc.IdentityServer.EidasLight.Validation;
using Abc.IdentityServer.Extensions;
-using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using System;
@@ -29,7 +28,8 @@ public class LoginPageResult : IEndpointResult
private IdentityServerOptions _options;
private IAuthorizationParametersMessageStore _authorizationParametersMessageStore;
private EidasLightProtocolSerializer _protocolSerializer;
- private ISystemClock _clock;
+ private IServerUrls _urls;
+ private IClock _clock;
///
/// Initializes a new instance of the class.
@@ -41,11 +41,12 @@ public LoginPageResult(ValidatedEidasLightRequest request)
_request = request ?? throw new ArgumentNullException(nameof(request));
}
- internal LoginPageResult(ValidatedEidasLightRequest request, IdentityServerOptions options, ISystemClock clock, EidasLightProtocolSerializer protocolSerializer, IAuthorizationParametersMessageStore authorizationParametersMessageStore)
+ internal LoginPageResult(ValidatedEidasLightRequest request, IdentityServerOptions options, IClock clock, IServerUrls urls, EidasLightProtocolSerializer protocolSerializer, IAuthorizationParametersMessageStore authorizationParametersMessageStore)
: this(request)
{
_options = options;
_clock = clock;
+ _urls = urls;
_protocolSerializer = protocolSerializer;
_authorizationParametersMessageStore = authorizationParametersMessageStore;
}
@@ -55,7 +56,7 @@ public async Task ExecuteAsync(HttpContext context)
{
Init(context);
- var returnUrl = context.GetIdentityServerBasePath().EnsureTrailingSlash() + Constants.ProtocolRoutePaths.EidasLightProxyCallback;
+ var returnUrl = _urls.BasePath.EnsureTrailingSlash() + Constants.ProtocolRoutePaths.EidasLightProxyCallback;
var data = _protocolSerializer.WriteMessageDictionary(_request.Message);
var msg = new Message>(data, _clock.UtcNow.UtcDateTime);
@@ -67,11 +68,11 @@ public async Task ExecuteAsync(HttpContext context)
{
// this converts the relative redirect path to an absolute one if we're
// redirecting to a different server
- returnUrl = context.GetIdentityServerHost().EnsureTrailingSlash() + returnUrl.RemoveLeadingSlash();
+ returnUrl = _urls.Origin.EnsureTrailingSlash() + returnUrl.RemoveLeadingSlash();
}
var url = loginUrl.AddQueryString(_options.UserInteraction.LoginReturnUrlParameter, returnUrl);
- context.Response.RedirectToAbsoluteUrl(url);
+ context.Response.Redirect(_urls.GetAbsoluteUrl(url));
}
private void Init(HttpContext context)
@@ -79,7 +80,8 @@ private void Init(HttpContext context)
_options ??= context.RequestServices.GetRequiredService();
_protocolSerializer ??= context.RequestServices.GetRequiredService();
_authorizationParametersMessageStore ??= context.RequestServices.GetRequiredService();
- _clock ??= context.RequestServices.GetRequiredService();
+ _urls ??= context.RequestServices.GetRequiredService();
+ _clock ??= context.RequestServices.GetRequiredService();
}
}
}
\ No newline at end of file
diff --git a/src/Abc.IdentityServer.EidasLight/Extensions/ServerUrlExtensions.cs b/src/Abc.IdentityServer.EidasLight/Extensions/ServerUrlExtensions.cs
new file mode 100644
index 0000000..d6aa6a0
--- /dev/null
+++ b/src/Abc.IdentityServer.EidasLight/Extensions/ServerUrlExtensions.cs
@@ -0,0 +1,65 @@
+#if IDS4
+
+using Abc.IdentityServer.Extensions;
+using Microsoft.AspNetCore.Http;
+using System;
+using System.Linq;
+
+namespace IdentityServer4.Extensions;
+
+///
+/// Extension methods for .
+///
+public static class ServerUrlExtensions
+{
+ ///
+ /// Returns the origin in unicode, and not in punycode (if we have a unicode hostname).
+ ///
+ public static string GetUnicodeOrigin(this IServerUrls urls)
+ {
+ var split = urls.Origin.Split(new[] { "://" }, StringSplitOptions.RemoveEmptyEntries);
+ var scheme = split.First();
+ var host = HostString.FromUriComponent(split.Last()).Value;
+
+ return scheme + "://" + host;
+ }
+
+ ///
+ /// Returns an absolute URL for the URL or path.
+ ///
+ public static string GetAbsoluteUrl(this IServerUrls urls, string urlOrPath)
+ {
+ if (urlOrPath.IsLocalUrl())
+ {
+ if (urlOrPath.StartsWith("~/"))
+ {
+ urlOrPath = urlOrPath.Substring(1);
+ }
+
+ urlOrPath = urls.BaseUrl.EnsureTrailingSlash() + urlOrPath.RemoveLeadingSlash();
+ }
+
+ return urlOrPath;
+ }
+
+ ///
+ /// Returns the URL into the server based on the relative path. The path parameter can start with "~/" or "/".
+ ///
+ public static string GetIdentityServerRelativeUrl(this IServerUrls urls, string path)
+ {
+ if (!path.IsLocalUrl())
+ {
+ return null;
+ }
+
+ if (path.StartsWith("~/"))
+ {
+ path = path.Substring(1);
+ }
+
+ path = urls.BaseUrl.EnsureTrailingSlash() + path.RemoveLeadingSlash();
+ return path;
+ }
+}
+
+#endif
\ No newline at end of file
diff --git a/src/Abc.IdentityServer.EidasLight/Extensions/StringExtensions.cs b/src/Abc.IdentityServer.EidasLight/Extensions/StringExtensions.cs
index afd2753..b7808b6 100644
--- a/src/Abc.IdentityServer.EidasLight/Extensions/StringExtensions.cs
+++ b/src/Abc.IdentityServer.EidasLight/Extensions/StringExtensions.cs
@@ -155,5 +155,16 @@ public static string RemoveLeadingSlash(this string url)
return url;
}
+
+ [DebuggerStepThrough]
+ public static string RemoveTrailingSlash(this string url)
+ {
+ if (url != null && url.EndsWith('/'))
+ {
+ url = url.Substring(0, url.Length - 1);
+ }
+
+ return url;
+ }
}
}
\ No newline at end of file
diff --git a/src/Abc.IdentityServer.EidasLight/GlobalUsings.cs b/src/Abc.IdentityServer.EidasLight/GlobalUsings.cs
index 86832c4..75a6b80 100644
--- a/src/Abc.IdentityServer.EidasLight/GlobalUsings.cs
+++ b/src/Abc.IdentityServer.EidasLight/GlobalUsings.cs
@@ -23,3 +23,9 @@
global using Ids = IdentityServer4;
global using StatusCodeResult = IdentityServer4.Endpoints.Results.StatusCodeResult;
#endif
+
+#if NET8_0_OR_GREATER
+global using IClock = Duende.IdentityServer.IClock;
+#else
+global using IClock = Microsoft.AspNetCore.Authentication.ISystemClock;
+#endif
\ No newline at end of file
diff --git a/src/Abc.IdentityServer.EidasLight/ResponseProcessing/SignInInteractionResponseGenerator.cs b/src/Abc.IdentityServer.EidasLight/ResponseProcessing/SignInInteractionResponseGenerator.cs
index 336cde4..c4b42c4 100644
--- a/src/Abc.IdentityServer.EidasLight/ResponseProcessing/SignInInteractionResponseGenerator.cs
+++ b/src/Abc.IdentityServer.EidasLight/ResponseProcessing/SignInInteractionResponseGenerator.cs
@@ -8,7 +8,6 @@
// ----------------------------------------------------------------------------
using Abc.IdentityServer.EidasLight.Validation;
-using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Logging;
using System;
using System.Linq;
@@ -31,7 +30,7 @@ public class SignInInteractionResponseGenerator : ISignInInteractionResponseGene
///
/// The clock.
///
- protected readonly ISystemClock Clock;
+ protected readonly IClock Clock;
#pragma warning restore SA1401 // Fields should be private
///
@@ -39,7 +38,7 @@ public class SignInInteractionResponseGenerator : ISignInInteractionResponseGene
///
/// The clock.
/// The logger.
- public SignInInteractionResponseGenerator(ISystemClock clock, ILogger logger)
+ public SignInInteractionResponseGenerator(IClock clock, ILogger logger)
{
Clock = clock;
Logger = logger;
diff --git a/src/Abc.IdentityServer.EidasLight/ResponseProcessing/SignInResponseGenerator.cs b/src/Abc.IdentityServer.EidasLight/ResponseProcessing/SignInResponseGenerator.cs
index b5a4c4e..b8ab59a 100644
--- a/src/Abc.IdentityServer.EidasLight/ResponseProcessing/SignInResponseGenerator.cs
+++ b/src/Abc.IdentityServer.EidasLight/ResponseProcessing/SignInResponseGenerator.cs
@@ -28,6 +28,7 @@ public class SignInResponseGenerator : ISignInResponseGenerator
private readonly IHttpContextAccessor _contextAccessor;
private readonly Services.IClaimsService _claims;
private readonly IResourceStore _resources;
+ private readonly IIssuerNameService _issuerNameService;
private readonly ILogger _logger;
public SignInResponseGenerator(
@@ -35,12 +36,14 @@ public SignInResponseGenerator(
EidasLightOptions options,
Services.IClaimsService claimsService,
IResourceStore resources,
+ IIssuerNameService issuerNameService,
ILogger logger)
{
_contextAccessor = contextAccessor;
_options = options;
_claims = claimsService;
_resources = resources;
+ _issuerNameService = issuerNameService;
_logger = logger;
}
@@ -117,7 +120,7 @@ protected virtual async Task CreateSubjectAsync(SignInValidation
return new ClaimsIdentity(outboundClaims, "idsrv");
}
- private Task CreateResponseAsync(ValidatedEidasLightRequest validatedRequest, ClaimsIdentity outgoingSubject)
+ private async Task CreateResponseAsync(ValidatedEidasLightRequest validatedRequest, ClaimsIdentity outgoingSubject)
{
var eidasLightRequest = validatedRequest.Message;
@@ -125,7 +128,7 @@ private Task CreateResponseAsync(ValidatedEidasLightRequest
{
InResponseToId = eidasLightRequest.Id,
IpAddress = _contextAccessor.HttpContext.GetClientIpAddress(),
- Issuer = _contextAccessor.HttpContext.GetIdentityServerIssuerUri(),
+ Issuer = await _issuerNameService.GetCurrentAsync(),
RelayState = eidasLightRequest.RelayState,
Status = new EidasLightResponseStatus()
{
@@ -176,7 +179,7 @@ private Task CreateResponseAsync(ValidatedEidasLightRequest
}
}
- return Task.FromResult(eidasLightResponse);
+ return eidasLightResponse;
}
}
}
\ No newline at end of file
diff --git a/src/Abc.IdentityServer.EidasLight/Services/DefaultIssuerNameService.cs b/src/Abc.IdentityServer.EidasLight/Services/DefaultIssuerNameService.cs
new file mode 100644
index 0000000..a2ba278
--- /dev/null
+++ b/src/Abc.IdentityServer.EidasLight/Services/DefaultIssuerNameService.cs
@@ -0,0 +1,75 @@
+#if IDS4
+
+using Abc.IdentityServer.Extensions;
+using Microsoft.AspNetCore.Http;
+using System;
+using System.Threading.Tasks;
+
+namespace IdentityServer4.Services;
+
+///
+/// Abstracts issuer name access.
+///
+public class DefaultIssuerNameService : IIssuerNameService
+{
+ private readonly IdentityServerOptions _options;
+ private readonly IServerUrls _urls;
+ private readonly IHttpContextAccessor _httpContextAccessor;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The identity server options.
+ /// The server uris.
+ /// The HTTP context accessor.
+ public DefaultIssuerNameService(IdentityServerOptions options, IServerUrls urls, IHttpContextAccessor httpContextAccessor)
+ {
+ _options = options;
+ _urls = urls;
+ _httpContextAccessor = httpContextAccessor;
+ }
+
+ ///
+ public Task GetCurrentAsync()
+ {
+ // if they've explicitly configured a URI then use it,
+ // otherwise dynamically calculate it
+ var issuer = _options.IssuerUri;
+ if (issuer.IsMissing())
+ {
+ string origin = null;
+
+ if (_options.MutualTls.Enabled && _options.MutualTls.DomainName.IsPresent()
+ && !_options.MutualTls.DomainName.Contains("."))
+ {
+ var request = _httpContextAccessor.HttpContext.Request;
+ if (request.Host.Value.StartsWith(_options.MutualTls.DomainName, StringComparison.OrdinalIgnoreCase))
+ {
+ // if MTLS is configured with domain like "foo", then the request will be for "foo.acme.com",
+ // so the issuer we use is from the parent domain (e.g. "acme.com")
+ //
+ // Host.Value is used to get unicode hostname, instead of ToUriComponent (aka punycode)
+ origin = request.Scheme + "://" + request.Host.Value.Substring(_options.MutualTls.DomainName.Length + 1);
+ }
+ }
+
+ if (origin == null)
+ {
+ // no MTLS, so use the current origin for the issuer
+ // this also means we emit the issuer value in unicode
+ origin = _urls.GetUnicodeOrigin();
+ }
+
+ issuer = origin + _urls.BasePath;
+
+ if (_options.LowerCaseIssuerUri)
+ {
+ issuer = issuer.ToLowerInvariant();
+ }
+ }
+
+ return Task.FromResult(issuer);
+ }
+}
+
+#endif
\ No newline at end of file
diff --git a/src/Abc.IdentityServer.EidasLight/Services/DefaultServerUrls.cs b/src/Abc.IdentityServer.EidasLight/Services/DefaultServerUrls.cs
new file mode 100644
index 0000000..ba58174
--- /dev/null
+++ b/src/Abc.IdentityServer.EidasLight/Services/DefaultServerUrls.cs
@@ -0,0 +1,60 @@
+#if IDS4
+
+using Abc.IdentityServer.Extensions;
+using Microsoft.AspNetCore.Http;
+using System;
+using System.Linq;
+
+namespace IdentityServer4.Services;
+
+///
+/// Implements .
+///
+public class DefaultServerUrls : IServerUrls
+{
+ private readonly IHttpContextAccessor _httpContextAccessor;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The HTTP context accessor.
+ public DefaultServerUrls(IHttpContextAccessor httpContextAccessor)
+ {
+ _httpContextAccessor = httpContextAccessor;
+ }
+
+ ///
+ public string Origin
+ {
+ get
+ {
+ var request = _httpContextAccessor.HttpContext.Request;
+ return request.Scheme + "://" + request.Host.ToUriComponent();
+ }
+
+ set
+ {
+ var split = value.Split(new[] { "://" }, StringSplitOptions.RemoveEmptyEntries);
+
+ var request = _httpContextAccessor.HttpContext.Request;
+ request.Scheme = split.First();
+ request.Host = new HostString(split.Last());
+ }
+ }
+
+ ///
+ public string BasePath
+ {
+ get
+ {
+ return _httpContextAccessor.HttpContext.Items["idsvr:IdentityServerBasePath"] as string;
+ }
+
+ set
+ {
+ _httpContextAccessor.HttpContext.Items["idsvr:IdentityServerBasePath"] = value.RemoveTrailingSlash();
+ }
+ }
+}
+
+#endif
\ No newline at end of file
diff --git a/src/Abc.IdentityServer.EidasLight/Services/IIssuerNameService.cs b/src/Abc.IdentityServer.EidasLight/Services/IIssuerNameService.cs
new file mode 100644
index 0000000..0437bab
--- /dev/null
+++ b/src/Abc.IdentityServer.EidasLight/Services/IIssuerNameService.cs
@@ -0,0 +1,19 @@
+#if IDS4
+
+using System.Threading.Tasks;
+
+namespace IdentityServer4.Services;
+
+///
+/// Abstract access to the current issuer name.
+///
+public interface IIssuerNameService
+{
+ ///
+ /// Returns the issuer name for the current request.
+ ///
+ /// The issuer name.
+ Task GetCurrentAsync();
+}
+
+#endif
\ No newline at end of file
diff --git a/src/Abc.IdentityServer.EidasLight/Services/IServerUrls.cs b/src/Abc.IdentityServer.EidasLight/Services/IServerUrls.cs
new file mode 100644
index 0000000..de9b53c
--- /dev/null
+++ b/src/Abc.IdentityServer.EidasLight/Services/IServerUrls.cs
@@ -0,0 +1,26 @@
+#if IDS4
+
+namespace IdentityServer4.Services;
+
+///
+/// Configures the per-request URLs and paths into the current server.
+///
+public interface IServerUrls
+{
+ ///
+ /// Gets or sets the origin for IdentityServer. For example, "https://server.acme.com:5001".
+ ///
+ string Origin { get; set; }
+
+ ///
+ /// Gets or sets the base path of IdentityServer.
+ ///
+ string BasePath { get; set; }
+
+ ///
+ /// Gets the base URL for IdentityServer.
+ ///
+ string BaseUrl { get => Origin + BasePath; }
+}
+
+#endif
\ No newline at end of file
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index 24e9850..f58f28b 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -9,7 +9,7 @@
https://github.com/abc-software/Abc.IdentityServer.EidasLight.git
git
- 1.1.0-dev01
+ 1.2.0-dev01
true
ids.snk
@@ -36,13 +36,13 @@
all
runtime; build; native; contentfiles; analyzers
-
+
all
all
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/test/Abc.IdentityServer.EidasLight.UnitTests/Abc.DuendeIdentityServer.EidasLight.UnitTests.csproj b/test/Abc.IdentityServer.EidasLight.UnitTests/Abc.DuendeIdentityServer.EidasLight.UnitTests.csproj
index 42d573c..9fc41d0 100644
--- a/test/Abc.IdentityServer.EidasLight.UnitTests/Abc.DuendeIdentityServer.EidasLight.UnitTests.csproj
+++ b/test/Abc.IdentityServer.EidasLight.UnitTests/Abc.DuendeIdentityServer.EidasLight.UnitTests.csproj
@@ -6,7 +6,7 @@
- net6.0
+ net6.0;net8.0
10.0
$(DefineConstants);DUENDE
diff --git a/test/Abc.IdentityServer.EidasLight.UnitTests/Endpoints/Results/ErrorPageResultFixture.cs b/test/Abc.IdentityServer.EidasLight.UnitTests/Endpoints/Results/ErrorPageResultFixture.cs
index aa8b2dd..6b963d7 100644
--- a/test/Abc.IdentityServer.EidasLight.UnitTests/Endpoints/Results/ErrorPageResultFixture.cs
+++ b/test/Abc.IdentityServer.EidasLight.UnitTests/Endpoints/Results/ErrorPageResultFixture.cs
@@ -1,4 +1,4 @@
-using Microsoft.AspNetCore.Authentication;
+using Abc.IdentityServer.Extensions;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.WebUtilities;
using System;
@@ -12,24 +12,29 @@ public class ErrorPageResultFixture
{
private ErrorPageResult _target;
private IdentityServerOptions _options;
+ private MockServerUrls _urls;
private MockMessageStore _errorMessageStore;
- private ISystemClock _clock = new StubClock();
+ private IClock _clock = new StubClock();
private DefaultHttpContext _context;
public ErrorPageResultFixture()
{
_context = new DefaultHttpContext();
- _context.SetIdentityServerOrigin("https://server");
- _context.SetIdentityServerBasePath("/");
_context.Response.Body = new MemoryStream();
_options = new IdentityServerOptions();
_options.UserInteraction.ErrorUrl = "~/error";
_options.UserInteraction.ErrorIdParameter = "errorId";
+ _urls = new MockServerUrls()
+ {
+ Origin = "https://server",
+ BasePath = "/".RemoveTrailingSlash(), // as in DefaultServerUrls
+ };
+
_errorMessageStore = new MockMessageStore();
- _target = new ErrorPageResult("some_error", "some_desciption", _options, _clock, _errorMessageStore);
+ _target = new ErrorPageResult("some_error", "some_desciption", _options, _clock, _urls, _errorMessageStore);
}
[Fact]
diff --git a/test/Abc.IdentityServer.EidasLight.UnitTests/Endpoints/Results/LoginPageResultFixture.cs b/test/Abc.IdentityServer.EidasLight.UnitTests/Endpoints/Results/LoginPageResultFixture.cs
index 73b85f0..47a1a91 100644
--- a/test/Abc.IdentityServer.EidasLight.UnitTests/Endpoints/Results/LoginPageResultFixture.cs
+++ b/test/Abc.IdentityServer.EidasLight.UnitTests/Endpoints/Results/LoginPageResultFixture.cs
@@ -1,6 +1,6 @@
using Abc.IdentityModel.Protocols.EidasLight;
using Abc.IdentityServer.EidasLight.Validation;
-using Microsoft.AspNetCore.Authentication;
+using Abc.IdentityServer.Extensions;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.WebUtilities;
using System;
@@ -14,8 +14,9 @@ public class LoginPageResultFixture
{
private LoginPageResult _target;
private ValidatedEidasLightRequest _request;
+ private MockServerUrls _urls;
private IdentityServerOptions _options;
- private ISystemClock _clock = new StubClock();
+ private IClock _clock = new StubClock();
private DefaultHttpContext _context;
private EidasLightProtocolSerializer _protocolSerializer = new EidasLightProtocolSerializer();
private AuthorizationParametersMessageStoreMock _authorizationParametersMessageStore;
@@ -23,8 +24,6 @@ public class LoginPageResultFixture
public LoginPageResultFixture()
{
_context = new DefaultHttpContext();
- _context.SetIdentityServerOrigin("https://server");
- _context.SetIdentityServerBasePath("/");
_context.Response.Body = new MemoryStream();
_options = new IdentityServerOptions();
@@ -35,7 +34,13 @@ public LoginPageResultFixture()
_request = new ValidatedEidasLightRequest();
- _target = new LoginPageResult(_request, _options, _clock, _protocolSerializer, _authorizationParametersMessageStore);
+ _urls = new MockServerUrls()
+ {
+ Origin = "https://server",
+ BasePath = "/".RemoveTrailingSlash(), // as in DefaultServerUrls
+ };
+
+ _target = new LoginPageResult(_request, _options, _clock, _urls, _protocolSerializer, _authorizationParametersMessageStore);
}
[Fact]
diff --git a/test/Abc.IdentityServer.EidasLight.UnitTests/Endpoints/Results/SignInResultFixture.cs b/test/Abc.IdentityServer.EidasLight.UnitTests/Endpoints/Results/SignInResultFixture.cs
index 75e3bbc..719d915 100644
--- a/test/Abc.IdentityServer.EidasLight.UnitTests/Endpoints/Results/SignInResultFixture.cs
+++ b/test/Abc.IdentityServer.EidasLight.UnitTests/Endpoints/Results/SignInResultFixture.cs
@@ -16,8 +16,6 @@ public SignInResultFixture()
_options = new IdentityServerOptions();
_context = new DefaultHttpContext();
- _context.SetIdentityServerOrigin("https://server");
- _context.SetIdentityServerBasePath("/");
_context.Response.Body = new MemoryStream();
_target = new SignInResult("some_token", "http://client/callback", _options);
diff --git a/test/Abc.IdentityServer.EidasLight.UnitTests/Extensions/StringExtensionsFixture.cs b/test/Abc.IdentityServer.EidasLight.UnitTests/Extensions/StringExtensionsFixture.cs
index ba91eb5..27f7ebf 100644
--- a/test/Abc.IdentityServer.EidasLight.UnitTests/Extensions/StringExtensionsFixture.cs
+++ b/test/Abc.IdentityServer.EidasLight.UnitTests/Extensions/StringExtensionsFixture.cs
@@ -167,6 +167,21 @@ public void CheckRemoveLeadingSlash(string inputUrl, string expected)
actualOrigin.Should().Be(expected);
}
+
+
+ [Theory]
+ [InlineData(null, null)]
+ [InlineData("", "")]
+ [InlineData("test/resource/", "test/resource")]
+ [InlineData("/test/resource/", "/test/resource")]
+ [InlineData("test/resource", "test/resource")]
+ [InlineData("/test/resource", "/test/resource")]
+ public void CheckRemoveTrailingSlash(string inputUrl, string expected)
+ {
+ var actualOrigin = inputUrl.RemoveTrailingSlash();
+
+ actualOrigin.Should().Be(expected);
+ }
#endregion
#region AddQueryString
diff --git a/test/Abc.IdentityServer.EidasLight.UnitTests/GlobalUsings.cs b/test/Abc.IdentityServer.EidasLight.UnitTests/GlobalUsings.cs
index d797591..e9fbeb2 100644
--- a/test/Abc.IdentityServer.EidasLight.UnitTests/GlobalUsings.cs
+++ b/test/Abc.IdentityServer.EidasLight.UnitTests/GlobalUsings.cs
@@ -25,3 +25,9 @@
global using Ids = IdentityServer4;
global using StatusCodeResult = IdentityServer4.Endpoints.Results.StatusCodeResult;
#endif
+
+#if NET8_0_OR_GREATER
+global using IClock = Duende.IdentityServer.IClock;
+#else
+global using IClock = Microsoft.AspNetCore.Authentication.ISystemClock;
+#endif
\ No newline at end of file
diff --git a/test/Abc.IdentityServer.EidasLight.UnitTests/Internal/MockServerUrls.cs b/test/Abc.IdentityServer.EidasLight.UnitTests/Internal/MockServerUrls.cs
new file mode 100644
index 0000000..3a891d2
--- /dev/null
+++ b/test/Abc.IdentityServer.EidasLight.UnitTests/Internal/MockServerUrls.cs
@@ -0,0 +1,8 @@
+namespace Abc.IdentityServer
+{
+ public class MockServerUrls : IServerUrls
+ {
+ public string Origin { get; set; }
+ public string BasePath { get; set; }
+ }
+}
diff --git a/test/Abc.IdentityServer.EidasLight.UnitTests/Internal/StubClock.cs b/test/Abc.IdentityServer.EidasLight.UnitTests/Internal/StubClock.cs
index 1ebf9e0..90241e3 100644
--- a/test/Abc.IdentityServer.EidasLight.UnitTests/Internal/StubClock.cs
+++ b/test/Abc.IdentityServer.EidasLight.UnitTests/Internal/StubClock.cs
@@ -1,8 +1,8 @@
using System;
-namespace Microsoft.AspNetCore.Authentication
+namespace Abc.IdentityServer
{
- internal class StubClock : ISystemClock
+ internal class StubClock : IClock
{
public Func UtcNowFunc = () => DateTime.UtcNow;
public DateTimeOffset UtcNow => new DateTimeOffset(UtcNowFunc());