IISHttpServer - No authenticationScheme was specified, and there was no DefaultChallengeScheme found - iis

I am trying to deploy Core WebAPI 2.2 (InProcess or OutOfProcess) to IIS 7.5. I am getting below error and below is the code.
fail: Microsoft.AspNetCore.Server.IIS.Core.IISHttpServer[2]
Connection ID "15636497907840974971", Request ID "8000007e-0000-d900-b63f-84710c7967bb": An unhandled exception was thrown by the application.
System.InvalidOperationException: No authenticationScheme was specified, and there was no DefaultChallengeScheme found.
at Microsoft.AspNetCore.Authentication.AuthenticationService.ChallengeAsync(HttpContext context, String scheme, AuthenticationProperties properties)
at Microsoft.AspNetCore.Mvc.ChallengeResult.ExecuteResultAsync(ActionContext context)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultAsync(IActionResult result)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResultFilterAsyncTFilter,TFilterAsync
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResultExecutedContext context)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAlwaysRunResultFilters()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Server.IIS.Core.IISHttpContextOfT`1.ProcessRequestAsync()
Program.cs
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseIIS()
.UseStartup<Startup>();
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
// Configure services
services.AddAuthentication(IISDefaults.AuthenticationScheme);
ConfigureSwagger(services);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseAuthentication();
// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "MyProject.Test V1");
});
app.UseMvc();
}

Related

Hosting ASP.NET Core 5 Web API on IIS: an error occurred while starting the application

I have an ASP.NET Core 5 Web API project that I'm trying to host on IIS. Everything worked fine:
I installed the .NET Core hosting bundle
I added IIS_IUSRS to allow the access to the published application folder
When I open the published application in cmd and run dotnet myAppName.dll, everything is working fine and I can test all my apis and all of them are working well.
But when I browse my project from IIS, I get this error:
An error occurred while starting the application
This is my startup.cs:
namespace storedProcedure
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
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.AddCors();
services.AddControllers().AddNewtonsoftJson(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
//adding dbContext service
services.AddDbContext<trainingContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString
("trainingDB"))) ;
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "storedProcedure", Version = "v1" });
});
services.AddDirectoryBrowser();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "storedProcedure v1"));
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(#"D:\Users\lenovo\Desktop\paul\web2-Net-CORE\storedProcedure\storedProcedure\Resources"),
RequestPath = "/Resources"
});
app.UseRouting();
app.UseCors(
options => options.WithOrigins("http://localhost:4200").AllowAnyMethod().AllowCredentials()
);
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
And this is my Program.cs:
namespace storedProcedure
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
NOTE: I'm integrating SQL Server database with my project and I added the database publish settings:
Click here to see an image of my db publish settings
I solved it, The Resources folder (where my static files are), was not included in the published folder, that's why it was giving me an error

Azure Feature Flag is not updating after cache expiration

We have FeatureFlag: IsServiceNeeded with no label set in Feature Manager of Azure App Configuration. We have used in built method AddAzureAppConfiguration by setting up the cache interval.
We are using .net core 3.1 web api and Feature Manager of Azure App Configuration.
We had IsServiceNeeded enabled during initialization of the app and after few hours, we disabled IsServiceNeed. We wait for entire day, but don't see the difference since the below returns true instead of false. We were expecting it to update every 3 minutes due to how we have it configured in program.cs file.
await _featureManager.IsEnabledAsync("IsServiceNeeded")
Let me know if you see anything odd with below. Thanks in advance,
Here is the code snippet we are using it.
Program.cs file
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context, config) =>
{
var configurationRoot = config.Build();
var appConfigConString = configurationRoot["AppConfigConnectionString"];
config.AddAzureAppConfiguration(options => options.Connect(appConfigConString).UseFeatureFlags(featureFlagOptions => {
**featureFlagOptions.CacheExpirationInterval = TimeSpan.FromMinutes(3);**
}));
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
Startup.cs file
public class Startup
{
public IConfiguration Configuration { get; }
public string ContentRootPath { get; set; }
public Startup(IWebHostEnvironment env, IConfiguration configuration)
{
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddHsts(options =>
{
options.Preload = true;
options.IncludeSubDomains = true;
options.MaxAge = TimeSpan.FromDays(365);
});
var conf = Configuration.GetSection("AppSettings").Get<Config>();
services.Configure<Config>(Configuration.GetSection("AppSettings"));
services.AddSingleton<IAppSettings>(c => conf);**
services.AddScoped<IProcessHandler, ProcessHandler>();
**services.AddFeatureManagement();**
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseHsts();
app.UseHttpsRedirection();
app.UseHttpStatusCodeExceptionMiddleware();
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
private static void LoadMediatorHandlers(IServiceCollection services)
{
foreach (var assembly in Assembly
.GetEntryAssembly()
.GetReferencedAssemblies()
.Select(Assembly.Load)
.Where(name => (name.FullName.Contains("Queries") || name.FullName.Contains("Commands"))))
{
services.AddMediatR(assembly);
}
services.AddMediatR(typeof(Startup));
services.AddScoped<IMediator, Mediator>();
}
}
Application of Feature Flag:
public class ProcessHandler : IProcessHandler
{
private readonly IFeatureManager _featureManager;
public ProcessHandler(IFeatureManager featureManager)
{
_featureManager = featureManager;
}
public async Task<ClassA> ProcessXyz()
{
if (`await _featureManager.IsEnabledAsync("IsServiceNeeded")`)
{
return new ClassA();
}
return null;
}
}
Please Note: I have just added the required code and replaced actual names for security issues.
Thanks in advance
What is missing is the middleware that refreshes feature flags (and configuration) from Azure App Configuration.
Open your startup.cs, add below
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddAzureAppConfiguration();
services.AddFeatureManagement();
}
And then add below
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// ...
app.UseAzureAppConfiguration();
}

How can I implement iLoggerFactory on my server IIS?

I implement iLoggerFactory on my .Net Core API , step :
creation of my folder 'logs'
implementation of the log in my 'logs' folder ( in startup.ts )
public void Configure(IApplicationBuilder app, IHostingEnvironment env,ILoggerFactory loggerFactory)
{
// log implementation
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
loggerFactory.AddEventSourceLogger();
loggerFactory.AddFile("logs/app-{Date}.txt");
app.UseStaticFiles();
app.UseCors("AnyOrigin");
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "WebToolAPI");
c.RoutePrefix = string.Empty;
});
app.UseMvc();
}
And I create some log in controller who look like this :
_log.LogError("\r\n -- \r\n Datetime : {0} \r\n ERROR : id'" + id + "' not found \r\n --", DateTime.Now);
When I test it my local machine it's work but when I put my code in my IIS server it doesn't work. It doesn't create logs in my logs folder.
I resolve the issue.
In Startup.cs :
public class Startup
{
string LogFilePath;
public Startup(IHostingEnvironment env)
{
// location of the logs
var exePath = Assembly.GetEntryAssembly().Location.ToString();
var directoryPath = Path.GetDirectoryName(exePath);
LogFilePath = Path.Combine(directoryPath + "\\logs\\"); // you can replace "logs" by an other folder name
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env,ILoggerFactory loggerFactory)
{
loggerFactory.AddDebug();
loggerFactory.AddFile(LogFilePath + "api-{Date}.txt",LogLevel.Debug,null,false,null,30); // you can replace "api" by an other file name for your log
}
}
In Program.cs :
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseKestrel()
.UseIISIntegration()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>();
}

ConfigurationBuilder haven't definition for AddJson

I'm trying to use connection string from my json file by doing next steps
Json file
{
"ConnectionStrings": {
"PlatformDatabase": "Server=xxxx\\SQLEXPRESS;Database=xxxx;Trusted_Connection=True;"
}
}
Access to json
var builder = new ConfigurationBuilder()
.SetBasePath(System.AppContext.BaseDirectory)
.AddJsonFile("appsettings.json",
optional: true,
reloadOnChange: true);
Configuration = builder.Build();
optionsBuilder.UseSqlServer(Configuration.GetConnectionString("PlatformDatabase"));
Error: ConfigurationBuilder does not contain a definition for
AddJsonFile.
Does anyone have this problem before? I tried searching it but all the solution I found doesn't work now (i suppose with version 2).
EDIT
note. I created .Net Core 2.0 console application
The problem was solved by install the nuget package
Microsoft.Extensions.Configuration.Json
You do not need to explicit add appsettings.json in ASP.NET Core 2.
You just need the followings inside Startup.cs -
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(
Configuration.GetConnectionString("PlatformDatabase")));
...
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...
}
Program.cs
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
Another Approach
You register IConfiguration as Singleton in DI container, and then inject it to your DBContext constructor. Then get the connection string inside OnConfiguring method.
public class Startup
{
public Startup(IConfiguration config)
{
_config = config;
}
private IConfiguration _config;
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton(_config);
services.AddDbContext<YOUR_DB_Context>(ServiceLifetime.Scoped);
...
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...
}
}
YOUR_DB_Context.cs
public class YOUR_DB_Context : IdentityDbContext OR DbContext
{
private IConfiguration _config;
public YOUR_DB_Context(DbContextOptions options, IConfiguration config)
: base(options)
{
_config = config;
}
protected override void OnModelCreating(ModelBuilder builder)
{
...
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
optionsBuilder.UseSqlServer(_config["Data:PlatformDatabase"]);
}
}

SpringBoot multiple authentication adapter

I have a very special requirements in my Spring Boot web application:
I have internal and external users. Internal users login to the web application by using keycloak authentication (they can work in the web application), but our external users login by simple Spring Boot authentication (what they can do is just to download some files generated by web application)
What I want to do is to have multiple authentication model:
all the path except /download/* to be authenticated by our Keycloak authentication, but the path /download/* to be authenticated by SpringBoot basic authentication.
At the moment I have the following:
#Configuration
#EnableWebSecurity
public class MultiHttpSecurityConfig {
#Configuration
#ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
#Order(1)
public static class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(keycloakAuthenticationProvider());
}
#Bean
#Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http
.regexMatcher("^(?!.*/download/export/test)")
.authorizeRequests()
.anyRequest().hasAnyRole("ADMIN", "SUPER_ADMIN")
.and()
.logout().logoutSuccessUrl("/bye");
}
}
#Configuration
#Order(2)
public static class DownloadableExportFilesSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/download/export/test")
.authorizeRequests()
.anyRequest().hasRole("USER1")
.and()
.httpBasic();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("password1").roles("USER1");
}
}
}
But it does not work well, because every time the external user wants to download something (/download/export/test), it prompts the login form, but after entering the correct external user username and password, than it prompts the keycloak authentication login form.
I don't get any error just a warning:
2016-06-20 16:31:28.771 WARN 6872 --- [nio-8087-exec-6] o.k.a.s.token.SpringSecurityTokenStore : Expected a KeycloakAuthenticationToken, but found org.springframework.security.authentication.UsernamePasswordAuthenticationToken#3fb541cc: Principal: org.springframework.security.core.userdetails.User#36ebcb: Username: user; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_USER1; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails#957e: RemoteIpAddress: 127.0.0.1; SessionId: 4C1BD3EA1FD7F50477548DEC4B5B5162; Granted Authorities: ROLE_USER1
Do you have any ideas?
I experienced some headaches when implementing basic authentication next to Keycloak authentication, because still while doing multiple WebSecurityAdapter implementations 'by the book', the Keycloak authentication filter was called even when basic authentication succeeded.
The reason lies here:
http://www.keycloak.org/docs/latest/securing_apps/index.html#avoid-double-filter-bean-registration
So if you use the Keycloak Spring Security Adapter together with Spring Boot, make sure to add those two beans (in addition to the valid answer by Jacob von Lingen):
#Configuration
#EnableWebSecurity
public class MultiHttpSecurityConfig {
#Configuration
#Order(1) //Order is 1 -> First the special case
public static class DownloadableExportFilesSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception
{
http
.antMatcher("/download/export/test")
.authorizeRequests()
.anyRequest().hasRole("USER1")
.and()
.httpBasic();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("password1").roles("USER1");
}
}
#Configuration
#ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
//no Order, will be configured last => All other urls should go through the keycloak adapter
public static class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(keycloakAuthenticationProvider());
}
#Bean
#Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
// necessary due to http://www.keycloak.org/docs/latest/securing_apps/index.html#avoid-double-filter-bean-registration
#Bean
public FilterRegistrationBean keycloakAuthenticationProcessingFilterRegistrationBean(KeycloakAuthenticationProcessingFilter filter) {
FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
registrationBean.setEnabled(false);
return registrationBean;
}
// necessary due to http://www.keycloak.org/docs/latest/securing_apps/index.html#avoid-double-filter-bean-registration
#Bean
public FilterRegistrationBean keycloakPreAuthActionsFilterRegistrationBean(KeycloakPreAuthActionsFilter filter) {
FilterRegistrationBean registrationBean = new FilterRegistrationBean(filter);
registrationBean.setEnabled(false);
return registrationBean;
}
#Override
protected void configure(HttpSecurity http) throws Exception
{
super.configure(http);
http
.authorizeRequests()
.anyRequest().hasAnyRole("ADMIN", "SUPER_ADMIN")
.and()
.logout().logoutSuccessUrl("/bye");
}
}
}
The key for multiple HttpSecurity is to register the 'special cases' before the normal one. In other words, the /download/export/test authentication adapter should be registered before the keycloak adapter.
Another important thing to notice, once an authentication is successful, no other adapter is called (so the .regexMatcher("^(?!.*/download/export/test)") is not necessary). More info for Multiple HttpSecurity can be found here.
Below you code with minimal changes:
#Configuration
#EnableWebSecurity
public class MultiHttpSecurityConfig {
#Configuration
#Order(1) //Order is 1 -> First the special case
public static class DownloadableExportFilesSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/download/export/test")
.authorizeRequests()
.anyRequest().hasRole("USER1")
.and()
.httpBasic();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("password1").roles("USER1");
}
}
#Configuration
#ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
#Order(2) //Order is 2 -> All other urls should go through the keycloak adapter
public static class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(keycloakAuthenticationProvider());
}
#Bean
#Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http
//removed .regexMatcher("^(?!.*/download/export/test)")
.authorizeRequests()
.anyRequest().hasAnyRole("ADMIN", "SUPER_ADMIN")
.and()
.logout().logoutSuccessUrl("/bye");
}
}
}

Resources