User assigned roles remain unrecognised - asp.net-core

I am trying to introduce an admin account into my project. I have updated the Startup.cs file to use roles and have added Admin and Standard account inside AspNetRoles and assigned a user using their UserID an admin. The relevant [Authorize(Role = "Admin")] has also been added to the page but the admin account remains denied access. I can't seem to find out what is causing this to not be recognised, I have searched similar posts which suggested implementing
.AddRoleManager<RoleManager<IdentityRole>>()
However, this did not seem to help either. Would appreciate any insight in resolving this issue. Using Blazor wasm. Thanks in advance.
Startup.cs
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.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDatabaseDeveloperPageExceptionFilter();
services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = false)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
services.AddAuthentication()
.AddIdentityServerJwt();
services.AddControllersWithViews();
services.AddRazorPages();
services.Configure<IdentityOptions>(options =>
options.ClaimsIdentity.UserIdClaimType = ClaimTypes.NameIdentifier);
services.AddControllers().AddNewtonsoftJson(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize);
}
// 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();
app.UseWebAssemblyDebugging();
}
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.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.UseRouting();
app.UseIdentityServer();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
endpoints.MapFallbackToFile("index.html");
});
}
}
Program.cs
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>();
});
}
AspNetRoles table
AspNetUserRoles table
Razor pages
#attribute [Authorize(Roles ="Admin")]
Despite the above implementations, when logging into the assigned Admin account, the message shown is
You are not authorized to access this resource.

Try the following...
Change:
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
To:
// Configure identity server to put the role claim into the id token
// and the access token and prevent the default mapping for roles in
// the JwtSecurityTokenHandler.
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options => {
options.IdentityResources["openid"].UserClaims.Add("role");
options.ApiResources.Single().UserClaims.Add("role");
});
// Need to do this as it maps "role" to ClaimTypes.Role and causes issues
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("role");

Related

How to stop Hosted Blazor WASM from navigating to api

I have designed my blazor wasm application and its hosted in blazor server app, therefore both applications share the same base url. When i launch my server app, it successfully launchers the wasm app. My problem is that when i hit the refresh button on the web browser , the api/server app loads in the browser instead of refreshing the blazor web assembly. How can i stop this?
This is my Server Startup class
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddControllersWithViews();
services.AddEndpointsApiExplorer();
services.AddSwaggerGen();
services.ConfigureCors();
services.ConfigureIISIntegration();
services.ConfigureLoggerService();
services.ConfigureMySqlContext(Configuration);
services.ConfigureRepositoryWrapper();
services.AddAutoMapper(typeof(Startup));
services.AddControllers();
services.AddRouting(options => options.LowercaseUrls = true);
}
// 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();
app.UseWebAssemblyDebugging();
}
else
{
app.UseHsts();
}
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.UseHttpsRedirection();
//app.UseCors("CorsPolicy");
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.All
});
app.UseRouting();
app.UseAuthorization();
app.UseMiddleware<ApiKeyMiddleware>();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
endpoints.MapFallbackToFile("index.html");
});
}
}
My WASM Program.cs file
public class Program
{
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.Services.AddScoped(sp => new HttpClient(new AddHeadersDelegatingHandler())
{
BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)
});
builder.Services.AddAntDesign();
builder.Services.Configure<ProSettings>(builder.Configuration.GetSection("ProSettings"));
builder.Services.AddScoped<IChartService, ChartService>();
builder.Services.AddScoped<IProjectService, ProjectService>();
builder.Services.AddScoped<IUserService, UserService>();
builder.Services.AddScoped<IAccountService, AccountService>();
builder.Services.AddScoped<IProfileService, ProfileService>();
await builder.Build().RunAsync();
}
}

Cors Error After adding window authentication in .NET Core 3.1

Wep API was working fine but after adding authentication middleware it starts to throw CORS error below is startup.cs code
Looked everwhere in google but nothing seems to work please provide me the right direction.
public class Startup
{
readonly string MyAllowedSpecificOrigins = "_myAllowedSpecificOrigins";
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy(name: MyAllowedSpecificOrigins,
builder =>
{
builder
.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
});
});
services.AddTransient<IJobRepository, JobRepository>();
services.AddSingleton<IConfiguration>(Configuration);
services.AddControllers();
services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
///app.UseHttpsRedirection();
app.UseRouting();
app.UseCors(MyAllowedSpecificOrigins);
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
According to your description, I suggest you could firstly add .AllowCredentials() and make sure client s set XMLHttpRequest.withCredentials to true.
Credentials require special handling in a CORS request. By default, the browser doesn't send credentials with a cross-origin request. Credentials include cookies and HTTP authentication schemes. To send credentials with a cross-origin request, the client must set XMLHttpRequest.withCredentials to true.
More details, you could refer to this article.

Asp.Net CORS security issue

I made a CORS policy in my asp.net core API, but it seems the API is accessible for the public, as I can see the JSON by just typing the API URL in browser. So I just want my front-end(which is a angular app in the same host of API) have access to API not everyone.
this is my start up class:
public class Startup
{
readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
builder =>
{
builder.WithOrigins("myurl")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
services.AddControllers().AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNamingPolicy = null;
options.JsonSerializerOptions.DictionaryKeyPolicy = null;
});
services.Configure<FormOptions>(o =>
{
o.ValueLengthLimit = int.MaxValue;
o.MultipartBodyLengthLimit = int.MaxValue;
o.MemoryBufferThreshold = int.MaxValue;
});
services.AddControllers();
string connectionString = "xxx";
services.AddDbContext<decorContext>(
option => option.UseSqlServer(connectionString)
);
}
// 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.UseDefaultFiles();
app.UseStaticFiles();
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory() ,#"StaticFiles")),
RequestPath = new PathString("/StaticFiles")
});
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
CORS is kicked in when Domain A accesses Domain B (like making an ajax call in js) and it won't apply when you hit the url directly. That's why it's called CROSS-ORIGIN.
You don't typically implement "script -> website" restriction. You could restrict access by location/IP, user identity/role/claims, or by checking if antiforgery token is present in a request. Check out Overview of ASP.NET Core Security

ASP.NET Core 2.1 Identity: Role-based authorization -> Access Denied

I'm using ASP.NET Core 2.1 with the new Identity framwork from .NET. The regular Authorization attribute works as long as no role specific role is requested.
Do I need some extending / customized policies to use roles? Below is a minimized sample of my code:
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>()
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
// Does not change anything
// services.AddAuthorization();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
HomeController.cs
public async Task<IActionResult> Index()
{
if (!await _roleManager.RoleExistsAsync("Admin"))
{
await _roleManager.CreateAsync(new IdentityRole("Admin"));
}
var user = await _userManager.FindByEmailAsync("danny.meier#tpcag.ch");
if (!await _userManager.IsInRoleAsync(user, "Admin"))
{
await _userManager.AddToRoleAsync(user, "Admin");
await _userManager.UpdateAsync(user);
}
return View();
}
[Authorize]
public IActionResult About()
{
ViewData["Message"] = "Your application description page.";
return View();
}
[Authorize(Roles = "Admin")]
public IActionResult Contact()
{
ViewData["Message"] = "Your contact page.";
return View();
}
It's a known issue in the version of 2.1 and has been fixed in 2.2 preview-1 .
The reason is that the new method of AddDefaultIdentity<TUser>() , which is introduced in ASP.NET Core 2.1 , will not make Roles enabled by default .
To walk around it , instead of using the new AddDefaultIdentity<TUser>() to configure Identity , simply use the old-style api :
services.AddIdentity<AppUser, IdentityRole>()
.AddRoleManager<RoleManager<IdentityRole>>()
.AddDefaultUI()
.AddDefaultTokenProviders()
.AddEntityFrameworkStores<ApplicationDbContext>();
Also , if you have already signed someone in before , please do logout first and login again , it will work as expected now .
[Edit] For ASP.NET Core 3.1, invoke .AddRoles<IdentityRole>():
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<AppIdentityDbContext>();
And then logout and login again.
Hmmm. I have the following code in an Asp.Net 2.1 project that is working:
services.AddDefaultIdentity<IdentityUser>()
.AddRoles<IdentityRole>()
//.AddDefaultUI(UIFramework.Bootstrap4)
.AddDefaultTokenProviders()
.AddEntityFrameworkStores<ApplicationDbContext>();

IHttpContextAccessor session invalid operation exception in CustomClaimsTransformer

I followed the official docs to access the HttpContext from custom components in a CustomClaimsTransformer.
I previously had a .NET Core web application, where I used the session to enable admins to jump into the application with the view (identity) of a different user (for support purposes). I store the information, for which user the view should be prepared in the Session. Now I wanted to make it more elegant and use the .net core authorization using claims and role based authorization. As there is a Windows authentication behind, I’ve to use the CustomClaimsTransformer. Now my problem is, I want to access the current session from within the CustomClaimsTransformer. I can inject the IHttpContextAccessor, but IHttpContextAccessor.Session always raises an invalid operation exception.
Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme,
options =>
{
options.LoginPath = new PathString("/Account/Login/");
options.AccessDeniedPath = new PathString("/Account/Forbidden/");
});
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddAuthorization(options =>
{
options.AddPolicy("RequireAdministratorRole", policy => policy.RequireClaim(ClaimTypes.Role, "admin"));
options.AddPolicy("Test1", policy => policy.RequireClaim("Rechte", " Test1"));
options.AddPolicy("Test2", policy => policy.RequireClaim("Rechte", " Test2"));
});
services.AddMvc(config =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
//services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddHttpContextAccessor();
services.AddTransient<IClaimsTransformation, CustomClaimsTransformer>();
services.AddDistributedMemoryCache();
services.AddSession();
}
CustomClaimsTransformer:
CustomClaimsTransformer:
public class CustomClaimsTransformer : IClaimsTransformation
{
private readonly IHttpContextAccessor _httpContextAccessor;
public CustomClaimsTransformer(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
var z = _httpContextAccessor.HttpContext; //works
var zz = _httpContextAccessor.HttpContext.Session; // System.InvalidOperationException: "Session has not been configured for this application or request."
I edited my ConfigureServices above, when pasting the code I removed some lines for readability, including the AddDistributedMemoryCache line, sorry. Session is working in the app except where shown.
Configure:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseSession();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
Reference Session and app state in ASP.NET Core
To enable the session middleware, Startup must contain:
Any of the IDistributedCache memory caches. The IDistributedCache implementation is used as a backing store for
session.
A call to AddSession in ConfigureServices.
A call to UseSession in Configure.
Also
public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
//... removed for brevity
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseSession(); // This must come before "UseMvc()"
app.UseHttpContextItemsMiddleware();
app.UseMvc();
}
The order of middleware is important. In the preceding example, an
InvalidOperationException exception occurs when UseSession is
invoked after UseMvc.
...
HttpContext.Session can't be accessed before UseSession has been called.