Redirect to HTTPS in Blazor - asp.net-core

I have a blazor app.
I hosted it on server and have access with https.
But when i do redirect (in one controller), happens exception.
Startap.cs
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseResponseCompression();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseMvc(routes =>
{
routes.MapRoute(name: "default", template: "{controller}/{action}/{id?}");
});
app.Map("/schedule", subdirApp =>
{
subdirApp.UseBlazor<Client.Startup>();
});
}
And method in controller
[HttpGet]
[Route("***")]
public IActionResult Return()
{
FileStream fs = new FileStream(_filePath, FileMode.Open);
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
List<ScheduleEntity> _list = (List<ScheduleEntity>)formatter.Deserialize(fs);
foreach (var x in _list)
Schedules.Add(x);
fs.Close();
return Redirect("~//schedule");
}
Exception
Please, help me

These API responses can be a bit misleading. Without seeing the rest of your code around the configuration of endpoints, I suspect this might be a CORS issue with the API.
Try adding the following code to the public void Configure(IApplicationBuilder app, IHostingEnvironment env) method in your API's Startup.cs class:
app.UseCors(opts => opts
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
);
The fetch response may be due to the request preflight being rejected.
Having said that, the first exception message is saying you're trying to load insecure content, so I'd also check your Blazor front-end app's configuration to see what the API client is requesting and ensure the API endpoint certificate is valid?

Related

"Issuer name does not match authority" error when using reverse proxy in front of SSL terminating load-balancer

I am trying to deploy our data API using APIgee proxy. The data API is using .NET Core 3.0 on an IIS server on AWS EC2 instance:
When I make a call to the data API using Apigee proxy I am getting this exception on the IIS server:
Category: IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationHandler
EventId: 0
RequestId: 80003dde-0002-fe00-b63f-84710c7967bb
RequestPath: /v0.1/wells/dpr
SpanId: |74716527-4b0a0a0f46d32af3.
TraceId: 74716527-4b0a0a0f46d32af3
ParentId:
Policy error while contacting the discovery endpoint https://example.com: Issuer name does not match authority: http://example.com
Exception:
System.InvalidOperationException: Policy error while contacting the discovery endpoint https://example.com: Issuer name does not match authority: http://example.com
at IdentityModel.AspNetCore.OAuth2Introspection.PostConfigureOAuth2IntrospectionOptions.GetIntrospectionEndpointFromDiscoveryDocument(OAuth2IntrospectionOptions options)
at IdentityModel.AspNetCore.OAuth2Introspection.PostConfigureOAuth2IntrospectionOptions.InitializeIntrospectionClient(OAuth2IntrospectionOptions options)
at IdentityModel.AspNetCore.OAuth2Introspection.OAuth2IntrospectionHandler.LoadClaimsForToken(String token)
at IdentityModel.AspNetCore.OAuth2Introspection.OAuth2IntrospectionHandler.HandleAuthenticateAsync()
at Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.AuthenticateAsync()
at Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context, String scheme)
at IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationHandler.HandleAuthenticateAsync()
From what I can see, the issue here is that the Loab-balancer is performing the SSL termination and making a call to the IIS server using HTTP and not HTTPS that is why the issuer name does not match. I have tried adding UseForwardedHeaders line to our .NET Core API:
public static IApplicationBuilder UseIdServer(this IApplicationBuilder app)
{
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
app.UseIdentityServer();
return app;
}
which is called here
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app
.UseCORS()
.UseCustomCookiePolicy(env)
.UseIdServer()
.UseRouting()
.UseAuth()
.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
However, that did not fix the issue.
Update 1:
I have also tried configuring the ForwardedHeaders like that in my startup.cs as suggested on the MS docs without success:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseForwardedHeaders();
...
}
Update 2
I tried overriding the request schema to https in the Configure method in Startup.cs as suggested in MS docs:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.Use((context, next) =>
{
context.Request.Scheme = "https";
return next();
});
...
}
That has resolved the issue. However, I am wondering how I can properly configure the X-Forwarded-* headers in the middleware.
Update 3
Thanks to #Chen who pointed me to resource which stated that I can configure the ForwardedHeaders in the Configure method like so
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedProto
});
...
}
Previously I tried the same but I used both ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto. For some reason, using just ForwardedHeaders.XForwardedProto resolved the issue.

CORS problem with custom controller and CustomClientStore in IdentityServer4

I want to add a custom end-point into IdentityServer4 but when I call API from another site, I have a CORS error.
I use a CustomClientStore to load my clients so i need to add CustomCorsPolicyService
Access to XMLHttpRequest at 'http://localhost:8082/embedded/log' from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
In Startup, I add my CustomClientStore and CustomCorsPolicyService
public void ConfigureServices(IServiceCollection services)
{
...
CustomClientStore.Init(_Configuration);
var builder = services.AddIdentityServer()
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiScopes(Config.GetApiScopes())
.AddRedirectUriValidator<MyUriValidator>();
builder.Services.AddSingleton<IUserRepository, UserRepository>();
builder.AddProfileService<CustomProfileService>();
builder.AddClientStore<CustomClientStore>();
//services.AddCors(setup => setup.AddDefaultPolicy(b => b.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod()));
builder.AddCorsPolicyService<CustomCorsPolicyService>();
...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
app.UseDeveloperExceptionPage();
app.UseStaticFiles();
// Add this before any other middleware that might write cookies
app.UseCookiePolicy();
app.UseIdentityServer();
app.UseRouting();
app.UseCors();
app.UseMvcWithDefaultRoute();
// This will write cookies, so make sure it's after the cookie policy
app.UseAuthentication();
}
In My Controller
[ApiController]
public sealed class EmbeddedLogController : ControllerBase
{
[HttpPost]
[Route("/embedded/log/")]
[EnableCors()]
public ActionResult Log(ParametersLog parameters)
{
....
}
}
Without CustomClientStore I could call services.AddCors(setup => setup.AddDefaultPolicy... to accept CORS
But now I need to use builder.AddClientStore<CustomClientStore>(); because of CustomProfileService.
How can I fix that ?
Thanks
this GitHub issue might give you some clues.
That says:
Solved When using Endpoint Routing CORS and IdentityServer4, the call
to UseCors() must be after UseRouting() but BEFORE UseIdentityServer()
and UseAuthorization(). Otherwise it will appear to work but
Pre-Flight checks will fail

how to auto-start/warm up .net core web app hosted in IIS

I have a .net core (3.1) web app which is hosted on IIS. I cannot figure out how to run a piece of code before the first request. I have done the following:
set the 'start mode' of the app pool = "AlwaysRunning" and "Idle time-out" = 0
set the 'preload enabled' = true on the web site
What i am missing is where/how i register the code/service that i would like to run before the first request comes in?
thanks in advance
What i am missing is where/how i register the code/service that i would like to run before the first request comes in?
If you want to call one of your mvc or web api after the application has start up completely to warm up your web application. You could try to use IHostApplicationLifetime's ApplicationStarted method.
This method will be called after the application started immediately.
You could inject IHostApplicationLifetime into Configure() method , then write the callback for ApplicationStarted that would be triggered when the application host has fully started.
More details, you could refer to below example:
Register httpclient service in Startup.cs ConfigureServices method
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient();
services.AddControllersWithViews();
}
Add lifetime.ApplicationStarted.Register callback in Configure method:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHostApplicationLifetime lifetime)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Default}/{action=Index}/{id?}");
});
IHttpClientFactory httpClientFactory = app.ApplicationServices.GetService(typeof(IHttpClientFactory)) as IHttpClientFactory;
lifetime.ApplicationStarted.Register(onApplicationStartedAsync(httpClientFactory).Wait);
}
private async Task<Action> onApplicationStartedAsync(IHttpClientFactory httpClientFactory)
{
var httpclient = httpClientFactory.CreateClient();
var httpMessage = new HttpRequestMessage(HttpMethod.Get, "http://localhost:5000/api/values");
var httpresponse = await httpclient.SendAsync(httpMessage);
if (httpresponse.IsSuccessStatusCode)
{
string res = await httpresponse.Content.ReadAsStringAsync();
}
return null;
}
Result:

CORS Error: No 'Access-Control-Allow-Origin' header is present on the requested resource

I am using .Net Core 3. I have programmed an API being called by a SPA hosted in a .Net Core Web Project.
For one POST action in the API, I get a CORS error in Chrome as well as Firefox while for another POST action in the same controller of the API, everything works fine.
The error that I get is
Access to fetch at 'https://subdomain1.domain1.com:50003/api/v1/projects/project' from origin
'https://subdomain2.domain2.com:50002' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
If an opaque response serves your needs, set the request's mode to
'no-cors' to fetch the resource with CORS disabled.
In the API,
In the startup class, I have following
readonly string MyAllowSpecificOrigins = "AllowOrigin";
public void ConfigureServices(IServiceCollection services)
{
CorsPolicyBuilder builder = new CorsPolicyBuilder();
CorsPolicy policy = builder.WithOrigins("https://subdomain2.domain2.com:50002")
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
.Build();
services.AddCors(options =>
{
options.AddPolicy(MyAllowSpecificOrigins, policy);
});
services.AddControllers();
services
.AddAuthentication("Bearer")
.AddJwtBearer(jwtOptions => {
jwtOptions.Authority = "https://subdomain.domain.com:50001";
jwtOptions.Audience = "portal-api";
jwtOptions.RequireHttpsMetadata = false;
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
var provider = new FileExtensionContentTypeProvider();
provider.Mappings[".hrc"] = "application/octet-stream";
provider.Mappings[".obj"] = "application/octet-stream";
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers().RequireCors(MyAllowSpecificOrigins);
});
app.UseMvc();
}
In the API controller, I have a POST action for which I don't get any CORS error
[HttpPost]
[Route("[action]")]
[ActionName("thumbnail")]
public async Task<IActionResult> thumbnail([FromBody]dataDTO model)
{
.
.
.
}
In the same API, I have another POST action, for which the browser gives the above mentioned CORS error
[HttpPost]
[Route("project")]
[ActionName("project")]
public async Task<IActionResult> projectAdd([FromBody]projectDTO project)
{
.
.
.
}
I have already tried moving the app.UseCors(MyAllowSpecificOrigins); to the top of configure function in startup.cs. It did not help.
I have also tried moving the app.UseCors(MyAllowSpecificOrigins); statement and changing its order in configure with no difference.
In firefox, I have also verified that there is a Origin header in the request to the action for which we are getting CORS error.

Problem in enabling CORS in asp net core web api v3.0

I am using asp net core 3.0 in my web API project. I have created various API's and all are accessible via Swagger or Postman. But when trying to access the same via any other client like React, Method not allowed (405 error code) is received. On investing further, I find out that at first, OPTION request is received from the React application and the net core web API application is giving the 405 status code. Further, I find out that I need to enable all the methods as well as origins from the net core application to accept all types of requests otherwise it will not accept OPTION request. To achieve this, I enabled CORS policy in startup.cs file but still had no luck. Following is my startup.cs file:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
var elasticUri = Configuration["ElasticConfiguration:Uri"];
Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
.Enrich.WithExceptionDetails()
.WriteTo.Elasticsearch(new ElasticsearchSinkOptions(new Uri(elasticUri))
{
MinimumLogEventLevel = LogEventLevel.Verbose,
AutoRegisterTemplate = true,
})
.CreateLogger();
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<IISServerOptions>(options =>
{
options.AutomaticAuthentication = false;
});
services.Configure<ApiBehaviorOptions>(options =>
{
//To handle ModelState Errors manually as ApiController attribute handles those automatically
//and return its own response.
options.SuppressModelStateInvalidFilter = true;
});
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
});
services.AddControllers(options =>
{
//To accept browser headers.
options.RespectBrowserAcceptHeader = true;
}).
AddNewtonsoftJson(options =>
{
// Use the default property (Pascal) casing
options.SerializerSettings.ContractResolver = new DefaultContractResolver();
options.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;
}).
AddJsonOptions(options =>
{
//Not applying any property naming policy
options.JsonSerializerOptions.PropertyNamingPolicy = null;
options.JsonSerializerOptions.IgnoreNullValues = true;
}).
AddXmlSerializerFormatters().
AddXmlDataContractSerializerFormatters();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
{
app.UseCors("CorsPolicy");
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();
// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
// specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
});
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
//Configuring serilog
loggerFactory.AddSerilog();
}
}
I tried testing the same API with the OPTIONS method from POSTMAN. It is also giving the Http Status Code as 405. But when trying to access the same request using the POST method, I received the response successfully.
Is there anything wrong with the above code or something wrong with the order of middlewares being called in Configure().
Try to add extension method and modifying your startup class:
Extension method:
public static void AddApplicationError(this HttpResponse response, string
message)
{
response.Headers.Add("Application-Error", message);
response.Headers.Add("Access-Control-Expose-Headers", "Application-Error");
response.Headers.Add("Access-Control-Allow-Origin", "*");
}
Startup.cs :
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler(builder =>
{
builder.Run(async context =>
{
context.Response.StatusCode = (int)
HttpStatusCode.InternalServerError;
var error = context.Features.Get<IExceptionHandlerFeature>();
if (error != null)
{
context.Response.AddApplicationError(error.Error.Message);
await context.Response.WriteAsync(error.Error.Message);
}
});
});
}
P.S. in my case I had scenario also returning 405 status error, cause was, similar action methods I used and there are conflicted
For ex:
[HttpGet]
public ActionResult GetAllEmployees()
[HttpGet]
public ActionResult GetCustomers()
Hope this will help at least to show exact error message
You need to add Cors in Startup.cs file under your web api project
add this variable in Startup.cs
readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
add services.AddCors before services.AddControllers() in the method ConfigureServices in file Startup.cs:
services.AddCors(options =>
{
options.AddPolicy(MyAllowSpecificOrigins,
builder =>
{
builder.WithOrigins("http://localhost:4000",
"http://www.yourdomain.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
services.AddControllers();
*** You can pass only * to allow all instead of passing http://localhost:4000","http://www.yourdomain.com in the WithOrigins method
add app.UseCors before app.UseAuthentication() in the method Configure in file Startup.cs:
app.UseCors(MyAllowSpecificOrigins);
Check this Microsoft help
Try this:
app.UseCors(policy =>
policy.WithOrigins("https://localhost:PORT", "https://localhost:PORT")
.AllowAnyMethod()
.WithHeaders(HeaderNames.ContentType)
);