No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

140 líneas
5.0KB

  1. using System.Security.Claims;
  2. using System.Text;
  3. using Campaign_Tracker.Server.Authentication;
  4. using Campaign_Tracker.Server.Configuration;
  5. using Microsoft.AspNetCore.Authentication.JwtBearer;
  6. using Microsoft.IdentityModel.Protocols.OpenIdConnect;
  7. using Microsoft.IdentityModel.Tokens;
  8. var builder = WebApplication.CreateBuilder(args);
  9. DotEnvConfiguration.Load(builder.Configuration, builder.Environment.ContentRootPath);
  10. // Add services to the container.
  11. builder.Services.AddControllers();
  12. // Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
  13. builder.Services.AddOpenApi();
  14. builder.Services.Configure<KeycloakOptions>(builder.Configuration.GetSection(KeycloakOptions.SectionName));
  15. builder.Services.AddSingleton<IAuthenticationAuditStore, InMemoryAuthenticationAuditStore>();
  16. builder.Services.AddHttpClient<IKeycloakTokenClient, KeycloakTokenClient>();
  17. var allowedOrigins = builder.Configuration.GetSection("AllowedOrigins").Get<string[]>() ?? [];
  18. builder.Services.AddCors(options =>
  19. {
  20. options.AddPolicy("ConfiguredOrigins", policy =>
  21. {
  22. if (allowedOrigins.Length > 0)
  23. {
  24. policy.WithOrigins(allowedOrigins)
  25. .AllowAnyHeader()
  26. .AllowAnyMethod();
  27. }
  28. });
  29. });
  30. var keycloakOptions = builder.Configuration
  31. .GetSection(KeycloakOptions.SectionName)
  32. .Get<KeycloakOptions>() ?? new KeycloakOptions();
  33. builder.Services
  34. .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
  35. .AddJwtBearer(options =>
  36. {
  37. options.Audience = keycloakOptions.TokenAudience;
  38. options.RequireHttpsMetadata = !keycloakOptions.DisableHttpsMetadata;
  39. if (!string.IsNullOrWhiteSpace(keycloakOptions.MetadataAddress))
  40. {
  41. options.MetadataAddress = keycloakOptions.MetadataAddress;
  42. }
  43. options.TokenValidationParameters = new TokenValidationParameters
  44. {
  45. ValidateIssuer = true,
  46. ValidIssuer = keycloakOptions.TokenIssuer,
  47. ValidateAudience = true,
  48. ValidAudience = keycloakOptions.TokenAudience,
  49. ValidateLifetime = true,
  50. NameClaimType = ClaimTypes.Name,
  51. RoleClaimType = ClaimTypes.Role,
  52. };
  53. if (!string.IsNullOrWhiteSpace(keycloakOptions.TestSigningKey))
  54. {
  55. var issuerSigningKey =
  56. new SymmetricSecurityKey(Encoding.UTF8.GetBytes(keycloakOptions.TestSigningKey));
  57. options.TokenValidationParameters.ValidateIssuerSigningKey = true;
  58. options.TokenValidationParameters.IssuerSigningKey = issuerSigningKey;
  59. options.TokenValidationParameters.IssuerSigningKeys = [issuerSigningKey];
  60. options.Configuration = new OpenIdConnectConfiguration
  61. {
  62. Issuer = keycloakOptions.TokenIssuer,
  63. };
  64. options.Configuration.SigningKeys.Add(issuerSigningKey);
  65. }
  66. else
  67. {
  68. options.Authority = keycloakOptions.Authority;
  69. }
  70. options.Events = new JwtBearerEvents
  71. {
  72. OnTokenValidated = context =>
  73. {
  74. var auditStore = context.HttpContext.RequestServices
  75. .GetRequiredService<IAuthenticationAuditStore>();
  76. var subject = context.Principal?.Identity?.Name
  77. ?? context.Principal?.FindFirstValue(ClaimTypes.NameIdentifier)
  78. ?? "unknown";
  79. auditStore.RecordSuccess(subject, context.HttpContext.TraceIdentifier);
  80. return Task.CompletedTask;
  81. },
  82. OnAuthenticationFailed = context =>
  83. {
  84. var auditStore = context.HttpContext.RequestServices
  85. .GetRequiredService<IAuthenticationAuditStore>();
  86. var reason = context.Exception is null
  87. ? "invalid bearer token"
  88. : $"invalid bearer token: {context.Exception.GetType().Name}";
  89. auditStore.RecordFailure(reason, context.HttpContext.TraceIdentifier);
  90. return Task.CompletedTask;
  91. },
  92. OnChallenge = context =>
  93. {
  94. if (context.AuthenticateFailure is null &&
  95. context.Request.Headers.ContainsKey("Authorization"))
  96. {
  97. var auditStore = context.HttpContext.RequestServices
  98. .GetRequiredService<IAuthenticationAuditStore>();
  99. auditStore.RecordFailure("invalid authorization header", context.HttpContext.TraceIdentifier);
  100. }
  101. return Task.CompletedTask;
  102. },
  103. };
  104. });
  105. builder.Services.AddAuthorization();
  106. var app = builder.Build();
  107. // Configure the HTTP request pipeline.
  108. if (app.Environment.IsDevelopment())
  109. {
  110. app.MapOpenApi();
  111. }
  112. app.UseHttpsRedirection();
  113. app.UseCors("ConfiguredOrigins");
  114. app.UseAuthentication();
  115. app.UseAuthorization();
  116. app.MapControllers();
  117. app.MapGet("/health", () => Results.Ok(new { status = "ok" }));
  118. app.Run();
  119. public partial class Program;

Powered by TurnKey Linux.