I'd like to hear if anyone sees any problems with how I implemented the security in this Oracle based MVC.NET app, either security issues, concurrency issues or scalability issues.
First, I implemented a CustomOracleMembershipProvider to handle the database interface to the membership store.
I implemented a custom Principal named User which implements IPrincipal, and it has a hashtable of Roles.
I also created a separate class named AuthCache which has a simple cache for User objects. Its purpose is simple to avoid return trips to the database, while decoupling the caching from either the web layer or the data layer. (So I can share the cache between MVC.NET, WCF, etc.)
The MVC.NET stock MembershipService uses the CustomOracleMembershipProvider (configured in web.config), and both MembershipService and FormsService share access to the singleton AuthCache.
My AccountController.LogOn() method:
1) Validates the user via the MembershipService.Validate() method, also loads the roles into the User.Roles container and then caches the User in AuthCache.
2) Signs the user into the Web context via FormsService.SignIn() which accesses the AuthCache (not the database) to get the User, sets HttpContext.Current.User to the cached User Principal.
In global.asax.cs, Application_AuthenticateRequest() is implemented. It decrypts the FormsAuthenticationTicket, accesses the AuthCache by the ticket.Name (Username) and sets the Principal by setting Context.User = user from the AuthCache.
So in short, all these classes share the AuthCache, and I have, for thread synchronization, a lock() in the cache store method. No lock in the read method.
The custom membership provider doesn't know about the cache, the MembershipService doesn't know about any HttpContext (so could be used outside of a web app), and the FormsService doesn't use any custom methods besides accessing the AuthCache to set the Context.User for the initial login, so it isn't dependent on a specific membership provider.
The main thing I see now is that the AuthCache will be sharing a User object if a user logs in from multiple sessions. So I may have to change the key from just UserId to something else (maybe using something in the FormsAuthenticationTicket for the key?).
Why use a Hashtable for the roles? A plain list would likely be faster to search unless you expect people to have more than a handful of roles. If you can predict all roles in advance then using a bitmask/flags enumeration would be even better.
You should try to avoid writing your own locking mechanism, as it's fairly easy to get wrong. Use the new System.Collections.Concurrent classes, or if you must roll your own then be sure to use Interlocked (as all the other locking mechanisms are quite expensive).
Caching should use WeakReference encapsulation to allow entries to be GCed and support retrieving user information from the database if an entry is missing. Maybe have a look at Velocity if you need a distributed cache.
Sharing user objects might not be a problem, but is probably not a recommended strategy. Many database access frameworks will track objects retrieved in a session or unit of work, and sharing objects across sessions would then be problematic. If you do go for sharing user objects then be sure to make them immutable.
Last, I personally despise the whole Membership Provider API, because it uses GUIDs for identification and the default SQL Server database design for user profiles is just horrible (aka performance killer). This does not seem to be a concern for you as you've rolled your own (db and implementation) but you might want to evaluate whether there are any real benefits involved from implementing the API, or whether it's mostly shackles tying you to specific ways of doing things.
Related
We have a fairly complicated framework (made up of multiple plugins) that we've developed for all of our future Groovy/Grails applications. One aspect of this framework is the ability to retrieve user information from the various systems that we store this data in. Currently we have three classes that represent a user (one for LDAP (non AD), one for AD, and one for database). The reason for three separate classes is because they access totally disparate systems and are based on different base classes to provide various functionality need to access these systems. There's also dependencies, etc. that require this three class approach. One of these classes (the one for AD) is also used by Spring Security to represent a user. It is also possible to create any user object type from another user object type.
What I'm trying to create is a way for us to cache these objects. For example, during login, one class is always loaded (by Spring Security). However, throughout the process of using the application, another class (for database info for example) might get loaded temporarily. Ideally I'd like to cache these objects (that all represent the same user) so that we don't have to reload information.
In the end what I'm hoping to accomplish, is the ability to pass one user object (say AD) to another user class (say database) factory method, and have the database user class check if it has ever existed before for this user and if so, instead of recreating itself, just grab the cached copy. I'd rather not use a central cache to do all of this caching, but instead store the cached information in the actual objects (just seems cleaner that way).
What I can't figure out though is how to accomplish this (from a design perspective). So I'm looking for recommendation on which design patterns might help me to figure out an approach to creating this functionality.
P.S. Just in case it matters, all user classes extend different base classes, however, they all implement a shared interface.
Sounds like the appropriate caching at the various services that are responsible for looking up the related User instances would be the most appropriate approach. Using the Cache plugin would make this quite trivial.
Your factory method could delegate to the appropriate service method which would be annotated with the correct cache. Just keep in mind that you will need to invalidate items in the cache as well if they are subject to changes.
i've a question regarding handling of user logon while porting an application to MVC:
in the "old" WebForm days, developers simply used the SessionState object to set a user to logged-on, by -for example- simply putting the userobject into the SessionState (and this userobject holds simple properties like name/lastlogon/etc.)
this stuff worked very well for us, and i've seen lots of applications doing it that way
yes, i know there is this MembershipProvide-thingy, but i've never used it
Now, in MVC, everybody tells me that "using SessionStat for this is bad" and "apps built that way are flawed in design" and that "there are tons of security risks" and so on.
I've used this method because it worked for the app very reliable, it was simple to implement and it covered all stuff we need.
(Sure, there is the thing with recycling web worker process and emptying the session - but thats not a problem in our case, since the app runs for each country on a dedicated machine)
I've read tutorials, telling me to put that stuff in the DB and -attention- doing a request to the DB to check if the user is logged in, per EACH request? But: Under no circumstances, this is a doable way since i want to keep DB requests on a minimum.
So my question is:
A) whats wrong using this way also in the new MVC app?
B) whats the best way to handle this scenario in a newly built MVC app?
Regarding the session-in-DB-idea: instead of doing this, i'd rater setup an additional service, like a "session-manager" thats get query over the network, but such simple requests should not go to the DB - isn't that a good idea?
Any idea, hint /etc. is highly appreciated since this scenario is really confusing me :-X
A)
A fundamental principal of the asp.net mvc framework is that its stateless. Data is passed around using http requests and sent to the views in viewmodels. Web forms tried to maintain state with viewstate etc thats why you would have seen the logged in user in session approach. Thats not to say session shouldnt be used completely in asp.net mvc, there are some circumstances when it can be useful. Like maintaining a 3 step form process that has to be persisted on the last step. But generally we already have a recommended way to handle the user logins, and thats forms authentication
B)
For accessing the user object, you can create a custom identity implementing the IPrincipal interface and add the required user fields you need. Then set the custom identity in a global filter and access it in your action results. Regarding not wanting to query the database for every request, why dont you just call it for the initial request, then cache the result until the user is updated where you then can reload the object and set it in the custom identity again.
with spring security i secure controllers in grails by annotation.
I have projects related to users in my modell
Question: if someone tries to manipulate i.e. the projectId (stored as session var) is it possible he can view projects which are not related to logged in user?
I could check every time if projectID in session belongs to the logged in user or do security hash on the projectID to make it harder to manipulate but i guess its an overkill?!
An other approache could be that users in my app are as well DB users so they restricted by the DB for accessing other data... just an idea of a friend but i guess as well overkill...
I know that the session var is serverside but im not sure if its save for manipulating by a user...
mybe i dont have to care about this thoughts...
I'm not entirely sure what your actual question is, since your post is hard to follow, but if you need instance-level security control, you should be using the Access Control Lists feature that Spring Security provides. It is a TON of application overhead, especially as the number of instances you need to secure grows, but it will keep people from seeing the wrong things.
That said, if there are other ways you can restrict access to entities, such as a simple SpEL rule, you will often find that you have a much cleaner, more simple security structure.
I have a site which has an area that requires authentication. Right now I use the roles attribute on all the controllers in that area, and I run a query to retrieve that users ID, and all their settings.
It seems like a code or design smell to me that I am retrieving the userid and settings each time a controller in that area loads up? I'm not sure if I should be using sessions, or if ASP.Net MVC 2.0 provides some unique way to handle this. Another concern is security.
Overall, I don't really know which way to turn. Design wise I would like the userId and settings retrieved only once when the user logs into the area. Right now I grab the userId each time a controller loads up, and then if required, I query the database for their settings each time as well.
One of the rules about security is that you shouldn't try to do it yourself. There are many pitfalls in doing an authentication system correctly without leaving loopholes or backdoors. Thus, in that regard, you might consider the SqlMembershipProvider that comes with .NET. It can be used with MVC and provides the means to get roles and the current security context, is easy to setup and configure and will be more secure than rolling your own.
If you are not using SQL Server, you have a couple of choices. One solution would be to use something like SQL Server Express or SQL Server Compact Edition to maintain the credentials. Another solution would be to mimic the SqlMembrershipProvider database schema and then write a custom provider that communicates with that schema.
The last choice would be to write a custom MembershipProvider class. While this is still rolling your own, it forces you into the structure of the MembershipProvider so that you can swap it out at a later date for a different one (e.g. ActiveDirectoryMembershipProvider) and provides a common interface for interacting with credentials and logins which for example enables easy use of the built-in Login control.
If you are already using a MembershipProvider and are asking about storing additional user-specific data, then I would suggest the SqlProfileProvider with all the caveats I mentioned above about the SqlMembershipProvider. the ProfileProvider provides a structure for maintain user-specific data with the currently logged on user.
For more information:
Introduction to Membership
Implementing a MembershipProvider
ASP.NET Profile Providers
You could also implement a custom identity. They are very easy to implement, and they let you store whatever user information you want in Identity, which is then stored in the cookies that Identity puts down, so you're not hitting the DB every time to get that info.
Just create a new class that inherits from GenericIdentity, and you'll be on your way.
You of course have to be careful how much info you put there since it's in a cookie, but usually user related information in the case you're talking about here isn't so big.
We use a custom identity to store a few bits of info about the user, and it works out pretty well.
You could store an object in session that holds all the required user information. You will just need to add a property in the Controllers, Views or other base classes where you want to retrieve the user information/profile. This would be the authorisation info as opposed to any authentication info (eg Forms authentication)
You might try "Windows Identity Foundation". I've been using it on one of my projects for a while. It allows for "claims-based authentication", which basically means that you get to designate "claims", strings of information that describe the user when she logs on.
Once logged on, the user's claims can be read from the HttpContext.Current.User field. You can also use "Role" claims that seamlessly integrate with a role-based authentication schema; meaning that you can give the user a "manager" role claim and then use `if (User.IsInRole("manager")).
As an added bonus, WIF makes it very easy to re-use your login screen in other applications.
All in all, it's very flexible, but the documentation is very poor. I've asked and answered a number of questions about "Windows Identity Foundation" on StackOverflow.
We have done this quite a few times in the past. Similar to what Thomas mentions, what we have generally done is implemented a new Membership provider based on the Microsoft SQL Memberhsip provider to do this. We inherit from the base MembershipUser class and add any custom properties we would want to have on the user object. You have to implement a database read for the Membership provider on the GetUser implementation, so you can consolidate your extra properties you need into that database read.
If you are using SQL server, Microsoft has release the 2.0 code for it. You can get more information at Scott Gu's blog.
http://weblogs.asp.net/scottgu/archive/2006/04/13/442772.aspx
If you want to start from scratch, they also have good resources at MSDN.
http://msdn.microsoft.com/en-us/library/f1kyba5e.aspx
and
http://msdn.microsoft.com/en-us/library/6tc47t75.aspx
Once you have implemented your provider, you can then add the Membership user to the Items collection of the current web context to get access to it from your code. The non extended properties from the base base user class are also available on the Request thread like normal.
With the Microsoft release of the 2.0 version of the source code , we found it helped us alleviate some concerns that exist about reinventing. Another thing to consider for your implementations is based on your scenario, you can bypass implementing some of the code. An example of this would be the CreateUser code if you are hitting a back end system that already has the credential information.
It seems like you're relatively happy with your authentication process but you want to explore other options for session/settings.
My suggestion has to do with settings only (roles, preferences, etc.)
In my opinion, having to traverse the whole technology stack from UI to Business Tier to DB tier to DB is sometimes a bit overkill.
For data that isn't likely to change during a session, this adds a lot of overhead... There are potentially several data transformations happening (DB (Relational Format) -> ORM -> Web Service XML Serialization -> Web Tier deserialization).
You might consider a session system that doesn't rely on a heavy RDBMS system or on the ASP.NET Caching / Session model. There are options that are very performant and that scale well.
You could use RavenDB by Ayende Rahien (Built for .NET). Its main goal is to provide low latency, high performance access to schema-less JSON documents.
Using this solution, you would set up ravenDB in the web tier so that access to data is very quick.
The first time you authenticate and retrieve settings, you would store the userID and settings information in this session DB.
Every time you load your controller after that, the settings data is accessible without having to go back to the RDBMS.
This DB could also be used to cache other web related data.
As for security, the settings data makes it to the web tier regardless of the method you use. This solution would be no more or less secure than the other options (more secure than an unencrypted cookie). If you needed to, you could encrypt the session data - but that will increase your overhead again.
Just another one of the million options to consider.
Good Luck,
Let us know what you decide!
Patrick.
I know what are you saying already (baad idea), but please read first :)
I am developing ASP.NET MVC based app, which will require some specific features:
combination of "local" users and facebook connect login, but FB users will be "mirrored" to some kind of local representation, because there will be some statistics and other stuff needed to keep for both types
authorization will be 3-layered instead of asp.net standard 2 layers. By this i mean : User is in Group (m:n) and Group is in Role (m:n), instead of User is in role (m:n).
So, if i would want to use standard authentication/authhorization approach, i would have to:
implement custom Membership provider, and it wont be even "right", because it will utilize methods like AddUserToGroup and AssignRoleForGroup etc.
implement custom Principal/Identity for sake of accessing my own User objects
casting HttpContext.User to my object every time needed...
implement custom Role provider
custom mechanism of sessting AuthCookie (unique userId in userdata, cant rely on username with third-party FB users in system)
... (you surely can think of something else)
Well, i really dont like the idea of "bending" and replacing every part to get pretty messy solution in the end. So I think of implementing my own mechanism encapsulated in one place - lets call it AuthService.
AuthService will be thread-safe singleton
Instead of AuthCookie will be using standard Session object (i know sessions also use cookies, but i really dont see advantage of low-level storage (cookie) over session)
AuthService will provide AuthService.CurrentUser (of my own type), populated from session on beginning of every request (Application_AuthenticateRequest, I think)
AuthService will provide in one place all methods - ValidateUser, RolesForUser, IsInRole, Logout, etc.
So now.. why should I not do this this way ? :)
I think session is equally secure to AuthCookie (same risks for ticket and authcookie)..
I dont really look for "modularity" (plug-and-play role providers, membership providers, profile providers..) - I deal here with pretty specific stuff, I dont expect standard components to fit.. have "my approach" any other disadvantages ?
Thanks for all good ideas and sorry my terrible english, I am from non-english-speaking country :)
R.
I can certainly see why you don't want to implement an entire Membership provider. However, I would take advantage of the low-level support offered by Forms Authentication (e.g. the cookie, expiration etc.) and just do my own custom authentication. If you do this, you can inject your own custom user class into the HTTP context and use it throughout your code. Your custom user object would implement IIdentity and IPrincipal. Your IPrincipal.IsInRole would work against your custom authentication scheme. This would allow your higher level code to use standard .NET framework permissions stuff. This is the neatest, simplest way to accomplish what you want while taking advantage of what already exists.