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;
}
Related
I am having difficulty figuring out how to set the current user in an ASP.NET MVC 5 application that uses ASP.NET Identity.
We use a Web Service that encapsulates authentication. A function calls that service and gets back a JWT token that can be "unwrapped" to retrieve the ClaimsIdentity. It's my understanding that all you should need to do, at that point, is call HttpContext.GetOwinContext().Authentication.SignIn() and pass the ClaimsIdentity to establish the current user and get that user to persist across requests.
However, this doesn't seem to be the case. If I query this.User in the controller or the view afterwards, it's an anonymous user (this.User.Identity.IsAuthenticated evaluates to false). Also, refreshing the page or redirecting makes it obvious that there's no current user (again, this.User.Identity.IsAuthenticated evaluates to false).
When I inspect the identity I've retrieved from AccountHelper, all the data is there. It's fully populated with a name, an ID, and a full suite of claims.
So what is the right way to establish the current user and get it to persist across requests?
// This call authenticates a user with the provided credentials against our user store
// and returns a bearer token and a ClaimsIdentity.
var response = new AccountHelper().AuthenticateUser(credentials);
if (response.IsAuthenticated) // This is true
{
// This comes back with a fully populated identity, as expected.
var claimsIdentity = response.ClaimsIdentity;
// This call has no effect, whatsoever. It doesn't set the current user.
HttpContext.GetOwinContext()
.Authentication
.SignIn(new AuthenticationProperties { IsPersistent = true }, claimsIdentity);
First of all, did you miss .Current in your code sample?
It should be
HttpContext.Current.GetOwinContext()
.Authentication
.SignIn(...);
Secondly, I'm assuming you've setup cookie authentication in your app?
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = CookieAuthenticationDefaults.AuthenticationType,
...
});
Here setting the authentication type is important! And when you generate the claims identity and before you pass it into the .SignIn() method, the claims identity needs to have the same authentication type so that they can talk!
I would use .CreateIdentityAsync() method from the UserManager class to create the identity instead, because you can pass the authentication type in as one of the parameters:
// Create an application user from your claim identity?
var appUser = new AppUser { ... };
// And pass the user into manager to create the identity with the same authentication
// type you used when you setup the cookie authentication
var claimsIdentity = _userManager.CreateIdentityAsync(appUser,
CookieAuthenticationDefaults.AuthenticationType);
I am using this way to impersonate users for admins that have developer role so that we can test the app.
I'm building MVC 5 webapp with Windows Authentication.
Since I have external authorization store, so I want to add some custom claims authentication. I handle the PostAuthenticationRequest event
void Application_PostAuthenticateRequest()
{
if (Request.IsAuthenticated)
{
var id = ClaimsPrincipal.Current.Identities.First();
...
//query authorization store
id.AddClaim(new Claim(ClaimTypes.Role, "SomeRole"));
}
}
Then in controller, I check the IsInRole("SomeRole") , but I found it always return false even the identity have the SomeRole role claim
Then I found out that in Windows Authentication, the IsInRole() is using groupsid claims as role
Instead of add my custom claim to groupsid claim, how can I set the IsInRole function use the standard Role claims?
Look like RoleClaimType is the way to go, but it is readonly I cannot set it.
I don't think you can change the behavior of the WindowsPrincipal.IsInRole method.
What you can do is create a new ClaimsPrincipal from a new ClaimsIdentity, using the claims from the WindowsPrincipal. One of the ClaimsIdentity constructors lets you specify the nameType and roleType.
Having set the new ClaimsPrincipal, your IsInRole calls should work on the specified roleType.
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.
I'm using ASP.Net Identity with ADFS 2.0 (I think).
Users log in at a separate server, come back to me, I check the ClaimsPrincipal and pull out the userID claim, then use that ID to retrieve the user.
So I'm only using ADFS/claims-based auth to get the user object; after that, I have things like usergroups and roles, but they are custom objects and I manage them in the application rather than using ADFS to manage them.
What I want to know is: How hard is it to use my custom database roles with the out-of-the-box role stuff? Specifically, I want to be able to use the Role("RoleName") attribute on controllers, and wrap some UI elements in User.IsInRole("RoleName") on the views to control user access.
What do I have to do to wire this up?
I'm not aware of any Role attribute. Do you mean Authorize("RoleName") attribute?
Adding a role claim that is compatible with IPrincipal.IsInRole and AuthorizeAttribute as a consequence is very easy. Just add a claim with the type ClaimTypes.Role
//when creating a new identity
var identity = new ClaimsIdentity(new Claim[] {
new Claim(ClaimTypes.Role, "MyRole1"),
new Claim(ClaimTypes.Role, "MyRole2")
});
//add a claim to an identity
identity.AddClaim(new Claim(ClaimTypes.Role, "MyRole3"));
Then in your controller, add the AuthorizeAttribute
Authorize("MyRole1")
I write a controller like below:
public class AccountController : Controller
{
public ActionResult Login(/*---*/)
{
GenericIdentity identity = new GenericIdentity("userName");
GenericPrincipal principal = new GenericPrincipal(identity, new string[] { "role1", "role2" });
this.HttpContext.User = principal;
/*---*/;
}
}
After login, I can get user name by User.Identity.Name in other controller.
But User.IsInRole("role1") always return false.
How can I assign a value to User, I don't want to use Membership...
You need to persist the user data somewhere so that all subsequent page requests have access to it. Usually you would create an authentication ticket and store it in a cookie. Then for each request you extract the data and create your IPrincipal. This can be done in the Application_AuthenticateRequest method of Global.ascx,
MVC - How to store/assign roles of authenticated users has more information on a simple way to do what you want.
Hm.
Using membership?
At least the lower level API. You need to assign it a principal in some event (which basically turns into a cookie and is deserialized with every call).
Details are in http://support.microsoft.com/kb/306590
Or also in http://msdn.microsoft.com/en-us/library/aa302399.aspx