I am trying to build an ASP.NET 3.5 website that allows users to log in and browse a couple of pages. I would like to restrict certain users to be able to view certain pages but I'm having trouble coming up with a custom and flexible system. I have seen MS's version of this but it's not what I am looking for. Can anyone direct me to some good online articles or even a video tutorial so I can do further research. Thanks!
P.S. I have tried creating a class that inherits from System.Web.UI.Page which does some checking but it's getting messy. All my other pages inherit from that common page. Is this a common practice? How have you guys solved this problem in the past?
The best way to implement this would be, Forms Authentication coupled with Custom Role Provider.
Hope you know, for Forms Authentication to work, you need not have to use the Complete Database Setup that MS uses to Authenticate.
You can simply have your own Database and Validate a user yourself, and just set the cookie.
String UserName = "CoolGuy";
Boolean isValidUser = YourClass.YourMethod(UserName);
if (isValidUser)
{ FormsAuthentication.setAuthCookie(UserName, false); }
This will authenticate the user "CoolGuy" for the session, provided YourMethod returns true.
You can use this, coupled with custom role provider. This gives you the facility to check User.IsInRole("Role"); in your code.
To Start with CustomRoleProvider.. here is a good reference... http://davidhayden.com/blog/dave/archive/2007/10/17/CreateCustomRoleProviderASPNETRolePermissionsSecurity.aspx
Raja
Well, without knowing the exact details of your app, one thing you could use is the Role Manager built into the Membership API.
Basically, you would create roles for each page and assign users to the roles (pages) you would want them to view.
In the code behind for each page, on the On_Load event, I would simply call the method
if(Roles.IsUserInRole(rolePageName))
{
//Continue page loading logic
}
{
//Redirect or transfer the user elsewhere
}
For this kind of logic you may want to reconsider using an inherited page, otherwise you're going to have to come up with a way to retrieve the URL of the page and pass that into some long list of if-else or switch statements to call the proper Roles.IsUserInRole method.
Related
I'm building an application in ASP.NET MVC4 as a learning exercise. I'm trying to understand
authentication and authorization. That seems fine, role based authorization seems fine for restricting certain controllers/actions to users who are part of a given role.
What I'm struggling with is how I can apply this to data which belongs to an individual user. Using a forum as a simple example how could the functionality be achieved whereby a user can only edit or remove posts that they have created but can view/add comments to posts of other users. Would this have to be done in code by checking the user associated with the post to be updated against the current user before allowing the update to take place, returning unauthorized if they don't match.
Is there a more elegant solution that can be applied rather than applying this kind of logic to multiple controllers/actions?
There's a wealth of information out there I'm just trying to narrow the search. Can anyone suggest a good tutorial/article on this. I've been looking at Forms authentication and Membership but I'd be interested in something using Identity too. I'm also using Entity Framework.
Thanks
Would this have to be done in code by checking the user associated with the post to be updated against the current user before allowing the update to take place, returning unauthorized if they don't match.
Yes, that's exactly what you do. While role-based authorization is a matter of a simple relation between users and roles, data-access level authorization is usually complex and involve custom business rules.
Of course, it could help a lot to create a thin layer of managers that will be commonly used as guards so that you keep all the code close together:
[HttpPost]
public ActionResult PostFoo( FooModel model )
{
// keep the access manager separate from the
// domain layer. operate on IDs.
if ( new UserAccessManager( this.User ).
CanOperateOnFoo( model.IdSomething, model.IdWhateverElse ) )
{
}
else
// return 403 or a meaningful message
}
or
[HttpPost]
public ActionResult PostFoo( FooModel model )
{
// switch to the domain layer
Foo foo = Mapper.Map( model );
// make the access manager part of the domain layer
if ( foo.CanBeOperatedBy( this.User ) )
{
}
else
// return 403 or a meaningful message
}
Would this have to be done in code by checking the user associated with the post to be updated against the current user before allowing the update to take place, returning unauthorized if they don't match.
No, you want to avoid hard-coding authorization logic into your code. Doing so leads to:
authorization silos
poor visibility
a chance there might be errors in the authorization logic
hard-to-maintain logic
Is there a more elegant solution that can be applied rather than applying this kind of logic to multiple controllers/actions?
Yes, there is. Much like you wouldn't hard-code authentication or logging into your app, you want to externalize authorization. This is called Externalized Authorization Management (EAM). There are several frameworks that help you do that from Spring Security in Java to Claims-based authorization in .NET to XACML-based solutions.
There are 2 fundamental authorization models you want to consider:
role-based access control (RBAC)
attribute-based access control (ABAC)
You can read about both on NIST's website (RBAC | ABAC).
Given the sample rule you gave:
A user can only edit or remove posts that they have created but can view/add comments to posts of other users.
RBAC will not be enough. You will need to use ABAC (and XACML) to be able to implement the relationship between the user and the data requested. XACML, the eXtensible Access Control Markup Language is a standard that provides you with:
a standard architecture.
a request/response scheme, and
a policy language.
With the XACML policy language, you can rewrite your example as:
A user can do the action==edit or the action==remove if and only if the post.owner==user.id
A user can do the action==view on any post
A user can do the action==comment on any post
Then, from your code, all you have to do is send an authorization request: Can Alice view post #123?. The authorization engine (also called policy decision point or PDP) will determine who owns the post and will reach a decision, either of a Deny or a Permit.
A key benefit to using externalized authorization and XACML is that you can apply the same consistent authorization to any layer (presentation tier, business tier, ESB, APIs, databases...) and any technology (Java, .NET, Python...).
Other benefits include:
modular architecture
configuration-driven authorization that is easy to grow as requirements change
easy-to-audit authorization
centrally-managed authorization
cheaper to develop and onboard new applications than writing code over and over again
standards-based.
There are several open-source and vendor solutions out there that address this market. Have a look at Axiomatics (disclaimer: I work for Axiomatics) or SunXACML (open source).
HTH,
David.
I am having troubles wrapping my head around the concept of multi tenancy in combination with websecurity (webmatrix framework from microsoft). I am building a mutli tenant website with:
mvc4
entityframework6
websecurity (from webmatrix)
Authenticate
I can allow users to register & login using the WebSecurity methods. I can verify if a user is logged in / is authenticated via User.Identy.IsAuthenticated.
Determine Tenant
I determine the tenant via the url ([companyname].domain.com).
Register a new customer
A new customer can create a tenant via the registering form in my application. If a user registers (without having a companyname present in the url) he will have to give some account inputs as some company inputs. He will then create a new alias which is conform companyname.domain.com. So, long story short, a Tenant is always coupled to 1 or more user(s) (1-N).
Requirement
I need to guarantee that a user from Tenant 'abc' will never be able to login to Tenant 'xyz'. (Therefore I also don't like the WebSecurity framework too much, as it seems a shared database for all my tenants (or am I wrong?)).
My question
Could you guys share some insights in how to handle the check on "tenant" and "authenticated user" in real world multi tenant applications?
The hot topics for me:
Do you validate the tenant + authenticated user once, or in every action in every controller?
Is it safe to rely on the default websecurity class or would I be better of designing my own user tables or are customer MembershipProviders the better alternative?
Should I use cookies or is that a very bad choice.
I would be very much helped if you could share some documentation where I can read all about these questions. I have the strong desire to see some more in detail documentation about multi tenancy, that dives into the actual design (maybe even code examples).
I already read through most of the "general documentation" / "commericial presentations":
http://msdn.microsoft.com/en-us/library/aa479086.aspx
http://www.businesscloud9.com/content/identifying-tenant-multi-tenant-azure-applications-part-2/10245
http://msdn.microsoft.com/en-us/library/windowsazure/hh689716.aspx
http://www.developer.com/design/article.php/3801931/Introduction-to-Multi-Tenant-Architecture.htm
If needed I'll rephrase / add code / do whatever is needed to get help.
Many thanks in advance.
Each solution you could get here would be dependent on what your app does and how it works with data, if you use repository pattern, if you use IoC etc. You might consider instantinating your repository by passing userid to repository class and doing filtering everytime application needs data, you can do that in your controller - this approach is used very often (even in VS SampleProjects - like "SinglePage Application" you might want to download some open source projects and just see how it's done there.
What I do in some of my projects where nothing "really fancy" is required and I don't expect a huge load is this:
- I setup BaseController that every other controller needs to implement
- in onActionExecuting event of the BaseController I do
public Employee CurrentEmployee { get; set; }
protected override void OnActionExecuting(ActionExecutingContext ctx)
{
base.OnActionExecuting(ctx);
string authenticatedUser = User.Identity.Name;
CurrentEmployee = mortenDb.Employees.FirstOrDefault(e => e.Account.Login == authenticatedUser );
}
so in all other controllers I'm able to refer to an Employee object that belongs to currently logged in user. You could do the same with your Company object. So I assume you would query Employees like I do and retrieve the Company reference and pass it to public property on your BaseController. It's maybe not the best solution, but it's rather secure as long as you remember to pull out data via Company object navigation properties (eg. Employees, Tickets, Requests etc. whatever you have in your Model )
'Hi --
I'm changing the way I build my UI from this:
If ( role == 'Admin' ) myComp.visible = false;
...to a totally dynamic UI based on what is returned from the DB. I'm architecting the best approach to this now.
I've read about role-based access control and understand that it's best that the server generates the UI after a user is authenticated, but apart from re-doing the entire backend to store MXML et al., is there a better approach?
Is it a bad idea to have a Permissions object that has properties like:
showTabOne:Boolean = true;
allUserToEditGrids:Boolean = false;
The components visibility and includeInLayout properties will be bound to these values.
The UI will also allow a user to create new roles and set permissions.
The only drawback I see is that every time a new feature is added, the app will have to be recompiled to update the bindings.
Any tips are greatly appreciated.
Thank you!
Permission object is fine, if you have complex enough policy, it is natural to abstract it into its own class. About recompilation - bindings can be set in runtime (BindingUtils), maybe you can use it to avoid it. Not sure what is
re-doing the entire backend to store
MXML
Normal way would be MXML controls composed after the authentification, indeed.
Be advised that someone can spoof a feed or flashvar to create a permission object to get themselves the credentials they require in a client app, allowing them to view/edit supposedly restricted content/areas.
A good approach for this would be, upon server authentication of the user and role, return a manifest xml defining what part of the ui is visible to the user and bind to those properties.
You can take security one step further and put restricted areas in flex modules to be loaded at runtime when the user navigates to that section. Before the module request is returned from the server, validate the user's right to load that module and return an error code if they are not logged in or do not have the role required for that module.
Storing mxml serverside for dynamic view generation is not a tenable approach. Yes you can, no you should not. Non-trivial use of the site would bring down the server with a quickness unless you implement a good caching mechanism.
See Web-tier compilation of MXML files for more info though as it's an interesting concept.
Check out the Flex Chimp and this article that describes it.
I need to slightly tweak the functionality of the ASP.NET Membership provider to add custom logging functionality. Instead of creating a wrapper class around the methods I wish to modify, I was toying with the idea or creating a custom Membership Provider and override a few of the methods.
All the examples I could find would show how to create it from scratch. I don't want to overwrite everything... just override a few methods. Can somebody point me in the right direction?
Thanks!
EDIT:
DOH! I can simply inherit from SqlMembershipProvider and override the methods. However, how can I get at the connection string?
What is it that you are trying to log?
If you simply want to monitor success and failure of authentication, ASP.NET Health Monitoring is already in the box. Events are logged to the WebEvent tables.
If you have other motives, well then..... ;-)
to answer your question about the connection string, override Initialize and capture the value from the config argument before calling base.Initialize
Everyone probably notices that most modern applications nowadays has a way for user to send crash/bug report either automatically or with user permission. Some examples are Mozilla Crash Reporter or most Microsoft applications.
I really like this feature since it allows me to collect the bugs report quickly with helpful information than just let my user reports the bug/issue traditionally such as submit a help ticket.
I wonder if there is an easy or systematic way to implement that capability in ASP.NET web application.
Have you guys had any experience or knowledge to share for both WebForms and MVC applications? Or if this could be implemented in Client-side like JavaScript/JQuery, that'd be good.
Thanks!
ASP.NET 2.0 introducted Health monitoring, which allows you to do this by just adding some stuff to the web.config. See: http://msdn.microsoft.com/en-us/library/ms998306.aspx
It can log to mail, sql, eventlog, etc. and allows you to set buffers. So it for example won't kill your mailserver if the sql database goes down or if some user discovers a bug and tries to call it too often a second :-)
You can also log failed authentication and app pool restarts with it, it's pretty usefull if you just need it working quick. It's still questionnable if it is the best solution to manage all the errors. Because it might not got all the information you need, for example browser version or smt like that.
ELMAH is a library that plugs in and detects exceptions. You can also log an event yourself. The events and a great deal of data like url parameters and browser information can be emailed to administrators and optionally stored in a database for display. (Rather like an event log for the web site.) It doesn't have a built-in user form that I've seen, but can probably be extended to include such an option.
I've been using/customizing it for about two years now and it is really exceptional.
Another option might be to use Kampyle which includes a feedback box on the bottom right of your web site. You could use Javascript to trigger the box to appear if an issue is detected on the web site.
For an ASP.NET applicatino--or any Web application for that matter--isn't this just a two-step process of:
Logging the error (obviously); and
Put a form on the error document to allow the user to enter feedback.
Or is there more to this?
Your errors will pass through the Application_Error method of the Global.asax.cs file (which you may have to create). I use this fact to capture the error and log it to a database:
void Application_Error(object sender, EventArgs e)
{
try
{
SqlConnection errConnection = new SqlConnection("Your connection string");
// After setting up a command object, I call a stored procedure to save information about
// the crash. I pass two primary arguments. The first is the URL:
errCommand.Parameters.Add("#URL", SqlDbType.VarChar).Value = Request.Url.ToString();
// The second is the error information.
errCommand.Parameters.Add("#EI", SqlDbType.Text).Value = Server.GetLastError().ToString();
// I pass some other information from my session as well...
// After setting up an output parameter called ErrorID, I call the command...
errCommand.ExecuteNonQuery();
// Now Error ID is stored in the session.
Session["ErrorID"] = (int)ErrorID.Value;
}
catch { } // I do NOT want the error handling call to throw an error.
}
Now, you should have set up your Web.Config file so that a specific page gains control when an error occurs. In this page, you'll check the session for the error ID and show it to the user. In the output, I ask the user to write down the error if they would like to call us for more information. If we do receive a request, I can go into the database and get a complete trace of the error.
You can checkout my tutorial on how to implement exception logging in asp.net - http://jesal.us/blog/index.php/2008/04/08/exception-logging-using-the-database/