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 )
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.
Our company has a multi tenant asp.net web application. The application is 3 tier e.g. website,business and dataaccess. We hold the tenant id in session after the user logs in.
When we need to get a list of 'customers or orders' we pass the tenant id from the website to the business to the data access and then to the database (and query for customers or orders for that tenant). (almost every business function takes tenantId as a parameter)
Sometimes when creating new functions developers forget to add the tenant id from the website to the database, causing a security issue.
Is there a way we could do this so that the developers dont need to always remember to pass the tenant id.
Any suggestions on how best to resolve this issue.
public class CommonService
{
public int getTenantId()
{
//do your validations and error handlings
string tid = session["tenantId"] // or get it from customs claims principal or set it in a httpcontext.current.items
return tid;
}
}
Then use the service in every business object to get the tenant id and pass it to the data layer without depending on the developers to do it. Its a very big security hole, missing an tenantId might return data which the user is not supposed to see and might shutdown the company
It sounds like you are passing all the values around individually.
If you construct an object that you can pass around freely, you will always have the information you need. I would assume that the UserId is always associated with a tenant. Can you build a simple object, store it in the session and then pass it to all functions needing it.
class user{
int userID;
int tenantID;
}
If you have a value in the Session and you need it in the database queries, you have to propagate it through the tiers to the database queries.
If your developers sometimes forget to pass the value and they get security issues, that is actually not a security issue but a security feature.
If the database needs that id, then the business layer methods should have parameters for it. How can they forget it?
One approach would be to create a View per table per tenant (may not be practical depending on the number of tenants you have and how frequently they change) and deny access to the application to the underlying tables.
This article explains how to do this as well as several other approaches and their performance tradeoffs:
http://msdn.microsoft.com/en-us/library/aa479086.aspx
We have many instances in our application where we would like to be able to access things like the currently logged in user id in our business domain and data access layer. On log we push this information to the session, so all of our front end code has access to it fairly easily of course. However, we are having huge issues getting at the data in lower layers of our application. We just can't seem to find a way to store a value in the business domain that has global scope just for the user (static classes and properties are of course shared by the application domain, which means all users in the session share just one copy of the object). We have considered passing in the session to our business classes, but then our domain is very tightly coupled to our web application. We want to keep the prospect of a winforms version of the application possible going forward.
I find it hard to believe we are the first people to have this sort of issue. How are you handling this problem in your applications?
I don't think having your business classes rely on a global object is that great of an idea, and would avoid it if possible. You should be injecting the necessary information into them - this makes them much more testable and scalable.
So rather than passing a Session object directly to them, you should wrap up the information access methods that you need into a repository class. Your business layer can use the repository class as a data source (call GetUser() on it, for example), and the repository for your web app can use session to retrieve the requested information (return _session.User.Identity).
When porting it to winforms, simply implement the repository interface with a new winform-centric class (i.e. GetUser() returns the windows version of the user principal).
In theory people will tell you it's a bad business practice.
In practice, we just needed the data from the session level available in the business layers all the time. :-(
We ended up having different storage engines united under a small interface.
public interface ISessionStorage
{
SomeSessionData Data {get;set;}
...
.. and most of the data we need stored at "session" level
}
//and a singleton to access it
public static ISessionStorage ISessionStorage;
this interface is available from almost anywhere in our code.
Then we have both a Session and/or a singleton implementation
public WebSessionStorage
{
public SomeSessionData Data
{
get { return HttpContext.Current.Session["somekey"] as SomeSessionData;}
set { HttpContext.Current.Session["somekey"] = value;}
}
public WebFormsSessionStorage
{
private static SomeSessionData _SomeSessionData; //this was before automatic get;set;
public SomeSessionData
{
get{ return _SomeSessionData;}
set{ _SomeSessionData=value; }
}
}
On initing the application, the website will do a
Framework.Storage.SessionStorage = new WebSessionStorage();
in Global.asax, and the FormsApp will do
Framework.Storage.SessionStorage = new WebFormsSessionStorage();
I agree with Womp completely - inject the data down from your front-end into your lower tiers.
If you want to do a half-way cheat (but not too much of a cheat), what you can do is create a very small assembly with just a couple POCO classes to store all of this information you want to share across all of your tiers (currently logged-in username, time logged in, etc.) and just pass this object from your front-end into your biz/data tiers. Now if you do this, you MUST avoid the temptation to turn this POCO assembly into a general utility assembly - it MUST stay small or you WILL have problems in the future (trust me or learn the hard way or ask somebody else to elaborate on this one). However, if you have this POCO assembly, injecting this data through the various tiers becomes very easy and since it's POCO, it serializes very well and works nicely with web services, WCF, etc.
I am building an application using asp.net mvc, DI, IoC, TDD as a bit of a learning exercise.
For my data access I am using the repository pattern. Now I am looking at membership and how this can work with the repository pattern. I am currently using a Linq to Sql repository but don't want to be tied to SQL Server for membership.
Secondly, I am looking to split out membership into a number of services:
AuthenticationService - identify the user
AuthorizationService - what can they do
PersonalizationService - profile
The personalization service will be what really defines a "customer" in my application and each customer will have a unique id/username that ties back to the AuthenticationService - thus, allowing me to use the default ASP.NET Membership provider, roll my own or use something like Open ID.
Is this a good approach? I don't want to reinvent the wheel but would rather these important parts of my application follow the same patterns as the rest.
Thanks
Ben
Take a look at the RIA Authentication, Roles, and Profiles services.. no need to reinvent the wheel.
To be honest, to achieve what I wanted was quite a simple process. I haven't implemented the AuthorizationService yet but this will follow a similar pattern.
My authentication service is quite simple:
public interface IAuthenticationService
{
bool IsValidLogin(string username, string password);
}
There will be a CreateUser method but I haven't implemented this yet.
Creating an authentication service using the standard membership provider is a simple task:
public class AspNetAuthenticationService : IAuthenticationService
{
public bool IsValidLogin(string username, string password)
{
return Membership.ValidateUser(username, password);
}
}
If I want to swap out the default SqlMembershipProvider with my own then I just need to change web.config. In order to support different types of authentication (perhaps forms auth and open id) I can just create a controller action for each and call the appropriate IAuthenticationService.ValidateUser implementation before setting an auth cookie.
The authentication process if for identifying the "user". In order to get the "Customer" I am using a PersonalizationService. The interface for this is again quite simple:
public interface IPersonalizationService {
Customer GetCustomer(string username);
}
This returns my customer (with addresses, past orders - the stuff we really care about). The GetCustomer method will create a customer object if one doesn't exist with the passed in username. So if using standard forms auth a customer will be created anyway during registration. If using something like OpenID, the first time they login a customer object will be created and linked to their OpenID username (hence the reason for separating what an authenticated "user" is from a "customer".
This process also works well for anonymous checkout since I can create an in memory customer object for "guest" customers, and finally persist this to the database if they make a purchase. In this case, I don't have a user (cause they didn't authenticate) but I do have a customer.
I am quite happy with this implementation. I think I will roll my own Membership Provider (since it's not really that difficult) and I would like to use the repository pattern for the data access. Interested to hear any opinions / suggestions on this approach.
Some resources I have used:
http://noahblu.wordpress.com/2009/02/19/custom-membershipprovider-using-repository-dependency-injection-pattern-magic/
http://davidhayden.com/blog/dave/archive/2007/10/11/CreateCustomMembershipProviderASPNETWebsiteSecurity.aspx
http://pbdj.sys-con.com/node/837990/mobile
http://mattwrock.com/post/2009/10/14/Implementing-custom-Membership-Provider-and-Role-Provider-for-Authinticating-ASPNET-MVC-Applications.aspx
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.