What claim in ClaimsPrincipal should I fill to make Roles Authorization work in .Net Core 2.0? - authentication

I have this method to sign in a user using .Net Core Cookie Authentication.
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> Login(LoginVM loginModel)
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, loginModel.UserName)
};
var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
// TODO: Validate against DB Staff/User.
// If valid, sign in.
await HttpContext.SignInAsync(new ClaimsPrincipal(claimsIdentity));
return Redirect(loginModel?.ReturnUrl ?? "/");
// Else return View();
}
I am filling up ClaimTypes.Name with the user name being posted up to the login View Model.
Is there like a ClaimTypes.Roles value to fill up?
I need to be able to use "User.IsInRole(...)".
This would be a collection of roles of course for a user. Not just one role.
Does anyone know how to do this?

Add like this:
claims.Add(new Claim(ClaimTypes.Role, p.Role.RoleCd));

Related

AspNetCore alternative for System.Web.Security.FormsAuthenticationTicket

We're using System.Web.Security.FormsAuthenticationTicket to create anonymous cookies for users that aren't logged in. Is there an equivalent in AspNetCore?
I'm well aware that ASP.NET Core cannot support forms authentication. The new way of doing things is cookies. So how to create a cookie that does the equivalent in the new situation?
Asp.net core cannot support form authentication. I recommend you use cookie-base authentication. This link can help you build it.
If you want to skip a method that requires authorized access. You can add attribute [AllowAnonymous].
[AllowAnonymous]
public IActionResult Privacy()
{
return View();
}
Or you can refer to this link.
Configure cookie in Startup.cs.
services.AddAuthentication("auth")
.AddCookie("auth",config=>
{
config.Cookie.Name = "cookie.name";
config.LoginPath = "/home/login";
});
Generate token in this action. You can fill the claim by receiving form data.
[HttpPost]
public IActionResult login()
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name,"myName"),
new Claim(ClaimTypes.Role,"myRole")
};
var claimIdentity = new ClaimsIdentity(claims,"id card");
var claimPrinciple = new ClaimsPrincipal(claimIdentity);
var authenticationProperty = new AuthenticationProperties
{
IsPersistent = true
};
HttpContext.SignInAsync(claimPrinciple,authenticationProperty);
return View();
}

Manually Authenticate a User with Claims for every request

I am using ASP.NET Core 2.2 and ASP.NET Identity on an API.
Is it possible to Manually Authenticate a User with Claims for every request?
I would like to use this during initial development stages ...
For authenticating a user without logging, you could try like:
public async Task<IActionResult> Login()
{
var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme, ClaimTypes.Name, ClaimTypes.Role);
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, "edward"));
identity.AddClaim(new Claim(ClaimTypes.Name, "edward zhou"));
//add your own claims
var principal = new ClaimsPrincipal(identity);
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal, new AuthenticationProperties { IsPersistent = true });
return View();
}

Authorization .net core 2.0

I have setup cookie authentication in my asp.net core application. I have a login page where the credentials matchup against the active directory. All this works fine.
Now next I want to implement authorization in my application. I have a table of users together with permission against them. For example permission like Reading & Write. When the user is successfully authenticated I want to check for these permissions and show them certain functionality while restricting others. For example, show certain dropdowns for write permission while hiding for reading permission.
What is the best approach to handle this in the .NET Core.
I have read about adding policy like:
services.AddAuthorization(options => {
options.AddPolicy("Read", policy =>
policy.RequireClaim("Read", "MyCLaim"));
});
Then in my controller:
[Authorize(Policy = "Read")]
public class HomeController : Controller
{
}
Where do I get the permissions for logged in user from my database and how to verify if the user has those permissions or not.
Would appreciate inputs.
Where do I get the permissions for logged in user from my database and
how to verify if the user has those permissons or not.
Right after a user is authenticated, you collect user's claims, and store them in Authentication Cookie.
For example, SignInAsync method.
public async Task SignInAsync(User user, IList<string> roleNames)
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.Sid, user.Id.ToString()),
new Claim(ClaimTypes.Name, user.UserName),
new Claim(ClaimTypes.GivenName, user.FirstName),
new Claim(ClaimTypes.Surname, user.LastName)
};
foreach (string roleName in roleNames)
{
claims.Add(new Claim(ClaimTypes.Role, roleName));
}
var identity = new ClaimsIdentity(claims, "local", "name", "role");
var principal = new ClaimsPrincipal(identity);
await _httpContextAccessor.HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme, principal);
}
FYI: It happens to be that I store them as Role claims. You do not have to follow that route, if you don't want.
You can then verify the policy inside Startup.cs.
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
...
// Set up policies from claims
// https://leastprivilege.com/2016/08/21/why-does-my-authorize-attribute-not-work/
services.AddAuthorization(options =>
{
options.AddPolicy(Constants.RoleNames.Administrator, policyBuilder =>
{
policyBuilder.RequireAuthenticatedUser()
.RequireAssertion(context => context.User.HasClaim(
ClaimTypes.Role, Constants.RoleNames.Administrator))
.Build();
});
});
...
}
}
Usage is same as what you have described.
[Authorize(Policy = "Read")]
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
}

Custom IsInRole() when using Cookie Middleware without ASP.NET Identity

To maintain compatibility with existing applications I was planing on using Cookie Middleware without ASP.NET Identity, as described in the documentation:
https://docs.asp.net/en/latest/security/authentication/cookie.html
This seems to work as expected as far as logging a user in, but I'm having issues with roles -- specifically when using the [Authorize(Roles = "ADMIN")].
In the code below, I can call p.IsInRole("ADMIN") and my implementation of MyClaimsPrincipal.IsInRole() is called and returns true.
What doesn't work is the [Authorize(Roles = "ADMIN")] attribute because it ends up calling ClaimsPrincipal.IsInRole (which returns False) instead of MyClaimsPrincipal.IsInRole() (which returns True).
[Authorize(Roles = "ADMIN")]
public class MyAdminController : Controller
{
public IActionResult Index()
{
var p = new MyClaimsPrincipal(ClaimsPrincipal.Current);
bool isAdmin = p.IsInRole("ADMIN");
return View();
}
}
When not using Identity and only using Cookie Middleware, can I use the [Authorize(Roles = "ADMIN")] attribute?
How? :-)
If I had to guess, I'm not implementing p.IsInRole() correctly -- currently this method loads the roles, then returns a True/False. Perhaps I have to 'load' my roles elsewhere in such a way that the ClaimsPrincipal.IsInRole is sufficient. If I was using Identity(), I assume this would be an implementation of IUserRoleStore.
My other 'if i had to guess' answer is that somewhere in startup.cs I need to replace the current ClaimsPrincipal with an instance of MyClaimsPrincipal.
Thank you!
You should add role claims when cookie is created.
In startup.cs:
app.UseCookieAuthentication(options =>
{
options.AuthenticationScheme = "MyCookieMiddlewareInstance";
options.LoginPath = new PathString("/Account/Login/");
options.AccessDeniedPath = new PathString("/Account/Forbidden/");
options.AutomaticAuthenticate = true;
options.AutomaticChallenge = true;
});
And login post method may be something like this(i assume that you have a custom login page):
[HttpPost]
public IActionResult Login(string userName, string password, string returnUrl)
{
var user = _userService.GetUser(userName, password);// i assume that _userService is injected
if (user == null)
{
//return Error;
}
var claims = new List<Claim>()
{
new Claim(ClaimTypes.NameIdentifier, user.Id),
new Claim(ClaimTypes.Name, user.GetFullName() ),
};
var identity = new ClaimsIdentity(claims, "Forms");
identity.AddClaim(new Claim(ClaimTypes.Role, "ADMIN"));
var principal = new ClaimsPrincipal(identity);
HttpContext.Authentication.SignInAsync("MyCookieMiddlewareInstance", principal);
return Redirect(returnUrl);
}

OWIN Authentication in MVC 5 Loops while User.IsAuthenticated = false

I'm trying to implement authentication and authorization in an MVC 5.1 app. The authentication takes place via Facebook that is custom implemented. (I can post that code if needed.) Once FB authenticates and sends back the code and the Authenticate method of the auth service is called to sign the user into the application. There is no auth code in the application itself (thus not using Identity or other membership services).
public async Task<ActionResult> Connect(string code)
{
if (code == null)
{
return RedirectToAction("Index", "Home");
}
else
{
// get access token
var accessToken = await nApplication.FacebookClient.AccessTokenAsync(code);
// get user info from facebook
var meResult = await nApplication.FacebookClient.MeResultAsync(accessToken);
nApplication.NRepository.SaveChanges();
nAuthorization.Authenticate(member);
return RedirectToAction("Index");
}
}
nAuthorization.Authenticate(member); creates a list of claims and executes OWIN SignIn,
claims.Add(new Claim(ClaimTypes.Name, member.Name));
claims.Add(new Claim(ClaimTypes.Role, "Member"));
var claimIdentity = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);
owinContext.Authentication.SignIn(new AuthenticationProperties { IsPersistent = true }, claimIdentity);
I'm using the Authorize attribute from Mvc namespace. But at this point /Profile/Authenticate/ which is my Owin LoginPath get's called again and again to redirect the user to FB and return to the Connect method above.
[Authorize(Roles = "Member")]
public async Task<ActionResult> Index(int? id)
I've checked the User property in the controller and it is not authenticated. I could set that to a new ClaimsPrincipal but I'd like the auth code to be independent of the HttpContext. And it doesn't seem to be right solution.
My Startup class contains:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
LoginPath = new PathString("/Profile/Authenticate/"),
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
CookieSecure = CookieSecureOption.Always,
ReturnUrlParameter = "next"
});
Maybe I am missing something completely fundamental? Any pointers would help, I've looked through articles such as the following but to no avail:
http://brockallen.com/2013/10/24/a-primer-on-owin-cookie-authentication-middleware-for-the-asp-net-developer/
http://www.khalidabuhakmeh.com/asp-net-mvc-5-authentication-breakdown-part-deux
I think this will solve your problem...it worked for me:
Add an empty method in your global.asax.cs file:
protected void Session_Start()
{
}
for some reason, the asp.net session cookie does not get set at the proper time without this. The Thinktecture devs think this might be happening if your webapp uses http and your identity provider uses https but I have not verified that yet.