Przeglądaj źródła

Improved token mapping and added debug information to protected result

Lukas Angerer 2 lat temu
rodzic
commit
b562a65cc5
4 zmienionych plików z 32 dodań i 9 usunięć
  1. 3 0
      CredentialManager.cs
  2. 27 7
      Program.cs
  3. 1 1
      data/my username.json
  4. 1 1
      wwwroot/main.js

+ 3 - 0
CredentialManager.cs

@@ -166,6 +166,8 @@ public class CredentialManager
         await using var fileStream2 = File.OpenWrite($"./data/{optionsWithName.Name}.json");
         await JsonSerializer.SerializeAsync(fileStream2, assertionVerification, _jsonOptions);
         
+        // we could also sign with a certificate from the Windows cert store
+        //
         // var store = new X509Store(StoreName.My);
         // store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
         // var collection = store.Certificates.Find(X509FindType.FindByThumbprint, "CE63FA2B6BCD8460150E7FBF9B138E9ED9852E3A", false);
@@ -179,6 +181,7 @@ public class CredentialManager
             .ExpirationTime(DateTime.UtcNow.AddHours(1))
             .Subject(optionsWithName.Name)
             .AddClaim("permissions", new string[] { "MagicClaim", "Foo", "Test" })
+            .AddClaim("roles", new string[] { "admin", "grunt" })
             .AddClaim("scope", "passkey")
             .Encode();
 

+ 27 - 7
Program.cs

@@ -1,3 +1,4 @@
+using System.Security.Claims;
 using Fido2NetLib;
 using Microsoft.AspNetCore.Authentication.JwtBearer;
 using Microsoft.AspNetCore.Mvc;
@@ -42,13 +43,17 @@ builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
         {
             IssuerSigningKey = jwk,
             ValidIssuer = "http://localhost:5172",
-            ValidAudience = "http://localhost:5172"
+            ValidAudience = "http://localhost:5172",
+            NameClaimType = ClaimTypes.NameIdentifier, // important to get the "sub" claim mapped to User.Identity.Name
+            RoleClaimType = ClaimTypes.Role,
         };
     });
 
 builder.Services.AddAuthorization(authorizationOptions =>
 {
-    authorizationOptions.AddPolicy("MagicClaim", policyBuilder => policyBuilder.RequireClaim("permissions", "MagicClaim"));
+    authorizationOptions.AddPolicy("ProtectedPolicy", policyBuilder => policyBuilder
+        .RequireClaim("permissions", "MagicClaim")
+        .RequireRole("grunt"));
 });
 builder.Services.AddMemoryCache();
 builder.Services.Configure<JwtConfig>(config => config.Key = jwk);
@@ -88,10 +93,25 @@ app.MapPost("/verifyCredential", async ([FromBody] AuthenticatorAssertionRawResp
     .WithName("VerifyCredential")
     .WithOpenApi();
 
-app.MapGet("/protected", () => Results.Json("Success!")).WithName("Protected").RequireAuthorization(policy =>
-{
-    policy.RequireAuthenticatedUser();
-    //policy.RequireClaim("MagicClaim");
-});
+app
+    .MapGet("/protected", (HttpContext context) =>
+    {
+        var data = new Dictionary<string, object>
+        {
+            ["Status"] = "Success!",
+            ["UserName"] = context.User?.Identity?.Name ?? "<unknown>",
+            ["Permissions"] = context.User?.Claims.Where(c => c.Type == "permissions").Select(c => c.Value) ?? Enumerable.Empty<string>(),
+            ["IsAdmin"] = context.User?.IsInRole("admin"),
+            ["IsGrunt"] = context.User?.IsInRole("grunt"),
+            ["IsNoob"] = context.User?.IsInRole("noob"),
+        };
+        return data;
+    })
+    .WithName("Protected")
+    .RequireAuthorization("ProtectedPolicy");
+    // .RequireAuthorization(policy =>
+    // {
+    //     policy.RequireAuthenticatedUser();
+    // });
 
 app.Run();

+ 1 - 1
data/my username.json

@@ -10,7 +10,7 @@
   "AttestationCertificate": null,
   "AttestationCertificateChain": [],
   "CredentialId": "7M3KnPu2OYqBI83iLPkHyaiuOTX4AsR9qg6fx9hOJdrdfTdk0a3Jd09CjVDJV/qxPTPJFlS02P49Gpp2yewx+g==",
-  "Counter": 84,
+  "Counter": 92,
   "status": null,
   "errorMessage": null
 }

+ 1 - 1
wwwroot/main.js

@@ -284,7 +284,7 @@ class ApiHandler {
         const data = response.status === 200 ? await response.json() : await response.text();
         
         if (response.status === 200) {
-            this.responseElement.textContent = JSON.stringify(data);
+            this.responseElement.textContent = JSON.stringify(data, null, 2);
         } else {
             this.responseElement.textContent = `${response.status} ${response.statusText} - ${data}`;
         }