/// <summary> /// Gets the expected value in a <see cref="X509Certificate2"/> for an <paramref name="configurationKey"/> using the specified <paramref name="services"/>. /// </summary> /// <param name="configurationKey">The configured key for which the expected certificate value is registered.</param> /// <param name="services">The services collections of the HTTP request pipeline to retrieve registered instances.</param> public async Task <string> GetExpectedCertificateValueForConfiguredKeyAsync(string configurationKey, IServiceProvider services) { Guard.NotNullOrWhitespace(configurationKey, nameof(configurationKey), "Configured key cannot be blank"); Guard.NotNull(services, nameof(services), "Registered services cannot be 'null'"); ISecretProvider userDefinedSecretProvider = services.GetService <ICachedSecretProvider>() ?? services.GetService <ISecretProvider>(); if (userDefinedSecretProvider == null) { throw new KeyNotFoundException( $"No configured {nameof(ICachedSecretProvider)} or {nameof(ISecretProvider)} implementation found in the request service container. " + "Please configure such an implementation (ex. in the Startup) of your application"); } Task <string> getValueAsync = userDefinedSecretProvider.Get(configurationKey); return(getValueAsync == null ? null : await getValueAsync); }
/// <summary> /// Called early in the filter pipeline to confirm request is authorized. /// </summary> /// <param name="context">The <see cref="T:Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext" />.</param> /// <returns> /// A <see cref="T:System.Threading.Tasks.Task" /> that on completion indicates the filter has executed. /// </returns> public async Task OnAuthorizationAsync(AuthorizationFilterContext context) { Guard.NotNull(context, nameof(context)); Guard.NotNull(context.HttpContext, nameof(context.HttpContext)); Guard.For <ArgumentException>(() => context.HttpContext.Request == null, "Invalid action context given without any HTTP request"); Guard.For <ArgumentException>(() => context.HttpContext.Request.Headers == null, "Invalid action context given without any HTTP request headers"); Guard.For <ArgumentException>(() => context.HttpContext.RequestServices == null, "Invalid action context given without any HTTP request services"); if (context.HttpContext.Request.Headers .TryGetValue(_headerName, out StringValues requestSecretHeaders)) { ISecretProvider userDefinedSecretProvider = context.HttpContext.RequestServices.GetService <ICachedSecretProvider>() ?? context.HttpContext.RequestServices.GetService <ISecretProvider>(); if (userDefinedSecretProvider == null) { throw new KeyNotFoundException( $"No configured {nameof(ICachedSecretProvider)} or {nameof(ISecretProvider)} implementation found in the request service container. " + "Please configure such an implementation (ex. in the Startup) of your application"); } string foundSecret = await userDefinedSecretProvider.Get(_secretName); if (foundSecret == null) { throw new SecretNotFoundException(_secretName); } if (requestSecretHeaders.Any(headerValue => !String.Equals(headerValue, foundSecret))) { context.Result = new UnauthorizedResult(); } } else { context.Result = new UnauthorizedResult(); } }
// This method gets called by the runtime. Use this method to add services to the container. // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { #if (SharedAccessKeyAuth || JwtAuth) #error Please provide a valid secret provider, for example Azure Key Vault: https://security.arcus-azure.net/features/secrets/consume-from-key-vault services.AddSingleton <ICachedSecretProvider>(serviceProvider => new CachedSecretProvider(secretProvider: null)); #endif #if CertificateAuth var certificateAuthenticationConfig = new CertificateAuthenticationConfigBuilder() .WithSubject(X509ValidationLocation.Configuration, "CertificateSubject") .Build(); services.AddScoped(serviceProvider => new CertificateAuthenticationValidator(certificateAuthenticationConfig)); #endif services.AddControllers(options => { options.ReturnHttpNotAcceptable = true; options.RespectBrowserAcceptHeader = true; RestrictToJsonContentType(options); AddEnumAsStringRepresentation(options); #if SharedAccessKeyAuth #warning Please provide a valid request header name and secret name to the shared access filter options.Filters.Add(new SharedAccessKeyAuthenticationFilter(headerName: "YOUR REQUEST HEADER NAME", queryParameterName: null, secretName: "YOUR SECRET NAME")); #endif #if CertificateAuth options.Filters.Add(new CertificateAuthenticationFilter()); #endif #if JwtAuth AuthorizationPolicy policy = new AuthorizationPolicyBuilder() .RequireRole("Admin") .RequireAuthenticatedUser() .Build(); options.Filters.Add(new AuthorizeFilter(policy)); #endif }); #if JwtAuth #error Use previously registered secret provider, for example Azure Key Vault: https://security.arcus-azure.net/features/secrets/consume-from-key-vault ISecretProvider secretProvider = null; services.AddAuthentication(x => { x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(x => { string key = secretProvider.Get("JwtSigningKey").GetAwaiter().GetResult(); x.SaveToken = true; x.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key)), ValidateIssuer = true, ValidIssuer = Configuration.GetValue <string>("Jwt:Issuer"), ValidateAudience = true, ValidAudience = Configuration.GetValue <string>("Jwt:Audience") }; }); #endif services.AddHealthChecks(); #if ExcludeCorrelation #else services.AddCorrelation(); #endif #if ExcludeOpenApi #else //[#if DEBUG] var openApiInformation = new OpenApiInfo { Title = "Arcus.Templates.WebApi", Version = "v1" }; services.AddSwaggerGen(swaggerGenerationOptions => { swaggerGenerationOptions.SwaggerDoc("v1", openApiInformation); swaggerGenerationOptions.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "Arcus.Templates.WebApi.Open-Api.xml")); }); //[#endif] #endif }