diff --git a/RIIT/RIIT/Components/App.razor b/RIIT/RIIT/Components/App.razor index a911b1c..7b9b9ee 100644 --- a/RIIT/RIIT/Components/App.razor +++ b/RIIT/RIIT/Components/App.razor @@ -15,8 +15,11 @@ + @* *@ + @* *@ + diff --git a/RIIT/RIIT/Components/Pages/Home.razor b/RIIT/RIIT/Components/Pages/Home.razor index 9001e0b..3bc1b59 100644 --- a/RIIT/RIIT/Components/Pages/Home.razor +++ b/RIIT/RIIT/Components/Pages/Home.razor @@ -5,3 +5,5 @@

Hello, world!

Welcome to your new app. + + diff --git a/RIIT/RIIT/Components/Routes.razor b/RIIT/RIIT/Components/Routes.razor index 511d40b..58f1b77 100644 --- a/RIIT/RIIT/Components/Routes.razor +++ b/RIIT/RIIT/Components/Routes.razor @@ -1,8 +1,9 @@ @using RIIT.Components.Account.Shared - + + @*

Windows vás nepoznal (401 Unauthorized).

*@
diff --git a/RIIT/RIIT/Program.cs b/RIIT/RIIT/Program.cs index 4529960..8ecf2a6 100644 --- a/RIIT/RIIT/Program.cs +++ b/RIIT/RIIT/Program.cs @@ -1,6 +1,5 @@ -using System.Security.Claims; -using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Negotiate; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; @@ -10,164 +9,111 @@ using RIIT.Data; var builder = WebApplication.CreateBuilder(args); -// ===== Auth mode switches (configurable via appsettings.json) ===== +// ===== Přepínač režimu (appsettings.json: "Auth:Mode": "Windows" | "Internal") ===== var authMode = builder.Configuration["Auth:Mode"]?.Trim() ?? "Internal"; var windowsEnabled = string.Equals(authMode, "Windows", StringComparison.OrdinalIgnoreCase); -// Detect IIS / IIS Express hosting (intranet scenario) -var runningUnderIis = !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("ASPNETCORE_IIS_PHYSICAL_PATH")); - -// Add services to the container. -builder.Services.AddRazorComponents() - .AddInteractiveServerComponents(); - -builder.Services.AddCascadingAuthenticationState(); -builder.Services.AddScoped(); -builder.Services.AddScoped(); - -// Authentication: primary = Identity cookie -builder.Services.AddAuthentication(options => +if (windowsEnabled) { - options.DefaultScheme = IdentityConstants.ApplicationScheme; - options.DefaultSignInScheme = IdentityConstants.ExternalScheme; + // ? Negotiate v aplikaci (Kestrel) – POZOR: nepoužívej za IIS s Windows Auth! + builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme) + .AddNegotiate(); - // Keep challenge on cookie/login page; Windows is performed explicitly via /auth/windows. - options.DefaultChallengeScheme = IdentityConstants.ApplicationScheme; -}) - .AddIdentityCookies(); - -// Windows Integrated (Kerberos/NTLM): -// - On IIS / IIS Express: do NOT register AddNegotiate(); IIS handles Windows auth and populates HttpContext.User. -// - Outside IIS: you may register AddNegotiate() (optional), but typical intranet hosting uses IIS anyway. -if (windowsEnabled && !runningUnderIis) -{ - builder.Services.AddAuthentication() - .AddNegotiate(); -} - -builder.Services.AddAuthorization(); - -var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") - ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found."); - -builder.Services.AddDbContext(options => - options.UseSqlServer(connectionString)); - -builder.Services.AddDatabaseDeveloperPageExceptionFilter(); - -builder.Services.AddIdentityCore(options => -{ - // Email confirmation disabled for now (can be enabled later) - options.SignIn.RequireConfirmedAccount = false; - options.Stores.SchemaVersion = IdentitySchemaVersions.Version3; -}) - .AddEntityFrameworkStores() - .AddSignInManager() - .AddDefaultTokenProviders(); - -builder.Services.AddSingleton, IdentityNoOpEmailSender>(); - -var app = builder.Build(); - -// Optionally guard against misconfiguration -// (Windows mode is intended for IIS/IIS Express intranet hosting) -if (windowsEnabled && !runningUnderIis) -{ - app.Logger.LogWarning("Auth:Mode=Windows but the app is not running under IIS/IIS Express. Windows Integrated auth may not work as expected."); -} - -// Configure the HTTP request pipeline. -if (app.Environment.IsDevelopment()) -{ - app.UseMigrationsEndPoint(); + // Vyžaduj přihlášení všude (Fallback = Default) + builder.Services.AddAuthorization(options => + { + options.FallbackPolicy = options.DefaultPolicy; + }); } else { - app.UseExceptionHandler("/Error", createScopeForErrors: true); + // ? Interní Identity účty (cookies) + builder.Services.AddScoped(); + builder.Services.AddScoped(); + builder.Services.AddAuthentication(options => + { + options.DefaultScheme = IdentityConstants.ApplicationScheme; + options.DefaultSignInScheme = IdentityConstants.ExternalScheme; + }) + .AddIdentityCookies(); + + builder.Services.AddAuthorization(); + + builder.Services.AddIdentityCore(options => + { + options.SignIn.RequireConfirmedAccount = true; + options.Stores.SchemaVersion = IdentitySchemaVersions.Version3; + }) + .AddEntityFrameworkStores() + .AddSignInManager() + .AddDefaultTokenProviders(); +} + +// DB +var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") + ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found."); +builder.Services.AddDbContext(o => o.UseSqlServer(connectionString)); +builder.Services.AddDatabaseDeveloperPageExceptionFilter(); + +// Email (no-op) +builder.Services.AddSingleton, IdentityNoOpEmailSender>(); + +// Blazor (server interaktivně) + cascading auth state (AuthorizeView apod.) +builder.Services.AddRazorComponents() + .AddInteractiveServerComponents(); +builder.Services.AddCascadingAuthenticationState(); + +var app = builder.Build(); + +// ------ Pipeline ------ +if (!app.Environment.IsDevelopment()) +{ + app.UseExceptionHandler("/Error"); app.UseHsts(); } -app.UseStatusCodePagesWithReExecute("/not-found"); app.UseHttpsRedirection(); - app.UseStaticFiles(); -app.UseRouting(); - - app.UseAuthentication(); - -if (windowsEnabled) -{ - app.Use(async (context, next) => - { - // Pokud už je přihlášený (cookie), nech vše projít. - if (context.User?.Identity?.IsAuthenticated == true) - { - await next(); - return; - } - - var path = context.Request.Path; - - // Nikdy neredirectovat: - // - bootstrap endpoint - // - identity stránky/endpoints - // - chybové stránky - // - blazor framework a static web assets - if (path.StartsWithSegments("/auth/windows") || - path.StartsWithSegments("/Account") || - path.StartsWithSegments("/not-found") || - path.StartsWithSegments("/Error") || - path.StartsWithSegments("/_framework") || - path.StartsWithSegments("/_content")) - { - await next(); - return; - } - - // Nezasahovat do statických souborů podle přípony (CSS/JS/fonts/images/maps) - var ext = System.IO.Path.GetExtension(path); - if (!string.IsNullOrEmpty(ext)) - { - await next(); - return; - } - - // Redirect jen pro "navigační" requesty (typicky HTML stránky) - if (!HttpMethods.IsGet(context.Request.Method)) - { - await next(); - return; - } - - // Pokud klient nechce HTML (např. fetch pro JSON), neredirectuj - var accept = context.Request.Headers.Accept.ToString(); - if (!string.IsNullOrEmpty(accept) && !accept.Contains("text/html", StringComparison.OrdinalIgnoreCase)) - { - await next(); - return; - } - - var returnUrl = context.Request.PathBase + context.Request.Path + context.Request.QueryString; - var target = "/auth/windows?returnUrl=" + Uri.EscapeDataString(returnUrl); - - - context.Response.Redirect(target); - }); -} - app.UseAuthorization(); - app.UseAntiforgery(); - - app.MapStaticAssets(); app.MapRazorComponents() .AddInteractiveServerRenderMode(); // Add additional endpoints required by the Identity /Account Razor components. -app.MapAdditionalIdentityEndpoints(); +if (!windowsEnabled) +{ + app.MapAdditionalIdentityEndpoints(); +} +/* +// ? StatusCodePages: nikdy nesahat do 401/403 (kvůli Negotiate handshaku) +app.UseStatusCodePages(async context => +{ + var code = context.HttpContext.Response.StatusCode; + + // Negotiate/Identity challenge – nesahej na to + if (code == 401 || code == 403) return; + + // 404 apod. klidně přesměruj + context.HttpContext.Response.Redirect("/not-found"); +}); + +if (windowsEnabled) +{ + // FallbackPolicy už vyžaduje auth – tady .RequireAuthorization() není nutné + app.MapRazorComponents() + .AddInteractiveServerRenderMode(); +} +else +{ + // Interní účty: výslovně zamknout UI + app.MapRazorComponents() + .AddInteractiveServerRenderMode() + .RequireAuthorization(); +} +*/ app.Run(); \ No newline at end of file diff --git a/RIIT/RIIT/appsettings.json b/RIIT/RIIT/appsettings.json index f709e5d..65e3f81 100644 --- a/RIIT/RIIT/appsettings.json +++ b/RIIT/RIIT/appsettings.json @@ -9,10 +9,8 @@ } }, "Auth": { - "Mode": "Windows", - "Windows": { - "RequireAuthenticatedUser": true - } + "Mode": "Windows" + // moĹľnosti pro Mode: "Windows", "Internal" }, "AllowedHosts": "*" }