Skip to content

Commit

Permalink
Fixes cache expiration and adds dotnet 8 support (#6)
Browse files Browse the repository at this point in the history
* adds .idea to .gitignore

* fixes namespace

* fixes errors due to dotnet 8 upgrade

* Adds logout button to samples

* adds cache expiration

* updates workflows for dotnet 8
  • Loading branch information
gislikonrad authored Nov 5, 2024
1 parent d49a05d commit 9ff39b8
Show file tree
Hide file tree
Showing 25 changed files with 213 additions and 47 deletions.
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

0 comments on commit 9ff39b8

Please sign in to comment.