Skip to content
This repository was archived by the owner on Apr 10, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:
with:
dotnet-version: |
6.0.x
7.0.x
8.0.x

- name: install_dependencies
run: dotnet restore ./src/Solid.Identity.Protocols.Saml2p.sln
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
with:
dotnet-version: |
6.0.x
7.0.x
8.0.x

- name: install_dependencies
run: dotnet restore ./src/Solid.Identity.Protocols.Saml2p.sln
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -352,4 +352,5 @@ MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/

Solid.**.xml
Solid.**.xml
.idea
2 changes: 1 addition & 1 deletion src/AspNetCore.IdpSample/AspNetCore.IdpSample.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
</PropertyGroup>

Expand Down
2 changes: 2 additions & 0 deletions src/AspNetCore.IdpSample/Pages/Logout.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@page
@model AspNetCore.IdpSample.Pages.Logout
15 changes: 15 additions & 0 deletions src/AspNetCore.IdpSample/Pages/Logout.cshtml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace AspNetCore.IdpSample.Pages;

public class Logout : PageModel
{
public async Task<IActionResult> OnGetAsync()
{
await HttpContext.SignOutAsync();
return Redirect("/");
}
}
1 change: 1 addition & 0 deletions src/AspNetCore.IdpSample/Pages/Shared/_Layout.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
<span class="navbar-text">
@(Context.User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value ?? "")
</span>
<a class="nav-link text-dark" asp-area="" asp-page="/Logout">Logout</a>
}
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/AspNetCore.IdpSample/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public void ConfigureServices(IServiceCollection services)
{
sp.BaseUrl = new Uri("https://localhost:5003");
sp.MaxClockSkew = TimeSpan.FromMinutes(2);
sp.AssertionConsumerServiceEndpoint = "/finish";
sp.AssertionConsumerServiceEndpoint = "/saml2p/finish";
sp.AssertionSigningKey = new X509SecurityKey(new X509Certificate2(Convert.FromBase64String(SigningCertificateBase64)));

sp.SupportedBindings.Clear();
Expand Down
2 changes: 1 addition & 1 deletion src/AspNetCore.SpSample/AspNetCore.SpSample.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
</PropertyGroup>

Expand Down
2 changes: 2 additions & 0 deletions src/AspNetCore.SpSample/Pages/Logout.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@page
@model AspNetCore.SpSample.Pages.Logout
15 changes: 15 additions & 0 deletions src/AspNetCore.SpSample/Pages/Logout.cshtml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace AspNetCore.SpSample.Pages;

public class Logout : PageModel
{
public async Task<IActionResult> OnGetAsync()
{
await HttpContext.SignOutAsync();
return Redirect("/");
}
}
1 change: 1 addition & 0 deletions src/AspNetCore.SpSample/Pages/Shared/_Layout.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
<span class="navbar-text">
@(Context.User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value ?? "")
</span>
<a class="nav-link text-dark" asp-area="" asp-page="/Logout">Logout</a>
}
</div>

Expand Down
3 changes: 0 additions & 3 deletions src/AspNetCore.SpSample/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,6 @@ public void ConfigureServices(IServiceCollection services)
idp.CanInitiateSso = true;
idp.RequestedAuthnContextClassRef = Saml2pConstants.Classes.Kerberos;
idp.AssertionSigningKeys.Add(new X509SecurityKey(new X509Certificate2(Convert.FromBase64String(SigningCertificateBase64))));
//idp.Events.OnGeneratingRelayState = (provider, context) => new ValueTask();
//idp.Events.OnValidatingToken = ValidatingToken;
//idp.Events.OnValidatingToken += (provider, context) => new ValueTask();
});
})
;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using System.Text;
using Xunit;

namespace Solid.Identity.Protocols.Sam2p.Tests
namespace Solid.Identity.Protocols.Saml2p.Tests
{
public class Saml2pEncodingServiceTests
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
using System.Text;
using Xunit;

namespace Solid.Identity.Protocols.Sam2p.Tests
namespace Solid.Identity.Protocols.Saml2p.Tests
{
public class Saml2pStatusConversionTests
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
<TargetFrameworks>net6.0;net8.0</TargetFrameworks>
<IsPackable>false</IsPackable>
</PropertyGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;

namespace Solid.Identity.Protocols.Saml2p.Abstractions
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,32 @@
using System.Security.Claims;
using Solid.Identity.Protocols.Saml2p.Options;
using Solid.Identity.Protocols.Saml2p.Exceptions;
// ReSharper disable InconsistentNaming

namespace Solid.Identity.Protocols.Saml2p.Authentication
{
internal class Saml2pAuthenticationHandler : RemoteAuthenticationHandler<Saml2pAuthenticationOptions>, IDisposable
{
private Saml2pOptions _saml2p;
private IDisposable _optionsChangeToken;
private readonly IDisposable _optionsChangeToken;

#if NET6_0
public Saml2pAuthenticationHandler(IOptionsMonitor<Saml2pOptions> saml2pOptionsMonitor, IOptionsMonitor<Saml2pAuthenticationOptions> monitor, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
: base(monitor, logger, encoder, clock)
{
_saml2p = saml2pOptionsMonitor.CurrentValue;
_optionsChangeToken = saml2pOptionsMonitor.OnChange((options, _) => _saml2p = options);
}
#else
public Saml2pAuthenticationHandler(IOptionsMonitor<Saml2pOptions> saml2pOptionsMonitor, IOptionsMonitor<Saml2pAuthenticationOptions> monitor, ILoggerFactory logger, UrlEncoder encoder)
: base(monitor, logger, encoder)
{
_saml2p = saml2pOptionsMonitor.CurrentValue;
_optionsChangeToken = saml2pOptionsMonitor.OnChange((options, _) => _saml2p = options);
}
#endif



protected override Task InitializeHandlerAsync()
{
Expand Down
14 changes: 12 additions & 2 deletions src/Solid.Identity.Protocols.Saml2p/Cache/Saml2pCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
using System.Threading.Tasks;

namespace Solid.Identity.Protocols.Saml2p.Cache
Expand All @@ -22,13 +23,13 @@ public Saml2pCache(IDistributedCache inner)
public Task CacheRequestAsync(string key, AuthnRequest request)
{
var json = JsonSerializer.SerializeToUtf8Bytes(request);
return _inner.SetAsync(key, json);
return _inner.SetAsync(key, json, CreateOptions());
}

public Task CacheStatusAsync(string key, Status status)
{
var json = JsonSerializer.SerializeToUtf8Bytes(status);
return _inner.SetAsync($"{key}_status", json);
return _inner.SetAsync($"{key}_status", json, CreateOptions());
}

public async Task<AuthnRequest> FetchRequestAsync(string key)
Expand All @@ -52,5 +53,14 @@ public async Task RemoveAsync(string key)
await _inner.RemoveAsync(key);
await _inner.RemoveAsync($"{key}_status");
}

private DistributedCacheEntryOptions CreateOptions()
{
return new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5)
};
}

}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using Solid.IdentityModel.Xml;

namespace System.Security.Claims
{
Expand All @@ -11,5 +13,17 @@ public static bool TryFindFirst(this ClaimsIdentity identity, string type, out C
claim = identity.FindFirst(type);
return claim != null;
}

public static bool TryParseAuthenticationInstant(this ClaimsIdentity identity, out DateTime? instant)
{
var value = identity.FindFirst(ClaimTypes.AuthenticationInstant)?.Value;
if (string.IsNullOrWhiteSpace(value))
return Out.False(out instant);
if (!DateTime.TryParse(value, out var parsed))
return Out.False(out instant);

instant = parsed;
return instant.HasValue;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ namespace Solid.Identity.Protocols.Saml2p.Factories
/// </summary>
public class AuthnRequestFactory
{
private ISystemClock _systemClock;
private Saml2pOptions _options;

private readonly Saml2pOptions _options;
#if NET6_0
private readonly ISystemClock _systemClock;
/// <summary>
/// Creates an instance of <see cref="AuthnRequestFactory"/>.
/// </summary>
Expand All @@ -31,6 +31,19 @@ public AuthnRequestFactory(ISystemClock systemClock, IOptions<Saml2pOptions> opt
_systemClock = systemClock;
_options = options.Value;
}
#else
private readonly TimeProvider _time;
/// <summary>
/// Creates an instance of <see cref="AuthnRequestFactory"/>.
/// </summary>
/// <param name="time">The provider of the current time.</param>
/// <param name="options">The current <see cref="Saml2pOptions" />.</param>
public AuthnRequestFactory(TimeProvider time, IOptions<Saml2pOptions> options)
{
_time = time;
_options = options.Value;
}
#endif

/// <summary>
/// Creates an instance of <see cref="AuthnRequest"/>.
Expand All @@ -46,7 +59,7 @@ public async Task<AuthnRequest> CreateAuthnRequestAsync(HttpContext context, ISa
// TODO: have some sort of providername default
ProviderName = idp.ExpectedIssuer ?? _options.DefaultIssuer,
AssertionConsumerServiceUrl = GetAcsUrl(context.Request),
IssueInstant = _systemClock.UtcNow.UtcDateTime,
IssueInstant = GetUtcNow(),
Issuer = idp.ExpectedIssuer ?? _options.DefaultIssuer,
Destination = new Uri(idp.BaseUrl, idp.AcceptSsoEndpoint),
NameIdPolicy = new NameIdPolicy
Expand Down Expand Up @@ -82,5 +95,14 @@ private Uri GetAcsUrl(HttpRequest request)
var path = request.PathBase.Add(_options.FinishPath);
return new Uri(baseUrl, path);
}

private DateTime GetUtcNow()
{
#if NET6_0
return _systemClock.UtcNow.UtcDateTime;
#else
return _time.GetUtcNow().UtcDateTime;
#endif
}
}
}
Loading
Loading