How to tell if ASP.NET impersonation is working? - asp.net-mvc-3

With ASP.NET impersonation, can one use Environment.UserName to determine if impersonation is working? That is if the site is impersonating properly, should Environment.UserName return my username?

You should use User.Identity.Name:
[Authorize]
public ActionResult Foo()
{
// If we got so far it means that the user is authorized to
// execute this action according to our configuration =>
// we can work with his username
string username = User.Identity.Name;
...
}

Related

ASP.NET Core custom defined User Roles implementation

I am trying to define a custom way of User Roles since my DB's structure for the User table is the following structure:
Role is a bool so if it's true the User is an Admin, else he's a normal User.
I know I need to declare the add.UseAuthorization() in Startup.cs. and I can add the Attribute [Roles="Administrator"] / [Roles="User"] inside the Controller but I am not sure how to define the role to be determined by my Role column from the User table.
I've been searching the internet, reading about Policies too but I don't think that's the right way to implement. Everything I've found online is about some sort Identity structure but doesn't make any sense on how to attach it to my Role column.
Hope, someone can help me out. Thanks!
If you are free to manipulate your DB, I would highly suggest using IdentityFramework, it's a powerful framework which can integrate in your own database.
But to answer your question specifically, there's two steps missing:
Pick an authentication scheme to login the user (e.g. Cookie-based, ...)
Once the user logs in, save the designed Role in a ClaimsPrincipal object. This way the [Authorize(Roles = "User")] declaration can pick this up.
Below you'll find a basic example using the default ASP.NET Core template in Visual Studio.
Add the Authentication middleware your ConfigureServices method, and configure it using a AuthenticationScheme. In this case I'm using Cookie authentication.
//in ConfigureServices, add both middlewares
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie();
//in the Configure() method, enable these middlewares
app.UseAuthentication();
app.UseCookiePolicy(new CookiePolicyOptions());
Now you're ready for action. Let's say you have an Action method in which you want to authenticate the user. This is where you want to transform your Role so it can be recognised by [Authorize]
Get the value you need from your database. You'd end up with a bool. Convert it to a Role Claim, and add that to a ClaimsIdentity.
bool roleFromDb = true; //this comes from db
//convert to Claim of "Role" type, and create a ClaimsIdentity with it
var adminClaim = new Claim(ClaimTypes.Role, roleFromDb ? "Administrator" : "User");
var claimIdentity = new ClaimsIdentity(new[] { adminClaim },
CookieAuthenticationDefaults.AuthenticationScheme);
//signs in the user and add the ClaimsIdentity which states that user is Admin
await HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(claimIdentity));
With that done, you can mark other actionmethods using the [Authorize] attribute, e.g:
[Authorize(Roles = "User")]
public IActionResult About() { ... }
[Authorize(Roles = "Administrator")]
public IActionResult Contact() { ... }
Now, only a signed in user with the "Administrator" role can visit the Contact page.
Check this resource for a more finetuned configuration of the middleware used.
Another way of implementing, based on my database without any modifications, is to use Claims and Cookies. I've managed doing this reading the following documents
Link One
Link Two
I've encountered only one major issue which was solved by reading this.
I'll also add the Login method and the Startup.cs rows, so others can see how to use it (if the docs aren't enough).
Login method from the Controller
[AllowAnonymous]
[HttpPost]
public async Task<IActionResult> Login(UserModel userModel)
{
if (_iUserBus.LoginUser(userModel))
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name, userModel.Email),
new Claim(ClaimTypes.Role, _iUserBus.GetRole(userModel.Email)),
};
ClaimsIdentity userIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
ClaimsPrincipal principal = new ClaimsPrincipal(userIdentity);
var authProperties = new AuthenticationProperties
{
IsPersistent = false,
};
await HttpContext.SignInAsync(principal, authProperties);
return RedirectToAction("Index", "Home");
}
else
{
ModelState.AddModelError("Password", "Email and/or Password wrong");
return View();
}
}
Startup.cs
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
});
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options =>
{
options.LoginPath = "/Users/Login";
options.LogoutPath = "/Users/Logout";
});
Hope this is useful to anyone in need.

JWT auth with [Authorize] attribute

Could someone shed a light on how default Asp.Net core attribute [Authorize] (with using Asp.Net Identity) understands how it should decode JWT token and get necessary info for granted access?
While forming JWT token I put in token RoleClaims for the user, does [Authorize] base on claims to grant them access to specific actionMethod
You can access your claims using the following code:
User.Claims.FirstOrDefault(el => el.Type == claim)?.Value
More details please follow this link
Create JWT & Authorize
[Authorize]
[HttpPost]
public string Post()
{
var identity = HttpContext.User.Identity as ClaimsIdentity;
IEnumerable<Claim> claim = identity.Claims;
var UserName = claim.Where(c => c.Type == "UserName").Select(c => c.Value).SingleOrDefault();
return "Welcome to " + UserName + "!";
}

Login based on user type

I am making a web application using asp.net mvc 3, which has login also.
There are 3 different types of users who will be using the site: Administrator, Operator & Distributor.
How can I create a login that restricts a Distributor from accessing Administrator's & Operator's part of the website. Similarly an Operator should not be able to access Administrator & Distributor part. Also Administrator should not be able to access other type of user's part. i.e. the site should redirect an Administrator type of user to his own part of website after login.
And finally no one should able to access their own part of website without login.
Please could anyone help me.
Look into the membership model of ASP.NET. This model is used to authenticate and authorize users for different parts of your web application.
With the membership model, define three roles within your application: Administrator, Operator and Distributor. Of course, also create users within your application and divide them over these roles.
Last up is the actual authentication and authorization. Use the Authorize attribute to define which role a user must have to access a certain part of your website.
[Authorize(Roles = "Operator")]
public ActionResult OperatorOnlyStuff()
{
return View();
}
And to make sure users should be logged in to even access anything on your site, define a custom authenticated route constraint.
public class AuthenticatedRouteConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
return httpContext.Request.IsAuthenticated;
}
}
And use this custom authenticated route constraint in your default route:
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new { isAuthenticated = new AuthenticatedConstraint()}
);

Require re-authentication for certain actions

For certain actions like changing email settings or administrator activities, I want users to re-authenticate before the action is completed. Is there a good pattern for doing this in ASP.NET MVC 3?
Descpription
You can create your ActionMethod with Username, Password and the field you want to change (Email) for example. Than validate this data in the [HttpPost] of your data. If the authorization has success, change it and if not add the error to the ModelState.
Use a ViewModel for that.
Sample
public class ChangeEmailViewModel
{
public string Username { get; set; }
public string Password { get; set; }
public string EmailAddress { get; set; }
}
public ActionResult ChangeEmail()
{
return this.View(new ChangeEmailViewModel());
}
public Action ChangeEmail(ChangeEmailViewModel model)
{
// authorize
bool isAuthorized = // your logic.
if (isAuthorized)
{
// change email
} else
{
ModelState.AddModelError("Username", "Username is not valid");
}
return this.View(model);
}
If you want to dynamically intercept and re-authenticate someone who is already authenticated, you could probably also handle this with a special cookie. The actions that require re-auth could be decorated with a custom filter that overrides OnAuthorization to check for the cookie, then redirect to take username & password if it is not found. Pattern, no code:
User clicks link to uber-protected action.
Filter on action looks for cookie and does not find it, redirects to sign in.
User signs in, and you write a special cookie
(different from the forms auth cookie),
then redirect back to original action.
Filter on action looks for cookie and finds it authorizing user.
The lifetime of the cookie would at least have to go all the way to the http post of the uber-protected action. You will have to decide when to delete it. For example, after user re-auths for one uber-protected action, do you want them to re-auth for second uber-protected action in the same browser session?

MVC 3 Cookies not working

I am using forms authentication for an MVC website and I am having a problem adding Cookies, I am using an Encrypted Forms Authentication Ticket and adding it to the Cookies but when inspecting my cookies it is there (by name "AuthCookie") but the value is always null and the Expires date is always set to "01/01/0001 00:00"... here is my Login controller code:
[HttpPost]
public ActionResult Index(Login login, string returnUrl)
{
if (ModelState.IsValid)
try
{
User user = UserManager.Login(login.Username, login.Password);
string serialUser = Serialize.SerializeToString(user);
string ticket = FormsAuthentication.Encrypt(
new FormsAuthenticationTicket(1, login.Username, DateTime.Now, DateTime.Now.AddMinutes(20.0), login.RemeberMe, serialUser));
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, ticket) { Expires = DateTime.Now.AddMinutes(20) };
Response.Cookies.Add(cookie);
if (String.IsNullOrEmpty(returnUrl))
return RedirectToAction("Index", "Home");
else
return Redirect(returnUrl);
}
catch (LoginFailedException)
{
ModelState.AddModelError("", "Login failed: Invalid Username or Password.");
return View(login);
}
else
return View(login);
}
At first I assumed the encrypted string was not working due to the length but I have tested this by creating a simple test cooke and I am getting the same result.
Can anyone help
When you call Redirect() or RedirectToAction(), you're terminating the response so the cookies aren't sent to the client. Some solutions:
Use TempData to persist the information across the direct, writing the Cookie in the action you redirect to.
Take a look at the way Forms Authentication cookie information is written in the NerdDinner code on CodePlex.
As mentioned in the comments, you can persist role information in Session. The recommendation to store the role information in Session and retrieve from Roles if not found would work, but I'd start by using the membership system as-is and performance tuning later if you see that it's a problem, rather than assuming it will be.

Resources