Allow Anonymous Access to Index Authorize Everything Else - asp.net-core

I'm trying to authorize all pages by default and allow anonymous access to the index page. But when I run my app the user is required to login to view the index page. I'm using Azure AB B2C for authorization in a Blazor Server .NET 6 project. Here is my Program.cs file. Can someone explain what I'm doing wrong?
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.UI;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using BlazorB2C.Data;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAdB2C"));
builder.Services.AddControllersWithViews()
.AddMicrosoftIdentityUI();
builder.Services.AddRazorPages(options =>
{
options.Conventions.AllowAnonymousToPage("/Index");
})
.AddMvcOptions(options => { })
.AddMicrosoftIdentityUI();
builder.Services.AddAuthorization(options =>
{
options.FallbackPolicy = options.DefaultPolicy;
});
builder.Services.AddServerSideBlazor()
.AddMicrosoftIdentityConsentHandler();
builder.Services.AddSingleton<WeatherForecastService>();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
app.Run();

Related

Blazor, windows account and AzureAD/Microsoft Identity Platform login automatic?

If I create a new Blazor server application, choose to use Microsoft Identity Platform and connect to our work.
When I run that application without any changes, my windowsaccount log in and my name/mailadress at work shows on top on screen.
I have an old project where I got this behavior before but last week the project doesn't logged in with my workaccount automatic anymore, I need to push login button and then my Blazor server app login in with my workaccount automatic.
What I know I haven't change any code that connect to AzureAD last week. What code is it in a fresh Blazor Server application that are configure with Microsoft Identity Platform that make an automatic login if you are logged in with a microsoft account on your computer?
My Program.cs that don't login automatic anymore.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));
builder.Services.AddControllersWithViews()
.AddMicrosoftIdentityUI();
builder.Services.AddRazorPages();
builder.Services.AddAuthorization(options =>
{
// By default, all incoming requests will be authorized according to the default policy
//options.FallbackPolicy = options.DefaultPolicy;
options.AddPolicy("Admin", policy => policy.RequireClaim("role", "Admin"));
});
builder.Services.AddAutoMapper(typeof(Program));
builder.Services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"));
}, ServiceLifetime.Transient);
builder.Services.AddServerSideBlazor()
.AddMicrosoftIdentityConsentHandler();
..
builder.Services.AddHttpClient();
builder.Services.AddHttpContextAccessor();
builder.Services.AddControllers();// Add support for API controllers
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
else
{
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Blazor API V1");
});
}
app.UseDeveloperExceptionPage();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
app.Run();

Blazor Server Role based authorization in Windows AD

Since days I try to get authorization working for my Blazor site based on AD group memebership but I cannot make it work.
I am using .NET Core 6 on IIS (IIS Express for testing) in an Windows Domain. I am logged in as AD user and authentication works, so my Blazor page is able to identfy myself.
Now I want to restrict access to some controllers or APIs to specified AD groups and
finally I found a policy option
builder.Services.AddAuthorization(options =>
{
options.AddPolicy ( "MyRole", policy => policy.RequireRole(#"Domain\Group"));
});
To check if the authorization is working I tried
<AuthorizeView Policy="MyRole">
<p>You are in MyRole</p>
</AuthorizeView>
and I also tried
[Authorize(Policy = "MyRole")]
public class MyWebAPIController: ControllerBase
{
...
}
Both tells me that I am not authorized altough I am a member of the specified AD group
This is my startup script:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();
builder.Services.AddAuthorization(options =>
{
options.AddPolicy ( "MyRole", policy => policy.RequireRole(#"Domain\Group"));
});
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers(); //<======= this is the line you need to add
endpoints.MapBlazorHub();
});
app.Run();
Can anyone tell me if there is something missing or what I am doing wrong?
Thanks !!

How to set default identity login page in .net core 6 mvc instead of index page in program.cs

I am developing web app with .net core 6. How can I set default page to Identity Login page instead of index page in program.cs. Below is my program.cs code
using Microsoft.EntityFrameworkCore;
using ASPNETCOREPRJ.Areas.Identity.Data;
using ASPNETCOREPRJ.Data;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DBContextConnection");builder.Services.AddDbContext<DBContext>(options =>
options.UseSqlServer(connectionString));builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = false)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<DBContext>();
// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// 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.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllerRoute(name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.MapRazorPages();
app.Run();```
You can change your code to:
builder.Services.AddControllersWithViews().AddRazorPagesOptions(options => {
options.Conventions.AddAreaPageRoute("Identity", "/Account/Login", "");
});

Is it possible to use tokens for API and cookies for get Razor page or Controller Action in the same app with using identity server?

I have an SPA project with .net core 3.1 & identity server and react.i want to Authorize API with token and Authorize Controller Action or Razor Pages with cookies in Get Request, Is it possible to use both of them in same app?
For example, I want admin area to be Authorize with cookie and the admin to have access to its views by cookie but User area works with react and Api by token.
Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>().AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
var builder = services.AddIdentityServer()
.AddApiAuthorization<IdentityUser, ApplicationDbContext>();
builder.Services.ConfigureExternalCookie(options => {
options.Cookie.IsEssential = true;
options.Cookie.SameSite = (SameSiteMode.Unspecified);
});
builder.Services.ConfigureApplicationCookie(options => {
options.Cookie.IsEssential = true;
options.Cookie.SameSite = (SameSiteMode.Unspecified);
});
services.AddAuthentication()
.AddIdentityServerJwt();
services.AddControllersWithViews();
services.AddRazorPages();
services.AddMvc().AddNewtonsoftJson(options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/build";
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
endpoints.MapControllerRoute("adminArea", "{area=Admin}/{controller=Dashboard}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseReactDevelopmentServer(npmScript: "start");
}
});
}
Yes, it's possible to authorize with different auth schemes in an ASP.Net Core application, you just have to specify it on the [Authorize] tag that you call before the method.
First you have to add both authentications at the services.AddAuthentication() call.
Then, lets say that you want your method to authenticate with JWT token:
[Authorize(AuthenticationSchemes =
JwtBearerDefaults.AuthenticationScheme)]
On the other hand, if you want it to authenticate with a cookie:
[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
You can check more of how it works at https://learn.microsoft.com/en-us/aspnet/core/security/authorization/limitingidentitybyscheme?view=aspnetcore-3.1.

IdentityServer - How to bypass authorization for simple debug

I have several .NET core API and I use IdentityServer 4 as a seperate service for authentication.
The problem is that in "debug" I also wish to run my API without authentication (without launching the IdentityServer).
So, I try to bypass it... I have try several solutions, but none work:
- With a AuthorizationHandler: Bypass Authorize Attribute in .Net Core for Release Version
- With a Middleware : Simple token based authentication/authorization in asp.net core for Mongodb datastore
- With a filter : ASP.NET Core with optional authentication/authorization
- With AllowAnonymousFilter : Bypass Authorize Attribute in .Net Core for Release Version
But no way, none of theses solutions work, I still got a "401 Undocumented Error: Unauthorized" !
Here is some parts of my code:
public void ConfigureServices(IServiceCollection services)
{
// JSON - setup serialization
services.AddControllers().
AddJsonOptions(options =>
{
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter(new TargetSpot.Core.Json.SnakeCaseNamingStrategy()));
options.JsonSerializerOptions.IgnoreNullValues = true;
});
// Force lowercase naming
services.AddRouting(options => options.LowercaseUrls = true);
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
// Setup the connection to the IdentityServer to request a token to access our API
services.AddAuthentication(IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(options =>
{
options.Authority = Configuration.GetSection("APISettings")["AuthorityURL"];
options.RequireHttpsMetadata = false;
options.ApiName = Configuration.GetSection("APISettings")["APIName"];
});
// Add swagger
services.AddSwaggerGen(options =>
{
//options.DescribeAllEnumsAsStrings();
options.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo
{
Title = "HTTP API",
Version = "v1",
Description = "The Service HTTP API",
TermsOfService = new Uri("http://www.myurl.com/tos")
});
// XML Documentation
var xmlFile = $"{System.Reflection.Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = System.IO.Path.Combine(AppContext.BaseDirectory, xmlFile);
options.IncludeXmlComments(xmlPath);
});
}
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.UseRouting();
app.UseAuthorization();
app.UseAuthentication();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseSwagger().UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Winamp API v1");
});
}
I had similar problem.
AllowAnonymousFilter works in ASP.NET Core 2.2 but not in ASP.NET Core 3.x.
After day of investigation I have found out that switching from UseEndpoints to UseMvc solved it and I can now disable authentication without commenting out [Authorize] attributes.
It seems that UseEndpoints does not use filter when registered by AddMvc but how to correctly register it when using UseEndpoints I do not know.
My solution
Startup.ConfigureServices:
services.AddMvc(o =>
{
o.EnableEndpointRouting = false;
o.Filters.Add(new AllowAnonymousFilter());
});
Startup.Configure:
// anonymous filter works with UseMvc but not with UseEndpoints
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action=Index}/{id?}");
});
//app.UseEndpoints(endpoints =>
//{
// endpoints.MapControllerRoute(
// name: "default",
// pattern: "{controller=Home}/{action=Index}/{id?}");
//});
I found the solution in this link: https://docs.identityserver.io/_/downloads/en/latest/pdf/. Obviously I had to remove the Authorize attributes I added manually in my controllers.
app.UseEndpoints(endpoints =>
{
// Allowing Anonymous access to all controllers but only in Local environment
if (env.IsEnvironment(Constants.ApplicationConstants.LocalEnvironment))
endpoints.MapControllers();
else
endpoints.MapControllers().RequireAuthorization();
});