Program.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. using System.Security.Claims;
  2. using Fido2NetLib;
  3. using Microsoft.AspNetCore.Authentication.JwtBearer;
  4. using Microsoft.AspNetCore.Mvc;
  5. using Microsoft.IdentityModel.Tokens;
  6. using Passwordless;
  7. // TODO: RoslynPad code for key generation
  8. var jwk = JsonWebKey.Create(File.ReadAllText("./demo-jwk.json"));
  9. var builder = WebApplication.CreateBuilder(args);
  10. // Add services to the container.
  11. // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
  12. builder.Services.AddEndpointsApiExplorer();
  13. builder.Services.AddSwaggerGen();
  14. builder.Services.AddFido2(options =>
  15. {
  16. options.ServerDomain = "localhost";
  17. options.ServerName = "FIDO2 Test";
  18. options.Origins = ["http://localhost:5172"];
  19. options.TimestampDriftTolerance = 300000;
  20. });
  21. builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
  22. .AddJwtBearer(options =>
  23. {
  24. options.Events = new JwtBearerEvents()
  25. {
  26. OnAuthenticationFailed = ctx =>
  27. {
  28. Console.WriteLine(ctx.Exception);
  29. return Task.CompletedTask;
  30. },
  31. OnTokenValidated = ctx =>
  32. {
  33. Console.WriteLine($"Valid token from {ctx.SecurityToken.Issuer}");
  34. return Task.CompletedTask;
  35. }
  36. };
  37. options.RequireHttpsMetadata = false; // dev only!!!
  38. options.Authority = "http://localhost:5172";
  39. options.TokenValidationParameters = new TokenValidationParameters
  40. {
  41. IssuerSigningKey = jwk,
  42. ValidIssuer = "http://localhost:5172",
  43. ValidAudience = "http://localhost:5172",
  44. NameClaimType = ClaimTypes.NameIdentifier, // important to get the "sub" claim mapped to User.Identity.Name
  45. RoleClaimType = ClaimTypes.Role,
  46. };
  47. });
  48. builder.Services.AddAuthorization(authorizationOptions =>
  49. {
  50. authorizationOptions.AddPolicy("ProtectedPolicy", policyBuilder => policyBuilder
  51. .RequireClaim("permissions", "MagicClaim")
  52. .RequireRole("grunt"));
  53. });
  54. builder.Services.AddMemoryCache();
  55. builder.Services.Configure<JwtConfig>(config => config.Key = jwk);
  56. builder.Services.AddTransient<OptionsCache>();
  57. builder.Services.AddTransient<CredentialManager>();
  58. var app = builder.Build();
  59. // Configure the HTTP request pipeline.
  60. if (app.Environment.IsDevelopment())
  61. {
  62. app.UseSwagger();
  63. app.UseSwaggerUI();
  64. }
  65. app.UseStaticFiles();
  66. app.UseHttpsRedirection();
  67. app.UseAuthorization();
  68. app.MapGet("/buildCredentialOptions", ([FromQuery] string login, CredentialManager credMan) =>
  69. credMan.BuildCredentialOptions(login))
  70. .WithName("BuildCredentialOptions")
  71. .WithOpenApi();
  72. app.MapPost("/registerCredential", async ([FromQuery] string login, [FromBody] AuthenticatorAttestationRawResponse attestationResponse, CredentialManager credMan) =>
  73. await credMan.RegisterCredential(login, attestationResponse))
  74. .WithName("RegisterCredential")
  75. .WithOpenApi();
  76. app.MapGet("/buildAssertionOptions", async ([FromQuery] string login, CredentialManager credMan) =>
  77. await credMan.BuildAssertionOptions(login))
  78. .WithName("BuildAssertionOptions")
  79. .WithOpenApi();
  80. app.MapPost("/verifyCredential", async ([FromBody] AuthenticatorAssertionRawResponse assertionResponse, CredentialManager credMan) =>
  81. Results.Json(await credMan.VerifyCredential(assertionResponse)))
  82. .WithName("VerifyCredential")
  83. .WithOpenApi();
  84. app
  85. .MapGet("/protected", (HttpContext context) =>
  86. {
  87. var data = new Dictionary<string, object>
  88. {
  89. ["Status"] = "Success!",
  90. ["UserName"] = context.User?.Identity?.Name ?? "<unknown>",
  91. ["Permissions"] = context.User?.Claims.Where(c => c.Type == "permissions").Select(c => c.Value) ?? Enumerable.Empty<string>(),
  92. ["IsAdmin"] = context.User?.IsInRole("admin"),
  93. ["IsGrunt"] = context.User?.IsInRole("grunt"),
  94. ["IsNoob"] = context.User?.IsInRole("noob"),
  95. };
  96. return data;
  97. })
  98. .WithName("Protected")
  99. .RequireAuthorization("ProtectedPolicy");
  100. // .RequireAuthorization(policy =>
  101. // {
  102. // policy.RequireAuthenticatedUser();
  103. // });
  104. app.Run();