Can I use ASP.Net Identity twice in my MVC application? - asp.net-mvc

I'm developing an MVC 5 web application with an existing database. The application really has two types of interfaces, one set for registered users only, the other set for admin users only.
Unfortunately both types of users are not stored in the same User table, rather, in two separate tables, i.e., tblUser and tblAdmin. This is an inherited database so there's nothing I can do about that.
I was thinking of creating two MVC websites, one for the registered users, and the other for the admin users. I could still do this, however, it would mean repetition of some code.
Another option I was thinking of doing was just having one MVC site, and create an Area within that to securely place all the administration interfaces and code.
I would then have two Account Controllers (standard Account Controller and one in the Area for Admins) each with their own Login Action.
Each Login Action would use the latest ASP.Net Identity for Authentication (i.e. setup ClaimsIdentity, IAuthenticationManager etc), something like this
private IAuthenticationManager AuthenticationManager
{
get
{
return HttpContext.GetOwinContext().Authentication;
}
}
public ActionResult Login(LoginViewModel model, string returnUrl)
{
if (ModelState.IsValid)
{
var user = _AccountService.VerifyUserLogin(model.UserName, model.Password);
if (user != null)
{
var identity = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, model.UserName), }, DefaultAuthenticationTypes.ApplicationCookie, ClaimTypes.Name, ClaimTypes.Role);
//Add claim to store doctor ID, roles can also be added here if needed
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, Convert.ToString(user.userID)));
identity.AddClaim(new Claim(ClaimTypes.Role, "AddRoleHere"));
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = model.RememberMe }, identity);
return RedirectToLocal(returnUrl);
}
else
{
ModelState.AddModelError("", "Invalid username or password.");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
My worry is that, if I use the AuthenticationManager.SignIn in both Login Actions, albeit they are different Actions, would this cause problems, e.g., sharing of the authentication cookie being setup, threading issues or even race conditions.
I feel I need to ask this question and hopefully get some response before I continue with this application.
I've seen a previous application with these issues, not necessarily to do with authentication, but let's just say it makes me very cautious especially when data is involved.
Any feedback or discussion around this would be great.
Thanks.

Related

MVC 5 Identity (v2) Authentication Without Creating an Application User

Is there a way to authenticate a session without creating an ApplicationUser in MVC 5 identity?
For various reasons, I ended up using a two layered authentication system. I parse a "user" object from my custom db into session, and in various places all over the site, the existence of this object is how the logged-in status of a user is determined.
I use Identity user stuff (e.g. claims, logins, etc.) at various places of the site. But at this one specific instance, I need to log in an anonymous Identity user and parse whatever user object is requested to the session. So how can I create an anonymously authenticated session with Identity V2?
In Identity you don't need to have user object to authenticate. You could create some claims on the fly and use them to authenticate. Consider this simple example:
[HttpPost]
public ActionResult AnonymousLogin()
{
var ident = new ClaimsIdentity(
new[]
{
// adding following 2 claim just for supporting default antiforgery provider
new Claim(ClaimTypes.NameIdentifier, "AnonymousUserID"),
new Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", "ASP.NET Identity", "http://www.w3.org/2001/XMLSchema#string"),
new Claim(ClaimTypes.Name, "AnonymousUserID"),
},
DefaultAuthenticationTypes.ApplicationCookie);
HttpContext.GetOwinContext().Authentication.SignIn(
new AuthenticationProperties { IsPersistent = false }, ident);
return RedirectToAction("MyAction"); // auth succeed
}
Now you have authenticated an anonymous user just like a real user:
[Authorize]
public ActionResult MyAction()
{
// all authorized users could use this method don't matter how have been authenticated
// you have access current user principal
var username=HttpContext.User.Identity.Name;
}

Add roles to ADFS IPrincipal

I have been looking for answer to this question for a few days now, but I have not found any success. I would post the links, but it would probably take up the entire page.
So here is what I have...
I have an MVC application, which uses the WC-Federation protocol. I have been able to configure the application, so that it authenticates the users, and returns the claims from ADFS. This works perfect. I can also extract all the claims with no issues. But I am doing this within one of the actions in the controller.
And here is what I want to do...
I want to use ADFS to authenticate the user, but I want to use my own internal roles to authorize the user to have access to specific controllers (e.g. [Authorize(Roles = "CoolRole")]). I want to be able to do this, because I already have a Web API that uses OAuth 2.0, with a backend SQL Server database to manage users and roles (internal and external user.) I now want a secure portal that will allow internal users to access the data with a single-sign-on experience. Looking at the Controller model, I noticed there are some properties associated with the authentication process (OnAuthentication, OnAuthenticationChallenge) and one for the authorization process (OnAuthorization.)
I don't necessarily need the code, but I feel like I've hit a brick all, and I need to be pointed in the right direction.
UPDATE
I tried this:
protected override void OnAuthorization(
System.Web.Mvc.AuthorizationContext filterContext)
{
//Private class to create a new IPrincipal based on my AppUserMgr
var user = _setCurrentUser(
(ClaimsIdentity)filterContext.HttpContext.User.Identity);
filterContext.HttpContext.User = user;
base.OnAuthorization(filterContext);
}
This returned a 401 (Unauthorized) response.
and...
protected override void OnAuthentication(
System.Web.Mvc.Filters.AuthenticationContext filterContext)
{
//Private class to create a new IPrincipal based on my AppUserMgr
var user = _setCurrentUser(
(ClaimsIdentity)filterContext.HttpContext.User.Identity);
filterContext.Principal = user;
base.OnAuthorization(filterContext);
}
This just calls the STS numerous times, before it fails. I even tried swapping after the assignment to after the base is called in both. No luck.
Prior to the previous ones, I also tried to add an AuthorizeFilter to the control, but that didn't help:
http://pratapreddypilaka.blogspot.in/2012/03/custom-filters-in-mvc-authorization.html
I found this link: http://brockallen.com/2013/01/17/adding-custom-roles-to-windows-roles-in-asp-net-using-claims/
From there, I guessed my way through
Here is the basics of what I did:
I ended up overriding the OnAuthentication method of the Controller, but still made sure to call the base. I did this from within an extended class. Here is the concept:
public class AdfsController : Controller
{
//Some code for adding the AppUserManager (used Unity)
protected override void OnAuthentication(
System.Web.Mvc.Filters.AuthenticationContext filterContext)
{
base.OnAuthentication(filterContext);
//Private method to set the Principal
_setCurrentUser(filterContext.Principal);
}
private void _setCurrentUser(IPrincipal principal)
{
//Put code to find to use your ApplicationUserManager or
//dbContext. roles is a string array
foreach(var role in roles)
{
((ClaimsIdentity)((ClaimsPrincipal)principal).Identity)
.AddClaim(new Claim(ClaimTypes.Role, role));
}
}
}
In the Controller, you can now add the follow:
public class HomeController : AdfsController
{
//I used a magic string for demo, but store these in my globals class
[Authorize(Roles = "CoolRole")]
public ActionResult Index()
{
return View();
}
}
I tested this by checking a role assigned to the current user, and that worked! Then I changed the role to something like "reject", which the user was not assigned; and I received a 401 Unauthorized.
ADFS is the authentication/token service in Azure. to enable the Roles Based Authentication, you can use Azure RBAC (Role Based Access Controll) service to basically Augment the claims that you get back from the ADFS and add the roles that you get back from RBAC to the token, and use the same token in your API so lock down or secure the backend with that augmented token...
here is the reference for RBAC:
http://azure.microsoft.com/en-in/documentation/articles/role-based-access-control-configure/

MVC with Identity 2.0+ samples lacking for managing user roles

I'm not a web developer by trade, but every couple of years I play one on TV or hang with them to look cool. The last time I raved with ASP.NET was back in the webform days. Back then, having a web-based UX to manage the users on your site was straightforward. I understand ASP.NET Identity 1.0/2.0 and Federation are designed to give developers all kinds of new glow-sticks and pacifiers to party with but it's amazingly frustrating to me to crack open VS 2013, fire up a new MVC/SPA web app and not be able to easily do something everybody else should need and likely be doing, which is manage their users via some admin UX on the site itself.
So, if you're DTC (down-to-code), I would appreciate any, simple examples of how to do the following (#1 is by far the most important. I can extrapolate to #2 and #3...I hope.). Assume nothing fancy (a local machine project using the embedded SQL DB. You know, project template defaults.):
Display all users registered on a website AND THE ROLES THEY ARE PART OF. I've already got everything I could ever want to directly know about a user down with Entity Frameworks. But why are roles so non-obvious here? Snippets for the M, the V and the C much appreciated.
Add or remove roles for a user.
Add or remove available roles for users.
I see the tables, much like the ones that have been around forever, in new MVC projects. The basic user stuff is exposed very easily, but an old, trusted and necessary friend (roles) seems to require some voodoo, mojo or secret sauce to expose in a similarly easy fashion. I'm not far from just mucking with the tables via SQL directly. I know that's bad in the new world order and will likely tip the bouncers off that they shouldn't let me into the party behind the velvet rope.
p.s. I've even seen some posts here and elsewhere suggesting roles be done with claims. While that seems logical, I would prefer ASP.NET Identity 2.0 stuff based on the vestigial of roles (.NET types, SQL tables, etc.) that still exist.
I find the issue quite straightforward (much more than it was before, at least with the membership system). The default installation uses Entity Framework as its backend and creates three tables (among others): one for users, one for roles and one for the many-to-many relationship. It also provides us with two classes that help us with managing users and roles: IdentityUserManager and IdentityRoleManager. With the default template we get classes inherited from these (ApplicationUserManager and ApplicationRoleManager). With these classes we get the basic functionality to manage users and roles.
A last comment about your last p.s.: When you login, the framework stores your roles (which were stored in the database) as claims (which are stored in the authentication cookie). You can access these claims via the ClaimsIdentity of the ApplicationUser.Identity so you don't have to access the database every time you want to know a role of the current user. This is also used in the Authorize action filters.
For 1. Create new controller with read/write actions using EntityFramework(right click on controllers folder) and select model ApplicationUser.
2 and 3. You can paste this code into Seed method in Migrations/Configuration.cs
if (!context.Users.Any()) {
System.Diagnostics.Debug.WriteLine("INSIDE USER SEED");
try {
var store = new UserStore<ApplicationUser>(context);
var userManager = new ApplicationUserManager(store);
var roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(context));
string roleName = "Admin";
if (!roleManager.RoleExists(roleName)) {
roleManager.Create(new IdentityRole(roleName));
}
roleName = "TeleMarketer";
if (!roleManager.RoleExists(roleName)) {
roleManager.Create(new IdentityRole(roleName));
}
roleName = "Marketer";
if (!roleManager.RoleExists(roleName)) {
roleManager.Create(new IdentityRole(roleName));
}
var user = new ApplicationUser() { Email = "informatyka4444#wp.pl", UserName = "informatyka4444#wp.pl" };
userManager.Create(user, "TestPass44!");
userManager.AddToRole(user.Id, "Admin");
user = new ApplicationUser() { Email = "s8359#pjwstk.edu.pl", UserName = "s8359#pjwstk.edu.pl" };
userManager.Create(user, "TestPass44!");
userManager.AddToRole(user.Id, "Admin");
user = new ApplicationUser() { Email = "marketer#wp.pl", UserName = "marketer#wp.pl" };
userManager.Create(user, "TestPass44!");
userManager.AddToRole(user.Id, "Marketer");
user = new ApplicationUser() { Email = "telemarketer#wp.pl", UserName = "telemarketer#wp.pl" };
userManager.Create(user, "TestPass44!");
userManager.AddToRole(user.Id, "TeleMarketer");
} catch (DbEntityValidationException e) {
System.Diagnostics.Debug.WriteLine("EXC: ");
foreach (DbEntityValidationResult result in e.EntityValidationErrors) {
foreach (DbValidationError error in result.ValidationErrors) {
System.Diagnostics.Debug.WriteLine(error.ErrorMessage);
}
}
}
}

MVC4 Trying to get the security model to work with my Environment

I hope someone will be able to put me on the right track, been trying to resolve this now for hours.
I am currently in the process of redeveloping a web application and I would like to use the MVC4 attributes for managing access to the various parts of the application.
The issue I am having is that the Authentication & Permissions are all handled by middle-ware applications that the web app has to interface with.
I was wondering if even with this restriction would I be able to use the security attributes & letting the web app know that the user is Authenticated.
Yes, you will be able to use existing Authorize attribute. All you have to do is write a custom Membership and Role providers that will use your existing services instead of relying on the default SQL database.
If you don't want to go through all this hassle you could also write a custom authorization attribute (deriving from AuthorizeAttribute) and inside the AuthorizeCore method call your service to check whether the current user has the desired roles.
Definitely. Not only is it possible, but also it's pretty easy. And if you can think of ASP.NET Roles as "activities", then you don't need to derive anything; everything you need is built in.
These examples assume securityService is the service that communicates with your middle-ware applications, and has two methods, GetUser and GetUserRoles:
Your Login action method
[HttpPost]
public ActionResult Login(LoginModel model, string returnUrl)
{
if (!ModelState.IsValid) return View();
var user = securityService.GetUser(model.Username, model.Password);
if (user == null)
{
ModelState.AddModelError("", "Username or password are incorrect.");
return View();
}
FormsAuthentication.SetAuthCookie(user.Username, model.Remember);
return Redirect(returnUrl);
}
In your Global.asax.cs
protected void Application_AuthenticateRequest()
{
if (Request.IsAuthenticated)
{
string username = User.Identity.Name;
string[] roles = securityService.GetUserRoles(username);
IIdentity identity = new GenericIdentity(username);
Context.User = new GenericPrincipal(identity, roles);
}
}
That's it. Login handles the authentication (when the user logs in), while Application_AuthenticateRequest handles the authorization (on every request). You then proceed to decorate your action methods with Authorize(Roles = "XYZ") making sure "XYZ" matches what comes back from your GetUserRoles method.

asp.net mvc user authentication/permission

i'm new to asp.net mvc and starting the following project. The company wants an intra-net website for various groups of people to upload files to a database, run reports off the it and amend data in several master tables in the database. The company use Active Directory and do not want the users to log in again to use the web site. The website will have different sections for various groups and the user's access to a particular page should be controlled from a database.
So far this is what i've come up with
changed the membership provider to link to the active directory server (based on Mike's blog post)
removed AccountController and the Views/Account folder
created a custom authentication class based on this link
I need to pull from a table in the database, based on user's AD id, his "role" (int), then cast it into the relevant SiteRoles. Would implementing this query in CustomAuthorizeAttribute be adviseable? is there a better place to pull the data from the table and store it somewhere so it can be reused rather than having to run a database query every time AuthorizeCore is called (which will happen whenever a user invokes a controller/action)?
A custom AuthorizeAttribute is definately the way to go as it will be applied before all other action filters.
Kindness,
Dan
I would use the out-of-the box ActiveDirectoryMembershipProvider rather than a custom attribute (because reinventing the wheel is generally bad, and reinventing the wheel in the area of security is bad to the point of incompetence in most cases), and the AzMan Role Provider to map AD groups and accounts to app roles.
This pairing gives you far more features out of the box (e.g., standardized GUI interface for permissions) than custom code, and is probably more secure, too.
You could do everything you want using the MVC provided FormAuthentication. Just create your custom ValidateLogOn method in the AccountController. Example:
public ActionResult LogOn(string userName, string password, bool rememberMe, string returnUrl)
{
if (!ValidateLogOn(userName, password))
{
return View();
}
FormsAuth.SignIn(userName, rememberMe);
Session["userlogin"] = userName;
if (!String.IsNullOrEmpty(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
Where your ValidateLogOn will be something like:
private bool ValidateLogOn(string userName, string password)
{
if (String.IsNullOrEmpty(userName))
{
ModelState.AddModelError("username", "You must specify a username.");
}
if (String.IsNullOrEmpty(password))
{
ModelState.AddModelError("password", "You must specify a password.");
}
/*
* Do your LDAP Validation stuff (DB queries, etc) here.
*/
}

Resources