Blazor, windows account and AzureAD/Microsoft Identity Platform login automatic? - blazor-server-side

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();

Related

ASP.NET Core Identity: how to deploy to production?

I'm stuck with deploying a SPA (ASP.NET Core + identity + ReactJS, all built from 'ASP.NET Core With React.js' template in VS) to production. It works fine in the development environment, but when deploying to prod (non-Azure), the API starts to return 401s.
I went through Authentication and authorization for SPAs article, it says the following:
To deploy the app to production, the following resources need to be provisioned:
...
A production certificate to use for signing tokens.
I have a link to the .pfx certificate on the hosting, but I'm a bit lost on how to implement it (and whether I actually need it?). Most samples I see assume running from the local/development machine (i.e. generate a self-signed certificate and load it from the file, etc).
Below is the code (skipping some irrelevant service configuration). I'm looking for a link to a resource that explains the changes needed to be done to deploy this to production (or a code sample).
Code:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDatabaseDeveloperPageExceptionFilter();
services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
services.AddAuthentication()
.AddIdentityServerJwt();
services.AddControllersWithViews();
services.AddRazorPages();
// In production, the React files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/build";
});
}
// 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.UseMigrationsEndPoint();
}
else
{
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();
}
app.UseHttpsRedirection();
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.MapRazorPages();
});
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseReactDevelopmentServer(npmScript: "start");
}
});
}
You need to provide a signing-key to IdentityServer, so that the keys issued by it are signed by the same key each time, even across re-deployments.
The answers to this question will show you how to add it to IdentitySever.
See also this link that provides this piece of code to add the key:
services.AddIdentityServer()
// .AddTemporarySigningCredential() // Can be used for testing until a real cert is available
.AddSigningCredential(new X509Certificate2(Path.Combine(".", "certs", "IdentityServer4Auth.pfx")))

Allow Anonymous Access to Index Authorize Everything Else

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();

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", "");
});

How to set the redirect URI when using Microsoft sign-in in a .NET 5 application?

I have created a .NET 5 application with Microsoft sign-in based on this explanation.
It is working fine when running locally. However, something is going wrong when running the application in Amazon EKS. This became clear to me after reading error message I saw in the browser and after reading the network traffic.
This is how this looks like.
What becomes clear is that there is something wrong with "redirect_uri" (containing http instead of https). This is really frustrating as my application is using https. I use https when opening the application in my browser. It is important to mention that this does not occur when running the application locally on my laptop. What I hope for is that there is a simple way to set the "redirect_uri" property that is used in my code. In this way, I can guarantee that the right redirect uri is used.
Here is the source code I would like to change:
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
var configSettings = new ConfigSettings();
Configuration.Bind("ConfigSettings", configSettings);
services.AddSingleton(configSettings);
services.AddSingleton<IAuthResponseFactory, AuthResponseFactory>();
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"));
services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
services.AddRazorPages()
.AddMicrosoftIdentityUI();
services.AddHealthChecks();
services.Configure<HealthCheckPublisherOptions>(options =>
{
options.Delay = TimeSpan.FromSeconds(2);
options.Predicate = (check) => check.Tags.Contains("ready");
});
}
// 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();
}
else
{
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.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
app.UseEndpoints(endpoints =>
{
endpoints.MapHealthChecks("/health/ready", new HealthCheckOptions()
{
Predicate = (check) => check.Tags.Contains("ready")
});
endpoints.MapHealthChecks("/health/live", new HealthCheckOptions());
});
}
So how do I change my source in a way that I can set the redirect uri correctly?
Looks like you need to enable header forwarding.
Step 1: configure the ForwardedHeadersOptions
services.Configure<ForwardedHeadersOptions>(options =>
{
options.RequireHeaderSymmetry = false;
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
// TODO : it's a bit unsafe to allow all Networks and Proxies...
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
});
Step 2: UseForwardedHeaders in the public void Configure(IApplicationBuilder app, IHostingEnvironment env) method
app.UseForwardedHeaders();
Step 3: Only use UseHttpsRedirection for production
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
// Forward http to https (only needed for local development because the Azure Linux App Service already enforces https)
app.UseHttpsRedirection();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
See How to set redirect_uri protocol to HTTPS in Azure Web Apps and .net Core X Forwarded Proto not working