Skip to content

Commit

Permalink
Add support for .NET 9 to access token management
Browse files Browse the repository at this point in the history
  • Loading branch information
josephdecock committed Nov 15, 2024
1 parent 13839d4 commit 472e395
Show file tree
Hide file tree
Showing 11 changed files with 77 additions and 12 deletions.
12 changes: 8 additions & 4 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,24 @@
<PropertyGroup Condition=" '$(TargetFramework)' == 'net6.0'">
<FrameworkVersion>6.0.1</FrameworkVersion>
<ExtensionsVersion>6.0.0</ExtensionsVersion>
<WilsonVersion>7.1.2</WilsonVersion>
<IdentityServerVersion>6.1.8</IdentityServerVersion>
<WilsonVersion>6.35.0</WilsonVersion>
<IdentityServerVersion>6.3.10</IdentityServerVersion>
</PropertyGroup>

<PropertyGroup Condition=" '$(TargetFramework)' == 'net8.0'">
<FrameworkVersion>8.0.1</FrameworkVersion>
<ExtensionsVersion>8.0.0</ExtensionsVersion>
<WilsonVersion>7.1.2</WilsonVersion>

<!-- TODO - we may want to lower the upper bound as we do more testing. -->
<WilsonVersion>[7.1.2,8.0.0)</WilsonVersion>

<IdentityServerVersion>7.0.8</IdentityServerVersion>
</PropertyGroup>

<PropertyGroup Condition=" '$(TargetFramework)' == 'net9.0'">
<FrameworkVersion>9.0.0</FrameworkVersion>
<ExtensionsVersion>9.0.0</ExtensionsVersion>
<WilsonVersion>8.0.0</WilsonVersion>
<WilsonVersion>8.0.1</WilsonVersion>
<IdentityServerVersion>7.0.8</IdentityServerVersion>
</PropertyGroup>

Expand Down Expand Up @@ -57,6 +60,7 @@
<PackageVersion Include="Shouldly" Version="4.2.1" />
<PackageVersion Include="SimpleExec" Version="12.0.0" />
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="$(WilsonVersion)" />
<PackageVersion Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" Version="$(WilsonVersion)" />
<PackageVersion Include="System.Text.Json" Version="8.0.5" />
<PackageVersion Include="Verify.Xunit" Version="27.0.1" />
<PackageVersion Include="xunit.core" Version="2.9.2" />
Expand Down
2 changes: 1 addition & 1 deletion access-token-management/global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "8.0.100",
"version": "9.0.100",
"rollForward": "latestMajor",
"allowPrerelease": false
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net8.0</TargetFrameworks>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
<PackageId>Duende.AccessTokenManagement.OpenIdConnect</PackageId>
<AssemblyName>$(PackageId)</AssemblyName>
<RootNamespace>$(PackageId)</RootNamespace>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,19 @@ public async Task<OpenIdConnectClientConfiguration> GetOpenIdConnectConfiguratio

Authority = options.Authority,
TokenEndpoint = configuration.TokenEndpoint,

// This conditional compilation is required because the
// OpenIdConnectConfiguration type in
// Microsoft.IdentityModel.Protocols.OpenIdConnect has a breaking
// change in version 8.0.0 that library. The revocation endpoint was
// added as a strongly typed property, which means it is no longer
// included in the AdditionalData. In our .NET 9 build, we require
// wilson >8.0.0, and in our .NET 8 build, we require wilson <8.0.0.
#if NET9_0_OR_GREATER
RevocationEndpoint = configuration.RevocationEndpoint,
#else
RevocationEndpoint = configuration.AdditionalData.TryGetValue(OidcConstants.Discovery.RevocationEndpoint, out var value) ? value?.ToString() : null,
#endif

ClientId = options.ClientId,
ClientSecret = options.ClientSecret,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net8.0</TargetFrameworks>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
<PackageId>Duende.AccessTokenManagement</PackageId>
<AssemblyName>$(PackageId)</AssemblyName>
<RootNamespace>$(PackageId)</RootNamespace>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net8.0</TargetFrameworks>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>Duende.AccessTokenManagement</RootNamespace>
Expand All @@ -14,6 +14,11 @@
<PackageReference Include="Duende.IdentityServer"/>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" />
<PackageReference Include="Microsoft.AspNetCore.TestHost" />

<!-- Pinned to avoid conflicts - we bring this in via IdentityServer, and that could conflict with
AccessTokenManagement's depednecy on System.IdentityModel.Tokens.Jwt. -->
<PackageReference Include="Microsoft.IdentityModel.Protocols.OpenIdConnect" />

<PackageReference Include="RichardSzalay.MockHttp" />
</ItemGroup>
<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ private void ConfigureServices(IServiceCollection services)
})
.AddOpenIdConnect("oidc", options =>
{
options.Events.OnRedirectToIdentityProviderForSignOut = async e =>
{
await e.HttpContext.RevokeRefreshTokenAsync();
};
options.Authority = _identityServerHost.Url();
options.ClientId = ClientId;
Expand Down Expand Up @@ -212,7 +217,6 @@ public async Task<HttpResponseMessage> LogoutAsync(string? sid = null)

response = await BrowserClient.GetAsync(response.Headers.Location.ToString());
response.StatusCode.ShouldBe((HttpStatusCode)302); // root
response.Headers.Location!.ToString().ToLowerInvariant().ShouldBe("/");

response = await BrowserClient.GetAsync(Url(response.Headers.Location.ToString()));

Check warning on line 221 in access-token-management/test/AccessTokenManagement.Tests/Framework/AppHost.cs

View workflow job for this annotation

GitHub Actions / Build

Dereference of a possibly null reference.

Check warning on line 221 in access-token-management/test/AccessTokenManagement.Tests/Framework/AppHost.cs

View workflow job for this annotation

GitHub Actions / Build

Dereference of a possibly null reference.

Check warning on line 221 in access-token-management/test/AccessTokenManagement.Tests/Framework/AppHost.cs

View workflow job for this annotation

GitHub Actions / Build

Dereference of a possibly null reference.

Check warning on line 221 in access-token-management/test/AccessTokenManagement.Tests/Framework/AppHost.cs

View workflow job for this annotation

GitHub Actions / Build

Dereference of a possibly null reference.
return response;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ private void ConfigureServices(IServiceCollection services)
// Artificially low durations to force retries
options.DPoP.ServerClockSkew = TimeSpan.Zero;
options.DPoP.ProofTokenValidityDuration = TimeSpan.FromSeconds(1);
// Disable PAR (this keeps test setup simple, and we don't need to integration test PAR here - it is covered by IdentityServer itself)
options.Endpoints.EnablePushedAuthorizationEndpoint = false;
})
.AddInMemoryClients(Clients)
.AddInMemoryIdentityResources(IdentityResources)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
using System.Net.Http.Json;
using System.Text.Json;
using Duende.AccessTokenManagement.OpenIdConnect;
using Duende.IdentityModel;
using IdentityModel.Client;
using RichardSzalay.MockHttp;

namespace Duende.AccessTokenManagement.Tests;
Expand Down Expand Up @@ -421,4 +423,40 @@ public async Task Multiple_users_have_distinct_tokens_across_refreshes()
thirdToken.sub.ShouldNotBe(secondToken.sub);
thirdToken.token.ShouldNotBe(firstToken.token);
}


[Fact]
public async Task Logout_should_revoke_refresh_tokens()
{
await AppHost.InitializeAsync();
await AppHost.LoginAsync("alice");

var response = await AppHost.BrowserClient.GetAsync(AppHost.Url("/user_token"));
var token = await response.Content.ReadFromJsonAsync<UserToken>();
var refreshToken = token?.RefreshToken;

refreshToken.ShouldNotBeNull();

var introspectionParams = new TokenIntrospectionRequest
{
Token = refreshToken,
TokenTypeHint = OidcConstants.TokenTypes.RefreshToken,
ClientId = "web",
ClientSecret = "secret",
Address = IdentityServerHost.Url("/connect/introspect")
};

var introspectionResponse = await IdentityServerHost.HttpClient.IntrospectTokenAsync(introspectionParams);
introspectionResponse.ShouldNotBeNull();
introspectionResponse.IsError.ShouldBeFalse(introspectionResponse.Error);
introspectionResponse.IsActive.ShouldBeTrue();

await AppHost.BrowserClient.GetAsync(AppHost.Url("/logout"));

var postLogoutIntrospectionResponse = await IdentityServerHost.HttpClient.IntrospectTokenAsync(introspectionParams);
postLogoutIntrospectionResponse.ShouldNotBeNull();
postLogoutIntrospectionResponse.IsError.ShouldBeFalse(introspectionResponse.Error);
postLogoutIntrospectionResponse.IsActive.ShouldBeFalse();

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using Duende.IdentityModel;
using Microsoft.IdentityModel.JsonWebTokens;
using Microsoft.IdentityModel.Tokens;

Expand All @@ -24,7 +23,7 @@ public DPoPProofTokenFactory(string proofKey)
{
_jwk = new JsonWebKey(proofKey);

if (_jwk.Alg.IsNullOrEmpty())
if (string.IsNullOrEmpty(_jwk.Alg))
{
throw new ArgumentException("alg must be set on proof key");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace Duende.IdentityModel.HttpClientExtensions
{
public class TokenRevocationExtensionsTests
{
private const string Endpoint = "http://server/endoint";
private const string Endpoint = "http://server/endpoint";

[Fact]
public async Task Http_request_should_have_correct_format()
Expand Down

0 comments on commit 472e395

Please sign in to comment.