Skip to content

Commit

Permalink
- Update Todo.Web packages
Browse files Browse the repository at this point in the history
- Use new YARP APIs
- Remove the acceptance of external tokens on the backend
  • Loading branch information
davidfowl committed May 14, 2023
1 parent f3c8762 commit 7804305
Show file tree
Hide file tree
Showing 6 changed files with 25 additions and 115 deletions.
13 changes: 4 additions & 9 deletions Todo.Web/Server/AuthApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public static RouteGroupBuilder MapAuth(this IEndpointRouteBuilder routes)
if (token is not null)
{
// Write the login cookie
await SignIn(id, name, token, provider, result.Properties.GetTokens()).ExecuteAsync(context);
await SignIn(id, name, token, provider).ExecuteAsync(context);
}
}
Expand All @@ -97,10 +97,10 @@ public static RouteGroupBuilder MapAuth(this IEndpointRouteBuilder routes)

private static IResult SignIn(UserInfo userInfo, string token)
{
return SignIn(userInfo.Username, userInfo.Username, token, providerName: null, authTokens: Enumerable.Empty<AuthenticationToken>());
return SignIn(userInfo.Username, userInfo.Username, token, providerName: null);
}

private static IResult SignIn(string userId, string userName, string token, string? providerName, IEnumerable<AuthenticationToken> authTokens)
private static IResult SignIn(string userId, string userName, string token, string? providerName)
{
var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, userId));
Expand All @@ -114,12 +114,7 @@ private static IResult SignIn(string userId, string userName, string token, stri
properties.SetExternalProvider(providerName);
}

if (authTokens.Any())
{
properties.SetHasExternalToken(true);
}

var tokens = authTokens.Any() ? authTokens : new[]
var tokens = new[]
{
new AuthenticationToken { Name = TokenNames.AccessToken, Value = token }
};
Expand Down
16 changes: 0 additions & 16 deletions Todo.Web/Server/Authentication/AuthenticationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,26 +99,10 @@ static void SetAuth0SignInScheme(WebApplicationBuilder builder)
}

private static readonly string ExternalProviderKey = "ExternalProviderName";
private static readonly string HasExternalTokenKey = "ExternalToken";

public static string? GetExternalProvider(this AuthenticationProperties properties) =>
properties.GetString(ExternalProviderKey);

public static void SetExternalProvider(this AuthenticationProperties properties, string providerName) =>
properties.SetString(ExternalProviderKey, providerName);

public static bool HasExternalToken(this AuthenticationProperties properties) =>
properties.GetString(HasExternalTokenKey) is not null;

public static void SetHasExternalToken(this AuthenticationProperties properties, bool hasToken)
{
if (hasToken)
{
properties.SetString(HasExternalTokenKey, "1");
}
else
{
properties.Items.Remove(HasExternalTokenKey);
}
}
}
14 changes: 7 additions & 7 deletions Todo.Web/Server/Todo.Web.Server.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="AspNet.Security.OAuth.GitHub" Version="7.0.0" />
<PackageReference Include="Auth0.AspNetCore.Authentication" Version="1.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="7.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.MicrosoftAccount" Version="7.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="7.0.0" />
<PackageReference Include="Microsoft.NET.Build.Containers" Version="0.2.7" />
<PackageReference Include="Yarp.ReverseProxy" Version="1.1.1" />
<PackageReference Include="AspNet.Security.OAuth.GitHub" Version="7.0.2" />
<PackageReference Include="Auth0.AspNetCore.Authentication" Version="1.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="7.0.5" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.MicrosoftAccount" Version="7.0.5" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="7.0.5" />
<PackageReference Include="Microsoft.NET.Build.Containers" Version="0.4.0" />
<PackageReference Include="Yarp.ReverseProxy" Version="2.0.0" />
<PackageReference Include="Microsoft.Tye.Extensions.Configuration" Version="0.10.0-alpha.21420.1" />
</ItemGroup>

Expand Down
33 changes: 11 additions & 22 deletions Todo.Web/Server/TodoApi.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using Microsoft.AspNetCore.Authentication;
using Yarp.ReverseProxy.Forwarder;
using Yarp.ReverseProxy.Transforms;
using Yarp.ReverseProxy.Transforms.Builder;

namespace Todo.Web.Server;

Expand All @@ -11,33 +13,20 @@ public static RouteGroupBuilder MapTodos(this IEndpointRouteBuilder routes, stri

group.RequireAuthorization();

var transform = static async ValueTask (HttpContext context, HttpRequestMessage req) =>
{
var result = await context.AuthenticateAsync();
var properties = result.Properties!;
var accessToken = properties.GetTokenValue(TokenNames.AccessToken);
req.Headers.Authorization = new("Bearer", accessToken);
if (properties.HasExternalToken() && properties.GetExternalProvider() is string externalProvider)
{
// Set the external provider name as the scheme so we can do auth
// on the backend with the right configuration
req.Headers.TryAddWithoutValidation("X-Auth-Scheme", externalProvider);
}
};

// Use this HttpClient for all proxied requests
var client = new HttpMessageInvoker(new SocketsHttpHandler());

group.Map("{*path}", async (IHttpForwarder forwarder, HttpContext context) =>
var transformBuilder = routes.ServiceProvider.GetRequiredService<ITransformBuilder>();
var transform = transformBuilder.Create(b =>
{
await forwarder.SendAsync(context, todoUrl, client, transform);
b.AddRequestTransform(async c =>
{
var accessToken = await c.HttpContext.GetTokenAsync(TokenNames.AccessToken);
return Results.Empty;
c.ProxyRequest.Headers.Authorization = new("Bearer", accessToken);
});
});

group.MapForwarder("{*path}", todoUrl, new ForwarderRequestConfig(), transform);

return group;
}
}
58 changes: 2 additions & 56 deletions TodoApi/Authentication/AuthenticationExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,64 +1,10 @@
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication.JwtBearer;

namespace TodoApi;
namespace TodoApi;

public static class AuthenticationExtensions
{
public static WebApplicationBuilder AddAuthentication(this WebApplicationBuilder builder)
{
var authenticationBuilder = builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme);

// Add the local JWT bearer
authenticationBuilder.AddJwtBearer(options =>
{
// Let the client choose the scheme via a header. This will
// redirect to another. If none was specified we'll use our default scheme.
options.ForwardDefaultSelector = context => context.Request.Headers["X-Auth-Scheme"];
});

// An example of what the expected schema looks like
// "Authentication": {
// "Schemes": {
// "<scheme>": {
// <options>
// }
// }
// }

// TODO: Make this support any configured provider
var section = builder.Configuration.GetSection("Authentication:Schemes:Auth0");

if (section.Exists())
{
// This is what the auth0 configuration looks like:
//{
// "Authentication": {
// "Schemes": {
// "Auth0": {
// "ValidAudiences": [ "<your audience here>" ],
// "Authority": "<your authority here>"
// }
// }
// }
//}
authenticationBuilder.AddJwtBearer("Auth0", options =>
{
options.Events = new()
{
OnTokenValidated = context =>
{
if (context.Principal?.Identity is ClaimsIdentity identity)
{
// Add this claim in memory so that we can look up the user by provider name
identity.AddClaim(new("provider", "Auth0"));
}
return Task.CompletedTask;
}
};
});
}
builder.Services.AddAuthentication().AddJwtBearer();

return builder;
}
Expand Down
6 changes: 1 addition & 5 deletions TodoApi/Authorization/CurrentUserExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,11 @@ public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
// to set the current user without adding custom middleware.
_currentUser.Principal = principal;

var loginProvider = principal.FindFirstValue("provider");

if (principal.FindFirstValue(ClaimTypes.NameIdentifier) is { Length: > 0 } name)
{
// Resolve the user manager and see if the current user is a valid user in the database
// we do this once and store it on the current user.
_currentUser.User = loginProvider is null
? await _userManager.FindByNameAsync(name)
: await _userManager.FindByLoginAsync(loginProvider, name);
_currentUser.User = await _userManager.FindByNameAsync(name);
}

return principal;
Expand Down

0 comments on commit 7804305

Please sign in to comment.