Skip to content

Commit

Permalink
Update DPOP to .NET 8
Browse files Browse the repository at this point in the history
  • Loading branch information
josephdecock committed Jan 19, 2024
1 parent 9f46c8d commit ec7fe6c
Show file tree
Hide file tree
Showing 94 changed files with 634 additions and 513 deletions.
77 changes: 77 additions & 0 deletions IdentityServer/v7/DPoP/.vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
{
"version": "0.2.0",
"compounds": [
{
"name": "Run All (interactive)",
"configurations": ["IdentityServer", "Api", "Web"],
"presentation": {
"group": "10-compunds",
}
},
{
"name": "Run All (client credentials)",
"configurations": ["IdentityServer", "Api", "ClientCredentials"],
"presentation": {
"group": "10-compunds",
}
}
],
"configurations": [
{
"name": "IdentityServer",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build-identityserver",
"program": "${workspaceFolder}/IdentityServer/bin/Debug/net8.0/IdentityServer.dll",
"args": [],
"cwd": "${workspaceFolder}/IdentityServer",
"env": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"console": "externalTerminal",
},
{
"name": "Api",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build-api",
"program": "${workspaceFolder}/Api/bin/Debug/net8.0/Api.dll",
"args": [],
"cwd": "${workspaceFolder}/Api/",
"env": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"console": "externalTerminal",
},
{
"name": "ClientCredentials",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build-clientcredentials",
"program": "${workspaceFolder}/ClientCredentials/bin/Debug/net8.0/ClientCredentials.dll",
"args": [],
"cwd": "${workspaceFolder}/ClientCredentials",
"console": "externalTerminal",
"env": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
},
{
"name": "Web",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build-web",
"program": "${workspaceFolder}/WebClient/bin/Debug/net8.0/WebClient.dll",
"args": [],
"cwd": "${workspaceFolder}/WebClient",
"console": "externalTerminal",
"serverReadyAction": {
"action": "openExternally",
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
},
"env": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
}
]
}
65 changes: 65 additions & 0 deletions IdentityServer/v7/DPoP/.vscode/tasks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"type": "process",
"command": "dotnet",
"args": [
"build",
"${workspaceFolder}/DPoP.sln",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "build-identityserver",
"type": "process",
"command": "dotnet",
"args": [
"build",
"${workspaceFolder}/IdentityServer",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "build-api",
"type": "process",
"command": "dotnet",
"args": [
"build",
"${workspaceFolder}/Api",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "build-clientcredentials",
"type": "process",
"command": "dotnet",
"args": [
"build",
"${workspaceFolder}/ClientCredentials",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "build-web",
"type": "process",
"command": "dotnet",
"args": [
"build",
"${workspaceFolder}/WebClient",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
}
]
}
15 changes: 15 additions & 0 deletions IdentityServer/v7/DPoP/Api/Api.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="IdentityModel" Version="6.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.1" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.0" />
</ItemGroup>

</Project>
13 changes: 0 additions & 13 deletions IdentityServer/v7/DPoP/Api/ApiHost.csproj

This file was deleted.

4 changes: 2 additions & 2 deletions IdentityServer/v7/DPoP/Api/DPoP/ConfigureJwtBearerOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using Microsoft.Extensions.Options;
using System;

namespace ApiHost;
namespace Api;

public class ConfigureJwtBearerOptions : IPostConfigureOptions<JwtBearerOptions>
{
Expand All @@ -13,7 +13,7 @@ public ConfigureJwtBearerOptions(string configScheme)
_configScheme = configScheme;
}

public void PostConfigure(string name, JwtBearerOptions options)
public void PostConfigure(string? name, JwtBearerOptions options)
{
if (_configScheme == name)
{
Expand Down
11 changes: 6 additions & 5 deletions IdentityServer/v7/DPoP/Api/DPoP/DPoPExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
using Microsoft.AspNetCore.Http;
using Microsoft.IdentityModel.Tokens;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text.Json;

namespace ApiHost;
namespace Api;

/// <summary>
/// Extensions methods for DPoP
Expand All @@ -21,7 +22,7 @@ public static bool IsDPoPAuthorizationScheme(this HttpRequest request)
return authz?.StartsWith(DPoPPrefix, System.StringComparison.Ordinal) == true;
}

public static bool TryGetDPoPAccessToken(this HttpRequest request, out string token)
public static bool TryGetDPoPAccessToken(this HttpRequest request, [NotNullWhen(true)]out string? token)
{
token = null;

Expand All @@ -34,17 +35,17 @@ public static bool TryGetDPoPAccessToken(this HttpRequest request, out string to
return false;
}

public static string GetAuthorizationScheme(this HttpRequest request)
public static string? GetAuthorizationScheme(this HttpRequest request)
{
return request.Headers.Authorization.FirstOrDefault()?.Split(' ', System.StringSplitOptions.RemoveEmptyEntries)[0];
}

public static string GetDPoPProofToken(this HttpRequest request)
public static string? GetDPoPProofToken(this HttpRequest request)
{
return request.Headers[OidcConstants.HttpHeaders.DPoP].FirstOrDefault();
}

public static string GetDPoPNonce(this AuthenticationProperties props)
public static string? GetDPoPNonce(this AuthenticationProperties props)
{
if (props.Items.ContainsKey("DPoP-Nonce"))
{
Expand Down
13 changes: 9 additions & 4 deletions IdentityServer/v7/DPoP/Api/DPoP/DPoPJwtBearerEvents.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
using IdentityModel;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using Microsoft.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using static IdentityModel.OidcConstants;

namespace ApiHost;
namespace Api;

public class DPoPJwtBearerEvents : JwtBearerEvents
{
Expand Down Expand Up @@ -44,6 +45,10 @@ public override async Task TokenValidated(TokenValidatedContext context)
if (context.HttpContext.Request.TryGetDPoPAccessToken(out var at))
{
var proofToken = context.HttpContext.Request.GetDPoPProofToken();
if (proofToken == null)
{
throw new InvalidOperationException("Missing DPoP (proof token) HTTP header");
}
var result = await _validator.ValidateAsync(new DPoPProofValidatonContext
{
Scheme = context.Scheme.Name,
Expand All @@ -56,7 +61,7 @@ public override async Task TokenValidated(TokenValidatedContext context)
if (result.IsError)
{
// fails the result
context.Fail(result.ErrorDescription ?? result.Error);
context.Fail(result.ErrorDescription ?? result.Error ?? throw new Exception("No ErrorDescription or Error set."));

// we need to stash these values away so they are available later when the Challenge method is called later
context.HttpContext.Items["DPoP-Error"] = result.Error;
Expand All @@ -75,7 +80,7 @@ public override async Task TokenValidated(TokenValidatedContext context)
// if the scheme used was not DPoP, then it was Bearer
// and if a access token was presented with a cnf, then the
// client should have sent it as DPoP, so we fail the request
if (context.Principal.HasClaim(x => x.Type == JwtClaimTypes.Confirmation))
if (context.Principal?.HasClaim(x => x.Type == JwtClaimTypes.Confirmation) ?? false)
{
context.HttpContext.Items["Bearer-ErrorDescription"] = "Must use DPoP when using an access token with a 'cnf' claim";
context.Fail("Must use DPoP when using an access token with a 'cnf' claim");
Expand Down Expand Up @@ -130,7 +135,7 @@ public override Task Challenge(JwtBearerChallengeContext context)
}
}

context.Response.Headers.Add(HeaderNames.WWWAuthenticate, sb.ToString());
context.Response.Headers.Append(HeaderNames.WWWAuthenticate, sb.ToString());


if (context.HttpContext.Items.ContainsKey("DPoP-Nonce"))
Expand Down
2 changes: 1 addition & 1 deletion IdentityServer/v7/DPoP/Api/DPoP/DPoPMode.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace ApiHost;
namespace Api;

public enum DPoPMode
{
Expand Down
2 changes: 1 addition & 1 deletion IdentityServer/v7/DPoP/Api/DPoP/DPoPOptions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System;

namespace ApiHost;
namespace Api;

public class DPoPOptions
{
Expand Down
12 changes: 6 additions & 6 deletions IdentityServer/v7/DPoP/Api/DPoP/DPoPProofValidatonContext.cs
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
using System.Collections.Generic;
using System.Security.Claims;

namespace ApiHost;
namespace Api;

public class DPoPProofValidatonContext
{
/// <summary>
/// The ASP.NET Core authentication scheme triggering the validation
/// </summary>
public string Scheme { get; set; }
public required string Scheme { get; set; }

/// <summary>
/// The HTTP URL to validate
/// </summary>
public string Url { get; set; }
public required string Url { get; set; }

/// <summary>
/// The HTTP method to validate
/// </summary>
public string Method { get; set; }
public required string Method { get; set; }

/// <summary>
/// The DPoP proof token to validate
/// </summary>
public string ProofToken { get; set; }
public required string ProofToken { get; set; }

/// <summary>
/// The access token
/// </summary>
public string AccessToken { get; set; }
public required string AccessToken { get; set; }
}
Loading

0 comments on commit ec7fe6c

Please sign in to comment.