Asp.net Core 2 AddAuthorization causing 500 internal server error - problems in Startup - asp.net-core

I have a project which i have configured to use JWT for authentication. FOr authorization I want to use role based policies. All good so I make the changes to my Startup.cs.
I have in "ConfigureServices" the following added service.
// Use policy auth.
services.AddAuthorization(options =>
{
options.AddPolicy("DisneyUser", policy => policy.RequireClaim("DisneyCharacter", "IAmMickey"));
});
and this works when I go get a JWT token.
If I change it to
// Use policy auth.
services.AddAuthorization(options =>
{
options.AddPolicy("DisneyUser", policy => policy.RequireClaim("DisneyCharacter", "IAmMickey"));
options.AddPolicy("AdminOnly", policy => policy.RequireClaim(ClaimTypes.Role, "Admin"));
options.AddPolicy("EmployeeAccess", policy => policy.RequireClaim(ClaimTypes.Role, "Employee"));
});
its still works.
However if I removed the first policy line and I am left with:
// Use policy auth.
services.AddAuthorization(options =>
{
options.AddPolicy("AdminOnly", policy => policy.RequireClaim(ClaimTypes.Role, "Admin"));
options.AddPolicy("EmployeeAccess", policy => policy.RequireClaim(ClaimTypes.Role, "Employee"));
});
I get the following status when I go get a JWT token..
500 Internal Server Error.
Wonder if anybody might have a clue as to why having these two options only breaks it?

Related

Authorization in ASP.NET Core razor

I have an admin area I want every user except normal user to be able o go to the admin area.
My user types are dynamic - what should I do?
My authentication is permission based.
I used this code, but it is for static account types:
services.AddAuthorization(options =>
{
builder => builder.RequireRole(Roles.Administrator, Roles.ContentUploader));
options.AddPolicy("Discount",
builder => builder.RequireRole(Roles.Administrator));
});
According to your description, I suggest you could write a custom policy like below to match your requirement.
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("NonNormalUser", policy =>
policy.RequireAssertion(context =>
!context.User.IsInRole("Normal")));
});

Require all policies by default in Api Controllers

I don't know if this may sound stupid, but I'm a bit worried about how authorization is done in Controllers.
Right now I'm using [Authorize] attribute to secure my end points. But, I'm a bit worried I forget to add a policy and anyone could access the end point.
Is there any way to apply all policies by default and just add an attribute forthe ones you want to allow?
In Asp.Net Core 2.x you can use a filter to set a global Authorization Attribute:
services.AddMvc(options =>
{
// This requires an authenticated user for all controllers/actions,
// except when at controller/action the [AllowAnonymous] attribute is set.
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
options.Filters.Add(new AuthorizeFilter(policy));
// In the same way you can set a global AntiforgeryToken
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
In Asp.Net core 3.x endpoint routing is introduced. When enabled you can set this per endpoint, as described in the migration documentation:
services.AddControllersWithViews(options =>
{
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
}).SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
with possible endpoint configuration:
app.UseEndpoints(endpoints =>
{
// equivalent of [Authorize] attribute on each controller:
endpoints.MapDefaultControllerRoute().RequireAuthorization();
});
Not asked, but recommended: Automatically validate antiforgery tokens for unsafe HTTP methods only.

Authorization Role/Policy Attributes Not Working In .Net Core 3

I've had no luck getting any Role or Policy attributes working in .Net Core 3. I started my project with the .Net Core Angular starter project with authentication.
I figured this was something to do with the new .AddDefault methods so I have simplified it as much as I possibly can and it still doesn't work.
Here is my policy:
services.AddAuthorization(options =>
{
options.AddPolicy("IsAdmin", policy =>
policy.RequireClaim("role", "admin"));
});
Here is my controller:
[Authorize(Policy = "IsAdmin")]
[Route("api/[controller]")]
public class AdminController : Controller
{
...
I made a custom Profile service that adds the claim to the token,
var claims = new List<Claim>();
if (await _userManager.IsInRoleAsync(user, "Admin"))
{
claims.Add(new Claim(JwtClaimTypes.Role, "admin"));
}
context.IssuedClaims.AddRange(claims);
Inside my access token (from jwt.io):
Other parts of configure services:
services.AddDefaultIdentity<ApplicationUser>()
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
...
services.AddAuthentication()
.AddIdentityServerJwt();
The plain [Authorize] tag is working fine with the access token on other controllers.
When I hit this controller with the access token I get a 403 response
What am I missing that is preventing this from working?
I try your code and find that the role claim key has been transformed to the standard Role ClaimsType : http://schemas.microsoft.com/ws/2008/06/identity/claims/role
So using ClaimTypes.Role will fix the problem:
services.AddAuthorization(options => {
options.AddPolicy("IsAdmin", policy =>
{
policy.RequireClaim(ClaimTypes.Role,"admin");
});
});
Demo
You should also be able to achieve this without needing a policy. ASP.NET automatically maps common claims to the Microsoft schema.
When you inspect your access token. You will see you are sending the role claim. But when you look at the claims in the controller, you will notice that it has been transformed to http://schemas.microsoft.com/ws/2008/06/identity/claims/role.
There are two things you can do. Either set the RoleClaimType to ClaimTypes.Role. Like so:
services.Configure<JwtBearerOptions>(IdentityServerJwtConstants.IdentityServerJwtBearerScheme, options => {
options.TokenValidationParameters.RoleClaimType = ClaimTypes.Role;
});
Or tell the JwtSecurityTokenHandler not to map default inbound claims like this:
JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
Since it's a static property this can be done at any time. But I set it somewhere during my service registrations.

Secure access only to controller in IdentityServer4

I created a basic IdentityServer4 as per tutorials http://docs.identityserver.io/en/release/quickstarts/0_overview.html.
This consists of APIserver, JSClient and ID4 Server.
OVerall all is good, now i am trying to go one step further, I want to create a basic controller in ID4Server called AuthorizedUserController that is restful, and that can only be accessed by Authorised user from JSClient.
I cannot find any examples on how to achieve this currently so hoping for some guidance.
You could make IdentityServer include bearer token authentication:
services.AddAuthentication()
.AddIdentityServerAuthentication("bearer", options =>
{
options.Authority = "you identityserver base url";
options.ApiName = "identityserver_api";
});
And then have an authorization policy that checks for the scheme and the client ID claim:
services.AddAuthorization(options =>
{
options.AddPolicy("JsClient", config =>
{
config.AddAuthenticationSchemes("bearer");
config.RequireClaim("client_id", "my javascript client");
});
});
And then add an authorize attribute to your controller that specifies this authorization policy:
[Authorize("JsClient")]

JWT Authentication

My team is building a web api in .net core. We use token authentication to authenticate any client, the token comes form the Azure AD.
We put this code in Startup.cs
app.UseJwtBearerAuthentication(options => {
options.AutomaticAuthenticate = true;
options.AutomaticChallenge = true;
options.Authority = "https://login.windows.net/1da3434a9-e5a6-4e9e-80c3-aca8ed37cb03";
options.Audience = "https://test.onmicrosoft.com/test_api";
options.RequireHttpsMetadata = false;
});
services.AddCors(options =>
{
// Define one or more CORS policies
options.AddPolicy("AllowAll",
builder =>
{
builder.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
This one only work when we allow anonymous access. I checked the token, and the token is valid. But every time we hit controller it will throw cors error. even though we enable cors
The sequence of adding middleware does matter!
To enable CORS for your entire application add the CORS middleware to
your request pipeline using the UseCors extension method. Note that
the CORS middleware must proceed any defined endpoints in your app
that you want to support cross-origin requests (ex. before any call to
UseMvc).
You should put services.AddCors above almost everything that might redirect your users via 401.
You cannot combine AllowCredentials & AllowAnyOrigin. Pick a specific origin and your request will likely work.