Add project files.
This commit is contained in:
		
							
								
								
									
										97
									
								
								Core.Cerberos.Adapters/Extensions/AuthenticationExtension.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								Core.Cerberos.Adapters/Extensions/AuthenticationExtension.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,97 @@ | ||||
| // *********************************************************************** | ||||
| // <copyright file="AuthExtension.cs"> | ||||
| //     Heath | ||||
| // </copyright> | ||||
| // *********************************************************************** | ||||
|  | ||||
| using Core.Cerberos.Adapters.Common.Constants; | ||||
| using Core.Cerberos.Adapters.Contracts; | ||||
| using Core.Cerberos.Adapters.Handlers; | ||||
| using Core.Cerberos.Adapters.Options; | ||||
| using Core.Cerberos.Adapters.Services; | ||||
| using Microsoft.AspNetCore.Authentication.JwtBearer; | ||||
| using Microsoft.AspNetCore.Authorization; | ||||
| using Microsoft.Extensions.Configuration; | ||||
| using Microsoft.Extensions.DependencyInjection; | ||||
| using Microsoft.Identity.Web; | ||||
| using Microsoft.IdentityModel.Tokens; | ||||
| using System.Security.Cryptography; | ||||
|  | ||||
| namespace Core.Cerberos.Adapters.Extensions | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Extension methods for configuring authentication with various Azure AD setups. | ||||
|     /// </summary> | ||||
|     public static class AuthenticationExtension | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Configures authentication using Azure AD for an API that requires downstream API access. | ||||
|         /// </summary> | ||||
|         /// <param name="services">The <see cref="IServiceCollection"/> to add the services to.</param> | ||||
|         /// <param name="configuration">The <see cref="IConfiguration"/> containing Azure AD configuration settings.</param> | ||||
|         public static void ConfigureAuthentication(this IServiceCollection services, IConfiguration configuration, AuthSettings authSettings) | ||||
|         { | ||||
|             var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? string.Empty; | ||||
|  | ||||
|             var azureAdInMemorySettings = new Dictionary<string, string?> | ||||
|             { | ||||
|                 { "AzureAdB2C:Instance",  authSettings.AzureADInstance ?? string.Empty }, | ||||
|                 { "AzureAdB2C:TenantId", authSettings.AzureADTenantId ?? string.Empty }, | ||||
|                 { "AzureAdB2C:ClientId", authSettings.AzureADClientId ?? string.Empty }, | ||||
|                 { "AzureAdB2C:ClientSecret", authSettings.AzureADClientSecret ?? string.Empty } | ||||
|             }; | ||||
|  | ||||
|             var configurationBuilder = new ConfigurationBuilder() | ||||
|                 .AddConfiguration(configuration) | ||||
|                 .AddInMemoryCollection(azureAdInMemorySettings); | ||||
|  | ||||
|             var combinedConfiguration = configurationBuilder.Build(); | ||||
|  | ||||
|             services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) | ||||
|                .AddMicrosoftIdentityWebApi(combinedConfiguration.GetSection("AzureAdB2C"), Schemes.AzureScheme) | ||||
|                .EnableTokenAcquisitionToCallDownstreamApi() | ||||
|                .AddMicrosoftGraph(configuration.GetSection("MicrosoftGraph")) | ||||
|                .AddInMemoryTokenCaches(); | ||||
|  | ||||
|             var rsa = RSA.Create(); | ||||
|             rsa.ImportFromPem(authSettings.PrivateKey?.ToCharArray()); | ||||
|             var rsaPrivateKey = new RsaSecurityKey(rsa); | ||||
|  | ||||
|             var rsaPublic = RSA.Create(); | ||||
|             rsaPublic.ImportFromPem(authSettings.PublicKey?.ToCharArray()); | ||||
|             var rsaPublicKey = new RsaSecurityKey(rsaPublic); | ||||
|  | ||||
|             var jwtAppSettingOptions = configuration.GetSection("B2C:JwtIssuerOptions"); | ||||
|             var jwtIssuerOptions = jwtAppSettingOptions.Get<JwtIssuerOptions>(); | ||||
|  | ||||
|             if (string.IsNullOrEmpty(jwtIssuerOptions?.Issuer) || string.IsNullOrEmpty(jwtIssuerOptions.Audience)) | ||||
|                 throw new InvalidOperationException("JwtIssuerOptions are not configured correctly."); | ||||
|  | ||||
|             services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) | ||||
|             .AddJwtBearer(Schemes.HeathScheme, x => | ||||
|             { | ||||
|                 x.TokenValidationParameters = new TokenValidationParameters | ||||
|                 { | ||||
|                     ValidIssuer = jwtIssuerOptions?.Issuer, | ||||
|                     ValidateIssuer = true, | ||||
|                     ValidateAudience = true, | ||||
|                     ValidateLifetime = true, | ||||
|                     ValidateIssuerSigningKey = true, | ||||
|                     ValidAudience = jwtIssuerOptions?.Audience, | ||||
|                     IssuerSigningKey = rsaPublicKey | ||||
|                 }; | ||||
|             }); | ||||
|  | ||||
|             services.Configure<JwtIssuerOptions>(options => | ||||
|             { | ||||
|                 options.Issuer = jwtIssuerOptions?.Issuer; | ||||
|                 options.Audience = jwtIssuerOptions?.Audience; | ||||
|                 options.SigningCredentials = new SigningCredentials(rsaPrivateKey, SecurityAlgorithms.RsaSha256); | ||||
|             }); | ||||
|  | ||||
|             services.AddSingleton(jwtAppSettingOptions); | ||||
|             services.AddTransient<IAuthorizationHandler, PermissionsAuthorizationHandler>(); | ||||
|             services.AddTransient<ITokenService, TokenService>(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										193
									
								
								Core.Cerberos.Adapters/Extensions/SwaggerExtensions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								Core.Cerberos.Adapters/Extensions/SwaggerExtensions.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,193 @@ | ||||
| // *********************************************************************** | ||||
| // <copyright file="SwaggerExtensions.cs"> | ||||
| //     Heath | ||||
| // </copyright> | ||||
| // *********************************************************************** | ||||
|  | ||||
| using Asp.Versioning.ApiExplorer; | ||||
| using Core.Cerberos.Adapters.Common.Constants; | ||||
| using Core.Cerberos.Adapters.Extensions; | ||||
| using Microsoft.AspNetCore.Builder; | ||||
| using Microsoft.Extensions.Configuration; | ||||
| using Microsoft.Extensions.DependencyInjection; | ||||
| using Microsoft.Extensions.Options; | ||||
| using Microsoft.OpenApi.Any; | ||||
| using Microsoft.OpenApi.Models; | ||||
| using Swashbuckle.AspNetCore.SwaggerGen; | ||||
| using Swashbuckle.AspNetCore.SwaggerUI; | ||||
|  | ||||
| namespace Core.Cerberos.Adapters.Extensions | ||||
| { | ||||
|     /// <summary> | ||||
|     /// Extension methods for configuring Swagger documentation and UI. | ||||
|     /// </summary> | ||||
|     public static class SwaggerExtensions | ||||
|     { | ||||
|         private static readonly string? environment = Environment.GetEnvironmentVariable(EnvironmentVariables.Stage); | ||||
|         /// <summary> | ||||
|         /// Adds Swagger services to the specified <see cref="IServiceCollection"/>. | ||||
|         /// </summary> | ||||
|         /// <param name="services">The <see cref="IServiceCollection"/> to add the services to.</param> | ||||
|         public static void AddSwagger(this IServiceCollection services, IConfiguration configuration, string DocumentationFile, AuthSettings authSettings) | ||||
|         { | ||||
|             services.AddEndpointsApiExplorer(); | ||||
|             services.AddSwaggerGen(configuration, DocumentationFile, authSettings); | ||||
|             services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>(); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Configures Swagger generation with OAuth2 security and XML comments. | ||||
|         /// </summary> | ||||
|         /// <param name="services">The <see cref="IServiceCollection"/> to add the services to.</param> | ||||
|         /// <param name="configuration">The <see cref="IConfiguration"/> containing Swagger and OAuth2 configuration settings.</param> | ||||
|         public static void AddSwaggerGen(this IServiceCollection services, IConfiguration configuration, string DocumentationFile, AuthSettings authSettings) | ||||
|         { | ||||
|             services.AddSwaggerGen(c => | ||||
|                 { | ||||
|                     c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme | ||||
|                     { | ||||
|                         Description = "OAuth2.0 Authorization Code flow", | ||||
|                         Name = "oauth2.0", | ||||
|                         Type = SecuritySchemeType.OAuth2, | ||||
|                         Flows = new OpenApiOAuthFlows | ||||
|                         { | ||||
|                             AuthorizationCode = new OpenApiOAuthFlow | ||||
|                             { | ||||
|                                 AuthorizationUrl = new Uri(authSettings.HeathCerberosAppAuthorizationUrl ?? string.Empty), | ||||
|                                 TokenUrl = new Uri(authSettings.HeathCerberosAppTokenUrl ?? string.Empty), | ||||
|                                 Scopes = new Dictionary<string, string> | ||||
|                                 { | ||||
|                                 { authSettings.HeathCerberosAppScope ?? string.Empty, "Access API as User" } | ||||
|                                 } | ||||
|                             } | ||||
|                         } | ||||
|                     }); | ||||
|  | ||||
|                     c.AddSecurityRequirement(new OpenApiSecurityRequirement | ||||
|                     { | ||||
|                     { | ||||
|                         new OpenApiSecurityScheme | ||||
|                         { | ||||
|                             Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "oauth2" } | ||||
|                         }, | ||||
|                         new[] { authSettings.HeathCerberosAppScope } | ||||
|                     } | ||||
|                     }); | ||||
|  | ||||
|                     c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme | ||||
|                     { | ||||
|                         Description = "JWT Authorization header using the Bearer scheme", | ||||
|                         Name = "Authorization", | ||||
|                         In = ParameterLocation.Header, | ||||
|                         Type = SecuritySchemeType.Http, | ||||
|                         Scheme = "bearer", | ||||
|                         BearerFormat = "JWT" | ||||
|                     }); | ||||
|  | ||||
|                     c.AddSecurityRequirement(new OpenApiSecurityRequirement | ||||
|                     { | ||||
|                     { | ||||
|                         new OpenApiSecurityScheme | ||||
|                         { | ||||
|                             Reference = new OpenApiReference | ||||
|                             { | ||||
|                                 Type = ReferenceType.SecurityScheme, | ||||
|                                 Id = "Bearer" | ||||
|                             } | ||||
|                         }, | ||||
|                         Array.Empty<string>() | ||||
|                     } | ||||
|                     }); | ||||
|  | ||||
|                     var filePath = Path.Combine(AppContext.BaseDirectory, DocumentationFile); | ||||
|                     c.IncludeXmlComments(filePath); | ||||
|                     c.SchemaFilter<EnumSchemaFilter>(); | ||||
|                 }); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Configures Swagger and Swagger UI for the application. | ||||
|         /// </summary> | ||||
|         /// <param name="app">The <see cref="WebApplication"/> instance.</param> | ||||
|         /// <param name="configuration">The <see cref="IConfiguration"/> containing Swagger configuration settings.</param> | ||||
|         public static void ConfigureSwagger(this WebApplication app, IConfiguration configuration) | ||||
|         { | ||||
|             app.UseSwagger(); | ||||
|             app.UseSwaggerUI(options => | ||||
|             { | ||||
|                 foreach (var version in app.DescribeApiVersions().Select(version => version.GroupName)) | ||||
|                     options.SwaggerEndpoint($"/swagger/{version}/swagger.json", version); | ||||
|  | ||||
|                 options.DisplayRequestDuration(); | ||||
|                 options.EnableTryItOutByDefault(); | ||||
|                 options.DocExpansion(DocExpansion.None); | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Configures Swagger UI for the application with OAuth2 settings. | ||||
|         /// </summary> | ||||
|         /// <param name="app">The <see cref="WebApplication"/> instance.</param> | ||||
|         /// <param name="configuration">The <see cref="IConfiguration"/> containing Swagger UI and OAuth2 configuration settings.</param> | ||||
|         public static void UseSwaggerUI(this WebApplication app, IConfiguration configuration, AuthSettings authSettings) | ||||
|         { | ||||
|             app.UseSwaggerUI(options => | ||||
|             { | ||||
|                 options.SwaggerEndpoint("/swagger/v1/swagger.json", "Custom Auth API with Azure AD v1"); | ||||
|                 options.OAuthClientId(authSettings.HeathCerberosAppClientId); | ||||
|                 options.OAuthUsePkce(); | ||||
|                 options.OAuthScopeSeparator(" "); | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         /// <summary> | ||||
|         /// Adds API versioning and API explorer to the application. | ||||
|         /// </summary> | ||||
|         /// <param name="services">The <see cref="IServiceCollection"/> to add the services to.</param> | ||||
|         /// <returns>The modified <see cref="IServiceCollection"/> instance.</returns> | ||||
|         public static IServiceCollection AddVersioning(this IServiceCollection services, IConfiguration configuration) | ||||
|         { | ||||
|             services.AddApiVersioning(options => options.ReportApiVersions = true) | ||||
|                    .AddApiExplorer(options => | ||||
|                    { | ||||
|                        options.GroupNameFormat = "'v'VVV"; | ||||
|                        options.SubstituteApiVersionInUrl = true; | ||||
|                    }); | ||||
|  | ||||
|             return services; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /// <summary> | ||||
|     /// Configures Swagger generation options. | ||||
|     /// </summary> | ||||
|     public class ConfigureSwaggerOptions(IApiVersionDescriptionProvider provider) : IConfigureOptions<SwaggerGenOptions> | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// Configures SwaggerGen options. | ||||
|         /// </summary> | ||||
|         /// <param name="options">The SwaggerGen options to configure.</param> | ||||
|         public void Configure(SwaggerGenOptions options) | ||||
|         { | ||||
|             foreach (var description in provider.ApiVersionDescriptions) | ||||
|             { | ||||
|                 options.SwaggerDoc(description.GroupName, new OpenApiInfo | ||||
|                 { | ||||
|                     Title = AppDomain.CurrentDomain.FriendlyName, | ||||
|                     Version = description.ApiVersion.ToString() | ||||
|                 }); | ||||
|             } | ||||
|  | ||||
|             // Map DateOnly type to Swagger schema | ||||
|             options.MapType<DateOnly>(() => new OpenApiSchema | ||||
|             { | ||||
|                 Type = "string", | ||||
|                 Format = "date", | ||||
|                 Example = new OpenApiString(DateOnly.MinValue.ToString()) | ||||
|             }); | ||||
|  | ||||
|             // Customize schema IDs for Swagger | ||||
|             options.CustomSchemaIds(type => type.ToString().Replace("+", ".")); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										22
									
								
								Core.Cerberos.Adapters/Extensions/TelemetryExtensions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								Core.Cerberos.Adapters/Extensions/TelemetryExtensions.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| using Microsoft.Extensions.DependencyInjection; | ||||
| using OpenTelemetry.Logs; | ||||
| using OpenTelemetry.Metrics; | ||||
| using OpenTelemetry.Resources; | ||||
| using OpenTelemetry.Trace; | ||||
|  | ||||
| namespace Core.Cerberos.Adapters.Extensions | ||||
| { | ||||
|     public static class TelemetryExtensions | ||||
|     { | ||||
|         public static void AddTelemetry(this IServiceCollection services) | ||||
|         { | ||||
|             // Add OpenTelemetry Tracing | ||||
|             services.AddOpenTelemetry() | ||||
|                     .ConfigureResource(resource => resource.AddService("lsa.dashboard.bff.api")) | ||||
|                     .WithTracing(tracing => tracing.AddAspNetCoreInstrumentation().AddConsoleExporter()) | ||||
|                     .WithMetrics(metrics => metrics.AddAspNetCoreInstrumentation().AddConsoleExporter()). | ||||
|                      WithLogging(logs => logs.AddConsoleExporter()); | ||||
|  | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,23 @@ | ||||
| using Microsoft.AspNetCore.Http; | ||||
|  | ||||
| namespace Core.Cerberos.Adapters.Extensions | ||||
| { | ||||
|     public sealed class TrackingMechanismExtension : DelegatingHandler | ||||
|     { | ||||
|         private readonly IHttpContextAccessor _httpContextAccessor; | ||||
|  | ||||
|         public TrackingMechanismExtension(IHttpContextAccessor httpContextAccessor) | ||||
|         { | ||||
|             _httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor)); | ||||
|         } | ||||
|  | ||||
|         protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) | ||||
|         { | ||||
|             if (_httpContextAccessor.HttpContext.Items.TryGetValue("TrackingId", out var trackingId)) | ||||
|             { | ||||
|                 request.Headers.Add("TrackingId", trackingId.ToString()); | ||||
|             } | ||||
|             return await base.SendAsync(request, cancellationToken).ConfigureAwait(false); | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Sergio Matias Urquin
					Sergio Matias Urquin