Implementing validation of active membership in .NET MVC - asp.net-mvc

I need to verify whether the authenticated user has an active membership to my site. For example, if the user's membership is active they are freely able to browse the "members only" area of the site, whereas if their membership is inactive or expired they are automatically redirected to the billing area of the website. They would only be able to view certain restricted pages.
I am thinking of approaching this by storing the user's membership expiration date in the FormsAuthentication cookie. I am using a custom MembershipProvider and already storing the user's ID in the cookie, so this would be easy to do. The authentication cookie is set to expire in 24 hours. Then I would check whether their membership is active using a custom AuthorizeAttribute, like so:
public class MembershipAuthorizeAttribute : AuthorizeAttribute
{
private readonly bool authorizeMembership;
public MembershipAuthorizeAttribute()
{
this.authorizeMembership = true;
}
public MembershipAuthorizeAttribute(bool authorizeMembership)
{
this.authorizeMembership = authorizeMembership;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (this.authorizeMembership)
{
// Code to validate the membership hasn't expired
}
return base.AuthorizeCore(httpContext);
}
}
Then I can just decorate my controllers as such:
[MembershipAuthorize]
public class ActiveMembersController : Controller
{
// Only users with an active membership can access this controller
}
[MembershipAuthorize(false)]
public class BillingController : Controller
{
// All members can access this controller
}
Is this a good approach to take or is there a cleaner/more preferable method to validate whether a user's membership is active? I would prefer not having to hit the database on every request just to retrieve the user's membership expiration date or status, which is why I want to store this value in a cookie. Also, is it fine to store this value in the FormsAuthentication cookie, or should I be storing this in a different cookie?

Storing that information in a cookie does not strike me as the right approach. The reason, as it is pointed out in this answer https://stackoverflow.com/a/706874/2168278 is that cookies are stored in the client's machine. So it's possible that they can be tampered.
Storing this information in a database seems more appropriate. If you are concerned about performance you can always cache your queries.

I would approach this differently. I would have a background process to check for memberships that are expiring and disable those accounts.
If users attempt to login I would check if the account is disabled and then act upon that.

Related

asp.net identity with domain controller

I need to achieve to authenticate users with their domain user/password, if they're are in the domain controller, but the application should be available for other users as well, who should be authenticated with their own username/password; this should be stored in the application database, and their username/password to be checked against the DB.
So far i started with new asp.net template in vs2015, choosing Individual User Accounts.
I'm able to authenticate users agains domain controller, but if that is succeeded I'm unable to store the user to HttpContext.User property.
In SignInManager i call PasswordSignIn and return Success or Failure depending on AD check.
public SignInStatus PasswordSignIn(string userName, string password, bool isPersistent, bool shouldLockout) {
if(AuthenticateAD(userName, password)) {
//
// to create identity/principal and assign to HttpContext.User
//
return SignInStatus.Success;
}
else {
return SignInStatus.Failure;
}
}
public bool AuthenticateAD(string username, string password) {
using(var context = new PrincipalContext(ContextType.Domain, "domainname")) {
return context.ValidateCredentials(username, password);
}
}
thanks for any hint!
The only way this really works is if you create proxy users in your application for users in AD. Essentially, you just set up a script that populates new users/updates existing users based on the data in AD on a schedule (nightly, etc. based on your needs). Then, you're dealing with just one type of user whether they're part of the domain or external. The only change you need to make is to selectively authenticate via AD or via the standard password authentication. Either way, the same user principal is in play.
You can use ADFS and allow users to choose where to authenticate. It is quite trivial to implement using default template. Just like usual login mechanics with Sign-in via google and local account.
I think this is most correct way of doing things, because domain users may end up with Kerberos/Ntlm, if they want, and it lowers complexity of your system.
Here is a WS-Fed example: Using Claims in your Web App is Easier with the new OWIN Security Components
For other stuff you can create app with default template. This app will have external authentication stuff as example.

Securely passing data between pages

I am looking to create a new Web App that will allow the user to first enter the users id then navigate around the site based on that user's id. So, first the user would search for an ID, select that user and have options available based on that ID.
Currently I am using the Query string to store the ID, so... /AddProduct/2222.
This works fine but I'm not too sure about the security aspects. I've thought about sessions and cookies but I don't think they are suitable for this scenario. Or do I encrypt the ID for the query string?
Does anyone have any thoughts?
Thanks
Edit
I forgot to mention, the users will be authenticated and have specific permissions on each page on the site. The data is also stored in a database. So, the site will be querying and editing/adding to current data.
So basically here you seem to be afraid that some user might modify an item belonging to another user. Alright, this sentence tells us already that you have users and items in your application and that there are some roles associated to those items. And you have a mechanism to identify those users. So you are probably using some sort of authentication such as the built-in FormsAuthentication for example. So now the question becomes: how to ensure that the currently authenticated user is not modifying the product that belongs to another user.
OK, so you have items that belong to users. I suppose that this information is stored somewhere on the server, presumably a database or something. One approach I would recommend you is to write a custom authorization attribute which would check if the requested resource id actually belongs to the currently authenticated user.
For example:
public class MyAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var isAuthorized = base.AuthorizeCore(httpContext);
if (!isAuthorized)
{
// The user is not authenticated or authorized => no need to continue further
return false;
}
// At this stage we know that the user is authorized => we can fetch
// the username
string username = httpContext.User.Identity.Name;
// Now let's fetch the id of the resource he is trying to manipulate from the request
string id = httpContext.Request["id"];
// All that's left is to verify if the current user is the owner
// of the account
return IsOwnerOfItem(username, id);
}
private bool IsOwnerOfItem(string username, string id)
{
// TODO: query the backend to perform the necessary verifications
// about whether the user has permissions to work with the resource
// pointed by the id parameter
throw new NotImplementedException();
}
}
and now all that's left is to decorate your AddProduct controller action with this custom attribute:
[MyAuthorize]
public ActionResult AddProduct(int id)
{
// if we get that far we know that the currently authenticated user
// is the owner of the resource pointed by the id parameter and we
// could proceed respectively
...
}
With this approach you don't need to be using any sessions or encrypting anything. The encryption is already built into the ASP.NET framework under the form of a Forms Authentication cookie which holds the currently authenticated username in a secure manner. This cookie cannot be manipulated -> the user cannot impersonate as another user. So once you've got the guarantee about who the current user is, all that's left to you is to perform the necessary authorization whether he can access the requested resource.

Security check an User to a access controller action

Hello guys I have a MVC actions that have Authorize attribute set on them. For each one of these actions there is a password/ security pin which is only valid for that Action.
public ActionResult Action_1()// generic pin 1
{
Return RedirectToAction("PinCheck", new { returnUrl = "Action_1" });
...
}
[Authorize]
public ActionResult Action_2()// generic pin 2
{
...
}
[Authorize]
public ActionResult PinCheck(string returnUrl)// generic pin 1
{
// request three characters of the pin in random.
...
}
[Authorize]
[HttpPost]
public ActionResult PinCheck(string a, string b, string c, string returnUrl)// generic pin 1
{
// check the three chars.
...
// How do I store pin check for the controller was a success and don't ask the user unless he closes browser or logout
}
My plan of action is checking pins stored by the Admin for the particular User for that particular Action in the Database. So far I have achieved checking PinCheck() routine but the problem I face is that the User has to enter the pin every time he requests that particular action. I made a way around this by saving an encrypted cookie on PinCheck success. But is there a way to modify the Authorize attribute and the Authentication cookie itself to achieve What I am doing?
You can also represent each Pin verified as a claim stored as part of the ClaimsIdentity in the cookie so that you can just query against the user's claims looking for the appropriate PinClaim in each Action. If you are using the ASP.NET Identity, you can do something like so when you verify the pin:
await manager.AddClaimAsync(User.Identity.GetUserId(), new Claim("<mypinclaim>", "<value>"))
await SignInAsync() // And then resign the user in to regenerate the cookie with the claim
One ways of doing this is by creating a custom role provider. You could create one by inheriting from RoleProvider. Then override IsUserInRole and optionally FindUsersInRole, GetAllRoles, GetUsersInRole to reflect your pin management logic.
Once done, register the custom role provide via the web.config.
A good article on custom role providers (http://bojanskr.blogspot.com.au/2011/12/custom-role-provider.html)

How does the Authorize tag work? - ASP.NET MVC

How does the Authorize Tag determine if the user is authorized or not?
Like say, if a user logs in and they try to go to a view that has an Authorize tag. How does it determine if a user is authorized or not? Does it do a query to database and check?
How about if they go to a view with a role authorization? Does it query the membership role table?
I am just wondering since I have what the ASP.NET membership tables considers duplicate userNames. I use a serious of fields to determine which user is what, allowing users to have the same duplicate userName, but still be unique in my database.
This caused me to have to write custom methods for lots of .NET membership stuff since it all used "userName" to do searching instead of using the UserId.
So I am now wondering if this could be the case with the Authorize tag. Since I have no clue how it works and like if I was not using .NET membership I would not have a clue how it would determine it.
The Authorize tag uses all the built in membership checks from ASP.NET. It's VERY easy to roll your own tag. For example:
public class MyAuthorize : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext == null) throw new ArgumentNullException("httpContext");
// Make sure the user is authenticated.
if (httpContext.User.Identity.IsAuthenticated == false) return false;
// Do you own custom stuff here
bool allow = CheckIfAllowedToAccessStuff();
return allow;
}
}
You then can use the [MyAuthorize] tag which will use your custom checks.
ControllerActionInvoker parses the attribute and calls OnAuthorization() on it when it's time to check the credentials.
The AuthorizationAttribute.OnAuthorization() method basically checks to see if User.Identity.IsAuthenticated is true or not. This just draws on the functionality of FormsAuthentication or whatever other authentication scheme you may be using.

asp.net MVC, how to redirect registered users that don't have a profile to page?

We are building a site using asp.net mvc. We want to allow the user to easily register and create an account. There is though a very special piece of information, that will be registered in his profile, that we want to show to him *after registration is finished, and he is logging in for the first time.
The logic is whatever the URL that was hit, if the user is authenticated and does not have a valid profile, redirect him to the "Create Profile" page.
The whole ui will depend on those profile choices. What approach should we use within the MVC framework, to force this workflow on the visitor? The ideas I can come up with require tons of code duplication in controllers etc, so its clearly a bad idea.
We are using Membership for users, but profile is our own implementation (no profile provider) that will connect profile data to a userId.
I think the easiest way to do this is either create a custom AuthorizeAttribute, extending the existing one or create a separate FilterAttribute. Either one of these would get applied to all of your controllers and ensure that an authenticated user has a profile. In the case where no profile exists, the filter would redirect the user to the page where the profile is created. This would be done by setting the result property on the context to a RedirectResult to the profile creation action. Only if the profile exists and is complete would the filter allow the user to proceed to the desired action.
Alternatively, you could create a base controller that overrides OnActionExecuting and performs the same task. I prefer the attribute mechanism as it is more flexible, i.e., you could have some public actions that are available without the profile (including the profile setting action).
Answering my own question: In the end I created a custom actionFilter. In the beginning, I took the path of subclassing [authorize] into [AuthorizeCheckProfile]. But then I realized that the use case was wrong: I did not want the logged-in only parts of my site to redirect to the create-profile page, if no user profile existed. I wanted any page of my site to redirect to that page, if its a logged-in user with no profile. The only place I don't want to check that is in the actual profile-create. Here's the code:
public class AssertProfileAttribute : ActionFilterAttribute {
public AssertProfileAttribute() {
}
public override void OnActionExecuting(ActionExecutingContext filterContext) {
if (filterContext.HttpContext.Request.IsAuthenticated == false)
return;
//we have a user, but does he have a profile?
if (filterContext.HttpContext.Session["UserProfile"] == null) { //not in the session
IUnityContainer container = filterContext.HttpContext.Application["container"] as IUnityContainer;
Profile hasProfile = container.Resolve<IProfileRepository>().GetUserProfile(Membership.GetUser());
if (hasProfile == null) {
//we have to redirect to the create profile
string returnURL = filterContext.HttpContext.Request.AppRelativeCurrentExecutionFilePath;
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = "Profile", action = "Create", returnTo = returnURL }));
} else {
//he has a profile but we haven't put it in session yet
filterContext.HttpContext.Session["UserProfile"] = hasProfile;
}
}
}
}
It has the side-effect that it will store the profile in a Session key. This way it can be easily be fetched so that further role checks can happen in every request with other custom filters. The implementation uses Unity and repositories for db access.
A big thanks to the community.
Try consider ActionFilter and FilterAttribute if not most pages need to do so, or else, you may actually put this redirection logic to global.asax (in those Begin Request or similar events)

Resources